pax_global_header00006660000000000000000000000064117400061710014507gustar00rootroot0000000000000052 comment=4b41a46a627dd7b4a3dcf8fbf4db5d0a4df84bb4 Multiverse-multiverse-0.7.0/000077500000000000000000000000001174000617100160475ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/.gitignore000066400000000000000000000002301174000617100200320ustar00rootroot00000000000000*.class .gradle/ .DS_Store* out/ multiverse-core/build/ multiverse-site/build/ multiverse-core/target/ *.iml .idea/ gradle.properties release.propertiesMultiverse-multiverse-0.7.0/LICENSE000066400000000000000000000011711174000617100170540ustar00rootroot00000000000000License This software is licensed under the Apache 2 license, quoted below. Copyright 2009-2012 Peter Veentjer. 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.Multiverse-multiverse-0.7.0/README.md000066400000000000000000000033621174000617100173320ustar00rootroot00000000000000Multiverse Software Transactional Memory ------------------------- A software transactional memory implementation for the JVM. Access (read and writes) to shared memory is done through transactional references, that can be compared to the AtomicReferences of Java. Access to these references will be done under A (atomicity), C (consistency), I (isolation) semantics. For more information see multiverse.codehaus.org Example ------------------------- import org.multiverse.api.references.*; import static org.multiverse.api.StmUtils.*; public class Account{ private final TxnRef lastModified = newTxnRef(); private final TxnLong amount = newTxnLong(); public Account(long amount){ this.amount.set(amount); this.lastModified.set(new Date()); } public Date getLastModifiedDate(){ return lastModified.get(); } public long getAmount(){ return amount.get(); } public static void transfer(final Account from, final Account to, final long amount){ atomic(new Runnable()){ public void run(){ Date date = new Date(); from.lastModified.set(date); from.amount.dec(amount); to.lastModified.set(date); to.amount.inc(amount); } } } } And it can be called like this: Account account1 = new Account(10); Account account2 = new Account(20) Account.transfer(account1, account2, 5); No instrumentation. ------------------------- Multiverse doesn't rely on instrumentation, so is easy to integrate in existing projects.Multiverse-multiverse-0.7.0/benchmarks/000077500000000000000000000000001174000617100201645ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/benchmarks/atomic/000077500000000000000000000000001174000617100214405ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_get_benchmark.groovy000066400000000000000000000011161174000617100270330ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.AtomicGetDriver def benchmark = new Benchmark(); benchmark.name = "atomic_get" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "atomic_get_with_${k}_threads" testCase.warmupRunIterationCount = k==1?1:0; testCase.threadCount = k testCase.transactionsPerThread = 1000 * 1000 * 10000L testCase.sharedRef = true testCase.weakGet = false testCase.driver = AtomicGetDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_get_display.groovy000066400000000000000000000036121174000617100265510ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.* def benchmarks = searcher.findAllBenchmarks('atomic_get') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset(); def xySeriesDataSet = new XYSeriesCollection(); def xyTotalSeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def series = new XYSeries(benchmark.date); def totalSeries = new XYSeries(benchmark.date); def entries = new LinkedList(benchmark.testCases) entries.sort {it.threadCount} entries.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerSecondPerThread') categoryDataSet.addValue(transactionsPerSecondPerThread, benchmark.date, testCase.threadCount) series.add(testCase.threadCount, transactionsPerSecondPerThread) def transactionsPerSecond = testCase.average('transactionsPerSecond') totalSeries.add(testCase.threadCount, transactionsPerSecond) } xySeriesDataSet.addSeries(series); xyTotalSeriesDataSet.addSeries(totalSeries); } writeLineChartAsPng(xySeriesDataSet, "Atomic Get", "threads", "transaction/second/thread", new File("charts/atomic_get_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Atomic Get", "threads", "transaction/second/thread",600, new File("charts/atomic_get_line_narrow.png")) writeLineChartAsPng(xyTotalSeriesDataSet, "Atomic Get", "threads", "transaction/second", new File("charts/atomic_get_line_total_wide.png")) writeLineChartAsPng(xyTotalSeriesDataSet, "Atomic Get", "threads", "transaction/second",600, new File("charts/atomic_get_line_total_narrow.png")) writeBarChartAsPng(categoryDataSet, "Atomic Get", "threads", "transaction/second/thread", new File("charts/atomic_get_bar.png")) Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_get_total_display.groovy000066400000000000000000000026371174000617100277620ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.writeBarChartAsPng import static org.benchy.JGraphGraphBuilder.writeLineChartAsPng def benchmarks = searcher.findAllBenchmarks('atomic_weak_get') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset(); def xySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def series = new XYSeries(benchmark.date); def entries = new LinkedList(benchmark.testCases) entries.sort {it.threadCount} entries.each { def testCase = it def transactionsPerSecond = testCase.average('transactionsPerSecond') categoryDataSet.addValue(transactionsPerSecond, benchmark.date, testCase.threadCount) series.add(testCase.threadCount, transactionsPerSecond) } xySeriesDataSet.addSeries(series); } writeLineChartAsPng(xySeriesDataSet, "Atomic Weak Get", "threads", "transaction/second/thread", new File("charts/atomic_weak_get_line_total_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Atomic Weak Get", "threads", "transaction/second/thread", 600, new File("charts/atomic_weak_get_line_total_narrow.png")) writeBarChartAsPng(categoryDataSet, "Atomic Weak Get", "threads", "transaction/second/thread", new File("charts/atomic_weak_get_total_bar.png")) Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_increment_benchmark.groovy000066400000000000000000000017121174000617100302420ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.AtomicIncrementDriver def benchmark = new Benchmark(); benchmark.name = "atomic_increment" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "atomic_increment_and_no_shared_ref" testCase.warmupRunIterationCount = k == 1 ? 1 : 0; testCase.threadCount = k testCase.transactionsPerThread = 1000 * 1000 * 1000L testCase.sharedRef = false testCase.driver = AtomicIncrementDriver.class benchmark.add(testCase) } for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "atomic_increment_and_shared_ref" testCase.warmupRunIterationCount = k == 1 ? 1 : 0; testCase.threadCount = k testCase.sharedRef = true testCase.transactionsPerThread = k == 0 ? 1000 * 1000 * 100L : 1000 * 1000 * 10L testCase.driver = AtomicIncrementDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_increment_display.groovy000066400000000000000000000040211174000617100277510ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.writeBarChartAsPng import static org.benchy.JGraphGraphBuilder.writeLineChartAsPng def benchmarks = searcher.findAllBenchmarks('atomic_increment') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset() def xySeriesDataSet = new XYSeriesCollection() def totalXySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def series = new XYSeries(benchmark.date) def totalSeries = new XYSeries(benchmark.date) def entries = new LinkedList(benchmark.testCases) entries.sort {it.threadCount} entries.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerSecondPerThread') categoryDataSet.addValue(transactionsPerSecondPerThread, benchmark.date, testCase.threadCount) series.add(testCase.threadCount, transactionsPerSecondPerThread) def transactionsPerSecond = testCase.average('transactionsPerSecond') totalSeries.add(testCase.threadCount, transactionsPerSecond) } xySeriesDataSet.addSeries(series) totalXySeriesDataSet.addSeries(totalSeries); } writeLineChartAsPng(xySeriesDataSet, "Atomic Increment", "threads", "transaction/second/thread", new File("charts/atomic_increment_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Atomic Increment", "threads", "transaction/second/thread", 600, new File("charts/atomic_increment_line_narrow.png")) writeLineChartAsPng(totalXySeriesDataSet, "Atomic Increment", "threads", "transaction/second", new File("charts/atomic_increment_line_total_wide.png")) writeLineChartAsPng(totalXySeriesDataSet, "Atomic Increment", "threads", "transaction/second", 600, new File("charts/atomic_increment_line_total_narrow.png")) writeBarChartAsPng(categoryDataSet, "Atomic Increment", "threads", "transaction/second/thread", new File("charts/atomic_increment_bar.png")) Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_long_increment_benchmark.groovy000066400000000000000000000017371174000617100312700ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.AtomicLongIncrementDriver def benchmark = new Benchmark(); benchmark.name = "atomic_long_increment" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "atomic_long_increment_no_shared_ref" testCase.warmupRunIterationCount = k == 1 ? 1 : 0; testCase.threadCount = k testCase.sharedRef = false testCase.transactionsPerThread = 1000 * 1000 * 1000L testCase.driver = AtomicLongIncrementDriver.class benchmark.add(testCase) } for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "atomic_long_increment_shared_ref" testCase.warmupRunIterationCount = k == 1 ? 1 : 0; testCase.threadCount = k testCase.sharedRef = true testCase.transactionsPerThread = k == 0 ? 1000 * 1000 * 1000L : 100 * 1000 * 1000L testCase.driver = AtomicLongIncrementDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_long_increment_display.groovy000066400000000000000000000041411174000617100307730ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.writeBarChartAsPng import static org.benchy.JGraphGraphBuilder.writeLineChartAsPng def benchmarks = searcher.findAllBenchmarks('atomic_long_increment') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset() def xySeriesDataSet = new XYSeriesCollection() def totalXySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def series = new XYSeries(benchmark.date) def totalSeries = new XYSeries(benchmark.date) def entries = new LinkedList(benchmark.testCases) entries.sort {it.threadCount} entries.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerSecondPerThread') categoryDataSet.addValue(transactionsPerSecondPerThread, benchmark.date, testCase.threadCount) series.add(testCase.threadCount, transactionsPerSecondPerThread) def transactionsPerSecond = testCase.average('transactionsPerSecond') totalSeries.add(testCase.threadCount, transactionsPerSecond) } xySeriesDataSet.addSeries(series) totalXySeriesDataSet.addSeries(totalSeries); } writeLineChartAsPng(xySeriesDataSet, "AtomicLong.incrementAndGet", "threads", "transaction/second/thread", new File("charts/atomic_long_increment_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "AtomicLong.incrementAndGet", "threads", "transaction/second/thread", 600, new File("charts/atomic_long_increment_line_narrow.png")) writeLineChartAsPng(totalXySeriesDataSet, "AtomicLong.incrementAndGet", "threads", "transaction/second", new File("charts/atomic_increment_long_line_total_wide.png")) writeLineChartAsPng(totalXySeriesDataSet, "AtomicLong.incrementAndGet", "threads", "transaction/second", 600, new File("charts/atomic_long_increment_line_total_narrow.png")) writeBarChartAsPng(categoryDataSet, "AtomicLong.incrementAndGet", "threads", "transaction/second/thread", new File("charts/atomic_long_increment_bar.png")) Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_weak_get_benchmark.groovy000066400000000000000000000011271174000617100300440ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.AtomicGetDriver def benchmark = new Benchmark(); benchmark.name = "atomic_weak_get" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "atomic_weak_get_with_${k}_threads" testCase.threadCount = k testCase.transactionsPerThread = 1000 * 1000 * 10000L testCase.sharedRef = true testCase.weakGet = true testCase.warmupRunIterationCount = k==1?1:0; testCase.driver = AtomicGetDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/atomic/atomic_weak_get_display.groovy000066400000000000000000000040061174000617100275560ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.writeBarChartAsPng import static org.benchy.JGraphGraphBuilder.writeLineChartAsPng def benchmarks = searcher.findAllBenchmarks('atomic_weak_get') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset() def xySeriesDataSet = new XYSeriesCollection() def totalXySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def series = new XYSeries(benchmark.date) def totalSeries = new XYSeries(benchmark.date) def entries = new LinkedList(benchmark.testCases) entries.sort {it.threadCount} entries.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerSecondPerThread') categoryDataSet.addValue(transactionsPerSecondPerThread, benchmark.date, testCase.threadCount) series.add(testCase.threadCount, transactionsPerSecondPerThread) def transactionsPerSecond = testCase.average('transactionsPerSecond') totalSeries.add(testCase.threadCount, transactionsPerSecond) } xySeriesDataSet.addSeries(series) totalXySeriesDataSet.addSeries(totalSeries); } writeLineChartAsPng(xySeriesDataSet, "Atomic Weak Get", "threads", "transaction/second/thread", new File("charts/atomic_weak_get_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Atomic Weak Get", "threads", "transaction/second/thread", 600, new File("charts/atomic_weak_get_line_narrow.png")) writeLineChartAsPng(totalXySeriesDataSet, "Atomic Weak Get", "threads", "transaction/second", new File("charts/atomic_weak_get_line_total_wide.png")) writeLineChartAsPng(totalXySeriesDataSet, "Atomic Weak Get", "threads", "transaction/second", 600, new File("charts/atomic_weak_get_line_total_narrow.png")) writeBarChartAsPng(categoryDataSet, "Atomic Weak Get", "threads", "transaction/second/thread", new File("charts/atomic_weak_get_bar.png")) Multiverse-multiverse-0.7.0/benchmarks/blocking/000077500000000000000000000000001174000617100217545ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/benchmarks/blocking/intrinsic_lock_stack_benchmark.groovy000066400000000000000000000012461174000617100314370ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.IntrinsicLockStackDriver def benchmark = new Benchmark(); benchmark.name = "intrinsic_lock_stack" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "intrinsic_lock_stack_with_${k}_threads" testCase.pushThreadCount = k testCase.popThreadCount = k testCase.durationInSeconds=30 testCase.transactionsPerThread = 1000 * 1000 * 10L testCase.warmupRunIterationCount = k==1?1:0 testCase.capacity = Integer.MAX_VALUE testCase.driver = IntrinsicLockStackDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/blocking/juc_lock_stack_benchmark.groovy000066400000000000000000000012161174000617100302130ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.JucLockStackDriver def benchmark = new Benchmark(); benchmark.name = "juc_lock_stack" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "juc_lock_stack_with_${k}_threads" testCase.pushThreadCount = k testCase.popThreadCount = k testCase.durationInSeconds=30 testCase.transactionsPerThread = 1000 * 1000 * 10L testCase.warmupRunIterationCount = k==1?1:0 testCase.capacity = Integer.MAX_VALUE testCase.driver = JucLockStackDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/blocking/simple_stack_benchmark.groovy000066400000000000000000000020551174000617100277150ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.SimpleStackDriver def benchmark = new Benchmark(); benchmark.name = "simple_stack" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "simple_stack_with_${k}_threads" testCase.pushThreadCount = k testCase.popThreadCount = k testCase.durationInSeconds=30 testCase.transactionsPerThread = 1000 * 1000 * 10L testCase.warmupRunIterationCount = k==1?1:0; testCase.driver = SimpleStackDriver.class benchmark.add(testCase) } for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "simple_stack_using_pooled_closures_with_${k}_threads" testCase.pushThreadCount = k testCase.popThreadCount = k testCase.durationInSeconds=30 testCase.poolClosures = true testCase.transactionsPerThread = 1000 * 1000 * 10L testCase.warmupRunIterationCount = k==1?1:0; testCase.driver = SimpleStackDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/contended_counter_benchmark.groovy000066400000000000000000000022041174000617100271450ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.ContendedCounterDriver def benchmark = new Benchmark(); benchmark.name = "counter" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "counter_with_${k}_threads" testCase.dirtyCheck = true testCase.threadCount = k if (k > 2) { testCase.transactionsPerThread = 1000 * 1000 * 5 } else { testCase.transactionsPerThread = 1000 * 1000 * 20 } testCase.warmupRunIterationCount = k == 1 ? 1 : 0; testCase.driver = ContendedCounterDriver.class benchmark.add(testCase) } for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "counter_no_dirtyCheck_with_${k}_threads" testCase.threadCount = k testCase.dirtyCheck = false if (k > 2) { testCase.transactionsPerThread = 1000 * 1000 * 5 } else { testCase.transactionsPerThread = 1000 * 1000 * 20 } testCase.warmupRunIterationCount = k == 1 ? 1 : 0; testCase.driver = ContendedCounterDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/contended_counter_display.groovy000066400000000000000000000033341174000617100266650ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.* def benchmarks = searcher.findAllBenchmarks('counter') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset(); def xySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def seriesNoDirtyCheck = new XYSeries("${benchmark.date} without dirty check"); def seriesDirtyCheck = new XYSeries("${benchmark.date} with dirty check"); def testcases = new LinkedList(benchmark.testCases) testcases.sort {it.threadCount} testcases.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerSecondPerThread') categoryDataSet.addValue(transactionsPerSecondPerThread, "${benchmark.date} ${testCase.name}", testCase.threadCount) if(testCase.dirtyCheck){ seriesDirtyCheck.add(testCase.threadCount, transactionsPerSecondPerThread) }else{ seriesNoDirtyCheck.add(testCase.threadCount, transactionsPerSecondPerThread) } } xySeriesDataSet.addSeries(seriesNoDirtyCheck); xySeriesDataSet.addSeries(seriesDirtyCheck); } writeLineChartAsPng(xySeriesDataSet, "Contended Counter", "threads", "transaction/second/thread", new File("charts/contended_counter_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Contended Counter", "threads", "transaction/second/thread", 600, new File("charts/contended_counter_line_narrow.png")) writeBarChartAsPng(categoryDataSet, "Contended Counter", "threads", "transaction/second/thread", new File("charts/contended_counter_update_bar.png")) Multiverse-multiverse-0.7.0/benchmarks/mono_read_benchmark.groovy000066400000000000000000000010151174000617100254050ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.MonoReadDriver def benchmark = new Benchmark(); benchmark.name = "mono_read" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "mono_read_with_${k}_threads" testCase.threadCount = k testCase.transactionsPerThread = 1000 * 1000 * 500L testCase.driver = MonoReadDriver.class testCase.warmupRunIterationCount = k==1?1:0; benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/mono_read_display.groovy000066400000000000000000000025341174000617100251270ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.* def benchmarks = searcher.findAllBenchmarks('mono_read') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset(); def xySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def series = new XYSeries(benchmark.date); def entries = new LinkedList(benchmark.testCases) entries.sort {it.threadCount} entries.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerSecondPerThread') categoryDataSet.addValue(transactionsPerSecondPerThread, benchmark.date, testCase.threadCount) series.add(testCase.threadCount, transactionsPerSecondPerThread) } xySeriesDataSet.addSeries(series); } writeLineChartAsPng(xySeriesDataSet, "Uncontended Mono Read", "threads", "transaction/second/thread", new File("charts/mono_read_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Uncontended Mono Read", "threads", "transaction/second/thread", 600, new File("charts/mono_read_line_narrow.png")) writeBarChartAsPng(categoryDataSet, "Uncontended Mono Read", "threads", "transaction/second/thread", new File("charts/mono_read_bar.png")) Multiverse-multiverse-0.7.0/benchmarks/multipleupdatebenchmark.groovy000066400000000000000000000010711174000617100263430ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.MultipleUpdateDriver def benchmark = new Benchmark() benchmark.name = "multiple_update" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "multiple_update_with_${k}_refs" testCase.threadCount = 1 testCase.refCount = k testCase.transactionsPerThread = 1000 * 1000 * 20 testCase.driver = MultipleUpdateDriver.class benchmark.add(testCase) testCase.warmupRunIterationCount = k==1?1:0; } benchmark Multiverse-multiverse-0.7.0/benchmarks/orec/000077500000000000000000000000001174000617100211145ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/benchmarks/orec/read_benchmark.groovy000066400000000000000000000012711174000617100253110ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase def benchmark = new Benchmark(); benchmark.name = "orec_read" def readNormalTestCase = new GroovyTestCase() readNormalTestCase.name = "orec_read_normal" readNormalTestCase.warmupRunIterationCount = 1 readNormalTestCase.operationCount = 1000 * 1000 * 10000L readNormalTestCase.driver = OrecNormalReadDriver.class benchmark.add(readNormalTestCase) def readBiasedUpdate = new GroovyTestCase() readBiasedUpdate.name = "orec_read_biased" readBiasedUpdate.warmupRunIterationCount = 1 readBiasedUpdate.operationCount = 1000 * 1000 * 10000L readBiasedUpdate.driver = OrecReadBiasedReadDriver.class benchmark.add(readBiasedUpdate) benchmark Multiverse-multiverse-0.7.0/benchmarks/orec/update_benchmark.groovy000066400000000000000000000024741174000617100256660ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.orec.OrecCommitLockUpdateDriver import org.multiverse.stms.beta.benchmarks.orec.OrecNormalUpdateDriver import org.multiverse.stms.beta.benchmarks.orec.OrecWriteLockUpdateDriver def benchmark = new Benchmark(); benchmark.name = "orec_update" def updateTestCase = new GroovyTestCase() updateTestCase.name = "orec_update_optimistic" updateTestCase.warmupRunIterationCount = 1 updateTestCase.operationCount = 1000 * 1000 * 1000L updateTestCase.driver = OrecNormalUpdateDriver.class benchmark.add(updateTestCase) def updateWithWriteLockTestCase = new GroovyTestCase() updateWithWriteLockTestCase.name = "orec_update_with_writelock" updateWithWriteLockTestCase.warmupRunIterationCount = 1 updateWithWriteLockTestCase.operationCount = 1000 * 1000 * 1000L updateWithWriteLockTestCase.driver = OrecWriteLockUpdateDriver.class benchmark.add(updateWithWriteLockTestCase) def updateWithCommitLockTestCase = new GroovyTestCase() updateWithCommitLockTestCase.name = "orec_update_with_commitlock" updateWithCommitLockTestCase.warmupRunIterationCount = 1 updateWithCommitLockTestCase.operationCount = 1000 * 1000 * 1000L updateWithCommitLockTestCase.driver = OrecCommitLockUpdateDriver.class benchmark.add(updateWithCommitLockTestCase) benchmark Multiverse-multiverse-0.7.0/benchmarks/overhead/000077500000000000000000000000001174000617100217615ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/benchmarks/overhead/boxing_overhead_benchmark.groovy000066400000000000000000000017411174000617100304100ustar00rootroot00000000000000import org.multiverse.stms.beta.benchmarks.BoxingOverheadDriver import org.benchy.Benchmark import org.benchy.GroovyTestCase def benchmark = new Benchmark(); benchmark.name = "boxing_overhead" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "boxing_overhead_with_${k}_threads_and_boxing" testCase.threadCount = k testCase.withBoxing = true testCase.transactionsPerThread = 1000 * 1000 * 100 testCase.warmupRunIterationCount = k == 1 ? 1 : 0; testCase.driver = BoxingOverheadDriver.class benchmark.add(testCase) } for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "boxing_overhead_with_${k}_threads_and_no_boxing" testCase.threadCount = k testCase.withBoxing = false testCase.transactionsPerThread = 1000 * 1000 * 200 testCase.warmupRunIterationCount = k == 1 ? 1 : 0; testCase.driver = BoxingOverheadDriver.class benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/overhead/boxing_overhead_display.groovy000066400000000000000000000032511174000617100301210ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.* def benchmarks = searcher.findAllBenchmarks('boxing_overhead') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset(); def xySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def seriesNoBoxing = new XYSeries("${benchmark.date} no boxing"); def seriesBoxing = new XYSeries("${benchmark.date} with boxing"); def testcases = new LinkedList(benchmark.testCases) testcases.sort {it.threadCount} testcases.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerThreadPerSecond') categoryDataSet.addValue(transactionsPerSecondPerThread, "${benchmark.date} ${testCase.name}", testCase.threadCount) if(testCase.withBoxing){ seriesBoxing.add(testCase.threadCount, transactionsPerSecondPerThread) }else{ seriesNoBoxing.add(testCase.threadCount, transactionsPerSecondPerThread) } } xySeriesDataSet.addSeries(seriesNoBoxing); xySeriesDataSet.addSeries(seriesBoxing); } writeLineChartAsPng(xySeriesDataSet, "Boxing overhead", "threads", "transaction/second/thread", new File("charts/boxing_overhead_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Boxing overhead", "threads", "transaction/second/thread", 600,new File("charts/boxing_overhead_line_narrow.png")) writeBarChartAsPng(categoryDataSet, "Boxing overhead", "threads", "transaction/second/thread", new File("charts/boxing_overhead_bar.png")) Multiverse-multiverse-0.7.0/benchmarks/overhead/boxing_overhead_total_display.groovy000066400000000000000000000025431174000617100313270ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.* def benchmarks = searcher.findAllBenchmarks('boxing_overhead') println("Benchy > Found ${benchmarks.size()} results") def xySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def seriesNoBoxing = new XYSeries("${benchmark.date} no boxing"); def seriesBoxing = new XYSeries("${benchmark.date} with boxing"); def testcases = new LinkedList(benchmark.testCases) testcases.sort {it.threadCount} testcases.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerSecond') if(testCase.withBoxing){ seriesBoxing.add(testCase.threadCount, transactionsPerSecondPerThread) }else{ seriesNoBoxing.add(testCase.threadCount, transactionsPerSecondPerThread) } } xySeriesDataSet.addSeries(seriesNoBoxing); xySeriesDataSet.addSeries(seriesBoxing); } writeLineChartAsPng(xySeriesDataSet, "Boxing overhead", "threads", "transaction/second", new File("charts/boxing_overhead_total_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Boxing overhead", "threads", "transaction/second", 600, new File("charts/boxing_overhead_total_line_narrow.png")) Multiverse-multiverse-0.7.0/benchmarks/uncontended_mono_update_benchmark.groovy000066400000000000000000000011011174000617100303360ustar00rootroot00000000000000import org.benchy.Benchmark import org.benchy.GroovyTestCase import org.multiverse.stms.beta.benchmarks.UncontendedMonoUpdateDriver def benchmark = new Benchmark(); benchmark.name = "uncontended_mono_update" for (def k in 1..processorCount) { def testCase = new GroovyTestCase() testCase.name = "uncontended_mono_update_with_${k}_threads" testCase.threadCount = k testCase.transactionsPerThread = 1000 * 1000 * 50 testCase.driver = UncontendedMonoUpdateDriver.class testCase.warmupRunIterationCount = k==1?1:0; benchmark.add(testCase) } benchmark Multiverse-multiverse-0.7.0/benchmarks/uncontended_mono_update_display.groovy000066400000000000000000000026321174000617100300630ustar00rootroot00000000000000import org.jfree.data.category.DefaultCategoryDataset import org.jfree.data.xy.XYSeries import org.jfree.data.xy.XYSeriesCollection import static org.benchy.JGraphGraphBuilder.* def benchmarks = searcher.findAllBenchmarks('uncontended_mono_update') println("Benchy > Found ${benchmarks.size()} results") def categoryDataSet = new DefaultCategoryDataset(); def xySeriesDataSet = new XYSeriesCollection(); for (def benchmark in benchmarks) { def series = new XYSeries(benchmark.date); def entries = new LinkedList(benchmark.testCases) entries.sort {it.threadCount} entries.each { def testCase = it def transactionsPerSecondPerThread = testCase.average('transactionsPerSecondPerThread') categoryDataSet.addValue(transactionsPerSecondPerThread, benchmark.date, testCase.threadCount) series.add(testCase.threadCount, transactionsPerSecondPerThread) } xySeriesDataSet.addSeries(series); } writeLineChartAsPng(xySeriesDataSet, "Uncontended Mono Update", "threads", "transaction/second/thread", new File("charts/uncontended_mono_update_line_wide.png")) writeLineChartAsPng(xySeriesDataSet, "Uncontended Mono Update", "threads", "transaction/second/thread", 600, new File("charts/uncontended_mono_update_line_narrow.png")) writeBarChartAsPng(categoryDataSet, "Uncontended Mono Update", "threads", "transaction/second/thread", new File("charts/uncontended_mono_update_bar.png")) Multiverse-multiverse-0.7.0/build.gradle000066400000000000000000000164751174000617100203430ustar00rootroot00000000000000import org.codehaus.groovy.ant.Groovy def executeBenchmark(String filepath) { execute("benchy-execute -p ${processorCount} -cp multiverse-gamma/build/classes/main:multiverse-gamma/build/classes/test ${filepath}") } def executeDisplay(String filepath) { execute("benchy-display ${filepath}") } def execute(String s) { Process proc = s.execute() proc.consumeProcessErrorStream(System.err) proc.consumeProcessOutputStream(System.out) if (proc.waitFor() != 0) { throw new RuntimeException('exec failed') } } allprojects { // apply plugin: 'base' defaultTasks 'clean', 'install' } project(':multiverse-core') { apply plugin: 'java' apply plugin: 'maven' apply plugin: 'project-reports' sourceCompatibility = 1.6 version = '0.7.0' group = 'org.multiverse' //install.dependsOn ':build' def localMavenRepo = 'file://' + new File(System.getProperty('user.home'), '.m2/repository').absolutePath configurations { testFixtures { extendsFrom testRuntime } deployerJars } javadoc { title = "Multiverse Core $version" } repositories { mavenRepo(url: localMavenRepo) mavenCentral() mavenRepo(url: 'http://download.java.net/maven/2/') mavenRepo(url: 'https://maven.atlassian.com/content/groups/public') mavenRepo(url: 'http://snapshots.repository.codehaus.org') } dependencies { testCompile group: 'junit', name: 'junit', version: '4.10' testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.0' testCompile group: 'org.benchy', name: 'benchy-driver', version: '0.1-SNAPSHOT' deployerJars "org.apache.maven.wagon:wagon-ssh:2.2" deployerJars group: 'org.apache.maven.wagon', name: 'wagon-webdav-jackrabbit', version: '2.2' } task benchmarkUncontendedMonoUpdate << { executeBenchmark("benchmarks/uncontended_mono_update_benchmark.groovy") executeDisplay("benchmarks/uncontended_mono_update_display.groovy") } task benchmarkCounter << { executeBenchmark("benchmarks/contended_counter_benchmark.groovy") executeDisplay("benchmarks/contended_counter_display.groovy") } task benchmarkMonoRead << { executeBenchmark("benchmarks/mono_read_benchmark.groovy") executeDisplay("benchmarks/mono_read_display.groovy") } task benchmarkAtomicGet << { executeBenchmark("benchmarks/atomic/atomic_get_benchmark.groovy") executeDisplay("benchmarks/atomic/atomic_get_display.groovy") } task benchmarkAtomicWeakGet << { executeBenchmark("benchmarks/atomic/atomic_weak_get_benchmark.groovy") executeDisplay("benchmarks/atomic/atomic_weak_get_display.groovy") } task benchmarkAtomicIncrement << { executeBenchmark("benchmarks/atomic/atomic_increment_benchmark.groovy") executeDisplay("benchmarks/atomic/atomic_increment_display.groovy") } task benchmarkAtomicLongIncrement << { executeBenchmark("benchmarks/atomic/atomic_long_increment_benchmark.groovy") executeDisplay("benchmarks/atomic/atomic_long_increment_display.groovy") } task benchmarkSimpleStack << { executeBenchmark("benchmarks/blocking/simple_stack_benchmark.groovy") } task benchmarkIntrinsicLockStack << { executeBenchmark("benchmarks/blocking/intrinsic_lock_stack_benchmark.groovy") //execute("benchy-display benchmarks/atomic_weak_get_display.groovy") } task benchmarkJucLockStack << { executeBenchmark("benchmarks/blocking/juc_lock_stack_benchmark.groovy") //execute("benchy-display benchmarks/atomic_weak_get_display.groovy") } task benchmarkOrecUpdate << { executeBenchmark("benchmarks/orec/update_benchmark.groovy") //execute("benchy-display benchmarks/atomic_weak_get_display.groovy") } task benchmarkOrecRead << { executeBenchmark("benchmarks/orec/update_benchmark.groovy") //execute("benchy-display benchmarks/atomic_weak_get_display.groovy") } task benchmarkBoxingOverhead << { executeBenchmark("benchmarks/overhead/boxing_overhead_benchmark.groovy") executeDisplay("benchmarks/overhead/boxing_overhead_display.groovy") executeDisplay("benchmarks/overhead/boxing_overhead_total_display.groovy") } task benchmark(dependsOn: [ benchmarkUncontendedMonoUpdate, benchmarkCounter, benchmarkMonoRead, benchmarkAtomicGet, benchmarkAtomicWeakGet, benchmarkSimpleStack, benchmarkIntrinsicLockStack, benchmarkJucLockStack, benchmarkAtomicIncrement, benchmarkAtomicLongIncrement, benchmarkOrecUpdate, benchmarkOrecRead, benchmarkBoxingOverhead]) << {} test { exclude("**/*AbstractTest*") exclude("**/*Benchmark*") exclude("**/*StressTest*") exclude("**/*stressTest*") exclude("**/*LongTest*") exclude("**/*PerformanceTest*") exclude("**/*performanceTest*") exclude("**/*Driver*") } task shortintegrationtest(type: Test) { include("**/*StressTest*") include("**/*stressTest*") include("**/*LongTest*") include("**/*longTest*") } task integrationtest(type: Test) { include("**/*StressTest*") include("**/*stressTest*") include("**/*LongTest*") include("**/*longTest*") } shortintegrationtest { jvmArgs = ["-Dorg.multiverse.integrationtest.durationMs=10000", "-Dorg.multiverse.bugshaker.enabled=true"] } task deploy(dependsOn: ['clean', 'javadoc', 'install', 'uploadArchives']) << { } // custom tasks for creating source/javadoc jars task sourcesJar(type: Jar, dependsOn: classes) { classifier = 'sources' from sourceSets.main.allSource } task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from javadoc.destinationDir } // add javadoc/source jar tasks as artifacts artifacts { archives sourcesJar archives javadocJar } uploadArchives() { repositories.mavenDeployer { name = 'sshDeployer' uniqueVersion = false configuration = configurations.deployerJars repository( url: 'dav.codehaus.org/repository/multiverse/') { authentication(userName: "$codehaus_loginname", password: "$codehaus_password") } snapshotRepository( url: 'dav.codehaus.org/snapshots.repository/multiverse/') { authentication(userName: "$codehaus_loginname", password: "$codehaus_password") } } } } project(':multiverse-site') { task clean << { ant.delete(dir: "${projectDir}/build") } task install(dependsOn: clean) << { def binding = new Binding() def parent = Groovy.class.getClassLoader() def loader = new GroovyClassLoader(parent) def shell = new GroovyShell(loader, binding) shell.evaluate(new java.io.File("multiverse-site/menu.groovy")) println "Copying charts" ant.copy(todir: "${projectDir}/build/site") { fileset(dir: "../charts") } println "Finished copying charts" } } Multiverse-multiverse-0.7.0/charts/000077500000000000000000000000001174000617100173335ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/charts/atomic_get_bar.png000066400000000000000000000574511174000617100230140ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix^ðIDATxÚíÝ}PVw~ÿÿÌt:N§Óé?Nÿètv¦ÓéN§l’M²¬……º²ýá~uõ»"k´Ü¨aÁl"Ñ%¢¢Œ–àz1ÞÅ›HL51ÊjQ‚+òµºø©Ä”à5X>ßóþÈuýÎuqÝœs®ÃÅ<_Î{¼8çpÎŹÎÝãúœ›g!„B!„Ä(Ï0 !„B!„B!„@!„B!€B!„B!„L·|ç;ßQÏ<óŒ¯þú¯ÿzêí&ãgB!„B¦aòóóƒçææ9~ü¸ßtþüÏÿ\íÙ³G êþG£OZGž}öYB!„B¦OþçþGýÙŸý™ï õOþäOüœ9ص—ÿüÏÿÔ§XyçËýÑ©;wîL)`B!„â8çÏŸ÷;h}õÕWý~þøãÃäZ9­èÖ­[*;;[ýÕ_ý•úƒ?ø}Ä_þå_ên7oÞ´|0ýæ›ojÉ8¤å@Þ»¤««KË{Åßÿýß«ƒÚ>@ïììTk×®UÏ?ÿ¼úÃ?üC=.ÙOúSõ›ßüÆÒü\¿~½ß4Ö­[çès´HËÔßþíßúÞ‹üíóæÍsjœ“Ï„B!„ ÉÏ~ö3ߪä éÿ½ÝäBéhvwïÞ­~ï÷~/ì°UUU± Àö»r·˜ëwèÐ!Ë‘k6¤µ"Úx¹¸Üü;¶?ù›YáÞ‹@€B!„I•ááaýíº÷5--MwONNöu“þ2\$ ‹|SoFZä¥ÞÞÞ1ꑾ՗;I Žäàûì3¿~2l¸ñËEÛ¹€;°ßÕ«Wu?9Ø7w XyÏrZ“¹ûöíÛÏS3d‚Í—H­YYY~ÝïÞ½ëëø·'$$B „2y2kÖ,¿Ö/¾øBw—ÿÍÝe8'1_ŒØ ßè›ûɰáÆoþÝpý Ô{6_x/%ÏïpšH- ‘ø^•U`B „2ᑃlóµrQ¸9æë*ä ¾¯¯ÏöÁ®ÖÖêøÝîé}ÚÉK/½ä7.;Ù{/v®ë „@!$nóî»ïÚ:Е‹Éíì†k <(R Èxös³$ð.Xæ‹Å­¼—Ày&óÉò΀B!„x\?` N®7póñìçæ5 r½ù èòZnl ó,Øí„!„B™T‘âÀƒUy†9ííía‡ ¼õmà]¬$wÁ’gwÈ]°¤äŽXánWK€È5/æSŸäÚ ï]°¼‡< ÄjΞ=ë79½íƒ>ðµÉ]·B½—Ày&óY°&‘ß—ß•Û{‚º•Ï„B!„˜§¼¼Üï@U®[–À[åÊݱ¼)**²t]‚ÈGzÈ;ï¼3vCC€Hä–¶§?EÓ¢ ­=ñáèZ+ó,Øû±ú™B „ÓÈ“ÂÃ]ßáÀÀ<Ü?üÃ?øúÉ·ñr}ÃßýÝßE¼ˆ[ZäßùÎwô°RòTté&ßèÝÐÇ i2? Ý{ •´~xoõk'òl™‡?ùÉOôu&òw ,ä9#2/å–»•••êË/¿ 9ÏþæoþÆ÷{$yFË믿ôâv;Ÿ !„B!„B „B!„B!„B!„B!„@!„B!€B!„B!„B!„B!„B!„B!„B!„B „B!„B!„B!„B!„@ˆ»yýõ×ý~ÎÏÏW¯¾ú*EQEQE¹ZÇ€è,]ºT}öÙgEQEQåj@(Š¢(Š¢(BEQEQ@¡(Š¢(Š¢¨é„„„1˜šš•’’¢«ººÚv·ÇïÓ EQEQ p9{ö¬ÊËËSº t7«ýÝ_¼O€PEQEQ$ €ÈÁwss³ïgy››k¹¿Ûã‹÷銢(Š¢( €DHZZšJLLTóçÏWð럜œ¬FFF|?Ëkéfµ`¢_¼O€PEQEQÄb:::TQQ‘ÚµkWØÁŠÕþVZ\ìŒ/Þ§@(Š¢(Š¢(b#ƒƒƒúbkZ@ìOOo™#OBooo×§oÉ‚"ÿó3?ó3?ó3?ó3?ó3?Gûó”H°k ¤›ÕþV®É°3¾xŸ- EQEQ- aRVV¦:;;õ먒’UQQ1æ.Pýýýaïªà)LÑŽ/Þ¦@(Š¢(Š¢(b#õõõjÑ¢EúÀ=33S_ÿáñxü†‘g_„{F¸þÁ®¡ˆf|ñ6=BQEQE8JRRÒ”ž¡(Š¢(Š¢ EQEQ „¢(Š¢(Š¢ Ô˜ºô駪áìYÕÐРΜQ ~ø´¤[]jøè#= óŠ¢(Š¢(Bu :Œïé‡8{¶Róæ)µhÑÓnË—+µj•&ÞÿŽë\WÝÛºUw‰QoµÑ¨MFm5ªÒ¨²nuåÜ>sŠ¢(Š €PS gΨ<ãßlãß<ãß"ãßRãßrãß*ãß㟠Í4šßkVj¥ü F‚1 ão0ÊøŒI(õ eü Sú³¼ví”jkk3j—QÕFյרFR_|q€ež¢(Š €P€¸SÑ2èLZÎ2Põõçù¶/$ÚÚÚ~­‡a^QE@¨ä7| .\¸à«X¤±ñ˜jnn6ê=£jzߨ£FI÷êúõS€D¿üËRÿfÁY¢‡a^QE@¨dÛš5úóöÖÙ³g]ÈÉ+'Õ'Ÿ|â«þþ‚°ÓÝÝlä`ÅAõÎ;ïøÊ ¦¼õEMÍÓÓvíRmÕÕªM~Þ»Wµ8 ÚR'NBQE@¨xÈšmþÓø¯ÿÊs ÛÖló›Æ¿ýÛ¿9žoC?ÿyØyÖ¾m[Üä¿ÿ;O>|ØWGÕóM·4ÉÿµF½oÔQ£Žu¢Y]ýè* EQ„ €L€ü|èç£s ø|{·í][éïÕïïÿÕ¯~õtÐп¢ÚªÛ¦=@êêöi¬yKZèØvPE@¨iŽŽ7Ô‡~è«ë¿¾×9uêš>ek×®6UmÔ×Ô´©½{ÛÔmêÐ!ùÿ §Ù°lÖÕÕ±í (Š €PÓ Ÿžë7üé_Ž+€üvýzuðàA_mÛÖnpãÿ!@(Š¢(B ÎòYAß´6n¼ê:@ª[«ÕÅ‹}5i®löki:þ< EQ„*¶yçFÕÞÞ®ÊËÛÕÖ­íjÇŽvUUÕ®vïnW55íêÀ€¼vò5¿i44”¹“+OúýŽ\¼@EQ!„Š)@V­ê{0½qc7± ¼¼ÿV‡ò•è¯õðaž2êçF-1*ߨB£Öµ^}ñÅ^¶¯E@(ÏyõÕ~¿áß|óMâ v~¹Suww«’îõF÷jc÷Fµ©{“ÚÚ½UUvWªw¿|€¸PC£Ëf¨ùÖp}EQ!„ dJDànž H¡( €BM1€¬]{×ïPû?Ú@ˆê.) ;Ïúå €ø×µS§ôí›ÛvíRmÕÕª­¦FµíÝ«ÚPm‡©¶={ÆüÎûï7é‡K¾÷^³ª­m6~nVG6«cÇšÕ‰rSBQ!„šZÉËûÜoø­¶@”À#ì‚““3öæ? û+Û¶µû êÚSäìjÛ¥ªÛªUM[ÚÛ¶Wh; µR{ÚöØÈ™3EjÆ ¾j(k»œ ¹ EQ!€S€œ9Ó –, ü-ßðÛȪÿ³J½û:sfm€´•µó²_õUhÔj£þŨ F•÷«{U÷&@vÞ¾9Ô<ËQ9¶r2`Ùü÷_ý;¡( €B2ý’÷yžßß³oßfÛé\Ývžu\@â çÎ]1ÖŸ½ÌÉ)jRgÏ6¨ººõÑGRW£žÆõëèSãš›ß3ªÖ¨÷:jÔ1£N¨ÆÆØ'Q!€K€´ÿó?«ÒÒR_mÞ¼€XÈ‘#Gü*@6n¼­Ž?î«Ê[•qO>ùÄWŸ~úilo^PÒvž­YÓõ4ºG—ÍÐëçj¿á/}zI550jøp´¤›£F2 û1 € @qß-[æ7-+9tès¿§ÁOG€˜ßÛo¼ ŸùýΆ+"D>wo½ÿþû®¤?`ù—ëFœÎ³+çΩncý‘Û1Ë2×mÌ“îU÷¦Mª{ëVÕ]Y©®Ÿ<÷t¨¥á×O†ý@a €Ä EE{ý—ÍŽUÖ_¶ª·ß~ÛWr'¸ÉÀe3ž¢·i †o͵µQäÓKŸª³ gŸž¶ÕpF}Øð¡.éV×P§>jøH}rùBQ„ €2þù<`ùçwÈ$Hqq¯:{ö¬¯Ž~vT-6þ…›oµÍµ¶ÒÛ[¤NŸ>í«ÏŽ~@TÓèm¨›ß3ªÖ¨÷:jÔ1£N4ëÓØ˜O„ €@H\dÙ²ßù½¿M¿Þä:@~÷»¥þ˦±üGÈo>ø:þ¼¯Ø§É¶y(ìÚþ==@ €„žoE{ý§ñÕWÅÓ ‘¶iÛÚ·;@ZÕª>øà_;w€ñÍÎ;õ=σC~NKKS‰‰‰jþüùêÀ~ý“““ÕÈȈïgy-ÝB%ÒðÑöŸèé@ €L6€|°üËñ EÔ©S§|5QËÙ¤ÈÝ»w È2K-ÆN­HŸnxÁJ¨D>Úþ==@ €2õò»€åÇŽÄj–O¹ÔcÓÞ2'??_ŸÛ)§oÉ‚"ÿóóÓŸûû Ô7ß|cì´‹ÿŸÞïý›oJŸ·ÿW¨ßþö½ {·/]ŠK€<|¸Ü@êÊël¤µµÕñüódgÛÈæÍ¶"`9Ã9¶ÒÒò¶-€”——Ûˆ¾=¨Ãåí›·Þ²ÊÊö²®g-€ÔÖîˆ @œ®Ÿ_íß—ñx²m¤qtù· Á±Ó훀¬]Ûe [öo± ÞÞõ¶r¤êˆm€\¾|9fû«W»Œõ§ÇØŽ´«;{ÔþýUMMÚ½»]½÷^:xðá˜ßÏ]nBͳ7[ÞTûöíÓ»”oÚ?ùäÛïÏ @¦ûñÊ•þ—-€È6m"Þï¤H°»\…CH @‚]#!Ýì\“a>Úþ==Z@ìU¤£¼¶¶j¿áåVx²²µöö­Fí0ªÊ(cÃÞ^Ó®þc×ÐB - ´€ÐB È„µ€ìÚÕ¦Ö­ =Ï~alsí¶€|V°~©õ@|”••ùZHÚþ±žÞdH¤õñÿ˜ b„õ»ï¶ù /· »* €@ d|“””4¥§@Æ .ü‹ª¬¬ôU[i €2©rðàA¿ €G9yr¥ßÊýÅë_„Ý|óÏߨ_ÿú×¾’ ; €O1¿7)@™¶¹xñ¢_EÚY¨Ô¼õú¯‡Ý€.Xj°ló•|¸ þ%þ;ëM›6@ €@â ý¯¾pP¸1âÎúµ×üÀÖÝ ›Ï%ýKü†Kßz€@ d|ëßÿýCcýÌÓ7בõthh‰QùFµÆ¨õª©é!€@ €¸p]gƒ±ü«ðëgss-!€@ €B €@ €@ €g©­]§¼õÕèò@ €@ ®doಠ@ €@ €@ €@ €@ €@ €@!€@ €@ €@ €@ €B €@\Hã±cª¹¹Y5¿÷žj®­UÍ￯šUÍÒýÄ Õðᇀ@ €â@úmV¸™Ð¾}; „@ €@ €@ €@ €g¹ml/Ž?î«;~;îùè£ ÕÝÝmT‰QoµÑ¨MFm5ªÒ¨2@ €@ÈTÈgÆÿæi•–Ö;@~ó›7ÃÏcÙ €@ €@ €@ “ µŸ×ª¶¶6µ«m—ªn«V5m5joÛ^u í€:ÔvHúí!@ €@H¬R]]í«wß}wʤ¤»$ì<[Ó¿€@ €+€˜‡_¿~= €@ €@ŒoJHHÓ½¦¦F¥¤¤è’¦<»ýÝ_¼O€@ €L@ ¿.ÔÛeo}üñA¹pá‚ÊÍÍYióòòÔÀÀ€.AŠt³Ú?0ÑŽ/Þ§@ €@& Ë~ç¿Ý¬©) ño¿ýÖXIæ©®®®1‘ƒïææfßÏòZ bµ`¢_¼O€@ €!;wîÔOï”$99YŒŒø~–×ÒÍjÿÀD;¾xŸ €@ $LîÞ½kl@–ù~H°kB-÷L´ã‹÷é@ €2¥"ÄVjÆŒ–Æ'øèìì yÀM ˆõé™BsòóóU{{»>}Kù?Ö?÷;f ‚ƒìl-€”¶•ÚHyyyLâtþݾt).òðár[©+¯³ ÖÖVÇË›';Û@6on´9Ëα––·mD/›6rúôiÇëç7ãÖRYyØ6@Öõ¬³ÚÚ1ˆÓõó«ýûã O¶-€4Ž.ÿV"8vº?pµk»ldËþ-¶ÒÛ»Þ@ŽT± Ë—/;^?‡Š‹mD¶iv’=ºÜXÈõë›b‰8^±ús,Ò]Òm ²M›ˆù€,Ì ‘¾¥šp×@H7«ý­\“ag|ñ>=Z@h¡„Z@h¡„Z@ìÕot«îînUbôËë»}x·Úºµ[UVvëÎuZ@âå¬sçÎéƒáþþ~_·¾¾>Ýíâŋޯê.X2pw‰ ÕßíñÅÛô €@Ht%ó*ܲV[Û @â ³fÍRÃÃÃcºK·ôôtW"‘g_„{F¸þn/Þ¦@ €@È´ˆl‡ˆÕk@Æ;IIISzz€@ €L€¤¥¥égRÈiWrq´Too¯¾°|æÌ™Š@ €ÉM›Î¨ý×õÕêÎÕd"¯ uù§Ÿ~Š €@ȤHà6­è~™Èç€È]™fŸ–œz$%¯[ZZP €@ Ä}€@ €@ €@ €L=€ê's;}: €@ €XJ‘±¡ðbÃé“Ð  €@ ÄRäÁxúµ·ÅãÑ£GjõêÕêŒlh €@ Ä-€˜Ÿúm~-Ïá9 €@ €×200 _Ë-xëëëõë7np  €@ Ä]€œ?~ô N© ø]’‘‘ €@ îÄœ'Ož¨ÌÌLÝò‘žž®†‡‡‘ €@ d|B €@ €@ €2urêÔ)5kÖ,¿‹Î³²²Ô×_ €@ î^„ìÉçMMMÆN €@ €¸¹è|÷îÝú¹f€ ªÔÔT$@ €@q ft>÷ƒç€@ €@\Hbb¢züøñpô÷÷«ääd$@ €@q r±yޱ‘íëëÓ‘gܹsGÃd‘|r€@ €â@îß¿ï÷ôss @ €S€´üúת»»[oÛºu¯Û8¦è6öÇÝ[·ªîÊJu¯ª €LöÛð B¤%$))I·à €@ öòòðÇƾ€ð B@ €@‰ît@ €@‰@ä”+@ €@& @þ¯ñ¿¬ÿÞÚ»w/™L™m|JòÐA@ €@&@·i[·n “ jñâÅQÝñª©©ÉØèèÖyzºxöööúú»ÃV`jjjTJJŠ®êêêˆÓŒ4|´ý'zz€@ €LI€„º¯”ÕëC Õ7ô3DFFFÔÑ£GÛ¿i„‹¬ÔyyyAR‚éætøhûOôô €@™Ò¡‡*y¡×–Dˆœ777û~–×¹¹¹Ž‡¶ÿDO€@ €nÃk1ÒrüøqcƒSì´´4 šùóçëÒœäädý{æqH·P‰4|´ý'zz€@ €§s¥§§«ÎÎΠÃttt @‘ÚåÝð‡h! ×úiøhûOôô €@™²VQ]Ø";ÑeÆ‚*r×-¹›àðð–9ùùùª½½]Ÿ¾% ŠüëŸ{³ÁAv¶Ç@JÛJm¤\o Æ NçßíK—â .·ºò:Ûimmu¼¼y²³mdóæF[‘°œá[iiyÛ@ô²i §OŸv¼~~£1n}g]YyØ6@Öõ¬³ÚÚ1ˆÓõó«ýûã O¶-€4Ž.ÿV"8vº?pµk»ldËþ-¶ÒÛ»Þ@ŽT± Ë—/;^?‡¼g…XˆlÓì${t¹± ë×7Å N×ÏžÊJ[Û´íÛ·Ç%@ºKºmD¶iq¼s€deeùík@Âýn @‚]#!Ýì\“a>Úþ==Z@h¡„Z@h¡„Z@h™Ò¡_¼x1ªqTTT¨®®..ä6³æì²²2ß)YDð222 €@ d|B €@ QÄÊC½Ï!€@ €¨øÐÁPá!€@ €WOÁ:wîœq@“gì<û}Ýúúút·‹/"@ €@ˆ{‘é.ÝÒÓÓ‘ €@ Ä=€È©V¡Â5 €@ €W’––¦Ÿó!§]ŒŒè’.3>Ø™3g"@ €@ˆ»×€„ºýÓO?E€@ €÷"inn6>¬Ù*))I—¼niiA€@ €÷B €@ €@ €2µ"w»ÊÈÈàIè€@ €ñHVV–8ÌeõIèMMMÆF·@_?’ššª<åNZæÔÔÔ¨””]ÕÕÕcÆ©¿Ýá'ûô €@™’hDûÄóÂÂBuãÆ õäÉ}ߣG;¶%¾þ²ÒÊ“Õt V¤›Õþ‰v|ñ>=@ €@¦,@¬¶rØ´†x#ßr§-oäµ<{ÄjÿÀD;¾xŸ €@ S rË]ùVÞ­H ÈñãÇ N±¯[rr²înFºYí˜hÇïÓ €@ dÊDNZ°`±óìÞkIÒÓÓUgg§_÷p-/‘ú›N4ã‹çé™BsòóóU{{»n=‘EþõϽǎÙˆà ;Ûc ¥m¥¶R®7Pã§óïö¥Kq ‡—ÛH]ym€´¶¶:^Þ<ÙÙ¶²ys£-€ÈXÎpŽ-€´´¼m zÙ´ Ó§O;^?¿Ñ·¾³®¬]Á‹Ü9K åo‚µ®¦¦¦F¥¤¤èª®®Ž8ÍHÃGÛ¢§@ €@ ‘ââbÕØØ¨oåëñxTUU•‰ á"+µÚþ==@ €@¦,@äÀÖ|ÝÇÊ•+uwiŽ‘'¤[ÉÉ“'{¶~žH°”••©ÎΧ;•¨cGYQQ1æ.QrëÞ`w‰ <…)ÒðÑöõô €@™V·áÍÌÌÔ§[ "¼™;wnÈë8‚ÆîYÒ:²ÈX ¤›LK®ÿð^wâ<#Ôs2‚]CnøhûÇzz€@ €ð8Š<àp*O€@ €)Y³f x©åV@ €@q yþ‡Ü‰IN7’»_É­s›ššÔãÇ9ú €@ €ŒÏ)XrQøž={ôµÞk7äZššÕÛÛ‹ €@ ãs ˆ´~ܺuK-X°À÷Lyann." €@ €ŒïEèr}ˆàÉÒ  €@ äÕ €@ “ ÃÃú…#Øs<äÙ €@ €â@²²²üÀa.¹„@ €@\ˆ@ãâÅ‹ñ@ €@Æ ´r@ €@byæÇÀÀGü€@ €ñÈ7ôs?úûû9ê €@ €Œ/@‚ÝýŠ»`@ €@Æí"ôPÅõ!€@ €WB €@ €@ €25rëÖ-5gÎ}Ê•”¼–n€@ €â*@C^„B €@ ®DZ; U__Ÿ¯›¼^n|ZòŒ@ €@q rÊÕððð˜îOž}ÚñúùƸõueåaÛY׳Î@jkwÄ N×ϯöïK€x<Ù¶Ò8ºü[ˆàØéþÀ @Ö®í²-û·ØHoïz[9RuÄ6@._¾ìxý*.¶Ù¦ÙHöèrc ׯoŠ @œ®Ÿ=••¶¶iÛ·oK€t—tÛˆlÓ&âx/nòèÑ#Û¹yó¦ñÏSwïÞuµZ@h¡„Z@h¡„Z@h™ä- áî~å­HÉæÔ××ëÞ¹sÇÒ5ÒÍj·ÇïÓ €@ dÊÄ{§+ïívKn{üøqKã:yò¤ñaÏV÷ïß{)¹5o¸»D…êx S´ã‹·é@ €2m®±z«]'­)æÈ³/Â=#\ÿ`×PD3¾x› €@ Ü+Ž"8œÊÓ €@ dÚDîê Š‘»+W®(@ €@q ³fÍÒw¼ v¬ŒŒ $@ €@q Á®w0_¨N €@ ®D.ŠîëëÓ½··W¥¦¦"@ €@ˆ{‘[iéèèèÐÈ“’ÛéJËHnn. €@ €¸¹Ö#Ômt‘ €@ Ä=€xO·ÊÊÊÒ·Ÿ•š;w®~h €@ €¸@ €@ €@ €©ÂÂB•œœ<ænà @ €@q EƆ‹@€$&&"@ €@ˆ{‘ç€466ê×Þ¹3ÖêÕ«ÕÙÐ@ €@ˆ[1? ÝüZž2sæL$@ €@q úµÜ‚·¾¾^¿¾qã×€@ €@ÜÈùóçGâ”Z°`ß5 H€@ €â@Ìyòä‰ÊÌÌÔ-éééjxx @ €@Æ €@ €@ €@ S ===*++Ëw –œz%×Ì™3@ €@ÜÈctïÞ=ýZ.óEèËå#€@ €·’œœ¬<~-w½x´¶¶ª»wïªÔÔT$@ €@q æ‡&&&ꟽw¿â9 €@ €W’’’¢[<:::4>ÒÒÒtwi‘~€@ €â@äÀÖ|ÝÇÊ•+u÷öövcÛ›ƒ €@ îDâ}øàìÙ³}ÝæÎ«ïE €@ ®„@ €@& @̧pEêj¸šš}͉TuuuÄiF>Úþ==@ €@¦$@äŽWÞÛï–Ý»`…H¸ÈJ——§t+ªts:|´ý'zz€@ €LY€ÈSÐÍà0—Ü–7‘ƒóææfßÏò:77×ñðÑöŸèé@ €2e"иxñ¢k§b…ê.·÷ÐÌŸ?_/æÈÃGFF|?Ëké*‘†¶ÿDO€@ €) »­NbŽ\n uåu¶ÒÚÚêxyódgÛÈæÍ¶"`9Ã9¶ÒÒò¶-€èeÓ&@NŸ>íxýüFcÜúκ²ò°m€¬ëYg µµ;b§ëçWû÷Ç%@<žl[i]þ­Dpìtà k×vÙÈ–ý[l¤·w½-€©:b —/_v¼~ÛˆlÓì${t¹± ë×7Å N×ÏžÊJ[Û´íÛ·Ç%@ºKºmD¶iq¼G - ´€ÐB - ´€ÐB - ´€ÐB ˆÛ×€H7«ýÝ_¼O€@ €âÂ]°úûûÃÞ%*TÿÀñF;¾x› €@ Ä&<+0òì‹pÏÁ×ßíñÅÛô €@ q”¤¤¤)==@ €@ €@ €@ €@!€@ €@ €@ €@ €B €@ €@ €@ €@ „@ €@ €@ €@ €@ €@ €@ €@!€@ €B €@ €@ €@ €@ „@ €@ €@ €@ €@ €@ €@ €@!€@ €@ €@ €@ €B €@ S c*0555*%%EWuuuÄqF>Úþ==@ €@H Y©óòòÔÀÀ€®cE•nN‡¶ÿDO€@ €2Ž‘ƒóææfßÏò:77×ñðÑöŸèé@ €@¢HZZšJLLTóçÏ× ¤9ÉÉÉjddÄ÷³¼–n¡iøhûOôô €@ .¥££ÃXŠÔ.ï†?D ‰`ÅN‹ŠyøhûOäôÌ ¡9ùùùª½½]·žÈ‚"ÿÇúçÞcÇlDpí±Ò¶R[)רñˆÓùwûÒ¥¸ÈÇËm¤®¼Î6@Z[[/ožìl[Ù¼¹Ñ@ä,g8Ç@ZZÞ¶½lÚÈéÓ§¯ŸßhŒ[ßYWV¶ u=ël¤¶vGLâtýüjÿþ¸ˆÇ“m £Ë¿U€ŽîœdíÚ.[Ù²‹m€ôö®·#UGläòåËŽ×Ï¡âb[‘mš]€d.7Vrýú¦˜ÄéúÙSYik›¶}ûö¸HwI·-€È6m"Ž÷¦Å]°õÅØ´€ÐB - ´€ÐB - ´€ÐB - 1H°k$¤›k2ÌÃGÛ¢§@ €@‰"eeeª³óéNåÁƒªÄØQVTTŒ¹KTлDžÂiøhûÇzz€@ €S__o,‹ô}ff¦¾þÃãñø #ÏÆõœŒ`×P„>Úþ±ž €@ $Ž’””4¥§@ €@!€@ €@ €@ €@ €B €@ „@ €@ €@ €@ €@ €@ €@ €@!€@ €@ €@ €@ €B €@ €@ €@ €@ „@ €@ €@ €@ €@ €@ €@ €@!€@ €B €@ €@ €@ €@ „@ €@ €@ €LƒÔÔÔ¨””]ÕÕÕ€@ €2>‘V^^žÐU`lˆ¤ €@ „¸ÁGss³ïgy›› @ €@!î'99YŒŒø~–×Ò €@ €B\OBB˜n‰‰‰!áá-sV®\©KZN~alyäÿXÿ\´`Zc,¯zþyµæ¥—T±Q+Œ×+^|Q­0þÆÜï}OýèG?Ò×¹Èÿ?þñÕŒÆ*l¬õ/¼°Æ˜%êÙgWªçŸ_¡^|q…ñó £ÿ\ßðiii*mYÚÓá×¼ JÔ E/¨çW<¯^\ñ¢JX‘ žÏ}Þox™ÆªUÏë÷URò¢ñ¿ñžV|×(ã}¿³Âø¬¬ø†—ÿ—¦.}:ü‹%Æß±Fýò{¿4þŽÆßa”ñžrŸÏõ~æÌ™Žç_¾ñzÕ~0:½Õj™Wßý®ß|›™”ä7½””=ü‹Æû{ÉxÏ?ÿšß<{饟û ?ëÿ›¥’Ö$©¿ÿ%ãï©ø%¿yöÜŠçÔüCÓøSÔ/ùCc~¿1ŸW­zA>ï7Ï-zÉoøŸýøgª$ÅÞøW½`|¦ß_å7ÏV<·B¥§¤û}þùùùŽ—·U3f<}/ïϨ•Ï=ç7Ï~f”ùýÍšõ =¼,g/ïïÅ‹ýæÙ÷¾—ë7ü?ýÓ?©Ä5‰z>?o,?2ßž[ùœß|{ù§/ûý=Ë–e>]þõòf,ÿÅ/ùͳÜ\ÿåÖ¬YOç—±<Ëÿ%Æò¿âÙ~ómnÀò¿Ð8°sº~®úÉOüÖÏ_óÍ<Ï–ÿ›ß_FÆOÕË/¯ñ­Ÿ²¬=k¼?ó|KL|Åý\é¿~~¯ð{~óì%c¹1?wîOŒágèå¬Ä~õêïûÍ3y=s¦ÿò_0ºü{×Ï׌åß<Ï~°ügff:^?Wüô§£ŸñþŒy¸M[a,wæ¿'55Õ˜/E~ëgà6íûߟï÷þÒ¥=~tý ܦ=»âY¿áe2ÏÌëçÊ•ÏúÍ·¹sgø-Ï¿]þ½ëgÑ‹EþÛ´€å_¶iN÷¯þïÿ­ÖóƼ~®xöY¿ùöб3OïG?Zî·~~ÏØæšçÙ /,ñ_ŸmÚË%/ûÖÏW¿¨ç“y¾%ÍNò[ž gú­Ÿ¿üå ~ólÉÿåÿeþ/µæåÿý”e-pýüñì÷ù˼pº~®NKó[?_“ùešg ~ð¿÷—ž.óD¶ÿ«ôrö}c›kžgÏÛ\óðòþfËyý|î5ÿmZÂÏü†ÏÉùñÓ¿tý,.~1`ý»ü.ÿÞõs¥±ü›çÙü€åîܹŽ×Ï×^yÅoý³M3~6¿¿ŸÛ@Y¾Ìëçw¿ë¿M{ùåL¿÷÷üú­ŸÛ´~ñ‚ßð¯¼òOÆð ~ëçŠþëç+¯ø/ÿ+RWø­ŸÇK–ÿWŒ¿{"Ž÷- „B!„ÄmÈ$H°k@¤!„B!„¸ï]°úûû-ß‹B!„BGžýaç9 ¼ØŒ¢(Š¢(Š¢Ü*Bˆ ^„yÆ|cž1Ϙo„yÆ<£„6Ì3æóŒ™ÀÝ@ˆÈyÓ .ÔçµkË™Tzzºêììd†DÈÝ»wÕ²eËXO¦££C©]»v13"¬—åååjxxXŸVºyófUZZÊŒ±˜¥K—êÓØHäÍœ9“g§˜,k™™™úúó·û$xäTY7åÔ«õë×sº…HË‘Ü^œX|9à}Ž–”¼æz@B!„B „B!„B!„B!„B!„@!„B!€B!„B!„B!€B!„B!„B!„B!„B „B!„B!„B!„BȤLBB‚.Þ'!„B!dÜà!„B!€B „B&7>Ìد¾¾^-[¶L%%%©äädµråJÕÕÕ5f¸Ë—/ëádóxnݺ¥–/_®»'&&ªÅ‹«‹/Žy/'NœÐ¿7cÆ •––¦***Ô£Gü†ùøãUVV–~/óçÏWuuucÞ÷ƒÔÆUjjªžžŒkÆ ª¥¥…œ@!„xAH¨î‚Н¿þZŒŒø““3f¸‚‚=œ97oÞÔ ´ôõõ©'Ož¨Í›7ëáæ>|ØÁŒ #ÃzÓÐР»i˜HÉëÀ÷/ïM~njjÒ??~üXƒGÞ!„B!$ÎÒÞÞîë&ñ¶R×ÙÙ9frÐ/ýÌ-&ÃÃúۼyó"¾/iÅð&//oÌû¹wïÞ˜÷/ïMêîÝ»|¸„B!„L6€Dêî 9*Øi^ˆ ¬^½ZƒCº;%LN»²ò~¼- Rò;rÊWUU•êííåÃ&„B!d*Ä‹i9 /̧e9ˆ\RVV¦ÒÓÓý #!„B!„La€ÈÅçÒïÚµka߃·¥Ä9+p¼VOÁ2G®9¹zõªî/Ó „B!„LpfÍš¥Ðå"q·rûöm}÷« ¨ŽŽÝM.?þ¼…7Ò:!ã,È5"kÖ¬3^óE胃ƒºŠ‹‹Ç WXX¨®\¹¢Ç#‘»pIÿ¥K—òaB!„2ёӞäVµVaa ¹üõ×_××wÈp¹M®ù¶¸‚9 K®ÿ˜3gŽ:uêTÐñÊmxçΫ[35òsàp2ÞÒÒRý7yoé+§dq !€B!„B!„B!„B!„B „B!„B!„B „B!„@!„B!„B!„B!„B!$>òÌ3ÏPEQEQEkù„B!„BÆ­å€B!„B!„B!€B!„B!„B!„L?€ôõõ©õë׫””•˜˜¨òòòÔÕ«W-ÿ~BB‚¥a¤düiiiª´´TݹsgÜf’wz¡Þ[OO*..VÉÉɺäuWWWÈñ555©åË—«¤¤$•ššªÞzë-Õßßï׿  À×ãÆª··7fã‹ô÷Fê,×®]S‹-Òïaîܹª®®.èøÇª_¨iGš’šš½|JUWWÛþÛÂý¾[a=š˜õ(Üðn¯GN–%Ö#֣ɾY]ƒEÆ8|°ñÉçÀzDÈdÈìÙá+Hd/+ÄãÇÕÈȈº}û¶Z³fë|od:§NRéééãºÑ÷ÞdCvðàAõäÉ]P‹/9Ù!466êùãñxTUU•ÞHySXX¨nܸ¡Ç%Ã=zT-Y²$fã³úYXÝq´¶¶ªÌÌLÕÜܬ–ÑŽ;lÇÊp‘æÅÙ³gõ2:00 KvhÒÍê´¬þ~”«ëѬG‘†w{=²»,Mûõ(Â?֣ɱÙ‡9.\P¹¹¹ÿÊ•+aħûzDÈ”ˆ| .þ|Ôãq²ã œ²±öîx$òZvjV§eõ÷£ëÑįGV†f=²»,MûõÈ@Xâo=r²üɼš7ožnɉôû999ºå‹õˆiYøwíÚ¥¾þúë ý.\¨ZZZôŠ(ßÈF·¬¬Ìñ7NæoždÃíÍÞ½{õ7]ò­€L§¼¼Üï[Ž={öèôÖïÃéG6hò-“üMRûöíÓݬFšƒÍߊn°Ž?®¿I±:ÜŸ[‘ÏEæñDlðç…hÈ<0ÏéfuZV?Z€°Mìzlx·×#»ËÒ´_„õ(þÖ#ï)Rr >þ|ý^#ý];wîÔã‰4=yï왎‘od‘‘áû¦'Üù¢²Â˜7ÔN7øßvÍ6ÞŸy§#;óy¡Ò+çÊÚI¨éÊ·hYYY¾oÊäu¸o`̹wïžÞ {/ÞñIs~gg§¥yäæøÜˆ•ñX9§Öî?ؼ6Ž`ßöÙ™'‘¾-tÖ£‰[B ïözdwYšöë‘€°Åïz$éèèÐð$†ßÝ»wÕ²eË,}&K—.U÷ïßgDÈtˆ9Òl*çßš7òm“4ŠÒ½+¶¹ÉØé_¦¸ãŽ·œLÇêF`åÊ•ú[ó9·¡¾A2çæÍ›ºYY6°ávˆ‡ö›‡±ßdn 5/&K ëÑÄ­GV†wc=š - qµ9ëQ|¯G’ÁÁA}u¨ÈïZœ~d¥¥gº¯G„L €„ú&HîB"F‰üo^¹œnðåœ[óÆG¦x· sÜüÆ)Ø7‘¾…¨¯¯WsæÌ±|¡b¬Çç&@ä\èXžsn^;gVºY–Õ߇Ոõ(F˽á£Yì.KÓ~=Š ¬Gñ¹EˆÕ 9ÝN.0g”Ç‘-™ž‘•Û|N­œj¾‡\„'w…ÈyÆ ~+—lˆ"5[¹ëÈ¡C‡ÔêÕ«us´D¾A1ŸÛë=çVÞC´çÜÊß'§ùœÛpw9yò¤Þ!…j*–S¼·M”³\¼hÞ¨¾·Çç6@d§ §@ܺuKÿ<žw‰4/¼w ‘Ï=š»ŽDúýhÂzûõ(Òðn¯Gv—¥i¿9ëQü­Gòw{[4d~Ègd¾nÃÉ~GÖ «_O÷õˆ) ¹ÈJVi^–¦@¹ðÎ|î«ô—ûnKùV@VPóÊ%·ìó6Q[ùFDv r^o°fcÙèËù¯2-¹5áÅ‹ýúËy§²ƒ‰tבHß¾ÈÆÔ{¯o)yêœW+ßèÈ7&ò~½_à½Ã­ÜÝíñÙéj¹÷ Ÿ…|þü±ío¸ìÜ“?ܸd‡hå¾ë¡ÞG¸ßw ¬G±_" ïözädYšÖë‘€°Å÷z$-?òwË-j£ˆxË­­f:¯G„L€B!„B!„B!„B!„B „B!„B!„B „B!„@!„B!„B!„B!„B!€B!„B!„B!„L.€ôõõ©õë׫””•˜˜¨òòòÔÕ«W-ÿ~BB‚¥a¤düiiiª´´TݹsgÜf’wz¡Þ[OO*..VÉÉɺäuWWWÈñ555©åË—«¤¤$•ššªÞzë-Õßßï׿  À×ãÆª··7ìøÂ o~ÿÞ’ùæt|=Òó\úÏœ9SíÛ·/â<¼víšZ´h‘þ¹s窺ºº°ïÏ;¯Cõ õYDš·’šš½|JUWWÛú¬#ý¾ÛË›•¿Ù­éÅj}ŠôÙý{# ïöòoŽ é}ºýþXŸ!„Lq€ÌŽPc#àÊãÇÕÈȈº}û¶Z³fëñF¦sêÔ)•žž>®MáÞ›B ‘oQÃåÁƒjݺuº¥@†-**ò}£fõÛÞ`ýΜ9£JJJüºÉN\¾¡—oïä[Ýo¿ýÖ¯ÿîÝ»õ7òÍÞ‰'ï°g̘1¦›LÓjdçi¾Ù_¤ásrrtK•ÓñÉk9ñF^;€ôF>ïóçÏG}`æä`f"˜ç­¼Où›Ì_°÷jZV"iÙ—õ)Òò?qcù—ìܹSwöûáNµròþXŸ!„GNÒš!;ÐŒŒ ß7¥á®_Žù@Ç)@$æoæfÏží‡ 9 2ŸW-§0ȵnàH«NVV–¯åF^[ý†õÞ½{eÁÞ‹w|r:Lgg§¥œ`Û³téRuÿþ}ËLÁÆ·aÃ}Ú• Ä{ V¸;çȇk³{ÀlÞ‡oß­þþD$Ò²/ë“•åßm€¸±üß½{W-[¶,äïG`ïõ‰B±z䤞ž¦ ׃˜wÖÒú!Íîò-—wÇh>…É)@dZyËÉt¬îDW®\©[@Ì×€„;%É››7oêÓ8ä€&Ð>ì7Ã%Üðrzƒ–™Pã“‹ÐåF2_š'Ož {€;ߨ†š·Ó¡$Ò²/ëS¤åßm€¸µüËk+_Œ×û›öë!„b%ߤÊ]±ä@]"ÿ<9ÙqÊ9ëæ·L'ðn-æ¸Ùì»HßâÕ×׫9sæX¾Ð×î·‚Á†—ÓãäV' 7ýsçÎé ÓCE®%ˆå9ëáæm°sÎ¥›ÕiYýýñˆø›Ú - á–ýxXŸ¬,ÿnÄ­åßéÊÜzÓ~}"„@‚íÍ×xÈõæ;BÉE¬rW‰ÐÈé<æ“ÜŠ1ÒéKVîÚsèÐ!µzõj}z”D¾±4_kâ=g]ÞC´×€Èß'§ùpwÁ’9  uª…œÂæ½ïàà ¾ø×¼S|‘†—ܺu+äÅvÇ·mÛ6=ßäo•sÂå›ÑP§|Iä JZJä=HÆó®=‘æ­÷®;òþ£¹kO¤ßO€ÈEÊrýÌyrš£y¸HËþD¯O‘>£ñˆ›Ë¤ßwr V¸÷ÇúD!€D8r’RÙ¡È·´Ò”.®šÏ—þrßzé/ߪÉμs’[^zOñ·ãô–€FÀ‚Æ!Mr=†LKn•{ñâE¿þr±¼€'Ò]{"}Û)cÞ{åKÉëp䑾A•oåýzÿ¾`ÏI0'Òðٱ˭E­ˆDŸ´xx¯ñ‘ÓÏäÜðHñ>·@> ùü?þøcËóÃΓ•qÉ¥•ç„zá~?‘e]€ë]‡ ÃEZöãm} lµÓº`ex7—»‰öý±>B™f!„B!„B!„B „B!„@!„B!„B!„@!„B!$¡(Š¢(Š¢(ŠÏò„B!„Bb‘ÿΜ$Ï?}ÅIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_get_line_narrow.png000066400000000000000000000635401174000617100245630ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔg'IDATxÚìiLTi›þßd2™L&ÿLæËd2&“7™LæÃd2™/“ÉdÒéht4FG#‚²Ù¸à¦"6Šm»5¨-Ýn".»b»4¶¶¶¨¸ƒ(âÒ ¸ˆŠ ( ‚Üÿs?ÝÅ[PTQÅï"W¨³Ô9uÕ©ªs=÷s?÷ó^Åx 0X, À`0ñÇ?þQþð‡?´òŸþéŸüïÇÊNŸ²§Q[[+_ýµüïÿþ¯ü¿ÿ÷ÿäÏÿüÏ õñÿ÷Kxx¸ìÙ³‡ƒ€?âòåËí̇òêÕ«>cVú›Á:|ø°üÍßüM‡ïkO½ŽþxM,ü111Þø£¢¢0XÝ@VVV›óüÝßýlÙ²EêëëÍöÆÆFcj5ºõŸÿùŸ, ÃÇåoÿöo[oÊý×ÝÆp3w/^¼0]€¶÷å¯þꯤ¸¸Ø¯ $ƒè'OžlsSž6mZ›å'N8½‰»ÒíUTT$“&M’üÇ”¿ø‹¿0yHÿðÿ`Öºl–.]jLŸC#?úÚæX¶<§û·“;v¸m@ÊËËeÁ‚ò_ÿõ_ò—ù—æXj8Ç/çÏŸwéý\¼xq›s,\¸°[×EM™Fÿå_þ¥õµ¨öàààv]·Ý¹&  ÚzÖ›øû÷ïÍÛ:MÄöäf¾qãFù³?û3§û®_¿¾K3¤ª£çj’¸޶íÚµËeƒ¥9SmòÔ hòºýsòóóݾ&ªIM¤³×¢Fƒ àƒhjj2ÑÛ xøðáfý!CZ×évÝÏÝhB#-öûhdH»ÐªªªÚ‘®¢2:OÍŸšÎ¶©¡²_ÿÿñ.½f°Ù›J5Zš3¥ºµ U_Û˜1c\zOíßO¥>ß\¿~½Íó $•••æµL™2¥Í65…î^ ÐÃp4+©©©f½&_ۯ߷o_· ÖØ±cÛìsúôéÖmgΜi³M÷uv|M Wh‚¸ã¶‹/šmjfì׫Ùqå5k·›ýúo¿ý¶Û墳Qëè}é*ºØf}iiië6GíŸ|ò  À×0räÈ67äÛ·o›õúß~½î׃eŸìíÍшŒý6Ý×ÙñíŸël›3ƒÓÙk¶OìWjýªî¢«VWËñµ8£«€ÁôÔDØçFiÒ¹=ìóšÔ´TWW»}3w'š£ûºz|ooëêuºƒÿùŸÿis,w’ø;z-îäUa°À`ú›7ovëF®ÉêîÞÌE°»»ºŠ`õä6oF°GÚ'£»òZß3}Ÿ\þ1Æ`€Áô-4ǃÕ|oæ`õä6oæ`i¿}w}¬e$\5CŽïYGå&0X`°>½á;ÞŒµ”==zätÇÒM«ã8ŠPkWé(B¥Ž(tVΠ7 –æœÙwÍin“m¡M‡ÖÂrÙÙÙmΣݯ?üðCkOG-vöZß3}ŸÕŒ*ôùú\-kÑQxW® ƒè!¬\¹²ÍXó†:‚c)]hCBB‚KyAjTºªƒõÝwß¹é‰mZòÀ±{ΓˆFëþþïÿ¾[¹T®¼g½W¯ ƒèh¥sgùU6¨ñ±ßïßÿýß[·i4Eó‹þõ_ÿµË$qi §?þñf_¥Vu×u‘éð‡¥— –B#{ö•Üm]|½²•‚pZ›KßÃÿû¿ÿ3y^ª[“ÖÙÒ÷RK2¬]»VîÝ»×é{öÏÿüÏ­ÏS¨5Ê-ZÔaò¼;×€ÁÀ`  ƒ0X, À``°0X,Þ  ô>-ZÔf9&&F¦M›æUöÄ1}™M/×ÍèE3zÿDÇû* ƒe0}út9sæŒWùèÑ#¯Ó—9ÐôrÑŒ^4£÷OÄ`^3X7nÜP_Ú¦—kŒfô¢½,Ð B!(Ä`"X´ÑŒ^4£—kŒÁùä“OÚÑ2tèPÃôôt··{ûx¾~>r°Èc@3zÑŒ^®1Ëéöììl‰ŽŽ–ÚÚZÃØØX³ÎÕíÞ>ž¯Ÿ­@4£Íèåc°º4Xj.ô ³AGEE¹¼ÝÛÇóõó‘ƒ!„b°ŒÁ>|¸ 4HBBB$33³Íö!C†HKKKë²>Öu®nw„§ÇóõóÁ¢ˆfô¢½\c V”••IBB‚¤¥¥9p©su»+3wŽçËçӀޅFµ_ÚöÁÓÿž.¿~ýÚ«Çóõå¦W—+++ÑëçËŽÿÑëËú¹F¯çË~1а¾¾Þ$sÁ"‚E+ÍèE3zÑL«‡ VG9HºÎÕí®äD¹s<_?9XB!K’““¥¼¼Ü<~ùò¥$%%Ijjj»Qt555NGÙu¶Ý±‹ÍÓãùÚùˆ`Ñ D3zÑŒ^4Áj‡ÜÜ\‰ˆˆ0Æd̘1&ÿª±±±Í>ZûÉY(gÛ;Êaòäx¾v>ê`QKÍèE3zÑL¬^ÇàÁƒýú|D°zŽ2vl§?TEE—iù¢½hF/ ƒÕ«# ƒUX¸C…Z&kÛ€¹ÞçÏŸàs!Ä`"X¬ž3W?†ZÜ"ÍÍ!Âd DCItÍèÅ`4X¡_ß™Áúº@ÞG,•7ÓWIMìy‘¸QÊ—l‘ÒÕßËôÝR°{¯\9tH.üô“œ=}ºß™«––<#µ¹ùºß›,ÕÜÔléÌ0Ú’É"?ÍèÅ`"X½›´í”SƒµéL”ì=4KŽo—‹kæIѲDy8/Q*£?—ÚIså}Hœ4Ÿ.Ç…[ûJË8ë>~²eÌ¢å]D¼¼™±Pªg-•çóWHÙ²T)ùf­ÜÝ´É:ï6¹¾g\=xP.fg˹_~‘³gOKnîI¹pá'¹téG¹råäåk×öZ×a—ܼ™)·nm•;wÒå×_ÓäþýuRRò­„Jcc¸µïDyÿ>BÞ½›l=wª¼};ͧ¶v¦¼~e;Fª«ãäÕ«ÙÖ¹âåå˹Öy?·Îo½G• äÙ³…ÖëY$OŸ.¶^Û)+[f½Î¯äñãë5¯”‡WIiéjKGªkiZ+÷î­·ô}'w玲·oo¶to1†èæÍïQºqc§\¿nÜ‚½Öû³_òó³äêÕƒæ=»|ù°õþ•‹³Í{©]‚EE[¹z÷.÷÷‹{s@™,¢hF/ ƒÕ+ü5í”4†­’æÀ0§kï²ÃºñgXæ;Ë$|ó|¾$¿š#‹-ÃòùÛH‰³ÌÇ´ÆP o/-2©>P*ƒeå½I/“¬3árêÇp¹º/\no •GëCåùÊ`y½x¼¼ûÄÈÇ)"ãÇþÆÉÒb­kI ”KÇKÓê`iü.LÞo›(õû&Ë›#ÓäõÉy•;[^ä}.E_HÙýe¿5)jP6Xæd“eLÔ”l·~ˆvXFd·eBö[&äË€qªY ‰5(jôt5.j`ÔðéqÔØ\¿¾Ç?5Œ“ãÛ"eÖë0§Ñ½Qëû·¨M´¹¹kTèÅ‹y–˜o¢E™ÑèÑ£G+äW‹×­”s–q8þ8Y²ž,“ÖöôŠ/å›g $Å2 ‹^ÆËçU³dVu´L«*ŸÕ&AÍAú>Hf•M”e…Ó仜XÙ›• '6/‹_'Iá²…R<<™3O^DÇËë©1R1]C>“A¤eÜ8KW¨¼›4YêfÌ”êÙ–KL”§Ögäqr²”®^-÷6lÛR¸cÇ€Ë;sìÕ–H¸u¿µLÞWÖÿD˨Ͱ Yˆ4[×âíÛ©ÖužkLŸC5yyåܹ“´öÑ‹f"X, ýúʳ¿œµLÆIi¿TB&ÊÁ½“dfõdÙdÝ8¯Y†h¬“¿c{/¢ñ˹_$ûb¶¼zPvì–íEÛeÓÝM²öÞZI½—*)÷SdiÉRYøh¡Ä—ÇKÌ‹™üz²7Ë„].‹-s¶>'Nvš+G¿Ÿ'9i‰’÷u¢ÜZ:OJ“æÊÓøYò2&Ú©Áº¿~½ÜعS.egû¥ÉÙfÌUIÉÞ÷ËÍýÙt9j4N#nÚíúêÕÓ½úñc46†Zf;ÊtÃj׬Fé´ËR»%ÏœÉ!?½h& `°ü»U”ûs®T|i« …R>Qv —˜W3dσUò¬r¾ÉÉÑ(”æò8Þ|ËË÷+­§Ïž–Ÿ.ü$‡®’}ùûd÷ÕÝòý•ïeë•­’v5MÖ\[#« WÉÒ;KeAñ§«hùL©˜=YÞM –¦ AR;#ÒDíX!w6n”kûöYïíÏýzagæªk昮SíÕ.ЇWš®ÌׯcL¾ÚÇòîÝ$©®ž-_šîPí2Õ<±óçÝ@/š‰` Vÿå…c,CpÂ2Všˆ>Q6ÿ"s_ÆÊÏO›(„vùiBµc=$ÛÍ·¿™+oœÜñÓIËI“¯®}%‰%q²èvˆ¬?$ÙÛÃäFòD©ˆ ‘,#>AžÏŽ”ÇK¥ø›ÕR´u«\ýáŸMÙ“u°ÎûÅä«iNšBxòd™l ]Ìš ¦ÔÇ/_Î3Û47M÷½zõy.µ¿ $ Áò9^>tI^Í>&MA³äÕ´Ïdݹ ²èUœ\«šÓ&ZÕÑs·m+’èèz n±þ7ÉÎ¥¾­:}VNœ8/?þxI¼*{÷^“; eëÖ[²iÓ]Y·î¾¤¦–JJÊ#Yº´L¾ø¢B_Èœ9UóÚúœ¼qšw¶zõÙ¼ù¶ìß] ¹{®Ëmëñ½oîIáêB¹´æ’œH?!ßg/ß].›NÇÈŽ#a’½5@n, ”3ƒ¬÷?@ª§Ëä©rëëx¹¶9Y®ìÝâ3]Ž}ù™V££Ñ¬Û·3LtëéÓE&Ú¥Q/~iL£aÓA%ÓϬFͺÛý8kÁB/ ƒå^ÛŸ'µ3”¦ñQò,f¢¬¾2^¾®‰–GÖM«³h•£¹š<ùƒuj1ïãýûú^Šde=õNnÕ/çä§Ÿ.È‘#—åÀ<Ùc™–ÌÌ›’‘q[ÒÒ~•5kŠåë¯HròcY¼¸\’’žIB ™=»Ú2{µùV""ÞKHÈ ü(ãÆµXF°I&Nl©SëeæÌ:‰‹«–¹s_Êüù•òå—Oeùò'²jÕCùöÛٰឤ§ß‘íÛ‹d×.ëÜGÏʤy/åÖ­¶Ÿ'Õ=>ö¹,^s[æÍ{aŒ˜žg„&óX_ÓW_=‘õkïË~ë˜ç×K©eâ^XëßN}+UÓªäfòM9‘yL~øa½ü5_~Ú1ÝÚ/D~M'5“ÇJCH€”Ïž E_EÈ…M1rrïB9öÓZùñü~9ÙK ä9Ïr|ô³œcò¸td¦æui~—æyi¾Wcc˜ÉÿÒ¬æƒéhKÍÓòš/¦yc™+­o6ŠÉ’ƒ…^  ‚åi>ÍŽëÆ~D>ŒŸ*ã'ÊŠ‚ Ù¬£¿š&8V9rÆŒ:)(hlg6bbZdÿþ|Ë”Ü0æDMŠš5-+W>4&fÑ¢§²`ÁscnââjŒÙ™2¥Þ˜5'j†Ô…†~0&iÚ´·Æ4Íšõʘ5SK–”s¥&KÍ–š®-[n¶{w1ejÎŽ¿`Ìš7Þ;5•‘‘[M–ê:µÙ˜>Ç}5Z¶oß5ÕÒè–FÄÔЩÕöÙgïö/VÈÚ¥e²Ïb®µÏÃø—Ro½­}ôÿÓO¥ 킜û~«œÉ\*7ÆZ†,Â.5^¯'5FìÂÚPùq÷TÙ{<^¶_Z.[ŠÒeoÁ^3 ÇÃ$òÃW›Á ?]ÿ©ßÝPt£–ÊP“¤#ËÊ–š‘ŽoßFZæi¼©#!µ¬…ŽŒÔí?·ŽœüðáÚ€1YD°Ð‹Áä`u£ÔÂíÍ7¤á³CÒ8!Bî/•ä[ã%ëC¨¼²Z÷]E«:¢Fh:Âøñb"7115¦{-1ñ¹1Úí¶bÅ#Ó ·~ý}Ó-§ÝsÚM§Ýu?üpÕtß©1Ñî<_}/ÕdÅÆ¾—  Ëø5th®\é®±USeNÕùòé—²úÁê9ߤ3SùàÁjÓͨÅ[µ:ÿoSÙº g™únZ¼V«ék Š+WŽÈÙ³¿ð™F3, Ë_úõµÔÂÃU·¤1d—e¬‚%ÿë I}$ç&ÊýâoÜŠVeeå™®½iÓÞHXØs³ß¾ý¦lÙRdÝð¬/lS«¹š6­Evì(!—¡‡“õ;Œ~Y×'dB³„}”ØðFYf™°­!äD@‹\µ ØÙ¯Lî×íôÛR°÷‚ìÞo™°M¦ŒÄóÄD©›1Í”—ÐQŽOã'ɯ§95XÓßL—˜×1Æ%¾H”/,s±´l©¤½Q¶n½KK°Ù.úµ°BæDÕÊ”Ð4®E¦5ËB‹ßYÆkŸµîøÌZ“û•¿áWÉ;˜'—Ž3Sï­[ç|Bï Ò:ÁÔýz"µSB¤fZ¨¼š*/¢CM„¬lNˆ«ëB,†Éù ŸIîw“$7mªœß8C.lŒ– ›âäbz¼\Úü¹\ÎH’«›¿”üŒårmó ¹ž‘*…ëäÖæ¦âþ­­[¥hûv¹™™iªïߨµËÌ_ymï^Éß¿_ò0sYêdã—‘K?þhæµÔ‰ÇÏŸ8ÑQ»ßj€i7¤ÖöÒù#uRKOhØouÀ&›tº#3»Á¯¤°0ó÷R½3¡¨è2,ôb°9XmJ-¾,•Iwå}ÄZi ”Óéc%ýÙxÉ}²Ü¥h•FE¾ÿ¾Ð$Ÿ‡‡7šxš/uà@>ù~Dûè—Žj\õÅ3ùÂ2X±af™¯PËtÍ Iß,›&×;5g³ÎÈÙ=gålæY9·ýŒœÛœ#ç¾Ë‘ܵÖÿÔÓrþë_ä|Ê)9¿ü¤\Xjý_ô³\\xB.ÎÿI.ÎË–‹s-S3爜?(gç앜9;åôœïå—Ù[-¦Ë©YirrÖz9·Öâ7r*ök9³B~‰N–ÓÑËåôÌ¥rvæb97c‘äNK’ ÓÈ¥©ó%oò|)ˆH”ÂðÏåvØçr7$AŠƒçʃñsäQÐ,) Š“§ãb¤rÜLy0]^*5S¤nl„¼î¼Zÿ¸/¥(p¥\¿^.Y˜³÷Ê©)‡åxÔqù1þŒþâ‚H¹"{¿+];®Ëþý×äС+’}Q~þ9·]åO‰ø§Œ‘ÒÑ‹¿„\iŒ–.5^:RØoµÀæƒVZú1ljÜ<)Gak(ÍšõFBB>JlìÙ½û!߈Á;‚•o ª¹wåmô—Ò Ç·•Œ§’cýðvõÜS§rͨ;ͧ‰Õ:Jï›oJÍ ˜VàÀÔ¬Ñ/­ãµÃú¬ýªØ©Ù›\#:Ïv‹Lµ8Ý2hQc?ʬ 2Çâ\˨}>¡YæOh’…!MòEÈù2´Q–Z&~ùÄIþ콬°¸jÒ;Y=¥^¾™úVÖL{#ë,n˜Q'iÖgrSÌkÙW#³ªeëœW²=¡J¾ÿü…ì˜ÿ\v.¨”Ý–IÜóåSÙ»¤Lö%?–Ý«JdÇš;²=í†dl¹"wœ“õ{OÉšCÇdõ±dÅ/{dYî6Yty£,¸¾F>¿½Jf—,‘˜Ç $òÙl§šÓw/—=ëWJöòT9“ø­\N•¢É+¥8l¹< Z(ÏÇÍ•×3å½eÔZÆŽ“wÖÿª±3äñعr+`±\ûµœ›&?fÊã³doðO’91G2¦^–Q×eíœÛ’úE‰¬ZñPRSKdýú{²iÓc€öîU£vJΞ=`™ªÍR\¼Rž?ÿÜt=þVŽ"ÐtIþVl¾<~œlº,µëR»0sð@~»ˆ`r°\ÿ’ì¼!µ פ.1NÞ Gw•-Obåç+‡œ>OKh9ƒ¹s«d‚uãÓšQ:¢ïر‹ä1 ™›o9X›­†ËÚûke壕²øébùüÅçS#Së§Jè‡P×2NB>„È”ú)[#KΓuùI²ûä2ùiÿ ¹¸ñk)LY#ʼnë¥læ:yñT…¦Hõø/¤.0^êÇÍ¿›³Æ€p© ˜!•ñò ðK¹¸R.nŸƒ¾—A%cÜÏ’:ö¢|X(_ߓĉeî´ ™3»Òj4=’eËîÊêÕù²qãÙ¹ó¨:´Ã2ÐVÃ*Crr¶XFm»eºvÈ ä`a°¬v¥nm¹%ï—ý$5_FÈÛIrhß8ÙRú…œÌíWÁN9vz¿\ÚwHî¤ÿ(¥©‡¤lé>©œ¿£9ûœäÔ`­i”˜ fÐ"ÓÆ7Ë¢‰ïå;ë7å@üK9»¤\n¯)‘»›îÊ­­·¤pG¡\Û{M®¼*—¬FÝùçå¬׳ƒ,0€#XZjáéþSòaÿ"yµxœTGÈ#á²ýÆæv•¹5yVGŽies[Et­t¾sç kÛYZhF¯hî Cæt¤èÍpy|1Snn/’sß”È_>•ô9¯dyä[‰ ý tTª¯°FÙôÙ{9ñ^nZ¬o¦à&i±¶ëŒ¬FÞ{ký[ëyµÑµR=»ÚÔk{f5üÊ—ËcëwëÕ ,^S,¿¦ý*·3nËÍÌ›r}ÏuÉ;'—\– ?]s^j šZ²¿ónÒÝ6Ë|¦1XÀs°®œüEªOeJÃé)R5?PžÏ }G§Èî‚íF„íØqÃÌç†J•,5Zä1 ½hvÅ93XUÓÇÉäÙ}5HY­]­³{ëåÛ {$åà)ùâ»™óåC™U-Aã›$ÜúMŠ›õJ–Z¿Oi–9ËÚ|[rw]—‚ÝÆ<ÝÞrÛ˜)5Uj®Ôd•[B5]/æ½WÖsÕŒ½öÖ˜³–¡S³¦¦MÍ[ƒu|Ñ nfÔÄÕÈ˹/åù‚çòtÑSy²ü‰<\ùPJ¾-‘{îÉô;Rd™Ä»nHþþüßÌ”…gÖŸF&õÿošýÓ`ÙHGb°À€ˆ`Ý>@Þ&Ký…`©š=^ÊãÆÉÞì(9˜wÀnäß93½LRR¥éúÓ.@í Ô.AZúhF/š½™sv oŸ\عBjbÃämì8¹~"\6=Z*«®’åO–›hØüÊù2÷å\‰«Ž“™u3MôlâûÏd³ (X.ãŽdJàú3øy‰„¾“qu¼ X"Ö^”™ûŽÊÜ3ÛeÉí5òõƒ¯eMñIû5M2ngHæÍLÙs}õÈ‘ËGŒQüåÜ/¦ÛQ»µòªõ»§Ý’Ú=©Ý”Ú]yý})M-•G)¤li™T|Q!ÏŸKÕœ*©‰©‘7Óß´¬õÖŸ,ýo3XjÞÔÌ5†7§æîÝäwR?µÞ˜=}~íÌZyõÚ¯:®Z^Í~%UñUÆä½øü…9_å‚Jy¶ð™T,ª§‹ŸóX¶¬Lž|õD§<–G+ÉÃU¥tu©”¤–Hñ·Årí}¹·þžüúݯr7í®1†·-cª¹·EÛŠäæ÷7Vät}·eV÷ȵý×$?+ßtÍ^9tÅ”ì¹tô’\̾h¢~ú^I'ƒe‡ØØXùä“OÚ¬ÓeG:"##C†j˜žžÞåyºÚßÓí}}>_ÊÁÒ¹ÌžÜøNšžÏ”šc“¤*f‚<Œ}ÇfË‘K‡[‡ÎkRú¼y/M’ºN¼vm±I^§ïBè “ž%Ijcj›ßD5)oRÚìW¸#SÞ~>UZ¦ÈÛ]Ó$?7Ë¥ã«):~á¸1Ij–¶ž;$©‡OÉ[.KìŠÛ2)þ©Œ/Aáï$|Þc™œš'Óö•éçÓdÆ£$™övšD¼0]žM·gpS°Ll˜hº>ÕÔÅÕÄ“·àùYôt‘1+®”oK¾• ÷6HútÙ^´]vÝØ%ûó÷cñ,Ꙍo/×­¿ñMãͲ®WC¢ÆD Šš8ížTã¢F»+5¦ÆF»/5"¦†G 5yjˆÔÝÝx×%5Ljœ4RWòM‰1TV=‡+£¥†«ly™”/-7FL ™³J«­FM ÛË„—ÆÀ©‘SCW[c ž½ºéuò&ò1€jßOz/ Ÿ5ƒ¨FQ #« œ:uJ¢¢¢:4XÎ-ÑÑÑR[[k¨&M×uwO·÷õùzË`uUùúõ]RýðKiy&/2gË«éäþüq²ÿD¢»pÌ&Ôò ZFAË)̵ZFiV‹æøñó´ôÑŒ^4÷YRÿµƒ{äÍòi"ŸÈ›ï¦KÞ‰Þy-Ç.˜œÑµ–Yl õÚh•3-#±Ð2ZlÛ÷…’u윽ø£üpõ3“NŤS2éÔLëï¯7ݗکݙڭ™ø<ÑLé¤yh:ÅÓäw“%äcˆ|ký)RšSÌtOþ¥¤‹°S¼{÷N‚ƒƒ¥¢¢Âmƒ¥æC$lÐÇjÔº»¿§Ûûú|½a°´³~r‹Š¶µ‹V•+ 5ÓäcY´”­K’ê©Ar{Q ìÿy‘d½`ý€”Z¯¿VBBšdþüJÉȸ%'OúþÈ?òsЋæ¥7ÿøy³Î2Z-£•2M®Ú×#¯I•»w_7EW—.-—Y³ª%<¼AÆo6)š.±zu©íªE’;«–oÏÃW˸¼2g^“õ[kÝGf5IÀ¥Õ&šçí‘¢ÔÁòqƒµaÃÉÊÊêÐPéòðáÃeРAÖ%D233Ûl2dˆ´´´´.ëc]׺ÚßÓí}}¾ž6Xj®>~ •»²ÚüW“¥ÑªçÏÈdžPùpn¥”¤,–דåæÒñ²cwš$¯x(S§¾5SÔ|ùåS3Éé~6¼™èzÑ<0õæÉ’7ßO“–ÉòvA¤Üص£W^«N=´wo|÷ݯ²lÙ™3ç•™7uüøfbúùóŸËªUdË–[rèÐÕ6¿©s~Ù-“§[·þTß-bzƒL<³QBšBLäË_£íPZZj¹ô.E¬ÊÊÊ$!!AÒÒÒœî¯f¬3tµ¿§Ûûú|=i°œ%‹¾ÏÜ'¿.Y"µrÍúJ]|ÊüèdÊ:©²N®ìJË B}‘×.ï•ú#S¥%zœ¼‹d&Þ>““Óë¯C§Ó9 7n¼+_}õØÌZ¡¿³AAMCvîò‰˜÷¢Õ\Ù &k|ìsÉÊË2ËßË‚š«òòr—»ëëëM²7¬Ž•öˆ‰‰1aS›³×ÿî.?yr×épç·‘riÆ27L»ßÉæÍ5ròä¯Ý>Ÿ¯-WVVöë×ßå’’ôúù²èu}¹¤ø 4]Œ”‰¤qJ¸”YFëqqqŸëËÏ/”¬¬|ٹ󑄆vüS­ÅtmûŸ¿uÞ¬ÐæPYS»Æ,ûÃõÖïqO¿_¬ŽF :3YŽ«£%]çNN”ýþžnïëóõx«ƒµ0ú®|ûm‰=z™~}4£Í~®7GîÜI—Æ›áÒ¸4L>„…ÈÕ+åÂñã>¡3.®¡ÃÖ¤I:àO-r°º0\öHNNnp½|ùR’’’$55µÝ(»šššGÙ9¯«ý=ÝÞÛçóƒEîšÑ‹æ¦÷ìÙÓR\¼F>< ‘w©“¥)$XÊ/–ËGŽô©Îï¿¿-Ó¦µ´ÉÁš2å£IÛÐÑ‹YYy~k´ºáŽÁ²Cnn®DDD˜õcÆŒ1ùWmöÑÚPÕ‰ê(ælO·÷öù0XBØ·ÌÍýY=J‘/‚¥6m¦| ‘‰‰rmÿþ>5YÉÒnÁéÓ%#ã¶™VlݺûöÁ”Šè¨,N6ZpÇ`õì×çÃ`ÑÒG3zÑìz/ZfäéÓEò¡.Tª¶ÇKÃg¥&.Nnffú”f5Vj°Ôh©áêh>×þf´Ô\55Kcã¦Öî,Ð/ –~¹œ"¤¶ šÑ‹fôþÆ+WÉ‹ ÒP.{ÉÛi‘§ÉÝM›äìéÓ>£Y» µËpÚ´·²k×Nû}ÝhÙÌU]]Îïw½›^7Y,Ð+…Fiù¢½hFo×,(Ø+¯_ÇÈÛ·Såá¡•R' 'JÉ·ßJîÉ“>£Y»5?ëóÏ_ÈÑ£—ú•Ñ:þ„éljúÚáN¸Ó¬×í,Я „BW¯·“¥fëן6ÊóÄD“§õ89Y.ó £rêÔ9Y¹ò¡„„|0ÿuÙW–æ¼Ýº•!_HCÃDil —––`ën—ßÁ —G²ˆ`"X´|ÑŒ^4û·Þùõ×ïŒ!ÐîÃ?ïò%K¤É2Z_|!Wò ÍÁÒH–F´4²å,m¤7V~þyð`µ1©ÍÍäÕ«ÙR\ü­é޵uj· È6¯›+ èUƒEîšÑ‹fôºÏsç~‘ÒÒÕòáC¨Iˆ¿úËASC«14T^Î+×÷ìñ Íš“ù¦Ó²=m´´kïöíÍòìÙB¡z÷n²”—/‘›7¿·ÞÃSNGzÛ\a°,ZúhF/šû‰^5Ož,³ŒVˆ)ñp!ç˜Ü_·NÞMš$µÑÑrkëV¯LÅã‰fWÊ:xÏhåȵkûäáÃUR[m¢TUUñrÿþZ¹|ù0u°9XB]ç¥K?Jee’46†š¢¥gÏœ6óÖÍœ)õ“'˽ äÜ/¿ôékt¥¬CwŒÖ… ÇåÎM–þù–Ñ “úú©RV¶ÌD¢4ÒçK× ƒˆ`ÑÒG3zÑÜõæåeÉ«WsäýûIfèÜØµKªæÌ‘Æðpyðõ×rþĉ>ÕìJYçF+ÇŒ¬|ôh…ÔÕÍ”¦¦ òòå\¹wo½e4úô5Æ`r°ÈUA3zÑÜõÞ¸±Ë˜7o¦›HŽ1_ʳ¤$“_¶t©\:z´O5»RÖÁÆ“yeõ«Yö1P¶| ’§õSåÉ“¯,;ÍTCýåc°,ZúhF/šý@ïíÛ&±»ºz¶Agº³³åÉòå¦ÄÃó $?+«Ï4wVÖAMÓõë»åñãdcµè‹ó$¿ä[ùªâ‹uH ƒ!„Ð)լܿ¿ÎŒ¢{þ|\¾ü[ä*÷知45UÂÃ¥zöl)ܱ£Ï^£F°æÏ¯É“ëäĉß*ª«±zü8Å­³gsúEÁR  ‚EËÍèEóÓ››{J>\iF–Y¦D“Ãûåù5-MÞN*o¬ßù;éér6'Çé´fÞ2~Úŧ]}oßFš×uþ|ºDEUI\Ü+§ezÚhÁä`‘»fô¢½nñÂ…cR^¾Øš¾–sç~ŸnÇ2UEÛ·Ëë˜yÿÙg¿™©ŽàÁÒèÙ½{ëLRº&§×ÖδÞÏ•&i]“×Ý-ëÐSF‹,@‹–/šÑ‹fôv‹W®‘/¥¡!Ü2=ÚtÃ]Û»×+KË$fš² õõSL…Êʦ¬‚-‚æ²Þ6ZD°9XB=¢欩‰3èÖ­­­ë»k°Ô¸iaϪª9¦Ðçë×Q¦ðçµkû[£T=UÖÁ×s´0X€-_4£ÍLïÍ›™òæM¤©€~ýú— –N9sóæv3ŽXÔdzšF§¨ÑJó}QÖÁS£E ƒEîšÑ‹fôz‘9r÷î&yÿÞyVyêb)½ÿ¼z5ËD©jjbÌ܈ùùY=úú:+ëàm£E ‚EËÍèE3z½NÍr6Šðãò@iŠ –ÒŸS%7÷ç>)ë ‘,hidËÕç¹j´ŽÅ`r° „z—Úµg9)‹›î ™f½n×raaòdÙ29wêTŸ¼NÍÉŠŒ|cr´\)ëàŠÑ:|å°¥p¬¹zƒˆ`ÑòE3zÑŒ^ïR§Øùø1ÔúõÏ7÷€––Bin‘¢¢m*ùpü¸<Ÿ?_ÞMš$7vîì“×ٲΌVÒ³$c°–¿^ŽÁä`‘»fô¢½=i²¶µ3WöÔúY 'JÅ—_š ñ}ñZ»SÖÁÑh7˸–qR`ý·þ¼ÅÂ`"X´|ÑŒ^4£·Õdi·`gæÊF5Vj°ÔhmÛÖg¯·;elL|‘(K›–š{ÞzëÏÛQ,   Ba›œ,— èΦËP»µ ±¯^³»e4÷*ðc T´T˜{Þ3ëÏÛQ,  ‚EËÍèE3z»­Y“Þ5ù]“à5¾¯^·;e4÷jÕ»Umî{ÞŽba°9Xän ½hF¯Çš¯íÛ'o##¥*>^.eg÷Ùë窱ƒæ`uòç­Jð½b°>ùä—øé§Ÿº}ìØØXó\GdddÈСC Ó-GíîvoÏ×ÏG‹–/šÑ‹fôzªùìéÓòpåJù*÷6l0“J÷•WË:ôëJîjœìÙ™Á4h[Ç=uê”DEEµ3XÙ–sŽŽŽ–ÚÚZC5aºÎÕíŽðôx¾~>r° „z“yJíÌ™RcÝ®9Òg¯Ã“²ý®‹ðøñãææ_SSÓº®ººÚ¬Ë±œ®«x÷îKEEE;ƒ¥ÇRGjƒ>V#æêvGxz<_?,Z¾hF/šÑëuÍÖ=½ä›oäCHˆùߗѬŽÊ:lÛV$3fÔÉ„ %2²Þ­*ñ>i°FŽ)MMMíÖëºQ£F¹|œ 6HVVVk¤=† "---­ËúX×¹ºÝžÏ×ÏG¹hF/šÑÛSš/>,5qqR7s¦‰lõ¥6[Y‡ˆˆ÷þA®^­7÷¼{÷ZdêÔfÙ²åNÿ5Xj†:3X®æ`•––Z®sF›c:žÃöÝ]mïè5{r<_>Ÿ~l´GLLŒù’ÙZ2úßÓåÊÊJ¯Ï×—š^].))A¯Ÿ/Ûˆ^ÿ]ÖÏuO¿lÛ6“›õlÍyüàAŸêŒl’“'[ÚÜ÷îß™9³Ékçëuƒ5|øpÓ]¥Ý‚YQVUUÃ4bÄ—Ž¡û–——wj(ˆ`ùf BáÀ¦Ž.ÔQ†:ÚPGöÕënêð^8~¼ôï¬Î’ÜOŸ>íѨDg9HºÎÕí®äD¹s<_?9Xän ½hFoojîëÉ£gÎ|#EEí#XÑÑûw,½xcÇŽ•Áƒêã[·nyÔíØÑ(ž¯,r7ÐŒ^4£·¯5÷åäÑšà®9W6ë¡æÊºíÉåí*gIk?9«ål»·çkç#‚EËÍèE3z}Es_M½}û-™5«Ñt jäÊ›æÊo –·¡Q5>9XB}‰¾2yt¿7Xñññ&éÚ•ÜAÿ1X´|ÑŒ^4£ÍNÏÝ“G÷ëJîöHHHh5SžVrýË`‘»fô¢½h=ytOéíuƒ¥9Aùùùæ±-bUWW'‰‰‰rôèQœ,ZhF/šÑ‹æ^›<Úo"Xö ÝöµV“«u°9XBýŸ¾4yt¿0XZ:À–Ü››kçå呃E‹V šÑ‹fô¢¹{ròh¿‰`,ZhF/šÑË5à+>>^òòòÌ4;---²ÿ~‰ŒŒlc°œ!;;[¢££M˜RÍš®ëîþžnïëó‘ƒEšÑ‹fôrû¹Ájjj’Ñ£G{=˾üCWK͇:VôqTTT·÷÷t{_Ÿ­@4£Íèå÷sƒ¥ÓâØ*Os°4‚•••%óæÍkc°†nŽ"™™™mž3dÈó<ûcèºÎÐÕþžnïëó‘ƒ!„úA’{NNŽWº mFmÔ¨QR^^Þá>eee’ iiiN#\ÎÌ]Wû{º½¯ÏG‹V šÑ‹fôrû¹ÁòöHAÎìÙ³Gf̘Ñé>ZØT“½‰`ul¬l´GLLŒé—¶}ðô¿§Ë¯_¿öêñ|}y éÕåÊÊJôúù²ãôúß²~®ÑëùrŸTrï‰"£ÎŒ›£Áê(GI×¹“e¿¿§Ûûú|D°h¢½hF/׸ŸG°tô_XX˜ÔÔÔtû©©©RQQÑjž´ ½HNNní2|ùò¥$%%™ç8޲Ó×ÐÑ(;Ç.¶®ö÷t{oŸ,!„Ðr°œUoïÎ(ÂÜÜ\‰ˆˆ0Ï1b„¤¤¤´1löÛÇŒcò¯ÛCMYgu¢:Êar¶¿§Û{û|D°h¢½hF/šý ‚å¬z»/Vr·/ùà磵dÐŒ^4£Í~V Ü©rh¡½hF/š‰`a°0Xô¡C!„ý§Vw¶"X´ŠÐŒ^4£ÍD°Ü4Quuu,r°è×G3zÑŒ^4“ƒåí‘„]Mçˆ`Ñ*B3zÑŒ^4Áê`$aGs*µœ€Î)ÈÁ‚BÉÁr¾RŠÁ¢ˆfô¢½hî÷¬‘#GÊ’%KÌœ?€,úõÑŒ^4£Íä`yÁ`EFFš+í"Ô(Vxx¸HCC"4£ÍèE3,O snÙ²ÅLacKn×  322¤ªª §C„BH–'ÐèUQQ‘™üY£Zj¶† &QQQ8"X´ŠÐŒ^4£ÍD°¼ÍÏÒ‰›Gã!‹~}4£ÍèE39XƒE«ˆ–/×ÍèE3z{Ñ`¹RdÔV ƒ!„’ƒå‹Švf°¨‘E‹VšÑ‹fô¢™V7püøq‰ŽŽ–šššÖuÕÕÕf]NNN‡,úõÑŒ^4£Íä`¹ -8ÚÔÔÔn½®5jN‡­"4£ÍèE3¬îäcuf°ÈÁ" B!$«>|¸©s¥Ý‚---†Z`tÆŒ2bÄœ,ZEhF/šÑ‹f"XÝÉÁê,ÉýôéÓ8r°è×G3zÑŒ^4“ƒÕ¨[Ôéql¨oݺ…Ë!‚E«ÍèE3zÑL `° „BˆÁD°h¢½hF/šý/‚¥£u®A*¹“ƒE¿>šÑ‹fô¢™,/¬ÀÀÀ6†ÊžTr'‚E«ÍèE3zÑL«P#åiÅö‚‚‰5 òÆ “åË—›RöÈÈÈ¡C‡¦§§·;FWÛÝÝ¿¿Ÿ,!„°,oD©âãã%//Oš››M­ýû÷Kdddëöììl3õNmm­¡š1]çêvGxz<_?,ZhF/šÑË5îçKK2èMßÛÐh– j.ô ³/ ¡ÅM]ÝîOçëç#‹<4£Íèå÷sƒ¥‘§°°°6“={`eeeɼyóZ× 2Ĭ·ßG×¹ºÝžÏ×ÏG‹V šÑ‹fôrû¹Áꬊ{wFÚž§“D———·Yï¬k²«íÇ“ãùòùô`£=bbbŒ«·}ðô?Ë,³Ì2Ë,³ìÚrŸ$¹wÆîägitfÏž=f.C"XD°h¢½hF/šd«§`oÎ:ÊAÒu®nw%'ÊãùúùÈÁ"ÍèE3z¹Æ,IMM•ŠŠ 󸾾ޔ!°7¶Qtšçål”]gÛ»Ø<=ž¯­@4£ÍèE³F°ŠŠŠ$ ÀD”úX×¹ŠÜÜ\‰ˆˆ0ÆdĈ’’’Ò.i^M—³:Pζw”ÃäÉñ|í|ÔÁ‚Bý¬V~~~§Iîž„}É<,ZhF/šÑ‹f?‹`i´J …VWW·®ÓÇqqq¦Fð_ƒE¿>šÑ‹fô¢™¬¬ä®>;B«²ûB$ƒE ½hF/š¹Æèí—«±±±Ýz5],ÿ6XB!9X=d°Í´-:9³ÖgRêcKP»,ZEhF/šÑ‹f"XÝAØY’û½{÷p:ä`ѯfô¢½h&«;P#¥Ñ*íTêcÌ,ZEhF/šÑ‹f"Xƒ!„B  ‚E+ÍèE3zÑì—¬sçÎÉòåËÛ­×jì.\ÀéƒE¿>šÑ‹fô¢™,w1räH©««k·^×=§C‹VšÑ‹fô¢™–»èhÞ=>ýôSœ9XB!9XîB'¶Ÿ&Ç­…5lØ0œ,ZEhF/šÑ‹f"XîBoÜ©*++k-4úøñcÙÒ¤€,úõÑŒ^4£Íä`¹ ͵ê¬Ðh}}=N‡­"4£ÍèE3¬î@»uÊ[¡Ñ   ©©©Áåƒ!„’ƒ0X´ŠÐË5æ£ÍèÅ`r°Èc@3zÑŒ^4û_–âðáæ–}Yí2|þü9N‡­"4£ÍèE3,wqòäÉÖ¤v{ƒUPP ÑÑÑ8r° „Br°ÜŘ1cdãÆ¦<ƒ½ÁÒ„ÔÁ"‚E«ÍèE3zÑL«°7UŽ•Û©äNýúhF/šÑ‹fr°ºAƒICCC;C¥e† ‚Ó!‚E«ÍèE3zÑLË]h2û”)SÌt9j°š››¥¸¸Ø¯ˆˆœ9XB!9XîÂ6-NG¬­­ÅéÁ¢U„fô¢½h&‚Õ]“e_ÉÝÝ :â0..Î9Xä1 ½hF/×x€7ožäç监ˆ²~ýzc¸ì –3dgg›’1SÆÆÆšuÝÝßÓí}}>"X´ÑŒ^4£—kŒÁj5ZšÃåªÁRó¡o¨ ú8**ªÛû{º½¯ÏG„BØÏ Vee¥éTh‚û¨Q£Œ! èö1¯\¹Ò.‚5|øpcºBBB$33³Íþ:ZQM™½As6‚±«ý=ÝÞ×ç#‚E+ÍèE3z¹ÆýÜ`EFFʃÌãÅ‹·É“²7I®BnŒ[G(++“„„IKKsá²€9¢«ý=ÝÞ×ç#‹<4£Íèå÷sƒ¥‘Í›RŒ=Ú˜»wïJii©Û•Ü %88Ø<×´J¼&{ÁêØXÙh˜˜ó¡³9{ýï鲚`oÏ×—š^].))A¯Ÿ/Ûˆ^ÿ]ÖÏ5z=_îuƒe]ѨŠ.755µ+<ÚrssM·¢ÖÐê Ž«£%gó vµ¿§Ûûú|ä`A!„ý<‚¥FG#VÚugË•RhTËÞ9áC‡dìØ±¦ÜCGHNN–òòróøåË—’””$©©©íFÙii‡ŽFÙ9v±uµ¿§Û{û|ä`‘Ç€fô¢½hö³,½qÛç]Íž=Û¬×pšVxw5 æ¬Ö•F·´*¼®ÓÉ¥5ÿÊÖ-iƒÖ†ê¬NTG9LÎö÷t{oŸ,òÐŒ^4£Í~XKMvjʆ   NÕ{ZÀÔŸÏG‹V šÑ‹fô¢™:XÀO „BH–— ÖÈ‘#eÉ’%>¥D°h¢½hF/šû}Kë_i©Í7ÒуZ»JçlhhÀÝ ƒE¿>šÑ‹fô¢™¬ê"ÔQ}[¶l1yX¶ätÍÅÒɉ«ªªp:D°h¡½hF/š‰`y^IXXXkM,-6ÚÕ¼y€,!„,¡ùY)))¦Â; ‚E«ÍèE3zÑL `°è×'wƒkŒfô¢½}c°tZÛ„Žtgª@‹V šÑ‹fô¢™Öï lc¨ì©yX€,!„,7¡F*''GC‹VšÑ‹fô¢™–· Q*r°è×G3zÑŒ^4“ƒåeƒ¥5¯jkkq4D°h¡½hF/š‰`yË`åå噺W555¸r° „Br°¼a°:=È(B"X´ŠÐŒ^4£ÍD°šÑ‹fô¢™,€Á¢U„^®1šÑ‹fôb°9XB¡ßå`)t‚瀀Ó%¨ÔǺÁ¢U„fô¢½h&‚Õ äççwšäŽÉ"‹~}4£ÍèE39XÝ€F«âã㥺ººu>Ž‹‹35²,ZEhF/šÑ‹f"XnB»uÂgG477ËàÁƒq:ä`A!„ä`uÇ`566¶[¯¦ ƒE‹VšÑ‹fô¢™V7(QQQRUU%---†ú822Òtr°è×G3zÑŒ^4“ƒÕ„%¹ß»w§C‹VšÑ‹fô¢™Vw FJ£UÚ%¨Ôǘ+r° „Br°úfÔ¡š³aÆIJJJ»É£322dèС†éééíŽÑÕvw÷ïïç#‚E+ÍèE3z¹ÆÜ`Í›7ÏÔÓÒü-M˜_¿~½1\6dggKtt´ÔÖÖÆÆÆšu®nw„§Çóõó‘ƒEšÑ‹fôrû¡ÁÒü*ÌÙö¸3Úöqj´ì'ŠVs¡ŽÔ}¬‰õ®nw„§ÇóõóÁ¢ˆfô¢½\ã~h°Ô8Ù >îŒö&É\¹r¥MkÈ!ÆtÙ0]çêvGxz<_?9XB!]„mðàÁ —ÊÊÊ6³Žêo¹º½£œ'ÇóåóéÀF{ÄÄʰ©ÍÙëO—õyóx¾¾<ÐôêrII zý|ÙFôúï²~®Ñëùr¿6X………,¥¥¥^Á" ½hF/š¹ÆèíW,gyVîä`åææšòÅÅÅ.å0é:W·{ûx¾~>r°Èc@3zÑŒ^®±Ÿ¬ºº:— Ö¡C‡ÌÄÐ?v: OK78e×ÙvÇ.6Oçkç# B!ô“,g£m쪫«cÙCk?9«ål{G9LžÏ×ÎG‹V šÑ‹fô¢ÙO"X¶‘‚¶r ŽT#••å¹]½=é´/LrMy hF/šÑË5îÇ]„Ý-Åú¿Á¢U„fô¢½h&‚ÕOÊ4€þc° „Br°zÈ`;wN–/_Þn½Î'xáœ,ZEhF/šÑ‹f"XîbäÈ‘fÄ`G£GÓ!‹~}4£ÍèE39XÝMè:X€­@4£ÍèE3¬ß¡£«««Û­¯ªª’aÆátÈÁ‚BÉÁrzãÖHUYY™™ÂE©C5²…Ó!‚E«ÍèE3zÑLË]h®Ug…Bëëëq:ä`ѯfô¢½h&«;ÐîÀÀÀ@S`Sd¦uD°h¡½hF/š‰` „B1X€­@4£ÍèE³_F°âããÍÄÎŽ9X”i ‹~}4£ÍèE39XÝ@BBB«™r4XÌSH‹VšÑ‹fô¢™V7ë`åçç›Ç¶ˆ•Ž,LLL”£GâtÈÁ‚BÉÁrö•Üík=¬#Fàtˆ`Ñ*B3zÑŒ^4ÁêŽÁª­­5µDCnn®yœ——G9Xô룽hF/šÉÁêNž<))))æqXXX›,&{&‚E«ÍèE3zÑLËC477˘1cLäjÔ¨QÒÔÔ„Ó! B!$ `°h¡—kŒfô¢½,@y hF/šÑ‹fÿÊÁª¬¬4óÚºµkPó¯p9D°h¡½hF/š‰`u‘‘‘òàÁóxñâÅm’Üãââp:ä`A!„ä`¹ "§±±Ñ<ÖQƒj¬îÞ½+¥¥¥2lØ0œ,ZEhF/šÑ‹f"XÝ©ƒeƒN£Ë¶ÑƒÔÁ"‹~}4£ÍèE39XÝ€N•£«²²2c®†nÖkTK·¹jÒlìj{gûedd˜ó)ÓÓÓ»u° „B?«ƒ•——'aaa¦û øˆ`Ñ D3zÑŒ^®q?6Xuïuw!è_‹~}4£ÍèE39X=˜äÞ½‘Ÿˆ`Ñ D3zÑŒ^4¸¸ B!$ ƒ…Á¢U„^4£—kÌ5Foÿ1Xñññ¦²89Xä`ѯfô¢½h&Ë Kç´™)GƒE,ZEhF/šÑ‹f"XÝ€¾ÌÏÏoMxWÔÕÕIbb¢=z§C„BHVwÊ4tôX'$1bN‡­"4£ÍèE3¬î,[%w­`®ÓÚ(´)9Xä`ѯfô¢½h&«8yò¤¤¤¤˜ÇZÑÝ>kôèÑ8"X´ŠÐŒ^4£ÍD°šÑ‹fô¢™,/¬ºº: ,ZEhF/šÑ‹f"XÞ=hã!Cp:ä`A!„ä`¹;zÐVŽÁ‘C‡•¬¬,œ,ZEhF/šÑ‹f"XîÂ¥ì£^!##Ø6ezzºÛÛ½}<_?9Xä1 ½hF/טQ„­F«#dggKtt´©¯Œ5ë\Ýîíãùúùˆ`Ñ D3zÑŒ^®1«Kƒ¥æBß0ôqTT”ËÛ½}<_?9XB!«Kƒ¥Éò---­ËúØ>¾«íÞ>ž¯Ÿ­@4£Íèåc°º4X­·Ïýêj»·çËçÓ€öˆ‰‰1ýÒ¶žþ÷tùõë×^=ž¯/4½º\YY‰^?_vü^ÿ[ÖÏ5z=_&‚E‹­@4£ÍèåÁê^–®su»·çëç# B!Ä`¹<দÆé(»Î¶;×ÓãùÚùˆ`Ñ D3zÑŒ^4Ár©*¼#´ö“³:Pζ{ûx¾v>ê`QKÍèE3zÑL¬^ÇàÁƒýú|D°h¢½hF/š‰`?1XB!9X, ­"ô¢½\c®1z1XÀ· ýúhF/šÑ‹fr°0X,ZEèE3z¹Æ\côb°9XB!9X€­"4£ÍèE3, ‹~}ô¢™kŒ^4£ƒˆ`Ñ D3zÑŒ^4Áä`A!„ä` ­"ôrÑŒ^4£ƒÈÁ"ÍèE3zÑL ‚E«ÍèE3zÑL `° „Br°0X,"XèE3zÑÌ5æc°9Xä1 ½hF/šÉÁD°h¡½hF/š‰`a°0XB!Ä`"X´ÑŒ^4£ÍD°9Xô룽hF/šÉÁ,ZEèE3×½hF/ ƒ!„’ƒˆ`Ñ*B3zÑŒ^4Á,úõÉÝࣽhF/ Á¢ˆfô¢½\c –«øä“OÚÑ2tèPÃôôô.ÙÕþžnïëó‘ƒ!„b°º4XÎ-ÑÑÑR[[kkÖuwO·÷õùˆ`Ñ D3zÑŒ^®1Ëcƒ¥æCßPôqTTT·÷÷t{_Ÿ,òÐŒ^4£—kŒÁrÉ` >\ $!!!’™™Ùfû!C¤¥¥¥uYëºÎÐÕþžnïëóÁ¢ˆfô¢½\c –[(++“„„IKKsáR3æNDÌ~O·÷õùÈÁ‚B1Xn£¾¾Þ${ÁêØXÙh˜˜6µ9{ýïéree¥WçëËM¯.—”” ×Ï—mD¯ÿ.ë罞/HƒÕQŽ’®s''Ê~O·÷õùÈÁ"ÍèE3z¹ÆD°ºDrr²”——›Ç/_¾”¤¤$IMMm7Ê®¦¦¦ÃQvŽ]l]íïéöÞ>9Xä1 ½hF/šÉÁr¹¹¹aŒË˜1cLþUccc›}´6Tgu¢:Êar¶¿§Û{û|ä`A!„ä`õ:ì×ç#‚E+ÍèE3zÑL ø‰Á¢_ÍèE3zÑL ƒE«½hF/טkŒ^ ðmƒ!„’ƒ…ÁÂ`Ñ*B/šÑË5棃ÈÁ"ÍèE3zÑL ‚E«ÍèE3zÑL ƒ…Á‚B! Á¢ˆfô¢½h&‚ÈÁ¢_ÍèE3zÑLÀ`Ñ*B/×ÍèE3z1X€,!„,@‹VšÑ‹fô¢™À`ѯOîzÑŒ^4“ƒ…ÁÂ`ÁB/šÑ‹f®1׃ÈÁ‚BÉÁD°h¡½hF/š‰`a°0Xôë£Íè壽,@‹V šÑ‹fô¢™  B!$ `°h¡Í\cô¢½,@y hF/šÑ‹fr°,ZEhF/šÑ‹f"Xƒ!„B  ‚E+ÍèE3z¹Æ,@ýúhF/šÑ‹fr°@Ÿ!##C†j˜žžN‹V šÑ‹fô¢™ðÙÙÙ-µµµ†±±±f9XB!9X ›Ps¥ŽÜ}E‹V šÑ‹fô¢™è.† "---­ËúXבƒEšÑ‹fô¢™,ÐM|òÉ'íÖ 4¨Sce£=fÍš%³gÏ–™3gÊ”)SÌO—çÎëÕãùúò@Ó«ËqqqèõóeÑë¿Ëú¹F¯çË,"Xèc`°úi–® t¶Q„555." t­}åN,GØçfA!„Ð}b°@¯ÀÝzÑŒ^4£ÍE/ ð¥E/š¹ÆèE3z1X¾  ƒ€Á 3è´=6˜©,Æ “””S“ÌŸõj­5›ÞåË—KUUÕ€¹ÞªÝß?ßößãô}~ðà™òDgÂ;v¬?~|@]ãáÇûõõ­¬¬”yóæ™ë«ÔÇ,Ðÿ¾¼ú%ÍÏÏ7S566ÊúõëáòWÄÇÇK^^ž477Íû÷ï—ÈÈÈq­O:%QQQÂ` 4<~üX‚‚‚äÊ•+æs­¤5kÖ ý.\èV Åþ„ˆˆÙ±c‡ùíRfffÊäÉ“1X€èþýqîl²m…F³üïÞ½“àà`ÓâÅ`ù’““ý:bÕtÒâêêj¿Öøé§ŸúÔo ðí&´ìÏ,G3™••e¢xþŽ 6­áómë.Ò†BHHˆiéû;TïáÇeôèÑæ¦«µ’êêêÌoVjjªßë\¸p¡ù,ëï–rûöíf `°ú4‡#<<Üôõ„k¬5j””——ûµÖÒÒR™1cÆ€ü|—••IBB‚¤¥¥ùýçyåÊ•ÒÔÔdºúW­Z%K–,×xúô馋ÔßñòåK lýíÒÇ}µÃ` –‹(,,4]Hz3(ÐVàž={Ú˜„ê³7‘íó]__oæ9õghÒ³+Ôh „®ï7nôi§7¡4‚eŸƒÕ—½ ,€Ár¹¹¹ ÅÅÅòzû{ÎYG#®Òg| ,êh°Ôtù;tÐÆÝ»wìïT_þva°« :tÈ é!v…æj؆6ëWGEGGóùö#h·-b§Ý*III~Ÿ££ îÚ-¨&K©Ý…Z‚ÄŸQTTd Ö@ŽÔ¼+û,F‚~ÝÒˆšýY·Fët¸³j1b„ß×ýˆËþ3Æä_ÙGwüÚe¤Ÿií\¼x±ß'¹kÔNK® h£ÁV³P©û2ƒ€ÁÀ``° ƒ€Á, ø0úK‘Ù6Õ,èÇF ƒÀ` €Áß1'Í;i[Ö¹üf̘aæ;2dˆÌž=»u‚lûýÎ;göÓ}죓ðêÜLÈì8Þ‰'$00м–9vìX»×­:ëÄÆÃ† 3çÓc-[¶Lnݺѽk²:[¯¦éùóçÒÒÒÒj‚¦L™Òn?lW÷³Gaa¡1Ljʪ««¥¹¹YV­ZeöWsd={ö´75kºîkÃå˗ͺ„„c¼”úØñõëkÓå‚‚³ÜÐÐ` ¾> |Â`=zô¨uš,[”Éq¿òòòvÇPS£Ûì#^MMMf]ppp—¯K£P6DGG·{=‹  zÚ-§¥ \5Nî,…&›/Z´ÈäWé~jè´Œ‚}Ù5_ÚM¨ùWrøðá«e‚‚‚L4JM›.;î§Ç]²d‰Ñd+ù ]†ä`€ÁÀ``° ƒ€Á,  `°0XýÛ`ýá€B!„^`ƒ<Œ\a°0X, ð}ƒU]]-‹/–¡C‡Ê Aƒ$::Z.^¼èòó?ùä—öQêñ‡.K–,‘âââÓd;_g¯­²²RæÍ›'C† 1Ôǯ  @âââdðàÁ2lØ0III‘ššš6Ûccc[·/_¾\ªªªzíx]éíj{G¸råŠDDD˜×$ÇŽëðxŽÇîl[gçîê½Pddd˜Ï§2==ÝmmΞßÓàûÕ7ß/gû{ûûÕÏß/€ÁÒ|ý‚444HKK‹Ü¹sGæÏŸïõ€ zžÃ‡˨Q£zô&àìµéÛŽ;¤¹¹Ù033S&OžÜéqô‘ŸŸoÞŸÆÆFY¿~½ùѲ!>>^òòò̱tŸýû÷Kddd¯ÏÕkáªÁº{÷®Œ3Fnܸa–õæ³fÍ·ãÊ~]½ÙÙÙæ3Z[[k¨7F]çê¹\}>ß/ÿù~uµ¿·¿_î~Æø~П ÖØ±³ h«×^¾|) .4-QÝ7!!¡µäJ ª³/çÑ£G%))©Í:mýŒ1´¶´þîÝ»6Û7nÜhZèÚ;xð`·€>ýôÓvëôœ®B¬ºzßúâxÞ2Xz½Ož<éñq܉˜uö^è·íF¤ÐÇQQQ.ŸËÕçwëeݬDBBDf͹tɵçñýêûï—+û{òýr÷3Æ÷ €þf°ÜYoý2¤¥¥ÉóçÏ;Ü.·nÝ2_Lmñéprrr·[Øö-mý!·aÛ¶m¦e¯­ =ÏÊ•+Û´ê¶lÙbn>º½©©É¼Žîþ霶ªU“rûöíf«Ðð¾}+Ðñ,++Ë´]}¼uÖ\WðàÁsSìèµØŽ§Ý3ååå.½GÞ<ž· –+Çq%ÄÝ@GïEGÇè(ºáÎ{ÒUtÄzïµ™+ÔdÅÆ ß/þ~u¶¿·¿_î~Æø~àËËÕ®@7» µË@óEf̘ѺN[×ÖV‰í‹nßÐÝ€žËñF¢7 »sWfÏžmZØö9"µ˜íQXX(ÁÁÁRZZêô¹gÏž6ïao¯?G°:{/ú¢…íø•±îIí`}lÜî‘çûÕ»ßWö÷Æ÷«?D°|éûÀ€‰`¹ÒòÕQOúCùÛ¥¹Í—­»7ͱï6Ðó8Žn±‡7[ص°ºjuåææJ@@€Ë‰Ã½}|ðŽ²–Ò¯©©1{¥eíì^.\{DÝÝÝfo8úoþšÅöööÝÞjÚ§-½w™®k“Óøz¿ÙÀÕ–ž-|1{Æ(]Ÿ½ÔôlÄ{¥©ŒÚ+myyÙš^œgÞµ¼{pÕ­˜˜˜ðÚ+-[üJƒ|U‡|ÙäÁ•Þ÷ïßMëºö6ÔæÖ./€*T°öo?!¨Á—€\]]™ï?þl6¤-w£|¢ÚÚÚŠv¶²©a{÷î]tsscŽ·oßFÍÍ͹騃ØÚÚ2õóãÇhddÄ4Z1ÑÇMZ £ z[[[sÓs…Q¨’¬­­EÎø›››Ö†p?zòäI´³³cþWg2<<\>Ÿp®º]ZZ2¿Ñóóss¨£Ó9ß¼|ãûóòUåò*®ô¤p F××צü¯_¿¾§0!_¿‚õçí§pûÑ__4êµqvvõõõ™‘¨ÂvuuÝ€|­,Y×£ÞÞÞ{çÔÈi¨Ñ–F„———÷®›‘¦FbsssE7@ÚÁ>òôE•«ÞBÒK‡/FÁR]566K+~KK‹±¬ä¡ç½ººZRÃ^ì}¤ëVwÜ }—é›—o|?þy{n-䫊å+T\éé»”—}O*1ÈÀo `Ü~¤`é¯/†±±±èôô4ózSSSôéÓ'#˜Á©(z„i«!™šš2#{‚”F„ÉQÝää¤é|t]#E•£ØH œFÕº'2éëœ/2ïç5 JovvÖŒ}ê(/¼::5„Ïž=3euÝ×èè¨IÇ•ŸÊ>44d½?=ÕñÏèÒu+ÅCu”¬/óÍË7¾ŸrÕ¤_êß·¯*•/—<„¦—V°T¶ßòPe –¬VOo?ÿ¸ý误K£e50uuuw#[›ƒ(ÙpÛ¤G÷…Bá^'¤"é!“º|;BÈËWVƒ†††;Ë€¾ûŽ`M§˜U–8=MÏ;Ë‘>É—/_LǧN:/½ƒƒƒ¨½½Ýë™´µµEGGG%5ܾ> ¡@VÝf¥‘eݰÕq¨U)_¹ÚÊùùªVùÊ’‡Ðô^½ze¦¥dÅS„¶ßòð +X…ŒÏ«ÛOl¹Ò÷BÎdž¦ ä/’ì¬5º–X£’XГSÅvÊ+Ý‘¨Šbòñmž?nFØI›I?fww×LÃI¡±u333÷êІOø‹‹ ã@š‡âút82ßûX~Æ;¯nλqü‘ Ó›ùªùò•Wzrr×BÕ«éùùy«Ó<òPE¬Øz[­Òÿ‡’ùjÕ“J¡¿Ia+¶H²qS>éÕ-IÊ9ÂÎa¹F]Q}}½·ãpè(ÎÞ¥`ùŽx5]%[òÝyH[Ýfùxèœo^¾ñ+eÁB¾~]ùò•‡Ðüß¿oß‘/€ß@Áùûã:—'ìIùK$WüÈ)V«P„h™Ã“¦Žßeþ÷Yå4==õôô˜é!‹LÒ%öQJõÑýé>“>"¶UN‘ªƒÊ›ZÓP¼ ]Êœ‰“Lº®ðºïØ"¥úÐ3Jú‰øL1¤ÙÛÛóv>U§£‘¸âˆJ®rrÕm¼JIϽ”UN®øþJV˜òõëÉ—KBÓ{óæ©7Ý«|œd)Ê›’D¾ªHÁú×í§`ùèº 5MÈ´+Gؤ¯†®ë=-º®Q6)lZ²O9øXXÔ¡È%k@€ü5”—–z¯¯¯ß».?$u8®UN.kŽ¿øÝ0:ôÝÖ º,D!ª¼ñý¥ß5“Îß>y]–ÝwÒ‰¶K Ÿ–šû¿§GÏBÏee%Øbò'[ZêÐ|ÞÓ“W[üp%+l!òõëÉ—KBÓ“Å*ö±Óô¨|/€ßÄ‚Å_T  ` ` ` `¡` ` ` `   VyûTùn6Zl~Ú‰¾¦¦Æì™–µÃ{¹ØÞÞ¾ÛMû«eíar¿®ðYõ¨û´•O{¢Ååëïï7¿f¡p>{–³|"Þ3MeÔžiËËËÎßO1¿-׳^{¦åa‹(XS~2«««haa!ª­­­˜’ÕÝÝmmm™]îµYòÈȈéÄK½wßð›››ÖŽ¼³³Ól8{sscʨ}[[[ÿ'ÜÚÚZÔÑѤ–£|ûûûf³éó¿”¿áááà||¹žÕÒÒ’Ù4ùüüÜR8uÎ7/ßø€‚UqËçœ:hí0/˃,R———Ay,..F½½½AiŽË‹,sssÞ÷¨Î[Ö³‡R°ZZZ¢oß¾¥­{N¢{ollŒ¾~ýZvËU¾¾¾¾huuµä|ŠQÞÓÏJÊQ¬è }—Òé›—o|@Áú/ËQAkjj*zñâ…±È 388xÏÂᓞ,YR”|ÓœœœŒºººÌõëëk£lù¢é®‡²`)¯¡¡!ïxR(fgg%'Éèè¨9Ÿß6XLùÒ蹨ކ‚•~V?6u”¬/óÍË7> `ÝW°BΗIÁ* Ñééé=eÉæÓ“×ù%-®45eurr\¡‡‡‡QSSSfÜJ(XmmmÑÑÑ‘·B¤CÓ¥ÇÇÇwç¢öööÜø¥(XYå MÇ×Ç*´~³žUV!ÖHßøðÿ¬`ùZª,ZÅ(Xú®)­øÐÿ= ÊCS`I –+Íb¬!»»»fšM K9,,®ðš~ÒôZ²¨ÌÌÌÜS¨ô=©p•Ëbä[¾ŸaÁÊ{VX° ò –"U†)B)6ÉNIÊPÚ‚•^隇|°’½+ÍP ÖÆÆFT__ou¤/·‚%ß9ˆCÒªRì Ïr•O¾qéƒe{VY>T:ç›—o|@Á*+Y“œ åÿ#%KJΓᦧ§£žžžèììÌü/kËÀÀ€Wy«]iÆ>X*Ëk~~Þ(l¥N……„ßÛÛËužNÇ“”œ×ÅÅÅ…qî·uúå˜"´•/”°ºº:GTr¡ëYÅ«õÜKYEèŠ(XW°4MÓÜÜl,Y²,H!J‡“BÔÐÐ`Âè}IëëëÖ<âC«¥°eMÛ¹Ò3ï2r­"tY€B­C>áÕqëÕ >u,‹î/®¬w?…(X¥–/‹ø=XzzÖÊÊŠwý†(X>iIõyV^9lñ P°P°P°  à·R°888888888J?î,(ÿ¨ß”žG0XÇIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_get_line_total_narrow.png000066400000000000000000000734611174000617100257710ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔvøIDATxÚì}kL”[{v“¦išæKÓ?MÓMó&MÓMÓôOÓ4ÍÎŽovëŽÙvœQQööŒŠâù„§-*ÏŠâä4Âp9 ÊAQDä,Êa¹¾¹Ÿýï0{f˜q|fæºÈ™çYϬ5׳f˜kÝë^÷úAANÅŸðAAP`AAP`AAP`AAXáÉøÝï~‡?ù“?™°üÇt¿VFüĦïÞ½ÃÞ½{ñ¿ÿû¿øÿïÿáÏþìÏ“çÿõ_ÿ…   \ºt‰>‚ (°ÂQRRòñ!öðáCÕˆWX7oÞÄ_ÿõ_›½¯Óõ>\±O‚ À"·Edd¤Ùþˆˆ ¬Ï@jjê¤vþöoÿ§OŸÆàà R®ÓéQ+Þ­ÿøÿ À"‚‹ Ü Ÿ>}ÂßüÍßLü(ÿÕ_ýÕ$aÀsûÐÙÙ©LîË_þå_¢±±Ñ­$AXAL¬¬¬I?ÊK—.t|ÿþ}«?â¶L{ÕÔÔ`Ñ¢Eø‡øüùŸÿ¹‡ô÷ÿ÷ʹªª*›Å¶mÛÑ'uˆçGÞ» ½½]©Ëçô¯ÿú¯8wîœÝ¤­­ ëׯÇþçâ/þâ/”ºDpΟ?6Ýϸ¸¸Imlܸñ³úED™xÿùŸÿyâ½w??¿ßLÝ~NŸAEÄ4" `âX~懇•GÃ9 ÄväÇüĉøÓ?ýS«×&&&N)†D@™{­‰‹ð0Wvá›–ÄL‰·ÉQ"ÁëÆ¯)//·»O„“ˆHkïE„AP`¡B|üøQñŽ~€¿ýö[åü7ß|3qNÊå:{½Añ´_#ž!™Bëîîþ™Ê+#+ñDü‰ø°T&‚Êøü¿ÿû¿ÛôžÅÃf,*EhIÌ”ð–)Tyo?üðƒM÷Ôø~ŠÉëíAeeå¤×Ïš5 Ê{Y¼xñ¤2…öö AXAL3LÅÊþýû•ó|m|þÊ•+Ÿ%°¼¼¼&]“››;QöàÁƒIer­µú%(\ â¦eEEEJ™ˆãó"vlyÏ2íf|þàÁƒŸ}O…š¹û2•wÉÇÇgÒùæææ‰2Sî_}õAP`¡6|÷Ýw“~ëêê”óòh|^®ûeìmêÍŒq™\k­~ã×Z+³&p,½gãÀ~1É_õ¹˜Êƒ5•À2}/ÖÌVIA3ƱQtn ã¸&-½½½vÿ˜ÛãÍ‘km­ßÙeS½O{ðßÿýß“ê²'ˆßÜ{±'®Š‹ (°‚øÂ8uê”]?ä¬nï¹5–ét×T¬é,s¦Ët¡q0º-ïÅôžÉ}²ùŸ1AP`ñe!ñ;ö¬Ï‰÷qf Öt–93Kø3¸ËsI#a«2½gæÒMP`A*„üà›þK(c¼xñÂê5¦©Ìm«cºŠPrWÉ*B1YQh-ÁL ,‰93žš“Ø&Ã*BÉ…e+îÞ½;©™~½qãÆ„OV-Zz/¦÷LQ¼^^+i-Ìe€·¥O‚ À"bš°{÷îI?Ä7d¦©du¡k×®µ).H„ÊTy°Ž;f—7f:Ê$åéôœ#!ñÖýÝßýÝgÅRÙrÏ̽[û„  ,‚ ¦’éÜZ|•"|Œ¯û·û·‰2ñ¦H|Ñ¿üË¿L$."Éáô»ßýN¹VL²ºË9ñȘýÇ2ÃK ž=ãLî†)>ñ^RAØÉÍ%÷ðÿþïÿ”8/á-ÂIòlɽ”” ‡ÆÓ§O-Þ³ú§šx@ÉQ¶yóf³Áóöô AXAAXAAAAAAAAAEAAEAAEAAP`AAP`AAP`AAP`ñAA¸¡Àª¨¨ÀÊ•+ñûßÿ³gÏF||<º»»-^ßÑÑØØXeãT1y.½#)) ÿó?ÿ£ØÏ?ÿü›:¦*·÷zWo ‚ 7X111(++ÃØØÆÇÇqõêU„……Y¼>$$çÎS®KIIAhhèDùÝ»w±bÅ ¼{÷N1orÎÖrS8ZŸÚÛlÞ¼yÒqdd$–.]ê4sv}j6r%Wr%Wru?®¦¿“.!°ÌA¼Y–ðõ×_[½^ÄÅãÇ'ŽåyDD„Íå¦p´>µ·gN`-[¶ >>×ËóÞÞÞIõ˜bÖ¬Y6—›{_ŽÔ§ööfB`Ñh4æÊæ¬K—.!<<Üâ5ÑÑÑŠË8+**ЬÏhO>03Á«a Ž7559µ>5ÌøJ¿º{Žeq'|~ù}å÷•ßWóÇnƒeÍãb®Ìøœ¹$9gk¹-1QöÔ§ööƒÅ8r%Wr%WruCÖþýû'Ò, *iŒé”—¬”¸+ã,s«ûúú¬®²³TnÚž£õ©­=Æ`1Î\É•\É•\=@`iµZ%õ‚9sæ !!A–ˆÄgÉ” ¬“ç¦1["Ò¬å²Vn.†É‘úÔÖc°h4Fó°,{S6°=ç€,r%Wr%Wr%WX„ë ,Îý“+¹’+¹’+c° ,z°È•\É•\É•\)°u ,F£ÑƒEP`уE®äJ®äJ®äJE0‹qäJ®äJ®äÊ,‚,ŽœÈ•\É•\É•,‚‹F£Ñh4u¼`Ñ(°z°8r"Wr%Wr%×ÏXæ@E0‹sÿäJ®äJ®äJå4TTT(ûåIFóÙ³g#>>ÝÝÝV_ÓÒÒ‚èèh|óÍ7ðòòBFFƤò¤¤$«[ÅLUnïõ®Þ=XäJ®äJ®äÊ)B7X111(++ÃØØ˜²yóÕ«WfñúÖÖVøúú¢´´T¹^ö- †Q€<:rÜÔÔäÔúÔ|l0Oà+ýêîýi8îèèðˆÏ/¿¯ü¾ªý¸ª¼ ï¿Ãhð(ªSªgìûê¬K—.!<<ܪ‡G„•"´Œ§éÁRŸ‹F£Ñh4G­<µ–|@ç(È(˜Ñ¶Ý&Ëš‡G‚¶M–±€0ƒ$çl-·%&ÊžúÔÞc°ç@®äJ®äªjÓ<@ó¾fŒŒ¢þd=3¹ÛŠýû÷£½½]y>88¨¤0¦S^à.Ó‚"²ÄdºPR;˜®¢“Õ…ÖVÙY*7mÏÑúÔÖc°ç@®äJ®äê*Vr«ý‘ýè[Ù‡âÛÅ6½æåËz ,V«EHHˆ"4æÌ™ƒ„„EX‹)JIIQ®•©Á¸¸¸IAîiÖò@Y+7מ#õ©­=z°8J$Wr%Wruk8Ö x­š4)^,[^SUuNI~USs–Ë‘” lÏ52¹Óh4f«¦¢kMÞ/}²ëe6¿NÄÕØ˜?>~<¥<:Sdq«B•‹£Dr%Wr%WrµÅjÎÖ@¤CëŽVäåäÙ-®ÆÇ˔߱ÑÑGNYX„*ãÈ•\É•\ÉÕši³µhßÔŽáEè¼Xi_ÂÑ‚ûÊ´àøø‰I¿ecc¿(祜‹ ‹£Dr%Wr%WâZq©C!Cx³ñ ´™ÚϪ£¾þŠþ×+Poåø%«Ö ®@ÔÖ&ÓƒE0‹F£Ñhžc²o`kB+t:Ôž©u¨®'ONâãÇeYg*®(°z°8J$Wr%Wru ®o<ÄûeïÑÓÂ{…ÕõôéQŒŒ,ÄÇ×õBë²2-XW÷ WŒÁbœ¹’+¹’«‡pÕ<@ã¡F%ýÂÓ£O®¯©é†‡CPZz‹y°z°8J$Wr%Wrõ<®ÅwŠÑÕ‹w+Þ¡ôV©Ãõ=¾ ƒƒ¡(.¾3í\)°Æ`Ñh4Muöäç' EËÞäiò®ïÕ«x¼†ÂÂ{3òþ]R`UTT(Û¹HÂÍÙ³g+ÛÞtwwÛôZy¹LèIIIV3™OUîìúÔÞ=XäJ®äJ®ä:Vp¿oz‹Á%ƒ(¿Zî„:5hoß‚wï–[L¿@Öƒ²²2Œa||W¯^EXXØ”¯ËÎÎFDD„Žüd>k{õY*7…£õ©½=Æ`1¦ƒ\É•\Éu:¬ê\FŽ m[òsò_u˜—‹·o×£¯o%´Ú¬åê6S„Sm344???e“hS%âBÔ«ò\„˜­å¦p´>µ·GGÄäJ®äJ®Î4Sm[Ûq%"Ë))òrÐÕµ==«‘ŸŸ3ã\]^`‰+55±±±V¯;zô¨rÀT`}óÍ7J=ÆuÊ9[ËMáh}jo1X4Fs–É4ààâAeZP¦"Øò³ÐÛÎÎ/Ö—àåÒK„’ØÜ¹sÑÖÖfñºææf„‡‡Ozi=¦˜5k–ÍåæÞ—#õ©½=z°8"&Wr%WruØÃ¤ÉCËž%]ÚU¯V›‰þþH¼y³A/®4_Œ«[x°.]º4I@™BÊŒ=XŸßž|` fŒÈÈHeÛð!•GGŽ;::œZŸšMÝ™¯ô«»÷§á¸¿¿ß#>¿ü¾òûú9ÇmÚðaåô®êE¶Îiõf`ppè+¿è÷Õmb°¦òð˜3k1HrÎÖr[b¢ì©OííуÅ1¹’+¹’ëggQO|ª$ •ä¡’DÔYõÝÇKÐÚºS\]R`íß¿_ V *iŒ¹)/kSj†Ut}}}VWÙY*wv}jk1X4FsX¥)ÛÜ ,P¶½qjBÒâÛZ„––½ªáë’K«Õ"$$DsæÌABB‚">W` D¤YËe­ÜÙõ©­=z°8"&Wr%WruÄdcfÙ ùE eÃfg¾ÏÒÒ4 £±ñªúÕ-3¹O•²í©?“;sÍ+¹’+¹º>Wm¦o6¾ÁТ!T\ªpú{,+K…N„††cªëWn•C¨R`q”H®äJ®äêÚ\+/Tb8dí›Û¡ÍÖ:ýý=ztE/®PWwÊáºn7Þ¦À"ï”ú6½Ý¤¬ o6P`î/°ç@®äJ®äêB\5д¿II¿Ðp¼aÚÞS]ÝieZ°¢â²Sꯕï¸/*õòèL/AGÄäJ®äJ®ŸÍµøv1úVö¡?²%·K¦íýÔ×WÚËËS?»ŽÜ¼\ÜxxIuIØõ|B‡CqPÿ§¤€Òíwª‹‹` F£Ñ>Oôœ¨W¼VÍûšš4ÔÔž=;‚‘‘…xø0ͦë54Š7êLíìiÙƒŸÞþ„°aðýä‹Ð¡P¬éZƒ¸¶8øŒûàþO ÎôbQ`ô`qDL®äJ®äjW‰¯êŒíć°(O-ŸÖ÷ÑܼCC!()¹mVHÝÖŸO®IÆ>ýuë;ÖcÙûe˜ÿi>B†CÓƒ/wàdýI\-¿ŠœüœI±W‡?žô[æL/Á,Æt+¹’+¹Ú̵ú—jŒàUü+äçäOó{HÀààÝÅâ;H©NÁ¦Øøf#–,Çü±ùX8²Ñ=шã ÇqåÑdk³­Ö{¯èžØnéOÊ)°z°8"&Wr%Wrv®ùYùx÷ÃÁÃx|~úîCzQ:ÎU¥àbÿJõG¤^H-ø¸º@DõFa[Û6}z—*.!³ Sµýê’«¢¢BÙ/O2šÏž=ñññèîî¶z}TTÔÄõ¦[ë’’’¬n3U¹½×»z{ŒÁ¢Ñh4ϱG—a(t:”ììΨ3£0*/àð³Ãˆ{‡ÈþHøë•Øz1uT„£M”k2 2\îž¹¤ÀЉ‰AYYÆÆÆ0>>Ž«W¯",,Ìâõ±±±(//W®ÕétHLLT—†ÍŽe£ck›![*7…£õ©½=z°8"&Wr%W÷4xaÂê7ÔO:®;]÷YuŠ—ébÅEÅë´µm«â… ÐÀï£"ú#°¹}35¹ÇçQ|oßþ„^ý5Ú)¦ùÔÞ¯n3EhÏþ|"´fÍš5q,âBn®ò<""ÂærS8ZŸÚÛc c:È•\ÉÕÖVÔI,’a…œŸêµYÚ,\~tÇŽ)ñP«zV)ñQ Æ(ñR7%ñS¿Tý‚»z!eúúüütwÇèmò|&øž=[£ÿ½û?¿q„… ")©ŽËX,¥¦¦*^*[QZZ:ɃõÍ7ß(õ×)çl-7…£õ©½=z°8"&Wr%W÷X‰ú?Xòh*°²ó³•y'êO(+ôVw¯Fðp°²rOVðÉJ>YÑ'+ûd…Ÿ¬ô›ª]ñV‰×J¼Wyy¹3&®/þˆšš_ÿêëÇ:ê4‘åÒ뫯¾Rlîܹhkk³é5--- BGGǤzLaìᚪÜÜûr¤>5·'ƒ#22RÙþùÈ#yÌcóØµŽEH½‰xƒùç+ÙÍåQŽåüºþuX4´HÉ%µB·›û6+9¦®<¿‚ò¶rT>®ü¬ökjJ12ƒžžxý±fÆøFE ¶vòo\CÃ',]:â”ú݃uéÒ%„‡‡OymUUüüüÐÜÜìT=Xô`‘+¹’+¹ºº==úTIº³n'víRþ·ÇÇ+ù¤$ëùéºÓJô\'z˜ Óñþý2¼zµÍ)õefjqûv1®]+ÇùóqútŽêyíßߌ;Z±eK;~ü±S/®zõzÀüï8=X¶zxZ­ÞÞÞhll´)†IÎÙZîìúÔÞc°ÓA®äJ®îcEw‹Ð³ºËšŸ ïò¬Žý rÕ|Š8u¾‰v‹îbpp±’ëÊø|vv>îêßÓõëe¸p¡gÎÔàøñ<Ø„„„ˆ‹{uëÞbµþ=/_þ¡¡CÐ ÃyóÆ1þ‚ƒGö+Wö!6¶ ›6½A|üKìÝÛ‚ÄÄg8uª))UúòÑßx°ž=ƒâÁòXµÿ~´··+Ï•´Æ‚ÀtÊ+-- ^^^hmmµº OR7X[eg©Ü´=GëS[{ô`qDL®äJ®îɵþd=FGñ|÷s­?Šye»°h™nBxˆàã¨tû6WÎÍÍý{…úß߇¸|¹ÉÉÕ8qâ jÄn}[;w6ëS6nlÖÿþôcÉ’AéàãóI1y¾dÉ¥lÍšnlØÐmÛ^aÏžç8|¸Q©Kꔺ¥ôôB¥M{Þãùó z15>‰kXØ'ÏŽÁoTHHˆ"4æÌ™ó›¼V¦Ä«ejÆ‘f-”µrs1LŽÔ§¶ö˜‹F£ÑÜË õâ§km—²Õ̓;°ºg5ÂÞ‡!0¶Ý¬WÇe7N]+Ôÿ>Ô)^ ñmßþRñ­Õ×#Þ"ñ-\8¢x‘Ä›$^¥ÐÐAÅË$Þ¦õëß".® ûö5èEѽ8ÊV¼S/V*Þ*ñZåLsfxs"+:zT™ Õ¿Ÿz®"tVʶ÷y ‹\É•\ÉÕ5MòYéuhÝÙŠ“u'8ˆÝÏw+±UŸÌþÏ÷ñV­êUâ—6o~ú×J\ÓÑ£ HJªUâRSË•ø§L+‰HË˯A§ B}ý ·ïWn•C¨R`1¦ƒ\É•\ÉÕ¹VQ€·ëÞb0tÚ4-Öv­E؇0\Ó‹)×hòôÿËÍÇ%-[¦s¸ýŠŠËzq ¯?É#ú•‹ ‹#br%Wrus®5É5¿nмíÎTŸQöõÛÙº9y¿&ôLI©Vbž–.ý€°0çÇ%=~|££¨®Nñ˜~¥À"T)°h4æ¸É¾o6¾Áð¢a]+º·ë:ŠË¿­KìStt²ïÌ™ZåÜ/¿Ô)9¢œ—TS“¬ˆ«ÊÊ uï)°z°8"&Wr%W7äZu® ÃÁÃhßÒŽ”ÊaÛ«mJ&öôô"ýÿñvŽ*+ûÌ­Às׺ºSÊ´à£GW<®_)°Æ`1¦ƒ\É•\݈k~V>^ǽÆÈ”],Sö\4¼*/(9¦öìi¿ÿ¨² ðþý‚iãÚÐp #zQWVvÝ#û•‹ ‹#br%Wru®•—*1´h:p±ü¢²Gà–ö-ÈÌÏÂÉ“õJNY xëVÉ´rml<„a}Û¥¥iÛ¯Xc°h4ÍÅ-?'/·¿„.H‡Š” ĽŽÃ‘…ø¥ê%ú²eJ>ª‹+¦ý½´´ìÅÐP(Š‹o{tŸP`ô`qDL®äJ®.ÌõÑ•G\<ˆÎ;qµäª²!ó†Ž ¸z§kÖt!8xXI:\[[wàÇ%(*ºçñýê’«¢¢BÙÎEnΞ=ñññèîî¶úš¤¤$«™Ê-÷´öƒE®äJ®äúe-/7/^@ CÕ™*l¹Aº œ|xÛ¶µ)qVûö5vvtû¸jðúuÂQPÁ~uUƒ²²2Œa||W¯^EXX˜Åë {íÉ>{ÖöâûÜrOk,ŽþÉ•\ÉõËZÙµ2¼_úÝkºq£ð.Flûzì9Ü lQ#"gdÎ×¼< ::6 ¿?Zm&ûÕݦ­m#âAnžò<""ÂiåžÖc°h4í y­4yhÙÛ‚Q½ˆª;Y‡„ Ð`ûÕ„„ !&F/¸n<œ¹÷“—‹ÎÎXôô¬B~~6ûÈ–x°RSSkñšo¾ùF¹Îø5rÎYåžÖ=Xý“+¹’ëÌÛC½pX>€Þè^ÜÊ¿…¥ï—"²ü0Â#{±té{œ;÷xF¹Š êéY®®µz¡•Ã~u'õÕW_)6wî\´µµY½Î³fÍrZ¹§µÇ,Ư+¹’ë šæš6aÔ G°·e/üÛWay\#.Áñã Ðhf–«V›…¾¾•èèX§L²_ÝÔƒuéÒ%„‡‡Óƒ5íÉÆ`ƈŒŒT> †Q€<:rÜÔÔäÔúÔ|l0Oà+ýêîýi8îèèðˆÏ/¿¯ÓÛ^ÉÍ|ˆþ€á5ÃÈ+ÍCxçj„ž~€€ 8|ø ²²ògüûZSS‚‘‘htwïP‚Ûù}5ì61XÖ<.æbŒäœ³Ê=­=Æ`Ñh4ÚôÛ³#ϯUã¡FxzóïÅ‚àAlÜøwïMK›ðò²hR^Xx>,ÅË—ÛÙGîèÁÚ¿?ÚÛە烃ƒJZcA`:åeX%×××guÝç–»{{ŒÁbü ¹’+¹Î×â;Åè]Õ‹wËß!3+KòOÀwE"¢;qíZÙ´¶­ˆ)sП/.¾£ÿÍ Åóç»Ù¯î*°´Z-BBB¡1gÎ$$$(âÀZL‘ˆ0kyž)w÷öƒÅør%Wr® Ç”‚²RpWÞeÌÛR‹Àð$'WÏ?kK¶¾ij:È~õäLîÖR6°=frçèŸ\É•\ÕÆµè^ºcº•ÜVw®"h)æ-z‡Ý'« ÑäÍP0½ÆºÀŠ FßÊ•ú÷ƒ·ëÖ¡}˼ܾÏwïFÓÁƒxzô(êôôêädT^¸€òk×Pzë ïÝC~¶úR8L5JE¸¥À¢Ñh4O±ºŸë”lìÏv´bMb¼ƒß#2±™YÚio»äömEuþø#Fýý­ ¬GW¯âñùó¨9sONœÀ³ÄD4ïß xµmÞlÚ¤ÔÓ³z5úW¬Àû°0 /Z„Ñ€|òñÁø¼yøè燑… 1¸d Þ-_ŽÞU«Ð‹Ž ЇÖ;Ѳw/Fýñã¨MJBUJ *._FÙõë(Ö¿ß‚û÷‘—›;­Þ: ,‚,ŽˆÉ•\ÉÕE¹f*û~X2ˆãûžÂ'´~{"%'}ÚÞ¿63SH¯õbf(4T/ìðvýzEÌIìí4ŠE"ŽD$‰XÑ$âID”´/¢JÄ•ˆ,["ºD|‰1öA/ÊF‚ƒ‘&bMD›ˆ7q"æDÔ‰¸‘'bODŸˆ?"E w‰®\¡À"ÍLJaèëûããúÿêåøï^­?y’âv}IE0‹F£ÑÜÀªSªÑ¤ÃÁ°X8Œ7/`ÛóÈÉÏqP´ÝGÝéÓJйL—é‚‚”é5™“ó‡o ¾þ8ÚÚ¶âÝ»Œùbpp1::Ö£±ñ**."??ëÞµÚ‹YgÝV\Q`ô`qDL®äJ®.ÎU›¥ÅËMopÍï#|ÄâÄ"„tEâRå¥ÏŽe’Uz_$±I2í'±GM úîY½ ú¯^mG¤^L-ÀÐÐ"¼}ûššöëßÿhµ™SOaêE–^i¸­¸â*B‚1XŒé Wr%WæúøÂchF±dþV¬{‰ÀÖµˆk‹C–‘ÇÈ{˜–†ÆC‡” õ‚Jbˆ^ïÙ‚wwáÕóxôõEáãG?%WUgg,š›÷¡ªêœCqS/_Ö³_)°z°8ú'Wr%WõpÍÏ·öÇNÄú|ŠŃX£=ƒ`½ø9÷øœ+ 3”œR²NÒŒ¡7> ]·Ö¢ïåJŒŽúcdd!ººÖ ¥eª«SPX˜Á~UW ,‚1X4æDËMªÃîcXì;†ÝgK2´›ÞlB¦•©¹¼œ%}@ëŽø°< c~¾Ú¼®-Áè ètèî^/v£¦æ,ŠŠîñ^«Ü\R`UTT **JÉh>{öìßl•c Ù%;66ß|óbòܰ—¡IIIV·Š™ªÜÞë]½=z°È•\É•\'[æ½BYþÁ^@âúvÄ=߉ ‘ $W'›½^rA=?²?†ã“Ÿ>®ñÃØùùøX³=QhmM@míe@ö+=X3Hååå׫zÁe ²oá¹sç066¦XJJ BCC'Ê ›ËFÇÖ6C¶Tn GëS{{ŒÁbü ¹’«§r5—”››‡ñ/2o‡B†q>çB‡B±îí:Ü7Š*ÍLCë¹x¿s>-òÁxø<|:îƒ÷Ùah{º uuI()¹Í~e –z BkÖ¬YË¿þúëßœ3ÞÏOÄ…¨WäyDD„Íå¦p´>µ·GG‰äJ®žÆõìÙDFöÂß_‡ðð~$%Õ)çÏ$Õb©ÿ(¶ùŒ#gÿ3ìhÝ@] Î<9ªòshOß„Áã¡ø´jä…Ñè½¼ QZš¦¯CÃ~¥K½«´´ÔªkãÆŠ×J„˜Xrr²rΙ6”óÆ‚MÎÙZn GëS{{ŒÁ¢ÑhždÖ–óGù~B^xeVýŒˆ‘@œz„÷×0¾Åãþó [„®ã±xróò4¹¼ŸŒÁrÕÒÒ‚ IªÖÑañš®®.øøøà«¯¾RLž÷ööN”Ë9S{Ħ*7…£õ©¹=ùÀÌ‘‘‘Š‹Õ0 GGŽ›ššœZŸš æ |¥_ݽ? Çò?É>¿žð}µ–r°i)æÎCÉAoèB| [ˆÞ=›ñöîTëÿü¾zî÷Õ¥VUUüüüÐÜÜlõºèèhŃeƒeìñ¢K},Îý“+¹’«LòHYXáÞx¼3Õ'(›³_ÉÕå=XZ­ÞÞÞhllœòZsÞãsæb䜭å¶ÄDÙSŸÚÛc ãÈ•\=‰«5u¬þ(û•\ÝG`¥¥¥é?×^hmmµiÊLV JÜ•q –¹U„’êÁÚ*;Kå¦í9ZŸÚÚc FóD“M‘ÓÒîNûžu4Æ`©F`b©LÍ’ikk›È›%&Ïåœ1$÷“µÎ[’_R°l`Võ¬ÂíâÛìWru-õÝwßáãÇ¿9/çæÎKåBÅ‘¹’+¹N«=ztééÉ8à_ˆáy‹ñnÙ!lØ­x­Ž5c¿’«k ,™ ´$°ƒEE£ÑhÓeùù9¨«;„ýñÅ(]p£óÂQzö,–¾_ŠÕÝ«q·ø.ïÍuÖ·ß~‹ˆˆeZÐø³»»ááá˜3g• GNäJ®äêt«¨¸ŒÂÂ#ØX‚ó–b l?ÔïDàh Ž×g¿’«{Ä`Y rÏÍÍ¥r¡ÀâÜ?¹’+¹:ÕkÕÔ´'gáÁüãõ^‚²“§ö! kºÖànÑ]ö+¹ºO,QвÕ!³º<¯­­µùõ™ÙgÏž„„„IAóæÐÒÒ¢lú,›K{"ôŒ‘””d5“ùTåö^ïêíуE®äJ®jçZQqUU;°gÑCô{/ÇÀ¢]8ødt8ùä$û•\Ý˃å ÄÆÆ¢¼¼\™^ÔétHLLT—%Èž…¾¾¾(--U^#bìСC冽ød>k{õY*7…£õ©½=Æ`Ñh4uÇZeéÿïÇãâ/7ás:¯Åxtì– .ÁÚε¸WÈÜU47ŒÁšˆh²–CkçοñXCÄ…¨Wc›Ä‰ÙZîìúÔÞ=X%’+¹ª•keå45mÀþe%èòŽÄÀÂx¬Ù†@] NÕb¿’«ûz°dµà÷ßïÔLî♲æÁ’Àú›7o*íÊ´¢˜(—iCiÆ‚MÎÙZn GëS{{ŒÁbœ¹’«Ú¸jµÙxõ*wnžÃ-ßóÐy-Âã#Ç:ŠŸ:BFaû•\Ý;ËÇÇg’ 2¶ÏÉä.±UAAAèèè°šb÷îÝŠ¸“)Å={ö`ëÖ­“ÊMaü^¦*7מ#õ©¹=ùÀÌ‘‘‘ÊÔ0 GGŽ›ššœZŸš æ |¥_ݽ? Çò?É>¿jø¾65¥éïw,W¡Ý{5ÞmÃé–}X8º§kOóûÊïëù¾Î¸À!嬌íUUUðóóCss³ÕëÄ#ÂÊØ‹&ž,z°ÔëÁ¢Ñh´©½V™xýz3äCêü«ñ Aõ¾#X4´ë:Ö!£ ƒ÷‰æ91XÎÚoP«ÕÂÛÛS^+AÛ¦ËX@˜‹A’s¶–ÛeO}jo1XŒs WrýÒ\«ªRÐÓ³§6<@«w,Þùo¡Ǜ4„³5gÙ¯äêy1X’"AVª9‚´´4¥YhË”™¸Ë´ ˆ,1™.ŒÿÍ*:Y]hm•¥rÓö­Omí1‹qäJ®jáZP‰7o6¡¼l./HðW0j"d8ÞlÀý‚ûìWrõ̬²²2N™·Ê,%*µS”’’¢dŠ—©Á¸¸¸IAîÉýd-”µrsí9RŸÚÚ£‹£Dr%W5p­®NÆû÷‹ñËÎL<óÞ€þ?áHù,Yˆd}û•\=ÚƒeI9²ŠÐÆñU3wo1X4íKZAÁ}ttl@CC.ù߯x­¶íCÈP06µoB¦6“÷‰Æ,Ó•ƒŽ®"$ÜS`qäD®äJ®b55g0¤R׎ÜAwúæ¯EbÙ:#¥*…ýJ®ô`Xœû'Wr%WÛ½Vxûv½¾îq)ø.½BP³iB†bËë-ÈÒf±_É•1XGNäJ®äj«ÕÖ&A§ ³×ñØ{ú|¢q´øG,^„óϳ_É•,K¨©©QR,È” ˜<—sFó\+,LGgçxó&W–¤ã½×"Ôü¸ !ƒAØÚ¶ÙÚlÞ'c°,A6i¶äN‘EÅ‘¹’«gr­«;.9×.¢lÞ^ôÍ‹Ä m¬’4ôBåö+¹Òƒ5Ä[ƒÞÞÞ‰sò\ö”ÜVçþÉ•\=‡kQQ:ººbÑÓ‰ë+ÒÑïµ5«wbч@l{µ ÙùÙìWre –-)Aɤnб±1U¤ èÁâ(‘\Éuf¸>yr:] ï%£Øç0úæ-ÇÏ9?*4_ª¸Ä~%Wz°ìXÆÛÖ`º? Á,æžVTtÝÝkÐß¿7cî£Ç+ 5‘;:€/w '?‡÷‰Æ,{áãトˆý—«[ÙTXLž‡……)Ó‡GNäJ®î˵¾þ8FGQžw …¾ÇÑï½§îþ„%ƒKpùÑeö+¹ÒƒåÈ BKAîOŸ>µ©ŽŠŠ %fK<^³gÏFBB‚Í[ïÈ>{æ¶šIJJ²ºUÌTåήOíí1‹\É•\íáZ\|==«10Ž»2ÐåŽÚeÛ±¤?;[wºŒ×ŠýJ®ªNÓ BJ¼U"Ää¹­âJ«¬Fï—L7&&&*‚k*dgg+Þ3K›%ËFÇÖ6C¶Tn GëS{{ô`q”H®äj׆†£ @uéq.8…wÞ‹q:u=Â>„ájùUö+¹Òƒ•&¡5Õ6;CCCðóóC{{ûo–ˆ ¹¹Èsb¶–›ÂÑúÔÞc°h4š-V\|½½ÑŠ×*3>^+PºËz‚°ëÅ.äæåò>у¥fUZZ:¥ëèÑ£HMMUž› ¬o¾ùFiÆ‚MÎÙZn GëS{{ô`q”H®äjl55%&ç4xúôˆâµª­<‚Bÿ³xçŠä”MXö~RËSÙ¯äJ–³V~~>âããs^â¨ í®¯¥¥AAAèèè°xMss3ÂÃÃ'ŽM–¹˜,cØTå¦p´>5·'ƒ#22R™Ã6|HåÑ‘céOgÖ§æcÓGwæ+ýêîýi8îïï÷ˆÏoUÕ9ý/tv¦+Ç%%·ðþ} FF¢Qt$¯½VáIÈDt.‘7G¯¿¯ü¾zÂ÷uÆÖwß}‡ßœ—sßÿ½]uUUU)Ó~" ¬AÄU[[›EAA=X%’+¹Úo"®>} Ðÿ8«ÿ¿ˆ7o¶atÔ µ‡Q´ð¼!åDÂÂq½ì:û•\éÁšNeÎ[bÀ×_ms=Z­V Žoll´©Msf-IÎÙZnKL”=õ©½=Æ`Ñh4ÈÎì¥÷Z4lÄŠÖPìkÙMž†÷ŒÆ¬éX’Àx›$–¤\°iiiʶ:­­­v‹8så†Ut’êÁÚ*;KåήOmíуÅQ"¹’«±ÜÿUL™ƒþüÕcqXþn9n<¼Á~%Wz°fJ`ɱxª^½z5‘hT„’ˆ†©V®ÙꑲW` $÷“µ¼wï–£·7ÊcæQy°z°8r"Wr^¯UKË^%¯•ä·*Ú—A?ÃäJE¸¢ÀâÜ?¹’«:¬¬,ËÐÓ³ ÅE·ñxÙ/è÷Zdu!û•\Éõ ¬›7o*ù°ŒÓ2È”áÛ·o©\(°8r"WrU…×*ÏŸïQ¼V Ç ½š…ç¾Ñ0ÿ'DU¯…—•¿{E÷دäJÖL ¬¬¬¬‰ vcUQQ1eî%‚1X4mú­¼üÞ¿_ŠîîÕ(.¾‹²ixç½×bö"®%YùY¼O4šÚÖ?ü€'N(錖¬ ´5AGNäJ®ÓáµÊÁ‹»0:ˆúúãÈËÉÁ“ʼnèò^Š­RÂ~%WrU«À2U¦™ÛíÉäN0‹sÿäJ®Î³G®âÇ0tu­AQÑ]_¼‹vßh< ØŠM¥»‘QÁ~%WrU³À’M„GFF~#¨$MÃTûßô`qäD®äê\ËÏÏAkëNètxòää¯ï}Ë x#iÃaœ¨:Í~%Wru%Áì‹/V¶Ë566¦ì'(Â+$$Ħ:$^+**JÉ¡%ÓŠ VóhÙr}RR’ÕLæS•Û{½«·Ç,Íõ­¢â2— ³s- ïA›™‰ÆEñx9o%¶]HÄíâÛ¼O4š«,ö8æLöÁ³±±±(//Wâ¸t:õ¹×öâ“ö­íÕg©ÜŽÖ§ööèÁâ(‘\]›«x­^¾Œ×ÿ? D]Ý©_Ó1œIC·ÏRdïÅÁgíÚê†ýJ®äª’4 "²Œ3¹;š¢A„“xÀ>÷zrs çÆû"NUn GëS{{ŒÁbœ¹º.×ŠŠ‹ EgçO(,ÌÀÕëŽãݼÙ|× ÓØ¯äJ®L4ú+JKK­z°¦º^b¿Dt 0ãx°©ÊMáh}jo,ŽÉÕõ¸æçgáÕ«mÐé‚P[ûk\UQz:ž‡Ä¢Þç'ìM¾„œ¼ö+¹’+Ö¯hiiAPP:::>ûz™ž4Œok¹)­OÍíÉÆ`ƈŒŒTF†©<ò˜Çµ·Ç,Æ9«ú¹>~|ÃÃ!xóf îÿ:%x3 ¯‚#P6?'Of³_É•\Ý)K<#²’Oðý÷ß+ª¾¾^ñ*ÙšÉ=-- ^^^J°¼-SfS]oXE'©¬­²³TnÚž£õ©­=z°8J$W×áªÕfâõëÍYˆêêä‰ó&bÀ')‹/àæö+¹’«»y°ŒÅÄùÈñÇíÊän)̓%2ÕõÉýd-”µrs1LŽÔ§¶ö˜‹Fs «ªJÁðp0ÚÛ7)BK nÏÊDÍšX´ùDàÈOh²óy¯h4w̃%?àâ±zõê•"¾ýö[å¼xµ¤ÌÔ3 wo,ŽÉUÝ\ 2ñæÍ&E\‰ÈšðfÝHÁÛ EÈäý¢Ñ<=–5H|VBB‚’á ‹#'rõT®EEéèêŠÅààyr:]Z[wNòZ¥ëE×+K1° ?û<ÀÍCÏØ¯äJ®ŒÁú#d[ĦfëV9±±±(//Çøø¸’>11ÑêFц½ödŸ=k{ñ}n¹§µGG‰äê|®EEwÑݽ>„éÿ¿]Tváá Tl Àsßh x…œ›Ù¯äJ®ô`M†Ï$Ael‡õ9¡eíµ"äæ Ïã¼-÷´öƒE£9×êëct4P?ŠÞ…¼¼Ü‰ó™ÚLœÖ®FÏB?Ü›—Œ³Ñª˜¤Ñh*X"¤4S§ KKK­z°$=„ˆ0cA&çœUîiíуÅQ"¹:‡kqñôô¬Æû÷ËP^ž:©ìbÅyÜNñGÿü…88¯·Ÿ²_É•\éÁ²ŒÏõRYBKK‹’SËZSñ–Y{Ž–{Z{ŒÁbœ¹:ε¡á(FGðüùžI^«œ¼$VmÁ³5~xâ»ûº}³„ýJ®äÊ,ëœWçã TUUÁÏÏÍÍÍV¯£ËyíÉÆ`ƈŒŒT> †Q€<:rÜÔÔäÔúÔ|l0Oà+ýêîýi8–AŸ¹òââÛX n•^deM*ÏÒŸxŒ÷þ¸â}Ö÷»_~_ù}u×ï«#Ç3.°ÊÊÊ”¼WS­ú› Z­ÞÞÞhllœòZs1FrÎYåžÖc°h´©M6cž|Nƒ§O(^«––}ÈËÓü1i¨¾ìpý^ä]€žùK°Ó»wŽq/A1XvÀÜêA{W¦¥¥)ž°ÖÖV›¦Ì «äDÔY[E÷¹åîÞc°ç@®öYUÕ9ñ×£¦æ¬r\RrKÿýŠÒ¿–ãáÓ®½]| uËÑîrßØÔœ[%ìWr%WÆ`ÙänÉlϲ$ЬÅIn'kyž)w÷öƒÅ8rµO\ùc|ü >} @{ûfŒŽú£¹ù€âÅ2¾öDý œM_€ÁþHòÖ 9¶“ýJ®äÊ,õB²=frç(‘\¿”¸úø±äߌj½Ðš§O']—Q˜-/Ö b‡?ÞÌ_…ÍÞ¯q÷d=û•\É•,ÂÓÁ,í·1W2-øéÓq“oËyå¼!&ë—ê_°½Úý!È›w»~@ÎÝ"ÞC1XŽC6x–u™“çrŽ Àâȉ\]Ùªõâi|Ü_ÿ(G½þïWV ž›bllLÁÛc°h4[M2°¿zµÃÃ!xôèʯbÊôç·{?Ãùõ¼o4c°¦O`étºßœÑEEÅ‘¹ºŠÉ>‚ïÞ­@wwÌD»5•~¦–ýJ®äJÖô ,DDDèÿ)u+[²ˆÉó°°0eú ÀâÜ?¹ª?Ã/úb š›÷MÊmeM`±_É•\ƒ5­KÙ-¹?}ú”Ê…‹#'rU±iôÿˆwcd$••&•%Õ%y¬Àâg˜\ÉU%iDH‰·J¦Åä9Ŧf+,LGoo”²åMQQúÄùÌ‚L¬ïX“9þVÖ½¢{¼4c°¦W`9 sÛãXƒì’‹o¾ùF1yÞÞÞ>隤¤$«[ÅLUnïõ®Þ=XäêI\++/add!Z[&mÒ|þñy¬z³ƒÑã¿Êê*Bö+¹’+=XªXÆBË„„„àܹsÊJE±””„††N”6;–Ž­m†l©ÜŽÖ§ööƒÅ8OâÚÔ´:]ª«“'Îåäç`û«í8‘ë‡á<ð½Œ5 t¸{® gÏÖè¿Oƒ˜?_¾:œ9SÏ~%Wre Öô,B²™³©÷ÉÔ ×8[`™«×xÅ¢ˆ Q¯Ès Ä·µÜŽÖ§ööèÁâ(Ѹd¢«k~бÅÅ·'Χ–§bu{(j·¡Ïo¶x?Çñ˜näæä±_É•\Éuf–IÏ`xnÉ ×8[`mܸQñZV-&''+ç iC9o€<—s¶–›ÂÑúÔÞc°hînååW14‚¶¶­J®+9§y Á¾æ}8T¸ƒþ(ò=‡èù#¸•\Í{F£Ñ~ DgçÍ?ŽjŸ<À–îTì €ß2Ä{=CÒÆ!‰ýô„Ï/¿¯ü¾ºÃñt|_=B`EGG+,ã,Ùš‡,õz°8÷O®3mZm¶þŸì:|ø°¥¥iç5ÃÞÒx¿Ðå>§5×ÏÖ°_É•\ÉU],kqVÓƒeÎc|Î\ ’œ³µÜ–˜({êS{{ŒÁbœƒ»q}øð—àÍ›ÈÏÏVÎ¥¦cã«ôÃ{¿%Øí]‡}Ñ=ÈÎÎg¿’+¹’«ë¬§ ,Óó²bP⮌c°Ì­"ìë볺ÊÎR¹i{ŽÖ§¶öƒEsg{òägŒŽ ¡áØÄ¹³5g±«Âïù£Ú÷8VÎÿ€«§ky¿h4šú–µÕƒ›jZÊZ]ÖV[[›2%hHl*Ïåœ1$÷“µ^ùmªyøùÈ3Þ+æ>1XòC,žªW¯^M$þlmmU<[T.X9‘«C&ì##ÁJ@{^žçŸÃÅ4? ù-ÀuŸ Ä.{;wŠÙ¯äJ®äê^,‰µ²”htppÊ…‹sÿäúÙÖØx:]€’Š!'?Gª6àÙ:_´û­E̼v=ØÈ~%Wr%W÷ŒÁ2LúøøLdV÷õõU¶i±'ŽË\wkhiiQ6}–lñ^^^ÈÈȘTž””d5“ùTåö^ïêíуE®jâ*ÉB;;cõ¸p””ÜÆÕò«¸p;ƒþóqÇçV‡½ÇÍ›%ìWr%Wre,Gæ!S"âJKK•)Is‡š(7ìÅ'ûðYÛ«ÏR¹)­Oíí1‹¦&“mnd»›×¯ãð ?'*ãQ»Å«ëó ‡ö5C£á}¢Ñhnƒõ%ÖÎ;ã±2†ˆ Q¯Èsãx°©Ê]ŸÚÛ£‹£Dµp• še£fÙ°ùVé-œ¿Šó‘é{«–¼GZÚCö+¹’+¹zŽ+&&F™ª3Á²7Mƒ­ëÛo¿ÅÍ›7•<[2%)¤sqÉ{Ï–òÜxãé©ÊMáh}jo1XŒsøÒ\óó³ñæÍ|ø°ÞÀ™GûQïƒÎ€åØàóûv?‡F“Ç~%Wr%WωÁZ»v턘2XöîSh«À’ëvïÞ?B§ÓaÏž=غu«ÕzŒßËTå¶¼/{êS{{ô`q”ø%¹––¦é…U::Öã~É-œOÇ@/4óS¹è=RSËØ¯äJ®äê™y°ÊËË•ç•x“~úé'ܾ}{Z–xcDX BKgΜiX´m*°Œ„¹$9gk¹-1QöÔ§ööèÁâ(q¦¹æåå ­m+††BPTyÓW¡?Ä…~?#"xW®¨ Ý€ÿn$%Õ²_É•\É•¬ÏÍ]%۱ȱaõ ½y°Æ`qîßu¬ªêêá…¦¦ËÊñ³g‡ñ~(ŧÂ04I™ˆ]Û…ôôBö+¹’+¹2Ë^Hž%ñX½zõJW²³@¼ZRFP`qää^//‹Öí‹'‹cé߉'ž°_É•\É•¬Ï…üÇ]EGG+çE=.^¼˜Ê…‹æŽËôçYx«£{p÷nïFc –£0$õ2úÇëë뫬0$(°8rr¯vk+)©’ýJ®äJ®ô`A%y°,m‘c dŸ=s¯KJJ²ºUÌTåήOíí1‹\áÁb¿’+¹’+c°T$°ÌÌÛ‚ììlDDDXÜ,Y6:¶¶²¥rS8ZŸÚÛ£‹£D[­´ô–Ç ,~†É•\éÁšQ%+ éLÍÞU„ö¬¡¡!øùù¡½½ý7¯q!7×y.BÌÖrS8ZŸÚÛc Í«­=Oü¤òèȱ,xpf}j>6}te>uuùxýb)Z6ú iùR¬ x‹Ã‡ŸáêÕ¬Z¥ÃüùÀÒ¥#¸té…Û÷o¿G|~ù}u_¾Ò¯žðù®ïëŒ ,{½TÎX"®ÚÚÚ,¾Ž,z°8JtF"Ñ_ð¬tÞ-òÆýÈD, •+دäJ®äJÖL,IÍ Ô3)°ÌÅ{¿Ö\ ’œ³µÜ–˜({êS{{ŒÁ¢M6 ZšP—äƒîžØV†˜˜nî#H£Ñƒ5“«¬¬ èëë›65•ð²´ŠPÞ“µUv–Ê]ŸÚÚ£‹£DKVX˜ŽõËÑ35Ñ+°,°ûö5C£a¿’+¹’+=X3*°,y“ìYEhÍõ9K ¹Ÿ¬å²VîìúÔÖó`1׌9«¬¼„'Y 0ì›1g4‚ *Ù¯äJ®äJ®_*ÈÝ’9+>ë÷¿ÿýŒæãr÷öèÁâ(ÑÔžÖîFÃyh˜áÕˆŠêCzzû•\É•\ÉÕî+°hê´‚‚L<-‹@W¸Ê×Ç`ÉÂ$$´B£Éãý¡Ñh4 ,‚,Žíµ²²Ë¨Io\[w :$'W³_É•\É•\Õ"°bbb”4Žfr'ÜW`qî_]V÷hš·zãyŒ?¶E5`ùòw¸}»˜ýJ®äJ®äªµvíÚ 1e*°œ™#‹ ‹£DÇM«ÍF­&}‹½P¼}BC>`ëÖ6äææ±_É•\É•\Õ$°d•ZyyùDÀ»```?ýô“~D|›Ê…‹¦{X|µ§}Ñ»Ä —·ÝD@À(Nªã½¡Ñh4µ¦i0÷\²‡Ï™3‡Ê…‹#'X•v^Åzãéæ l]ÛŒ¥K? -­”ýJ®äJ®äªfeÈä.é´Z­ò\2‹‹sÿ_ÖòósPu3!^(Ø¿K– bãÆ7ÈÎÎg¿’+¹’+¹ªY`eee!!!Ay.Ýc°¾ÿþ{* ,Žœ¾•ä_Ó>èˆôÆå½÷”)ÁcÇدäJ®äJ®®–¦all ?üðƒâ¹š;w.>~üh³Ì\wK¨¨¨@TT”â1›={¶"ðL·êIJJ²šÉ|ªr{¯wõöƒå^ö(c7:Wx£v÷"lߨ‚ÐÐ!\»VÆ{C£Ñhž˜ËV«ÖKœ—N§Cbb¢"¸ 0ìÅ'S—Ööê³Tn GëS{{ô`¹Ñ(Q“Çç–b`‘7´'wéûq?þ؉ÌL-GÄäJ®äJ®®$°œge«À2…-ã”".äæ Ï#""l.7…£õ©½=Æ`¹GœCQæ4mõÁËØy¸r< £8t¨‘1äJ®äJ®®(°œ¹Þç ¬ÒÒÒI,Iz*¢ËX€É9[ËMáh}jo,×%–]Gß/<>¶;·· 8x—/WpDL®äJ®äêªËËË ƒƒƒ_L`µ´´ ((Vë1öpMUnËû²§>µ·Ç,¶œlTUÄUÁùýˆŒìÇêÕ=ÈÈ(佡Ñh4WX%%% HÕ0“«ªª ~~~hnnvªÈ“5lºÛ{Z|_™lÜæƒ»—‹2†ÄÄ7Ðhfޝô«»÷§áXqžðùå÷Õ}ùòûêØñɃeÉìϲG`I¾-ooo466ÚÃ$çl-wv}jo1X®çð0e³È^™²{öˆW‡óç»%WƯ+¹’«GÆ`‰ˆ²döîEhI`™žOKKS¦&[[[­®Â“Ô ÖVÙY*7mÏÑúÔÖc°\8Î!ó>êö,ÄÛ^(J;ˆèèeZðîÝ"Æt+¹’+¹ºk,gzÁ¬ ,K3cHî'ky ¬•›zŽÔ§¶öƒåšV”šŒ·‘óðä€/n^Ñ 8x;v¼„F“ÇûC£Ñh̃õeW*²=z°\qäT~òGe»›ª[ËqèÐ3èpöl GÄäJ®äJ®ž˜‹{ºƒ¥N®ywïàÙ–¼ŠõByÎaÄÆv"<|·o—0¦ƒ\É•\ÉÕÝc°Ìa``€‹‹#'G¦Ï@ï/Ôž™»·²”ínââ^#''#br%Wr%Wwõ`Y[=h°©’[ž#°hvx­4TˆBßb½¸Ê]ŽãÇ딚þù ïF£¹{ –a¥ !ƒ©Ipujj*• GNvX~Úu¼X;Í[½Q]r6¼Á’%pãÆCŽˆÉ•\É•\=)ËÞT c°8÷oÞŠ“öc Ä5× óþ=„…}ÀúõÈÊÊgL¹’+¹’«§Å`X99È535;—¡+Ü OË"pæL•2%xôèSŽˆÉ•\É•\™‹ À¢ÙkÚ«ð&Ò çáIÕ~lÝÚ†!\½ZÎûC£Ñh̃EP`qäd/×ÒÄmÊ”à“¬ÈË»…åËßaíÚ.dfpDL®äJ®äJAŹ{¸æ¥ßCæ´Åxãy}8Ο/W‡8ÐÄ8r%Wr%WÆ`9–¶»±†¤¤$«[Á8Zîiíу53\ ÎBOØ<Ô&ÍCÓ³]عó.Á¥K•%’+¹’+¹Òƒ5}BË63–Œ­mvü¹åžÖc°fÀ4”ïÅ»EÞxöÐEEWõýÒ‡U«z‘ž^ÈûC£ÑhŒÁúòKă¨SäyDD„ÓÊ=­=z°œk·o›ä¶º–µhÙäƒ×/–âêÕb`×®çÐh8J$Wr%Wr¥K%K2ÄOËsã¬ñŽ–{Z{ŒÁrÜàåeÑÞIn«+¾h}±ûö5#0P‡””*Æ9+¹’+¹2K]ËÜuÆ O-÷¤öäc0cDFF*PÃ(@9njjrj}j;VÄ”9èÏ¿xâ‡'On`Ó¦!DE}ÀÝ»ÅnÃ_úÕûÓÜqGG‡[óó¤ï«ñ±ÁáìÙÆ9+¹’+¹2‹ À¢ËširsñhÏZt/õÆËgþHKËEPûöµàÌ™„‡À×w\/®†‘”TÇQ"¹’+¹’+=Xc°¬³ßGýÆExñ£Þ¾^‚ÇŸ(âêܹ*ÞFc A–ÝÁìi7еOúâyË&ÄÆ¾ÅòåïpçN1G‰äJ®äJ®ô`Q`ŒÁ²;ÏÕù3è[ìÚëóQ\œŒÐÐAýýzœœ<Æ9+¹’+¹2‹‹ Ë^+>¾ !ÞxVº/æ! `Ç×s”H®äJ®äJÁ¬Ï f¯Ø½]áóð¼> M Bjj9ch41Xî)°d—ìØØXec1yÞÞÞ>隤¤$«™Ì§*·÷zWo,£x«¬,4lÆó óÐP³+Wö"&¦÷ïp”H®äJ®äJ–û ¬œ;wcccŠ¥¤¤ 44t¢Ü°ŸìÃgm¯>Kå¦p´>µ·Ç,ã`öëh_9O} ÉýAA#سç94Æ9+¹’+¹2ËÍÖ×_ý›sÆÛ͈¸õj€<ˆˆ°¹ÜŽÖ§ööèÁúC0{JúC½Q{ËIIÅÐéÅ{5G‰äJ®äJ®äêkãÆŠ×j||\±äädåœ2m(ç çrÎÖrS8ZŸÚÛc Ö”Û©³?)Ö–^êùàöíÆÐh4ÍsVWW|||ðÕW_)&Ï{{{'Êåœ)fÍšes¹)­Oííy´K£Aåî(t.÷Feþ:,Yò›6µ#''Ÿ£Dr%Wr%Wrõ,­x°Œc°¢¢¢èÁúŒöäc0cDFF*s؆©<:r, œYŸ3Ž›jkðlc0Z6ÍÃý;ç±pá’“_:\¿é£ZøNDZô«;ó3>îïïwûþTó÷uºŽù}å÷ÕÖcXæ¼1ÆçÌÅ É9[Ëm‰‰²§>µ·ç‰¬ü×Ð郺ã>8r°!!øzµœ£Dr%Wr%Wrõ\–¬”¸+ã,s«ûúú¬®²³Tn:Åæh}jkÏÓc° SNáÝ"oT^ ÆêÕo݃ŒŒùÇC£Ñh4 ,³hkkS¦eå ˜<—sÆÜOÖò@Y+7ÃäH}jkÏ“=X¥Ç¶ã]ˆŠÒÖ!8x»v½°+G‰äJ®äJ®ô`¹­Àšn§|pÇö<1VžFƒÇ»"ðv…7®'ý¢¤`HN®ž–¶˜k†\É•\É•y°(°·÷`åe¤£q} š7û`ÏÖGXºô=nÝ*á(‘\É•\É•\)°×X_Ê´7®¡#b FDx76lxãP †ÿßÞùøD‘¦y|ÿ4c0l$fgádÖÓs`ÐQ–…ÕÑÌi4¸˜uâ,œÞ޳CfâJttÖ̰8ÃÉr²xš]n89££Y‰â{|ßÙ⊢»ê­îº«?ò„®ýV=UýV}ßç}ª^ Ã0Œ,uëö…³6ßêËöf³}û+ó«_ý‘V"¾â+¾â+¾"°€¬Œ“ÙÛÿÉ>)øIëy³cÇŒùä“ߓ瀯øŠ¯øŠ¯, ‚•i2ûð/jm·à‰ÆA³oßSsíZ?­D|ÅW|ÅW|E`9X‰«Þ^3únµùãÁSÿÓ¦¥e<ç¯`À0 ÃÈÁB`AÑD°úº>1SoW˜¯Þk4?©™1}4B+_ñ_ñ_X@V¦öÕ…vó|G…éúù‡æ­·^˜žžòð_ñ_ñD°2µ;gÞ5ßíø;óË·úÌ»ïþÙܸñ%­D|ÅW|ÅW|E`eÊØØ˜ihh0¥¥¥¦¼¼Ü\»vmÉòŽŽŽÐ¡b¢–Ç]¿Ð·Wp9XŸnF~ñæߪ6?­7|ð'r0 Ã0r°²a||ÜlÛ¶Í ØÁž5¨ñéÓ§—{ƒk ã°ÁÓ-’myù¾½B‹`}Ñ{ÕŒø±©ÇÔþä‰é좕ˆ¯øŠ¯øŠ¯D°²¥¥¥eYÄÊÄ…®‡>×××;/Ïuyù¾½BÊÁêëºdþR[i>«}ß4ìÿ‹éííÏ»ŠMž¾â+¾â+9X)°ÊÊÊLOOÙ²e‹(YN¿xñbq¹º ÙòÐgÍs]$Ûòò}{…ÁúúÂûæù›Û̇5WDö·æÖ­/h%â+¾â+¾â+¬\±nÝ:ÓÚÚjæææÌìì¬9yò¤9zôè’åAJJJœ—§Ú^6ååóöôƒñÌÏÞ½{m Àû‘êÿZN}øsólûÍÑ¿¿k::î­ùþ0Í4ÓL3]\ÓE!°‘°òÐR$‹V#XJf?±ÓüÏ›»ÍÁÝߘîîÿ •ˆ¯øŠ¯øŠ¯D°V%m–_@¤ÊAÒ<×å.9QqÊË÷íåkÖ—½¿1cÕæ÷Ûß3G}cnÞì#Ï_ñ_ñ_ÉÁZ)”à®nA‰,™º ?¾ì):=]ö”]ºåÁ.¶lËË·íB«ÿòÇfzg•éùñGæƒþ‹V"¾â+¾â+¾ÁZ .\¸`6mÚd»9²$É]èÝOaï [ž*‡)›òòm{ùþ¬¯/ž0Ï««Í?oÿÌtvþž÷¯`†a¼+ øó¹’¸½|Ž`Ýio2Oßø‰ùeýmÓÛ{›–¾â+¾â+¾Á‚ÂeÍs°>¿iþð^­ùïmûÍG¿6¿ýí[±ÉsÀW|ÅW|% kÁêë½lFßÞi¶0¿þׯi9á+¾â+¾â+,@`ecýÿÖa¦«ß4=ož3Ýÿ~»h*?†aF °V¤5ñ»ZÍóÊsqÿ§æ³Ïúh9á+¾â+¾â+,@`ű/¦®-W'™'»Ì¥_ôÐ÷¯øŠ¯øŠ¯ä`ËÕLyyZû¦ò§¦û×½´œð_ñ_ñ• °b ¬T,Ì¿þ›ÏéÓÇ0 ÃÈÁV.-'|ÅW|ÅW|%‚•Çh˜ToBïèè}“yÔò\——ïÛ˵ÀúÝﮇ ,-§ï_ñ_ñ_ÉÁÊCnÞ¼iêëëÓŽå§qøÂÆêK·Oÿ'ÙßÉÉÉÄŸOoú»ï¾+Šß¯¦u^©¯ÔWêëÒé¢XWi¬µ`ÑrÂW|ÅW|ÅW"X†U* ËAÒ<×å.9QqÊË÷í­†ÀÂ0 Ã0r° Pp¥z ïÙ³g¡OÙ¥[žëòòm{D°h%â+¾â+¾â++¶Àz÷SØ{ Â–纼|ÛÞZ,Þ¿‚¯øŠ¯øŠ¯¼«ÈÙ°aC¢·G‹V"¾â+¾â+¾"°  Ã0 ÃÈÁ,|ÅW|ÅW|ÅWä·À¢ï_ñ_ñ_ÉÁ,|ÅW|ÅW|ÅWƒ…a†aä`,ZNøŠ¯øŠ¯øJ Xôýã+¾â+¾â+9X, ‚E+_ñ_ñ_X@†a†‘ƒµ& ™}ûöÙ7 oܸќ8qÂŽ»ç§££#t¨˜¨åq×/ôíÁÂW|ÅW|ÅW|-rÕÜÜlÍëׯÍìì¬ikk³‚ËÃìX‡ †œnylËË÷푃Ež¾â+¾â+¾"°–!¡URR²8-q!õê¡ÏõõõÎ˃d[^¾o­D|ÅW|ÅW|E`-c```I«´´ÔŠ.¿Ó<×åA²-/ß·G†a†!°–066fjjjÌäääâ¼uëÖ-[ÏáŠZ$Ûòòy{úÁxægïÞ½6Äêµô?›éo¾ù&§ååó´gÅà¯ÎkÒϧ7­kL1ü~©¯ÔWêkêé¢XÃÃæªªÊŒŽŽæ4D‹,|ÅW|ÅW|Å×¢Œ`õõõ™ŠŠ óðáC§&Ís]žëòò}{ä`‘瀯øŠ¯øŠ¯,ÓÝÝmÊËËÍøøxèSxzuCØSv閻ز-/ß¶G†a†!°Ræ(¥2?z÷SØ{ Â–§Êaʦ¼|Û,Z‰øŠ¯øŠ¯øŠÀZuôÓ$o,òð_ñ_ñ X´œð_ñ_ñ• °ÈÁÂ0 Ã0Á¢•ˆ¯øŠ¯øŠ¯D° ¨}ÿøŠ¯øŠ¯øJ °ˆ`á+¾â+¾â+¾"°€, Ã0 # ˆ`ÑrÂW|ÅW|ÅW"X€À¢ï_ñ_ñ_ÉÁB`1¼ÉV"¾â+¾â+¾"° WxcjBÆ"Ä0 Ã0ä‰+©w}®¯¯'‚E+_ñ_ñ_X)¥¥¥æõë׋Óú¬yä`‘瀯øŠ¯øŠ¯,ÈuëÖ-›WRR’VXyægÿþý¦¡¡Á¼ýöÛf×®]ö6ÓûöíËiyù<íY1ø«óšôóéMÿìg?+Šß/õ•úJ}M=À‚Œ"X;XE’ƒ¥y€À‚ ñž"|öì™óS„€À‚ôî«8ïÁ âÏÍÂ0 Ã0Œ,ÈCâþ0ñ_ñ_ñ_ ÙWP±ñ_ñ_ñ_Xù  €À@`ä ÛãYÒ²CQlذÁlܸќ8q¾‹,©¾êýjž¯Ç7Ož>n¶mÛfìoX¡Ó§O'ÞïþþþŒÞXìØ±Ã\¼xÑ^—d.\0;wîD`+iè¢ní$¢hVR™™™1UUU¶5ŒÀJ---‰ŒXE¡Á‹Ÿ>}šHßÖ¯_ŸW×%pá^!Ô2Nj+($»ººl/©´··[“þ[öºÔ0¨®®¶€¤"?{zzÌ–-[ìMXïMzñâEâ¯I§NJ¬‡¶¿Y]“dü±‡ÀV‚PnGMMÍ Húy•mÞ¼ÙLLL$ÒÇÑÑQSWWWt¿åG™¦¦&sæÌ™Äþv[[[ÍÜÜœíÒ?yò¤9zôh¢Ïimm­íM*ÓÓÓ¦²²rñº¤Ïk­C`+Ç Ûî$ݘ‹µ;;;—ˆ$!¿üⱘ~Ë/_¾´ã™&%AKXyHh%¹›ûîÝ»kÍY ôÀ‚"Xþ¬µìE@`+‡ôõõ™ŠŠ óðáâ;ÇIÍ7KõV±üž“,°ôDhP`It%= ñàÁƒ¢»­åu ¬ÑÝÝmõNrÞCyÞãϺ 멤={öð[.p”øíEëÔÝrèÐ¡Äæì(Á]Ý‚Y2uêu#IdddÄ ¬¤£'•wåÏÁâ)BHôͨXZþÅéP¤NDË¿M›6%ú_Å$°üçuëÖ­6ÿÊåIêBÒïW]ƒGŽIl’»¢uz­JÒQãÀ{¡LŸ×27€À@` °€À@` P€ÊKe‹i˜@ ) °X€ÀÈq’jœIoZcùÕÕÕÙqÐJKKMCCÃâ Øþõ¾üòK»žÖñ—£Ay5~šæ—””Øjoݺµl_._¾l¿·~ýzSVVfdŽ£wýúuSYYi÷¥ººÚôöö.Ûo 謎7nÜh·§²Ž;fîÝ»Ç @`¬®ÈJ7_¢ijjʼ~ýzQíÚµkÙz|Wëù¶‚I¢ìéÓ§f~~Þœ¨Ë, , X, °X…!°~ðƒ`†a†a9°% ²Œ\!°X,ä¿Àzúô©9räˆùáhJJJÌž={ÌíÛ·¿¿nÝ:§ud*¿¬¬Ì=zÔ<|øpÅ|ò¶—nß&''Mss³)--µ¦Ï?N[ÞÐÐÙ·oŸÙ°aƒÙ¸q£9qâ„yöìÙ’åï¼óÎâòãÇ›'Ož¬ZyQþF-OÅÀÀ€Ù±c‡Ý‡mÛ¶™ÞÞÞ”åËN·,ݶ£Ž…èèè°¿OÙ‡~Û·°ï¯4Ô¯µ©_aëçº~eò£~ÀÒ_äÕ«Wæõë׿þýûæàÁƒ9¿xh;===fóæÍ+zÛ7]Ø.^¼hæçç­]¸pÁìܹ3m9ºA Úã3;;kÚÚÚìEË£±±ÑܹsÇ–¥u>ýôS³{÷îU+Ïõ\¸ ¬˜­[·š»wïÚiÝ|NŸ>»—õ¢ŽÅÕ«WíoôùóçÖtcÔ<×m¹~Ÿú•œúµ~®ëWÜßõ  Vyyz‹@­Þ0¦§§ÍáÇmKTë655-¶€\ZPé*ç•+WÌ¡C‡–ÌSëgÓ¦M¶µ¥VøÌÌÌ’ågÏžµ-tµÄ._¾œñhýúõËæi›®èbuÜÖ¢¼\ ,ï7nd]NœˆYºc¡‹·w#ú\__ï¼-×ïG±pZ¸YS]mÌþýÆ|õ•Û÷¨_k_¿\ÖϦ~ÅýQ¿ M`Å™ïC•áÌ™3fjj*åòššsïÞ=[1ÕâÓE¸¥¥%ã¶¿¥­ ¹ÇùóçmË^­ m§µµuI«îܹsöæ£åsssv?2½é§Vµ|’}üñÇvž+ ïû[Á XWW—m9º£\•—+¥ó¢c¼7€à±ðÐ1ðÍsÝ–ë÷£ÄUm­Y¨ßOÿéOßO»ˆ,ê×ÚÖ¯Tëçº~ÅýQ¿ŠD`©µ|êÔ)³eË–Å–mX>‚*ÿÂé Øº/_ØWÿMH7µ¦=RWnGÒmWQƒÊÊÊÅÈ€>+WÆ…±±1{SLµ/^yêž™˜˜p:F¹,/WË¥—¸7€TÇ"U©¢qŽITt$ˆî½ž¸òÈzçCýÊãú•ný\ׯ¸¿1ê@> ,×®À˜]†ê2P¾H]]Ýâ<µ®V«Ä«èþ.€LoÚVðF¢g™lÇõ¢ÐÐÐ`[Øþ‘t-f?ÃÃæªªÊŒŽŽ†Þ ;;;—ÃÕ*¯#XéŽÅZ´°ƒUfáž´Œ…ŸMìyê×êÖ—õsQ¿ !‚•Oõ  h"X.-_=õ¤ å÷7–ù%•-Ó€rDüÝÚNðé?¹la§jaEµºúúúLEE…sâðj——K¥ÜÕÌ ;©r<4Ïu[®ß_©õkíêCœõ³©_qcÔ/€"XªìþåKøŸøQR¬žBº@;vlIeÓ£¹Qá—§œ.]ºd8`»„Böþ\/GDûmŽˆü“Ÿþ‘°§œº»»í j||<åruy¡¿|ùÒ&û/2ÁýÈuy¹XzÊI]Z###vz%ŸrŠ:ÞSJ:ïÙ<åõý0²ÉÁ¢~­~ýŠZ?×õ+îoŒúPh+ç•ô¨ ¢î…v•ëÏÕÐr½§EËÕ R…õW6=âìu9„]<Ó Ey(©ºtP¾†¶¥G½oݺµd¹’…uÉzÊ)*A7ïÝ02}N•£Vž¿Lµµ¿žÁwÍ·¿åÅYžîw¡}йÐù¿~ýºóþǾD•¥ Ë{zÒíGØ÷ãˆ,E²ÞxãûÈ•ëS„Ô¯Õ¯_Qëçº~eò£~ŠÀ , …À@` °X¿KÉ9rÄŽ#¥å5nÚíÛ·¿g<,•_VVfÇJK5²{®ˆsorrÒ477Û±ádúì þšŠ¡¡¡Å±Õ4N[pì2-× §ÞòãÇÛ\ÃÊ [?“±=T®ËXj:axc¥i5VZooohyÞ6Ó-KçCÔ±Nc¥¥#ìû+ õ«0êWX}ˆ*ïÅ‹ö˜k¹Æ6ÔàÖQP¿ P`=Xø‹ƒ.øª ¯^½²#ßß¿ßH›ë€‡¶ÓÓÓc6oÞ¼¢7°}Ó…íâÅ‹f~~ÞÚ… ÌÎ;Ó–£Äàà =>³³³¦­­Í^´<Í;wlYZGôîÞ½;myQëÇT~nÞ¼iêëë#¿ßßßz!|ðàÙºu«¹{÷®ÖÍäôéÓ±÷Ïe½¨c{õêUû}þü¹5Ýè4Ïu[®ßwç¯Ô¯¯_qëCTy\­­­fnnÎîÿÉ“'—&ê@ÖŸþÊþôßµzØžž6‡¶-Q­ÛÔÔ´Ør²¤ZvåÊsèС%ót‘S P­-µgff–,?{ö¬miª%vùòåŒ/@Á>ˆ¶éŠ.VQÇ-NyÁõ3X:VUUU6Rõý]»vÙÈJ:t¾oܸ‘Õ…=S?‚ÇVoïF$ôY"Òu[®ßwã V¾`ƒÔ¯®_qëCTyú,ñâ¡Ï~CýH€Àj[ø“ÀÒWTΜ9c¦¦¦R.¯©©1÷îݳS-8]„[ZZ2naû[Úº{œ?Þ¶ìÕ ÒvÔ"ô·êÎ;go>Z®–¢ö#Ó .pjUË'™BúšçŠÂûé. *¯««Ë¶]ŽQºõu£Ó…°ººÚîk”_ííí¶œ¨íißO:êŸÎ‹ŽñZÜ‚ÇVÂCÇȼ4Ïu[®ßwW5ú¥þíÿ õ«@ëWT}ˆ[^P`éø…ýƨ_&°µzcáï?þôß5Š¥Ö².0[¶lYlÙ†å7¨ù/ܙނ­ûòòò%7!Ý üy ©+·#é¶«¨Aeeåbd@Ÿ][°cccö¦˜j_¼òÔ=311¹éÖ÷óèÑ#{ãÓM:]y£££¦®®ÎéœÔÖÖšñññ¬.Ü®9 qo©Žmª2RE7ÂŽqܨRzq5˜fšúU¨õ+U}ˆ[Þ±cÇl· D–×Eö£~ä±À*OñwláÏ‹\ésyš¿0Ôe |ÿÍZ­k…Õ*ñ*º¿ Ó€¶¼‘èäY&Ûq½(444ض?G$,¤ï1<D•§$w=È ã*!ÝÝÝš4Oý( –½ò¢VÁé¸[¾zêIJ¡ÿþÊ–é @9"þ‹›¶|ºÅO.[Ø©ZXQ­®¾¾>SQQáœ8·¶~”Àrmñª»J ¶Q(wg5sDÂŽmªÍsÝ–ë÷W*‚EýÊßúåZânÿÚµk6ñúÕö·¿¨yé*»?Dùþ'~”«§P„.Ð ‡û+›nüQá—§œ.]ºd8`»„"2þ\/GDûmŽˆü“Ÿþ‘°§œÔ"Õ *]ךº€¼ÇÐ%†”Lì¿È÷#j}ùíE¤t °VLü¬æ6^½zezzzÌæÍ›WLd577›ÁÁA;ʽKnkk³7ñl}w]¿¿¿?ôFÞØØhœŸŸ·û¨}wïÞ½l½›7ošúúúXB0û÷àÁ;ØôÝ»wí´ÄßéÓ§coÇe½¨suõêU;hòóçÏ­Ipjžë¶\¿¬X.ótƒÖóŠ<("533kW®\1‡ŠUæÙ³gmäE‘ŽË—/;û¨›·¢g«%°víÚež>}«lùìG¾WUU™Çç\`EíßáÇÍ7²ÞN&â=x®$Ž<¡'ôY¢Óu[®ßÖÿSb+(°ÎŸ?oYÙÍ›76 ’³!ÑŠÙà%¹\÷=yyy3þ™È÷$&ËÐg£CBABaQVg×µÔo¿ýV½¿|ùò±{R.ÏMg&ƒÌÔë>#‘Y¢ÔÚÚ:a >ݬ¾ì$%æHçS•‰áнÿÿñF}f‰Ðèš.1"’³!ß·,Q“Ïöã?¥©®žByÿLPPP0îýË–-CSS“úYÖ¯_?®LLÓL&A AÄ‚A0¤Þ—ähÝûwïÞý"bee5¤¤±²çÏŸ+“g Õ/IÛIàÖ/{ñâ…Z&ƒ}ÝûbŒù̲¬I÷þÉ“'¿XS]#3™.ÓE'lllÆÝ¯®®+ÓÿÞ¿úê+‚ ‚ ËÁ÷ß?nÀZRR¢Þ—¯º÷å¹/1 ºÉØúÑ™Ñ×-“g Õ¯û^Ce† ÀTŸY7ñ^(çw|)¦‹€Lg@ô?‹!k°‚ ‚ ˆ‡ ²us3$)\ºy2¨okk›ñ`w&ÑyÖØúM]6Ýçœ þçþg\]3I²Ÿì³Ì$¯ƒ„ ‚„ ÂlqéÒ¥ t%™|¦ƒ]CýåDÓE@æ²Ì”ý]°t“Åù,úš‰NFÿq¤!‚ !‚0WHþÀL È—ä˜2d.ËL™" öº' ËkÙ&ØX³ ¯ÙdÛ Ó€AЀAXd@¬?X•30tñöí[ƒÏèo}«¿‹•@,9»CvÁÊŽX†¶«O"9/ºKŸ$·B» –öû³@ŒELL̸vdyÛƒÆ"@²ëÖTŸE_3ÑYÌš@Þ/ï•m‹';AݘŸ AAB1ï8zô踪ä-Lý­rew,-¶oßnT^‚ ä§;äܹsÑϣȖ¶úËŸfQhÏßÿýßQ.‡1šMöyŒý™A4 Aó 9)ÜP~‡b tŸû÷ÿ÷±2™—ü†ý×6‰[" r†ÅÿøGõY¡œŠ.÷dFÒ_ôól@Ò= ]»„J¢Ú­~g9›D4ü¿ÿû?5ÏD¾o1rΈh)[îž>}SjöÏÿüÏcïƒ$g´ìÛ·oÒäö™üL‚ ‚ ‚ ‚ h@‚ ‚ ‚ !‚ ‚ ‚ !‚ ‚ ‚„ ‚ ‚ ‚„ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ h@‚ ‚ ‚ !‚ ‚ ‚ !‚ ‚ ‚„ ‚ ‚ ‚„ ‚ ‚ ˆ¥m@òóóáíío¾ù+W®Ä¡C‡ÐÚÚ:åóMMMð÷÷ÇòåËUÊ놆†qÏ„††bÅŠ*CBB&Ô1]ùLŸ·ôööíÛ7îÚËË 7nœw.T»‹•Ô“šRSjJRSjJMçšúãH‹0 ~~~ÈÍÍÅÈÈFGG77·)ŸwvvFxx¸ú¼0,, ®®®cå111ðôôDgg§J17rÏØr}̶>soo2²iÓ&<þ|ÞùöíÛiw±’zRSjJMIjJM©é\Ó" ÈdhÈTøúë¯ >/ƒïW¯^]Ëk£Ëõ1Ûú̽=s2 òYù „zRSjJRSjJMIËÑÔâ ˆD@"##ÕeUSaÏž=jÔCž^»vM½§…,Ë’ûºuÊ=cËõ1Ûú̽=s2 $I’$I’¤eÑ¢ ÈW_}¥rÕªU¨¯¯Ÿò¹––ØØØŒ=/¯ÛÚÚÆÕ£eË–]>ÙçšM}æÜžt-õs@$Œ§uÒòu>®«ªªæµ½Å~M=M­%õ0ݵôSêaÚkÉ•¤ü}Êß§ü}:_í/ŠÈíÛ·áîî>å3¾¾¾jD7ÄÇLJEázPêIM©)IM©)5%™² 0!˜¬L÷Þd9rÏØrcr2fRŸ¹·Ç®%©)5¥¦$5¥¦ÔtI   ±mt{{{ÕmcuÌúKŠdÇ+ÉûÐÍ™l¬öövƒ»DMU®ßÞlë3·ö˜B’$I’$I.i’––¦n­+ñï¾ûêàyªºä‡È’+ÙùJ(¯õsFÄÄ:ÃPùd9³©ÏÜÚc„3!$5¥¦Ô”¤¦Ô”šr ÖnÉËöLæ€p-(IM©)5%©)5¥¦4 Ä’3 œ ¡žÔ”š’Ô”šRS’‚„$I’$I’$i@F@HêIM©)IM©)5%!h@¸”ëk©)IM©)5%©)s@h@F@8BRSjJMIjJM©) AB’$I’$I2„ álgBHjJM©)IM©©9V˜’4  ׃ROjJRSjJMIjjz2h@ΆPOjJRSjJMIjJb&$??ÞÞÞê‰à+W®Ä¡C‡ÐÚÚjð=555ðõõÅòåËaee…ØØØqå¡¡¡X±b…Ê ïŸ®|¦Ï[z{Ì!I’$I’´,f<Íà¬/…ŸŸrss122‚ÑÑQDDDÀÍÍmÊçëêê`kk‹ììlõùöövœ:uj¬<&&žžžèììT)æFî[®ÙÖgîí1ÂÙ%’šRSjJRSjjAÆ#6ï¿Ãýêêñ"æwÁ2$2Ž92!â¡ |Ë@ yíááat¹©ë3÷ö˜Âõµ$5¥¦Ô”¤¦ÔÔü™›Žº#uªñø°ÿ2gš…¦o@$¢ ÿ)ŸùöÛo~øA5*òMwuu•˲,©G·N¹gl¹>f[Ÿ¹·Çg—HjJM©)IM©©géxøV5 ûù(Ó¬4µhòÕW_©\µjêëë >wôèQ cppÇŽÃÆ•ëcÙ²eF—OÖÞlê3çö¤Ãh© ///ÕEk;²|å5¯yÍk^óš×¼æõü]g£ýb;††Ñ¸·¥)¥fùyEäöíÛpww7!ã¡…Ý%[Œ€0BROjJM©)u ¦ÔÔR™—†ÚcµrBãîFdEg™µ¦‹&ÄP„@’ªõ ˆî{²¹gl¹193©ÏÜÛc××’Ô”šRS’šRS30ñi¨9^ƒ!Íšv5!;:Û"4µH„††õuoo¯ºm¬î€YI‘$ Ë²+1!BYŽ%[÷êï%»cÚ%jªrýöf[Ÿ¹µÇg—HjJM©)IM©©„4TŸ¨Æ Ã >îüˆœ¨‹ÒÔ" HZZœÕøwß}‡ÀÀ@uðl(§!,,L}V–^ŒKBˆ‰1t†¡òÉÚ›M}æÖÏ!I’$I’\x¦&¤¢*¨ ƒšA4ïhF΃œYÕ—žþŒd>¶äe{< ¤žÔ”š’Ô”šRS‹2‰Šñ8©GÅxø7#÷~î¬ë,*º¡ž>X\|•„° 0„ëkIjJM©)IM©éÜÊS•p@ËöäÞË5I½b>FG5Êî*FFìç݄ЀŒ€Ô“šRSjJ¨)55#¦$¦àÍé7X7€Öm­È‹È3YÝ2y¿ï~Z8ï&„„°hB’$I’$¹hŒGR *ÎT`ÀI1[[ñ2â¥Ië—œYv\7Žûü9L½?_9!4 # $õ¤¦Ô”šRjJMÚxœ­@¿S?>ù~ÂË;/笭²²PeäfÏAÂõ \_KMIjJM©)¹Ô4ãQ~®ý.ýhÛÒ†üÛùsÚ^IÉ% : ©is@Άpv‰š’Ô”šRSr©hš’œ‚²óeèséC»O; nÌi{ééqŠé؉Þ^W¼|y—»`4 $I’$I’K‚ÉÏQz¡}®ŠñðjÇ«›¯æÁ¸…c`À õõHMM˜²:ЀŒ€Ô“šRSjJ¨)5kãRŠÞõ½èðìÀ«ð¹ÿ^RSñþýAÅ|¬Caáu³Ò”„`I=©)5¥¦ÔšRÓ92%—Jг¡( +œ—vóò"ÐÓ³ÍÍ;žkvšÒ€Œ€Ô“šRSjJ¨)55±ñxú={е¹ E׋æ'·$%55Ç14¤AiéE³ÕÔ" H~~>¼½½ñÍ7ß`åÊ•8tèZ[[z¯¼ï«¯¾šp?44+V¬P2ãrS×gîí1„$I’$Ir"__yîÝèÚÔ…âkÅóÖnVV4::<ÐÖæƒÌÌÇf­‘E???äææbdd£££ˆˆˆ€››Û´ïKHH€‡‡ÇOOOtvvª“"÷Œ-×Çlë3÷öáìIM©)5%©)5Ïâ«ÅªéèÞÔâ+ÅóÚvEÅY 9 ²ò¤rlöš.š%X 1„¾¾>ØÙÙ¡¡¡a‚‘Á·ü´×bTŒ-×Çlë3÷ö˜Âõµ$5¥¦Ô”¤¦Ôô7]+B—{—ºÜêõå×êò«ùj;#ã Z[ýÐݽ 99÷-FS‹7 ‰ŒŒ„¿¿¿ÁçΞ=«>'Ð7 Ë—/WëÑ­Sî[®ÙÖgîí1ÂÙ%’šRSjJRÓ¥®iáõBtnîTÌKBKæÕx¨K½^_Áà uuHII²(M-Ú€ˆ‘®Zµ õõõS>W]] ww÷qïÓ¯GË–-3º|²Ï5›ú̹=é0ZêÂËËKuÑÚŽ,_yÍk^óš×¼æ5¯ÛuS|z|zÔ-ußÞ|‹·µóÛþ»wøôé úúœQYc‘z.ŠÈíÛ·Ç }H™®Aa„’zRSjJRSjJMgÔþWèðê@¯k/J/–Î{ÄCXPp ýýÎhh؇´´‹ÕtÑä€L!˜Œ†r äž±åÆäd̤>so9 \_KRSjJMIjºT4-¸Y€vïvô¹ô¡ìBR’Sæý3¤¤$âÝ»ÃtDqñU‹×Ô" HPPšL.èííU·Õ0O¶¤ÈÐ’%í.Píííw‰šªÜÔõ™[{Œ€pv‰¤¦Ô”š’Ôt©iš+m>mèwéGùùò1ÂÜÜûèîvCKËvddÄ.Š~j‘$-- ÎÎÎê@ü»ï¾C`` :xþR"cè C妮ÏÜÚã9 $I’$I.æßÉǧ-ŸÐ盧ŠñHJY Ï’Œªª u{Ýòòó‹JãEyút[ò²=ž„NROjJMIjJM©©._Þ}‰O[?aÀiÁ h<äPÁGho÷FG‡—úz±õÓEi@ˆ¥c@¸Æ–zRSjJRSjJMgüˆ<´úµb`ÝÞœyƒ”Ä”ý>ËÊΫQêê ÌäPÁ/arc2 AÂ&ÎØQS’šRSjJ·¦y‘yhÙÖ‚ÇTž®Djbê‚~’ßÑܼ==nÈͽ7çíEgGÃJù'_i@’$I’$ɹJ꾟‹æíÍtDåÉ…7¢¢kêWïÞBjj⼴Рݻi@Î0qÆŽš’Ô”šRSÒÔšæÜÏAóOŠñÐ ¢ê×*¤&,¼ñ³<>|؇þ~'Üœ·v%êa;j‹åŸÍg›y‚ЀÌ!©'5¥¦Ô”:PÓE«iNT>îøˆA‡ATU#5>Õ,¾Ÿüü;èësEcãnňÄÍMŽÇódļˆÁ­ü[¸PzÇjaOãlÚˆ3Ê?Á‰ó¡!!©'5¥¦Ô”:PÓE§ivT6šv6aH3„š5HKH3‹ï#%%I1SÔàõë˳®ïYú3DäE ôu(‚ª‚ð![?mÅúÞõ°ýl ‡AlîÜŒwàHݯ9[å_£òO _ç; BB0„$I’$ÉEÃ쇊ñØ­ÅxSŒG\šÙ|¶œœèêÚ„ÖÖ­xñâ©QïILMÄå}׊®áô›ÓøùÝÏðoñǦîM°¶ÃÚ‘µpëvö–m8øþ NUžÂÕ⫸Ÿsñ©ñ“æ~+ÿt1ßQ‚’zRSjJM©5µxM³f¡qO#†ì‡P{´Ö¬Œ‡l§[©Ù^·¢"xü2©”d<Êz„¯nà\ù9¾ ÄΦðìô„ã £písÅ–O[°ïÃ>œ¨>K%—ñ2±é3;ýÉ‹'jâùTÿ¤œ„ á[êIMIjJM©)i@Ó¬GYhØÛ ·¿¼Eú³t³úÜ™™1xÛî…‚ž ¸VuR]µ·a/|Ú|àÒuëàÕá…ÝM»ñKí/8_v7 n"Fyoòž²PýÔ" H~~>¼½½ÕÁW®\‰C‡¡µµÕàó>>>cÏ¢½½}Ü3¡¡¡X±b…Ê uLW>Óç-½=F@8cGRSjJMIjºšf>Îć}TãQX· Æ#.-÷rïáÊë+8©˜Œõà×êwÅXØÁ š[¸w¹ã§æŸpøÝaœ©8ƒë…×Õ¼‹Ä”Ä%×O-Ò€øùù!77###EDDÜÜܦ|Þßßyyy곃ƒƒV ‰111ðôôDgg§J17rÏØr}̶>so9 $I’$I._ļÀ‡€ßÇá:dÄfÌy›b¢²£TÓ æAL„˜ 1öCö°U Ɔž ªéóqºæ8â;®«ªªæµ½Å~M=M­%õ0ݵôSêaÚkù›H=øûÔÜ®%¡5 ²m¬±íc7 ºÏË–³ñåñxòñ BêCÔ-iwvì„ç 'ì>Û©[Özôy  7Ç›«[ÚÞ«¾‡Ü¹È+Ì›Õç­¨xŠÞÞõhkÛ‡wïÊÌZßøø6lÚ¼~ý›”oÞnnŸZ2oŸgQD@nß¾ ww÷iŸ-,,„ª««MA`„9 $I’$Iš†’Óñîð;5ÇCŒF£G#Ö|^ƒåßš‘5êµÜ—Cõäp=9dO3¤QÝ“Ã÷ä>9ŒOå“ÃùîåÝC\úÜœ4ž’’ŒÚÚcRÚ/) ±}·n3ZüfBú™) Eiii°¶¶Fee¥Q9rÏØrS×gîí1„k–IjJM©)IMMÍôØtÔ©SLJýÔ]®äþž¶=8£ü)ÿœ°§qŽ)ÿ ¥p+ÿ–z~Å\nW;³³£Ñ©˜Ÿ¶6_u«Ý¹n/99qq鈉ÉDTT""^âæÍW¸v­!!%8{¶'OVâØ±>\‡€€zìÞÝ„íÛ›±eË'xxt(&£[]v5lmGi@ !(( êëÞÞ^uÛXݳþ’¢¨¨(XYY¡®®Îà.R²5¯¡]¢¦*×oo¶õ™[{Ìáše’šRSjJRÓ93ÏÒñ6ð­j<ö5 óÑoÆC¶¨•¦œóÎb›ÿguàì½Eùú"X-[ÈÏ\QqF=T°²ò4žOb|S«ªGÊ÷rÿ~îÜy‰ððW¸r¥/–"8¸¿þZ…£GkqèÐ;ìW ×ÎMض­>>mؼ¹6ôÀÉ©_ù¾‡`cóÖÖ£X»vŽŽpuíUÆ^]ðòjÇÖ­­Ø±£{÷6âàÁzÖáĉœ>]‰óçËÕ¥UׯáÖ­Ü»—§¼gpB¤¤dHi¯dºh†³³³:ÿî»ï&œë¡?@׿ŠèSbb ƒa¨|²ŠÙÔgní1Â;’šRSjJRS“¸tÔþR«Feð, Êýû¹÷±óãN8(üm/î`ã¦Ñqù 6`Kì]“}Ž„„T<}š‡³™‹Û·óVˆË—_ãÂ…2œ9óAAÕøå—·8r¤'Of)Æ!þþðön‡»{Ö¯ïźu°³ÆêÕ£ŠaUŒÃ°b ”}¯b(ºcÑ®ŒVÅh|TÆQ øùç÷jR·´!mI›Ò¶|ù,ò™bc3C“j²ï÷êÕbå3 ¸ø·å÷ee#pqT È&&žžžèììT)æE|©µÇ’$I’\ÄãRŠÞõ½èðìÀ«ðWˆÊŽÂîÆÝêR«#uGpïYòŒ¶Ð]ÐNJê”Ï,K®Š‹¯ðçËÓA¢!SA×âð´×&+_jí1™’šRSjJ.BMãQ¢‰ž =èôèDaX!"s#±£y‡š\~´æBoä}Ѻ ¥iNÎ}twoBkë6dd—ž‹ææŸÐÓ³yy÷Ø™bz¡¡¡A}ÝÛÛ«n«;`Ö_R¤Ý婽½Ýà.P_Z¾ØÛcׂ’Ô”šRSÒ²5-T EçæN5Á\ŒGHI6tn‚Kb(Üüç| ÝYÉ c@ŠŠÂ00°ïßÿŒÔÔDö?æ€Ì ÒÒÒàìì¬Ä¿ûî;å?L :x6”Ó &ÅÐ9³)_ìí1™’šRSjJZ¦¦…á…èðèP·Ô--ƹòsp®ß§kÏ`¿®Ïì·Ð5d@RSãñáCúû½o°ß1b¾[ò²½Åu:I’$I’“ ,o¼B‡—b<\{QZ„S§¡É=Íϯ±Öa`Þ·Ð)Sñò΃dÔ}5†=×¢{ó&å{õ§-[вm>î܉ƽ{Q€w‡áí/¿ æÄ Tž<‰Šà`”]¸€’ÐP_»†WááÈ¿}y÷î!'* ™!ãéS¤ÅÇ#%yq滬„0;0™’šRSjJšŸ¦7 ÐîÝŽ>—>^.ÄÑ¢óXûà6l7¶ÂusÛ‚m¡kŒÙxsæŒjº7nÄç5kÔ¯† HeúiäFFªï}uó&Š®_ÇëË—Qzñ"ÊÏžEåéÓ¨ BíÑ£¨;|õ¢A¿4íÚ…f´nÝŠvtzx¨mõººbÀÉ CQÚµ¶ÆèêÕY»ƒÊ½~¥¬wýzt+cžå=mÊ{[ýüмcwïÆ‡ýûñþçŸQˆšcÇPõë¯ê÷T~þ¡ß©Y— àw'«ýÞbí¦O8|æõ‚n¡;S³¡¥œX^Pp••§ .JO¶øúNr2Ò‹ÌÇ‘¥.“eb²\L–Éò1YF&ËÉdY™,/“ef²ÜL–‰Ö² ­eûv|òõE»—ºÓ£™>‚„$I’$É™óåÝ—ø´õœ{¦›NåÂÚ©Îå¸p;k޷ЩÙݪrsä2jjŽ£©i7:;7cxØCCöê!‚{”û1:ªQFy¿8Šðù³Š‹¯²p AÂgìHjJM©)9ךæEä¡Õ¯½ëpýH%ª…õúvx\LGij$³3/^Ĩ;T½yŒ÷ïâÓ§­èïwQL„ z{×£¥eÞ½;ŒòòsÈÏ¿…ŒŒØ í½~}ëwr•惄 a×,“Ô”šRSr>4Í‹ÌC˶4hql×{غtaõÞRlŽÂ“´g j6 îÝB^æ””\Bmí1|ü¸ ]]îY«žJÞÑá…††½¨ª RÍCvvRRff–Ä„(#dšî‚EЀ0Â;’šRSjJÎ¥¦¹÷sñq{3ò쇱ݳ6޽° ‰ÃÁ¬+ˆK‹›W³Qsá*cÏ ²ô$êë ­ÍW=ƒãóg[õòææí¨«;‚²²óÈÏ¿còââ,ö­EòŸ„`I’$Išsîç v[+¬³cÖn©ÇÚØË8QŒøÔø93=›ÜÐrp;¯ïECÚ>4ø ÝÝ›02b‹ÁAG´·{ãÇ}¨ª:‰¢¢kÈÊŠVêKæÏŒ¤!!©'5¥¦$5µDMs¢r½¥ §l?Ãní04Çsàøúg¿ Fbj¢ ͆-ú=\Ðù‹:"¼ÑU°ÝŽøüY1!=ÑÜüÞ¾ Dié¼|yi&޶°Ÿ2bq$??>>>ê‰à+W®D`` âÈÛ§|¾©© þþþX¾|¹JyÝÐÐ0î™ÐÐP¬X±BeHHÈ„:¦+Ÿéó–Þs@¸f™¤¦Ô”š’¦Ó4ý^.îoî„ßêQ8;õÂéî¸4{ã|Ùy$Í _B×l4íÛ…¾Í®ŠÙ°Á —ý¿:càÑ:|~c«š¶6|ø nw[XxYYÌ:šÁ~ºx4µH""//£££Dpp°jH¦‚³³3ÂÃÃ122¢2,, ®®®cå111ðôôDgg§Joooõž±åú˜m}æÞ# œ !©)5¥¦¤i4}V„3ëÃa lÙÒ—ÌÓpëÚˆK%—<³‘÷j/EÛ!_ x:btíjŒlYƒÏgÆÚ ·h½ºŒª¶ö”–†(㧤¥%°Ÿ’Œ€ÌbD–-[6eù×_=ážDO´Á·ü´×F—ëc¶õ™{{Ì!I’$Éi"°“’Rpýt%v8ÂÕzû–ÁåÝvlîÜŒ«Sìòô"å ÊŸCãµ]è>ºÃ>v€âZü¬1¼=6 9s‡š ^XŽÌÌÇü9Ì™KdggŒ€ìÙ³GzˆQ^»vM½§…,Ë’ûº†Fî[®ÙÖgîí1™’šRSjJNΰ°RlÝÚ{ûÏðòPÆcegâøz¸Ø~Æ›Ï8~î\º7À»ÝáŠi­ie‹Ú×—Qÿü :îzbð¤£[W«f㳯-ú‚\ÐzkjâO¨[ߦ¦&°Ÿ’Œ€Ì7jjjàèè¨æyL…––ØØØà«¯¾R)¯ÛÚÚÆÊåž>t#*Ó•ëc¶õ™s{Òa´Ô…———ºŽPÛ‘åë|\ËÏ}>Û[ì×ÔÓô×ú_©Ï쯥ŸRÓ^wttP\:_a÷ö.8*ÆãâÚa\}—!GììqCöǽè/ÞŽá˜u=k­˜ Ål¬Æ°žh¾q _Ä¢0/¿OùûtÑü>µhRXX;;;TWW|Î××W€èæ€èFLa„¤žÔ”šRSê0[:a:æ|î6ºãP¥5âcW£í´b2ì1ºÖýÎh9èʳ§ÇN§žì§Œ€˜¡IKKƒµµ5*++§}v²Ù|Ý{“å@È=cËÉɘI}æÞs@H’$Irb·!ò~·5†ÖZ£s³ËØ â4$s@,È€DEE)ÿ—­PWWgÔ’$ÙñJò>ts@&ÛK¶ò5´KÔTåúíͶ>sk΄ԔšRSÒ0SR4 ©ÑWh6ØO©©%m.‡>§ ×××"”×rOrö…¡s0 •O–C1›úÌ­=žÂýÀIjJM©)99_¼¸¯üÝL†¯¦Î ¡Vì§Ôt‘í‚eh‹]¶Ç“ÐIêIM©)IMMÍììÛ¸r%[ߢØõ8FVkh@ØO©éR6 ÄÒ1 $I’$9ˬ’‘Ÿ ׯÇÀO1¯Åx8"'È›>ÙÜ‹ú‘$ ÁI=©)5%©©QLMMDQQnÞŒÆ6M ^¯ûÍxdôÁÆ6{©;‚9`eàß“O¨%û)5¥!ƒázPêIM©)IMçŠiiq(-=ƒ;w"á/ÆCsÊñÈ8ãí|ˆØôXjÊ~JMi@F@HêIM©)IM¿œOðæÍ DDÜÅMJì)ÆcÒÎzcC‡=޾=ŠgéϨ)û)5¥!˜B’$I’_ά¬G¨­=Œû÷oc§¦¥vŠñ°qÂóó^ŠñpÀ±ÚcˆK£V$IB0ÂÿÈÔ“šRS’š~9ss#Q_¿ÜÄMÊÖÅÐj'$…(Æ£Sƒã5Ç—GMÙO©©%©ÎíÐç×_Í‘= ׃r}-5%©)5ÜFSÓOˆŽ¾‰½šrÅxü‚!'ćzb}—'ªO >-žš²ŸRSK4 b,t9•Y¶lGö4 œ áì5%©)5S]CK‹¯j<4¥(·=‚Ag<»ê ×.üZý+Ò¨)û)5],K°bccáéé‰ööö±{mmmê½äädŽìi@H’$IÒä”35žz‘äb3 ßÿ=†‡‡'Ü—{«V­âÈž„³!œ]¢¦$5¥¦&£œáñæM0zz6(ÆãiŠñÆægô+Æãñ ¸v;âTå)$*ÏQSöSjºH ˆ,µšÊ€›’ŸŸ|óÍ7X¹r%ÇET&CMM |}}±|ùrXYY©‘]„††bÅŠ*CBB&¼ºò™>oéí1„kAIjJM©©9SÎð¨®>¾>'DEEà°¦•«*ÆÃÑ·7+ÆcN¿9mrãÁ~Ê~JMÍЀ|ûí·ðððP—]ŽŽªlmm…»»;¾ûî;£êð÷÷G^^žúÞÁÁA«†d*ÔÕÕÁÖÖÙÙÙê{Ĭœ:uj¬<&&F]ÖÙÙ©ÒÛÛ[½gl¹>f[Ÿ¹·ÇgBHjJM©©¹RÎð¨«;‚þ~GÅxDâ¨æªV Ïv=ÜUŒG‚ß#1%‘š²ŸRÓ¥”2UzRRÒÕ)¦ÂPû‘#G&Dso΄ԔšRSs¡œáññã.Åx8àÁƒ‡Ò䡯zzÖnÄÝîXßíŒsåçæÝx°ŸRSjjfÄ”ÜGGG455Ì;9zô¨šg"K¶Ž;†Œ+ׇnDeºòÉÚ›M}æÜžt-uáå奮#Ôvdù:×òsŸÏöû5õ4ýµþWê3ûké§Ôô×÷ù++£µÕOù»î„gÏžã´cj­w¡ÛN11ØØ·çËÎ#¿0Ÿ¿Oùû”×föûÔ¢ Haa!ìììP]]mð9™Íã¡›ð.‘F@!©'5¥¦¤ei*gxttx¡·×‘‘±Öd£Îz:×nBøãXß㊋e‘œ’LMÙOIF@þ4ø—¥P³= =-- ÖÖÖ¨¬¬œöYIªÖ7 ºìÉr äž±åÆäd̤>so9 $I’ä|R{†Gw·ºº6âÞ½xœÓdâµ?:ìÜqýéFlèYå™äçÉÔŒ$™2666ã ‡.= ]’Ë$oDv·2fI’$ Ë²+1!BYŽuèС »@ÉîX†v‰šª\¿½ÙÖgní1™’šRSjºÔžáÑßï¢F=""’pQ“÷ÖÛÐf¿WâÜàÖ½—J.™ñ`?¥¦ÔÔŒ ˆÙžx>Õ.Z†rÂÂÂÔm~eéU@@À¸$tœ}aè C哵7›úÌ­=žÂýÀIjJM©é|R{†Çà £šçq÷Îs\Ҥჵ>9x"$q=6v¹árÉe³x°ŸRSjjFÄØ(Çl ›ß1Xìí1™’šRSj:Ôžá14d¦¦¸s+—5)h°ÞŠ.$oÀ¦îM¸òúŠÙ/µb?¥¦ÔÔŒ ˆ,’e>„eƒ9 $I’¤©¨=ÃcxØ^ýzçV&®i’Ñh½}p.e=Ü»Üqµø*õ"Iæ€Ì¹¹¹Ðh4j¾AÂÙ΄PS’š.]MµgxHÄC"·oe!\“ˆ&+o49nÁétWlîÜŒkEר)IM1}þÆLwÁ"h@¸”zRSjJZ¦¦·?ÃÃQÍõ¸s3·4ñøh剆u[pò…+<;=VFMIjÊÓ$¡OÅùÈ!!©'5¥¦äÂhª=ã¯Ïgp'<wŸ¡ÙÊõë¶âD¶ <;<^NMIjʈé AB’$I.êžá!”×7ópOó-Ö›ñÞÉGs]àÕî…¯nP3’d ÁgBHjJM©éÌ©†‡D?"Âsñ@ó­V›Pç¼y.ði÷ÁÍ‚›Ô”¤¦Œ€Ì­)..VO1—%WBy-÷®åúZjJRSËÖTÿ üü[ˆ ÏA´ã#|²ÚˆZ*pÆ–¶-¸]p›š’Ô”9 so@òòò¦LB§ ¡álg—¨)IM-SSý3BCC±bÅ •!!!3.7u}æÞ# œ !©)5]ÚšêŸá!G7³ðÌ1ÖëQ¾~ö½vÁ¶ÖmˆxAMIjJMÖ€ N¸/¦ÄXâïï¯.åUë V ÉtHHH€‡‡ÇOOOõ„v¡˜¹gl¹>f[Ÿ¹·Ç®%©)5]ºšêŸá!9og!A+W”®ßÝ%.ØÞ²÷òîQS’šRÓ…7 666ª hmmU „P^»¹¹©Ë³¾RÇtgˆôõõÁÎÎ  ˆ ¾Åj!¯å3[®ÙÖgîí1™’šRÓ¥§©þ²ËÕ“[/äxV.(vÛ‹¥ÎðoöGdn$5e?¥¦ÔÔ| ˆ$šO•„^QQñEufggO9{ö,"##Õ×údùò媉Ñ54rÏØr}̶>so9 $I’‹‹ééÏ&½?Ùrï©b<žkn¡ËÊ…nûá_îŒwà~î}êI’¤ù ‰vÈ’+¡¼þRóQSSGGG455MùLuu5ÜÝÝÇ®õ Èd9!º•éÊõ1Ûú̹=é0ZêÂËËK ãi´|몪ªymo±_SOÓ_kI=Lw-ý”z˜îºº:Jù-n¥ü=+¯««Âû÷—Õ3åïS£¯-ú ÂÂÂBuY• CóQ__?倛Ë€p=(õ¤¦Ô”ür†cxØNá%ŒŒØ£¤äÒ„3<ä¹ø[éÈЄ¡ÛÊ yãñÆ»›v#*;Š:²ŸRSjjS --MœTVVNûìTK¾ å@È=cËÉɘI}æÞs@¸”¤¦Ôtñ˜¾¾´ß'Ÿ^J¦&ÚÛ½Ô3<䙄iÈÒ\SGΦŸ±åÍzìi܃èìhjÈ~JM©©åÔÔT:thÂ}ÙJ7##è:¢¢¢Ô3CêêêŒ^’d¨\» ”låkh—¨©ÊM]Ÿ¹µÇ’$ÉÅ—ó9{k ¦Þ‹GŽÃÕxd¹Æ–ÊõØÛ°³R?’$-Ï€|ÿý÷èêêšp_îýðÃFÕ1]Dc¦D g_:ÃP¹©ë3·öáLIM©éâbfæãßÌÆdPî÷X­Ã ÷#ðªtÃþ†ýx”õˆº±ŸRSjj¹Ä9øúë¯M²<ËØóDL…ÅÞs@¸”¤¦Ôt±9µ|¿zj¹!âQ冀x¬êÆ~JM©©Å™aokk›p_ΑSÍ Ë# œ !©)5µfe=BCÃ>SËc ˜ÌêÆ~JM©éâ1 2P•HÇû÷ïÇ"”\‰ŒLwøAB’$IÎÄxD£±q¯j<Þ¾ Dzz¬z?õÉsƒ„Ú‘$¹¨ ˆäzL•ÃÑÛÛË‘= gC8»DMIj:Kfg‹ñØý»ñ8ú§ƒ“ðÒó:¬×Ó€°ŸRSréD@´Ë­lllÆ"´µµUw`"h@¸”ëk©)IM¿œ99QhjÚ¥ÔÖSŒGÜoeÉÉÈó¿VëM(¶Û‡ñ; î‚E-ÙO©)5]t„ álgB¨)IMMi<àãÇŠñР¦æ8ÒÒâÆÊr*¦dõ¼±ù î`ÿ‡ýˆÈ‹€•O^<¡®ì§Ô”šÒ€4 $I’äxÊÍÍ;08è ž`ž–ÿ'Srú!ÞÛþ„w«}pìÂì}¿2¹.I’K0D­ž¢»í®,Éúøñ#Gö4 œ áì5%©é´Æãžb<üã¡QŒÇ¯ŠñHøSâù¥Ç¨µ ÀGkwœ=z{jN{Ž5e?¥¦ÔtQøøø±¤s]’ŸŸ¯žÆMЀp=(××RS’šNμ¼´´lWŒ‡#ªªN"5õO¬»OPéˆ6+W\Ùó+ö–AtV45e?¥¦$s@~üñG\¸pAÝ~W×€ÈX<„„³!œ]¢¦$5È—/#ÐÚº ލ¬<¥ı²Ÿ¢ÂõWtY­Ãmß“Øûò¢³£©)û)5%ÑB×tèŸ|nª“Ð æ€$I.ãqG1[ã±oÞœg<ÒccQêŒnëux¸ñWìK>ƒ¨œ(êF’$s@ô±lÙ2åéÀÃ!Ûð._¾Ü¨:d¹–º…¯DM nãkÌó¡¡¡ê)í uLW>Óç-½=F@8BRSj:wÌÏ¿OŸ|•¿—NŠñFJÊŸŒGZBJ¶]TGüºˆ¾ˆ9¨)û)5%™ ’l¾~ýz´µµ©ddd•••ª1qvv6ªäåå©Ë¸¬Œ/}>&&FÍ?éììTéíí­Þ3¶\³­ÏÜÛcׂ’Ô”šÎ n)· ¿ß gã‘4V–’”„âý¡è´qA†} ~¾~‘Ù÷©)û)5%™2êêê¦< ]¿_1b`¾ôy|‹ÔB^{xx]®ÙÖgîí1™’šRSSO7ÑÞ—Ÿg<äÁ¢c×ðiÍØ ðÌ D¼x@MÙO©)ÉÈLMˆîIè³Ý‚7;;Û`dºçeé—˜]ƒ¢»lºr}̶>so9 $I’¦úã®/ôõ¹¢¬ìüxã!‘óáh²ßŒòÕ?áÄ¡[¸“òº‘$É…FMM ÑÔÔôÅÏKôe²\cËõ1Ûú̹=é0ZêÂËËK ãi´|몪ªymo±_SOÓ_kI=Lw-ýÔÒ¿Ÿ¦¦8ôôlAo¯+êê•òšqåõÏ’ñÞy êVûàÌÎÛˆÏÏ›ãÏÓÄþÅß§ü}Êß§óÖ¾EÂÂBØÙÙ¡ººzVÏ3b¹®¥žÔ”šZ‹Š®£³ÓC1ëQZ¢ÜKWžªÛðÑfB¼o#<*‘š²Ÿ’Ô”9 ³5 2Ë"K®’€¾jÕ*uÞÚÚzFõ¤¥¥©ï‘öÙ>?Y„ӕ›º>so9 \ JRSj:3_CW×fôôl@IÉ¥ Æ#óá”ùì@Ûjg\ßp×n¤RSöS’š2ÄTÄÍÍM]%—„nlGTT¬¬¬Ô\c–$M÷¼v(Ùš×Ð.QS•ë·7ÛúÌ­=æ€$I~©ñ¸¢MèîvSŒÇå ÆãÅ“íØ…. î8^Ç¥³/¨I’Ì1µ‘¥=²®à‡~PÓeeeê²(cOBŸj­©èÓ=/³/ ƒa¨|²ŠÙÔgní1™’šRÓ™0¯__VLÇF…›”×W&9DðåÁ=è¶uÀC»P\8š‹çI©Ô”ý”¤¦Œ€Ì…ѱØÛcׂ’Ô”šg2õëPaë`×,Ä\zMMÙOIjJMŸ/‚ƒ æ€ðõ¤¦Ôt~ŒGÊËÏ+ÆÃE=½üÕ«“>÷4檽\ðn'Î9¤!úd5e?%©)5]òý÷ßãÀŒrЀp6„3!Ô”´(M3gÑß/ÆÃ7'}îQÜi¼þÉ×nÀ¥5‰ˆ8øÉIÔ”ý”¤¦ÔtÁ ˆœÿ![ðJÞ‡ì~åèèˆüü| p4OB’$ivLIIDEE°b<œÐÖ¶E1·'}îAò9äTÌÉšu¸nóá?5 9!•’$IšË¬––\¾|YÍÑ&¢K.Hhh(Z[[9²§álg—¨)¹ š¦¦&âÍ›3p§O¾ÈÏ¿3és‘—ä¬n©{wu.{}DÒ“Ô”¤¦Ô”ššsˆD?Š‹‹¡ÑhÆÎ‘Ã=<<8§ázPêIMÉyÕTŒGeåiåoÓ:´¶nÅË—w'}."ó .º {­­¾Žóš‘p?—š’Ô”šRSKLB—üÀÀ@õ„t‚„³!Ô“š’ó¡ijj‚bW‡óeþ( °C›Ýz\°JÁßä>/¥ž¼æ5¯y=×ón@äÌÉ30 agg‡êêjƒÏ1ÂI=©éÒÑ4=ý™òî Ù£±q²³£'}î~î}üR²YÇ×¢kí:„[=Ek7â¦$5¥¦Ôt1E@rssÕs?¦Ûµj:¤¥¥ÁÚÚ•••Ó>;YŽƒÜ3UùRk9 \ JRÓ…ä»we“ÞÏȈE]] j<ö"+ëáäÆ#ç>WnCÒ¹5è]c(ëHvèÂÓ+¯ÙOIjJM©éb4 “í~5Ó]°¢¢¢ÔHJ]]QK’´»<‰é1´ Ô—–/ööáLIMÍ………áKGqñU=ãqøwã±_1&}oTNÔnÇãk¶è³³CâêëØ·¦OW²Ÿ²ŸRSjJM{úT46?d*c(§Aζ0tÎÅlÊ{{<„$Is1##öøüù²B”•]À»w‡0ÛÃJù×0ê0f>g>ƾûp°h-ê·®C›½'ÎXåâˆS?bà ¨#I’äRÏ‘h‡ŸŸŸòǤmìž¼–“Ìeg+‚„³!œ]¢¦äË—wÑÑá…ž7]—C¤¦äÎʵ¨Þí‚nû ¸¾:{í‡s±Œ:²ŸRSjJ2òdÉÕððð„û###f‘\M0„kA©5]8ʺ?îÀÀ€#ÊËÏ*÷’Õû˜j‚J¹ßgç„(›'Øf;„¨µÔ‘ý”šRS’9  Èààà„ûbJh@h@8ÂÙ%jºtÍß½ûY=Ë£¶ö(RSãÇ•2 ^Öý¸½ÿ’“¨#û)5¥¦$# “ÀÆÆhmmÅèè¨Jyíææ¦.Ï"h@H’\J 扨ª:© öáÅ‹'ž‰K3h@’ãÒ©%I’$s@ ï€5UzEEGö4 œ áì5]",) E_Ÿ3Z[·"'çþ„ò„´¯9ï&{ƒ„Z²ŸRSjJ22-ÄhH´C–\ å5Í ׃r}-5]ÌÏ¿…ÎNtwoRþø…O(OLMÄɪ“ØÒà€¬S.hv_kЀ<™$jB²ŸRSjJ2„ álgB¨égvv4š›·c`À eeÆ̵LJI™Š3ð«wDÖI' ÚÙ#Çá<¬» î‚EmÙO©)5%™sè.Û2MMMð÷÷ÇòåËUÊ놆†qÏ„††bÅŠ*CBB&Ô1]ùLŸ·ôö˜B’¤±ÌȈU”óššHMMWžœ’ŒóeçñS²~uÄ€b<²ÂãÑóžHŒþíÁk×^ÃÇg¶¶£ððÁÕÔ—$I’9 S†¯¿þz‚yЧö™™Ôk œ®nõ+ ƒ««ëXyLL <==ÑÙÙ©ÒÛÛ[½gl¹>f[Ÿ¹·ÇgBHjj ÅhTWŸPG}}€jDÆçɸTr »j\¤QŒ‡2íob³u.xu !:‹š²ŸRS’š2òeDŒ…l¿«}=µÏ˜Ú€Lflt·ü•Á·ü´×²S—±åú˜m}æÞs@¸”¤¦†™ŒÒÒ‹èïwBKËvdgGMxæjñUì«\ìöè··Gºý-¸[õ"Ä»‰²¨)û)5%©)s@Ì3ÄX²gÏ5ê¡Ýö÷Úµkê=-dY–Ü×B^Ë=cËõ1Ûú̽=F@8BRÓ©¿ßèêrGgçfÜšP^Žƒå‘sÜ}Hµ¿‹ÍÖ}¸äÓŽÄǙԔý”š’Ô”Åa@ZZZÔóG´K½äu[[›Ázt£1Ó•ó¹fRŸ9·'FK]xyy©.ZÛ‘å+¯yÍë¥sýáCŽb:v ¿ßE)»9¡üyãs+÷Bα5¿‡ûp·îG¨oòÒK¨'¯yÍk^/¡ëy7 †ò<æ*Ä××W€èæ€øøø0ÂI=©é¬ÌŸ(æc††PUõ«z° nyD^Žz"÷[ô:Ø#Éî>6YõãòÖOHzò‚š²ŸRS’š2²p¤««kÎ Èd³ùº÷&Ë{Æ–““1“ú̽=æ€p-(IMSSãQ[{LM0ÿþg¤§?W~?÷>Nåû /Ð=ÄÛGa“u?®øµ"9ö5e?¥¦$5eÈÜC»_i9ݬ»±Dÿ¾ìx%yº9 “í‚ÕÞÞnp—¨©ÊõÛ›m}æÖ# œ !©©n‚yyùy ¬Csóde=W³¹[‘ØÝŽˆµ‹VŒÇ ®moEâÓtjÊ~JMIjJMçÏ€hwºÒn·«O9"22ò‹ÍŒ!R__¯.¹Òž¼.¯åž.äì Cç`*ŸÌͦ>skç€$),, Cw·::<‘Ÿg\ÙãÌǸ˜¹ ‡V£S1Oì©Æãº ’ãÒ©I’$¹pK°fºÕî—@w‹ÝùÀbo΄K[ÓÜÜH|ú´}}®xýúò¸²'/žàJúO(<¸ë4xdwë!„ýÔÈË‹»Ÿ˜šˆO÷ãÍ.4»:â–}¼lFpkoÂöSjJM©)ÉÈŒ »,éžB®Ekk+V®\É‘= ׃r}-5GŠÙho÷V͇˜íý¤”$<~|U?Ù I1áö‰ð\=‚Ûû?àyR*5e?%©)5¥¦–c@d *‘Ž÷ïßËQWW§FF<<<8²§álg—¨é<03óššvªË­dÙ•,¿’ûÉÏ“ñ4êgÔl·AÆu¸jŸ /ÅxÜ9PädjÊ~JRSjJM-ЀH®ÇTööördOB’ä2==ïÞVÌß¾ýEM8×øÈèó³Å{7'„Ú§ÀÇfw¾7ãA’$I2ä‹!Ë­lllÆ´µµUOá&h@8ÂÙ%j:W æI¨¬<¥n©ÛظWÝbW-KNFòÝ@¼÷µÅ»Mθè _ÅxÜ;¬$jÊ~JRSjJM‰!h@¸”kA©éüQ”C?}òEnîý1ã‘vë(>ø¬A­»3Î:¤c«ígÜ;Rg¶Æƒý”šRSjJ˜²`Ð]¶e,jjjàëë‹åË—ÃÊÊ ±±±ãÊCCCÕyaHHÈ„÷OW>Óç-½=F@8Bš¿¦ùùwÐÑá‰în7†7Ž¡Ñk ª7»àŒ&~kFùË[jÊ~JRSjJM¯ñóóS€~ÈL·á5Ö€H’»,óÊÎÎV“Þe¹×©S§ÆÊcbbàéé‰ÎÎN•ÞÞÞê=cËõ1Ûú̽=怤y3++ÍÍ?a``ÊËÏ+÷’Uã‘}ý8>z¬A¥‡+Nj2±mí0î­¥f$I’äâ6 Û·o3údÙ²esb@Ž92!â¡ |‹ÔB^ëîÈ5]¹©ë3÷öáLižš¦§?Ãû÷ÕóššcHMM@Šb<ò®œ@‹ûT(Æã¸& þvÈ:QKMIjJM©)5]D–øäå婯µÙkÇŽxôèÑœo¿ýÑÑÑêIë’ô.ß´îiì‘ȈòZî[®ÙÖgîí1„kAIóÒ4%%UUAŠñpÀ‡û‘‘ñ)II( §kQ湚Åx !*¨šš’Ô”šRSriå€èšÝ×2èýî»ïæÄ€ÈsGÅðð0qìØ18pÀ`=ºÑ˜éÊù\3©ÏœÛ“£¥.¼¼¼ÔN¬uÒòu>®«ªªæµ½Å~M=M­åÜÔ_€’’å÷š+úúö¡¬,A5oÂΣc“=J¼6à°&;†Ö¶hô•~ÊþeÚ릦&êÁß§Kü÷éÒ¼^¨ß§ b@$Ï@ ш´´4õunnîœå€Èl¾-ĈHÛŒ€X~„$—* n¢«k³BwåúM¤$&¢ø|:Ö¯E±·jò±C3€‡§+©I’$¹´s@âã㨾Öh4ãr@d‰Ô\IªÖ7 ºìÉr äž±åÆäd̤>so9 \ J.œ¦ÙÙQhiÙ†þ~'”–^DjbJÏþŠN×µ(ôÞ„ýšWØéØGÁo¨)IM©)5%™¢‘‘üøãjäcÕªUª10…Ñ¿/ è²ìJLˆP–c:thÂ.P²;–¡]¢¦*×oo¶õ™[{ÌáZPrá5ÍÈxŠÔ<êê ¤'Ç¡ü̯èr±C;ö:a§S/Ÿ« ¦$5¥¦Ô”dÈ\ž2Ùy ““°°05ÇD–^ŒKBÈÙ†ÎÁ0T>Y{³©ÏÜÚc„3!äÂišššˆššãêÎVõõ‘™ƒŠÓAèv¶ÃKìÖc—K_(£¦$5¥¦Ô”dd¡ ›ßÁö÷Iè$¹x™Œ²² pBs³?rÓï£òdzœìçã…šìZßõÿÛ;§(εo¿eAAiY¯eŠ”M4"›AŒ$GÜ5jLð˜\¢ILŒFâAq%ˆ¢D‚"nÁ8ƒA%"÷ÇÝy›oféaša®Ëú•ÓËòòòŒõÚ-=='{úƒÒ¿6lÔÔtd¤tÄÊ;‡F×ݾý¥¼|¹Lž·gÊ»ŠÀãJβ2ù±<‘ª¯¸Áržâ)ž"”ü=Óß×ãç)žâ)ÂSZ@‚€èŒWæô»®b,úƒÒ¿vú«ÚkRyâqžâ)ž"|kh¢Ÿ5P±ºÝ•@Ó õüh¡&ýÿñíídèÆ"y•,ËWÊ+k¼Î‚…oœ§xЧOi r¢Sïj-{°½{÷ÊñãÇÝ~/::Z†‡‡G—õ³®³ºÝ•@Ó õüB_Й®ššKÒÒ²G†$Êë¢y¾4Uv­þN-ë‘ÝGj%vä߆dya¯Ä/–Œœ7²öÚ)cýéºÓxÈyЧxŠð”1 Á @nܸ!ÉÉÉÒÛÛ´¤µµU222<~Ï]:Î-5¾¶[9.Ò åüô„1åLvv¶q›‘´þŒåG5¿p_ÆOßËÍÍeð÷ty»c‰ü½8I®Ý+ñÉýòñÞÇÒÐÐ4nSøgß²ž§øaï²¾‡ ?¸ž†ú2×Óð¹ž=q7ûÕDgÁ²€hðÑÑÑáñ{´€Lß„‚¥7¾—Þß²dè³Dy“´P*Š7Iòâg²æƒ69sæ*!„B¡<Ý“üb5ñðx¡ë¬n·2&ßôB=?Æ€Ðt&©®îŒüñ[±¼=ºP†’Êåâ5²tE«¬\õ‡?ñ3žržâ)ÂS<ÅÓP@ìÄSâ+0ñ4 –v ó6K”§ív§jù1„¾ 3Q—/_”ÇvÈÛÓ#GêBi*Ê’¬5u²dÙs9t¨ O9Oñá)žâéL @¼µfL$QôÝÞÞƒám»Ýé…Z~´€P2Ótï^™¼¹œ$o2Êãüt)Úü½,J=Ÿ<êê<å<ÅS„§xЧÓ-ÉÏÏ7ÆL֛У¢¢‚…{~ŒA3EßÊËŸÓåMÁBéÎL–Í{JeaÒß²aÃ9wî !„BÓ1)(( 6\;ß3#¡6?íÐõë§ä¯[ïÉÐÆxy±l‘ìÝ÷/I\ú\V<•ŠŠëxÊyЧOñO§s¢]|F¤+ýýýRTT$§NâÉž„þ ô¯ šjkÏIGS‰¼ý$N^/Ž“¯?_%K³9Ÿûäë¯oâ)ç)ž"<ÅS< ‡Äyü‚ógúuîܹ<Ù€PBíRT-šöÈÛƒ åMJœTî]&™6HÊâ¿å³ÏîKu5žržâ)ÂS<ÅÓ° @Ì7¡ëX†ÚÚZã³¾ Ð®1 À„<éö/_Êà±y³d\ݹXòwýGeÛ¶ÇrþüeåååÆ;JTeeeãÒðµÝßý§{~Œ¡/h(©þ§“ÒWþ® ŽUûãdÓ¡c²té+yソä‡~ÆSÎS„§xЧh&¹~ýº¤¥¥NÅh b…ÂÂBãå‡ú®‘ÁÁA)--5“ÊÊJÉÊÊ2ŽI•““c¬³ºÝ•@Ó õüh¡&$TTûÓ9éþê=yækÇÉΓ¥’•ý—,[öRnÂSÎS„§xЧˆ±­®òw|ˆÕÄ D"##G—õá[ýœ™™iy»+¦êù1M¹ª/Iûwëe Ã!w7,O«Š¥èývINÖ †_¥ºšq!„c@œ¡{’sP0™H}}ý˜èèh#(qPtÕí®š^¨çG 5!S©–>‘ùñò{C>¿˜)¶Þ—ÄÄ7²yóïrî\-žrž"<ÅSyòÄë,R:5¯·Y¢y`ÌlU\ü‡œ>]‡§OñOñ…§A @Ì™®Ìév]¥¾Ç·elH°ß¶îùÑBMÈdëî—ŸI_æByð¡CŽ]É–ŒwyääôÊ÷ß7à)ÂS<ÅS„§´€L§Ú…Є1 È5~û•tç'KG^¬œø)M¾?yÉx{yZÚ€8ÐŒG!„c@Bk, ¡6dzúYÿà é\·LzÞ•«’¤òâ²~ý%)é|üq‹\ºTƒ§OñOžÒBŒ¡/h`ª«¬”'råŇœù!^Î_ûLvízd%%RUuOžâ)ž"˜1/äÅS<ÅS„§xJŒA“èç/‡ÈŸÙIÒºÆ!Õ ‹åêµoeÛ¶ÇÆ‹·ly"çÏ×â)ÂS<ÅS„§Œ!Z@P`~Ö{TÚW/•®ÌXù©v‘ÜlþLöí»/‹¿–¢¢§rêÔ5C999Æ:»¶Ï´üh™™5!5ÕÕÒøÉ6yž¶@š>Š—{m‹¥©éKù䓇’”4(|Ð)gÎÔá#ç(žâ)ÂS<ÅS}¸VƒMôsff¦mÛgZ~Œ _}só·ë.ûTþÌX$?ˆ“;IKË'òå—M’žþJrs{äøñø‡B!“èèh]ÖϺήí3-?Z@ÂKëQ׎öUIÒž·@n7,”ßÛ7HEÅUÉËë1‚C‡šñsOñá)žâ)ˆ•ý"##mÛ>“òÓÆ”3ÙÙÙF?BóDÖÿƒ±ÜÕÕÔüÂqÙ6Ü1²þÙ»¹u1Azzß—nÉæÍÏ$9ù|ñE‡´¶âŸ•e×ÿñ'ðe-÷øaïòóçÏñƒû×S®§AËŸZ@h¡ÄcòWÏrihøFvîl5˜oØÐ.gÏ^Á7ÎQ<ÅS„§xЧ´€ø;D×Ùµ}¦åÇ™€|ñÅIMý[V¯î–ŠŠzüB!„ˆ•õæ,O½½½^gšèöpÏðÕ•+g½ yyO嫯ð˜sOñá)žâé @œßâî} î}·…·÷\²=Üóã= ᩚÊÿHsÉ ¯Hu5>qŽâ)ž"<ÅS<%ñITTùM2´€Lo]ÿ÷éKuÈõ/¼Î‚uºî4~qŽâ)ž"<ÅS<%!ARí÷G¥­ IÚóãä÷_JkëNYºt@®\ó{>|(²råž!„Bˆ@¨ ™€Î“Æ«¥‰CîžZ$]]Eòã—%'§W–,ù[/~3âåÐhðñî»ÃrèЯøÆ9ЧxŠðOñ”@èêŸêþ[ºW,ÛJWûR¹ví{Y¿þ¿’”4(Ÿ~úPª«käàÁfY¹ò…ÄǯåÀûxÇ9ЧxŠðOñ”@¨ ±®Ë?VÈýÒ¤;Ã!- ‹ä×_÷Hi靯‹ׯïpû>üäÅSËxŠðOñ1d ˜5kÖ¸uQQQ£Ÿõá[#@ýœ™™iy»+¦êùÑ|ÕTþGîlN—žå¹{)U~ø¡fR¦Õ¥v‰sOñá)žâ)ˆ ­ÃÃÆ:d¬3ÑnYºÞD?ë:«Û] 4½PÏ1 ÁUýç¤/5Vî~'u?5kžZžV!„Bˆ1 S@ww·ÄÅÅIDD„!ýÜÓÓ3º]×¹iy»+¦Êùé cÊ™ììl£ÏŒ¤õÿ`,?zô(¨ùsù^õ9y\´HÚ bå^]±”•=“¤¤!cZ݆†&üœ&˦ðþe=OñÃÞe+‰\O¹žr= Vþ3"ÉËË3Z@œÇ€äææÒ- aÙôÜ9¹¹'KúSc¥ù‡Åräðõ O«‹ŸôYÆS„§xЧˆ1 S€»Ú|çuîÆ@è:«Û­ŒÉð'½PÏ1 “§kG>–î ‡<øh\úñ`Чե-žâ)ž"<ÅS<%±ñJÇ}8q7 Voo¯×Y¢ËxŠðOñ1ÂZ@&®šªJ¹½'UúÒbåúáBY³¦+d¦Õ¥v OñOžâ)ž€H©áè‡ÿ¼LpW’|ºõIL|cL«{ñâeüA!„c@@€{týôaiY/ä:äÔ§‡‚6­.µKxЧOñO- @2ƒúƒ^®>'·¼+/–ÄJýžÕ’—ÓÔiué_‹§xŠðOñ1@fHmÈ/§6-?L‹¦Å´ºÔ.á)žâ)ÂS<ÅS ™fº~é¹»{‘ô,sHŦýS:­.B!„c@€$LkC._¾ ·¾Ï’¾¥±r£d•ä,ëžòiu©]ÂSC999Æ:«Û] 4½PÏo¦·€Ü¾¶[~Ýá?—-”Òw éiu©]ÂS±Øènu.{·¤&½ ùiué_‹§xŠðOñ1d ˜3gŽTTTÈüùó%**Êø£ûûûG·k·,m1ÑϺÎêvWM/Ôó›i- µµçä^]¡´8äaÆ )Hx¶ÓêR»„§xЧOñO @l ""B¶oß.CCC288(;vì’’’1Û]‰ŒŒ´¼Ý]~¤êùÍœ1 Õr§qÜ-“ç‹ãeÿ’Êi7­.B!„c@¦­Í×ÀÃDm ¡Äÿüô„1åLvv¶ÑŒgFÒú0–=z4)éÿúëYyP“&=iqr5}³d-y&§Nýô¿/\üœÉ˦ðþe=OñÃÞå®®.üàzÊõ”ëiÐòŸˆªv @œ°ÝÐuV·[“áOz¡ž_8¹r嬴Ü.’–’8ùï’4Y¿èö´žV—þµxЧOñOc@¦€®Ý®4Qiw¬M›6›JgÇò6K”§í®]˜M/Ôò›c@ªåÁ½OåÎ÷qÒŸ/ß&~'k ;gÜ´ºô¯ÅS<ÅS„§xЧ 6qøða™;w®Ñõjýúõc¡+úî oïÁð¶ÝÝŠ@Ò µüÂ} È/¿|'–JçÊEr+y¥?›iuB!„†8' ÇüµäêÕ*ùía‘ÜÙµHþJ\,{ՆݴºÔ.á)ž"<ÅS ßiàBCížâ)ÂS<ÅSD €L\MMGä¾ÄŽ!G»[µ¶î”–[iò85CîÆ­“C[jfô´º!„BŒ%±±um]¡ô:–Êw¹ß2­.µKxЧOñO- @bS⎑õ—¸ Ð¿Oñá)žâ)b €Ø +WÎz @t;j—ðOžâ)ž"Z@B†œœ‰ˆˆ·¾¼¼\bbb •••ù½ÝîôB=¿Pmáb‚B!ÄáÂ… ’™™9.©¬¬”¬¬,éëë3¤AŠ®³ºÝ•@Ó õü@¨ AxЧxŠðOñ”Ä’ ã}øÖÀD?k bu»+¦êù€Ðá)žâ)ÂS<ÅSìÝ»WŽ?n|v @¢££exxxtY?ë:«Û] 4½PÏo*Óu§½Î‚¥Û¹ P»„§xŠðOñÑ2¥´¶¶JFFÆè²kânLHdd¤åí®š^(ç§'Œ)g²³³(Ú<‘õ–Yf™e–Yf™e–Yv]žˆ¸i™>- Ô†à'ž"<ÅS<ÅSD HÈ£‡;y¡ë¬n·2&ßôB=¿P @芟xЧOñOc@¦E@ân©ÞÞ^¯³DyÚnwz¡–- Ô„ <ÅSGçÌ™ƒ1ÐÕÕ%………Æ9ªÒÏ V/J`zñihhááa”ÒÒR# ‰“ŸŸ/7nÜ·oß¾;vL–/_Ž16páÂÉÌÌäÀu4äxòä‰ÄÇÇK}}½Qîµ"gÏž=c#W¯^ÐûÊàÿ“šš*GŽ1îOªÃ‡KZZ7ΩEoœ‘‘‘a3Ú100 Fm×®£¡Æ–-[hñ˜dÒÓÓ¥§§#`Ö¬YÓîþDÜ8gZ{G ˆ½ÝñãÇ–&Œ½{÷^r °ï:ªÝY´Â!11Ѩ …‰£^VTTÈüùó:}ÇB?ÆØxoÚµkFHqq±QÖõÞ¤:t豎€dÊÐþË)))FQ°çÌ ¼oß¾]†††Œî¬;vì’’Œ±‰+VÝÜ 0º»»%..nôþ¤ŸC½U‰@˜¦¦&£{‹>è}h ÓÑ£GÇ<<ƒÿ¨ÎA×ûyõê•ÄÄÄ`Äѽx˜h B×K{¸uëVÈ×ÒOt’mqê½@€$L©­­‡Ã!---˜1I0®&ð2ϬM ¡ŒÎÎæ€hP£OÜ¿#&é^ê÷' CNžF‘@€€@@€@@Æ0]^¼É B€  ˜ÞÁ‡³\·ÕÖÖJFF†DEEItt´äååIggç¸ý._¾lì§û8§ÓÜÜ,¹¹¹ÆúÈÈHIKK“êêêqÇrâÄ ã{³fÍ’9sæÈ®]»¤¿¿Ì>gÏž•¸¸8ãXåôéÓ㎻»»[6mÚ$³gÏ6òÓ´6nÜ(wîÜá€P B<­× âéÓ§2<<<$¤§§Û/''ÇØÏ™¦¦&# Ð ¥§§GÞ¾}+;vì0ö×àÁ™£GŽ6Ìè>º¯Éõë×uF`¢ÒÏ®Ç¯Ç¦ËÆòëׯ€G€ Äß~ûmt!f+…ë~ãÒЇ~ÝæÜb244d¬KHHðy\ÚŠa’••5îxÚÚÚÆ¿›ªµµ•@¦[âk½·1ÚÊ]7/× F”¢¢"#àÐõi·++Çc¶€¨ô;Úå«´´Tž={Æ  ဘAƒ¶œxà œ»eM4Ñ1 [¶l‘yóæ d4 ãDŸë¶úúz¯Ç`¶”˜hw.×t­vÁrFÇœÔÕÕÛ5€)æÿ÷t$nwrïÞ=cö«äädioo7ÖéàñóçÏ…‰¶Nh,葵k׎K×yú«W¯ ŽÛ/??_®^½j¤£è,\º}ÅŠüØ@0Õh·'ªÖj`áO¢è`ð?üÐß¡ûiÀ£Óä:O‹«Á‰vÃÒñ‡C***ܦ«ÓðÆÇÇ­Ôè²ë~šnII‰ñ7™Súj—,Æ€€€€€€€½ÈÿüÏÿ „B!„ФjL0i- @  @bÒÓÓ#ëׯ—˜˜‰ŒŒ”¬¬,©««³üýˆˆKû¨4ý9sæHII‰´´´LÚßdæçéØººº¤°°P¢££ éçÎÎNé566Jnn®DEEÉìÙ³eëÖ­ÒÛÛ;f{NNÎèöM›6ɳgÏ‚–ž¯¿××vwÔ××Kjjªq ñññrúôi·é¹¦íi›§¼}y¡”——秪¬¬Ìï¿ÍÛ÷'Ê×Ô”/oûÛ]¾&rŽQ¾(_áZ¾¬ž›îÐt]÷w—žþ”/€i€è[Oðׯ_Ëðð°Ü»wOÖ®]kûÜD󩨨yóæMêEÜÛ±é…éÈ‘#òöí[C‡–´´4é辡¡ÁðgppPJKK‹ŽI~~¾Ü¸qÃHK÷9vì˜,_¾CzƒÒuVó²ú}ÊWø”/_ûÛ]¾ü=Ç(_^®=#ÿ(_Ó»|ùp8sáÂÉÌÌôùý«W¯z}§|3‰õ,h­Ž7º»»¥¸¸Ø¨iÑ} F#|«µî¶:uJÖ­[7f^TæÎkÔ&h-ÓÀÀÀ˜íŸ}ö™Qó¡5 'Nœ˜ðdÖ¬YãÖižVÑ‹/ߦ"=»ý½ÏŸ?p:¹¹z¡_óF¢èg½IYÍËê÷}1r¹Ùˆ$&ЬZ%ríšµïQ¾¦¾|YÙ?òåï9FùrÏ#ÿbGþéÿV¡|…^ùšÈy©^%$$-9¾¾Ÿžžn´|Q¾B%ñg½z2ïÛ·Ož>}êv{JJŠÜ¹sÇ(XZã¡Ñ-[¶L¸ɹ&I/Ä&4j®4Ê×|¶oß>¦ÖbÿþýÆÍC· Ç1Ñ ˆ^ ´ÖHÿ&Õ¡C‡ŒuVÑæ]çZ× ÐñãÇš«Ù•ž]ˆþ.êñT\À]½ÐõÀÙ]g5/«ß÷|¬X!#åàŸå‡ÿY¶„P¾¦¶|¹Ûßîòåï9FùrOéÈ? @ô«P¾B¯|™]¤ôA<11Ñ8V_×Þ½{t|å§Ç¾k×.î_á€hmèùóçÖÜxëÿ©ÀùÂ;Ñ ¸kíUìȱ:ßDôïÜÏS›Tµï«?xÊWkÅâââFk¾ô³·gÚÚÚŒ›š»c1ÓÓæùŽŽKÙ™ž]ˆ•t¬ô‘õ÷îÎ wi¸«½óÇ_µ®è½Õ >L4ÉÉÊW—/OûÛ]¾ü=Ç(_ãÑV…#ÿnŽüÓÿ­¶‚P¾B·|)íííFà¥A¢§ôZ[[%##ÃÒo²bÅ yòä ÷/€) @¬vµò³K–6ƒjZç‹Öi3 FÝfAunžè\ór½è ÄÔDò±Z¨óòòŒZç>´žj„œijj2š‰õ‚éíwôèÑ1+½éÜâÉ‹©¨Ar-2#÷”qŒœ6~÷x¤|·²ÚŸÔyF T§³<(zݸqã˜Â¢_Í¿Vfùú믥¨¨EæÆž´IDATÈh^V´FĹ¯®Ù‡V!Ð>´ú÷éßé܇ÖÛ,"'Ož4n0žš~µ €9 ¢^lu0¢óEÂõ8ìNÏîD/òÚ¥¡¹¹ÙXžÌYD|ya΢¿{ ³ˆøú¾7Bù ~ùòµ¿ÝåËßsŒò5–Òÿûçkåkz”/ý»Í õC#çq¹OiY±:øšòìd‚³`é )=Áµ¹X›öt s_VÝ®óhëvòµÀ9‚Ïlr¶Rá7í§ë®X/âÚŸUóÒ©«««Çl×~¤zÃð5‹ˆ¯Ú½8šsw«ô³§>¬Vjh´D×üû\ç·2¯¹Ýéù³ÝÓy¡Ç ¿…þþgÏžõ»ÆÊŸ9ö½¥¥78+ó¨{:oß÷'Ñ–… ÿiù°: å+øåË×þv—¯‰œc”¯èùëåŸn§|Mßò¥-?úwëµ úà­SÿZ…ò¬€@@€@@€€@€`z ===²~ýz‰‰‰‘ÈÈHÉÊÊ’ºº:Ë߈ˆ°´JÓŸ3gŽ”””HKKˤýMf~žŽ­««K %::Ú~îììô˜^cc£äææJTT”Ìž=[¶nÝ*½½½c¶çääŒnß´i“<{öÌkzÞöw>~SêÛDÓëïï7<×ísçΕC‡ùô°¾¾^RSSïÄÇÇËéÓ§½Ÿéµ§mž~ _Þ*åååÆù©*++óë·öõýÉÄ_/ìÊ/XåÌ×oçïßëk»Ë…3ºŸ¯ã´ûø(gFÈK¿2Ò€Co¯_¿–ááa¹w]»ÖöÄD󩨨yóæMêÑ·cÓþ‘#GäíÛ·†>,iiiÓÑ¥¡¡ÁðgppPJKK›¹I~~¾Ü¸qÃHK÷9vì˜,_¾ÜczþîõêU¯7t_ééƒ×öíÛehhÈ8þ;vŒyÐqåþýûòÎ;ïÈ­[·Œe}hÛ³g_¿¹Õý|y[YYiœ£}}}†ôAQ×YÍËê÷ƒŒ3`”3_¿ÝDÿv«ûZ.L.\¸ ™™™¶ž×VŽra€ÜQìˆ,g¤µ¥Þèîî–ââb£¥@÷-((­9³Z«ënÛ©S§dݺucÖéÍZkèµ–NkoÆlÿì³ÏŒE­Á;qâÄ„o̳fÍ·Nó´ŠÞÄ}ùæOz¾öOOO7Zª&šž~Ö‡ýìîAÑDïóçÏü6‘‡nWoõ¡Æ|@Sô³>,ZÍËê÷§"±²ÎW™…ræ«\LVh¹PôoOHH0Z@í>¯}å  Ñà#eDÿïkAˆÞ$öíÛ'OŸ>u»=%%Eîܹcܰ´&QN¶lÙâ×ÍÏÝ>ZC«8&4Z^´öLóÑ{çÚÀýû÷Ánך|=Ž‰Þ˜õƯ­ú7©´K’®³Šv›ðô¯é?~ܨq´â‘»ý]óÚµk—åwé¹ êŸ”žÐßE÷™Š#Woõ8õorþûÜ»§¼¬~ß+±^4‰ˆ¯2*åÌW¹˜ŒÄŽr¡ìÝ»×XïîûÞºZMäø(gfÈm— ã¶å D[3ôF9þüÑQoãôÆâü@3ÑDq®‹郓sÿiíª c7ìxÑV¸¸¸Ñ–ýlµ&µ­­ÍÊÜ‹™žv{éèè°ô ãngV¬X!Ož<±ü`ä.½7Ý®41»`ykÁñ§/¼·0ŒÜyë. jÙ­~ßgâÏz›_e"TÊ™•rawbG¹hmm•ŒŒ ß$qw|”3˜æˆ»ªØÏ]öY'þVÙjwâ|SÖÖm^×Ú,óèÜ…i¢ˆæåÈhdj"ùX½Yæåå- Îc@¼uI2ijj2ºk胋·íèÑ£c<ô†·ýµƒ?-3žÒÓAè:Ñ€úªæÉ“'½>ÈNEͬ'o§¤fÖj±ñ£xM$ñU&B¥œù*v v• ýl¥¢`²ŽoÆ—3˜nˆ+oq‡k©ÎŠ¥êŠþïú4‘¤öMw¾Ik>®³²8cg ˆ»š9_µuµµµâp8,èõ·öÏÝþÚ=NªúºRUUe L÷„ŽfßtoÞºë[®ë¬æeõû~$6tÁÒç‡6 \[@¼•‰P(gVʅ݈]åb¢3”Ùu|”3˜æˆsÐáß½ :ñÐñÎ3Bé`U=EÑíÎã|Ò)}u_²2;Ï×_-EEEF÷(Ek&Çš˜}Óõ¢ŸþÎc@¼Í‚¥-úàæ©K…va3§ñ}õê•1È×ùæëz¾öWš››=âô7½Ý»w¾éߪ}¿µÔS—/Ež´¥DA™ÌÙy|ykή£ÇÈì<¾¾?Ù¸;>¤¬ãôwÑãÓîÎûù*S]Î|ýv“€ØY.|}"]°¼å Â01ƒÿfÁÒR½qhm¬6™ëUç>âº]ç§×íZ{¦72ç›Nmivåðvƒ4¥>h¹ë®¡G:CóÒ©r«««Çl×ÁòðøšÇW­¦>t™sâ«ô³·r_5¥Z³¨Çkþ}îÞ‡àŒ¯ý½ë¢V8|¥§-æí~¦}À­œš¦þúûŸ={Ö²þ<YIK­¼ŸÀÓqxûþT Z4ð5Ë– ®ûù*¡VÎ\[Gýi]°²¿åÂß$Ð㣜@˜ ÊKÜ€`  @  @a€ „B!„Ðdj4ÿü,JÇ•X6¦IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_get_line_wide.png000066400000000000000000000755301174000617100242050ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix{IDATxÚì}iL•k{õ›4MÓ4_šþišþhš&MÓMÓôOÓ4Í›7çD{NNÎé1 ó “Œ"8ጂâˆ"N8{@PQ™gPQADA™ÇõÝ×í d”ͼYaïçÙ<ÏÞ‹½Ÿ}¯ûº®ûú‚ ‚ ‚ f ¿£AAAЀAAABAAABAA AÄRÃ?üÃ?àw¿ûÝ ÿñÿqñ}y y}™Fss38€ÿùŸÿÁÿûÿú§ª)·ÿë¿þ ÖÖÖ¸zõ*ß|A4 AK YYY_ Î…999óf0¿Ð HLL þê¯þjT]gêy,Äÿ A AÄ„‡‡Ç¨c777o@ddä°óüÍßü Μ9ƒ¶¶6½¿««K›>‰ŽüÇü A AÄÒA__þú¯ÿzpÐú—ù—ÃÎìN >|Ð)VºüÅ_ü^¾|¹¨ A AñÍHHH6huvvvÿþýûãr'“VT\\ {{{üýßÿ=þìÏþL×AüÝßýÞöäÉ“I¦wíÚ¥M‘C"òܵµµúXuÿú¯ÿŠ‹/Ny€^SSƒÍ›7ã?ÿó?ñçþçúXbÈÌÌÌ––6)=wìØ1ì[¶lù¦ÿ‹˜‰Lýó?ÿóàs‘×nnnþUjÜ·üO‚ ‚ ˆ9¥¥åàU¹ú÷À6)”žÎ`÷äÉ“ø“?ù“q{ìØ± Í‚ŒÑþVЏe`>ھ˗/OÚ€H͆D+¦;€—âò¡“——7åÿ‰¼&1Yã=1:4 A4 A ===zv}`€úã?êíË–-Ü&ûåq„Ñ 3õC#‘IQjhhøj >Ѭ¾¬$%æHçcíÃ1tû¿ÿû¿Oê9K„f¨é#"5òº%EMžÛŠ+&¥éP=…ò÷SAaaá°¿ÿî»ïPWW§ŸËêÕ«‡íÓ4Õÿ AAB1g9˜ÖÛ¥8zèöëׯ“122ö˜‡î{ôèѰ}òØñŽ/EÛ)à¹/##Cï“ÁþÐíb&óœ%­ièöoÖt¨‘M—‰¢&&&öWTT îùÚÿûßÓ€AЀA,üüóÏì%%%z»üº]÷-dh1öÈh€ÌèÝ'ïøCÿv¼}〱žóÐÂ{¡ôïøVL™È€Œ|.ãq²‹ ‚ !‚˜sÈ {hm†…Åк Ô766Ny°;•h€=¥®“Ou°;^dd:ÑD™ÜgÈÈÈU°†‹O湌ÔLtšô—# A AÄ|…ÔLÅ€|K½!k@frŸ!k@¤À~ht¹-ËOÖ,ŒÔl´å„i@‚ h@‚ d@îßþíß÷Él¼Ô7üË¿üË„EÜaÿðÿ +”®è²MfôG½ÐϲHdhh'ô*‰~ ,õ;HoÑðÿ÷u‰¼n1ÒgD´”%w9‚/^Œ©Ù?ýÓ? þ$éѲmÛ¶Q‹Û§ò?!‚ h@‚ ‚ ‚ !‚ ‚ ‚„ ‚ ‚ ‚„ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ h@‚ ‚ ‚ h@‚ ‚ ‚ !‚ ‚ ‚„ ‚ ‚ ‚„ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ h@ÃbÛ¶mÃî{xxÀÙÙyÖ9Wç] ¤¶Ô•º’Ô–ºR[r>è:rÜIB¢áââ‚GÍ:+++çä¼KÔ–ºRW’ÚRWjKÎ]i@ˆye@?~Ì‹µ¥®$u¥¶Ô•¤¶‹XWb^’$I’$Irq“„`„3$u¥®Ô–¤®Ô–ºÒ€Œ‡ßÿþ÷_q$ÂÃñ|ùrͰ°°)ï7ôñæûùXÂ\O’ºRWjKRWjK]i@Æ1 ã!66îîîhnnÖôôôÔÛ&»ßÐÇ›ïçc„3$u¥®Ô–¤®Ô–ºÒ€LÀÈà[D€Üvss›ô~Co¾Ÿ5 $I’$I’$ ÈäÇÄwß} DDD Û¿lÙ2ô÷÷Þ—Û²m²ûGbºÇ›ïçc„3$u¥®Ô–¤®Ô–ºÒ€LÕÕÕðóóChhè¸1+“Ý?™ˆËTŽ7ßÏÇæz’Ô•ºR[’ºR[êJ2´µµébkF@¦~>y p(¤;¦¼1ܱüžûååå³z¾¥t¿®®ŽzÌÀýR¾_Ê}¹ÎR~ñzÀûsùýµ( Èh5²m²û'S“1•ãÍ÷ó±„$I’$I’dd¢¦¦Fß®¯¯‡¿¿?‚ƒƒ¿Zª©©iÜU¢ÆÚ?2…iºÇ›oçc s=IêJ]©-I]©-u¥™RSSagg§î+V¬Ðõ]]]Ã#½/Æëƒ1ÞþÑj(¦s¼ùv>Ö€0ד¤®Ô•Ú’Ô•ÚRWy„ï¿ÿ~QŸÎtÔ•ºR[’ºR[êJBЀ'ŒŒÆ$õ1 ÓÒîS’$I’¤!! Èh 1Ÿ<¹(b¢¸øõ00‹‹³¨¯³Ô•¤¶Œ€Ð€Ð€0Ï“„j>z{-Ð×wFÿ¦ ¡±cÞ7u¥Ô–ºÒ€Œ€Ð€Œc@zͼÐmá‡N´­ÞÏ®{ÐèµõëáÝÖ£¨Ús‡N¡ôäiŸ;‡Ç—.!ÿúuäDE!óöm¤ÅÅ!91qI›žž,-goo!Mˆµíé1GW×)eî,©)¯³Ô•¤¶Œ€Ð€Ð€ó©÷SPx¶!ãý…n8™â˱~¸umžÞŠì(Ø…òxëµv£Åf:Ì·¡{Õ&ôš®StCŸéjô­´D¿±‰âJµÍB™;tØ8¡ÕÑ ÍnÞø¸Öï7nDíÖ­¨Þµ •AA¨8xeGŽ 44%gΠ("…W¯"ï·ßƒŒ»w‘š€GIIßüú““‘–ŒŒ»Èʺ…œœ(äåÝ@aáU=¸•mIÉi”–†¢¬ìÊËCðêÕTV¡ºz7Þ¾Ýwï¶àýû¨¯÷ÅÇÞøôÉŸ?»¢µÕ¶ãÖÖôöš(®Òƒèîn 5¶T´Fg§þÛöv;E´µ­ÖÇkiqRtÑÇon^£Îå¦Ï×Ô䉯F/}þ}ÐаN?Ÿü7èçWW·IÑ_?ßÚÚ­ŠÛõó¯©Ù©^Ë.ýzÞ¼Ùƒªª@ýú*+÷áõëýúõVTT<¤_ÿË—‡•G´/^Çóç'´>¥¥§ðìY˜Ö«¤ä ž>=«õ+*:¯¡õ|üø’Òö²Ö· àòó¯k½óò"‘›¥ô¿‰ììhÅ[úÿ‘™y[1VÿÒÓï©ÿUœþ¥¦&èãŠnŸ?'ýñZDB’$ÉÎrÌKÓŸŠW’Ðî¦ #šíwÞu\rU Ï«_˜`Sσj@¨ª;Ôv“Ø®S^5vRd[5p6ï6ÇÊþ•0ë1ƒm›-\]°¶v-¶–oÆÁ¼OÜ‹Q‡wö2BÂP´ó¬22çPíwu¾'иö0š½÷¡Ís7:<·(ú¢ÓÃ]kœÑíl‡+ôZ¯Bÿ*ÀØHý^‰>[Sô:›¡ÇS æý”ÉÙª¸ÇÝÁŠ',ÐsNñê*ôƘ¡/^ý]š1ús•!zb†îR t–[£ý=Zëœñ©aÐË@^ð2pûv›¨Ë]æååÁz .pxË€[Ú2À–µ ¨e =ž®©©ãuqzzzœhßSŒUƒî;j~[ÿ½ Èe`.Ç“º Øåø2€—¼œOö2À—óËÀ\áò|Ĉ!ç'AŒ‚<_1/^ÕÏ_ … y=b4ÄpÈë{ýz¯6"òzŘ¼y _¿1.¢‡14¢1:¢—1@¢Ÿ"1F¢§%1LbœÄ@‰‘C%ÆJ –-1\b¼Ä€uv ­•)³RÍR‰$©ÿa¯©N»võ’Þ.ÏI^ƒ¼VÑ$77R›~þy¥®Ô–d„ ažç,šŽòÃYh[} }+=ÑneƒäNð­4ƒoƒ/N>;9îL}vvŒËÀW¼2¨“® le'Y™!—AŸ Xe *3ìoÞoÆKuü§jà™¯›éjù°Ãw»¬ÕcŽKj ®ŒÊQ5hÜ«¸µßëÔ}WEuÛÆ0S¿ízMàÖ½ ~íVØÖl‡½ Î8Z뉳¯üpýéVÜÍ@òà äÞ9€§7¡ìüaT:ŠÚÃÇP¿ÿöAý®`|رï·àýæ­x¿a#Ö­C“§'>»º*mV£ÓÆ=ææè71AÿÊ•ú¶l“}òy¬üÍT¢5¬­™¹ô+‰xyƒÀZ™Ÿpý~¬ª RFÄ_ŸµÚÜH´¤¯ÏD{e€ÜÕã6ê÷©/yËûZÞç))¨/¯³Ô•Ú’¬!h@8Ëñ­¦£ìx!Z£Ñk² ]«Ì‘sÀ;žšÁ¯þ‹éˆO×Ϲ©†ÿcÿÔuÚèAœÌXË ¶ÌhË ·ÌxËl³ÌˆË ¹Ì˜Ë ºÌ¨Ë »Ì¸Ë ¼ÌÈË€Qfìe_fôe†_fü%œüpÌב˜’ˆ{êqÑÙѸ® ÐEuœ3%gpBŸuž½¯÷bwånl¯ÚŽÍÕ›á[ë pjr‚M› L{La¢ ŒM« \ê]àSåƒ-϶`oî^I9‚°„0\¸{×b®!:2±×c‘p5.'"óÂäŸGqXJOÝAIØu”„_À³°0¼8~å!!x½?ÞìÙƒ·;v ÎßüüðÑÛŸÜÜÐâä4®y³{7^*ãR|ö¬6+R+Ã÷î·˜sÚ|TVFŽûx1U³!¦CÌGuu€6#ò¾sÒ×gªÍмß½µ‰S-¦FL·˜pI KNNâ¬'I]©-u¥!XBŠéxZŒÏ®ñè1ݳU(Þe‹Y¦Øð~¸éÁiéIe"6£»ÛJ×ô÷›Î(×Õ%èØbÈ©OLND\zn©Áç e€.=¾„³j0yªäŽ?=ŽÃ%‡qàÙìy±ÛË·cSå&ø¼õÁšk`ßlU]«`ÒgëVk¸|P&¦ÒþÏýð$ràhÆQ„%‡á|ây\I¸‚ßîÿ†˜¸ÄÆÅŽk@$r"ÆE¢*­ÎÎ:âÒkjª#.k×ê(Ëë}ûÔÿ4/^Ôµ/)K´˜¢U°&2S¡¤kIÄO"}á“ÈÞÛ·ÛÑÐà«M¸Ôéô÷¯Ô¿å¾l—ýLû"I’¤!Y2¦£ôÔ34»¥¡{Uº•é(ßh…ÐDSø×ø šŽ””D¥ÙEÏ/9÷b.$W_ê$1tF¹­íø¢1†bRrî§ÝÇm¥Udv$ndßÀ•Ì+ˆÈŒÀ™¬38™}GóŽâ@¡22Å{°íù6¬µ~\²ùÕfì*Û…½¥{\Œ#¥Gþä¢Å£ÈC(8½åûðγNÿj·³CŸ‰ º­¬tJXýúõ: ¬üÐ!”„‡#ÿÚ5]œ?Âü…ȹè"©×‘ˆˆDFkÚ¯³Ô•Ú’Œ€4 Ìób:JñÉ£Ýæáè´°Â[/ \¼eŠÞƒ¦CR^¾ Ñ…À²ÚRs³›^ݨ àê¨)$çÎÃãêÿÚ„ðð’E­cbb2âãÓp÷nnÝÊBTTnÜÈÃÕ«…¸xñ‰Öãô鄆–âØ±2„„”ãÀW ªÄîÝÕØ±ã-¶ly‡ßÃ×·ÞÞ•~ŸàêúŽŽ­°³k·¶fËÆ*ìÞUŠýòpèÔC¾…à„“:²²þõz‘42‰¾è‚þv[¸|v†•ŽåzáÚ=o<¸è…üwTlsA½‡=:¬Õ ×Ôm¶hôòÐiaUAAxqìŠ.\ÐK#§ÆÇ37y–¸ÐÓ¾Þ¼)åà‹ß_Ô–d A²Tg9LG£÷ tY\E‹­=Váæeì{ê©MÇÃÌ;() ׫}YAÈVß–Õd¥¥ñŽáB‰4÷¢¸¸_ÿ_sršÔºsÖLHRR2Rqï^:nßÎDtt"#ópíZ.]zŒóç‹pæL N) ŽÇ_âàÁ ìÛW‰={Þ`çÎlÝZ‹Í›ßÃÏï||>ÂÓ³ kÖ4ÃÉ©í°±éT檦¦½06LLú±jU¬¬º`kÛÕ«ÛÔû¹nnŸàåÕˆuë°aÃøûש÷ý[ìÚUÀÀ*ìßÿÁÁå8r¤ 'NoœØ‚̈}H ã{¿áÑÃ…“êuûåíÿùži_EE_Vc$”ß_Ô–d„ Y‚¦ããÚJtZÞR†Ã­Ö&ˆ?µÇr¤¨}…öx®ŒaÕ¶Z¼:ø ÏN=Cá•BdÞÎDrâC$ß‹DZÔidE@AèV)‘ˆ‰DNä=)‘‰¨HdE",QWÍpâáJy‘Œ[£<›<±¾~=¶ÖnÅõ>•2Ç_×+™]TïÙßò~ÃíÌÛHHMø&üÕà[ ÈÎ;ùEm ´¯ÊʃÊ| _â˜&„ß_Ô–ºÒ€4 ‹,ÏsÀt4ø~@»u&j|6 Ýr%žì4ÆÕ».¸^¾ åo·£­ÍAwË–¦oÒXNV²ú–«D3Ä lÞ\{5µPT__|)-íÕÑ ^|î{öÁƒÁ’È•D¬$R%ªÊ@z:·ÀÞ²K›kÓ>xš÷`‡â1eN®¯î©Û©ŽmÈ_ûÏvÔ ìðKŸ-FÞoyH‹KÓ襦DjKdYbé‰"5'R{Òfo«kQ¤&EjS¤FEjU#¼pí®ŽæxêZçÏN°é´i¯©n^i©Þß«ÛVýÙ]7¸ô¯óÇ®ê]Øÿz?ލÁ±4ÃŒ(Š·¶†ïµoOû’eµ¿4y<õå ~¾ Bo—æ’ÒãG–Ü–H«œ'O"§Œä—:®ÒÆ:jK]i@F@€éh@›M^o؆[S”¯7ÆíH{Ü.÷Å»O:­ª©ÉKw©–/ùG’¦8MÕ©<’µV $ÍÕ RÒ›d¦\R–$!¦$6¶Ný/1,UhõêžE_ˆÎ÷ìS*µ7¿)c!©kò¾Ø··;6¾Çz·f¬±í€•é£)ʨlPå€I?Ϊû¿Yv#Ω)ë·³ÅÇÊðøâcd+Ó“ò Y¯Ê%«sIƒFé›"«vÉê]²ŠW—¥¥^Õ«ÃÞ^¯ò%«}•ï߅°}HŽ Ñ«…?>ªû½©;°ñýFxôwu1û{8¶:Âõ³+<ÔghmãZøÖûbã‡:b²]™ù€êUaÿ«ý.ÖæFzˈÁ‘%š/<¹€Ë…—uï™(5H—%œc3bõJhR éÑâ]il*äêÚMóAŽX5,E¯våJ¡~9ø {ýßa›gÖÙ·ÃI™[3ã~X)câiÒ‡êöQeX.Xw!Ò¥qê}Ÿ¼«ÙÊàä]ËWæ$C™”DÝßDúœH'yiì(ýO¤ŠôC‘¾(ÒEú¤H¿é›òêàÁq ˆ˜1 bÄDˆ™S!æ"ôy(Ž–Å¡òCÚ|ˆ 3"æf‹(‹Á³"¦EÌ‹˜13vj@m­Øæ=æzU2cõ#¿å¾l_L¦g>ÚÕûúê· P·ij7¯GÍ–õx³}=*w®GE€Êöøâù^_”ì_‡¢`<ñAþѵÊxy!ã¤'RO{àÑYw$žwÃý‹®¸{Ù·®9âæo«qã¦=®Ü²ED¬5ÎÄY ì9Ž'™âpêJÌ0ÂÁLõ;ÓÁYæ8”e…,[ÎrÀ‘l'Ë^ƒãÙ8‘ãÐìu8•½aÙ›ž½ g²vâ\Ö\ÈÚ‡‹YÁ¸œu×2Cq=# ‘ç~ ·Ò¯ánZÔ´ È·Ô¬dfÞA^Þ &é¥åå!º&EVñ«WFîÓ'7´·;躕/«Yêú•¦&OuíÜ€·Ê@ÊbRÃRRrZ×Äɪ`w‘œüpÞ}Fæ¢w ¯³$#  È"Ïóf:ì?âñÞ£(Ûb‰6kc2AQ ÞZ3nOޱVG’bnYùÉÛ»Q/!+5[·¾Ó«QÉJOÌ¡eíB ,< Ë-_¿ü¼DØŽ„ø4`s+6ZuÁÕ´æjl© Ї2*[Wõâ€2)§”I ßùjÜAò½û÷ýÉ‘ÉH¹®xY1B tÏ«ÏæŰ$¤†*S<ü©‡÷'"uߤ*îN@Ú®¤ïˆGúÖûH÷Cú¦{Hßpëc‘á{>·‘¹ö2½=cå,·›ÈrD–ËoÈv¾l§ëÈq¼ŠÜÕWçpyv#o{6çP`}…VáŠjÀl†Ç'ñÄâŠÌ£Øü(ŠWÁS³”˜ã™Ù”šíW ÂsÓ=xa ¸e¦ÛñÒt+ÊMý7¡Âd^™ø¡ÒdªLÖ¢ÚÄ 5+=P»ÒïV®Áû•.¨7vBƒ±#ðÉØŸlÐjd…v#KtYŒ«m•:^™©Ÿzn[P`± YVûfsìB‘¸úœ®à¾K‹»^pÇ/1[ÒpsW&~;ƒkÇòqå\á°)$ª& *HOéÍ3ñj`µ±ú•Ç/iÃñ¥x~Ÿ6"bHĘˆA£"†EŒ‹˜æfwmhÄØˆÁ£#†§¨èòóo(#t{FCÊ‚ÞÞ­°°èƒ§g®\yÍ믳ԕ„`Ä0¦£ÅîrGÑ>+e:ŒP`Œ§É«ðºjÓ¤zr ö7P4)Þ¡g²|­,S+«PíÙS¥¿Èd¦™3HœAZÌ”Aé­«ˆ_‡Ôga¼A²…Eõу­¬âfÔeb$ââ¬èº²nŠî+ûtª˜·¢iÖ)Óã§>cRã²Q™ûÍæ=Øbу­–ÝØ®¸C£]Ö]ØmÓ…=Ê Úv`¯]öÛwà€C;®nÃ!Ç6„8µâ°s ŽªçyÌõ3Ž+žpkÆI÷fœRŸß0Ï&œöjÄ™µ8ëóçÔk:ïW > bã{\ÜT‡Kþïpeë;\ÝV‹«êómg ®«×c÷üX…È JDí{›^!:¸1!åˆ9\†[G_àÎ ÅÐRÄžz†ØÓOqOR/Ï!.â î+ïÿñ×ó‘ð[Då"1&‰·³›¤¸ŒñÓÛ.^Bô™³ˆ EÔ‘#ˆ:xÑ{qk×NÄnÛ‚û›6⡟/Ò¼½‘¿Æ%«=ðÊf j-œÐhj¶•–è16A¯‘ ÚŒ­” rD­±zŒ‘žmE¾Q Ò!É8÷WžÅ“˸i‰ëæwpÙ2l’qÆ!§\òêþÇ|J²éî,Ǿ ±—ä¾z5ÑÑɸ?N˜(dg_@qñqe@ö*3"iaÞ:LRÁ$%LRÃ$ELRÅ$eLRÇ$…LRÉ$¥¬¸ø¬ž<’%%ålºµ5ü¬ó:K]i@Ö€|›éXÝŒÌKÁÈ9a©Ó«j6¡$ÆÏ‹öNª'‡4â“Aùòܸñƒî…!}2¤÷áC废Åb_®–$ Q(M}æ¶dpŒÔ¸“y‘y‘¸ôø’^zY–`–¥˜ƒ^ïFPÙ•ú"¨Ø{ ±/ßû³Mq8e%ÎݲÁ'Ü;î†G{½³ÕžëPæ¶U«}ðÎÚ ÍÝðÙÔ ƶè1²@¿‘±úmŽv#{|2rÅ㵨6Þ„ò•;Qb²y&‡‘jz ñ¦mr—MnáôÊ6NÃ^ã\˜aÛªçð·¬ÀÛ7ðu®…G|}¥Ái%v®‹Õõ8¡¡)8{ö>®\¹©ŒÍeÜ»wF™åp$&†«ëôõúÏ"%Ejø.*^Q¼1ë©m$É‚d¹ña¦Ãï5Òã‘rÉunFhp7Ƴ «ñ$åø„ËQJÿ iè'½¼¼štC>éµ±m[­îŸ!]´9ƒÄ$rt橱œ‹ð4çÿVmsq2­A}¦Ai&9ž¹«y¦A;P×Î{÷p3ç&®^ÕÍ.¥éåh«¡IÑ¿,ðeq€•°k5‡÷;;l/sAp¾'“}q=vî]݆”Ó;‘²¥»Q¹9uÞAøä„v»=è´Ü®U›Ñeê‹î•è1vDŸ‘µ25¦Š&ÊØX£Smk5ö@ÓJ_|0Ù‚ÓT˜ïÇ3‹£(´:…L›sxh wWß@¤c .:Åá”S9fá {Ö¸$$䙾î_¾üXG¾eBŠïG^g©+ ±Äk@›n®EkH:Ró7#á– ^­7B‹ÃJS8{¶”º,á÷¬¬&+†Éêa²’˜ô‹‘Ædµ1é##ýd¤¯Œô—qûä¦ûÍHß“~݇FúÑ8µ|Ý<3¤ì ÎæEdÒ)Ü¿ué—. èä”ᅥš×Pç ~çÑäuÍkŽ£Õ)íöûÐi€n‹­è5Û€>“ñ—޾ìÿÁVب¾V›ôÁÌpV·7[uã€};κ~F´ÏG<ò¯Cáî*¼ .GÙ‘2r£r‘}+±HSß-)Rð(‰ïY’5  ȼwã_LÇ3|:TˆÖÈkHyã†ÛŒQ´ËíVÆ(tAþ¥³HNJµÀöºúŽàë×€µu—æ† Ô¶—zß|N§â u¥®äRÒv¼t11!bFü>øis"&å››gŽa@:÷Ø¡/kÊ·¡,þ Î!åXîUá¢ÿ;]û.-ð±í€2&¦Æýp1ï¿ú^ ¶kGÄêVÜwnE¾s ª[[Ñ®¶w©ý=êq}ÊÔ@™ù-÷e{‡}ZÕã>+sóÉã×6¢Þ·6~À;uηÛߢ: Uê9¼Úÿ åóØôèÞ™d©é°ûü3BЀ,ˆšŽ—yh¹‹¶ÌƒHiµÄõlSd£ÃÒU›ñäL¨º°_%E¢Å ¬ÒQ ‰nH”C¢õ¸}›K.’$I.6N%]l<k‰2S´Ù#ÿ˜1" M±ý³36ÕûÚGæàó#Ø›qwî`Ë…Tø*‚ÇÖ×pôl€…u'LL{açØÏuà¿ã ö¿Ô½{n\)DBÌ“ fALƒ˜1b&ÄTˆ¹xúeGËP~¨\›1!bFÞîx‹w[ÞáýÆ÷Ú¬ˆió"&¦uMþ(í;õc¤~ä÷mi@ eìF’„`dšLðUwbÑþ( mÕÞHî2ÇùÇVH[‰VÛ•x·ÖÏŽ‡ =.nðobÔ\òu¥^Cê6¤~ÃË«{÷V₺8J}g:HêJ]©-9™…šgÞN¾€ü“;Ðèmƒ.»•xfŒÔ_“gÕ÷üGïøèó 뾘'¿ø°áƒ~~u›êPç_§ŸoíÖZÔn¯ÕÏ¿fg ªwU£zw5ÞìyƒªÀ*TU¢r_%^ïW^¡â`*U <¤/¿ÔÆ«ìX^¡ X©sH*¸hU¢ÌdÉ™­]ñ¹b/BQDž\|‚Ç—km ¯¢àZÖ:ïFò"ó´ö97s­ÿY·²y;™±™º1lú½t¤Å¥!-> © ©ƒº~mši@Ö€|[kz ê2Π«tÚÛ-‘TïŠã¥«qóÊJ|t6E£‹5^ïEÖíÛz]zY*8¸~~õze*Y¡j£ºØ9òR¯\µØ ™CK]©+Im KÔwûþ”rPKШϊ‰AÕ¡@t¹Y¡ßÑÝá–¨J Djjü7_jdSµ9ˆNŽÃ…Ø$¹š€“ذï9Ü6WÁÞý#Ì,º`jÞ ë5 pÜR5‡òá‘ß{7°1ç6¿Ú=ªéqluÔ XwYÿqQ«ù-÷e»}‡½~œ<^þNþ^޳ñÃÆi™¿s{³^3v¬ÛLß—í©R¿44U&(=.÷2´ʼ“©¾ã³ô@\ä20—º ÔeÀ.wÀË@^ô2°—¾ ôeÀ/1bĈ1ƒ FA ƒ‡G_h#!†BŒ…DtÄhˆáãñzïkmDĈ1yðF1,b\Þn{«Œ16bpÄèˆáã#HŒ"1FbÄ(‰aã$JŒ”*1Vb°Äh‰áã%¬Ó¶Öè²êB·e7z,zгª½f½4 †‚§§'~ÿûßÛ&÷Gr$ÂÃñ|ùrͰ°° Ï3Ñã§»®Ï7_ ÈT:ÉJßÒ'gÑTˆ¾&G´tBbù&ì醋1&¨ñ^…V;sTîÙ‰ôKѺ¸uºHÏ I§’Ò‹CzrÜQ-Îz’Ô•ºR[r*«‹ó3Ñêb9QQ¨ Ù„^W3ô¯1FËi”ÜŸ±ç+ýw"Õ@ü¬`K-ã®]5ðõmЩÅñ77ïQ·[ô¤Ü.5`–åãå{322wXÀPÓ#‘‘H˜1b&ÄTˆ¹}Š£eG§éjzVõ­BˆúlîÙ ïFo$M²É/ɬÃàææ6ª±±±pwwGss³¦˜Ùö­Ÿîþ¹>ß|1 Ož\ÔŸ€ââs£î—ÎâWPU±íï½Ðßa¶¢HÈ߀Šu8™hŠ2 tZšáõ†­¸µû.¶m­Õ]Å¥»øÚµØ·ïµî:.ÝÇy!"I’$çŸÜŒÀ§#î:*ÒçeŠúS~Ƚ9«ÏAšàJô_=Jv€LÐùø4è”dSÓ^XXt«±Ág½K@À9R¦ë$£¢rÔwjŠÁŸOLv LûMk?ªúªtôŲÛo´éá{gárÁöövåÖÍQ[[;e"ƒs™€Ü#ó­Ÿîþ¹>ß|0 b>z{-ð¬ÿ þ=`B²²nãÅ‹c¨¿½èyë…¶»gqÿa8¶UlÂ,S<Ùm‹ÎUfx鸮ñ°µhƒ­m6o~¯/2ã“”Ä;g=©+u%©í<×5é!*bCÐqÔ°7B×ZKT‡îFfl윿¾{÷ÒõjRø.ÝéeA–µk?êI>SÓ>XYuc͚Ϻé®d;V¦ûbEGç 1qêeëû­Ï}¬ ”ù¼½àWï‡Àª@½j™K‹ ¿<Œ¸ô8¾¹ Öìàøñãj`9ªáû?þø#¾ûî;õ¦µP€ˆaû—-[†þþþÁûr[¶…‰?Ýýs}¾¹6 b>rrÀg}+L,ºááÝŽŒŒCèê°AO»5: ö¡õt<îÝŒ‚ÿëÍØ‘e´­>h5µÄËU›fu.u:œ,ÆØØ ^X˜÷M]©+Im´®™éwPïÞ#fè·^‰¶uxyüð°ÅSæ e’ïîÝ ][)iÍ¼Ò ºx{7ÂÁ¡&&}zÙz7·f]k)«K?þBg$È0R—92½Í7ïš‹OŸ~—HcÒÕ.=X™¬÷K*ØE5~ØT·I×£H*—¤~=L~È÷ã¸,HRQQWW×IE<ª««áçç‡ÐÐÐq/fe,LôøéîŸËóÉ`€Cááá¡ß˜îX~ÏÄ}©ùo‘7cà›‚u×á®w0LœðÆØqÎ×põØ+uá*סߙz~‹é~]]õ˜û¤|¿.”ûåååÔcî‹®3süB|¨½‹¶Oô¯D¿•):ý}ð&"iññ BŸ×¯+‘šZ‚«W •é¨ÂéÓMø/¯&¬^Ý¥ÚÙuÃÝý¶ooÄÉ“Ÿ”yé4ââÒõÕñ_¼yóoÎãÉV=Vù‚¸q|Îãï¯i@Ä|ÔÔÔL:媭­Mc32?# ã­£~qÕo¨2ñÂ'Sä{ƃ3w™NE’$I.IffÞAå‹@t'[ gú,LÑà·%aaHIHX°¯KV¼};—/êåð÷î} KËчMïX·²naï뽃«sɪ[-@22)Œ¶ÊÕx&d¤­FB¶M¥&cèã§»®Ï7Ÿ È›MÛñøòe; ¯F/Xt[`ÛÛm¸VpmÉ¿gß¼)¥1¤IMMUoR;½}ÅŠºþ£««kØc¤7ÆX}2F‹¦Œ÷øéîŸíóÑ€p¦ƒ¤®Ô•Ú’‹K×ää‡xúô,>~\‹žhºè‰Vw'tYZâíŽ(¼reÁeˆ quý¬kDdµ­ðð’Á}²d°¿î_²uk-¢¢r'uÌ;™wpàÕ8´9hÊmÙ¶ä–~ž õ Èàûï¿_Ôç›ODò2Ç3 ÌÛ$I’$É©Q–°¯ª DW—5šË\ñ>tZÑicƒ7È¿qcѼVYxÿþ×°¶î„§g“n´8ÙZQ‰‚H4D¢"9UzJGK–‚ù–==§Ñ×g9'&„„˜1È/ÎzRWêJR[êúíQ‘’’3hlôFw·ÞåúãíÁíhwp@»½=*ƒ‚tGöÅ íÇÉz `Yê×ήC7S¼?mRÇ—º©‘:©‘º©‘:’Åj>ºº2þ8â+šBBÌ‹F„ÌM¦¶Ô•¤®Ô–ºÎdT$oÞìQOK45y¡"á ªwïÒQ‘V''¼:pY11‹B[i˜¸iÓ—ô¬mÛÞêníSÉÌ•³œZôJZ²¢–¬¬µÐߟ²pAAÁUvÕßdÄ(ð’Þž–vŸ„Xš„3sÔ–º’Ô•ÚR×™ŽŠœÖ&DÌÈ›ªÝxuZ׉H½Èç5kP2/º¯OWÛ{÷2ô’¾ÒÑË«Q×”Le)ÿy7°³f'¬º­àñÉ'žŸ@|jü‚IÓÿsuõn|RϽ·wÚÚÐØè¥ ˆ…éå F@úû­ðüù%F@ˆ¥k@H’$I’œfgGãÍ›ž%iZ%Åá(ºxA¯ Õca&”;6/»¯O…ÒiýäÉgX³æ3ììÚRŽøø´Iÿ½tW—.ëÒm]R´¤ûºtaŸ/)Zéé÷PTt••ûðñ£úZ¢³Óõêù¾zu@§]¥¥ÅKÃ’´+àÜœ˜‚ÎΑԕºR[r‰ëšœœˆgÏÂÐÔä¡ ×¥€=;=ÅçÎéÞ"=ææøèíÒÐPÝ}}!k{íZ6mz ‹ìØñÑÑ9Súû¸ô8~y.Ÿ]`Óiƒ@¥U´2r³¥Ejê^FEÅ!|ø°¶èQ¦H"ò“•Ð22&Ž^ ¬‚5惄` ó“IêJ]©-I]™“êê]èî¶ÐKúÊ€6õA“Ú&&¦ 4´T{>ÃÁ¡‡¿D||ꔎ‘”œ„óEç±áâ%¿å¾lŸüq’´™ÍÅ\4+C#f£µÕI›Ê܈S²Þ³4 k@H’$I’'*¥ÅihðÑK¶ÊªJR"5"R+"5# ½ûú•+ظñƒNÏÚ¹³ÑÑÙS>†D@$âÖì¦##!‘HÉÈÇIš”D—$mJÒ§$ª£ÃN§U•—ë4+I·Z¬ï)‚ÎΑԕºR[’ºN"*ò¥¥¡:¨³Ó¯_ïE滈gÄÆêÕ³d-Cw_Ÿmmcc3X+«nøø|DDÄÔÓ³„R"5"6Öpk·GDÃ:T~ôÑ%)—‚qÑP ÈÓÓã–Ô{–„` ó“IêJ]©-I]§ÄÜÜH¼}»==ñÕƒèZé'"}E¤¿ˆ!º¯Ï•¶’žuâÄs8;·`õê69R†„„Ô S× ®áåËè«Û„övôô®BF‹ÛVÃ¢× ½õªZ ˜NµÐÞ³4 # œ#©+u¥¶$uýƨHž??ϟנ³Ó¯_ï¶ “tZ—ŽëÓé¾>´½|¹ë×KzV7víªFLL–NCËÍÒ¯ÿíÛmhiqA_Ÿ™ÒÂEß—í¹:ýêÿ¢@ÒGDú‰x4yÀ²ÛR÷‘~#Kí=KB°„$I’$Éi3/ï7=ð–¨H}½ŠŠ"† ¾% "Ñ…Ð}}4Js¿ÌÌ+8q"¶¶-س'_Œƒ:Ò!‰|Hd²Ç“ëÒi]:®;¶:êìÒ‰})¼Wh@F@8;GRWêJmIêj0Jñô‹Çu$@ «¥^ÆÐuR’®¯û:ŒŒÆäl¼†‰šûåç_Ahh œœZáèØ†£G_ !!å›Î% /^Æ–w[ô*Z>ê|§KN#1%qѾgi@Ö€0?™¤®Ô•Ú’ÔuF˜Ÿµµ[õ*O>¬× ð†FEdÅ,Y9kd÷um6Fà é6÷»té1üüêuzV@ÀܾõÍÏ%!%'Ÿ„—:·E·¶½Ý†k×X¡: g8;GRWêJmIê:µA~¼îe!uíívj°ééÃÓ¤—È@÷õ™2 3ÙÜOŒ‡1"¾¾õÚ˜Lç¹Þɼƒ¯À¡ÍASnßùãªcŒ€4 $I’$I’“ŽŠ\Wƒÿ¨È5¾øÕ€ß0dö›ûé(FBŠNÉrtlÕ)ZÇ¿Àƒ)Ó:¦DA$"Q‰ŽœR¯I¢%¬!h@8ƒÄÙ9êJRWjK]É)DEÊÊŽ(Cଗ«•¨~ãœèèQ7›û]¼ø¾¾ °´ìÆž=’ž•9­ãI]ˆÔ‡HˆÔ‹H݈Ô$}CĆ‚„9´Ô–º’Ô•ÚR×%KYAêÝ;mÞ¿?«ÛÊ }Qvÿ˜.—ÂðùÒÜo,ʲ½²|¯¤gùù}ÐËúN÷˜²b–¬œåÔê¤WÒ’µde-Ö€4 œAâìu%©+µ¥®ä$™–v_/i;Þ*XíMöè»m‚¾Õ&èð·Ãë»ûô¹ áõ=xªJcCip(¥áát+½D¤§ˆU·<>yè^#ÒsdÜš•—·i@’$I’$I1!Êi(ž66éë;¥·\ÕõR´þüøqÝàð“»;ŠÎŸ_0¯1)é.\xŸXYu#0° ±±™Ó>®tW—.ë¾õ¾:EkSÝ&\|rñ«­˜ì¥¤nåÜ¢!h@8ƒDm©+I]©-u%e¹Þ¾>Kô÷çêqI{{¶NÏ*.>÷õÊVIIx†Vgg´¨ñKÉéÓº×ÈBy­11ÙØ¹³=ذá®^-4ÈqãÒãpøåa¸|vM§ «ý¥~Æÿ¿6 M4  sh©-u%©+µ¥®äPÒÛ>¦ùIYÆ·ÙÍ mx~â’>\0¯7>>‡¿„ƒC»‡}Fhh©AÒ³„Q¹Qxë.k8·8äß…êÇLýÌE„„`„³s$u¥®Ô–¤®óÖ„HÚÕdÌǰÿÇ¥KhôöF§­-^>Œ”Ìk–ô¬óç‹°víGXZv!(¨±±†9vr¼½±¯oŸïS?s¡!XB’$I’ä¼® ùÖ¿Í¿~õ~~貲«¿ ^{ttvìx«Ó³6n|k× ¦—î•Ó~S¼S?ù=Q‚ÎΑԕºR[’º.jms¢¢P·y3º-,Pˆô{÷”’žR;»v¬Yó'O>Cbbò”#µ‡º óÍE„„` ó“IêJ]©-I]—„¶Y·oãíöíèQF¤f×.dÞ¹³ ´ô¬sçŠáíÝkë.ìÝû÷îM.=Kú†ó#ûi@& OOOüþ÷¿ÿj{xx8–/_®6åý†>Þ|?# œA"©+u¥¶$u]*Úfܽ‹7»wk#ònëVdÑ]}>óæÍ5~{ sólÚT‡ë×óÌ{vAÀÍÍí+ www477kŠI‘m“Ý?Ó=Þ|?k@H’$I’\’õ%÷ïãõ¾}趴㑹à^Ãýûi–ô¬¬YÓŒ°°gxø0y^?çk@ÚÛÛ•ã3GmmíWDßâê ·Å¨LvÿHL÷xóý|Œ€p‰¤®Ô•Ú’Ôu)k›úàÊB§µ5||PpåÊ‚ÓIҳΞ} /¯&X[wbÿ~IÏJgÄ8~ü8"•KŒ4 Ë–-Cÿà}¹-Û&»$¦{¼ù~>Ö€0‡–¤®Ô•Ú’Ô•Ú>BJb"^;†{{4yxàÉ… R³¨¨\lÝZ«Ó³üýëpãFÞà>©!ñòê„……LZ÷àÒ¥ É ¢¢®®®ƒ÷GÑjB¾ûî»Iï‰éo¾ŸÎ ‘Ô•ºR[’ºRÛÿ£î®~ò$ZñY‰ž†‡/¨îꌋKÃÁƒ°µí€›Û'ìÙ󎎽xúôËx¯¬LÆ|˜u² ˆ˜ššš1ÜŒ€Lþ|òàPx(×/3zùÍû¼Ïû¼Ïû¼Ïû¼¿¤îâCl,ÚÔ¸¨mõjT]¸€ÊŠŠ÷z Ÿ <ü)¬­ûP\<|,(&ÄÍ­wVŸÏ¬1“áþð‡io¼Ù6Ùý“©É˜Êñæûùá I]©+µ%©+µŸO.^D“—:lmQväˆN×ZhZZXôŽ:45í_|1C9–˜(Mh²)K«@555»JÔXû }¼ùv>Ö€0‡–¤®Ô•Ú’Ô•Ú~ ®]Cƒ¯/º¬­Qqðà‚ꮾfM ž<éý*âêÚ½¸S°âââÇhllÔÛ’’’ b@Òûb¼>ãí7ôñæÛùá I]©+µ%©+µs£¢ð~Ó&Ý]½2(éjŒ;ßµ”t{û.vš© 9sæÙâ6 ?ÿü3zzz¾Ú.Û~ùå—y±ÂÖ÷ß¿¨ÏÇ> $I’$I’†aö­[¨Uã(ijX€ŒØØyoB$bbÒ'§„‡—,þU°d¶,2ÙbñÎ Q[êJRWjK]É…¨­1 bDĈ1¡®óÄ€üøãº)ž¤]ÉêL††½²ÕO?ýD'°Ä sh©-u%©+µ¥®äBÖVR±*÷îÕ©Y’¢%©ZÔuÔ€ŒU„þðáC:F@x±¥¶Ô•¤®Ô–º’ ^[)N¯ÖÅêR´.ÅëÔuŽ ÈÀ²°FFFºöA(·ŸtD!XB’$I’$¹H(Ëõ–=ª—ï•e|e9ߥ®É‚lDH0BR[êJ]IjK]©íBbòÇ( Õ ?¯Yƒ§gÏÎiwõ%!h@˜CKm©+I]©-u%—¤¶Êt< ÇgWW´::âÙÉ“Hž#²¤j@ë֭òe˾¹:ÁIm©+u%©-u¥¶ O.\@“‡:ìíñâèÑYí®¾¤" ~~~ƒfÃPÐ Ö€$I’$I.T\¹‚]°^ŒÔ„Ö€Ò€Hgî¼¼<}{ âñùóglܸ·oߦ`„"jK]IêJm©+¹$µÍ‹ŒÄ5&î¶´Äë½{‘vÿ># 0P#ÂÑnK?ö¡a-µ¥®$u¥¶Ô•\êÚfGGãÝÖ­º©á›Ý»‘q÷.k@¦k@š››õmY‚755UßÎÍÍe  g¨-u%©+µ¥®$µý#3ïÜAÍ®]Úˆ¼Ý¾Y쮾¤"  Ò·­¬¬†Õ€üúë¯t¬!I’$I’$‡0ýÞ=T©ñ³tW¯Û¼9ó´»ú¼^k½½½X±b…Ž|üòË/èéé¡`„jK]IêJm©+ImG¡tWu𠺬¬Pïç‡üë×!h@˜çÉZêJRWjK]Ij;³Lyð/A§­-½½ñøÒ%Ö€4 œåà u%©+µ¥®$µYJwõç'N ÍÁÍnn(>wޱƒŸþyXѹ‰‰ Þ¿O'À’$I’$Ir*LJBÉéÓhQã·Vgg< ›“îêóº}´Îçpww§`„jK]IêJm©+Im¿‘EçÏã“S·KwõãÇ‘®]‹N”‡„ %!02“‹Ú€ 5#û~° g9¨-u%©+µ¥®$µ5ónÜÀ‡õëÑmeõÅlŒ†Ån@¾ûî;tvv~e8ššš°lÙ2:Ö€$I’$I’fNtôÒ5 Rl¾zõj466j"½@^¾|©‰# ¼HP[êJRWjK]Ij;\²¤ªªjX÷ó¡lnn¦` /Ô–º’Ô•ÚRW’ÚÒ€v^1! ùþûï5¹/ g9¨-u%©+µ¥®$µ¥™1BЀ$I’$I’s`@–ú*X g9¨-u%©+µ¥®$µ]ZºÎº‘”+‚„yžÔ–º’Ô•ÚRW’Ú.M]gÝ€馃 g9¨-u%©+µ¥®$µedÆ HVV¦µâUAA<==u4Eº§ïÞ½ ƒûG[ak$ÂÃñ|ùrͰ°° Ï9Ñã§»®ÏÇ’$I’$IrQ±–àN¶>dݺuÈÍÍÕ=DúûûqãÆ 899 ;Çxˆ…»»»6AB13²í[?Ýýs}>F@8ÓARWêJmIêJm©ë¢.B‹ÒŒÐµ%œ‹èÛnnnßüøéîŸë󱄹ž$u¥®Ô–¤®Ô–º.ZbhH$22ëׯf@~üñGmh,,,1ìo–-[¦ÿnè1dÛX˜èñÓÝ?×çc„3$u¥®Ô–¤®Ô–ºÒ€L!ë—_~AMMͨ©®®†ŸŸBCCÇŒ}™èñÓÝ?—ç“7À‡ÂÃÃC;ã7§üæ}Þç}Þç}Þç}Þç}ÞŸîýY7 ===øõ×_§U22rõêU¸ººŽùYuKбa„3ÔºRWjKm©+µ%—XÄÄÄd˜á0T Èx;Ò€ŒV#!Û¦R“1ôñÓÝ?×çc s=IêJ]©-I]©-u]ÔEèIIIÓ:Fpp0jkkÍ…,3;t€8˜’U__ý7#W‰jjju•¨‘)L=~ºûgû|Œ€p¦ƒ¤®Ô•Ú’Ô•ÚR×%c@¦å@jj*ìììôÀý§Ÿ~BPPl¶ÅŠºþ£««kØ1Ä´ŒÕ'c´Šñ?Ýý³}>ö!I’$I’$—Œ‘NèÓiB8º¤ïb<# œé ©+u¥¶$u¥¶ÔuÉi hee5,bA€„yžÔ–º’Ô•ÚRW’Ú²ÄPd¼îçÓ]‹`„¤¶Ô•º’Ô–ºR[’Iw?7Ô*XÄâ0 $I’$I’$k@æu't‚’ÚRWêJR[êJmIF@æy2דº’Ô•ÚRW’ÚR×¹7 ãÕy°„„³Ô–º’Ô•ÚRW’Ú22+äóçÏ4 4 $I’$I’$k@ c@&³ Ö²eËèá“ÚRW’ºR[êJR[F@¦o@VºXnw$¥cwdd$k@xQ ¶Ô•¤®Ô–º’Ô–5 †KÁâR»4 œåà u%©+µ¥®$µedÆ ÈÏ?ÿŒ;w¢®®Ž£}’$I’$I’5 3k@œœœt‡¤`IÄÚÚèììä蟄³Ô–º’Ô•ÚRW’Ú223)Xõõõ8sæ V¬X1X|ndd„ððp444Ð °„jK]IêJm©+ImYb82ý(..†•••ŽŠˆùá‡àææFGÀIm©+u%©-u%©-# 3Û ]êC‚‚‚ð믿Ò°„$I’$I’d ÈÌ‚„³Ô–º’Ô•ÚRW’Ú22m2™&„ýAÖ€ð¢@m©+I]©-u%©-k@¦e@F6Ë€°G g9¨-u%©+µ¥®$µeÄ )XqqqpwwGSSÓà¶ÆÆF½-))‰N€5 $I’$I’$k@ g@¤!aOOÏWÛeÛ/¿üB'À?˜Ô–º’Ô•ÚRW’Ú2b8"©VcրЀ0Ï“ÚRW’ºR[êJR[Ö€Ô€üøãºÏ‡¤]õ÷÷kJBWWWüôÓOtŒ€ð¢@m©+I]©-u%©-# †­«ýáÇt¬!I’$I’$YbØ> ⸌ŒŒðý÷ßkÊí§OŸÒЀp–ƒÚRW’ºR[êJR[F@ o@æyR[êJRWjK]IjËF@8ÓARWêJmIêJm©ëâ2 ²ÚÕ¯¿þ:­NèðôôÔé[?üðvïÞ­ Ù‡"<<Ë—/× ûêíŸêãúùXB’$I’$I.Jbbb2Ìp åd;¡¯[·¹¹¹èííÕ«hݸqNNNƒûcccucÃææfM1+²m²ûGbºÇ›ïçc„3$u¥®Ô–¤®Ô–º.Z"Fc&:žK4d2øQ‡½ËÒ¿“Ý?Ó=Þ|?k@˜ëIRWêJmIêJm©ë¢5 “rL‰ŒŒÄúõë·-[¶LoúÙ6Ùý#1ÝãÍ÷ó1™’ºRWjKRWjK]­‘%w%-ÈHåúå—_PSS3lûxÆg¢ý£g:Ç›ïçc I’$I’$¹h ˆÔnXYY¡©©É`«W¯êNꌀLý|òàPxxxèÐÜ€;–ß³q¿¼¼|VÏ·”î×ÕÕQ¸?@êÁ÷ëB¹/×YêÁï/^x.¿¿fÝ€ŒÕ}*«`M”Ú5Z „l›ìþÉÔdLåxóý|¬a®'I]©+µ%©+µ¥®‹º},N¶>$88µµµúv[[›^fvè{`(‰²Œ·JÔXûG¦0M÷xóí|¬a®'I]©+µ%©+µ¥®KÆ€©©©°³³Ó÷Ÿ~ú AAA_¥t‰)¯ÆxûG«¡˜ÎñæÛùXB’$I’$IÒ€Ì# ]Òw1žÎtÔ•ºR[’ºR[꺤 Hqq1ŒuÊ•PnË6‚„yžÔ–º’Ô•ÚRW’ڲĠ$//oÌ"tšÎrP[êJRWjK]IjˈA ˆD;Ö­[‡ÆÆÆÁmrÛËËK÷!–¶!I’$I’$YbðNè===_mïííµ4 Œ€p¦ƒ¤®Ô•Ú’Ô•ÚR×Ef@ººº¾Ú.¦„„„yžÔ–º’Ô•ÚRW’ڲĠÄÄÄnnnhhhк…rÛÉÉI§gŒ€ð¢@m©+I]©-u%©-# 3 Rh>Vú‹/èXB’$I’$I²İËðŠÑh‡¤\ å6Í g9¨-u%©+µ¥®$µedF AÂ# œé ©+u¥¶$u¥¶Ô•d ¬_¿yyyz)ß®®.;vL’¡d<ÄÆÆêž#’ò%ôôôÔÛ¾õñÓÝ?×çc s=IêJ]©-I]©-u]´¤®®N§\ ¤ý—_~цÁØØø›)FDŠØ'k@dp.®orÛÍÍí›?Ýýs}>F@8ÓARWêJmIêJm©ë¢5 NNNxõꕾ½cÇŽaiRC£SAvvöWüQ› DDD {¼,÷+¦e¨o à‰?Ýýs}>Ö€$I’$I’‹Ö€È@XÒ¦¿þú«6 ¥¥¥¨¨¨ø¦Nèbf¬­­ude4TWWÃÏÏ¡¡¡ãFH†FPFb¢ÇOwÿ\žOÞ špÇò{6î———Ïêù–Ò}ùŒPÃß õàûu¡Ü—ë,õà÷¯¼?—ß_³n@†ŽeP,÷{zz¾jL8Ö€0ד¤®Ô•Ú’Ô•ÚR×Eo@~þùgìܹsÒQbiÎrP[êJRWjK]IjˈA ˆôÿ•˜$ÝHV¿’¥s ÐÙÙÉÑ? I’$I’$É™IÁ’¢ð3gÎèÚŒÚ © GCC# ü`R[êJRWjK]IjËÈÌÔ€Hô£¸¸VVVƒ=A¤¡››k@HjK]©+Im©+ImY2³EèR¤;¤Œ€Ô–ºRW’ÚRW’Ú2ò;Õi@H’$I’$IrÁžžá­‡ô!á“ÚRW’ºR[êJR[F@ f@LLL†Ž¡”:‚5 ¼(P[êJRWjK]Ij˃1IIIñÓ€p–ƒÚRW’ºR[êJR[F@fÞ€0ÊAB’$I’$I²dÖ ˆôühnn戟„³Ô–º’Ô•ÚRW’Ú22ó$77W÷ýhjj⨟„yžÔ–º’Ô•ÚRW’Ú²df Èh«_q,ÎrP[êJRWjK]IjËÈŒ¡EևЀ$I’$I’¬1¨!h@8ËÁ$êJRWjK]IjË  k@˜ëIRWêJmIêJm©ëâ4 ÅÅÅ066Ö)WB¹-ÛÎrP[êJRWjK]IjˈA H^^Þ˜Eè4!4 $I’$I’$k@ j@$Ú±nÝ:466n“Û^^^ºGÁ?˜Ô–º’Ô•ÚRW’Ú2b0")W===_mïííÅ÷ßO'À^¨-u%©+µ¥®$µe ˆa HWW×WÛŔЀЀp–ƒÚRW’ºR[êJR[F@ j@LLLàææ†††ô÷÷kÊm'''žE°„$I’$I’d ˆÁ ˆšU„þâÅ :F@øÁ¤¶Ô•¤®Ô–º’Ô–Ã.Ã+FC¢’r%”Û44 Ìó¤¶Ô•¤®Ô–º’Ô–5 3b@ÎrP[êJRWjK]IjË  k@H’$I’$É…o@¤¾ãøÃàí±8ð˜‰PPP û†HúÖ?ü€   455 {Lxx8–/_þÿÛ»×(î½íãçO‰D©(=(D(‰ñˆD,–ƒRQZðP°Ø'XZ,E(ERZ, ö®(>õX*ÜV9¢øXmäN©(ù>~æÜ&›ý1›$›äõ– wwfg6×îwf®ï¯É4<<Ï_]@^¼xÑv¹yófÚ¼ysº{÷n¥-Z@ŒÑדøÊWÞ_yË×ÞÒlö«\­.’‹ŒŽŽf70¼sçN©1ñZÙåUo¯Û÷g ˆ¾žÄW¾ò–øÊ[¾.º’Ït•O·[«˜.öܹs¥¶uþüùÔ××—îß¿ßt©˜š·Ù,Q–×vaêt{ݶ?c@ˆˆˆˆhÉŒ);ÕîLZSŠÄ½/šÝ£Ùòzc(:Ù^·íO ˆšâ+_yK|å-_Í‚ÕEÄ óþŒÑדøÊWÞ_yË×%@¾ÿþûtôèÑi¯ÇÝ̯\¹’°´ˆZÞò•øÊ[¾oµ€T@Þzë­lÆ«z³`­[·NX℈ˆˆˆŒ©4€ÔïÐÉ}@ „xËW¾oùÊ[ÒÒýìÙ³i¯?}ú4­ZµJ0ÄA·|%¾ò–¯Ä[c@ª qa-<ÈnŠét£e¤¿¿_Ðâ À[¾_yËWâ­êHŒõh4îøø¸$` Rí4¼ÑÝjãÆÙô³¡M›6e7̓¢–ƒ·|%¾ò–¯Ä[- Kî> ˆ1 úz_ùÊ[â+où*€@ ñ–¯|%Þò•·¤¤}öïߟz{{§1 ¯BDDDDÆ€T@†††&ÃFmééé‘´€(˜¼å+ñ•·|%Þj©ö> ׯ_Ïç-13ÖÁƒÓÅ‹%c@xËWâ+oùJ¼5¤ºR¼zñqÜdÍš5’€Þò•øÊ[¾oµ€T@ÆÆÆ²Ç1ïèèhöøÚµkÆ€ DDDDd HµäÒ¥KéøñãÙã·ß~{ÊuëÖIZ@LÞò•øÊ[¾oµ€ÌÎ4¼¯_¿NëׯÏZ>Ö®]›^½z% â À[¾_yËWâ­1 î"€¨åPÓA|å+o‰¯¼å«c@ˆˆˆˆÈÆ<~ü8mܸq² Vt½Šñ6lµ¼å+ñ•·|%Þj©6€ìܹ3Ý»w/{|øðá)ƒÐ÷îÝ+ â À[¾_yËWâ­1 ÕÞÞÞôòåËìqÌzÁãöíÛéîÝ»iÕªU’€Þò•øÊ[¾oµ€T{œžžžìy>û•û€ DDDDd H¥dåÊ•Y‹Çƒ²ð±zõêìõh‰eТ`ò–¯ÄWÞò•x«¤²¶ÅqûöíË^~h;vìŒqPà-_‰¯¼å+ñÖj§áÍo>Ø××7ùÚ¦M›²² ÄA·|%¾ò–¯Ä[- î"€ ÐB¼å+_‰·|å-iiHÌx•O¿[«²³`ßÓjy£õNŸ> z ·Üg«õ;]>ßû3D_Oâ+_yK|å-_e‰» GQ1-ïL§ô-ózÎÈÈHHccc™³×fº~§Ëç{Z@Ôt_ùÊ[â+oùºhHË—/WÒmh¦$.ÎÃôœxÜßß?ãõ;]>ßû3„ˆˆˆˆmi·•c¦$î/ûÚ²eK:sæÌ”åq7ö‰‰‰Éçñ8^kD«õ;]>ßûÓ¢¦ƒøÊWÞ_yË×E@bêÝè4›¤HÜðphh(:uªéûš£Vëwº|>÷?€\EöìÙ“õ Ìœñÿ\<©˜çrKéùï¿ÿÎYx^û?ü^»ýygùáüåxàù|ž¿æ<€\»v-½ýöÛéùóçs@‚ñññ)wY×¢DMñ•¯¼%¾ò–¯K¤¤Þ Uí΂Õi©7F"^kgLFqýN—Ï÷þŒ!"""¢E=½‘ªšëرcéáÇÙã'Ož¤C‡¥'NL›%*ZaêÍU»ÝVëwº|®÷§DMñ•¯¼%¾ò–¯K&€T5ö£Ù}>FGGÓ¶mÛ²×ׯ_Ÿÿxùòå”uâÞî“Q/Ø4[¿Óås½?÷1ß7ñ•¯¼%¾ò–¯H±bÅŠE½?- j:ˆ¯|å-ñ•·|]RdÿþýÙ èNÇ€`ñ""""2¤ÒSâæa£6€Tyh!Þò•¯Ä[¾ò–´€dc®_¿>9 =xñâE:xð`ºxñ¢$°Äˆ~ž¼å+ñ•·|%ÞRù4¼õǽ*Ö¬Y# hqPà-_‰¯¼å+ñV Hµ$¿z ¾Ž«ò"€‘1 •K—.¥ãÇgãŽèÅ1 ëÖ­“´€(˜¼å+ñ•·|%Þj™ix_¿~ݧ#Z>Ö®]›^½z% â À[¾_yËWâ­1 Kë> ˆ5ÄW¾ò–øÊ[¾.’bœ‡BDDDDÆ€ÌY醻~C ˆšâ+_yK|å-_—HéëëKããã®øý9/µ¼å+ñ•·|%Þj™Õû€4’ñ!Rù ôFêéé‘´€(˜¼å+ñ•·|%Þj1 ¯¢Ÿ§¾žÄW¾ò–øÊ[¾ ÐB¼å+_‰·|å-i™Ù}@Œ@ˆˆˆˆÈ9 /^¼@µ¼å+ñ•·|%Þj©&€4›ý*Woo¯$` ˆƒoùJ|å-_‰·Æ€t@ò™®òévkµråÊtîÜ9I@ ˆƒoùJ|å-_‰·Z@ªë‚eª]„ˆˆˆˆŒ1 –¢DMñ•¯¼%¾ò–¯Œ!Þò•¯Ä[¾ò–Œ¢–CMñ•¯¼%¾ò–¯Œ!""""c@ €¨åPƒÄWâ+oùJ¼åë Å{‡4âôéÓÙÔ¾¡ááá¶—W½½nߟ1 úz_ùÊ[â+où*€”"õIill,Óàà`öZÙåUo¯Û÷§DMñ•¯¼%¾ò–¯H$.¾ÃÔœxÜßß_zyÕÛëöýBDDDDH¤··7MLLL>ÇñZÙåUo¯Û÷§DMñ•¯¼%¾ò–¯H¤ÞëÅ;°·Z^õöºyñÈUdÏž=YßÀüÇÿÏÅóÇÏéþ–Òóßÿ³ð¼öþø½vûó8ÎòÃùËñÀóù<iÑ¢DMñ•¯¼%¾ò–¯Z@ª¯•]^õöº}Æ€‘RÁ,XÏŸ?o:KT£åµÛít{ݶ?- j:ˆ¯|å-ñ•·|@fxF÷‰{_4»F³åUo¯Ûöç> æû&¾ò•·ÄWÞòUé"V¬X±¨÷§DMñ•¯¼%¾ò–¯""""2D@Ôr¨é ¾ò•·ÄWÞòUÁ¢ úyò–¯ÄWÞò•xk ˆ"€¨åPÓA|å+o‰¯¼å«c@ˆˆˆˆÈ j9Ôtð•øÊ[¾où*€À}=ùÀW¾ò–·|å-D-oùJ|å-_‰·Z@Dá$""""Z@ˆ·|å+ñ–¯¼%- @ôóÔד¯ÄWÞò•xËWZ@ˆ·|å+ñ–¯¼%- @ˆˆˆˆÈDÑ¢¦ƒøÊWÞ_yËWÆ€oùÊWâ-_yKÆ€@QË¡¦ƒ¯ÄWÞò•¼å«c@ˆˆˆˆÈ j9xËWâ+oùJ¼Õ"€ Æ€èëI|å+o‰¯¼å«- Ä[¾ò•xËWÞ’ DDDDD´€oùÊWâ-_yKZ@ €èç©-_‰¯¼å+ñ–¯´€¨é ¾ò•·ÄWÞòU1 DDDDd ˆ"€¨åPÓA|å+o‰¯¼å«RdÙ²eÓTËéÓ§ÓÊ•+3 ·Üf«õ;]>ßû3D_Oâ+_yK|å-_H3FFFÒÀÀ@Ë488˜½6Óõ;]>ßûÓ¢¦ƒøÊWÞ_yËWdH\œ‡é9ñ¸¿¿Æëwº|¾÷g  Õ«W§žžž´eË–tæÌ™)Ë{{{ÓÄÄÄäóx¯5¢Õú.ŸïýiQÓA|å+o‰¯¼å«RÏ_K2€Ô#¯µ3&£¸~§Ëç{Æ€‘8vìXzøðaöøÉ“'éСCéĉÓf‰zþüyÝY¢j»0µZ¿Óås½?c@ôõ$¾ò•·ÄWÞòU©ÑÑÑ´mÛ¶ìÂ~ýúõÙø—/_NY'îÑè>õÆP4[¿Óås½?c@ôõ$¾ò•·ÄWÞòUé"V¬X±¨÷§DMñ•¯¼%¾ò–¯""""2D@Ôr¨é ¾ò•·ÄWÞòUÁ¢ úyò–¯ÄWÞò•xk ˆ"€¨åPÓA|å+o‰¯¼å«c@ˆˆˆˆÈ j9Ôtð•øÊ[¾où*€À}=ùÀW¾ò–·|å-D-oùJ|å-_‰·Z@Dá$""""Z@ˆ·|å+ñ–¯¼%- @ôóÔד¯ÄWÞò•xËWZ@ˆ·|å+ñ–¯¼%- @ˆˆˆˆÈDÑ¢¦ƒøÊWÞ_yËWÆ€oùÊWâ-_yKÆ€@QË¡¦ƒ¯ÄWÞò•¼å«c@ˆˆˆˆÈ j9xËWâ+oùJ¼Õ"€ Æ€èëI|å+o‰¯¼å«- Ä[¾ò•xËWÞ’ DDDDD´€oùÊWâ-_yKZ@ €èç©-_‰¯¼å+ñ–¯´€¨é ¾ò•·ÄWÞòU1 DDDDd ˆ"€¨åPÓA|å+o‰¯¼å«c@ˆ·|å+ñ–¯¼%c@0Oœ>}:­\¹2Óðð°â-_ùJ¼å+oI f‡‘‘‘400ÆÆÆ2 f¯BDDDDÆ€ r"|DªÍ‰ÇýýýZ@Ôtð¯|%Þò•·¤ÕÓÛÛ›&&&&ŸÇãxÍ}=ùÀW¾oùÊ[2•³lÙ²i¯õôô4 ¹ŠìÛ·/S´œüíoËþŸ‹çÿûßçtKéùÐÐ?fáy.~ø½.”çqœå‡ó—ãçóyþ@´€]‹²¨7$^TN> ÖóçÏKÏ‚ ˜1qïvîRKqlQ•@Ð5´ûƒoùÊW𖯼ÅâöUÂÀ[𕯼_yËWÀâC €@@Aw±lÙ²I¡:nܸ‘öîÝ›V¬X‘V­Z•Ž?žÝû÷×É}=zôhzúô)c*&ÿüóì:sæLÚ¾}»'IÌqrìééaÄ,­!¨†?þø#mÞ¼9«‘sLplívŽ;¦ÅcرcGzöì#*`ùòå î&€ÀIr5tZ@ªuçÎËZ›P }ôQæ©cBµÇÖè¾[¶lÉj_uû9L²€8þ|6%¤¦ëj‰¾Èù”…q!3³ 0Æ1¡k‰ÒyËRt¿8tè>õУÛU„PtÇŠ©¹Ñ9·nÝʪ%f¼ŠqÅ1 fÁÂ’½ÈPã97¾ò¶s¢U)¦1 /׬Yãþ*È‚úÍ®_¿>ÿQ¬µGgD–8D׫Ç„^ѺSž£Z¢2"¿GX(wû8F€@€€`‰²PnÄ醡 €AÐ@@@@@,ìðQTí²ÑÑÑ´{÷î´bÅŠÔÛÛ›öíÛ—=z4m½ï¿ÿ>[/Ö)nçÖ­[iïÞ½Ùë===iûöíéòåËÓ>ËW_}•½oùòåiõêÕéĉéÅ‹SÖùöÛoÓÆ³Ï²eË–ôõ×_OûÜOžø [?ÂC‘³gÏN›3±N¬›óã?f¯ eÁ$k?|¶x~ãÆìùŸþ™žø| €Ðåäßÿþ÷äkBòVŠÚõ>|8mqÑËŠ-&¯^½Ê^Û¼ysËÏ­9Ó>Ͻ{÷¦}þøl¡»wïúr ,´Òêõfc0¢ T½n^µ!&ÊÁƒ³À¯×ëÝ®Ê|ž¼$ï‰._'OžLOŸ>õe@XÌ$ ÑrÒŒ<4»eÍ4€ÄcÇŽ¥µk×N 2D@`|Ë®^½Úô3ä-%9Ñ«v»e»`‰1'?üðC¶<öóÌ[o½•] Ç ñªÈ/¿ü’Í~õöÛo§d¯ÅàñK—.e"'Z'bbŒÈ;ï¼3m»ÅAèããã™80m½ýû÷§+W®dÛ b®X¾k×._6€ù&º=ÅTµeƒE;$ˆÁàÿøÇ?²ñ±^ž˜&·8-n„“è†ã?6lØ.\¸Pw»1 ï¦M›²ÖŒ5ñ¼v½Øî‘#G²¿)ŸÒ7ºd@€€æ&€üå/!"""""šUM 0k-€$çÙ³géðáÃiåÊ•©§§' ¤~ø¡ôû—-[VjPlõêÕéÈ‘#éÎ;³ö7åûkôÙ?~œ8z{{3ÅãG5ÜÞ7ÒÞ½{ÓŠ+ÒªU«ÒñãÇÓóçϧ,œ\~ôèÑôôéÓ9Û^«¿·Õòz\½z5mÛ¶-û ›6mJ_ýuÝíÕn»Ñ²FûnåEpúôéì÷nûoköþÙFùšŸòÕlýªË×L~cÊ—òµXËWÙßf=b»µë×Û^|ʰÀH°ãþ矦‰‰‰ôË/¿¤wÞy§òxNìçÂ… iíÚµ³zoöÙâÀôù矧ׯ_g:sæLÚ¾}{ÃíÄþúõë™?/_¾L'OžÌ:9û÷ïO×®]˶ë|ùå—içÎs¶½²ßEÙÁíÛ·ÓúõëÓO?ý”=“ˇ~Øövʬ×Ê‹‘‘‘ì7:66–)NPñZÙ}•}¿òµxÊW«õ«._íþÆ”¯&Çž7ÿ”¯…]¾Ú E¾ûî»ÔßßßòýW®\iz!®|s@úú«Q«ÓŒ'Ož¤wß}7«i‰u‡††&~ÙZŽzË.^¼˜:4åµ8¨¬Y³&«MˆZ¦?þøcÊò?þ8«ùˆš†¯¾újÆåË—O{-öY–8Ø´òm>¶WU‰ïûÒ¥Kog&'¢Z/âà›ŸH‚x'©²û*ûþV¼9Ǽ9Ù¤´eKJÿ{Jÿõ_åÞ§|Íù*³~'å«ÝߘòUŸÿ÷æ_ß›ñY”¯î+_3ù]†W›7oÎZrZ½ÇŽYË—òtKiçõñc>uêTúí·ßê.ߺukúù石‚5q=vìØŒkŠ5Iq ÎùôÓO³š«Hù±Ÿ÷ßJ­Å'Ÿ|’ú(ÛN«ýÅg?qâ„ó°HÔE^·nÝdÍM³þŸQŠÞ™Àkk¯úÞ|ÖâI$ðÅ~žÑ¤}_Û¡Ñ~£VlãÆ“5_ñ¸YJ‘{÷îe'µzŸ%ß^4Ï?|ø°”GUn¯ªRf;eúȶ{¯çE½mÔ«½kÇ“VµµÄ¹59B“òÕÅå«ÑúU—¯vcÊ×t¢Õã¯oþýß7ÿâÿ²­ ÊW÷–¯àÁƒYðŠØh{wïÞM»wï.õìÚµ+Ý¿ßù ˜·R¶«U›]²¢4úÓQ{Í€‘ºó‚Zlžé<öU{"ˆH®™ì§l¡Þ·o_V+SìCÛ¨F¨ÈÍ›7³fâ8`6;Á={vЇsµ½…ÜÒÈ‹ù¨Aª-2oÎ)Óxó³i»Ç£ò5·å¡ÌúU”¯…ÐÒUå«Î¿÷ÞüË[>âq_ƒÊ×Â*_Áøøx6€ºñÞ2'º•iéYêå ˜ÝR×[P[³³ŠÄî?^¯§–™À£mñ`û©=¢H•5HõjZÕ*ŒŽŽ¦ 6”x8×Û«2€Dßæ¹ìCÛÌ‹z}`ãµ²û*ûþftÒ¢|Í_yhgýNÊW»¿1åk*yëGÞêQû\ùZØå«U)Û"Ýíb€¹ó×@E‰ÂZì#ýI‹3jÄ º˜å!ˆì{ï½7¥°Ä¥Uóo™YD¾øâ‹tðàÁ¬y9ˆ‘b_ݼm|†NûÐÆßg±m³YDΟ?Ÿ`5ýF€|Ä8ØÆ`ÄâA¢ösT½½ªHä£Kí[·²ç³9‹H+/òY@â{ïd‘VïoF'c@”¯¹/_­Ö¯º|µûS¾¦ròÿµzMùZå+þî¼E#üˆï¨8nc&ç©(+e_+_À\΂ƒ¦âÍÅÑ´éŠ}YcyÌ£Ë#åG+–˜‚/or.SÃ'„è§[¯8âÑŸ5öS ^¾|yÊòèG'ŒV³ˆ´ªM‰ƒc>ww(7êÃZ¦†&j@âóæ_í\àeæ5¯z{í,oô»ˆÏßE|ÿß~ûmÛ5Ví̱ßl[q‚+3z£ÏÑìýí„h ùë_ÿÓòQv,åkîËW«õ«._3ù)_ÿáù›}MþÅråká–¯hù‰¿;¦¨í$€Ä…wLý[å ˜« ,ÌòìÙ³tøðá´råÊÔÓÓ“Ò?üPúýË–-+µN(¶¿zõêtäÈ‘tçÎYû›òý5úl?NH½½½™âñ£GnïÆiïÞ½iÅŠiÕªUéøñãéùóçS–N.?zôhzúôiÓí5[¿øùs…o3ÝÞ‹/2Ïcùš5kÒgŸ}ÖÒëW¯¦mÛ¶eïÙ´iSúú믛~¾ÜëFË}­¼ NŸ>ý>CÃÃÃm}×­Þ?›´ëEUû›«rÖê»k÷ïmµ~Õå¢H¬×êsVýù”3À" ÿÓÖŽ"pĉãÏ?ÿLé—_~Iï¼óNå$'ösáÂ…´víÚY½8jöÙâ„ÿù矧ׯ_g:sæLÚ¾}{ÃíD@¹~ýzæÏË—/ÓÉ“'³“yÎþýûÓµkײmÅ:_~ùeÚ¹sgÃíµ»þ•+WšžÐ[m/.¼ÞÿýôêÕ«ìóðÁS.tj¹}ûvZ¿~}úé§Ÿ²çqÑöᇶõ—]¯•·###Ùotll,S\(Æke÷UöýsFærsQÎZ}w3ýÛË®ßi¹Èùî»ïR¥¿ë2ŸO9,’ò¯7ê{£ë¥wµ¥ÍxòäIz÷Ýw³–‚Xwhhh²æ¬l­n½e/^L‡šòZœ¬£†>jé¢öö?þ˜²üã?Îj£﫯¾šñ‰yùòåÓ^‹}–%Nâ­|kg{­Öß±cGÖR5ÓíÅã¸èȉÇõ.sâû¾téRÇ`3¹è®õ6.jò ´ ÇÅbÙ}•}ÿ|2¯µ*ÝPÎZ•‹Ù –‹ þöÍ›7g- Uÿ®[}>å °H„­oôéÿþ_.„ÄIâÔ©Sé·ß~«»|ëÖ­éçŸÎNXQ“'ÇŽkëäWo¨¡ œœO?ý4ky‰Ú³ØOÔØk?ùä“,üÄò¨ÉÏ1Ósœø£Õ#þ¦PtIŠ×ÊÝ&]ÀÇöÎ;—Õ8–ñ¨Þúµû:qâDé ŽzÛ« á_ÊFÄ÷ëÌÇ…Q­·ñ9ão*þ}õ>{£}•}SúšhH«2Ñ-å¬U¹˜RE¹>úè£ìõzïoÖÕj&ŸO9,²ò¯šÐñ¯Ò!$Z3âD¹nݺÉÑfãâÄR¼ ™i Š5p}}}SBP\8ûOGW…»QÅ…L´êlܸq²å&—­I½wï^Êê}–|{ÑíåáÇ¥.dê­_d×®]éþýû¥/Œêmï½÷Þ˺]EÉ»`5kÁi§/|³°v/Œêy[oíÔ²—}ËÒÎëVe¢[ÊY™rQu©¢\ܽ{7íÞ½»áû; õ>ŸrXà¤^Uìÿ©YçPj·Ê6º#ÄxâI9Z?¢y=j³ò`± ÓLHì«6ÈDÊ5“ý”=YîÛ·/k)ŽiÖ%)çæÍ›Yw¸piÐΞ=;ÅÃf4[?º1´Ó2Óh{1=&_#hž?¾é…ì|ÔÌ6òv^jfË›6Š×LH«2Ñ-å¬U¹¨:€TU.âq™Š‚Ùú|K¾œZ©eæ- õ¨­1Y±âB=ˆÿk/’fr‚Œ¾éÅ“tì§vV–"U¶€Ô«™kU[7::š6lØPz@o»µõÖîq1PµÓï°–o¾ù&˜Þˆ30—}Ó›y[¯oy¼Vv_eßßv ©  V\ø/Ú",Ô¶€4+ÝPÎÊ”‹ªHUåb¦3”Uõù”3À ÅÐÑÞ8 ÇxÄxˆâŒP1X5fO âÂ%ºóOB1åb«îKefçùâ‹/ÒÁƒ³îQAÔLÇšä}Óã3t:$þ¾ø;‹c@šÍ‚-qáÖ¨KEta˧ñÏùO¾µŸ£ÕúÁ­[·âlw{ÿüç?3ßâo¾ßQÚ¨ËWOÑRŸ!˜ÍÙyZy›Ï®Ÿ¿“ÙyZ½¶©÷ùbrŒ?ˆï%>_t,®×ªLÌw9kõÝÍF©²\´zÿLº`5û|Ê`<„´7 V\Ɖ#jc£É<¨ûˆÇò˜Ÿ>–GíYœÈŠ'¡˜Ú2ïÊÑì™+M\hÕë®G1#öSå^¾|yÊò,§Õì<­j5ã¢+Ÿ?›]·ª)šÅø¼ùßWï~EZ­Ä <¦-sÁÑj{Ñâ‘ñ‰îgѼÌï"¶ßE|ÿß~ûmi?Ú¹0*³­¸p,s‚FŸ£Ùûç3€Dˆà›—­ µëµ*ÝVÎj[GÛi](³~•å¢ÝÒéçS΋4€ÿÃ=s@@ €@€E@ˆˆˆˆˆˆfS“æ‚ÿÔgE1|IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_increment_bar.png000066400000000000000000000535111174000617100242120ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxWIDATxÚíÝlU÷}?þJÓ4MÓ4íŸiMÓ¤iÚÓ4µÛº®ëX³ãøAK—¬uhš|p“‘’&ípÃ'þ$mš0ºª…®ËÚÒൄDIK]–ò#È5Ÿti+_“   ŃˆËÌïïyrkc_ûþvðã)½Ä½÷î9>÷Üó>û>?Þ‘DDDDDD”wX""""" """"" """"""""""""""R¯üÆoüFzÇ;Þ1Z¿ù›¿yým¤‹þ¾¨·ûtDDD´2"ò¶ÌÁƒ¯ÙiŽ:|øðuµ“ âs™¹ãŽ;&ÈêÕ«ÄŽ-€ˆˆˆˆHíòßÿýßéW~åWFwÂ~é—~iôñ¯þê¯Úy³cës‘Úå™gž³öÑ~tÌó§Ÿ~ºäNÛdUœ^x!µµµ¥_ÿõ_O?÷s?—~ög6ýÚ¯ýZþÚÑ£G§½sø©O}*GQ¼Ç»ßýî|Þ#§OŸÎßëñó÷þÝßýÝô¥/}©ìÎS§N¥üãé=ïyOúùŸÿùü½dïÿûÓ¿ÿû¿×dÇv¢a?üp¾lbzqîÍC=4áû–3ã§sùòå¼§+ÆåWœcÇŽåÃ~û·{ô}c9¯\¹rÒÃðêñùÔr^J-ÓJÖa©Qþæoþft‡+vÖbG5þ-¼vóÍ7WÇ{,ýÌÏüLÉq·nÝ:åNeìÀNôüñ|u¢a_þò—§ ƒžžžô ¿ð 5Ù!- ·ß~û„ÓŠåVÍü¶|ùòÑÇñyË/ÀPê}7mÚÔϧVó2Õ2‘&exx8ÿ•¹°Ãµ`Á‚üõ–––Ñ×bxŒWÎNv!ñ‹uñ8ñËýþç¦sçÎ¥÷¾÷½%Oxÿþù—™ã(vR';´Å¯¿óïœÖ7#N /Nñqû±Óxþüù²wÞJa`ü{ĸ•îÄW;lªù¬'@ê5•|>åœQ￱™ó"" ""uÈ?ýÓ?•µÃ7þ¤èj{@Æ3UH=‡5³¤^óWÉçŸI³þÆ™4/""""R‡Äqôådªãî'J-Ï©ç°fžR¯ù«äó™ìÒ¸øgÒ¼ˆˆˆˆH÷e¿ó÷˜(ÎÀÀ@ÉqÆ_Zu¢{4Œ¿ VÜ"®‚WÄ*väÈ‘¦$Îy)>(Î1(\eªðwĽ6šµC\ÉüUr•²øL†‘è­Š«oÅ%’ãs«÷ߨŒy™Î:," ""5È<0fÇë}ï{ß„ã¿Tn\« 6LëøüØQžê> q¹ÔzïàN5,.í:þ0 Fܤ^ó7ÝyŸÎç3Õù;µú=/Ó]‡EDDD¤ÊĨKßQÈøû(üÞïýÞè°øU:n ÷;¿ó;Sž$¿àǽ~ã7~#7*îR¯Å/ÛÚ‰Ÿj'3z†Šï4ãüò/ÿrÞ»P¸´k³Rîü•³C]ø|â^!ñÙ;q?˜O~ò“Þ­¾^c#祜uXD@DDDDD@,™©ùä'?9æùwÜ‘>úÑ*¥”RJ)Õп_ ³ ·Ýv[úÎw¾£”RJ)¥TC @D)¥”RJ)QJ)¥”R ¢”RJ)¥€€(¥”RJ)QJ)¥”Rêí ¾¾¾´víÚ4oÞ¼4þüÔÕÕ•ÇŒsâĉÔÑÑ‘ZZZÒ²eËÒSO=Uò=·oßžZ[[óêîî®ùðfO@”RJ)¥€T˜»îº+9r$ŒŒ¤¡¡¡´uëÖ$…œ˜:;;'}|Š{TªÞìéˆRJ)¥”äèÑ£iåÊ•éøñã×ô0< ˆDOÈl쉸PŹãŽ;ÒÀÀ@~øV¬ñ¯çž{î¹çž{î¹çž×ûùÛ û÷ïO7Þxc:vìØ5Ãâ¤ìñ)‚‰Î©ˆ×j5¼ÙÓÓ¢”RJ)¥ô€T‘Ý»wç—Ö«]M”8=» „DÅáX›7ožô¦ÂU¥âjY¥®:UéðFO@”RJ)¥€Ô0±C?QgçÎiáÂ…ù¡W›6msúDçPĽ4JÝW£šáž€(¥”RJ)™A)u>Èõ0=QJ)¥”R"¢”RJ)¥@¤™uðßH¿õ­tðàÁ«ÿÆóB}ó›oÕž=oÕ“O¾U{÷^­xòq}±•RJ)¥DdÂJ7Þ˜ÒW¾ru¦âßeËRúë¿NéýïOéƒL馛RúЇRºå–”n½5¥ÛoO)îú¾fMJ)ýÝߥô±]}þ‘¤ô7ã‹­”RJ)  o€|ë[ßM?ÞŸž}¶?¿Äñ3Ïô§þçþôå/÷§ù—«Ãÿõ_¯ÖW¾ÒŸ¾úÕ«õµ¯õ§]»úÓ׿~µây ÿÊWúlp”RJ)¥@äÚúÆ7ÆÛd€¨~¶î¸#¥U«RúèG/ÏŠ Ê7¿y ÜÁüºø7–e¡¾ùÍ·jÏž·êÉ'ߪ½{¯V<Ža1î·¿Ýkc­”RJˆÈÌÈÓO?=¦¤qõ¡]N_þrM?Îüó°±VJ)¥DdÆ$þÖâúö·¿ ¢”RJ)™=ùÈG.¥]»vÖO< ¢ª¬GýQú¿ÿw0=ûì`̾WƒÙº3˜Ö®ÌÖ§Ál}LwÝ5˜6nLÿø`úÄ'Óßÿý`úÔ§Ó}÷ ¦ûïLûÙ4ãlÙ’þáÒÀç>—þñÓÀ£¦mÛÒ@wwؾýêóž÷^™‰¹ûîÏŽYvo J)  Ò@€\މñ‹µYn1<¿?“€(¥”Q ÈúõÒg>ó™Ñúr ¾J)¥@@DÈ„Y½ú;cÖ·Ïþó–µRJˆ€Ô O?ôPö–_­Jî¡ ×gýèÑG¯î±g˾V{úg>ñ QJ)Ù /d¯Ïã¿ýÛ¿ˆQJ)±ñQJ) ëÉ'¿—ž}ö`:xð`úÖ·æë`¡¾ùÍ·jÏž·êÉ'ߪ½{¯V<Ža1î3Ïì™°þå_¾Ÿ-»3éé§Ï¤3gÎdßõ3éž{Τ{ï=“ýÍgÒ¦MgRgç™tß}gÒÿù?gRW×™|ü<“>ó™3鳟=“yäLÚ²åLúô§¯ŽóðÃ'ìT)¥D@äíRq÷îú§Ú}œ±ÓýØc?šÑéÏftÓ¦M£µmÛ¶ë ßýÖ·ÒÁ={ÒÁl¸<Ï¿ñ·ê›ß|«b¼B=ùä[µwïÕŠÇÙ°YUûyÆäc9doU“m\Œsçƒvª”R"  3 ßÏ>àâÏõÑl×@úÿùŸ¯N8û.Õjcr9@”RÒ„ôõõe ÆÚ4oÞ¼4þüÔÕÕ•'wM¶µœ3gΔï¹}ûöÔÚÚšWwww͇7{z òôãÏ}.Éf0;9³:“-Ã3÷Ü“ÎÜ{o:“½÷™ÎÎt&ûlÎlÞœÎÜ:“m[Î<ð@:ó™Ï¤3=”Î<üp:³eËÕç1,÷û?  ¢”ºÞrWÖâ9r$ŒŒ¤¡¡¡´uëÖ$ãóì³ÏfÌÕSdO¶nooO.\È+в§°e®ÁðfO@@®V`#eÉó½ï¥”A¢¢=Ö¢=ý=öØŒÈç>÷ÙŽù3£µoß>ºä¶ÛN¥ø‡­/|á v²”R×÷!X‘¹sçŽyíõ×_O+W®L§OŸž ±3ßßß?ú<\j5¼ÙÓÙµkwYn_ûÚ×ä:ÈëÙr+†eüÐ6rË-ÿߘåöðÃϸ¶ÁNŸRRÓ:tèšÏe;»víÊO–––1Å ‰×j5¼ÙÓë ƒÙT<<ð€ˆRÒèœ8q"k`nNgÏž}íøñãÙ¶èöÑçSd¢áÅ=*Õoöô@¤~Ù—ÍÓcB µ{÷n¥Ôõ £Gæ‡Y8Šø8uêÔ´r=÷€7Ź#k5ò÷ò†2û·Ïr毹ï¾ûªZ~CmmuÈáÇ˞¿¶¶¡†¤Òõí§5Èîlïµxþ¾ô¥/•=ë׿Vw€ôööV¼¾½¼cGݲsçβçoË–³ H¥ëÛK== H¹ó·cÇËuH\V¹šö¡mC³Û;Ï=÷ü­ço[€ìß¿?Û>ݘŽ;6aÃDUÎ9ñZ­†7{zz@ô€è©_ÈDÑ¢DÈÃ3¾m¨æÂ 3µþ+Û¸œm„/_¾œ.ïÚ•·—ÛÚÒål\ÎVòËÙrºãdËår¶œ.gËéò† éòÆér¶}¼ü‰O¤Ë›6]}ž}Ibü¾ýW¿Ø+= ‘8ÄaY¶1:yòä´ÆñÏ W•ŠKù–ºêT¥Ã==©mÛðv¨¼mˆËZ-·lüþl£n‡YH=S$÷Ò(u_j†7zz    ¢d%n`x=O@@@@jÛ6|ó›²É\N==—óCœvíºœoóÚÚ.g“¸œ­C—óáíí—³É^Îfãr6—Ó† —ÓÆ—Ó=÷\NŸøÄå´iÓålÖ.gëÝå´~ýˆÙÙ©®mˆÉ>ñDíÚ†@ËLÈã÷Þ›¯g…ŠC¾gBÛŸ‡yë 3µm     3 úÐ9¼é³Ÿý,€€€€€€H}2ÑMjdzmÃÇ?þpúû¿ÿûÑzúé§+^n'²¶`ð _Èoo0øïÿž·mKƒÙijÃ`6ƒÙ f›ÁÓàÇ?ž?ñ‰4˜Ms0k˳ÏlðþûÓ`ö]ÌŸß{o>îÿÛ¹4D@@@@®€ŒoªH=Ú†=öhˆ€€€€€ˆ€€€€€4¤mx챈€€€€Èõ§7nL=ôÐhU² ©¨møçl{       "     õh::þ-uvvŽÖ®]»D@@@@@f~Û                   "                        ×@úúú²¸6Í›7/ÍŸ??uuu¥ÁÁÁiŸ(Û·oO­­­yuww×|x³§      殬Å9räHICCCiëÖ­98¦;||öd[áööötáÂ…¼ÖdŸÔžÂ–¹Û==©asçέxxìÌ÷÷÷>Ç«ã¬ÑðfO@@@@@@j˜C‡•ìá˜jxKKKŽ”b°ÄkµÞì退€€€HrâĉlޜΞ=[ÑðÈœ9s®y­¸Ç¤ÚáÍœ^ñJVœ;²­ßÀÀ@Þ{’7”Ù¿ÍxÞ¨F¦œùk@¢‘©fù µµÕ ‡.{þÚÚ†J×·Ÿvv6 åÎßúõ¯Õ½‘éíí­x}{9vhê ;w–=[¶œm@*]ß^êéi@Ê¿;^®;@¶mÛVUûЈ¶!Î-gþz{_l@ªi_hSË¿U«†ëÞ68p âõíµ®®º· Od+N¹ó×€ìÝ»·)ûok€=z4­\¹2?~¼¢áz@ô€èÑ¢Dˆ= z@ô€èÑ2­ìß¿?Û>ݘŽ;VÑð©ÎɈ×j5¼ÙÓ*²{÷îìCX–Nžmß¾}¤      µÈ¢E‹Òððð5¯Çk‹/žÖ{ôõõe pmš7o^š?~êêêšÈöíÛSkkk^ÝÝÝS¾çTãW;¼ÙÓ™•‰C­&ÈtϹ+kqŽ9’FFFÒÐÐPÚºuk’Böd[ÕèQ¹páB^k²%¿§°¥ S_íðfO@@@@@dÖdÁ‚ÙÂYv€ˆ:wî\¶ÐnO .¬è=ã=ŠÏ‰óþþþÑçñ8¦9Y¦¿ÚáÍž€€€€€È¬>d²“ÐccPI:4¦¤¥¥%GI1PâµÉ2ÕøÕoöô@@@@@fõ}@âûeÙRŒs8¢âñ~ðƒŠÞëĉÙ½9={vÌa^ãSê [S_íðfN¯x%+ÎÙÖo`` ÿ,ò†2û·ÏÕÈ”3H42Õ,¿¡¶¶ºäðáÃeÏ_[ÛPCRéúöÓÎΆ¤Üù[¿þµº72½½½¯o/ÇM²sçβçoË–³ H¥ëÛK== H¹ó·cÇËuȶmÛªjÑ6Äù¤åÌ_oï‹ H5ík#mj¹ó·jÕpÝÛ†T¼¾½ÖÕU÷¶á‰lÅ)wþ½{÷6eÿïm}#£G¦•+W¦ãÇ—ÕàDˆ= z@ô€èÑ¢DˆwB/+û÷ï϶O7¦cÇŽMë‹x­œs2ŠÇ¯vx³§     2«rgöAÅ/ö•Þ }÷îÝùa['Ož,y•©¸4ïDW‰ÓTãW;¼ÑÓ7³aÆQlTz'ôÉNb/NÜc²ûdLtE©ñ«Þè退€€€È›‰渇G¤ÐãqñâÅ´qãÆìËý†¾'¾72ž€€€€€€LÐPü8N¤®ô>       “$Î[(ô ÄÉä‘çŸ~Ú瀀€€€€€L+Ïd-EW\o9Å‚»iÌ9K–,!©Ïex¯\¹’–.]š÷|,^¼8 “€€€€€€Ì¼û€€€€€€€€€€€€€Ì,€ôôô¤E‹9é|ùòåé'?ù )€€€€€HmOBŸèÎç}}}ùݽ@@@@@@j8éü±ÇËïûQ K—.¥ùóç“€€€€€€Ô Åèß÷šdîܹé7Þ¸ƒƒƒ©¥¥…@@@@@¤v‰“ÍWeÞùóçs€Ä½@Ž;–ÃäÃñÁ €€€€€€Ô 'Ožs÷óâºpá)€€€€€Hm/Éžyóæåå¼     R7€€€€€€€4ü*X      uHr%     Ò€,Ë–^ÜtP@@@@@¤î9xð`¶ nqÅ+©?@&»oÔtÏ)þ?åìÙ³Y£tW~cèx|úôé’ï¹}ûöÔÚÚšWwww͇7{z     ³ö$ôÉ*nFX.f&JÜÐ0vâ&‡Q;wîÌ{]&Ëžl+ÜÞÞž÷ÊD­É>©=…-s †7{z     .Ã[ƒL‰zRJü;óýýý£Ïãñêøk4¼ÙÓ:äÞ{ïÍ{=FFFòúb¶£¯M–8L+Æ+$ÇkµÞì退€€€ÌZ€ §%K–TuÈTyõÕWó»«Þ7Ÿ?¾¬÷)>¬ÚáÍœ^ñJVœ;²­ßÀÀ@Þ{’7”Ù¿ÍxÞ¨F¦œùk@¢‘©fù µµÕ ‡.{þÚÚ†J×·Ÿvv6 åÎßúõ¯Õ½‘éíí­x}{9vhê øÑ¨ÜùÛ²ålCRéúöROOCRîüíØñrݲmÛ¶ªÚ‡F´ }}}eÍ_oï‹ H5ík#mj¹ó·jÕpÝÛ†T¼¾½ÖÕU÷¶á‰lÅ)wþ½{÷6eÿ¯á)†A½ÎéÈ–z4fÅ瀬Fˆ= z@ô€èÑ¢Dˆ= ³ï$ô}ûöÕõ¬‰ S 7S¯Õjx³§     2kRn/G%‰+^ÅyÅç€_küÿ+\Ujpp°äU§*Þè退€€€È›‰;¡W{‰Î)ΩS§òC®âÊWQñ8^+—¸—F©ûjT3¼ÑÓ7óüóÏg ì¦ü×ûf¥Ô%y¯‡é€€€€€Ìj€”ºûy5WÁ™ðÄóéT-χ` €€€€€€€€€€€€\§÷©d˜€€€€€HÍrñâEÚd:WÁjii!© …+].·;¾â†z»ví"©Ý!X.µ      uÈ¢E‹Rggg:{ö, €€€€€H}rkö—Ç9qVô‚Üœ-…¾¾¾ôÆoЀ€€€€€Ôç¬W_}5ß /]ºtôäóeÙݾ}{:wî)€€€€€HíRœèýxá…²xSÞ+™?~¶ðV€€€€€€Ô÷Nèq~HWWWZ²d 1€€€€€H}"     R5@¦sÂÂýA@@@@@@ªÈø›N÷š‚;íííipppôµóçÏç¯íÛ·@@@@@¤v‰_óz¼¶xñbRÚ$µš Ó=¤ø°­Érâĉláwä7?ŒûŒq˜Vô”ãµZ oöô@@@@@܈°™ ñzl”ã¼’¡¡¡ôàƒ¦ÎÎβާø’ÀÕoæôŠW²âÜ‘mýr æ eöo3ž7ª‘)gþhdªY~CmmuÈáÇ˞¿¶¶¡†¤Òõí§±h@Ê¿õë_«{#ÓÛÛ[ñúörìÐÔ ;wî,{þ¶l9Û€Tº¾½ÔÓÓ€”;;v¼\w€lÛ¶­ªö¡mC___Yó×ÛûbCRMûÚ€D›Zîü­Z5\÷¶áÀ¯o¯uuÕ½mx"[qÊ¿FdïÞ½MÙÿ».½âÜ£'Dˆ= z@ô€èÑ¢Dˆ= ³¬$0‡FÕâNè“$NÊR;èS¯Õjx³§     2k²|ùò1à(®rï„>@b%» „DÅzóæÍ“þ¿ÂU¥âjY¥®:UéðFO@@@@@@ÞL@£Ú;žOÔ{2>qoQÝÝÝ5Þì退€€€ÌJ€ÄŽoôt¼òÊ+£7"ûlþžS·'Û ···§ .ähÙSØ2×`x³§     2kçzLv#ÂK—.Õ ¯¿þzZ¹re:}úô”‰ùþþþÑçñ¸CÕoöô@@@@@fõexãp«åË—ÞˆpÅŠipp°¦ç“|.[‘víÚ5­ž’–––¼'¦x¯Õjx³§     â> 5Èd°8~üxö!Ü>íCµ&>wîÜš oæôŠW²âÜ‘mýòÞ“¼¡ÌþmÆóF52åÌ_#L5Ëo¨­­î9|øpÙó×Ö6Ô€Tº¾ý´³³!)wþÖ¯­îLoooÅëÛ˱CSg€ìܹ³ìùÛ²ålCRéúöROOCRîüíØñrݲmÛ¶ªÚ‡F´ }}}eÍ_oï‹ H5ík#mj¹ó·jÕpÝÛ†T¼¾½ÖÕU÷¶á‰lÅ)wþ½{÷6eÿïºHàãÔ©SÓˆ= z@ô€èÑ¢Dˆ= z@®ãžžžü~ Å—ÝC²~ò“ŸÔ “cRÎ9ñZ­†7{z     ³ Ïd-Eʼn®Ð©v¢Ë½ Ödã^¸ªTœ‡RêªS•oôô@@@@@äÍ,]º4=öØcùaCʼn+`UréÜd*€Dâ^¥î«QÍðFO@@@@@@ÞL1:Æßù¼QwB+o52ž€€€€€€]­é7Þ¸q8ÑT'R €€€€€€”•8Ù|Uöá?>È•+WÒ±cÇr˜|8>XZääÉ““^¥*N¨©éex!ÅwB¯ä¼                  ³ gϞ͹ŠÄ è‹/ÎÏÿ¸166      µÈ­Ù8qâDþxÓ¦McNB_­€€€€€€H­÷úÊ/Y²$‡ÇøÃtüøñiß ]@@@@@dZ p÷þˆçÃÃÃùóFÝ @@@@@@f @Z[[óW^y%ÇÇ‚ ò×£W$† €€€€€€Ô ±ã[|ÞGG,¡,ùÒ@@@@@@jzÞ¥K—æ‡[-‹%ùfV¬X‘_!K@@@@@¤¦©+@-Z”:;;õr€€€€€Hý÷ÿˆKðÆyqõ«›³¥Ð××—Þxã :ú‚õꫯæô8¤p"zœ ²}ûötîÜ9Rúœ½/¼ðB¶o½'HÜŒpu,=zî$Çù!]]]ùÒ@@@@@@fÄU°Šï#2QâÜ’µÙ?oÞ¼¼G%P388Xò=ã°¸bTwww͇7{z     ³ ÃÃÃyG1" ÷)"宬E:räHÉï°¾uëÖ$“eO¶nooO.\ÈkMöIí)l™k0¼ÙÓ™µY¾|ùpWœR €ŒO@¤Ô{ÇÎ|ÿèóx\|JµÃ›==Y €Æ¾}ûjv(ÖtrèС’= qyà@J1XâµZ oöô@@@@@f-@Êíå¨ 'NœÈï9RꈽOñ|V;¼ÙÓ™µ‰{~Äy ÈÑ£GÓÊ•+ÓñãÇKŽw=÷€¯dŹ#Ûú ä‡oå eöo3ž7ª‘)gþhdªY~CmmuÈáÇ˞¿¶¶¡†¤Òõí§ H¹ó·~ýkuodz{{+^ß^Žš:dçÎeÏß–-gJ×·—zzrçoÇŽ—ëmÛ¶UÕ>4¢mˆ Ö”3½½/6 Õ´¯H´©åÎߪUÃuo8PñúöZWWÝÛ†'²§Üùk@öîÝÛ”ý¿†äùçŸÏïû1ÕU©ªÈþýû³í×騱cS¾ÏDçTÄkµÞìééÑ¢Dˆ= z@ô€èÑ2k{@&ºúU­¯‚µ{÷î¼§åäÉ“Óú…«JŠJ]uªÒក€€€€€„>YM÷ü‰ð2䔂KÜK£Ô}5ªÞè退€€€È JÜ ðzž€€€€€€€€€€€€4 /¼ðB~‚xrã5šäÈ‘#“ž£!     RS€DoÇÙuþüùÑ×âqÜ©<®\%     R3€Ä!WÃÃÃ×¼~åÊ•q²6€€€€€€\gºæõ@ €€€€€€HM²|ùòlá¬NçÎK###yÅã[³%‡g €€€€€€Ô q¢ùd'¡ÿøÇ?&©íexÑÛ‡\EÅcøºD@@@@@@@@@@@äí8¿ã†n}\öüµµ 5 •®o?íìl@Ê¿õë_«{#ÓÛÛ[ñúörìÐÔ ;wî,{þ¶l9Û€Tº¾½ÔÓÓ€”;;v¼\w€lÛ¶­ªö¡mC___Yó×ÛûbCRMûÚ€D›Zîü­Z5\÷¶áÀ¯o¯uuÕ½mx"[qÊ¿FdïÞ½MÙÿk8@â—÷èéxå•Wò稓'O昘ê<†jΉ×Ê9'£xüj‡7{zz@ô€èÑ¢Dˆ= z@ô€ÌÚ8×c²^ºt©¦WÁœð*QãÿßTãW;¼ÑÓq‡[-_¾<Í›7/¯+Vä;Ó•Üd²ûĽ1&»OF¹ãW;¼ÑÓ”@Ïõ<=i@îÌ>¨¸jÓøÃ¨Ê½ ¯€€€€€HÉlذaã2Õ½,@@@@@@ʾÈ‘#GòÇ…¸2ÖÆ³/÷7H@@@@@@jâ+B?Žû,\¸@@@@@¤¶‰{W®µÿþüñóÏ?ï©-@žÉZŠ®¸å}ŠwÓ˜s@–,YB      RŸËð^¹r%-]º4ïùX¼xq&©@@@@@@@@@@@@@®€œ={6-_¾|ô¬8ô*Îÿ¸166      µÈ­Ù8qâDþxÓ¦McNB_­€€€€€€H­ÒÒÒ’†††òÇqÕ«€ÇøÃtüøñ4þ|RÚ¤øæƒsçÎÍŸ®~å>      RS€´¶¶æ=¯¼òJŽ ä¯G¯H ©@bÇ·ø¼ŽXBY²Ït)€€€€€Hm/Ã[¸ùà²X’ofÅŠù²@@@@@@j ë qÅ«ÂåwÇW­®‚‡rÝ•µJqÉߨx|úôé’ÿgûöíùIðQÝÝÝ5Þì退€€€ÌJ€Ä]ЋÁQ\qYÞZäÃÙ ;q§õ¨;wfÎ-“Ž¿'Û ···§ .äµ&û¤ö¶Ì5Þì退€€€ÌZ€4öíÛW×Ã&êI™7oÞ¤ãÇÎ|ÿèóx¼:>Á oöô@@@@@f-@jÕËQ*÷Þ{oÞë122’׳µxm²ÄaZ1^!ñ8^«ÕðfO@@@@@dÖ$.½‡ Õ3¯¾úê˜C½âñùóç'¿øîìA©ÚáÍž€€€€€È¬ÈóÏ?Ÿ-°›Òàà`Ý77Œâs@ÖF 3 {@ŠW²âÜ‘mýâæqøVÞPfÿ6ãy£™r毉F¦šå7ÔÖVw€>|¸ìùkkj@*]ß~ÚÙÙ€”;ë׿V÷F¦···âõí娡©3@b;]îümÙr¶!©t}{©§§!)wþvìx¹îÙ¶m[UíC#Ú†¾¾¾²æ¯·÷ņ¤šöµ‰6µÜù[µj¸îmÃ*^ß^ëêª{ÛðD¶â”;ÈÞ½{›²ÿ×p€Ltõ«Z_k¢Þ€R=S¯Õjx³§§Dˆ= z@ô€èÑ¢DȬ> }²ªÕù!qÅ«8ï£øâ«`?„©pU©è•)uÕ©J‡7zz     ÒÀœ:u*?ä*®|ãµRçPĽ4JÝW£šáž€€€€€€Ì ”º$ïõ0=)ÊÙ'M×ë<6lÅÆx€4â!     2‹ç,9rdô„ôÈŋӯ³/÷7H@@@@@@j{Þ‰ÇÕª.\H      R[€î„'gïß¿?7(t€€€€€€Ô Ïd-EWÜq2¥üŽèÅç€,Y²„@@@@@¤>—á½råJZºtiÞó±xñâ4<Á oöô@@@@@¤ŽY°`AêééIK–,IóæÍËÿȸÊÖd‰Ã´¢§¤x\|B|µÃ›==©câD÷Ø(§¡¡¡ôàƒ¦ÎÎÎ’ã—:W¥ÚáÍœ^ñJVœ;²­ßÀÀ@Þ{’7”Ù¿ÍxÞ¨F¦œùk@¢‘©fù µµÕ ‡.{þÚÚ†J×·ŸÆv )wþÖ¯­îLoooÅëÛ˱CSg€ìܹ³ìùÛ²ålCRéúöROOCRîüíØñrݲmÛ¶ªÚ‡F´ }}}eÍ_oï‹ H5ík#mj¹ó·jÕpÝÛ†T¼¾½ÖÕU÷¶á‰lÅ)wþ½{÷6eÿïºHô< ˆDOˆ= z@ô€èÑ¢Dˆ= z@ô€ÔÇ«ã¬ÑðfO@@@@@@˜C‡•ìiiiÉ‘R –x­VÛ==iPNœ8‘-ð›ÓÙ³g'gΜ9×¼VÜcRíðfN¯x%+ÎÙÖo`` ï=ÉÊìßfïM¹5[+ãßf<¿û½ïM³oÒÝwßîɾMï|gZ—UÇïÿ~êøƒ?Hø‡i]VôG©ã=ïIüÇi]ö:þäORÇûÞ—:þôOÓºlyäÏcxöæÏŸŸ,Xþê¯þ*ÿ÷#ÙÖªœùûЇnKú§wgÛ›{òùZ±âcéïìHïzWGúýßïHðëÒþaGz÷»;ÒýQGzÏ{Ö¥?þãŽôÞ÷v¤?ù“Žô¾÷­ËþGú³?»úüþh]Ví£óó·p᪖߯nH÷¼¹Übù­åõ®wåËmݛ˭ãÝïΗۺ7—[Ç›Ëmݛ˭ãÏþìêóžã_üÅèüÅ¿·g[²rçï†6¦åË7æóõÁÞ“/³w¾sݛ˭#_nø‡ëÞ\no.·uo.·Ž|¹Í™sõy ÿÓÒ²hÌçÙÖÖVñúöwÿã¤K–\]ß²õâï²÷Ë×·7—]¬?늖]¾¾Å²›l}ËÆ]‘-ÇâùûÀ>Pöüµ¶Þ•-·«ëÛûß¿1[^wV¼¾ÅðÿÏÿüc>ÏÂ÷ ’õ­#û›îimMwg{è7nLw-_žWc¹­‹eW´Î­{s¹®o±¬ ë[¶ óõ-¯-{½xþ Ë­œù[¶ìÎlýؘ}g³Ï3Ûøë¿Þ¯oo-»«ë[aÙÅrûã?¾v}‹Ç1,ÆûÓ?ý›1Ÿçòìo­t}[Ë+[_îÎv^bþ>¶bŵë[,»Âú–-›uEË._^EßÕgu6nñü-Z´¨ìùûÀ:Ò_üÅ=ÙÎÈÝùç¹|ù]£Û¸w½kÝèwõêr[Wô]ulÝ貋u.¾¿±lßûÞŽù<ÿ:ÛKª¦}¸'û{ïÎÖ‰˜¿ø·äúV´[Wô]å¶®¨m(ž¿X~qä@9ó÷‘Ü‘ýí³mÛÕõ-¾«ã×·ø¾¾õ]½º¾½õ]å¶®¨mˆe¼zÌçÿVÓ¾nˆõ-[gcþòåË«Òõ-†gã/›7oLûµ*Û/wþæÎýx¶¼®®oøÀÝo®kå¯oñ¼Ð6´¶.óyÆ«•®oûŸÿ3Ýý¿þ×Õõ-ûûþ.{¿ ÷GŠÚ†’ë[6îûÿüÏÇÌßM™Ê¿¿ø‹;3‹_]ßb¹ýþﯯx}‹á±=üó?ÿ˜Ïóêš±ÿ ³¤DDDDDäí™™èxMDDDD@¤æ)\kpppÚWÁ©8qïrî2>ãOÆSJ)¥”RªQ 2«RîJ/–›åfÙYn–›Xn–›_zËÍr³ìÄr³Ü,7Ë @DDDDDDDDDDDDDDDDDD@DDDDD@DDDDD@DDDDDDDäjæÌ™3ZR^úúúÒÚµkÓ¼yóÒüùóSWWW´`¦±ÜÖ¬Y3ºÜ6oÞœÎ;gÁ”‘X~¾³åoãlëÊˉ'RGGGjiiIË–-KO=õ”…Rá:·`Á fŠœ={6Ýu×]ùúOŸ>mÁˆ\ïL)/±qÚvíÚ•÷&ÉÔùÜç>—//ßÙò¶mqøKü8ðÁ~0ÿUU¦N,³žžž´dÉ’|'0îN}ñâE ¦‚vᡇ² ¦‘{ï½7ÿ~F»õÅ/~1MDD&I+}óÍ7çǰÊô×¹¨Å‹§S§NY SäøñãéöÛo÷­"¯¼òJÚ°aCzôÑG-Œi|?xà4<<œbúàƒ¦ÎÎN ¦ÌÜvÛmùál2u^}õÕ´|ùòѶ!ë9™$GÍ‹‰D)/ñ+×ã?>fÇZ&N,£b¨ùÎV–K—.¥ÖÖV bŠÄIÀB"‡)/ýýý~Á/#qÁƒè)>ÄQ""dÿþýéÆoLÇŽ³0ªˆsg¦÷uE'iTâJkã(‘é'.ñÃþЂ¨¢Ð6ˆˆŒËîÝ»óKSê^//qŠÏq,‘ëx'Æ/ªµ[v–ßÔ‰^£¸Üb,«… º €4l}[ºti~þGñ/û2yâ˜øŽÆ¡W›6mrz‰¤¸Ü¸L?ñCAáÞZQñØù"""""""""""""""""" """"" """""""""""""""""""""""" """"" """""""""""""""""" ""ò¶Éœ9sò2Ÿ"""""R÷x‘·7>Škü°ýû÷§Ûo¿=Í›7/µ´´¤ŽŽŽtúôékÆûîw¿›ã¿Ï /¼Ö®]›¿>wîÜtË-·¤}ûö]3/_ÿú×óÿwà 7¤ ¤‡z(]¼xqÌ8O?ýtZ¾|y>/üàÓ“O>yÍ|¿úê«ióæÍiþüùùôâ½î»ï¾ôƒüÀ.""""2S2Ù늟üä'iddd «V­ºf¼5kÖäãçèÑ£9(-çÏŸOW®\I>ø`>~à¡8?þø(l31NŒ[ÈÁƒó×6lØÃ$*Ÿÿ˜·xÞ××—?ã7rðÄü‰ˆˆˆˆÈ ÈÀÀÀèkB/ÅøñN:uÍ{ÄN +î1Î_[¹rå”ó½…´··_3?'Nœ¸fþcÞ¢Ž?îÃy»dª×Kƒ‡@Mt˜×xÄP6nܘƒ#^Ÿè°8ìj:óS艊ÿ‡|mݺ5;w·-""""r=¤€†è9)•Š˪ qÈý÷ߟ/^<2¹Ž'ŸÇ°C‡•œ‡BOI!q8×ø÷î!XʼnsN¾÷½ïåÃc"""""Òä,Z´(ßA“Äk _|1¿úÕM7Ý”^yå•üµ8yü™gžÉAQHôNÄ{â‘»ï¾ûš÷-> ýÒ¥KyÝu×]׌wçw¦çž{.ŸH\…+†ßvÛm>l‘f'{ŠKÕNå$'ƒò“ŸÌÏïˆñùä„ï7þ½'6Ù´ûúúÒÚµkóéÌŸ??uuu¥ÁÁÁi/Ûéümå|6Õ®oÓù›ßnß§©>£z®¯…Š¿³Ôü­Y³ftþ6oÞœÎ;W·÷«dû1Û¾O""r=ä+_IiÙ²É+†OG4"o¼ñFI/¾øbºûî»ë ‚Bbš===iñâÅuÝi?ÝâÄÅ<†‡‡ÓÐÐPzðÁÇìŒÏž={òeváÂ…¼bç$^›îðrçoºÃëõ~?üáÓÒ¥KSþMõÕk}-ä¹çž+ Ç;ï¼3=ÿüóéÊ•+ù<~õ«_M·ÞzkÝÞ¯ÜíÇlü>ˆˆ€\“øå´Ü†®øµxÎ7Þ˜¿×-·Ü’Ž?^Öû}ãßH÷ÜsϘ×b§ ~QŒ_ïâÆ×_}ÌðÇ{,ÿå2~Ùûú׿^qƒïs!ñx¢ªb°v"ñxõêÕÓþvȽ÷Þ›žy晪ߧ’ñØq*^?§»l'›V¹ŸM=2צZ÷gÂ÷i²Ï¨ÞYµjUÞk[Nâo®×û•»ý˜ß'k Æ£>š~ò“ŸT Ø¡‰_À¢ûJ6R¿8Nô~ñËmìøò…/|!ï…‰÷Œ_ãÆâ_ ?ÿùϧ 6äÃã—ÇØyª@âýZZZ&}Ÿgq£^<þTÃKjRÉü×úýÆ'>—X&ÍØaŠCUŠwæ¦Z¶SMkºÿ¿™™jÝŸ)ß§É>£z$¦õÐCMûÿÅç»k×®¼' ^ïWîöc6~ŸDD@®Ið’%KFÌôT)n€'ûEtªÆ¬øÿ,Ëæ·D±CU|œvÂpöìÙšìàÜwß}ùañ7¡(wþ‹Ç¯døLÈtÞg:Ǥ—»ÃtâĉtóÍ7ùœ§Z¶•,“RŸu32Õº?S¾O“}FõÈm·Ý–Nž<9íÏ:*G;uêTÝÞ¯Ûëýû  "R2qXFœrûí·—rlj†Åt‹±qC…Šç7ÜpCÅo©ÿ'‘ÆIø1@ØîÝ»KîðUÛRÍŽI-wèfrÈÑ£GÓÊ•+¯9”o6ô€LµîÏ”ïÓdŸQ½Ö×8¼'_*'ñù>þøãc¶gµ~¿r·³ñû  "2­ÿŠ;*ÅLìÜÔ qÌzñÎ@üb;þj-Å©eÈø<õÔSù‰¥“e¢ãžãµé»$Î%hä1ëû÷ïÏÏ'šè$êé.ÛrŽY/õÙÔ S}Ÿ¦Z÷gÂ÷©ÔgT¯õ5¸+ÉD¿Ê×úý¦»ý˜ß' ÄüàùNQ—‘ŒÉ ‰“4ã¸ç;1qˆV­2ÙU{¾üå/§7¦W_}5‡<Üÿý£Ã ǬÇüT{Èg?ûÙü}âï‹c¤ã—ÂÉÙˆ®üÿ§ÔU°&þv;+vÒâ—Ý^x!^Ï«öįDZ³<þ°˜é.Û©¦5Ýÿ_O€Lõ}šjÝoö÷iªÏ¨‰uo²‹Œÿq8ééÓ§óÇ—.]ÊO¾¿S\Ë÷+wû1¿O"" ×$ÍhDâ—Ùè>“U‹nûI _Òb§Z€*®Ê;`Æ;MË—/ϧ×Ìß·oߘáqâ|\{~ª«öLu~úSÍßt†×òý&[Gâ3ˆÏ"î[ðôÓO—|¿JYŸÎ{Mµl§š©>»zdªïÓtÖý™ö}¿=(gýšÎø±c—ÂÎ2Ž_üãï+,‰î}QË÷«dû1Û¾O""r=DDDD;% "6ì""¢v픀ˆØ°‹ˆˆvJ@DlØEDD´S""6ì"""Ú)i؆])¥”šÉ% """"""5Ìÿ?õV„±gj¢IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_increment_line_narrow.png000066400000000000000000000501361174000617100257650ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔP%IDATxÚímlTç™þ+­V«ÕjµÚ/«ý´ZUZ­öÃjµÚ/«Õj…",³FµÜÒ'®ßB¨]Ò‚y#q qMJ  yBX§$Ðââà:8ÐÄØ‹KMpmì‚×Ä÷®'{ü?æ}ÎÌØ3¿Kºå9çŒÏ™ßœ™9×s?÷óœ¯B!„ T_á-@!„Â`!„Ba°B!„0X!„Bƒ…P6ôÕ¯~Õ¾ò•¯LÇ?üÃ?äß‚O1׃B,„f±NžÃ! BIéöÛoŸ¾ èb¤ ±þzë*++Ó2X;vì°?ù“?‰ùÜ–––¸M] #ýïÞ½{Ý8Ò¶^x!aãsðàAû‹¿ø‹@.¸É¬êêêˆÇÒû–Îë ßVVV6ýXçÓÞ?¢XûݰaCVÎOP¯%Þ{ŠÁBƒ…PF599é²ÞeáÂ…n}qqñô:m×ó’ÍIÊ8øŸ£ÌËgŸ}fÃÃÃöŸÿùŸ1 êÃ÷ÿßÿýßÎüé"m›.Øþõÿöoÿ–ÐkV†Ío*edvîÜé¸Õ…ª×¶lÙ²Œ¬ùóçÛÕ«Wí?øAÔמÊë ?Î?þã?Ú‡~8ã9ï¿ÿþM¯ehhÈíwõêÕ3¶ÉàeòüùZyOý #„0X%­ð‹¡×òè£ÎXÿòË/§d°–/_>ã9o½õÖô¶·ß~{Æ6=7Öþ5ÒQš˜˜¸iÛ»ï¾ë¶Élø×Ë&òšÕýä_¯î¥´~|’0XÞkçò¿öT^_øq»z%VKÑ××7½-üõÌ›7/£ç'È×’È{ŠÁBƒ…PÆ´xñâ/á¿þõz^*K57þçèëÏžù·é¹±öïÿßXÛü™žDêŸ$a¿bll,k+W:¯/Öq¢í7VÄ3'鞟l½ B,„2*]¤ýµQ*:÷Ë_7£‹âÈÈHÒ§Xf'|znª&%Ýmñ^g& V¦^_*ç'™š¤L3æòµ „0X¥¬þð‡I]Ћ®ÓÍ`…wßÄË`er[.3X™z}©œ“\1ΦׂÂ`!”²TÇ’ŒÁŠW÷IAÖ`er[.k°2õúR9?ѦNÈãlz-! B)Ió…_\4Ç’_Ÿ~úiÌ焽4GQø(BͤQ„ (ôoëêêÊ™ÁRÍ™¿‹J5>Þ(=CsMåꂟÊëKe”§Î©Œ¯¤l£F/j ·L3æâµ$òFa°JX[¶l™qaù¯ÿú¯ˆÏ ŸJA£ =566&T##o, §ÏFV"ÞÃ! B!„ !„Bƒ…B!„ÁB!„B,„B! B!„ !„Ba°B!„0X!„B,„B!„ÁB!„Â`!„Ba°B!„k.ëÁœ±\WWgwÝuW ‘‰}Î…(DnÎ5Ìpà wì¿îb° Ä`Ý}÷ÝööÛoŸ~úiàûœ QˆÜœk˜á†îØÁÂ`§OŸ.È/g!rs®a†f¸1X(K‹ ‚  ‹ÖÜ0à 3Üœk ¢‹º˜á†n˜©ÁBd°hýÀ 7ÌpÃLkn¬îînkhh°¢¢"+))±ææfñœþþ~[³fÛòåËíðáÃ1÷ÙÖÖf ,pÑÚÚøö\,‚ ‚ +¦ššš¬««Ë¦¦¦lbbÂZZZœáò400`åååÖÙÙéž#óµmÛ¶¨ûkoo·ÚÚZsQ__ïÖµ=×Ç#ƒE«f¸a†f2XIK&jþüùÓË›7oŽ›±òKfEo°'=®©© l{®G u 0à 3Ü0Sƒ•´”©òg°.\h´¥K—ºnDAŽGýu#ʤù ›Öµ=×Ç#ƒE«f¸a†f2XIIµV•••6444½nÞ¼y¶eË›œœt]ˆ[·nµ7F݇ž.F,Ýí¹>5XAA VÂêéé±ŠŠ ëëë»)C$cåIFK™¬BÌ`é{á—´¨çÜõ7Ýe™Ü ÷7W–½(^-Ÿ?¾ x½eqóù. þBü=+ÄÏw&Ïæ¬Áêèè°ÒÒRëíí½i›Š¾Ã V,é¦Ië‚ÚžëãQƒEÝÌpà 7ÌÔ`ÅÕÜÔ -I*pW· L–BÝ…›6mŠÚÅæÊÓhÃX£öRÝžíãQƒEÝÌpà 7ÌÔ`%-–Há×îÝ»mÑ¢E®kpÆ 3ŠÜ#Õ0i.©XóJ¥³=ÛÇ£‹ ‚ ¨ÁʺbÕcåÃñ²i°lùò¨Aëf¸a†f2XÜ*‡[å¤j°"©€ µpà 7Ìpc°0X,Z}0à 3Ü0“ÁBsÕ`]xè!;ÿä“öáÎöË—^²wÛÛíícÇòæKùÒKçmíÚ¶b…FvNÚ®]Sw@A`°0X™5X/Uì·ŸU±gžù•íØñ‘µµ —lÏžÓöâ‹ÝöÊ+]ö“Ÿ¼g¯½vÒÚÛßµ7ÞxÇ~ö³ãvìXv¿8/¾øIè=4;{öKÜO>1»ë®){î¹s´øà†n˜áÆ`a°2g°:éÌLÑÞ½Ýö㟶ÝϽo/?ýŽzä§vô—ìÝo·ÚéšGíüëíÒÊ:»V^i“!öûÛî¶þ•ë¬û[íèª6{eõAÛ¾ºÃZý‘ÕßqÙV­úÜV®œ°ŠŠI++ûÂJKÍýÕ²ÖãŸÛêÕWCœ°šMe1j÷Þû{kjºl÷ÝwÉÖ¯ÿmØð[Û´é‚57ØÖ­¿¶Ç?Ÿ°¹khøßisåéK“uš…<ŒýèLè3ôyèó5úL}úl|H} Ü0ÃÁBskáñ£G­óÀ;½gÛ¾Ý~½u«] ½þßß{¯ýñÎ;mò¶ÛìFy¹]]½ÚFî¹Ç~·~½}úÈ#vîéXWÛíø ‡ì§ûßdîd–dšž}ö#ûÁ~åÌ”LÕÖ­ý!“õ©3[2]<ð;ûîw/93&SÖÐ0êLšÌšL›Ì]EEä÷¹¬lÊïÈ‘ã´øò$žþC«ªúbF¶òÎ;oŒÉ"«3Ü,”£y°ví:k÷Ü3a·ÞªZ¤/ìÕW3þ…èxóM{ï'?±žçŸ·_=óŒ}ºe‹3Z2\2^2`2b2d2f2h2j¿ ¶žq““‘Ë„±¬®½_„. µ!{òÉ^{á…÷íÍ7;¨K˜ƒÑÐp=b¶²ªêsÞ‚ 0X¬Â›Éý7Þ°S¯¾jìÚe?ý´ 47ÛÐý÷Ûh}½]ûæ7틲2ûß+ìwÝeÃk×Úo7l°þdzvì°÷_xÁN÷œ}òÔSö›‡¶K÷ÝgWêêìóo|Ù°‰Ûo·ñêj»ÜØhƒ7ZßO¤4=űc?·ýûOÙöíçìûß´ÚÚ+vÛm7lÕªköï|f=Öo»w÷ØáÃ'¨ÕÈR>üŽíÝû¾=óÌÇ¡srÁÖ¬ù½«ßSò®»þàÌpuõdÄ Ö7¾1ißûÞEWß÷õ¯_è/³–êZ~øág®_|ñ}{ýõsú=¢.f¸1Xˆ Vðq옛^BÓLhº M;qA÷µŒa°>zöYëzõU;%û5Ót½íjÅT¦0]¬o»m2tñ¾n—]ñ½jÇ~úÓwié¦qªLÓ¶m½!Sô[÷>¯\ù¿î½VvQƒžx¢/ô^Ÿ±ƒOÎÈF©À=¼kõêÉ›j°Tw·o_—ýð‡Ú£öÛý÷¹Ú½+¾<ŽºŽ5Àâ‘G~m­­¹ Ù\è6&«3Ü,”cƒUHË`}öï¸Ú¯/ÊËíÚªU®ûQ™1ìÿòå—­#Ní—.Öé.Ô?ü»çžw‘®¬œ°µk‡mË–Oí¹ç΄LÃ/8aï›Ì‘ Ñã÷9Ó$ó$ssûíÎTÉ\=õT¯3[2]ÙÈ¡®à—^ê¶;ιÊXjÐÄ­·Þp¯­®îŠ\ñØc}¶sçY—éÔô#œW‚  a° ªõ“Háϳ÷°³;wZÿÖ­®ëQõ^_Üz«ë~Tñ½²a¿úÁ¬û¥—ì7ߌyLM{¡‹¯¦•ÐèFe`êÖÒ:Ôsò½¥û³Ÿ}ÙÕª ’2|êÆ«ªúƒëÖS÷žÞ‡ºàºýÔý—n[¦ïV £§z<½Þ‡ú}ûÛÃn´ª¦ ¶êø”}{þùœùVw3Y ¸a&ƒ…¨ÁÊOƒ•jV#d¼:_{ÍÎüèGÖ÷Øc®ð^5^7BÆëze¥ 9øýïÛÇ--öþ‹/Ú;‡Ǹ8ÿÂel”ÕRv«²òº­X1i #.û¥,ØÁƒ`gã\û Í7oËn€Œ‡þª Uëµ]Óqèù¹2Ó™ÉÈýÜeädªd®d²Ö¬q¦KïL˜Ì˜º–[Z>v&-Ѭßk¸a¦ ‘Á*œÖOÈxýâÐ!ûàùçíüOØïxÀÆjjÜt*´×èGtT1þéÿØN¼þzÄý¨^Ku[šßK&Ddu“©‹L™Õ{©î+Óä¹N¤Ð\™ª;?´ýûßs#4ƒ>‡š²ãdÈôv‡ ­jízCïñÀæÍnê˜ÝÁöÛÐwëÓæfëݶÍ>jmuÓ€hôªj÷~þÖ[ÊâwY¼çž;ëºÕ½¨nFM²«nG½oê†Tw¤º%Õ=©÷9ÙÉU¿õ­?¸ÉU««¯‡Þÿø^à 7 Qƒ•_¡‹µ.ܺˆ_üÞ÷Ü(GM1¡ÐcÍóÕûä“Ö³{·ýB÷|¼ÉÄœp#u1Ö…W#5‚Q#7nt#uÁŽ×õäŸÑ¼®î†½øâ¯³RhžÎTïíßï&­Õôª{d^Z·ÎVÍ™&«Ñ¢ê¶•¡½ÜÔ䌬›7í™gb¬ÛÚì“§Ÿ¶_oÙbƒ¡ÿùLûmh°?VUÙÄÊ•6õµ¯ÙdE…]»ã«­µËßþ¶] g™7 ˜8÷ì³ÎPÿò•Wœ¹Ngn6/T8¯ÌŸ éUP¯IsU`¯÷Yµ|*¼W¾ ¸2œ*ÌÏþé<ó›¡ Ïäta¿nÅý6 ƒ…È`D«OY,e³”Õ’)iP¶K¦aì[ßr˜ó?îæ;º€ûo¶ýæ›ï¸n%ÍÉ¥ÑmêvÓ\]2;êŽÒ-ƒ4———1ÒEW£çü£ét?Æ—^Èx¡¹?~þ#;5½Æ™—LÌø5•†¸½)6dnd¢ô¾¨N5oz?d¶dº4Y­LXƺC¯Uû×Ķʎi:C¯·ÿÑGíÂ÷¿oC¡×ôû{î±?„ÞÈë_ÿº{Íš$W¯_ÝÆªÓSòoB¦PÝɪ×Sײjö4O[Gœº½ðДÊj M%¡)%4µ„²…ê^þòü\ÌÈø^ÃL ƒ…Á¢ÿ~Îs«nKõ[ªãR=—êºTߥ:/]¸uÑÖ[kÕƒyÆëÈ‘7ë¼fŸW–ûøÞ}÷xÌ‹n…決éd44@@æQY!e‡dJ´^Û5‰¬LæÙ¶6÷ÿÚO"Óddka2Ñqäˆ{ýšÄÈíÛ­/d 2‡¿ ·áó¸LäªUî|ʔɜéýY³Æ.}÷»Î¼ÉÄÉÌÉÔ½¿w¯3yÎLúL¶ßk²T™^MžËTjn/}Nø^à 7 ‘Á¢Õç]¼ß|Óe?” QVDÅe{Bjey4âQ#5R5DGw5<±.º± ̓è¦SN+W×Á ò¹–‘üÅÿü{>ؽÛu;ªûQæTÝ‘ê–T÷¤º)•Ñó ªº1Õ©nMuoª›SÝêöŒu®ÿÿ] ®9c­ng³¹0A.¿g0“ÁBÔ`Ù5^Gº: s!4ððÃ6º(»Û •—»9½4·W¬‹n¦»éˆàB¦YFU…øªëSa¾jûT¨¯‚}îÇ:×Ê”©îo¨®Ñú¾õ=;}ç{»r»(û±½ZñŠý¤êU{½ñU;¶ùeë|öE—Q<µoŸËÊéÎ AegÝè`‚À`a°È`ÁLv¤+tqÔE8ÖE7ÓÝtœëÙ3Ï›2eºW§²Šþð‡Î\k€…2Ÿ½n±Ö¿u¥3Ý^ñ¿º6e¾Õm-.c/®A2⺉»2žº—¨ ù™çžs¦\ݧ2æÊÜÉœ5Z3WSrðù&ƒ5k Vww·544XQQ‘•””Xsè‡}tt4âsëC_ÚyóæÅÝg[袰`Á­º˜¼=×Ç£‹º.>œë\œk dør®¶_»¹Ìt¨Ûo»nM5¿µmœ±—;nÇ~xÈÞßó‚3PºÕ” •²œ¿~äg´4rVÆKLÝš2d2f2h^·§wóveNÕý©®fÕª»Y5‡Ê®êŽ Ê´ÊÊ~úí”Q”a”q,ôÏ8¿á,k }aºººljjÊ&&&¬¥¥Å®p=zÔjB_²x«½½ÝjkkmllÌ…L™Öµ=×Ç#ƒE«ƒÅ¹žM]eª×RÝ–FšªŽË?‚õÁëG¼üò/“º]²¥'v£eÕ%Ù½w¯õ<ÿ¼Ë¨ê6UÊ®j`‡2­ø¡yæÔõ­:Duyªë3ÖgÜÕ«56ºº6Õ/jjÖ”ÝUí›j5@Ý ™šÿŒÏ7¬¬KFkþüù3Ö]»vÍ*B-›‹/Æ5X2+zƒ=鱌YPÛs}Ó#c,Õ«it«FfjT§¨fMƒ54Õ†Fvj ²hʨ¹;3|ýë.›&§ÁªžP º7 HÐH^òÔ@ÕÆe»[ï55X1ÕÙÙySë™Ð—`_¨#Å3XÅÅÅΤù ›Öµ=×Ç#ƒE«f¸ç"³2Xš4U-ÍŸ–éŒAfi5݆jÄ4˜@]š.CSnh„§ nÜèæAÓ´å©.ωÊJ×Õ©ÐHO­Ó6=GÓoh´§þWûÐH`íóthß:†Ž•ì¼hd¦É`ÅT¿U†>”CCCÓëúúú¬ººzz9žÁŠ´ÝŸKw{.§ì…_u¡•ú½–þ¦»|åÊ•@÷7W–Ãÿ¿¾o…Äë-‹›Ïwn_î6päȯB è˶eËg¡ß²Q«¨éš´ûî»âj½^y¥ßzz.$½ÿXÙœlòötuÙ…>°_=êŒô‡ Ôåýûm°µÕÕ}¶e‹ý!d´®„ š²cŸë[6©Q¿·ÝöåM6jD_ mÓÜh£<`ã>j—žxÂu“^øÑì³×^³ó?ùILƒÅïYzËsÚ`õôô¸n@*¿d®6Xd°hÝà 3Üs—Y¥¾öZ§µµ}èn®‰nu&Å=÷üÞ­Ómôœx·`RA~míUw;¨»îºæö9צáP˜êÁ4ÚRõaªû¤¥ÅÕiÂZÕ‘©žlD=?1 –Ìœº1Õ…©îË·s8¬,ª££ÃJKK­··7b†(R$S¥uAmÏõñ¨Á"¢#ÒFݶIY/ÝX\7Âö߃SϽóÎ3n¥ÛCÍ5“T¡hô¦æµÓ]4/žº-50@£25…†êÒ4“¹ìòÄ`9óå:ù =?Ü\…/{£ò4ÕC¬Q{©nÏöñÈ`чn˜“ÁXUõÿÍ•§?ž ­ÿœÑÁoy;+ãëNº••îÈ ‰…uÝA¡ÇZ§mzŽž«ÿ9~䬹`°’ÍPÅ3X’æ’Š5¯T:Û³}<æÁbî˜á†9ùŒ+VLEüýüÚ×Ì**&CÛÕí8a_ÿúu[µêsWl¿zõÕûcè7õ!“6jüŽY]ÝkhuÝ“÷Þ;ì²gŸ… Ýgvß}CnTä\tSRlØ0è²i›6ýÆue67ê2n>ÚïLà“Ožw#(Ÿ~úWì¿}û¯Ü­©Z[?r™µçž;k»v±Ý»?pÆñ…N;–—^ú¥»}Õ«¯ž²ýûß³:íµ×NÚÿüÏ/\fï§?=áîä(Be±”ÍRVKÙ-e¹”íRÖKÙ/eÁ” ÓÈKÂÔˆLÎÔËs9µó`(MPšÏÇ#ƒE f¸aN>®ß”ÁR7aUÕugF”ýzýõwI‘Y‘iùÉOÞ³}ûN93#Sóâ‹Ýî†é{öœv¦GæG&hçÎC¦èCgŽd’d–ZZ>±§žêu&JfJ¦jëÖ_Û#|êÌ–L—Ìׯƒn¥L™Ì™Lš²oMMŸ9ó&'3×Ð0âº?eòdödú4ÍÅw^ufP¦Pæ°²rÂn¿ýi,-|͸õVs7l×kÓk›ŒY¼¶¨q옫ãRѾfåW}—î¡ü½Ûj鯖µ>›õ_d°Ð¬7XAs9žþÃ!™šQƒ¥š¬|®Áª®·÷Þ»z“©¬©™²'žèsæ®±ñ²{ž²weeSöo|2qWœÉ{øáß8“()“©ÌXªÅùº½–n…¤Yö3]ÿ•ù¿0X,Zºpà 7Ì>“¥LVyùTèwr"dÎå5¯ û¿ùÍ ;sfjÚ\iRû_üu”¹É~î²wÊÒíØñ‘=öX¿mØð[[»v8dNÿàºQËʾíóšÕ×Úw¿;ä²qÊÖ)›§.Ke“}A×ecþ/ ‹Z ¸a†ææ–ɪ©ù£3•ÕÕÿ2B§µ¿£G»îSu“nß~Îu{>øàE»÷ÞßÛwþÑäÔÀÕ¯Ýsψ­_ÿ;×-ªnSu«ªfìÍ7“›±?Ùú/ "ƒE f¸a†;ï˜e T¿öüó=!cõ+Û²åSg´d¸d¼dÀdÄdÈdÌdÐdÔT¿¦b~8¹Të¿0Xˆ,‚ ¢ C]‰êRܵë{úé­¹yÀî¿Èu=ª R]‘ê’Tפº(ÕU©.Ku]ª óàÁ“®K3Ýé)0Xˆ -]˜á†î‚bVQ½ŠëUdÿÔSŸ¸¢ûûî»ä¦ÊP1¾LØí·O¸"}ë«h_Åû,D µ0à 3Ü0§šVBÓKhš M7¡i'6mºÀ(BD‹VÌpà 7ÌAG}ýçç<ÓÈQ ¢‹ ‚ R9YUõÅŒ9Ï´äœg, ­¸a†f¸ zÎ3MOôœg, ý÷pà 7Ìps® ‹ÖÜ0à 3Üœk ¢‹ ‚ fw`°0X´~à†n˜áæ\c°5XÔ-À 7ÌpÃL "ƒEëf¸a†f2X, AA,D‹VÌpà 7Ìd°5Xôßà 7ÌpÃL Ö,2XÝÝÝÖÐÐ`EEEVRRbÍÍÍ6::šðöHjkk³ ¸hmm |{®G‹VÌpà 7Ìd°bª©©ÉºººljjÊ&&&¬¥¥ÅªD·‡«½½ÝjkkmllÌE}}½[Ôö\,‚ ‚ +iÉHÍŸ??åí2+r°žô¸¦¦&°í¹>,Z}0à 3Ü0“ÁJZ13Tñ¶;æ7dZÔö\,ê`†f¸a¦+)õ÷÷[ee¥ ¥´]š7oÞMëü¯t·çúxd°hõÁ 7ÌpÃL+aõôôXEE…õõõ¥´½2X:Á^øUWWç\»÷ÁÒ_–Yf™e–Yf9˜å9k°:::¬´´Ôz{{SÚ¯&Jë‚Úžëã‘Á¢Õ3Ü0à 3¬¸:pà€-_¾ÜRÚÞÅæÊÓT±Fí¥º=ÛÇ£‹º˜á†n˜©ÁJZ2,‘"™íáÒ\R±æ•Jg{¶G‹VÌpà 7Ìd°².M@šÏÇc,‚ ‚`,”'‹ÖÌpà 7Ìpc°0Xôßà 3Ü0Ã͹Æ`!2X´ú`†f¸a&ƒ… Ê`AÁÂ`Ñúf¸a†›sÁBÔ`Q·3Ü0à 35Xˆ ­˜á†n˜É`a°0XAA`°,Z}0à 3Ü0“ÁBÔ`Ñ3Ü0à 35X, ­¸9לk¸a†ƒ…¨Á"‚ j°,Z?0à 3Ü0“ÁB,úï©Õ€f¸a†ƒ…Á"ƒE«f¸a†f2Xˆ,‚ ‚  ‘Á¢õ3Ü0à 3Ü, ý÷pà 7Ìps®ç¤Áš7o^BqË-·à„È`Ñún˜á†™ V"’qòG4ƒ5þ|œ5XAA V²:|ø°ÕÖÖÚèèèôº‘‘·îرc í£»»Û¬¨¨ÈJJJ¬¹¹yÆþ¤¶¶6[°`‹ÖÖÖ¸ûŒ÷üt·çúxd°hõÁ 7ÌpÜÇ5X‹/¶ÉÉÉ›ÖkÝ’%KÚGSS“uuuÙÔÔ”MLLXKK‹3\žÚÛÛasQ__ïÖES¼ç§»=×Ç£‹º˜á†n˜ó|,uF3X©Ö`Éhù»e>äH=éqMMMÔÿ÷üt·çúxd°hõÁ 7ÌpÜ笅 :3 nA#Åðð°UWWÛ¢E‹RÚgggçŒ Vqq±Û¯ß€i]4Å{~ºÛs}>nëÖ­³C‡qO›9l°hýÀ 7Ìpà w'ôX#áR ̓EAD – ³½®3”N:•òLîˆ ­>˜á†n˜ :ƒuäÈwsfiåÊ•3j°–.]Š¢‹þ{˜á†n˜©ÁJG7nܰeË–¹Ì•nôé…ˆ ­>˜á†n˜É`!j°‚ ‚, ‹ÖÜ0à 3çšs=ç ÖÁƒmñâÅ3ŠÚËÊÊìÒ¥K8!j°è¿‡n˜á†™¬TŠÜ#ÍÜÞÝÝ÷~zˆ ­>˜á†n˜É`EŠÚwìØáæ½ò¬«W¯ZII Nˆ,‚ ‚ +YùMUø¼W̃E‹ÖÌpà 7Ìd°Rî7xýúõ› Õè註4¢‹þ{˜á†n˜©ÁJR*f_½zµŒŒ8ƒ¥¹°z{{ñZµjNˆ ­˜á†n˜É`%«³·ûû…¢‹ ‚ ¨ÁJÁd)“¥{*˜¢ ­˜á†n˜É`! ý÷Ôjp®a†f¸gç(BD‹ÖÌpà 7Ìd°0XêDÔ`A5X¬åË—»IE,Z?0à 3Ü0“Á È`,Z}0à 3Ü0X+Ù,U¢S=ø588躽›Ië±ÖÅ2fšK*Ö¼RélÏöñ˜‹¹c`†f¸a.°y°4“{:“Œ¡lß®g6܈ ­>˜á†n˜ó8ƒuêÔ)[¹r¥ëÞBùe°‚ ‚È¢ÁŠ5{{:£,Z}0à 3Ü0l+ÖìíéŒ"D³Ë`Ñ3Ü0à 3Üy0Ñ("ƒE«f¸a†fj°5XAA VfæÁJe"ƒE«f¸a†f2XIš¨ññq 5Xôßà 7ÌpÃL VÐ# ãÝO‘Á¢Õ3Ü0à 3¬# #݃P¡É÷íÛ‡¢‹ ‚ ¨ÁJVLÅ@‹ÖÌpà 7Ìd°2X‹/¶7ÚÐÐn‡,úïa†f¸a¦+ƒUUUåj¬ÔE¨,Vee¥uwwÛõë×q?d°hýÀ 7ÌpÃL+]¾|ÙvîÜiË–-›.n×  ÛÚÚlxx'D AAPƒ•Ž”½:s挻ù³²Z2[%%%VSSƒ#"ƒE«f¸a†f2XAHõYÍÍͶtéR5XÔ-À 7ÌpÃL Â`Ñún˜á†î,¬D&õæÇBÔ`A5X (|RÑh‹9²È`Ñún˜á†™ V :|ø°ÕÖÖÚèèèôº‘‘·îرc8!j°è¿‡n˜á†™¬d¥ G'''oZ¯uK–,Á ‘Á¢õ3Ü0à 3¬Tê±¢¬Dk°üÝŠÑÔßßokÖ¬q“›jž-eÎbIópé~ˆŠÖÖÖÀ·çúxÔ`ADσµpáB7Ï•º§¦¦\h‚Ñêêj[´hQÒf-’¬¼¼Ü:;;ÝþÕ¹mÛ¶¨ûioow]”ccc.êëëݺ ¶çúxd°hõÁ 7ÌpÃ\5XÑŠÜßzë­@ ÖæÍ›ãf¬ü’YÑìIý“¦»=×Ç£‹º˜á†n˜ `,uÛ¹Ðã³gϦÔÝ-KvðàA7a©ö/Èñññ¨ûQ7¢2]žôXë‚Úžëã‘Á¢Õ3Ü0à sžg°‚T4ƒ¥õ[¶lqu]¶uëVÛ¸qcRûñO‘îö\O'Ø ¿êêêœk÷>XúË2Ë,³Ì2Ë,³œ—KÙ+½2Yd°È`Ñêƒn˜á†9/3X2;êº b&÷hKEßá+–‰TÓ¤uAmÏõñ¨Á¢nf¸a†æ<¯Á*++›a¨ü‘ìLîÑ – ÜÕ-(“¥Pwá¦M›¢þŸ7*O£ cÚKu{¶G‹VÌpà 7Ì–Á’‘JwÆöHÙ¯píÞ½ÛMû ®Á 6Ì(rô|Í%k^©t¶gûx̃EA6Öl¸ß`¬z¬|8,Z}0à 3Ü0XKS2¨[ åŸÁ¢ÿf¸a†f¸sd°N:e+W®œq³gD‹ÖÌpà 7Ìd°®ŸJu!š]‹ ‚ ˆ¹G‹ÙPŸ…Á¢õ7Ìps®9×pÏ9ƒ…¨Á¢ÿf¸a†fj°0X,Z?pÃ̹†f¸g¿Á:s挕––º.A…k¢‹ ‚ ¨ÁJA]]]Q‹Ü1Yd°hýÀ 7ÌpÃL+)[µvíZ™^§Ç nŽ,D ý÷0à 3Ü0Sƒ•¤Ô%¨›/‡ëƳbÆs ­¸a†›s͹†{N,Ý€9\2],j°‚ ‚¬TVVf5556<,Z}0à 3Ü0çqKveª.\¸0=ÑèÀÀ€3Aš€4¨l˜tôèQ·ÏxÏkoo·ÚÚZs!S¦uAmÏõñ¨Á¢nf¸a†æ<¯ÁR­U´‰F¯^½˜ÁºvíšUTTØÅ‹ã,™9XOzì7{énÏõñÈ`Ñêƒn˜á†¹æÁRw n™ãM4Z^^n£££Ös=óÌ3¶oß¾„2]ÅÅÅ.“æIµ.¨í¹>5XAÁ«®®N¸+1ÒvÝ”:¨í¹<žN°~ÕÕÕ¹´¨çÜõ7Ýå¡¡¡@÷7W–½(^-Ÿ?¾ x½eqóù. þBü=+ÄÏw&ÏòÒ`É\ &l°È`Ñ7ÌpÃ̹æ\Ïù ÖÁƒÝ|XþiÔexéÒ¥@ V´¯dj¢´.¨í¹>5XÔ-À 7ÌpÜç5XGŽ™6<~ƒÕÝÝ×$$;Š0Úó—½Qyª‹5j/ÕíÙ>5XAQ`5XË–-³;v¸n-¿ÁÒÂTæÁJd>¬xKÒ\R±æ•Jg{¶G‹VÌpà 7Ì–Áò›ªð™Û³5“»F.fSÙ>5XÔ-À 7ÌpÃ\`5Xívýúõ› •º»âj£Ùm°hýÀ 7Ìpà wŽ –ŠÙW¯^ín—#ƒuãÆ ëííuÆkÕªU8¡9l°‚ ‚È‘Áòn‹)T°È`Ñún˜á†™ VŠ&Ë?“{*S4 j°¨[€n˜á†™,D‹ÖÌpà 7Ìd°0X,‚ ‚ æ„ÁÒýÔ%(©À}É’%®þª´´D‹ÖÌpà 7Ìd°RQUU•õ÷÷»Ç6l˜QäÞÐЀ¢‹þ{˜á†n˜©ÁJVšëjbbÂ=^ºt©3Vçγ¾¾¾„grGd°hõÁ 7ÌpÃLË'ÿmc4÷•–'''Ýr¶frÇ`QƒEAyUƒ¥{ç)cuáÂg®.\èÖ+«¥mˆ ­˜á†n˜É`%)]ØýuWkÖ¬qëÕªÞ5Xôßà 7ÌpÃL V Z¶l™ë\¾|ùôºòòr7‘Á¢õ3Ü0à 3,„Á"‚ "7kñâŶqãF²Td°hýÀ 7ÌpÃL+(ƒ¥ù¯4Eƒê®4z°²²Òº»»íúõë¸j°è¿‡n˜á†™¬ttùòeÛ¹s§«Ãò ÝU‹ÕÖÖfÃÃÃ8!2X´~`†f¸a&ƒ•Ž”½:s挭\¹rzN,M6ZSSƒ#¢‹ ‚ ¨Á BªÏjnnv3¼#2X´ú`†f¸a&ƒ•EùçÑŠ$Õv龆EEE.#&Ó6::sŸê¢ÔD§ŠÖÖÖÀ·çúxÔ`Q·3Ü0à s×`é¶8Þ=Ã#Ù[åD3XMMMÖÕÕeSSSn†ø–––˜7’noo·ÚÚZsQ__ïÖµ=×Ç#ƒE«f¸a†æ<Ï`•••Í0TþPV+\2Z±ö-³¢7Ø“ûëÀÒÝžëãQƒEAy^ƒ%#uìØ±Àº QgggÌ –¦ ó2­ j{®G‹VÌpà 7ÌyžÁJ6K•®ÁêïïwsnÅšà4Ò~ü¯3Ýí¹>5XÔ-À 7ÌpÜç5XšóJuCÙ0X===VQQa}}}1Ÿ—Ï,`/üª««s*ϹëoºË2±Aîo®,{Q(¼Z>þ|AñzËâæó]ü…ø{VˆŸïLþžeÝ`:uÊÍ{oT_º«££ÃJKK­··7î~"Õ4i]PÛs} ­>˜á†n˜ ,ƒ…ò×`A‘Cƒ¥<«]]‚ =Ö:D‹ÖÌpà 7Ìd°Rna­F “5· ý÷0à 3Ü0Ã#ƒ¥lÕÚµkmdddzk¦uüCd°hýÀ 7ÌpÃL+…™ÜuÃçpݸqcVƒc°‚ ‚˜“kbbâ¦õ2],2X´~`†f¸a&ƒ•‚ÊÊʬ¦¦Æ†‡‡Ý-^z\UUåº5Xôßà 7ÌpÃL V #£¹üñÇ8!2X´~`†f¸a&ƒ•Šd¤”­R— B1WÔ`A5XƒE뇖.Ü0à 3Ü, 5XÔ-À 7ÌpÜ75Xª¯ÒÍœ½ÇÑÂ{"ƒEëf¸a†f2Xq$ã¤é¼ÇÑÂ{¢‹ ‚ ¨ÁB,Z?0à 3Ü0ÃÁÂ`Qƒ7Ìpà 7ç:oæÁŠUgE ,Z?0à 3Ü0“Á Ð`c°¨Á"‚ j°’I/Š‹‹qBd°hýÀ 7ÌpÃL+™Ì•›Ž!<,X`ûöíà QƒEÿ=Ìpà 7ÌÔ`%+¦b ƒEëf¸a†f2X³p¡¿[1šÚÚÚ\VLÑÚÚwŸñžŸîö\,‚ ‚Èãy°Ž?n›6mºi}ss³8q"i£IíííV[[kccc.êëëݺhŠ÷üt·çúxd°hõÁ 7ÌpÜç¬Å‹»ƒ‘F.]º4ƒ%ó¡7Ì“×ÔÔDÝO¼ç§»=×Ç£‹º˜á†n˜ó¼+V·^²Ó4DÛ—F#NMMM/ëq¬ŠñžŸîö\ ­>˜á†n˜ó<ƒ¥š¡‘‘‘›Ö[III +ÒúXÅõñžŸîö\O'Ø ¿êêêœk÷>XúË2Ë,³Ì2Ë,³œuƒ¥Ì‰2U.\p™ÅÀÀ€3 ñº¹È`‘Á¢Õ3Ü0à 3¬(3¶G›hôêÕ««ÁÒºdj¢üÏOw{®G u 0à 3Ü0çy –×XVVfEEE.ÊËËmtt4°z.o”öi”]øÿÅ{~ºÛ³}<2X´ú`†f¸af¬´æÁŠ6–憊6OT²ÏOw{¶Ç¿½½ÝjkkmllÌE}}½[Ôö\,ê`†f¸aÎó¬ ²TñL\¸ŠŠŠ¢>_fEÖ“×ÔÔ¶=×Ç#ƒE«f¸a†æ<Ï`ije]2©õë×»¬ÕÔÔ”‹]»v¹uѤnD=Ï“k]PÛs},Z}0à 3Ü0çy+ÒèÁ Gjvxe°ü5X ™ÁÒ ö¯ºº:×ïì}°ô7Ýå+W®º¿¹²þ·ø5¤x½eqóù. þBü=+ÄÏw&ÏrRä-‚ªÏŠ´ŸXûŽTÓ¤uAmÏõñÈ`Ñêƒn˜á†9Ï3XÙF ªîÊ_ƒåEÞÅæÊS·e¬Q{©nÏöñ¨Á"‚ ˆ«Áʆ]— F*ôXëbÕ0i.©XóJ¥³=ÛÇ#ƒE«f¸a†æÌ`­]»ÖÕ åj&÷XS6äÃñ˜‹¹c`†f¸a.°y°§ÍT¸ÁÊÆYÜ*‡ Ü0à 3Ü0ç]K]Z]]]3&·uëÖÙ¡C‡pBsØ`A‘Ãi"=V1ú¢E‹pBd°hýÀ 7ÌpÃL+ƒåÍä®Ú¤ŽŽŽé H³Uƒ…Á¢ n˜á†n˜óªëÈ‘#ÖÜÜìkFw ÖÒ¥KqBd°hýÀ 7ÌpÃL+i–õeË–¹ÌÕ’%Klrr'D AAPƒ…0X´~hé 3Ü0ÃcƒE5Xôßà 7ÌpÃL VÀk6Lº‰Á"ƒ7Ìpà 7Ìy•ÁZ¾|¹]½zÇC AAPƒ”Á:yò¤»ñ²7U"ƒEëf¸a†f2X̃-¨Ï¢‹þ{˜á†n˜©ÁJ±È=Zp/B2X´~`†f¸a&ƒ…0XAA`°0Xd°à†n˜á†¹ æÁ¢‹,úïa†f¸a¦+@ƒ5>>ŽÁ"ƒEëf¸a†f2XAô¢¸¸'D AAPƒ•ìèAo:†ðX°`íÛ·'D‹ÖÌpà 7Ìd°’S1PƒEÿ=Ìpà 7ÌÔ`ÍÑQ„ýýý¶fÍ×í¨Ûó>|8æóÛÚÚ\MÑÚÚøö\ ­>˜á†n˜™+- Xyy¹uvvÚÔÔ”ŽŽÚ¶mÛ¢>¿½½ÝjkkÝí{õõõn]PÛs},Z}0à 3Ü0“ÁʺbÕcåÃñ¨Á"‚ j°Pž,Z?0à 3Ü0ÃÁÂ`Ñ7Ìpà 7烅È`Ñêƒn˜á†™ *(ƒEA ƒEën˜á†nÎ5 QƒEÝÌpà 7ÌÔ`!2X´~`†f¸a&ƒ…ÁÂ`AÁBd°hõÁ 7ÌpÃL QƒEÿ=Ìpà 7ÌÔ`a°0X´~àæ\s®á†n ¢‹ ‚ ¨ÁBd°hýÀ 7ÌpÃL a°è¿§Vn˜á†n ‹ ­>˜á†n˜É`!j°‚ ‚,D‹ÖÌpà 7Ìpc°0Xôßà 3Ü0Ã͹Æ`!2X´ú`†f¸a&ƒ•[Õ××Û¼yóâ>¯­­Í,Xࢵµ5ðí¹>5XAA V :zô¨ÕÔÔÄ5XíííV[[kccc.dÊ´.¨í¹>,Z}0à 3Ü0“Á D×®]³ŠŠ »xñb\ƒ%³¢7Ø“˘µ=×Ç£‹º˜á†n˜©Á DÏ<óŒíÛ·Ï=Žg°Š‹‹mjjjzYµ.¨í¹>,Z}0à 3Ü0“ÁJ[}}}V]]=½Ï`EÚ>þüÀ¶çòx:Á^øUWWç\»÷ÁÒ_–Yf™e–Yf9˜å¼4X2Wƒƒƒ ,2X´~à†n˜9לk2Xq$C)’©‰Òº ¶çúxÔ`Q·3Ü0à 35X1\±–½Qy£££1Gí¥º=ÛÇ#ƒE«f¸a†f2X97X’æ’Š5¯T:Û³}<æÁ"‚ æÁÊºŠŠŠòúxd°hõÁ 7ÌpÃL å‰Á¢ÿf¸a†f¸1X,Z?pà 7Ìps®1Xhv,‚ ‚ 0X,Z?pà 7Ìps®1Xˆ,ê`†f¸a¦ ‘Á¢õ3Ü0à 3, ‹ ‚  "ƒE«f¸a†f2Xˆ,úïa†f¸a¦ ƒ…Á¢õ7çšs 7Ìpc°5XAA "ƒEëf¸a†f2XƒEÿ=µpà 7Ìpc°0Xd°hõÁ 7ÌpÃL QƒEAÔ`!2X´~`†f¸a†ƒ…Á¢ÿn˜á†nÎ5 ‘Á¢Õ3Ü0à 3,D AAPƒ5ç Vww·544XQQ‘•””Xss³ŽŽÆüŸ¶¶6[°`‹ÖÖÖÀ·çúxd°hõÁ 7ÌpÃL+-555YWW—MMMÙÄÄ„µ´´8ÃMíííV[[kccc.êëëݺ ¶çúxÔ`Q·3Ü0à 35XKFkþüùQ·Ë¬ÈÁzÒãšššÀ¶çúxd°hõÁ 7ÌpÃL+puvvÆÌ`;æ7dZÔö\,‚ ‚ +Põ÷÷[ee¥ E}μyónZçÏx¥»=×Ç#ƒE«f¸a†f2X©§§Ç***¬¯¯/æóò9ƒ¥ì…_uuu®ßÙû`éoºËW®\ tse9üo!ð«ÁRH¼Þ²¸ù|!þžâç;“¿gyk°:::¬´´Ôz{{ã>7RM“Öµ=×Ç#ƒE«f¸a†f2XiëÀ¶|ùrH¨‹Î•§©bÚKu{¶G AAPƒ¸dh"E¬&Í%k^©t¶gûxd°hõÁ 7ÌpÃL+ëÒ¤ù|<æÁbî˜á†n˜™ å‰Á¢õ3Ü0à 3Ü, }äAÁBd°hõÁ 7ÌpÃL ”Á¢ÿf¸a†f¸1X,Z?pà 7Ìps®1Xˆ,‚ ‚  ‘Á¢õ3Ü0à 3, ‹þ{¸a†›s͹†ƒ…È`Ñêƒn˜á†™ ¢‹ ‚ ¨ÁÂ`a°hýÀ͹æ\à 3Ü,D u 0à 3Ü0Sƒ…È`Ñún˜á†™ Â`AÁÂ`‘Á¢Õ3Ü0à 3,D u 0à 3Ü0Sƒ…È`Ñún˜á†n ‹ ‚  "ƒE«f¸a†f2Xˆ,úïa†f¸a¦ ƒ5ÔÖÖf ,pÑÚÚJ‹VÌpà 7Ìd°P:joo·ÚÚZsQ__ïÖQƒEAÔ`¡%s%ÇíIkjjÈ`Ñêƒn˜á†™ JUÅÅÅ6555½¬ÇZG u 0à 3Ü0Sƒ…RÔ¼yónZ7þü¨ÆÊ ¿Ö¬Yc÷Þ{¯Ë†UUU¹¿é.766º¿¹²ìE¡ðjùž{î)(^oYÜ|¾ ƒ¿Ï ñóÉß3 Vd°B!4{…Áš¥5XZ‡B! JQÞ(ÂÑÑÑ„G"„Bƒ…âHs_%3V¸üµYAA,ˆ’ý0Á 3Ü0à 3Ü,Ä—nÎ5Ìpà 7 !„Bh.ƒ…B!„ÁB!„Â`!„Ba°PaK·îñ¢PÔÝÝm VTTd%%%ÖÜÜìæ%+nÍ»æqoڴɆ‡‡ 漋½P>çþïu!}¿ûûûÝ­ÄtwŒåË—ÛáÇ ò\/\¸0¯™‡††¬©©Ég…_¼xƒ…fï—´P¤/cWW—»MÑÄÄ„µ´´8ÕïZ»v­:uÊnܸáØ_yåwï­BÐÑ£G­¦¦¦  V¡i``ÀÊËË­³³Ó}¾ÕhÚ¶m[Á½'NœHi~ʤU«VÙž={Üo™b÷îÝvÇw`°?ȳMú1ŽvÃí|—²Yù®k×®YEE…káb°òW›7o.ˆŒU<­^½ÚFFFòšñ–[n™u¿e,Är©Å[¬pS¹oß>—ÍËw=óÌ3޵>ç^7‘+V¬p-ü|—x>^p¿e?þxÞs®_¿Þ}¦õ;¦Øµk—[‡ÁB¬Y$ÕlTVVº>ýB:׊%K–Øàà`^³öõõYuuuAÎ/\¸`¶}ûö¼ÿ\oÙ²Å&'']×ÿÖ­[mãÆu®ï¾ûn×Ušïº|ù²•••Mÿ–éq®³v,„Áò©§§Çué"\hR«oïÞ½3ÌG>J|~Y¨ ‰«W¯º{Ÿæ³Tì,cåIF«ºÀ=>}:çYœlI”Áò×`広…0Xÿ§ŽŽ+--µÞÞÞ‚>ïù^{i„U!š¬B0X%n°dº EÄqîܹ‚ýÝÊõo a°B:pà€Â]©t¿T›á eÖW#jkkùœç¡TðíeîÔrÿý÷ç}mŽ ÜÕ-(“¥Pw¡¦")9sƬB‘F ªîÊ_ƒÅ(B4'Zø…È\ÜÊÚix³X-ZT0ó¢ÁòŸëeË–¹ú+v'_¥®"}¶Õ5¸aÆ‚)rWöNS°ŠÔxðæ2Tèq®ëI1X!„B,„B! B!„ !„Ba°B!„0X!„B,„B!„ÁB!„Â`!„Ð,Ò\™p¶Po÷ƒ !„æ AÁ`!„0X!„ÁBa°Bhö˜“H÷ ô–u¿êêjw³ââb[³fÍôM²ýÏ;~ü¸{žžãßn¼«{£iýüùóÝMh;vÓkÙ¿¿û¿[n¹Å.\ènÆ~ï¼7ÞxÃÊÊÊÜkY±b…½þúë7½nÝÌY75.))qÇÓ¾zè!;{ö,'! Be×dE[/ÓtéÒ%›ššš6A«W¯¾éyºÁ®žçWOO3L2e###vãÆ Ûºu«{¾Ì‘_{÷î6n2kzŽžëéäÉ“n]cc£3^ =ýzmZîîîvËׯ_w†N¯!„ÁB¡Ya°>ýôÓéu2Y^–)üyƒƒƒ7íC¦FÛü¯ÉÉI·®¢¢"îëRÊSmmíM¯§¿¿ÿ¦×¯×¦èëëãä"„ÁB¡Ùi°â­U¥.ºHÝá&MlݺuÎPi}¤.Ku &òz¼ –Bÿ£.É––æd#„ÁB¡¹o°¨Ë,„0X!„B,„B!„ÁB!„Â`!„Ba°B!„0X!„Bƒ…B!„ÁB!„Â`!„B! B!„ !„Bƒ…|oâW¾BAyƒ5+ B!Äu a°ø "„B\×0X|B!®k,>ˆ!„×5 ⃈Bq]Ã`åýqddÄ6lØ` ,°ùóç[mm­½ûî»;Þ¼yó\èX .´7ZoooƧˆ¤ññq÷ŠŠŠlÑ¢E¶k×®¸ûlkksï—¢µµ5éíɼ¾xÛ3½?©³³ÓV­ZåÞ£òòr{ýõ×#î/|ßѶE;vww·544¸ã”””Xss³ŽŽ&üÞ&–̹ÉÔç0‘÷b®}Ïâ»L~޽g¬×W__?ýú6mÚdÃÃÃÛ_*¿+…ö=Ã`a°òÞ`ÉPéËpýúu›šš²>úÈî»ï¾Œ^h<阴%K–dôÇ?ü¸~é‡qË–-699i¶uëÖ?lájoowïÙØØ˜ ýÈj]¢Û“}}‰nÏÔþÎ;gË–-³Ó§O»e]D¶mÛ–ô~y^SS“uuu¹Ï¡ÎEKK‹»$ûÞF;Vªç&[ŸÅ¹ü=‹wî2õ9ötâĉ˜†yíÚµvêÔ)»qã†{¯¼òŠUUUelÉþ®â÷ ƒ…Ášýkùòè‘€ÔÂMö ë_§Çúò”––º}ÝqÇÖ××—Ôþ:d÷ßÿŒuúqSËO­,µ¯]»6cûŽ;\ S-°ýû÷§üãýëGÆ“Gº0ø ©÷#(éqMMMÂÛçšÁZ¿~½9r$íý¤b*tð>}o£+ÕsãW躺@™­XavÏ=f¿øE0+‘uñ¾³á{íÜeÚ`­^½Úeã“‘˜3µ¿dW ñ{†ÁÂ`Í ƒ•Ìú0郿}ûv»téRÊK?Ìj©è‹úòË/ÇlFÚŸZØú÷ô£ýÈeÑ´OµÕô·ævîÜin»Zˆºe°´¿âââ¨ûÑ6qúœüÏ·=V—G*¯?èý…KçEïI.~øÕeâ¿(Å{oã+Ñÿe®î¾ÛììÙ/—?ùäËådMV*+Þwb¶|Ï¢»L,ëñÇOøÿtÞ÷íÛç29™Ú_²¿+…ø=Ã`a°òÞ`©ï]?&K—.nņ×&Ä3Xþ’h-×x_Jÿÿ,½v¿áÓ…Á_¡TúÐÐP ?Ô=ôKß‹ÁKå'ûúýÏOeûl6X‰ì'‘Údøûûû­²²rÆyŽ÷Þ¦òžÄËàú¥ë§g®<ÉdÕ×gÞ`ÅûNÌ–ïY´s—IƒuwÈå $üP¨»tpp0cû âw%ß¿g, Öì3X‰v¦Ðe¨îÕcUWW'e°’ù’GÚ¦ãú[ÖzŽÌžZ¾å–[Òj¥Å*rW‘¿Ž#“yàÀ˜®t3XéüÀyašÍ¬žž«¨¨¸©«9Û¬ð¯Ï­·F~Þ×¾–ÜW-ƒï;1[¾gÑÎ]¦>Çê~R÷Z2Òyß»wïŒß¹ ÷—ìïJ!~Ï0X¬¼Ï`Åkåê×ÿeÑtÐKµ!þ5µ¬ÃGµød+\‡vªÑ©¾@ëÝ>× –jv²YÒÑÑáêù"c'úÞ&S’ȹÉF+Þ÷,Þwb6|Ïb»L}ŽUâ ñtç2µ¿DW ñ{†ÁÂ`å½ÁÒûl誡wÕah8± Õ=©ØSõÚ®cu!e°¢nzá…lݺuvùòe·¬ÔûæÍ›§·{µ!z=éÖ`=ñÄn?âS-‚ZtѺ$o„Œþ'Ö(ÂhÛçZ¡.6jŸ9sÆ-grt“Zùºè‡wÏ$úÞÆ;V¢ÿM™¬ÁŠ÷=‹÷Èõ÷,޹˄ÁÒg2Ú …ðÿSÄÅ‹Ýã«W¯ºâþð‹~ûKöw¥¿g, ÖÜ0XiŒ"Ô—__µ •ÆUÑ«¿.Céc.mW‹G?Ôé,/4zI’HÝ úñ/++sÇÕÜ0ÇŽ›±]…ùšc%Þè¦xu jYzõgkÖ¬q5 ñ¤ÓXs¼ÄÚ~üx¯/‘íAî/ÚgDç@çBóó¼ñÆ1÷—jmH"ûŠ÷ÞÆ{ñÎ]"&K™,u*sÔ(Âxß³D¾³í{þ;‘Ìç.‘çë­©y•±Ÿ÷~Dšû)Èý¥ò»Rhß3 kö,„Bˆë ñAD!Äu a°ø "„B\×0X|B!®k,Ä!„×5„Á⃈Bq]Ã`Íñ"AAäS B!„ЬÒÿ’ÐÅÕÚhüIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_increment_line_total_narrow.png000066400000000000000000000564161174000617100271770ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔ\ÕIDATxÚíilU×zþ¯TUUUýUõKÕOUu¥ªê‡ªªú¥ªª*ŠŒ| BA ¸Ûx1Æ„’à‹1‰BBB̆0Ç9`0`À0&b° ¾ŽÇSb°ë÷ïw·ÛwûøŒÞÇgü=Ò#Ÿ½×ò^ç9ë Ïz×»×ú•€€âW¼,  `°~ýë_˯~õ«aþã?þcô})Xô)#½À`ƸtéÒ(S ¼|ùrT™  ŸÀ`4äää¸4XYYY,~¸1X þâü£üíßþíðÌ_ÿõ_?þ»¿û;~œøá¦Ÿ,üEUUÕˆ™ùóç8>~ü¸Ç%w´¢¡¡AÒÒÒäþáä/þâ/äÏÿüÏåïÿþïsׯ_÷ùÇïw¿ûaúôÿñÿa ?Ü®ÊÖ¯_o¼6ڞ澕––º¼®?ÏϹ§OŸ‘J­¯¯ŸwïÞ5ÊþùŸÿyøºú:'$$¸&þ äsñôšŽå= À`à‡PôÇHˆõ¯y.99Ù–Áúä“OäÏþìÏ<ÖÝ´i“×Mývõ¿{÷î5~€]•íÙ³ÇgãSQQ!õW\ ÖÂ… ]¶¥¯›çç\6sæÌáÇÚ&ôõSCäéº+W® Jÿê¹x{M1X`°W<þ܈˜?(“&M2ÎÇÇÇŸÓr­ço4H¡k¼·iÓ¦‹ÁŠ‹‹“¾¾>ùøãÝ>÷±}DÓ§O—9sfD™Öõt}½ÓQ1000ªìÂ… F™š ëy5‡¾~,ó¹;ë²>÷±>ÖÇÖrgx«o·<Ô푃!„b°¼¬U«VÓ‚j²Ì)¸¸8ÿg-÷¥®îíÁbˆfô¢½ô1Ë«ÁÒ$÷•+W‘¬©S§Jyy¹Lš4‰–ceÒ ÝüRç¥Í7žþµ{ÜÝÝÐë…ûq¬éÕãöövôFù±ó_ôFß±¾¯Ñkÿ8* –3*++ÄwO9JzΟœ(k}»å¡n£@4£Í襉`y5XëÖ­“®®.#rSWW' ÒÚÚ:ê.;­ãê.;çëz«o·<Øí‘ƒ!„’ƒåq,WëaiÄJ§uŠ0??_š››G]C׆r·N”+ãæ©¾Ýò`·G‹Q šÑ‹fôƲf™>Ý-‰`#Ô˜Es{¬ƒÅZ2hF/šÑËš 3å ,‰‹‘/šÑ‹fô¢ƒ…ÁÂ`1‡!„ƒ…ÁD°¢½hF/š1X ¦ ¹hF/šÑ‹æPòìéÓrï½÷0X€£@4£ÍèEs øÍþýò˼yÒ±d wr° „B;\îp8$;;[zzz æææçÜÁ[}»å¡n,òÐŒ^4£75_úmë((_22ŒeôœæV©±zç6Ãh…JoT¬—_~yÔ9ë†Êj>Ô±šÐÇYYYnÛñVßny¨Û#‚Å(ÍèE3z#JsuµÜþè#y–˜(÷JJŒDu P§uJpÏžk!וkÅŠFÔjppÐàŽ;Œs&tÚPÏ›ÐÇzμշ[êöÈÁ‚B)¬ûê+éÊÍ•žÌL©?|Ø8§ÉëšÄ¾jÕFR{8<Ϩ4X?–™3gçiéãÎÎNÿçW;ÖúvËCÝ,F¾hF/šÑöš««¥qÝ:y6{¶4®_o;¥  C22~1–a'½Qi°òóó–5+//–ceÒŠœœc^Ú|ãé_»ÇÝÝݽ^¸Çš^=ÖLÐÝÇÎÑ}Çú¾·ç÷‡K—¤oèw©kè·ü決wï¾lßþ@ŸÉÆ?JssKØéJƒå*Zc=ç*GIÏù“e­o·<ÔíÁbä‹fô¢½á¨ÙÜœYs­4çJÏ}õUäævIff>\¶z£Ò`郚weÍÁruaWW—˻윯뭾Ýò`·G„Âp§usæ C¿aÕÕgdݺF™=û™¬_ßh‡óóøu°\­‡ÕÚÚjL êƒJ}¬ç¬Ðµ¡Ü­åʸyªo·<ØíÁbä‹fô¢½áªÙÕæÌ©ÊÌìú=ï’ŠŠK¡—•Ü]Àº¤C4¶Ç:X¬%ƒfô¢½á¨ÙÝæÌškõÑG·#J/ Ábä‹fô¢½!ÕìËæÌ‘¦ƒÈÁ‚B2ú»9s¤ƒˆ`1òE3zьޠk—Í™‰`r°Èc@3zьިÐlgsfr°‹‘/#_ô¢½h¶0›3Á,!„PÀÍ™ÉÁ,F¾Œ|Ñ‹fôƼæpßœ™ ‹<4£ÍèÍã´939XƒÅÈ—‘/zьޘԬ‘ªÞÌLcsæKƶ6ºP¨.ZRrÏX@4ÚûƒÈÁ‚Bcsfr°Æîö tUnrÒ¤I#ꔕ•ùµWŸ·úvËCÝ,F¾hF/šÑkGs¤nÎLË‘òµµµ#L†c¨ã³³³¥§§Ç`nn®qμշ[êöÈÁ"wÍèE3zǪ9Ø›3“ƒFkîܹÒÙÙ9|¬æC« }œ••åöÿ½Õ·[êöˆ`1òE3zьޱhÅæÌD°ÂÄ`ÕÕÕIiiéˆsñññ2888|¬õœ;x«o·<Ô푃!„Іrsfr°ÂÄ`©Qhiiñúqqq~µc­o·<ÔíÁbä‹fô¢½¾jŽ¶Í™‰`Á`é‹¶bÅ ¿#D±ÁÒ7€I+rrrŒyió§íwwwôzá~kzõ¸½½½Q~ìü½Ñw¬ïkWå7.^4¦ûçΕöÓ§óº9óܹýCë¹xñFTéµ{ÕKóŽnݺåSŽ“žó''ÊZßny¨Û#‚ÅÈÍèE3z=i§Í™‰`…Ø`544¸Mì6ï²ëêêry—óu½Õ·[ìöÈÁ‚Bh¥LŸî–á¶939XAZËÝzXj*êëëÝ^C—mp·N”«ëyªo·<ØíÁbä‹fô¢½£ –+ öÍ™‰`&LˆêöX‹õsÐŒ^4£×Wƒ¥åá´93ë`ˆ,F¾hF/š‰`¹2Xá¶93,€Á‚Bñ+Ü6g& `°ùÝ@/šÑöüvϯS„ô1 ƒEîšÑ‹fôú@M\¿¿f $'{¼‹>Æ`"XŒ|ÑŒ^4£×^:rDz²²ä§ü|¹pì˜,ZôLnÜù»pçŽþ ÐÇ,@„BoÔECŸ%&Jãúõr¦ºZ޹$K–<úÞ—a“¥æjþüAÙ¶í¯ Ábä‹fô¢½îXSU%íË—KßܹråàAãÜŽßIb‬_ß(‡Ý2Z”W_ÕP^È®]ô1 ƒEîšÑ‹fôº£®Âþ$=]ÚÞzKÎ ­êê3²fÍ}cEö½{¿¥1X€£"4£Íèõ™ÕÕÒôÁò,)I¾/+3ÎéŠì‹uJ^^—=ZKÁä`A!ô•éÌ˓øõׯ¹}û®JJJ¿¬^Ý"ÕÕ¬mE ‚ŨÍèE3z}fÃöí2”$÷Ö®•³ÕÕÆ¹ îJRÒ3c³fú˜–KxÚäÙDss³äççK||¼LŸ>]*++G”—••ùµ²·úvËCÝ9Xän ½hŽ|½çN’Ö•+åiJŠ\ýâ ã\UU,[öhè{ýgùê«Kô19X¾-Whii‘Y³fI]] JWW×sß0\îp8$;;[zzz æææçÜÁ[}»å¡n#_4£Í‘¯·þðaù%#C.[&çOœ0Î}ùåe™;·OÞz«MN:GÁ²g°V¯^=*be…š}AMè㬬¬1×·[êöÈÁ‚ÂÈæ?4Ö¶úýæÍÃç¶l¹)‰‰Ïdóæß󑃃5iÒ$©¨¨©S§Ê„  ‘½½½Ãå:m¨‘-úXϹƒ·úvËCÝ,F¾hF/š#Some¥<^²Dz‡¾³ëÊËs§N••+[%-í‰ÿùç×%)i@JK›èc"Xãc°4©ÛÙ`Y †«%=çON”µ¾ÝòP·G„Fë¾úJz33¥£ @j3Îéªì%%÷$9¹_öìù–׉¬ñ3Xšà®Ó‚j²”:]X\\<ê.;½»ÐÕ]vÎ×õVßny°Û#‚ÅHÍèEsäé½õÉ'F"ûÝ †ÏUVž—üüŸ$'GWe¿@Á Ü:XîÖÃÚ¹s§Lž<Ù˜\¹råˆ$w…® ån(W×óTßny°Ûc,ÖÏA3zÑ9zkNœ‡o¾)}óæIý¡CÃç÷ïÿFRRžJqñ]•>&‚5n°ækEc{D°é£½hŽ ½W÷í“§iiò‡¡ïès'OŸÿðÃ;ƪìÛ¶Ý ‰`p9XBF¬®–æ÷ß—ÄD¹±mÛðùªªsòæ›%#CWe¯ãu" `°¡½hF¯/¼èpHWn®A}lž//¿,óæý"Ë—ÿ('Ož£‰` óúhF/šÑë 5Z¥Q+^ù¿Mš•eeß«²ôÑmú˜,€ÁbTDt½hF¯/Ôü*ͳz’šjä]™çOŸ>+¿ûÝIK{*\¡‰` „B_Xð q‡`ûow šçŽ‹’•Õ-rüøy^+r°‹QÑ ô¢½¾P×´Òµ­n}úéˆó»v]“ääyÿýfc!Qú˜À`1¯O~zÑŒ^/ÔUØ;/–žÌL¹TQ1|^Í”š*5W»w_£ÉÁ,FED7èc4£×^ß¹ÓØG°eõjc_Aó¼Nêt N :èc"Xƒ!„ÐÕLý°j•ôÏ™#×vïQ¦ ìšÈ® íšØÎëEÀ`1*B/}Œfôza]y¹ô}¯>^²Dj++G”éÒ ºƒ.Å@Á )<íAè\î®^YY™_{õy«o·<Ô푃EšÑ‹æñÑûû?6ÙïlÚ4â¼.ª‹†êâ¡ååuô19XáOˇdggKOOÁÜÜ\ãÜXëÛ-u{D°¢½h¼Þó'NÈ£eËä—Œ ¹|øðˆ²ŠŠ:™?ÿyãvcûú˜VT,5ú‚šÐÇYYYc®o·<Ô푃!„å·{÷ÊÓ”i-*’s§N(Ûºõ†±Qó¦Mwx­ÈÁŠ<ƒ5iÒ$‰‹‹“Ù³gËÎ;G”ÇÇÇËàààð±>Ösîà­¾ÝòP·G‹Q šÑ‹æÀè=[]-÷JJd )I¶oQ¦ÉëÅÅ?HJÊSÙ¿ÿú˜Vä,+&‚yë`¹Z窦¦FRSSóÓ¦M3ò¯FÔѵ¡Ü­åʸyªo·<Øí±kÉ ½h¶¡·ºZ×­3¦o}¿:—:¤«²?‘¢¢Öˆ\•>&‚5n˜0aBT·G‹Q šÑ‹æ±é½pì˜ü´h‘ôdgË¥#GFÕß¼ù÷ƪì[¶|OÁÂ`r° „ФLŸî–ÉÉrÍc9ëÿœ:uNÞz«MæÎí“/¿¼Ìë1X€£@4£Í£ –+ ÿvÏžQõ+*. }gþ,Ë–=”ªªú½,@y hF/šý1XÎu·oo0Ve߸ñ.}Œ^  ‚Å(ÍèE³ƒU]}VV¯n‘””~Ù·ï*}Œ^   Bí¬£Gk%7·Kòó;¥²²–× b°,FhF/š=ñ‚®èÁ`íÝû­Ì™Ó/ï½w?"Ve§‰`r°˜×G3zÑRj{r²Ç»äóÏ¿£Ñ‹ÁD°¢½höÆ»ë×Ë@b¢\ÿüs#q=5µ_¾ù¦ßø>¼sG$=}pè{ñ©9r‰>F/ ƒ!„ž¨{ >\¶L~úÎ3]¸°W._îñ¨&+3ó9¯Ä`"XŒÑŒ^4{b]y¹ü2ožü¸b…œ;ujø|BÂs—ß“¯¾*ô1z£Û`¹ÛƒÐt£cWõÊÊÊüÚ«Ï[}»å¡n,òÐŒÞXÒܰm›è^‚·7mU6~ßЮŒŠ`egÿ‘>FolD°¼¬“'OJVVÖ¨z‡c胒-===Õ„é9wðVßny¨Û#‚Å(ÍèÍÕÕÒ²zµô§¤È7ûö(Ó»ׯ¿+¯¾ú\ÒÒþ(7nüÉ\ }%Êècôb°žV#æÞêÛ-u{ä`Acµ••Ò™Ÿ/yyÆckYEEäätüê«:#Ñ=7÷©Ìš58ôýùB¾øâ¯!Ä`)>úè#9tèËzñññ2888|¬õœ;x«o·<ÔíÁbˆfôF»æo§))òÃ»ïŽØ¨ÙŒZÍžýL6l¸;jm+ú½, šššdáÂ…në¹ú¿¸¸8¿Ú±Ö·[Êöô `ÒŠœœc^Ú|ãé_»ÇÝÝݽ^¸Çš^=nooGo”;ÿ„çÿÃöíò"9Yîýß” Y^]}ˈXåçÿ"ß|Ó5zíëû½ö£Ò`©¹jmmu[,FhFoôkÖ;ÛÞzKúæÍ“Ëåå>G­èc>ÇD°Ü,ë]†®î8t•£¤çüɉ²Ö·[êöÈÁ‚F/9"½CƒíG¯¿.5UUns­x­ 9Xc¸‹Ð]=ó.»®®.—wÙù[ßny°Û#‚Å(ÍèfÍ×wí’¤$i,-SÔŠ>æsÌ:X>®‡åª\׆r·N”¿õí–»=ÖÁb-4£7*5WWKóÈ@r²\Û³' Q+ú½1Á/L˜0!ªÛ#‚Å(Íè6Í5'NÈãÂBéÉÊ’‹‡­¨}Ìçƒ"Ê`AáxðòáÃÒ—ž.X¹RÎþß–7äZAr°@Ì,FEhF/šÍï?ûLž%&Ê­O> XÔŠ>æsŒÁe°˜×G3zÑ(ž=}Z¬Z%OÓÒäÊ¡C㵢ыÁD°¢½1¡ù±cÒ•“#?-^,çxÔŠ>æs1ËݺTÎ|ùå—q:ä`A¡[^Ý»WúçÌ‘û%%Æ]ƒäZÁ˜ÎÁRãd¥;ƒåiû@‹QšÑÛšïlÜ(‰‰òÝŽãµ¢ùGäaeeåð"˜&:;;sÕC£@óúhF/š­}Úï»]áêÕ«ÆǺÍĉ¥¸¸Ø0qV”••ùµWŸ·úvËCÝ9Xä1 ½á Y—]Ðåt†Ê}Õ!ZÑÇè¨u°Ô-NŸ>Ý0@J}|ãÆ1M7ºBAAÔ××Ë‹/ŒÙ$##c¸ÜápIõ===ÕŒé9wðVßny¨Û#‚Å(Íè ÍW4ýaU±l\w;dQ+ú˜ÏqÌ/4êÎ`¹‚uCe5ú‚Z ŸN[ºƒ·úvËCÝ9XÂPóÖæÍÆ–7õ>'× ’ƒ K#X‡’¥K—Ÿ‹7Î[ëè9wðVßny¨Û#‚Å(Íè •fÝœùï¼clÖ¼óÝÚ°ˆZÑÇ|Ž#Ò`éÝ‚S§N ÈJîÞ –y]]þ¡µµÕãÿyZäÔ[}»å¡lOß&­ÈÉÉ1æ¥Í7žþµ{ÜÝÝÐë…ûq¬éÕãöövôFù±ó_;×û¾¦Fz23åqá YQÐ%ùù¿Q«hÕ)Çú¾F¯ýã ¬™3gŽ0TVú»’»¯¬½{÷w)Á"‚Å(Íè Í×vï–äd9_PvQ+ú˜ÏqDF°ÔHjÅvr°¬æÍUŽ’žó''ÊZßny¨Û# BL6­['ý‰É²)ã"¹V¬@¬@î7èÎ`•––J[[›ñ¸¯¯ÏX¦Àj0Ì»ìt»WwÙ9_×[}»åÁn£@4£7škªªäÑë¯K{Jžä$´‡mÔŠ>æs‘K—dÐ}»ÆÊ™VÔÔÔHjjªq^/]³f͈½jºÜ­åʸyªo·<Øí±kÉ ½ÁÖ|ùË/¥7užÔ&m”üìǵ¢Ñ1K×§JJJex Ö%¢±="XŒÑŒÞ`j¾QV&O^M–-¯VEDÔŠ>æs‘ËÝ*îc¹‹D–Á‚ÆÏVWËÝ·Kä§™R²à;r­ 9XãäîŽÌÏD°¢½¡Ó|þè1y¾Tfɧï_¨¨}Ìç8æ‘e°˜×G3zcCó¹­åÒ9sžœHÙ.G¾ºD£™, ‹zьޱjÖ(Õ©¥»¥gFšy뫈ZÑÇ|Ž#Ö`544ÈŒ3Œ)A¥>Ös€,adòÈá r)i´½š+§vç5ä`Û`]¹rÅm’;&‹£"4£7²4k”jÛ{õroFÜ^P$窪èc4£7K£UÒÙÙ9|Nçååkdr°˜×G3zûwÿ^òóŸÉìÙ"YYÏdÛ¶[RQQ'gÔJïoS¥á½éc4£7”K§uÃgg¼xñ",ÖƒÂ`ÁB/šÑ;’¢ƒ_7üùµT¹ºç úÍè ƒ5000꼚. 9XÂ05X®0tþ‚ÃÁka8¬™3gJVV–tttÈàà A}œ‘‘aL"XŒŠÐŒÞÈ1Xô1šÑ&KÙÝ%¹ß¾}Û§k¸ÛƒÐÄÕ«Wœ.ˆMœ8Ñå^„eee~íÕç­¾ÝòP·Gy hF/‹÷4Ÿã_¦A”F«Ô)õ±¯æÊÙh¹ÂÒ¥K»5:¦Ó‘›6m2 — ‡Ã!ÙÙÙÆ¦ÓÊÜÜ\ãœ;x«o·<ÔíÁbˆfôºãž=ßÁâsŒÞX[hÔÁr†-ë6ô5¡uÚÒ¼Õ·[êöÈÁ‚:óôé³²fÍ}y=ñ^L,1XPWW7"‚o˜.«Ósîà­¾ÝòP·G‹Q šÑ;bÑÐ#—†e=²;㨠ÌNôx!}Œfô†‰Á:wîœ:¯yRµµµ7XÍÍÍ’œœ,íííÿÏÓFÓÞêÛ-e{ú0iENNŽ1/m¾ñô¯Ýãîîî€^/ÜcM¯ëç ½‘}¼eËMIKz"w¯—þŒ ©?thD¹óßhïïXÓ«Çú¾F¯ýã ¬W^yEz{{G×sS§N ¨Áº~ýº$$$HSS“_""XD°Ð‹æXÓ[UU#Ë—·Ë›©MÒ¾P.[&5.Ve§ÑŒÞ0`y2E/¿ürÀ®USSc$Ïß½{×§'=çON”µ¾ÝòP·G„±Íýû¿‘ôô'r ÏaL ÞþðC^#Í`é²ÖmrLèZXº¤B Vyy¹±íNKK‹Ç»ôtéWwÙ9_×[}»åÁn£@4£W©û~ðA“¤&öÉ­ü÷äIzº\9x>æsŒÞH4Xú푪 /4ªFHM†·;Ý\­ƒåj=,wëlY¡kC¹['Ê•qóTßny°Ûc,Ö’A3zŽ ’—×)E™w¥{ÞByôúëRsâ}Ìç˜>ŽTƒ¥¹Vî P___XÜì-{Âa‹ "XŒÑ;z·oo¤¤©Xö• $&ÉécôÒÇѰLƒNê–9æB£³f͵Ò:ˆ>ƒ! -O:'+W¶ÊÜ”ŸåöÒ5ò4-M¾9p€×BÖÁD°¡½cááÃõ’‘ñ‹”,¹%= 2åñÒ¥rÞ‡)Aú˜Ï1z1X Ì óúhFohøá‡w$1ñ™T})Ï’’äîúõô1zÑm9XŠŠŠ c=,ë² :eøðáCœ,FEhFo€XYY+K–<–¬]Ò¸bùÄXžÁj°ôB×ÁD°¢½#©›4¿ûn‹$'÷Kõû‡d 1QKKécô¢9Ú#XVSå¼r»¿+¹r°Èc@3zÿį¾ª“ÌÌ^)\üPš‹ÖHJŠ\Ý»—>F/šc!K7îïïe¨t™oûå"XŒŠÐŒ^×üä“[F"ûÖ’+Ò•%?-^,µ••ô1zÑ+,MfŸ;w®±]ެ/^ûªñJMMÅéƒ!ôƒ'NÔÈ›o>”yóúäü‡ûe )Iš>ø@ÎTWóú@K9Xæ¶8®¨ûæ"XŒŠÐŒ^߸oßUIK{*ï¼õ@þ9säÛ={ècô¢9V×ÁR“e]ÉÝß%Üí/èk¹¢¬¬Ì¯½ú¼Õ·[êöÈÁ"Í‘£W7i~ÿýfIL½_”®œéÌÏ—ÚcÇècô¢9–×Á <(Oå‡ÃXB#fÊÜÜ\ãœ;x«o·<ÔíÁbˆæÈÑëp\úLw¬ûlŸ $'˽µkƒ6%H£½,·åj>ô5¡³²²Ü^Ç[}»å¡n,#ƒÛ¶Ý0¢V¼ß$÷Ö¼'ýCæêÚîݼ6’ƒ%ÒÞÞnL *4Á}Ê”)†š1cFÐ –Þ­¨ëp™ÐÇžî`ôVßny¨Û#‚Å(Íá­÷äÉsCŸÑ?Hjê©ø¼Fºòò¤sˆ‚0%Hó9Fo„¬ŒŒ inn6¯\¹rD¾TÞÐF0 –«óz£?×±Ö·[Êöô `ÒŠœœc^Ú|ãé_»ÇÝÝݽ^¸Çš^=Öz{|ð`½ÌŸÿTÞ}÷¹uð+#jÕ¾q£Ü¿w/$úÿF{Çš^=Ö÷5zíÝ`i$e``Àx0VeÿnçNú½hf,ß0mÚ4c:púôéÃçfÍše$š…tñÓhn£@4‡—Þòòº¡Ï\¯,YòXN•Ÿ4öìÎΖ‹a8%H£½1°ˆ,ƒ!Í?þ½‘ȾiÓ¹úÅÒŸ’"?¼û®œ=}š×Br°¼ã•W^‘¢¢¢°‰R"XŒÑJ½'Nœ—eËIFÆ/røP4­['‰‰Ò°c}Œ^4Áòoý+]*@óôîÁääd¹zõªô÷÷ãnbÄ`1¯fôþ/÷îýVRRž :[åìÑ*é((ž¬,¹øõ×ô1zÑLÖØðøñcÙºu«‘‡e& k.–nNÜÑÑÓ!‚ŨÍQ«·ºú¬””Ü“¤¤Ù¾½A®îÛ'OSRäAqqÄL ÒÇhFoä`iôª¡¡aèË&ixM,]lÔÛ¾y€,#GŽ\”œœnÉËë‡ã‚4®_/φ¾û¶mãõ¬ñMr×ü¬5kÖ+¼"XŒŠÐ-zËʾH>“ÒÒ&©©<. ¥73S.9B£ÍD°¸‹ƒÅ¼>zÑìÞ“'kä­·~”ôô'ràÀ7òÍþýò4-MZ‹Šäì©Sô1zÑLVà –n‹cîAèL·ÊD°¢9\õ8peÈXõÉòå?JUUÜݸј¼QVF£ÍD°o°fΜ9ÂPY©yX€,#™ÕÕgdݺFcJpË–›Rsâ„¶®­å­<Ð× ÷öÈÁ‚Ðwffþ,ß~ûlÄçEMVVÖ ©?xPž¤§KÛÐç)Z¦!„b°\Ý=8Ö»Ý,Ý’gpppøXë9_Ë}½po£@4ûN™>Ý-uJðæ§ŸÒÇèE3zC“äîŽþæg¹3X®Î[¯í­<Ð× çöô `ÒŠœœc^Ú|ãé_»ÇÝÝݽ^¸Çš^=ÖÅ‚£]¯a¦\ç?È­ÿ‹ZE³~ç¿è¾cý£×þqD/4J‹£@4‡$‚åÆ`ÑÇèE3zCÁ †Ár•ƒ¤ç|-ôõ½=r° ôz‡`¬,a,Ýàyƌƴ•Rë¹@ßE¨‰ôžî²sWî|]»× ·öˆ`1 D³ÿ‹‡¾óN›,\ØK‹Ï1šÑžëÊ•+n“Ü}5Y®þ׺ö“§u <•úzáÖë`±– š}ç©SgeéÒG’—×ilyë‹Ï1šÑ¦K£UÒÙÙ9|Nçååkd…&L˜ÕíÁbˆfßxâDa¬^ý‘œ®ª–öåË=ÞEH£Íè ™ÁÒ)AÝðÙ/^¼ £«  ‘ÎúÓéC½‹y}4G®—9súeÆ»rùðayš’"M|@ó9F3zÃÛ`i"»»$÷Û·oãtˆ`1*BsȸoßUIL-[nʵ={dÀËÊìô1zьްZ¦A”F«tJP©1Wä`AJ~þùwCæê™ìÜù|¿e‹vG³ ‚ŨÍÁ Þ%¨w :ÊÏËã¥K¥+/OΟ8A£™>Fod,5Nº<ƒùØÍ:€,Ǔ֭oNUœ’î¬,yøæ›röÔ)^!S„€£@4ûKëÖ7ç;¤/=]~x÷ÝQk\ÑÇh¦Ñ‹ÁrBoo¯w(NžF3zéãè6Xu ”ÁÒÈ•u;}¬›I›Pó¡/¨ }¬«Ë»ƒ·úvËCÝ9X0ÚiÝúæ÷}$IIruß>^aäç`yº{Ðd||ü¸,dY¯­u‹úØSÛÞêÛ-u{D°F³fëÖ7÷KJäIjªÔ•—ÓÇhF/š£#‚eÞ)h.ÇàLÍ:tèP@ ÖªU«ŒiA5Yæ¡õE}Îðt£·úvËCÝ9Xä1D«fs뛲OoÈ+VHïÂ…R{ô(}Œfô¢9úr°‚±ƒN7®\¹ÒˆdM:UʇF«“&M"‚åÆX™´"''ÇxÓ™Î^ÿÚ=nooèõÂý8ÖôêqcccØ<ŸãÇJRÒsùbÛé]ºTž¼õ–|W_µzƒul½Ñ{¬ïkôÚ?މe*++ÄwO9JzΟœ(k}»å¡n,m4·¾©ØQ#?½—Û†Þßgǰ „FLëܹs#ÌŽ‰5kÖHmmm@ Õºu뤫«ËˆÜÔÕÕIBB‚´¶¶ŽºËN븺ËÎyŠÍ[}»åÁn,ò¢Y³¹õMÕöcò45Uš×®¥ÑŒ^4Gÿ]„¯¼òŠ1…çjZO§ó±Òkéa~~¾477ª£kC¹['ÊU“§úv˃Ý9Xä1D«fsë›Ú²ƒ2˜(·6o¦ÑŒ^4ÇF–+3èu°qb4·G‹Q`´i¶n}óíæò,)I®ïÜI£½hŽ–FT:;;Gïèè‰'²gM,ǃ֭on—n”þ9säÊ¡C¼6ÂØÊÁÒnT=xðÀÈ‘R¶´´‘-o‹a"XŒŠÐl¥¹õͲ×JKÑ*é›7O.9B£½h޽–æZ¹[h´¯¯§Å‹y}4’æÖ7E+ZäáÒ×¥+'GÎ?N£½hŽÍ,s:pæÌ™Fî‘rÖ¬YÆo€£"4ûBsë›õÅ·¤{ÈX=Z¶LÎ:E£½hŽÝ  B;4·¾ÙVRoL >(.–3¬q!Œõ,@‹QšÇJsë›Ãœ6’ÙïnØ@£½h&‚e¢  ÀغÅ9+\–iÀ`‘ƒ…ÞðÓüùçß ™«gròƒrc†ï·n¥ÑŒ^4“ƒe¢°°pØL9¬`ìSˆ`1 Œ<ÍæÖ7uïí0ývï^úÍèE3,çu°®\¹b<6#Vzgá²eËäÈ‘#8r° Asë›ïW®7¶¾¹\^Îë!$ËÖ•Ü­u=¬É“'ãtˆ`1*Bó0uë›yé?KËEƦÍŽ£ÑŒ^4Árg°tb….ÑPSSc<®¯¯XV{{»,]ºÔÈóRêã¶¶¶uÊÊÊüÚ«Ï[}»å¡n,òÂI³¹õMÞ‚y´h‰ü”Ÿ/5UUô1šÑ‹fr°Ü¡jèKrÍš5Æã¤¤¤9XÚì955UvíÚ%/^¼0¸sçNIOO.w8’m=enn®qμշ[êöˆ`1 'ÍæÖ7˳ïKÏ‚LùqÅ 9{ú4}Œfô¢™–¯Pó3mÚ4#r5eÊyþüy@®ë*fÝPY͇¾ &ô±§mz¼Õ·[êöÈÁ‚áBs뛵ù7äÉÐ@éÞ{ïñº@ÉÁ ¬ñjÔÊÜëpÇŽÆ9:m¨ç­ù_zμշ[êöˆ`1 ÍæÖ7Ÿ-©•¤$ùýÇÓÇhF/š‰`…?~llÅcN=êãÎÎN—Éõ&<-á­¾ÝòP·Gy ¡Öln}søu‡ÿœ>F3zÑL–¿ èjxÌ)BTC0cÆŒ€¬üü|#‚eÍÁÊËË#‚åÆX™´"''ÇxÓ™Î^ÿÚ=Ö¾äõÂý8Öôêqcc£ßÿ¯[ߤ¦>“ËE‡åYJŠ\9p ªõFú±IôFï±¾¯Ñkÿ8è+##Cš››Ç+W®‘än5Avà*Zc=ç*GIÏù“e­o·<Ô푃CEÝú&)±_®/Y/}sçÊ¥#Gx] „ä`I0ë]ƒj¬nݺ%MMM2qâÄ€,½cPó®¬9X®î"ìêêry—ó›·úv˃Ý9Xä1„ƒfÝú&%ñ‰ÜË{Gº³²ä|e%}Œfô¢™¬@,4ªQ%=6ï Ô:X­­­F4LïTêc=g…® ån(W9LžêÛ-v{ä`‘ÇjͺõͼÙ]òpÁbyTX(çN¢ÑŒ^4“ƒeúƒ¯«ÆbÒ¤IÆyjiY8Àº¤C4¶G‹Q`(5ëÖ7‹’Ú¤'m¾´þîwr¦ºš>F3zÑLËî¹þp[ó®4!]¡rîܹìYÅ BÝúæí”Ûò$)E×­ã5’ƒÈeÌÅE§OŸ>|nÖ¬YÆ]W€£¢èÓln}³>½N“äûÏ>£ÑŒ^4ÁŠ´u°@x,æõcS³¹õÍ®yÇ sõíž=ô1šÑ‹fr°0X,FEè«fsë›ÊŒ]ò4%E.>L£½h&‚5Kï4—gpf î"ä`ÁÐS·¾ÉZØ-—ç­—ŸçÏ— ¯ „¬ñ2XÖ-lÔPYém;@‹QQ¸.Ú(/döl]èö¹lÙrO¤uÉô·¥sÑ"©9q‚>F3zÑLk< –©êêj 9XÌëG EoVqÃöåËåìéÓô1šÑ‹fr°ÆÛ`¥"‚Ũ( –+ §ÑŒ^4Á ’ÁÒ¥tû@Ä`A!9X2Xõõõ’””d쓈`1*Â`ÑÇhF/š‰`h/Bw Ô]„®®mnÉc¢¬¬Ì¯½ú¼Õ·[êöÈÁ"a,üòËË1m°ÈÏA/šÑVIîî8^ùYµµµ#L†ÃáììlcªR™››kœsoõí–‡º="XŒÇÂO>¹)… ÷‰`Ý@/šÑ« ê‡ÃÇj>ô5¡³²²Üþ¿·úvËCÝ9XО:uNÞz«M>K:)ý Iï"äõ‚’ƒ¥«®®NJKKGœ‹—ÁÁÁác}¬çÜÁ[}»å¡n£@_Y^^'Yr9µTúÒçJý¡Cô1Ñ ô¢½áb° Œü`¬ä®F¡¥¥eTŽ–?ËGx«o·<Ô푃Eƒ/ܲå{)HøA'gÉÃeˤ¦ªŠ>&?½hFo¸¬ÂÂÂa3ål°ƒ¥®tÅŠ~Gˆb)‚¥o“Väääo:ÓÙë_»Çííí½^¸G‹^\½ºCÊRÏÉÀìd¹ýá‡në766ÆLÿÆ¢^ýk½Ñ{¬ïkôÚ?ºÁÒ»Ú®\¹2œð®èíí•eC#â#GŽÔ`iÞÑ­[·|ÊqÒsþäDYëÛ-u{ä`Awüê«:Éžß)—Ò6H_Zº\9x×BÃu™W5Ê2yò䀙«††·‰Ýæ]vº—«»ìœ§Ø¼Õ·[ìöÈÁ"ÁnÝú½$¶Ê£99òèõ×}ÚO>F3zÑŒÞ,s%÷ &HMMÍð¤ÌÁRS¡×t]¶ÁÝ:Q®r˜<Õ·[ìöÈÁ"Áó]‚g¥¨¨U>Jª‘þÙÉrgãFú½ô1šÑªJÖ¬Yc<ÖÝ­9XS§N ‹;ÕøEs{D°ºã‘#—${A§Ô¦m’'©iòÍô1zécú½‘¶LË/dÚ´iFäjÊ”)òüùsÑk°`xsÛ¶’ŸØ&ísòäñÒ¥rÞ‡)A!„1¼Ð( ‚Å(Ð=OŸ>+«V=‰ç)Á»ë×ÓÇèE3}ŒÞH3Xã±Öˆ ƒÅ¼~8N ^”œÌN9—ö‰<™“*ßìÛG£Íô1z#Ñ`…C¾ ‚Å(ðŒìØÑ y³Û¤mÎ"éX²DÎ?N£Íô1}©kúôéÒ×ׇ£! †pJðÝwu‰—äiB²4––òº@a¤¬K—.IzzúðR €£¢àñë¯uJð'©NûLžÎI‘«{÷ÒÇèE3zéãhYËÉÏ"‹yýñãçŸ'y‰?ÊRKGþb©­¬¤Ñ‹fôÒÇÑ’ƒ¥&ʽ! ‚Å(ðŒTWŸ•Õ«[äƒÄËòtv²4}𜩮fä‹^4£ÍѺ  Ž/Ž ’—ó“œLÝ*O“SäÛ={x] „u°,FEcå®]×%7é¡ÎÊÊs}»å¡n¬èàîÝ×$;é‘´¤¾.yyr!S‚BCl°Ì;Í圩SY‡ ˆÁš4i’TTTÈÔ©S•ãU¤FÈL¨‘ÓÈ– }ìÉÜy«o·<ÔíÁŠìQ N ®]{OÖ$^“¾Ù)r¿¤$hS‚ô1Ñ ô¢½a2EŒ¥ÔÄ• ýÈ<þ\†~|ÖJQQшrž—·úvËCÝ9X‘›ÇpìX­,ÎÿIަî’þ¤d¹¾k¹èE3zÑ‹9XÁ€FkÔX™P£eÝ‘ÖHceÒŠœœãMg:{ýk÷¸½½= × ÷ãñÖ{úô’›Ò!÷ÒÞ”ŸóËƒï¾ ¹þÆÆÆ˜éßXÔ«M¢7zõ}^ûÇQi°4©ÛÙ`Y †«%=çON”µ¾ÝòP·GVdQ§?ø YV%\—¾ÄTiY³FΆhJBa E°4Á]§Õd)uº°¸¸xÔ]vzw¡«»ìœ§Ø¼Õ·[ìöÈÁŠÜyýÊÊZ)XÜ!_¥|!ý‰ÉòÝÎän ÍèE39XÁÃΡžÉ“'Sƒ+W®‘ä®Ðµ¡Ü­å*‡ÉS}»åÁn¬Èœ×ÿâ‹«’=§CšÒVH÷¾8dšÉÝ@/šÑ‹fr°"Ö|­hlVdŠtJpݺ&)Jh_Óä‡wß•³§O3òE/šÑ‹f"X ÜAVxòøñó²¤à±|™²_úg'IÃŽ¼.BHÀ`1*+÷í»*™s~’;©oKwf–\üúkF¾èE3zÑL `°˜×ëÿ®_ß(+gß”ŸÓäAqqØN ÒÇäç ÍèÅ`"Xa?*Ò)ÁÂÂÇr(åÐÿN nÛÆH½hF/š‰` +÷ïÿF²S’ß§­”ž…™réÈ^!$ `°UïÆwåíÙ¿—Þ¤¹ÒZT$gOb$ˆ^4£ÍD°‹yý±è=q¢F^ý‘ì›SnL Þ(+#—½hF/šÉÁ,FEcÕ{àÀÉJûI¾O[%½óÈ¥Š F‚èE3zÑL `°àX¹iÓYžpGz’æÉV®”s:%!„ƒˆ`…|TTUU#Ë–=”=sŽHB’|ÿÙgŒÑ‹fô¢™ ƒÅ¼þXõ‚!„0†–ip6X®r”ôœ?9QÖúvËCÝ9XöyôèÉ_ð(æ ¹hF/šÑÅkõêÕÒÚÚj<~üø±,_¾\JKKGÝe×ÕÕåò.;ç)6oõí–»=r°KÝò¦0ùéHÊôx!¹ èE3zÑLVD¬ššIMM5ŒË´iÓŒü«utm(wëD¹ÊaòTßny°Û#‚8nÝú½¬~íª—_æ¤KýáÃŒÑL£ÍèÅ`r°ì$³¿³´En$IGVžÔVV’Ç€fú˜>F3z1X€–döw2îʣײäÁ;EröôiFh¦éc4£ƒÈÁ²“Ìþ~b½ô½:Gnô¹B1X€–Ýdö=¯–K_BŠ|ûŌь^ú˜>F/ ƒe‡¥ïÝ•ÚW×K×ÜL¹øõ×ä1 ½h¦Ñ‹ÁrÝèØÕ^eee~íÕç­¾ÝòP·Ë,Mfwɹ÷j¡´-ySÎyX<”Q šécúÍèyƒurè‡2++k”Ár8’-===Õ„é9wðVßny¨Û‹å,Mf/™w]z^+Mk? oB!ËžòÐŒ^4£Íä`‡ÁRèÚPîÖ‰ò·¾Ýò`·K¬Ÿ]— 3KåqZŽ\2™ŒÑŒ^4£ÍD°B„ &Du{±’ƒµ¹øšÜ›Y(-‹ß–s§N‘!„,}+X£"Mfß¼è’týv®ÜZ³Q šÑ‹fô¢™ˆ^ƒŒy}Mfß•zÔHf¿¶ísòÐŒ^4£Íä`"Xvxp½T½ö™tΞ/—ËË¢½hF/š‰`r°ìp÷'WäÆoß‘ó_—ó'N0ÿ!„,@Ë·]’‡¿Í”Ûo–È™0Z<”‘/zÑŒ^4ÁÂ`a°".K“Ùw朔Ÿ›"×6n%ÍèE3zÑL ‚e7™ýÈœ=Òóê\©ß{Q šÑ‹fô¢™ ËqQ.ÏZ+msòåB…B1X ê"Xû6]û¿-;9¿ ûÅCù¢ÍèE3, +ìs°¾x«Zº›.×Vm&ÍèE3zÑLV°qõêUcƒcÝ‚fâĉR\\,#ꔕ•ùµWŸ·úvËCÝ^8G°4™ýËÌ/¥÷·©ryˌь^4£ÍD°B‚‚©¯¯—/^Èàà 8p@222†Ë‡dggKOOA5czμշ[êöÂ9ëØ×çålâÇòèµL¹pøóúBÉÁ 'X7TVó¡ŽÕ„>ÎÊÊrû¿ÞêÛ-u{áÁªØU#·f®¦¹+¤&eä‹^4£ÍD°¢Ö`iëСC²téÒásñññÆyk=çÞêÛ-u{ᘃõåúÓòhƹV¸!¬%Íô1}ŒfôƼÁz饗 N™2EZ[[GœwF\\œÇëxªo·<”íéÀ¤999Æ›Îtöú×îq{{»Oõ+Þ8"½3RåöÖ¯Ú~°}ÕMÇèòc“èÞc}_£×þqLD°öîÝ+ .$‚æ9X§Nž•“ó¶IçÌyr~gyÌ!„’ƒq°Fp\å(é9r¢¬õí–‡º½pÈÁ:þÕY¹6{µÜŸ](5_g^ÍèE3zÑLV¸¡´´TÚÚÚŒÇ}}}Æ2VƒaÞe×ÕÕåò.;ç)6oõí–»½pËÁ:ºã”<˜™/ß-xOΆùâ¡ä1 ™>¦ÑŒÞ˜5X555’ššj—É“'Ëš5k ³a…š.wëD¹ÊaòTßny°Û §ÖчtÏH—‹+Ê¡½hF/š‰`E3¬K:Dc{á’ƒUU°Gzf¤ÊÙM‡˜¯‡BHˆ>Œ—Á’éÓݲmV®œÙwŒQšÑ‹fô¢™Vƒå·Ár…¡óg*OEõ‡–Ü ô¢½h& ƒ…Á ¾ÁbT„fô¢½h&‚…ÁÂ`a° „B À`1 D3zÑŒ^4Á,æõÑŒ^4£Íä` Ö˜ï"dT„fô¢½h&‚…ÁÂ`A!„ƒÂË`1*B3zÑŒ^4ÁÂ`a°˜×G/šÑKÓÇèÅ`™¸zõªäåå[ÐLœ8Ñå^„eee~íÕç­¾ÝòP·G‹Q šÑ‹fôÒÇ,Xºt©\¹rEe``@6mÚd.‡C²³³¥§§Ç`nn®qμշ[êöÈÁ‚B1X~CV\\Üð±šu¬&ôqVV–Ûÿ÷Vßny¨Û#‚Å(ÍèE3zéc –ߨ««ÁŠ7L—Õ€é9wðVßny¨Û#‹<4£Íè¥1X~¡¹¹Y’““¥½½}øÜK/½4ªž5Âå oõí–‡²=}˜´"''ÇxÓ™Î^ÿÚ=Ö>äõÂý8Öôêqcc#z£üØ$z£÷Xß×èµÕëúõë’ MMM~Eˆˆ`‘ƒ!„Áršš™1c†Ü½{×§'=çON”µ¾ÝòP·Gy hF/šÑKc°¼¢¼¼\¦OŸ.---ïÒÓ¥\Ýeç<Åæ­¾Ýò`·Gy hF/šÑ‹fr°ü†W´B׆r·N”«&Oõí–»="XŒÑŒ^4£ÍD°‚] 4šÛ# B!$ D‰ÁbT„fô¢½h&‚…ÁÂ`1¯^4£—>¦Ñ‹ÁD°¢½hF/š‰`˜2XB!9X, £"ô¢½ô1}Œ^  ‹<4£ÍèE39X€£"4£ÍèE3,  B!„,@‹Q šÑ‹fô¢™ ‹y}4£ÍèE39XawûZQVVæ×^}ÞêÛ-u{D°¢½hF/}ŒÁòÙh¹‚Ãáììlééé1˜››kœsoõí–‡º=r° „B –mƒ¥æC« }œ••åö:ÞêÛ-u{D°¢½hF/}ŒÁ²m°âããepppøXë9wðVßny¨Û#‹<4£Íè¥1X¶ –«óqqq~]ÇZßny(ÛÓ7€I+rrrŒ7éìõ¯Ýãööö€^/ÜcM¯766¢7ÊM¢7zõ}^ûÇD°ˆ`‘ƒ!„ÁŸ,=çON”µ¾ÝòP·Gy hF/šÑKc°vaWW—Ë»ìœÿÏ[}»åÁn,òÐŒ^4£Íä`ÙZËÝzXº6”»u¢ü­o·<ØíÁbˆfô¢½h&‚tL˜0!ªÛ# B!$ D‰ÁbT„fô¢½h&‚…ÁÂ`1¯^4£—>¦Ñ‹ÁD°¢½hF/š‰`˜2XB!9X, £"ô¢½ô1}Œ^  ‹<4£ÍèE39X€£"4£ÍèE3,  B!„,@‹Q šÑ‹fô¢™ ‹y}4£ÍèE39X QVVÆ^„ŒÑŒ^4£ÍD°@ àp8$;;[zzz æææçÈÁ‚BÉÁc„š+uä&ôqVV,FhF/šÑ‹f"X`¬ˆ—ÁÁÁác}¬çÈÁ"ÍèE3zÑL#^zé¥QçâââÜ+“VäççËâÅ‹hXFF†ñ×îqaaa@¯îDZ¦W-Z„Þ(?6‰Þè=Ö÷5zíc°ˆ` ÄÀ`Eh–ž Œæ]„]]]>ßE ð]ûÊŸu°œaÍÍ‚B¡ÿÄ` Àß7zÑŒ^4£ͱ¢ƒøÐ¢Íô1zÑŒ^ @xƒ€ÁÀ``°pݶÇd¬àêÕ«’——'&L‰'Êš5kŒ5É¢Y¯®µfê-..–ŽŽŽ˜éoÕíïoëç8–>ÏÍÍÍÆ¶aºÆôéÓ¥²²2¦úxÒ¤IQÝ¿ííí²téR£•ú¸­­ ƒ"ïÃ+Ðé•+WŒ-ŠdÓ¦M†áŠVH}}½¼xñÂÐ|àÀc?®XÀÉ“'%+++& V¬¡¥¥EfÍš%uuuÆûZI6lˆýµµµcZC1’šš*»ví2¾»”;wî”ôôt à :R _Îî6ÛŽVh4+ÚñäÉIHH0F¼¬èÃêÕ«£:bå sçΕÎÎÎ¨ÖøòË/‡Õw ðí'tÍ,g3yèÐ!#Šíøè£ ­±ðþ6§‹t 0{ölc¤íP½2uêTãGW×Jêíí™ï¬ÒÒҨ׹bŠ㽬ß[Ê;vç0XƒÐŽäädc®?úX9eÊimmj­MMM²pá˜|?xð@ eóæÍQÿ~.))‘çÏŸSýk×®•¢¢¢˜èã S¤ÑŽÇËÌ™3‡¿»ôq(£v,€Áòׯ_7¦ôÇ8V £À½{÷Ž0ÑÕg5‘±öþîëë3ö9fhÒ³+j´baêûÚµk!âzƒF°¬9X¡œmÀ` –¨©©‘3fÈÝ»wc²¿£=çÌÕW±ôƒ¥w‡:,5]ѽiãÖ­[1û=Êï. À`yAyy¹qKw,„Øš«aÞÚ¬?¼zçQvv6ïï(‚&|›;VY¾|yÔçèh‚»N ªÉRêt¡.AÍhhh0 V¬@ïÔ¼+kw‚ˆéÇ¢æhÖ­Ñ:½ÝY5Nž<9ê×ýŠEƒeíãiÓ¦ùWÖèN´B§Œô=­Sƒ+W®Œú$wÚé’+±4˜k*õq(óG1X,  `°0X,€ÁÀ`@#R™µ­~À`@) ƒ, ÂÇœ¸ÚwÒ<Ö½ü.\hìw/ùùùÃd[ë;wΨ§u¬×ÑMxuŸ4=glH[]]=ê¹>|Øø¿—_~Y&MšdlÈì¼ÞñãÇeæÌ™Æs™={¶=ztÔóÖ ucã‰'íéµV­Z%7nÜ ÃÀ`@pM–»ójš>|(ƒƒƒÃ&hîܹ£êéf»ZÏŠëׯ†IMYgg§¼xñBÖ®]kÔWsdÅÞ½{‡›š5­£uM\ºtÉ8WXXh/¥>v~þúÜôøêÕ«Æq¿aèôù0XëþýûÃçÔd™Q&çz­­­£®¡¦Fˬ¯çÏŸç¼>/B™ÈÎÎõ|š››G=}nʦ¦&: „§ÁòvÞS”Nѹš†t6ijÀ–-[f*=ïjÊR§}y>fK©ÿ£S’›6m’ŽŽ: D¾Á2M‘F¾<Á4EÖiñ,ÍÁZ½zµL™2e„QS£À`@Ä,Mnײºº:ÏÁŒt™ÐéFçëú:Eh…æ|]¸pÁ(×6, ^yåÀhz  ÖÍ›7»“’’äÁƒÆ9MN¯ªª2 “ .é5Ô iŽÖo¼1êºÖ$÷¾¾>ƒK—.U¯  @jkkë(ô.F-_°`  ‚–Ó¥ |5Nþ,…&›¿ýöÛF~•ÖSC§Ë(X—MPó¥Ó„š5cÆ ©¨¨py]]¦aÖ¬YF4JM›;×ÓëšÌ%tÊ,0X, À``°0Xƒ€ÁÀ`  ƒÓ/â¯~!„F+, ÀïÀ`ñFø]Ã`ñFø]Ã`ñFø]Ã`Þˆ¿k¬¨#vvvÊÊ•+å7¿ùÄÅÅIvv¶\¸paÜÚ{饗 j[“&M’¢¢"¹{÷§t…ÞÞ^ã9L˜0A&Ož,;vìðzͲ²2ãõRnÙ²ÅïržŸ·òñ¾ž¢®®NRSS×hÖ¬YrôèQ—×s¾¶»2wm_½zUòòòŒv&Nœ(kÖ¬‘®®.Ÿ_[_´ùÓ7ãõ>ô嵈´Ï™·¾Ï÷±IÕééùåææ?¿ââbéèè·ëå{%Ö>g, VÔ,5Túaèïï—ÁÁA¹yó¦¼ñÆãúCcBÛ¬¨¨)S¦Œë—¿s»VècII‰<þ\díÚµ#¾Øœáp8Œ×¬§§Ç ~Éê9_Ëý}~¾–×õnݺ%Ó¦M“k×®Çú#²aÿ¯ãK½¥K—Ê•+WŒ÷¡öŦM›Œ_[wmµo‚õ^ŒäÏ™·¾¯÷±‰ÚÚZ†¹  @êëëåÅ‹ÆsyòdDù'Ÿ|bŒ0uvøðá1ñèõõKÆ„>võÃ`5¤æ— Bgeeù\ikÅŠRUUeû:c1ú`}úúÚºkk¬}cÅÐïÒДÈìÙ"‹‰\¼ƒåË9oŸ‰pøœ¹ë»ñ6XsçÎ5¢ñþ@5×õüý^‰ÅÏ ƒËŸóNÐ7þæÍ›åáÇc6XúŬ#ý îß¿ßãÈÐÕõt„­_à&¶oßnDÑôš:BÔ‘ u4·uëV),,4Êu„¨?2Xz½øøx·×Ñ2Õiýr²Ö÷VîiÊc,Ï?Ð×s†ö‹¾&¡øâ×)ë’·×Ö[[¾þ¿'sµ`Èÿ{|çÎÿûk²Æb°¼}&Âåsæ®ïÆÓ`i[¥¥¥>ÿŸöû¡C‡ŒHÎx]Ïßï•Xüœa°0XQo°tî]¿L¦N:<ŠuÎMðf°¬_$îF®Þ>”Öÿ™>ôÜ­†O¬ùJoooÈõªU«Œð½j0Cùþ>ký±”‡³Áòå:¾ä~øûÅßÜÜ,ÉÉÉ#úÙÛk;–×Ä[× ýý4Í• 5Y¹¹ão°¼}&Âåsæ®ïÆÓ`-r¹--->¿”:]ÚÚÚ:n× Ä÷J´Î0X¬ð3X¾NŽaÊP§4káÂ…~,>ä®Ê´]ëÈZë¨Ù3©Ç/¿ü²­Qš§$wMò×vÔd–——{üá²Á²óȦpŽ`]¿~]FM5;‚åüñyõU×õ~û[ÿ>jc1XÞ>áò9s×wãõ>Öé'^óÚï{÷îñ=èëùû½‹Ÿ3 +ê#XÞF¹ú…ký°è—t  –æ†X¿Ôtdí|W‹Œ`9£²²ÒHPuWùzÎ×òH3Xš³ÌÜšš#ŸÏU2¶¯¯­?¹!¾ôM0"XÞ>gÞ>áð9óÔwãõ>ÖM·û=7^×óõ{%?g, VÔ,ý`ßúÕÐ/wÍÃÐÛ‰5QÝ„&{j~–ë—±N!Ê`¹»»iÏž=²lÙ2yüø±q¬¡÷Õ«W—›¹!ú|ìæ`­[·Î¸ŽêÓ\ѹ›:P˜wÈèÿxº‹Ð]y¤MêŽÀŒãñ¼»IGùú£ï<=ãëkë­-_ÿ߯3ËÛçÌÛg"ÔŸ3o}7Kß“înRpþ?Mƒhkk3÷õõÉýÎ?ú¼ž¿ß+±ø9Ã`a°"Ã`Ù¸‹P?üúaд†q5éÕš—¡ác5\Z®#ý¢¶k°LêÝKúCâj:A¿ügΜi´«kÃTWW(×Ä|]cÅÛÝMÞòtdiæŸåçç9 Þ _¦žÖxñTîܾ·ççKy ¯çî=¢} }¡ëó?~ÜãõÆšâ˵¼½¶Þž‡·¾óÅdi$K§ 5r¨»½}Î|ùL„ÛçÌù{Ÿ÷/õõ‡[—Jðå5Öˆê3_Wk?òzcù^‰µÏ ƒþ àw ƒx#àw `°x#ü®a°x#ü®a°oDü® oD€ß5 V„¿!„Âh"À`„þ?݃Lw‚£Q5IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_increment_line_total_wide.png000066400000000000000000000673451174000617100266220ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ixn¬IDATxÚìkL”Ùžî'™œœLNNNΗÉ|šL&9™œ'''çËd2™˜ Î6Þ±cÝ[îr±•›xoÑn¼ÒÒ¢m‹(¢"^[¥UE¹ ˆŠwÅ»`KK+Þ¸) êæ9µÞÞÅPE‰UTAñû'Oxßw-j•?–Uïó®õ_ë¯DAAá£ø+AA!‚ ‚ BAA!‚ ‚ B1Tñÿøú«¿ú«ýÿñ?ïCÚáßg4ÒÛ!‚ ¾e‚‘qöìÙ~7ÍFçÎ ¨›l Á߉  AÄ0ˆ„„§$..Â-„ Bá½øóŸÿ¬¿ýÛ¿í¹ ûoÿí¿õÿÝßý7oÜØòw"‚À€Ax/Š‹‹{Ý„MŸ>½×ùñãǼis%Ǩ­­Õ´iÓôÿðúÏÿù?ë?ý§ÿ¤¿ÿû¿·®]½zõƒo—-[f™"óÿüÏÿl½w=²^ë¿þ×ÿj½öÿþßÿ[;wîô gcc£-Z¤ù—ÑßüÍßX¯e ÙÿøG:uÊ+7¶ÎÊÖ­[g±1í™Ü›ŒŒ §¯;˜÷×·7oÞX#]¦¾áç÷îݳÊþçÿüŸ=¯k8O:Õå4¼¡øûxó½ Äôcú0A„ ÂKÒsÃenÖ̪ùi¿æ‘Ù´i“þú¯ÿzÀº6lp{Sin`ýîÞ½{­Tge»wïþ`cpøðaý—ÿò_¼rC:2cÆ §mnž¼¿¾e“'Oî96{~Æ0 ôº©©©>ùûx뽸cŠ!Bá§x÷îõ”Ù~Ã5aÂëzPPPÏ5Snê æ&Û扵cóäþéÓ§zþü¹þõ_ÿuÀ„÷¾¯ÿïÿþï–927©®ÊÌ ­ãõÿûÿï½g3BãhºÌþÖ­[­·™¢fÞÛgŸ}6$dìØ±êèèÐÆ]¾÷y}Ûù§ú'ݸq£WË—/÷{/MMMÖëFGG÷*3h(ÿ>Þ|/ÂôCû0A„ ‹Ñ÷fÑ>MåÛo¿íuý‡~ø(2iÒ¤^uÊÊÊzÊNž<Ù«ÌÔèõÍJ]&ºººú•>}Ú*37ãŽ×yú÷l¦÷8^7Ów<ú2„±¿÷¾ÿ.Ç÷þ1ï¯o;}§Ò™p1ª¯¯ï)ëû~ÆŒ3¤o¾—aŠ!Bá‡øôÓO{Ý€ÙŸ›ŸŽ×M½1 fοcsjódÛ±ÌÔèõw 2Ç‘‚É¿0á˜xoÔÖÖæ32п˓÷7P;®^w ¹»y÷ôïã«÷‚!Bá§07±Ž¹&)Ü1çí››ÆæææAß¼ dú¾†©û±7ñž–¹{ŸCi@†êý}Ìßg09Cýoôç{!‚À€A AlÙ²eP7|}“¢=é;=ÆÝÈP–ùsd¨ÞßÇü}ÌßÄ_ÿÆáô^‚ 0 ACfý` ˆ»y÷Λ9 CYæÏ¡zó÷qµ4®/þÃé½A`@‚ ¼f_†¾7_f ÇxðàÁ€uú.­êl†¾«`™½!Ì*XFfE,Dz .øÍ€˜œÇ)@&ÇÀ¾Ê”ýßaöÚð× ñǼ¿Y¥ÌüM14aF«Ìê[f‰dówê£?Þˇôa‚  A„bõêÕ½n¼þíßþÍi½¾KåšÕ±ì1oÞ¼šŸon”Ýíb–Kê\wefi×¾Ó€|±ÈP½¿}ïò÷q—¿ã­£¯ßˇöa‚  A„‡av¢(¿Ã}÷Qø?ÿçÿô”™§ÒfS¸ÿõ¿þ—Û$ióßìåðÿøV]#³Kµ¹fžlûê&ÞÝM¦rÜiÜÔùïÿý¿[£ ö¥]ýe@ûþsCmÿû˜½BÌ߯˜cvÌ~0_}õ•ÓÝê‡êßèË÷2˜>L!‚ ‚ ‚ ‚ ‚ 0 AAA`@‚ ‚ ‚ 0 AAA`@‚ ‚ ‚ 0 AAA`@‚ ‚ ‚À€AAA`@‚ ‚ ‚À€AAA`@‚ ‚ ‚À€AA!Fj|õÕW½Î4}útŸË_íŽÁ®pE°…+lÑpàÚ÷¾‚±â‹/¾ÐÉ“'}®ø¥ÝÑ ØÂ®¶p…-\1 İ2 W®\áC¶pEp…-\l˜+„V!„B¶0 # <é@p…+l\a W A‚-\áŠ` W[r@0 žrð¤Á®°Ep…-\1 9 !„Bˆ!‰1cÆôÈY´··kéÒ¥7nœ>ùäåææö«“““£ñãÇ[ÊÎÎvÛ¦»úž–û»=F@xÒà WØ"¸Â®0"ÎbÅŠZ½zµÞ½{§®®.¥§§ëèÑ£=å………ŠW[[›¥ÄÄDëš«pWßÓr·Gs=\á [WØÂâ1#ÆxØÃ'%%õœ››sãúìaŽãââ\¶ã®¾§åþnžt ¸Â¶®°…+ċČ„õœ›ãîîîžssìXÞ7ÜÕ÷´Üßí‘‚B!„0 åË—[Ó®Œ ±OÁ;v쀿çXþ!í æõ†{{Œ€ð¤Á®°Ep…-\1 “„žššj„Lœ8Q‡Ò„ qa<ìrŒ„„kn ½sšŸ¾8ojjòi{£é¼µµCpÞ÷'|è¯ÃýÜ|΃ï/>8÷ç÷W@¾QTTd%¦”#a® &'ñ¾§åþnžt ¸Â¶®°…+# µkת¥¥Åzò_SS£©S§ª±±±ß*Q¦Ž³U¢ú¾®»úž–ûº=r@B!„ä#÷q¶ˆñ0S¯Ì¬äädÝ¿¿ßk˜½1\í“áÌØ TßÓr_·ÇO:\á [WØŽ>iÒ$—€ø9Œq äöØ„õ¾\á [WØŽRâ,0 Äh6 <å€-\\a W[ ‚B!„0 ‚[¸ÂÁ®°EîuyÏ až'láŠà [¸"Ø¡ÊËu#'Gm3gêuT„À€ð”¶pEp…-\l½¯ÊâbÝ[¿^o¦MSk\œ®oÛf™VÁ"0 !„BÈk:}오¥émHˆžÎ›§Kûöõ”íÙsYS§¾Ó™3ݽîùîÞ•fÌx‹!A°…+\á[¸"Ø~˜Îýø£-Y¢wS§ê×ÔTÕ9b]//?©œœš9³MQQ¯•šú«"#»tî\‡u¿wûöŸýΪƒ!ÈA°…+\á[¸"ØlÎvïÖó9sÔªŸÓÓU]Td]/.®Ôúõ÷4mÚÅŵjÛ¶ë–1eÛ·×jÆŒvM™Ò­˜˜×>7‚ž !¸Â¶®°Aª0‰åÙÙjŸ1CÑѺ“™©ÊÒR«ìرÓJK{ ·š7ï©öí»4,¹b@r@B!„†¹ªLbùºuz¡Ö„Õnßn%–›²<§%KY9fšÕ‘#5Ãúß2" Ș1czä,ššš4þ|Y2Ç=êU'''GãÇ·”ms‘îÂ]}OËýÝ# {¶®ìÚåX~Q þ–X¾rå/*,< ³Ñn@ÆŒÓ#wåvM˜0¡Wœœ?ÞR¶Íéº wõ=-÷w{Œ€ð Á®°Ep lÏ9¢Æ¥K­ÄòÇ‹ë|~¾u½¼ü¤rsk•˜Ø¢ˆˆN­[WЉ匀x`D>$ª««{Ý„*>>^mmm–­k®Â]}OËýÝ9 Ì¡Ep…+l\íÅ}ûôtÁ+±¼aÕ*>zô/‰å•Ê̼­èèÛýÏKÛ=ãÍ›XNÈ02 ÑÑÑjnnî977çÆõÙÃÇÅŹü}wõ=-÷w{Œ€ð Á®°Ep H¶&±|Û6µ&$èMd¤î}÷ªJJ¬²¢¢SJOÿ-±|öìÚµë \1 Þ1 555ÊÈÈèu-((HÝÝÝ=çæØ\sîê{ZîïöÈA!„P É$–ßÙ°AQQjŸ1C7¶lQ…ÍŒ˜²#GÎjéÒF+±|ñâÇÊÏ?3 ˆw ˆ¹‘nhhpû{cÇŽT;Žõ=-÷w{Œ€ð¤Á®°Ep ¶ÕEEúyõju…„èùœ9º¼{wOÙ¾}µ`ÁS+±|Õª=z®ïvñâŃaM# ¦Øå ÖÜ@{ç4?}qÞÔÔäÓöFÓykk+<†à¼ïOøÐ_‡û¹ùœ…ß_öyp«¼\¿¦¦ê}p°^¦§ëÖ_¦Y]¾|E……O”œüJ‘‘o”ݨ»wàëç﯀6 &ïáÖ­[”ca® &'ñ¾§åþnžt ¸Â¶®#‘í¥½{õlþ|½ у´4>v¬'±|Æ;ŠŠêÐŒíÚ²å†ÊË+àÉÈÐÚÚZ—‰×öU¢ZZZœ®Õ÷uÝÕ÷´Ü×í‘‚B¡á,MšäR&±üúÖ­j³Ý뼎ŒÔÝõëUY\ü—Äòj­^ý³BBº4gÎsíÞ}žä€xWû˜›îóçÏ»| ³,¯«}2œ½Þ@õ=-÷u{Œ€ð¤Á®°EpöÄYØ®¿ŽŠRÛÌ™ºa3!'ÿ’X~øpRSÕÔ©ï´dÉ#ýøã9822²bܸqÝû€°Ž:‚+\a‹à:R Èå½{{êíÝ{Ióç?SHÈ[¥¥=бcìX>ú,„`„'®p…-‚ëˆ1 fÇò­[¯+>¾M‘‘¯µ~ý]W‚B!4xU;6 ‰Šz­™3Ûl&ä†eF`Fá O:àŠà [¸¢Á¢"ý²r¥Þh@öî%±œÂZæzÂÁ¶p…ÃGê”Íx4¬Ze_¿þZg~úiàU°`Fá O:à ¸Â®p´ñ8~ÜÚ»ÃG¶û3Öu³‡GRÒŸuýzï{•»w¥ØØ7°c„À€ „B Âxœ8¡Ÿ¿ùÆ2—,ÑÙ¿“Ï‘•uKo´re‡í^D=&ä7óñgåäÜ€!9 „'H<é€+à [W÷ª2Æ#=ÝÚµüqJŠÎ>ÜS–›{MÓ§¿R\\«öì¹d];|¸Qóæuë”íú{åå݃## „9´ÌõDp…+l\ÝâbÝÿö[Ëx4-Z¤ã±oßE%&¶(&¦CÛ¶Õ– „'H<é@p…+l\?Òx””¨~ͽ Õ“/¿TÍ¡C=e‡ÕhÁ‚§ ïTfæm•—WÀ– „„B ^•ÅŪËÈP—Íx<]¸Pç~ü±§ÌìTþõ׿*8ø­Ö¬¹¯’6$‚a„'®p…-‚ëÇÒRÕ­[§®°0=?_çóó{ÊNœ¨Ò7ß<°ŒÇŠUTt ¶Œ€Œ,2f̘¹Šû÷ï+99YAAAš4i’­£õ*ÏÉÉÑøñã-egg»mÓ]}OËýÝ9 ÌõDp…+l\?ÖxÜûî;Ëx<3ÆãÀž²²² }÷Ý=…†v)%¥Ig`KŸÙ# ® HCCƒ¦L™¢ššuww«¥¥ÅÖù¿ë)/,,T||¼ÚÚÚ,%&&Z×\…»úž–û»=F@xÒà WØ"¸V6ãqwýzu†‡ëÙܹºà`<Ì’ºÙÙ7ùZ³g¿ÐÁƒçaKŸ l²jÕª~#ŽanÎ t{˜ã¸¸¸®ïi¹¿Û#!„Bl<ÊÊtwÃËx<Ÿ3G÷ïïU¾sçUÛ}D»fÎl×®]˜4J È„ tøðaMœ8QãÆ³þ‘ííí=åfZ–±‡96×\…»úž–û»=F@xÒà WØ"¸~ˆñ¸“™©7z1{¶.þðC¯òýû/(9¹YQQ¯½ºa }–a@ÌõÕ«WëÝ»wêêêRzzº–.]:àï;vPí8Ö÷´ÜŸí™`—c$$$XsíÓüôÅySS“OÛMç­­­ð‚ó¾?áCîçæs| ê¼¾^¿äæêMd¤ÚçÍÓãÊÊ^å—.5Úî#šÖe3U_Ïçß_Ÿ¤1Oûñ°‡1"f$„F@xҸ¶°…ëŽx”—ëVV–^ÛŒGsR’.ïÝÛ«¼¨¨ZË–5Z+[¥§ÿ¬’’*ØÒgGïˆIºîk@oÀåH˜kƒÉÉp¬ïi¹¿Û#!„B=2Æcóf½ŽŠR‹ížêòîݽʋ‹+m†ã¾e<–.mÔ±cÕ0C“€n¦]bd¦c­X±¢ß*Qfu,g«Dõ}]wõ=-÷u{Œ€ð¤Á®°EpufùÄšz•ššÚ+ Ý„ÙÃÕ>Î^o úž–ûº=öa½oW¸ÂÁÕÑxÜØ²E11j‹×Õ;ûÕÉɹ®¨¨%%5[Éæ°¥ÏŽÚ¡ Ç|‘@lžt ¸Â¶®–ñغU¯Œñ˜9SWwìèWg÷îËš9³Ív_ðR;v\…-}BžA!„ÐÐëú¶mz«ö3t-7·_y~þyÍ™ó\‘‘o´yóMkcA¸! Á‚-\áŠ` ×A©vûv½´}Ç™ã¾å?ýtF))Ò¥uëî©´´¶ôY Ø„yž°…+‚+láê}™Q3ÚaF=ÌèGßòãÇOiÅŠ_¬•­ÒÒèĉ*ØÒg1 # ¶p…+‚-\i<òò¬üŽWÆxääXyŽå¥¥•ÊȨWHÈ[}ýõ#ž†-}B‚B¡ÁɬdÕg%˜›®ú“Ó±qãm…‡wjþüg:tèÜ„`Á®pE°…ë ßÇ®]j·öò0{zô5FÛ·×*&æ•Zµoß%ØÒg1 9 |(À®®°…ëàdv+oIH°v/¿¹i“Sãă1Æ|äæÖ–>‹!0 <å€-\\a ×A={Ô’”¤×Ó¦éVV–*œ3½ÊL³ŠˆèTVÖí·¤.}– !„B~Ö¥½{Õmo4·¶¶ÂcÎûþ„ýu¸Ÿ›ÏYx ¿ï¯Û6£ñtáB½ Wsn®®]¸à´~yùM-_þJoµaÃ]ºt•ÏÎGÜ÷WÀV26# Œ€ð¤p…+la;œ¸ž;tHO¾üR]!!ª_³F•ÅÅNë=Z­ÔÔFke«ôôû*.®„-bd$g9æÚ`r2ë{ZîïöÈA!„|«›ñhZ´HoCCußf<ª\’’*­^ý³e<–-{¨¢¢jø!r@†£Yµj•­ãgÏž)%%EýV‰jiiqºJTß×uWßÓr_·ÇO:\á [ä®5GލÉv_ò6$D÷ÓÓUuâ„ÓzeeZ¿þ®Âº´hÑœ…-bd¸ìâlŸªª*EFFZ×?ûì3+ÿ£«««W³7†«}2œ›ê{ZîëöØ„õ¾\á [ä[®g ôxñb½ ÖÏ«W»4F[¶ÜPTÔkÍšõB\€-}6าº“7n\@·ÇO:\á [ä®glÆãÑ’%–ñxðÍ7:uü¸ËרµëŠfÌh·}·kçΫp¥Ï22š Èh r@B¡ÁI“&¹Ô™Ÿ~Ò¯¶ïVc<ÒÒ4œ×ìÙ/ùZÙÙ7¬á‹ÈÁ€`@xÊÁ“W¸Âõ7 ÎÂvÝ2+Wªº¨ÈåŽE‹šÚ¥õëïYyp¥Ï2‚Á€0Ï“¹ž®p…-´©>vÌåïÒòå­•­V¯~ ââ*xÒgÉÁ€`@áI‚+\a‹>Þ€8«_RR©5kî[Æ#5õW;vŽôYF@0 r@B!÷ª(+û`R^^¡ÌÌ; ïÔ‚Ouøp 9 ‚žt ¸Â¶èT^®[¶èudämÛ®+:ºC‰‰-úᇋð£ÏÂBÂ\OW¸Â}à ÛîÝjŸ9Sí3fèÊ®]®‚µwïeÅŵjúôWÚ±ãüè³pÅ€Œ€ð¤Á®°E¦sùùz>gŽÞDFêfv¶5 b®oß^«ÈÈN]¾üÖúî¼{WЉù³’’ÚñF›6ÝbI]ú,\1 9 !„Їétaáo›††ªnÝ:U”–ö*7›ž;×ÑëûÓ˜éÓÿ¬ÒÒJ"„!áIà W[÷ª:qBÒÒ¬½<~Y¹R§lçÎêMúÎéwêÿ(8Ògáhd̘1=r‰‰‰Nëåäähüøñ–²³³Ý¾Ž»úž–û»=r@˜ë‰à Wز²U™î®_¯®ÐP5¥¤X»™»ª»ÿ…†¾³ÝÄ©ßH|üŸáIŸ…k Ž€¸3 %%%Š‹‹ëW¯°°Ðö᯶¶6KƤ˜k®Â]}OËýÝ# <é@p…+lG»nlݪ×QQz1k–Î8à²ÞÎW5kV³µ¤îâÅý^ׯÿ‡ù°}}ÚÌÉC˜Ògá: Èëׯ5uêT=zô¨_=ss~Åá‘…96FÅU¸«ïi¹¿Û#!„ÐhÕå={Ô6s¦^Ú¾÷®îÜé´ŽI$Ïɹaå|ÄÄt(+ë¶ÊÊ*zÑßhÊ”nÛwí{íÙó3\­$33StZ/((HÝÝÝ=çæØ\sîê{ZîïöáI‚+\a;êV¶úñG=›;Wo""tsÓ¦ž•­eÉ7l¸£iÓ^+>¾MÛ¶Õº\Õ ®ôY¸ŽrR__¯3f¸¬çì÷ÆŽ;¨vë{ZîÏöL°Ë1¬¹öÎi~ú⼩©É§í¦óÖÖVx Áyߟð¡¿÷só9;šÿý×ORû·ßêYÙ*#CW/\èWÿöí_”™ùHaa]Z¸°Íf:óýÅçß_^<HbÌGcc£ËzŒ€0“W¸Âv”­lU\¬«Wÿ¶²Õòå:uüx¿:……§µbÅ/ ~«””&å矇+}®Œ€|˜q\%ËÙŠYÎr$̵Áäd8Ö÷´Üßí‘‚B( W¶Ú°A]aajúòK-(èWçСsZ²ä±Íx¼Ó²eõÓOg`‡äãVÁrUϾJTKK‹ÓU¢[ßÓr_·ÇO:\á ÛÑ ëÛ¶©#*JÍIIº°¿ò}û.iÞ¼g }«ôôŸUTt ®ôY¸b@ôÁ#ƒ5*fo Wûd ¶¾§å¾n}@XïÁ®° d]Ú»W­qqz«kyyýÊss¯)!¡Eo´~ý=•”T•> W ˆcܸqÝ# <é@p…+lQ5‡éÙüùꌈЭ¬¬^+[™es7o¾©éÓ_)6ö¥u\^^Wú,\1 Äh7 !„Ð`U}ô¨~MMÕÛÕ¯Y£ÊÒÒž²ââJk”ÃŒv$&¶hÇŽk0CˆÂSØÂÁ¶ƒWeq±~NO·V¶z¸l™Nõ”™|ŽÕ«¶ò;æÏ¦}û.•>‹!0 Ìó„-\\aû+[•—ëNf¦µ²Õ“… uöÈ‘ž²‚‚3Z¶¬ÑZÑjÉ’G:t¨®ôYDá)láŠà ÛSíöíꈎVKb¢.:¬leöìX´¨ÉÚÃcåÊ_¬==àJŸE£xÄÕ¾}õ»ßý'@B!ÔO÷íSkB‚^ÅÄèZnnÏõÝ»/köìçÖ®åkÖÔëĉSðBˆYÆÂQ® ÈØ±cqŒ€ð¶pEp…í¬lu䈞.X ÎðpÝÞ¸ÑZÙª¼ü¤¶m»®¸¸6EE½Ö† wTZZ Wú,bÄyõl’gææfëZ¹íC… „ØÂÁ¶Õ¶û…Æ¥K­óûß~«Ê’k)ݬ¬ÛŠŽîÐŒíÊɹa™¸Òg9 ƧŸ~ªwïÞõ»n®ýáÀ 0‡láŠà:ŠÙ£a ‡1Æ€#R\\¥µkëÞ©ääfíÜy®ôYÄÈàòA\r@0 !„F©ÊË­)Vfª•™re¦^=Z­´´+±|áÂ'Ú¿ÿœ"dð1aÂÅÅÅYÓ®º»»-=þ\3fÌÐ'Ÿ|‚`„ÿ˜°…+‚ë(ck’ÊMryKB‚•l~øðY}ýõ¯ÖRº©©¿Zçp¥Ï"F@<Êq•„^VV6èUµœÅ¥K—”˜˜¨qãÆé÷¿ÿ½V¬Xa™ÇÈÉÉÑøñã-egg»mÓ]}OËýÝ9 ÌõDp…+l}¾²Õ?XËévØÌ‡Y^׌p,\øÔñHK{ cǪáŠ`Kˆwö1ŽkÒ¤I–A02Çׯ_ÿ¨é\ÎbΜ9:þ¼Þ¿o°ìß¿_±±±=å………VÒ{[[›%cVÌ5Wᮾ§åþnžt ¸Â¶¾”Ù8Ðl Øfm(¸+ïŠfÍj¶r¾MÛ¶Õ›¥té³°…k€³ÚÕĉ½²º;b]³¼occ〿7Ð&ˆîê{ZîÏöL°Ë1¬¹öÎi~ú⼩©É§í¦óÖÖVx Áyߟð¡¿÷só9ë³öÊËõK^žÞM›¦ këòs «%K^« à^@ñåû‹Ï¾¿>üÜçdòäɽ ‡£»ú‡Ž€ìÝ»×Ze‹F@xҸ¶¾a{Íf<^MŸ®æ™‰Ê]Te%–§¤4)?ÿ<\lñ­1FÃ[;ž&ÄÑÜ8Ë‘0ד“áXßÓr·GB!oéÂþýjNJÒËi±Ú3븵”î²eõÓOgàƒòì(ÇÇŒŒ =zôÈ:îèè°–¡u¼·¯ÕÒÒât•¨¾¯ë®¾§å¾nžt ¸Â¶^_Ùª @O-Ò›påOÏWD襧ÿ¬¢¢SpE°…« ˆYr×Ü{j<úÊ1ªªªi]7›¦¥¥Y7ãŽaL‰«}2œ›ê{ZîëöØ„õ¾\á [oéÔñãz¸b…:ÿªc;4=¢Uë×ßSII%\lá:< ˆÙŸ#44´Ÿ!Ná¸do ¶ÇO:\á [o¬lU—±Voþ¦ÊàLÍùU›7ßTyy\lá:¼ ˆ«]Ð?f,"ð B¡a®òr]ߘ­öàh]š²R+fÞÒŽ×à‚ÞIè®äÍü‚[¸Ây—íù­{ô$,Q÷þßBmL¬Ñ¾}aJŸ…-\‡¿!0 Ìód-\\GÛŠGT±H?ÓÞ¤c:t¨–ôYØÂB0‚` W¸"ï²=¶³L—§¥«õó(ŸµGG NÁ> [¸ŽLR[[«Ï?ÿÜšredŽÍ5‚BÈÿ:{FåÓ²õòóMÚ¨²Â2¸ „F®¹pá‚Ë$tL„§°…+‚«Ø–—ŸTnÎUåGPûÿ‹Ôø4U93ú,lá:ò ˆí˜3gŽš››{®™ã¤¤$k‚>` WWïk×®ÛJN~«à`).î­¶m»e]/+«PÖÆ[Ê+ÕóÉÓÕðÅ—ªÉÿfôYØÂ5p ˆ™rõîÝ»~×ß¿?,öÃÀ€0“W¸šdð¹PZÈe=üÓl=NÐåÝ»áEŸ…-\Ó€tuuõ»nL ‚Bhˆ ˆ³°]¥[¶À !¸dòäÉŠ‹‹ÓóçÏÕÝÝmÉÇÆÆZÓ³F@ø [¸"¸ú΀T”‘`NŸ…-\Ü€˜DsWIèwîÜù ×pügqéÒ%+§ÄŒ¨üþ÷¿WZZšZZZzÕÉÉÉÑøñã-egg»mÓ]}OËýÝ9 ÌõDp…k`êØ±ê Œè³°…kÀÆh˜ÑcŒÌñ‡š¾FÄYÌŸ?ßZmËŒ®˜é^6l° ‰= ¯¶¶6K‰‰‰Ö5Wᮾ§åþnžt ¸Â5ðTTT­•+Ñ´à—ú,lÑèñf¸2 }Ó{bssn ÛÛia®Â]}OËýÝ9 !HÆã”V­jPxðkß«ÎÐp Bhtç€øÃ€ÔÔÔô ²L‰£A1×\…»úž–û»=F@xÒà ב¯ãÇO)-íB‚»”ŸxXáÓôböl]8xpÀU°`GŸ…-\Þ€TVVjÅŠý®›<êêj¯û÷ï+,,LMMMþžãɇ´ãXßÓr¶g:€]Ž‘`Í ´wNóÓçæïäËöFÓykk+<†à¼ïOøÐ_}}^SS«Í›[òN»gЫ˜êœ;W÷ œÖ7Ÿ³ðãû‹ÏÎýùýåsòé§Ÿª½½½ßusmâĉ^5 W¯^ÕÔ©SU__?¨F@áI‚+\‡»Nœ¨RzúÏ6ãñV[“+Õ<=^/ccU›› [ú,l# j~÷»ßyíµªªª¬äö{÷î}PŽ…¹6˜œ Çúž–û»=r@Bh䨸¸Jß~{ß2™s.èIü½ŽŒÔÍìl,/‡Bˆ¾a–…mnnîwÝìb–Ìõ†9tè&M𤆆†W™2Kó:[%ªï뺫ïi¹¯Ûc„'®py*)©Òš5õ }«Œ¹µúuö"u†…éî† ƒÚ˶ôYØ¢Q7bnlÍHÇÇ{6"4FÁÜ„»[©ÉÙ> ÎöqµÏˆc˜½1\í“áÌØ TßÓr_·Ç> ¬÷à ב4âQ©ŒŒ:›ñèRÚÜ;z°`©Þ†„¨~ÍU–”À–> [4â¸úÜ€˜\W¡££cX¬®eö& äöáI‚+\‡¿JK+µn]º”:çgÝMY­·ÁÁjXµJ§Ž‡-}¶ˆÁ„™n5yòäž§L™Òo§rbt„ÂxTê»ïîYÆcñÜFÝøze<~MMÕé£Ga„"„À€ð”ƒ'p…\½a<*´~ý]…‡wjáœÇº²"K]¡¡júòK=r¶ôYØ"F@ ó<™ë‰à WÏUVV¡ ~3óæ<ÕùÕÛõ&"BÏçÌÑùƒaKŸ…-lÉñÆÍîáÇ­ý@—Ý5S²žûL›6m²–ßu4 f¬ÁîB0‚` W¸Ž•—W(+ë–Íx¼VRR³Nl<ªæ¤$½ŽŠÒ n"HŸ…+lѨq4}w>ìNè9 ¶p…ëð7'µyó-EE½Vbb‹~ÚT¢góç«3<\w23µ‰ lé³°Eä€|DŒ;Vý ‡Y†7(('À °…+ ®ÆxdgßTtt‡ZuhK¥/^¬·¡¡ª_»V•¥¥°¥Ï"Ø2â b’Í£££ÕÜÜl÷ïßëÞ½{–1‰ŒŒÄ ‚B#ÞxlÙrC11ŠoÓþœ3z¸l™µ—ǃ´4U8'„9 ¾4 .wBokkà 0ÂLØÂH®ÆxlÝjŒÇ+͜٦=[ÏéÁêßv/o\ºTÕÃdAú,\a‹F݈݄8î„>Ø%xMËÇ”›ÈÉÉÑøñã-egg»mÓ]}OËýÝ9 ÌõDp…ëÇkÛ¶ëŠ}©3ÚµsÛ%Õ­]«®5¥¤èlAlé³¶põ·ñV d0*/,,´–ü5#.F‰‰‰Ö5Wᮾ§åþnžt ¸Âõã´}{­íóò¥¥Üm×t;3ÓJ.6w®ÎåçÖ>‹` W ÈoanÎ t{˜ã¸¸8—¯ã®¾§åþn„œrs¯Y£fÔcÛÖZÝÈÉQGT”Z’’tiß>!„Ðp2 MMMÖ”+&ýøƒe>ÿüsŸ³Ú–Ù‡Äæx ¸ÜÕ÷´Üßí1“W¸~˜òò®Yù±±¯”“s]WwìP»íó²}Æ ]Í˃-}Á®ÃÑ€ÄÆÆêþýûÖqjjj¯|¤¤$Ÿg×Í*\ƒyÇúž–û³=ÓìrŒ„„kn ½sšŸ¾87Õ—í¦óÖÖVx Áyߟð ÌþZ\ܤÄÄWV‚ùž=ô¨¢R/gÏVGt´~Þ³gDñ5Ÿ³ô7¾¿ø<àÜŸß_>7 æI|WW—u WØ¢Q7bnló>’““­ëf>˜Ù!}°û€8ÛïÃ]¹ ³7†«}2[ßÓr_·Ç> ¬÷à ×ÞÚ»÷’fÍj¶7Ú¸ñ¶*‹Š­]Ëñ0»˜WÁÁ¶pÉËð~öÙgÖt«I“&õ\›2eŠ•À5ÂlŽÈí1“W¸þ¦}û.*9ù…""Þ(3óŽNž(U}F†Þ††êñâÅ:óÓO°Ep…-\Á€Ã/ÈA&íßQ³g?·N}ÿý•—”ëΆ Ö&‚OçÍÓ¹„Btòé§ŸjéÒ¥Ãf”ƒ`„'®£ëþý4wîs…‡wjýú»*-9©ÙÙz¥æ¤$]üáØ"¸Â®b@Ìþf)X“ï`V¿ Ó¥K—ÔÙÙÉÝ?„yž°…+R®œ×¼yÏlß=úî»{*-­ÔµÜ\½4›Μ©+;wÂÁ¶p Ô)XÏž=ÓÖ­[­<{‚¸ÉÉÉÉÑóçÏqŒ€ð¡[¸"¯qÍÏ?¯ùóŸÚŒG—Ö­«³ŒÇ¥={Ôš Ž˜]·}ÁÁ¶pE9 fô£¶¶V¡¡¡={‚˜Íãââpä€ „ÐGëÇÏiá§¶ï—.edÔ©¤¤RçÔó9sô&"B·²²trn"ˆBä€x9L~HZZšµC:Á‚-\á:X:tN_~ùD!!]Z³¦^ÅÅ•:{ø°ž,Z¤®ÐPÝûî;UŒòMé³p…-b, WØ"r@ú‡Ùó£­­Í+Oí]ÂÂBÅÇÇ[í%&&Z×>´ÜÛ¯7ÜÛc„'®ÃÅ|DE½Umm·õ9t÷®4}z·¾þºÕ2+W6¨¨¨Úª[»}»^MŸ®¶¸8]Ù½~ôY¸Â1â:Ο?oíûÑÒÒ2dÄÜ|¨ö0ÇŽ{‹¸+÷öë ÷öÈA ÍœùR—/¿íõYdLÈ_tëØ±ßŒÇe›Ùhµ}ž½Š‰Qí¶mpC!r@7}ÊÓU°\   uww÷œ›csíC˽ýzý=F@xÒà:¤I“\êÂz1{¶ÞDFêÖæÍl"HŸ…+l# ƒKBw¥Á懸2 ή;¾¶»ro¿ÞpnÏt»#!!Ášhïœæ§/ÎÍf”¾lo4·¶¶ÂcÎûþ„ÏÇŸ[fÃùÜ]½·Æœ+á^ž›ÏYxðýÅ÷çþüþÑ2‚-\G¾JJ*µrå/ª’XÑgá [ÄÈð5 Îr ̵-÷öë ÷öÈAùK;w^Qdäk-\ød@+„"Ä£¨­­ÕçŸnM 22Çæš·WÁ2‰î­媼ïëzúzí=F@xÒàêo™etÍF‚o”›{í?r@0 ôY¸"Ø2âmrá—IèjBœýnß0{_ ´Æ@åÞ~½áÖû€°Þ7‚«?µeË ……uiéÒFW©º¨HSR0 ôY¸"ØŽ®>7 f´cΜ9jnnî¹fŽ“’’¬=B†CŒ7. Ûc„'®þÙLpΜ犉y¥}û.Y+YÝÉÌÔÛÐP=\¾|ÀU°àGŸ…+l# í„þîÝ»~×ß¿?,nÄGk‚*•—ŸÔúõw­ÍÓÓVYY…Î?_­ jŸ9Söï‡B!¦`Œ€ ØÂÕs™ ׬©·6\·®N•ÅÅjX¹RoCBt÷ûï]îéWú,\lá𤽽]K—.µVØúä“O”››Û¯NNNŽÆo);;Ûíkº«ïi¹¿Û#„¹ž®iÿþ‹š>ý¥’“_¨ à¬j·o·öôx²h‘N»ÙÓ®ôY¸"ØÂÕ¯d <o倬X±B«W¯¶vW7»®§§§ëèÑ£=å………ŠW[[›¥ÄÄDëš«pWßÓr·ÇO:\]©¸¸Òö™úP¡¡]Ú´é¦Îüô“žÍ›§×QQººs'\é³®°…ëÈ5 fÔÂ[ÄŒ|ãasœ””ÔsnnÎ t{˜c³;»«pWßÓr·GBÈ™òò®jÚ´7úòË&?Z¥ºŒ kOŸW¯V%{z „îd Õ¯ì bFB_Ûwww÷œ›ãÚvWßÓr·ÇO:\UTT­””&ED¼±™kºdöô˜>]ÍÉɪùˆ==àJŸ…+‚-\ýb@ì+]Ù—Ûí+“«pðàA¯åË—[Ó®Œ ±OÁr\a˼‡¾1Ð \îê{ZîïöÈa®'‚«]ÙÙ7­éVË–=ÔÉÂ=²}6t†…éFv6\é³®°…ëÈœ‚å‹¥vÍt®ÔÔTk$dâĉ:tè&L˜Àˆ ãa—c$$$XÓîŽÍO_œ×ÕÕù´½ÑtÞÔÔ!8·k¤ÿ{®\iÔüùmš>ý•Ž»«gè]x¸—.Uí¹sô×:7Ÿ³ðàû‹ï/Îýùý5*–á-**²ÓÊ‘0ד“áXßÓr·GB£Wåå'õÝw÷¬¥u¿ýö¾Î<¤–ÄDµÏ˜¡‹ìéB(F@*++{™{¤¥¥©ººÚ+†cíÚµjii±žü×ÔÔhêÔ©jllì·J”©ãl•¨¾S˜ÜÕ÷´Ü×í‘Â\OW£üüóš9³M -*8X­Ûç°ÙÓãÞúõ^ÝÓƒþJŸ…+‚-\ýj@>ýôSkŠ”³iSfº”·F<Ìk™)XÉÉɺÿ~¿:fo Wûd8Ë¡¨¾§å¾næz¢Ñ͵´´RiiòV™™wtu{®ÞL›¦' êta!\é³®°…k`g7ÛÞÞÄ«hr{Œ€ð¤^®»w_VTT‡æÍ{ªÒý'ôtþ|½¶™«yyp¥Ï"¸Â®i@Ìùæææ~ן?®ßÿþ÷"F·A Nœ8¥¯¿~¤ððNmßZ«ºuë¬==|ó {z „ lbnlÍHÇÇ­ £††kdÄÝfy# ¶p¼¶m»n¯¾úU5»è¥íÿwsR’j‚+}Á¶p |br=\mDØÑÑå„yž°…«÷TXxZóç?Stt‡î8£_¿þZ]aaº¹y3\é³®°…ëè1 öéV“'O¶rŒ¦L™b­ØD`@xÊ[¸z.³´®I.7Iæ&ÙüFV¶e<~MMÕ©ãÇáJŸ…\a‹F×A ª±–Õ5ËëžÈ=aMµ2S®.îÛ„B£3„À€ð”ƒ'Hpõ¾ÊÊ*¬͆‚ÖÞÒÏißXIæ÷Ö­S…Ÿ÷ô ¿Â®¶põ»™3gŽ‚‚‚úå€ —ex1 ä€0×$®ûö]Ôôé¯4{ö Ý´ÇZV÷é‚ÃfOú+láŠ` W¿yóæõ˜¾dìØ±8F@øP€-\?P%%UZ¶ì¡Âº´ëû=]¸ÐÚPðÚŽpE°…+l# Žû€\¸pÁ:¶x˜•±Ú¾8 pä€ „>@;v\SDÄ-Ny¬›ß~¯·!!jHKcO„Bä€ô ÇÐÍ~ Ÿ|ò N€þc®¨¨¨Z‹=Ñ´iotìûcj·ý_mILÔ¹„+‚-\a‹qe@ÚÚÚ¬c³oUU•u|þüy¯å€455iþüùVž‰‘9~ôèQ¯:999ÖhŒQvv¶Û×tWßÓr·Gs=Ñðçºyó-…„t)=õ®~ùj©ºBCukÓ&¸"ØÂ¶ˆ¢¸¸XiiiÖq¨íËÓ1dâĉ^1 ‘‘‘Ú¹s§Þ¿o)//OQQQ=å………Š·ŒQbb¢uÍU¸«ïi¹¿Ûc„'hxs-(8«Y³^Øþ_¾ÔÙoó¬==}ýõˆÙÓƒþ [¸"ØÂÕï«`ÙØƒÏ>ûÌùøÃþ wïÞyåu¤˜Ñ{˜›sÝæ8..Îå빫ïi¹¿Û#¡á©òò ­[Wg-­»uÅ9½H𥗱±ºÄž!„È^±xñbkÔÃä•åææZ×ìa¦e™ëŽù'æš«pWßÓr·ÇO:Ððãzðà͘Ѯ9‰Ou{ÙZkOºµkGäžôWØÂÁ®o@ž={¦É“'÷Lí2ÇÍÍÍN“ßí1ÐÀîê{ZîïöÈa®'>\KK+µjUƒBCßêÈòB½ŽŠÒ³ùóuæ§ŸàŠ` WØ"r@>6AÜû,3õÊÜ0þùç^3 ÉÉÉÖˆcHRR# .Œ‡]Ž‘`uL»;6?}q^WWçÓöFÓ¹ù¿ïŸÛå×;|¸NQQ¯õÍ— jM]©.›ù¨ÍÍ¥¿Òß¼zn>gáÁ÷Ÿœ{óûk°ç>7 ±±±ºÿ¾uœššÚ+ ÝÑ$xΞö;^s–#a® &'ñ¾§åþn„ü«ãÇOiÉ’GŠ£3_mýmO•+UY\ „Bä€xjÌ“ø®®.ëØ¬zeŒÇ­[·T__¯ßÿþ÷^1 fÅ+“÷á˜âl¬––§«DõÂ䮾§å¾næz¢áÃuëÖÖNæ›Ô¨õ‹™jMHйü|¸Ò_a W[r@†b#B3*aÎí«_ykÆÆFk4Ŭ|edŽÍ5Ç0{c¸Ú'ÃYÅ@õ=-÷u{ä€0×ùŸkaáÍûL Ñ/tgÁ7ê Ñí¬,˜Ò_a W[r@¼m@Ì ±ñxøð¡uã=aÂëº1eÃ!—ì ÄöáIò×òò“Ú°á®BBÞêðüÃê ×£%Ktª¨žôWØÂÁ–¡0 æÆÖ1ïÃ$Œ›0.,::ZÄè6 ²~üñœâã[õõujŠŸ«W±±º¼w/lB‘2ÔËðÚ7œ4iRϵ)S¦X«Œ€ð¶Æµ¬¬Béé?+"äµÎÌÙlíéQŸ‘¡Š²2Ò_a W[F@abäæyÂ6иîÛwI11¯”wZ/§ÅèÙܹ:SP;ú+láŠ`KÂO:÷¸WiéÒFŇ>Ó½„ez¡ÚmÛ`F…-\lñµ1+^Ù—ßí+o­‚E‚?•›[«Èˆ7:w@]!¡úeÅ U•”À!„ò‡1» ;G9Û@`Áv8jÏž»š=û‚ƒ¥„„÷ÊË»§£G«µpá}qGÏ¢Õ§óìéA…-\láê_bŒFyy9wüæyÂvÄJf ª™ñýo{zdfê¤í³^ôWØÂÁ®~6 Œr`@xÊÁ¤€0 ÎÂvýñâŪfOú+láŠ` ×ác@ÌÒ»mmmÜñc@ H„Bh˜óçÏ+44T---Üõc@xÊÛ§’’J ý¶®°…ëH2 ÎV¿òö*XÎ^{„ ½êääähüøñ–²³³Ý¾¦»úž–û»=r@˜ë‰Vyy…23ï(&¼B…-‚+lá:Ò’Ð]i¨òCª««{Ý„*>>Þš f”˜˜h]sîê{ZîïöáIX[·ÞPLÔKí‹>¢×¡‘ú+l\a בd@üÑÑÑjnnî977çº=Ìq\\œËßwWßÓr·GBεk×͜ٮ͑'Õ«–¤$]üá‡WÁ‚B!4Ê HMM222z] RwwwϹ96×\…»úž–û»=F@xÒzëÀ š5ë…ÒÃ/êé´DµOÿBWwì€+ý¶®°…ëH5 sæÌ±nˆ}±º¹‘nhhè—#2˜åÝÕ÷´Üßí‘Â\Oô›Ž©±6\rW Ñ õzÚ4ÝÌÎp?¸Ò_a‹à [¸s2oÞ¼³Ñ×€x;Ä8»Å‹z„a4€˜`—c$$$XÓîŽÍO_œ×ÕÕù´½ÑtÞÔÔçÕÕו‘Ñ®ÙÁ¿êVì2½ ЋݻuõÒ%·¿o<é¯#åÜ|΃ï/>8÷ç÷—Ï ˆY•éÂ… = é&ÚÛÛµpáBxÕ€˜¼‡[·n}PŽ…¹6˜œ Çúž–û»=r@ÐhÕ‰UJK{ ™ÁÏtaúZuM ÖýôtU•”À!„ ¤ex›§ôŸ|ò‰×ÌGmm­ËÄkû*Qf/g«DõÂ䮾§å¾næzŽv•–Vjݺ:Å„´ªnÜ8UUUõlPèÍsÓm^ÓU˜ey]í“á,‡b úž–ûº=r@˜ë9ZU^~RYY·Þ®#1ûÔªÇ)):SPWú+l\a ×@5 ÅÅÅJKK³ŽÍŽèŽ9 'N+gcÈí1“ŽÑ¨íÛkóRyÓŽéUè4=Ÿ;WçóóáJ…-‚+lá:š–á}ÿþ½>ûì3käãøƒÞ½{'bt„¼­½{/+>¾U™‘§Ôñ…ZããuiÏØ „B£Ñ€žrÀv¨”Ÿ^sæ<׊Ðkz5[¯bcU»};\鯰…-\a‹FÛÈPìõAŽaž'l=UAÁ¥¤4iap½îǤèMD„nee ¸—\鯰Ep…-\Ø€ ‡|‚žtžŠŠªµlÙC%N}¬ÚØUê Uݺuª(-…+ýÁ®°E£ydÒ¤IêèèàŽ‚WTRR¥ôôŸõEð þ½Þ‡èÁ7ߨêÄ ø „Bä€HgÏžUTTTÏR¼„§°ý••Uhýú»Š kWql®µ—Gcjªª…+ýÁ®°EŒ€ôÞó•ÈÁ€0϶îdöòÈξ©èÈ—:}PoBÂõäË/uöða¸Ò_lá [Dˆó$tW;v,N€>`ëRyy×4ã‹vm›V¬—aÑz‘œ¬ À•þŠ` WØ"F@ BÞÓ¾}•˜Ø¢u5z¯¶™3ue×.Ø „B䀞rð¤Ã{:tèœæÍ{ªÔjŒš«Žèh]ÏÉ+ýÁ®°EŒ€xgoæ€Ü¿_ÉÉÉ ²VÞ***êUžc»‰?~¼¥ììl·¯ç®¾§åþnæz'žÑ’%4/¸A÷b¿Vgx¸îdfªbˆöò ÏÒ_a‹à [¸ŽBÒÞÞî5ÒÐР)S¦¨¦¦FÝÝÝjiiÑwß}×S^XX¨øøxk%.£ÄÄDëš«pWßÓr·ÇO:†‹Ž?¥•+QüÔ'º›®®àÕgd¨rˆ÷ò Ï¶®°…kV¿²ËŒVx#V­ZÕoÄÃ1Ì͹ns÷Ñõ=-÷w{ä€ «¤¤RkÖÔ+6¸E§¦gYKê6¬\©SÇÃ!„"ijկìËíö•™*tðàA¯ &èðáÚ8q¢µóºùGš{£cFFìaŽ2?îê{ZîïöáI‡¿T^^¡ÌÌ;Š o×ј]ꜪG¶¾xº°®ôW8À®¶Œ€xg –/–Ú5&gõêÕz÷º”žž®¥K—ö*ÌûrWßÓr·Gs=ý¡­[o(&ê¥öEÑëÐH=?_5‡ÁÁ¶pE°%dä­‚ežöãacDÌH# ·]Ž‘`uL»;6?}q^WWçÓöFÓySSÓ°x?»v]±õ¯m‹=¥—‘_¨%)Iw±|í¢¿f Äsó9 ¾¿ø<àÜŸß_i@LÒu_âxî,GÂ\LN†c}OËýÝ9 È:pà‚fÍz¡ôð‹z:-QíÓ¿ÐÕ;`ƒB‘2ò ˆI@7Ó®Œ 12Ó±V¬XÑo•(³:–³U¢úNarWßÓr_·Gs=}©#Gj´pá-¹«†è…z=mšnfgëä0\R—> WØ"¸Â®޼¼<}òÉ'ÖÔ«ÔÔÔ^Iè&ÌÞ®öÉp–C1P}OË}Ý9 Ìõô…Ž;mû¿÷«’§6êVì2u††éîúõª(+ƒ+‚+láŠ`K;¡;†c¾H ¶ÇO:†R'NT)-íf?Ó…ékÕ55X÷ÓÓUURWWØÂÁ®‚ä•–Vjݺ:Å„´ªu‡êqJŠÎÀÁ¶pE°…+„ „¹žÞÓöíµŠy©¼iÇô*tšžÏ«óùùpEp…-\láŠ!áI‡÷ØîÝ{Yññ­ÊŒ<¥–ˆ/Ô¯K{öÀÁ¶pE°…+„ yOùùç5gÎs­½¦ÇQ³õ*6VµÛ·Ã!„B‚ä=¶g”’Ò¤…Áõº“¢7º••0{yÐgá [WØÂB‚†Û¢¢j-[öP‰S«6v•ºBBU·n*JKaJŸ…+l\a W ÁòÛ’’*¥§ÿ¬/‚_èìôïõ68D¾ùFU'NÀ’> WØ"¸Â®‚ä••Uhýú»Š kWql®µ—Gcjªª…B!„0 # È;lÍ^ÙÙ7ùR£êMH¸ž|ù¥Î> ;ú,\a‹à [¸b@r@÷Øæå]ÓŒ/ÚµmZ±^†EëEr².83ú,\a‹à [¸b@>4ÆŒÓO}#''GãÇ·”íö5ÝÕ÷´Üßí1˜ª¨¨Ð±cO5o^·‚ƒ¥¸¸·Ú¶í–U¶oßE%&¶h]DžGÆ«mæL]Ùµ nôY¸ÂÁ¶pÅ€|Œ( o»ájk³”˜˜h]ûØúž–û»=r@Wš4É¥RCn¨1j®:¢£uÝfXá…B! Èssn\Ÿ=Ìq\\ÜG×÷´Üßí1àÄYØ®w†‡ëNf¦*ØËƒ> WØ"¸Â®Ï È„ 4vìX+//¯WyPPº»»{Îͱ¹æ*ÜÕ÷´Üßí‘2: H%{yÐgá [WØÂâýxøð¡æÍ›§¬¬¬GHŒŸŠc}OËýÙžév9FBB‚Õ1íîØüôÅy]]OÛ ôó |¼sn<¼{ÞÔÔ!:7Ÿ³ðàû‹ÏÎýùý5*VÁêèè°’±!d´è‡.*>®u@'„B1â#â,GÂ\LN†c}OËýÝ9 £ÂÂÓJIiRZð%=ÀÐgáŠ` WØ"r@|«V­Rcc£uüìÙ3Û YŠ222ú­ÕÒÒât•¨¾S˜ÜÕ÷´Ü×í‘x*-­Tzú}ÍÚ {Ó–èuä4ÝØºuÀU°àFŸ…+l\a W ˆ—¢ªªJ‘‘‘ÖýgŸ}fåtuuõªcöÆpµO†³Šê{Zîëö ,åäÜP\øsŠÜ ®àÕÙÌv…“sØÒgáŠ` WØ"F@†iŒ7. Û#$0´ÿÍJx¡ýaÕ95T©©ª.*‚ B!„È!†02rtôhµ–,y¤ï¦V«5$VÏgÏÖ¹„-OæàŠ` WØ"F@ ó<½™çQ¡ŒŒz¥L½«†ðùz;]Wwî„-s“áŠ` WØ"r@ O9¼«mÛj5;âW]ÿVoB~ÛÁüä w0‡-}®¶p…-b„À€ •Ÿ^ó›T²K UêUª*.† B!„È!0 <å𞊊ª•úu£²§–êåÔijZø¥ÎÀ–'HpE°…+l# „yžÞSYY…Ö­»§S¯êqH’Zf&èâ¾}°e-\lá [Dá)‡w•›{M‹¦ÝWmÈ2u„OÓ-[`Ë$¸"ØÂ¶°e„[u ò®:§”YU{˜ccT\…»úž–û»=F@†N'NTiõòz˜²OoþªËW©êÄ Øò Á¶pE°e$Ð Hff¦gáÁ÷Ÿœûóû+ ˆ1.oÈ!d(TPpV«gßÔ…)iz¥›ÙÙ:IžB!„Pà€ÃáLåH˜kƒÉÉp¬ïi¹¿Û#Ä3•”TiíŠÛ*œ¼]¯§„ªnõðÜH9´p…+‚-\a‹Èñ¡!q¶ÊTKK‹ÓU¢[ßÓr_·Gˆ÷ò<²³n(oêOz99B _.Õé!ÜH9´p…ëÿoïn|£¸ï<Ž÷O³-[ T”)¨¤ˆBmLG”\ …Š4Wrä\r¡é¥Î)45…æ uCÈ…Sy¸rAÈ)>Óü»|§Z´¯w×;k{í×[úˆÏ,ŸùÍ|~3Ä[¾ò–ŒiÐÄ»1J½'£Úõk]>ÑûÓR»~ö³þô/Ë?H‹:ÓÀwþ>ééQÓ¡‰øÊ[¾où*€Œ–––i½?c@ƯÞÞߦ^ÿ‡ôÉÂJƒKW¥÷íã ‘‚F Sµ–ãwN¤—¿w>_ørúë¢'Óý`wúÍ{ï©é ¾ò•·ÄWÞòUA#©ØÏóÕWÎ¥žÅÒ_,M—þqGú`’^$¨-_ùJ¼å+oÉ Ó¸–ãà³iߊ_§ÿ]øíô?]ϦVÓA|å+o‰¯¼å«c@òÕ‘#§R÷Ó'Óå…ÿ>ÿVWêã§ *""""Z@òÕ»ïžH?úÞïÓ‡ v¦¡'–§ó/ÿhZ½HP _ùJ¼å+oI )Òñõý}úÕâ×Ò…O¦ ß}1xç}=‰¯|å-ñ•·|@ $_õü]:°üpZðwéÒÓ[Ó©#GÔt_ùÊ[â+où*€À|õ«_Lÿ¾þÝtmÁÚtmņtæ?zFDDDD´€ä«÷ÞûMz}ÛÉôñ‚-éæâÕ©¿ûu5ÄW¾ò–øÊ[¾ 0$ý¬ûtzÿ/§¿,üVúxÇž†{‘ >´|å+ñ–¯¼%c@¦(ýýý©««+µ´´¤Ù³g§mÛ¶¥›7o>´ÎÞ½{S[[[¦îîî²Û,·~­Ë'{Ó¹äÐÁSé—ËßHi2}ºagúàØ15ÄW¾ò–øÊ[¾ ù±~ýútæÌ™tÿþý4<<œ<˜V®\ù`yoooêììLCCC™"¬Ä¼R”[¿Ö哽¿é:äèÑRÏÓ¿L7Ú¿.­|>ýöç¿Pà21DkH¸9ÔW >wtt”üÛrë׺|²÷7ÝZ@bœÇ­ï¥‹ 6¥ëKÖ¦Ó¯p²«Aâ+_‰·|å-i™¢¤§§'mܸñÁ¼ÖÖÖl~ñ:1¯åÖ¯uùdïo:éyåDúÝ7¾ŸþoÑŠtöûÿ6­^$¨-_ùJ¼å+oÉ)NSSS¦yóæ¥k×®=4$ÍÍÍcng¬õk]>™û‹  bÖ¬Y“˜…tÿNÄô¥K—Æõ÷¿9úQ:ñí§¿.x2ýaÓÓÇgÎLÊ÷ŸÊÓü¨ÃtAüp¼6Êt”³ü˜:×/Óʃ™xýš- û÷ïO«W¯Ö2 Ç€¼}¬/Yw0 ¶¯Hÿ¹z{úà­#j5ˆˆˆˆŒ™|Š[F#óª“Q¼~­Ë'{8äøñ÷Ó/¾Û›>[ðTú拏Ò¯ÿÜ ­-_ùJ¼å+oÉÉa×®]éúõëÙç;wîd¡-¾/<%jpppÔ§DìÂTnýZ—Oôþ} È[{ÞMçŸØ’þ¼è;éÔ~ªч–¯|%Þò•·d ÈäÒ××—–-[–ÝØÏ;7íØ±#»/&BI©÷dŒ6†b¬õk]>ÑûkÔ£§SË~˜n·+~îG3îE‚jøÊWâ-_yKZ@¦)ÅìŽûk´1 ï{?½·öÇ_e©¿ãÅtâȯDDDDÆ€ ‘™Ì’æÏ/©_oîI^°:]xrszÿ§½NZ5H|å+ñ–¯¼%- @r £ñÕükO<•Þßm€¹>´|å+ñ–¯¼%c@ €L@ñ"A5H|å+ñ–¯¼åƒ @DDDDÆ€@@Ôt_ùÊ[â+où*€@!}hùÊWâ-_yKÆ€@ïS°jøÊWâ-_yË- @ˆˆˆˆˆ4~QËÁ[¾_yËWâ­DÑÏS_Oâ+_yK|å-_Rô÷÷§µkצ–––4{öì´cÇŽ488øÐ:{÷îMmmm™º»»Ën³Üúµ.ŸìýiQÓA|å+o‰¯¼å«2N6nܘΞ=›†‡‡ÓÝ»wÓîÝ»³@R ··7uvv¦¡¡¡L]]]Ù¼R”[¿Ö哽?c@ˆˆˆˆHÉ‘"ÍÍͦãæÑûÓ¢¦ƒøÊWÞ_yËWd ÑÒÒ2­÷g  @Ôrð–¯ÄWÞò•x«D@ôóÔדøÊWÞ_yËWZ@ˆ·|å+ñ–¯¼%- @ˆˆˆˆˆhQÓÁ¾ò•xËWÞ’ úyò–¯ÄWÞò•xk ˆ"€¨åPÓA|å+o‰¯¼å«c@ˆˆˆˆÈ j9Ôtð•øÊ[¾où*€Àâ-_ùJ¼å+oÉÔ™½{÷¦¶¶¶LÝÝÝZ@ˆ·|å+ñ–¯¼%- ¨½½½©³³3 eêêêÊæBDDDDÆ€ w"|Dª-Ÿ;::´€¨éà_ùJ¼å+oI ò§µµ5 ?˜ŽÏ1Ï}=ùÀW¾oùÊ[2¹ÓÔÔôÈ¼æææ’Á£ bÖ­[—ž~úé¬5eåʕٿ1ýÔSOMèþfÒô† øQ‡é‚øáxm”é(gùáú¥<0=™×/D 0e@€ÑÆ€Ä<@Aîž‚588XñS°ã&ÞýQÍ{@FR<6„ˆˆˆˆ(O ˜2T{@‚·|å+xËWÞbzû*€ÀÉÀ[𕯼_yËWÀôC €@@ÁÔ¢©©éýýýiíÚµ©¥¥%Íž=;íØ±#{? j÷5Þ¯SðuÛ¶méæÍ›ŒÉ™ðX™«¬ÍŸ+W®¤uëÖ¥ÖÖÖ4þütôèQ¦Ôá˜3gcr``` mܸ1;^CñùúõëfvƒüˆBåìÙ³ixx8ݽ{7íÞ½; $¨õë×§3gΤû÷ïgÞû,mذ!íÙ³‡9•/¼ðBºwï^ÖÕuçÎiË–-ŒÉ‘U«Ve]Ý7nÜH .|p ‹ÏS½uIÒ€œ;w.ëÒ7wÈ—¨=Ú¿ÿC7Í?ácq˜S&Ô‡;w¶6Fä@ âàQ ‚ˆ.™ùñÑGMùÚùF#˜- Åc@¦zïHƒÑ××—ÚÛÛÓÅ‹™QGŒ­É¯ ðÄ&¤‘ˆ§µ Jñ0Š .0¢Î׫©~ @ €4‡Ê ©é:_¢/rá‘…q#OféììdŒ2aÊ¥ -KÑýâÙgŸÕ§>'bzt»ŠŠîXñhnÔÎùó糂|‰'^Ÿâ1 ž‚…{“¡Æsb|åmíD«R<Æ0¼œ;w®÷« uÌ>þøãÙøâZ{ÔFta‰² º^mÞ¼Ù ôœˆÖ¥xä9ò%*# ï Åç©>ŽQ €@@ €€@ €€˜¡4Ê‹8½0À4   €ÆÅ¹¬¯¯/­^½:µ´´¤ÖÖÖ´nݺtýúõGÖ;qâD¶^¬S¼óçϧµk×fó›››ÓòåËÓñãÇù.o¾ùföw³fÍJsæÌI»víJ·oß~hcÇŽ¥… fßeÉ’%éÈ‘#|ï7n¤mÛ¶¥Ù³ggû‹mmݺ5}òÉ'~pS%„”š¡âóÏ?OÃÃÃBŠ+Y¯««+[¯˜sçÎe"BË­[·Òýû÷ÓÎ;³õ#<³ÿþÁ&ÂL¬ëøðóy6lÈ‚I(>üþñÝbº¿¿?›þòË/³ÀߦxùÓŸþô`^„B+ÅÈõ®]»öÈ6â¦?–·˜Ü»w/›·xñâ²ß+Z1 tvv>ò}®\¹òÈ÷ïº|ù²€@£róǃ] Fëæ52ÄD@Ù´iS8bþh]¢ÛU%ߧЊ¿‰._»wïN7oÞôc@˜Î¤¢åd, ¡¡¸[ÖxHŒÙ¾}{š7oÞCA&‚ LãƒÏcÙéÓ§Çü…–’Ñkäv+í‚ULŒ99uêT¶<ö“Ì׿þõì=‰ç@>ýôÓìéWßüæ7ÓgŸ}–Í‹Áão¿ýv( DëDl#ÂBŒyæ™gÙnñ ô;wîdÚ¸qã#ë­_¿>úè£l:n²^z饪·SÉz7nLgÏžÍŽÃø-vïÞÝ(Uëm©}÷·™¨c±‘ϳr¿]½Žã'Ož3P®_¿>9s&Ý¿?ûŽL+W®¬Ûöª-Wfây&€@9€ÌŸ_Z5¤Õ^ЊçÅ縸´··gÛZ¾|yº|ùrUÛ{ë­·Ò³Ï>ûм¸øGÍaÔÒEMâ_|ñÐòW^y%«¡Œ¼7ß|sÜæØ~\„ ÄçÑnœŠ[á&!ˆÏ/o´òÜsÏ¥·ß~»æíŒç¦;nŠÏJ½-µ¯ñþ6Å|ußöÕ \JK–¤ôÔS)ýö·ùJæ•;'¦ÂyVê·«wY±bEÖš[ ñ®×öª-Wfây&€@=€T3qaسgOúüóÏÇ@âÆ%jºâBvàÀ1kGÛ^ÔÐÆ N×^{-k…‰mF cÔ$×¾úê«iÆ Ùò¨aŒ›¤¼Hl¯µµµävbYü?‹/ÞÅë—[>V—’ñ|ÿ¼·7’ø]“ɸ1Š.)Å7må¼-·¯Jÿ~¬ð±jUJŸ|ò·é?þñoÓÕ†ñrçÄT9ÏJývõ ±¯]»vUüwñ»÷ôôd-õÚ^µåÊL<Ï À  Ñ÷7.¶=ö؃ZБ}£Ëâ m©šÏr­â¿™ÿÕw/DqãTÜ;º* är#³uëÖ¬{Dü ]%ªýþÅëgùT •l§’¾çÕÞ]¹r%-]ºô¡ß¹œ·ãñ¤\ `1qY"„tuÕ?€”;'¦ÊyVê·«gYõU ¼zõjÅÇ@(º£]»v­nÛË£\™îç™h¤RiW«qtÉŠî1dõêÕUj.‚£-‹ý×ÌÆ:† ŠéY³fû";ÖßÄ`Ñ„û‰vèС1oìjm©å$Ï·©Ürîܹ´xñâGºòMt ÈÈÓç‰'F_oÁ‚êNµñrçÄT9ÏJývõ:Ž£{Ot_ª†øÝ÷ïßÿP9—÷öª-Wfây&€@)€Œv—TÍü (®­Š’â‹IÜÄä@¢ozñE?jfG>•¥˜<[@FrôèÑli)Fëßó*]Þh$Æ Ldßô¾¾¾l<Ñhƒ¥+õ¶š¾é•ü6êÙRî<+wNL…ól¬ß®^Çqt!ܵ–sõÚ^¥åÊL<Ï À  qáûä«»ª¸ù‰~àñ¸ÈH^ cFÿæX7+ÑE+¯RêéÏÊývõ qL–zˆÀÈ¿‹n¦×¯_Ï>ß¹s'|?ò¦8ÏíU[®ÌÄóL4z©á)XqqŒ‹EÔÀF3y J-îÍóHbyÔ˜ÅL­¤ xúNÜhÖ]#nŽ.\˜í7žüøñ‡–ÇÀùxÆ|¹§ó”ë75“…ñ/ëÖ­ËúD—#n6ÆzÆýXËGî¿Ü÷«dyžÛ+uŒÄo¿E¼Ÿàرccno¼}Ó+ÙV9oË}r¿]%!$ZB¢;V´|äõ¬rçY%çÄT;ÏF–Õw•¬7¶ñ(ÜJ<ŽÿøÿüíÝyno<åÊL;Ï @#\×PPàºPPຠ€‚ຠ€‚×5@‚×5@êVPM'Œƒÿ—´‡Ž‰"gûIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_increment_line_wide.png000066400000000000000000000544001174000617100254030ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxXÇIDATxÚí}l”åžþO²Ùl6›_6ûÏfÿÚlN²Ùì›ÍfÿÙl6bÚ´[B Ö«ô ¥oV¤©àž¢X‹"Åïd^_èq¾ýö[WéÒãå_°ºººÜ¾ý×^ù\ZZq^2Þ?_K4O§òF!Bù¤›nºiü„K'k:QÕ¿Þ}eee mÛ¶Ù_üÅ_D}lcccÌ“JÀ†û¿»wïv'¨áö=÷Üsqƒ}ûöÙßüÍßørB:™RQQöXò-‘׺¯¸¸xü¶ÞOòO!Úó®[·.%ï_¯%–§„!„Ò¤ÑÑQw•Ù;áš={¶»?//oü>í×ã&s’íIW¬ƒ£+÷_ýµõ÷÷ÛÿüÏÿDmx}þÿû¿ÿsáH'©‘öé„6øþÿüÏÿŒë5«Bºt¢¿}ûv÷skˆš^Û‚ ’@rrrìÒ¥KöøãG|íSy}¡Çù—ùûè£&<æý÷ß¿æµôõõ¹ç]ºté„} @É|ü|-ñxïg!„ !ä£BO½a*>øà„û_|ñÅ) yóÍ7Ç÷½õÖ[öé±Ñž_3uI###×ì{çwÜ>Œ߯ðÏkÖðžàû5|'¡?“ Þký¹‚_ûT^_èqB‡ÒIÁUÑÝÝ=¾/ôõÌš5+©ïŸ¯%O !B¥AsçÎpæ]!׿Á÷ëqS óü€zÒ•íà}zl´çþ¿ÑöW âé¿‚ïÅÐÐPÊH´Ÿ+‘×í8‘ž7±NÞ}RõZ !B¥I:‰ îÍPSx°‚Çíë¤q```Ò'oÑÂ@èsè±S=‰Ot_¬×™Ì’¬×7•÷g2=ÉþÓùZBˆ‚BIÐSO=5©¾Ð¦èD+ ¡ÃcbU@’¹/d½¾©¼?zOÒõ3N§×‚B„J‚4Ž~2$Ö¸ûpò³$™ûÒÙ’¬×7•÷'ÒÔ¸©ø§ÓkA!Bù,­Ëzò¥5&‚õùçŸG}LèÔªáÖhKkCh,¡±‚÷µ··§-€¨ç%xz ¼Y¦¼ŸCkm¤ë„x*¯o*³”é=U0”T­Òì[š"Yï[²Æt¼–x>Ã!DA!´iÓ¦ '^ÿû¿ÿöq¡Såjv,O«V­Šk|¾N”c­¢éR“}‚kŸ¦v ”Šu@’õúâ}íñ¼?±úwüúSýZâý #„!„”V¢ŽÖßá)t…ÿøÿß§«ÒZîßþíßb6Ië ¾ÖrøéOê+´JµîÓ•íTÄÇ:ÉTe(x¥q=æïþîï\uÁ›Ú5]d²¯o2'ÔÞû£µBôÞ((ìh=˜»ï¾;ìjõÉúSùZ&óF!B!„Bˆ‚!„B!B!„Bˆ‚B!„B„B!„!„B!„ !„B!B!„Bˆ‚B!„B„B!„!„B!„ !„B!B!„Bˆ‚¦«î¾ûî ÛÕÕÕ¶lÙ²”“®ãf ø‹·ø x‹¿x ÓÝßÐóRH–åË—Û[o½•r>ÿüó´7[À_¼Å_À[üÅ[˜îþ@ )åƒ>à—ñðoñð6‹ý%€@ ˆ à/Þâ/à-þâ-P!€@ÏÉxN¼üÅ[À_¼Å_¢ø‹·ø x‹¿x T@’¢ŽŽ«­­µÜÜ\+((°††œð˜žž«««³¼¼<+,,´D}ÎææfËÏÏw455ù¾?Ýǣ虢êëë­½½ÝÆÆÆlddÄ] ñÔÛÛk%%%ÖÖÖæ£p²eË–ˆÏ×ÒÒbUUU644䨩©q÷ùµ?ÝÇ£ÂÕ À[üÅ[À_¼* >J!#''g|{ãÆ1+ÁÒɼÞOº]YYéÛþtÆsÞâ/Þþâ-Ðâ£T鮀̞=ÛöíÛgóçÏwôôCGüÿ¦¥htŸ_ûÓ}<* \ͼÅ_¼üÅ[ â“ÔëQVVf}}}ã÷Íš5Ë6mÚd£££nˆÖæÍ›mýúõŸCUpE%Ñýé>= @ˆêìì´ÒÒRëî àáIAD•l¬€è öVuuµ+½yéWÿ¦bûôéÓ)=^¶mãoò¶u‘?ð7·õ½€ø›‰Ûø1óüÍØÒÚÚjEEEÖÕÕuÍ>5e‡h \O…îókºGã9oñoñèI@{÷îuSëj¶«pRº†])„ ÇÚ°aCÄ!LÞ¬Rš-+Ú¬SSÝŸêãÑÂxNÀ[ü¼Å_¼z@|”Nèì;wÚœ9sÜЫuëÖMhB×C¡µ4¢­«‘ÈþT d)Z?ÈL8Þt VX~ ¹Z„·€¿x‹¿€·T@f|ÉF¥=€„„ñ²x ø‹·ø xK„Bájà-þâ-à/Þâ/ÍÈráöÛíÜ]wYïÆvú‘GìÔ¶möáŽö‡_´÷öï·ÖC‡ø’ˆƒ^8m+W^µoÔ,i£¶sg¾= ˆ@¶”¾cÏÜxÀ^¹ñE;Tú”µ•>dÝpõ.\i*.·‘¢l´¨Ä.–,µs¥µÖµh}¸x£µ•?foUn·×jwÛÞU¿±ÝkÞ°÷¾kOnê´_>ú©ýò—ŸÙÖ­ŸØ¶m§¬©é#Û¾ý¤íØqž}¶Ó~õ«ìùç;ìÅÿ`/¿|Ü~ýëßÛo~Óf¿ýí»öÚkïØÁƒoÛáíöƿˈ_âçŸÿ,ð~š<ùƒ­Ÿ}f¶lÙ˜=ýô)¾ä¸‡¿€·ø‹·@@‚ˆNøuâ¿oß{.((ìÞÝaÏ=÷íÜÙi»ž~ß^Øú޽òàak¹ÿ·vøî­uõû}ÝVû°r³}zË:ûâç«ìÂM•öMÉÏìû¢ëíÛ⛬ÿ† ûâ¦ÛíTÙ:;þó‡ìÈÍM¶Én{ni‹m[zÔ6-ýÀÖÞòG«^Òo‹_¶ŸýìŠÝtÓˆ•–ŽZIÉU+.³¢"³ë¯sۺѢïÜãn¾ù[[ºôRàDÿ«¨¶ÊÊ!«®´[o°Ûnë·U«.Ø/~ñµÝqGŸ­]ûUÀÿ/mýú³vß}_ØÆ½¶iÓçöàƒ=öÈ#ݶeKWBéÖ[¿ž~!Wø‚e,ò´ç™gNXMͷ߯±À÷Ò·ÖÜü¾ðÙÅ_À[z@  ›ëÈ{ûàAkÛ»×:žÞN<ý´}²u«u?ô}qß}Ö·fõßv› ­XaßÞ|³]½á+.¶‘²2û¦¼Ükkíë_ü¾\·Î>ß´É>Ûò˜ØÖlÇ·?ooÿê7vø¥Ã¶ÿ×Ç"&‰'Ÿi{öwU¾p¹7xöÙ¬¼üû Õ»[n¹J᳋¿€·T@ ®rÖÖ^±… Õ£ð}àäý«iõKø»7Þ°wZZìøË/[ç®]öQS“}öØc.€(ˆ|½zµ &ß,[悊‹‚‹Ìp Èü)hlÎlØà‚ŽÏÉ@ðQRzûÀŒRðî½÷ŒÝ~{à¤î+)ùÞÊÊFþ_´5kúlóæ?BÒÇö °Žñe )Gß áªwååßâ= W3Bi}ýukûÍo¬ã…ìÄŽöÉOX÷#Ø÷ßo_­]ký·ßnCUUvyÉ--µ±ë¯·ï-²K·ÜbƒÕÕöõªUöeà}ù¼¡Áº}Ô>~òIë|öYké%{÷·¿µ£‡û:ËØ‘#oYKË»öÜsﻪŒ*0ª¶,_>솗 ÝÖÐ1íÓcTÕÑÿÑÿåJW⦊>?¯¾úŽ«67Ÿ´Gí² ÎØ7ŽE¨Þ™ÝsÏ—.$ës¸s燮ŠwàÀÛøÉgñ¨€ ã9㮲¼ù¦½óÚkvü•Wìƒ_ýÊ>jn¶Ïí›7ÛÙõëíüwØÀ­·ÚŸïÍ•Ÿý̾/.¶ï.´oþsÜ÷§º:ë <æÌ½÷ZσÚ§ÿ{2ð~Ms¬“; ª*¢¿5k¾rÕUMT=¹å–K®š¢ªÊc}fÏ>û¡íÛ×fo¾ù»¬xÿ‹ý³³gO»«tªŸIöÎ;Ï[uõE[¼ø[+.þÞõO)àÞ~û7ìPÃW¬ß¿tóÍß¹ÏXCC¯ûj(¢ªx Éz.õ`鳩­ÏãßvŸ[…k}&>ÊûÂgñèA®fL©Êrø°›ŽXÓøì³nšâÓ>ê¦-ÖôÅV­Š@ÔóÒµe‹ö‡—^²c4•×qèÐQwZý$:ÙSÏŠîu"¨Bdj[÷ÏÔ¾“lýì:Ôêú4!ÂÖ­ŸÚ|î&V¨­°%K.ÙÂ…ß»` þ$õ-é3 >'M¨  4aÂo843´déÒѨ= zN… …}ï»ïŒ # <úL*0ë5)´ès©£P¤P£Ï¦‚ö•½ßq•ðoñ—‚fzÔÎ2¦~”³ëÖ¹á`ª¬|wãö}I‰¦ž–¯Ö¬qCÀ>ݺÕ>ܹÓ~ÿÊ+“^{E]uÖ0àÑw’9(è½SPxâ‰S÷§Çî¹ç\ Hü) ¾ŸNèD^ÁC3¸iÆ6”é8A…ª2¯¼rÜ}.5ŒKŸ= ëÒgS:ès©‰ô¯¶u?þ ˆ øØâ¡Þ5Æ«Ùþ“Ç·?>ð€}u×]6PWg—–.µ«€¢ž5Ük¶0õ©hÈש'Ÿ´÷Ÿ{ÎÞûÍoÜp²xÇþÏ”¾“Lûì*îßÿ®íÞíU ºÝÐ' ’çå gÒÒš2Zï†P©2¡!UZg:}výïMù]à³öCoŠ*#3uØß»ø‹·@ÑÂ/}ÊfÁšêsjÖ®ö={ìÄ3ϸÙÀzï¿ßõ¨\¬®v=)Þ´Åšìëúz×—¢¡amßnxá{çÕWãšõ+“úN¦Óg7RS·‚œÖ¤)+»âÖ±ÑTÍÚÖýÚ¯ÇiŠhý?­!“î—î/™>ì‹ï]üÅ[ Qá—>óý „‹w[ZÜ `=õ”~øa;!êI®¨p³}©‰^ÓkƯ¾;ït}+jºÿpÇ;7o¿þzFõ¤ò³;Õ¦n­=£E+µHeºú4„O³¸)Àj²M”àÖáyä÷PEMëìhÂ…hD3ÈizkM}.ð¾Ø°ÁMØ ž¦SO<áúšôüš5N³Ñ©¿IÓi§»: ûÒçgÅŠ?»E+*®°¾ ×𨀠z@`fs4p2¨C$ê„Q':‘Ôl^ßÜr‹[GEè¶îSS½£Çêÿ´íÛçž#Ý}'Á+uWW_ '…áÚÚ^Càÿ($þÀ.0«ïIáY½O ÒúYµÐd{ ¦ë°/}no¾y$p‚1:Þà¿lÙ˜íØñ)ßO@¢Ù믪 š–X'šŸþò—î ¹ª%:±TõD'“:±Õ4Ä:‰Ô‰¯Nu⨓FUaB‡zùÙw¢“8ÍÊ'÷sïÚõCæñÇ]€úcàõŸ „!^W‰ „ß¡+ÜϪa…îç/*r}Pn¨ ¥¡‡ý+Wºaˆ_Þs’èÂÔcÙÇò!ÐÔ¥ªf­“ï¿KpáÑD‡}%³Áø»†·øKAô€ÀÌõ7p§~Hª¿D}&:yT߉N½Uéu¢x1p¢¬D-©C¶¿üò«ÐO±ï$ÚI\ªšº'3¤IAMÁÍ[øÒD¶]% °_Ùôxý?ý”Ÿ øªç=ðJÇisÌéÚ¿äKHáíàA&ä»Â…>O .À=ô ! #çÁLáD!åϧϢç¿ÂŒ>£.È>¯ ;úìjÒ}ކô™vïCà}UXÒg]áI!*žÅH# ûŠîôÙUï>“¯¿ÞÊw'ß»x‹¿DðwR'‹o¾éNu’¨D]™Ö‰¡®ÚëêµNu"¨“@„몿fþÒIŸNø~8Ù;ú㰛о“h'q“iêNÕ&¼¾·oŸ;y~+Á+ð|v}è‡  ërïû /üP…zê)7üët j8˜†…¹JT ˜h¸˜Â¢†©¥  >^¦ ©áfªjZmW‘Z·Î KÓtÛª j¸šª‰ïïÞó³«à¬ªœ*r7Ýô­X1äúŒ4$PÕ;Íž¦‰ø^å{oñ—‚è˜bc´N5Þ_'ZûD=:áÓÉžÖFÑIÞŸ5õpàäîËÀ‰Nê¢ÄMÇ!M03ö±‡Ò©áÞUÁž~ÚõJu=ö˜õlÞìôÏ©³zµkÜ×g,ÚgWaF½W ;ª^¨¾ÍÎV­¶Ó÷ØÉe­íæGíÍEOÚþ…»ìÅë_´=e/Û¯Ë_¶ßÞú²\ó’½õÀ‹öîÖç­cçs.X©z¦ª*hz­ ^¿Ë°¼iƒ(YoÝeÝÅõöåÂZûSér¾áfûvá"-^èúh\ï†\5OCÓÀUÅQ•O ¡*ˆkHšªêÉQ ×J…r]Ðï¡& P8ÿ¨¹ÙtU-Òõ»ª ®ê§Âzë믧4°gÊÒ|/ÕÑÑaµ/¯ÜÜ\+((°†† ûØšš›5kVÌçl|¹åçç;š_Â~ïO÷ñèa<'p’Ág—Ï®ŸŸ]ÍF§FyM  ^§Ð¡]?»é[»­â¼müÅi{býû¶ûÁ£vð‰×ìÝg^¶ABBÁB‹œª2©À¡à¡!’ " $ &ª*¨(°¨j© ‚Œ‚ª‹ : <>W¬hª© §†/jÍ"U&5㞆1ªZ¤Š¥ªΨª¨—‚—ªšŸ‚˜™‚™ªâ©À¦à¦jß |/àoúÀQ{{»ÙÈȈ566º@ªÃ‡[eeeÌÒÒÒbU/´¡¡!‡B‹îókºG„«@á³›…ŸÝ4R‰zIÔS¢ÙÞ41ƒÆÔ„ ( * ,šÝK3w©‘>á…FqUG SRCÃTÔP±!âÃ@˜P•òã@èQÅRV¨z©)ÀUÉÔ¢ªªjjˆ¦*œ’©j§&Ð5 ]Ó´ÏѾx’4é€z{ Ô—æÖ²ÑÄšZ=;Û¶¹Š««êh([ ܨ¢£×~”Ê)ß T@¦ÿ,‘œœœ ÷]¾|ÙJKKíܹs1ˆNæõ&xÒm¿ö§ûxô€0Î`:¡é¦5 —fãÒ¬\š®Zkáx mê_mëþé8kW´â†¶)ì¨Â£amÀ¡µl4ñ€›úÇÔÔ3æª:+V¸p£ŠŽª7nUsn¸Áͤ¦JŽª> Búqèš[ÛFhZè@€RõF•$MF ‰.4TU USsÓCg@_ß»ô€dLikk»¦²5ðK¸gÏw;VÉËËs!&8Ðè>¿ö§ûxT@¸šx‹¿x›)ÄÚ5fíJEuTüêmÑLjªä¨ïECÁ4Ó™fSûÄ›ˆ@ÓBk‘Î{ïuCÖ4¼LSCkÆ4Um4TMÃѼ顽)ºuŸöé1nvµÀÿQÕGÓDë¹z–¦¡qª¹…;5ËšÖ¼ ¼7]tàµi='?' òL$#HOO•••Y__ßø}ÝÝÝVø…ò+€„Û\QIt:§7Ø#XÕÕÕnìŸ÷áÓ¿©ØÖû”ÊãeÛ6þ&oûâÅ‹ø¿¹­ï…™ôó¼ýöÉÀ¿_J¯ÚuÏ=vÛmWç?,ôYQñmàoÞ%Û¼ùk7´ë•Wº­½ý¬uttúöz¢]¥ŸîþuvtاNÙGGºêÈg¯½f}o¼a=P¡êÉÏbº~\ï(Vá÷Û¿íÐSyüŒ n˜•G°>Ξ=w¡•8®fÞâ/Þ2´k2hѪªKó1[¶ìrà¹>ÊêÏÙÑ@ˆQÿŠúXÔÏâÖ¾ÙµËõ¹¨ßE3šiýõÁ¨Fô­YóÃ8Pã&(/@4cš¦<×p6ÍŽ¦an -Z°v¦OýLdš¨µµÕŠŠŠ¬««+l…!“éÉÐ}~íO÷ñè€lÇÏ¡] ·ÜrÕNžüáoê§ŸŽÙÒ¥£YB’=K¡C“hæ2…M ¦oáVý«5˜t?a…ßµwïÞÀç°Ðz{{ãz|høÝöf•ÒT¾ÑfšêþT W3oñð6y³v-_þÝxøð¤R^þ-^¦©D¡BkÂh…  ß5Ù G¬"i-hëj$²?ÕÇcæô¼Å_ÀÛä íºñƱ°kµ‰ÂÊ 7\µÒÒÑÀã¾³›n±²²ûÙÏ®ØÏþ­-^|Ù–,¹lK—^²[nùÆ–-û&ð7ùÏVQ1ì*0UUCV]}ÑjjÝp±º:õ¸üÉV®ìw¨¾þ‚ýâ_ÛêÕç!é¼ÝygŸ­Yó•Ýu×W¿õçìž{¾´uëÎÚ½÷žuaiÆ/ìþû{­¡¡×Uv6mú£mÞÜc=Ôã~–‡>m>zÚ¶lér=3¿üå§¶uë§öøãŸ¸0¶mÛÇóŒí©§>r?ÿÓOŸt ;>tÕ¤]»:íW¿úÀž{î}à^x¡Ã^|ñöÒKíγW^9n¿þõïmïÞ6WÚ¿ÿ=ûíoßµ––wìµ×Þ±ŽÙÁƒo»apò9³`VÒÿÝ•+¡kÙ|<* \é¼Å_ÀÛäQ[{åš ÈgŸ™•—_±Ã‡[ÝÉ´Nªur­“llë¤['ß: ×ɸNÊurþòËÇÝɺNÚuòþüóîd^'õ:¹×I¾NöuÒ¯“………‚'Ÿü8N‚Â'Ðð‰56~ꆗ=öXW TtÙ#œv!CaC¡CáC!DaD¡DáDCÑî½÷Œ­_6\¾tý1wÝuÎÖ®ý*lúÜ4………… …!…"…#…$…%…¦ÊÊ‹.D)L)T•—ÿÙ…,…-….…/…0…1…2…3…4…5…¶… ¯ºN%%掭׶qc¯ûÙô³Ëy'o`ü~¯grX¡‚²&€d:Ï>û‘-[66B>ÔBHâ¬Xñg{ÿýï® w+V|oÛ·ŸtÕ™ìq¡IÃäêêþ䂪Ošl@gÙ²?Û­·¸ð¤pµyó]8SxS¸SøS8LháË +Óe„+q\é¼Å_¼…)„UBJJÆSG>¡JÏ’%ßÙ‰cãáCaoçή¸þÿouÕ&U•vîìtU" /khÐÔ¯_Z}ý×V]=è*3ªÀ\ý˜«À¨B£žUwTý¹ÿþ/\õHÕ%½&U§T½zýõ·3:¬L—uV Æ"3ÖðñðwZ…ÊÊo\¸«¨øÎž~úTÒŽuäÈ[n¸œ†ÅiøÛÓOŸpÃÙz¨Ûî»ï 7 í¶ÛúÝв›oþÖ +.sCÈ41Amí ž¦ákš¼@Ãßšš>rÃçÔ£áwo¼ñ»iV ˆ à/Þþâ-þB†y«@¡`¡þ 5ð+€(ˆ¬^ýµ &š`@AEEÁEfÅŠa×?£`£þõ÷()8ð¶ FÉ+D@ ‰ 4„KC¹vì8á†v=òH·ê¥!_·ßÞïf@ÓP0 ÓÐ0M}Ë-—ܱU«¾vCÈ4”L hh™&(ÐP3 9;|øhü= DðoñoƒQs¼šäÕ,¯¦yõ56~æšéÕT¯)˜Õd¯ÙÆÔt¯æû… ¿wÍøË—»æ|5é«Y_Mûš!M3¨@= €¿x ø‹·ø xë šZÓkZâgŸýÐMS¬5^4m±¦/^µê³`!* €¿x ø‹·ø x›:"¯aó-Ñþ2]Ö°!€@¸šÁÕ"À[üÅ[À_¼Í¢’î5l Æs2^ðñðoñ—‚¨€þâ-þÞâ/ÞÂÌó—B € * €¿x‹¿€·ø‹·@„Ba<'ã9ñðoñ ˆ à/Þâ/à-þâ-PA„ W3oñoñ ˆÀ_¼Å_À[ü¼¥dzŽŽ«­­µÜÜ\+((°††Œ{8577[~~¾£©©É÷ýé>®fÞâ/Þþâ-P™¢êëë­½½ÝÆÆÆlddÄ]àˆw¨ZZZ¬ªªÊ†††555î>¿ö§ûxô€= >JA#''gÊûu2¯èI·+++}ÛŸîãQájà-þâ-à/ÞÕÖÖµÂk^^ž )ÁE÷ùµ?ÝÇ£„ñœ€·ø‹·€¿x ô€ø¤žž+++³¾¾¾)í—fÍšuÍ}Á“D÷§ûxT@¸šx‹¿x ø‹·@ÄuvvZii©uwwOi6T@ô{«ººÚ%_ïçÙf›m¶Ùf›m¶Ùf;ÙÛ@Z[[­¨¨Èººº¦´?VO†îókºG„«€·ø‹·€¿x T@ÐÞ½{­°°Ðz{{§´?t“7«”¦ê6ëÔT÷§úxô€0žðoño¥úpLf¨´–F´u5ÙŸêãQájà-þÞâ/Þi$-P8“Ç: 0]ÉÊ’¢ÂÕ À[üÅ[À_¼* (ëã9ñoñoé!€@¸šÁÕ À[üÅ[À_¼Å_¢èA®fp5oñðoñ—‚èa<'þâ-þÞâ/Þ= ˆÂÕ üÅ[À_¼Å_À[ü%€@øå¢ø‹·ø x‹¿x‹T@ Æs2žoñðoñ—‚¨€þâ-þÞâ/ÞD €@¨€p5ðñðoñ—‚èüÅ[ü¼Å_À[z@ ®fp5ðñðoñ—‚èz@„«\-Â[À_¼Å_À[ü%€@èa<'à-þâ-à/ÞBVô€Ìš5+.®»î:’À_¼Å_À[ü¼¥’XQ°&RÉÉÉ!)Ðô€ø7ëÀVUUeƒƒƒã÷ ¸ûŽ9×stttXmm­åææZAA544Lx>©¹¹ÙòóóMMM1Ÿ3ÖãÝŸîãQájà-þâ-à/ÞBVö€Ì;×FGG¯¹_÷Í›7/®ç¨¯¯·ööv³‘‘klltÄSKK‹ 4CCCŽššw_$Åz|¢ûÓ}Ñý©>®fÞâ/à-þâ-PùQ«V­éZ ]}'©TªGã9oñðñèùQºb¯E%¯â1<IÀ_¼Å_À[ü¼¥$9Óð^½zÕ,Xà*óæÍ³ÑÑQ’À_¼Å_À[ü¼¥2ý"Dô€= ˆÂÕ ®á-à/Þâ/à-þN¯²oß>›;wóââb;þ= µ= ~*RY»v­«zŒ9vìØáî‹$ ÓÒã<é¶îókºG„«€·ø‹·€¿x Y[IE¹pá‚[ÜÐÚ¥Û“zžàjL¢ûÓy<½ÁÁª®®vcÿ¼ŸþMŶúsRy¼lÛÆßäm_¼x?ð7#·õ½€ø›‰Û¡ÿâÏÌñ7ådttÔæÏŸŸÔºº:W î©­­¥B„«€·ø‹·€¿x ÙV ®L$«$ÜóD{îp=ºÏ¯ýé>= µ= GŽIê,Íx¥¾ààY°BÿŸ7«Ôàà`ÔY§¦º?ÕÇ£ÂÕ À[ü¼Å_¼* qT"™Ê7XgÏžuC®4ó•ÐmÝ-¸h-hëj$²?ÕÇcìñoñoaºû›–•ÐY„ÐE›’w& W3oñðñ¨€ü¨ãÇÛ¢E‹Üð!”}èIz‰¶úy"³`!* €¿x‹¿€·ø‹·@dR«Ÿ'2 ʼÂxNüÅ[À_¼Å_À[z@2v!BDðoñðñ¨€ Àô Ñú<è¡ø‹·ø x‹¿€·T@R@†‡‡ ô€þâ-þÞâ/à-= þxfÁÊËË#)PüÅ[ü¼Å_À[* ‰o¦+oºÝP´¢÷ž={H ô€= þ Ábª]* üâá/Þþâ-þÞRIz™;w®­_¿ÞúúúHô€þâ-à/Þâ/à-= É ååå®ÇCC°T)++³ŽŽ»rå é€ à/Þâ/>à-þÞRIά .ØöíÛmÁ‚ãÍç………ÖÜÜlýýý$z@€ÿH°Tý8qâ„-Z´ÈUEF ¬²²’Ä@ðoñðñ¨€$w%tõ‡444ØüùóI ô€þâ-þÞâ/Þ= É ˆ à/Þâ/à-þÞRI8€Ä³¡·>¢èI(€„.:)€°FÀ_¼Å_À[ü¼¥âë¬XUU• Žß700àî;räIÀ_¼Å_À[ü¼¥Ä¿¢ GGG¯¹_÷Í›7¤@ðoñðo©€ø@4Ô*R‰·$xØV$õôôX]][üP댨òMZ‡$??ßÑÔÔäûþtÈš`Íž=Û­ó¡aWccc-@XQQasæÌ™t˜ §ÞÞ^+))±¶¶6÷üîµeË–ˆÏÓÒÒↀ 9jjjÜ}~íO÷ñ¨€p5ðñðo!«{@"5¡¿ù曾7ƬxK'óz<évðbˆ‰îO÷ñèa<'à-þâ-à/ÞBÖö€x'Ì•››ëÐí“'ONi8W¤*˾}ûÜ‚†z~ýÃÃßGôT)ñ¤ÛºÏ¯ýé>®fÞâ/Þþâ-dmÄOE ºÓ¦M®¯dddÄ6oÞlëׯŸÔóO œèþtOo°G°ª««]òõ>|ú—m¶Ùf›m¶Ùf›m¶“½=#ˆª Á P¡ÂÕ À[üÅ[À_¼…,«€( hh”+¡G jÊ ÑNÐÃõTè>¿ö§ûxô€0žðñðo!k{@Š‹‹'Ž`&»z¤¢t »R޵aƈÿÏ›UJ³eE›ujªûS}<* \ͼÅ_À[üÅ[ ò£4]ñ<\õ$T;wîtÓújèÕºuë&4¡‡{¼ÖÒˆ¶®F"ûS}<Ö€éJÊÈd«ÉP´~™p<* \ͼÅ_À[üÅ[ ò£4宆 ¡ì ŒçÄ_¼üÅ[ü¼¥$¥äøñã¶hÑ"׿€¨€þâ-à/Þâ/à-¤H« Oe,”yèIyz$¦C„«\ͼÅ_¼üÅ[üAÑÂ/=þâ-à/Þâ/à-= W3¸šx‹¿x ø‹·ø;3ȉ'¬¨¨È ¹º­û= @ˆ¯¤½½=b:!„ à/Þâ/à-þÞRñ5€¨Ú±råJ¿O·kkkÝ!ˆÀ_¼Å_À[ü¼¥Ä·¢!W£££×ÜõêÕi±b8„«\ͼÅ_¼üÅ[üadddäšûJ ô€= ¾ââb«¬¬´þþ~sèvyy¹ž…¨€þâ-þÞâ/à-߈Í#5¡úé§$z@ñoñð–§áUÐPµCC®„n>¨€þâ-þÞâ/à-¤DÐB!€p5ƒ«€·ø‹·€¿x‹¿3+€=zÔ6lØpÍý vìØ1’= €¿x‹¿€·ø xKˆdîܹ6<<|Íýºoþüù$* €¿x‹¿€·ø xKÄ¿¢Ù®"éºë®#)Ðô€ø@òóóm``àšûµHAAAÜ!Æ#–jjjâz\ss³{m¢©©É÷ýé>®fÞâ/Þþâ-deD'¾ªtœ9sf|!ÂÞÞ^´@¡_ÕéðáÃî9c=®¥¥ÅªªªlhhȡТûüÚŸîãÑÂxNÀ[üÅ[À_¼…¬íQ¯G¤…/]ºä[¹|ù²•––Ú¹sçbÌ+zÒíà0”èþt W3oñoñ²¶â ·*.._ˆ°¤¤Ä}í'Ùºu«íÙ³'®JI^^ž«ÄxÒmÝç×þtÈÚ?)Xtww[EEEÜCµÂíÏÉÉñm:§7Ø#XÕÕÕ®ôæ¥_ý›ŠíÓ§O§ôxÙ¶¿ÉÛîëëÃüÍÈm}/àþfâ¶~Ì<gdQø8{ölÜ„ ã9Ï x‹¿x ø‹·ø;ƒ+ ûöísëO»«!YçÏŸ÷%€Dê1™LO†îókºGã9oñoñ²¶äСCã 8€tttÄ<‰žì,X‘ºíÍ*¥>”h³NMuªGÐò£,X`Û¶msÆ‚ˆfÀšÊ: ñ¬+€HZK#Úº‰ìOõñ¨€p5ðoño H˜ÕÎCW>OÕJèšy+•Jõñèa<'à-þÞâ/Þ= A³5]¹råšÀ¡áD±©Qæ®fà/Þþâ-þÞRIiQ³ùÒ¥Km``À«W¯ZWW— &‹/&)Ìðô€¤4€ôööFœ¥J Õˆ à/Þâ/à-þÞRñu^…à•Ч2/¢ðoñðñèA®fpµoñoñ—B¡²°¤¯¯Ï ¹’Ô€>oÞ<×ÿQTTDJ ø‹·ø x‹¿€·T@ü åååÖÓÓãn¯[·nBzmm-IÀ_¼Å_À[ü¼¥Ä¿¢µ>FFFÜíùóç»àqêÔ)ëîîŽ{%tDðoñðñ¨€Ä%OZûCÛ£££n;U+¡@è€, ùùù®âqæÌ>fÏžíîWUDûÀ_¼Å_À[ü¼¥â[щopßG]]»_ãдB:¢ðoñðoéñuÞ ¸áV………ã÷•””¸²À_¼Å_À[ü¼¥Â: €Ì sçεõë×Så Â/þâ-à/Þâ/à-ä­ÿ¡)xÕ÷¡Ù¯ÊÊʬ££Ã®\¹B: ðoñðoéIά .ØöíÛ]ˆ×ˆ®^ææfëïï')PüÅ[ü¼Å_À[* ÉéQõãĉ¶hÑ¢ñ5A´aee%‰ $¹Mèêihhp+¤#* €¿x‹¿€·ø‹·@dZÌ‚¼ŽH8©·¤¶¶Örss]EE¡fpp0êsj˜BMMM¾ïO÷ñèa<'à-þâ-à/ÞBVö€ŒŽŽº GpˆðÐÚ “ "áT__oííí666æVXollt$’ZZZ¬ªªÊ†††555î>¿ö§ûxT@¸šx‹¿x ø‹·µâââ #õø@B¥ í¹u2¯7Á“n÷¡$º?ÝÇ£²¶DAãÈ‘#¾ ÅŠGmmmQ+ šX!%8°è>¿ö§ûxT@¸šx‹¿x ø‹·µÉV9 ===nÍ‘h †{žà×™èþtÆsÞâ/Þþâ-dmˆÖüPßB*Hgg§•––ZwwwÔÇÍä ˆÞ``UWW»ž—~õo*¶OŸ>ÒãeÛ6þ&o[1ð3q[ß ø¿™¸í3Ïß”ãÇ»u?bÍJ•himmµ¢¢"ëêêŠù<áz*tŸ_ûÓ}Ñýé>®fÞâ/Þþâ-dmD= ×Üßßßo¾p÷Gk~õøD÷§óxzƒ=‚U]]í’¯÷áÓ¿l³Í6Ûl³Í6Ûl³ìí”]yW¥ãÌ™3îʽèííu'Õ±†Q¡ø‹·ø x‹¿x T@&%õzDZˆðÒ¥KIëÑ}“éÉ~|¢ûÓ}= µ= Ç·E‹Ùàà`ÒÈ… &ôšèöÀÀ@ÄÇë1Ñ*5‰îO÷ñ¨€p5ðñðo!k+ áf¿ò{,­®® HpHmmmVV@ô{«ººÚýó>|ú7Ûš •Ç˶müMÞöÅ‹ñ3r[ß ø¿™¸ú/þÌÓÒ„ ¿úCÂ=O´ç×S¡ûüÚŸîãQájà-þâ-à/ÞBÖV@R!Íx¥¾ààY°B‡0y³JiXX´Y§¦º?ÕÇ£èI¡Îž=ë†\iæ+¡Ûº/Z…ÖÒˆ¶®F"ûS}<* \ͼÅ_À[üÅ[ ¤•+Wºž…t­„mJÞ™p<ÖÉ^ðoñðñ¦»¿) «V­¡$k„d«¨€p5ðñðo!++ 2ÔÞÞ>aÁÀááa[½zµíß¿Ÿ¤0ÃÐ’òixÃÝV³øœ9sH T@ñoñð– ˆ¿Ä[ ]½­­­ã ¦ª„Bã9oñoñ³$€:tÈÜm­ˆÜ2þ|’À_¼Å_À[ü¼¥’œixµJù‚ \åcÞ¼y6::JR èɬu@®fÞâ/à-þâ-P™0ó¢ðoñoéIz™‹ò@¨€p5ðñðoñ7KHaa¡]ºt‰D@Ð’üòÞ{ïÙ’%KƧâET@ñðoñð– HR׉ý!ô€þâ-þÞâ/à-= ¾7¡G"''‡¤@ðoñðo©€0 /€‚¨€þâ-þÞâ/Þ©­B= €¿x‹¿€·ø xKHJÈðð0„ à/Þâ/à-þÞRñ'€D›ýÊ#//¤@Ð’xñfºò¦Û %??ßöìÙCR ø‹·ø x‹¿€·T@ü‚ÅT»ô€ðK¿x ø‹·ø xKÈŒ›«§§Çêêêܰ®ÂÂB;pà@ÔÇ777»*Œhjjò}ºG„«€·ø‹·€¿x YYI…z{{­¤¤ÄÚÚÚlllÌmË–-ßÒÒbUUU644䨩©q÷ùµ?ÝÇ£²®$•Ú¸qcÌŠG°t2¯èI·+++}ÛŸîãQájà-þâ-à/Þ$jöìÙ¶oß>›?¾åææºRÓüF’†i©RâI·ƒgäJtºGã9oñoñèI¢4ÓÖ¦M›lttÔFFFlóæÍ¶~ýú¨Ö,ŸèþtOo°G°ª««ÝÏK¿ú7Û§OŸNéñ²m“·Ý×ׇø›‘Ûú^ÀüÍÄmü˜yþÎÈ¢j€‚‡'UB¨€Ðô€ø.5e‡h'èáz*tŸ_ûÓ}®fÞâ/à-þâ-P™FŠÖ2ŽGЂ \ÍÀ_¼üÅ[ü¼¥B!€0ž“ñœ€·ø‹·€¿x‹¿Dðoñðñ¨€p*O € * €¿x‹¿€·ø‹·@@ω¿x ø‹·ø x‹¿W3¸šx‹¿x ø‹·øKAô€= W3¸š·ø€¿x ø‹·øKAô€þâ-þÞâ/Þ= ˆÂÕ üÅ[À_¼Å_À[ü%€@èz@À_¼Å_À[ü¼¥B!€0ž“ñœ€·ø‹·€¿x‹¿Dðoñðñ¨€ „B„«€·ø‹·€¿x T@= €¿x ø‹·ø xK„ÂÕ ®fÞâ/Þþâ-þ@&¯šš›5kVÌÇ577[~~¾£©©É÷ýé>= @H’uøða«¬¬Œ@ZZZ¬ªªÊ††† -ºÏ¯ýé>®fÞâ/Þþâ-PI²._¾l¥¥¥vîܹ˜D'óz<é¶‚‹_ûÓ}¿ö§ûxT@¸šx‹¿x ø‹·@$‰êîî¶ŠŠŠñíX$Üþœœßö§óxzƒ=‚U]]í’¯÷áÓ¿l³Í6Ûl³Í6Ûl³ìí@>Ξ=w¡ÂÕ ®fÞâ/Þþâ-þR™²8Â1™ž Ýç×þtÆsÞâ/Þþâ-Ð’â@mÛ›Ujpp0ê¬SSÝŸêãQájà-þÞâ/Þi@$­¥m]Dö§úx¬Ó•¬\ =77wF W3oñðñ¨€ ã9ñoñoé!€@¸šÁÕ À[üÅ[À_¼Å_š‘è!€@¸šÁÕ À[üÅ[À_¼Å_¢ðoñðñèA®fp5oñðoñ—‚èz@„«ø‹·€¿x‹¿€·øK!€0ž“ñœ€·ø‹·€¿x‹¿Dðoñðñ¨€@ Dðoñðñ¨€ ã9ñoñoñ—B¡ÂÕ À[üÅ[À_¼Å_¢è!€@¸šÁÕ À[üÅ[À_¼Å_¢ðoñðñèA®fpµoñoñ—B¡èI‚:::¬¶¶Örss­  Àlpp0êÿinn¶üü|GSS“ïûÓ}<* \ͼÅ_¼üÅ[ ’$Õ××[{{»ÙÈȈ566º@I---VUUeCCCŽššwŸ_ûÓ}= @H ¥þpDë¡ÐZÑÖÕHdªG„«€·ø x‹¿x T@¦‘´@áL>ë€d/ø‹·ø x‹¿x ÓÝ߬ Ù(* \ͼÅ_¼üÅ[ ‚².€= W3¸šx‹¿x ø‹·øKAô€þâ-þÞâ/Þ= ˆÂÕ ®fà-à/Þþâ-þ@= @"€p5ñðoñð Æs2žðñðoñ—‚¨€þâ-þÞâ/Þ ¨€þâ-þÞâ/ÞDa<'þâ-à/Þâ/à-þ@ T@¸šx‹¿x ø‹·øKAô€= W3¸šx‹¿x ø‹·øKAô€þâ-þÞâ/Þ= ˆÂÕ ®á-à/Þâ/à-þ@ ô€= ˆ à/Þâ/þâ-þÞR!€@ÏÉxNÀ[üÅ[À_¼Å_rjnn¶üü|GSSÀ_¼Å_À[üÅ[ ‚’£––«ªª²¡¡!GMM» ù.…¥VOº]YYIðoñðñ¨€ ÿ•——gcccãÛº­ûèüÅ[ü¼Å_¼z@ïš5kÖ5÷åääD Áª««³Ûn»ÍUSÊËËÝ¿©Ø¾õÖ[Sz¼lÛÆßäm¯Zµ ?ð7#·õ½€ø›‰Ûø1óü%€dI!„B¡Ld(\ˆîC!„Bˆ‚|—7 Öàà`ܳ`!„B!DAS–Öþ˜Ì: ¡ î H%”2Mö‡ðoñá-þâ-Ên ˆ/üÅ[„¿x‹ðoñ—‚B!„šy"€ „B!„ !„B!B!„B@Pj5kÖ¬q¿êèè°ÚÚZËÍ͵‚‚khhpkÄ ÿüÕZ;ž¿6l°þþ~ŒñYò˜ï‡ä}ïòýë¿zzz¬®®Îòòò¬°°Ð8€)IüìΞ=c|P__ŸÕ×׻ϭÐísçÎ@ÐÌÿRAþJ_ííí666f###ÖØØè òG+W®´ãÇÛÕ«WÇ/½ô’•——cŒ:|ø°UVVòýÀ÷mƨ··×JJJ¬­­Í}/è¢Ï–-[0&I:vìØ”Ö±à*gê¼Å_ÿ¤ê’¦-”§sæÌaHF~v,Xàú?‚¯Ú£Ä¤¡+úNÐЫuëÖÑ„î³TeÒèÈ_预·v˜ÐíLèk$€ „B!„ !„B!B!„B@B!„B„B!„"€ „B!„ !„B!B!„B@Be‰2eQNE!B¡4 !DA!„ „"€ „ÊìðLè¾ÖÖV«¨¨°ÜÜ\ËË˳ºº:;wîÜ5;zô¨{œü<'Nœ°ÚÚZwNNŽ-Y²ÄŽ9rÍkyå•WÜÿ»îºëlöìÙöðÃÛððð„LJz/݉Òd½t¬©¾7©ú,fòïY¬÷.YŸcOÇŽ‹(W®\iÇ·«W¯º×øÒK/YyyyÒžo²ß+Ùø{FA„29€F&é édÿ ß§ÛúãRTTäžkÉ’%ÖÝÝ=©çÛ¿¿­Y³fÂ}úã¯+‡ºJ§+‰—/_ž°Û¶mî ¥®à½òÊ+Sþìç×aOºîÄ)8°y' ’nWVVƽ?ÓÈÚµkíСC ?ÏTNºu‚üùŒ×ÛHÇšê{¬Ày[àÎìÆÍn½ÕìÝwý ñÜëwb:üžEzï’@–.]ꪹ“‘~æd=ßd¿W²ñ÷Œ‚ ez™Ìý!Ò†'žxÂΟ??å¢]éÒ²_|1ê•Åpϧ+´:ÁñôÌ3ϸ*ŒžSWu%1øjàöíÛmÕªUn¿®0ê$ɯ¢çËËË‹ø<Ú§Ÿ3øwðãcí6¤d*¯ßïç •Þy’Ž# I >i‹åm¬cÅûÿ£…åËÍNžüaû³Ï~Øžl™J‰õ;1]~Ï"½wÉ :ÖÃ?÷ÿÓû¾gÏW HÖóMö{%Ï ˆ‚PýÕÛùóç_ +€ÿ¡tå3Ö­àÿSxíÁH'NÁã±5T¡¯¯Ï—™ûî»Ï ÐÏà •˜ìë~üTöOçÏóÄ3ö|²'F===VVV6á}ŽåíT<‰U –Î/½ðáI!¤¦&ù$ÖïÄtù=‹ôÞ%3€,¤ÀÞÞÞ¸?BÃÑΞ=›´çóã{e¦ÿž@¡L ñµšÂ, ¿P?HEEŤÈdþ†Û§ã_™Õc†<´}Ýu×Mùl´ÿ£fQ5áë8 a{÷îzb—h$‘?Oܦs¤³³ÓJKK¯Ê—ê Hè¯ÏÂ…áwýõ“ûU›J‰õ;1]~Ï"½wÉúkx†/MFzßwïÞ=á{Îïç›ì÷J6þž@¡L áÎ’&s ¾Z¥’à?&:‰ñ;€hlzð}]™ •%X~V@BuàÀ×@IáÆ7ë¾x÷gZQÏ@*Ǧ·¶¶º~¢pÍÒñz;™±éñ¼7ž’Y‰õ{ëwb:üžE{ï’õ9ÖR5p'ú=—¬ç‹÷{%Ï ˆ‚Pýá;8«ÒÉÆkºH5’{R3¦Æ7k¿NV4D˯ivžçž{ÎV¯^m.\pÛÚ°qãÆñýÞØt½žD{@yä÷<úù4ZW# ͼ^ô¢Í‚i¦ ÁÒɘ®àž8qÂm'sv]%ÖIqèð—x½u¬xÿ$%³$ÖïY¬ß‰tÿžÅzï’@ô™Œ4‰@èÿÓ0Ósçιۗ.]rÍ÷¡'Å~>ßd¿W²ñ÷Œ‚ ezI`,ýqÔ ]U™\M©ÁãÂUžW Ñ~]1Ó‰L¢ÄC³ïèD+Üp »ãjnü#GŽLدÆyÍ1kvžXã¦ueÒë©««sc¢cI'Ñæ¸¶?ôø±^_<ûý|¾HŸ½z/´>ÁÁƒ£>ßTǦÇó\±¼õ:b½wñ„UB4K•¿fÁŠõ{ÏïÄtû= ýž˜Ìç.žÇëÄVSáÆã±®øëçóü·ö…ŸÏ7•ï•lû=#€ B™@B!þ®!DAˆ/j„Bˆ¿kˆ‚_Ô!„×"€ Ä5B!þ®!DAˆ/j„Bˆ¿k@_Ô!„×"€ ”´/j€™B„B!„š‚þ?Ôæ*é †®IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_increment_long_line_total_wide.png000066400000000000000000000637071174000617100276370ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxgŽIDATxÚì½YlTÙz¿)ŠŽ¢è¯(7GQ.¢èHQ”‹(Š"EQE­Ò¨ÕF€çl0žc&3cfÌŒÁ0f6°±ñ\xb2cÍL3ãƒ1`h7}ø}¬Ý_q ã¹Êv¹ü¼èµ÷.j—–«ö»×z×ú3AAAôQü ‚ ‚ ‚ !‚ ‚ ‚„ ‚ ‚ ‚„ ‚ ‚ ‚ \øÃôgögùÇüGÏû@røù îòZƒÙ#Áç@OÚWSS“V®\©ÿýßÿÕÿûÿOñaaÿ÷ÿ·‚‚‚´oß>þC ‚„ w'N|ö¥o8uê”G]„’€€ðÿäÚÏþx߇ÒßüÍß´ù^{«mÒæ ‚„ GLLL›_ÞQQQ$ \ð³’ÿ§ž|ôõûÎÊÊúäØßþíßjÛ¶mjnn¶Ž·´´X‰”éùÏÿüOÚyÞòå˾ êèß:ó^ñÿöí[ë¾y¾ñêæ"Õûçþç¯kÚ‘ŸŸ_»Ã‹z£ý¹ò½tä´'¿£ÝýpÅÿ·ñéø<ÓkÑQûš?þ'ûgϞݣϼîüôÄ%A$ At¿Dͱ¹3Û÷™bNg¾7oÞ¬?ÿó?ïð¹6lèôÂÆ\àµõoM¡©¹xhëØž={º|álÆ•›;ª]½ÈèɈ«\DFF¶ùoÍë;ƨQ£Ú|^[ÿ¾·®¾Wgý{yy}|lÛô“0tôºæÂ¶/ÚŸ«ÞKgN{rÑÜÝÏgÿ¿GŽÙí¶iŠË÷Ÿ>}ºÛŸwÝý? !‚ \ïÞ½³îÚ¿DGŒaí6lØÇ}æ¸y^w.Bíaî&:>ÇÜÙ6Ã(>»˜èìΣ™íÆ\™ ˆöŽ™ >ÇýÿþïÿÞ¥÷lz%/¶Ì…°Wn~n34ż7sÁäLâJC† ±Æ¼oÚ´©ÝŸ·õXysÌœÏðÿñ}–€t彺Âÿ?ýÓ?éòåËŸ<çܹsŸ½—úúzëuÇ÷É1“õfûså{éŠÓî´QW~ô¤mÚ ¦g©½÷íø ¦mt'\ù@ A=ŒÖSö¡f(„ãþô(i}¾¢¢âã±£G~rÌ<·£×7…¥&L‘iëcÇŽ³Ž™ Çýæ‚¥+ïÙ ½pÜo†8sÞÛ.ì?okŽ?¯¹ˆtùRµßA6;î7ÏëɸcÁhë;–殣ã1óÜŽ^ßñßvt¬£‹”öÞ³cÁ­Á¬1à꤯\tå|m]D÷VÒ•÷ê ÿmÝ oýºÑÙÅ»³í¯¯ÞKOÚ¨+?z³mvÖÒYâÊÿ‚ H@‚èA˜‹<ÇzSíŽãÚÍEÕóçÏ»ý…Ü;–æ¹=½ÈuöXgïÓ H_»èîÝâÞJ@úÓë×íÎ8þÞþûó½ôÕç€«ÛæÿüÏÿ|²¿;“6ôæÿA$ At1¶nÝÚ­/ãÖE¤Îö€´¾ÓÙÙ]ÿÞ<Öß= ½áÂ]z@úÓkæçÑÞK_}¸ºm¶ž«­‚ýþø? ‚„ ˆ.†ãÜ žŒ‰veÝCoh5 ]9ÖzXãù:«éìg(þ[;oojܾ¸èw§÷ÒWŸíûúë¯{Tb&lp\Ý<6S wÕWoýABDÂ|i·þB5k08Æ;w:|Në©GÛZàõÌOf†ûl7f曎¦ÔìËÄŒuwžaÆÛga²ÿf- g.HúÚE~~þ'ûÍL[]™i¨?ÞòßÚ¹i³&Ù3aٷ̴Çm­˜í꟱?ÞKg¿£®øèÉ{ëé,X& >9f†Œåää|ìE1{ãÿ +ŸwA€ÑA˜Åè¿LÍØê¶¢õô°ö…ÂL$$$tiì´¹ìlí 3ego_vvÌL»ÙzˆFw^Ë]8®íÐu@ú:q…ÿö¢+Îûêgìë÷ÒÙï¨+>zúÞœY£Æô’üÝßý]¯ý¶uή~ÞABD;aVjîh\·=ZÏåÿoÿöo™;†f ö¿üË¿tZTjîp›yöÿð‡?XÏ5˜Í>s×±Í~(Ê5w„Wâ¶ó0wßíÓ‹:“€ôµ ûE¦ý\æosñØzÖ­îÎøãŽþ; »s³Vˆñ`.@M²cÖ¹˜;wn›Å̽õ3öå{éìwÔŸθHJJú¬mvõÿÖ¬»bÞ×ÿýßÿY5Dv—f óþÌ”»ëÖ­Óµk×\òÐÏ;‚ H@‚ ˆVaÖsp¼€2^AABA8fHYÛïš0³þ˜íßÿþ÷.âGA$ AD÷>€;ö»ßý®Ýa7AABAt+ÌlZ111Ö¸uSSa3ÖýË/¿´j-Ì GAABAAABAA AAA AAA$ AAA€AAA€AAABAAABAA áÚ˜;wî'ÛfµåñãÇ÷9ýuÞÁnñŠWÀ-^q îàµõu'  ˆ&LÐÑ£Gûœ;wîôËy¸Å+^·xÅ-¸ƒW­óçÏó¡€[¼^q‹WÀ­{%!Ü*φ„ „;€W¼âðŠ[¼’€Ô€nñŠWÀ-^·Ô€€€p—ƒ;€W¼âðŠ[¼’€Ô€5  w9¸ÓWÀ+nñ ¸Å+ A c=¯xÅ-à·x%!èáC·x¼â¯€[z@Ü/¹}û¶&Ož¬aÆiÔ¨Q***úäxZZš†n‘ššúÙ¿ïìxwŸ?ÐÏG €´wïÞ•···Nž<©÷ïß«±±Qk×®ýx¼  @ÑÑÑjjj²ˆµöuõxëpöõÜý|ô€p§ðŠWÜ^q‹WbÉ’%Ÿõx8†¹ø6RíaGEEuù¸«_ÏÝÏG c=¯xÅ-à·x%é FŒ¡C‡é»ï¾ÓСC­âåË—›aY¦gÄæ±Ù×Õã­ÃÙ×s÷óÑÂÀ+^q xÅ-^I@:ˆ/¾øBË—/×»wïÔÒÒ¢+VhÁ‚ŸoC† éòñ¶ÎçÌë¹ûù¨ÂÜÍ7‰‡=L"bzBèéþùL°ã111Vל=;6÷ÅöÍ›7ûô|ƒi»¾¾½°m´×²m>gñÁ÷Ÿƒs[£FµK_¾Ÿ™€˜¢êÖ ˆãv[5f_Ww¥&£;¯çî磄±ž€W¼âðŠ[ÏÇJ6ÚŠÿ?¡¤ƒ0èfØ•IB f8VRRÒg³@™Ù±:š%ª½ã­‡09ûzîv>j@ë xÅ+n¯¸%!éfdddè믿¶†^ÍŸ?ÿ“"tf틎ÖÁèèx[5μž»€ÁE¥ÍFâÎáXOâ‰ç£„;H€W¼âðŠ[Ïçdn®®¯[§§ zççGB¸WPÂZÀ+^q xÅíÀ¦öÈýšªÇsæèçý¬Ç³gë‡-[tìÃ1‚„»¸Å+à·xÜö˜ª²2]عS÷’’ôjüx«—ãéÔ©º±nNåæ~òÜÂÚÂNgÁ"!eí`³é̺½j•ãâô«¯¯^ÄÄèÇåËuvß>UVT||nî©\mººI³ÏÖØ7cå÷ÎO±/b5æý=zÿȺÞ{üá÷{o:yˆ„ p‹W¼â·xÜÕ‰C‡tmýz=™6M¿øûëux¸,\¨‹ééª.-µžS^Y®}g÷iõ­ÕšútªüñWÈÛͬŸ© ×7(».[¶£6%>NÔŠ7+>¹æÛðáϼ§óH@j@·xÅ+p‹WŒnkŠŠtyëV=úpmö64T-AAªOLÔ•Í›u¬ ÀzNqM±Ò/¦kÉÝ%Šy#Ÿ_}4áÕ-x°@[/oUÁ±‚Ï^·ðX¡FuðÇ'!èÜ⯀[¼âÖÃÝV•—ë®]º»x±^~¸þzç뫆øxÝX³F§²³­çäÈÓæ+›5ïÑ<…¿—ﯾŠ{§åw–k×…]*­.P^I@j@ú°Žãtf¦n%'ëù¤IVGSt´î,[¦s{÷~8^®Ì3™Z{c­¦?™® – óØìË<)[¥­Çç߱㢢£›åëûGMœØ¢íÛ¯€ô€ðá„[¼^q‹Wð$·'òóumãF=™1êãh7NæÏ×ÅíÛUQ^ Œ Vo†éÕ0½¦—cîùÚre‹òOä»ì}˜äcìØ_tñâ{ëzïúuiüø÷JO¿FBP¸Å+^ñ€[¼Â@u[S\¬Kiiz8ožÞ„…©% @?Íš¥«))*/9 ÔË©V½†©Û0õ¦ŽÃÔs¤ŸnÕwôÖûš8ñ•¾ÿþŸ\ó™$dâÄw$ = €[¼â¸Å+ ·•åå:¿{·î.]ª—'ZêžM™¢›«W«´0Íš‰jÖO³¬™©~ °fª23Ví?»ßšÁª·ÞWyy•²³ë´}ûE­^}S>>ïÛ¼ôö~OBPàÎuuZ Ƴɓ«ãøxü¸l±ÊòÖjõšòlеö†YƒÃ¬ÅaÖäÈ=™ëò÷RRR­ÌÌÓJK»¬U«nkΜNJ‰iTpðÏòòú£ÆkV||ƒ.¼¯°°ŸuáÂ{z@î ᯀWÜâÜÝíñÇuuÓ&ý4s¦5¤êÍØ±º» QåkÕõšØ4QÞ¿z['ÝOÒöKÛu¤öˆKÎ]TT«ýûÏjË–´|ùš5«^ÑÑM üEÞÞ¿jüø×š6í©/¾§ ®i×®óÊÏ?.›‚„1´Œ¡Å+à·x…ᶺ¤D—¶o·ŠÅ›?$¿|H:ÌŽ—mw¢V]žþquqÓÓ±òöJí9·GeUe=>_AÁ1íÙsN))Wµté]͘ñD‘‘/åç÷ÎÂ<ž1ã§ÇîXÏÙ»÷œ õx,3ìjÂfÁ"H@¸ƒ„[¼^q‹Wè·•:·g5nST”5¬êqÂDUo×ês± hi{uñ®¾¾éÈÏ?¡]».X½II÷”ðÔê½0½¦7Ãôj$&ÖkÅŠ­ÞŽýûϨ¨¨ÆãÚ, A  Jê²³­ÿ¦LÑ;_5ÄŒÕñMQZ"Bo;_]¼5•ÊÍ=©;¿×ºu7´páM™Ò`Õa˜z S—Û¨9sYõ¦nãàÁÓVÇ`òNBÐÂ$À+^q xnèJJŠêgÍÒÛà5…èLr¸6 Vø‹®­.Þzf©yójÒ¤ç {k%æïÉ“Ÿkþü‡Öqó¼ììSÖ¿£Í’€Ô€0†ðŠWÜ^=Ømui©.îØ¡û ¨i|¨ÞúèûÅÁÚqÄOñÛ]]¼;3K™žÓãqèÐI«„6KBиÅ+^·xÀäßèúJ঎ãìÞ½º¹r‰~š®?/]Ÿí¯}Y^Zt)TóüiuqWÍ,E›%!¨€ŽFj—ÖÏ=•“£ËWèά zà¥{S¼•¿sŒ6‹Ðâskµêð­Ûr±Wg–‚À-^ñ ¸Åë@O@ÚŠûkêTúJ]Y¥¦±>j÷–mÑxm]¬™«ª;ó"ƿꗙ¥h³$ 5 €[¼âp‹WK@^{ûêTØlmÍRŒ×†¼af)j@î q§¯€WÜâz'Y±ö²ÛÎ,E›õàä‹/¾øŒî7‘––¦áÇ[¤¦¦vzÎΞïìñþ>5 0üPÒo ˆ3Ç ­¦¦&‹ØØXk_OŸïìñþ>= Üé¼â·€WwàÀ®L] œNBˆç% æâÜH·‡yÕãç;{¼¿ÏG c=¯xÅ-àµ?9t¸PeQËôbL¨®^Ñá,X…Ç qF Hÿ$ #FŒÐ!Cäï﯌ŒŒn6l˜Þ¿ÿqÛ<6ûڋΞïìñþ>= Üé¼â·€×þ ÔfÓþ¹)j¦šØ*-,Ä-= î_„~ÿþ}%$$(%%¥ËÇÛê!1ÉJwzTŸïìñþ<Ÿiv#&&ÆÊŒíÓüÍ6Ûl³Í6Ûl³íªí){tË{²®OVeN~ѶGÌ‚ÕÜÜl[wõ8= ô€p§ðŠWÜ^û‡]™‡T’¤gÞcU´&·ô€ ޤ­ ³¯;5ŽÏwöxŸÆz^ñŠ[Àko“S\¢ƒS6êåè`UÎ\¢ªÒ2ÜR2p%K–èÁƒÖã§OŸ*11QÉÉÉ]>nŸ%ª±±±ÍY¢ZaêìùÎïëóÑÂÀ+^q xí³: ›¶.Ý©Gc&êûˆÙrrqKÈÀK@ª««j]¸9ÒªïhiiéòqfmŒöÖÉh«†¢£ç;{¼¯ÏÇ: ÐlÞ‘¥3~óôØ7Be[·áz@¸ÓxÅ+n¯½Zç‘wDyëôrLª’Vª²¢·´Y‚Æz^ñŠ[À«kÉ-+×¶™éj3Ng'%ª¦°·´Y‚ît^ñŠ[<àÕµ”ÙlZ³ö ®zM×(ÕìÙ‹[Ú, A ¸žõ{«,0Y/¼ƒU»v½Ž~HFð$ = €[¼âp‹W—’q¤TÑÛÕ4&X§g-PMI ni³$ 5 €[¼âp‹W×’W^®Õ êÞ˜XÝ?Idz³qK›%!èÜ⯀[¼º–Š,Û’¯c>KõÔ?L§¶¦á–6KBP®g]V±2CÓôÊ+Pg/UUy9^€„ p‹W¼nñêZö—km|¦žŒ וIÓt­JÛürôÊ'@·,PMI nWÆ_|ñ­#--MÇ·HMMíöqW¿ž»Ÿît^ñŠ[x^,×üq5ºï©Ç1±:•[ ¤·Ž¢  @ÑÑÑjjj²ˆµöuõ¸«_ÏÝÏG ÀÀbkA©bêt9>lØ0½ÿþã¶ylöuõxëpöõÜý|Ô€0ÖðŠWÜ‚{{-³Ù4uG•VØÔઇӦéx~>nþˆû÷ï+!!A)))ö˜d¥«Ç»ÒãÒ×s÷óÑÂÀ+^q îëuyv¹&?¯ËÁ j®ó»wãèéïhnn¶Š­ééþùL°ã111Vfloœæo¶Ùf›m¶Ùf»ï¶·)UDâymЛ€@ÝX·NÎÃÛ~Û#¶j ̾®ïJMFw^ÏÝÏGw:¯xÅ-¸×Ceåš°ö¤Rüë¥_ |øŽ®-*Â-ÐÒŸ±dÉ=xðÀzüôéS%&&*99ù³Y ;œ%ª½ã­‡09ûzîv>j@ë xÅ+nÁý¼š:é;+5+ø¬îG©!*J§33qK›¥Äêêj…††Zî#GŽ´ê?ZZZ>yŽYû¢£u0::ÞV …3¯çn磄;€W¼âÜËëÊœ2EL¼¢š°Ez¬¶lÁ+m–Á´úСC=ú|¬àì,*Uȼïµ;d·Þøúëî’%ª.+à x4$ = Üé¼â·ÐÇ^—W(rà %ÔêIÐX=™¯“yy¸¤ÍÒBBÂ8OÆz^ñŠ[pW›í¨fî²):äº.Œ›®Waaú~çNÒf©!!¡„;€W¼â\ëuÍ¡2ÅÝT^øz½õó×­ädUVTà6K  5 ®cOq™‚“.i]H^«>1QÇ qÔ€€€ÐÂÀ+^q =#ÿFþgû +*r\S/êDZÑjŠŒÔÙýûñE›¥„„ „±ž€W¼âzÆŽ5>ú…¼üÑø‰o”–vY6›æìµ)4ì¾*#“ô60PW7nÔÑûqF›Å+ Aw:¯xÅ-ôÕ.éã3ôÖß_÷.TMI ¾h³x%!¨pAÒV|Øÿ<.N§²³ñ@BÐÂÀ+^q‹‡ÞO@ðC›Å+ A c=q‹W¼n]F™ÍFB›Å+ Aà¯xÜö.¦À|árM¸GB›Å+ A @ï±6¯Lñ7µkÜN=šèßaRxŒu>H@z@¸Ó¼âpÛ¶)UȼKJ ÎVS`°ž$$XæÍ‚…7Ú,^I@j@ë‰[¼âpÛ-2K˾ê´Ö«!0T “&éÌx¥Íâ•„ p‹W¼n]GAy…b6Ó²€*= ŠÐó¨(ß³¯´Y¼’€Ô€¸vf«éG5?è¸nǪ1b¼.¦§ã€„ p‹W¼n]ËâƒJŒ8©ËA z¦Ë©©:ú!!Á+m¯$ 5 €[¼âpë2Öç•)!î¸NÌÕË `]ݸQ•ÝH<ðJ›Å+ Aà¯xÜvJú‘2MM¬Vµß2½òÔõ5kTU^ŽWÚ,^I@j@\GVi¹¦-µ©Ôw½^ûøëÆŠª.+à Aà¯xÅn]GaE…fn,W¾ïÖ‰G€n$%©¦¸¯´Y¼’€Ô€0ηx¼âÖµ3[ÍßQ¢Lÿt½òÐõ¹ótìȼÒfñJ HÏ#66V_|ñÅ'ûÌvkZGZZš†n‘ššÚéy:{¾³Çûû|ô€p§ðŠWÜz+ökwH†š¼ƒumÆ,ÈÏÇ+mèq.ÊÊÊÕfÒQ(::ZMMM&‰1ûzú|g÷÷ù¨ObÓ¡bmŸ°KϽBumÊ4ÊÉÁ 5 ÎÇ›7oäçç§Gu;1ç&볇yl™ž>ßÙãý}>z@¸ÓxÅ+n=Œ¢R¥NÙ­ŸÆŒ×õ¨É:™‰WÚ,ÐâºØ¸q£²²²ÚL8Ìöˆ#4dÈùûû+##ã“ãÆ Óû÷ï?n›Çf_{ÑÙó=Þß磄±ž€W¼âv`ÏlU¦Í‰»uLŒn‡ÇèÔž=x¥Í5 ®[·n)22²K=÷ïßWBB‚RRR:|¾IVڋΞïìñþ<Ÿiv#&&Æj˜öìØüÝÛ7oÞìÓó ¦íúúz|ô¶|Ð^ʶùœõ”ŸçHy…R—ïÓ-¯©º2QÇ·ïè·÷Ã÷Ÿ|u}{@& &ùxðàA—‡\577[ÅØô€PŸŠ¤®Ý«ËÞ3õȼªS¶èhV/z@ºmÍrÕQÒ:i«FÂìëNM†ãó=Þß磄±ž€W¼âv °cë~õ›«§>cutÍUºIâA›Å-^Ñ4¼mõ€,Y²äcÉÓ§O•˜˜¨äääÏf‰jllls–¨Ö¯×Ùó=Þ×磄±ž€W¼âv ±gÏAY F¯P•-Y­Êòr¼Òf÷I@ª««jí9r¤UÿÑÒÒòÉsÌÚí­“ÑVoJGÏwöx_Ÿît^ñŠÛBnÖ!UE$©itˆJç®TUi)^i³@ˆçÅСC=ú|Ô€€»St¸@±Kôrt°J§-SYQ^¨!<)èáN௸uÊŽùp,·“€˜D¯´Y<ÐB€0Γ±ž€W¼âÖ¥˜¡U¥sVXC­*Ç')7;¯€[j@H@H@¸ËÁÀ+^qëZL1yù’ÕVqù±…V±9^·ô€€€¸6ñ°Ùd[½^O}ÆéŒÿ<íH;€j@H@H@¸ËÁÀ+^qëb>$5›6[ ^ö™¥-k÷Z âpK  ã<ë xÅ+n]ÊñmÛu/x¢nމצ¥{t¤¼¯€[j@H@H@èáN௸u-u»wëö¸ÝóŠUÊì=Ê*-Ã+à–ÞM@ÌB{]áË/¿$ <„Ó™™º1q²ê½&hËäÝÊ(*Å ôMb GÚK@† B&@¿˜¸Å+àu€»=•“£ë“ôÌ+LÛ'ìÖæ¼¼nñÚC°ŠŠŠ­ÆÆÆûž?ní³ÙldÔ€ð¡€[¼^¨Ûùùº6}¦š¼ƒµ;t—Vì/Æ+à¯ýŸ€|óÍ7z÷îÝgû;o¿ý–L€>p‹WÀës{¬°P×çÎÓ+ïeú§kÞö•ÙlxÜâÕ=3Ôª½„8ÔëFR’^û(ßw«fl(SÑ K<`$ #FŒPTT”5ìêýû÷ ŠŒŒÔ×_M&@¿˜¸Å+àÕÍÝV—–êæòå•ú®×Ô¥6e—•ã•ö…[¼ºo H{EèdÔ€ð¡€[¼^ÝÔmUy¹n¬^­Wþªö[®øÙÕÚYT†WÚ,nñêÞ ˆ “q5JC‡µ0/]ºD@Â]Üâðê†n++*tmãF½ ÖéÀyJ˜tLòIdãÆÊÊÊú˜Ô8ưaÃôþýûÛæ±Ù×Õã­ÃÙ×s÷óÑÂÀ+^=›MWRRô6$”„6‹[Ü= ®ˆ[·n)22ò“^•Ö½,¿wv¼­^g^ÏÝÏG c=¯xõ,¾OO׫ˆñº?6N³ƒÏt8 ¾h³¸Å+ HÂ$zaÛ>h¯î°}fÿ~½š2E/Â&jeèQy-¼ ä3™eþœ^"ÿi4ÆçWyÇÖkÔñ•ÖþšK5øãû‹Ï¾¿úôüý’€\¼xQ£G¶îÊÌc³ÏÙ:’Žj ̾®ïJMFw^ÏÝÏG ÀÀædn®žLŸ®×¡J =$ïYW4ëè.•V—â¨9}út» Dw’ކ,Ùg23mu4KT{Ç]ýzîv>j@ë xÅ«gpìÈ=œ7O?û(+,Cþ“n)ªb»òNäá–6‹[ Ä¦·#>>^ÏŸ?ÿ¸Ï<Ž‹‹³ÖqEb¬}ÑÑ:wõë¹Ûù¨a¬'௛ê’ÝY¶L-~*KQØø; )KÓîs{pK›Å-PÒV1ô»wï>Ûÿ믿jèСn±*x_¿wø¹éáNà¯îOeE…n¬]«Ÿ‚t:t¹¢B~”oám¸’"ÛQni³¸z@ÚK@ZZZ>Ûo’wI@cPàÞSêþšªæ0]ž­„€ëòÉÚ¯·–ª¤º?@ HGáååe-Š×ÐÐ`ÍÎd0#""¬áY= üb⯀×?qa×.5ÔÃÀÉZèwN~; 4ùÞlåžÌÅ-m·@HWgÀj¯ýÚµkdƒ<aœ'nñ xýÓ™™jˆ›¢çþãµÖ·ZAª5öa¼2.dà–6‹[ ¤»a ÓÛa†\Ìc’îrீף:‘—§ú3õÚ7D;| ¾ä¼NѺëëd«´á–6‹[ „ ç©-*Òý õÖ'P9~û=ëªünÍЂ T\SŒ# „ á.w:¯xužªÒRÝ^±ÂJ<*ü·hJÜM…\X¢IÏ&)çTni³¸Å-= Î^èVUU)))é³ýK—.Umm-™5 |(à¯0(¼š)u¯­_¯7þÁ:í¿B3ÇßPdUªÆ6UúÅtÜÒf·Ô€¸*ùæ›oôòåËÏö›}ß}÷™= |(à¯àñ^/¥¥éeH¸®ù%j~Èš’Ÿ­€–@­¹¹F•¸¥ÍnéqeÒÖªßöøòË/ɨðXÎíÙ£gÑzè7I+üë4sO…Þkîù*ª-ÂPÒ ÈðáÃõüùóÏö›µ@¾úê+2z@øÅÄ-^Áã¼Öeg«>.AÏ}"´É÷×oÊiE4F)®1NYuY¸¥ÍnééÍÄ\ØšžŽû÷ï\ˆðîÝ»VψY  „Üâ<ÅëñÇõ`ƽöÖ.Ÿ<%­¼¢øû³ú&TÛ.mÃ-mpK H_$ ¦Ö£½…›››ÉèáC·x…ﵦ¸X?.X¬7ÞAÊõÞ£Åó¯kþkäÿ‹¿VÝZ¥òªrÜÒf·ô€ôå4¼f¸•——×Ç…½½½ÕØØH@0 ©*/ו«õÆ'HÞ)Z:ýªVÈPPKf?ž­#ÇŽà ¨a‚ît^ñê$6›®lLÑ+¿0ö^¦åq—´¹´@^MPô‹hežÎÄ-mp‹W‚Æz^ñê<ßoß¡çÁ‘ºî=K«#Ïj[Nµ¦?™®·!Úzy+ni³€[¼ºCrèÐ!k=ÇiwͬŸ~ú‰L€>p‹W^Ïî߯Ÿ"&ë¡W¬6­ÑŽÝgµôÎR«ÎcÅ+TVU†[Ú,à¯î€”––~,:wL@Ξ=«èèh2j@ÜšS¹¹º;KϽµ#¨XiiµùÊfÿ¬™õ3Up¼OŒ9R›7o¶¦ßuL@Ì X¬BÂ]ÜâÜÕ뱂ý8}¡^{ë€_–¶l¸¤}ghâˉšØ4QûÏîÇ-mp‹WwL@“ŽÖ+Ÿ³: ã…š½‚tØ;])+/*¯æˆfý4ËêõØre‹lGm¸¥Íâ·xu×dÈ!úùçŸ?K8Ì4¼Ã† # „ÜâÜÂkey¹®¬X¯×Þ!ªôZ¯”EçUXf³ê;L‡©÷(«.Ã-à·xu÷Ä›7NÏŸ?·_ýU7nܰ“ÐÐP2j@ú›M7nÕ ¿p“¤Í³êTTT«ÔË©ÖÌVf†«üùx( ÈÝ»wÛ] ½©©‰L€~1q‹Wè7¯g·ïÒ“ Ý3CiSjtøðqežÉ´Öò0kzì9··€WÜâu % ö$Äq%ôîNÁkfÌŠµþ­)\OJJ²VW·G[ÉMëHKKÓðáÃ-RSS;=ggÏwöxŸÆz^³×ºý™º?nš‰ÖΉ¥ÊÉ9¥Âc…ÖêåfóMW7 ¨:Ú,^q Ô€¸8âããUWWg ß2³ieff*""ⓤ£(((°¦ü5=.“̘}=}¾³Çûû|ô€p§ð:X½ž8”§›QóÕ8fœŒ;¤Ì}u*¯*ת۫¬:Å÷«¤º·€WÜâu°' m…é éjb.Ît{˜ÇQQQ=~¾³Çûû|Ô€À`£¶°PWâ—éÕè`åïѾô:kÿ¶KÛö6LSŸNUÞÉ<\xBR__o ¹2az0¾ýö[+a=zt^Ïô€deeiÚ´iŸ$ #FŒ° Ûýýý•‘‘ñÉ¿1³m™çøÍÀÕÙó=Þß磄;€×Á⵺¬LßÏ^«×c‚Uæ¿U{6Ÿ²ö¬;¨ØÆXE¼ŽÐ®ó»p xÅ-^=)1C¥nß¾m=ž?þ'uqqqÝz-û¿3ĨÚ|Îýû÷• ”””{HL²ÒÑy:z¾³Çûó|¦ØqŒ˜˜kl ½qš¿ûbÛ$¨}y¾Á´ýâÅ |ôÂvë¿ñã¦íõÖ-]Y®&¯0ð]­#;¯éܹó:R{D‹+ø×`m»¿M¶J›Çû5Ÿ³´7¾¿øþb»?¿¿ú<1wâ[ZZ¬Çß}÷u±|åÊÝúðåГ•ÐÍÝý}ûö)22²Ýç˜UÖM16= ô€p§x|^ëÖ¦«Á7Rß™¯½‹«T^^©ŠÊ ­¾¹Z¿háý…*®)Æ-à·xõÔÇ»óæ®¼Ù~÷îÓ+¡wÔ£Ð:i«FÂìëNM†ãó=Þßç£<‘“ÛèaÀdý8fª$–¨´´ÚÚŸ~1]cߌՔgS”{*Wžž€˜DÀôx˜¡QöZ ¦WÄ1Iè(’““õèѣɅ™fÖñ{É’%‡d=}úT‰‰‰Ö¿i=K”Y}½­Y¢ZaêìùÎïëóÑÂÀ«'{=¶7W·ÂõÓèHåÄç©èHµ?ûT¶&=›¤qÍã´óû¸¼â¯ƒ%1¶Žu“'O¶ö›ñ`f…ô®Duuµµjºù÷_ýµ–.]j]l·u|äÈ‘Vý‡}Ø—=LÒÒÞ:mÕPtô|g÷õùX„ù¾¯žèµ:û°~˜°X/FUAÔ~æ×Zû‹jŠ´àÁk¸ÕÚk­áW¸¥á·x½3x&)0íFõqŸ···UÀånSúzâùèáNàÕ“¼V)Ö¹¸Õz5:Deá;tøào=&ÑXwc Ôü‡óUT[„[Ú,^q ƒ±„pÏ •¥e:5c³µ–GMðåïªúxlç… oפ瓔]—/€ÁXòÍ7ßhÁ‚nÓËAÐÂÀëÀôZi³©v~º½ÂuÖ©òSmåžÌU|C¼Ud¾ýâv\ÒfñŠ[Ì= fý3¬©w03VéìÙ³úù矹ú'aœ'nñ ]òZµr¿ê½£uÕ;Qù«ÿ4unIM‰’î'Éÿ­¾µZå•åx¤Íâ·@ ˆ>ÎJµmÛ6«Ä^ˆnjAÒÒÒÔÐÐ@&@ ¸Åë E¦.°l)‡ô£ß4Ý÷š¬#‹ód³ýöolGmÚpmƒ[5çÑÖâ’6‹WÜ= í‡éý¸xñ¢?® b#ŒŠŠ"# cÒV|Øß0f¼Jfí—­âOÏß}~·"^E(¦1FOÄ!5 ÝSb¦Ô5+¤ô€nñJbO@*Šÿô¼¼yšötšB߆jÛåm¸£Íâ·@AÂ8OÆzâ\›€˜ã¥Õ¥Zrw‰Uç±òöJ•WQçA›Å+n.Ä»wï¬ÇÅ혵Az@øPÀ-^I@Z' )WSÔ¤ÄúD+Àm¯¸z@º^^^Ÿ$Ž˜:‚\åTêxغè¦h8s_Ô€t?L¢a³Ù¸â'á.nñ:È©¨¨Tþ¬Cz6:\"Wv8 ¾h³xÅ-ÐÒã —ƒ„qžŒ¡Å+äl­ÒŸEª÷‰VMÚŸV*ŸY?SsùíóhÇ? _,Äm¯¸Å5 Î…Y󣩩‰+~îr௃#µ*ŒÜ§W£ƒufæ&UVTüÖRY¡¥w–jÔ‡?÷Þß³>‡øãóáOÞ©<ÜÑfñŠ[ ¤çQWWg­ûÑØØÈU?  l¶JíMªÔc¦êNè Õfåÿ¶ÿ¨M[/oUè›Pÿ¬ÅoòYdzA5.Â!5 =¶f¿b,îr௞KfÆ •ù§ê¥W¨Î¬Úþqÿžó{4ñåDE¾ŒTÚ¥4«÷£½?…ÇXáœ6‹WÜ= N¡·õ!$ ŒóÄ-^=h¸Õ‘ZížTª†Ñº»HµEEÖþìSÙŠoˆ·Lý!ÕêÁ+m¯€[j@z-!H@¸ËÁ$¼zúp«£Ú¾êŒê¼–é™ßNßkí7ëwÌy4G¿jÍÍ5*¯,Ç+m¯€[z@H@H@¨'†[8­}Á¹z5&DWæ%«ª¼\%Õ%V¹YÁ|ñ½Å*©)Á5 }›€\¼xQ£G¶†\Ìc³ á.nñ:0)*ªQÊôÓº9fº›¢S99ÖÌV뮯S`K µ‚ùáã‡ñJ›Å+à¯}Ÿ€œ>}ºÝ"t’Æyâ¯o¸Õ–õuØ;]¯½CtymŠŽÚlÚvy›Æ¾«IÏ&é`ÝA¼Òfñ ¸Åkÿ% ¦·#>>^ÏŸ?ÿ¸Ï<Ž‹‹³Ö!èáC·x í2Okøcjðž {S樶°P{ÏíÕĦ‰šðj‚v]Ø…WÚ,^·xíÿÄ ¹z÷îÝgûýõW :”L€psJJj´rö÷Z¥¦€p]عS9§r4õéT…¼ Ñæ6·9³@¿% ---Ÿí7I  w9p‹W÷fsÊÚæ[d ·º½p©Š«ò5ïÑ<ü ä›É*¯*Ç+m¯€[¼ºWâå奨¨(544èýû÷æqDD„5<«+qöìYÅÆÆZ ËW_}¥¤¤$ë5#--MÇ·HMMýì5:;ÞÝçôóQÂXOÀkGdg×))òŠnúÎTCxŒŽçî×ò;Ë­™­Ý[¤âšb¼ÒfñŠÜâÕ=ShÞ^úµk׺ô¦†¤®®Î¶e˜ÌÌL+±GAA¢££ÕÔÔda’³¯«Ç[‡³¯çî磄;€×ö‡[UkÉ‚uÈgÞøéÚºuÚxmƒ‚Z‚4³~¦òOäã•6 xÅ-^Ý;1a ÓÛaz0 æqW“öÂqø–¹ø6Ría›^—®oξž»Ÿh‹ÔÔËZpN ¾‘z?CûŽoÒØæ±Š{§ÌÓ™8€“€¸2LHVV–¦M›öqß°aìýŽÏ1ûºz¼u8ûzî~>z@¸Óxu$'ç”fÅÜÓq¿Õz¦ªÉŠz¥ˆWÊø>¯´YÀ+nñ:xûЭo¿ýV<ød[Åï]=ÞÖyœy=w>Ÿiv#&&Æhoœæï¾Ø®¯¯ïÓó ¦í/^ࣶ[ÿ=žººïµxñ]mñ-×[¿Ý]µP³&(´%TŸÔ¹óçh¯°m>gñÁ÷ß_l÷ç÷WŸ$ æ‚øË/¿ü$ih ûsºÛ²oß>EFFÒBà¯=dÛ¶Kšô£nÎTãø J=9ÚÙjÕ­U.›ÙŠöJ›Å+à¯}Öb ûxó¸=:êèÊô¾Õ@˜}]=Þ•šŒî¼ž»Ÿ€ÁK^ÞI%LþI‡öègßÙvNQàÏþZx¡ŠjŠp Á2‘œœ¬GY›››­if/°í³@566v8KT{Ç[aröõÜí|ô€p§ðZ^^¥eËîhïE= ŒÔ‰ã5éq fü4Cy'òðJ›¼â¯$ ŽQ]]­ÐÐPëÂý믿ÖÒ¥K­‹mÇ0IIGë`tt¼­ g^ÏÝÎÇ: Ì÷ ƒÛkzúEE‡>Ó©ÐÕz¨M•AŠmŒUæ™L¼Òf¯¸Å«ç% Õyô¤¤7¢¯Wdw‡àéáNx¾×üüš:õ©Rƒ*ô: HU›‚Ó0Néß§ã•6 xÅ-^_òòåK·I@cP๔—WjÅŠÛšä÷P·ÆM×£?Í¿ MW7ÉvÔ†#ð̤£Ù¯ìt6SAà¯Ý##ã‚ÂÃ^épø.5xko¶·’o®PYU^i³€WÜâÕ³ûLWöév[cjÌ‚‚ÄàN@ç‰[¼º†Ã‡kúô'ZtQõácuaá­»¨¢Ú"¼Òfñ€WÜÂàªqfª]‚À-^;¦¢¢RÉÉ·4οIÇb“Ô8v´öNTÞÉ<¼nñŠ[`,‚\ÇîÝçÞ¬ÔèB=óQíº@e×fàg ˆ=ªªª”””ôÙ~3•nmm-™= übâ¯Ý¤°ð˜fÍúI“BïëBü=Šñú°/¯€[¼âè1ñÍ7ßX3^µ5 Öwß}G&@  ¸Åk±Ù*µfÍ ¼ÕYkô2x´NnNÐQ[9^·xÅ-Pâ8–»¯BBw:ÀݽîÝ{Váã_jî”jÝŽóÓÝaªÍÏÂ+௸z@Z‡™íêùóçŸíohhÐW_}E&@ tÀ‘#µJœóHa¡ *\§W¡Þºº7@ H{a.lMOÇýû÷õþý{‹»wïZ=#QQQdô€ð‹‰[¼¶9Üê¨Ö­¿&ßà7Z¹t‹Çùèî¼Õáp‹WÜ= …©õho!Âææf2j@øPÀ-^[qàÀ~¦È„³:;g¬^†ëüîÝxÜâ·@ HWà ·òòòÒСC-¼½½ÕØØH@Â]ÜâÕ¢¢M[tKÞa/´sͽ ôÕeËTU^ŽWÀ-^q ô€$ àºáVÉ©äòJÓVíÓãØ05ÆDëTN~€‚„»ÜéÀ«ë^owö1Ny ÿé?¨fé4µèÚÆ:j³áp‹WÜ= =øøx 6쳦á%aœ'n«×#e•ŠN>¯Qa/”²1EÍa!úiæLÕâp‹WÜâg"!!ác²Ñ:2d™= |(àvPyµµiÞ>›ÆŒ}¡¸•º;3AoÃÂtaçN¼Ò¾p‹WÀ-= ®ZäôéÓÖc{‡™kÆŒÊÏÏ' `а©ì°|fÞoü]½V¿êîâŪ*+ÃPâªÄq%tÇÇf=¯¿þšL€~1qëñ^÷;¤ÍG5&ô¥ÖoÈ׋˜5Mœ¨º¬,œÒ^q‹WÀ-= ½‘€455YͼÕÕÕÖ㺺:j@H@ç‰[özøøaÅî×èðgŠKú^7-×/º¾nÝ +2§½â¯€[j@ú,)--ÕÒ¥K­ÇŸÔ€|÷Ýwdô€ð¡€[óZ\S¬9§·h̼K ˆþI%²ôfìX=™6MÇ ðH{Å-^·ô€ôÕ4¼¿þú«FŽiõ||ûí·z÷î™5 Cye¹Vý°A>‡åüZÖÔéñ¬D½ ÑÅ;pÔ€ ”u@Ξ=«¸¸8k×W_}eõ¨8®¤Þzv-ÇZ{¤¥¥Yñ†ÔÔÔNÏÙÙó=Þß磄;Ð3òoä·9³Uê© ¬Ù ïˆçŠŸsOÖnUK@€î/Z¤jŠÌi¯¸Å+à–•€L›6ÍšIË®·´´hÆ VBÒVq{[QPP èèh«Åkíëéó=Þß磄±žÐ3<¤Qþ˜¿íûvŸß­ð[³å7ÿ²B'¼Pþ– 5~ø|zùáwêtf&Þh¯¸Å+à–¾N@êëëåååõq–ze†Ñ£G÷ø5M"⸆Hg ˆ¹87YŸ=Ì㨨¨?ßÙãý}>z@¸ÓÝgÇŽ‹ žR¯1þ- ˆyª5»NjòOÓä·;O>oµ.ùºn/_¡_üýusÍURdN{Å-^·xíŸ$""B·oß¶ÏŸ?ÿ“aR޽݉“'O~Ö2bÄ+)ñÿð埑‘ñÉóÍ*ì&iqL`̾ö¢³ç;{¼¿ÏG @÷“±ã~Ñ÷—þhý¾üpýÃßÊ'¸YÓ¦ÿ¤cÛª9<\ S§êøáÃ8èÏÄ\›aS&̬W&Y¸råŠnݺeÕst7L2dõ¬´÷ïß·V_OIIé°‡¤£UØ;{¾³Çûó|¦ØqŒ˜˜«kΞ›¿ûbûæÍ›}z¾Á´m~GðášmÕ.æÌÑ/¡¡z’Ÿ/Ú«[n›ÏY|ðýÅçÛvúãüýº¡¹(6ÛöÙ¯º»È… äççg%/Ess³UŒM5 Œõă+°’¶âÃþó竺¤O´WÜâp‹Wwé1‰€éñ0=ö¡R&L¯ˆc’ÐY˜ MÝÈ7:}n뤭 ³¯;5ŽÏwöxŸÆzB×(ª-RâãÄ<Ñ^q‹WÀ-^Ý,1¶Žu“'O¶ö›,lܸq]zÜÜÜßó£t÷îÝ6/Y²D<°?}úT‰‰‰JNNþl–(3uo[³DµÂÔÙó=Þ×磠{˜iu7^Û¨€ú8…®>ÕaRx¬gî6 ¯}ñÁQ_âÞÞÞíÖq´5Œ«£µ>LïHhh¨µÏœËÔØëNìaÖÆhoŒ¶j(:z¾³Çûú|ô€p§ºNV]–¢žÅ*d®|~Öòåw衽âðŠ[¼´ÄÝÃ,pèÉ磄±žÐ9eÕeJº—$¿ó‹ù\“§4èhúa5ÆÄ€Ð^q xÅ-^I@OI@¸Ë[w`û¥í ®Sز }£=›Oéá‡ß³’ùµõë;œ ´WÜâp‹W7K@ÌŒWöéw[ÓÝY°ÏK@ú“üãùšúdšsö[í–-¾­«ÉëôˇÄãÁÂ…ª).ÆÀ@K@Ì*èŽ ‡#­Aиí-**+´êÖ*ù^š¯Àè'Š{¦Ú”L½×óI“t*;¯´WÜ^q‹×š€˜DÃf³qÅOÂ8OܺûÎíÓ¸ÇSœ|J!o´mžNª7¡¡º´};^i¯¸¼â¯=¡—ƒ„»ÜArÌšsÍ•_ÁNù½Õò…·t{ÑRýâï¯Û«V©ª¼¯´WÜ^q‹WOH@ÌÔ»fm ‚ ?0kzlººI~Wæ( î‘¢cž©nUº~Vý¬Y:VP€'OJ@êêêh-’G€p—·}Iv]¶¢NWà†ù¿QΊ25EEéed¤ÎîßWÚ+n¯¸Å«'& í-"È,X$ ŒóÄmoQZUª¤;‹å[’&Ÿàf­šsEfÎQKP®nÚ¤£6^i¯¸¼â¯ž\„ÞÔ‡€p—·®fÇÅ ¼:Wþñ÷Ý  7Zu÷’’T]R‚WÚ+n¯¸Å«§'  @_pøøaÅß›#¿ÍV‘yÁÂ<5‡UÔ):™›‹#‚„»¸u³¦GòÍdùT¤È7ôµÖÎ<§'qñj;Vß§§ã•öŠ[Üâ·0{@âãã5lØ0j@H@ç‰[—²ïì>»¶@~3n)vâc]¹ÜnusõjUVTà•ö ¸Å+na0Ö€$$$|L6Z' Ô€€p—·=¡¸¦X‰·“ä³­H~AÍ*Ÿµ×*0]5äÞ¨qEj ÓÓ„ÈËÃ+íp‹WÜ= ǯ¿þª‘#GZ=ß~û­Þ½{G&@ Àg/Д–ËgÁEÍ ÿA'Äëux¸.ìÚ…j@îrp§Ã5Ø*mJ¾º^Þ{sØ ³1«Ô¨ëÖõÚ´º´YÚ+n¯¸Å«‡% Ôy€0Γ1´]aÿ™ý «Ý(Ÿ Oupb¦~öÔÃyóT[T„WÚ+௸j@º¦ðœ á.nÛìé1óâjy/9«¤°:=¨ÆØXÕ<ˆWÚ+௸z@º£FRss3Wü$ Ÿ±ébª|dibà=]‰˜¯·!!º¼u+n¨éyœ8qBcÇŽý8oOâìÙ³Š‹‹³zS¾úê+kV­ÆÆÆOž“––f-zhHMMýì5:;ÞÝçôóÑÂŽþ$÷d®Æ×nR@ä ߪ¿ý¸|¹ªúaZ]Ú,^q xÅ-^=,qœv·5]­™6mšµšºY¼°¥¥E6l°{(::ÚJr ±±±Ö¾®oξž»ŸÆzöåUåZx~“¼VœÔºà2½«'3fèøáÃx¥½â·xÜRâº"ôö2dH^Ó$"ŽÿÖ\|›¬ÎæqTTT—·g_ÏÝÏGw:úƒôs»ä0SS®ènèT½?AçöìÁ+à·xÜÒâþÓðžÓì8FLLŒÕ5gÏŽÍß}±}óæÍ>=ß`Ú6¿#ýyþïü¨õWvÉ/¹F;sÔ⬧˗«¦¸x@ûµC{ó¬öêÉÛæs|ñyÀv~¹Õ: Ý]#äÂ… òóóÓ­[·\Úƒ@5 Œõt-ûOg*8;S NéIàD=‹›¤SÙÙx¼â¯€[j@ú/yùòe·êêj=Z7nÜèR …Ù×Õã®~=w?5 Œõì-JjJ”P½MQ1çt.p¾^Õ¥íÛñ xÅ-^·Ô€ô~ÒÑìWv:»KoÜÜ\k=‘»wïv8‹”™š·£Y¢Ú;Þz“³¯çnç£ú‚ u ^kS®ßv½õ ÐíU«TU^Žj@ú&±ÏteŸn·5f½Š¬¬,§’Ç0k_t´FGÇÛª¡pæõÜí|ô€p§£79t"OáÙ™ZP¢&ß0=š‘¨c`¼^q‹WÀ-^ûeVO§ÚíË0 zòù¨a¬go`Öô˜[¡é1Õºé¯çáQ:»?^¯¸Å+௞7 /á9 w9¦Ûm'(ru‘l>kôÚ/XW7m4ÓêÒfñŠ[À+nñJB à…µG““¥~ôÚ;P?.X¢ê’Ü Aw:\çÖvÔ¦ÅG÷iIL{OÐØÌÍÅ+à·xÜâ•„ \ëvOm®VÒYïùz® ;ÒñJûÂ+nñŠWÜâ•„ \붤ºD33*Ï/ÕnuuÅZUVTà•6‹WÜ^q‹W‚p-«+*%j½Bu3ažj ñ$ = àZ·« ´hÙ>ÝòŠ×ýq±:} —´Y¼âðŠ[¼’€Ô€€kÝ–W–kñžªò]¡FßP[ŸŠCÚ,^q xÅ-^I@z@ÀõnS‹sµ/r³^Ž Òù9ËU]V†?Ú,^q xÅ-^I@j@Àµä-Ö¦EÛU?f‚~˜8CÇåãH@z@ÀµnÍšvìÑ÷>‰z©cÛvã‹6‹WÜ^q‹W‚pÛcÛgûöRqÄ 5y…¨fÉz¦Õ¥Íâ·€WÜâ•„ zŽFj—}³7êÅèP˜¼PU…Eø¢Íâ·€WÜâ•„ \€´ö_ ‰WùÞƒx‚èý?´Y¼âðŠ[¼’€Ô€0Γ„1´€WÜâpK   w9H@€6‹WÜ^q‹W‚h“¼ƒ9::‹¨!H@¸ËÑ{”••éH ½¬ƒK–u8 Vá±BœÑfñŠ[À+nñJBP‡BÏÈZ·M?yשqst8'·´Y¼nñŠ[ „ á.Gï ·:2S½'*+%·´Y¼nñŠ[ ÄÕñÅ_|¤³ãí=/--MÇ·HMMíôœ=ßÙãý}>j@¥%%*šúÛp«Ã‰«U^^Ž ¤·‘îì·GAA¢££ÕÔÔdkíëéó=Þßç£d·Z“¦'cÂu2|®çæá–;sxÜâ·@ˆ;' æâÜH·‡yÕãç;{¼¿ÏG ÈÀ!gÿA]ž¡ûÞQÊÚ²·ŒMÆ+௸j@Ü%1b„† "edd|r|ذazÿþýÇmóØìk/:{¾³Çûû|ô€¸?%Å%*Ž_n ·ÊŸ½¦GípK›Å+௸z@z)qŒû÷ï+!!A)))þ;“¬tç<ŽÏwöxŸ÷&{õV=®ãó”('@ ˆ;' &š››­blz@ÚN<ì8FLLŒÕ5gÏŽÍß}±}óæÍ>=Ÿ;o×”ÕÅ éºç­Ãœ~½úúúAí³·¶íàõ۴×ÞÛ6Ÿ³øàû‹Ï¶ûóûkP& mÕH˜}Ý©Ép|¾³Çûû|Ô€¸ÙìV¥¥*™¼LM£C”7w­Ëf·Â-m¯€[¼â¨é¥dÉ’%zðàõøéÓ§JLLTrròg³D566¶9KTë×íìùÎïëóQâÆ³[­Ú¢†1ãtlÂ|äÆ-chñ ¸Å+nqK ˆ»­ÒÖ:ÕÕÕ µö9Òªÿhiiùä9fmŒöÖÉh+±éèùÎïëóQâ~äî;¨KAÓtÇ'FÙÛvã¨L+¡:Ô£ÏGˆûP\\¬²IKn5ol6n¹ƒxÅ-^·ô€ ¶d05 ý0»ÕŠ-z6fœj',Ðá¼|Ü2†ðŠ[¼n©!!á.‡ëÉÙs@?&èGßXemÛ…[î ^q‹WÀ-= $ $ Ô€ôÂp«¢b•Ç-Ñ‹1¡:4Žöâp+j@A|—#{YŠžSuäB)(Ä-w¯¸Å+à–j@z!ñؽ_W¦ê–ß$eíèßÙ­C‹W¼nñŠ[ „ ñлEGŠT³Øn•»`½[ ·â^ñ ¸Å+n‚Ä訨PÎÒMz>&LU©ðp^H@z@zav«]ûuÍŠnZíöp§ƒ;H€WÜâp‹W‚×s¤°PG£“ôbt¨rm°zAëÉZÀ+nñ ¸Å+ AˆË‡[å.Þ¤ÆÑa:•¤¢Â#Üéàà·xÜâ•„ ¤f·ÊØ«~“uÝŠõ'$ = ®nUP¨Ê‰‹¬^œÅÝv¸wðŠWÀ-^q ô€$ xœ§5»Õ¢ V‡-fñouŒõ¼â·€WÜâ•„ ÄåíÒ÷ê¦ï$k†+3Ów:¯xÅ-à·x%!¨q9f ³–‡YÓ#{ɦ5Ü €‚d Üå°Ù¬ÕËÍ*汋­U͹ÓxÅ+n¯¸Å+ A ˆËÉÚ¾[·}ãt% ^Ù»÷{Ô chñŠWÀ-^q Ô€$ n’>¬êÈ…z6f¬²–¥p§ðŠWÜ^q‹W‚×c³Ùthþ:5QYÜ{Èp+j@7ËÆ¦eèGßX]LPΞÜé¼â·€WÜâ•„ ÄõÎËWí„z6fœ²Wlf¬'௸¼â¯$ = ½3Ü*oîoíJ'/Uqq1w:¯xÅ-à·x%é<¾øâ‹´iii>|¸Ejjj·»úõÜý|ž^’µu—îúÆèRÐ4åî=È HÏ‘¶¢  @ÑÑÑjjj²ˆµöuõ¸«_ÏÝÏçÉ= ‡òulü<5Œ§¬•[¸ÓÁ‡^ñŠ[Üâ·@ˆësñm¤ÚÃ<ŽŠŠêòqW¿ž»ŸÏk@ÊËË•7g^ŽVÉ”å*--e¬'chñŠWÀ-^q Ô€ôN2lØ0½ÿþã¶ylöuõ¸«_ÏÝÏçi= Y©ºç­‹Á3tè@2ÜAÂ+^·xÅ-ÐÒ» H[û‡ Òåã®~=w>Ÿiv#&&ÆÊŒíÓüíîÛ§OœÒ‰ˆyz꡼õ;Üûg›m¶Ùf›m¶Ù Ûô€Ð2à{@Ìp«üÄ߆[O]¡’âîlp ¯xÜâ·@HÿÖ€˜}]=îê×s÷ó 䬔tÝ÷ŽÒ…™:”Ép+ÆÐ⯀[¼â¨éÇY°;œ%ª½ã­_×Ù×s·óyBÈáÜ<7W?yE(kÍV>H¸ƒ„W¼nñŠ[ ¤oÖio=³öEGë`ttÜÕ¯çnçÈ뀘áV‡g%[íŠV¨´„áV VBo#†êÑç¨= f¸ÕCï‰::K¹ÌnÅ$¼âp‹WÜ= ÄÀ wI@lmŸ·ÊÉSÝØ9úÉk¼®MãCƒ1´xÅ+௸j@ž£Q£Ú¥`æ*k¸Õ‘i+UVVÆwðŠWÀ-^q ô€$ .H@ÚŠûφ%*?;— j@ÞO@ø%å^ñ ¸Å+nñ@ABÂXOÀ+^q xÅ-^I@øÿÚ»×(®½ã÷O IP¤¢(Z”D%i¬•ˆ¢”Š¢(X ŠE,¥HEQŠ¢(½‹OÅRáŠRQ|,Š¢ Ô«ä<ùNŸ•u³»3“5‰y½Ã‡ìîLfg?;çÌ|Ή$¾ò•xËWÞ’  ˜ørúòé¶wÁŠå ª$¾ò•xËWÞ’ ÆyëI|å+o‰¯¼å«‚©@´rð–¯ÄWÞò•x«D@ˆˆˆˆˆè!Þò•¯Ä[¾ò–ô€@1ÎÓXO¾_yËWâ-_èÑÒÁ¾ò•·¼å+oI""""2D@´rhé ¾ò•·ÄWÞòU9 Ä[¾ò•xËWÞ’9 @´rhéà+ñ•·|%ÞòU9 DDDDd­¼å+ñ•·|%Þê@s@Œõ$¾ò•·ÄWÞòU)NOOÏ5ràÀÔßߟiÿþý¹ÛÌ[¿Óåý~z@´t_ùÊ[â+où*€t@ÚqêÔ©488˜ž={–ihh({m¼ëwº|¢ßÏ""""@º@ââÑï§DKñ•¯¼%¾ò–¯H‡döìÙ©··7-]º4:tèå}}}iddäíóx¯µ"oýN—Oôû™b¬'ñ•¯¼%¾ò–¯HEÜ»w/ §}ûöµí!‰°R¦G¥~ýN—OôûéÑÒA|å+o‰¯¼å«R!/^¼È&cëiË’qíàŒßž{î¹çž{î¹çž{Þéói@šÍ‘ˆ×ÊÌɨ_¿Óåý~z@´t_ùÊ[â+oùª¤¶oßžîß¿Ÿ=~ôèQÚ´iSÚ½{÷˜»D=}ú´é]¢‡0å­ßéò÷ý~æ€ëI|å+o‰¯¼å«R!/^LË–-Ë.ìçÏŸŸÍÿxõêÕ;ëÄÿÆhõ2šÍ¡h·~§Ëß÷ûéÑÒA|å+o‰¯¼å«2‰˜9sæý~þ @´rð–¯ÄWÞò•x«D@Œó4Ö“øÊWÞ_yËWz@ˆ·|å+ñ–¯¼%= @ˆˆˆˆˆèÑÒÁ¾ò•xËWÞ’ Æyò–¯ÄWÞò•xkˆ"€håÐÒA|å+o‰¯¼å«s@ˆˆˆˆÈ Z9´tð•øÊ[¾où*€Àâ-_ùJ¼å+oÉ Z9xËWâ+oùJ¼Õ"€ 怑= Ä[¾ò•xËWÞ’ ÆyëÉW>ð•·ÄWÞòUâ-_ùJ¼å+oI""""2D@ô€hé ¾ò•·ÄWÞòU9 Ä[¾ò•xËWÞòÁ Z9´t_ùÊ[â+où*€À""""2ˆV-H|%¾ò–¯Ä[¾ 0ÄXOâ+_yK|å-_tÌR¦ýû÷ë!Þò•¯Ä[¾ò–ô€ ;œ:u* ¦gÏžeÊ^3„ˆˆˆˆÌAåDøˆT[# èÑÒÁ¾ò•xËWÞ’TO___yû<Çkæ€ëɾò•xËWÞ’9 ¨œžžž1¯õöö¶ 5Õ³víÚôÅ_d½)+W®Ì~¿çŸþù{}¿éô|xx˜]x^?¯SåyÔ³üpþRx>‘ç/D0i@¦Íæ€Äk€‚Ê©ÝëéÓ§…ï‚ 7ñ¿?ÊüFêç†U)“†²$xËW¾‚·|å->l_( ¼_ùÊ[ð•·|@|x  ˜\ôôô¼ªãÚµkiÍš5iæÌ™iÖ¬YiÇŽÙÿ‡Aç¾ÆÿשùºmÛ¶ôøñcÆTLx¬N¨¾ŽU×VÏ;wÒÚµkS___Z°`A:sæ SºpÌΞ=›1ððáô~ýúìx Åã ˜Þª#*•_ý5ŒŒ¤W¯^¥={öd±nݺtõêÕôæÍ›ÌÛ£G¦•+W2¦BΟ?ŸÔ êÖIÏÝ»wÓâŋӕ+W²ú y¾ùæÆTÌ¥K—ÆõÍ0–eË–¥Ã‡gç°Ð¡C‡ÒòåË8I¢;Äɱ··—] zCP /_¾LK–,ÉZäÔ êÖÉÎöíÛõx¼V¬X‘ž€ !€€€"€€˜Úá£^Ë.^¼˜V¯^fΜ™úúúÒÚµkÓƒƬ÷óÏ?gëÅ:õÛ¹qãFZ³fMözoooZ¾|yºpá˜}9~üxöw3fÌH³gÏN»wïNÏŸ?g³gϦE‹eû²téÒtúôé1ûýèÑ£´mÛ¶4kÖ¬ìýb[[·nM¿ÿþ»/€Àd !­^Pñ×_¥‘‘‘·!aÅŠcÖÊÖ«çúõëY ˆÐòäÉ“ôæÍ›´k×®lýõ9räm°‰0ëĺ5~ùå—ìµááá,˜„âqãþǾÅók×®eÏÿþûï,ðÄþ€À$ þùçÛ×"„Ôz)×»ÿþ˜mÄE,«ï1yýúuöÚ’%Kr÷+z1j ŽÙŸ;wîŒÙÿØ·ÐíÛ·}¹¦ZÉ{½ÝŒÕl˜Wcˆ‰€²aÆ,pÄë͆„Ű«"ûSë Åßį={ö¤Çû² |Ȥ¢ç¤µÐP?,k¼$æ€lß¾=Í;÷ A>à“ÏcÙ•+WÚîC­§¤F çjÜnÑ!XõÄœ“Ë—/gËã=@`‚ù裲 ô˜$^uùã?²»_}òÉ'éÞ½{Ùk1yüܹsY ¨½± 1GdãÆc¶[? ýÅ‹™Ö¯_?f½uëÖ¥K—.eÛ â.\±|ÕªU¾lM {Š[Õ eH“Á¿üòËl~G¬'n“[[Ü'1 +æ,\¸0Sí–¾1$Ë @ @ €@ €L¨9ÿúQiAw\C ¸†@<p ÄÁ׈ƒ®!týàyòäIúꫯRêííMƒƒƒéòåË]{¿žžžLñ^³gÏN[¶lI·nÝêúû…šñüùólfΜ™æÌ™“<˜»Íd~…öïß_zy«ýk¶Ÿ×®]KCCCÙþÍš5+mÛ¶-=~ü¸åöòÖ/»½àÊ•+iÙ²eÙß,^¼8>}ºíþ×>C«e­¾‹Ø·5kּݷ;v¤§OŸö6oûe¿embËZÇK™²ñðáô~ýúÔ××—)?xð £²Vfÿ”µêÃ"^Lµr–÷Ý•ý¼yë7ó1>g¢|tzNËûÇsŸnåL@&e‰‹ 8€ÿþûï422’þøã´qãÆ®žjÄ{žœ-:t(-_¾|ÜÛ+»ÊZknŽþTy,NårVô¸*ûÙ‹®éÒ¥Bòüùói```ÌvËžƒòö«l½2Ë™"€t/€,XÐZ9D«MÙBVÿZ<Ž~áÂ…Ù¶â„}ûöíRÛûé§ŸÒ¦M›Þy-*¸h͈–ƒhÝxùòå;Ë¿ýöÛ¬&ZŽ?>îÊ"¶CxÜî"! {­â âqT²E—Wq‚Œ}®rývË7oÞœÎ;×ñþçsF¥]|õ¶Õ{•ýnZ1z>=±¤´tiJŸžÒ¿ÿ]ìre­ì±Óx¼”-3fÌèjYËÛ?e­9ÿ;ú³`ô'~W@м–W&&C9Ë;®º@V¬X‘õæ¶#>Û’%K²Ä"ÛmWnòþ¾l½2Ë™"€t7€”y½Ž8X÷íÛ—þúë¯q_Eeé; ×?þXº5#Z¢Ò­ñý÷ßg-ñÍh%‰ÖúŠï¾û. gË£Õ#*îª.Šb{1ü¢±,>g}…R¿~ÞòÆý¨ugG¥´tôŠ6Z]ÛU^ÇŽËZUŠT‚ÍÖ/³<ˆï%<™ˆÊ:ºÉëO$yÞæ½WÑ¿Ï «V¥ôûïÿ<ÿÏþy^$„(kåÊZÙc§ñx)[6âÂ$Ê_, ÅPŽx­Š²Ölÿ”µbìý‰¿ßGÉ+“¥œåWÝ ñ^»wïÎý»½{÷fåa<å¦ì9²l½2Ë™"€LÊã£B™7oÞÛ–™úñ˜E.Šê ^+_«‚Tÿ7 F÷»þ"-*óú1§Ñ}㵫¨\·nÝšuÙÆg¨uß–Ýÿúõdz¼Æ½{÷²“P\¤6{ßPtíß¿?w{­Ö/º¼h%[tÇË^¼x1›ãÐlgQoËŒ—-óÝô€(kåÊZ‘íµ;^Êú߬tZÖÊ쟲ö.µÞZ¯Gãóñz‘WÎòÊÄd(gEŽ«ªH ! ÜE¶SödeÊYÞ92¯^™ŽåL@&e‰ÂøûèUTÈÑêãžëïüÎbŒf, 4†TuQÔêŽ!?üðCÚ°aC6$"ˆÖ”íÛ·¿]^/ûÓé¸ô¯¿þ:ÛN|¾Ÿ­í†$Õî:Óî.X­–7îG|®ÚûÅçï£~Œm<®Ý 4*Þ˜ÈX_Á4n/oý¼åÄ 'Z•nܸ‘=ïæC¢å*NÔ]üE½Í{¯¢ߎNæ€(kåÊZÞöòŽ—²e#¾‹øNêç€Ô?e·—·ÊZ{öüÿOÞke½È+gyeb¢ËYÑãªÊÇd«›ÒT¦Ü”=G–­W¦c9@îqÞ+ lÀÑ*]w1Q®~¬jtÆI8–GŠÊµÓ‹¢šâŽ Qù7ëBŽ ;Æ`ÇûÆí1/\¸ðÎò­ yw Ék‰‰Ö’Ú˜ü‚ã4óˆ ³Ý}·Û-o|ÿh‰Ï¯G+X|®úqþõËïf÷|oµ½fëç-ouŒÄßÄw÷L?{öléÖ®"•u‘måy›·yß]Ñ=!üOÏGÑ»`)kåÊZÞöòŽ—²e#.Zj÷ìÅãvCIŠ”Í²-ÁÊÚ?<ýYÐæ'–÷"1¯œ)“­œ5÷e޹"ëÇ…mÜ:·ŠÒÉ9­Ù9r<çðéVΤ{p )€8xàRqðÀ5¤\C ¸†@<€kH¤+QYA0 ø?=Ùróºv(IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_long_increment_bar.png000066400000000000000000000647261174000617100252430ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxiIDATxÚìÝlT×ÿÿJ«UµZ­VûOµÚ?V«J«Õþ±Z­¶Mó«­KíÚÅËŠ %i\²Ü4lÀ.Ô4Å)MLj·q“O›¦L71NJ’vâÃb1“)qLàc°ÎÚñÄðuœ‘YŸï}¸³w~ÿ¸Ç3Æ~¾Ð‘gæ^Î=sçν÷1çþø„"„B!„,åÌB!„B!„B!„B!„B „B!„B1“OúÓêŸøD¨üã?þãÂ[!9ÞŸ”ùR×bž„õ@&Ë×ää¤úéOª¾úÕ¯ª¿ú«¿Rþ箋<¾ûî»Õý÷߯<ÈJ!„Ìל8q"j£/å¿þë¿ÔN( |Nf×¹hwWW—ú›¿ù›˜m«e“ežB1œŠŠŠ˜ïM›6vHxï‹äsÊd=ív9r$lØßþíߪgžyFMMMéáÁ`PCJzGn¿ýv–yB!d>æþçÔ§>õ©Ð†õ¯ÿú¯Ã6îlyÿdá/£™®²ÙîÿþïÿÖ‡XÙ¯ÿå_þ¥:wîßwB!äV˱cÇÂ6¬ßýîwÞ¿òÊ+ 7Ä©úpæÌµ~ýzõÿðꓟü¤>Vûïÿþïõko½õVÊü‡~Xï Iò릴]rùòe]—},ø¿þ뿪¤½122¢~ðƒ¨;ï¼SýÅ_ü…®KvÄî½÷^õÇ?þÑȉ©yñóŸÿ\×!ÿ_ŽÓollŒù÷ìÙ6ÞÞ½{]ïP%ú¿nÚêfþOOOë_ðe|™¯ÎÈNª ûçþçP½²Ýwß}q/š‹åÏd[ÍÓL¾£é®L|Þ2?ãI¯E¢åk÷îÝa¯ïÚµ+£u^:ŸA&ó’@!Iò­o}+´• ±ìÈÉ_û59™ÓÍù©§žRög–pÜ'žx"éŽìàÅú¿r¢©ì<ÄöÜsÏ¥¼ã,Ç•Ë/ª©îdd²bj^lܸ1æÿ•úYµjUÌñbýÿ¹Hªmu;ÿ׬Yz,óØŽ,†DõÊŽm6–?SmI6O3ÙiNw=àöó.))I{Ù”“˯÷÷÷§½¾K÷3 „BˆáÌÌÌè_íhqq±~½°°0ôš —ñÒÙ µ#¿&:Ç‘_¶å0Šñññ¨‰d¿<ÊÕnd§Hv â “>çëÿþïÿžR›¥W¹³%;Âr\¹¼o94EÚ&;Lnbr^äççëcÞùË_Æ}¿‘ÇÊË0™ž”Ûn»-kI¥­&æÿ?ýÓ?©?ýéOaãø|¾¨¶ŒŽŽêzËÊʆ €ærù3Ù–Tæi:˨Éõ@&˦ý]"=KñÚíl£Y6Ò‰ÉÏ€@!&rgÊ>TB…p¾~èСŒù ü믿ö‡?ü!l˜Œ›¨~9±T"'™F{óÍ7õ0Ù!q¾.;,©´Y½p¾.‡¸Ù Ÿëya¿ßÈyá|¿²éf.$‰<Üf.’J[MÌÿX‡9{E¤œ?>4,²=yyysºü™lK*ó4eÔäz “eÓù]ÇñÚíDj¬÷“¬wÂäg@ „ ³|ùò°ªý ²üu¾.ãe²î«_s¤¸¸Xåçç«ÒÒR=n¢Èa\Ry,¯™žëé …B¡P( q‘±±1µfÍšÐùòxbb"æ¸ÃÃ꺺ZíÛ·/n}±zL/¦†çrzòÛÅ™ŠŠ 544¤{OdA¿<ç9ÏyÎsžóœç<çù\?¿%RUU¥{5œç€lÙ²%îøSSSúdmz@è¡P( …B¡Ð’vbýÚŸ¨Ç!@bS!¯™žëé …B¡P( q¹â•œ÷á<Äy¬GyDŒŒ„ת­­Uqa²¯*^u*ÓáÙž™»òº÷uÕ}¢[8qB½vâ5õâ‰uyéÄKºÈ0)GOU='zt‘ÇGûŽ2ÿ( …B¡PnU€.ä+¹ò•ylƒCÒÛÛ«/Õ+;þ%%%úü`0˜ð ¹—F¢ûj¸žíé¹+‚õÖ?É!ëß*ëß=Ö¿oYÿ¾mýûŽõo£õo³õo«õïûÖ¿ïÉ¿éï1ÿ( …B¡Pþ°Hï„î¼dïBœÞ­€…GéÉ tvªÀæÍ*PU¥Û·«À÷¿¯µµ*`µ;ððÃ*𓟨ÀÞ½*°{·–¬Þ}ûTKK@×½ys@UVÔ¶mUSP;wÔ®]õ£ÔÃÔO~P{÷Ô°07@( …B¡PY¨QßøÆ:¤ÔªUJÝsRßú–Rßþ¶RßùŽR7*KJmݪ”%÷;ùÏÿLZïÞ½CêñÇoT-Õ®Y£Ô}÷)uÿýJ­·üðÀJ}ï{áU[³D54 9*-jQêå—Õ¾}ªy Yy<ªe Eµ´ªýûUÛ@›:0p@=7ðœzvàY=ìXï1VÖ …B¡@H:ÙøÑFõÊ+¯„•Ŷ²ùöô·Óšo›¬2Læùb^Iïx‡Ú?½_MOOëy¸azƒz`úÚŠé U5]¥¶OoW;¦w¨ÚéZµ{z·Ú:½Uµþ©•…B¡P ‹ ëëÃîÉòðûšojiQÝݺGa`ß>5Ðܬ<5 ¯·¶ªýûÕ@[›8p@ <÷œxöY=ìÍ£GÈ-V66+ºqž—Ì·5Ö¿û¬÷[ÿdY|Àú'˘sÞ}×ú'=Llä( …@1ŸýìgaÅ@¶o?Vïo~ó›y i™?*Bo0•ùf ó[ITï¯íSO=uE]¹rEÕÖ^Q?üáõ£]±Ú{EíÙsE=úèkÞ^± vÅš?WTSÓçÍÍïB¡P( !  Îy)¿ÿý祿üaõ¶µµ-*€ÈÉû»w§7ßdRuuWæ Ow=­ž³Úm—×^{mþ]íÅz¾¤³(Ëø7Nß‘·é†}˜,{Ó6¨ika˜¶ÞÄtE…š®ªRÓÛ·«é;Ôtm­š¶"y~©¾>iÝ2¯2XèyÎFœB¡P €ÈÎŸí ›w/¿ü2I Û_Ú®öìÙ*GŽÉøýÉa~ê'?I{Á¸b-L„B¡P(€E W­™âìMøÝï~@(@*_¨ ›o„B¡P(„’]€ìß¾=¬/¾ø¢€TU½£~ñ‹_„Jä|›/ñýú×jà…þ÷äý§žºqòþÓO«gž¹q¿œ°ï<ÿ~uò·¿3€È!eÎ@…B¡@I}aõ Bæ#@®ÔÖ*õä“i/r•±¹Èºu°÷öÈ#,(€œ)/·¾‹{C¥µµÕ@vîüYØû{õÕWÙ¨S( !€²˜â³æ³ O=õ¡P(  €@( …@ dÞäÔOª>*===dž¤õíVõì•goÜÓæJ­úᕪ]ù‘zøÊÃjÏ•=êÑ+ª½Wöª†+ êgW~¦š®4©ú+õêÙ·Ÿ5¶~ûã+¯(ÿ‘#Êï÷+ÿ±cÊÿ«_é+ÑùTþßüFù­7í·–'¿õÙèñž^?ï·þ²ƒB¡PÈ<Èè訪©©Q………ºÈãË—/‡ÓÒÒ¢ŠŠŠtñxôdò?”‡ÕûŒµ—Ÿéòö^WWFùÖëÎ6466FÕ_S3@žyæ„êííÕuÈß×_=¬ý™dËoÑ? >ýôÓúïï~÷»œo_xÎsžÏßç·$@ªªªô ÎyÈ–-[è¡„z@è¡ÄUH,€d»$ =ö˜±íÛ÷‡Õý /é)ûeaõþüç?Ÿ—¿º¾üòq GÉOÞwžÀ/¯ýîwLXïko¼¦ùé«cþcêWþ_©çüÏ©ƒþƒê7þßèa‡ý‡U‡¿CñQÏûŸ×ÏŸ>̯áz@n€ÄúµßùZ¬s$äµtÎÉpŽïvx®§@ €ÜJ‘{ï ¨ëû.ËŸ~îñ¨–5ÐÚªöïWÖúyàÀ5`}¬õ¡ KVom핌¶ C‰ïdmÊTYÚÛ†ïMÏè6Uo¤Ç2Ímƒ?bYÚÚþ¯õ™T ÐË^ee@mÛP55ë»P»vÔ~°¶mkU°¶Á²n XóúBÒ6—X®¦§§Õ‘é#z;Q6]¦œ¶¾‹ÓåªrºRmŸÞ®vLïPµÓµj÷ônU=]­6MoR/õ½ÄŽ<ÉnäŠWrÞ‡óXWÁ’/J¬«DE”l|·Ã³==@ äVˆ~C,dn’é¶¡®îJÒ6g²møOëŸÌsväHV322¢¹’+_I‘Çòš3roŒx÷ɈuE¢ñÝÏöô €@€Ì£8/Ù»§@ €sÙ»÷¼>±Þ.¯½öš€<8õ ^Û套^ €,T€,Æ@  ‡+¦’ʶ!€ÄºBb.ÒVSca¡.T"!”é¶¡²ò¬jjj ¹h)€<ôÄCjÏž=¡"0dÇ€@ €d ‘Û2¿¶ OZë_S‰Ü6¼òÊ+ìØ@ €@€@ €B €@ €@ €@¡@ €@!€@ €P €@ B €@ €@ € !€@ €l'///ª'ž,---ª¨¨HÇc|x®§@ €@(ÄPŽ?¶ž 8œéîî¶V.åjrrR—ÍÖ7H^35<×Ó €@ b0eeejbb"c€Èμßï=—Ç›äKihx®§@ €@(ÄPNž<©£Ñ’C²òóóUii©jooOXGaa¡š =—Çòš©á¹ž €@¡C‘é‹/Æ><<¬ª««­/Ͼ„ç”DFðbjx.§çür:SQQ¡†††tï‰ÞPZsñÜ@|>_XýMM£F62‡¬v9Ûë=ë5Ùȸ™AybÃÍ®¿­í’‘LsssTûËfÊŒ$Óå탺:#éìì «ßë=k õõõQí7¯×›ñòvIvh ¤µµ5ª~S k¿çC1€dº¼½×Õe ò#[dý55ÓÆâl¿)€È:ÀÍöÁ$@œõ›ˆì ;Ûëñˆ›í«)€ô÷÷‡ÕßÑ1n ‘í_\o }}}9ÝŸáyzÏoi€È›ØµkWÒñ¦¦¦ôÉÚô€ÐB= ô€ÐB= ô€ÐB¡$ãÈyï¼óŽk€Ä:§B^35<×Ó €@ â2gΜ‰{âµlÄGFFôã±±1k…SvžHä!LöU¥@«Ne:<ÛÓ €@ ©߯­¬ïÂÀÀ€^ß XëªG <ý´°¾h­­jÀÚæXóvàÀ5`möïW'û[0±Ø";ݧNŠ9¬··×ZÑ®Ó;þ%%%úü`0˜ð ¹Œo¢ûj¸žíé@ €¹Ý6 47ƒ z ôô €@ €@ €×¥£¿Cõø{ôyÀ¿òÿJ=çNýÚÿkuÐPýÆÿuÈHöVþuÄD=ï^¿vôÍ£„@ €[ 'êëõöÀ.Gfoç^¶ O[ÿÒÝ644@ €@nE€$Û6@ €@ €@ €lä羟«ßþö·¡rìØ1B €@™€˜Ü6@ €@!€@ d1䨱^kS= ï°þòËz>67(g@µ´ ¨ÖÖµÿ€õ‘ ¨¬ÿ? Çß¿ÿO€@ €’þ¶A¾{én6nœ €@ €@ €@ „@ €’@xàÿS•ƒù°3——UŠ‹‹ÃÆiiiQEEEºx<ž¤u&ßíð\O€@ €Ì€Dn}ôQ2Ý?~üxØNxww·õ—«ÉÉI]6[Ÿ¬¼/ÉÆw;<×Ó €@ €LYY™š˜˜=—s¿ßz.7É—,N’ïvx®§@ €@1”“'OªÆÆÆ°× Õììlè¹<–×â%Ùøn‡çzz€@ €C‘é‹/F#™üüü„ç”$ßíð\O€@ €b rèÑ®]»ÒîaXL= Î…Ì™ŠŠ 544¤ç¡ÞPZsñÜ@|>_XýMM£F62‡¬v9Ûë=ë5Ùȸ™AybÃÍ®¿­í’‘LsssTûËfÊŒ$Óå탺:#™ÎÎΰú½Þ³FR__Õ~Sñz½/o—d‡Æ@Z[[£ê7ÁÁÁ°ö{>ôH¦ËÛ{]]F"½ü‘õ×ÔLˆ³ý¦"ë7Û“qÖo ²ƒîl¯oÄg n¶¯¦ÒßßVGǸ1€D¶}p½€ôõõe¼¼]³vðMÄY¿)€444Dµëµ­FÒÓÓ““ý¿[ rÞÃ;3Ò9åöâ9ÎñÝÏõôè¡„z@è¡„z@è¡„—9sæLܯí«D˜W‰Š<„)Ùøn‡g{z€@ €ÑîS§NÅ.—åwŸŒXçP$ßíðlO€@ €2RPP° §@ €@!€@ €@ €@ €@ €®< €@ €@ €@ˆ}ÚTÊ’%K €@ Ä@Î ùùùH€@ €bî,Ùy°ïâmgbbB¿&;‘€@ €b Ë—/W333Q¯Ëk+V¬@ €@ €s‘C­â„s@ €@ FR\\l-ï›ôaW³³³ºŒ[ÀFµlÙ2¤@ €@1{H¼“Ð_ýu¤@ €@1‰ßï·>„Uª  @yüöÛo§UÇ… TUU•*,,Ôÿ_vJ]ö7YZZZTQQ‘.Çøð\O€@ €nD˜a.^¼h}€÷¨“'OêC¸äŠZÛk”›I'ÝÝÝú*\“““ºl¶–yÍÔð\O€@ €â"²‘vöxÄ:Ñ=ÈμôÊ8{hä<SÃs==@ €@5@¶mÛ¦ÊôNèr"{WW—Z¹r¥>„KÞÄÕ«WÃ"ãÈ KKKU{{{Âú¤-Ò“bGËk¦†çzz€@ €,Z€TWW‡°‘éÐeܽ{÷êK÷ƒA½r®««‹9îðð°žæ>Ù€¦Ñcâl‹ÛṞ €@ ‹ rÒt¿~l÷xHïÅŽ;ôŸJä×~‡ó"Ò/SSSzº‹±Ĺ9SQQ¡†††ôá[zCiýÍÅsSñù|aõ75ÙȲÚål¯÷¬×@d#ãfþåMˆ 7»þ¶¶KF62ÍÍÍQí/›)3L—·ä‡ ™ÎÎΰú½Þ³FR__Õ~Sñz½/o—d‡Æ@Z[[£ê7ÁÁÁ°ö{>ôH¦ËÛ{]]FÒØØUMÍ´1€8Ûo ²p³}0 gý¦"û+ÎöúF|Æâfûj ²Ÿæ¬¿£cÜ@"Û¿>¸Þ@úúú2^Þ®Y;ø¦â¬ß@¢Ú¿õÚV#éééÉÉþ_NnDë±ìD§z9é: ‰vø“$Ö9åöc`x®§G= ô€ÐB= ô€ÐB= ‹úNèrå&‰ôZôööêǧNJùÙ‘² DŠ޵gÏž°“ÔGFFôã±±1k…S«AŠw“}U)¹šV¢«Ne:<ÛÓ €@ €Ü̱cÇôŒ”¬]»6ì9©<ÕȉåÒc"ˆÙm}+œ'¡ jÖYkZ©³¤¤DŸÿáì1‰u…ÜK#Ñ}5Ü Ïöô €@ 1rýúu éùX±b…>”*It¾ÈB˜ €@ „@ €@ €@ dADn"¸|ùò°“Î×Xöûï¿ €@ fOBuçóÓ§O'½”, €@ €¤9é\6Brß'@ä^K—.E €@ €sq¢#ò¾©Þ„@ €@RJ~~¾úøã£À!7ÕKt7s@ €@I;r²yYY™š˜˜Ð‘{œ;wNÃDnH €@ ÆrñâŰ»Ÿ;Ëää$R €@ €˜½ ¯ DzBäáR¸/ €@ dÎB €@ Y¿  €@ €Ì)@ä+¹pႪªªÒWÎZe}¢²SâLKK‹***ÒÅãñ$­/Ùøn‡çzz€@ €,J€䦃nÏ!¹ÇúOž<©oh(—ð}Ü^£XéîîÖwU—“Ú¥l¶>Yy-^’ïvx®§@ €@È¢ȉ'Ô† \]ñJ6Ò‘=ÎÈιßï=—Ç›äK–áøn‡çzz€@ €,Z€Ä»¯”TÏ)..V]]]jåÊ•ú.yW¯^ —ò¤gÄŽ ™ #€@ €c‘;™@ €@ˆ€¤r¬ÂÂB¤@ €@qûJWöåv#KQQ‘:räR €@ €˜;‹Kí@ €@æ Ë—/WuuujttÔõÎt¬Ã·Ò+---ºFŠÇã1><×Ó €@ dQäëÓs<Ò r¿õ¡ž>}Z}üñÇÄÍðÈtww[ H¹šœœÔe³µ$Èk¦†çzz€@ €,ÚC°ÆÆÆô ½¤¤$Ô;±ÊúDäýñññœDvæý~è¹<Þ$_JCÃs==@ €@¸¡éý8sæŒZ»v­î8,]º4éδŒW\\¬ÿOii©jooOkxd¤gfvv6ô\;¯Èåvx®§@ €@‰9?DfòÊ•+Sþ?ÃÃ꺺ÚúrìËhx¼çÉòn‡çzz€@ €ƒ™ššÒ'cg:|!÷€82g***ÔÐÐ>|Ko(­¿¹xn >Ÿ/¬þ¦¦Q#™CV»œíõžõˆldÜÌ¿ ¼ ±áf×ßÖvÉÈF¦¹¹9ªýe3eÆ’éòöA]‘LgggXý^ïY#©¯¯j¿)€x½ÞŒ—·K²Cc ­­­Qõ›Èàà`Xû=zŒ$Óåí½®.#illŒª¿¦fÚ@œí7Y¸Ù>˜ˆ³~S‘tg{}#>cq³}5þþþ°ú;:Æ$²ýëƒë¤¯¯/ãåíšµƒo ÎúM¤¡¡!ªý[¯m5žžžœìÿe ©Ü„о?H.뜊r{‰10<×Ó£„z@è¡„z@è¡„EÕyÓÁxIõ!²‘ Ô^k-8ò QªÃ#a²¯*^u*ÓáÙž €@ ‚u3²ó`ï<Û™˜˜Ð¯ÉNd*éííµ>œuzÇ^®¦%çwƒÁ”‡Ç:‡Bè¾n†g{z€@ €Ç gff¢^—×V¬X‘•sF ²zŽJ¶§@ €@qôÄH¦ç€@ €@HÌÈý9ä>rØ•\½IŠÜ€p£õ ,[¶ )@ €@Ìžï$ô×_)@ €@ÌÞ䯵ßWés#¤Èã·ß~%@ €@Ì„@ €@ €@ daD®vµråJ£wB'€@ €˜Yc}¨Np8KªwB'€@ €”"ÐHõŽç€@ €â*ôr@ €@²¹äîää$" €@ €Ì=@N:¥Ö®]«* €@ €Ì-@âÝ=«`Åú¿‘iiiQEEEºx<ž¤u&ßíð\O€@ €E{z¼’êù!±ÀáLww·õ—ëC½¤l¶>Yy-ÓñÝÏõô €@áF„.{QEvÎý~è¹<Þ$_² Çw;<×Ó €@ €¸Hqq±î1)--Uíííaà Õììlè¹<–×â%Ùøn‡çzz€@ €,j€œ9sF­^½ZBŠ<–×2Éð𰪮®¶¾ûö$:¼+Ùøn‡çzz€@ €,Z€ô÷÷Ç= =S„LMM铱é‰ »8SQQ¡†††ôá[zCiýÍÅsSñù|aõ75ÙȲÚål¯÷¬×@d#ãfþåMˆ 7»þ¶¶KF62ÍÍÍQí/›)3L—·êêŒld:;;Ãê÷zÏH}}}TûMÄëõf¼¼]’immªß@ÃÚïùÐc ™.oïuuHcccTý55ÓÆâl¿)€È:ÀÍöÁ$@œõ›ˆì ;Ûëñˆ›í«)€È¾š³þŽŽqc‰lÿúàz#éëëËxy»fíà›ˆ³~SihhˆjÿÖk[¤§§''ûYˆôvlÛ¶MMLL„^“Ç[¶lÑ÷1XçH”ÛK@Šçd8Çw;<×Ó£„z@è¡„z@è¡„E}'ô™™™¨×¯_¿® RªC6Ò###úñØØ˜µB©Õ¿E^%Jî5ë*Q‘‡0%ßíðlO€@ €âH0Œz]P’*@z{{­gÞ±/))ÑçDÖ)÷ƈwŸŒXçP$ßíðlO€@ €r3k¬U.;>>®Ï]"°>\9<+I:·êô €@ Ž+`Å; ýÝwßU€@ €bô2¼ éíž)ò|@ €@æ €@ €@ €@ o¼ñ†Ú³gOÔë2s?Ž €@ æ²|ùruõêÕ¨×嵕+W"@ €@ˆ9€Äº'†%K– @ €@ˆ9€Èó&&&¢^—{,]º)@ €@ÌDv|¥§cxx8t#‹/êž¹A! €@ €ˆœëïF„SSSH€@ €bö2¼r¸ÕëõoDxõi”@ €@1@ €@¹%²ÙúÔ"¯¬ëð®diiiÑ'ÈKñx<Ƈçzz€@ €,Z€tuuéû8/»+‡d½ÿþûiÕ#9q=@ÒIww·µ€”«ÉÉI]5òš©á¹ž €@ ‹ ÇŽ õJ8rúôi½Sj>úè#kÙ¸O]¾|Ù5@dº~¿?ô\;¯Èåvx®§@ €@È¢HII‰ÞÉåw‘+`¥sYˆ9ò¼¸¸Xåçç«ÒÒRÕÞÞž°®ÂÂBÝ;òX^35<×Ó €@ dÑĉŽÈ;Ÿ§z'ôóçÏ[ØÆ”z<ä~#ÕÕÕÖ—g_ÜqbýÁ‹©á¹ž €@ ‹ ²£üñÇGC.ÛìW|;‚‘‘‘”¹’Þ9Y{1ö€82g***ÔÐÐ>|Ko(­¿¹xn >Ÿ/¬þ¦¦Q#™CV»œíõžõˆldÜÌ¿ ¼ ±áf×ßÖvÉÈF¦¹¹9ªýe3eÆ’éòöA]‘LgggXý^ïY#©¯¯j¿)€x½ÞŒ—·K²Cc ­­­Qõ›Èàà`Xû=zŒ$Óåí½®.#illŒª¿¦fÚ@œí7Y¸Ù>˜ˆ³~S‘tg{}#>cq³}5þþþ°ú;:Æ$²ýëƒë¤¯¯/ãåíšµƒo ÎúM¤¡¡!ªý[¯m5žžžœìÿe r²yYY™š˜˜Ð¹~ýº:wÉ:Y;¦x72Ì ±Î©pžâvx®§G= ô€ÐB= ô€ÐB= ‹¶äâÅ‹q!WtÊ$‘ø¸ÝC266f­pjõ/HñÆ·¯*%½0‰®:•éðlO€@ €çÐ3¹o"€ôööêÞy]Nz—ó?‚Á`ÂC¶ä^‰î«áfx¶§@ €@™Gô,äé@ €@ €@ $ÛÕ‡\Iäô+VèC”V¯^ €@ fò€õ!^¸pA?Þm-ÍΓзlÙ‚ €@ æ"÷«°O_¹r¥†Ç;ï¼£o.˜ÎÐ  €@ $­+Vɽ?äùÌÌŒ~žêÐ  €@ $¥Èec¥ÇcxxX㣸¸X¿.½"‰nH €@ iGv|ç}TUUé×å¶ìr‡t@ €@1z^¹9 nµÊÞò(ù@îÑWÈ"€@ €£!€@ €9ÈòåËU]]½€@ €¹ˆÜÿC.Á+ç}ÈÕ¯î·>ÔÓ§O«?þ@ €@ææ¬±±1½B—ó@ìÑå\––5>>Ž €@ ssˆô~œ9sF­]»6tO¹á&ùB¤˜ÍÖ§æ¼·ˆ\ÖWŠÇãIZO²ñÝÏõô €@á$ôˆÈù!2“åé©D68‚•H€tww[x¹šœœÔE"¯ÅK²ñÝÏõô €@ .óÑGYËÆ}êòåËQ‘s¿ßz.õª$ßíð\O€@ €E ™™ÝÃἡ]äÞ ©Fâ#GŽèÇ‘‘“ÝgggCÏå±¼/ÉÆw;<×Ó €@ dÑdõ¡:Áá,rH*9þ¼õm =H¬sBÕl|·Ãs==@ €@-@²³è&‚‘‘‘¸;äô€„ÃÃ.ÎTTT¨¡¡!}ø–ÞPZsñÜ@|>_XýMM£F62‡¬v9Ûë=ë5Ùȸ™AybÃÍ®¿­í’‘LsssTûËfÊŒ$Óå탺:#™ÎÎΰú½Þ³FR__Õ~Sñz½/o—d‡Æ@Z[[£ê7ÁÁÁ°ö{>ôH¦ËÛ{]]FÒØØUMÍ´1€8Ûo ²p³}0 gý¦";èÎöúF|Æâfûj ýýýaõwtŒHdû××H___ÆËÛ5kß@œõ›HCCCTû·^Ûj ===9ÙÿË:@RíåH”X‡o9ë‰r{ Hñœ çøn‡çzzô€ÐB= ô€ÐB= ô€Ð²h{@äžrå&“‰w¬@ ó*QéŽïvx¶§@ €@¹™S§Néû~ÈÎó\D"÷ƈwŸŒtÇw;<ÛÓ €@ €$9|*Ý«`¹IAAAV/œíé@ €@'¡Ç+&Î!€@ €@ €@ €@ €3gΨիWëC®¤Ècy@ €@ŒDnnï$t@ €@1 éíØ¶m›š˜˜½&·lÙ¢ïB €@ Æ"‡\ÍÌÌD½~ýúõyq¹Z@ €@ÈH0Œz]P@ €@ F²ÆúP7Y üøø¸šÕE?`}¸rx €@ €ˆœhï$ôwß})@ €@Ì^†W !½rÈ•y > €@ s@ €@ €@ €[ r~Ç’%KBã{œd9}ú´õamÖ‡o-]ºTíÙ³GŸÈîœ^dI–––UTT¤‹Çã1><×Ó €@ dÑD`!—ßµÇ+ö8É"72ÀqÇ™ššÒ'kÓB= ô€ÐB= ô€ÐB= ‹¤$ÑÕ¯ì’l':Qõ8$H¬s*Êí%ÆÀð\O€@ €EûJWöåv#‹AÎåH%Ò}ùòå.ä2´ÎpÙˆÛ‡dY+œZýâÂd_U*$¼êT¦Ã³==@ €@8$…žŠTÓÛÛk}8ëôŽý²eËô#;㱆—””èó?‚Á`Âs(1‰î«áfx¶§@ €@™§—ì]ˆÓ €@ €ÜÌo¼¡ï\™¹ÇW€@ €b Ë—/×W¼Šu¬•+W"@ €@ˆ9€$ºKy&—á%€@ €¸‘“¦'&&¢^WK—.E €@ €s‘_éé;”Ë ô¤\¼xQ÷Œl’/ €@ €˜ˆœëïF„rO@ €@1z^9ÜjõáÊåi¥Üc}Îûx@ €@ˆ1€@ €@ €@ €,<€lÛ¶MFÂex €@ FR]]ÂF$@òóó‘ €@ Ä@ä> ýýýú±Ýã!WÆÚ±c‡^à  €@ Ä@œwBw>–û,[¶,¥:NŸ>m}X›õ´äæ…{öìÑWÖr¦¥¥EcGŠÇãIZg²ñÝÏõô €@Y´™œœÔ½½½úñ©S§R>DÎ!‘ñ¯_¿®árøðakÙx 4¼»»ÛúÀËõt¤VäµxI6¾ÛṞ €@ ‹ ÇŽÓ3R²víÚ°s@V®\™q½‚;²sî÷ûCÏåq¢»¬'ßíð\O€@ €.ÃkEz0JJJtÏÇŠ+ÔÌÌLÚuHÈ‘#GTMMMè5¹Â–¼îG^‹—d㻞ëé@ €@ Äî9¼ŒŒŒÄ<·ÄN¢+l%ßíð\NϹ9SQQ¡†††tï‰ÞPZsñÜ@|>_XýMM£F62‡¬v9Ûë=ë5Ùȸ™AybÃÍ®¿­í’‘LsssTûËfÊŒ$Óå탺:#™ÎÎΰú½Þ³FR__Õ~Sñz½/o—d‡Æ@Z[[£ê7ÁÁÁ°ö{>ôH¦ËÛ{]]FÒØØUMÍ´1€8Ûo ²p³}0 gý¦";èÎöúF|Æâfûj r± gýãÆÙþõÁõFÒ××—ñòvMŽÌ1gý¦ÒÐÐÕþ­×¶HOOONöÿnùʯÿ´>Àô€ÐB= ô€ÐB= ô€ÐB= áµ>×5¡C°¤÷B~Ñ_½zµ«z=±Î‘(·—€ÏÉpŽïvx®§@ €@È¢ˆ\­êÂ… úñnkivž„¾eË–”êîèË—/ëÇSSSú2´Îpû*Q@ æU¢"aJ6¾ÛáÙž €@ ÄqøP0ÔåªW²sþÎ;ï¨óçÏë{z¤¹tï:kM*ÿWî"ŒìŒ;#(‰wŸŒXçP$ßíðlO€@ €cg\›’çöÕ¯R½ˆÛ8/Ù»§@ €@¹ùÅ^z<†‡‡5>Š‹‹õëÒ+"à €@ Ä@dÇ×yÞGUU•~].ÉUVV† €@ f/Ãkß|p•½åQòÜ£¯E €@ óö> €@ €B €@ ¹ˆ\ñʾündÉÖU° €@ ‹ rt'8œÅy7s@ €@q †ì,@ €@Èœ„^@ €@HÖ"—ÞœœD€@ €¹È©S§ÔÚµkU @€@ €¹H¬«_q,@ €@Èœ„¯¤z~ÈéÓ§Õ–-[TAAZºt©þ`œ=*±p“,---ª¨¨HÇc|x®§@ €@7"Ì0555ª¿¿_ÍÎΪ`0¨žxâ '@ÒIww·µ€”ësS¤l¶–yÍÔð\O€@ €b0gïIº‘y¿ßz.7É—ÒÐð\O€@ €E mÛ¶©ÂÂBc瀜îW£££1‡ëiî“ h‚ãݯÄíð\NϹ9SQQ¡†††tï‰ÞPZsñÜ@|>_XýMM£F62‡¬v9Ûë=ë5Ùȸ™AybÃÍ®¿­í’‘LsssTûËfÊŒ$Óå탺:#™ÎÎΰú½Þ³FR__Õ~Sñz½/o—d‡Æ@Z[[£ê7ÁÁÁ°ö{>ôH¦ËÛ{]]FÒØØUMÍ´1€8Ûo ²p³}0 gý¦";èÎöúF|Æâfûj r˜»³þŽŽqc‰lÿúàz#éëëËxy»fíà›ˆ³~SihhˆjÿÖk[¤§§''ûYˆœ4- ¶}BºäêÕ«jÇŽú NÞzë-kù¸O?>áxSSSzºô€ÐB= ô€ÐB= ô€ÐBÈ"¼ o¬Ç²½lÙ²”ëéííU«W¯VçÎK:n2€Ä:§¢Ü^b Ïõô €@YÔ±ï„.—ÑHHä…©ž"+L¹£úÅ‹c—øÈȈ~<66f­pjuv¼C˜ì«JÉ¥|]u*ÓáÙž €@ äfŽ;¦g¤Dîˆî<dåÊ•®nfèìYg­iåµ’’}þ‡\®7Ñ9r/D÷Õp3<ÛÓ €@ €ÄÈõë×5¤çcÅŠjff&+—핞—l&ÛÓ €@ €@ €@H¶’é½> €@ ä–< €@ €²H"W¯’Ëâ@ €@ÈœäĉjÆ ¡Kñ@ €@Èœ$Þ%t¥p~ €@ ÄøIèñJ~~>R €@ €p^@ €@!€@ €Ä‡`e2Œ@ €@ŒäêÕ«€@ €b ‰®~e—ÂÂB¤@ €@qûJWöåv#KQQ‘:räHJu>}ZmÙ²EßU}éÒ¥úƒ aã´´´è:¥x<ž¤u&ßíð\O€@ €Ey–‰KíÖÔÔ¨þþ~5;;«‚Á zâ‰'4Hìtww[x¹¾Ù¡”ÍÖ'+¯ÅK²ñÝÏõô €@á*X#qÂFvÎý~è¹<Þ$_²8I6¾ÛṞ €@ Ä`Nž<Ö"ç’Jœ@It~I²ñÝÏõô €@ †ráÂkù¸_ŽŽ†ðžÎ¡_ÉÆw;<—Ós.dÎTTT¨¡¡!Ý{¢7”Öß\<7ŸÏVSÓ¨‘Ì!«]ÎözÏzD62næ_PÞ„€Øp³ëok»dd#ÓÜÜÕþ²™2cÉtyû ®ÎÈF¦³³3¬~¯÷¬€Ô××Gµß@¼^oÆËÛ%Ù¡1ÖÖÖ¨úMdpp0¬ýž=Æ’éòö^W—€466FÕ_S3m Îö›ˆ¬ÜlLÄY¿)€Èº³½¾Ÿ1€¸Ù¾šˆæî¬¿£cÜ@"Û¿>¸Þ@úúú2^Þ®Y;ø¦â¬ß@¢Ú¿õÚV#éééÉÉþß- ·ÞzËZ>îSçÏŸO«‡z@è¡„z@è¡„z@è¡$­ôööªÕ«W«sçÎ¥tŽE¹½¤xN†s|·Ãs==@ €@ˆ‹È s•õ)^¼x1áU¦äÒ¼±®yS²ñÝÏöô €@ ïF†ÎȽ1âÝ'#Ö9‰Æw;<ÛÓ €@ €Ì£È òô €@ €@ €@ €@ „@ €@Ø• €@ €@ €@!€@ €@ €@ €@ €@ €@ „@ €@ €@ €@ €@HZÉËË •dÃçLKK‹***ÒÅãñžëé@ €@ @$×㥻»ÛZ@ÊÕää¤.›­%A^35<×Ó €@ €Ì#€Èμßï=—Ç›äKihx®§@ €@™c€«üü|UZZªÚÛÛÖSXX¨fggCÏå±¼fjx®§@ €@™C€83<<¬ª««­/Ͼ´ê¼˜žËé92g***ÔÐÐî=ÑJëo.ž›ˆÏç «¿©iÔÈFæÕ.g{½g½F"7ó/(oÂ@l¸Ùõ·µ]2²‘innŽjÙL™1€dº¼}PWgd#ÓÙÙV¿×{Ö@êëë£Úo ^¯7ãåí’ìÐHkkkTý¦288Ö~χcÉty{¯«Ë@£ê¯©™6gûMDÖn¶&â¬ß@dÝÙ^߈Ï@Ül_M¤¿¿?¬þŽŽqc‰lÿúàz#éëëËxy»fíà›ˆ³~SihhˆjÿÖk[¤§§''û  ’©©)}²6= ô€ÐB= ô€ÐB= ô€ÐBHÎ뜊r{‰10<×Ó €@ €Ì!@d#>22¢Y+œZÝ…ïÿÙW•  ¯:•éðlO€@ €2G÷‰uŸÞÞ^ëÃ[§_/))ÑçƒÁ„p‘{i$º¯†›áÙž €@ d¥  `AO€@ €B €@ €@ €@ €@ „]y@ €@!€@ €@ €@ €@ €B €@ €@ €@ €@ „@ €@ €@ €¤•¼¼¼P‰—––UTT¤‹ÇãIZg²ñÝÏõô €@  +ÝÝÝÖ^®&''uÙl}²òZ¼$ßíð\O€@ €2‡‘s¿ßz.7É—,N’ïvx®§@ €@™C€ªÙÙÙÐsy,¯ÅK²ñÝÏõô €@ sX¯ççç§Us|·Ãs9=çBæLEE…Ò½'zCiýÍÅsSñù|aõ75ÙȲÚål¯÷¬×@d#ãfþåMˆ 7»þ¶¶KF62ÍÍÍQí/›)3L—·êêŒld:;;Ãê÷zÏH}}}TûMÄëõf¼¼]’immªß@ÃÚïùÐc ™.oïuuHcccTý55ÓÆâl¿)€È:ÀÍöÁ$@œõ›ˆì ;Ûëñˆ›í«)€ô÷÷‡ÕßÑ1n ‘í_\o }}}/o׬|SqÖo Qíßzm«€ôôôädÿz@è¡„z@è¡„z@è¡„Ó瀔ÛK@㻞ëé@ €@²p¬@ ó*Q‘ÿ/Ùøn‡g{z€@ €9ºH¼ûȽ1âÝ'#ÝñÝÏöô €@ ó( zz€@ €@ €@ €@ €B €@ ìÊ@ €@ €@ €@ €@ €@ €@ €@ €@ €B €@ €@ €@ €@ Ähòòò¢J²´´´¨¢¢"]<ñṞ €@ d’Nº»»­¤\MNNê²ÙZä5SÃs==@ €@È<ˆìÌûýþÐsy¼I¾”††çzz€@ €9Hqq±ÊÏÏW¥¥¥ª½½=áø………jvv6ô\Ëk¦†çzz€@ €,exxXUWW[_ž}iõ˜^L Ïåôœ ™3jhhH÷žè ¥õ7ÏMÄçó…ÕßÔ4jd#sÈj—³½Þ³^#‘Œ›ù”7a 6ÜìúÛÚ.ÙÈ477Gµ¿l¦Ì@2]Þ>¨«3²‘éìì «ßë=k õõõQí7¯×›ñòvIvh ¤µµ5ª~S k¿çC1€dº¼½×Õe Qõ×ÔLˆ³ý¦"ë7Û“qÖo ²ƒîl¯oÄg n¶¯¦ÒßßVGǸ1€D¶}p½€ôõõe¼¼]³vðMÄY¿)€444Dµëµ­FÒÓÓ““ý¿Eq¬©©)}²6= ô€ÐB= ô€ÐB= ô€ÐBHÎ뜊r{‰10<×Ó €@ €Ìad#>22¢Y+œZÝ…ï&ûªR@ áU§2žíé@ €@²˜ÞÞ^ëÃ[§wüKJJôùÁ`0á9r/D÷Õp3<ÛÓ €@ €Ì£,èé@ €@ €@ €@ €@ €@ €°+@ €@ €@ €B €@ €@ €@ €@ €@ €@ €@ €@ €@ €@ €’fZZZTQQ‘.€@ €Bæ&ÝÝÝÖ]®&''uÙl-¹ò €@ „àÃï÷‡žËãM² €@ €Ó),,T³³³¡çòX^ €@ €ãÉËË‹z-???.<ìâLUU•µ°oÕ½)X_,ù›‹ç;ï¾[íØ±Cíüæ7Uíç?¯ª>ûYUyÛmªêöÛUÕwªª»îR•òú¿¨ª¾ô%Ue_ù¹Ï©ââbõÿñúïÒ¥Ku³þU«¶©¯½ÖÚIÙ©î¼s‡ºýöíê¶ÛªÔç>We=®´^«Rwß]¥>ÿù*õ…/Tª/}©JÝuW•õw­®Ï®¿´´4¬½ß©øŽÊÛ‘§ë-­-Uwí¸K}¦ò3궪ÛÔíU·«;«îTwUÞ¥>_õyõŪ/ª/U}I?¿³üΰö.[¶ÌÕüÛ±d‰ª½÷^ÝŽÖ|Ú*óìæ|«¼ã=ߪnηJky‘ù&ÃV„½¿²²²°ú¿ùÍ*kØ]ïç?_kͧõÙÏVêùvÇUz¾ÝuW¥žo_übÕÍùViÍÃõaïoõêÕQíÏÿA¾®÷Þ÷ª»wÞ­nÛz›žoŸ«üÜùVuc¾}¡ò z¾Ý]u·ž§…Ë Ã>ïõÖÆ Óåmûÿù?jÇÊ•º²¼m·–¥Jk™«²þVÉ|³æe¥cÞÉ2Wi½vï—¿öþÖ®]Vÿw¾S¡¾ò•ËÛ½÷îÐËÜg?[us™«¼9ß—7Yþ<ìóX¾|yTû¿²í+jõÎÕÖŽSmø|«úœº£êugåz^ÙË\^ežž—_þæ—Cí•¿ß±¶t™.oUòý\±"´¼Õȼ’åMæŸý]•eÌšo•_øÂïª5×[ïïkËY¿Ì+ý}*µÞßÝ;Õg>S©çÛí·Ç^Þî¾»RûêW¿öþ¶lÙÖþ55kÔ×v~M¯_d¾ÝQsGhyÓó­êæ|«t|W­ù–÷­¼°åmµ#’éò¶ÅÚ!Þñ•¯ÜXÞ¬uÉ÷eùúÌgBß՘˛õü»Ö¼t.o_ûÚ×¢ê—ïé7¾±óÆû³æÛç>·-éò&ó-?ÿëaïï~kËÙþoT|Cï,-owTß‘Òòv÷wïû<¾ño¸Ú>ÔZóC/o²ž“eK¾§Ö|“õ¿½m[Þn®ãœË›ü¬¿¸¸J­\¹óÆû ›oö:®2´me./¯òæ¶áþ°÷÷ŸÖgëlï¦m›Ô’KôçñÍßTwÿànõ٪ϪÛ*ÛYÇ9–7™wlº#¬½ò×ÍöµÚZßï´–YyÎùwy»9ßV[Ë©óý}ÏÚ vÖ¿vmµÕ¶ÿ]Þîºëû¡åÍÞ6ܘo•Žmƒ<_öþ¾þõ¯GµÉŽ%º½2ßîÜqçùvs›zGå¡mƒ½¼ÙÛ†¢EaŸ·ü°šéòö}ë;¶Ój›Þ±æÉv™_öòvsÛ ÷?œû#Ö¼¼ÇÚ;ßß}ZœõûÛª‚‚ËÛ7¿¹ÓšW5¡mƒ|︣2ô]µ—7{Ûàü­¶lÙ¢ ÔÒ¥KÕ£>ª3&…ù¶yóæÐ|Û³ggƤ™|gÓ_DZ®K/.\PUUUª°°P­ZµJ½üòËÌ” —¹ââbfL’ŒŽŽªšš½¼I‘Ç—/_fƲÐW˜$½Èʱ¿¿_ÍÎΪ`0¨žxâ ’8Û¶mS§NRׯ_×óîðáÃê`Ƥ˜W_}UmÚ´‰ï,ë¶9ÍÅ‹Õ=÷Ü£Nž<©¿§òãÊã?ÎŒÉ ÇW‡‘$ëÖ­SÐÛ)íííjÆ ÌBØH“D‘t~~>3"ƒHoIž>úHÝwß}úWA¾³¬Ûæ2<ò=†RVV¦&&&˜I²dɶ „°‘&éF~)¤$}´9rD÷&‘äyòÉ'õüâ;›ÞºM‘JKKõ¯ª$ydžuuu©•+Wê@¹;õÕ«W™1l™)d×®]úû)Û)Ï>û¬~@HœÈ±Ò÷ß¿>†•¤¾ÌIY±b…a†$ÉùóçÕÆùκÈð𰪮®Vûöícf¤ðýÜ»w¯š™™Ñ‡˜>öØcª®®Ž“f|ðA}8Iž±±1µf͚жAÓs@!qòÖ[oéÃbd‘¤ù•ëàÁƒa;Ö$vd9¡Æw6³LMM©¢¢"fD’ÈIÀ;‡I/~¿Ÿ_ðÓˆ\ð@z@œç€pT!„ÄHoo¯Z½zµ:wî3ÃE8w&µï(Wt ÙŠ\i- ‚’zäbï¼ó3ÂÅv€m!„Dä…^З¦¤{=½ÈñÐö¥egP®S^^ÎŒá;;'‘“©íž#9Ä£¶¶–còSˆœ€.‡] B¤ÈáXrÉl’ZΜ9£BR\ñJÎûpžÂU°YÀ;1ü¢jnÞ1ÿ’Gzär‹2¯–-[ÆýSHÖ–·’’}þ‡ó—}?rŒ|GåЫݻwsz‘$¹Ü8I=òC}o-)ò˜ó!„B!€B!„B!„B!„B!„B!„B!„B!„B „B!„B!„B!„B!„@!„B!€B!„B!„B!„B!·Lòòòt¡„@!„9ß „@!„@!€B¹µñá,‘Ãz{{ÕÆUAA*,,TUUUêòåËQã½ñÆz<ÇYÏ™3gÔ–-[ôëùùùjÆ ê÷¿ÿ}T[žþyýÿ–,Y¢Š‹‹Ucc£ºzõjØ8¯¼òŠZ³fnKii©:zôhT»ÇÆÆÔž={ÔÒ¥Kõô¤®ÿøÇêí·ßæ'„B!d¾ $Þ낊÷ß_ÍÎΆPVV5ÞæÍ›õxμõÖ[‚–‰‰ uýúuõØcéñÎ}Z?ÿøã5x¤}„@!„y¡¡¡Ðk‚»—"r¼‘‘‘¨:d§_†9{Lfffôk÷Ýw_ÒvI/†òòò¨ö\¸p!ªýÒ6)çÏŸçÃ%„B!äVH²×ƒ!‡@Å:Ì+1”;vhpÈë± “îRiÝ"EþòõÄO¨ññq>lB!„B2@l4HÏI¢Øhp–•)@äGyD­X±" 2B „BȈœ|.ÃNž<™° vO‰9œ+²ÞTÁrFÎ9yóÍ7õp™!„B!$ÇY¾|¹ÞA—“ÄMäìÙ³úêWk×®UÃÃÃú59yüرcv¤wBê,È9";w×yúÔÔ”.555QãmÛ¶M?~\×#‘«pÉð|›@!„\G{’KÕ¦ ‹t"‘“Ázè!}~‡Œ'à‘Ëä:/‹+8‘ðäüÕ«W«®®®˜õÊexï¹çÝ›!¨‘ç‘ãI½uuuú=Ù—ô•C²8„@!„B!€B!„B!„B!„B!„B!„B!„f!„B!€B!„B!„B!„B!„BYð3ðŸ P( …B¡,¢BHÎB!„BØ÷#„…B!„°ï@X !„Bû~„°B!„öý !!„Ba߀c áÄĄڽ{·***Rùùùª¼¼\½ùæ›sÖæ¼¼<]dZÅÅŪ®®N;wnΧ'%V®^½ªÛPPP –-[¦ž}öÙ¤u¶´´èù%Åãñ¤=<^ûbµóôéÓjóæÍº}K—.U{öìQãããqëK6~ºõINž<©Ö­[§ÿÏ=÷Ü£Ž=š°ýö{ˆ7,Þg!mÛ²eK¨m>ú¨ )ÏÛdõ§ûÙðÊÎwÊÄr‘Îw`ttTÕÔÔ¨ÂÂB]äñåË—]}§Òiߩ̗·TÞó­ö}Jö¥û~“k>ÊûL%ò=p»Jö9f²M^lß'@æ@V­J\bDvŽdÿøãÕìì¬:{ö¬Ú¹sçœî¼Ø‘ivuu©+VÌé >rºÎÈÊrïÞ½jffFƒAõØc…­¼"ÓÝÝ­çÙää¤.²â•×Ržj»ìlÛ¶M:uJ]¿~]>‡V<ð@Æã§[ß;ï¼£JJJ”ßï×ÏeÃòøã§ÜþtÆ“Áþþ~Ý.ù,žxâ ½²OwÞÆ›VºŸM†_)¾Si~§’Õ—l¹H÷; ;*ÐÃ¥´··« 6d\_ºí[ôß©$ÿܾç[íû”êò“î{OuüãǧÇW_}UmÚ´)ªÞt·)ÉÚ•îúc1~ŸY‘_yÒýR:_“ÇòY½zµ®K6äçÏŸO«¾_|QÕÖÖ†½&+DùõC~i_C>ú裰áO=õ”þÕF~…xþùç3^¹Hý²"±#í<ÈÊÁ^ÑI䱬”Snbƒ*m69~¢á»víRÇŽsÝþLÞ§¬äËgªó6Þ´Òýl2ß©ô¾Sé.#‘ËEºß%K–Ìéw*YûýwÊ0@Ry-Ù²?¾OÉ–Ÿ¹HYY™îµMyo÷ÝwŸî)L¥ÞDßdÿ?ÝõÇbü>² " ÷¾}ûÔû￟ñÎ’¬|Eëòe%[~æ 2­ÆÆÆ¤ÿïÉ'ŸÔË}&ßt·yé®?ã÷ €9~QV@+W® ý’ã<~3•%çÊ"Ù¯ñ¾xÎÿ³Êj«sçMVþÎcT¥»UŽã6±2þñ¬»xå=ØÝ½é¶ß9~&Ãí ë–ì¼Æš®9`dd$i}ñÆOuxª+åTŸMwå~áÂuÿý÷‡}ÎÉæm*ó$•ÿï |§ÒûNýÿíœ=ŽÂ0F¯É ¤ã”œQRBEÁ \€šššÕ)+o”xfˆùÙä=É»NBæ³=“±#6ⵋœßn·Çd2ù­×ç4ü¬¦º®M}Ö±lÿ[ôdÙÏ+étú¸^¯Ùïéíël6{ZÑ1¯Ä˜ëŠ.m6›?Ï'‡u¼§½OD—N§Sõº¿™vô_Þ€ ©˜¦¼×ÐeQ Ìçó*êš®ñ¤ˆYšñ^ßè5õfIJýoÑ“e?¥¥÷¤oþº­{ŠèÕ6æEû1ê dpH›Ç­N5„:âÒ“%åצ¡¢K¹]dJFk›ìv»j\m9šúŸ·¾â0FÏÕ+ïùùµÇã±ZûжàÓûÛFòk­gSHRh*£)O{9»ˆþþmöÞWS‘뽦 ; –ž,Ûÿ=yì§´¢TQ-àö´Ý,¢'k̳ú1ê dˆÄ{¹\ª\Ñ@åC§;Âhšr:U¯Wé$¥&K];Œ¬×ëÇb±¨R%„¢/Ëåò·¾Î¯ÕõôÍW_­VU;º?ås*ª‘KIªw©Ðwr»`uÕ7¯C÷UŸO÷«ç‘æäês½E¨:j-|L;¤f{ÖñV} PŠBÏçêïWî0¢H—öfJ€÷·µÎåý~_MÅ4eµgÙETzz&éôùDÛ³®M½Ö±ôdÙþ§õ䵟’ˆl¯k³OJSDÑ1/ÚŒQO8 8 ƒp@$p¼¢HzÕ§…uin«^1jpV½¼~uÆ}'KuÑ",Ú^9«ƒWn¶Î«m3‡ÃŸzåŒ*jbí0bEn]©sõ•š¡¼N u°¹}ºsõÍó+š¢ûÓÿ5Ó}¥ùÿi½~¯¶=â»Úk;Þªï²}GÏB{¬ï÷ûptÌÓ¹{Ú²~[ë:¬gWÂAS1MYíYvÕ€&3õ^þ*úœK1ñh0!µ¦ ; –ž<¶ÿmzjÚwĶ<Çkb«­sK8 }ƨ¶1ï™1ylzÂÁù>˜ûFÌýp@0B`î‡!0÷ÃÁ€¹FÌýä-FH¡P( …BOø'ü%b¦¡þä»IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_long_increment_line_narrow.png000066400000000000000000000573111174000617100270060ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔ^IDATxÚíLT×›ÿ?Éf³Ùl¾Ùì?›Íþ±Ù|’ÍfÿØl6›l6›Í¦1º£« „–BQÊ/©…ªh‹J¡ÚÒj±X‹ÕâÇÒZ¬ÖbµZi¥Z‹ZµÖª´J±P(¶XQÊóå9Ÿ½ä2Îïf`îëMÞaî=wî™÷Ü™;ïóœçœó;Åïx 0X, À`Èã÷¿ÿ½üîw¿ç?üÃ?ÄßÀ¦O9UÎåä÷påó588(Ï=÷œüÏÿüü¿ÿ÷ÿäOÿôO õñý×IFF†444pA Ä'Ož¼ç¦¦<}út\ýÈb°0X\§ÈÞbñº÷íÛ'õWåñµNÖg“Ï<À`PPPàñæ”——‡Á↋v‡\§PîÑ~ÝÊþæoþF¶mÛ&CCC¦|xxØEnýÇüŸy€Á±Ão¿ý&ý×=~ãøË¿üË 7/n8èñÿ õ>Í×ýÃ?˜.@kÿ_üÅ_ÈÕ«Wù¾ ˜š8|øð„ÇâÅ‹'l:tÈç&Ðü… ä‘G‘¿ÿû¿—?û³?3¹÷wgö?>àÚÚµkÍÍ^Ï¡­S}íŠîîns.+ã_þå_dçÎAß$»ººdåÊ•òŸÿùŸòçþçæ\úC³páBùä“O"rÃÔ{ñâ‹/šsèó5O¦ººÚãs+**&·~ýú°0|=7œ×Îûÿ믿šŒ¯ï«ú#¬eÿôOÿ4~^ý¥¦¦zíþšŒÏ_$_‹¯÷4”ïh°÷H\o}?íÇiÔÉ×竼¼|ÂþU«V…tÏ æ„ò^ ‹-¿IèF¨ô¿µO“EùálÙ²EþäOþÄç±555~oÜúæé¹šÈª7GOe»ví Øh^‡¶ˆ½‰†rƒÔ{‘››ëñ¹z~;\.—Çã<=² V ¯5Ü÷?99yü±¾Çôó¡†È×yõ‡;Ÿ¿H½ïi(¦ Øû@¸×{Á‚A65yݾÿÌ™3Aß,€Á!áîÝ»¦gÝ$Íþ„„„ñ}Z®Ç…2×Ö ýLh˜¿¯¯ïž›¥¿–£ŽÒ›¾Þ ½•éš}ÿ¿ýÛ¿ôš5ªdÿ1ÑzÍëPÝÚu¢¯MÂ1X‘|/fΜirN^~ùe¯zÝsU´LëSþû¿ÿ{Ô V ¯5ïÿ?þã?Ê¥K—&söìÙ{^KOO9ovvö„25x“ùù‹äk ä= æ3Éû@(ŸMë» ÔÈ ·×mJýlƒH^0XÀokÎ~Ó°Bùª·ïë­·B2XGŽ—}ôÑGÊôX_ç×ÄU…&±º—8q”é ×¾_oȼfí°ï×.ŽpLÆd¿–^÷÷®W$íeVw–½;h2 V ¯5ï¿§.,{TKyýúõñ2÷×sß}÷Mêç/’¯%÷4˜Ïh$ï¡|6íß}ìíuÛM¸'=þ¢K‘¼`°€OÌ;wÂMÊèû~=.ƒaOHuoqj«Ñ^¦Çú:¿ý¹¾Ê|Ý„½½f{B¯RçØ‰´ÁŠÖ{H}žLÂd¬@^k$ÞOÑ ÷óú¢?sîç/Z¯%”Ïh$ï“ùÙôÁòg°"y À`¯Ð1{>&ZÛaÏ+Ñþþþ o8Á´8õØPÄÃ-ó÷:#a°¢ý^ÛÚŸ,ƒË÷ßý¼ÁäÑL¶ÆX¾–hÝ"ýÙüïÿþï ûƒ2™× ˜€W_}5¨›{’j¸,÷–ª¿¨Íd–Å:‚5ïÅT‰`ÅòýwTw¬4N¥×­û@¤?›î£= ˆÅ5ƒ&@s ‚¹±†’“ɼ£É,›n9X”¹wûØëó—ƒåOÛtyÿÝßsoS'DÃÔL¥×­û€·²9sæ„”ƒ¥Bì3¸ëc"#Ð÷k²®,0½)¹ß0t";¾ùæŸÇ¸M÷4‡ûÈ9!dÒ‘C¾†\GÓ`i®‰½û@ó/¬Ql–‹)œn´ß‹ýû÷Oد#© ƒ5Yï¿û{®ŸY5³ šèèEÃӌߑÖ‹×âï;‰û@(¯-ÔQ„Ц¦¦ eÚ¥ùÎ;ïŒGÁô}œŒkÈý`°0“MÚošÛà îÓX*JJJÊ]ÐJs?éîh´Úý̓åÞ…̹¦â{aŸÛ(˜y°¢m°"ñþ{C ïy´4FûµøûŽFâ>êk gŽ6rýíßþí¤}=Õèý`°€Ã¡3MûÊ«°à>—Í¿þ뿎—i‹Os þùŸÿÙoÒªF(tž™ßÿþ÷ã«Þë κO[Á†ä'«ËD[ôö™Ä­nžXÃÏÃ1XÑ~/¬Q«.ý¯?Žî£ƒ15ß_°Þs+KßýU3§ó<=õÔS“¥'Kc4_‹¿ïh$îἺʀûg3Ðk«óŽéëúßÿý_“Ãg½—:‡š¾>’aÓ¦MråÊ•ˆ\ƒ`îwƒp(t>#û„þ°À`€vùèì⚬ÐQSºm_Ô××:s0X÷/¼ŸîK]“Í[· Àt4bAAÉÑœ&5Tšk2cÆ “ë¤#Ä`°0X,€ÁÀ``° ƒ€Á¬é ]áÝ{ñâÅådœs:Љº¹ÖhF7šÑí›î¿»,‡¬%K–ÈG}Qê²)‘>çt us­ÑŒn4£Û71X¬ˆñܹsŽür:Q7×ÍèF3º1X J B!„, ­t£ÝhF7׃ÈÁ"oÍèF3ºÑL ‚EëÍèF3ºÑL ƒ…Á‚B! Á¢Õ‡ft£Ýh&‚ÈÁ¢ÿÍèF3ºÑLÖ”3X===RZZ* †ú¸»»{¼ü¾ûþPWW'÷ß¿áÖ­[#^ëúˆ`ÑêC3ºÑŒn4Áò‰ÌÌLÙ¹s§ŒŒŒÖ××KVVÖƒ ššš$??_ ;H•Ǻ>r° „Br°übÆŒ÷ì›5kVÈKÍŠ:X ú8///bå±®­>4£ÍèF3,¿Xµj•‰ZŽŽîØ±Ã쳬ÄÄD™9s¦¤¥¥™c}A»õ<ô±î‹Ty¬ë#‹¼4£ÍèF39X~ÑÛÛ+ÉÉÉãùUú¸¿¿ßã±RRR"µµµ^Ïç)â¥æ,Rå±®/ZkÿÕý´~ÐŒn4£Íèž®«¸¸ØD¥ì9XEEE^2ÉàNŒ`é¶hGAAqíÖKÿ‡³Ý|¹Y\c-W["r>¶Ùf›m¶ÙžÎÛÓÒ`yŠÖøŠàø3Xžršt_¤Êc]ßdF°ÄåòJ§´~œ¹£¥‹ft£ÝqÁÒƒšweÏÁ²"¬¬¬”®®®ñîIJ²2©®®öÚÅfÊð9j/Ôòh×uƒå 1XûNí3‘;ýï¤Ró÷Íäj ÝhFw¼,5OÚ%¨#•úØ2TŠ––3•ƒ› ˜ü«ááaŸ9L:—”¯y¥Â)v}SÅ`=üëÃ’=”-K~^"yƒyR8P(ÿø¸”ö–ÊŠ+dÕ÷«¤ü»r©è¬ªŽ*Ùðõ©¾V-›¾Ú$›¿Ü,[¾Ø"uëdÇç;dç¹òFÛ²ûÌnyçô;òîÉw¥éD“úä|xìCiþ(6?ø«o¬6«ìû2ÇÜŒ,SùÞ™÷hé¢ÝhFw<¬paŸÒ!ë›*«óÁ¥r}Q©|ùp™|þèÓòYÞZ9¹ìiYY%ÍUòÁ ÏJÓ«ÏÈ;o¬‘ÝM«eçGe²õt™lü|¥<{u¥<õÝ cÆÔ” “¦fMM[毙’>œ.©wS%ù·dIûÓÿº­û'ÛÜ9¹kTͤ¬ªŸ«˜ëB1XÎF, VÓKå½õMòÞšw¥iå;òþ²Ýr0—^üºÍ|UŽ¥o–¾ gRž•óIk䫤ÒùÀRé}`‰üòÀCr7)E~KJ–_“Éͳ¤?=Wn<\(Ý.“μÒQ¼Z¾Y¾F¾.F¾~v½\}ñy¹ôò r®n“œþÃfùäíZùpÿ9px«¼sìUyãô«òÚç¯Ê+_¼"/ù²1Sjª6´oªoªŒÙRÓµúûÕ²òÆJŸæÎ—n5yiwÒŒÑ{èöCæø¬[Yæ¹9¿ä˜ó%å]å²¶s­T|[!••æ5¯ÿz½<×þœT_¯–¯½(¯n”—¾zI6_Ù,µ_ÖÊ+—_‘­_l•ºKuòÚÅ×dÇ…Rÿy½ì<¿SvÛ% gäÍÏÞ4æñíÖ·eÏé=²÷Ô^c"ßûô=%|ÿøû&Rx¸å°lzã„$•^—Ó~“¤¥Ró‡Ïhé¢ÝhF7 ƒIƒuàÄŸFC˃9߇“NÈ;††6Ù±ãsyuËEy¥ú¼l©8+[V}&¯”œ’W ŽË«9Ék™‡åõ´&Ù•²WÞr½)MÉÛå£_–Ó©ÏÉ…´µrmÑJéJ+–¾´Ü1ƒöˆÜNY4fØ‘Räöƒ‹d(#Snf/–ŸË“þ¥cÆ®´TzÊÊä»òrùö™1Ó¶aØi{Q¾Ü¼Y.mÝ*ŸïØ!gwí’3»wûÔ­fäàñƒF¿š5+jZ4úÕØÚhÌŒšŠí:»ËDÈÔô¨ùQ´íÒ6Ùzi«1Gj’Ô,Õ|U#›®n2&JÍ”š*º=ûͳÆl©éRóµ¦k<ýÝÓÆ”©9S“¶üÆr)ý¡Ô˜75qjæŠú‹¤` À˜<5{júÿ²XzÔ˜A5…j3†3dÑEŒž^/IKzeïÅ«FꥯîÈCKnÉ“û÷™×ºû³Ýr¤åHÜÝ|>ƒ¼4£ƒ<а¹ù#9tèy÷Ý“²{÷Ù¹óœÔÕ]”Í›¿”êêkRUÕ!ååßÉŠ7¤´xŒ¹ßÉ“tÈŠ´kRöÀe©xà¬l|ðÙ–þ¼•¹Wš²wIó£¯Ê©Å/ÉùÅëå«Åk¤#g…|Ÿý¸ôgåù4X?””Èwcï÷7UUruãFùb̜߹SZß~[N45ÉÇGNË›PNÞ€ì»xm‚ܯ¾y4ÿ–1q‹^, [hºg‹,6†OÍ¡FÉ~rpz,ä ªftc°@Œ'Îô={å•/dÓ¦¯dÆv©¨è”Õ«¿—ÒÒ^É_ÕáóG·2ëˆlu’7]»å}WwUË×ÓÒá*–W–Œ¸’åW†t»òåK×J9ízVޏjek—lw½']Çd묔¸®ËbW¯<èöåc£Æ¤ÔaùmìÏ) ERSïJZÚIO–ô‡oÉ¢G~–´œyð±$¥è;IZöµ#ç—o’¶õuÒ¶­^Z÷ì™L^ºÑL ‚7ܾý‚äçIJʨääü*uu—¦Ìk;öá‡òé{ïƒðy}½\~å¹6f :*+¥{õjé3%ƒùùr++kÜŒ §§2PT$?,_.]cæãëõëå«—^’Kuu>†Ö£†D‰ÐjXt €52jhÔØè€5:Z—FåÔ©Ò× ¯E ’¥ÁÇ–ÈÇs囲%r©âQ9¹1S>¨K“Ýo&É[iÒ¸'GÞÝû„zg|ôNœ~û 9ýÎ;F·šÆHåºc,?ø Eö¾uR_úXŸ:(ï5Ê¡¬×¥%õ%3Rö»¤¹”*¿>°H~X”oòú®>ñŒ\®xQ¾¨Ý"çþð…üxìúÕ@7š‰` œæT3¢ øšˆ¯ ùš˜¯ úš¨¯ ûš¸ïËhh¤ì§‚Ó}ùÓOÊ÷c&®kíZé{¾vc~µi“\®­•‹cFíüë¯K[Cƒ´66ÊÉýûåøÁƒÆúZ~|ÔL'¡SOèHÊÉN°T´RbhnWCÃYÙ^3ƧOÈ΢#òÖ#{å½ë¥%éE¹’¼R~LÎ1#]Yø°üY ]E+å›§+äÚ /˜èšvëµ $ê!$ Á¢õÃhºðF’~Ô,ûNî3Ó]èT:™ìcƒÉƒw”ô;éf²YÂBç ÓyÀtޝ`Îÿîéw'uY$h¡‰ö¯¿þ¹Ô¼tE^|ꢼTpZ¶f6ËΔwåýämr6µR:S7æKMØÏ‹‘¾Ü"ù~ùJéxæmÔ|¼3cæÕtý25ßk4Áä`ÑÁš,ª™RS¥s‰©ÉR³µhx‘1_jÂÔŒ©)Û~a»1iž–^ªø©Â¬§{ŸŽ‰Ѹ{÷g¦+Zþ׬þV* ®È³mòÒKcê[òIúKr%cµü°(O†¦ÉÝä…òó#ÊK‹MTQ»|5ÏL£”šwìȦ¦à~Æ=œ,@‹VnF–V‚½v'®ë\gºµ›Q»s~Î1ÝÚ Ys­FŽýûKM™r‹{k÷ãþýŸÊ®]çäå—¿4£,u$åã¹7äÉ´vy&ù¬Ôgü&粞•o)•ÁŒIN‘;i‹L¯м;íÒÅ`ÁB7 ƒaÄ©3ÒëŒû:C½Î”¿ìÎ2©ûS¼4ö—>š. GN›e‘^o}S^9|@^x³E*¶œ••UW¥ðÉnÉZ<(.üQV¦]‘Ú¬dß’ùô±M¾×]·Î ˜¸´m›ÕJ>„qd°zzz¤´´T õqww÷„cêêêäþûï7ܺu«ßsú;>ÜòX×G‹VšC£æ^iôêû±?…þ×(–.{/Ë"eôæKÚ¥ryðãÍ’òö[> VCÁVù0¿RÎç>)äÊÏié2òÀòóCKo^ž|¿|¹9zuÓ&3ˆŽ0=þþû|ÆÑLk:¬ÌÌLÙ¹s§ŒŒŒÖ××KVVÖxyÓX‹*??_ Í>oðw|¸å±®,òÐ:5÷ÊŠ^YÐíXåbÅ:ß®b÷‡²¼¾YŠ^ýDo:%W“‡W}!ù…çä©ÌS²1¹Yþ²[-zI>[´Z:Òòäç”ErçdéMÏ’öÅ…rqÙ 9óô:9ùÂF9µí59ýöÛa%åOJ·ë÷΋Ê9Q39Xn˜1cÆ=ûfÍš5þX͇:R ú8o¬eå þŽ·<ÖõÁ¢Õ‡æÐg°wùø vAs§äÛ8zTv:"[Þ;"ë÷‘Õo•寕§7 «÷ÈÖ¥»ä­G·Ê‘E/ÈÙä5ò­«H†’Éí¤å»—ÈÅÌ9þX¹,Ý {Öl–]·Ëë;vËŽ½M²ûð92‰]’¯¿~I —þ* ÓFdIÞ¯òÚk—É­ä~惵jÕ*µ5ܱc‡ÙgA» u¿}¬û¼Áßñá–Ǻ>r° „A›Ê3•²°´CX8"þ$™Ÿn4S©†©ñð‡òú¾¦1ƒó¶1Të6¬çŒÑRÃ¥ÆK ˜15dmcÆL šµ­EçV5JùsŒ‘SC§Æîå÷£×ôáQÌFŽ&kÐÛÛ+ÉÉÉrß}÷êãþþþñrÝ玙3gz=Ÿ¿ãÃ-e}z-ÚQPP`¢–s×ÿánkn\$Ï7]¶-:E¯n_»vÍQz­mÕÍç;¶¯G»¿ãõýïÉÙ—·È™ò ù¢t•tK_mº*µËR».µ ³ @»4/Kös屚ÏLWçSo—šÎø4ñz}}iæ~Þö´4XÅÅÅ&‚eÏÁ***"‚EùHhF7šMR½&×k’½®" I÷š|ß›—/7zHFÆ忤.’ά\“¬¯Iûonõi62\¿H¦kP²]ý’ãê“\× ÉwuK‘«Sw}#O¸ÚåI×UYéúRV».I¹ësYë:'ϸ>“g]§å9×§ò‚ëÙè:&5®f©u‘­®C²Íu@¶»Þ“z×>ÙåÚ#oºvËÛ®ÙãÚ%û\õòžk»¼ïª“\¯ÈW­4»jä˜k£wUËI×9ízV>s=#ç\kå‚ëiùµJ¾t­”«®'¥Ýõ„t¸Š¥ËU(Ý®|¹áÊ•>WŽ ¸²Ìº™¿¸2ˆ`‘ƒå?Zcßç)GI÷“e?>ÜòX×GùHhF7šmln6ÓKè4:Ý„N;¡ ˆû2ºNæE‹d8#ì—© ˆëZžC>*¿,^læÓ×uÏ‚ékôÿ¸t©Yˆ]×þü¡´TnŒ™¼ž+Ìíº&èwO?-]kÖ˜…Øuáv]+ô›gŸ5kxêÂ캠»¾6‘ùUMY¨]z×µEuÍO}íj"ux]sôÜÎfMж7Þ0ÚÔdê’TºF§N,« ÆëZ'0KTi4Зæ³JäÔ;»ùŒ;É`éˆAÍ»²ç`yE800àq”{›¿ãÃ-v}ä`A!ùHájÞóàëÒ—ž.=r±æÙi9Ý9XA¢««Ët êÈA¥>Ö}vèÜPÞæ‰ò”ÃäëøpË£],ZøhF7šƒOî÷e6âqÄè¸f/l8xTJV+kµÊ±’b¹µ(Y:WäÉÅmuòq ´ÁrÐLîö)â±>r°ÈQA3ºÑÌ”‘ºÖ{ö´Ê¥7$3óGÙZ]%_®\(·ÒSäÛ5«MW$Ÿq –£A‹>šÑft‡£y÷î3òøã?Jú#¿HÙêe÷› åÇ%©r3'SÚŸ^>Õe“¸Ö, 9XBƒgCC› Hfö/Rºç=Y{a‘)Cn/3\K‹ä‹-[äØáÃä`a°0X´øÐft£ÝÁjþÃtû <šó‹T¼ý¡<Þ[ ›?N“ëeÈÔåûU«Ì¨Æ©¾8,@9*hF7šÑ=å4ïØñùØoÊÍ1þ,/½y\žúî)Éí}PìZ,¹™fJ‹oÖ¯—“ûö‘ƒ…ÁÂ`ÑâC7šÑ͵Fs0ܶí¢<úè/&ªµã3²ñêFÉÊ’u‘óÏÉpú"ù© @¾Ü¼YZ>ø€ ƒ!„Âææä•W¾¬¬[&Oë†ÏdçùòDï’ñkš¼uð é^Ql&n½±b…œýõ)ß…ˆÁD°hé¢ÝhF÷”ÐÜÜü±¼üò—òðÿš‘‡:qÿ§û¥²£RÒï¤ËÊo åä¶§åfn®ÜÎÈ0ËéŒóD°‹œr5¸ÖhF7šýðÃ?–M›¾’ŒŒÛRZÚkæÔúðØ‡²åòylð1yø×‡eû§ë¤½j1Zj¸týH]ʇ,€Á¢¥‹ft£ÝhöÁ#GŽIuõ5Y´hXV®¼!ûöúãÜZŸí–²ïË$õnª¬ê.“ßÞhºµ ±·´T.¼öš||ô(,@„B臷Ȇ ícF뎬^ý½ìßÿ©ÙðøAyþúó’ùk¦‰l½vn³\®­1IñwÒÓ¥kíZ³x59X€­>4£ÍèF³:ô‰TU}#iiw¤¼ü;ij:ñÇÜ­šeû…í²ôÇ¥&WKs¶>|—™æá×G‘_rräú /ȉˆ`Mtñdw&&&ú,÷‡ºº:Ÿ‹'‡[ëúÈÁ"WÍèF3º§šæƒ˺uߎ­»RQÑi¶­²}§öÉÚε’v'ÍŒBÜy®ÞL\ª˜jâ?.—Æ~ÿŽ…¹ð49X>püøñ &#CeGSS“äççËàà aaa¡Ù©òX×G‹–.šÑftOeÍÁÒH–F´4²¥®ñnÅc‡eó•Í’ósŽ™WKç×:Ò|@¾xåé/.–»iiÒ=ö×öÆD°"ììléïïÙ`©YÑ7Ø‚>ÎËË‹Xy¬ë# Bát ædin–-ÍÕÒœ-{ùgßå7–›¤x1~Oë³Èôõ矗¡1/p++K¾Þ°ANîßOV¸8uê”TWWßÓ…¨]†3gλHiR__ïó 2:::¾­u_¤Êc],ZºhF7šÑ=4ë(Cm¨£uô¡ŽB´—8q@Ö½^2ngHÁ@¼zéU9úñQùì­·ä»òr¹3öÛ?PX(—kk¥ÅÏÂÓD°¼@BGG‡×òÎÎN)))‘Ú±7ÙWN—;ÔœEª<–õé¶hGAAéw¶>Xú?ÜíŸ~ú)¢ç›.Ûîÿ ¿§§ÇQz­mÕÍçÛúx?›ŠŸo7«¬ì'yä‘©«ë2ójÙËÕT½ñõRòk‰<|çacº>¹ø‰t\¿._74HßOÈȘÙú¥ªJ®íÝkf7=@.—WFêõOkƒ¥"V­Zå÷¸¡¡!“ N‹-]4£Íèž~šu&x^g†×âýøžc´»P» µûP»µ;Q÷ÿ}¹úâ‹òóØïÞ퇖Ž1³eÌ”'Œí'‚5Í;º|ùrØËSN“î‹Ty¬ë# Ba<°¡¡Í¬q¨kꚇºö¡û1´|0¾Ð´&Æk‚¼&ÊkYkc£tVT`°|áÂ… ^»+++¥««Ë<îí핲²² yZî]lÖ¨¼Ÿ£öB-v}D°hõ¡ÝhFwú‹ÔÕ]ôxŒÎ©e-4­S=è”{Oí5e,PSÑÚÚ걬¥¥E233±Y°`É¿ö™Ã¤Ó<øšW*œòh×Ç4£ÍèFó=Fëc3ÒPGêÈCxÏ<[§öIÊhŠ|?ö§Ðÿº­û1X`Ê,r5ÐŒn4£ÍS…:gÖ¦M_IFÆm)-í5sjYeå}åR3ög‡në~  ‚E«ÍèF3ºÑì‡: ¼Î¯³Âëìð ŠKÿÎTJZi—$§Ý‘…K¿×§Ï™ý:K< ƒ!„@]×P×7\´èŽ,]Ú/ÙÙ#rñâ¿úJ×5¾+uu—ˆ`"X´úÐŒn4£ÍÁòСOÆÌÔqseAMÖâÅ·1X€,òÐŒn4£Í¡pÑ¢ß<þV¦¤Œb°,Z}hF7šÑæPXXø«ÇÖ’%Ã,@„B ·o¿ 99¿MÈÁÒmr°,Z}hF7šÑæ0øúë—¤¨è¶éÌͽ#¯½v9¢çÇ`a°è¿G7šÑfts­#Ìii°tñdw&&&N8¦®®.¨Åýny¬ë#‚E«ÍèF3ºÑ=ÝqÁ:~üø“ÑÔÔ$ùùù288hXXXhöyƒ¿ãÃ-u}ä`A!„Ñe\¬ììléïïßVó¡ŽÔ‚>ÎËËóú|LJ[ëúˆ`ÑêC3ºÑŒn4Á §N’êêê ûdttt|[ë>oðw|¸å±®,òÐŒn4£Íä`5 ÷äh¹cæÌ™>sº|ny,ëÓ lÑŽ‚‚󡲜»þw»§§'¢ç›.Û¢W·¯]»æ(½Ö¶êæóí ýN¼Ÿ9ñó=™÷³im°TĪU«‚ŽÁ" B!$Ë 4ïèòåËå8é¾`r¢ìLJ[ëúÈÁ"oÍèF3ºÑLV@¸pá‚×Änk”ÝÀÀ€ÇQvî]lþŽ·<Úõ‘ƒEÞšÑft£™¬ ¦¢µµÕk¹NÛàmž(O9L¾Ž·<ÚõÁ¢Õ‡ft£Ýh&‚uÌš5+®ë# B!t@–§™×=qÆŒ¬i3 ­4£ÍèF3º£h°Ô8ÙéÍ`ùšÚL}ƒEÿ=šÑft£Ý1ê"ÉÍÍ•9sæà„ÈÁ¢ÿÍèF3ºÑLV(9XÞ’Ü=Š"‚EëÍèF3ºÑL+¨—Ëeæ‡Rêã‹/â‚ÈÁ‚BÉÁ,Z?´tÑft£Ý, 9XèF3ºÑŒn4Ç_–bÙ²e’ÀLîD°hý ÝhF7š‰`EÂ`•””Œ›©pfrooo—ââbcÔ4‡K“çíSA¸Óêêê|.žny¬ë# B!Œã,5gΜ1­ˆÕÍ›7eùòå²ÿþ€ÎÑÑÑ!)))rêÔ)3̓Π¿qãÆ +455™™ä ;H•Ǻ>"X´úÐŒn4£ÍqÁ²›ûc5J΃UYY9!b嫎@ fEß`û(G«+Rå±®,òÐŒn4£Íqžƒ¥æG£. ¢¡¥¥Å|XªªªÌãôôô yRj˜5iëׯ7Ëë ˆ dÍš5íìì4y_µµµAE¼ìù`á–Dz>½Àí(((0®Ýú`é¶Ùf›m¶Ùf;2Û1¦addD,X`"WºÐ³§5 ½E€ÔXYÐçi$ˆ††Lî,"X´úÐŒn4£Í̃åšÔín°| ËSN“î‹Ty¬ë#‹¼4£ÍèF³æÁ šà®Ý‚j²”Ú]XQQ1! ¾««Ë<îí핲²2©®®öÚÅfÊÓш¾Fí…Zíúˆ`ÑêC3ºÑŒn4;0‚¥ êsçÎÔžœœ,7nÜøš¸®£µk°¼¼|B’»&Îgffc£]šexyÊaÒ¹¤|Í+Ny´ëc,!„Ðaó`i’»§™ÛÛÚÚüvsE ¾òµâ¡>"X´úÐŒn4£Í‹`iDiË–-&1Ûn°4OjöìÙ¬i3 ý÷hF7šÑftÇÈ`ÙM•û¼W¬EH‹ÖšÑft£™VÐùšnß¾}¡Ò„mS €©m° „B#ƒ¥ÉìÙÙÙÒßßo –Î…uõêUc¼41Á¢õƒft£Ýh&‚$t¡fûìívZKèr°è¿G3ºÑŒn4“ƒ‚ÉÒH–Ž®S;E ‚E«ÍèF3ºÑL ƒ!„’ƒQ„€­4£ÍèF3¬¬©0é&‹,t£ÝhF7šã*Ëår™IE,Z?hF7šÑf"X2X'Ož”¬¬,F ’ƒ!„’ƒ)ƒåmŠ÷µ ý¡½½]Š‹‹Íä¤;xðà„òººº Cöw|¸å±®­>4£ÍèFsG°ÔDy£N6è4)))rêÔ)³¦¡Î¿qãÆñò¦¦&³p´FÉ”………fŸ7ø;>ÜòX×Gy hF7šÑf̃.*++ï‰XÙ¡æC©}œ——òñá–Ǻ>"X´úÐŒn4£Í̃剉‰²oß>™?¾•¨"nÞ¼9^®Ý†Ù² }­sèïøpËc]9XBaœç`ݽ{×£pr°ôØõë×›s ˆ dÍš5ÊÝá«ûÑßñá–Dz>½Àí(((0aQ˹ëÿp·{zz"z¾é²mÑ)zuûÚµkŽÒkm«n>ßÎÐïÄû™?ß“y?‹ÉbÏvCJ–FkÔXÙM›}~-"Xä`‘·€ft£ÝhvT–©æææ°Î¡IÝîËn0<å(é¾`r¢ìLJ[ëúÈÁ"oÍèF3ºÑç9XF©|Aܵ[PM–R» +**îe§£ =²sïbów|¸åÑ®,!„Ða9X:gU$&­¯¯—9s昮Áòòò Iî ÊÛ¨rwhnØèèèø¶>¶ÏÉny¬ë#‚E«ÍèF3ºÑ‡¬@&µæÇ RRR"µµµ!•{‹xÙ§“·<Öõ‘ƒEÞšÑft£9s°Ü'õf°B#khhÈ${‡ZÏ,½Àí(((0*˹ëÿp·µ‹7’ç›.Û¢W·¯]»æ(½Ö¶êæóí ýN¼Ÿ9ñó=™÷³¨wr° „Â8ÏÁÒ GïÞ½{Ï~Ý7oÞ¼€ÎQYY)]]]ãÓ>”••IuuuÀåî]lÖ¨<5}¾Fí…ZíúÈÁ"oÍèF3ºÑì°Q„j6¼¬@s°ZZZ$33ÓœKçÓÒüªááá€Ë=å0é\R¾æ• §<Úõ‘ƒEÞšÑft£Ùaó`éè>R@»5wH©ŒæææÊœ9s¢2 qÖ¬YQõíúˆ`ÑêC3ºÑŒn4;,‚¥9XÞ’Ü=Êš6ÓØ`A!„0†ó`©[Ôåq4²£ÔÇ/^ÄÁ¢õƒft£Ýh&‚0Xôß“«n4£ÍèÆ`a°ˆ`¡ÍèF3ºÑ,-¨k Fj&w@„Bèø¬äää †ÊÎPgrD°hõ¡ÝhF7šÁR#êŒí€,òÐŒn4£Íä`yQ*"X´~ÐŒn4£ÍD°"l°tJ]Þƒ!„’ƒ!ƒÕÚÚ*ééé{D°hý ÝhF7š‰`…o³¸3Š,úïÑŒn4£Íä`…‘äîægy2g« j1dLJ[ëúˆ`ÑêC3ºÑŒn4Çq+ðd¨ìhjj’üü|“ë¥,,,4ûB=>ÜòX×G„Bç9XÑ0Xj>Ô‘ZÐÇyyy!ny¬ë#‚E«ÍèF3ºÑì€Ö… $))Ét *õ±î Æ`%&&šç¦¥¥I}}ý„ò„„ßÖǺÏüny¬ë#‹¼4£ÍèFsœç`9sÆk’{0&ËBgg§”””Hmm­Ï—¯ü.LJ[ëúˆ`ÑêC3ºÑŒn4ÇyK£UË–-“þþþñ}ú¸¨¨ÈÌ‘ †††L²7,ÏÆÊ¢Ƶ[,ýÏ6Ûl³Í6ÛlGf;&3¹ë‚Ïî‘Y³fEÄ`yÊQÒ}ÁäDÙ·<ÖõÁ¢Õ‡ft£ÝhŽó–¬ááá{ö«é Ô`UVVJWW—yÜÛÛ+eeeR]]}Ï(;ÌÔÓ(;÷.6LJ[íúÈÁ"oÍèF3ºÑì°¬ääd3â­¯¯Ïtm)õqNNŽé> ---’™™iŒË‚ Lþ•»iÓ¹¡¼Íå)‡É×ñá–G»>"X´úÐŒn4£Í‹`i"»·$÷+W®Deš‡P»"§K}̃!„:p,5R­Rã¡ÔÇÑ2W,•C ÝhF7šÑ渜 ħÁ¢ÿÍèF3ºÑŒn ‹ÖºÑŒn4£›këØ±cRQQqÏþªª*9~ü8Nˆ,!„¬`1wî\¹yóæ=ûußüùóqBD°hý ÝhF7š‰` _ 5Ϙ1'Dý÷hF7šÑfr°‚…ÎÛd_&ǂ΅5{ölœ,Z?hF7šÑf"XÁBØ5R¥‹4[vtt˜È–N@ ÈÁ‚BÉÁ škåm¢Q]SÁ¢õƒft£Ýh&‚´;P—̱&MII1ëêr°è¿G3ºÑŒn4“ƒ0X´~hé¢ÍèF3º1X,r° „¸ËÁRìÛ·Ï̇eŸ–A» oܸô¹ ï™úÁS~—?ÔÕÕ™ŽÊ­[·F¼<ÖõÁ¢Õ‡ft£ÝhŽãÖáÇÇMÝ`µµµI~~~Pç:räˆyèÉ`ƒ¦¦&S÷àà ¡š6Ý©òX×Gy hF7šÑæ8ÏÁZ°`lÙ²ÅLÏ`7X:‚0˜y°nݺ%©©©ÒÝݶÁR³¢Ö‚>¶Ony¬ë#‚E«ÍèF3ºÑç,»©rŸ¹=˜™Ü7oÞ, •n'&&ÊÌ™3%--Mêëë}ž+!!Á> úX÷Eª<Öõ‘ƒ!„Æy–šžÛ·oßc¨tš&ÁÂõë×%777 ˆ•NhZRR"µµµ^ñô|}‘*e}z-ÚQPP`¢–s×ÿán÷ôôDô|ÓeÛ¢Sôêöµk×¥×ÚVÝ|¾¡ß‰÷3'~¾'ó~uƒ¥ÉìÙÙÙf¹5X###rõêUc233:‡š«®®®€»µûQ“Á‰`‘ƒEÞšÑft£9.s°¬eqoÞ<áIJJb=›in°hý ÝhF7šÑ#ƒ•““#íííæqyyù„$õ¢¢"œÐ46XB!Œ‘ÁÒé¬|¨ùóçcuùòe3·U03¹"X´úÐŒn4£ÍD°<$|ëÜWº}÷îÝ grä`‘·€ft£Ýh&ëÿ £Þ4b¥3¬[KÚ(4ªåk®*@‹VšÑft£™–è»=視¸ØìW©3¼r° „Br°B€ÎM¥Ý.—k|_JJŠaˆ`ÑúA3ºÑŒn4Á,úïÑŒn4£ÍèŽÁš;w®¬Y³†(,Z?hF7šÑf"X‘2X:ÿ•NÑ yW:z0##CÚÚÚäöíÛ¸r° „Br°Â.¾¼mÛ6“‡e%ºk.V]]ôõõᄈ`ÑúA3ºÑŒn4Á ½ºpႤ§§Ï‰¥“æåå|ŽÂÂB‹)«a f1dLJ[ëúÈÁ"oÍèF3ºÑÇó`ù‚ægUUU™ÞÁ‘#GŒs7XMMM’ŸŸ/ƒƒƒ†jÂtŸ7ø;>ÜòX×G‹VšÑft£™Q„áÖ­[’šš*ÝÝÝ÷,5ú†YÐǾ¢bþŽ·<Öõ‘ƒ!„Æy–.‹c­AèÎ`–ÊÙ¼y³466šÇîK“éGGGÇ·õ±îóLJ[ëúˆ`ÑêC3ºÑŒn4Çy+99y‚¡²Só°. ››;¾ín°<ådù:·¿ãÃ-e}z-ÚQPP`ú­–þwû§Ÿ~Šèù¦Ë¶û'è×î|'éµ¶U7Ÿogèwâý̉ŸïɼŸEÝ`©‘jnnëj®ººº¼"XD°hõ¡ÝhF7šÁ 4Jå žºí&ËSŽ’î &'Ê~|¸å±®,!„0Îs°tÎ+ùIxE800àq”]°Ç‡[íúˆ`ÑêC3ºÑŒn4;,‚ÕÚÚjæ½Rs0YK¡sCy›'*ØãÃ-v}̃ÅÜ1hF7šÑf‡Íƒå­{/ØQ„á`Ö¬YQR"ÚõÁ¢Õ‡ft£ÝhvXË}ä`(£ÁÔ4XB!œæ"X´úÐŒn4£ÍD°@Ü,úïÑŒn4£Í莡ÁÒž“’’L— Rë>@‹ÖšÑft£™V8sæŒ×$wL9XB!9X!@£UË–-“þþþñ}ú¸¨¨ÈÌ‘ˆ`ÑúA3ºÑŒn4Á Ú%¨ >»cdddJLg€Á¢ÿÝhF7ךkîii°†‡‡ïÙ¯¦ ƒE‹ÖšÑft£™VHNN–¼¼<éëë3‹+õqNNŽé>ä`A!„ä`…0‚Ð[’û•+WpBD°hý ÝhF7š‰`…5R­Ò.A¥>Æ\‘ƒEÿ=šÑft£™¬¢­­M 9›={¶TTT˜nF ž¢cþPWWçsñäpËc],Z}hF7šÑæ8`… 桵µÕŒ<Ԯݻw›.»Á MMM’ŸŸ/ƒƒƒ†jÞt_¤Êc]9XBaæ`©áÑÅœ½E—,ZÇ„ûÄ` –šu°ô±&âGª<ÖõÁ¢Õ‡ft£ÝhŽÃ–'žÁzìÖ1Á@#XRZZ:Á`%&&šó¥¥¥I}}½Ïs$$$˜óØÏ©û"UëúÈÁ"oÍèF3ºÑLVP‘1å¼y󤫫Ëã1RRR"µµµ>Ïãi¾®H•Dz>½Àí(((0*˹ëÿp·{zz"z¾é²mÑ)zuûÚµkŽÒkm«n>ßÎÐïÄû™?ß“y?›ÖËŠÞ444Hnn®×c†††L28,r° „¸œËWžU89X¾"Fþ –§œ&Ý©òX×Gy hF7šÑæ8EèÍDݼy3`ƒU]]-ÝÝÝãæI§)°ŒÊÊÊñ.ÃÞÞ^)++3ÏñÖÅfÊð9j/Ôòh×Gy hF7šÑf‡ä`ù=hÑ_7—…––ÉÌÌ4Ï™3gŽTUU³á©|Á‚&ÿʾþ¡§&5i¾æ• §<ÚõÁ¢Õ‡ft£ÝhvHË)hMÇàN5 :0ˆö¢ÒSakr° „Â8ÎÁ e*0= ­4£ÍèF3ºã`š0µ ý÷hF7šÑftÇÈ`;v̬èÍ£:~ü8Nˆ­4£ÍèF3¬`1wî\3bÐÓ(Âùóçã„ÈÁ‚BÉÁ e4ád̃ˆ`ÑêC3ºÑŒn4;6‚¥£ûûûïÙß××'³gÏÆ ‘ƒEÿ=šÑft£™¬`¡?ì©Ò5u‰eGG‡‰låååᄈ`ÑúA3ºÑŒn4Á škåm¢Q•ƒ!„’ƒ´;099ÙLÀ©LII™0; ‚EëÍèF3ºÑL `°è¿G3ºÑŒn4£ƒ…Á"‚…n4£ÍèæZÇUkÙ²efag÷¬@§ihkk“ÂÂBÓ½¨#uâRív´£®®.¨Åýny¬ë# B!Œã¬’’’q3ån°]§P Zkk«ŒŒŒ˜Qˆ»wï–œœœñò¦¦&ÉÏÏ—ÁÁAC5cºÏüny¬ë#‚E«ÍèF3ºÑì€y°Îœ93abQY¸|ùrÙ¿ÈçÕh–5ú†YÐǾ¦€ðw|¸å±®,òÐŒn4£ÍqžƒeŸÉÝþX#QsæÌ ú|ú¼ÆÆF)--ߧݺß~ŒîóLJ[ëúˆ`ÑêC3ºÑŒn4ÇyKM•vkYQ§––óX»ü‚]*ÇêZœ7ožtuuy4n|u?ú;>ÜòXÖ§Ø¢Ƶ[,ýÏ6Ûl³Í6ÛlGf;êëðáÃRUUe§§§OÈÁ e±gÞ444Hnn.,"X´úÐŒn4£Í̃¥Iê ,0‘+Bݽ{7äsÙ#8žr”t_09QöãÃ-u}ä`‘·€ft£Ýhf,¿¨®®–îînóX—×Ñi ìÃe§³Ã{eçÞÅæïøpË£],Z}hF7šÑfG°B…æmeff㢉ñÚåè¾ÔŽš.oóDyÊaòu|¸åÑ®y° „B‡ÍƒÕÓÓcÖ!´ºµkP HRRRÔ š}J‡x¬­>4£ÍèF³Ã"X:!h{{»y\^^>!ɽ¨¨ˆ5m¦±Á¢ÿÍèF3ºÑŒî,í6<r° „Â8ÏÁr9î(ÂöövÉÈÈð: ¼®yXRR"µµµ>MŸ¯\±pËc],Z}hF7šÑæ8`EçÏŸ—ÔÔT¹~ýºÏㆆ†|.$Ï,½Àí(((0ýÎÖKÿ‡»ýÓO?Eô|ÓeÛý¿ôkƒÆIz­mÕÍçÛúx?sâç{2ïgÓÖ`µ´´HRR’\½zÕï±þ –§œ&Ý©òX×G‹VšÑft£Ù¬eË–™ˆK¨9X{÷î5£;::<–WVVJWW—yÜÛÛ+eeeR]]íµ‹Í•§‰÷¾Fí…ZíúÈÁ‚B–ƒ¥ùP–™r7Xæ`yK’·G·233; ˜ü+ÎÁW“Î%åk^©pÊ£],Z}hF7šÑf‡E°ÔèVV»âæÍ›²|ùrÙ¿Tºu‚Òh"Úõ1sÇ ÝhF7š6–=šc¬‰ÚsæÌaM›il°hý ÝhF7šÑCƒeÍ䮑íγ& u,05 „Bcd°>lÖTèŒîöªùóçㄈ`ÑúA3ºÑŒn4Á ###& ]#WóæÍ“»wïâ„ÈÁ¢ÿÍèF3ºÑLÀ`Ñú¡¥‹n4£Í莱Á"ÏŠ,!„¬¬©0e‹ºÑŒn4£ÍqÁÒØué@ý÷hF7šÑfr°"d°Nž<)YYYãS5"X´~ÐŒn4£ÍD°"0–7’ŸE„BHVˆIîÞèZ„€­>4£ÍèF3¬£­­MŠŠŠLÂüìÙ³Íĥީ«« j1dLJ[ëúÈÁ"oÍèF3ºÑÌQZZjŒÖõ ‡‡‡¥¦¦Æ. MMM’ŸŸoò¼”………fŸ7ø;>ÜòX×G‹VšÑft£ÙÁó`…šƒ¥FËÞ½¨æCß0 ú8//Ïëóýny¬ë# B!t@–'ܼy3dƒuêÔ© ¬„„cºìL÷yƒ¿ãÃ-u}D°hõ¡ÝhF7šã4‚åkô E&ÁÚÛÛ%##Czzz&Ôå_ ôþŽ·<Öõ‘ƒEÞšÑft£9Ns°¬‘‚Öt îÔdíÆÆÆ ÎyþüyIMM•ëׯ!rRK/°E; ̇Êrîú?Üm5¹‘<ßtٶ轺}íÚ5Géµ¶U7Ÿogèwâý̉ŸïɼŸE½‹0RS1´´´HRR’\½z5 'ÝLN”ýøpËc]9XBaœç`E{÷î5Kîtttø¥§S7xeçÞÅæïøpË£]9Xä- ÝhF7š™+bù\vèÜPÞæ‰ò”ÃäëøpË£]9Xä- ÝhF7š™+êÐ Jã¹>"X´úÐŒn4£ÍD°@œ,!„b°0X´~Ðft£Ý\k ˜Ú‹þ{4£ÍèF3º1X,Z?èF3ºÑŒn®5 ƒ!„’ƒˆ`ÑúA3ºÑŒn4ÁÂ`a°è¿G7šÑ͵æZ£ƒˆ`ÑêC3ºÑŒn4Áä`A!„ä`a°0X´~Ð͵æZ£ÍèÆ`r°È[@3ºÑŒn4“ƒ¼-ðì©Ü×qvÔÕÕù\<9ÜòX×G‹VšÑft£™VÀF+˜ýÞÐÔÔ$ùùù288hXXXhöEª<Öõ‘ƒ!„’ƒuƒ¥fE¬}œ——±òX×G‹VšÑft£™VD Vbb¢Ìœ9SÒÒÒ¤¾¾Þçydttt|[ë¾H•Ǻ>r°È[@3ºÑŒn4“ƒ¶Á²£³³SJJJ¤¶¶6¨ó¨9‹Ty¬ë#‚E«ÍèF3ºÑL+¢K144d’ÁÁÒ lÑŽ‚‚ãÚ­–þg›m¶Ùf›m¶#³Áò’Ó¤û"Uëúˆ`ÑêC3ºÑŒn4Á Û`UVVJWW—yÜÛÛ+eeeR]]íõyÖ¨¼Ÿ£öB-v}ä`‘·€ft£Ýh&+¬y°<ÍsÕÒÒ"™™™fÿ‚ LþÕðð°Oc¦sIùšW*œòh×G‹VšÑft£™VÔ1kÖ¬¸®y° „BæÁqb°hý ÝhF7šÑÁÂ`Ñn4£ÍèæZc°,Z}hF7šÑf"XÀQ B!„, ­t£ÝhF7׃ÈÁ"oÍèF3ºÑL ‚EëÍèF3ºÑL ƒ…Á‚B! Á¢Õ‡ft£Ýh&‚ÈÁ¢ÿÍèF3ºÑL ƒEëÝ\k®5ºÑŒn   B!$+(Üwß}ãô†ºº:¹ÿþû ·nÝê÷œþŽ·<ÖõÁ¢Õ‡ft£Ýh&‚°Ñò„¦¦&ÉÏÏ—ÁÁAÃÂÂB³Ïüny¬ë#‹¼4£ÍèF39Xa,5êH-èã¼¼<¯çñw|¸å±®­>4£ÍèF3¬° VBB‚ŒŽŽŽoëcÝç þŽ·<Öõ‘ƒ!„’ƒ¶Áò´æÌ™AÇ~|¸å±¬O/°E; LXÔrîú?Üížžžˆžoºl[tŠ^ݾv횣ôZÛª›Ï·3ô;ñ~æÄÏ÷dÞψ`Á¢ÿÝhF7šÑ͵&‚Z–î &'Ê~|¸å±®,òÐŒn4£Íä`EláÀÀ€ÇQvîÏów|¸åÑ®,!„¬°æÁò6–Î åmž¨`·<ÚõÁ¢Õ‡ft£Ýh&‚uÌš5+®ë#‹¼4£ÍèF39X N ­4£ÍèF3º1X,úÈ!„B  ‚E«ÍèF3ºÑL 8Ê`Ñft£ÝhF7 ƒEëÝhF7šÑ͵Æ`r° „Br°,Z?hF7šÑf"X, ý÷èF3º¹Ö\ktc°,Z}hF7šÑf"X€,!„, ‹Öº¹Ö\kt£ÝN7X,펺º:Ÿ‹'‡[ëúÈÁ"oÍèF3ºÑLVØ+455I~~¾ š}‘*u}D°hõ¡ÝhF7š‰`EÝ`©YÑ7Ø‚>ÎËË‹Xy¬ë# B!$+"+11QfΜ)iiiR__ïóø„„ßÖǺ/Rå±®­>4£ÍèF3¬ˆ¢³³SJJJ¤¶¶6¨ˆ—š³H•Dz>½Àí(((0ýÎÖKÿ‡»ýÓO?Eô|ÓeÛý¿ô÷ôô8J¯µ­ºù|;C¿ïgNü|OæýÌ£‡††L28,"X´úÐŒn4£ÍD°¢d°<å4é¾H•Ǻ>r° „Br°ÂFee¥tuu™Ç½½½RVV&ÕÕÕ^»Ø¬Qy>Gí…Zíúˆ`ÑêC3ºÑŒn4ÁŠ8ZZZ$33Ó› ˜ü«ááaŸ9L:—”¯y¥Â)v}̃ÅÜ1hF7šÑfæÁŠ:fÍš×õÁ¢Õ‡ft£Ýh&‚âÄ`A!„ƒ…Á¢õƒn4£ÍèæZc°ÀÔ6XôߣÝhF7šÑÁÂ`ÑúA7šÑfts­1X€,!„,@‹ÖšÑft£™ ƒEÿ=ºÑŒn®5×Ý,@‹VšÑft£™  B!$ ƒ…Á¢õƒn®5×ÝhF7 ƒEÞšÑft£™,$êêê¦ÜbÏ´~ÐŒn4£ÍèÆ`M[455I~~¾ š}ä`A!„ä`¡æJ·}œ——G‹VšÑft£™ 2:::¾­u9Xä- ÝhF7šÉÁ!â¾ûî»gßÌ™3½+‹vjäëÑG5ÿÃÝ.))‰èù¦Ë¶E§èÕí¥K—:J¯µ­ºù|;C¿ïgNü|Oæý ƒå¦.0XS4K÷ƒB„5Šp`` àQ„À`?й¯‚™ËöÜ,!„Fž,ûaB7šÑft£Ý,À—Ý\k4£ÍèÆ`L`°0X, p6té‹NA[[›ɬY³döìÙRUUeæ%s‚nwÍÒ]QQ!}}}޹îªÝ)Ÿsû÷ÚIßïööv³Ì‰®Žár¹äàÁƒŽ¼Ö‰‰‰q­¹§§GJKKÍuVêãîîn ˜º_R§@¿ŒgΜ1Ë KMM1\ñŽeË–Ikk«ŒŒŒí»wï–œœG\ó#GŽ˜5Æœd°œ†ŽŽIII‘S§N™Ï·6š6nÜè¸÷áøñã!ͯ8™™);wî4÷2e}}½deea°7䩽{[p;ޡѬxÇ­[·$55Õ´p1Xñ‹ÊÊJGD¬ü!;;[úûûãZãŒ3¦Ü½ ƒ¸!{€¶xÁr7•&šïؼy³Ñê¤Ï¹ÕM¤ ‡´´4ÓÂw¨Þ}ûöÉüùóÍ­ÎtóæMÇÝ˪««ã^çªU«ÌgZïcÊ;v˜},€ÁšBМŒŒ Ó§ï¤k­œ7ožtuuŵÖëׯKnn®£?çRRR"µµµqÿ¹^¿~½Ü½{×týoذAÖ¬Yã¨k½dÉÓUïèíí•äääñ{™>ŽuÔƒ0X6œ?Þté°Ó ­¾††† æ#¡úì&Ò© ‰¡¡!³öi7Gܵ[PM–R» u*'àÂ… Æ`9:bPó®ì9XŒ"Ó¢…ïDÍNЭQ;Þ¬ZçÌ™ã˜ù¿œh°ì×zÁ‚&ÿÊ݉WhW‘~¶µk°¼¼Ü1Iî½Ó)Xœm44dXZZzÏqË–-“ãÇ›ó(t£–/Y²„‹  ¢í–Ó© 5NÁ,…&›?õÔS&¿JSC§Ó(اMPó¥Ý„š•””$ûöíóx^¦!%%ÅD£Ô´é¶ûqzÞ5kÖMÖ”ÚeH, À``°0X,€ÁÀ``° ƒ_ëw¿û„B!Œ',fä ƒ€ÁÀ``°ÀÔ7XýýýR^^.÷߿̜9Sòóóåĉ“Vß}÷Ýg¨u%&&Êš5käêÕ«“^ŸÒnÞ¼i^ìY³dΜ9²cǿ笫«3ï—rëÖ­A—{{}ž^g[[›š×7{öl©¨¨¾¾>¯çów|°çSœ:uJ233ÍsRRRäÀ>_¿¥Á[™·k¡¯­¨¨hüµUUUÉÀÀ@Àï­¿ó{mø®Åö»‰ÏK0ßžž)--•„„C}ÜÝÝÖw-˜×Çw €83Xz“×/ÂíÛ·ettT¾øâ Y±bŤބ-hûöí“yóæMêß½^;ô¦¸~ýz¹{÷® ˆ &ÜÔÜÑÔÔdÞ³ÁÁAC½Áê¾@Ë}]–-[&­­­222b®ÏîÝ»%'''äãƒ=ßåË—eÁ‚rîÜ9³­? 7n øõsœþ 9sƼ.½555æG Ø÷Ö[]Á^¾k±ý®ù;Ÿ¿ÏK°ß 56;wî4åÊúúzÉÊÊ ù|Á¾>¾kLEƒåry§hë6Ø/«}Ÿ>Ö/NRR’9—Þ®_¿Ôùöïß/eeeöi‹G[¹ÚÂÒVï­[·&”oٲŴʵõµgÏžo:z~½ÁXÐǾn‚zÓ°n€ }œ——py(7CO¯9’Çû*_µj•>|8ì׊N½ùÛ?Ÿ¾·Þê öÚxÃØïÒØ”HZšÈÒ¥"Ÿ~Øóø®÷] ö³ãþy ö»1cÆŒIý®ù{}|טª+˜ý6臾¶¶VnܸòM_oÊÚJÑ/é[o½å3"âé|ÚºÖ›·…íÛ·›–½žS[‡Úêµ·ä¶mÛ&%%%¦\[Ãú©›¾žO»¼AËT§ýÆd?Þ_¹ûëÐmýñÒ›[ÚØ/¶¶š}ÝMë3›©§ãƒ)WèuÑ÷$7}í.±ÿû{oýÕèóý™«%KD.^üãöW_ýq;“Åw-¸ïZ°Ÿ÷ÏK°ß 58úýÓ2¥vaê¾H|×<½>¾kĹÁÒ~÷êêj™?þx ÖžGÈMß~Óô×Jóö…´?Ç5öºí?Bú£ &Ä‚†Ñ5_"x«wݺu¦«B5XÝÁ¾~ûñ¡”[èìì4?fú#ì©^¥vñtuuù=Ÿ·ã-ôfhÞG°7ýöövÉÈȘpý½·¼'ÁF•Ü¡¿Ÿ–¹² &«°Pø®Eø»Ìg'ÐÏ‹¯Ï~oo¯$''—ëcÍ› ÷»æíõñ]`*¬@»ƒì2Ô®ÍÉÍÍ ê¦ÌÜS™ÖkoUë1údQ·íáûPZh¾o5ñXëѾ½{÷Nø‰tˆ††LR¨·VrCCÄëã þŽä|±hUŸ?^RSSïéþŠE«Úýë3ö;tFF‚ïç»æÿ»èkðöy ö»Q\\l"Xö¬@º0ý}—}}Nÿ®w,-\½ÙÚ¿(zƒŽôM_óBì¡xmUûmÉVµ;_Ÿ—`ßO߃p¿kÁ¼>¾kÄ™ÁÒ/õű_ ½±k«Móì#g²³³Mn–ëX»5"uÓ÷6²i×®]²|ùr²Whؽ²²r¼ÜÊ Ñ×n^È /¼`Σú4A[s¾ºÌ¬Ñ1ú_£½•»¿ÕeÕ§zõzh7’}l Wó¥ Éö•ûùüï¯Ü:²I£ .\0Û“9²I#úƒßÑÑÒ{ﯮ@Ÿï áä`ñ] î»æï|þ>/Á~7ôZè5±ç`Ù¯O°çó÷úø®0] Vˆ£õF§_m=kW^í9:Ö›Œ–kkGoÒáÞô-êÈ%ýñ:׿æ@h½:|º¹¹yB¹æ)i¤ÇßÈ&9 ÚŠ¶rb´‹@óüAo¤¾æwñUî^¿¶"UŸî×hê²çÙØËõýrŸ¯Æ×ù<ï¯ÜÛgDŸ£×Bçæ9tèÏ÷7Ô¼@Îåï½õ÷:ü]»@M–F².ücä*ÐQ„|ׂû®ù;Ÿ¿ÏK°ß 5{ÖÜPJ}ì+ß1ïf óRñ]`ª,€ÁÀ``° ƒ€ÁÀ`a°0X, ˜šËÛzT.*j}ºâ|bb¢Y-UæCE[[ÛøÚbºŽš¯µÂ‚}¿}?Ug ÐÅPÝÏ«¯_÷[¯¿¢¢Â,Ìõ´ãæÍ›æ=×óéÚiº˜­?Xk£éstm´øýü„òÙòw­uuu­æ ¾žƒå—ÇþB5?“ {·oß6‹ÙΛ7oÒLVii©œ9sFFGGÍÊ555æG<\íüøñ€~È9"yyy÷œwÙ²eÒÚÚ*###FÃîÝ»%'''ä×¥mýúõr÷î]ó~lذa‚aºç³tù²Y€úܹsf[ÍÝÆƒ~9Îßµjjj2 %ªñÔ}Öèó`°îÁ÷c®±?ý ƒÈ>5 ÑȃFGnݺTû÷ï—²²² Î¹eËÒHÇž={Ö¨?Þ=‹–ÁÊÎΖþþ~ŸÇ¨¶ÔÔTéîîè¼úž„úºô¹j^,ècO†ÓªU«äðáÃa¿¡˜w÷k¥æÈ2z }¬¦4к}> Ö=¨ûSƒ¥ÿ£a°¶oß.+V¬0²htÄáä|ÉR£è9·mÛ&%%%¦\#1j¶…vwE+‚¥uUWWû}ÞæÍ›¥±±ÑïyÕpèqéñv>«KRIZZšÔ××û4Xúþ%$$x­S¯‹ ƒå~­ôuê{`?<½vouú|¬ ШÕ±¿³cú?Ø(V(ËårÉ7&˜%_9GÞ~üì‘ çÔ.«žžž ßÐöövÉÈÈðøÜÉ0XK–,‘ŽŽŸÏ»~ýºäææú=¯•[¤Ý©]]]½ŽÎÎNcDkkkÇ÷­[·Ît ªÉ²º=EôÕhŽU°ï¯§kåéÁD#}>,—‡¿ucVäJ»¼üEÒ`écŠXÔí3fU‡v‘Ù#XþÎJ4äüùó¦N M$",þŽ×î'í^ó5W&¸444L0dþ044dº-h’{yy¹y_çÏŸ/{÷îõiˆcÁòv­ˆ`˜tƒå+zeE­Ü·CýTccÿQR3äÁrélšƒe7#þÎl«¥¥E’’’|&ÒGÚ`in&ˆrž`Gpuq7Xî8xð I|÷Í‹f–¯kå)‡J÷ZW Ï€ÁGÍÿýùÛì &ikÞš,5=špn?n×®]²|ùréíí5Û©¬¬ ¨o£ýÓÊÁÒ×ã/K#4jØÜ»ê&Ó`]¸pÁkòt ]nvh—&¿[fI“ÿí¦Àýx}Ÿ¬ˆ˜¾jìy`/¼ð‚yßôzjŽ“FŠì4w¨IÔH—jRLæ(B×ʨ¯?œQ„þžƒe00öçòñ§å¡þj7MVV–‰didA ‘ûqjˆ’““Í1:_Rsss@%¨†ÍS·¿sj^‘Ffü"ô! 6zÈñúíS+DÂ`iDGõ[ï—§y¼¼¯‘>}ŸìIí±Rä]„ÅÅÅ&×ɬy°ôZè À``°0Xƒ€Áˆ+ƒ!„BÃç¸Á‘Ãÿ²/B8¹¯ÈùIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_long_increment_line_total_narrow.png000066400000000000000000000563051174000617100302130ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔ\ŒIDATxÚìkLUi{þߤiš¦iš~iš~hš7iš~hš¦IÓ4Mc&ì3Vƒ‚rÅrPD<á•ÁÓ0:âà08*ŽƒE䤠¢â‰ÑgTÐÁ‘aG^}¹ÿÜëýoÞÍfŸ÷öáw‘+쵞µ×Z×zÖZûzîç^Ïú¯â7  ƒ0XÀûøío+¿ùÍo†øÿøw˜éSúʺ‚ù8îîœ_===²sçNùßÿý_ùË¿üKùÓ?ýSƒúù¿ÿû¿%&&FŠŠŠ¨P€Áã‹«W¯Ž¸©)¯_¿P?², õäÝûÀxì÷éÓ§å¯ÿú¯­îëh›œóƒÜBrr²Õ›Sbb"‹.Úƒ¤žÜ¹Œõ~+ûÛ¿ý[Ù¿¿ôõõåýýý†QÔèÖþçrÎ ?üþ÷¿—¿ù›¿ºqüÕ_ýÕ°›7ôƒÀ?GݽŒå~ÿøãF iþ_üÅ_ÈÇ¹Þ ø&ªªª†Ý8-Z4lº²²ÒîÆ™ÐüÝ»weÞ¼yòÿðògögF®Äßÿýßóš››¾¡mÞ¼Ù¸Ùë:´uªû®xöì™±.S.Æ¿þë¿ÊáÇ]¾I¶··ËÚµkå¿þë¿äÏÿüÏuéÍìÙ³åÒ¥K^¹ázëXìÚµËX‡~_ódrrr¬~7++kØrÛ·o÷øÃÞw=ÙWOŽÿ¯¿þjD`ty=®æÐa-ûçþç¡õêya³ûk4Î?ocêÎ5êê}Àõ­ÇÓ|9:Ù;¿233‡Í_·n[÷_»8<1£},Lz-…¹^ý‘4/3ug),»ƒFÓ`9³¯Þ8þÖº°Ì£ZÊ–––¡2Ëý™0a¨žÞÜgŽ©+ç¨7ïæ×‚~¶µßæ&ÜšGÑ%oÖ,`ï½÷Þ°›†) ÿÍçërî ó„T˧¶ÍËtY{ë7ÿ®½2{7a[ûlžÐ«Ô1v¼m°ÆêX8³=k&a´ –3ûêão-ša¹^{tdN<=ÿÆj_Ü9G½yÍsÓQË‘Áòf€Á6¡?bæù@šhmó¼ýÑèêêrù†ãJ‹S—u÷GÜÓ2Gûé ƒ5ÖÇÂÕÖþh¬ñ<þ–ëu%f´5Žç¾ŒÕ}ÀÛçæÿüÏÿ ›ïÊC!£Y`°À0|úé§.Ýl,“T=`Y¶TEmF³l¼#X£q,|%‚5žÇßò¨îñÒèKû2V÷oŸ›–OZ{ `<ê Í1påÆêNN‚7óŽF³Ìßr°œ)³ìö1ßž£,GÚüåø[s[C'Œ…©ñ¥}«û€­²©S§º•ƒ¥„˜à®Ÿuˆ g×hÕ,0½)YÞ0t "s9dï‘ë±4XškbÞ} ù¦§ØL:t,&On¸c},JKK‡Í×'yRk< ÖhËc®ç¬šY…FMôéEÃÚˆßÞÖ8ûâèõÆ}À}s÷)BEYYÙ°2íÒ1å‹ÇßLÇ\ÇÊÒã ?°jætœ§ 6XM–-c¹/Ž®QoÜ<9ú–ËsÓÙºÕqÇt¿þïÿþÏÈá3KCM÷O‡døè£äÛo¿õJ¸r¿,@BÇ32ÿÐ,€Ð.]\“ƒúÔ”N›¿Ô×Þ{æ`°–¼ƒîK}'›­n!,€èÓˆÉÉÉFÞˆæ4©¡Ò\“wÞyÇÈuÒ'Ä`°0X,€ÁÀ``° ƒ€Á¬À…¾Þ:z÷¢E‹¼ÊÑX§/3ØôRÇhF/šÑûGZþ®b°0X/^,.\ð*õµ*Þ^§/3ØôRÇhF/šÑûGb°À˜¬;wîÕElz©c4£ÍèÅ`q0XBa°ƒˆ`Ñ D3zÑŒ^êƒÈÁ"ÍèE3zÑLÀ`Ñ*B3zÑŒ^4ÁÂ`a°ÈÁ‚B1X€­@4£ÍèE3,@ýúhF/šÑ‹fr°|Ì`=~üXRSS%$$DBCC¥¢¢bXyAALž<Ù`~~þˆï;*wuyß,ZhF/šÑK¹Ájmm•ððp¹víš Hww·ìÞ½{¨¼¬¬L’’’¤§§Ç`JJŠ1ÏÙrKxº>_ß9XB!K²³³GD¬Ì¡æB© ú911Ñéro¯Ï×·G‹V šÑ‹fôRÇ,™2eŠœ>}Z¦OŸ.“&M2Dôöö•k·¡F¶LÐÏ:ÏÙrKxº>_ß9Xä1 ½hF/uŒÁ’ &ÈöíÛåÍ›7Òßß/;vìM›6 +·Äĉ.·¶=OÖçëÛ#‚E+ÍèE3z©c –Qce‚-dÁr}{z˜hŽäädÃÕ›N<ýÏ4ÓL3Í4Ó0-¡¡6é­íù¥ÁÒ¤mKƒen ¬å é_Û,ZhF/šÑK ƒ5æ0Ïç Äí1„Â`äÍãÇ¥]ŠÃ`@2X´|ÑŒ^4£ÍcÍÆ³g¥åƒ¤oÁy'ßmÛ†Áe°ÈÝ@3zÑŒ^4ª«å~^žt-]*¿‹Œ”gƒ¿q·‹Š†wÚ  Á¢ˆfô¢½h6±®Nš–޵kåMD„t¦¥ÉWR_Sc”—^-•]vIòËd™óvŽÌ˜)Ož¿y? þÍü;sý  ƒ!„^?yR¾ÿ}y+½ƒ¿]wï–ËçÎeÅMŲý»í²èçEý»hYÿl½üò ¬íX+;^íö»—;ø—õ2 ƒˆ`Ñ D3zÑŒÞàÔ¬êá®]†¡RcÕ:h°ÔhÕ]¨“¢[E’õ}–Ì{5Oæþ:W6·m–#·eúÝò+åjçOË1X€,òÐŒ^4£7(4kWßWŸ~jtýi`GF†Ñ%Xw¡V5’ O7HLŒ,üe¡l{²MNÜ8aw}Ü•„„^‰ˆ ~‘‚‚¯¼º¿,@‹–/šÑ‹fôú¬fMN×$õ7‘‘FÒúý}û¤®®Böµ_Ö>_+o"$©'I>lùPÎ\s.‡JÍU\Ük¹t©ÛxÜýûo%>þWM ƒ!„ЧxíÌy²}»ü:ožü²`1ÌÂ…Ê“’÷Mž¬è\a$©§v¥Jîƒ\·ºô4rÕØ8|€òdpþï0X€­@4£Íè Í—*+åÛÜ\y™˜(ýQQÒ¾y³4œ>$»î–”î™ófޤÿ˜.û¾Þ'ç/wk55õrôèM™=û÷òûßü-œ=[0X€,òÐŒ^4£×¿5_¬­•»È«VÉ›9sŒÿ_쑜G;$¡7A")?dÈgw?“šú·ÌÔž=dýúdÑ¢Ÿ c¥ÿcb~'w`%%ýƒˆ`Ñ D3zÑŒ^ÿÔlzeÍåeR’ÜØ¿Ur¾Ù,ñ}ñû:V6µo’Ïï|.uë<6Së×?“ÜÜrìØMc9SÖ‚oåÞ½?š«ÁŸ=))éÀ`r° „ú-_YÓ¼{­|Ô¼Ö0Tj¬²[³åØÍc^7S¶XXøµ,_þÆèLNÓ§ŸËÅ‹1X€­@4£ÍèõmÍ–¯¬ù6;Uò¯,7ºþ´ pçãrêú©Q7SãQÇ,@¹hF/šÑë=ͯ¬y²v‘>¿Db^Í‘¥ÝK壇ÉÙÆ³ãb¦Æ²Ž1X€-_4£ÍèõX³é•5¿Î‘SæÊ©ñ²¨kެx±BòîçIÅ¥Šq7SD°9XB}ž¦WÖt/Y ?Ï‹óûcdå“YÓ±F îHU}•O™©±$ Á¢å‹fô¢½C,}Xj·ÜôÊšg«’åuT¸4~!ÛnEJfûF9xóˆ»áWfŠ ‹Ü 4£ÍèJh¨Mš–¹Uô…<ÌJ“WÑaòÕ†0ù´"V2/HÖ§7dÝ yò×È9X€-_4£Íè=ƒe ƒóïìY#] çH{B¤{£¬ÞrYâ^L7,@„Â17Xçæ~$«f?” =3…ÁÄ„ FЕrEAALž<Ù`~~¾Ãm:ZÞÓòñÞ,Z¾hF/š‰`Y3Xn¦ˆ`Y(OÊËÊÊ$))Izzz ¦¤¤óÜ]ÞÓòñÞ9Xän ½h&Ë–Á¢Ž1XN—«ùPÇj‚~NLLt{yOËÇ{{D°hù¢½h^½§N—µÁ"‚ea ¦L™"'N”ÈÈH),,t©<$$Dþømý¬ólÁÑòž–÷öÈÁ‚ÂàäçŸ|.̳ûaù•rŽU0&¹·µµIzzºäåå9]n-Â¥fÌ•ˆ˜ùòž–÷öˆ`ÑòE3zÑ\zëê.ȱµ{¥gVœœÍÛOc°¬£¯¯ÏHæv¶œÖpce¢9’““~iÓ‰§ÿ=~ùò¥W×çëÓÁ¦W§;::ÐàÓ–ÿÑëÓ®4Ê¥ø÷¥5"Q*ŠOŽ(×ó:Xêw4õ¥Á²–£¤ó\ɉ2_ÞÓòñÞ,Z¾hF/šƒCïá¢Sò]xª4%®“‹UUÔ1¬áÈÎΖöövãó‹/$##Crrrœ.7=e×ÝÝmõ);Ë.6GË{Z>ÖÛ# BƒûwÊË™qRõþ‡r°¬£¡¡Aâââ c2cÆ #¿ª¿¿ßér…Ž ekœ(k9Lö–÷´|¬·G‹–/šÑ‹æàÑ[^S#'“÷ÊOaó¤êàaê˜ÖøaÒ¤I½=ÆÁbü4£ÍÁ¡÷Hé9iŠÌ”‡sSäâÙ³Ô1ã`@4X´ŠÐŒ^4£w옗BžÍZ"×VfÊÅÚZê˜Tƒ!„pôYU['ùë ¥gV¬\ؽ—cB ‚E«ÍèE3z=áñÊj)›¿G~Œˆ—ú£Ç¨c"X€,úõÑŒ^4£×î-:+÷ÂÖÊ7‹—Ë¥ÊJê˜,@‹VšÑ‹fôºËÚº:ù`Ç y1k\Ï|_. NSÇD°9XBÝäéêÙŸ\(=á±r¥`?Ç„,@‹VšÑ‹fôzÂOOWJmÄò4f¡4–”PÇD°9Xô룽hF¯'ÜöI©´„¥Éש+¥¡ºš:& Á¢U„fô¢½îò\M­ìX{JºÃæÊ­9Ô1,€Á‚Bè UTË‘y‡äåœX¹~ø0Ç„,€Á¢U„fô¢½žpû‘sr5<[¾_"eeÔ1,€Á¢_ÍèE3zÝeu]lÜV.OÃåëµëäbM uLÀ`Ñ*"º^4£×]¯ª‘œÄÓÒ#·ss©c"Xƒ!„Ðî:U%%òSÔ\i:vŒcBÀ`Ñ*"º^4£×]ê¨ìëòªåËðuÒš´T.WTPÇD°‹~}òs¨c4£×]–ÖÔÊúUÕòbv¼|³%ËãWÞPÇä`"X´ŠÐŒ^4µÞOʪ$/î´ü<;Jš ¨c"Xƒ!„У⩚“+/æÎ—ë^|å $ Á¢U„fô¢9èôVÔÖJZÖy8g¹´¦­†ª*ê˜À`ѯ^4SÇèu—‡+«eÓâ Æ¨ìßìÜI“ƒåk„ #h‰‚‚™_ß,ZhF/šÇFïû'jäPä1ù9"Zš}ð•7Ôq,{(++“¤¤$ééé1˜’’bÌs¶ÜÛëóõ푃!„£O•}éžz¹2ç}ùqÑbi,-布å_KÍ…:Rôsbb¢ÓåÞ^Ÿ¯o­@4£Í£«·¸ªFR—_•öÈiÍÈú1xå uLË-ƒ5eÊ™8q¢DFFJaaá°òšÖÏ:ÏÙrKxº>_ß9Xä1 ½h=½»ÏT˶Ø:ùyN´|3†¯¼¡ŽÉÁòmmm’žž.yyyv#\jÆœ-w&bæÊú|}{D°h¢½h½iŸ]”âȃÒ+7¥Ž‰`ù×S„}}}F27,×·§'€‰æHNN6\½éÄÓÿL3Í4ÓL;7}çÁY’ySš£ÖHç²eÒöÕWŸ ›Hƒe-Iç9[îLN”+ëóõíÁ¢ˆfô¢Ù{z Ê«%}áM錜'­[¶ÈÅqzå uLËedggK{{»ñùÅ‹’‘‘!999#ž¢ëîî¶û”­rË.6O×çkÛ#‹<4£Í££wýu²'ªBú"¢ä«O?¥ŽÉÁò/ƒÕÐÐ qqq†1™1c†‘Õßß?lûÉÞ8PöÊ­å0y²>_Û,ZhF/š½«÷|],ÚÙ$•Ñ»¥'nž\?y’:&‚ÅHî–˜4iR@oq° „Ћ£²WTÉâ¥÷äaì2éX±BΟç¸@  ‚E+ÍèE³»z·×Ⱥ˜&鉌‘ÇúÊ?Ë·¢Ž‰`0Xô룽h½µƒLÊk”ÏbNÈ«È(i>tˆ:F/ Á¢ˆfô¢Ù]½ÅUÕ2wõWreÞfy¹h±\ °WÞPÇ,@„Ž*¿¸ýŰéÜÒjIšÿ­<»X~XëÛ¯¼ä`"X´ŠÐŒ^4û¸+ »%4òW™¿¨W ¾’ôƒõ’Ý }‘Qò`Ïê½,@y hF/𥄆Úd_L¬Ü**¢ŽÑ‹ÁD°h¢½hvÙ`YÃàü+çÎQÇèÅ`r° „Л‹ã1X€­@4£Í,ê˜ ‹~}4£ÍãËÏÎU½Áâ:Æ`"X´ÑŒ^4{ú¢æuIµv Vù•rê½,@„:⹚ZY°í¦œŽÍ“¾è»Or¼  Á¢ˆfô¢Ù‰.Á”„fù.6Iž§¥ÉåŠ ê˜ëƒÈÁ"ÍèE³']‚G•Ë/¶¥ŽÑ‹ÁD°h¢½hv²K0)»Q£²¤kÁB¹~ò$uÌuŒÁä`A¡']‚5ÈOsâäIæ&Þ%ÉÁD°h¡½hö„?¯‘∃Ò-_:D£™ ‹~}4£Ížt ®ÚT+ç¤IÛÒer¹¼œ:F39X€­"4£Ížt æÆŸ–ÞÙÑòõ‡»¨c4Áä`A¡'|ÿP¥\š½]žÇ-¦âbŽ $ˤ¤¤È„ †ÍÓiKZ¢  @&Ožl0??ßáv-ïiùxo­@4£7P4k—`öúRù1lÜ_·Þ£Dvê½Ai°ª««%11ѪÁ²‡²²2IJJ’žžƒjÒtž»Ë{Z>ÞÛ#‹<4£7P4(?/'æî——³cäÆþýÔ1šÉÁr¯^½’ˆˆyöì™ËK͇:Vô³5w—÷´|¼·G‹V šÑšs ÎÈ7a«äÑ’er¥¼œ:F3,w°wï^)..¶j¨tzÊ”)2qâD‰ŒŒ”ÂÂÂaå!!!20004­Ÿuž-8ZÞÓòñÞ9XB8ô“•ŸKϬX¹¾}§\¨«ã¸@r°ÜAKK‹$$$8±jkk“ôôtÉË˳»¼š1[p´¼§åã½="X´ÑŒ^Õ|øL™ÔGm“¢Êå£Ç¨c4Áòj®ÚÛÛîìëë3’½‰`Y7V&š#99Ùè—6xúßÓé—/_zu}¾>lzuº££½>mù<÷ç³OŠ¥cÖb¹µj“´>xðzÇjZÏkôz>í—ËÚS‚öL–¥Á²–£¤ó\ɉ2_ÞÓòñÞ,ZhF¯?i®¨©•SK÷ÈËYs¥f_>uŒf"X£i¸Ì‘=ázñâ…dddHNNΈ§ìº»»­>eg¹>GË{Z>ÖÛ# Bè¯ÖÛ#‚E+ÍèõGÍǶçËËYqr~ãØ%²SÇè jƒåmLš4) ·Ç8XŒ%ƒfôú“æó•ç¥aÑfy¾XÎ~A£™q°€ÿ€­@4£×5—‘UÃâM†Ñ¢ŽÑL `° „Ð]ÖÕIÕÆŒ.Á£;ò9,€Á¢UD˽hö„ugJå~\š|=g•‘ÔN£™–‹Ã*XòwÞÁéƒE¿>šÑÄškòòáN.Ûc Ç@£™,;PãdN[ËÑh〭"4£705×WUÉëCós¿ ŽÑLËUTTT ÑdBWW—1¯®®§C„0ÈxùèQãU7£·¯¾á˜@r°ÜÀ{ï½'oÞ¼1_çM›6 §C‹VšÑ,šÕ׷픞°¹²oÕaã¥ÍÔ1š‰`¹ í ´e°ÈÁ"‹~}4£784_)+“G Ëä›°U’Spš:F39XžþO™2EnA} ±²³³ÓxóÔ©Sq:D°h¡½®ùæþÏäåì9>·@”Ÿ§ŽÑLË[9X¶’Ükkkq:ä`A”õÕÕrÝy¶PÞ_Æ'»!ôëq°Ô-†††¯ˆQêç{÷îárˆ`Ñ*B3zTsÓ‰ò-8}útFr' BÀüòàA錑âˆC²ñójŽ $k´ VXXØ0CeNFr'‚E«ÍèõoÍõ55ò$3S:#æÉ†… ~×%Hsû­ÁR#ňíä`ѯfôžæ¦“'¥kÁBiŒÌ’¤ì+ñ” uŒ^¿1XD©ˆ`Ñ*B3zOóƒ>’_"¢dod¹¬ÿ¢–:F3¬±6X:$COOކ,aðrE…<_¾\¾‹I’”„/ý¾KB¿5XMMM=ìeÏ€­"4£×w9Ø2¶É¾è)‰Ý' ¶ßÈC¹ŽÑë7ËÖ(î.%§©c®côú‹Á 3žhëìì4º®”úyáÂ…F÷¡7 –BÇ~²7”½ro¯Ï×¶G‹V šÑkÎ+ååòSÊ2i‰Y%‹—|+i7s¥ª¾Š:æ:F¯?,Md·ÕÅ÷í·ßúÄîFÒüe{Œƒ!4±ùÐ!ù5*VJ¢ eöÞ:Éùj/ÇB¦A”F«ÔX(õ³¯˜«`,Zh.½kk¥5ë}ù9bžlŠº)õ{ä‹Û_PÇ\ÇÔq°4 üÏ`ѯfôú¯––J×â$ù**S§ß“„ïÖIÙ•2ê½Ô1 Á¢ˆfôºÃ{òkDŒ|>ç”D9%¿ß$µk©côRÇþn°êëë%++kÄü­[·ÊåË—q:ä`AGõ55Ò¾q“tÍY(ëç~)÷6ɾûû86JÖ{ï½'½½½#æë¼éÓ§ãtˆ`Ñ*B3z½Ìë%%òrþbiš³]’6ß’¸ŸåÄÔ1zÑH,kC˜ðÎ;ïàtÈÁ¢_Íèõ"ïçåÉ«Ù1R0§BâËŽHêO©Ry©’:F/š-KÇe2MŽ :ֻヒÓ!‚E«Íèõª«åéêõÒ1;I6,º'1OVÉÖ'[¥îBuŒ^4bK¸5RÕÖÖ64Ðhkk«ÙÒH9XBÏx£¸XzbJýì=²2çšDÿ:WÜ=À±0s°4×ÊÖ@£}}}8"X´ŠÐŒ^øíî=Ò+GÖIê…²à—Rr­„:F/šƒa,íÔWæ˜ 7Þ›ÈÁ¢_Íèu—*+åYêù~örÙ²ì®,zš.«\-Õ ÕÔ1zÑÌ8X€­"4£×UÞ**’ÞÈùR¾_¶|rU¢û£åÃGRÇèEs°E°9XB/°®NlÿP~›+¹s/ËæË‡$¦?FŽÜ9±0Ør°§OŸ6ÆÃ2–A» Ÿ?ŽÓ!‚E«Íèu‚—ËËå‡%éò |­ìȸ++ž®•%=K¤¬±Œ:F/šƒ1‚UUU5”Ônn°nݺ%III8r°è×G3zý –Ÿç̓ӳ?—=Ÿ7J|_¼lxºAj.ÖPÇèEs°æ`͘1CöíÛg Ï`n°ô BÆÁ"‚E«ÍèµÍ‹uuòpÓy6_r5Jnãõ»(ùø›©cô¢9Ø#Xæ¦ÊrävFr' BhgÏJG|ª|9+Söf7Ëû­Ù2÷×¹rüæqŽ„ä`‰Lœ8Q^¿~=ÂPé0 !!!8"X´ŠÐŒ^Ëí|zP~ 4SÇåЉ+²´k©,ëZ&—+¨cô¢™Ö“Ùããã×å¨Ázûö­<|øÐ0^qqq8r°è×G3zM]‚55òpM¶tÎZ$y©WåHã)#jõ~ëû¿ò†:F/š,ËôZkìééÁéÁ¢U„fôòÚéÓòcl²4…m“¹·<+Í·Úo?uŒ^4Á²m²ÌGrgˆr° „f7ü=òKX¬["§Î\‘Ï6O –\/áø@HÖèA‡tHII1Ì™>y˜••e¼~ÇkÑ1KÈäÉ“ æçç;ܦ£å=-ïíÁ¢ˆæñ×[_U%R7˳’dÿú«rær™1¶UúéRÕPE£ÍD°FiiiÒÔÔdäoépÇ—… 3XöPVVfŒ¹¥]’J5k:ÏÝå=-ï푃EšÇ_ïµ§äED‚\ ß%G5Éçw>7Feÿ åê½h&Ë1:::Œ.A…¤iÓ¦†hæÌ™­W£YÎ,5êXMÐω‰‰n/ïiùxo­@4¯Þ;;òåçYs¥hñY©¨¸,9rŒ÷ n>L£ÍD°œƒFš?~l|ÎÌÌÖ·téR—×§¬ââbY¹rå0ƒ5eÊãÉÄÈÈH),,öB¿g¾{CD8ZÞÓòñÞ9XŽ/?/6Jë¬åòùŽF©n¨–U?®’„Þ)m,åAH–óÐúþþ~ãóôéÓ 3tÿþ}iiiqy$w“1Ó(X{{»ÕeÚÚÚ$==]òòòìF¸ÔŒÙÛŽ½å=-ïíÁ¢ˆæ±×{õóbùiö"¹ù±”¿"%×JdÁ/ dý륦¾†:F/š‰`‰Ë¦ÈüG_§ß¼y3bàQW"XEEE’`s} &{Á²n¬L4Grr²Ñ/m:ñô¿§Ó/_¾ôêú|}:Øôê´¦ ×Át]|½u¿ôΚ'§VUIMM½{|LbßÆÊ¶>¯ßò ×w°éÕi=¯Ñëùô˜,5:±ÒÈ’©+O¡Q-sä*ìEh, –µ%{/šv´¼§åã½="X´Ñ<6z/«”–yòpÖj9ñqƒ1XèÖ'[eîë¹rôæQê½h&‚å>ô‡Û<ï*55Õ˜¯nOGxw999òìÙ³!ó¤Ã˜ˆììì¡.Ã/^HFF†ñ˧ìôõ<Öž²³ìbs´¼§åc½=r° {^ùô¸t‡ÅKõÜ)/½$—*dÙOË$¥;EÎ]>Ç1‚,Ï1cÆ £;044th^xx¸¦s ÆkuÔ˜L:U¶nÝj˜ kåº-Í¿2å}™ ¦ÌÖ8QÖr˜ì-ïiùXo­@4¡Þº:¹µ*WºgÆËÉõ礮¸qBâ~“-ßo‘º‹uÔ1zÑLË7ÆÁm˜ùˆÛc,Æ’AóØèm8S!ßE¯’¯Ã7Hia½1/ï~žñÊ›O¿ú”:F/šËsƒõÞ{ïɦM›œŽRÀ3X´ŠÐLzv“žYó¤jñA©®ª—Ú‹µ’ù4S濚/'¯Ÿ¤ŽÑ‹f"XÞ1X:þ•>ɦÝašc¼òæõë׸› 1XkjåfÊn霹PÎl¯0æ•])“¤ž$Yñb…œo8Ï1‚,ïwjÒùþýûÜ(S¢»æbé»óÌß'ˆ`Ñ*B³¿é½xìœ|?g¹|™%'þ0ïÈí#Æ+ov>Þi<5H£ÍD°F=K£WwïÞ•èèè¡1±t°QG¯uä`‘Ç€æñ¢èÃ96Ø33NªSK]ÝEcÙÝwKT”j>D£Íä`_’»ægé:Â; ‚E«Í>k°¬apþ¹½n¡ª¾JÖ<_#‹^,¥WK©cô¢™Ob°ÈÁ‚Ð]ƒ¥åg®‘E¿,’ŒŽ Ÿ~å „0Àr°ôµ8¦wZÒWå"X´Ñì+ëà—%úwѲçÁê½h&‚5¶+,,l˜¡2§£r°è×G³/¬Ø×±Rt«ˆ:F/šÑ;öKT]]ކ­"4û«*.ÚÏÁºrŽ:F/šÑ;>‹(9Xú#Ë_of¯³û!Ç B8nKǼÒ"X´ŠÐì/,ÙwAžÍJ–ÛK?4Þ-¸®cäüþ/ÏüÛñjuŒ^4£w| VSS“1î•ùË™9Xôë£ÙWybs•¼œ9O®oÙÿ‡é¦2kðï‡Á?…þŸ=øWÙ\I£Íè?ƒeíéAž"$‚E«;ƚš‹RœR*½³âäê'GyÇn“9oçÈ¿ÿ`ØõLQ,®c4£×‡“Üm‘ü,r° ôž+¿,±å§Ù‹¤ñøiã7¶|(Q¿‹’P;åWÊ9~BD°h¢Ù’'^—k³?§sÓäRù9)¿\.©?¥JâËD)m,¥Ž¹ŽÑŒ^  ‹<4»ÂùMòpÖjiIÚ(õ55r¸ù°Ä¼Ž‘­­[¥öb-uÌuŒfôú¶ÁÒ<Ïœ9ÓèTêgˆ`Ñ*Bóx°®î‚䯿./f-–ûs 3•Ýšm˜«ÃwSÇ\ÇhF¯ï¬7nØLrÇd‘ƒáXóüùù$¡^~‹“æ=ÆË™“z’dùOËåÜås#¡,V¥¥¥IWW×Ð<ý¼téRcŒ,@‹VšÇl|«’kr8ú¬ü>Wn)’‚{Æ»så‰íÔ1š©côúÁÒ.A}á³%Þ¾}+“&MÂéƒE¿>šÇ„…‡îHEø~éŽY,WJOÉÆ§%îUœ1uŒfê½~i°úûûGÌWÓå¬Áºuë–¤¤¤Ë¿ûî»’••%Ö)((É“'ÌÏϱGå®.ïïÛ#‚E+0˜4çîüZn‡eIGBšœ­?* Y(«Ÿ¯–ó ç©c4SÇÔ±¬°°0ILL4 ÑÀÀ€Aý¼páB£ûÐh£Ž¯Q/ýþñãÇï›PVV&IIIÆ+y”jÆtž³å–ðt}¾¾=r°`°°¦¦^¶¯üFÚÂS¥uu¦ä}kŒmõñ7s| „þm°4‘ÝV’û·ß~ëözÍ£_j.Ô‘š ŸÕÔ9[n O×çëÛ#‚E+04—•]‘­ ¾”—áñr?g§±ZôË"9uýuŒfôRÇ1Lƒ)V©)RêgwÍ•F°Š‹‹eåÊ•CóBBBŒùæËè)¿DÅÉ‘†-ÆS‚ûïí§ŽÑŒ^4^Ë›ÐèLQQ‘$$$Árc{z˜hŽäädÃÕ›N<ýÏ4Óþ4ýøñÉÙñƒÔÏÙ#/'ʶ§+eé/K×Ýp|˜fšéÑžƒ¥}™³yÔÉM˸ût¢½$çl¹39Q®¬Ï×·G‹V` i®¬¼$kRÚäad†|¿2YôØ~Ý uŒfôRÇ~ÁRãd2@úÙuc™““#Ïž=3>÷õõØÓStÝÝÝvŸ²³UnÙÅæéú|m{ä`‘ÇÈšOº.«ãžHgd‚\ûh‰Äþjÿu7Ô1šÑKÓEøÿÑÐÐ qqq†1™:uªlݺÕ0æPÓeo({åÖr˜§C„ÃøÙgwe^ôK¹µ|‘-ØÕÕ5b~gg§¼ûî»8r°è×G³TUÕËò5OeMJƒtÏ›-ßìÞN£½h&Ëô‡[#Ummm200`°µµÕˆl%&&âtˆ`Ñ* rÍ¥¥—Ô);Ö”W1³åîgû©c4£ÍD°As­l 4Ú×ׇÓ! 1?/º)³ã~–/²2åU\´Ü8~œã!$ËYhw`XX˜ñ’cexx¸twwãrˆ`Ñ* bÍ;>½-áq]Ò¸~™ô.^$eeÔ1šÑ‹f"XƒE¿>¹îh®­½();îJlâ#ù~Ùbé\±Bª«©c4£Íä` ­"ôº£ùÌù:‰ZÝ"ËÖ_”Þó¤m˹PWG£½h&‚åÒÒÒŒ;[æ`1L9X0x˜_Q)³¿¶“þèhùvÏŽ „,w‘žž>d¦, ï)$‚E«(ð5×]¨“Œ3¥23®WJ¶í“ß š«æÂBêÍèE3,OÇÁºqã†ñÙ±Ò' W¯^-¥¥¥8r°è×`Íe—ÊeÞÁJ _ð“4gn“_çÍ“ë'ORÇhF/šÉÁòô‡Ü|$wóÏ:ÖÔ©Sq:D°h¨æƒ7Š$|Û ‰_þDž¦¯•ž¤$¹|îuŒfô¢™–· VOOñY‡hhhh0>755‘ƒE @Ö^¬•Ì;ˬÔïeÃÆ;òrI¢<_½Zêkj8>Br°¼e°ªªªdëÖ­Æçèèèa9XξìùÖ­[²téRàéëut}æãhYÄÔFw¥2??ßá6-ïiùxo­@o°ôaéðé«¥²àún ‹ë•Û.ʯqqòdÛ6êÍèE3¬Ñ¦áíÛ·2cÆ #r5mÚ4yóæSß[¹r¥‘ǥ݊ýýý’››k.k]ÖPVV&IIIF$M™’’bÌswyOËÇ{{ä`‘Çà ž¾vZBÿô¿NÜ+9åevlŸÔ|pÒHfÿzß>êÍèE39Xþ2–-ó',5êXMÐÏöÞƒèhyOËÇ{{D°hzÊîÊÜ´ç2+²_"“~”egOÈœ½$nÑKiޱφávQuŒfô¢™–?¬k×®ˆ`M™2Å0]‘‘‘RXX8lyƒKM™¹AÓy¶àhyOËÇ{{ä`AOÍUü‚7òå½ßçÎ×ÞHTìY¼ä¥´fn‘¾øx¹zú4Ç BHÖh¬ŽŽã=„¦.BíTC4sæL·Ö÷øñc‰‰‰1Ök mmmÆØ[yyyv#\öÆàr´¼§åã¹==L4Grr²659{ýïé´Ö‘7×çëÓÁ¢WBCmòç+äReeÀêôèQМϦiѸÓz^£×óé17X .4L‘"33sX"ºyÊ477KDD„´´´Ø]®¯¯ÏHö&‚Ey Þ§a¦¬apþÅÚZêÍèE39Xca°ô‡^ÓúÔ «û÷ï&IŸt:¼ƒF½>|èpYKƒe-GIç¹’e¾¼§åã½=r°Ècp—U Uv uŒfô¢™¬qhT»­tÚôô ³ã`•”” Þ»C¥µµÕjyvv¶´··Ÿ_¼x!’““3â);ÚÁÚSv–]lŽ–÷´|¬·GôÏ\=#ó»í¬ò+å+!9Xca°4’¤+Í2%£+4ªeerdÒìu¥Ñ­¸¸8cž¡ùW¦¨™ :6”­q¢¬å0Ù[ÞÓò±Þ,ZžòÈ#Õ¾\b;‰`Ý@/šÑë K¸ÍMQjjª1_û@ããã}â©DÀ4·Gy žpσ=q'K"b_IÁ·ƒÚ`‘Ÿƒ^4£×§†i0 .jvc·ù$  ƒE«È¿©¯¼ÙðtƒÄ”‘Èè×R±»L^ÇÆÚ}Š:F3zÑLËÇÁþa° ÿ²âr…$w.“¹»%~áÏÒ¼-Ï™ý˃9>BˆÁD°hºÊâ¦b™û"Yæ®ü^V§=“gkÖÉÏ Z<”:F3zÑŒÞq2XúÄ ixK:û! ‹<†±áþ{û%¢eµDÅ÷ÊÇ™wäçÁóâùÚµR_UE“Ÿƒ^4£×— –Žânn¨Ìiots@‹VÑØ±îBlÿn»D]Ú#ѯå\ö銒‡»wSÇD7Ћfôú¢ÁR#UWW‡£! úêà¡õU²òù*‰=\&sç¾’{™É똹ýÅ!ôUƒE”Š­"ßeic©,ìL–¸-_Éò%ò|ùJy™˜(WÊʨcôRÇhF¯/,šAGä`ѯï[üâöý,Ub’~”=é·¤oÞ|iÏÌté}‚Ô1šÑ‹fôŽ“Ájjj’èèhã5.€­"ßàÞo÷JÄ—›%2ö•”gœ’ßEEÉý}û¨côRÇÔ1zýÅ`ÙzÍ O’ƒÇgðÐÌöL‰.?4Øðy%_¯Ú)¿Î›'7Nœàø@¡¿%¹Û"ùYD°háà¡—*$¥3Uææ^’eñ?È‹%Ëä§ÔT¹TYI£ÍÔ1zhƒEƒ«<ÙtRæ¾H’¹«žÈ®Äòkì\y²u«\¨«£ŽÑ‹fê½,@‹V «ëˆîæ9XÓ§OÇéÁ¢Uä!ë.ÖÉæ¶Í]ù™¬ˆ|,/cÉÓÁú½XSC˽hF/šƒa¬·oßÊŒ3ŒÈÕ´iÓäÍ›78r°è×÷€•—*%µ3Mææ]”½1åuD´|óñÇän ÍèE3ã`9Æ­[·déÒ¥Fã»ï¾kDÄ,ßmXPP`$Ô+óóóG¬ÃQ¹«Ëûûöˆ`ù+ðÔõS2¯3Yæ¯}$5qŸÊ«Ø8¹yü8-_ô¢½h†–7ò¬V®\i<‰¨‰ñýýý’››k.ÊÊÊ$))ÉÈõR¦¤¤óœ-·„§ëóõ푃åÿ<øåA‰|²R–,h—DZk¤kÙ2¹\QÁ±Â`ÉÁÒ¨“·¡FË| -5êHMÐω‰‰N—[ÂÓõùúöˆ`ùw+0§%G"¯} Q÷¥7r¾´¾ÿ¾Ç¯¼¡ŽÑ‹fê½~f°BCC¥¯¯Ï«ëÚµkÃ"X:J¼š.s¦óœ-·„§ëóõ푃åŸy 5õ5²¦cÄ;)ŸFVùV÷öï'w½hF/šƒ1ëêÕ«2þü¡¡<ÅãÇ%&&F:::¬Ž¯e‚y„ËQ¹½±»ÜYŸ/oOOÍ‘œœlœt&g¯ÿ=Ö:òæú|}z4õ^úê’,ýy…,Ü~K¢r¥/~‘Ô±š ŸÝ^ÞÓòñÞ,×’ÙÓ﯑ir7f‹ÔUÔÑ ¤å‹fô¢½Ác°¦L™"'N”ÈÈH),,V"CÓúYçÙ‚£å=-ï푃å|2ûúš•Ò9k\JÉ—ºÚ:Ž „Âà1Xæhkk“ôôtÉË˳û=5c®lÇ|yOËÇs{z˜hŽääd#ljröúßÓ鎎¯®o,§‹¾+’ÜO7Hï̹R“}"àõº;ýèÑ#ôø´‰è Üi=¯ÑëùtÀ,E__Ÿ‘ìM‹,w¸³e§œY•)?ÎJêÏΑǀfê½hF/,kËZŽ’Îs%'Ê|yOËÇ{{ä`ÙNf_ÿ`½ÜŽ[-"ÖHMI5y h¦Ž©c4£7x Vvv¶´··Ÿ_¼x!’““3â)»îîn«OÙY®×Ñòž–õöÈÁr.™}]ãjyž(×î’ºjò­ „Ñ8XÖÆ¹jhh¸¸8cþŒ3Œü«þþþaËèØP¶Æ‰²fÜì-ïiùXo–ãdömÇ2¤gfœÔ­ýœV šÑK£½ÁÁ-Lš4) ·G–ý‘Ù¿Ÿ)]3çKõž3ä1 ½Ô1uŒ^ ðmƒåë­¢÷wJ}Âzù~vªÔ;O+ÍèE3uŒ^ ð}ƒåËÉì›nfÊÃÈT¹37Kj+jÉ€BˆÁD°¹U~š5_êVä“Ç€fô¢½h& Áò4™}ÿ®,#™ýüŽ´ÑŒ^4£ÍD°9X%³_?.Ë7Êa R}¨‚!„ä`"XžðÀ¥Ïä˘tù*:CjÏÖÐ D3zÑŒ^4Áä`yÂË>’ÂKCâ.¹PWç3-¹èE3zÑL ƒåw,MfÏÿt»ôÌœ+ç7¦ˆfô¢½h&‚ÈÁò4™½x}–ü4+^ÎRJ?„Br°,Ox¬þ˜4.X+æ¤IµJ˽hF/š‰`a°0X~‘ƒu°ò3ùnNŠ\‹Ï—ÁCÉc@3uL£½k°&L˜0D[(((É“'ÌÏÏw¹ÜÛëóõíùC«àÈéž5_ªÖ|B+ÍèE3zÑLk4–5”••IRR’ôôôLII1æ9[îíõùúö|=K“ÙìØ!/gÆIù‡ÇèÛ‡BHÖx,5êHMÐω‰‰N—{{}¾¾=_Ž`•Õ—IUJ¦< K”Ê#å´ŠÐŒ^4£ÍD°ÆË`…„„ÈÀÀÀд~ÖyΖ{{}¾¾=_ÍÁ:~þ˜Ü‹^!Ís×ImYß]´än ÍèE39Xe°¬ÍŸ8q¢ÓåÞ^Ÿ/oOOÍ‘œœlœt&g¯ÿ=îèèpzùã¥GäyØB¹˜ö‘1x¨7¶?ÖÓ®è ”éG¡7À§MDoàNëy^ϧ‰`Áò¹¬Ïs÷ƒ‡žÍ>@?>„Br°|9Kç9[îíõùúö|%«úBµ”®Î–³HÙþSô룽hF/šÉÁòŧ»»»í>eg«Ür½ž®Ï×¶ç‹9Xe5eÒŸ!"Ó¤ª¤’~}4£ÍèE39Xã9–­ñ°tì'{ã@Ù+÷öú|m{¾Á*.9&­s’åòâ,©«ª¥U„fô¢½h&‚ˆ˜4iR@oÏ—r°Š ¤{Ö<)[·—>{!„ä`ÀÂX¬Ò‡Ã_Ê|rË.cðÐ’½ŸÓ*B3zÑŒ^4Á,g)¡¡6ù}x’œ=vš~}4£ÍèE39XX –ËËçWUTÑ*B3zÑŒ^4ÁÂ`a°¼i°è£‡BH ƒ…Á¢ˆfê˜:F3z1XƒEšÑ‹fô¢™,€Á¢U„fô¢½h&‚0X¶Y~¥ÜîS„ZN?=„Br°0X,ZEèE3uŒ^4£ƒ|Ç`ѯfô¢½h& ƒ…Á¢U„^4£—:¦ŽÑ‹Á¾m° „Br°0X,ZEèE3z©cê½,@y hF/šÑ‹fr°,ZEhF/šÑ‹f"X, „B1X€­@4£ÍèE3,@ýúhF/šÑ‹fr°‹Vz©c4£ÍèÅ`r° „Br°\„ FÐ2yòdƒùùù×éhyOËÇ{{D°h¢½hF/uŒÁrh°ì¡¬¬L’’’¤§§Ç`JJŠ1ÏÝå=-ï푃EšÑ‹fôRÇ, –šu¬&èçÄÄD·—÷´|¼·G‹V šÑ‹fôRÇ,§ Ö”)Sdâĉ)………ÃÊCBBd```hZ?ë<[p´¼§åã½=r° „B –Khkk“ôôtÉË˳áR3æJDÌ|yOËÇs{z˜hŽääd#ljröúßÓ鎎¯®Ï×§ƒM¯N?zô½>m"zwZÏkôz>OöõõÉÞD°ÈÁ"ÍèE3zÑLÖ(,k9J:Ï•œ(óå=-ï푃EšÑ‹fôRÇ,‡ÈÎΖöövãó‹/$##CrrrFÖÛ# B!$Ëe444H\\œa\f̘aä_õ÷÷[Fdž²5N”µ&{Ë{Z>ÖÛ#‚E+ÍèE3zÑLkÌ1iÒ¤€Þ9Xä1 ½hF/šÉÁb°h¡½hF/š‰`a°0Xô¡C!„,@‹V šÑ‹fô¢™*ƒE¿>šÑ‹fô¢™, ‹VzÑŒ^ê˜:F/ ƒ!„’ƒˆ`Ñ*B3zÑŒ^4ÁÂ`a°è×G/š©cô¢½,@‹V šÑ‹fô¢™  B!$ `°h¡—:F3zÑŒ^  ‹<4£ÍèE39X€­"4£ÍèE3,€Á‚BÉÁÂ`a°ˆ`¡ÍèE3uLc°9Xä1 ½hF/šÉÁD°h¡½hF/š‰`a°0XB!Ä`"X´ÑŒ^4£ÍD°9Xô룽hF/šÉÁ~€‚‚™À ,ó¬ñìmÀ` –hhh™3gÊǃ²¾=çÌÚWÁtŽƒÁÒ§C- –š®@‡>´qÿþý ½Oç½ ƒ0XPRRb<Ò !v…æj˜mÖ^}ò())‰ó;€  ߦˆv«ddd|ŽŽ&¸k· š,¥vê$Œ»wï+X O jÞ•yO¿n飿@Ö­Ñ:}ÜY5N:5àÇý Fƒe^Ç3fÌ0ò¯Ì£; í2ÒsZ»333>É]£v:äJ°@ ¦1 •úy<óG1X,  `°0X,€ÁÀ`€Ã_™ ¶Wý€Á?6R, 0X øŽ9±öÞIÓ´¾Ë/!!ÁxßYHHˆ¤¦¦½ Û|¹úúzc9]Æ|=ú^}OšÎŸ8q¢ñBÚºººûròäIã{ï¼óŽL™2Åx!³åûó*++%,,ÌØ—ÈÈH)//±ßúBg}±ñ»ï¾klO×µe˹wï ÆÖdÙš¯¦éùóç2000d‚âããG,§/ÛÕåÌÑÜÜl&5e]]]òöí[Ù±c‡±¼š#s 75kºŒ.kÂÕ«Wyééé†ñRêgËý×}Óé[·nÓ¯_¿6 îƒ>a°žƒ+W®±\ZZš\¾|ÙXBŸbÔòÅ‹SÙ`°`l Ýr:”³ÆÉƒ¥Ðdó 6ùUºœ:FÁ|Ø5_ÚM¨ùW3gΔӧO[]¯ÓnD£Ô´é´årºÞM›6šLC>h—!9X`°0X,€ÁÀ``° ƒ€Á, €¬ßüæ7B!„Ð f°€‡‘+  ƒ€Á¾o°ººº$33S&Ož,'N”¤¤$¹råʨmo„ u[S¦L‘M›6ÉÇG}{Jkèíí5öaÒ¤I2uêT9xð ÃuÇK™ŸŸïr¹­ý³¶Ÿ·nÝ’””cÿÞ}÷]ÉÊÊ’ÎÎN›ës´¼«ëS\»vMâââŒï„‡‡Kyy¹Ýý7i°Uf«.tß–.]:´o[·n•îîn§­£õ»Z7\kã{­yã|qåÚèèè•+WJHHˆAýüìÙ3®5Wök €3Xz“× áõë×200 _ýµ¬Y³fToÂ&è6OŸ>-Ó¦MÕ¿åvÍ¡7ÅíÛ·Ë›7o¤¿¿_vìØ1ì¦f‰²²2ã˜õôôÔ¬Îs¶ÜÙý2!--MšššäíÛ·Fý?~\.\èöò®®ïþýû2cÆ ¹sçŽ1­? »wïvzÿ]YNÐnܸaì—ÖEnn®ñ#àê±µµ-Wë†km|¯5Gëst¾¸zm¨±9|ø°Q®,,,”ùó绽>W÷k _4X¡¡¶éÚºuõb5Ÿ§Ÿõ™9s¦±.½!µ´´¸´¾ÒÒRÉÈÈ6O[<ÚÊÕ–¶z_½z5¬|ß¾}F«\[_'Ožtû¦£ë׌ úÙÞMPo¦ B?'&&:]îÎÍÐÚ>{sy{åëÖ­“ªª*÷ßzó7??=¶¶¶åjÝØÂàïÒà”Hd¤È²e"Î}k͵kÍÕsÇò|qõÚxçwFõZs´\køªÁre¾ô¤ÏËË“çÏŸ»}Ó×›²¶Rô"=vì˜ÝˆˆµõiëZoÞ&8pÀhÙë:µu¨­^ó–Üþýû%==Ý(×Ö°þx릯ëÓî[Ð2Õi~c2_ÞQ¹å~è´þxéÍ-rð[[Íön‚ÅÅÅFëÓ™›©µå])Wh½è1›¾v—˜ÿ;:¶Ž¶åì÷™«Å‹EîÝûÃôƒ˜vÆdq­¹v­¹zîXž/®^jpôúÓ2¥vaêØ:_\½6RSS–y–3]˜Ž®%g÷/د5.‚娅«7[ó EoÐÞ¾ék^ˆy(^[Õöž¶ñf«ÚF2®-XË-ÐyΖ{b°Üm :ZÞ^¹æëŒe^HCCƒ‘cd-ÛÙcëJ^ˆ+uãi‹k͵kÍ™õÙ;_\=þÖ®O¯5Wök €3XzQßüÅл¶Ú4ïÀüÉ™øøx#·@ËõF¬ÝÞºéÛz²éÈ‘#²zõj#d¯Ð°{vvöP¹)/D÷ÇÓ¼?üÐXêÓ<mÍÙë23=£ß±÷¡­rËýP]¦í©^­íF2A?›Wó¥ Éæ7*Ëõ9ZÞQ¹%ôÉ&6ܽ{טÍ'›4¢¡?ø­­­n{GÛröûöàIךkך£õ9:_\½6´.´NÌs°ÌëÇÕõ9Ú?®5üÅ`¹ù¡ÞèôBÐÖ³†p5áÕ<'CCÇz“ÑrmíèMÚÓ›¾‰úä’þˆX ë_s t»úøt]]ݰrÍSÒH£'›å,h+Ú”£]šàz#µ7¾‹½rËík+Rõé|¨.ó<ór=^–ãÕØ[Ÿµå•Û:Gô;Z:6Oee¥Ýãën^ˆ3ërtl퇣ºsÖdi$köì?D®œ}Šk͵kÍÑú/®^jöLcC)õ³½|Gg®MgÇ¥âZÀW À``°0Xƒ€ÁÀ``°0X,  ø¦Á²õ>*g_*êîöôóS¦L1ÞæÌ[æÝÅ­[·†Þ-¦ïQ³÷®0W—³ÇSu:}ªåzuÿu¾iÿ³²²ŒÀºRŸæèíí5޹®Oߦ/³uÓ»Ñô;ún´òòr‡ç;ç–£ºR8õn4[°÷},»¸?øç®ùm˜oãõëׯËl§M›6j&kåÊ•rãÆ 0^ œ››küˆ{ªÝÙå/_¾ìÔyuuµ$&&ŽXoZZš455ÉÛ·o Ç—… º½_jжoß.oÞ¼1ŽÇŽ;†¦çÒýûÆ ¨ïܹcL«¹Û½{·ËÇÁ™åÕUYY™ñ¢äžžƒjüðCã¸i}jŽ“FŠÌ#h–P“¨‘®ÿ×νä CQ]¥ `¬ŽKr z›Ô´NÌ9ä,†Ï€›mÎ)~9‹°u¯ê,Àÿ™Y„­ý°Šûs»ílùýÛ‡`^ÓŒãX:Yé,$}ŽK †¡ŒÉzI˲tul2K0míµ]ë?ó]Q:3­Y„­ÑÑîQÏø<¸³´Â+œ½^këxmO§/×éý£öt¬˜òŠpš¦ò­SK]+÷"ë`ÍóÜ}}¬žÿJÀìYkë8öö@À@À°,, ௖RJ)¥”:_¯€ÀuûÃJà“aðIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_long_increment_line_wide.png000066400000000000000000000653031174000617100264260ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxjŠIDATxÚì{L•év¸OÒ4'MÓ4ýç¤éMs’¦éMÓ4iš¦iÌDƒ3™©f# 7EEn"Â8‚ŠŠ ŽxEt/ãx¿02ÞuTï¢#àp@œAEÖo¯÷œÍoƒûìÍÞÀ~–yÂþ.î¿õ­w½ïo„ ‚ ‚ ÂGñAAABAA AAA AAA$ Ax'~ÿûßËo~ó›nþñÿqäýB²ûú”¡ò^ì‘à÷À@~¾ÚÚÚäÓO?•ÿýßÿ•¿ú«¿’?ÿó?7èëÿþïÿ–èèhùüóÏù† AC5®^½úÎúÊõë×GÔM(  ß'ïþðÇç}äÈù›¿ù‡Ÿë`ýlò3O$ Ax9’““þ瘘H _{€|Ÿò{Àן÷zûÛ¿ý[Ùºu«´··›ã&‘ÒêÈþçò3O$ A Åøõ×_åw¿û]÷¬ý×Ýã?wþCæë'FþÏè@øòó~öì™beÛÿ—ù—òðáCþ½ABÃ-N:Õã?ÖéÓ§÷Øþꫯ\þGÜ—¡ÕÕÕ2uêTù‡øùíokÆjÿýßÿ½ÙwóæÍ>ÿ‡¿xñbs3¤ï¡O7õs×hhh0ïe þ¯ÿú¯²sçÎ~ßDÔ××˼yóä¿þë¿ä/þâ/Ì{éXXX˜\ºtÉ+7$Þr±zõjóú÷uœ~AAÿ›››Ûã¼åË—{|Cåêïzò¹zâÿÕ«Wæ ¾ž¯^íCoRõØ?ÿó?w¿¯þ…‡‡;^4?Þü\\9È¿ÑþþðÆ÷[}ÚŸ§U W?_999=ögggèw^¾qI An"22²û?QýXoäô£mŸ6szòò¦M›äÏþìÏ\ž»~ýz·76zƒçèïj£©Þ<8:¶{÷î>ß8ë¸r}¢Ú×›ŒÜ€xËEBB‚ÿ«ïo‹ÅáyŽþþ`% }ý\=õÒýZÛB>4apõ¾zc닟?o}.îœ䦹¿¿<ý~O˜0¡ß?›Ú\n¿¿²²²ß¿ïúû= !‚ ¼æ  í?ÑqãÆ™ýAAAÝûô¸ž×Ÿ›P[èÓDûsôɶ£hnn~çfÂÝ“GíFoŠôÂÙ1½á³ßÿïÿþï}úœµ*a³¥7Â:®\¿nš¢Ÿ›Þ0y’€xÓÅèѣ͘÷7:ýz{•×cz=å?þã?|–€ôåsõ†ÿú§’Û·o÷8çÆï|.æ}§M›Öã˜&@ƒùóçÍÏ¥/Nûó3êÍßùÙ´ý[P´²äìó¶ÿýÙèOxó{@ AŒÞ7S¶¡:Â~ÿ_|1 ¤÷ø³gÏv;þ|cz®«÷ׯR m2í}ìÊ•+æ˜ÞØï×–¾|Î:ôÂ~¿!ñä&|°]ؾÞÞ.ì¿^½‰´?f.¤Ñ{¸Í`& }ù\½áßÑ!ûªˆòèÑ£îc½?ŸQ£F êÏŸ7?—¾8íÏϨ7 ägÓþß‚¾vöyÛ'©Ž¾wÕ o~‚ !b€ñá‡öøOÕöY?Úï×órnß0Úû‰¥>u´?¦çºzû¿ëꘫ›gŸ³}í¢k x;ñ•‹¾\ÏÑMô`% }ù\½áßÑÓðÞïë w7ïžþüùêsÈϨ7 æÏ¦» ˆ»Ä›ß‚ H@‚@èMž}?‚6BÛ‡ý¸v½©jiié÷Èýyb©çô&×Ócî>Oo$ ¾vÑߧŃ•€øÓï÷íÏ8þÁþýù¹øê÷€·6ÿçþ§ÇþþLÚ0˜ß‚ H@‚èclÙ²¥_ÿ÷n"õ´ÒûI§»§þƒyÌßÁp1T* þôßÛ~Ýþú‡Òçâ«ßÞþÙì= –£†}|‚ !¢¡cœûsã11ÑÞì{Ìcí¤/Çz«±¿ž»w_ÛpñßÛ¹³©q}qÓ?”>_ýpvìƒ>PˆNØ`¿º¾Ö)ûêk°¾A€чÐÿ´{ÿ‡ªk0ØÇ“'O\žÓ{êQGkôžùIg¸±Ív£3߸šRÓ— ˆŽu·ž¡ã¿m³0Ù¾]‹Â“_»8vìXý:ÓV_fòG2Xþ{;ןYMö4ô©»Î¾¥Ó;Z1ÛÛ_£?>wÿF½ñ{` ŸÛ@gÁÒ(--íqL‡Œ:t¨»Š¢ã{ЗßwA€á"t1:ûÿLulµ£è==¬m¡0ŒŒŒ>ÖIwk_蔃}èî˜N»Ù{ˆFÞk(º°_Û¡?ë€ø:ñ†gÑç¾ú}ý¹¸û7êßýÜçÉ“'~¹n €_Üâp‹_ÜÂP÷KBâS¾ýö[þÑã·€_ÜâpÀ~I@H@H@* €_Üâp‹_ÜÆs2ž·€_Ü~q‹_‚ à·øÜâ·@„  !¡ÂÓ À-~q øÅ-~I@z@¿¸Å/à¿€[z@H@H@xšÁÓ Ü⿸ü⿚€466Jff¦ôuCCC÷ñQ£F½ƒ»(..–±cÇŠŠŠ¼~Üß×£è`ÄÄÄÈÎ;åíÛ·†’’‰í‘€ô'JKK%))IÚÚÚ )))fŸ·ŽûûzT@xš¸Å/n¿¸* Ä{ï½÷ξ1cÆ 8Ñ›yý&ØB_'&&zí¸¿¯Gã9·øÅ-à·@ˆ‘mª]]]†íÛ·›}ö ȸqãdôèÑaÎu:ŒKßÇúZ÷y븿¯G„§€[üâð‹[ âA455IHHHw‡¾niiqxn]]dddHaa¡Ó÷sT1ÑäÅ[Çý}½¡”€ì¹±‡ôô€ ¯$--ÍT5ì{@RSSžßÞÞnšµ±¢ß`ö‘œœlJo¶ìW?öve}¥X¬NÜ8á“ëâvMM >i['¿À~‡ã¶þ^À~‡ã¶ |Œ<¿Ã2qô´ßUÀ]⨧B÷y븿¯çï ˆX,Ná)€w9÷Ó9<0¿€[üâèñvèŒWÚ÷aßb? V^^žÔ××w×ÊÊÊ’‚‚§C˜l³Jµ¶¶ºœuj Ç}}½!™€8 ¯räÚSaÒøð>ÇÃc½q øÅ-~5ÑäB‡\éÌWо¶%åååfª^½ñŸ0a‚éÿèèèpÙC¡ki¸ZWÓ㾾ÞpJ@¢ÞDÉäדeê«©2­}šLÿeº$¼HĶDInM–Y-³dvólÉhÊŸ},Ÿ4~"Ù?e˂ȢúE²ä‡%’W›'ËŸ,—O*«­’5×Ⱥëdý ²éî&)º]$[om•íÕÛeÇͲëÛ]²§j|ñͲ¿b¿º~HŽ^;*Ç¿>.'®œ¯.}%§ËOË™ g†Õ/’ìÆl“€dý”Å/ÖAJîŽWÇ@ & ž†ý”½#ñzÃ)i ™! aÉR>[GfÈýèOäöÔlù.n¡Ü˜¹X*Rråjzž\š—/ròålþ29¹j™œ(Ì“cŸåÊá/˾£ dÏ©y²ãb–]'ëoÌ“•·?‘üšy’óÃ'2¯q®I`4‘IkI“”ÖIjK2‰Ž&<šøÄ¼Œ1‰PdG¤„w†KèÛP é ‘`량]ͶîŠ CÜMê4Éÿ9<éÄ-à·ø%!†srâ³Sò妯ä˵'¤ôÓ/¥téq)]xD¾œwH¾ÌØ/'f핲ÄÝrjÆ9»UÎMÙ,£6È刵r5l¥T†äË·Á‹åvðyü±ü01Mž†$JËÄ8ùeâdéž$¿Z&Ê[Kˆ¼ž!íaS¤-|š´D%ȳÉÉÒ8u–4ÄÏ‘ú™Ö¿›’%µ³çKíÜEòdþy²$O¾_¶\j >•ûëVÉíÂÕr³x­|³}½\ݽA.íÛ(çÊÉ/7É—§ŠäÈ…-²ïÊÙ]Y,ŸÝÜb‰Íw7ËÆ{eýƒõ&ÑЄCeß/3‰ˆ&$š˜h‚2ÿ§ùÖdižÌ}Ö¿„É•_Mœ&½d’§ˆ7æüèŽhów§¼šbÞ'öe¬yϸ_âÌûÏøy†¹Ö̶™æºÉÏ“ÍçÚ’j>ŸÙ˜-éÍé2§iŽd6ešDkîÓ¹òÉÓOÌç¯7ëúµ,hX \(9õ9²¸~±,©["¹?äÊÒÚ¥’_›/Ëž,“åß/—WÈÊÇ+¥àQÔÈêšÕÆÕÚkeÝ}kbvƒqXx·P6ݱ&hwŠdËí-R|«X¶ÝÚ&ŸU&Û¿ûc²¶óæN“°í¾±[>¿ñ¹ì­Úk·}•ûä@å9XqÐ$p‡¯6Iܱ«ÇL"Wz¥Ô$se—ËLìdùI9U~JN_<-¯4Éè ëŸ0ëª ŒõÆ-à·ø%!†pòå•/]Þ ëq¯4_Ÿ;/§O—ˉWäÈ‘«²…ìÙS%%%7eëÖ[²eÓm)ZS-›—ß”ÂEUR˜U)…×dsÚÙœtIЦ_­ÓÎʶ)§d{ä ) ;&»'”/,_Èщ%r2t‹\œdM< äFDžÜ‰Ì‘‡‘Ö„%2C~ŠL•戙ò|Ò4k‚cMzBÂå×à‰Òe –Î0y=)R^FM‘_b¦É‹¸Ò–0SZ““åiiÒ”‘!OçΕŸ²³åÇœùa‰5ñÉÏ—ÇŸ~*5«W˃uëä^a¡Ü.*’êmÛäæŽrc÷nùæ‹/¤âàA¹vô¨K¿:”Lo¦õ¦Zo®õ&[o¶õ¦[o¾õ&\oÆõ¦\oε¢7ëzÓ®7ïZyÑ›y½©×›{½É×›}½é×›M4Ф`óͦ‚Sx¯ÐTsÖß_o*;k®•ÕW˪šU&ÉÐdC“M>4 ÑdD“MNrëreqÝb“”åü˜# Êü†ù¦Š”Õ˜%óžÎ3ÉŽ&=šüh¤É&Eši’¤É’&M‰ÏM¥É”&Uñ?Ç›$K“-Mº4ùÒ$L“1MÊ49Ó$M“5MÚÂÞ†I诡b©Ì“øÌV‰ˆ™9«Cò¯\0××ÏU¿.u ¾ôgùÜy&`‚ žrâp‹_‚Y°1±Ù¼ù®¬_ÿ@V­z$Ë–}/K–ü`uý£Ì›×(™Ï$3µQ>žù£|<í™;ù±|þP²BîÉ‚àÛ’ò¬ ¿"EQg¥dÊ ù"æ°Ý+_MÛ!çãŠäëøuR5½@ª§çËýé‹äq|¶ÔÅeJcÜliŽM–ç13ä—ɱ.¶¤$ùÃìÙòÌšä4X~ÈÍ•ïW¬‡kÖÈ]kbsËšÔ|»k—TîÛg’™Ë'NÈ…3gøÅü'Öï¾*Ñ3ÚåÖ­?*}ð@ÿ툖}kªYš(i4ãÅ 3¾'K²tŽïY¸ðGÉÉ©—Å‹ë­_Cäæþ K—ÖJ~~­õëz"Ë—/+V<–•+KAÁ#+5²zu¬YóPÖ®} ëÖÝ— îËÆ÷¤°ð®lÚtGŠŠîÈ–-·¥¸ø–lÛvK>û¬Z¶oÿNvì¸);wÞ”]»¾•Ý»oÈçŸß½{«ä‹/¾‘}û*åÀJ9x°Bº.‡_“£G¯É±cWåøñ¯¥´ôŠù^”•]–¯¾º$'O–Ë©Så•Ö 7o½í¡U“™)¿¯g.ž1U%­i5H‡Ûéð:NÿK¼©®„ý&±í±¦Z£•­iÅH«KZ‰Ò¡_$ $ üÞÅ/à–   ã9‡åMœ&9z3­7Õzs­7Ùz³­7Ýzó­7áz3®7åzs®‰¹YÿüºÙQ.Ç‹NKÙú/å̪CraÙ^¹¼x»\_°En|²^nÍY)÷g-•lj ¤~úÇòtjª´FÏ_&M‘7ä+x¢¼”Ó¤):IêcæÈã¸l¹;}‰|;óS¹š´A.¦n•“i»åhú!ù"£LJæ^¢y×dmöw²|þCÉYP/óç7HvöO’•ÕhMÀžÊܹOåãŸIff“Ì™Ó$ééÍ2{ö$-­ERS[$%¥U’“ŸKbâs™9³M^XÞ–øøŸ%.î™6­]bc_JLÌK™2å•LžüZ¢£;$2²C""ÞHxx§LšôVÂf4»¬ÞYb[]ÖL´ü*á–×2ÅòBâ-Í’diÙ–'2×ò@XnI®¥J–[¬ §¥\6ZÎÈK™ì°•Ï-ûå e··|&'-›å¼e\±¬” K¾Ü´,’»–,©±dÊ–YÒh™éòg÷fì2©HZ+W>.–KKwIù†ýriÏS¥;Ž¡nüÞÅ/n‚„§Œ£ïÅëM⥯¾’«ÇŽIå¦w¥ú³ÏäΦM¦·åñÊ•R»t©ü¸p¡<7OšÓÓåyr²ü/¯¦L‘Îðpéš8QÞ††JGt´´O›&m3gJKZš<ËÌ”ŸæÏ—º%KäûåËM¿Ì½åVq±ÜܹÓôÈ\;|X®XoV/ž>=ìžÐëP-²¥C·6Þ]+reéÃLYX3S²M‘Ìš‰²èV¸¬¾:U¶ž›)ûKgKÙ¾¹R¾c¾T-‘;k–Z½,“¬~ë-’««ÆO>1ÞšgÏ–ÖÔTiKL”Ÿ­¿Ô«ú~%o'M2낃÷7òzòdy+¿LŸnü·¦¤üÿþ%ë{ê÷ÁaÿÒúõf˜_wÿRI‰Üس§»éê‘#.ýžš·WΧ~&—ã6HUôr¹6_ê'¦Ê Ë3©D[H¬ü>Kj¦dÉí„<ù6}µ|“³I*Wo—ovì‘ë‡É¥2†¼ñ{¿¸* DÀ' 08è0¤””WÚ%Ó§¿–ââÛ#æk+·&WJKÍ eÕÞ½¦ÿö–-réYµJž,[&õ‹›Fþ&ë v‹õæúEB‚¹i”_CBÌMµÞL¿š:ÕÜtëMtóœ9ÒhM|ê­7ϵÖçGÖ„è¾51ºc½aþnûv¹ñùç.oµgFo¤õ†Z“+ý¼ôF[o¸uâM²ôF\oÈõÆ\oÐõF]?Ox@oàõF^'$xa½±×|ýœõ†_?WMÄštY?M ôkÑDAó5$Ï”§é3凹3äáÂéR'×VÇÈùÂ()Ý&ûö˾ýá²ÿ`Œ<” G§Ké¡,9y(OÎ\'W|&û¾0^5IÔd­üäI¹pöì‚uúôE9vøk9´µ\­<#‡²K娬òÕôr>ºP®‡­ÛÁÖ¤(8YÚƒ­IUp¨´…ÅÊOѳäû¸yò`V®ÜÉZ)·Wl°þ›ïÝuk²zÉúµó»€„ øõN5ÆzS}¹¬Ì$ Úp¯÷Ú€¯Oè®]+W¬0 ú Z±&Ú¸¯ ü®n_ÆÄÈ/qq&ÙÑÊVf4©Ñ†ÿŸ²²äG뿹:kbT›—gÿY“¥Öki¥F“œ[[·ÊwÖ¤å[ë °&Vû÷›ªÍ×Ç›ÏU/O†»pÎÌv¦3™é”ÐC±i~0«wee—̰Â]ÛoHɪk²sa¹ì™}RöO?,G£w›>¨¯ƒ­IgH–éuz!š¬„O“§SgI]â'ò8s±Ô,Yn¾o·­ß/MJ¯9"å§Nñ{ð‹[ü’€ô€~i’î/C¥iÞ¶Ò¼~ôídLO”NT l\}[ }+›Ó¿–­ÓÏÊΨcr t¯œ Þ,ß„åËãI˦˛‰“LŸÓ‹¨8iŠO•†Ys¥n~Ž|¿l™©¢ir«IåUkÂëÉ@¯}?Ñ3Ãï]Ü= À/ È0A M44áÐÄcù“å&™Õ2ˬ©¢‹]j¢¢ ‹®Ç¢k·è:/ºp¤&6šàh¢ãò?¢g L’ݘ=$è°/°AgWÓYØt¶¶å‹jdEúY5½R6D•ËÖ‰'ä`ȹ¾^ª#—H]dºYèíÄPy.?O‰“?ÌL•g™›aZÓa„Ú¥Ãø¾>vL.zq lÖXá÷.n A@ƒÿˆÅ¾i^‡péP.Ò•Üš,S_M5C½tÈ—ýÒ!`:L¥4«ÚßÙ"¡]¡f¥yýèë*ˆW=üiØWIÉwfêè+¾7SQgÏ®“…ñeiäM)¾,;'“²èír}Ê*¹?e4NN•ŸÃ§Ê¯Cäͤù%6Îôép>íoÒ>"º§½I:„ðëÒR·½:$Ï@AÂÓ üâ6`ÑâO\9aVŒ×•ãuy]I^W”y#k¬4ò­&Zÿh¢•]‘^«+ºB½®T¯+ÖëÊõº‚½®d¯+ÚkFW¸ŸþËt³â½®|?³m¦$µ%™Þ–”Ö3|,­%ÍThÒ›ÓM”Ù”i®?÷é\ùäé'2¯qždý”%óš/ ÈÂJN}Ž,®_,Kê–Hî¹²´v©ä׿›ahË¿_n*=+¯4ÉTAM¬®Y-k®‘µÖʺûëdÃý ²ñÞFS Útg“I¸Šª‹eÃ×{dÕÉc’·ÿŒ,ÜzUæ®þNÒ?’„ŒIœÞ éáßKNÈwRuFöMÝ+gâ ¥júR©‰ÿXžM)í‘ÑÖde¢tDFÈÏñÓ¤yV’4deʓ܅ò`Õr¹µy= ¿p T@¼’™™)AAA}ÝÐÐÐãœââb;v¬¡¨¨Èí{º;ßÓãþ¾= ŒçÜ5´Ú¡UŸ¬4ô£n¬8(§ËOËÉò“òÕ¥¯¤ìr™I`J¯”šÆúcW™¡]‡¯6ÃÃôüýûe_å>“äì­Úkšïwߨm†í¼¹Ó !ÛþÝvS¥Ùvk›I„¶ÜÞb’‚Íw6›˜Â{…f˜ÙúûëM%gíõ&YZU³Ê$šlhҡɇ&!šŒhR¢É‰&T‹ë›êNÎ9f(Úü†ùf¸ZVc–Ì{:Ï$;šôhò£I&Cšir¤I’&Kš4%>O”„¦T‰4_b¿Y)“Oo‘¨ýû%¢ø”„­¸.¡óHHÂS™2©YÒ"È¢égeí¬ÝR’±ZŽÎ/3S\& ÕK"åúª)ß^ZZ*IIIÒÖÖfHII1ûœ…»ó==îïëQáiàvH–àŸ-u]ëzünZõfÕíNþ\% ãOÉ΄}r$±HÎ$®ë3³åöŒYò$.^š'GÉëÐy,˜&ß§„Iuö$¹¶,\.FKÙŽX9²/AöO“ÏÏdÉÎKKeGåZÙ~s«Iú4!ÔdñÌ…3ünÜâwd% ï½÷Þ;ûÆŒÓýZoÎUª-ôubb¢Ó÷sw¾§Çý}=z@`¨ñå•/Mã¹³?zOƒ3ž=U²cÇwRTt[6l¸/«V=’üü'²hQ½deý$M’žÒ$ó¦?‘œ)wdYø7²fâÙ\*‡ÂvÉ™ðuR™+÷"2åLj™Ò-oƒ'J{X¸4N™"fL“Ê9qr6gº/˜)û‹’¤doŠŸ˜%›¯Ì‘ßZÏ;ËL•I§ˆÖê”V®´ª¥/²7œ\ï¹±‡Ÿ9ÜB $ ÙÙÙ¦êÑÕÕeؾ}»Ùg –¥ûm¡¯uŸ³pw¾§Çý}=* <ÍÜâ7°’;W( 4¹;{ö‚”•]–#G®Ê¾}•²{÷·²m[µlÚtWÖ®¹/ë—Ý–ÂùßHñœKR’|ZöN?"G¦î–¯¢Š¤û¬Z^Hhh—ÄŽ”ââÛCâó:}ºÜ¬¿räÀ×rtûE9¾þ¤œXvLN.Ø'ç2wÊå”Ír}zÜœºDDÍ•úIÉÖDeªtZBÍ‚‘šÀ<´|,U!‹äBø§r|ÊÙ=c‹¦m“eYÛe~ÞnI_÷…$nß/ñûJâÑ}’^¶W²Î|.K.ì–U—÷Èæk{dWÅÞã&Ù?Õ;üÐâ×HKK3ûÔÔT* Nö‘œœl~ðlÙ¯~ôÅvMMO¯hÛø¼müøŽÛú{a¤|=å'OÊsçäÇóåÞîƒòíªb¹¿¢Xjs7É÷sòåûó¤1n¶´Nž!¯B#ÍаŸÃ&ËO3å~d¦TD.–Ókåà¤Ù6ñ˜¬9/‹£¯HÆô ™žvC"³oJxÞ·2yu¥Ä^‘é[ÎËì=dá‘˲øØYYz¸L6u}“ÌÏŸgÛî|yoÛ†?®?,GOûí÷9ê‘Ð}ýéɰ?ßÓãþ¾= ˆèz)WNœŠƒÖde×.¹]\,Ö¯7 AÖ/Z$s?‘æ”Ùò-W3+Ô·c‡ÜÝ´IjV¯–Ú¼|Í$ ÑÑ&!ÑĤìì9ÙV½Mæÿ4_¢^GÊÒ[±ra[ªÌ•‹ûVKÝâEÒ7ä‡kQ!èüâ¿xÀ-~aº=x°B/®“ÈÈ7’šÚ*›7ß‘3g.v×¾‘½U{%¯6Ï$"QQ&1Ùw¹Pî®7IÈP®EAð‹[üâ·ø…!ìöÌ™ R\|[ÒÒþ o$'çGÙ·¯òóŽ\="«kVKJkŠª¥C¶ ïn”+‡vÊã•+‡Ìp-* = ÄãÇ¿–+¾—˜˜W2}úϲvíCùê«KïœWv©L6ßÝ,™Ï2M2’ô<É4µ»´ßTB´"2†k‘€XcÔ¨Qï0nÜ8—ÇÝEqq±Œ;ÖPTTäõãþ¾žnñ‹[À/n½‹6¨ïÜySæÎ}j×õ£nÛ×{TP.ž‘ßí?.è×Ñfš_îW§ý½rü˜I>|9\‹ ˆ‡qùòå7á}I8죴´T’’’¤­­Í’’böy븿¯Gãe·øÅ-à·ƒ‹V@Ö®}`½ÇúÙTF´B¢•‡‰ËùsòÅ7_Hþ“|™þËt‰z%Ù?e›O_8e†e öp-z@<ŒiÖ,±¥¥eÀ ˆÞÌkh }˜˜èµãþ¾žnñ‹[À/n}‡ö†hˆöŠhÏÈ–-·M‰³ó]=&k®‘Ô–T™ôv’Ìiž#îm//i* ƒ1\‹ ˆqíÚ5)((xgˆ–É=z´õ!%%%.ß#((Hºººº·õµîóÖq_4®_4³féìY:‹–Φ¥³j¹¬¤\úJ6ßÙ,sŸÍ•ðÎpIlK”•VÊ¡ë‡ÌqM:|=\‹¤Wètmm­Óãuuu’‘‘!……….{Jz‡&/Þ:îÏëé7؆}$''›Ò›-ûվخ©©ñéõm¿ƒ·ÝØØˆüËmý½€üÇm#åë9zôª¬^Ý(±±o­÷aíf‘ë׫]þýª›Ur²ñ¤ä5åÉäד%îuœ¬k['G•sÎÉ·7nHÃ¥KÒ°aƒ¦õkx¸¼ÊÌ”†õëÍp-=nÿ~b±8Å—>†u¢_Dvv¶ÛóÚÛÛM³6z@/ ¸Å/n¿¸õw㺮°ž™ùÌ4®ëÊëº{Ÿ†vUî“eß/“?ψ7’Õ˜%[om•Óå¬|¸®e’ Gñ§„ HBûîÞ½ëq⨧B÷y븿¯Gãe·øÅ-à·C²²Ë²zuÄÅý"±±/eåÊGRZz¥oS}\Ö>X+³Zf™¾‘ÙͳeýýõRz¥´ûœÞõH@<Œêêj§×yyyR__o^755Y3ˬ}"½‡0Ùf•jmmu9ëÔ@ûúzô€ /öî­’ùóLU$=½Y¶m»%gÏ^èÓß=Y~RŠnÉ'O?‘ˆÎ™Ù6S>}ü©¬8øÿÏ;wŽÄÓЛ ‡ÇÊËË%&&ÆÜøO˜0Áôttt¸ì¡Ði|]­«áÉq__ O‹·øÜâ·Ã“Ó§Ë­÷®÷$)é¹DEuÈÒ¥?ÈáÃ×ûü÷Ï^8+;¿Ý)‹êÉ”WSdê«©²¸n±ìúv ˆ?c̘1#úzô€0^p‹_À-~q;ü9|øšI@¢£;LB¢‰‰&(ýyýûeÅ÷+$áE ˜ OŠð‹[À/nñ ¸í:kÛ¶j™3§Ù ÑÒ¡Z:d«¿ïãn,bD& 0p¾üòŠiVצum^_µªFNœ¸Ü§¿{äÚ í •Ÿ¬4ô£në~‚ à·øÜâ·xp‰N߫ӸjU$#ã™™ÞW§ùuv~Nsެ·þ±µ¿®•ìÆl‚À/nñ ¸Å/nñÐ7Nž,7 ΜùB&O~-ùùOäÈ‘«=+'W¾‹‹?zœ„ øÅ-~·øÅ-ô‹ƒ+dñâ:‰Œ|#©©­²yó9sæb÷ñ]»îIZÚ ï’ÄÄ7²mÛ]ŸŽ$ $ 0Â8sæ‚ß¶&ˆˆ7’“ó£lØðX¦Oï’[·þx?øàH|ü¯æ<‚ à·øÜâ·xð Ç-+V|ß#ù°…&!Ó§¿&!èüâ¿€[üâÞ%2òW‡÷‰¡¡]$ À/nñ ¸Å/nñà]RR^½S¹¿Kâã_‘€ô€€wùì³j™6­Sª«»ÌýàÝ»o%6ö = À/nñ ¸Å/àvð’ÄÄ_̰«¸¸—>O>H@H@ÏÉxYÀ-~q øÅ-~I@ÜŨQ£Þaܸq=Î)..–±cÇŠŠŠÜ¾§»ó==îïëQái࿸üↂßQ¹|ùr›ðÒÒRIJJ’¶¶6CJJŠÙç,Üïéq_*ŒˆdÚ´iÒÒÒÒ½­7çšÕÙB_'&&:ýûîÎ÷ô¸¿¯G„§€[üâð‹[ ⥸víšôØ$]]]ÝÛúZ÷9 wç{zÜß×£„ñœ€[üâð‹[ ÄK¡7ÒµµµïôˆôŽÑ£G»ì)qu¾§Çýy=ýÛ°äädóƒgË~õ£/¶kjj|z½@ÛÆïàm766â¿Ãr[/à¿ÃqÛ>Fžßa€è‘Ýï z@€ H¿CûîÞ½Û§ Ýןž ûó==îïëÑÂxNÀ-~q øÅ-ÐâaTWW;m¼¶ÍÕÚÚêp–¨ÞC˜Üïéq__Æsnñ ¸Å/n/‡ÞtWTT8=®Óò:['ÃQ…«ó==îëëQáià¿€[ü⨀ ¡3f̈¾= @AÂÓ üâð‹[ün©€€€0ž“ñœ€[üâð‹[ü’€T@¿¸Å/࿸* ÜÊ“€€T@¿¸Å/࿸*  ã9ñ‹[À/nñ ¸Å¯O]£/¼÷Þ{d T@¿¸Å/à¿€[* ž% šXØã,=z4™= @ˆ÷†`•••IRR’´¶¶vïkii1ûÎ;G¦@ð‹[ünñ ¸¥â½äÃ?”ÎÎÎwöë¾>úˆLÀ/nñ ¸Å/à–ï% :ÔÊYBÀ/nñ ¸Å/à– ˆWqãÆIbb¢vÕÕÕehnn–„„ùàƒÈèz@¼Û⬠ýìÙ³}~ŸÇKZZš‰Åb1ïëjÖ-wQ\\,cÇŽ5yý¸¿¯G„§€[üâð‹[È ˆ†~Áš4Œ3Æ ¯oݺÕç¿_[[+¡¡¡ríÚ5SAцö5kÖôH@ú¥¥¥¦ ¾­­Í’’böy븿¯Gã9·øÅ-à·°= Þˆ¼¼¼G}&ý ½™×¤È>AÒabÞ:îïëQái࿸üâºâ>’#GŽÈøñãME¿ˆ/^ôH@ô]W$""BJJJ\¾ŸãÒJŠ-ôµîóÖq_ØôôtsÃ<ЕÐõÜåË—›™³:::dÅŠ²hÑ"‡çÖÕÕIFF†ö«bb¿(¢§Çý}=* <ÍÜâ·€_ÜBÀV@4°%] ]“M<ì§ðÕJˆ³hoo7ÍÚXÑo° ûHNN6cÿl?|úÑÛ>½^ mãwð¶Ÿ?ŽüËmý½€üÇíÞñ3rüú<ÑD ²²Ò¼¶UÅïë: Ú€®Ã®4 Qt8Vnnn&õúúz󺩩I²²²¤  Àé&Û¬R:›–«Y§zÜ×ף豻כf 6U^^n^WTTôk%tm,ׄEß#''§Gº¾gLLŒ¹Ö„ Lÿ‡}ÅÄQ…®¥áj] OŽûúzT@xš¸Å/࿸* ŠS§NI~~¾yÕ£DgµòE¸ê ×cÀ¿¸Å/࿸…¡îׯÓð¾}ûÖT(´òñÑG™^bd' <ÍÀ/n¿¸Å/à– È°[„¾ ÐBBÂÓ žfnñ‹[À/nñ;r]ÅüÃ?ìÑt"OŸ>%S ð‹[ünñ ¸¥Ä»MèŽV>¯ªªr»–Að‹[ünñ‹[ үЦóM›6™u?ì],ðý÷ß'S èñ^bŸtô^÷£?ë€T@¿¸Å/࿸* ncôèÑòúõëw]Õ;((ˆLÀ/nñ ¸Å/à–ï% Úl>mÚ4iii1 ˆ®òðáC“˜èêåÀ/nñ ¸Å/à– ˆ×ÚÚÚ«ŸÛÓÖÖF¦@ÐâÝix5 ÑJȘ1c LÁKð‹[üâ·øÜR´„ ð‹[À/nñ ¸¥Äç³`T@¿¸üâ¿€[* ƒš€è+oÄãÇ%--ÍÌœe±X¤¬¬¬Çñââb;v¬¡¨¨Èíû¹;ßÓãþ¾= = š,袃žö„††Êµk×Ì‚†:…ïš5kº—––šUÕµ©]III1ûœ…»ó==îïëQái࿸üâ¶rõêU‰õhÆ«¼¼¼w*ö¡7ç*Õú:11qÀç{zÜß×£„ñœ€[üâð‹[ØgSð*}í7nœ9rDÆo†téñâÅ‹îã:,K+#¶Ð×®9tw¾§Çý}=* <ÍÜâ·€_ÜBÀV@4Ép†.FØ×$fùòåÒÙÙ)²bÅ Y´hQã½ÃÕ{»;ßÓãþ¼ž~ƒmØGrr²É|m?|ú‘m¶Ùf›m¶Ùf›m¶{{XNëOû5ñ°…&"öÍíT@¨€ð4p‹_À-~q T@¼ÚtÝ;±¿wÔ#¡ûúÓ“a¾§Çý}=z@Ï ¸Å/n¿¸…€íÑdA{7<éÑtv¥Iˆ¢Ã±rssß™%JgÇr4KTï!LîÎ÷ô¸¯¯G„§€[ünñ‹[ ò§ é‘p ¤D£¤¤D>øà3ô*''§Gº†®ál G=®Î÷ô¸¯¯Ç: 0TñKú¹sçü:„Ë[‹!ÕëQáià¿€[ü⨀ôav(bä' ŒçÄ/n¿¸Å/à–Ÿ¯„îÉ"„À/nñ ¸Å/n HŸ£¢¢B¢¢¢L5x Ð2è ˆ«ÕÏ2 Að‹[ünñ‹[ 2 ÕÏ: Aà·øÜâ·@AÂÓ žáð‹[ünñKBBHHïáX9FPüâ¿€[ü⨀x-Ñ•ÌI@èüâ¿€[ünéñJÒ—Y°‚‚‚Ȩ€~q‹_À-~·T@üðCY´h‘466z|3íhøVŽ;ŠââbS…QŠŠŠ¼~Üß×£„ñœ€[üâð‹[¨øøxÓã¡É€VA¢££¥ªªJ^¿~= ē㽣´´T’’’¤­­Í’’böy븿¯G„§€[üâð‹[ØY°šššdëÖ­2a„îê„Åb1Oô›››ý’€èͼ~l¡¯½vÜß×£¶Ä>´úQ]]-QQQ¦*¢‰Ãûï¿ïöfZÏ7nœù;RRRÒ¯ã½C+3]]]ÝÛúÚ~F.OûûzT@xš¸Å/n¿¸…€­€¸ íÉÏÏ—ñãÇ÷ùïÔÕÕIFF†è¸³Š‰}³¼§Çýy=ýÛ°ääd3öÏöç}±­ßc_^/жñ;xÛÏŸ?Ç~‡å¶þ^À~‡ãvïø9~‡T2Ðhoo7ÍØ=N„§<ÍÜâ·€_ÜâwU@ú²¡m}$ Žz*tŸ·Žûûzô€@@õ€ô^tÐYÒ×5Bòòò¤¾¾¾»©=++K ú|¼÷&Û¬R­­­.gèq__ O3·øÜâ·@ÈŸ¢¬¬¬ûæÙ---fß¹sçúôåååcnìu6-íïèèèèóqG=º–†«u5<9îëë±Hà‚_Üâp‹_ÜÂP÷ëóD$ììì|g¿îûè£|Ò32fÌŸö¨øúzT@xš¸Å/࿸* vÕg È@{@ˆá“€= >M@t}]çC‡]éìMŠ.@˜ |ð™À/nñ ¸Å/à– ˆw{@œ5¡Ÿ={–La„' ŒçÄ/n¿¸Å/à–Ÿ¯¢—Åb1½о¾uëYÀ/nñ ¸Å/à– ÈÐ_ˆ è!H@xš_Ü~q‹_À-~ý›€èlWãÇ÷êJè= €_Üâp‹_Ü= #$$¤GÂaO_WB'¨€~q‹_À-~q T@úšhôuÅs‚ Ä£ ÊA„xøÅ-à·øÜRñY¢Sî¶µµ‘ÐøÅ-à·øÜÒ2ø HEE…DEEIkk+YÀ/n¿¸Å/à– Èà& ÎVAïÏ,XŽþnï(..–±cÇŠŠŠÜ¾§»ó==îïëÑÙÒ{æ«Ì‚å(á°ÒÒRIJJ2C½”””³o ç{zÜß×£ÂÓ À-~q øÅ-lÄá.Ñ›s•j }˜˜8àó==îïëÑÂxNÀ-~q øÅ-lˆ·qãÆ™ŠIDD„”””ô8$]]]ÝÛúZ÷9 wç{zÜß×£ÂÓ À-~q øÅ-t¤ººZ‚ƒƒM¡èkÝ7¨««“ŒŒ ),,tY!q5¼ËÝùž÷çõôlÃ>’““MækûáÓl³Í6Ûl³Í6Ûl³=ØÛ>O@*++6¡4 ioo7ÍØT@¨€ð4¿¸Å/࿸* =B«éééÒÒÒÒ½O_§¦¦š5B¼‘€8ê‘Ð}ýéɰ?ßÓãþ¾= ŒçÜâ·€_ÜBÀö€èP¡ÎÎÎwö¿}ûVƌӧ÷ÈËË“úúz󺩩I²²²¤  àY¢t­G³DõÂäî|OûúzT@xš¸Å/࿸* v HGGÇ;û5)ékR^^.111æÆ~„ ¦ÿ£÷{êÚÎÖÉpÔCáê|Oûúz¬CŸ' !!!fÊØææfÓ» èëøøx3<ËÑ×Dg¸^ O3·øÜâ·@Än,gMè÷ïßbd' ŒçÄ/n¿¸Å/à–ŸO뉆V;´2 èk’* €_Üâp‹_À-!¹!1| „„„§<ÍÜâ·€_Üâwd& /^”ÜÜÜwöçççËåË—Éèüâ¿€[ünéñ^òá‡Ê‹/ÞÙ¯ûÆO¦@ð‹[ünñ ¸¥â½ÄÑš¶xï½÷Èèz@¼—€èÂy---ïì×µ@Þÿ}2* €_Üâp‹_À-ï% zã«•Žºººî…kkkMeD($èüâ¿€[ünéñZ¢½Î"loo'S øÅ-~·øÜRñî4¼:Ü*$$¤{!ÂÐÐPimm%K èažfð4p‹_Ü~q‹_)))ï̬åhx—»(..6 òJQQ‘×ûûzô€0žp‹_Ü~q Ù¢qäȳˆý´»:$ëéÓ§ýzŸÓ§O›ÆuG H¢´´T’’’¤­­Í IîóÖq_ O3·øÅ-à·°S§NuW%쪪*sSÝ×xùò¥„‡‡KCCƒÇ ˆ^W¿ ¶Ð×ö3ryzÜß×£¶d„ ²iÓ&3ý®}¢3`õg 6È&º=nÜ8=z´DDDHII‰Ë÷ 2Ÿ-ôµîóÖq_ O3·øÅ-à·°û¤£÷Êç}] ýÑ£G’Ð§Š‡®7’‘‘!………NÏqô÷5yñÖq_Æsnñ‹[À/n!`{@ôFùõë×ï$: ¯»§ø¶Ð䣾¾¾ÏC®´º¢ÍÚXÑo° ûHNN6?x¶ìW?úb»¦¦Æ§× ´müÞvcc#>ð;,·õ÷>ð;·màcäùõy¢ÍæÓ¦M“––“€¼}ûV>|h“˜˜˜>½‡³… š€8ê©°ïGñô¸¿¯GlHmm­ÓBgtHôN>òòòº+$MMM’••%NÏ·Í*¥UW³N ô¸¯¯Gã9·øÜâ·@H¯$Ä~%ôLÁë*)//7ÕݯMïÚÿÑÑÑárÈ–®¥áj] OŽûúzô€0žp‹_À-~q ô€ ¡Ð¤g$_ O3·øÜâ·@„ z@|€èL':äJCÐ?úè#3D)88˜, à·øÜâpKÄ» H||¼<~üؼÎÉÉéÑ„žššJ¦0ÂÆsâ·€_ÜâpKˆO]¯ÂÖ>~üx“xܽ{×,.ØŸ•Ð * €_Üâp‹_Ü~ÍX¥kèvggg¿VB'èz@ú:m¬V<êêêLò1nÜ8³_«"® $¨€~q‹_À-~q T@úzãkß÷‘––föë84]! ð‹[ünñ ¸¥Ä«Óðêâ€:ÜÊb±tï 53dT@¿¸Å/à¿€[* ¬B0|?üP-ZD•ƒ ÿðð‹[À/nñ ¸¥2ø ˆ®ÿ¡Sðj߇Î~-UUUòúõk²z@¿¸Å/p‹_À-= ƒ3«©©I¶nÝjú@lèÚ R\\,ÍÍÍd T@¿¸Å/à¿€[* ƒÓ¢Õêêj‰ŠŠê^D#LLL$c èÜ&tíÉÏÏ7+¤÷5RRRz,nh ­¨èº"JQQ‘Û÷qw¾§Çý}=* <ÍÜâ·€_ܳ`y§OŸ6Õ’Þ Hii©$%%I[[›A“Ýç,Üïéq_Æsnñ‹[À/n!`{@:;;M…Ã~1Bº6H_ãåË—. ï$ zs®Y-ôµ«a]îÎ÷ô¸¿¯G„§€[üâð‹[Ø HHHH„ÃíéklذA8`^÷N@t¶­®®®îm}­ûœ…»ó==îïëÑÛ¢‰Æ¹sç’““MéÍ–ýêG_l×ÔÔøôz¶ßÁÛÖ5|àw8nëï|àw8nÛÀÇÈóëó¤?Ug¡ÉG}}½Ór* ô€0žp‹_À-~q ô€˜Ð5?´qÚ“pÔ?bŸ„8ê‘Ð}ýéɰ?ßÓãþ¾= ŒçÜâ·€_ÜBÀö€TTT˜u?Z[[½6–³Y°ôŽf‰êïùž÷õõèz@ÜT/ú; –»ž ]ÃÙ:ý=ßÓã¾¾žfnñ ¸Å/n ˆ]º3¼ÑÒ—3fŒO×+ñõõèa<'à¿€[üâè!H@xš_Ü~q‹_À-€€TWWKpp°r¥èkÝGPüâ¿€[ün©€x5©¬¬tÚ„NBà·øÜâpKˆW­v¤§§KKKK÷>}ššjÖ!¨€~q‹_À-~·T@¼–€è«ÎÎÎwö¿}ûvHÌE0ÂŽŽŽwökRBBð‹[ünñ ¸¥âÕ$$$D¥¹¹Yººº ú:>>Þ Ï"èüâ¿€[ünéñZ¢æÎšÐïß¿O¦@ð‹[ünñ ¸¥âÝix5ÑÐj‡¹Rô5É= @È $ À/n¿¸Å/à–   ã9Ï ¸Å/n¿¸ÅïðO@´¿ã½÷Þë~í Û9ªJRRRÌð­÷ß_rssM#»ýõzã.Š‹‹eìØ±†¢¢"¯÷÷õ¨€ð4p‹_Ü~q SÑÄB§ßµ½v†íw¡ VTT˜µCt­}ûö™Y´ìþDii©$%%I[[›A“Ýç­ãþ¾= @ˆ—Ã~ ‘þ& z3¯Y -ôµNì­ãþ¾žfnñ‹[À/n/…V@8 ™™™=qãÆ™ŠJDD„”””¸|   ó>öï©û¼uÜß×£„ñœ€[üâð‹[¨ÞñrÌYo‰òÑGI}}½Ãsêêê$##C ]¾Oï°æéq^O¿Á6ì#99ÙüàÙ²_ýè‹íššŸ^/жñ;xÛøÀï°ÜÖß øÀïpܶ‘çwÈ$ /^¼èwb{úÿùçŸKBB‚ÓsÚÛÛM³6z@ @z@\Í~eÃÝM´«pUqp—€8ê©Ð}Þ:îïëÑÂxNÀ-~q øÅ-\ˆm¦+Ût»½ÑA{9úÒÐÐÐ\è4´ö7àyyyÝC²ššš$++ËügC˜l³Jµ¶¶ºœuj Ç}}=z@Ï ¸Å/࿸z@úP©èk”——KLLŒ¹±ÿàƒ$??ßÜŒ;:>aÂÓÿÑÑÑᲇB“WëjxrÜ××£ÂÓ À-~·øÅ-0 Ö²w$^ø[\¼xѬ\Þ;´Šqùòe!FvÂÓ üâð‹[ün©€ø4ùðÃÍŒWŽfÁ?~<™ÂO@ω_Ü~q‹_À-= >M@\­R>ix * €_Üâp‹_ܧ¡MÓ---ïìonn–÷ߟL Ä{ ˆÞøj¥CW(×ô”ÚÚZSILL$S øÅ-~·øÜRñ^¢½Î"Ô5=z@¿¸Å/à¿€[z@¼: ¯· 1ÓÓ*¡¡¡=Öñ ¨€~q‹_À-~q‹* #fz@€„ øÅ-~·øÜRñ~’žž.AAAïô€0 /= €_Üâp‹_À-= ^M@222º“Þ Èèѣɨ€~q‹_À-~·T@¼»Hee¥ym«xèÌXsçΕcÇŽ‘)Ðô€x/±_ Ýþµ®òÁôé=ªªª$%%ÅÌ ¥‹æææš™µì£¸¸Ø$;JQQ‘Û÷tw¾§Çý}=* <ÍÜâ·€_ÜB@V@4éhkk3¯5(//7¯+**úÜ¢=$zþÛ·oMâ²oß>‰ï>^ZZ*IIIæ:Š&+ºÏY¸;ßÓãþ¾= ŒçÜâ·€_ÜBÀö€œ:uJòóóÍ먨¨= ãÇðûj2c ½9׬ÎúÚÕ*ëîÎ÷ô¸¿¯G„§€[üâð‹[èY°l¡Œ &˜ÊÇG}$ý~­€8p@233»÷é [ºßþÝç,Üïéq_Øo†­r¢ÉK}}½ÃÞ[¸šaËÝùž÷÷õ¨€ð4p‹_Ü~q T@¼úôÿóÏ?—„„* Nö‘œœlÆþÙ~øô£/¶}z½@ÛÆïàm?þø–Ûú{øŽÛ½?âgäøõy¢ÿPCBBº‡`iõBŸè{ô¾öG=º¯?=öç{zÜß×£ÂÓ À-~q øÅ-lDg«züø±y““Ó£ =55µOïQPP æu{{»™†ÖþÜ6KTkk«ÃY¢zarw¾§Ç}}=z@€»áCæµÎz¥7çwïÞ•G™5=ú:uoLLŒù»ºvˆÎª¥7ãö¡I‰³u2õP¸:ßÓã¾¾žfnñ ¸Å/n ˆƒ›q6¥Û¶Ù¯úºˆ§a?eïH¼ë€.øÅ-~·øÅ- u¿>O@ô‰½V<êêêLò1nÜ8³_«"zŒÙ O3ð‹[À/nñ ¸¥âÓDo|íû>ÒÒÒÌ~ͦM›F¦0 ÄçÓðÚ´X,ÝûBCCÍ YÀ/nñ ¸Å/à– È]„ ð‹[ünñ‹[ „ ái~q øÅ-~·øõ¢3^Ù¦ßí¯fÁ"¡$ÑUÐí{ìW3'¨€~q‹_À-~q T@éO”––JRR’iŽWRRRÌ>o÷÷õ¨€ð4p‹_Ü~q ]IOO—   ¯õ€h"b?|«¿ ˆÞÌë7Áú:11ÑkÇý}=z@Ï ¸Å/n¿¸…€íÉÈÈèN6z' í¹víÚ;qãÆ™÷‹ˆˆ’’—_“!MbìÝç­ãþ¾žfnñ‹[À/n!`+ Ú³ Ã§l é/^¼¹sçʱcÇúý~?–èèhilltx¼®®Î$=……….gærµ`¢§Çýy=ýÛ°ääd“ùÚ~øô#Ûl³Í6Ûl³Í6Ûlö¶_¦áuôZŸâðÁýz¯›7oJxx¸|ا Ýןž ûó==îïëÑô€x‡‹Å"µµµ.g™Ò©yÍÕ{“»ó==îëëQáià¿€[ü⨀x1œ­¤nº6†³u2õP¸:ßÓã¾¾ë€.øÅ-~·øÅ- u¿#b¬þ†.`8’¯G„§€[ünñ‹[ B€= $ $ <Íài࿸üâ¿$ ĈL@ω_Ü~q‹_À-= $ $ <Íài࿸üâ¿$ = @AÂÓ žfàð‹[À/nñKBÐÂxNüâ¿€[üâè!H@xš_Ü~q‹_À-~I@H@øÇ$ À/nñ ¸Å/nñ@„„„ñœŒçÄ-à·€_Üâ—„ øÅ-~·øÅ-P¼5jT7:Ï>Š‹‹eìØ±†¢¢"¯÷÷õèz@¼ˆôg¿³(--•¤¤$ikk3¤¤¤˜}Þ:îïëQái࿸ü⨀ ¡Doæõ›` }˜˜èµãþ¾= ŒçÜâ·€_Ü= ƒœ€Œ7NF-RRRâò}‚‚‚¤«««{[_ë>o÷÷õ¨€ð4p‹_Ü~q T@1±ºº:ÉÈÈÂÂÂ~½&/Þ:îÏëé7؆}$''›Ì×öçÙf›m¶Ùf›m¶Ùf{°·G|¢ÑÞÞn𵩀Pái࿸ü⨀ø=qÔS¡û¼uÜß×£„ñœ€[üâð‹[ d¼¼<©¯¯7¯›šš$++K œþ=Û¬R­­­.gèq__ O3·øÜâ·@dÖq´ÎGyy¹ÄÄĘý&L0ý.]KÃÕºž÷õõX†*¹ú˜1cFôõ¨€ð4p‹_À-~q T@Æsâ·€_ÜâpK  O3xš¸Å/n¿¸Å/ 1" „„„§<ÍÜâ·€_Üâ—„ ð‹[ünñ‹[ „ áiO3p øÅ-à·ø%!èz@žfà·€_Üâp‹_Æs2žp‹_Ü~q‹_‚ à·øÜâ·x BB@BPüâ¿€[ü⨀ ^Œ5ªgQ\\,cÇŽ5¹}Owç{zÜß×£„ñœ€[üâð‹[ Ä ‰ˆ£(--•¤¤$ikk3¤¤¤˜}ÎÂÝùž÷÷õ¨€ð4p‹_Ü~q T@1Ñ›s•j }˜˜èô}Üïéq_ d   éêêêÞÖ׺ÏY¸;ßÓãþ¾žfnñ‹[À/n È & Žö=º_ïc¾§Çý}=z@Ï ¸Å/n¿¸z@¨€øäzú ¶aÉÉÉæÏ–ýêG_l×ÔÔøôz¶ßÁÛnllÄ~‡å¶þ^À~‡ã¶ |Œ<¿Ó¢ûúÓ“a¾§Çý}=z@€Ì‚ÕÚÚêp–¨ÞÏÝùž÷õõèa<'à¿€[üâè¤u@œ­¢kc8['£¿ç{zÜ××£„ñœ€[ünñ‹[ dŘ1cFôõ¨€ð4p‹_À-~q T@ „„„§<ÍÜâ·€_Üâ—„‘ ã9ñ‹[À/nñ ¸¥„„„§<ÍÜâ·€_Üâ—„ è!H@xšÁÓ Ü~q øÅ-~I@z@ω_Üâp‹_Ü=  O3ð‹[À/nñ ¸Å/  ÿø€„ øÅ-~·øÅ-¨€€€0ž“ñœ¸üâð‹[ü’€T@¿¸Å/࿸*  @$ £Fý¿öÎÇ%Žkoã÷OQ%T"Š%QDÑj¬( †‰"X‹X E"Å@ bn%Á7bHà¦JƒâkPC¼Šçõ9}GÆuwgÎ:«»úù,_Ü™™}æœ3óœ_æ‰ †‡‡Maa¡¡¡¡Èןöñh¡6ƒ@[ôE[}Ñ– $Ä…ññqÓÜÜl666l´´´ØeQ­?íã1„þœÚ¢/Úè‹¶c@2È€èa^.ÐCš"[ÚÇ£„Ú mÑm ôE[‚4ââb“——gª««ÍÈÈHÒí ÌÞÞÞÁg½×²¨ÖŸöñBAA0ä„XXX0fppЩÅDæ%ªõ§y<]`/ü|÷Ýw¶éÍs¿ú{Ÿÿúë¯=ÞyûŒ¾éû¼¼¼Œ蛕ŸU. úfãg/Ðãìé{.fÁÚÚÚ²ƒµia ý9 ´E_´%Ðm Æ€œº‰7¦BË¢ZÚÇc ý9 ´E_´%Ðm Æ€¤‘ÞÞ^³¸¸h߯¬¬˜®®.Óßߟ° “7«ÔúúzÒY§R]ÒÇc AAÁdbbÂÔÔÔØÿÒÒR;þc{{;é ý/dÿWã8ëOúx´€P›A -úh‹¾hKÐ’AäççŸéã1„þœÚ¢/¶è‹¶c@Bmú¢-¾h‹¾ÚÒ‚Á€AAh!ÐmÑ—@[ôE[‚å1 ôç¤?'Úè‹¶ú¢-úb@€}Ñ} ´E_´%h AAA`@0 ÔfP›A -ú¢-¾h‹¾` ¾h‹¾Ú¢/¶ŒÁ€`@¨Í 6mÑ}Ñ–@_´E_ 0„ ‚ ‚` `@¨Í@_´%ÐmÑ—@[ôÅ€`@BNmÑm ôE[ôe 82<Z—0 €ÉPffflW=ÔAzPmÑèè衇fHéè7s”éekkË"Dh𮌇‡Œ]3£çíÛ·YQ;ŸMhâµ€øÇ€dC¯ `@2‰‰ S^^n>~üˆ'cl¢+˜© ’hÖ¶X"SÑ¢É)>|ø€i¾eÃ=  ãñãÇv Hš¨Óƒú{SêN3±477# åCÆ£Ò^ “º]tuuÑ—>"4]Ý®dBꎥ)º!:fgg­hÑŒW÷áÂ,Xp¦,¨å<9mÑ7:Ôº¤i ¥é… ø?+¬L»¥¥¥vü‡¿Öއº®¨LP׫7n0=bÔʤ)Ð!ZT)áýï0…ÞgøF `@€ 0 €À€À9![þ)'ÿ<gÀh`@0  ²Û|ø#vÝÄÄ„ill4ùùù¦  À´µµ™¥¥¥#ÛýñÇv;mãßÏìì¬immµËóòòLmm­yùòå‘syôè‘ý^nn®)..6ýýýfssóÐ6Ïž=3ö\ª««Í“'OŽœ÷ÊÊŠééé1EEEöxÚ×Í›7Í»wï¸à€È’h¹LÅçÏŸÍÞÞÞI¨««;²]KK‹ÝÎÏÌÌŒ52-kkkfww×ôõõÙíeüŒŽŽ™m£m=þüóO»¬££Ã…ÞÇž¿ÎMŸ§§§íç¯_¿ZãóÀ€d¸ùûï¿–É„x­±Û-..Ù‡úµÎßb²³³c—UUUž—Z1<š››œÏüüü‘ó×¹)æææ¸¸È6´<Ù uŠ×Í+ÖÄÈ \½zÕ-×%Lݮœ×¢ÐwÔåk``À¬®®r±p– ˆgÔr’ Ï4ø»e¥j@4¤··×”””222"€3l@4ø\릦¦’žƒ×Râ¡î\±û ÛËÆœ¼zõÊ®×10 §Ì7ß|cÐ5H~ü˜öã)â±¹¹iÏ!??ß\¸pÁÜ»w/pŸÃÃÃV/ÅÐÐóúDçï<§§§MKK‹=¿¢¢"ÓÓÓcVWWî/h{×ý‰©©)SSSc¿SYYiž ºv®¿7hûx:êw†Aùã¸÷´ ë˜Ê=ü¼å3 $# ˆ‚”€¿~ýjöööÌû÷ï͵k×ÒzsðÐ1ÇÆÆLIIIZ ìØãúQáwûöm³³³c¶··M__ß¡Â(–ññq«ÙÆÆ† ¤Zv}Øóòhoo7¯_¿6»»»öú|ø`JKKÍÛ·oígÝ(îܹúü]¶Óß›7oìyéZ ØÂÛUÛDÇr½6äµÓÍkAû J/®yC$÷ïß·ë###¦¶¶6åý¹žy-1ö_Q¦ÅlÎgaÓ•ëo»ýääd(CùâÅ ÓÔÔtd¿®÷  ór-WÎc>À`@Òg@ÊÊGªµqÍdþez¯_^^n÷¥öÜÜœÓþ~ÿýwÓÕÕuh™ 8Õf¨æ@µ_¾|9´þ§Ÿ~²µ0ªUxôèQÊ……ö¯‚ÁCï“=$(³{—Ð{²a×GqƒÔ9G¹}²õׯ_7ÏŸ??öù§ò;UhûÓgXmËõÚ$bÿ~²c1¦ºÚ˜+WŒù÷¿Ã}¼æ–×\ÓNlzq͹¹¹iÍkAçG^‹Ïÿî¿Êö_ú… ³,(OdB> JWé2 uuu¶57úmUUU¶1Ì~“å› ï»–+ç1Ÿa@0 é5 .Ë}(±šÏŸ?§üP¤ÂTî[™ë·ß~s®ÍP­‘ ]_~ùÅÖ kŸª%Q톿†âçŸ6v½j=TpGõP¤ý©ûE"´N¿Ó_ ø·Z{^s¶ ¥êý'ZÕº&+¼>|hkU‚ñ¶wY/t]¤ÉiÖj&÷ßH‚´ :VØï™†cÞ½ûçóþóÏç0&„¼æ–×\ÓNlzqÍz0QþÓ:…ºrhYy-Þù‘×Â1°ÿ’Ñß“0 Ay"SòYPºJ‡ѱúûû¿w÷î]›RÉ7®÷H×rå<æ3 $# ˆú#ª@¹xñâAÍŒ¿?f˜‡"æªåK”‘üß)Û?oÿCš sŸS5Ÿª¿v…ëÍ›7m“­~ƒ×|ëzþþíSYï±°°`oBzHw\…šö÷—hû°ëòaûúÖóóóæò厮s¶a4 óýdè>é™™–C^‹8¯¹¤°é%YÚ_YY1ëõÞ_Ó›j^Kt~äµ`Ôêñíþëö_úëÚ ’Š Ê™’Ï‚ÒU: HCCƒùôéSÒï©U¶±±1å|ãzŒâ~Öó ÛÕʱK–šMÕG=¨ðˆ}(rɘñÖé¸þÚ"m£4/ôÙß="•š‡dc50XÇуáãÇ“ÞlŽÛÄÖÖ–L–¨¶httôÐõIFÐöaöwµE333¶ù>¶{ÑiÔÊÆfŸK—Žnóßÿº÷~$¯çµ°ç(½¸æ¶¶6[»ê¦‹XP^ {~ç>¯ÅyÝÜy-z_–ॠʙ’Ï‚ÒUÔDÝ{ü-‚‰Pk(\ïiñî‘®åÊyÌg Ht$ÞS’ËòüZ…¤?«`ú¡Hýeý›j‹’Íe­l,OŸ>µƒÚ¯Ï¥–…]’jMbÐöÉÖ«óIö—˜˜°câ à «­KY—k#ŽÓB^sËkaö—,½¸ê/7¯¹œyí0^ë‡×êû9U-‚òYPžÈ„|&]Em@Ô…T¸ÃìÇu2—|t *WÎc>À`@2Ò€(3¾Û¢R¬Z?õ{öÏü¢g꣩õ*@Õm$ª‡¢D3†üúë¯æêÕ«¶K„PmJooïÁz¯¿¬Îç¸ýÒüñG»ý>õÏT-E².IÞ¬úN²Y°­=ý.ïxú½ºþ>¶zïMª‚WýLìþ‚¶Z‹n8ªUšµŸÓ9cˆj®t£Žmâ«mбÂ~?ÇB^sËkAû J/®yC×B×Ä?Ä}\÷t~äµä üÿ+h™«Aù,(Oœv> ›®¢4 J“‰&Ó¥É%߸Þ#]Ë•ó˜Ï0 ôgÁR†UV­šî4PÎßWUM†º k½\¼ ×ã>y¡ATøÇkBV­>Ø:®¦Ç|ùòå¡õêªZ C‚jbT[âõÉW õÓ Bf²y·“­=¾jGôû´\µ`ú]þ~þþõÒ+Þœï‰öoû õ‰Òˆ¾£k¡9ÓŸ={æ\Û¦°³¯ mƒÎ#èÚ…5!j ùöÛZ>Â΂E^sËkAû J/®yC-Þœý ½OÖ•$LÞt­ &¯ýÃúþ«,ÉKëS}H ÊgaòD¦å³Øtï’æÂl¯[M…9Î=-Þ=2•{øyËg Hú Ïð ‰!ñÏ ñÏð ‰!ñð ‰IKâ!‚ ‚ × dÿ ¹v=ÕÜ6IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_weak_get_bar.png000066400000000000000000000556311174000617100240210ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix[`IDATxÚíÝ}¬÷þHUUUUUõŸªªªªZ©ªªªªªìC6›Í²^XX(5µ Y;öÆ×Žc/\¼xMìÄpk§lÌ’µ—à$Øqœ5v Žü ë/”½þ9"/ôò ›Ä ‚¯ |órnæÎ=çÌyº×—×[úˆsÎÌæÌœ3¯óï̇’ˆˆˆˆˆHò!«@DDDDDDDDDDDDDDDDD@DDDDD@DDz‘_ú¥_JúЇFëßü›3õ>° ÿ¿¨näßþÛ;fó73fø©S§Òßû{otø~ô£1ÃwîÜ9æïÿÝ¿ûwSn}Å:øò—¿œ~ï÷~/ýãüÓßÿû?¯xü±},Ýxãéé§Ÿ¶SŠˆˆˆLÕTôŽwðÜëƒù"@î¼óÎ1óX·nݘáq`]~ÿý÷þØc~ÇwL©õµyóæôOÿé?­¹½uëýù n«""""S:q[ëpñâÅR2¯½öÚ˜y|ò“Ÿ3|áÂ…c†O›6mÌð¿8|Û¶mSf}=ûì³c¦÷Ïÿù?O?þx:{öl>|dd$Çp´Ž|ä#‘©˜ÿ÷ÿþ_úgÿ쟜ý“òOÆ :¨+¿>ÿÑ?úG£ëå_þË9fxe]ÿƒðòãÔ£óçÏ/ž ÷ÿá?̧7òÿïÿÍO±ªL+ÖÑ;ï¼3eà)" ""M&~a/œ}ö³Ÿóüå—_®{0×Ìé3o¿ývêëëKÿú_ÿëüÀ;ºÿÕ¿úWùko½õVÓ_üâsÅ4âòJëÀ»ï¾›O«ÒŸà?þÇÿ˜ž|òÉÒ¢GMò'’>úÑæÿ1­Y´Jüõ_ÿuÓë´º•#¾#qJ[åµèçPyü /äÃÏœ93æïb:Õ‰ƒöh±Š¾!•eŒurÝu×{Ê\õi_Ñ%þ6ÖÓÝwߎ;VúÀ}ëÖ­£ˆŠz衇ꮓ8Õ¬8­Ï}îs-m¯eþÿ­l«""""Òå|êSŸ=‹ƒ¹sçÎåÿ”Û9¨‹> ÅN×µªºŸD­ù0jým\Çh­aO=õTÓÔÑ7¡ØrÑÎêÆÇü]œzTT­õ\éçËPü»XwÕ(ôתê>%‘"vjU´Ê>|¸i€üÕ_ýÕ˜÷ô/þâ/®“è\^œÖîÝ»Ko«eÿÿ""""2ɧþįȕ±9sæä¯Ïœ9sÌi@ÅS„š9˜¯¤ø‹T´,DkÀ‰'.; môëu\1)Ú«Í/ p_ÿð‡?ÜÔ2G M]‘è›ÿï8*–mÁ‚M¯×hQ(ÎgÙ²eùëÿøÇǬç¹sçæÏÿý¿ÿ÷ùóh(þ]´ìTò·û·c†MŸ>=ŸO,ã-·Ü2fX@¦˜Xöµk׎¶ÄD_‹Õ«W_¼fÞão|ãc^ l5“âvUöÔ²vþÿÀ!"""2IR}0¿fÍšüõè\|=~ñn ×\s͘q¢ƒv%?üáÇ ‹qëM?:'Wž«‡U.eµÅ×ã ·™eŽÓwНå+_i{Ý~ŠÍãôªJ«A¥Å'ZŠØ¸úê«GŸÇéQÅTŸÖuàÀÑaÕ뤺cû¸_`U½DZÜÅÓ¸*-;ͤ¼ZÛK£Ö‰vþÿ""""2IR<àúßÿûç¯Ç¿Å×c¼VRìt\ý«wür]ãÖ›~ñoë «w ;Þ2;ÞGÅ}*ÚM±5#–©Ø:³oß¾|œ¡¡¡1§‹[ V®\9fzÕËX¯ªá§;Å©v•>8µþ&–±YÄ4¢H™4jivþÿ""""2 R}C¼è^L±_Eœž•«`UþÕw4o&ÕücÕ}ªo\8ÞÁuõºŒõˆ«L#®äÄ«ï ý>Š÷‰Öƒêþ?Í$ïS±5"®FUë*iµýFŠÓ‹Óþ¾ûÝ“ø?Œ·L­þÿ›ÝVEDDD¤‹‰›ÆÈâüüZ©¾Tn\«’+V4uþ}È7ºH­ûHô ‘¸tkõi>íþr^¼òUT\v·VŠWxŠñ£µ VšY—ÕË—ß­5Χ?ýé–‰›S_/ƒ³hñ‰Ó·ZéËÑÊÿ¿Ì¶*" ""]Ju‡çêþ•/[9妒øÕ9Îãÿÿá?4ìÄ- q¯†è€ãFÅ/óñZür]óõljDËPñNè•S…â»r©ß²)žê6Þ ûŠ7.¬õ ~­u×c=ÆyÀ)îÝòùϾfçîh¨Œÿ1^3ë£Þðê>DqGõf÷l‰uñ‰O|"ïSùDKPlc²€ÓO~ò“ŽüÿËl«"""""""" """"" """"" """""""""""""""""" """"" """"" """""""""""""""""" """"" """"" 2òùÏ~Ìó;î¸#}ö³ŸUJ)¥”Rª£U}Ü ’ç¶ÛnK?üá•RJ)¥”êhˆˆRJ)¥”F9xð`Z¶lYš9sfºæškÒK/½4:lÚ´i—Uu6lØfÍš•×úõëÎ¯ÑøíŸèùˆRJ)¥”qrèС´hÑ¢ôæ›o¦‹/¦áááôÈ#ŒH½lݺ5-Y²$:u*¯¥K—毵:~»Ã'z~¢”RJ)¥¤NV¯^=¦Å£:烃ƒ£ÏãñâÅ‹[¿Ýá=?QJ)¥”RR'sæÌI›7oNóçÏO3fÌÈÿ§OŸgúôééúë¯OO<ñĘ¿Ó¶¢å¤’x¯—Fã·;|¢ç J)¥”R @ê$€ñÐC¥óçϧ‘‘‘ôðçx æ¸GŽI+V¬H>úhÝ’ÀJ™•âøíŸÈùÅP©êËð å­'±¡Ä¿ž{î¹çž{î¹çž{Þîó$@â×ü€G%‘h /gÏžÍ;ckÑ¢”RJ)¥´€”Ntª®H½ìj€Ôê#¯•é“Q¿Ýá=?QJ)¥”RR'Ñ=N» „DÅéX>øà˜NêGÍ?~<Ýwß}iÍš5—]%*®žUë*QÕ§05¿Ý὞€(¥”RJ))™èX>wîÜüÔ«ûï¿L'ô;v¤›nº)?°_°`AÞÿ£Øb‰{cŒwŸŒZ}(êßîð^Ï@”RJ)¥€L¢ÔëO2æ J)¥”R @@”RJ)¥€€(¥”RJ)  J)¥”R @@”RJ)¥”¥”RJ)  ´zá…éÕWw¦;/ýÏ+õ½ïý¢¶nýE½øâ/êûß¿TñøÒðÿi½*¥”R @@ì µëškRzúéKëé¯þ*åÏÿëM铟LéúëSºá†”>ýé”n¾9¥[oMéöÛSZ¼8¥¥KSZ¶,¥ÿößRúã?NéŽ;Rºå–çœõª”RJ)±ƒˆRJ)¥€€ˆRJ)¥€€HkùÌg~–^~ùå1Õê²mõÕ4˜-Üà+¯¤ÁÁÁ4¸m[üÖ·ÒàSO¥ÁoûÒ°¨ï|' f Ÿ×3ϤÁM›Òà³Ï^ªçž»ô<†eãþÍóÏ{ß•RJ)  S 7Þ8œ¯ÿJý÷ÿþß[^¶/¼Lé»ß­½€ŸúÔ¥á7ÝtiæŸýlJôG—î®»RºûîK wç—†ýá¦÷²eò¾÷¾^|ñGéÙgÓk¯ æ˜Ü¶m0}ë[ƒé©§Ó·¿=˜mƒ—ê;ßÌÞæKõÌ3ƒiÓ¦Áü{îÒóãÆ4§ò:Û¶mGÚ°aúÁö§ýû÷§—^ÚŸ}tzì±ýé/ÿrZ¿~úÚ×öçã<þøþôoìOßüæþ´qãþôÄûÓ“OîÏÖï¥Ç1,Æ{ú鿵=*¥€È•ý>zé ø¥—Ú;˜Žç!lÜý= ò¨8pîðæŸˆOõ+Ôe›l'7ÿlŸ|Ïö¨”R"   J)  2%røÞ{Ó–-[Fëûßÿ¾O¥”R" ÝÈßfÿ‰âò}õ«_-½\+Wþ4}ýëçÒ¹sçҳϞËÖϹÔ×w.}æ3ç²ÙœËÖѹ´dɹl1Îeëè\¶ŽÎ¥+Îew.Ýwß¹ô§z.Ýÿ¥çwÝu.Û>Ï¥ï}ïHI€üÿñ¿²M㻣Õή€ÜsÏÿIÏ<óÌh½íc”R @@š>{>;²øÂ¾0ZOg’îdéÒáô—Ùþ:‹çŸùÌ¥ÿFlvj[û»¯|% mÙ’†††ÒÐÖ­i衇ÒÐç¡/9 ­Y“†þìÏÒPŒ³vmúó?OCÙ:ú‹¿HCÙ6:”ýdž֯OC6\zžówëÖMJ€ÜyçócÞËV¶ÿ+ ·Þú·cÖÙ_dﻃ¥”R)L|ûÛßIçbæO>Ù±7õ\¶î@”RJˆ€€€(¥€€€”È¿øX¾®*µmÛ6QJ)é@î½÷ÏÆ,×~ðƒI3Ùx_ûÚ×Fëë_ÿ:€ˆRJ©:@<˜}ï/K3gÎ̾`®É¾¤_3|Æ iÖ¬Yy­_¿þ²¿o4¼ìøôù€Hç2œ­·â²}ñ‹_QJ)õAÈ¡C‡Ò¢E‹Ò›o¾™.^¼˜†‡‡Ó#<2:|ëÖ­iÉ’%éÔ©Sy-;]âµf‡W§ÝéMöù€€È• ¸,v7ÿüÒÚ°”RS «W¯¾¬Å£˜8ø}ǧe“Ã;=½É>?²uøK_Jç²75îírî7Ò¹?ÿó|=žëëKç²7é\ör.[ sÙ:9—mOç–/Oç²õtnåÊtîOþ$ûÜçÒ¹ûï¿ô<[àsÙ:Ýóï€(¥drdΜ9ióæÍiþüùiÆŒùâôéÓ£Ãã´¬h©$ÇkͯN»Ó›ìó)[ïÝw_JëÖ]Z¸ý(îrØúÆ›š­ãÁ§žšÒùÿ6nLú†³75ZÎf>œÍp8ÛŽ†³íhøž{Òp†²á iÃú§iø _HÃÙö3œoxõê4üÐC—žg€‹q;qsUQJH™6mZz(û>þ|I?üpzàÆ ¯ÎôéÓ›^k~íLo2ϯøÅZÌÙ7IÜ”-ZObC‰{ýüĦM]H@¶ìòõ ­®¿½=HÙå[¾üLײoß¾–··‘¾¾®äKÙÁcÙ÷sÓ¦]È–-[ZÞ?Ïô÷w ׯòÄó½=H«Ëw8H¾ÝTN‰íÀ›7Ìl÷ó¶¯o¤£¹ýö‘ ÿþðÜsÏ'÷ó$@â×ü€G%‘h Ñ¢D ˆ- Z@&k Hþ™Ö€L¶?üÃáô…/|a´V­Zå_¥Ô¿$:UW¤x€]«D¼Öìðfúd”™ÞdŸ€€ÈdÈ“+W¦|p´ââòÁHu  .¥Ô Ñ=N» „DÅéXñeU}¨8ǶÞU¢Æ^} S»Ó›ló™ŒùF¶‹Ë÷½ï}@¼©;—/Oög6Z•Ms*älx/›Æ{ÙgÛ{ï½—ÞÛ²%ßöÞûÜç.½~ÿýé½HïeóxoÕªô^z/;&x/;Fx/Û&ßËÖÉ{<’Þ[»6½÷å/çãüÊWÚþ~úîwÿ&½øâ`þßöíƒÙ¶:˜¾õ­ÁôÔSƒÙ÷Ê`¶o]ªï|g0[§—ê™gâÔÊÁôì³—ê¹ç.=a1nw`ªd²ßä‰'žHsçÎÍO½º?û*vBĽ/êÝ£ÞðZ}(Ú™Þd›€€€L €ü0^\¾7N)€äŸi± Ñ'° ˜3œ­Çv¿Ÿî»ï½ì³°£›¾ý:0U2ÉÒÍû“LÅù€€€€(     ¢€€€€€L€;ßÖeÛn¥¾ùÍoN €<ñÄKé¹çž­W_}Õª:@þOVÅåûJ Ò»êÏ´²WS @@@@@@> µ;ÛÆöë[iÿk¯¥ýû÷§ýÙ‡oì³û{,íϾÀö¯_Ÿöíkiÿ† iÿã§ýßøFÚÿÍo¦ýÙ>·ÿ‰'Òþl'ÚÿÔS—žýëù¸?zñEë@@@@@D]^C=”Ò=÷¤´m[göÏÜ\@@@@@@@D@@@@€ˆ€€€€L@¢ïÁÎW^I;wîL;_}5_£•íW£•Íc´âo*õýï_ªxÃJî‹r ¯ýùŸçŸ³•zùå—á@@@@@¦@†cÂßøFG?t¤<@ª?Ó¾›}8Á€€€€€€€€€€€€€€€€€È mÙy±@D@@@@ºâ²E€ˆ€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€H×3mڴ˪ÌðȆ Ò¬Y³òZ¿~}Ãy6¿Ýá=?©v†ÇN½dÉ’têÔ©¼–fËÖÊB ã·;|¢ç      ]HœŽ>Ç‹cÇkqüv‡Oôü@@@@@¤0æÌ™“¦OŸžíG×§'žx¢Ôð™3g¦‹/Ž>ÇñÚxi4~»Ã'z~     ÒdŽ9’V¬X‘}Y?ÚôðZ-$•2-*ÅñÛ>‘ó+îÅÜ‘}P å­'±¡Ä¿½~~"¾pº Í›7—^¾^¤Õõ·w` ')»|Ë—Ÿé:@öíÛ×òö6Ò××U€ÄXÙ÷sÓ¦]È–-[ZÞ?Ïô÷w Ùö\fùöö ­îŸ‡3ô e—¯¯o¤«YµjUË߽Ⱥl;.»|ýýgºíÛ··¼ž‹é.d"ºñüØÚµ=ÈTY_í>ŸWÁ:{ölÞÙºÙáZ@´€hÑ¢D ˆ- Z@´€hÑÒ3€Ôê#¯•é“Q¿Ýá=?©“Õ«W§£Gæ?ž}Ü—Ö¬YÓôðÊU¢†‡‡k^%ªú¦Fã·;¼×óÙ±cGöþß”¸/X° ïß122ÒôðHÜc¼ûdÔêCQoüv‡÷z~     2‰2cÆŒ)=?šµmÛŽôâ‹;Óë¯ïL;wîL¯¾º3ßg+õ½ïý¢¶n½T1~¥¾ÿýKcXŒ÷ƒü5€ˆ€€€€HíÏ´%KRˆÎ}¦=üðДH|¦ýÁ¤ôì³Ûü³Å‰qW¯þ»ôòË/Ö«¯¾ Mäµ×^­×_@@@@@@šùLû£?úá˜ezâ‰'¤@n¾ùÿŒY¦Gy@@@@@@@@@@@@@D@@@@@D@@@@@@@@@@@@JgÚ´i—Uu6lØfÍš•×úõëKïôô&ûü@@@@@¦ @j¡V]uÕUMO¯^b§]’må§NÊkiö.l­|à71¼ÓÓ›ìó™R Xk<€LŸ>½#‰ƒïÁÁÁÑçñxq¼Mïôô&ûü@@@@@¦ì)X/eߦq€<<<<úÚÉ“'ó×ânŒÍdΜ99X®ÏÖ~lpÅÌœ93]¼xqôy<Ž×š^v§7Ùç     2erõÕW§óçÏ_öz¼6oÞ¼ÒÓ;räHZ±bE¶a?Z·…¤ØºÒhx3-.e¦7Ùç     2eÇã¤Ù> Õ9{ölÞÙZ Hùù7Âbîȶԡ¡¡üô­ØPâß^??_8]ÈæÍ›K/_/ÒêúÛ;0Ѐ”]¾åËÏt ûöíky{éëë*@â¬ìû¹iÓ‰®dË–--ïŸgúû»l{.³|{{V÷ÏÃz²Ë××7ÒU€¬Zµªåïƒ^d]¶—]¾þþ3]ÈöíÛ[Þ?ÏÅt—RöýܸñpOÒêþylíÚž¤Ìòõ ñ™6Ç{=Hœ:ýâ´«80Ž:qâD¶ÂnOsçÎí@jõˆ×šÞLŸŒ2Ó›ìóÓ¢D ˆ- Z@´€hÑ¢dJ÷¯úk¯½ÖÔ4V¯^Ž=š?>~üxöAp_Z³fÍeWŠ~&õ®5ÞðêS˜ÚÞd›€€€€€ÈuK§±\“f̘‘W<þñÜôßïØ±#{ÿoÊÜ,X÷ÿ3NÜû¢Þ}0ê ¯Õ‡¢éM¶ù€€€€€¸á$J h*Ï@@@@@@@@@@@@º»³7)®ÊÔêÐ@@@@@@šJܳ£‚Vï„.     ÒT¢SôîÝ»óǕӧO§•+Wf+úΤxŧâã¸H«÷ qoŠÊÕŸâ’º‘]»vé      ȶìíïïÏß­µbùóç“€€€€€€tç2¼.\Èo$-óæÍKçÏŸ'é@@@@@@@@@@@@@¦@6oÞœ®¾úê1Î.\˜~úÓŸ’€€€€€€t¶z­;ŸïÙ³'Û0—€€€€€€t Ñéü±ÇËïûQÈÙ³gÓìÙ³I@@@@@@:":ªïûá>      ÒQ€LŸ>=½ÿþû—cxx8Íœ9“@@@@@¤s‰Îæ·doÜÉ“'s€Ä½@Þyç&7Å›*     Ò)€:thÌÝÏ‹uêÔ)Î^†7-!3fÌÈË%x@@@@@¤kéùU°@@@@@@º 8媓Yš­áè?RL­þ%ÕÙ°aCš5kV^ëׯo8ŸFã·;|¢ç     2%rM¶æâ¦ƒÈ+¯¼’­äÅ5R/±SÇ]×£Ó{T fkå ¡…ñÛ>Ñó™²Ù¹sgöŸ¿¹í+^ýìg?K×]w]z÷ÝwK$ÎGŸÇã€L«ã·;|¢ç     2e2Þ%x£Êô‰ƒ gþŽÔÈœ9sò{‹\Ÿ½;±A7<¼xñâèóx\ï&ˆÆowøDÏ@@@@@dJwB¯ ÍäÀÙ ¾½©#Gޤ+Vdþ£uǯ7ïFã·;|"çWÜ‹¹#ÛR‡††òÖ“ØPâß^??_8]ÈæÍ›K/_/ÒêúÛ;0Ѐ”]¾åËÏt ûöíky{éëë*@â¬ìû¹iÓ‰®dË–--ïŸgúû»l{.³|{{V÷ÏÃz²Ë××7ÒU€¬Zµªåïƒ^d]¶—]¾þþ3]ÈöíÛ[Þ?ÏÅt—RöýܸñpOÒêþylíÚž¤Ìòõ ñ™6Ç{ÈËð>Ž=Úô)WÑç$:ckÑ¢D ˆ- Z@´€hÑ¢Ä}@:vW³©ÕG"^+Ó'£8~»Ã'z~     S çÏŸOóçÏo»H½S–V¯^=ÚBrüøñìƒâ¾´f͚ˮ5<<\ó*QÕÓk4~»Ã{=?+ .ŽVú€4ÈŽ;²íã¦üõ äý?FFFÆŒ÷Æï>µZSêßîð^Ï@@@@@äŠê„þú믧ɜNß,q²Í@@@@@äŠH«­      ¥wBo÷&„      Me×®]Ùʺ!ï -     Òq€Ô»ûy'®‚%     2¦ãy3¥€€€€€€tô,©yV† €€€€€€t §OŸé @š¹ ÖÌ™3I@@@@@@ÚHåJW•ËíV׬Y³²ü, €€€€€HçNÁr©]é:@®¾úêôÀ¤cÇŽ9ÚîäÖl­D8+ZAnÌÞÄ={ö¤÷ßßÑ?€€€€€€tç¬ãǧÇ<-X°`´óù5ÙÚܰaC:qâ €€€€€HçRL´~¼ýöÛÙÊ»!o ŒÌž=;[q‹‰@@@@@@º{'ôèÒßߟæÏŸO     Ò]€€€€€€€´ fnBX¹?ˆ€€€€€H[©¾éàxiå!K³5[èÔ77ŒZ¿~}éážÞdŸ€€€€€È”<ë¥ìÛtI¶¾vòäÉüµ×_½Ô´^y啼Ãz5@b§é:u*¯@ÊÖÊ~ëÓîô&ûü@@@@@¦,@ↄçÏŸ¿ìõxmÞ¼yMOçg?ûYºîºëÒ»ï¾{@âà{pppôy<.^Y«Ñðê´;½É>?) ÀÂx)Ó$‚žýù;R ¸ááÅ‹GŸÇãx­ÙáÕiwz“}~     S sæÌÉÓ®âÀ8*n@x{¶ÆæÎÛÔ48_DM5rªSì_Òhx-4µ3½É>?)Ýd¼N诽öZSÓ|=ztÜn- Íϯ¸sG¶¥ å§oņÿöúù‰øÂé2@6oÞ\zùzV×ßÞž¤ìò-_~¦ëÙ·o_ËÛÛH__W`eßÏM›Nt [¶liyÿ<Óßßu€ dÛs™åØÛ€´ºÎpÐ €”]¾¾¾‘®dÕªU-ô ë²í¸ìòõ÷Ÿé:@¶oßÞòþy.¤» ²ïçÆ‡{V÷Ïck×ö e–¯‰Ï´‰8Þ›û€\:ˆ»&͘1#¯xüãÿ¸íËúÖë¯5;¼™>e¦7Ùç§D ˆ- Z@´€hÑ¢D ˆ–ìWRë*Rq¥­zW‰ox§§7Ùæ      H$î}Qï>õ†wzz“m~     W @âjWóçÏŸÔwBÓ¦òü@@@@@®€,\¸p 8ŠÕÊÐ@@@@@@ÆM@£ìÏ@@@@@@ZŠVé@â’»qe&®d×®]Ùʺ!¿D¬€€€€€HW2ÞM'ÓU°@@@@@d uB¯ôŽD@@@@@@@@@@@djäí·ßN×^{m~ÊUT<Ž×@@@@@@: Ý»wÛ B@@@@@¤£‰ÖŽ»³7éäÉ“£¯Åã;³Oü¸Gˆ€€€€€Hǧ\?þ²×/\¸f̘A     ÒY€ŒŒŒ\öz @@@@@@¤£Y¸pa¶b§'N¤‹/æoÍÖZœž%     Ò1€DGóñ:¡ÿä'?!éìexÑÚ§\EÅcø®D@@@@@@@@@@@djdûöíéÁ¼ìõþþþôÆo€€€€€€t W_}u:}úôe¯ÇkóçÏoj{öìÉVìÒ¼ÿÈìÙ³sÐÄ•´*©ÕÁ½:6lH³fÍÊkýúõ çÙhüv‡Oôü@@@@@¦$@ja ’«®ºª©iÄÔwíÚ•ß¼0.ãûÌ3Ïä—ñmf‘Ø©—d{Á©S§ò Ìl­|!´0~»Ã'z~     S ñ‹üÉ“'/{=Z0¢5£ÕobØ qp>888ú<ǽIZ¿Ýá=?) 8°–Ž#GŽŒÞˆðСC9$×Jüý³Ù;sOl4€Ì™3'¿ëúõÙ»d13gÎÌÿ®8xm¼4¿Ýá=?) èë1ÞÏž=[út®¨y󿥣GÖ' ³bÅŠlôn I`¥ÌicÅñÛ>‘ó+n„ÅÜ‘m©CCCyëIl(ño¯ŸŸˆ/œ.dóæÍ¥—¯iuýíè @Ê.ßòågº}ûöµ¼½ôõu qVöýÜ´éDײeË––÷Ï3ýý]È@¶=—Y¾½=H«ûçá ½HÙåëëé*@V­ZÕò÷A/².ÛŽË._ÿ™®$.ÚÓêþy.¤» ²ïçÆ‡{V÷Ïck×ö e–¯‰Ï´‰8Þ›ËðÆéV .½á¢E‹ÒððpKÓŠ_÷ãW¼Ûc“€Mœú¥D ˆ- Z@´€hÑ¢D ˆ÷éHêµ(T¤V‰x­LŸŒâøíŸèù€€€€€H¬Y³&½û¸ˆḚ̈W¯^=zJÖñãdzŠûò¿©¾JT´ºÔºJTõ)LÆowx¯ç     rE$λû/»§dýô§?mêïwìØ‘½ÿ7åîsçÎÍobX<…«8|Á‚yÿ‘‘‘1Ó´ŒwŸŒZ}(êßîð^Ï@@@@@äŠȶì­t/$n.Øè4¡^¥xIß©8?+ Ñ"ñØc壋‰S©Ú¹ˆ€€€€€Èe)¢£úÎçÍÞ ]@@@@@¤é«U½ÿþû—#úp4ºT¬€€€€€H©Dgó[²7îäÉ“9@.\¸Þyç&Ñq\@@@@@¤c9tèиwBKÆ €€€€€€tô2¼âÐË\‚W@@@@@D@@@@@@@@@@@ä ȱcÇòS®"Ñ}Þ¼yyÿk¯½–@@@@@¤³¹5[;Ìßÿýc:¡ßŸú      HÜëcdd$<þüûöíKp'té,@•Ľ?âùùóçóçî„      ȬY³ò#GŽäø˜3gNþz´ŠÄ0Ž$l‹ý>–ÅÚÉ244”ß!]@@@@@¤£—á]°`A~ºÕ5±žE‹åWÈé(@@@@@@@º «¯¾:=ðÀZ9@@@@@¤û‰ûÄ%x£ßG\ýêÆìMܳgOzÿý÷ý€€€€€HwNÁ:~üxzüñÇó~ •ŽèÑdÆ éĉ$      Ýé­o¿ýv¶òn½'HÜŒpq¬¹:‰–“¥Ùš1cF>þƒ>x^4qYߨõë×_6FÃËŽÿAŸ€€€€€È× =ú‡ô÷÷çwH¯—»³7y×®]éÂ… éâÅ‹é™gžÉOñª$vÚ%ÙV~êÔ©¼+[+øM ¯N»Ó›ìóq¬’‰ÖJâà{pppôy<.¶ª4^v§7Ùç     2erþüù¼…£x3ÂJŽAÊ&Z@žÍÞ™{b£ùy¢³{¼^'^kvxuÚÞdŸ€€€€€È”ÈÂ… Ç€£XѤL*Ó™7o^:zôè˜×«Sœv£áµæÓÎô&ûü@@@@@¦,@¯¿þzÇN½Š_÷ãKôöXãZ@Jϯ¸sG¶¥ å§oņÿöúù‰øÂé2@6oÞ\zùzV×ßÞž¤ìò-_~¦ëÙ·o_ËÛÛH__W`eßÏM›Nt [¶liyÿ<Óßßu€ dÛs™åØÛ€´ºÎpÐ €”]¾¾¾‘®dÕªU-ô ë²í¸ìòõ÷Ÿé:@¶oßÞòþy.¤» ²ïçÆ‡{V÷Ïck×ö e–¯‰Ï´‰8Þë9@ʶr´2ÝZ} âµf‡7Ó'£Ìô&ûü´€hÑ¢D ˆ- Z@´€h™²- qϸ2S;Y³fMz÷ÝwóÇgÏžÍ/3[<À®\jxx¸îU¢Æ^} S»Ó›ló¹b—Ïû~ÄÁq«Ù±cGöþß”¸Ï;7¿toõô%õîƒQox­>íLo²Í@@@@@äŠH­«_µs¬n_Òw*Î@@@@@äŠê„>^u«ˆ€€€€€¸¡€€€€€€€€€€€ÈÈÛo¿®½öÚü”«¨x¯ €€€€€€t »wï·:„€€€€€HG­wgoÒÉ“'G_‹ÇwfŸøqŽ$N¹:þüe¯_¸paR\Ž@@@@@@¦@FFF.{=P      ÒQ€,\¸0[1‹Ó‰'ÒÅ‹óŠÇ·fk-NÏé@¢£ùxÐò“Ÿ€€€€€€tö2¼híˆS®¢â1|€€€€€HW"           òÁHôï¸êª«FW•q@@@@@@ZHÀ".¿[y<^UÆq €€€€€€ˆ€€€€€È¸§cµ2L@@@@@¤c9}ú4€€€€€€HgRïêW•š9s& €€€€€Hû©\éªr¹Ýêš5kV¶‚ŸmjZ{öìɾ îÌï¢>{öìÔßߟ†‡‡ëb§:6lÈçµ~ýú†ól4~»Ã'z~     Sò¬N\j÷žlÙ½{wºxñbɾ×å )¤^b§^’í§NÊkiö.m­|!´0~»Ã'z~     ®‚U"‘"l$ÎGŸÇãÅñnµ8~»Ã'z~     S Û·oO>øàe¯ÇiTo¼ñFKÓ|óÍ7/k™3gNŽ’ë³w'6Èb¢¯I ¥˜zýOßîð‰ž€€€€€È”ÈÕW__ñªÖU°æÏŸ_zz̶‡Ó±cÇj?räHZ±bE¶á?Z·…¤Þ©aÆowøDί¸sG¶¥ å­'±¡Ä¿½~~"¾pº Í›7—^¾^¤Õõ·w` ')»|Ë—Ÿé:@öíÛ×òö6Ò××U€ÄXÙ÷sÓ¦]È–-[ZÞ?Ïô÷w Ùö\fùöö ­îŸ‡3ô e—¯¯o¤«YµjUËß½HœÆ]vùúûÏt ñƒm«ûç¹8î2@ʾŸ7î @ZÝ?­]Û€”Y¾^$>Ó&âx¯ç©wzTÙËð¾õÖ[éºë®K¨;ÞÙ³góÎØZ@´€hÑ¢D ˆ- Z@´€h¹ÂZ@'Ož¼ìõ'NäW´j6;vìH×^{mzçwŽ[ Z}$âµ2}2Šã·;|¢ç     2e¶ÑÒ§FÅ/óQ‡Ê[Fu”®äùçŸÏÞ€kò¿«•Õ«W§£Gæ?ž}PÜ—Ö¬YsÙU¢âÒ½µ®UÝJÓhüv‡÷z~     W @¢¯Çx7"Œ–ŠvnjXl¹)Û@âµ äý?âr½ÅĽ1Æ»OF­ÓÄêßîð^Ï@@@@@䊺 oœnµpáÂüF‚Q‹-s#Á‰N,ÓTž€€€€€ˆû€€€€€€€€€€€€€| rwö&Åea«ûp”½ ¯€€€€€HÝÄM+بH½›ó €€€€€€´tÝ»wç+-qe¬•+Wf+úΤxÉÙâã¸ÈܹsI@@@@@@: ¸9^åò³qÏŽÈ®]»ôÎd[öÆö÷÷çoÈÖZ±ÈüùóI@@@@@@ºsÞ .äw*–yóæ¥óçÏ“€€€€€€t             S ÇŽK .=+N½Šþ×^{-€€€€€Hgrk¶v<˜?¾ÿþûÇtB¿3>õ@@@@@@:™3g¦‘‘‘üq\õ*à±oß¾tàÀ4{ölΤxóÁéÓ§çÏ+W¿ré(@fÍš•·x9r$ÇÇœ9sò×£U$† €€€€€€t q`[ì÷±,ÖN–¡¡¡ìý¼…@@@@@¤³—á­Ü|ðšX‹?Ï¢E‹ò+d €€€€€€t       €ìÙ³'¿dïŒ3ò+gõ÷÷§ááá1ãlذ!ïSµ~ýú˦ÑhxÙñ?èó™’‰+^U.¿[]Í^ëžlÙ½{wºxñbÞy}]ö%X¼‡Hì´K²­üÔ©Sy-ÍÞ…­•ü&†W§ÝéMöù€€€€€LY€Ä]Ћà(V\–·•DŠ߃ƒƒ£Ïãñâx7š^v§7Ùç     2eÐxýõ×;zJÖ›o¾9¦$nv()%^kvxuÚÞdŸ€€€€€È”H«­ãåàÁƒÙöpã˜+hovXk¾†W§ÝéMæù7ÂbîȶԸ4r´žÄ†ÿöúù‰øÂé2@6oÞ\zùzV×ßÞž¤ìò-_~¦ë‰û µº½ôõu qVöýÜ´éDײeË––÷Ï3ýý]È@¶=—Y¾½=H«ûçá ½HÙåëëé*@V­ZÕò÷A/§q—]¾þþ3]ÈöíÛ[Þ?ÏÅt—RöýܸñpOÒêþylíÚž¤Ìòõ ñ™6Ç{=H\z7ú%t"o½õVºîºëÒ:Ú‚ D ˆ- Z@´€hÑ¢D ˆ)Ò²k×®leÝpÙU«ÊfÇŽéÚk¯Mï¼óNS}(âµf‡wzz“}~     S µ®~Uö*XÏ?ÿ|Þ’rèСºW‘ äÔ»JÔxëOajwz“m~     WT'ôñªÙþ!㦘¸÷E½û`Ô^«E;Ó›lóq#ÂI”¸ÁáTž€€€€€€€€€€€€t wgoR\•©Õ>       MeÅŠ£Ø¨H§ï"     W8@¢SôîÝ»G;¤GNŸ>V®\™­èH@@@@@@:{ÞZãfysçÎ%é,@*wB«?Å #qƒB}@@@@@@¤£Ù–½±ýýýùã¸#z±ÈüùóI@@@@@@ºsÞ .¤ ä-óæÍKçÏŸ'é@@@@@@@º ý<@@@@@¤g‰Žç      =È5Ùš;{ö¬#~é>@vîÜ™ýço½¯€€€€€H×R¼ìnué      ï„>^MŸ>@@@@@Äex@@@@@@@@@@@@ꟂÕÊ0ŽäôéÓ      H½«_UjæÌ™$      í¤r¥«Êåv«kÖ¬YÙ ~¶4fšÅNu6lØÏ3jýúõ çÙhüv‡Oôü@@@@@¦ä)X¼Ôn=€ÔKìÔK²½ n†µ4{—¶V¾Z¿Ýá=?WÁê"@âà|pppôy<^ïV‹ã·;|¢ç      mdΜ9ykËõÙ»d1Ñ×äâÅ‹£Ïãq½þ'ÆowøDÏ@@@@@@ÚH1GŽI+V¬È6üGëþ]½SÃßîð‰œ_q#,æŽlKÊ[ObC‰{ýüD|át ›7o.½|½H«ëoïÀ@ORvù–/?Óu€ìÛ·¯åím¤¯¯«‰°²ïç¦M'º-[¶´¼žéïï:@²í¹Ìò ìí @ZÝ?g8è@Ê.__ßHW²jÕª–¿zuÙv\vùúûÏt Û·ooyÿ<Ò]HÙ÷sãÆÃ=H«ûç±µk{2Ë× €ÄgÚDïMy€DΞ=›wÆÖ¢D ˆ- Z@´€hÑ¢D ˆž¤V‰x­LŸŒâøíŸèù€€€€€HY½zu:zôhþøøñãÙÅ}iÍš5—]%jxx¸æU¢ª§Ûhüv‡÷z~     Rõîó±cÇŽlû¸)}Á‚yÿ‘‘‘1ãĽ1Æ»OF-ØÔ¿Ý὞€€€€€€L¢Ì˜1cJÏ@@@@@@@@@@@@@@@@@@D@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@D@@@@@äJÈ´iÓFk¼lذ!Íš5+¯õë×—ÞééMöù€€€€€H©•Øi—d[ù©S§òZš½ [+øM ïôô&ûü@@@@@¤ €ÄÁ÷àààèóx¼8Þ&‡wzz“}~     Ò@fΜ™.^¼8ú<ÇkÍïôô&ûü@@@@@¤ €Ôz}úôéMïôô&óüŠa1wd[êÐÐPÞzJüÛëç'â §ËÙ¼yséåë@Z]{z²Ë·|ù™®dß¾}-oo#}}]H€•}?7m:Ñu€lÙ²¥åýóL×2mÏe–o``oOÒêþy8ÃA/RvùúúFº U«Vµü}Ð €¬Ë¶ã²Ë×ߦëÙ¾}{Ëûç¹8î2@ʾŸ7î @ZÝ?­]Û€”Y¾^$>Ó&âxO ˆ- Z@´€hÑ¢D ˆ- Z@´€tºH¼ÖìðNOo²Ï@@@@@@:p¬áááºW‰oxõtÛÞd›€€€€€€´xñî÷¾¨wŒzÃ;=½É6?™D™1cÆ”ž€€€€€€€€€€€€€€€€€€ˆ€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€ˆ€€€€€€\Ê´iÓ.«êlذ!Íš5+¯õë×7œf£ñÛ>Ñó6R/±S/Éö‚S§Nåµ4{—¶V¾Z¿Ýá=?é"@âà|pppôy<^ïV‹ã·;|¢ç      mdΜ9iúôéÙ›s}¾A3sæÌtñâÅÑçñ8^/ÆowøDÏ@@@@@@:”#Gޤ+Vdþ£u[H+eZTŠã·;|¢ç      ÌÙ³góÎØZ@jãRÅÜ‘m©CCCùé[±¡Ä¿½~~"¾pº Í›7—^¾^¤Õõ·w` ')»|Ë—Ÿé:@öíÛ×òö6Ò××U€ÄXÙ÷sÓ¦]È–-[ZÞ?Ïô÷w Ùö\fùöö ­îŸ‡3ô e—¯¯o¤«YµjUË߽Ⱥl;.»|ýýgºíÛ··¼ž‹é.¤ìû¹qãឤÕýóØÚµ=H™åë@â3m"Ž÷®H€Ôê#¯•é“Q¿Ýá=?- Z@´€hÑ¢D ˆ- Z@´€´‘Õ«W§£Gæ?ž}PÜ—Ö¬YsÙU¢†‡‡k^%ªú¦Fã·;¼×ófÇŽÙöqS~`¿`Á‚¼ÿÇÈÈȘqâÞãÝ'£VŠzã·;¼×óI”3fLéù€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€ˆô<6lH³fÍÊkýúõ     "ÝI|h-ÉöòS§Nåµ4Û ·V¾ð@@@@@D:™ÀÇàààèóx¼8¶F‘NgæÌ™éâÅ‹£Ïãq¼      ÒñL›6í²×¦OŸ>.<*U̲l«]¾|yÞšrk¶EÇ¿½~¾"Û«îýÝßM+ãß{ïM¼hQZöá§»²Zö+¿’–ýꯦe¿öké®|$-ûõ_OË~ã7Ò²},Ýõ›¿™–}üãiÙoýVZöÛ¿}éùG?šûÉßù4{öì4gΜôŸÿóξ(ÿ°ôò}ô£+³„{³/ ûò?üá»Ò/ÿò²ô+¿²,ýê¯FÝ•>ò‘eé×}Y6î²ô¿qWúØÇ–¥ßüÍeéã_–~ë·îJ¿ýÛ—žÇ8ùÈâÑå‰ÿËù/-¯¿;²/Š•ÙÿýÞìS)–oeö •¯¯_þåÑuvW¶–ÖÙ]±Þ ëì®lûÉÇëÙx7eë´¸|¿ÿû¿_zùfͺ'ûÀ¼/?ùÉ•Ù:º»°ÎîJ¿ökË ëì®l-+¬³»²u¶¬°ÎîÊ×óïýÞ'ò婼Ÿqªa«ÛÛÊ«®J÷eŸò±|±Îòõõóuv×Ï·³Ê:»+¶¥Ÿok±Þî*lkùólœ%YUÖW,_¼§eßÏnX‘~÷wïÍþ]™/×Â…÷dÛÚ²|{«lk—ÖÛ]ùzûÅ:»ëçÛYeÝ•o‡1îïüÎ'ÛÞþ+ÏÿøŸH÷fÛÂÊ•Ùòe_Æ+²éµ»^3cƘåûL¶=—Y¾Ï|æŽìÿ½2ûR¾´ƶV½þÚ¯ýbÿŒuûç/öÍeÙçç¥õÃb¼}ì¦1Ûÿ5Ù·«ûç²l[™}Ý›ÄÄòݳpakûga}*{­¸|ŸÌ¶ß²ËwÕUñ™ö‹ý3ÖW;ûç¯ÿú’¶·ÿÊóÛ²#«{³ÿï}ÙÁ_ñ{ ýó³ÙðâòÅgZÙåûÄ'þ8û»{óíÿ–[îͦ÷ßÚÞ?gÍš7fûyµº®Ì¦qo¶}åûg¶ÝÝÛW¶ÎîŠõVXg±>–ÖÙ¸ûgö7ÅÏÛX¾²ïçüA|­ÌŽá/ퟗ>ÓÊïŸñ¼²Î~ë·>Õöö_y~w¶o¯œ93Ý›ms±|+²£üv÷ÏßÏŽ½ŠËwc¶ï—Y¾Oú¶ìÿ~ofŸKûç¢Eœogí쟿ñŸ³ýÇgÚDIù¤VxMDDDD@¤ã©\kxx¸é«`‰ˆˆˆˆˆ´œ¸÷G™û€T§º³™RJ)¥”R*)ÀK¬3ëÍ:³Î¬7±Î¬3- "> ¬3ëÍ:³¬3ëÍ:³ÎDDDDDD@DDDDD@DDDDDDDDDDDDDDDDDDDDDDDD@DZË´iÓFKšËž={ÒwÞ™f̘‘fÏžúûûÓðð°Ó`-]ºtt=øàƒéĉVL‰Äú³Ÿ–ûLóÙÖ|<˜–-[–fΜ™®¹æšôÒK/Y)%·³9sæX1 rìØ±tÏ=÷äÛYT<~÷Ýw­‘+ùÃTšK|`îÞ½;]¼x1ŒŒ¤uëÖå ‘ñs÷Ýw§]»v¥ .äëí™gžI·Þz«Ód^yå•´xñbû©Ï²®äСCiÑ¢EéÍ7ßÌ÷ÏøAå‘G±bJä7ÞHëׯ·"䦛nJO>ùdþ]õÄO¤›o¾ÙŠñ¥-e_ØÓ§O·"J&ZC¤q~ö³Ÿ¥ë®».ÿ•Ð~곬Y½zµ6sË-·¤“'OZ rÕUWù._ÚHüj¨¤Øž}öÙ¼%Iç«_ýj¾¾ì§Í–Å©0ñ£Àõ×_ŸÿÂ*õëkóæÍiþüùùÁ`Ü¥úôéÓVL‰ï€5kÖXMäsŸû\¾OÆ÷@Ô7¿ùÍü5)‘8oúÆoÌÏk•æ¶³¨y󿥣GZ! ràÀtûí·ÛO[Ì‘#GÒŠ+Ò£>je4Ø/zè¡tþüùü´Ò‡~8=ðÀVL“¹í¶ÛòÓØ¤qŽ?ž.\8ú]µˆˆ”È[o½•Ÿ‰Ò|âW¯§Ÿ~z̵ÔN¬£"Ôì§åsöìÙ4kÖ,+¢N¢3pÀ£’€ˆÓbšËàà _ðK$.t- Å> Î i2;vìH×^{mzçw¬Œ£ßLsû¥«:H·WX«H D'.±oß>+¢Ï}ß""MäùçŸÏ/S©É½ùÄùÑ•K-Æa\-fÉ’%VŒý´ã‰Õ•V£8Ýã¾ûîs~~ƒDô8í*§cÅ¥²¥~Þ~ûí Ò|âŠWÑï£ØÄU°D®Ð¿®¶¿Î¬·ú‰£¸üb¬§¹sçºw €ôd[[°`AÞÿ£øë¾ÔNœ ûfœzuÿý÷ë„ÞD¢å(./.Í'~¨ÜG+*ë """"" """"" """""""""""""""""" """"" """"" """""""""""""""""" """"" """""""""ÈL›6-/Ë)" """]?€ù`ã£XÕÃvìØ‘n¿ýö4cÆŒ4sæÌ´lÙ²ôî»ï^6ÞöíÛóñbœâtÞ~ûítçwæ¯OŸ>=Ý|óÍéõ×_¿lYž{î¹ü﮺êª4gΜ´fÍštúôé1ã¼üòËiáÂ…ù²\ýõéÅ_¼l¹?ž|ðÁ4{öì|~1­/}éKéÇ?þ±7\DDDDd² d¼×?ýéOÓÅ‹G‘pË-·\6ÞÒ¥KóñŠyë­·rPZNž<™.\¸~øá|üÀC1O?ýô(l31NŒ[ÉÎ;ó×V¬X‘Ã$*W/,[<ß³gOþüý÷ßÏÁË'" """“ CCC£¯B*­Õã=zô²iÄA +¶˜œ?>íºë®k¸\ÑŠQÉ’%K.[žƒ^¶ü±lQðæŠ€ˆˆˆ|ÐÒèõz}0â¨Z§yU#&€²råÊñz­SÂâ´«f–§Ò§|­[·.8q›-""""2•RAC´œÔK ÅÓ²ZHôY½zuš7oÞÈDDDDDDd $:ŸÇ°7ß|³î2TZJ*‰Ó¹ª§Ûì)XÅDŸ“ýèGù𘇈€ˆˆˆLp®¾úêü=:‰w {÷îͯ~uà 7¤#GŽä¯EçñmÛ¶å ¨$Z'b…è#rï½÷^6Ýb'ô³gÏæuÏ=÷\6ÞÝwßÞxã|:‘¸ W ¿í¶Û¼Ù" """8í).UÛ,,Ê$Á?ÿùÏçý;b¼O\&·xYÜÀIœ†ý?®½öÚ´yóæšÓËð.Z´(oÍÔÄóêñbº<ð@þª\Ò7NÉÒDDDDDDDD@DDDDD@DDDDDDDDDDDDDDDDDDDDDDDD@DDDDD@DDDDDDDDDDDDDdB7ø}H)¥”št% "S """¾›DDć¼ˆˆønò"""¾›DDć¼ˆˆønò"""¾›DD¤cò'OžL÷ßš5kVš>}zZ²dIúÑ~ÔôßO›6­©q¢búsæÌI<ð@zçwº¶^*óoÙŽ;–î¹çž4sæÌ¼âñ»ï¾;îôöìÙ“î¼óÎ4cÆŒ4{öìÔßߟ†‡‡Ç _ºtéèð|08q¢åéÓm´ŽÍ¿ìòEÞ|óÍtÓM7å³hÑ¢ôâ‹/Ö\¿Õëz¼aãýšY6lȷϨõë×—z¯ý}§··fþÏš_¯ö§FïQÙÿo£ñk­Çø6“ZûKÙ÷¥Ñøe??®Äý @@D®$€\sMýª‘G|¡¼ÿþûéâÅ‹iïÞ½éÞ{ïí8@*‰ùlÞ¼9Í›7¯«Mõ–-ž|òÉtáÂ…¼žxâ‰tóÍ7;8Àؽ{w¾~FFFÒºuëò/ùJî¾ûî´k×®|Z1Î3Ï<“n½õÖ–§WÉ+¯¼’/^Üp7šÙåÛ·o_Z°`AÌŸVyä‘Rïy³ã5Z[·nÍ·ÑS§Nå˜ñZ³ójöïÛÜJ¯›Nm׽؟šÝ^Ëþß›ÿ7Þh Žãí/^®²ŸWâþ  "R÷È)~E­—ãǧÏ}îsù/}1îŠ+FQköWÅZÃ^xá…tß}÷y-2æÎ›ÿz¿êþìg?3ü±ÇË _öž{î¹–¿°¯ºêªË^‹y6›øro´ÞÚ^ü߯»îºü—ÕVjÍ¿Þðx¿·mÛÖöc+Ë]½.â`§rà‰ÇqÙ켚ýûn¤™×mû“aj´ýw ·ÜrKÞR[/õö—N/WÙÏ+q©{ä_>úhúéOZsø7Þ˜~üãç_dñk_´¬^½ºÔ—b­qâ—Û8ð©äßøFÞò¿ªÅ|zè¡1¿>þøã9~bøùóçóåhõ ;âWËø?E}ó›ßÌ_k6q:E­_€+_øÏ>ûlþKd³ë¨Öô¾úÕ¯æÓ©õ÷õ¦Wkþe†Gâ}‰u<LÕë"àË\\þx­Ùy5û÷ FÛþdÙŸmÿÝHÌkÍš5 ÿ®ÑþЊñ믿>ß÷ëM¯Ñøe??®Äý @@D¤î‘S´fÄüüùóG)­×? ¾pŠ:­$RüeîšlùŠŠªâyßq Cœ{݉œhÕY¸páhËM ñÿ‹ÿgñîzW±yþùçóºêSA*‰SØ*—ጃ•èü[üR®^ŽFÓkôÿ¨~Þhþ†W'ú┼·ß~;ÞÍ«ö4Z•«îÄûÞÎU{ý}7¨£Blk±qšcq¼FÛþDïOÍn¯Hl{ã], ™SšŠ‰ÿw¥…$ÖG|æû•”¿ìçÇ•¸?ˆˆ€Ô=rŠNŠñ…¿ÒFSzt\-ž;Ããºõ1<~U‹/¸â—S\ÒµrŠG½/ÎJhâ¬ÖiqÐçSǼâR—¯¿þú˜áqv€§ÑU{ý•kåGÅãF}"êM3~qŒå­üÿjÝ'¡ÌôʤÑü o»ˆ¿‰÷"Þÿ—_~¹ôò—¹GL½i˜š¹oÁxËQïï{ØÖãµ²ªÇk´íO¶ý©º´“÷ÙˆÄm\:º)nÿÑòÿï¸Dm«ã—ýü¸÷'¹’"""â»I@D|È‹ˆˆï&ñ!/""â»I@D|È‹ˆˆï&ñ!/""â»I@ć¼ˆˆˆï&éɇ¼RJ)5ÙJ@DDDDDDºÿ,RjLIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_weak_get_line_narrow.png000066400000000000000000000514501174000617100255670ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔRïIDATxÚí}lUežÇ'Ùl6›Íf³ÿl6›Íf³Éf³Ùl6›ýg³Ùlˆ´KC`i`Z¥­ Xú‚X‹8õ”)Ú¬vŠbQQ„aª JEE„EDPl‡©¶ÓÒ:Ej±¿½ßgr:çÞÞ÷{ÛÞ—Ï7ù¦÷œçô<÷{Ï}ù>¿ç÷üÎ÷ ¤ßã%À``°0XƒÀdãþáì{ßûÞÿñÿ1÷¾ |úĉÀ?ýÓ?õñþûïµ Øýѵ¿óÎ;Aíï½÷^Ðÿÿó?ÿsν^z yäûßÿý_ûó?ÿsûã?þcG=þïÿþo[¸p¡mß¾%,²¡?ê‘ÌÁd›•l4XË—/êcÓ¦MAí2þöÕ«Wµ?ùä“Aí5559õzíÞ½Ûþò/ÿ2ìûm¢®O6¾WÀ`Ðx¸¸ªª* V‚8xð`P7ÞxcP{IIIPû´iÓ‚Úu¼¿}ÿþý9ózíØ±#è|ý×m[¶l±¡¡!×><<ì̾¢[ÿùŸÿ‰Áƒ@öâ»ï¾³¿ú«¿ûñù‹¿ø‹ @~´=ÿìÏþlìuùÛ¿ýÛ vïµþ“?ù÷WSc###cíþ©Ú?ýÓ?uç˃õÕW_¹)@ï\zΟ?Ÿ3Æ  Šø|–.]´½oß¾¨?VñLïœ>}Ún»í6ûû¿ÿ{g,d*þîïþÎí;uêTÜ?Š=ô3}:‡"^tçòåËî\^>Ï¿ýÛ¿Ù¶mÛþ¡íêê²üàö_ÿõ_ÎÜè\2œŠ*½ýöÛq¿¦¡Q*™ AS®Þ>åy÷ìÙãÚ¿þúë ÿÓyB!S¢ˆ£r³¼ç¨×dÁ‚§tC§%•¦ÿÕëTWWgÝÝÝ “ööö1“(®_¿>êk¢©Pÿ¹î»ï¾¤Þ¯‰èOæ½ À`Ü|óÍc?4ú±úæ›oÜ_¿HåGK9Eþ¤îp ÍS × T¸ÿ•yÐl¸¶çŸ>nÃ Ü ä)•âgŸ}6èÿ45æÄp¯³—g¥çàÿ?½v¡FÉojÂ14§Kð›¹pTTí‹/¾ˆÛ`½ôÒKA×ô‰'žˆùš(yÝ®ãÇ'ü^MT? SMM) àýйýAÓTþ)¬x£A¡Q‘!Esz{{ÇýàÆŠ>hÅ™LIh4Æß&Cåßÿÿñq=gEØü¦RFK¹AÒ­):=·âââ¸_WE„üý¬X±ÂíÿŸÿùŸ ×yÖ¬Ynû_þå_ܶ¢:þÿSdÎÃ|Ô6}útמãâÅ‹ƒÚdÔüÐsüñÇÇ"iÊujllg`ã¹ÆÏ<óLÐ>™ÉxàŸ‰‰N}¦¢C €IE¨Yijjrû•dì߯ˆE2kÞ¼yAÇ(ÜÛo¾Ô¦c£_ÉÏž9móJèGÛ¿_?êñív@Ñ ˆ¦“É¥JF"ïU €”šPš_åÁ_FÀ›òG^”Gó¯ÿú¯1“Ä!R­"%xëXQ‘íSä!ì‡y’ –ÙóWr÷¦²d ¼R‰Â?© §¿0i¬{ðy¯¥’ãõ:ÊpȪvÙ<6y\‘ïx™Ïë­=4‡Oáã…j–éµø¿ÿû?—ÿæéP$Oï1NÃsçÎ¥E"ïU ƒ€Á,  ƒ0X, À``°0Xƒ•/xà‚¶kjjléÒ¥iåDœ3“™oz¹ÆhF/šÑû†þ®b°0XwÜq‡½ùæ›iå矞ösf2óM/×ÍèE3zÿ@ ˜4ƒuòäɼúÐæ›^®1šÑ‹fôæ€Áºxñ¢­X±Â lÞ¼y¶wïÞ±¶iÓ¦c(Z[[­°°Ð±¥¥%f±ŽOµ}ªû› ƒ!„æ ³Ò`]ºtÉJKKíèÑ£6::jýýý¶qãÆ ƒ íííV]]m޵µµn_²Ç§Ú>ÕýÁbˆfô¢½\c –566E¬BË`É|èõ ÇUUUIŸjûT÷Gy hF/šÑË5Æ`YQQ‘íÞ½ÛæÎk3fÌp"ƒ –Ž™>}º•••Y[[[ÐÿkZQ‘/z¬}‘ëøTÛ§º?"XŒÑŒ^4£—kŒÁrjýúõ622bÃÃöaÃ[³fMØc;;;­¾¾Þ𛛣F¸dƉˆùOµ}*ûÓÀch™¹zï§¿l³Í6Ûl³Ív|ÛYi°‘±ò £¥HV$ ¹do"XD°¢½hF/š‰`E€’¶C V4j°Âå(i_"9QþãSmŸêþÈÁ"ÍèE3z¹Æ,—à®iA™,QÓ…k×® J‚ïêêr{zz¬¡¡ÁšššÆ­²ÓêÃp«ìB§ØbŸjûd÷G‹Q šÑ‹fô¢™VX(q}Ö¬YnjpõêÕAIîVQQáŒKqq±Ë¿òG¼Õ†ŠT'*\S´ãSmŸìþ¨ƒ!„RkÒ-Ÿ+ú#‚Å(ÍèE3zÑL äˆÁb^ÍèE3zÑL ƒÅ¨½hF/טkŒ^ Èlƒ!„’ƒ…ÁÂ`¥éMö ŸØ]wXY™ ˜^·¶¶óŒŠÐŒ^4£ÍD°0X¬d¹mÛY[ºtÔΜùýy?ùÄÜöÖ­ç˜×G3zÑŒ^4“ƒ…ÁÂ`%Ãå˯™+2Y••ß2*B3zÑŒ^4ÁÂ`a°’áÍ7¶¿’³G½h?ýé‡öÒK¿´½{ßfÎB!9Xƒ«ª~g§OûܹQ»õÖoí‡?üÂV®ü*Ð××¶`ÁˆÝtÓˆ{\_ÿ•kûÉOÎY[Û)ûùÏÚÁƒoeÅÊæÍ‹È\þ"yæ™ÓVY9¸†ßÙí·ÿÎZ[?̽K– å¼^¢D°Ð‹Áf°1ûö½í¢YŠj)ºuÿý—mùò>«¨øÆJJ¾ ˜²oÛýn¦F¿œ¶pÈaƒ%³qÛmÃöË_^sROžrÛ¹j:¤·¢âš½ûîàØ”÷í·_·-[>"_½hF/ L¢ÁJƒáPK‘,E´ÙÊÔèW>¬êê¡qQÊ> ˜Ž«9©W‘+Ï\å[^!Ñ 4£ƒ²À`½½oŸyí5{§½ÝÞݳÇÞÛ½ÛŽîÚeïïÜiÇwì°_¾ü²xñEûà…ìäsÏÙ©mÛìWÏ>k§ŸyÆÎlÙbþô§öQK‹mn¶3?eÇ[íÈ}OÛ¡ºgmß²m¶ç¶ì•ÛígßÑöÜÔfoÜÚjï,Ùl'ª~l­Xoê¶®{°îüÀ¾\µÊ¾ºçë¹ûnë­«³ß®Xa}Ë—[M]©ª²eËìëÀkò»¥KmèöÛíê¢EöME…]»å^¸Ð¾½ùfY° ªÞ¯êëí××ùóuëìüÆî¹KÓ±Ÿý̽o<˜_62¤¯½vÄví:j/¾x"`Te--Lë'öÈ#íᇿpQD™YE%;¾ÿý¨̬¥t…Ci©ÙÖ­¿²ööwÉ?b°ÀÔ,”k·ÞjßÜv›3.20_/Ybƒç c#ƒÓ_[ë Œ POÀ¬ÈÉu74Øoî»Ï.4üzõjëzè!ë\»Ö¾øáíRÀÌ\\·ÞÎ>ü˜¸ÿ {{åÛçó¶kéÏìù[aO•°'JÚ–Š¶­r¯íXùªýâÁÝöÆ#;íݧ^²Ûž·¶owFïxÀðÉ Éʾ÷óŸÛ»¿ø…3G2Š2ŒÑô~ØÚjŸüä'öÙúõÖxž_ž{@ÓïZ‡ËËm4ðË­×D¯Á@uµ3{—ï¿ß.56Ú§=fgŸzÊLOÒÃD|Ýßxãpà‡þÛ¹ó}Û¾ý7­õÔSgmãÆó¶~ýgöÐCÖÐÐmwßÝc55WlÉ’ßÙ-·\³o¼0£VVö­-ZtÕ–-´;ïü­­Zõeà=òkkl¼dMMlóæs¶eˇ¶mÛ©€É »RôŽ;†sòKsÙ²¯ÇE줷ªj4ðZõÙÍ7^¿«­í¼Î]öÄ»©ì3ÚG/š‰`a°0XwäÍ”Y:s¿RÒ{è3i2o'^xÁ>xj«zô);½úqûøžõöiÍjûâö€©\Xcƒ7Ýf#óKmxþMÖWºÄ.ÝXg§o\c%mÏü­öÜüWì§7½n?¹åˆ=²äûaíǶúžÏmÍš.[·îs{ì±O­¹ùc{úé3öüóØÏ~vÌ~ñ‹wmÿþûãÈÁRΕ¿¶[àãb¯¼ò›±c^}õˆ›¢njúÔÙ¥K¿¶ÒÒï¦uÈî¹ç+Û°á¢;Ïž=‚^4“ƒ…ÁÂ`å_NR¢¹_Ñ̆¢=JüVôçÑG/¸h¢B«V}e+Vô¹h‘¢FŠ)Фh’¢JK—þÎE™mjhø‹>mØð™‹F=ýÄ)ÛñD‡½¾ùöî¦ívê±;ÿÈ틵kí7 Ö{×]6¸l™›Î¼~ãö]I‰›ÖÔtgߊöå~`=dyÄÎmÞlgž~ÚEìdòdödúÈ; o²Tã-ð’ZuõwAæ*Ú{içÎcnºUï•»îú­-\xͽ‡ª«¯ØêÕ¿¶M›Î¹iÙdŒ.Ñ ô¢™`aÎüø†F¿ñ ý+*&#¦HØÚµ_¸|¦M›>q?¸ÊszñÅ_º¼§½{LXbþá7ÞpÓššîüU[››vÔô£¦!5©iIMOjšRÓ•š¶Ôô¥¦15©iMMojšSÓšöÌGƒ•N*úÜs'a¾ï¾ß¸$úÒÒëVQq5ð~é±õë?ó3Îè:Äë!9Xƒ•‡£"ý8¾ÿþиüE9²Qï•c¦Ü3%ä+1_ úJÔW¾÷£,åÁ}òøãnaÂñÀ9ÞÞ»—‘o”‘Úµë}gÜ5¥[W×릪Õ\¶l ðy½l?þ‰›Þ}ýõ·‰n ÍD°@>¬|˜×÷j$<92f®tïÅ矿˜³š£¬‹>êha‚V`**v½´Ô†/¶ßÞy§‹š}¶aƒ[ ª•¢Gþs{ë7ÈU‰@™©^øÀ™«¼ìÌÖM7]wæK&lݺKΔ½òÊû“öVNh& Íä` £¢1“¥•f¥¥£n%ÝÓOŸÍi½‰Nv¼þºÛ¹Ó~µu«ûÉOÜJO•ÊPI åŠ)OLÓ’ÊûjåJë|øa7y¦µÕ~ùÒKväÕWé‡D»4}¸eËûÑ>³•+{Üô¢¦QÕ´ãcwÓš~æsŒ^4Á9f°`¬tæÙ:ä¦%UCµÎ>mj²®5k\~˜’ó¿-+s&Lyb*Ý¡ŸÿèGöñæÍvª­ÍÞßµËïߟ÷×E‰òJ˜Wâ¼èµPB õJ¬W‚½íŸzê#—xOÎß³Ï~èû, ·kyu{ 1X€£À¼Ð¬`2RÊ ûø‰'ìóõëÑ’á’ñú®´Ô123´ ?þ±3l2n2pñ¬ÌÅ…* ¡(«JE¨dÄâÅC®„„JI¨¤„JKhÕìk¯½d®4Õí/M¡Rù`²ø£7ï ÖÅ‹mÅŠVPPø^›g{÷î jommµÂÂBÇ–––qÿ«=Ñã³½?r°ÈcÈ5Í*þª¢¬ªúþ±ÇÜT£¦5õ¨)HEÁ4%y¥¦Æºï½×­¤Ô”¥¦.5…©©Ì|)K¡"¨Z «¢¨*Žª"©*R^þ­+žš¯71çsŒÞ¼3X—.] Œ¸JíèÑ£6::jýýý¶qãÆ±ööÀè´ººÚkkkݾxÛC‘êù2½?"XŒóQ³’éu{&%×+É^ÉöJºWò½î& ºa#7ÝäJT¨žØ¯|Ð%íçSY ÝöG·ÿ‰¦YSJºWTìg?;žQ7_çsŒf"X ¢10Ò Xù!s¡̃WUUÅÝžîóezä`Až*¶ªûbªÌ„ÊM¨ìDÌÛ?••¹™ º*Bænÿ´x±3jš²TMµÆ9Sm1:8Meªì…j)¢¦B±2|*‡¡Úc*«²Š´©L†j‘©@ì…¦&·@å3T›Lc?FÕ8SY Õ*SÙÓ[·ºÚgšV=ùüïoõË4ÜJõß”ã¥UŒ*Š«¼J°×Ô£n³¤ºo*ŒÛÜ|Ö%Ú+!ÿ7ÞâýÉÁÊDƒUTTd»#ϹsçÚŒ3œˆÁÁ?ÜÝ^Ó†ŠlyÐcí‹·=©ž/Óû#‚Å(ÍéY5én`ü½óê«Î¤È¬¸˜¿òŠ 5™™w+¤€É9©˜LÌLЇº‰¹n`0G2I2KŸlÚdçæN&JfJ¦JÑ6%öËlÉtÉ|)ÏLQ6™2™3™4wó•+󀉓™ónb.“7˜†›˜ë|êCýÊ€^xôQûhãvôÇmöú#»íŲ'WŸ°‡W}fµ5¸Uyù°»{îŒððÃîöM*¨ª©JÝjˆ÷4š‰`M¦M›f룷‘‘ŒŽ6ØšÀ—‹¿=Ó§O»=\©œ/“ûÓÀ£5/`ÍK{o<ýMuûÊ•+i=_¦oç›^mwwwç¼Þhf#W¯o4ÍŠˆ}0Œ½Û·Ûå'žp&«7`ú†¦o°®ÎÝ´}xñbû.`ÖFçÏw†m8`ä®V-·Þš•vqÙýöQÍ£v|ùÛwÇvwöŸÜÔa—œ²‡+ÎÚCUçlÃÖòT¿=óÌ.ÿ7ÎÚ'Ÿ\šX½QrÎrýó¬Ïq>|_M´Þ¬4XŠÆÈXyÑR$‹,Fhκ²9Xë,Z Eù”û¦2gZÙynÓ&ù’9»¬;Üsý¶öNë¿}™}½p±]+- ˜³ïÛ7%7ÛoK—Ú¥’»ìôüíý’õövÙãöæ¢{£úY;°ò{ã¡—ìÍÇwÚÛϾâú‰÷žš¹¾Ï1¬¸ ¤íPƒå7ár´/Þöxr¢9_¦÷G„0ãMesöÁæ§í—ëZíØž´ãË·Kµ_ÝòCûø¦ûí³ïßm_Î_fCóËí»y2gåveÁíöÕ-5vyéÝÖu笫á±iM™<™=—ûk¼5XJp×´ L–¨éµk׎[E§Õ…ÑVÙEjbKõ|™Ö,FhFo>hV2ýîÝïÙóÏ}`Oÿäkyè¸=YÔš+ØS·²Ÿ–ì³í¥;mßÍOÛ»·W.öG‹Q šÑ‹æÔr°tOLÝšI·rênh°¯—.uwZ´Èå]ܰÁ•÷xoÏ®1, V>ƒ,!ŒsöÈ##Þ»ñ­ƒÝ]TL¹]¿½ë.»¶p¡+X{¥ºÚ~½zµËõÒíš:¸_&9X, £"ô¢½ù¦YS†••ƒVZ:j·ß~ÕÝwqÏžwmÅŠß¾¿vÓŠq¬Ý»×Ý1@Å`uÏÌÁÊJ»^ZjW+*¬§¾ÞÝKóLk«ýùÏ“¾G&×8ón`°9Xä1 ½hN@osóÇî>ëÖ}ž|Uú€‘Ò ËµrQ•ù{ëêì›[ou·hX¶Ì•«ÐÝTöí÷Åäg@é  ‚Å(ÍèEsúô¶·¿cwßÝc·ßþ;W}>]ýÉL}ð Î\]~ðAg¶®ßt“3_2a—fL¦Lwxk‚¢]äÙa°9XB8¥liùÐÝögíÚ/ì7OX 0MžÙ²Å>ûѬgåJ7½¨iFM7jÚñüc¹iHݪ)/¯E”"¶½"¶÷ßïnë¤Û;a°,FúhF/š3\ïÞ½GlÕª/mÑ¢«ö LÚsS¢¼æe"”@¯ˆ+¡^‰õJ°—©øè©§\â½𳱘l4“¤ûhêÞ™ºý’w¦on»ÍÝžÉÝ#óž{ÜTëT“Å`r°Èc@3zÑœ½O?}Æ.¼fkÖtÙSöœUB%"T*B&cH÷‚,-u¥$TRB¥%Tbâ×^Kÿ”Ù$š$?“o‡„ÁD°é£½hN“^.mhøUT|cÛ¶Ê*‚ªb¨*Šªâ¨*’úmY™}[^ƺ¡w&š$V „æÛÚ~e·ÞúÝÿe{ýõ·3öyê¶?ºýOÔêõj’¨ƒ0XŒ|ÑŒ^4ç¡Þ×_ï°üµÝrË5ÛºõtÞ¯ªË·÷4 ƒE® šÑ‹æ ÔûÜs'­¢âªÝ{o·íÝû6+OÞÓ,@‹‘>šÑ‹æ Ö»ÿa{è¡N[¸pضlù03 ÖT¯"$‚0XB“á‹/ž°Å‹‡¬¾þ+{íµwxMÈÁÂ`a°ù¢Í\c®q:¨‚¤—ìæ›‡í©§Îr‰`a°0Xän Í\c®qºøòËÇmÉ’¯í®»z­½ý]®19XƒÅ¨½hæ£7–ò²”Ÿ¥<-^r°&Ü`¥ÒÞÞÞnÕÕÕ600àX[[ëö%{|ªíSÝ,FhF/š3[¯Vj¥¡Vjå!טVF,™½ ô¸ªª*éãSmŸêþÈÁ"ÍèEsæëU­,ÕÌRí,ÕÐⓃ5!«¨¨È¦OŸneeeÖÖÖ–P{AAŽŽŽmë±öEB¬ãSmŸêþˆ`1 D3zÑœ=zUý]UàU ^Uá¹ÆD°&V__oÍÍÍq·‡‹pÉŒ%óŸjûTö§7€G?jjjœ«÷ÞxúË6Ûl³ÍvflŸ9Ói÷ÝwÅÝ×°½ý<¯OnçÄ*¡¡!—Ìo;,"XŒôÑŒ^4ç‚Þ-[>´… ‡í¡‡:mÿþÃ\c"XSk°Âå(i_"9QþãSmŸêþÈÁ"ÍèEsöêÝ»÷m»÷Þn«¨¸jÏ=w’kLVòhll´®®.÷¸§§Ç¬©©)îvo•]ØUv¡Sl±ŽOµ}²û#‚ÅÈÍèEsîéݺõ´Ýr˵À÷ù¯íõ×;¸ÆD°GGGGÀ©W8cR\\ìò«†‡‡ãnT*R¨p9LÑŽOµ}²û£„æ&_ým»ÿþËvë­ßX[Û¯xM¨ƒ•Y˜1cFN÷G‹‘/šÑ‹æÜÖ»mÛ)«¨øÆ~cûö½Í5&‚rÙ`1¯fô¢½“Ç:lÍš.[¸ðš=ýô®19X€£"4£ÍèM_xá[´èª­Zõ¥íÝ{„kL äšÁ‚B85TAÒµk¿°òòakiùˆ×„,@‹QšÑ‹fô¦‹/½ôK»ýößÙÝw÷X{û;\c"X€,æõÑŒ^4£7=Ѭ·ìG?úÜÊË¿µææ¹Æä`"XŒŠÐŒ^4£7]ܱãxà»þk»óÎßÚž=ïÚ3Ïœ¶ªªßÙM7}gK– Ykë‡9}m¥·²rÐé]ºôjÚõb°9XB˜§ýûÛ¬={Ý-ú6gM–ÌUEÅ5ûàƒoÞO>±€©üΞ~ú, Ábä‹fô¢½éauõ5;s&øwáܹрéø&'õ*rõþûCAze²–-Á`r°ÈÝ@3zÑŒÞôðæ›¿ ûÛðýï›Í›—{”®p¸ñFÃ`"XŒ|ÑŒ^4£7=¼óÎáq,Et–.½–“z—-ûzl:Ô¯·ºú;   BazØÖöQÀLŽ™,/')—s°/ ÒøÙ³—_îÄ`"XŒ|ÑŒ^4£7}|î¹mÅŠoÝ4Yeå·iMøÎT“U[ûÓ[UuÝ^xá3Vr°ÈÝ@3zÑŒ^4S `°ù¢½hF/šóH/ ƒ!„b°,FhF/šÑ‹f"XƒÅ¼>šÑ‹fô¢™, ‹zÑŒ^4sÑ‹Áä`A!„ä`¥‚iÓ¦c(Z[[­°°Ð±¥¥%áötŸ/Óû#‚Å(ÍèE3z¹Æ¬¨ííííV]]m޵µµn_¼íé>_¦÷Gy hF/šÑË5ÎBƒ.âŽ7ÜpCZ –Ì…©=®ªªŠ»=ÝçËôþˆ`1 D3zÑŒ^®q,'?#¬éÓ§Çm°ŠŠŠÜñeeeÖÖÖÔ^PP`££¸‰£k_¼í¡Hõ|™Þ9XBa–OîÝ»×EXúûûÇöõõõ¹}‡Jø|V__oÍÍÍQ#\~ó«=žˆY"çËôþˆ`1 D3zÑŒ^®q–¬Ù³gÛÈÈȸýÚ7gΜ¤Î944ä’¹‰`%ÞŸÞý¨©©qóÒÞOSݾråJZÏ—éÛù¦WÛÝÝÝèÍñíпèͽm½¯Ñ›úö¤,EW"¬xs°b¬p9HÚo{<9Q‰œ/Óû#‚Å(ÍèE3z¹ÆYÁRî”®5-¨ÈŠØÛÛk•••6kÖ¬¸ÎÑØØh]]]îqOO544XSSÓ¸Utš†Œ¶Ê.R{è[ªçË´þÈÁ‚Bs0+R’ûÁƒã:GGG‡UTT¸ÿ)..vùWÃÃÃAǨöS´:PÑÚÃå0¥r¾Lë£@4£ÍèEsÖÁ’˜yóæÙŒ3õøÌ™3SÕ\Ï)—û£µdÐŒ^4£Í9P p«FEhF/šÑ‹f"X, 9XBav¬ºº:W6 ÙJ@4£ÍèE3,TÔ3SÉVrä`‘Ç€fô¢½h&Ë­j;~ü¸{ìE¬mÕªU¶gÏœ,FEhF/šÑ‹f"XÉ ÷Xõ°â­ƒÈÁ‚BÉÁ 1X*~é•'PM+áØ±cä`ÁbT„fô¢½h&‚• öïßoëÖ­sËË˃r°æÎ‹Ó!‹y}4£ÍèE39X©àúõë®»"WºÑs¸{"XŒŠÐŒ^4£ÍD° B!$ ƒˆ`1 D3zÑŒ^®q֬ݻwÛìÙ³ƒ’ÚKJJìË/¿ÄéƒÅ¼>šÑ‹fô¢™¬d’ÜÃUn?qâ„UWWãtˆ`1*B3zÑŒ^4ÁJJjòÉ']Ý+¿Á²™3gâtÈÁ‚BÉÁJ~SZ÷Š:XD°¡½hF/š‰`%ÝoðÚµkã U¿»4 ‹y}4£ÍèE39X BÉì‹/¶¾¾>g°T ëüùóÎxUTTàtˆ`1*B3zÑŒ^4ÁJ—.] ªÞî§w @„BHV&K‘,Ý‹P¤D,FEhF/šÑ‹f"XƒÅ¼>zÑÌ5F/šÑ›™«ÓÚÚZ7½èG¸éÇP´¶¶Zaa¡cKKKÌ~bŸjûT÷G‹Q šÑ‹fôr³Ø`iJ0]8pà€UUU…5XÑÐÞÞ*çK”IÓ¾dOµ}ªû# B!Ìrƒ5oÞÕö©î£@4£Íèåç@’{$Æ2d®ºººâžÔ”¤’½‰`…7Vý¨©©q®Þ{ãé/Ûl³Í6Ûl³ßvV–iˆ‹×`…ËQÒ¾Dr¢üǧÚ>ÕýÁbˆfô¢½\cê`ÅœRkll‹põôôXCCƒ555[e§û†[ez¾XǧÚ>Ùý‘ƒEšÑ‹fô¢9Çr°FFFlîܹ)å`Å2XÚ_\\ìò¯†‡‡ƒŽQm¨Hu¢ÂEâŸjûd÷G‹Q šÑ‹fô¢9Ç"Xº-ŽßP%“ƒ5ÑHg­®Lì:XBaŽÕÁ’‘:tè÷¦É0Ábˆfô¢½\ã,6X™¥ä`‘Ç€fô¢½hΙ,UrOµÈ( ‚Å(ÍèE3zÑLˇcÇŽYyy¹[áòË`A!„ä`¥Ñ`E«ÞžŽU„€£@4£ÍèEsÞE°¢UoÏÄU„,r°Ð‹fô¢™kŒÞ¬š"D°¡½hF/š‰`a°0XB!Ìü:XÉ´"XŒŠÐŒ^4£ÍD°4Qƒƒƒ,r°˜×G3zÑŒ^4“ƒ•î•„8"XŒŠÐŒ^4£ÍD°]Iî„¢nJ¼cÇœ9XB!9X‰‚R D°¡½hF/š‰`¥É`Íž=ÛÖ¬YcÝÝݸr°˜×G3zÑŒ^4“ƒ•ƒµdÉ—c¥)BE±.\h'Nœ°k×®ánˆ`1*B3zÑŒ^4ÁJ===¶eË+..Kn×  [[[­··§C„BHV*PôêôéÓîæÏŠjÉlÍœ9Óªªªp·ïСC ëÀ.!>Ô`µ··»ó 8Ê„i_¼í¡Hõ|™Þ9Xä1 ½hF/×8Ë – ŽŽŒŒŒÛ¯}sæÌ‰û_¦õG„B˜c9X“a°Õ~ŠV*Z{ºÏ—iýÁbˆfô¢½hα–V ê^ƒ™\É]Ó–¹Ü9Xä1 ½hF/šs,«¤¤$ÈPù™L%w=‹QšÑ‹fô¢™Ö,©D+¶ƒÜ0XB!9Xd°ˆRÁbT„fô¢½h&‚•fƒ¥’ ZÙòÏ`1¯fô¢½h&k‚ Ö±cǬ¼¼<èfÏ€£"4£ÍèE3¬K*Db¦¬"Ä`‘ƒ!„f]’{$’ŸE‹QšÑ‹fô¢™À`1¯^®1šÑ‹fôb°,FhF/šÑ‹æœŒ`>}ÚæÏŸï¦E=Ö>@„BHV8~üxÄ$wL,FEhF/šÑ‹f"XI@Ѫºº:ëëëÛ§ÇË—/w5²9XÌ룽hF/šÉÁJšÔ ŸCqýúõŒ¸é1‹zÑŒ^4sÑ›•kxxxÜ~™. 9XB!9XI ¤¤Äªªª¬··×FGGõxÉ’%núÁbT„fô¢½h&‚•Ä ÂHIîçÎÃéƒÅ¼>šÑ‹fô¢™¬d #¥h•¦E=Æ\ÁbT„fô¢½h&‚0XB!Ä`"XŒÑŒ^4£Í9Á:|ø°­]»vÜþuëÖÙ‘#Gp:ä`1¯fô¢½h&+QÌž=ÛÇí×¾¹sçÆuŽ'NXmm­Ëßš9s¦3lZ‰è!\}(Z[[­°°Ð±¥¥%fŸ±ŽOµ}ªû#‚Å(ÍèE3z¹ÆYl°Â™7ÜpC\çP%øcÇŽ¹â¤*óðòË/»2ñô!´··[uuµ 8ʬi_²Ç§Ú>Õý‘ƒ!„f¹ÁRDÅ›Š@)•,üEJc,™9Vz¬Ú\ÉŸjûT÷G‹Q šÑ‹fôr³Ü`é‡[‘ªÎÎαB£—.]r¦(– ýÿŽ;låÊ•A«¨¨ÈU/++³¶¶¶ ÿ)((pÿç?‡öEB¬ãSmŸêþÈÁ"ÍèE3z¹ÆYn°”k©ÐèÐÐPÂÓâœ9s¬««+ì12rõõõÖÜÜ5Â%3–È´¦ÿøTÛ§²?½<úQSSãÞtž³×ßT·»»»Óz¾LßÎ7½ÚþôÓOÑ›ãÛÑ›»Ûz_£7õí))Ó é@Ý2Ç+4ZZZjýýýIKÑ™íÛ·[eeeÄcdÜ45I‹,!„:X ZD(Ô`…ËQÒ¾Dr¢üǧÚ>Õý‘ƒEšÑ‹fôr1XÖÔÔd—/_3O*Cà7cS†===ÖÐÐàþ't•¢fáVÙ…N±Å:>ÕöÉî,òÐŒ^4£Í9–ƒ%ìÞ½ÛÕÃò—eДá—_~×ÿwttXEE…3&³fÍrEJýSŒþöââb—5<<t™²Hu¢Âå0E;>ÕöÉî£@4£ÍèEsŽE°öïß?–œî7X*kk²à/ù‹ý‘ƒ!„æX–"JO>ù¤K¼ö,Mõ¥R d¾ÁbT„fô¢½h&‚5AËoªB+·Ç[Éd§Áb^ÍèE3zÑLÖ,­ö»víÚ8C¥ªX¥,FEhF/šÑ‹f"Xa döÅ‹»ÛåÈ`é~‚çÏŸwÆK‰é€,!„¬áÝ'URÁbT„fô¢½h&‚•¤ÉòWrO¤D ‹<4£ÍèE39XƒÅ¨ÍèE3zÑL ƒ…Á" B!Ì*ƒÕÝÝí¦%¸Ï™3Çå_ÍŸ?—C‹QšÑ‹fô¢™V2X²d‰]¼xÑ=^½zuP’ûòåËq:ä`1¯fô¢½h&+Q¨Ö•w_À¹sç:cuöìY»pá•܉`1*B3zÑŒ^4ÁJþ«ö•¶GFFÜ6•ÜÉÁ‚BÉÁJ……….bÕÙÙéÌUQQ‘Û¯¨–Ú,FEhF/šÑ‹f"X B?Üþ¼«+V¸ýšU…w@óúhF/šÑ‹fr°’@qq±›œ7oÞØ¾ÒÒR·ÂÁbT„fô¢½h&‚0XB!œƒ5{öl[³f Q*"XŒŠÐŒ^4£ÍD°Òe°TÿJ%”w¥Õƒ .´'Nصk×p7ä`1¯fô¢½h&+ôôôØ–-[\–—è®\¬ÖÖVëííÅéÁbT„fô¢½h&‚• ½:}ú´•——ÕÄR±Ñªªª¨ÿ§ÈWmm­Í˜1ÿvíÚqæL†MeÄ–––qçˆÕžèñÙÞ9XBaŽ&¹+?kݺu®Â{4ÔÕÕÙ±cÇܽ GGGíå—_vSÚÛÛ­ººÚeÆ´/ÞöP¤z¾Lï£@4£Íè峊0,Íò s¡̃û£b±ÚC‘êù2½?r°Èc@3zÑŒ^®q–,ÝÇ»a(“¹UŽ"X;vì°•+WŽíS2½öûѾxÛC‘êù2½?"XŒÑŒ^4£—kœå«¤¤$ÈPù©<¬DàgΜ9ÖÕÕ´?þsÇj×O*çËôþÈÁ‚B³Ü`ÉH:t(mSƒŠÎlß¾Ý*++‰`%ÑŸÞý¨©©qaSÏÙëoªÛʱKçù2};ßôjûÓO?EoŽo{Doînë}ÞÔ·'Ý`%¥Jæ¼ár´/Þöxr¢9_¦÷Gy hF/šÑË5Îò–j^ie[*hjj²Ë—/»ÇCCC® ß@x«èúûû£®²‹Ô:Å–êù2­?r°Èc@3zÑŒ^4çX–Ê+¨î•~ü“EGG‡UTT8c2kÖ,WÚ!ô|2]Ñê@Ek—ÔÊù2­?r° „ÂËÁ ·z0•U„]ò!û#‚Å(ÍèE3zÑœc¬Ð•ƒ©¬"Ùe°˜×G3zÑŒ^4“ƒ•e…F,FhF/šÑ‹æ¼`ü5XB!9Xh°tƒçùóç»)AQµÁbT„fô¢½h&‚•Ž?1É“EóúhF/šÑ‹fr°’€¢UuuuÖ××7¶O—/_îjd"XŒŠÐŒ^4£ÍD°„¦uÃçP\¿~=#Ê`°ÈÁ‚B³Ò` Û/Ó…Á"‚ŨÍèE3zÑL+ ”””XUU•õööº›‹z¼dÉ7}ÈÁb^ÍèE3zÑLV+#%¹Ÿ;w§C‹QšÑ‹fô¢™V2‘R´JS‚¢c®ÈÁ‚BÉÁ,FEèåsÑ‹fôb°9Xä1 ½hF/šs&KùUº™³÷8½c,FEhF/šÑ‹f"X1 ã¤ò ÞãHôŽä`A!„ä` £"F¾\c4£ÍèÅ`r°Èc@3zÑŒ^4çL¬hyVä`ÁbT„fô¢½h&‚•Fƒ588ˆÁ" B!$+Ñ•„±XPP€Ó!‚ŨÍèE3zÑL+‘È•è•ceaa¡íر#®s8q–/_îªÀÏœ9ÓÖ­[gýýýQÍ\(Z[[]ŸbKKKÌ>cŸjûT÷Gy hF/šÑË5Îâ)Ât”bX¹r¥?~ÜÝ(zxxØ6mÚä —ß`EC{{»UWWÛÀÀ€cmm­Û—ìñ©¶OuD°¢½hF/טU„ã £å7n± –̇^Pz\UU•ôñ©¶Ouä`A!„Yn°>lk×®·_Ó|GŽIêœGÁ***r¦«¬¬ÌÚÚÚ‚ŽW®—L™ß EËÿŠu|ªíSÝ,FhF/šÑË5Îrƒ5{öl·b0Ü*¹sç&|¾‹/ÚÂ… ­»»;l{gg§Õ××[sssÔW´©ËXǧÚ>Õý‘ƒEšÑ‹fôr³Ü`E›¾K´LéS§lÁ‚váÂ…¨Ç ¹do"Xá•G?jjjÜ›Îsöú›ê¶Lp:Ï—éÛù¦WÛŸ~ú)zs|Û#zsw[ïkô¦¾=éKF§¯¯oÜþÞÞ^·"0^tttØüùóíüùó1 5Xár”´/‘œ(ÿñ©¶Ouä`A!„YÁÒ·"UšºSdE¼té’‹lÅJÄö°k×.›7ožû¿phll´®®.÷¸§§Ç¬©©iÜ*;•v·Ê.4ÊëøTÛ'»?r°Èc@3zÑŒ^4çX–r­"U¤)•¢¥þèVEE…ÛW\\ìò¯TÎÁÕ†ŠT'*Ü4f´ãSmŸìþÈÁ"ÍèE3zÑœc9XÞt`II‰+*––– jè9årD°¢½hF/š©ƒrÄ`A!„ä`a°0XŒŠÐ‹fôr¹Æè̓UWWçÊ„æP%Z¦d—Áb^ÍèE3zÑLÖ,ýôÌT¨ÁJÇ} ,FhF/šÑ‹æ¼‹`iU›nÔì/,ª•…«V­²={öàtÈÁ‚BÉÁJþ’þǪ‡5kÖ,œ,FEhF/šÑ‹f"XÉ,¿ôʨf•pìØ1r°ÈÁb^ÍèE3zÑLV2Ø¿¿­[·Î=.//ÊÁJæfÏ€£@4£ÍèE3«}¸~ýº«´®ÈÕœ9sldd§C„BHÀ`1*B/×ÍèE3z1X€,òÐŒ^4£͹•ƒÕÝÝíîCèMjjPùWóçÏÇåÁbT„fô¢½h&‚• –,Yb/^tW¯^”ä¾|ùrœ9XB!9X‰B·ÈvµjPÆêìÙ³vá›9s&N‡£"4£ÍèE3¬dê`yЭq´í­¤9XÌ룽hF/šÉÁJºUŽ"VÎ\¹ýŠj© ÁbT„fô¢½h&‚• ôÃíÏ»Z±b…Û/¹xñbœ9XB!9XÉÀ+.:oÞ¼±}¥¥¥n…! ‚ŨÍèE3zÑL `°˜×G/×ÍèE3z1X€£@4£ÍèEsNE°´bÐ+ÏÊxWž8qÂÕÌš1c†+í ›G÷÷÷ÓÚÚê’æÅ–––qçˆÕžèñÙÞ9XBa,Uq÷*?U¶!¬\¹ÒŽ?n£££nõá¦M›‚Š”¶··[uuµ 8ÖÖÖº}ñ¶‡"ÕóezD°¢½hF/×8Ë –ŒÔ¡C‡Ò:½%£å7g2zÁ<èqUUUÜí¡Hõ|™Þ9Xä1 ½hF/×8Ë V¼QªDpôèÑ –ªÅËtù ˜öÅÛŠTÏ—éýÁbˆfô¢½\ã,7X*Í i«tA÷5\¸paP‰µøpÆ.V{(R=_&÷§7€G?jjjœ«÷ÞxúË6Ûl³Í6ÛlÇ·=éëØ±cV^^>.)=œ:uÊ,Xàîc˜Î,"XèE3zÑÌ5FoVE°Â­Lt¡ÐÑÑaóçÏ·óçÏǕä}ñ¶§û|™Þ9Xä1 ½hF/×8’Ü#1Þü¬]»v¹©ÆK—.E]…§(Y´Uv‘ÚC§ØR=_¦õG‹Q šÑ‹fô¢™JîqGÁüPí§hu ¢µ‡ËaJå|™Öu° „«ƒ• PÓ\î£@4£ÍèEsF°êêê\Òu*9X û óúhF/šÑ‹fr°&È`Õ××™©Pƒ55²,FhF/šÑ‹æœ`)'H·¹ñÞ…ÁÁA[µj•íÙ³§“à B!$kË4„{¬ZM³fÍÂéÁbT„fô¢½h&‚•ŒÁò*¹+¹[õ¬¼¤ä`‘ƒÅ¼>šÑ‹fô¢™¬$°ÿ~[·n{¬Šîþ¬¹sçâtˆ`1*B3zÑŒ^4ÁJׯ_·ââb¹š3gŽŒŒàtÈÁ‚BÉÁ,FEè壽hFï,ò¬ÈÁb^ÍèE3zÑLVš V&T-D°¢½hF/šs*‚¥›4 áhÈÁ‚BÉÁJ—Ázï½÷lÑ¢Ec¥,FEhF/šÑ‹f"Xi¨ƒ‰äg‘ƒÅ¼>šÑ‹fô¢™¬$“Ü#‘{ÁbT„fô¢½h&‚0XB!Ä`"XŒÑŒ^4£ÍyU‹,r°˜×G3zÑŒ^4“ƒ•Fƒ588ˆÁ"‚ŨÍèE3zÑL+]«=àtÈÁ‚BÉÁJtõ WŽ!”………¶cÇœ,FEhF/šÑ‹f"X‰"¥üQ¯x£e¡hmmu¦Nlii‰Ùg¬ãSmŸêþÈÁ"ÍèE3z¹Æ¬"3R‰ì÷ÐÞÞnÕÕÕ®š¼X[[ëö%{|ªíSÝ,FhF/šÑË5Æ`¥l°d>ô‚zÐ㪪ª¤Oµ}ªû# B!Ä`Åe°ŠŠŠÜtdYY™µµµµ+™~tttl[£%ØÇ:>Õö©î£@4£Íèåc°âŽT V__oÍÍÍQÿ/ZnX¬ãSmŸÊþôðèGMM›—öÞxú›êö•+WÒz¾LßÎ7½ÚîîîFoŽo‡þEoîmë}ÞÔ·sÞ` CCC.Ù›,FhF/šÑ‹f"Xd°Âå(i_"9QþãSmŸêþÈÁ‚B1X1 Vcc£uuu¹Ç===ÖÐÐ`MMMãVÙõ÷÷‡]ezÞXǧÚ>ÙýÁbˆfô¢½h&‚•p«ŽŽ«¨¨pû‹‹‹]þÕððpÐ1ª ©NT8ãíøTÛ'»?ê`QKÍèE3zÑL¬IÇŒ3rº?"XŒÑŒ^4£ÍD°@Ž,!„, ‹QzÑŒ^®1×½,Ù‹y}4£ÍèE39X, £"ô¢½\c®1z1X€,!„,@‹QšÑ‹fô¢™ ƒÅ¼>zÑÌ5F/šÑ‹ÁD°¢½hF/š‰`r° „Br°‹Qz¹ÆhF/šÑ‹Áä`‘Ç€fô¢½h& ÁbT„fô¢½h&‚0XB!9X, ,ô¢½hæs1X€,òÐŒ^4£Íä`"XŒŠÐŒ^4£ÍD°0X,!„b°,FhF/šÑ‹f"X€,æõÑŒ^4£Íä`M9¦M›6ÆHhmmµÂÂBÇ–––„ÛÓ}¾Lï£@4£ÍèåÁ3ZáÐÞÞnÕÕÕ600àX[[ëöÅÛžîóezä`A!„¬˜KæBŽÔƒWUUÅÝžîóezD°¢½hF/׃Ó`ØèèèØ¶k_¼íé>_¦÷Gy hF/šÑË5Æ`Å4XáöOŸ>=îötŸ/Óû#‚Å(ÍèE3z¹Æ,"XiìOo~ÔÔÔ8Wï½ñô—m¶Ùf›m¶ÙŽo;or°´/ÞötŸ/Óû#‚Å(ÍèE3z¹ÆD°â^EØßßu•]¤öÐó¦z¾Lë,òÐŒ^4£Íä`E­ƒ©–j?E«­=ÝçË´þˆ`1 D3zÑŒ^4Ášt̘1#§û£„BH,#‹QšÑ‹fô¢™ ƒÅ¼>zÑŒ^®1×½,@‹Q šÑ‹fô¢™È+ƒ!„’ƒ…ÁÂ`1*B/šÑË5棃ÈÁ"ÍèE3zÑL ‚ŨÍèE3zÑL ƒ…Á‚B! Ábˆfô¢½h&‚ÈÁb^ÍèE3zÑLÀ`1*B/×ÍèE3z1X€,!„,@‹QšÑ‹fô¢™À`1¯OîzÑŒ^4“ƒ…ÁÂ`ÁB/šÑ‹f®1׃ÈÁ‚BÉÁD°¡½hF/š‰`a°0XÌë£Íè壽,@‹Q šÑ‹fô¢™  B!$+ã1mÚ´q Ekk«:¶´´ÄÕýÁbˆfô¢½\c VÂrÉÞD°Â+~ÔÔÔ¸yiï§¿©n_¹r%­çËôí|Ó«íîînôæøvè_ôæÞ¶Þ×èM};/ V¸%íK$'Ê|ªíSÝ,FhF/šÑË5&‚ÖÕÕå÷ôôXCCƒ555[e×ßßv•]è[¬ãSmŸìþÈÁ‚BÉÁJVQQáŒKqq±Ë¿:Fµ¡"Õ‰ —ÃíøTÛ'»?"XŒÑŒ^4£ÍD°&3fÌÈéþ¨ƒE-4£ÍèE3u°@Ž,FEhF/šÑ‹f"X, sèB! Ábˆfô¢½h&‚òÊ`1¯fô¢½h& ƒ…ÁbT„^4£—kÌ5F/ ƒ!„’ƒˆ`1*B3zÑŒ^4ÁÂ`a°˜×G/š¹ÆèE3z1X€£@4£ÍèE3,@„BHÀ`1*B/×ÍèE3z1X€,òÐŒ^4£Íä`"XŒŠÐŒ^4£ÍD° B!$ ƒ…Á"‚…^4£Í\c®1 ƒEšÑ‹fô¢™,@‹QšÑ‹fô¢™ ƒ!„B  ‚Å(ÍèE3zÑL ƒÅ¼>šÑ‹fô¢™,hmmµÂÂBÇ––"XŒÑŒ^4£ÍD°@*hoo·êêjp¬­­uûÈÁ‚BÉÁIBæJŽÜƒWUUÁbˆfô¢½h&‚’EAAŽŽŽmë±ö‘ƒEšÑ‹fô¢™,$¦M›6nßôéÓ#+~¬X±Âîºë. [²d‰û›êv}}}ZÏ—éÛù¦WÛwÞy'zs|Û#zsw[ïkô¦¾Á"‚€)+Ks°´,$¼U„ýýýq¯" Ä€j_%R+þÜ,!„&N ˜$úfC/šÑ‹fô¢9_ôb°Zô¢™kŒ^4£ƒÙÀ``°0X,"A·íñ˜/8qâ„-_¾Üf̘a3gδuëÖ¹šd¹¬WµÖ<½k×®µÞÞÞ¼¹ÞÒžëïoÿç8Ÿ>Ï/^t· Ó0æÍ›g{÷îÍ«k\TT”Ó×·»»ÛV®\鮯¨Ç—/_Æ`ìûðæ ô!=~ü¸»EÑðð°mÚ´É®\E]];vÌ®_¿î4¿üòËî~\ù€XUUU^¬|Ã¥K—¬´´ÔŽ=êÞ×$mܸ1oô9r$©ŠÙ„ŠŠ Û¶m›ûîÛÚÚlÑ¢E,Àt¶@_Αn¶«P4+×qõêU[°`ñb°r9±Š…Å‹[___Nk¼á†2ê» ƒø‚Nçr+ÔLîØ±ÃEñr›7ovZóáýíMi PVVæFú¹éݽ{·Í;×ýèªVÒàà`Þ|g555å¼Îûî»Ï½—õ½%nݺÕíÃ` V@9 .tsýùpÅ9sæXWWWNk½pá‚UVVæåû»³³Óêëë­¹¹9çßÏëׯ·‘‘7Õ¿aÃ[³fM^\ã;î¸ÃM‘æ:zzz¬¤¤dì»K§2j‡Á¬8qêÔ)7…¤ã|FÛ·o2¹éó›È|{ ¹ûœæ2”ô,cåAF+¦¾Ož<9¥QœÉ„0(‚åÏÁšÊÙ À`ÅŽŽ›?¾?>/¯w®çœ…[q•Oïñ|0XZj°dºrZ´qöìÙ¼ýžšÊï. À`ÅÀ®]»Ü’î|± ÊÕð–6ë‡W+ª««yç”ðíEì4­ÒÐÐó9:Jp×´ L–¨éB• Éeœ>}Ú¬|V *ïÊŸƒÅ*BÕ#ý|Ԝ˺­Órgiœ5kVÎ×ýÊGƒå¿ÆÅÅÅ.ÿÊÝÉUhÊHïiM ®^½:ç“ܵSÉ•| ^ÍBQ§2ƒ€ÁÀ``° ƒ€Á, d0²¥Èl¾Ýê d±‘Â`0X€Á`° sÌI¸ûNzÛº—_ee¥»ßYAA­X±bìÙþã>ìŽÓ1þóè&¼ºOšöOŸ>ÝÝöСCãžËÎ;ÝÿÝpà VTTänÈzÿ¼}ûöYII‰{.eeeöꫯŽ{Þº¡³nl»~ýºmذÁ/säÇöíÛÇŒ›ÌšŽÑ±Þ{ï=·¯¾¾Þ/QCŸ¿ž›¶Oœ8ᶯ]»æ žƒa°>ÿüó±}2Y^”)ô¸®®®qç©Q›?â522âö-X° æóRÊCuuõ¸çsñâÅqÏ_ÏM¼pá d¦Áе?Z”¦èÂMC†š4°U«V9C¥ýá¦,5-Ïóñ"X¢þGS’›6m²ÞÞ^.6,È~ƒå™"E¾¢Á3EþiÃd –r°mΜ9AFMF €Á€¬7XJnWÛÑ£G£>/ÒåAÓ¡çwŠÐå|½óÎ;®]}0X0)˜={¶3 JBO·Áúè£ÜêÁòòrëììtû”œ¾ÿ~g˜<(º¤sÈ )GëÞ{ïw^’ûÐÐãÊ•+ÇWWWgGŽqç´ŠQíwÜq L4-§Rñ§D – dóxÀåWé8:•Qð—MùÒ4¡ò¯æÏŸo»wï{^•i(--uÑ(™6m‡§ó®Y³ÆiòJ>hÊ,0X, À``°0Xƒ€ÁÀ`  ƒ•÷/ä÷¾!„f=+ã ÀoÀ`ñ¦ø-Ã`ñ¦ø-Ã`ñ¦ø-Ã`Þ”ø-¬œSöõõÙêÕ«­°°Ð¦OŸnÕÕÕöÎ;ïÄýÿÓ¦M‹ëQç/**²5kÖØùóç'L“×_¤çÖÝÝm+W®´‚‚G=¾|ùrÄó8q–/_n3f̰™3gÚºu묿¿?¨½¶¶v¬}íÚµÖÛÛ›ôùüÐyc½Æ±úOôù GµŠŠ ÷?¥¥¥öꫯ†}}C_ëHm‘4ÄóZ´¶¶º÷§ØÒҒеŽõÿ‰D_‹tõ7YŸ³X×.Q½±Ž÷:Jg<÷9JôºÄ:>Ñï•|üœa°0Xye°d¨ôÁ¸v횎ŽÚG}d÷Þ{oÚ –õ³{÷n›3g΄~ùG{núBÛ¶m›]¿~ݱ­­Í-Zñ<ú¢<~ü¸{}†‡‡mÓ¦MîËÊC]];vÌKǼüò˶dÉ’¤ÏçáÀVUUó5ŽÕ¢ÏïìÙ³V\\l'OžtÛ2c7nLèšÇ{\¬×¢½½Ý½GõC©}ñöïÿO†ÙšÌ>&ãsïû8QíñäÈ‘¸ s¤ÏQºŸW¢ß+ùø9Ã`a°²Ï`Í›™1 Ñn4ôôôØ}÷ÝçFd:¶¾¾~läïè/\Ûž={¬¡¡!hŸ¾,gÍšåFY}_½z5¨ýÉ'Ÿt#VÀvîÜ™ôÏ 7Ü0nŸúŒú’Šõº¥z>i_°`'óã«ÿhíºÞû÷ïOù0™çúZèKÛûôX?–ñöïÿÇBà·)ð#eVVfvçfï¾›ºÁŠg_¬ÏD&|Îb}.&Ê`-^¼ØEà£!Úç(ÝÏ+Ñï•|üœa°0XÙi°Ùïƒ>ÍÍÍöå—_†m_¸p¡9sÆ} 5*Ó—occcÒ,ÿ[_àžyæ9ÓèGý¬_¿>h4·eËgîÔ>22âžG²_<úbÓèRšÄ­[·º}ñBaýp#uï‹kÇŽnÄïkî|›7ovç ÷ÿÑήÿDÚ]½ÆSñÅúZÈØë9ûŸ¿öÅÛW¼ÿË\Ýq‡>¿ßþä“ßo'b²’1X±>™ò9‹õ¹˜ƒ¥¾šššbþ_¬Ï‘Œ¤ŒFYÀ9ë;!ÚùbŸè÷J>~Î0X¬¼2XŠFé‹jîܹc#Úhù9úàø¿°“5X¡Ñ³yçê7yúaðçW(”®‡t|Q+*WRR2yÓãX#a/^t¦3ÜsñΧi™®®®¸^£pç»pá‚UVVFý¢¤7\ÿñ¶Ç{MãÍýHô‹?Ükî‰DIâýÿhõÌ•™¬ÚÚ‰5X±>™ò9‹çs‘nƒuGÀá^ºt)êÿÅúùÑÙÙ錥›ÉŸè÷J>~Î0X¬Ì7XñN&8e¨pºò±ü_JŠ^)ü«Ñˆ÷÷‡Â“5Xê+Ô¨ÉàyL¦Ÿx¿ V¬XáFšþ\‰H)?N:å¦ôÅÍ€nß¾=è5Lô|úßx Z¢ýÇóü¦bd鵘ŠVèG¦¼|ü1ß~›ØÇ+ƒë3‘)Ÿ³XŸ‹t,M?ÅqNôs444ä´ãEèñ‰~¯äãç ƒ…ÁÊ«V<#^­*Ô† ¿¡?É|(7Äÿ%©~"­¤Kw+ÜÈ*VT£££ÃæÏŸwÂp*çKÇʳXýGkWÎÎdæ†D{-Âåvh_¼}ÅûÿSÁ’±ñÿ(É …F°¢}&2ásÏç"ÝKi Jç<‰|ŽR5X‰~¯äãç ƒ…ÁÊ+ƒ¥¹?ÇJyþ•/J†ÕêA_Ì?üpЇL_0±¦×âYÝôüóÏÛªU«\˜]ÐÈÓŸëåå†è9¤šƒ%}ÒéÏ•ˆ¶Úg×®]î‡)tJƒ¦X½åØúÒU±ÿË%ôyÄ:_,¡Û±úÕ ýxiÊøôéÓn{"W7Åz-¼ÕIºî©¬nŠõÿÑ0Q9XJÒV~Þƒz~šž÷ë31ÕŸ³xßÇé4XzOFZ¤Ï”›ÒíE¸ôzè»ÐŸ×•èñ‰~¯äãç ƒ…ÁÊNƒ•ä*B%;ꃡѴBºJ€õçh¨]õYÔ®Ñ>¨þ™–ü{S ñŒ$eØôCn:A_þÊ[P_Zò|èС vå;ÈÐÅZÝkÔª/I¯&Œ¨Ç±r’¢S#C=_O_¸z@©Œ¬c¬XýÇjô¾ÐÿèZèúïÛ·/áçŸH´hç’!Œ§>O¤çíÿ1YŠdÝxãï#WéXE¨Ï€~€½Ï– Qèq±>™ö9 n§³Î” n•I‡Áò.¹“n•0HöøD¿Wòñs†ÁÂ`eŸÁø-Ã`Þ”ø-,Þ”¿e,Þ”¿e,À›¿eƒÅ›à· ƒ•ÅoJ!„0Û 0X‰ÿ¤%¬ÆÌV‰IEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_weak_get_line_total_narrow.png000066400000000000000000000540271174000617100267750ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔWÞIDATxÚíylçÿ¿RUUUõSÕªªªªªRUUUUUý§ªª E hP1Ä6æ2¾8b˜$ÜÂ8Ž00Ÿ±9Í !&€bÀÁ6`À@üùùóDë®—õÞµ=»ûzKoywf=³¯™Ý÷óÌgžùƒ „B!¿êl„B!B!„ !„Bˆ€…B!„X ¶þþïÿ^þð‡?ôøþá‚ï ÂŽO=úÇüÇ^ë8}út¯ùíííòGôG=ó?ÞkþÉ“'{ýÿ?ýÓ?ÝöÒmðå—_ÊÿüÏÿÈÿûÿOþøÿØXÿ×ý—DGGKnn.%B,„[Ž?ê}…ƒÁ+°RRRz­cÓ¦M½ækp°Ÿ¿xñâ^ó¿ùæ›^ó“’’‚j{É_üÅ_8ý¼ Ôþ ÄÏ*B,„‚@ú#îì.!!€å¥*++{­câĉ½æ‡……õš?lذ^óõõöóËÊÊ‚f{åçç÷ZÞ_ýÕ_ÉöíÛ¥££ÃÌïìì4a_{·þã?þƒ€… ¡ÀÕo¿ý&ù—Ùóãóçþç½~ùÑò~{þÙŸýYÏvù›¿ù›^ómÛúOþäOÌ_=5öúõëžùö§jÿôOÿÔ,/ÖÇÍ)@Û²tݼy3h‚5B,„P/i‰ýÏôéÓ{=?zô¨Ë+ONï\¾|Y&Ož,÷wg‚…†Š¿ýÛ¿5Ó.^¼èñâÒ¥KMèÓeh‡­wçþýûfY¶zžýוœœ¯h›ššdáÂ…òŸÿùŸ&Üè²4pj¯Ò±cÇ<Þ¦Ž½T.TzÊÕ6MëŒl}á'P!DÀBhPåVÖ­[g¦k‘±ýtí±èOÀ7n\¯×h¸Mßÿ}¯yúZWË×âg[8pœgê@´í§ëº'ïYO/ÙOß°aƒÏÛVÃ}!»žþ³õúØzì´çÇ>L½ÿþû=Ïõô½O;644ôÌsÜ&Ž…ó}~a:œ»ÛÇú¾íO3Úzæ<‘}€uöyq×»ä ? !Bƒ*ûtõÕ«WÍtýk?]_ן€e_ÔìØk¡=öóôµ®–oÿ¿®æ¹ú!ïë=Ûö«uœ&_eߥïɾwíÚµkæ5wîÜéu:Ó¾—gþüù½–çø]Ù1Xêé8=l«sö?ú= =º ­ÁòFîz°Ü,_ø X°49x©Eçö²¯kÒßÇ{ý£åM¯…㼫åû{ž»÷Ù9Ž-f€T¯´—mºöXÙ¿¾¦¦Æå¶ô´®Èqhoj‘úzŽce ãžÊvzÔfo.nð…Ÿ€… ¡AÕ¶mÛ¼úÁr,¸öµËñ´Ž»¬œ7=X*ûá/ú8Ôq`R[ ˜»m©ÛÏéÕvöÿ§µežîCÇùZ+f{ü×ý×}^}èLŽW:+ÆwõžúËOÀBˆ€…РJëT¼ Xý©kñg Ö@Έ,•ýš69r¤×k&íkxÇmél gr¼‚Ó&îÀÛ€¥ÃXØ÷lþÛ¿ý›©-óDzaƒýîúؾˆßÝ>ê/? !Bƒ&ýasöãi/ûú g¯qÁÙLŽWêØUz%›Z¯(tuÙþ`,=Ýe JkxlWÚ8Gd÷DŽè:k&í+<8nKÝþRmËÐ+!µÝqt­»²ÿ?sK{ëï< X*ÝOö½Iz5Ÿ³«LIë¶ì—§§¥÷ïßß³M”¡¯÷Ô_~O?«!B>K…´ÿÁÑúgrJA¯.´)55Õ£ú *îÆÁr6ŽÒ`,•^ÚïxÊמû+Õ:,ƒ3Ù_!§¯×Þgòd[:¾OžÁÙkbbbú°T:ø¬«Û¹’öØééÅþÔRõ‡ß›Ï*Bˆ€…Or,¨v¬¯²É~Û)!ûž­£ù—ù·EâÚC¤ci·¾V­=+:M{œ̃°l={ö#¹ÛNei€° á­ìOÅö5 §ýÀ¤îîÁgÛ–Z¯ÛQ‡C»ì³Ï>sZ<®=;¶×k¸Ñ×y²=\Íw¬áÓá=•ŽY¦Ûâÿ÷Mý›C{òô3¦Sƒáõë×ýÂïÍg!DÀB!„"`!„B°B!„ !„Bˆ€…B!DÀB!„"`!„B!B!„ !„Bˆ€…B!„X!„B,„B!B!„"`!çúì³Ïz=OJJ’éÓ§ûÍþ^ž• +¬°Â kð±:þN°P¿ÖŒ3äûï¿÷›ïܹã×åYÙ°Â +¬°+ Y2`]¸p!dlXa…VXƒ•€…,°0Æã@6 уE+VXa…V¢‹sÿ°Â +¬°Rƒ…X´œ`…VXa¥‹€…¨ÁÂcŒ Xˆ,ZN°Â +¬°Òƒ…Xœû‡VXa…•,¢‹V"¬°Â +¬,D ÆcL "`Ñr‚VXa…•,DÀ¢ VXa…VX Xˆ,Z‰°Â +¬°Òƒ…¨ÁÂcŒ©ÁB,ZN°Â +¬°ZÚ2n\Ÿ&`!j°8÷+¬°Â k–3°=X´a…VXa%`!ÆcLÀ"`!z°h% +¬°°Xˆ,ê`…VXauíª*¢‹V"¬°Â +¬þrmy¹´|ü1W"j°0ÆcøøáÃò¤û÷ê—E‹¤º²’q°=X´a…VXaõÅg äELŒÜ^³fPX Xˆ,ê`…VXƒšõbNŽ¼ŠŠ’22•€…èÁ¢•+¬°Â´¬?nÙ"Ýáêü®]ƒÊJÀBÔ`aŒ1Ê+ï®Z%Ï'O–S……ƒ¾þ€XÉÉÉ2lØ0—¯ÑùŽvTff¦Œ5Ê8##Ãëùþ^žÕ×G¬°Â +¬VuME…<˜?_Ú¥®¤dHX:`•——KBB‚GË•Š‹‹%±{'´··khÓižÎ÷÷ò¬¾>j°¨s€VXaµªuª¶¤$yøÉ'&h kÀ¬çÏŸKxx¸Ü¿ß瀥áBÓ«MúXƒ›§óý½<«¯,Z‰°Â +¬Vô©¢"y'÷V¬0§‡’5`ÖæÍ›%??ߣ¥óG-Ç—ˆˆÉÎÎî5äÈ‘ÒÕÕÕó\ë4Oç;Ê×åY}}Ô`aŒ1¶šÏíÞmŠÙ¯wç+¼Ÿ€ X ïq•½%55UÒÓÓ]þ¿†1Oç{ÒcæÍò¬¾>z°h% +¬°ZÉW·m3Ã0\Êζ k@, WMMMý XªŽŽSÌM–÷ëÓŒÍöJJJ2ç°mRýëËóææf¿.ÏÊÏÿ3¯î×`ߟ¶çmmm!ñùåxåxêç÷·l‘×qqòci©¥Ž×€ Xή ô&d9,g5H:ÍÓùžÔDy³<«¯,Zİ +¬Cm½ÕÍýO?•§Ý¿?Ç‹‹-Çã`9†+Çç+W®ìéñzô葤¥¥ÉºuëÞºŠ®µµÕåUv}Íw\Ÿ¯Ë³Úú¨ÁÂcl%×––ʯ³fIËœ9R[VfÉ÷«¶¶VbccÍô±cÇšú«ÎÎÎ^¯Ñ±Ÿ\åj¾³Þ3_–gµõуE‹VXa…Õ*>qè<›>]~^¼Xª½¸R,?hĈ¬/ÀGrg¬Xa…VX]Ÿ—'/'M’[ë×[ž•[å K,Z‰°Â +¬°ÚûrV–¼ŠŒ”+Û·+ Y2`aŒ1Æ6ߨ¸Q:££åìž=óž Xˆ,Z‰°Â +¬Öd­ª’ÆeˤcÊ9yà@@±°5XÔ9À +¬°Z޵¦¼\¥¦Jkr²;z4àX Xˆ,Z‰°Â +¬–b­;|XžÌœ)ÍiiRíá ›éÁB,Œ1ƸŸÞ¿_^ÄÆÊO_|Ð,D-bXa…VK°^øî;錌”kß|ð¬,D 5°Â +¬CÎzMïW²‚•€…èÁ¢E +¬°Â:¤¬wV¯–“'›ÓƒÁÂJÀBÔ`aŒ1k{óÂ…Ò>s¦)l&6¢‹1¬°Â ë ³êÐ :ãyóÌ ÁÆJÀBÔ`QÓ+¬°Â:¨¬:h¨Ú¸|¹L4Y Xˆ,Zİ +¬ƒÆznÏsÛ›_Ô¬,D ÆãAñ•ÌLsÃæKYYAÏJÀBô`Ñ"†VXapÖ[ëÖÉËI“¤~߾د,D 5°Â +¬ÆZ]U%?þ¹<›>]N:d)Æ;/Kbb‡„‡wÉôéÏ%3ó* уE+VXa…ÕÚ¬µeeòëœ9òë¬YR[Zj¹p5uê¹rå÷ß±ë×»dÊ”×~ Y,D Æc¿ûxq±<>]îwÿ^TWVZîý%'¿è W6ݸ!2mÚ ¢‹V"¬°Â «õXÏìÛ'/cb¤aíZËòEFþæô÷m„.¢‹:Xa…Vk±^ÊΖWQQruÛ6Kó¥¤tÒƒ…èÁ¢•+¬°Âj}Öë›6Igw¸:—›ki¶ìì‹2iÒ«î0ÕÕ²4\iM5Xˆ,Œ1ÆÖpU•Ü[±BžÇÅÉ©,û>+*jdéÒÆîpõR¾ûî‚|ûíUIIyiN ΘÑÉU„ˆ,Zİ +¬Ö`­©¨‡Ÿ|"mIIr¬¤Ä²<§eÚ´§2oÞC9zôã`!j°¨s€VXaµ&k]w jOH ˜ eU–oHdä+Ù²åÇAÛ¯,D-bXa…V¯YOÊóØX¹³j•%nØì̇×Éœ9-2sæ)*:5¨û•€…¨ÁÂcì•ÏïÚ%‘‘òã–-–}YY—$:ºSV­º+••Õƒ¾~¢‹1¬°Â «Ç¬?lÝj†a¸˜“cÙBö%Kš$&æ…ìÚu~Èö+ QƒEM¬°Â «G¬?­Y#/bbäLA%ßs~þ™:õ™ÌŸÿà­BöÁÞ¯,D-bXa…V—¬z«›_-’'ññrüða˽תªïeÆ›¦ý›o®Yb¿°5XcŒeܸ>ýè㥦¬Ì‚…ìÇeÖ¬_%!¡]8i™÷ð+99Y† æöu™™™2jÔ(㌌ ¿Ïµõу+¬°Â¤Ë™º§[ñJÁ;/KTT§¬^}Gªªª-µ_:`•——w'Ö·«¸¸X¥½½ÝXC™Nó×üP[5XÔtÀ +¬!°,ô>ËËkº‡~–ØØ²{÷9Kî×€ XÏŸ?—ððp¹ÿ¾Û€¥áAÓ©MúXƒ™¿æ‡ÚúèÁ¢E +¬°°†Êyyõ2eJ‡,XÐ,¥¥µ–ݯ°6oÞ,ùùùæ±»€5räHéêêêy®uš¿æ‡Úú¨ÁÂcÖP²¯_ß QQ¯$#ãËoË€ X ßóÜ]Àr6øðá~›j룋1¬°Â\®--•Ÿ/¶lÀ*.>.))%)©M<û5 –†«¦¦&=Xþ[Ÿ~`l¶WRR’9‡mûê__ž777ûuyV~îø7˜yu¿ûþ´=okk ‰Ï/Çkàóý´{·¼™qð ´Ì+ϦN•ó¹¹–c-/¯•O?½/“'?ïYgn¿Å8XŽáÊñ¹í*¹ÖÖV—WÑõw~°¯,Œ1WWUÉ­õëåUD„ÜþòK3ˆ¨ÕÞãÞ½g%.î¹,Zô‹”•Õäv‰€¥Ò±\óäËü`_=X´ˆa…Öà`=»w¯<íþ¾~œ’"§°«ž\»ö¶)dß¶íj@ï× É}Ĉ¬o€Å8X°Â +¬UÄÞ´t©tFEɵ­[-ÉzèÐ IJj•ääVó8Ð÷+·ÊA– X´ˆa…VXýã+;vÈËI“̽•”X’U{«´×jíÚÓ‹ û•€…,°0ÆûXÄ~è¹`Ç”)r~×.K¾G­¯JKûÅÔ[åå ªíOÀBô`Ñ"†VXƒ‰µªJn~õ•)bÿiõj©®¨°$ëž=ç$6ö¹¹RP¯ ¶ýJÀBÔ`QÓ+¬° k}^ž<‰—Öäd9UXhIV½)óš5?Idd§lß~%h÷+ уE‹VXa pÖÚòri\¾\:##åÇôt˲ê(쉉mfTv=˜÷+ Qƒ…1ÆìËYYò"&FšÓҤ΋"öÁöÖ­?Hdä+Y·îÖ²Sƒ…X´ˆa…VXÝúxq±<œ7OžÇÅÉ…œ˲––ÖÊÂ…dʔٷ¯>dö+ QƒEM¬°ÂH¬UUrãë¯åUd¤ÜYµJjúYÄ>¬¹¹ç%6ö…|þùÏR^^Rû•€…èÁ¢E +¬°ë™ü|iŸ9SÚ’’äôþý–e­¬¬–/¾¸#QQ²sçåܯ,D Æ[Ü5ååroÅ y%×7o6½XV}¯EE'eæÌv™=ûW9|øxÈî3¢‹Ö?¬°ÂjaÖKÙÙòbòdy°`Ô>liÖôôk¦}Æ›UÈN¢‹šXa…5DX9"æÏ7áêâ·ßZšõèÑc2þC™:õ™äçŸa¿°=X´þa…V‹±VU™Ó€z:ðîŠæô •Ywí:/11/dÉ’&©¨¨a¿°5Xcl-Ÿ.(¶ÄDiOH0íV~¯ZȾrå]‰Žî”¬¬Kì?¢‹Ö?¬°Âj-VjA‡\Сt+±»b-,<%ññOdîÜ9r¤ŽýJÀBÔ`Q¿+¬°Z‹õbNŽ<Ÿß±ãû•€…¨ÁâÜ?¬°Â:4¬§ŠŠäqJŠ<íþN<›—7àïçС’}IÖ¯¿%‹ý"3g>éRo̳gÿ*Ë—7Jzú²wïY)/¯õh™ß}÷c÷ÿ¾ê^Žt/ïuwèºÎg˜€…èÁ¢å+¬°>kue¥Ü^³Æ±ßÚ°Aªý\Ä~äÈqÉɹ(_}u³ûû÷¾$&¶ËG½–¨¨NIIy,K—6ÉæÍ×%7÷œ”–c¿Òƒ…XcØ>Ÿ›+ϦN•–¹såÄÁƒ>-«¤¤ÎÜ•°°ßdêÔçæÆÈl+ÔK{°òóóeÞ¼y.ÖèÑ£eøðá!ÙÙÙ½æ9Ò,Ç~™:ÍÓùŽòuyV_=X´a…5XYO:$ã“äJÄù$ñç·†N`¿ÂËVO5fÌijjòè%55UÒÓÓ]öpiót¾'=fÞ,ÏÊëÓŒÍöJJJ2ç°mRýëËóææf¿.ÏÊÏÿ3¯î×`ߟ¶çmmm!ñù ¦ãµ¡ @ž‡O’¼ðÙ–ñXΟçxåxíÿó èÁÊÍÍ•øøxÿ§££ÃsÓƒE­DXa…õûª*¹½jµ<™8YVF]èþM9Ï~…•S„žôð¸ XÎjtš§ó=©‰òfyV_5Xã`qÝ‘#ò0aŽü8q‘,™Ó Gr?Âkݺurÿþýž°¤Ã ØÇS^+W®ì9…øèÑ#IKK3Ëp¼Š®µµÕåUv}Íw\Ÿ¯Ë³ÚúèÁ¢•+¬ÁȪ7i~+E¾“M¯±_a%`ÕÖÖJll¬ ï½÷ž¬ZµÊ„ƒ¾ˆýëÇŽkê¯:;;{½FCš«q \ÍwVÃäËò¬¶>ÆÁb¬Xa 6Öëk6ÈÓ°Ùs\ ΰ_a%`ù:dëóèÁ‚VX‘õXi©4%Í—†°y²nÁsAö+¬ô`!ˈ,Œq ¹>/OÚ"¦Jé„m²cÛ%¶ ¦ …^À¢å+¬°úuTöõßÈÓcd{\¹ûìWYæ”àÞ餤„±­pÖ`ip²w_Ë›ÁB=X´œ`…VG×TTÈÕ”/¤ùÃÙµ¢†ý kèÔ`•””ô jiÓãÇÍ´ªª*’ ‹sÿ°Â kÿ†`((–Ÿ#fIýG«¥pwûÖЪÁzÿý÷åõë×oM×izÓfDÀ¢å+¬°z®6äÊ“cåpB®”•Õ°_a ½,=ØWÀ¢‹€…1Æ^¹¢RêS¾––§KÑš£lºã`=ZÌiÁ®®.ã––‰7·½A,ZN°Â «'®Ì/•Ûóåjøb9º¯Šý +5X}¹WVV’\Xœû‡VXݺ|}‘´Ž“ê¤L©¬`¿ÂJ –‘&ÅqãÆ™{ê©õñ•+WH-,ZN°Â «ë^«î0UÓª4\•u‡,ö+¬ô`!Æûà’¼*¹úÑçÒþ‰T”²M05Xˆ€EË VXaõÅZÀÞ2~š)h¯®ªb¿ÂJ–³«?øàFr'`qîVXaukráHÂnik†b`¿ÂJ V ë¨ìÍHî,ZN°Â «Íö—³}!M³åØþÃìWXéÁr% RŒØNÀÂcWÖÛÜèín®ÎZ-ÕlL –;ÑKEÀ¢å+¬°öYÈ^R'y3˜5ë ›Ù¯°Òƒå¡tH†ööv ‹sÿ°Â k/ïÉ®—c¿’G‘ r2¿ý +5XÞèÌ™3Õëfψ€EË VXC—µªªZ2×Kㇳ¤!e±Ô”•±_a¥Ë[õ5Š;W°0Æ¡çƒOÈö¸rsJðʆ­lL –/Eî}™ú,-'Xa ÖÛ.IÙÄmÒ1UÎìÍc¿ÂJBÔ`Á +¬ýe-/¯‘õ ¯JCØtè„|’ø³\\"ã“äDq1ÛSƒ5Ð+,,L¤¥¥EºººŒõñ´iÓÌéCDÀ¢å+¬á;/Krò ï’™3;eÇŽkݾ"Ÿ†_“öð)roé2©®¬d¿ÂJÖ`,-dï«Èýúõë-ãܹsÝu²éñz÷Ýweùòå&¤¹Rff¦Œ5Ê8##ÃïóCm}Ô`Á kh³ŠÖÌöá—Ñreûvö+¬Ô` ö0 ¤´·J’Z{®TZ$¯÷4Ôº-íËËË3=`}©¸¸XÍM¦ÕÎtš¿æ‡ÚúèÁ¢•+¬Ò×EIÝÓO8À~…•¬`hÔUý–†Ýx6éc=Mé¯ù¡¶>j°0Æ®Ûã XÚƒ•ŸŸ/óæÍëó5#GŽ4¯³ÿæ¯ù¡¶>z°h% k¨,>ðZ6`ÕÔÔ˜š)G­ZµJêêê¼Z–­vk̘1ÒÔÔäòuήfô×üPZŸ~`l¶WRR’9‡mûê__ž777ûuyV~îø7˜yu¿ûþ´=okk Z¾ââ.Ç+Ç+ÇëÁXï¿ÿ¾èWVnn®ÄÇÇÓƒE-'Xa@ëØV_~y[¦F¶ÑƒÅgV«õ`9ë-±éwÞñi|-oj”tš¿æ‡Úú¨ÁÂ8ô\\|\RRZeiüòtòT—W²½0‚€¥ÃØß&Ç&fA‡\ðDëÖ­“û÷ï›ÇfXû@àâlWɵ¶¶º¼Š®¿óƒ}}ô`ÑJ„5´Y³².KTT§ìK;*‘‘r}ófö+¬°Z-`é±öT566ö 4z÷î]Ü]¹fSmm­ÄÆÆšÿyï½÷Lý–†W½dÂ\óäËü`_ã`1Ö ¬¡ÉZQQ-K—6JLÌ 9¿8]:££å|n.ûVX­°´Öª¯Fµ7j ‡lì!"‚a}ô`ÑJ„5ôX Ou×OeÁÇ÷åçOÒäi÷1~âÐ!ö+¬°Zy˜=¨·Ì± 4:a„^=PÈú¢ ãàuzú5‰Œ|%;¾<#OâãåÁüùRS^ζÁ8Eô`Ñr‚Vß\ZZ+ <©SŸÉ÷[‹äet´4¬]Ë~…V –€Å¹Xa\ïÝ{VbcŸwÛ?Ë›ÒåUT”\ÊÊb¿Â k ¬¢¢"3–ý° zÊðÁƒ$-'Xaä±­Ö­k¨¨W²cÛ%iZ²D:ââäta!ûVX)`•••õµÛ¬sçι{ Qƒ…1öŸ9.³g?îþîm“£û*¥5%E~3GŽ•–²}0´€5vìXùæ›oÌð öK¯ ôt,D-'XaõÍÙÙ—$:ºS¾øâŽœÞW /&O–{+VÈ÷UUìWXa Ä€eªGn÷e$wD çþa…Õ½++«eÙ²{2iÒKÙµë‚\ÉÌ”W‘‘òCFûVX9`é-m^¾|ùV ÒaÜÝÿуEË VXûïNI|üùøãGRr¤Vî¬^-/cb¤>/ý +¬°´˜}Ê”)æv9°Þ¼y#7oÞ4ÁKGgG,Œ±ÿýÍ7?˜±­6n¼)µeeò(5UÚ¥îða¶ÆÁPƒe»-Ž3ë}ð‹–¬°úÏeeµ’–ÖÜݰí}ûÎÈÉ¢"y6uªÜï>†«++Ù¯°ÂLã`iȲÉ!Xœû‡Vÿ;/¯^ââžË§ŸÞïZ5r1'ÇܬùÆ×_³_a…5ÇÁB,ZN°Â:°c[mØpËŒmµmÛU3íæ† æfÍvíb¿Â k°ö`!Æx Æ¶ª“9s~•™3ÛåàÁ“RSQ!¿,Z$O§M““²0Ö¬ææfsJP¥îcÆŒ1õWãÇ'µ°h9Á «Îɹ(ÑÑ/eåÊ»f8†ãÅÅÒ>s¦<üä©)+c¿Â k0÷`MënEݾ}Û<^¼xq¯"÷””’ ‹sÿ°ÂÚ±­4Ti¸ÊÉùý‡âìž=òrÒ$¹½f ûVXC¡KǺêìì4?øà¬®]»& ŒäNÀ¢å+¬^muÒœœ3§EJJêÌ´ké¿ß¬ùòÎìWXa •, T6éØWúüõë׿9#¹°0Æž;#ãª)dׂv}^]U%Ë–És½Yóþýl#ŒC©kÔ¨Q¦Çª±±Ñ„«Ñ£G›éÚ«¥ó‹–¬°ºÛªF>ýô3ƒÅ ÓŽ=*gÏ6ÖÇìWXa ±,ý!¶¯»šÝýe ÒóŸ:Â;"`qîVXûv~~½4T-/¯5ÓNÈóÉ“¥qùrÓ‹Å~…ÖkìØ±ætà¸qãz¦M˜0Á\aˆX´œ`…Õ¹õ67z»›­[è™vyÇs³ækß|Ã~…VÆÁB,Œ±§Öâõ?n17jÖ6Û¦ÿ´f¹RðìÞ½l'ŒCµëý÷ß—%K–ÐKEÀ¢å+¬^x×® 2iÒKY¾üžŽA§Õ–—ËÃyó¤=!AŽ[àfÍìWXa€¥ã_é Zw¥WFGG˹sçäåË—¤çþa…ÕÁUUÕ²jÕîïÊNùöÛ‹=Óu4v•]Gg¯®¨`¿Â +5X¿ëÑ£G²}ûvS‡e+t×Z¬ÌÌLiii!¹°h9Áò¬ž„„6™5ëW9räøÿ-ó»ï¤3*Jn~õûVXéÁê[Ú{uùòe‰êþ°‰¥ƒ&$$`¨ÁÂ8$½}ûïc[­_ß`nÚl›~cãF錌” 99l'Œ©ÁòNZŸµjÕ*3Â;¢‹–¬¡ÄZ^^#Ÿ~_bcŸËÞ½g{¦ëiÀûŸ~*ÏôfͰ_a…•,DÀâÜ?¬°zâ‚‚32uê3Y¸ð”–ÖöL?~䈴%$È£ÔT©À›5³_a…5j°ô¶8¶{:š[å°h9Áj¬›6Ý0c[¥§_ë5ýl^ž¼Œ‰‘Ÿ¾øB¾‚ÁCÙ¯°Â`+,,¬W ²·Öa!Æ¡à£Gɼyº§RXxª×¼¶n5ƒ‡^Ù¾m…15XžIƒTUwk °h9Áª¬»wŸ—˜˜²ti£TTTÿß¼îïÆ{+VȋɓåLAûVXéÁò\þè¥Òñ³RRRdĈæªC-ŒommíóõÎNG:J‡‰Ð›M«322¼žïïåY}}Ô`Á «÷¬zUàêÕ?ITT§de]ê5ïXi©ü:gŽ<îþn;VRÂ~…Vj°¼“ŽyÕÞÞîÓ2æÍ›'õõõÒÕÕ%²iÓ&¸\,W*..–ÄÄDó¾ÔÉÉÉfš§óý½<«¯,Z‰°zÏzèÐ IJjíþ®zÜ}|ï5ïta¡tÄÅIÓ’%R]YÉ~…Vz°¼×™3g̸W®zœ¼•-W=cî–† ݸ6écû±¸ÜÍ÷÷ò¬¾>j°0îÛ;w^în¤¼ðð®îãè•de]—;®Hdd§|ùåí^c[©/eeÉ«îïÄ·laûaL Vÿåìt¯Wž:uÊmÖèÑ£M‹ˆˆììì^óõ>Òì›Nót¾£|]žÕ×G­DXûWS§¾‘+W~?.nÜÐÛ„‰ÄŽ’={νõú†µkå¥Þ6lÏö+¬°Òƒå{‘{_îO}ÖíÛ·Í} =½‰tcc£¤¦¦JzzºË.û÷ân¾'=fÞ,ÏÊëÓŒÍöJJJ2ç°mRýëËsÝŸþ\ž•Ÿ;þ f^ݯÁÌ—’ò²'\Ù¤!kæÌ×½^©¾^ž-[&ÝÇÍñââ€ççxåx ôçmmm~_~@4zñâE —††¯þ¯££ÃsÓƒE­DXýéÈÈßœ/&tõ¼æÄ¡Cò´ûxi^¸Pj,r³fö+¬°2’{jkkeüøñróæM¯ÿ×1`9«AÒižÎ÷¤&Ê›åY}}Ô`aìÜ Ïäòå®·z°fÌè4óÏïÞ-ÑÑrkýz¶ÆÔ`ù?`é ž5éi(µ>Öižª°°Ð\x÷î]N™­\¹RšššÌãGIZZš¬[·î­«è´ðÞÕUv}Íw\Ÿ¯Ë³ÚúèÁ¢•«{WVV›+£¢ºzBÖï5X¿IfæU¹¾i“¹YóÅo¿e¿Â +=XþX:¼B_E¬¾þ¿¯¢½]±±±fúرcMý•ï`/ûÉÕ8P®æ;«aòeyV[ã`1Ö ¬îGeONnÕqhútÇÔ©rª¨ˆý +¬Œƒ50K{«æÎ+?õ*@í•ò‡tÒÁT°¯,Z‰°öm½ÍM\ÜsY¶ìÞïaÊù€R[ZÊ~…Vz°v$w½á³£Þ¼yc‰à€¬°0ïÚuÁŒoµyóuóÜUÀb{aL Ö€,ÇÓs* ],-'XÅéé?šp•“óL¡°ø à «VXX˜%¼¥¥Å  ÖÇÓ¦M3§‹sÿ°ZÙ:ûŠweòäçRXxº×¼P X|†a…ÕK Ùû*R¿~ý:É…€EË V˺¬¬FæÍ{$IImRRR×kÞ ½ò–,>ðÂ:”Ã4hÒÞ*=%¨ÖÇ„+ÆV¶Þ 9>þ‰¤¥5KEEuï/çï¾3ã[¹ºŠmˆ15X°‹–¬ä}ûê%&楹Y³ã¼†uëL¸º˜“Ã~…VX Xˆ,ê`õÄzçÈÈWf°Pûé:ìÂÃÔTiŸ9ÓÜþ†ý +¬°zÀÒú*½™³íq_¶½°h9Áj¯_K¢£_ÊÞ½g{M?]P qqòs÷qPÝÇýÙ¯°ÂJÖ€, N:<ƒíq_¶½°0Jëmo>ÿü¾L›öT:ÑkÞÕŒ y)×ÒÓÙVcN"z°h%Âê‰õ¶7zOÁ¹s[¤¬¬¶gzue¥4.]*Ïcc¥>?Ÿý +¬°°5XÔ9ÀꉋŠNÊ”)²ti£ïÊ6ýøáÃÒ–”$-sçʱ£GÙ¯°Â «õ–«:+j°X´œ`*ïÞ}^¢¢:eÓ¦½¦ŸßµK^FGËOkÖÈ÷UUìWXa…5°Ö“'OX,Œ‡Ä[·^ëW¯$;ûb¯é·6lÎÈH¹”ÍvÂ[3`¹ºzÐæ‘#G’\X´œ`4ëiÀU«îÈäÉ/dÿþÿ»íMmY™<œ?_žt®O<È~…VX­°lW Ú†cpô¨Q£$??ŸäBÀâÜ?¬ƒâŠŠù䓇’Ð&GŽüßmoNJÇÔ©rÿÓO¥¦!د°Â «åN2‹–¬Cí#GŽËÌ™í²pá´z†`Ø¾Ý Áðã–-ìWXa…•«5X{êüü3óBV¯þéÿ†`¨ª’{Ë—Ë ‚!/í„1¼€USS#Ë»¿ÈµjÕ*©««#¹°h9Á:`ÎʺdŠÙ32~è™Vwø°´&'˯³g˱’ö+¬°Â˜ëý÷ß7W :»Šðƒ> ¹°8÷ë€ø«¯nJtt§ìÙs®gÚ¹Ü\y9i’Üùâ ¯†``¿Â +¬– XZäîíˆ,ZN°öÿJÁjY¼øg™:õ™sæŒÇ5XçΓ””óÿ:ú»Þ(ÚÝ0™™™¦÷L‘‘á÷ù¡¶>j°` V= ¸ti“L™Ò!EE'Mñúîã_ï'¨÷d¿Â +¬![ƒUVVf‘*ª»Åi_ƒåéÍžçÍ›gN3j¯Wgg§lÚ´É®¾T\\,‰‰‰&Ø©“““Í4͵õуE+q(XËÊjeΜ™5ë±”–“c%%òë¬YÒÚýy­;|˜ý +¬°r¡MoÞ¼‘±cÇšž«1cÆÈëׯûµ Z® ä5<èÆ³IÛß–Ç×ù¡¶>j°ð`ûС2}ú3ùüóûRYY-góòÌÀ¡÷V¬0‰²0ÆŒƒ5:uê”Ë,BC˜} Óiþšj룋Vâ`²îÝ{V¢£_ʆ ·Ìó7o–W‘‘r%3“ý +¬°Òƒ5Pº}ûv÷—o´477{TXo“}—¯óCm}Ô`Qç0X¬Û¶]•ÈÈW²sçessæ_>ýTžM*§ Ù¯°Â +5XöÒ ¤÷!´"ÔSƒú?~üx¯—uñâE —††—¯£ËëÓŒÍöJJJ2P[+@ÿúòüÖ­[~]ž•ŸÛ ¼º_=}ýöí­Û)ùùõòCuµt¦¤Hk÷ç®¶¼< xõ».>¿¯¯Áð| Ž×AXÓ¦M3½NªÅ‹÷*rwušÏQzõ¡†²›7oº}­³#æ¯ù¡¶>j°ð@º¢¢ZÒÒš%>þ‰—KÙÙÒ)77l`û`Œ©ÁrÕÛ¢Wþ©ôªA V×®]3½P:ä‚'*,,”qãÆÉÝ»w=:ef»JN‡rpu]çûú¨Á¢Îa°XKJê$)©MRSJyYµü´f¼ŒŽ–ó»w³_a…Vj°<hTë|ô¹íêAOÇÁr¼ÅŽÍ®jŠtl'Wã<ù2?Ø×G uƒÁZX¨·½y.+WÞ•Ú’£Ò2gŽ´%%Éq ÁÀ~…VX-°ô\{¬MP=z´™®½Z:ÏÒHSÁ¾>z°h%4kNΉŒì”ôô¥~ß>y1y²4.]*Õ••ìWXa…•,O¤?Äö½N³gÏ6Ó5=N™2EP`ˆ,ì/oÞ|ÝÜöf×®ór-=Ý ÁpuÛ6¶ Ƙ,oe\Të¨lš0a‚Ë¡Ph,ZNÁϪ·½Y¾¼Qââ:äàþãòs÷gª£»‘uzÿ~ö+¬°ÂJ"`Qƒ«;ë8V‰‰Þ%3gvʶm×åãIrr«T”È“™3åajªÔ––²_a…Vj°‹,X= Wqq¯äòåßÇZ»qCdêT‘O>i“óß~'QQÒ°~=ûVXa¥Ë郶áíéU„ˆ,8-èÃÑÑra×.¶Ƙ,_˜uwû@eow·gAô`Ñr ЀåLÝÓ³_a…Vz°ü°4HUUU‘PXœûVW‹ý +¬°Rƒå§€E/‹–Sè°ê•‚¡°ø à +=Xƒ°th½ "`áàvyy­|üqKÈ,Œ15Xƒ°Îœ9#QQQæ¾wˆ€EË)8Y>Þý™x"ËþDŸaXa¥k0V_÷ä*BçþƒÃg$&æ…d.=muu!ûVXa¥ËEî}™ú,-§ÀvNÎE‰Šz%GVÎÈH¹¾y3ûVXa¥k0"`áàô–-?š{ žû<ÝŒou>7—í‚1¦‹€…èÁ¢•Øß+W­º+Ó'·Ë½?•§ÝŸ…‡±_a…Vz°;`Í;WFŽI ‹sÿÎZQQ#óç?´ø;Ò6}¦<˜?_jÊËÙ¯°Â +5Xƒ°RSS{”cÀ¢‹€EË)p\RrL’’ÚdKÊ)y=IÖ®e¿Â +¬°UÀ5j”Ô××÷¼«ž‹€Å¹ÿ¡±Þ°yå’Ÿ¤.ü+iŸ2CN–æÔùRSVF‹VXa…•a5X¸¿>|¸NVO½(íã¤aõ—lŒ1&`!z°h9ùâýûOKfd™tLœ$—wî¤E +¬°Â¬ã`yZƒe_·Õߺ/GeffʨQ£Œ322¼žïïåY}}Ô`6뮜órdÂvi‹š&§÷罹VXa…5XÖ“'O¼.r÷&`¹Rqq±$&&š+ÕÉÉÉfš§óý½<«¯¬Àn%îøú¼\[,÷ãSåØÑ£´ˆa…VX¹ËÕÕƒ69rH–† ݸ6éã„„çû{yV_5Xëí‹OɃgÊÍE_Hu?nÖŒ1ÆØbËv¥ m8Gë©©üüü X£G6W)FDDHvvv¯ù캺ºzžëcû°çn¾£|]žÕ×GVàµ+*ª%'¹Lž~#7n£E +¬°Âl5XþŠÁÓ€e¯ÆÆFIMM•ôôt—˱Ÿîæ{ò¾¼YžÕ×G V`Õ9=zLÇæHÛ„)rz÷>j:`…VXƒ±ËŸêOÀRé­z´ÇŒ,ï×§›í•””d> ¶V€þõåù­[·üº<+?·y –_[~QÎ~ô…ÜùXî]º<伺_ƒ}Úž777‡Äç—ã5xy9^}{NÀê£I§y:ß“š(o–gõõQƒ>´£Jî}8[~HX)ÕlŒ1f,ß–ãô•+WJSS“yüèÑ#IKK“uëÖ½u]kk«Ë«ìúšï¸>_—gµõQƒxçþ¯>$mããäôçÛ‚ž•úXa…•,?+WãZ9>¯­­•ØØX3}ìØ±¦þª³³³×ktì'Wã@¹šï,èù²<«­¬À:÷_™š#íãc¥zS>5°Â +¬Ô`ùO#FŒ`}Œär-§êŠJ9;e­ü,-•»ÓÈհϤàÛ:¶ ÆSƒ…X´œ|a=µ¿P~ˆ—Šð­r°ð­DXa…Vz°‹sÿ¾°^Ø‘-OÃbdW\±””£ÎVXa…•,DÀ¢åä ëõ/6H[ØIŸ}J**jh% +¬°Òƒ…X¸¿®)/—¦¹ir;,U6-½$UUlŒ1¦ °h9õ›õÄ¡Cò8.AŽ…m­›®ÐJ„VXa¥ °8÷ï ëùÝ»¥#|œm…1ÆÔ`!-'¯–3uOO›Ó(ee5´a…VXéÁB,j°ü°‚ùJAj:`…Vj°Xˆ¬! X´a…VXéÁB,j°XcŒ Xˆ¬¡uue%=X´ˆa…Vz°Xˆ,ùØÑ£ò8)ÙåU„Ô9À +¬°Rƒ…Xô`yèS……ò,vŠ”Gm“… ~‘íÛ¯HBÂ3™0¡Kâã_ÉŽ×h% +¬°Òƒ…XÔ`y|ðîÚ%/£dGx‰¬]{›m‚1ÆÔ`°=X¾øÇôtyþQ´¬ ?/;v\¦•+¬°ÂJ QƒÕoWUÉÝ+äqøt™}[öí;C¬°Â +5X,DV]SV&>ž'·#>‘yñMräH­DXa…Vz°Xˆ¬þúxq±´MOáëå³…MRQQÍvÁcj°Xˆ¬þº~ß>鈊•¼‰{eýúZ‰°Â +¬ô`°5X¾øòÎòâ£hù:ü˜de]¦ÎVXa…•,¢ËßZ¿^žLœ,K'ý gh% +¬°ÒƒEÀBÔ`õ×zÛ›¦OËý’åÓ™·¥¤¤ŽÚŒ1Æ,DV­·½y”8[.}´L–¥ý$••Õ´a…VXa%`!j°úë“EEÒ3MŽNÌ”¯6Ü ÎVXa…ÖÀXÆ ë±§ÊÌÌ”Q£Fgddø}~¨­/”{°ÎïÞ-M’‘ììK´a…VXa ®,OVqq±$&&J{{»qrr²™æ¯ù¡¶¾P®Áúá›­Ò1q’¬>-û÷Ÿ¦ÎcŒqè, šNmÒÇ ~›jë ɬª*iX¾Z~8]V&\“’’c´a…VXa í€5räHéêêêy®uš¿æ‡ÚúB­«¦¢B~ž³@nMøDV§]ïw1;u°Â +¬Ô`UÀröºáÇûm~(­O?06Û+))É|@m­ýëËó[·nùuyý}~¥®NZ¦&ˉ‰$7»y@Ög³xú¹î×`æ³ÞÜÜôûÓjÇë`<çxåxõô9=Xô`Y²Ë >“Ÿ/O"â¤`b®ää\¤¦cŒ1=Xîj”tš¿æ‡ÚúB¡ëâÎoåÙ„ÙU!……§¨s€VXa…•€å8Ýv•\kk«Ë«èú;?Ø×j5X×Ö~-ía“eÃ̳rôè±_u°Â +¬Ô`Yn,gãa9 ^:¶“«qž|™ìë •¬êª*ùiá2ù9,Y¾J»$UUÕ´a…VXae$w›FŒÁúXÁVƒU[Z*÷ãSåRØÙºáRÈ|©`Œ1¦ YHÁÔƒuòàAù5z¦”MØ*»rÎÓJ„VXa…•€…‚3` Ö¹ÿ³»÷ÈÓ‰±²;ªH85$6u°Â +¬Ô`°PÐô`]Üœ)OÃbe[|µ”–ÖÒJ„VXa…•€…¨ÁòéJÁÅë¤åÃéòÍÂ3ƒVÌŽ1Ƙ, Ê,½íÍO)ŸË­?‘ÎÒJ„VXa…•,D –/®;rDîÇΑ“a_Êžœzê`…VXa¥ уå‹Oåï—ÇM—CÙrðÀ Z‰°Â +¬°Òƒ…¨ÁòÅg¶}gŠÙwÏ8<¤ÅìcŒ©Á"`¡ èÁºðÅVi?Y²ÖHU­DXa…VXéÁBÔ`õßUUr-uµü<>Iv­«£ÎVXa…Vj°Ë—ÖDmY™ü45M®„}.û¾=A+VXa…Vz°˧+KsD’ÔDl’CEu!óå€1Ƙ,DÀÖĉœi ‹“ƒÓöHyy-­DXa…VXéÁB,_·ŸZŸ-OÆÇHÞ¼#–-f§ÎVXa…•, ˜¬³ ·HËøi’¿¶Š–¬°Â +¬ô`!–/®®¨âWÈOa©R´“û bŒ1¦ °|jMÔ•;Qóä|øJ9RTKË VXa…Vz°Ë—óáÕ»Éðx©š²MÊJ¿çŠ:Xa…Vj°XhH{°ª7í“öñ±røã}WÌN+VXa…•,²\ VÝâo¥m|œZ}˜óûcŒ©ÁB,ŸZUURŸ´Q~ù0QŽì(§å+¬°Â +=Xˆ€å©eܸ>}}bš”î¯ Ê›:Xa…Vj°Xh`–3uO¯,£å+¬°Â +=Xˆ€å×€Åù|Œ1ÆÔ`!‹V"¬°Â +=X,DÀ¢ÎVXa…V"`Ñr‚VXa…•,DÀêÿU„œÏÇcL "`Ñr‚VXa…•,²VÀâÜ?¬°Â +¬Ô`Y\Æ {ËŽÊÌÌ”Q£Fgddx=ßß˳úúèÁ‚VXa…V–ËùÅÅÅ’˜˜(íííÆÉÉÉfš§óý½<«¯o0ÆcL V€, š^mÒÇ Ï÷÷ò¬¾>z°h% +¬°ÂJÀ2kôèÑ2|øp‰ˆˆììì^óGŽ)]]]=Ïõ±Nót¾£|]žÕ×G u°Â +¬°°z©±±QRSS%==Ýe—†1Oç{ÒcæÍò¬¼>ýÀØl¯¤¤$óµµô¯/Ïoݺå×åYù¹Í¡À«û5Ø÷§íysssH|~9^9^9^?É«;::L17=XÖíÁÂcŒ©Á ð€å¬I§y:ß“š(o–gõõQƒE¬°Â +¬,Y¹r¥455™Ç=’´´4Y·nÝ[Wѵ¶¶º¼Ê®¯ùާØ|]žÕÖG u°Â +¬°°ÞRmm­ÄÆÆš`2vìXSÕÙÙÙë5:ö“«q \ÍwVÃäËò¬¶>z°h% +¬°ÂJÀt1"¨×G ÆcLÀBA°h9Á +¬°ÂJ"`Qƒ+¬°Â +¬,D­DXa…VXéÁB!°0Æcj°‹,Xa…VXa%`!j°¨s€VXa…•,D-'Xa…VXéÁB,Œ1Ƙ,¢‹V"¬°Â +¬,D çþa…VXa¥ °h9Á +¬°ÂJ Qƒ…1ư=X´a…VXa¥ °8÷+¬°Â +5Xˆ€E¬°Â +¬°°5XcŒ15Xˆ,ZN°Â +¬°Òƒ…Xœû‡VXa…V¢‹V"¬°Â +¬ô`!j°0Æcj°‹–¬°Â +¬ô`°5XÔ9À +¬°ÂJÀBô`Ñr‚VXa…•,DÀÂcŒ©Á"`!z°h% +¬°ÂJÀBÔ`Qç+¬°Â +5Xˆ€EË VXa…Vz°‹,Œ1Ƙ€…èÁ¢•+¬°Â +=Xˆ,Îýà +¬°ÂJ  PeffʨQ£Œ322èÁ¢•+¬°Â + ù¢ââbILL”öövãääd3,Œ1Ƙ€…ú) WšÞmÒÇ ô`ÑJ„VXa…•€…ú«‘#GJWWWÏs}¬Ó¨Á¢ÎVXa…V꧆ öÖ´áÇ÷¬l¶×ìÙ³eΜ9¦7lÚ´iæ¯/ÏgÍšå×åYù¹Í¡À«û5Ø÷§íyjjjH|~9^9^9^?'`¡~õ`!„BÈ"`…H –NC!„ õS¶«[[[=¾Š!„B,äF:ö•7ã`9ʾ6 cŒ1ÆÔ`! ÊÛ&¬°Â +¬°2+ q`à +¬°Â + !„BÈÚ"`!„B°B!„X!„B,„ü%½mÍÁ®sçÎIJJŠŒ1BÞ}÷]Yµj•‹,XYu|5ëòåË¥¥¥%è÷±2ógÙþx …ãööíÛæ¶`z§‹qãÆIIIIHìÓÑ£Gåþlnn–yóæ™ý©ÖÇ÷ïß'`¡àZÁ.=˜ëëëÍ­‰:;;eÓ¦M&p£æÎ+gΜ‘7oÞÞ¼¼h#GŽ”Ù³g÷ÜÛþu555æuúûåèMyõþi:}øðáæFµUUUo½—‚‚óï¼óŽŒ=ÚÜÙñ>zG•°°0ó^"""äðáÃo½o½¡³ÞàøÝwß5ëÓe-[¶L®\¹ÂGˆ€…Bƒ²úš®¡éÁƒÒÕÕÕ‚¦L™òÖëôæ»ú:{]¼xÑ& e?–7oÞÈš5kÌë5Ù+77·'¸iXÓ×èkm:yò¤™–ššj‚—Z;¾}oúüܹsæùË—/M Ó÷‡"`!„%Ö;wz¦iȲõ29¾®©©é­eh¨Ñyö=^¯_¿6ÓÂÃÃݾ/í…²)11ñ­÷sûöí·Þ¿¾7uCC;!BY3`¹›îªJOÑ9; éÒ4€ÍŸ?ß*î씥žôäýØz°Ôú?zJrÓ¦MÒÒÒÂÎFˆ€…B°l¡H{¾\ÉŠìOö7`i ÖÊ•+e̘1½‚š-„ !„>`iq»Î;uê”Ë÷`ëé²IO7:.×ÓS„öÒš¯ãÇ›ùº„ !„Eï¿ÿ¾ Z„îï€õÃ?˜«£¢¢¤±±ÑLÓâô²²2˜lÒÞ%]††!­ÑZ°`Á[˵/rïèè0ž7oÞ[¯›;w®ÔÕÕ™å¨ô*F?cÆ v6B,„éi9ÊÀÓàäMÀRi±ùgŸ}fê«ôuètûa4|éiB­¿?~¼9]®Ó0aÂÓ¥¡MŸ;¾N—»dÉÃdòAORƒ… !„Bˆ€…B!DÀB!„B,„B!B!„ !„B°B!„X!„B,„B!DÀB!„"`!„B°BfCþácŒqÀ°,°B!~Ë‹%B!Äo‹%B!Äo‹%B!Äo ñ¡D!Äo"`ý‡òñãDzxñb5j” >\åøñãÿÿ°aÃìtû:në¾æõÅàɶÈÌÌ4ŸOuFF†WûÚÝÿ¤¼ÝþZß`gîö·¼î^ïl;*§'rvy»_ܽÞÛï•P<ÎX¬ X¨ôÀxùò¥tuuÉ?ü ,ð{À²I×STT$cÆŒÐ/WïM¿ÐrrräÍ›7ÆÙÙÙ×çrô‹²¾¾ÞlŸÎÎNÙ´i“ù²²iîܹræÌ³,}M^^žL›6­ß˳©¼¼\Üncwë÷öý]»vMÆŽ+.\0Ï5Œ}õÕW^ísO_çn[›Ïh{{»±þPê4O×åéÿFØÌu ÆqæéçØ[vO__WWçQ`îë8ò÷ûòö{%3+ðÖ¸q}Û´µëJ=’E‹™™¾655µ§åãiëÏÙ¼ƒJZZZ¯iúeùÞ{ï™V–¶¾Ÿ?Þkþ7ß|cZ¬Ú+((è÷Ï;ï¼óÖ4]§§Ò/)wÛÍ×å){xx¸i÷çÇÙÝú]Í×ý]VVæó`Þ·ã¶Ð/mÛJ륧ëòôÿÝ©û·©ûGJ$"BdÖ,‘'|XžLswLXá8sw\ TÀš2eŠéw%WÇ‘¿ß—·ß+¡xœ°X°¼™n'=ÒÓÓåÁƒNçGGGË•+WÌ©­2ýò]¹re¿{°ì[ØúnÓÎ;MÏ™¶~t=«W¯îÕšÛ¾}» w:ÿõë׿}ô÷‹G¿Ø´u©Lꬬ,3ÍSi·¾³–ºí‹+??ß´=ÝFΖ·yóf³gÿïjyÎÖïÍ|•îÝÆCñÅï¸-4Øë{¶ÿ:ÍÓuyúÿîÂÕŒÒ}üþüÆßŸ{²ú°ÜV9Îܰt]ëÖ­sûîŽ# ’4"º“³~'¸Zž»×{û½ŠÇ‹€RK{£ô‹êƒ>èiѺªÏÑÇþ »¿˱÷l\÷{µyúÃ`__¡]éZãà/jí• ëéyÓÇîZÂ6ݾ}Û„NgïŶ<=-ÓÔÔäÑ6r¶¼††‰wùE߯³õ{:ßÓ}êi퇷_üζ…³exÓKâéÿ»’fQ[¸²ICVròÀ,wÇ„UŽ3OŽ ¬Ý ÷îÝ».ÿÏÝqd¯ÆÆF,µ±Ùß×{û½ŠÇ‹€eý€åé©@/OjwºÖcÙ)iï•vÿjkÄv€Ûw…÷7`麃š<›û³O¿ fÏžmZšöµ}õHÙëâÅ‹ætƒ~q»  ¹¹¹½¶¡·ËÓÿõ4 y»~OÞßP´¬ûÚCуåxÈDE½ýšW¯¼;¼ú°ÜV9ÎÜþXzúÉ“go£ŽŽS í©_ïí÷J(g,VHõ`yÒâÕ« õ C¥úó µ!ö_’ºž¾®¤ów–³–•»^ÚÚZ?~¼Çþ,ÏWž¹[¿«ùZ³3˜µ!®¶…³Úæéº<ýÿ¡èÁÒ`cÿ£¤aȱËÕ1a…ãÌ“ãÂßKË´@Ü“åxsù°¼ý^ Å㌀EÀ ©€¥¹}•Ö Ø_ù¢Å°zõ‰J¿˜—-[Öë Ó/w§×<¹ºi×®]2þ|ÓͮҖ§}­—­6D߃¯5Xʧœöµ®®ö),,4?Lާ$lÒS¬¶Ë±õKW‹ˆí¿\߇»å¹ãp|înýîæ;J¼ô”ñåË—Íó¼ºÉݶ°]¤ûÝ—«›Üý¿+ T –ik}~õýééyû×¹;&†ú8óôsìÏ€¥ŸÉ¾.Rðä”›½”ÛÖÃ¥ÛC¿ í뺼}½·ß+¡xœ°X°úy¡;ê¡­iíÒÕXû ¯ã³è|mýèjé%ÿ¶S ž´$5°é‰³Ó úå¯u º.½ä¹ªªª×|­wÐ@çîê&w­Vý’´ £ÖÇîj’\-S[†ú~m|ÎÆò¥eí.`¹[¿»ù}}.ôt_èþ?zô¨×ïß›1Ò\-K¡'ãóôõ>\ý¿7!K{²&Nü½çÊWê1 ?À¶cK‘ãëÜV;Î{·ý9ΔJ¸uÈ,ûãB{î”[‡0èïë½ý^ Å㌀EÀ ¼€…Bñ[FÀB|(Bñ[†X|(B!~ËX|(B!~ËXˆ%B!~Ë‹%B!Äo+€?”cŒq °B!„,©ÿúÀÞñXóIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_weak_get_line_total_wide.png000066400000000000000000000575431174000617100264230ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix_*IDATxÚì½yLÔÛÿÿIš¦iš¦é?MÓ4MÓ¤iš¦išþÓ4Mcn4Øk̵”UAvQ¼¸àê½n(â†;‚(¢Èz\wÄå‚^. ‚xyý8ïû¾Ã0 ¼fy<“g˜y¿‡yÃÃãð~žs^çüAB!„Bhœô „B!„ !„B!B!„B@B!„B„ýÃ?üƒüáè÷?þã?:ß¶Ñï§l ýÓ?ýÓ€kܺukÀù¶¶6ù£?ú£þóׯ_p¾¢¢bÀ÷ÿó?ÿ³ÓñR ~øáùßÿý_ùó?ÿsùã?þcÍêñÿ÷‹¯¯¯œ:uŠÿ”!DA9«Loz‡ºyï›yG QQQ®±{÷îçÕµñù„„„ç÷íÛ7à|DD„Sñ:þ¼üå_þ¥Ùöf«Gl«!DA9µÔM®¹À°°0ÈU\\<àóæÍpÞÝÝ}ÀùI“& 8¯^o|¾  Àixeffx¿¿þë¿–ƒJGG‡v¾»»[ Ãjtä?ÿó? !DA9£~ûí7ù«¿ú«þ›³¿ø‹¿pƒÈMÝÈyþÙŸýY?—¿ýÛ¿pÞÀúOþäO´¯jêQOOOÿyã©pú§ª½Ÿ3÷ïßkS¬ ï¥ÕÖÖ:MðD!BY)ÕÃn|s<àù•+W,ÞÌY3}¦¦¦F.\(ÿ÷¯Ýx«›î¿û»¿ÓŽUWW[}Ó¸~ýz-©÷P=ä†Ñ·oßjïe¨'ø·û79vìØˆoDäûï¿—ÿú¯ÿÒnþÕ{©@¦F%®^½j5SÓQu󭤦´Ž©:Ã㜜íüÇ|ŸzS©›v5b¥jC ?£bâéé9ä”9Ói_ªE}¯â##¾qÏÍÍíQÊ[¶l±ÈDM53~¯U«Vª½Žä÷M[E!BÙXÞÞÞý7bêfîóçÏÚWãå±ÜÔ©šã¢ks6­“0w0Ì}¯º¹V7 æÎ8qÂêjU›`5õÈ Ìq6Ôy¨ŸÁøû;Ó a|ÓoΦ5%JÆaǜըÌÏ?ÿlu9sæÌ€Ó½{÷ËD—¿WUUÕˆÛêHBˆ‚Bv&5õGõ"nĦM›¦wss0 ÈxŠ57ó÷ø+«‘5ÐÜÜ<è†t¸Þkµb’ºi7íÍ7>§‡ññÿøÿ°êgV#4Æ¡KU› ~o5Jýl³fͲš«Q0¾Ntt´vüþçpž>}ºöü_þå_´çjTÀøûÔÈŽAwïÞpnòäÉÚuÔÏ8àœ 2ÆR?ûÎ;ûGbT­Ebbâ €gÍ¿ñáÇSaË·3å‘N-ËïOà@@BÈNdz3Ÿœœ¬WEÀÆÇU÷hÈìÙ³¼FhôÓO? 8§^kéýUq²áæÙôœa)[uSk|\ÝôZó3«é;ÆÇwìØ1f¶*üš«éU†QÈ90ß}÷]ÿs5=ÊX¦ÓºêêêúÏ™21-lò˜IAøpÿÆêç6žÆeÙ±FÆÏ\{ntb,¿?!DA!;‘ñ ¯òǵãê«ñqõºÑã¢cÓ^oÕsm|N½ÖÒû¯¥s–nt‡ú™ ï•Õ>c•ñh†ú™ŒGg?~¬½æÕ«W¦‹ÄÅÅ x?ÓŸÑ’Mƒ—šî¤¦ÚjpÌ}ú­ ê=T ÈH4ÜÈpd,¿?!DA!;é†xª(ÜXÆuêæ´¥¥eÄ7u#éõ6½¶ôþzŸîçL÷V1lP¨V¹2–á¸ñ0~}YY™E–ÖÖ5˜.};’Zˆ¡^§öñ0„Uke˜~fðHËïOA@BÈNtàÀÝЙDuÄtÚÌp# ¶UÛbí¿¡éyU«bxü7ó7C®žeN¦«`™+–·ô3ö÷'€ „ !d'RóäG@F3¯^Ï[ž³E ˆ’ñ c_¾|yÀkL7.jù]S–æ–6'ÓÈ RËÙŽ4€¨eŠGÆþýßÿ]«m±FjáãÐÕcã"ûáþFûû@B„²©?s7—Æ2®O0÷Ó¥oÍíAaº –Ú»C­Ä¤¬VIJ´,ëx5ÈxŠª!0¬‚eø=Lw4·F¦Eþꦵ¦usmÊRñW!Îðj%/U$nºƒ¸ªû0þ>µçˆ=0­ÿ±&€(©'ãѵ•¹UÒÌIÕ¿Ÿšöwîܹ~&êwêgíïom[E!BÙPjÓ8ã25?ßœL—ÊU«ckÕü{u#?Ü> æö‘Ï¢¤–n5æ3Öžs㕯”Õ²»æd¼Â“z½-0'kXšþœjù]s¯Y°`Á¨ˆ’ÚœÒøøH™ñQÓ·FSË1šß$m!„ !d#™<›Öwd¼L¬aÊAª×YÍãÿ×ý×a‹¸ÕƒÚ«A`«×*«žyuLõ\›ýp碤F†ŒwB7LR7؆¥~G*ã©nCmØg¼q¡¹|s,Uñºâ¨nÈUpR{·¬Y³Ælq·0¼^Ýü«×YÃÃÒyÓ"µ£ºµR{¶(ÿ÷ÿ§Õß~5¤Ú˜ d*8=}úT—ß$m!„ !„B!DA!„B@B!„B„B!„"€ „B!„ !„B!DA!„B@B!„B„B!„"€ „B!„ !„B!DA!„B@B!„BäŠZ³fÍ€ç<ë:«á S˜Âæ0µµMï# hTdñâÅòÓO?»_½z5!×uVæ0…)†)Lajk@C{÷îñO˜Âæ0ÅÄ”‚:€`Œ1ÆcÇ21‚á S˜Â0…)L ˆÂ|PxÂæ0Å0¥„‚¡'æ0Å0…)L ˆŒ1ÆcL "€ÐBOLáS˜ÂæD †'LaŠa S˜Â”‚ ô†Ð»S S˜ÂÔ¢cŒ1Æ@# üG†'LaŠa S˜bF@„ù ÌÅ0…)LaŠa Sbæ0Å0…)L1# ˆ‚1ÆcŒ©!€ F@è Á0…)L1Laê4–Ù³‡4@˜ O˜b˜Â¦¦ús"€ ½!ð„)†)LaŠaJ!€ j@0ÆcŒ Ć'LaŠa S˜b"€0”ùµ0…La S Ó wENŽ4-[FAzCè]‚)†)LaŠaj;—ÉË­[å‹——¼èûÊ*Xˆ‚1ÆcŒmâûGJçÂ…Ò«€ØËÏEAŒ€`x¦0…Laê„Ó­:´boL ˆ O˜Â¦p€)Lpº•znL ˆ O˜Â¦p€)L]pº# ˆ‚1ÆcŒm2ÝÊžìð$22R&Mšdñ5꼩M•––&S§NÕœšš:âóz¿Ÿ½_z—0La S S˜:Ît+F@tRaa¡„……Y@,)77WÂÃÃ¥­­M³ 5꘵çõ~?{¿5 ̯Å0…)L1Laêø«[Q2BuvvЧ§§¼}ûvÌDÝ|«hz¬‚µçõ~?{¿# ô.a˜Â¦¦0uüéVŒ€ŒP{öì‘ÌÌL«†:?mÚ4™|€Ÿ§|žÚÙs6>¬\)=‹K]f¦S}ž:d1·ªÕHBˆi1W¡ŽY{ÞššŒ‘¼Ÿ½_z—0La S S˜:þt+F@ÆH,=OLLì1ijj’øøxINN´ Tkk«ÅU¢†:oz½±¾Ÿ½]Œ1ÆcÇžnE È8òòrñ÷÷׎Ϛ5K«ÿèîîðµ÷…¥}0,77ú2–÷³·ë1Bï†)LaŠa SÇYÝŠ Д)S¸ž‹ì„Κàð„)L1La S¦[9S§ Èu=Lð„)L1La S¦[1‚ cŒ1ÆØŽ¦[Q‚ ô†Ð»S S˜Â»S{ÜLDa>(ókaŠa S˜b'dj¯«[Q‚ ô0Ñ»S S˜Â;S{ŸnÅ"€`Œ1Ƴº5 ĽK¦0…)†)L{º# ˆÂ|Pæ×Âæ0ÅNÄÔW·¢@èa¢w ¦¦0…)v0¦Ž<ÝŠDÁcŒ1fu+j@ ˆz—0La S S˜:öt+F@„9¶Ì…)†)LaŠŒ©³­nE "€ÐÃDïL1La Sl§Lqº# ˆ‚1ÆcÌêVÔ€@# ô.a˜Â¦¦®ÆÔ6d@˜cËüZ˜b˜Â¦Ø˜:ûêV‡×HDD§xzöJpp§¤¥=$€ =LôØÁæ0ÅãÍÔ¦[¥§?’  ßäÁƒßïáž>í•€€/ãB ˆŒ1Æ»´]aº•ÁK–t÷‡ƒž<ùM-ê$€ =Lð„)†)LaŠmÍÔÕ6ôñé5{oçáÑKAæØÂ¦¦0…)¶SW\ÝêâÅþÛ 5 ‹D¡‡ ž0Å0…)L± ˜ºÒt+ƒsrnÈÚµoÄË«§ïë¯ÜÛBž= ì¡@0ÆcŒ™n5ÖàQÑwÏö¶/x|‘ÄÄ×’—w­¿]Õ‚¨iW‹w³ "€ÐÃDL1La S¬'SW›nuþ|…¬^ý‹<’’^õ«vÕN ˆ O˜Â¦p€©S2uµéVçÏß”øøßƒÇ–-¯äÊ•«vÙN ˆ O˜Â¦p€©Ó1u¥éVÙÙ·äûïÅÛû‹lÝúRòó¯Úu;%€ j@0Æcì4v¥éVçÎÝ’•+߉Ïùá‡}Á£Ü!~nbæ0…)`êðL]iºUVV¥ÄŽoïnÙ¶­N ʪ@5 ž0…)LáS‡fê*ӭΞ­”åËß‹O·lß^'……åÙN ˆ O˜Â¦p€©C2u•éVUÛ$¾¾Ý²cÇs)((sèvJAÔ€`Œ1ÆØ.-³giW˜n•‘q[–-kî ]òãµRTTæ¿—ÃÈÈH™4iÒ°¯KKK“©S§jNMMÕý¼«]zì0La S Óq æÔwÜ™§[>}[–.m?¿.Ù¹ó™Í‚# £Paa¡„…… @rss%<<\ÚÚÚ4«Ð¢ŽéuÞÕ®G s–1La S Ó‰ Îøûž:uG¢£• ºd÷nc®Ú)<ô}þáÃxðy:¡Ï•”HÃúõòÕÛ[>mØ Ïrs‡]ËßsçêdÙ². ê’ýûËÝ»Õ.ùyêDsI„:¦×yW»# ôØa˜Â¦¦ºp:vLš—-“/}Áãub¢Ü¸xÑ)™=z_ÂÂÚ$0°CRSII‰k·S§ØÄ4|˜>7¬òÔÚÚjq¨ÑžwöëQ‚1Æc½¬öìx²g| ’O‹ÉÓ¾Çe……Nù»9R#¡¡í²hÑ'9pà¡Ýj@Æ!€(©½-,ís1–óÎ~=F@è±Ã0…)L1LÇêë¹¹ò:)I¾øøHsLŒT;æ´Lªé»7j—  rð ýF@tÔ”)S¸žÅ> ¬[a S˜b˜ZãÛ§OË»•+¥ÇËKÖ­“›ÙÙNÉT…ŒƒHpðǾû¢}!äÝx°r(1B†)LaŠa:”K‹‹åajª´……Égy¾c‡\ÍÏwJ¦*d¤¥=ì Ÿ$$¤]®¡@3Œ1ÆÛ¯æåÉ‹mÛ¤ËÏOZ##åÁ¡CÚžÎø»ªà‘šúP«ï m“#GîÓ ˆ O˜Âæãá[YYò¶ïÞ ÇÓS~YµJª23–© û÷?ÒV´ o“ôôû´S¢Ã¦0Å0…©Í­v+?rDZ–,‘n__y¹u«\»|Ùi™–””ʾ}µÍÃÃ?ȱcÕ´Sbæ0Å0…©­]^P µ;wJg@€´‡„Èãýû¥´¨Èi™ª]ÊSRžÈÂ…ÚîåÇߣ@5 cŒ1¶µ+rr¤~Ãùâå%ïW¬»§N9õï«‚Çž=*x|–¨¨V9qâ.퀂 ôÚÁ¦0Å0…©Í—'¤)6V ?oÚ$7ú‚ˆ33-**•Ý»ŸÊ‚ŸeÉ’9uê.픂 Ì[†'La ˜ÂÔ–Öv+OI‘ÁÁÒ(Ïvï–²‚§fZTT&»v=ë ]ý«œ>}‡vJAzíà S S˜ÂÔ–¾~é’¼Ú¼Yº½½å×¥Kå~zºÝ,£k+¦*xìÜY+~~]²ti³œ9s›vJAŒ1ÆÛÒ·32¤ñûïµetß$$È­QîVîH.,,“;jÅ×·K–-k–ŒŒÛ´"€ÐkO˜b˜Â¦¶riI‰DDÈõ0âìL Ë%9¹N||ºeùò÷’™YI;¥@赣Ǧ¦0…©­|ëÜ9y³v­6ͪ1>^ª22\‚iAA¹lÛöB¼½»%.îde<AŒ1ÆÛÆ%%rÿèQù5:Zº}|äÕ–-r݆»•Û“óóËeëV<¾È÷ß¿“sçnѨAzíè )†)Laj —ʳ]»´%t?öý~œ’¢-­ë Lóó¯Ê–-/µàß(ÙÙ7i“Œ€ ó–™ S S˜ÂÔV›þ¼q£¶i`Óòår÷Ä —azåÊUÙ¼ù•xy}‘U«~‘óç Ô€ ½vô„Àæ0µ‰ïž<)ïû‡ õ}¤b‚v+Ÿ¦yy×$)éµ\#aaŸdþüß$(¨CÒÒöM›~k×¾•œ‚5 ˆB¯=!¦0…)Lu÷µK—äå–-Òíë+-ÑÑrÿȻ٭Üá#0°GjjzµûÇ¿ÊÂ…_´½¼z$!á\¼xƒ6Ç"€0o™¹ ¦0…)Lõ~Ϫ³gå—øxmÝ·k×Ê­¬,§çÑ) ¼yôHÄǧGrs Ô€ ½vô„`˜Â¦X_¦%%òààAiˆ.??©Û¶M®æå9%3UD~öl¥6ê±sç3Ù´égñòê5{âáÑK;c@¨ÁcŒõòÕü|y¾}»|ö÷—¶ðpyxà€”;ìïS\\ªÕhœ8qWöí{$?üð¢ï^â,]ú«,Z¤ê;¾jVÕ1uN½&<¼gÐȳg"ÁÁ]´j@„zB0La S.N«ï¨_¿^*Οw™Ñ Ú)L ˆ O˜ÂÃÔÄœúŽ·‡†JçÂ…RûãRžŸÏèí”bæ0…)¶]©9|xÐnå®4zA;…)Q‚1Æc¡öcbæ0Å0ÕÍå……ˆ«^ÐNaêðäÎ;)S¦L‘o¿ýV6nÜ(ÍÍÍC¾~Ò¤Iƒlª´´4™:uªæÔÔÔŸ×ûýìýzÔ€0æ0Å?i»“?Û¹Sº||-XÑNaêà$&&F*++åëׯÒÛÛ+d1€XRnn®„‡‡K[[›fnÔ1kÏëý~ö~=F@è Á0…)L]Þ%%òxÿ~é\à/u WÉÊùµÃ®‚…i§0u²)Xj4d´DÝ|«ƒÔã°°0«Ïëý~ö~=j@0Æ»²UAy{`°ÔûÆÈúù÷eíÚ7rñâ íœ*( ý(îî¿I``‡¤¥=„ÆÎ@ÔHff¦,_¾Üb™6mšLžÄ®VÏ Ù;¯D¶ni—ÒÒG|žòyÊçé(Ÿ;ÅÈ©S§$$$ÄêïéèèЊ­aæ0Å0Ê7ÏŸ—_–¯”óüåȼ\Yß çÏWÀ”v Sj@†!.€˜«PǬ=oMMÆHÞÏÞ¯G ÆcgöõÜ\iX >’1/CÖÆýÜ]’’’´›ç¡nÐ_?kÖ,­þ£»»{ÀkTˆ±´†¥óæj(Æò~öv=öa=p S˜ÂÔ™­6|¾e›6âQì‘"‰±µrîÜ-˜ÒNaJÑgI^®§¡'æ0ut«MŸþ¸[>Í÷— m²%ú¡deU”v S²GQ‚1ÆØa]R"SR¥Í+PªÝ×ËŽ¨»röl%\0&€ ½!ð„)†)LõuõÁ#Òì*ÏæÆÉÞð ÉȨ‚)í¦Da>(ókaŠa S}}çøIùea´ÔÏ]"i‹Kú‚Çm˜ÒNaJ "€ÐBïL1Laª¯oÉ”×A+åýÜ9tIΜ®‚)í»ÂˆaÇòáüÍ7ßpgOÁcŒÇìç.Hmè:i ™Yræd\0v¥,Œ=TÉf‚ˆBo(ókaŠa Ó[m"x/f‡|šë'…~iröHLi§˜ßõÝwßIOOÏ ãêØŒ3¸³'€ÐBïL1LajµË ¥2nŸ6âqÕg—d¸ SÚ)fdp=ÈP„Æcl•‹ŠåúêÃòan€ÜöÞ"Ù)%0Á˜óš6mš„……iÓ®z{{5777KHHˆLŸ>;{½!ô.ÁæC»¤/h¬;)Íî‹å¡g‚\Ü•SÚ)fdø¡ŠÐ‹‹‹¹³'€0”ùµ0Å0…©Y&eÉ(©›·B.oË…)íSb½TÚš={¶L™2E³züàÁîê ô†Ð»S S˜² *t¨ðQ˜” SÚ)f@¨Ác¬¿svækÓ¬šÜC¤tý‰ß§_Ácj@„zB0La S=}no‰TymÑ Ì¯¯>¤œÃÔQK­v5sæLvB'€0”¹ 0Å0…ég¸¦-¥«–Ô½µ"EÊ `ŠaJ ÈØˆ»»û€ÀalvB'€ÐBïL1L]iÆ¡ÚæjAµ™`yÞ˜b˜2¢_QAƒÏ cŒñ™ô[rÑÿ„6âñ0r³\ϽŒ©Ñ?€0ÊA¡7„ž˜b˜º6ÓÓ'ª$30K«ñ¨ ]'Ù`ŠaʈíˆZr·­­;xóA™ S Sczæôm9tIšæ.–×A+åÖ™L˜b˜RbûRYY)>>>ÒÚÚÊ]<„ÞzB`ŠaêLÏœ¹-CJ¤~îyë-wŽŸ„)†)# ã@†ÚU° cŒËU²7¼BjÝã¤Ù7Tª† ÆxbŠÐ‡2õ!zCè]‚)†©ã3Í̬’í‘w¥Ú}½´y/’‡)©.·‰ í¦0µ£‚ Ìe.(L1L“iVV¥l^òP*<¶É§ù äÉŽ]RZ\ S S˜@# ž0…)ÖiVÖ-Ù´¬VŠ=R¤ÓÃGžoÙæÐ›ÒNa S' 5552gÎmÊ•²z¬Ž!ÆcÇqvö-YûR.z‘Ïó|äåúD¹zå l0Æö@ªªª†,B'„@è ¡w ¦¦öÏ4;û¦¬ûYÎÎÏÐF<V'ÈõÜ\XÒNa Sû j´#&&FZZZú©ÇQQQÚ!ˆÂ|Pæ×ÂÃÔ>™^¸pSÖÄ¿‘£ósåÓ|ùeùJ¹yþ< i§0…©}5媧§gÐñ¯_¿Ê”)S¸³'€ÐBïL1LíŒé… ²zÕ[Ù;¯D>x.’¦%1Ruö,ìh§0…©ãîîîAÇU(!€@0ÆÛsrú‚Çê·²mþMyï.­¡ár÷Ä Ø`Œ+€¸»»KXX˜477Koo¯fõ8((H›ž… ô†Ð»S ÓññáÃ5ùY<={%4´[z¬¿xñFßçüY?ÿ¾4øÅÈÇEÁRsø0Ìh§0…©cUh>TúÓ§O­z;wîô}`Fj#&ß~û­lܸQ 1–”––&S§NÕœššªûyW»5 ÌÅ0…©c[TÝå^9¿VêÆK§ÿBy´oŸËm"H;…)L,€(© ¡F;T€PV­ Jªˆ½²²R«Q#(ÚÊPÊÍÍ•ððpikkӬ‹:¦×yW»# ô„`˜ÂÔIˆ9õïòñ•g;wºì&‚´S˜ÂÔ ˆ-d©~DÝ\+À©Çj˜^ç]ízÔ€`Œ±sWßDcL±(5’™™)Ë—/ò5nnnÚ댿GÓ뼫]zB0LaêØ¾|ùšÅ#Ú)LaêT¤¬¬L«Ù0URR’\»vmDïe¨™1c†444X|¹Õ¸ô:ïJ×S Æ`cEDDhó Y}çãz=gOýŸ›~…ÏØŸ«v Ñ=ÏË»&Û¶½?߯¼ø<åó”ÏS[>÷òÝwßI{{û ãêØÌ™3G5rêÔ) a„ O˜Â›q^ÞUIL|-^^_äȲRi a„v Sì:# æzÛ úæ›oÆ´¿ÈHj$Ô1½Î»Úõ¨ÁcÇð•+W%)é•<~\Q-¿,Y!Ÿ.”‡iiWÁ‚ÆØ©ˆZæµ¥¥eÐqµŒ®ZR×%''ËÛ·oµÇÚ²±Æ7̦!ǰÊSkk«ÅU F{ÞÙ¯Ç=!¦0u,çç_•Í›_jÁ#1þ…Ô­J”/^^R×÷÷³¬¨¦´S˜b×Q7ªj¤£¾¾¾#Âׯ_k7Õí¼dPyy¹øûûkß3}út­~DÝ<[eQ!ÅÒ>c9ïì×cÖÇ0…©£rÙºõ¥x{‘Õß7Èý¤½òÅÇGÞô}f_»|¦´S˜b»`:îDÕz µ¡Ͱõ’¼ã½°3\zB0Lajß.((—~x!>>_äûï¥b÷ é_—,‘ʬ,˜ÒNaŠ]{Ä0ÝÊÝݽ#B#ÈþE ÆO¼ ËeÛ¶:ñöî–•+ßIñ¡\i‰Š’ŽE‹äþÑ£0ÂS‚ ô†ÐS S=‚G™$'?Ÿn‰‹{/—Nþ$oW¯–nooy¶k—”–”À”v SÌ"€0”¹ 0Å0›‹ŠÊdÇŽçâëÛ-Ë—¿—óg+äÅ?hæ?oØ WóóaJ;…)¦ĜΟ?¯íb¼ì®š’õîÝ;îì ô†Ð»S S3ÁãÇkû‚G—ÄÆ6ÉÙ³•ò(5U>/X ïcc¥¢ïï*Li§0ÅŒ€ ¡‚‚‚þ¢sãrçÎa÷ž@Œ1v­àQ*;w>?¿.Y¶¬Y22ªäÎéÓÒ*í!!r÷Ä 8aŒ©N³fÍ’}ûöiËïµ–µû€ ½!ð„)LÙÅÅ¥²k×SY° K–.UÁã¶TääÈ»¸8éòó“Ç}Gaí”v Sì²# Æ¡Ãtçó±ì„ލÁð„)L!xìÙ£‚Çg‰ŽþUNŸ¾-åùùò:ñ÷_nÞ,e0¥ÂS2MžIXX›¤§WkÇK‹‹åùŽZðx“ ×ú‚Li§¦Œ€@5 c<êà‘–ö@‚ƒ?Ihh»=z¿ÿ܃C‡¤3 @~]ºTn;/Œ15 ¶ Ú”+%U€>cÆ ­þcΜ9ÜÕ@è ¡w ¦Øi˜:¤‚ÇǾÏÇv9r¤¦ÿxÕÙ³Ò)Ÿ-’êôt˜ÒN1L±u ’/^h¡GEEqgOa>(ókaŠšéáÃ5ZèX¼øc_ùÁC-£û˪UÒíã#Owï–R7¤ÒNaŠ©± µ×Gww·öxæÌ™Zðxüø±ÔÕÕ±:„Þz—`Š–é‘#÷%$¤]›nuðàmú•:^VX(/·nÕ6üyÓ&mcA˜ÒN1LÇ¢‡Ajïõ¼§§G{ÎNèŒ1v4=Z-¡¡mZyZÚÃþà¡6|´oŸt-X ïW¬ŠœxaŒñD©S§j#õõõZø˜6mšv\ЍsˆBo½K0ÅŽÀôرj û -©›šj<ú|÷Ô)i Õ|çäI˜ÒN1La:‘Dݨ×}DGGkÇÕ4µC:"€0”ùµ0ÅöÌôøñ{ñA:dÿþG‚GÅ… Úh‡õx´¿6 SÚ)†)L'8€(Íš5K›n5{öìþcÚ YˆBo½K0ÅöÈôĉ»Ù* vʾ}û‚Giÿ9Uסê;T‡ª÷Pu0¥Â¦0µ£‚ cì(>yòŽDEµôÏ’’òd@ðP+Y=ݵK[ÙJ­puýÒ%˜aŒ±½ï¾ûNÖ­[Ç(„ÞzB`Š‚ééÓwdÉ’_eÁ‚ϲgÏ)..p¾úèQm/µ§‡ÚÛ¦¦0…©µÿ‡Z‚WÕ}¨Õ¯|}}åÎ;ÒÕÕÅÝ<„ù Ì¯…)¶¦gÎÜ–¥KUðè’Ý»Ÿ j×rµ{¹ÚżæÐ!˜b˜Â¦ö>«©©I<¨Õ ÑU-HZZš477sgO¡7„Þ%˜â aš‘Q%11Íâç×%»v=“¢¢ÁãZ^ž¼IH/ÞÞR»c‡”Ãæ0u´5úQSS#>>>ý{‚¨ÍøÃ'€`Œñ¸83³J–-k_ß.Ù¹³¶/x” 8_ZT$Ï““µàѰn\í "pÃc')BWõ!IIIÚéˆBo¯÷ûÙûõ¨a.(†©½2½p¡BV­úE¼¼¾È–-/Í>ß=qBÚû>»ÚÂÂäÎéÓ0¥mÁ¦0uÖ¢öühkkÓ{,_¾\ªªª¤··Wº»»e÷îÝZ ±@,)77WÂÃõŸK922R;fíy½ßÏÞ¯Ç=!¦öÈ4'§BV¯~«Í›_É•+WÍ¾îæ… ò>6V>/X SSaJ;…)Laê줲²RÛ÷ÃÒˆÅH¥‚ˆ¥‘•ሺùVÿ©ÇÆ{‘ w^ï÷³÷ëQ‚1ž>\#‘‘ŸÅÓ³·ï3ê‹9òT;~ñâ¾Ï¤7ZðHJz=d𸚟/?oØ Õy¼Ø¶MÊŠŠàŠ1Æ®@ÌM‡ë*X7oÞvdÚ´iZHñêûÓžž>༛››bŒ:fíySõýìýzŒ€Ð‚a:á#0°G<øý3çÙ3‘àà^Yµêƒ<6mz-yy×Ì~¯Ú±üÙÎÒíí-oW¯–ë—/Ôv S˜bW1]ùj¬«`½xñB|}}µM ­Q}}½ÄÆÆJJJŠÅãŸe¸óÖŒ¸ŒäýìùzªÁl¬ˆˆm¡¡!«¯ãñ\ý»çõœý9<õnú>£{¾dI·ÔÔôøÜù=„ü&ׯ?òûï9"Ÿƒ‚äs\œ<ÉχçÏ?|ø>Où>^’““­¥ ã-­5ÔyÓëõýìízŒ€Ð‚a:Q>wî–,YÒ"~~ŸÅß¿§– AA¿É¡Cµ×©‚òºmÛ´óúõëåê•+ð£Â¦˜ߥ–ϪÝÚ2Ô÷uƒ®FKüýýµã³fÍÒê?Ôò½ÆR{_XÚÃÒys5cy?{»û€°8†éx[íݱaC½¶‰à?Öª5܇ôÃäsßg|Ó²eróüyøÑNa SlçLÇ=€¨ÑŽ˜˜iiié?¦«U¬Ô¨†RާœýzŒ€Ð‚a:^.)ùIRRžˆ¯o·¶§ÇåË¿¯l%Cý}è;þ±ïóçÞñãð£Â¦˜¡wBïéétüëׯvqc+€`ŒÇgÎÜ–ÐÐ6Íê±ñ9Kä§’øaŒ15 –ˆéô'%J zCè]‚©ëYr¬^ý‹6ê‘’òX1}ÅCÚ)Laб$wwwm—íææfm¹Weõ8((H›ž… Ìe~-L]ÃÅÅ¥²cG­Vç±qc½V÷aîuªÀœB;…)†)5 cZk¨"ò§OŸrgO¡7„Þ%˜º€»'‹}’èèm¥+³¯+)‘ÇûöÉç  ´S˜b˜226© ¡F;Ô”+eõ˜ðAÁ;¿srnÈòåïÅßÿ³:ô`È×Ý?zT>I[x¸Ü=uÊâ*XpÅcj@„ÞzB0L¸¨¨L¶ly)^^_dëÖ—Úss¯»}挴FEi;˜?8t¦´S˜b˜2BAÔ€0Ãtd>xð6â±bÅ{mÄÜkn^¸ ïãâ¤Ë×WžîÙ#¥V¶‚)í¦0ÅÔ€ +UßñÍ7ßô?Ê†× ½!ô.ÁÔñmØÅ\Õz?nžÃµK—¤!!AÛÁüÅ?HYALi§0Å0edìD µü®áñP6¼@0ÆŽkÓ]ÌÕjW¦¯)/,”—[¶hÁ£~ýz¹–—;Œ1¦„)XˆzB0L­÷P»˜»´¸XžíÚ%ݾ¾òîûï¥"'¦´S˜b˜2BAÔ€0Ãtd¶´‹¹ÁÓÒ¤3 @Z¢£¥*#¦´S˜b˜R2>ÄR5 zCè]‚©cÙš]Ìï8!m¡¡ò±ïs¢úØ1˜ÒNaŠaʈ}öövcì ¶fóʬ,i^ºT>/\(RSµa‡1Æx܈¥Õ¯ vssãΞBo½K0µs·‹ù‹å—øxéöö–Ú”Ò¢"˜ÒNaŠa Óñ †•® ËíšzêÔ©’™™É=„ù Ì¯…©z¸]̯^¹"?oܨ­lõ*)IÊóóaJ;…)†)L'~ Kí@è ¡'¦Žåáv1/+*’ºädùâí-o×®•ë¹¹0¥Â¦0…)«`!j@0Æ#·Å]ÌKJäIJŠt-X MË—Ë­ìl˜aŒ1¶¿RVV&7nt<))I®]»Æ=„Þz—`jnóš#GäÓ¢Eò!"Bîœ> SÚ)†)Laj¿ä»ï¾ÓV¼2· ÖÌ™3¹³'€0”ùµ0@·‹ùí¾°ÑÚ:Tø¨9|¦´S S˜ÂÔþˆ*B齈Bo;{½!ô.Át„jsµ[ù“={´ÝË߯X¡ífS S˜Â»Üˆ mmmÚcµoyy¹ö¸²²Òê;wîHTT”öýj÷ô¤¤¤a—ñMKKÓF_”SSSu?ïj×£„¹ Ø>˜µ‹yÍ¡CÒ±h‘´FFÊíÓ§aŠa S˜b×­)((Ѓ’Ï€™3gZõË—/צq©Q“îînÙ½{·H†Rnn®„‡‡kÁG9²ï²:¦×yW»# ô„à‰g:Ô.æwN’}ÿŸ?Éý#G`Ša S˜bF@ŒõõëW™5k–6ò1cÆ éééÕû¨ b©€]Ý\+À©ÇaaaºwµëQ‚ñÄy¨]Ìo;'M±±Òµ`®×söçðÔÿ¹Á£ùþªªjmsoï9p U{^ZT$ û÷ËW??ùuýz¹qñ¢ËñUí”ö¥ïsõ·|ž:óç)ÏíëótÜHPP6j¡”0 ÝÒ4*S©Õ³Th©­­öµæjÔ1½Î»Úõ¨ÁØö´‹yI‰<ê Ÿýý¥9&F*³²à„1Ƙk¤zÖÕÊUJjÕ+<?~¬b¨%u­Qvv¶Ìž=[^¿~mÕ”$Ã*Oj©^K«@ö¼³_æ‚âñcjnóêôtùØ÷¬-4Tîž8SÚ)La SL Èh7"Tuê¹aõ+k÷151¶¥šµ·…¥}.ÆrÞÙ¯G sA±í™šÛż*#CZ–,‘΀yxð cŒ±#5Òaîqoo¯LŸ>;{½!ô.Møt«‹+²äóy+çÏÔv S S˜ÂÔшa'ô)S¦Hyy¹öXmPH „ù Ì¯ÈéV»#oIKp¸´‡„ÈÝ'`J;…)†)Laê ¤  @’’’´ÇjGtã™3grgO¡7„Þ¥qŸnµÜÿgy¹Fºüüäñ¾}òÓë<`J;…)†)Lajç«`ôõëW™5k–6ò1cÆ éééáΞ‚ñ¸M· ðl“Šˆßë<^nÞ,eðÁcŒ9€ ½!ô„LÄt«€…r68[º|ü¤1>^®çæÂ”v S8À¦0uÖB„ù ÌÈéV?øVJ‹¨´FDHUFLi§¦0…)L=€¨ÂsD¡7„žñžnµÌóµÔ®’Nÿ…òààA˜ÒN1La S˜ºÊÈìÙ³¥££ƒ;xÆã2Ý*¿I®úï–n/oy¾}»”ÁcŒ1v¥ŠŠ è_Š@è ¡'ÄÓ­V,k”ÓÞçäó|y“ ×òò`J;Å0…)L±+Ž€/»kjêC Ìe~­Ó­’çݯ`iŽ^*·Îƒ)íæ0Å®\¢BÆPž’bI¹¹¹®­Ì¥©³ö¼Þïgï×c„ž‰œnµ'⦼p•¦€¹sò$Li§¦0…)fdä«_ìææ6!DÝ|«ƒÔã°°0«Ïëý~ö~=j@ðDL·JÝp[*æn•¶ùò å€üDÆcL ˆ5«_–Û5µšú“™™i³2mÚ4m•-///IOOp^ŸÞÞÞþçê±qÆú~ö~=F@è OŸ///íø¬Y³´úîîî¯Q{_XÚÃÒysAh,ïgo×£„¹ ¶rIA‰ü}¸/xøËíÐíRv)¦¦0…)†)5 Ž·ú”)S¸;¡c{ç™tZÞÏ ‘G> R|ü2L1La S SF@7€ × Øñ\vø¼¼ðZ!õîK$Û˜`Œ1ÆÔ€@# ô„èï«.ɃàDi™ WbOKqQ)L1La S SF@ ȱóAíŸgYAÜ[¹S>Îñ“â€rù\9L1La S Sj@ ˆ¬3Ï’¹»=M>xÊÍy?Hæ¾r˜b˜Â¦¦0%€ j@°þ¾}ì”4úFIíÜ89¾æ'msA¸`Œ1Ƙ‚Áºò¼yႼ—æ¹Ár<$Orr*`J…)LaŠa S¢ëËój~¾<_$ŸæúJ¦×9~øëe¥ÿK¦[aŒ1Ƙ‚á?²ÄœúŽ¿ó”óïÉÖ­/˜nE…)L1La S"€0Ô¶dyì{¦[ÑFa S S˜Â”‚ ô†ŒOm¦0Å0…)L ˆ‚ cŒ1¦@è q,ß¼pAšcb ´Q˜b˜Â¦0%€ óAmç²ÂBy•”$ÝžÞrÁÿ¤ÅU°àE…)L1La S"€Ð2j?HK“N?©Y¸I½ÞÉ®]Ϥ¤¤T®‘°°OâáÑ+!!_äèÑgð¢Â¦¦0…)@ðè|+;[~]-¿ú†Ê&¯jIHh+W®ÂcŒ1ÆD¡7D?—ÈÏ›6I—§œñ='K"š%+«ž´Q˜b˜Â¦˜Da>¨¾~”š*Ÿ}Èí[%Òï<øž´Q˜b˜Â¦˜D¡7D_WfeIKD”¶‹yÂü²eËK«w1‡'m¦0Å0…)L ˆ‚­›n•Ÿ/õë×ËgO_I÷º(q+ÞÉÅ‹7`ƒ1Æcj@„Þ]R"SRä³·Ÿ\÷ùQ–.úENœ¸ Ozì`Ša S˜bF@„ù úºêìYi 7>ѲÚóqÿ²ºðd~-L1La SL "€Ð¢›¯^¹" k¤cþI›Ÿ/ këuYV—Þ%Ú(LaŠa S˜@˜nõtÏ­Îã'¯½ñÆâ²ºcŒ1ÆÔ€ ½!£òí3g¤5(T^yÅÊß§V-« Ozì`Ša S˜bF@„ù #òµ¼rÑã¨lZóB—eu™_Ëœe˜b˜Â¦˜  æ^7yòdÝλÒõTƒ1ØXZ#6$iõu<ž?þ|\¯g‹ç÷Ž—ö€Pyì™ I‘ϵeu'êçqžv÷ïûÿú=Wíú>oll„Ÿ§|žòy:n×g„‡qdßÈÍ•7Ëâ¥Åc‘ìò¾j“eu1ÆcŒ©±“uL¯ó®v=j@t˜nµ5Y:=|$Ûã„$'=³Ù²ºÌ¯…)L1La SL È8Óã†UžZ[[-®5ÚóÎ~=j@ôsõÑ£òÁ7Xîyl”-KÙ|Y]æ×¦¦0…)¦Dç}@Ìíb.˜¨½-,ís1–óÎ~=F@ÆîŠœy³d¥4¹/–] ®Ùí²ºô.Á¦0Å0…)L £Ð”)S¸žE ˆu.+*’ÚÄmÒáî+g=NËÞ벺cŒ1ÆÔ€ §# Ãûþ¡ÃòÁk‘Tºo–ñ5²¬.½K0…)†)LaŠA'ŸzóÂi‹“_ÜÃeoð5mY]æ‚2¿Ã¦0Å0…)1¢ït«ÂBy¶îù4×W2<ÏÊá´zB0La S˜b˜Â”‚¨±Át«ÔCÒæ(×çn“½«ífY]Œ1Æcj@ĉzCnegKCðri˜%û#¯Ùݲºô.Á¦¦0…)f@œ`îbyA<]µU>Î] g|³ää±ÛÌÅ0…)L1La SbDWïI“¶yRîþ£L¾ãTËêÒ»S˜Âæ0%€ ˆøVæ9iˆ•Wscä`l¹C,«‹1ÆcL "€8Xr/ÏÏ—'+¶Hû\ÉÈ–sY·è Á0…)L1La S¢Dg—”ÈÝíiÒî±PJçí–û*þƒˆùµ0…)L1La S"€L@r¿y:Süb¤nîrI_Sî2ËêÒ»S˜Âæ0%€ È8úê•+ò(z‹|˜³P2C²åbÎu> 0ÆcŒ ˆ¢sr/)‘Û›hu?y핳GnЂa S˜b˜Â¦DÑîâc™òÆ;ZžÍ])§KjY]æ×¦¦0…)¦@ì$¹_½|E†'IëœÉ^’-WòÊé ¡w ¦0…)†)LaJA}]ZR"•ëÓ~Ÿnå·O.œ¾Æ‡ÆcŒ1@ôOî×fÊ[Ï(yì¾J²v”ð!@ïLaŠa S˜Â”‚ úÏ],˹"‚å×9‹$gE¶Ë,«ËüZ˜Âæ0ÅÔ€ È8&÷Òâb©ˆ? çøÉOûår6ÁƒÞ%˜Âæ0ÅŒ€ ˆ \¶7S~™!毕œýE|Ð`Œ1ÆS‚ 6HîYyò `“4Í –Kk²]zY]z—` S S˜Â3‚ c´Ìž=¤¯ÇöÙ ¤,$U rù`a~-LaŠa S˜bj@DbN}Çx­“+G øP¡w ¦0Å0…)L1# ˆbû‡ ÆcŒ15 ˆB¡'¦¦0…)†)L ˆ‚™_ S˜b˜Â¦0%€ „Þ%˜b˜Â¦¦Œ€@ý¯‚Ň ÆcŒ15 ˆBo=!0Å0…)L1LaJAŽ@˜ O˜Âæ0ÅÔ€Ø&Mš4ȦJKK“©S§jNMMñy½ßÏÞ¯Ç=!¦0…)†)LaJ±@,)77WÂÃÃ¥­­Msdd¤vÌÚóz¿Ÿ½_ÏžÆcŒ1¦ÄሺùV Ð õ8,,Ìêóz¿Ÿ½_zB0La S S˜Â”2L™6mšLžºsçŽDEEÉ”)SäÛo¿•¤¤$m_46¦jOÓ7Jss3`t’bËg€¾Ÿ§|®ê£/^Htt´¸¹¹ÉìÙ³%//(:·ÑiÓ¦f jll”åË—kmTY=~ûö-!k?”>R>UUUÒÛÛ+ÝÝݲ{÷n- Ñ+&&F*++åëׯ׌Œ Œ*,,”°°0>øµ;½~ýZ<<<äæÍ›Úÿ{Õ‘óã?FG]»vmTû•¡ÿ'9vì˜ö÷I9==] ñ‡sb¥þpNž<:K† ±©³³S<==µÞ:>øµ7%&&2âacJKK Æ o¾ùÆáþ>@8]@ª÷Ž}]ff¦6҄Ʀ={öh,ù ÐïsTMgQ^^^ZO(½ËóçÏËÌ™3µ:µÇB{{;`tüÛ”œœ ˆ1jÕªUÚÿuõ·IùÈ‘#Ú1B “š¿ìëë«ÍEú´Så3fHCC@Æ ºº: á3ÀFª¯¯—ØØXIIIÆþ¿oÙ²Ezzz´é¬[·n•uëÖF'-^¼X›æ†Æ¦¦¦&qwwïÿû¤Ûû¨@œXÕÕÕÚôu£‡ô“êa:uêÔ€›g4r)~Æ!ŽÏýÕÑÑ!S§NÄ(¥ zUð0H¦^ê£{÷îÙ}/½£H-’ F@Œk@ì}Ö@œTååå2gΩ­­†D]ÍØÿϳjÄž¥Vg3 *” ±K-<ñøñc@Øèo‘½ÿ}"€ ˆ*;;[[.’¡mý¤æ)–5T7ujÕ–ððpÀð`WREÓ†Q%5-#>>ž9öc*@WÓ®TQVÓ±ÔÜhlª©©ÑÒGjÅ+U÷a\Â*XYqÓA¨í™ÂulR#Jj©CÅqúôéì­B±ûv:kÖ,­þø\j:‹ú?¯¦^%$$P„®ƒÔÈ’ZÖé#Õé`ØûKY=¶÷EB!„Bˆ‚B!„"€ „B!„!„B!DA!„B!B!„Bˆ‚B!„"€ „B!„!„ GÙx“ BB„BÈ ‚!„ !„„‚B„BŽ>Œmz®¼¼\BBBdÊ”)âææ&ÑÑÑòöíÛA¯+++Ó^§^cü>555¥Ÿà5W®\wwwígñòò’K—. ú¹›ššdãÆòí·ßj×SïµaÃyðàÿà!B!d/!d¨ã*T¼{÷Nz{{ûCB``à ×EFFj¯3Vuuµ(Thiii‘¯_¿ÊÖ­[µ×«ð`¬S§NõfÔkÔk ª¨¨ÐŽÅÆÆjÁDY=6ýùÕϦžß¹sG{ÞÕÕ¥õó!„!„²óòêÕ«þc*„F)L_×ÐÐ0è=ÔM¿:gJj.u~ñâÅüc#„ !„ÐDKM{RKÕZ,F@”T1øš5k´úõ:xÔ2¹ÆËâªp¢¦a©ú9sæÈùóç;¯Z†×ÃÃCÍP¡F=7}zßuëÖi¿“aI_5%‹„¡ÿ¯½³}±)ˆã¸?mÑJ‰h‰(í&¢eÑzAdóBmíF"")Ñn%Ê !ÙD»­"J+ÑnäÅÊSÆ~Gg›{œsfæÜs÷é~>5í½çafΜû›ß|çi €@€ @€ @@á{É@ |@€, €/@€PiàË@¥ €/@€Pi¾ @¥ €/@€4¼Òþüù³9zô¨Y¹r¥Y¶l™Ù³gyôèQðý---A×((þU«V™cÇŽ™×¯_7ì™’ôòòöñãGsðàA³bÅ ôùǹñ={öÌìÝ»×,_¾Ü´¶¶šžžóåË—šó3çOœ8a&''KÇç¢x}eìK?6âÉ“'fûöíöž7šÛ·og–oº¬óÎå=CHYœ?Þþ>Î;õ®}÷7’ز¨*½Ù²3ß»‹}^ßõYå¨ç !ËŽbß‹ïúØz¥í ˆE‚CŽãû÷ïæÏŸ?fllÌ>|¸r’ tÍš5kÚ8*Ê›þ•+WÌïß¿m¸|ù²iooÏG ‰ááa[>?~ü0}}}Ö™'ìß¿ß<}úÔÆ¥k®_¿nvìØQ:¾„{÷î™Ý»w{ËØ—~lþ^¾|iÖ­[gž?n¿K¬ôööF½óÐë|eqëÖ-ûýúõ« jHêXhZ¡÷φ™Í4fÃÎBDZÏzýǃežU¯Øz¥í €Å$@Ö¯ÏÔ[ZÄÄÄ„9räˆíÑÓµ˜é9 í=Ì:744dº»»kŽ©1±zõjÛK§ÞÛoß¾Õœ?{ö¬íñTÞÍ›7K;æ¥K—þwLi†"'î+·zãÓ³oÞ¼Ùö –i¼úÒ/:¯÷}÷îݺˆeò. 5j’šÐg5&CÓ ½ßÇtÛmºgÌ–-ÆìÛgÌãÇõ c>›˜v泋F ŽŽ;‚[D‘U¯Øz¥í €Å&@bŽ;ÈIœ9sÆ|úô)óü¶mÛÌèè¨uXêÕSãääÉ“QÎ/ëõЪ“pñâE;ò¢Þ3¥sêÔ©šÞÀ .Xñ£ó¿~ý²ù(ë˜åøÕ;©gR¸té’=ЦMdõô&ŽýƶÇ1´Œ²âëïï·ñdÝ__Vú1ç…Þ‹Êx.Fé²ðUžÝüëXhZ¡÷ûÄÇÎfÚþ}õêß÷RF€ølb¾Ø™Ï.!@”ÖéÓ§½÷ùìHBK ñ-ÓÊRuBQ|¾ëcë•f´3 @ fÈ‘¯]»v¦G´h}€‹Û )+@„Û·~:¯®RÃÉß­© šc]ECF£:mmm3#7úìëIMxûö­eYyIâÓ´—÷ïß•QV|oÞ¼1»ví*lå=oVú¡çCßièÜó؆QVYdÅÓËzÒj‰øHéìl¬ñÙÄ|±³»¨Z€ìœV€ïÞ½+¼ÏgG.ãããVx©3¦ìõ±õJ3Ú Y€„NµŠœ’¥é Zâ:m~hx]½Y‰t§” J+-d$€’P&PgÙÕÕe{*ݹÚy#./^¼°Ó9Ô°)h×®]«)ÃØøto¨€‰M?$sÑ3›Ws1’6™­[ÿ¿æçÏ8ó*#@|61_ìÌgU Mï ±Œµ£©©)»€:”ôõ±õJ3Ú Y€dµ˜bŽ{H÷˜jW,9T¡¿éFR©¹én#Béäí%ªÉê™óõŠ?xðÀlذ!xAo=ñU±s’/ý¢óZ30›sÓ‹Ê"kn¹Ž…¦zQÃßm´I,¤G@Šlb>ØYˆ]T-@4mT ¸C≱£zHl½ÒŒv†dÆ ºk<4oÙݹE‹Uµ{ŠPÃåøñã5NHØ7})dwž«W¯šC‡Ùi B=—îZ“dnºòPï=ŸžÓ«]´[ÍÀÀ€m¸¥§|$h [²Ý¦%Zäë:ßt>|ñùž#ýÝ—¾ï|5î4%oddÄ~oäî<¾²Hv×Ñ{¯gwßýE4j ˆQk}‚~ƒÊŸ¦?º×ùlb®í,ôw\¥Ño2o)M.zîd„D塺Ð]W{}l½ÒŒv†Àb %wÁÒbD9õÆjÈ\ TÝ9â:¯ýéu^½grd®Ò–®ÉTŽ"™ 5´²¦k¨q¤yÓJK[ZÞ¿¿æ¼æ[Kðøvçñõzª‘쉯 Ï¾5EqªgQùMž/ëÿ!ÄÄ+@|éûÎçý.tÞ…Þÿ;w¢óó?bŠâ’` ùÿyù(º?F„h$dÓ¦#Uì‚%P5±- †ôu>›˜ov–­òÿl5lµ¥tĵ üè¹µEmÙëcë•f´3 @“À— @¨´ðe€ ÒÀ— @¨´_€ ÒÀ— @€J_€hH¥M ÂB€:ø ( ßÉRÚÚÑIEND®B`‚Multiverse-multiverse-0.7.0/charts/atomic_weak_get_line_wide.png000066400000000000000000000575541174000617100252220ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix_3IDATxÚí}lUÕžþo2™L&“Édþ™L&“Éd’Éd2™L&óÏd2™CÓ [áZAûFÅrÁª[E«(ˆÖ¢XD‹ V®TA¤òrA¹E±½X,¶-R[ûýgÝìþvOOÏKÏn{zúy’'œ}öîÞ§NÏÙÏZë»Ö/ !„B!„FI¿B!„Bˆ‚B!„"€ „B!„!„B!DA¡ÑÐ?üÃ?Ø/~ñ‹~ÿã?þcú}`û~?y$ôOÿôO®ññÇØßÙÙiôGÔ¿ÿðáÃöôÑG~þŸÿùŸÓŽ—<öØcö¿ÿû¿öçþçöÇüÇÎzüßÿýß6oÞ<Û¶m”!DA¥«Âoz‡ºyí›ùñ@JJJ\cýúõöëÆÚ¿åÊ•ö?ûì³ö¥¯]»vÙ_þå_F|¿ÔÿÏx|¯"„!”ÖÒMn¤À‚‚H‚:pàÀ€kÜrË-öçææØ?iÒ¤ûu¼ÿ¾}ûÒ†W]]Ý€óýõ_ÿµmڴɺººÜþîîn†Õ;òŸÿùŸ„"€ „ÒQ?ÿü³ýÕ_ýUÿÍÙ_üÅ_ ¸Aä¦.qžögÖÏåoÿöoì÷XÿÉŸü‰ûWCzzzú÷û‡ÂýéŸþ©;_:o¾ùÆ ±òÎ%FçÏŸO›à‰B„ŠSja÷ßœ-Z´hÀö»ï¾õf.žá3§OŸ¶;î¸ÃþþïÿÞÝxë¦ûïþîïÜs§NŠû¦ñ¡‡r¡HçP ¹×;pùòew.¯žàßþíßlË–- ߈¶´´Ø}÷Ýgÿõ_ÿånþu.2õJ|ðÁq3 ïåÐÍ·¤!mÞsªsðïÞ½ÛíÿþûïüœÎ.Ý´«ÇJµ!Þk“Ù³g9d.|Ø—jPô³â´téRkmmMøÆ½¾¾¾?DÉ>úhT&jæ?×ý÷ß?¬÷k"¿ÿpÞ«!DA¡Öm·ÝÖ#¦›¹üÑýë¿QNæ¦N5 þ¢ëH¯“ˆtŒH?«›kÝ€FÚ·uëÖ¸o¨U›àï¹HæFõ¥—^ðszä¨Hœ½:½ÿω]xðßôGrxM‰ä;‘¬^™¯¾ú*îòÚk¯ ø?}æ™gb2Qq¹ÿ\ ¿Wýý !B¥˜4ôG­ÈÞXvv¶{>33sÀ0 ÿ¡xnæ=ù[üeõ,¨7àêÕ«ƒnHcµ^kÆ$Ý´‡·æû÷)pøŸÿÿø¸^³zhü¡KADµ ú½5J¯mæÌ™qsU‚ÿ:¥¥¥îùÿùŸÿÀyêÔ©nû_þå_ܶzü?§žO'Nœ°oòäÉî:z ,°OAÆ/½ö§žzª¿'Fµƒ^<ÿÇ/¾øâ€ç¶â‘ÿ}&':´,™ßŸÀ"€ „PŠ(üf¾ªªÊ=¯"`ÿójñNÉÉÉpŒ ´=ýæ7¿°OÇF;¿Š“½›çð}ÞT¶º©õ?¯›Þx^³†ïøŸòÉ'“f«ðã/4×ð*¯×ÀëñQÏ?lL›6­[ãü ÖÕÔÔÔ¿/œIxaû_`aá±þõºýø¼žxäx‘Þ/±z'’ùý !B¥ˆü7¼ò§Ÿ~êž×¿þçuÜpˆ¿è8¼Õ[-×þ}:6Úùý?m_´Ý¡^³¿ð^Ö:ÉÊß›¡×äï9{ö¬;æË/¿0\ÌßK°|ùòç Ѽ4ÜICí¼œH?£×o(Ð9T’ˆbõ€Ä Éüþ„!„R@á â©(Ü/]…nNÛÛÛ¾©K¤Õ;ü8ÚùƒÞëuGák«x j–+¿¼çÕãá?þСCQYÆ[×>õm"µC§u<¼°¯¼ágž™| ™ßŸ‚"€ „PŠèùçŸOè†.¼ :Ùða3±z@FrßHô€Hþé‡ZX0|áB¯%Kñ‹Gš-Êÿsªm‰÷ÿ0|¿jU¼Çó73äìY‘> V¤bùh¯i¸¿?!DA¡‘ÆÉ'@†3®>È‘Ü75 ’†1Ïï¼ó΀cÂ.júÝp–‘¦ޤðÈU®fÇòTVV×ø{ÝÈÇZ$Ò:£@$MÝ>Ì'Ù–sÿÌW²¦Ý$ÿ O:^½‘Ëðשéw#sûí·+€HZœÒÿ|"áL=>¾5œZŽáüþ‰¼WBˆ‚B#¤ð‚çðúOþib½!7žÔê¬qüÿú¯ÿ³ˆ[= Z«AØ:VV˼žSËuÄ×Q ’z†ü+¡{C…tƒíMõ›¨üC݆Z°Ï¿pa¤üH,U¼.Žº!WpÒÚ->ø`Äânõ xÇëæ_ÇÅÃ#Úþð"­¨¯´f‹XüßÿýŸ«¿ñ~õé=¦@¦àtîܹ@~ÿDÞ«!DA!„B!B!„Bˆ‚B!„"€ „B!„!„B!DA!„B!B!„Bˆ‚B!„"€ „B!„!„B!DA!„B!B!„Bˆ‚B!„"€ tЃ>8`»¨¨È-Z4ê«ëNîpŰ…+lq*p ¿ï$€@œîºë.ûÍo~3êþòË/ÇäºÁ°…+\1lá [œ \ (¥ÈÉ“'ùP€-\1\a W Û4æ:nÈÅ‹­´´Ô233-''ÇöìÙÓ¿oÒ¤Iƒ®ššËÊÊr®®®Žy½XÇ'»¬¯—*cŒ1Ƨ·Çe¹té’åååÙÑ£G­¯¯Ï:::lݺuH4Õ××[aa¡uvv:»ç†{|²ûÇúzô€ÐÒá WØb¸Â®(ª¨¨Ðã®XD7ç‚îI †}|²ûÇúzÔ€0Öî°Åp…-\ Q”m»ví²3fXFF†û%®]»6 €è˜É“'Ûœ9s¬¶¶vÀÏkØ–zN<鱞J±ŽOvÿX_Z:0\á [ WØÂ•E >ú¨õôôXww·­]»ÖV­ZñØææf+++³7Fí!QXI¤GÅ|²ûÇòzzxŸ†WÉØ{sê_¶Ùf›m¶Ùf›m¶ÙNv{\µæ+xxRQOÈPêêêrÅØô€ÐBKà WØÂ®°Åô€$,U‡h7Øá$R„žK¤&Ã|²ûÇúzÔ€0Öî°Åp…-\ Q¤t »R‘5kÍš5ŠÔ[ZZÜã¶¶6+//·ªªªA³Diö¬H³D…aŠu|²ûGûzô€ÐÒá WØb¸Â®¥Âò©S§º¡W+W®P„ÞÐÐ`ùùùîÆ~æÌ™®þÃßc"imŒ¡ÖɈTCíød÷öõXcŒ1Æ@RHÑêIÒázô€ÐÒá WØb¸Â®Daœ'láŠá [¸bØRB!€ÐÊAK†+\a‹á [¸@PZŒ1ÆcL „2âÞºõœÝsOÍ™£E{íå—›ø¥ ®pŰ…+†-= HðÞ²å¬-ZÔggÎüáÚŸnn{óæs|@0†®pŰ…+lá@ "€ë’’ýáÓBÈâÅ?ñA \áŠa WØÂD Ö·ÝösÄ×”›kvß}­¶zõWVUuÁž}ö3Û²å”íØqÌÞyçC;xŒ1Æcj@$Aü`§O÷ ¸þ¹s}–Ÿßm7žµÇo …f[±âŠ•”´Ûwþ`sæüd7ßÜgóæu‡^ë÷VZú­•—m?ü•=ùä«®þÌ^~ù¤½ñÆÇ¶gÏöÜrr†4€ÉùÅOÛâÅ×ìÖ[vïÉššOá0×… »àJk2\1lé!€@Rç&ùÀ÷­¾þ°mßÞh›7ÿÖžyæw¡°rÑz¨Å–/ÿÆŠ‹;lÁ‚.›=»Çrsûì—¿¼ánlî¹çª=ðÀ×VQqÉÖ­;oÏ?ÿ©mÝzÂvîüØöîý ýH$@’¾I¾ãŽnûä“ç©S×Ý67ËÉsÍÏ¿aGŽ\ëŠyç½¶iÓgða<=\a‹©Añu“üÞ{ïÛ[o±×^ûÄÝälØpÎÖ®½h+W¶Ø¯~õ}góç_·[oí …•ŸíöÛ´»ïî´{ï½bsÙ*+¿´§žúIX ^ø ŒÖd¸bØÒB!€ŒÉMrþ}Ö°w¯}ðî»öáž=vøwìp}½yë-ûh÷n;úæ›vtçNûø7ìØŽÖXWgÛ·Û'¯½fÇ_}ÕNlÛf'¶nµ“/¿l§¶l±S/½d¿Ý¼ÙN¿ø¢yá;SScŸ>ÿ¼}V]mŸ=û¬Ý¸Ñ>}z£z¼Ú®±#¾`‡~õ¢(}Éöl±·nµ7oßf;fo³í7¿ju7o³·f×Ú¾_n²÷ç?gG­·Æ»Ÿ´ß?fgK+­©lµ]úÕJ»|ßýÖzß}veÅ »²|¹}ó«_YÛ²eÖvï½vuéRûöž{¬½´ÔÚKJ¬£¸Ø¾+*²ÎÂBë¼ûn»¶x±}úÿøaÑ"ûáÎ;­kÁ»>¾]ÏÏ·o¿Ýnüò—Ö=ožußv›ý4gŽõÌžm½·Þj½yyQÙ~WP஫×sù׿¶¯~Ø.>ö˜}þÔSvö¹ç#±k|ýuû(Äùƒÿ÷×¶ ¢’·{÷Û±ãcH5TO¡TÃöL5„oíÚ/Üp¾•+oåå­¶lY›-Yòm(x| ߇‚jd¬7ßµCǰøE’ÞÊ<ò…’¹uëI÷ÿwðàûÜ@`Œ15 ˆ|é½åw3­›jÝ\ë&[7ÛºéÖÍ·nÂu3®›rÝœ¿p¡»Y×M»nÞu“­›yÝÔëæ^7ùºéÖM¿nþt~%ZËËíëûï·Ë<ànÊ¿r¥µ¬ZeÍ=dÍkÖØW!_ ݨ_ª¬´/yÄš*CAcõ“vê×ìãûž³†²ì½ÒZ{»ðUÛ±°Î^Éßm/ÌÙcÏÜ|ÀžÉ;hÕsß³Í öÚËwï±×Jß¶+Þ²ú•»lß#oØûë^·#ϽjÇk·ºÿ㯼âB””BÕ±PPÈRØRèRøRSS(S8SHSXShkØ¿?*[…3…1…¯Ïׯ·¦Ç·Kîwn %1;1kýô…îlô æb,¦b(fbôÅÚµv~Ý:æòþ> ½þ£»vÙ‡¡×øþ{ïÅ|Oh‚õ0½ýöa×Ûôúë®ç©¶ö·®J7¢ê‘R}z§z¨Ùxà²-_~Å–.½ê†ß©5]Cð4ôNÃðT3¤¡xz¬ç´OÇèXýŒ~VçйtN[×еtM][¯¡®®ÑŠŠº™¹m|÷ÝßêYׂ‚>÷¢I) ¿sÿꩼ㎭¤¤Ãî¿ÿkŸ{òÊ «¯?Â$´&ö˜Da˜êKvî<êêMTw¢ú“ÊÊK®E7ÀºþÃÕn’uƒ\TÔáêYT×òØc]‹ê]T÷¢›,ÕÁŒ6[!×Ëôb­|æ;õøsvzÍzûôþ*û]Ù#v¡ä!ûrq¹µÌ¿×®Ì …ÀÙ ízÞ<ë•k=³òìûÜÛ훼Åvé–¥vö–ì“[*íPÞÓööÍ/ØöY¯Ymî›öü­{mÃÜCöDþQ[»ð„U~fÝsÁVÞ×ìz'ÔK¡OõZ¨÷B½êÍP¯†z74 †Þ½ûî1YQÜŸ5 ªùð¯ ú( ý?~±7KáT3ãéÿ^5]š¨¢°°ÓMN¡€¢a•K–´»`©¿½?¶m;î‚íD(Œ§‡+l15 ˆB ë†Y7Ϻ‘ÖM“n°~ø’›éëž{¾u3é&K­úšL³0©%X7`jÁWë½Zî£Ý(e¯Bõ†ÓöÊÆmׯP0{æmkØPgÇžÞb§×UÛçUOÙ<âzÔõMY™ë½R¯–z»Ô ösn®ëQ¯˜zÁÔë¥^.õj©K½V_VVZÓOع Ü0»ßÖÖÚñmÛìã;ìH(@ixïÙÔ !Zè–[,&~Ž>ânwÈM,¡÷÷ÓOŸsaUa^µ]sçþdyy (]n½ü½{oªaàÕW?qÓ|Óê‰á [¸@³`á!†*íÙó¡[E-ÁZ+Ek¦¬Yó•®2oÞ÷É®–A5 ªm(+ûÆÕ:Œe¯B¢ÖP. 9ÓP4 QÓP/ ùÒÐ/ ÓP°¯V¯vCÃ4DìÛ%KÜ1 Ó2 %SˆÑÐ2 1ÓP3 9ÓÐ3 ÇÓP4 IÓÐ4 QÓP5 YÓÐ5Èø÷¾}‡Ü{Y=Š ÅZohÙ²o\€V¨ÏËë û.7kžþ.žx¢ÉõíÛ?™ÐS{cŒ1¥E¡•cä¼tiï Z…“'»\O|~ãŠêU3£ZM` Úß«_Åø*ÊWqþïCªRýꊢÕ©~H=0 B .§jk]1¿z^â©ÁcÿY ${…o —T/^YY›ë}TŸfÌ[¸ð7SÞªU-.°¿ðÂ׳˜êÓyó9 WØbz@„qž#æW^ùÜ-êë!Ÿ~úëUŒð°ÁO7mr=&êÑP0 !S‹z^úrsÝÄ :¦õ¸h¨™‚ކŒ©çôæÍöÉ«¯ºÙÇ’*ÆØä‘­éÒ„  ªÓRY´èNR-úÞ…………™ººc¡Ÿm€-ïY [j@ ˆôõæÍg¬¨èºååõÙw^'|¤@ÝÒ{÷º¡c*âWËïžyÆ õÒ,bªaQO‹j^44LCÅTó¢™ßTë¢YÇ4DL52ê¡QË™Pè9ñÊ+öñÎnºäߌóé’Óá³@ô4Y„†miX¤ÖÒp.Õkix—†yÝu×57ìKÿ4 LÃÁ4=´†‡Á–÷,†-= ÆxÌê–íßï¦[V­‹Šé5Dì“OºÕ¸¨ø^CÃT¤ïM—¬b}MM­â|ÕÀ¨¦åËGuCËT”rË;VWg‡ß~ÛÞ?p€ÿ×Q¶ ÝUS¥ÂwÀÿú׿wñ©yÊß}÷5W8¯º¬õë?wõ*¬Wýp®ùÒKŸºÿÙ³ûlñâ4F`Œ ˆB+láPmK(P(XhÝç+p(x(€(ˆ((˜( (¨xÅø 0ZSFÁFGAGç·/½äÖs9²{· DLH1²“KhªàW_=î&ÐÂ>xÙM)¬©…5ŰfÁ+(èt3Íi bM¡‰(45±¦(Ž>üÃ15ű¦<&„ð [¸@ÐÅ‹­´´Ô233CßM9¶gÏžûkjj,++˹ººzÐÏÇÚŸèñãýzÔ€0ÖO`®*Æ×Œb;wºY¾4›˜†viˆ—†ziaJÍ"¦!` ¦!a¦!b*¦!c:¦!dJ¦!e§CçдÇZ€RCÎFchÛD (ZHÓhkñEÍZ§õ„4·gT@Ñ´ØZ´qÅŠV76áŽÏØbj@’Ô¥K—,/ôåwôèQëë볎Ž[·n]ÿþúúúÐo¡uvv:»çâÝ®dÏ—ê×£„– ×D­âxÍöÉk¯¹é‰U<¯"zÓ«¨^Åõ*²W±½ŠîU|¯"ü-rEù*ÎW‘¾ŠõU´ÿiM $°€ò¾íÞ}Ä-zªõ}y䋨l—-k³_ÿú² **–W¯Kmí)7£—‚N¤Ìglá:áHEEÅ ¿tó-¨ÿÚÑ“V ©3ãÜôùRýzÔ€`ŒG|XØ{ïÙáúz7Ýñ©-[ÜôÄš¦XÓkÚb-8í&Y=. 2*¦(5tLF=2ê‰QÐÑ2­ó¢¡e :ê±Q‚†–i =SR1¿zn”4äLÓ'khš‚Ñ•+¬õ¾ûìëòrûúìrèóñ÷¡×زr¥µ<ô5¯^m_­Yc—BaëRèõùÈ#öÅ£ÚÅP˜ºøøãÖTUeä'Ÿt¿£†¿{úi׫¤Þ!…µÏž}Ö1Ðð¸3¡ð¥^'MH 0w꥗# ŸÓÔÐê•Ò„ {ªC ¯ûø7\¯•&4PT~ç·Fަ˜nØ»×…ÅhlU(¯õ¤hJa ë*)iwkýaUù>7³W~þu·£½ÿþ¯]mŠÖGQÈÙ¼ù´[ÄñÍ7?rSóžÇ§]ÉÎζ]»vÙŒ3,##Ãý×®]ë߯aYêñ¤Çz.ÞýáJö|©~=z@héÀpMõÙÅöïw7Óº©Ö͵n²u³­›nÝ|ë&\7ãº)×Íù±×_w7ëºi×ÍûñW^q7óº©×ͽnòu³¯›~Ýü+( (|öÜsv6~ ¿ …†së×Ûç¡q>$·BÅ…'žp!CaC¡CáC!DaD¡DáDÃÑ4|M½<ª»QÈR]z‡4\M3™)ì(ô(ü() )))$),)4i‚…(…)…*M鬥°¥Ð¥ð¥¦0¦P¦p¦¦°¦ÐÖ«e声u‹p†®¡avz-z}zÍêÍR•‚Ô§ë6Ú'ë6[ïٞÇv[Ý#ïÙæÕGìékk–_´²Ò+nÇÛoÿÑÍòå Óº)¥¥ívß}WÜtĪgQ½Ê¦Mgì•WN¸¢zͦae|`ØÒ’ÒdÒ¤Iöhè¿§§Çº»»mmèrUèCÞ¿?\“'OŽ{¤ë%s¾T¾žÞžý* }éil ÷æÔ¿£±ÝÚÚ:ª×›HÛß}÷ò…ÕÔ´Ø®]ß„ÂÊ·ŽÊœ±¦¦Ôà­¶†÷ß_| ½=.ˆZó<<)ˆ¨'„z@0láÊôÆxl ü5ûšz¨Ô+¥ž(õ>©ÇI½LêYÒ4õ¦¨WE½+êeQo‹†ß}»¤ÔÚCå»ùwÙ÷óØõ[çÙO¹·Z_Î,ûéæ[íûÜÛ­-÷.kÎ]bŸß¼ÂNæi ó6ØoæWÛÅ/Ø{Kjí½å¯Ø{+_³ÖÙoÖ¿a /î´#ÛwºÜ4Ù‚†Ž'®˜ÏYz@R$€¨¨:<€øo°#Õ@è¹x÷ÇS“‘ÈùRýzÔ€`Œ1á.UghÓð; ¹Ó0;Õ¿¨&æÔKµvbã‹öÉã›ì“5ÏÛ±ûžµÆ¥ë­±àI;~çcvêö ;3g•»¥Ü.Þ\f-9Åv5g¡uÍšk½³ò¬7'×®ß|›uÞ2ß¾½m±]¹½Ø¾^¸Ô~_ø+kYZn-å¿vCèÔ¤™ÝTÇ£Úõi-½†Æ×_'€`<‘ˆ Ð5ìJ!DÖp¬5kÖ šJ³cE›%j¨ýáC˜’=_ª]Z:0\á Û‰fÇïÞý‘[²öÅ“öÂÓ'¬æ‘ãöÜöì½GmcÁaÛ8ÿ={Û{>o¯½tón«»åU{÷¶¬aÞzûäöµvöŽUöÅ+ìr~©}{ûÝQÈ<âBËÉ­[]ïËû¡0Åû÷,\Çù: µµµ6uêT7ôjåÊ•ŠÐ%­}mŒhû#ÕP$s¾T»ë€0ß7†+\a‹£[Ó××¶ººF·È£¦'Ö4Åš®XÓ—•}½n©²Òͦö]aaÿú9?Þq‡u””¸É4M‹|žxå;R_ïz{àÎ{v¢pe%ôòד¤ãõ补î°Å#[¢i‰Ã§¢Öœš…Mõ0—**ܔϚ"Z³—) hV³ö%KÜŒiZTµ3ZÐóðÛoOè€Â{– @&¢¨ÁcŒƒ«­Ñ”ÄEE¶yóoãšføP( |¼s§«1Ѻ1*Ôÿfùr7óOsçÚÏyyÖ (ß––ÚïCßÙªMÑÔÑŸ¼úª}øÎ;ü`j@„VZ:àŠá Û‰à_<íÖ@ÉËë³;ï¼n55Ÿºçµ"½†mi-”;ïüÁ-ØxàÀðW•?´oŸ›]Lëר(þ«Õ«í›eËÜú0Z÷E‹uvÝy§]½ç7ÃXÓO¸¢ùO¶ow³ñžÅ©4!QÂXO W¸Â WÕ,YÒîgÔêñ{÷¿Z¼V¼×"œšöøüºun¯¶²2·x¥·(å ÚÕ{ïu djJd-©ټ>Ø»—÷,à ˆ [¸Â°M7®¯¿Þh+V\±9s~²‡þʹÖëSÈÐ4Æ  -¡€¢0òâE.œ(¤|z¬Ð¢ð¢£0s,ô3 cPxÏ@ Œ1Æ'aM¼jUK(ˆôØý÷mo¼ññ˜¿& ÓjÜ¾Ý ÛºPUe-+Wºá\?Üy§Þ¥a^×B÷ö¥á_¦á`ïØá†‡ñÿ:²Ö$ú?Ò”ÎbïBŸm¡ÿ¯o—,±ï ìû… ˆB+láŠá Û‰ÌuÏžlíÚ/ì¶ÛºíÞ{¯Ú+¯œHÙßO…îºéUá» àÿë_»‚ø® \¼ å¯Ý}·+œ× ðçë×»‚zÖÆêóãzñÌP ÓÌešõLCÜ´p¥X(Üim…71ÔTÍêmÒ¬gWBÜ®.]jÅÅ®®G\5}³z¦ún¾ÙúrsÝc=§}:FÇêgô³:GÌÅ3ëê ˆÂ8OØÂöpÕš#‡ìé§ÏÙw\·‚‚N{á…3qÍœ•J7ݺá>þê«®5^S_ÝWhJaM-¬)†5ÕpgA»YÖÄj±×”ĺI?B@å z®çç[÷m·¹ž"›5Ëzo¹Åmëyí×q:þ›²2÷ó:ΧóêüºŽ®§ëêúzšpàÈ[oÙï¾kï8À,nÕ ´ÌÑê‰á WØâà¹*tlÚô©Ý}w§ÍŸße6œsádÜó -¶¨Vx-¾¨ï¯xÀ-ʨÅPÔ²¯E¬p­øÑn”S­Wáè›oÚáwÞ±†ýûS~½fÁBŒ1ÆGôÖ­'ìž{®Ú¼yÝöØcíÝw?Hßú”Ý»íÄÖ­îÿ‹G‰@R­W@= ¶p…+†mÚpݱ㘕—í Öz¨ÙÞzë³5ñ~÷ŸD ã“1\á [œâ\ëëØêÕ_¹)|W¬hµ×_?FÁãö³€‚补î°Åã„ëÞ½Øã7¹¡Y¥¥ßÚË/ŸLß2gÁâ=KAÔ€`Œ1Æéè÷Þ{ßžyæw¶`AWè;ûš=ÿü§vðàû°ÁÔ€ -s´tÀöp9kæ¬_sÖæÍ¿µ¢¢»ýömåÊË¡PÒk§O÷¹û’³g{íŽ;º !„q` W WØÂÃ6}¹@= ´Îa¸Â¶®°…+Q‚1ÆcŒÓÏD-®p…-†+láJAÔ€`ØÂ®¶pŰ¥„B¡•ƒ– W¸Âöp%€ j@0ÆcŒ15 #¢I“& r¸jjj,++˹ºº:áýAŸ/Õ¯G-®p…-†+láJ‰@¢©¾¾Þ ­³³Ó¹¸¸Ø=ïþ Ï—ê×£„±ž®p…-†+lášV$RE$ßtÓMÝ|+ÕyÒã‚‚‚¸÷}¾T¿= ´t`¸Â¶®°…kZ ¿‡ “'OŽ;€dgg»ãçÌ™cµµµögffZ___ÿ¶ë¹x÷‡+Ùó¥úõ¨ÁcŒ1Æi;kÏž=®…¾£££ÿ¹ööv÷ÜÁƒ>_ss³•••ÙÆ£öøÃM¬ýñô¸$r¾T¿= ´t`¸Â¶®°…kÚiÓ¦YOOÏ çõÜôéÓ‡uή®.WlMHâ×ÓÀ³_EEEnl ÷æÔ¿£±ÝÚÚ:ª×›HÛß}÷ØËï¯Q j*€Ä[+€DªÐsñî§&#‘ó¥úõ补î°Åp…-\Ó¶Dµ*ˆÖ°+µÌËW¯^µÅ‹ÛÔ©Sã:GEE…µ´´¸ÇmmmV^^nUUUƒfÒ0¯h³D µ?|S²çKµëQ‚1ÆcŒ'T ÈPEèˆë –ŸŸï~fæÌ™®þ£»»{À1Zû"Ú:ÑöGª¡Hæ|©v=z@héÀp…+l1\a × @¼!A999–‘‘á¬ÇgΜI™UÁõšÒùz¬Â|ß®p…-†+lá:¡J=ÑBK†+\a‹á [¸@Є cŒ1ƘÀÈÒ¥KÝ´°Ã] Ñ‚a W¸bØÂ¶˜¸¤E½°1Ü•Ð5 ¶p…+†-\a‹©‰Kš•©±±Ñ=öz<®]»fË—/·Ý»w“èáC¶pÅp…-\1lé v!ÂHµH¼ë€ j@0ÆcŒ15 q-ŽçM?«5=¤cÇŽQB¡•¶pÅp…-\1lé 6€ìÛ·Ï*++Ýã¹s稙1cI€>` W WØÂÖ‘™†···×­d®žéÓ§[OOI€>` W WØÂÖÖ!€`Œ1ÆcLAô€`ØÂ®¶p…-¦$ºvíÚeÓ¦MPtž››kW®\! P‡láŠá [¸bØRlz¤•Ï?n………$z@øP€-\1\a W [z@‚ *:öÙgݺþÒÕÕeS¦L! P‚1ÆcŒ© .€øCGøº¬B¡•¶pÅp…-\1lé 4€Lž<Ùnܸ1(ptttXff&I€>` W WØÂÖàˆŠÍ,X`ííí.€h-óçÏ»`’ŸŸO „ØÂöpŰ¥$¸réÒ¥«ŸûÝÙÙI cŒ1ÆSì4¼ !ê ÉÈÈpf ^­°…+†+láŠaKȈDaœ'láŠá [¸bØR2ê³`¡ââb7|˯HûÂUSScYYYÎÕÕÕ1¯ëød÷õõ补î°Åp…-\Ó2€hÈUPÚ¿¿D ÑT__ï=T͉¬£ç†{|²ûÇúzÔ€`Œ1Æã´ 999nÑÁduýúu›={¶]¾|9ᢛs¥>Oz¬ 3Üã“Ý?Ö×£„– W¸ÂöpMÛòÑGÙüùó“žñjÆ VWW1ph;;;ÛMí;gΫ­­°_ëh%vOzm ’XÇ'»¬¯G c=1\á [ WØÂ5mÈPSðÊñÖ‡455ÙâÅ‹ãêñhnn¶²²2Û¸qcÔãV¢½æhÇ'»¬¯G-®p…-†+lášÖEèC9ÖM²'…–––¸‡\iÈ—Š±é‰<<ûUTTä’±÷æÔ¿l³Í6Ûl³Í6Ûl³ìö¸œ†w¨”xH¤ =—HM†ÿød÷õõ补î°Åp…-\Ó¶d¤‰_ý=$mmmV^^nUUUƒf‰êèèˆ8KTøùbŸìþѾ5 ŒõÄp…+l1\a × @zzzlÆŒIÕ€Ä –ŸŸïžŸ9s¦«ÿèîîpŒÖÆjŒH½)ÑŽOvÿh_Z:0\á [ WØÂuÂÜÜÜc85 #­ ×*IÅë±ÆcŒ1žPEè4”Z¢„– W¸ÂöpMË’*½ˆÆzb¸Â¶®°…ë Z =ÙE= ¶p…+†-\a‹é‰KÇŽ³¹s纚cŒ1ÆSx‰¶úy³`!z@0lá W [¸ÂÓ2 ð<SBaœ'láŠá [¸bØRè,D¡•ƒ$¸b¸Â®¶ô€@ Ô€`Œ1Æãô Ñê<¨!€ÐÊ[¸b¸Â®¶ô€ŒJ¹ví„Â8OØÂöpŰ¥$˜Ï,X™™™$z@øP€-\1\a W [z@’ ÞLWÞt»áÎÊʲºº:’5 cŒ1Ƙà†`1Õ.„VZàŠá [¸bØÒ2âdÚ´i¶jÕ*kmmånŸÂ8OØÂöpŰ¥ddÈÂ… ]‡†`©dÞ¼yvüøq»qãwÿZ9` W WØÂÖ‘‚ÕÖÖf›6m²™3göŸçääXMM]½z•$@ ÆcŒ1¦$¸â—z?NŸ>msçÎu½" #S¦L±‚‚= ¶p…+†-\1léÙ•ÐURYYi3fÌ P‚a W¸bØÂÖ‘ ˆB+láŠá [¸bØÒ’t‰gBo}D ÆcŒ1¦$©¾èàPd8k„»Ÿ —ŠÚµ¸¡\]]ðþ Ï—ê×£„– W¸ÂöpMË!X{öì±ÂÂBëèè讽½Ý=wðàÁ„εÿ~W°@êëëÝù:;;Rô\¼ûÕìùRýzÔ€0Öî°Åp…-\Ó6€hAžžžAÏë¹éÓ§Ç}žëׯÛìÙ³íòå˃ˆn¾•ê<é±f­XûÕìùRýzô€ÐÒá WØb¸Â®i@† ‰Ô€lذÁêêêúÏé—<ìëëëßÖc=ïþp%{¾T¿5 cŒ1Æ8mHvv¶k×°+ÝËZ€pñâÅ6uêÔ¸ÎÑÔÔäŽ÷‡šð.}I¬ý‘BS2çKåëé àÙ¯¢¢"×5ç¥cý;Û.\ÕëM¤mMs à·=Ã÷ëxÙÖç,<øþâó€í±üþ“¡ŠÐ8×9>ZZZ†¼á¦düö€0ζpÅp…-\1l© |¥ŸœœËÈÈpÖã3gÎ$=­o´=ïþxj29_ª_Æzb¸Â¶®°…kZ 5Ô,Xši+Ú,QCíú|©v=j@0ÆcŒ1$À"ií‹hë`DÛôùRízô€ÐÒá WØb¸Â®&€h¶«3f¤ôJè–Î×£„±ž®p…-†+lá:aHnnî€Àá÷pVBGé@hå€-\1\a W [z@ ‰®xŽ&NÁcŒ1ÆÔ€@èå €ÐÊA \1\a W [z@F-€hÊ]ÍÌ„ Œó„-\1\a W [j@F<€;vÌæÎ릈EZ9` W WØÂÖ C-"˜J³`@¨ÁcŒ1ÆiT„>”©!€ÐÊ[¸b¸Â®¶ô€@„qžŒ¡…+†+láŠaK „B-®p…-†+lášžäôéÓ6kÖ,7äJÖc=‡ cŒ1Ƙ@HccãEè„­°…+†+láŠaKH D½K—.µöööþçô¸¤¤Ä­‚¨áC¶pÅp…-\1l© ,€hÈUOOÏ ç{{{-##ƒ$@ °…+†+láŠaKH°¤»»{Ðó %ÆcŒ1¦$Ð’››kvõêUëëësÖã… ºáYˆþ0a W WØÂÖÀˆ ͇*B?wîI€>` W WØÂÖ`§áUÐPo‡†\ÉzLø €ÐÊ[¸b¸Â®¶ô€ŒHAŒ1ÆcL „B-®p…-†+láš^äСC¶fÍšAÏWVVÚ‡~H „ØÂöpŰ¥$¸2mÚ4»víÚ çõÜŒ3â:ÇñãÇ­¸¸ØÕL™2Åͤå)R{¸jjj,++˹ºº:æ5cŸìþ±¾= ´t`¸Â¶®°…kZHaÀÓM7Ý×9´’ú±cÇÜâ…šÆwûöínßx®!Õ××[aa¡uvv:+Ìè¹áŸìþ±¾5 cŒ1Æ8mˆZäÛÛÛ=¯ õf WþE cÝœ+õyÒc­M2Üã“Ý?Ö×£„– W¸ÂöpMÛ¢[õt477÷/DxéÒ%bÝ$G’~¾®®Î–-[6 €dgg»U×çÌ™cµµµ~&33Óýœÿzn(Å:>Ùýc}=j@ë‰á WØb¸Â®i@Të1ÔB„]]] ç’§OŸn---QÐ)++³7Fí!QXIdؘÿød÷åõôðìWQQ‘{czéXÿŽÆö… Fõzi»µµ#°í¼_Ç˶>gáÁ÷Ÿlå÷טLëáV¹¹¹ý æååYGGǰΥÖýmÛ¶ÙâÅ‹‡Ùýc}=j@ë‰á WØb¸Â®(ªªª²Ë—/÷‡ M3ë¿Á®¨¨è’ÕÖÖfåååîgÂg‰R¯K¤Y¢Â‡0Å:>Ùý£}=j@ë‰á WØb¸Â®*€ìڵ˭âŸvWC²®\¹×Ï744X~~¾»qŸ:uª[ÄÐ?„Ë¿æÌ™®þ£»»{À9Z†Z'#R E´ã“Ý?Ú×£„– W¸Âöp0dß¾}ýÅãþ¢Åc -ù§ôMÇëQ‚1ÆcŒ'LQijÏ>ë £ýDC©’Y¥G¡•¶pÅp…-\1lé 4€øCGøÊçñ®„ŽÒ7€0ζpÅp…-\1l© 4€h¶ª7n ªáˆ5U,¢Ã®pŰ…+l1= IÅæ ,°ööv@z{{íüùó.˜¨pQ‚1ÆcŒ© ,€\ºtiÈ•Ð5e,¢„?LØÂöpŰ¥$ÐixBü+¡'2/¢Ã®pŰ…+l15 ˆB+-pÅp…-\1láJAÔ€`Œ1Æã \ÒÚÚê†\I*@Ÿ>}º«ÿ˜5k)€B+láŠá [¸bØÒlY¸p¡]¼xÑ=^¹rå€"ô’’’5 |(À®®°…+†-5 Á­õÑÝÝíϘ1ógÏZSS+¡@hå€-\1\a W [z@‚ ž´ö‡¶{zzÜ6+¡@0ÆcŒ15 ¬¬,×ãÑÜÜìÂGvv¶{^½"Ú‡èá¶pÅp…-\1lé ,€èÆÖ_÷QZZêž×84­Ž¨áC¶pÅp…-\1l© tÞ™3gºáV999ýÏååå¹²= |(À®®°…+†-= ¬BÁcŒ1ÆxüiÓ¦ÙªU«èå €ÐÊA \1\a W [z@F>€hýMÁ«ºÍ~5oÞ<;~ü¸Ý¸qƒ»ãëîî¶õë×»@â ÑT__o………ÖÙÙé\\\ìžîñÉîëëÑBK†+\a‹á [¸2 VRñ›XD7ç‚îI †}|²ûÇúzÔ€`Œ1Æã´ ‡²5kÖ z^è>üðÃaóèÑ£ƒz@²³³](™3gŽÕÖÖ8^µ& -þ­þ$ÖñÉîëëÑBK†+\a‹á [¸¦m™6mš›ñ*Ò,X3fÌHø|/^´yóæYkkkÄýÍÍÍVVVf7nŒÚCmhX¬ã“Ý?Ö×£„±ž®p…-†+láš¶$Úð¨D§á=uê”Íž=Ûššš¢×ÕÕ励é‰<<ûUTTäÞ˜^:Ö¿£±}áÂ…Q½ÞDÚVH‡GðÛžáÁûu¼lës|ñyÀöX~zQhooôüÕ«WÝŒVñª¡¡ÁfÍšeçÏŸylx‰T#¡ç©ÉðŸìþ±¾5 cŒ1Æ8m{@tc«ž R˼|éÒ%×3«PÚÓÎ;-''Çý\$UTTXKK‹{ÜÖÖfåååVUU5h–(MÝi–¨ð^šXÇ'»´¯G c=1\á [ WØÂuÂÕz µ¡z*’YÔÐß;’ŸŸïž›9s¦«ÿÐt½~imŒ¡ÖɈ4L,ÚñÉîíëQÂXO W¸Âöp0Än•››ë”óòò,$8ÖÒkJçëÑBK†+\a‹á [¸N¨‚ROÔ€`Œ1Æc¢Ã®pŰ…+lá@H²Zºt©›6¼†#ÑixQúÆy®®°…+†-5 - è…ðk±` W WØÂÖ‘™†···×fΜéz>¦OŸn===$j@0ÆcŒ15 k= ´t`¸Â¶®°…kšê< Œód -\1\a W [j@F-€¤ÂªßˆZ:0\á [ WØÂu‚œœëêê⎟‚1ÆcŒ©ùòÑGÙüùóû§âEZ9` W WØÂÖ]d(SBaœ'láŠá [¸bØRxúPž` W WØÂÖ¦á%€`Œ1ÆcLAô€`ØÂ®¶p…-¦dxë€PBaœ'láŠá [¸bØR2*äÚµk­°…+†+láŠaKH0$ÚìWž333IÔ€`Œ1Æcj@’ ÞLWÞt»áÎÊʲºº:’= üa®®°…+†-= Á Á bª]¯I¼½-᪩©q¡G®®®ŽyÍXÇ'»¬¯G c=1\á [ WØÂ•Y°â"‰<奄¾Þ Ýjìrqq±{n¸Ç'»¬¯G-®p…-†+láJÁ¢›sA÷¤ÇÃ>>Ùýc}=j@0ÆcŒ1$É’í†{Í™3ÇjkkìW±{___ÿ¶G+€u|²ûÇúzô€ÐÒá WØb¸Â®$ˆ_ÍÍÍVVVf7nŒúsÑjSbŸìþ±¼žÞžý***rc½7§þíÖÖÖQ½ÞDÚþî»ïà1Ûáÿ‡÷kªoës|ñyÀöX~¥}‘ººº\16= ô€ÐҸ¶°…+l1= £@"ÕHè¹Dj2üÇ'»¬¯G ÆcŒ1&€$@***¬¥¥Å=nkk³òòr«ªª4KTGGGÄY¢ÂÏëød÷öõ补î°Åp…-\ I®ªîWCCƒåçç»çgΜéê?º»»£µ1†Z'#R°‰v|²ûGûz¬Â|ß®p…-†+láJI!edd¤õõ补î°Åp…-\ ˆ‚1ÆcŒ©!€@h堥î°Åp…-\ (-ã_ª_Z:0\á [ WØÂ•’DÉÌÌ´¾¾¾þm=Ösñîú|©~=j@ë‰á WØb¸Â®$H¤ç'Ož÷þ Ï—ê×£„– W¸Âöp%€Ð2*×ÓÀ³_EEE.{oNýË6Ûl³Í6Ûl³Í6ÛÉnO˜=ïþ Ï—ê×£„– W¸Âöp¥$€Y°:::¢Î5Ôþðó&{¾T»5 ŒõÄp…+l1\a WÈ0×j=­}mŒhûƒ>_ª]Z:0\á [ WØÂ•’BÊÈÈHëë±ÆcŒ1&€ ­°…+†+láŠaK„Â8OÆzb¸Â¶®°…+Ñ‚a W¸bØÂ¶˜DÁcŒ1Ƙ‚è¡¥p…+†-\a‹éAÆy®®°…+†-5 ­´t`¸Â¶®°…+Q‚1ÆcŒ©AZ9hé€+†+láŠa W¢Ã®pŰ…+l15 ˆB+láŠá [¸bØÒB!€P‚1ÆcŒ ˆ [¸Âî°Åô€ ã<ë W8À¶®°…+Ñ‚a W¸bØÂ¶˜DÁcŒ1ÆÔ€@ ô€ÐÒá WØb¸Â®D †-\áŠa WØÂD¡•ƒ– W¸Âöp%€ j@0ÆcŒ15 £¬I“& r¸jjj,++˹ºº:æ9cŸìþ±¾= ´t`¸Â¶®°…+$‰MõõõVXXhÎÅÅÅî¹áŸìþ±¾5 ŒõÄp…+l1\a WÈÝœ+õyÒã‚‚‚aŸìþ±¾= ´t`¸Â¶®°…+$É’m“'O¶9sæXmmí€ý™™™Ö××׿­Çzn(Å:>Ùýc}=j@0ÆcŒ1$ 577[YY™mܸ1j‰ÂJ"=*þã“Ý?Ö×£„– W¸Âöp%€¨®®.WŒMHäàáÙ¯¢¢"76Ð{sêßÑØnmmÕëM¤íï¾û#°þ/|x¿¦ú¶>gáÁ÷Ÿlå÷ׄ ‘j$ô\"5þã“Ý?Ö×£„– W¸Âöp¥$ UTTXKK‹{ÜÖÖfåååVUU5h–¨ŽŽŽˆ³D…aŠu|²ûGûzÔ€`Œ1ÆcH€jhh°üü|wc?sæLWÿÑÝÝ=à­1Ô:‘j(¢ŸìþѾ= ´t`¸Â¶®°…+$…”‘‘‘Ö×cæûÆp…+l1\a W"€ÐÊ[¸b¸Â®¶ô€@ cŒ1Æ@= ¶p…+†-\a‹éAÆy2Ö®®°…+†-\ ˆZ:àW¸bØÂ¶˜DÁcŒ1ÆÔ€@ ´rÐÒá WØb¸Â®D †-\áŠa WØbj@„VZ:àŠá [¸bØÂ•‚¨ÁcŒ1ÆÔ€ ­°…+†+láŠaK„B c=1\á [ WØÂ•‚èÁ°…+\1lá [L"€`Œ1ÆcLAô€`ØÂ®¶p…-¦@çÉZ¸b¸Â®¶Ô€@ ô€ÐÒá WØb¸Â®D ÆcŒ1¦@h堥î°Åp…-\ ˆ [¸Âî°ÅÔ€ QWMMeee9WWWÓ‚a W¸bØÂ¶˜42ª¯¯·ÂÂBëììt...vÏQ‚1ÆcŒ©AKáC©Ö“ÐBKà W [¸ÂÓ‚‚Wff¦õõõõo뱞£„±žp€+\1lá [L  \“&MôÜäÉ“‡ žý*--µ{î¹Çõ¦,\¸Ðý;ÛK–,ÕëM¤í²²2xŒÀ¶gxð~/Ûúœ…ß_|°=–ß_z@B!„JY@Æ"Õ€è9„B!„ (py³`uttÄ= B!„B4liíDÖ —¿6cŒ1Æã MA)£Dß¶p…+‚-\a‹Ò›+ñÇ[W¸ÂÁ¶p%€ „B!„ÒO„B!„!„B!DA!„B!J-Mš4©ß(8?~ÜJJJ,##æL™b•••n}”[S]ôxŒ‚,X`ííí€@7ÝtÓ¸û#€ ¾$DZÔBGHð¡®®®Îõ6¡`´aÃǔτ`?[5|E sæÌq-ž(‰ë®]»lÆŒî&Nk+\»v 0wUUU" Ýÿýî3@ß_òæÍ›ÝsDAKc”çÍ›çÆ~¢àÞ¯òôéÓ­¥¥ ¨©©É/^Ìgª¹¹ÙÊÊÊlãÆÀèsàÑGµžž7ÔuíÚµ¶jÕ*À¨»îºË uCÁ¨­­Írssû¿Ãô8Õ{— ˆ2uêÔ)7¤E7w(X©õhÛ¶mnšÑð%Žþ0ÇgÂȨ««Ë²²²€TÄ«àáIA„!™ÁéäÉ“)ß:?Þ¤ Ôâ¯IõÑDgjhh°Y³fÙùóç1‚¢¶&¸Ïfl"€Œ'i¶¶ð¢P‚‚‘&£8{ö, Føû*Õ¿Ã ˆ2Ž´sçN7%$]×ÁJc‘½) u#§™Y ÃgBÊJ…Ò^Ï’†_”——3¦> ©]îBd ÇÒÔÜ(y>}Ú¬4ã•ê>ü5 Ì‚…&ìM-ž£Ã¶ÉK½JšÆP,§NÊú*qõž9s¦«ÿð·Ú£ä¤!,ú,ÐЫ•+WR„Ô»¤)ÏQ°Rc„·F˜¬Ç©^ÇHA!„B@B!„B„B!„"€ „B!„ !„B!DA!„B@B!„B„B!„"€ „š / q²`(B@B¥AÐ € „!„"€@Bˆ‚Bh|‡¿Ã÷544ØâÅ‹-##Ã233­´´Ô._¾<è¸C‡¹ãtŒÿ<§OŸ¶’’÷üäÉ“mþüùvðàÁA¯eÇŽîçnºé&ËÎ檪*»víÚ€cÞ}÷]ËÍÍu¯eΜ9ööÛozÝmmm¶fÍ›2eŠ»žÎµzõj;sæ ÿá!B!”*!d¨ç*®\¹b}}}ý!aÁ‚ƒŽ+..vÇùuêÔ)(ZÚÛÛ­··×Ö®]ëŽWxðkÛ¶mýÁFaFÇèXO}ô‘{®¬¬ÌYÃ_¿^›¶?î¶oܸá^B@B¡ _~ùeÿs !^/Eøq---ƒÎ¡›~íó÷˜ôôô¸çfÏžóu©ÃSaaá ×sñâÅA¯_¯Mnjjâ?!DA!„Æ[‰õ|´ Š4Ì+<Ä( ,_¾Ü=iH˜†]Åóz¼Y?£!_ëׯ·«W¯òŸ"€ „Bé@¼Ð ž“hòBƒXÖpˆj@***lúô邌‚B@B¡4 *>×¾£GF} ^O‰' ç ?o¼C°üRÍÉáÇÝ~]!„ !„ÐkÚ´iî]EâAÏ>ûÌÍ~5wî\knnvÏ©x|ß¾}.PxRï„Ρ° ‘+V :¯¿½««ËyÙ²eƒŽ[ºt©}øá‡î<’fáÒþ»îº‹ÿl„!„kiØ“¦ª7X$@$ƒ?øàƒ®¾CÇ)ðhš\ÿ´¸ '†¥úY³fÙ®]»"žWÓðæåå¹Þ …m‡§ó®ZµÊýNÞ”¾’E Bˆ‚B!„B„B!„!„B!„ !„B!B!„Bˆ‚B!„B„B!„!„B!„ !„B!B!„Bˆ‚B!„B„†õÆþÅ/0Æãqo„ £‚Bñ]†!>´B!¾Ë!>´B!¾Ë"€ ć6B!¾Ë"€ ć6B!ÄwB„FüC»½½ÝV®\iYYY6yòd+,,´Ã‡Çýó“&MŠëYçÏÎζU«VÙùóçGìwò®7ÔkkmmµeË–Yff¦³_¾|yÈó?~ÜJJJ,##æL™b•••ÖÑÑ1`qqqÿþ5kÖØÕ«W‡}>¿tÞXŒc]?Ñ×'=zÔòóóÝÏäååÙÛo¿‘o8ë¡ö õ;Ä⦦ƽ?åêêê„þ¯cýüH*QA]o´þÎbýß%úûÆ:>Gýžñ(ÒßQ¢ÿ/±ŽOôse"þ@!ˆ“‡¾8nܸa}}}öÙgŸÙŠ+ žt]»vÙôéÓGôæ(ÚkÓþ–-[¬··×¹¶¶ÖæÏŸ?äyt#ÑØØèøtwwÛúõëÝ—¹§¥K—Ú±cÇܹtÌöíÛmáÂ…Ã>Ÿ§ýû÷[AAALƱ®Ÿèë;{ö¬Íœ9ÓNž<é¶VÖ­[—Ðÿy¼ÇÅbQ__ïޣκ‘Ôsñ^+ÞŸ02š×¿³xßljþîñÿá‡Æ(‡ú; úu%ú¹2ÿÎ ˆ‚P:œœ¡Cj-¦¶¶6»ÿþû]‹žŽ-++ëo9‹·õ0Ҿݻw[yyù€çt31uêT×J§ÖÛëׯØÿì³ÏºOµàíØ±cØ_Ì7ÝtÓ çtÍx¥/ñXÜ’=Ÿ~÷Ù³g»Ôáܼƺ~´ýúÿÞ·o_Ò7ˆÃyÝá,tSãÝ Iz¬›Éx¯ïÏÇRèÞ-tg6gŽÙ’%fGŽ$@ây.ÖßD*üÅú»©²`Á׃MÑþŽ‚~]‰~®LÄ¿3"€ ”n$‘ç}Ò—ÄÆíÊ•+÷Ï›7ÏΜ9ã¾°Ôª§›“ŠŠŠ„¾ü"£ZÝàxzñÅ]Ï‹ZÏtG}t@kà¦M›\øÑþžž÷:†ûŬ/~µNêw’7oÞìž‹W6©¥×ûb¯««s-Žñ2Št¾ 6¸óDúùhç‹týDöKú㱸1 g¡à«×ìýz.ÞkÅûó±ÂÇ]wYèïàÛŸþ‡íDBÈpH¬¿‰Tù;‹õw1DתªªŠùs±þŽ´t#>'”,õ™í|±ŽOôse"þ@!ˆ“z3ôE>cÆŒþÑhõúbñßÐ 7€Hþ¸œÐkõ‡ Ý8ùÇwk¨‚ÆXq#£^ÜÜÜþž=ŽÕ’êéâÅ‹.”Ez-Þù4쥥¥%.F‘Î×ÔÔd‹/Žz#4Ôïéúñî÷ÿ4Þ±ç‰ÞEb鉴²ÇûóѤ¬æ…O !ÅÅ#@býM¤ÊßY<A»B ðÒ¥KQ.Öß‘_ÍÍÍ.x©1f¸Ç'ú¹2ÿÎ ˆ‚Ðx ñµJpH–†+¨Äÿ¥­Þu¯«5Ëûô5nѵƒŒçá\'Þ/ËÒÒR×Ré«=T†_§NrÃ9tc- mÛ¶mÃDϧŸ7À$zýx^ßX´ÌÅb,z@ÂÿdæÎ|ÌO?%öç5œëo"UþÎbý]@4¼'žËDÿŽººº\u¼ ?>ÑÏ•‰øwFA„Æs‰tÇ”Èó1ÞbªY±ô…*éßð›¤á|Ajlºÿ&B×j&()ÈH-s±ZÅlÖ¬Yqô&s¾ fNŠuýhûU30šcÓ£±ˆ4¶\ÏÅ{­x>šFªD7þþ›6……ðh©ðwÏßEÐDÃFUÀÏyù;J6€$ú¹2ÿÎ ˆ‚¤ÿKÐ_ã¡qËþ™[T¬ªÙS$ݸ¬^½zÀ—¾€c _Šgvž­[·ÚòåËÝ0I-—þZolº^C²5 úýô{úÇjG›­fçÎîÆ-|ȇ' aó¦ÛÔM‰Š|ý_¾á¯#ÖùbýáÛ±®k¸ts§!y§OŸvÛ#9;O,Þì:úOfvžX?M#U¢"jÕ'è=¨×§áþãbýMŒõßY¼ïã ˆÞ“CM"Ï&¿ô{{=$â¡ÏB]I¢Ç'ú¹2ÿÎ ˆ‚Pºa΂¥bD}q¨5V]æ*Põ×~ÍO¯ýj=Ó™ÿKHSºzC9¢}AzV ÑV¤áº9Ò¸i]KSZ‚˜KºAõþ¶‹õ7‘jgá½£A®³!éÆVSJ@üêùÑï­)j‡{|¢Ÿ+ñ ¥SA!„ø.Cˆ‚Ú!„ßeˆ‚Ú!„ße@âC!„ße@âC!„â» !âC!„â» !B#ò¡1Æw#DA!„B¡$ôÿ_li­”žŸpIEND®B`‚Multiverse-multiverse-0.7.0/charts/boxing_overhead_bar.png000066400000000000000000001546311174000617100240420ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix€IDATxÚì½ÿ«MÏûÿÿøÓNòî%’WD‘ˆÈD$"¢ˆˆÄƒH""ñ!ʳD‰Dijěȓˆ<м"óyݦ÷œæ¬3kfÖì½ÎÙûœûM+ëìµ×|¹Ö|¹®k®Yû/ó¿üõ×_F!„B!ÚÂÙÉB!„BÈB!„BÈB¤zTN#•g/´^i‡½ØF³L„2@Èÿý¿ÿ7z„øòå‹Ù²e‹™4i’™8q¢Y¹r¥¹{÷nWd¾ÃAúS¦L1[·n5/^¼hu’pGˆ>˜uëÖ™ÿú¯ÿ²çïß¿¯MïáÇfõêÕæÿüŸÿc&OžlvîÜi¾~ýš_¬|¡ûBב[«V­–Þ?ÿüceNù§NjNœ8‘LçÞ½{fÑ¢Eöž9s昫W¯FËçò¬»V'›”láèÑ£¶}r9r¤Ñ³NÝ?R ÆXS\úÙñÓ ¥Ù|Bý°I½d€Œ/D†¢¯ Í›7G(h?þ4þü1Ïž=36lèºâ ŸK—.™ÿþïÿnÕ‰• ÅúÔ©Sæ÷ïßö8yò¤Y¼xqm:(<°òùŸÿùsàÀ«4—N"M'›;wî$g¸yó¦Y±bŰô·oßnvíÚe~ýúeË¿{÷î!E•çÏŸ›3f˜GÙ¿?þlöíÛ×J=S²½råŠm£ß¾}³ŠŸåæ•{¿ñc€´­ü×õC 2@„BÈÿƒU‰Ÿ>}2›6m²+|wíÚµƒêwÝ }ùòe³qãÆ!Ÿ¡dã¡ÇŽÇþÇC®>|Ø®à)¿páBñd1a„aŸ‘g.(Ë!¹µe€,Y²Ä®TÅ@Vsçε+9Õô©ʽƒóåày߸q£ãò—LÖUÙb<8C8G¹ËÍ+÷~?³gÏZ¹íرc˜ìöìÙ3¸¢Â¹»Ž1åçõäÉ“Ac¾êuÇš5k–­+ÆïË—/¯c(’/ùSŽ3gÎdɲ®loß¾5óæÍö}ÚËëׯ“}¼éoÓ§Oì;©:¤ÒŒ+¥2 ŽïÞ½³çô¾ïÒ¤_P_ÿYÔ_9u+é‡uí­¤ ¡gÒ¶ÌY]¸p¡½>{öì¨#7϶úB*ÝX?N¥Û¯ãƒBô”‚2vèÐ!óñãÇàõ ˜§OŸZÅÕŒ¿&Jfè;¬„`H8Ž?nc¼ÔäƒÇÞ÷º;vÌN^\g¦¥ 0"«Ô‰ƒ$>Ë…‰¸É H(Ä CŠÉ¥‰²ÄòbKåsðàAsþüùàõª‚üPêà¹ðÑ0@ª²¥œ<#ß@ •½.¯Üûýt0Œ¿ÿnÎý¶F_¡ú×ù Pæé/.?ÚWU0PiË|…féÒ¥C mÒEy$ÚfŽ,ce[¶l™Ux?¶Ÿåô=òf­j”ÄêJ35®8øuIÉ€Õ³k×®Ùs8”3÷÷õë×ÍþýûƒÏ"Ôbu‹ë‡MúIª ¡gҶ̧M›fW+#ÂO»Žœù#§/4i9éÆúJ*Ý~„¢§ &\åÞïßo‡”…¾áàÜ/ç(ºö°œ;wΆb4‡ÊÁ¹oVW}ȃ6ê·×YÆÊÆŠ£¯øqÎg9}¼Q†ªrŠÕ!•fj\¡¿WŸCJ÷ïß·mPQÔœcqë¹H¬nu¤úaS$V†Ð3i[æxäYu‰Í)BóG¬ž%í ·ÅúñX„¢§ <*ìñ'Q¼W„±à5vЦ¿ä_j€Wu"ÂrGI>¹Jéš5k쪃¿$’ä{ ¯¨ Ç(ðb±\_…åúœ•ž— = •ƒMè¼h¹2y]¼x1ª˜ŒÆ HlGc$f°¤®ß¾}Û†©øá@¹Joîõ’²£ŒRoú‡;/í{9uˆ¥Y2®¤dÀ³Å™@Ÿ¦?¹ÿÝç®”È:Gþ©~ØÔ)i#mÊœ¾É<ÂØAûfµ2E§yv³/¤ÒÍ12ûy|Bˆž5@B&^5ÞŠÅdüŸ sG¼¯¾rM>Õ·ùts$4Ѥ&&<€±óÝ6@cCxN=sß:„¥¾QËû#¹$&ÛÐ>ËÍ+÷~?”‡³zÝ÷pºMî´o?t®‰Qõp’_î H¬lx_1>ñbû«!©¾W¢ §ÒL+¥žoV>Z¿~ýàß<÷w›HÓ~Ømd$eŽÃÀï¥y¦êÙÉ HªÅúÊX„¢§ ”M?F—ýþ¡ØÐèÇýâàv(Ω𥜷`>}Ú* n`Å;ä+Ineètõ£žþØ[°PÚ˜H«¡P¹ùU?§^ÎûE}yÕ}Äë×m–Î ‘òÙ»w¯•uÅkÉJƒï}«‚ÑÃ$çö ´ù¬”lÝ[¬('oÁJÝï§ãâ«9ª1Þ~L:×Qp]øýhþüùƒßåån“wÃ…¹2Ðwsd+›kSx_y  dnß+QSi¦Æ?ÎÝÕ%G(v¤íöað?c cN¨œ¡ñ«[æÜ{Jʺ޶ÌIË9h?¤—"•gN_(i¹éÖõ•±8>!Dk›cGR4–ÅY&gÀô=8\çw ¸Ž—…ÑìˆguËý9žA&$â±CaLL „JJÒ­[·†\g g²N½+å…dbv¿=ÁÁyL!Oy6s~×Ã?õãs<|Ô«úe³Þ©ЇÛãCø{-R¸ßáYðüÙÄÛÔÓÛ-¯1oöÉùºrÄ·Ê¸7 ¹×;xNc®í`ܹë´#^™ì@áÀhnª`«¬ÊQÊ“+›ƒgÉѤÄÒL+”Ùû2ÈiOÎì;þ¯z­Sã×H %e¨K»M™“ 4×1dsB°Ry¦êYÚrúXª¯ŒµñA!Z3@„cÞ”ƒR)„„2@„­Àªá¼@ 79Ž9ÒèY§î)Åe¬)Dýl€øé„Ò,Í'·Íçä'¤7 6B ä_ÿûwìÁ‚öóçOóçÏóìÙ3³aÆÖ&ò¹té’ý×6XÙP¬O:e~ÿþm“'OšÅ‹צƒòàÁ+~qöÀVi.œšNbwîÜI*ÎpóæM³bÅŠaéoß¾ÝìÚµËüúõË–÷îÝC Š*ÏŸ?73fÌ0=²þüÙìÛ·¯•z¦d{åÊÛF¿}ûf ,>ËÍ+÷~)ãÇiKùïæ}2@zÓB ]2@X•ˆñéÓ'³iÓ&»RÀw×®];è¡Îõö…®]¾|ÙlܸqÈg(Ùxèñ†ã±ÿñãÇ뇶+xÊ/\¸P< M˜0aØgä™ ÊrHnm K–,±+U1ÕܹsíJN5}ê†rïàx½j€ ?‚:x.|g4 ªl)'ÏÈ7PBe¯Ë+÷~? ãï߿ۃs¿­ÑWh§þu>”yú‹Ë…Ä…öU”CÚ2ßEQZºtéC›tQɃ¶™#ËXÙ–-[f)ÇãÇíg9}¼YE«%±:¤ÒL+N~]R2`õìÚµköÅ¥Ïý}ýúu³ÿþà³µXÝbm'·_§Únª ¡gҶ̧M›fW+#ÂO»Žœù#§/4iýÞ…b\ L$(¸xҜ׌›˜‡Ú7:Y÷=Ý3gÎba øû bïFSïbWžó:ržZap¼zõÊNN¡²ä >x§1¬ÜäW%ñÍ›7Ñôðº-_¾¼öú¶mÛlØFˆ ÁŠ­|¥žimH¶¡4š¬>åÞïßo‡”…¾áàÜ/ç(ºö°œ;wΆb4‡ÊÁ¹oVW}ȃ6ê·×YÆÊÆŠ£¯øqÎg9}¼Q²ªrŠÕ!•fj\¡¿WŸCJ÷ïß·mP.Qcqë¹H¬n9¤úuŽ+Cè™´-s<ý¬ºÄ懡ù#VÏ’vÐïýX!Æ…⃧†ý ¾2‹÷Š0¼ÆNÑô—üK òªND@î(É'W)]³fõNú{@b!I¼Æ„qÔ…c”N.xǨB@ÎÊ ÏË…ž„ÊÁ&t^4€\™/^¼ULFc¤N¶£±3XR×oß¾mÃTüp \¥7÷zIÙQF©7ýŽÃ—ö½œ:ÄÒ,WR2àÙâL OÓŸÜÿîs×Jd]Ò·ëúui~9ånSæôÍÍ›7Û±ƒöÍjeŠNól£/ôz?Bˆqg€„b¼j¼‹Éø?5Èæ ºx_}åš|ªo?òéæ HÈ›™òp2!áŒmœï¶BxÂsêÙä <„¥¾Qa#¹$&ÛÐ>ËÍ+÷~?”ç´zÝ÷œºMî´o?t®‰bRõœ’_î H¬lxu1>ñbû«!©¾W¢ §ÒL+¥žoV>E\¿~ýàß<÷÷X6@FRæ8 ü~Qšgªžm®€ôj?Bˆqa€ lú1ºì‡ðßņF?î—e‚M…/å¼ëôéÓVIp6^'_Ir{@(C§{@¨õô÷€ÄÞ‚…ÒÆDZ …Êͯú9õr^5êË3¨îó ^¿n³tNˆ”ÏÞ½{­Ü¨+^KV|¯^Œ&O·g Í·`¥dëÞbEù;y Vê~?·ÍQ÷cÒ¹Ž‚ëÂlèGóçÏü./p›¼›(..tÈ•¯sŽ,cesm ¯.oCÌí{% r*ÍÔ¸âÇÏ»ºäÈ…‘´Ý~(þg¬aÌ •34~• 9ý:DIB×Û–9i9'í‡ôR¤òÌé %í Ÿû±Bôòè·Ø…eq–Ɉ}Ï×ù®ã¥FaôQâdÝrl2pñØ¡0&&PB%È %éVå·K˜ ˜¬SoÁJ­01»ßžàà<¦§Vr~×Ã?õãs<|ÔË%v8³Þ©ЇÛãCø{-R¸ßáYðüÙÄ›+&J[NZ¼Ù'çw@êÊ»?TÞVãÞ$ä^_ìà9aŒ¹¶ƒqç®ÓŽxe²E£¹©âB¬V°*G9(O΄XÙ|hV¯^mäjòäÉfçÎæëׯÙùÅʺ/t¹å°jÕªaéñ+¼ÈœòO:Õœ8q"™Î½{÷Ì¢E‹ì=sæÌ1W¯^–ÏåYw­N6)ÙÂÑ£Gmûä8räH£gº¤Œ±¦¸ô³â§J³4ŸÜ6Ÿ“Ÿ ñe€È°Bôµò×_ÿŠ!08PÐ~þüiþüùcž={f6lØÐuÄA>—.]²¿Û¦+Šõ©S§Ìïß¿íqòäI³xñâÚt0PuC¹wp2 <ï7nt\þ’ɺ*[ŒgçY¹yåÞï§söìYk #·;v “Ýž={WT8w×1¦ü¼žÝ\ M4©É‡‰`lã|· ÂãØžSÏ&oà!,…ð:XÞÉ= 1Ù†öpðYn^¹÷ûé¤<œÕ뾇Ómr§}û¡sMˆª‡“ürW@beÃûŠñ‰Û_ Iõ½9•fj\)õ|³òA(âúõëÿæy¸¿Ç²2’2Çaà÷‹Òm•7°âò•$·„2tº„úQOHì-X(mL¤ÕP¨ÜüªŸS/çý¢¾<ƒê>âõë6Kç„HùìÝ»×ʺâµd¥Á÷¾UÁèa’s{Ú| VJ¶î-V”¿“·`¥î÷ÓqñÕÕo?&ë(¸.̆~4þüÁïòò·É»‰‚áB‡\ð:çÈ2V6צð¾ò8ÈܾW¢ §ÒL+~œ»«KŽ PìHÛí‡âÆÆœP9CãW©’Ó¯C””!t½m™“–sÑ~H/E*Ïœ¾PÒrÓ­ë+cq|BˆÖ GÑ# ) Ëâ,“3`ú®ó;\ÇKÂèvijºåþØ í&$â±CaLL „JJÒ­[·†\g g²N½+µÀÄì~{‚ƒó˜BžZaÈù]<þÔÏñðQ¯êXP”]Ìz§+nágìµHá~„gÁógo®<š(m9iñfŸœß©+GìþPyx«Œ{“{}±ƒç„1æÚÆ»N;â•ÉŒæ¦ y°ZÁªå <9á!±²9x–Mú^é*A,ÍÔ¸B¹‘½/ƒœöä¼ÁN±ãÿª×:5~•¶åœ~¢¤ uåiS椅Íu Ùœ¬Tž©z–¶ƒœ>–ê+cm|BˆÖ !ÄØƒ7å T !„Æ!„ !D+à='¼‚䆇!4>!„ !D„ª°w°HÿÇÎü·ùÇxb4ePš÷X~n£U·¶òí‡gU7>!„ !„B!„ !„B!„"„B!„"„B!„"D!„B!D!„B!D!„B!d€ÑK H=*§‘ʳÚ@¯´Ã^ì9eR?Bˆ4@þþÏßÑ#Ä—/_Ì–-[̤I“ÌĉÍÊ•+ÍÝ»w»>pþ”)SÌÖ­[Í‹/Z ÜâÇfݺuöGœ88ÿþ}mz>4«W¯¶?F5yòd³sçNóõë×ìübå ݺŽÜrXµjÕ°ôøµ\dNù§NjNœ8‘LçÞ½{fÑ¢Eöž9s昫W¯FËçò¬»V'›”láèÑ£¶}r9r¤Ñ³NÝ?RŠËXSˆúÙñÓ ¥ÙI>¯^½2kÖ¬±ãÊÌ™3͵k׊ê%¤7 6B ä¯ý=B`p  ýüùÓüùóÇ<{öÌlذ¡µÉ€|.]ºdŵM#$V6ëS§N™ß¿ÛãäÉ“fñâŵé` xì}ïá±cÇìäÅuvÊQª3!²êA8Iâ³\˜ˆ›¬€„B¬0¤˜´Pš(K,/&ÇT>4çÏŸ^¯ È… ž ß ¤*[ÊÉ3ò ”PÙëòʽßOÃøû÷ïöàÜokôÚ©ÏežþâòC!q¡}UÅå¶ÌwQ”–.]:ÄÐ&]”Gò mæÈ2V¶eË–YEÊñøñcûYNß#oVѪFI¬©4S㊓_—” X=sŠ!JŸûûúõëfÿþýÁgj±ºÕAŸfu£€>·yófþXÒORe=“¶e>mÚ4»Z ¹«;9óGN_hÒú½ !ĸ0@˜HPpݤɀJÈMÌCí,‡ûžnâ¥}#Åß÷@H{7šzë¼rxðœ×‘óÔ ƒƒo&§PYr ¼ÓVnò«‚’HhG,=¼nË—/¯½¾mÛ6v…âB°b+_©gš»Ç£éd’m(&«O¹÷ûß÷Û!e¡o88÷ËÇ9Š®ƒ=,çγŠ(Fs¨œûauÕ‡xü©Ÿãá£^¾çÔyà\Ìz§Š‘ÛãCø{-R¸ßáYðüÙÄ›+&J[NZ¼Ù'çw@êÊ»?TÞVãÞ$äbú<'Œ1×v0îÜuÚ¯Lv È`47U\ÈƒÕ Vå(åÉÙƒ+›ƒgÉѤÄÒL+”Ùû2ÈiOÎËìFþ¯zÃSãW'¡3„sº¶CØcÎ&ô’2Ô•§M™“Š9×1dsB°Ry¦êYÚú¹ !Dß Bˆ±oàA©B¨ !„ !D+°*FØôj(•BýX!d€!º ¡*ì] ,Òÿ5ÿ-Gþ1žM”æ=–ŸÛhÕ­dZ×…BˆB!„BÈB!„BÈB!„BÈB!„B B!„B B!„B!D!„B!DˆñÀÀÀ€„Уr©<{¡ ôJ;ìÅþ0šeÒø „0@þóŸ¿£Gˆ/_¾˜-[¶˜I“&™‰'š•+Wš»wïvu@æ;¤?eʳuëVóâÅ‹V' w„øðáƒY·nýq(Îß¿_›ÞÇÍêÕ«í\Mž<ÙìܹÓ|ýú5;¿XùB÷…®#·V­Z5,=~…™Sþ©S§š'N$Ó¹wïžY´h‘½gΜ9æêÕ«Ñò¹<ë®ÕÉ&%[8zô¨mŸGŽiô¬S÷”‚1Ö—~6@ütBiv’Ï«W¯Ìš5kì¸2sæLsíÚµ¢zÉ_ˆ !D_ ÿú×_Ñ# ÚÏŸ?ÍŸ?̳gÏ̆ ºn€8ÈçÒ¥Kö×aÛ4BbeC±>uê”ùýû·=NžuC¹wp2 <ï7nt\þ’ɺ*[ŒgçY¹yåÞï§söìYk #·;v “Ýž={WT8w×1¦ü¼žÕ·ùts$4Ѥ&&<€±óÝ6@cCxN=sß:„¥¾QËû#¹$&ÛÐ>ËÍ+÷~?”‡³zÝ÷pºMî´o?t®‰Qõp’_î H¬lx_1>ñbû«!©¾W¢ §ÒL+¥žoV>E\¿~ýàß<÷w›ϾI¨c· ‘”9¿_”晪g'+ ©>ë+cq|Bˆž2@P6ý]öCøo„bC£÷Kˆƒ?Ø¡8§Â—rÞ‚uúôi«$¸ï¯$¹= ”¡Ó= Ôzú{@boÁBic"­†BåæWýœz9ïõåT÷y¯_·Y:'DÊgïÞ½VnÔ¯%+ ¾÷­ F“œÛ3Ðæ[°R²uo±¢ü¼+u¿ŸŽ‹¯æ¨Æxû1é\GÁuásô£ùóç~——¸MÞM :äÊ€×9G–±²¹6…÷•·À¡@æö½9•fj\ñãÜ]]rd€bGÚn?ÿ3Ö0æ„Ê¿J  {?Ô‘p¬˜¡ßIB×Û–9i9'í‡ôR¤òÌé %í 7ݺ¾2Ç!„hÍù÷¿D(¤(h,‹ã­cÀô=8\çÕ’\ÇKÂèvijºåþØ í&$â¢CaLL „JJÒ­[·†\g g²N½+µÀÄì~{‚ƒó˜BžZaÈù]<þÔÏñðQ¯êXP”]Ìz§Š‘ÛãCø{-R¸ßáYðüÙÄ›+&J[NZ¼Ù'çw@êÊ»?TÞ*ãÞ$äbú<'Œ1×v0îÜuÚ¯Lv p`47U0ÈƒÕ Vå(åÉ ‰•ÍÁ³ähÒ÷JW bi¦ÆÊì}ä´'ç vŠÿW½Ö©ñ«“Â9]Û!ì1gzIêÊÓ¦ÌI šë²9!X©9Ž9ÒèY§î)Åe¬)Dýl€øé„Ò,ͧ´ßv³ 2@Ô…bÄ ýõ¯èƒíçÏŸæÏŸ?æÙ³gfÆ ­MäséÒ%û+®m!±²¡XŸ:uÊüþýÛ'Ož4‹/®MåÁƒV>üâì¬Ò\:95Äîܹ“TœáæÍ›fÅŠÃÒß¾}»Ùµk—ùõë—-ÿîÝ»‡Už?nf̘a=zdÿþüù³Ù·o_+õLÉöÊ•+¶~ûöÍX|–›WîýR0Æ2RÊn¿•Ò?ˆBÈé’ªDŒOŸ>™M›6Ù•¾»víÚAuއ»n2¸|ù²Ù¸qãϘ¬ñÐã ÇcÿãÇ!×>l=ŠxÊ/\¸P< M˜0aØgä™ ÊrHnm K–,±+U1ÕܹsíJN5}ê†rïàx½j€ ?‚:x.|g4 ªl)'ÏÈ7PBe¯Ë+÷~? ãï߿ۃs¿­ÑWh§þu>”yú‹Ë…Ä…öU”CÚ2ßEQZºtéC›tQɃ¶™#ËXÙ–-[f)ÇãÇíg9}¼YE«%±:¤ÒL+N~]R2`õìÚµköÅ¥Ïý}ýúu³ÿþà³µXÝrÛqµß6é'©2„žIÛ2Ÿ6mš]­Œ?í:r朾Фô{?Bˆqa€0‘0QâIs^3Bnbjßpèd9Ü÷tÏœ9sˆ„âÇOÄÞ&Ôå‹Wžó:ržòT:^½ze'§PYr ¼ÓVnò«‚’øæÍ›hzxÝ–/_^{}Û¶m6ì #Ä…`ÅV¾RÏ4wGÓÉ6$ÛPMVŸrï÷¿ï·CÊBßppî—s]{XÎ;gà 1šCåàÜ7««>äAõÛkŽ,cecÅÑWü8糜¾GÞ(YU9ÅêJ35®Ðß«Ï!%ƒû÷ïÛ¶(—(€Î±À¸Æõ\$V·Bý¶©+Cè™´-s<ý¬ºÄ懡ù#VÏ’vÐïýX!Æ…⃧†ý ¾2‹÷Š0¼ÆNÑô—üK òªND@î(É'W)]³f]uð÷€ÄB’x 㨠Ç(\ðŽP…0€œ•ž— = •ƒMè¼h¹2)^¼x1ª˜ŒÆ HlGc$f°¤®ß¾}Û†©øá@¹Joîõ’²£ŒRoú‡;/í{9uˆ¥Y2®¤dÀ³Å™@Ÿ¦?¹ÿÝç®”ȺI[Îí·Ê7t½M™Ó77oÞlÇÚ7«<):ͳ¾ÐëýX!ƈñªñV,&sàÿÔ ›3èâ}õ'iò©¾ýȧ›+ !ofÊÃÉ„„0¶q¾ÛáqlÏ©gî[§€°Â7ê l`$÷€ÄdÚÃÁg¹yåÞï§“òœV¯ûžS·Éöí‡à4QLªžSòË]‰• ¯.Æ'^l5$Õ÷JäTš©q¥ÔóÍÊ¡ˆëׯü›çáþ $·ßvÛI™ã0ðûEiž©z¶¹Ò«ýX!Æ…‚²éÇè²Â#ý¸_BüAÅ9g£¥£î-X§OŸ¶J‚°ñ:ùJ’ÛB:ÝBý¨§¿$ö,”6&ÒTHEnõr^5êË3¨Æ‹¯_·Y:'DÊgïÞ½VnÔ¯%+ ¾W¯ Ê“§Û3Ðæ[°R²uo±¢ü¼+u¿ŸŽ‹Ûæ¨ÆŽû1é\GÁuásô£ùóç~—MÈn“wÅÅ…¹2àuΑe¬l®MáÕå-p(¹}¯DAN¥™WüøyW— 0’¶ÛÅÿŒ5Œ9¡r†Æ¯N X¿­£¤ ¡ëmËœ´œˆöCz)Ryæô…’vÐÏýX!úÎù÷‚G(¤(h,‹³LÎ@ì{†¸Îï@p/5 £?ˆ'ë–ûc“;˜ˆÇ…11*A^(I·nÝr ‚É:õ¬Ôj³ûí Îc yj…!çw=|ðøS?>ÇÃG½üXbçs1ë ¬x¸=>„Ÿ±×"…ûžÏŸM¼¹òh¢´å¤Å›}r~¤®±ûCåám5îMBîõÅžƘk;wî:íˆW¯:Pd0š›*.äÁj«r”ƒòäìAˆ•ÍÁ³ähÒ÷JW bi¦ÆÊì}ä´'çev #ÿW½á©ñ«$Öoë()C]yÚ”9i¡˜sC6'+•gªž¥í Ÿû±Bô"„{ð”J!„ú±BÈB´«b„mðj(•BýX!d€!º ¡*ì] ,Òÿ5ÿ-Gþ1žM”æ=–ŸÛhÕ­dZ×…BˆB!„BÈB!„BÈB!„BÈB!„B B!„B B!„B!D!„B!DˆñÀÀÀ€„Уr©<{¡ ôJ;ìÅþ0šeÒø „0@þþÏ¢Gˆ/_¾˜-[¶˜I“&™‰'š•+Wš»wïvu@æ;¤?eʳuëVóâÅ‹V' w„øðáƒY·nýq(Îß¿_›ÞÇÍêÕ«í\Mž<ÙìܹÓ|ýú5;¿XùB÷…®#·V­Z5,=~…™Sþ©S§š'N$Ó¹wïžY´h‘½gΜ9æêÕ«Ñò¹<ë®ÕÉ&%[8zô¨mŸGŽiô¬S÷”‚1Ö—~6@ütBi–æSÚo»Y ý™· !D_ ýë_Ñ# ÚÏŸ?ÍŸ?̳gÏ̆ ºn€8ÈçÒ¥Kö×aÛ4BbeC±>uê”ùýû·=Nž}2›6m²+|wíÚµƒêwÝ }ùòe³qãÆ!Ÿ1Yã¡ÇŽÇþÇC®>|Øzñ”_¸p¡x²˜0a°ÏÈ3”åÜÚ2@–,YbWªb «¹sçÚ•œjúÔ åÞÁyÈ€rð¼oܸÑqùK&ëªl1œ!œcdåæ•{¿ŸÎÙ³g­ŒÜvìØ1Lv{öì\QáÜ]ǘòózòäÉ 1_õºcÍš5ËÖã÷åË—ƒ×1É—ü)Ç™3g²dYW¶·oßšyóæ û>íåõë×ɾGÞô·éÓ§öTRiÆÆ•RPÇwïÞÙsú ßwiÒ/¨¯ÿ,êÆ¯œºu«ß––!ôLÚ–9«¢ .´×gÏžubäæÙV_H¥ëÇ©tûu|Bˆž2@PÆ:d>~ü¼¾`ÁóôéS«²Z€Àà×DÉ }‡• ÇñãÇí`Œ—š|ðØû^÷cÇŽÙÉ‹ë À”£TfBdÕƒ:q’Äg¹07Y …XaH1¹ 4Q–X^Lb©|!DO L$L”xҜ׌›˜‡Ú7J ð=Ý3gÎba øñÓ„±w£ uùâ•Ã缎œ§<•ŽW¯^ÙI$T–\Äï4†UÝ䇒øæÍ›hzxÇ–/_^{}Û¶m6ì #Ä…`ÅV¾RÏ4wGÓI1$ÛPMVŸrï÷¿ï·CÊBßppî—s]{XÎ;gà 1šCåàÜ7««>äAõÛkŽ,cecÅÑWü8糜¾GÞ(CU9ÅêJ35®Ðß«Ï!%ƒû÷ïÛ¶((jαÀ¸Æõ\$V·Bý¶©+Cè™´-s<ò¬ºÄ懡ù#VÏ’vÛÇbýx,ŽBÑSˆöƒøÊ,Þ+ÂXð;EÓ_ò/5@È«:a¹£$Ÿ\¥tÍš5vÕÁß Iò½Æ„qÔ…c”Nx±X®¯Âr}ÎÊ ÏË…ž„ÊÁ&t^4€\™¼.^¼ULFc¤N¶£±3XR×oß¾mÃTüp \¥7÷zIÙQF©7ýŽÃ—ö½œ:ÄÒ,WR2àÙâL OÓŸÜÿîs×Jdݤ-çöÛNåºÞ¦Ìé››7o¶cí›UžæÙ;J7ÇÈìçñA!zÖ ˜xÕx+“9ðj0Ìñ¾ú“4ùTß~äÓÍÐD“š|˜8ðÆ6ÎwÛ!<Ž á9õÌ}ë–BøF,ïä˜lC{8ø,7¯ÜûýtRÎêußÃé6¹Ó¾ýœ& DÕÃI~¹+ ±²á}ÅøÄ‹í¯†¤ú^‰‚œJ35®”z¾Yù qýúõƒó<Üß#a€äöÛn #)s~¿(Í3UÏNV@R},ÖWÆâø „=e€ lú1ºì‡ðßņF?î—°CqÎÙhé¨{ ÖéÓ§­’àV¼C¾’äö€P†N÷€P?êé ¥‰4R‘D½œ÷‹úò ªñâÄë×m–Î ‘òÙ»w¯•uÅkÉJƒï}«‚òÄ$çö ´ù¬”lÝ[¬('oÁJÝï§ãâ«9ª1Þ~L:×Qp]øýhþüùƒße²ÛäÝDÁp¡C® xsd+›kSx_y  dnß+QSi¦Æ?ÎÝÕ%G(v¤íöCñ?c cN¨œ¡ñ«$Öoë()CèzÛ2'-ç¢ý^ŠTž9}¡¤ä¦[×WÆâø „­ þýïè…eq–É0}×ù®ã¥Faô;âYÝrlÐvñØ¡0&&PB%È %éÖ­[C®33Y§Þ‚•Z `bv¿=ÁÁyL!O­0äü®‡êÇçxø¨Wõ ,(Ê.f½S„·Ç‡ð3öZ¤p¿³àù³‰7WM”¶œ´x³OÎï€Ô•#v¨<¼UƽIȽ¾ØÁsÂsmãÎ]§ñêU FsSƒ˜uëÖÙqâàüýû÷µé=|øÐ¬^½ÚþÕäÉ“ÍÎ;Íׯ_³ó‹•/t_è:rËaÕªUÃÒã×r‘9åŸ:uª9qâD2{÷î™E‹Ù{æÌ™c®^½-ŸË³îZlR²…£GÚöÉqäÈ‘FÏ:uÿH).cM!êgÄO'”fi>MÇ•6Ê DýX!F܉)u' ÚÏŸ?ÍŸ?̳gÏ̆ Z› ÈçÒ¥KöW\Û4BbeC±>uê”ùýû·=Nž}2›6m²=¾»víÚAuNúu“ÁåË—ÍÆ‡|†’‡o8û?~ ¹~øða»€§üÂ… œЄ †}Fž¹ ,‡äÖ–²dÉ»RYÍ;×z\«éS7”{ç!ÊÁó¾qãFÇå/Qª²Åxp†pŽ‘•›Wîý~:gÏžµ2rÛ±cÇ0ÙíÙ³gpE…swcÊÏëÉ“'ƒÆ|ÕëŽ4kÖ,[W”Ô—/_^ÇP$_ò§gΜɒe]ÙÞ¾}kæÍ›7ìû´—ׯ_'ûyÓߦOŸ>ØwRuH¥WJe@ß½{gÏé/|ߥI¿ ¾þ³¨¿rêÖ­q¥´ ¡gÒ¶ÌY]¸p¡½>{öì¨#7϶úB?÷c!„ÊØ¡C‡Ìǃ×,X`ž>}jC¼z ªz£X Áp?~Üòx©É½ïu?v옼¸ÎÀN9J`&D¼“Ô‰ƒ$>Ë…‰¸É H(Ä CŠI ¥‰²ÄòbrLåsðàAsþüùàõª‚üPêà¹ðÑ0@ª²¥œ<#ß@ •½.¯Üûýt0Œ¿ÿnÎý¶F_¡ú×ù Pæé/.?‚SU\PiË|EiéÒ¥C mÒEy$ÚfŽ,ce[¶l™U¤?¶Ÿåô=òf­j”ÄêJ35®8øuIÉ€Õ³k×®ÙsC”>÷÷õë×ÍþýûƒÏ"Ôbu‹î%ãJIBϤm™O›6Í®VF„Ÿv9óGN_hÒú½ !ĸ0@˜HPpñ¤9¯!71µo8t²î{ºgΜ9ÄÂ@ñ÷=DŒuêòÅ+‡ÏÉ…óÔ ƒãÕ«Wvr •%×ñÁ;aå&¿*(‰oÞ¼‰¦‡×mùòåµ×·mÛfî0B\Vlå+õLsÛWÓÉ6$ÛPMVŸrï÷¿ï·CÊBßppî—s]{XÎ;gà 1šCåàÜ7««>äAõÛkŽ,cecÅÑWü8糜¾GÞ(YU9ÅêJ35®Ðß«Ï!%ƒû÷ïÛ¶(—(€Î`\ãz®«[¥ãJIBϤm™ãégÕ%6?¤Í±z–´ƒ~ïÇB1. <5ìñ•Y¼W„±à5véøKþ¥yU'" w”ä“«”®Y³Æz*ýXíXH’¯1auᥓ Þ1ªãAåy¹Ð“P9؄΋+“âÅ‹£ŠÉh¬€ÔÉv4V@bKêúíÛ·m˜Š”«ôæ^/);Ê(õ¦ßq¸óÒ¾—S‡Xš%ãJJ<[”~ú4ýÉýï>wí DÖ9ò/WJåºÞ¦Ìé››7o¶cí›ÕÊæÙF_èõ~,„ãÎ ÄxÕx+*ðjÍtñ¾úÊ5ùTß~äÓÍ73åádBÂÛ8ßm„ð86„çÔ³Éó&,…ð:É= 1Ù†öpðYn^¹÷ûé¤<§Õë¾çÔmr§}û¡sM“ªç”ürW@beë‹ñ‰Û_ Iõ½9•fj\)õ|³òA(âúõëÿæy¸¿Û4@JÆ•n #)s~¿(Í3UÏ6W@zµ !ĸ0@P6ý]â–ý7·°¡Ñû%ÄÁO Å9fó¬Ó§O[%Á Øx|%Éí¡ î¡~ÔÓÕŽ½­¥‰´ •›_õsêå¼jÔ—gPÝçA¼~Ýféœ)Ÿ½{÷Z¹QW¼–¬4ø^½*=LžnÏ@›oÁJÉֽŊòwò¬Ôý~:.n›£;îǤs×…ÏÑæÏŸ?ø]^à6y7Q\\è+^çYÆÊæÚ^]ÞÖ„™Û÷JäTš©qÅŸwuÉ‘ #i»ýPüÏXØ*ghü*5@šŽ+”!t½m™“–sÑ~H/E*Ïœ¾PÒú¹ !Dß %¿‚BŠ‚Æ²8Ëä ľgˆëü×ñR£0úƒ(q²n¹?6¸ƒ ‰xìP(¡ä…’tëÖ­!×™ ˜¬SoÁJ_LÌî·'88)ä)ƒ.çw=|ðøS?>ÇÃG½üXbçs1ë ¬x¸=>„‰°×"…ûžÏŸM¼¹òh¢´å¤Å›}r~¤®±ûCåám5îMBîõÅžƘk;wî:íˆW&;Pd0š›*.äÁjÞsÊAyr<é±²9x–Mú^é*A,ÍÔ¸B¹‘½/ƒœöä¼ÌNaäÿª7<5~•¶å¦ãJ'e¨+O›2'-s®cÈæ„`¥òLÕ³´ôs?Bˆ¾3@„cÞÀƒR)„P?B BˆV`UŒ° ^ P ¥B¨ !„ !DW!T…½ „Eú?¢æ¿åÈ?Æ£)ƒÒ¼Çòs­ºõƒLëú±BÈB!„B B!„B B!„B B!„B!D!„B!D!„B!d€!„B!d€1zTN#•g/´^i‡½ØF³L„2@BÈßÇ_¾|1[¶l1“&M2'N4+W®4wïÞíê€Ìw8HÊ”)fëÖ­æÅ‹­NîñáónÝ:ûãPœ¿ÿ¾6½‡šÕ«WÛ¹š9Ž9ÒèY§î)c¬).ýl€øé„Ò,ͧé¸ÒFd€ôgÞ2l„ým€0ˆÅŽ(h?þ4þü1Ïž=36lèºâ ŸK—.Ù_‡mÓ‰• ÅúÔ©Sæ÷ïßö8yò¤Y¼xqm:(<°òá—l8`•æÒI¤édsçΤâ 7oÞ4+V¬–þöíÛÍ®]»Ì¯_¿lùwïÞ=Ä ¨òüùs3cÆ óèÑ#û÷çϟ;}ûZ©gJ¶W®\±môÛ·oöÀÀâ³Ü¼rï—"0~ ¶”ÿ¦ãŠ  B1n V%b|úôÉlÚ´ÉzôøîÚµk=Ô9îºAûòåËfãÆC>CÉÆC7ý?†\?|ø°] ÀS~áÂ…âÉb„ Ã>#Ï\P–CrkËY²d‰]©Š¬æÎk=®Õô©ʽƒóåày߸q£ãò—LÖUÙb<8C8ÇÈÊÍ+÷~?³gÏZ¹íرc˜ìöìÙ3¸¢Â¹»Ž1åçõäÉ“Ac¾êuÇš5k–­+JêË—/¯c(’/ùSŽ3gÎdɲ®loß¾5óæÍö}ÚËëׯ“}¼éoÓ§Oì;©:¤ÒŒ+¥2 ŽïÞ½³çô¾ïÒ¤_P_ÿYÔ_9uëÖ¸RZ†Ð3i[權.\¸Ð^Ÿ={vÔ‰‘›g[}!•n¬§Òí×ñA!zÊA;tèùøñcðú‚ ÌÓ§O­bˆW#€Á¯‰’ú+!ŽãÇÛÁ/5ùà±÷½îÇŽ³“×€)G©Ì„ˆw’:q’Äg¹07Y …XaH1¹ 4Q–X^Lb©|¹Jéš5k¬§ÒÕŽ…$ù^cÂ8êÂ1J'¼X,×Wa¹>ǃÊór¡'¡r°  W&¯‹/F“ÑX©“íh¬€Ä –ÔõÛ·oÛ0?(Wéͽ^Rv”QêM¿ãpç¥}/§±4KÆ•” x¶(ýôiú“ûß}îÚA‰¬sä_:®”Ê7t½M™Ó77oÞlÇÚ7«•):ͳ›}!•nŽ‘ÙÏãƒBô¬0ñªñV,&TàÿÔ`˜38â}õ•kò©¾ýȧ›+ ¡‰&5ù0qàŒmœï¶BxÂsê™ûÖ) ,…ð:XÞÉ= 1Ù†öpðYn^¹÷ûé¤<œÕ뾇Ómr§}û¡sMˆª‡“ürW@beÃûŠñ‰Û_ Iõ½9•fj\)õ|³òA(âúõëÿæy¸¿Û4@JÆ•n #)s~¿(Í3UÏNV@R},ÖWÆâø „=e€ lú1ºÄ-ûonaC£÷Kˆƒ?Ø¡8§Â rÞ‚uúôi«$¸ï¯$¹= ”¡Ó= Ôzú±Ú±·Õ ´1‘VC¡ró«~N½œ÷‹úò ªû<ˆ×¯Û,"å³wï^+7êŠ×’•ßûV£‡IÎíhó-X)Ùº·XQþNÞ‚•ºßOÇÅWsTc¼ý˜t®£àºð9úÑüùó¿ËËÜ&ï& † reÀëœ#ËXÙ\›ÂûÊÛšP sû^‰‚œJ35®øqî®.92@±#m·ŠÿksBå _¥HÓq¥“2„®·-sÒrN Úé¥Hå™ÓJÚAnºu}e,ŽBÑžRð; (¤(h,‹³L΀é{p¸Îï@p/5 £?ØÏê–ûcƒ¶;˜ˆÇ…11*A^(I·nÝrœÉ:õ¬Ôj³ûí Îc yj…!çw=|ðøS?>ÇÃG½ªo`AQv1ë ¬x¸=>„‰°×"…ûžÏŸM¼¹òh¢´å¤Å›}r~¤®±ûCåá­2îMBîõÅžƘk;wî:íˆW&;P80š›*äÁjÞsÊAyr<é±²9x–Mú^é*A,ÍÔ¸B¹‘½/ƒœöä¼ÁN±ãÿª×:5~•¶å¦ãJ'e¨+O›2'-h®cÈæ„`¥òLÕ³´äô±T_kãƒB´g€!Ƽ)¥R!4>!d€!ZU1Â+x@nxˆBãƒBÈBA¨ {‹ôìÌË‘Œ'FS¥yåç6Zuk+ß~xVuãƒBÈB!„BÈB!„B B!„B B!„B 2@„B!„2@„B!„2@„B!„Bˆ½ÈÀÀ€„Уr©<{¡ ôJ;ìÅþS&õc!„äï¿ãGhp®;Úš08&Nœh¦L™b¶nÝj^¼xÑš°>|hV¯^mDjòäÉfçÎæëׯÁú7)Ý÷Cr¤ž9¬ZµjXº>|0ëÖ­³?6ÅÁùû÷ïG4½{÷î™E‹YΙ3Ç\½z5Ù~JÚVêYÁÑ£GͤI“ìqäÈ‘FÏ&uÿH).cM!êgÄO'”fi>¥ãh7Ë DýX!FÌaLŒ£= úyüüùÓ\ºtÉþšk[F öƒÌŸ?ì/Å8pÀ*¹Ö=÷ûwîÜI*ºpóæM³bÅŠa颸Ÿ:uÊüþýÛ'Ož4‹/±ôž?nf̘a=zdÿþüù³Ù·o_c9ä|/õ¬®\¹bV®\i¾}ûf ,>ËÍ+÷~)ãÇi[ù—2v !„Ò¢’ó öÔ©S­çš?~4ÊãòåËfãÆÒ<|ø°]YÀS~áÂ…lá¡Ü²ú2RÈ’%KÌ—/_¢ß¡nsçε+Õt'L˜0ìûÈd¤ÒÛ´i“¹qãFÇr(QªÏ ãÁBÀ9FVn^¹÷ûéœ={ÖÈÈhÇŽÖ0rp¾gÏžÁÎÝuŒ)?¯'Ož˜ 6 +çA³fͲuÅ|ùòåàõ_¿~Ù|ÉŸrœ9s&K–ue{ûö­™7oÞ°ïÓ^^¿~ì{äM›>}ú`[JÕ!•æ§OŸl;cEŽû×®];då«DÔñÝ»wöœþÇ÷]šô êë?‹ººœºu«Ý—–!ôLÚ–9«¢ .´×gÏž=dU´ŽTžmõ…~îÇB!¤æ³ãÇÛ2õ]»v ñç¤ÇJ†DnšÇ޳“ר1Fraâ©òb2KÝwðàAsþüùàu&lV)PÆ9Nœ8a?k+½*<d<HõY¡¸Pfß@á³Ü¼rï÷ÓÁ0þþý»=8÷ÛÚ¡C‡l;õ¯ó Ì/X°`0?êVU\PiË|EiéÒ¥C mÒEy$žUŽ,ce[¶l™U¤?¶Ÿåô=òÞ¾}û0£$V‡TšÈééÓ§ö^®Sg”µª üº¤dÀêÙµk×ì9Š!JŸûûúõëfÿþýÁgj±ºu»Ý—”!ôLÚ–ù´iÓìj%`DÄÆüÜÑm„eûØÊ‚cÁ…Š„Ò]³f]±ð÷l„VpÚJo4V@êžÕh¬€Ä –ÔõÛ·oÛ0?(WémÚ'›”e”zÓï8ÜyißëtŒÀ+NxåplIžUåãš6NXûß}îÚA‰¬›†UuÃ)i#mÊœ¾¹yófkÔоY­LÑižmô…^ïÇB1n &_iCQ©®€TßTÔ4¼¯¾²žJ³é »ØF÷n ì-`wN:±„·5åµïfz„ Œäس íáà³Ü¼rï÷ÓIyN«×}Ï©ÛäNûöCñš(&UÏ)ù宀ÄʆW÷âÅ‹Ö‹í¯†¤ú^é*i,M®ß½{× Àÿþý¥žoV>E\¿~ýàß<÷÷X6@FRæ8 ü~Qšgªžm®€ôj?Bˆqk€°‰šI#„ ðÿ{§OŸ¶º\ñù M,º·`¥Òt{@(OjJ_5ªM„øúºÍÍ9!M>ijOÃ߳῵ªÛéUÁˆbòt{Ú| VêY¹·XñÜ;y Vê~?·ÍQ÷cÒ¹Ž‚ëbÇñöΟ?H?r›¼›(..tÈ•¯sŽ,cesm¯.oECÌí{% r*M6Jûû ªÊÀÔ%G(Œ¤íöCñ?c cN¨œ¬TÃGÚ))CèzÛ2'-ç¢ý^ŠTž9}¡¤ôs?Bˆ¾1@šþHj¢c©••<ÓLÞÕï1ÙÖÀwPhnݺÍÃLH4¡°¨TšLLÖ©·`¥VšþþIÎ÷Ql]Œy§Šƒûm Îc!V¦ÂýÏ‚ßao®|›(b9iñfŸœß©+GìþPyx[{“yýp4b¾1Æœ,÷îÝ;x¹ò fŠ FsSÅ…CÁž:uªõ\³¢ñãÇFy\¾|Ùlܸ±Qš‡¶+ xÊ/\¸-<”[V_FÊY²d‰ùòåKô;Ômîܹv%¢šî„ †}™ŒTz›6m27nÜèX%“uõYa<8C8ÇÈÊÍ+÷~?³gÏZíØ±ÃFÎ÷ìÙ3¸¢Â¹»Ž1åçõäɳaÆaåã#hÖ¬Y¶®ƒ/_¾¼þë×/›/ùSŽ3gÎdɲ®loß¾5óæÍö}ÚËëׯ“}¼éoÓ§OlK©:¤Òüôé“mg¬ÈqÿÚµk‡¬|•È€:¾{÷ΞÓÿø¾K“~A}ýgQ·B—S·nµûÒ2„žIÛ2gUtáÂ…öúìÙ³‡¬ŠÖ‘ʳ­¾J7ÖSéöëø „}o€?~Üœx”ñ¨ïÚµkˆ‡<'=VB0$rÓµ÷r:£TUeà×%%VÏ®]»fÏQàPÎÜßׯ_7û÷ï>‹PˆÕ­Ûí¾¤ ¡gҶ̧M›fW+#"6æçæ™Ûš´ƒœtc}%•n¿ŽBÑ÷ÈÌ™3ÍLJ±=uƒ£ïéN¥IH{šòêÕ+;è‡îmÃA©{óæMô>¼YË—/¯½Ž×£óŠrt;½¦õÌÝãÑT¾¡gJ£ÉjVîýþ÷ývHYð2;8÷ËÇ9Š®ƒ=,çγa†Í¡rpî{M««>äÁ3óŸ_Ž,cecÅÑWü8糜¾GÞ(CU9ÅêÐtŒà~ß!A¯>‡” îß¿o¶mÛfÏQQÔœ¡BÇõ\$V·‘2@be=“¶eŽGžUB2K©æ™ªgI;Èíc±~<Ç!„è{„s–ÝÁß¡0ŸXzxoªQ,Í’//auáÝ6@X^­,80\¨H(Ý5kÖØ ÏFh§­ôFc¤îYÆ HÌ`I]¿}û¶ SñÃr•Þ¦}²IÙQF©7ýŽÃ—ö½NǼâ„ÇQgÀ–äYUn1®iã„¿¸ÿÝç®”ȺiXU7 ’6Ò¦Ìé››7o¶F í›ÕÊæÙ;J7ÇÈìçñA!zÞa‚ð•6•ê HõMEMóÀûê+ë©4›®€0Ð㱋mtï¶ÂÞ6pç¤[AM„)¯}7Ócy$÷€ÄžUhŸåæ•{¿ŸNÊÃY½î{8Ý&wÚ·Š×D¨z8É/w$V6¼¯/^´^l5$Õ÷JWIcirýîÝ»ÖHþ÷ï/õ|³òA(âúõëÿæy¸¿Ç²2’2Çaà÷‹Ò!D× !ÄØ…7å T !„Æ!„ !D+°ÚGxÅ?ÿü“"„Ðø „2@„EªÂÞÞäÿØ™ÿ–#ÿOŒ¦ JóËÏm´êÖV¾ýð¬êÆ!„"„B!„"„B!„2@„B!„2@„B!„2@$!„B!„ !„B!„ !„B!„"D/100 !ô¨œF*Ï^h½Ò{±?ä”IýX!FÄÙ‘8†ÎuG[ÇĉÍ”)SÌÖ­[Í‹/ZÖÇÍêÕ«íGMž<ÙìܹÓ|ýú5Xÿ&å¯û~HŽÔ3‡U«V K÷ÇfݺuöG¦88ÿþýˆ¦wïÞ=³hÑ"+Ã9s昫W¯&ÛOIÛJ=+8zô¨™4i’=Ž9ÒèÙ¤î)Åe¬)Dýl€øé„Ò,Í'§-çÖKHo 2l„2@†‹‰ctT?Ÿ?šK—.Ù_qmËAÁ~ðàùóçý…ØXÅ Óºç~ÿÎ;IEnÞ¼iV¬X1,]ÿS§N™ß¿ÛãäÉ“fñâÅ#–ÞóçÏÍŒ3Ì£Gìߟ?6ûöík,‡œï¥žÕ•+WÌÊ•+Í·oßìÅg¹yåÞ/cü m)ÿ¹ãŽ þ5@„BH‹HÎg(ØS§NµÞ>V4~üøÑ(Ë—/›76JóðáÃveïâ… ²…‡BÀêËH K–,1_¾|‰~‡ºÍ;×®DTÓ0a°ï#“‘JoÓ¦MæÆË¡D ¨>+ŒgçY¹yåÞï§söìYk #£;vXeÒÁùž={WT8w×Q@ý¼ž}²íŒ9î_»víÕ‚PÇwïÞÙsúßwiÒ/¨¯ÿ,êVèrêÖɸSmo%e=“¶eΪèÂ… íõÙ³gY­#•g[}¡Ÿû±BÈ©ùìøñãv@Æ£ŒG}×®]C<ä9鱂!‘›æ±cÇìäÅuvŒ‘\˜8Gj„¼˜ÌR÷x ›U Ž'NØÏÚJ¯ φR}V(.”ÙWêø,7¯Üûýt0Œ¿ÿnÎý¶vèÐ!ÛNýë|(ó ,Ì…Ä…ºU”CÚ2ßEQZºtéC›tQɃg•#ËXÙ–-[f)ÇãÇíg9}¼·oß>Ì(‰Õ!•&rzúô©½—ëÔe­*¿.)°âpíÚ5{ŽbˆÒçþ¾~ýºÙ¿ðY„Ú@¬nŽ;¹ãm¬ ¡gҶ̧M›fWx#"6æçæ™Ûš´ƒ~ïÇB!¤æ³™3gš?1&b{ê]ß;˜J“ ö24åÕ«Wv2 ÝÛ†‚R÷æÍ›è}xÉ–/_^{¯!FçåÜ_QévzM뙻ǣ©|CÏ*”F“Õ¬Üûýïûí²àevpî—s]qÿçγa†Í¡rpî{c«žròà™ùÏ/G–±²±âè+~œóYNß#o”¬ªœbuh:Fp¿ï ¿WŸCJ÷ïß7Û¶m³ç(—(€ÎÐFQäz®«[§ãNîx+Cè™´-s<ý¬º’YJ5ÏT=KÚA¿÷c!„Róç,+»ƒ¿Ca>±ôð U'¢Xš%7^^Â.êÂ'ºm€°l[Yp`,¸P‘PºkÖ¬±+þž˜'µÛéÆ Hݳ˜Á’º~ûöm¦â‡å*½Mûd“²£ŒRoú‡;/í{ŽxÅ £΀-ɳªÜb\ÓÆ «qÿ»Ï];(‘u7Úr·ÇàÐõ6eN}6oÞlÚ7+<):ͳ¾ÐëýX!Æ­Âá+m(*Õœ·»ÄòÀûê+ë©4›®€0ోmtï¶ÂÞ6pç¤[Ay[S^ûn¦GØÀHî‰=«Ð>ËÍ+÷~?”ç´zÝ÷œºMî´o?¯‰bRõœ’_î H¬lxu/^¼h½ØþjHªï•®’ÆÒäúÝ»w­‘üïß_êùfåƒPÄõë×þÍóp·m€äŒ;m #)sŒ,¿_”晪g›+ ½Ú…bÜ l¢fÇaB#|ÁÿÞéÓ§í„îW9¿RWŽØý¡òð¶÷&!6òúáhÄ|cŒ9YîÝ»wð:rå̌榊 y°ZÁ*å <9{besð,9šô½ÒU‚Xš´/ÊáÆ”wÿ~Êì}ä´'çev #ÿW½á~:Äù»p¥N ÒßV*)C]ºmÊœ´P̹Ž!›‚•Ê3UÏÒvÐÏýX!úÈBŒUxJ¥BýX!d€!ZÕ>Â6þùçŸa¡TBõc!„"„è*„ª°w·ù?¢æ¿åÈ?Æ£)ƒÒ¼Çòs­ºõƒLëú±BÈB!„B B!„B B!„B B!„B!D!„B!D!„B!d€!„B!d€1zTN#•g/´^i‡½ØF³L„2@|v$ŽÀ Zw´5hsLœ8ÑL™2Ålݺռxñ¢5a=|øÐ¬^½Úþ(ÕäÉ“ÍÎ;Íׯ_ƒõoRþºï‡äH=sXµjÕ°t?|ø`Ö­[g¼Šƒó÷ïßhz÷îÝ3‹-²2œ3g޹zõj²ý”´­Ô³‚£GšI“&ÙãÈ‘#žMêþ‘R0ÆšâÒψŸN(ÍÒ|rÚrn½d€Œ/D†¢? Ä1ÊŸŸÇÏŸ?Í¥K—ì¯Ã¶e„ `?xðÀüùóÇþòì¬bÐiÝs¿çΤ¢ 7oÞ4+V¬–.Šÿ©S§Ìïß¿íqòäI³xñâKïùóçfÆŒæÑ£GöïÏŸ?›}ûö5–CÎ÷RÏêÊ•+fåÊ•æÛ·oöÀÀâ³Ü¼rï—"0~ ¶”ÿÜqGˆ !„’9ùU?CÁž:uªõö±¢ñãÇFy\¾|Ùlܸ±Qš‡¶+ x/\¸-<V_FÊY²d‰ùòåKô;Ômîܹv%¢šî„ †}™ŒTz›6m27nÜèX%“uõYa<8C8ÇÈÊÍ+÷~?³gÏZíØ±Ã*“Î÷ìÙ3¸¢Â¹»ŽêçõäɳaÆaåã#hÖ¬Y¶®ƒ/_¾¼þë×/›/ùSŽ3gÎdɲ®loß¾5óæÍö}ÚËëׯ“}¼éoÓ§OlK©:¤Òüôé“mg¬ÈqÿÚµk‡¬”È€:¾{÷ΞÓÿø¾K“~A}ýgQ·B—S·NÆj{+)Cè™´-sVE.\h¯Ïž={Ȫh©<Ûê ©tcý8•n¿ŽBÑ÷ÈñãÇíÀ‰Gú®]»†xÈsÒc%C"7ÍcÇŽÙÉ‹ë À#¹0qŽÔ y1é¤î;xð 9þ|ð:6«(0'Nœ°Ÿµ•^•ÿ¿½óÑ)ZÿþùSž?EòƒHŠˆ""éD#šŽˆœ2‘hD“ˆH<#j>%J$¢|J"‘‰"EÖs^«Ö´fÍÞk­½ï{ß_fÞ/íì¹÷½¯õ}íëZ×µöM»PÇÝ0@¶Bq!ϾRÇg¹iåÞïËÁ0þñã‡=8÷ûÚ‰'l?õ¯ó Ì¯^½z"=ê*(‡ôe¾‹B³aÆI†6rQIƒ¶Ê©ËXÞ6nÜhÇÓ§Oíg9c´÷ïß?Å(‰•!%“zzþü¹½—딥*¬¿,©:Àã0::jÏQàPÎÜß·nÝ2G-l‹¢>+[«óNî|ËCQ›4]ç .´ÀˆˆÍù¹i掅*ý Gnl¬¤äöëü „}o€,Y²Ä|úôi’1ÛóP69ú«ƒ)™„±—¡*¯_¿¶“~ѽM (uoß¾ÞÇjÖ¦M›J¯³jÈ £[åÜ÷¨´[^Õræîñ¨Z¿EmU$£Š7+÷~ÿû~?$/¬2;8÷óÇ9Š®ƒ¸ÿK—.Ù0CŒæ¢|p†+å¤A›ùí—S—±¼áqô?Îù,gì‘6ÊPXO±2T#¸ß_`¼‡íªƒ‡š}ûöÙs”@5gh£Ðq=׉•­Õy'w¾å¡¨Mš®sVäñº’Y—0ÍT9ëôƒÜ1ÇÓq~Bˆ¾7@8Çýëþ. ó‰Écõ&|ÅdÖ™`Yå%ì¢,|¢Ýîõ˜gÁ±àBEŠänß¾Ýz,ü=±•ÔvË놤¬­ºá‰,©ëwïÞµa*~8P®Ò[uLVÉ;Ê(åfÜq¸óºc¯Õ9‚UqÂãȇ3`ë¤*·×ôqÂ_Üÿîs×êÔu;úr»çà¢ëMÖ9å´F ýOŠVÓlçXHÉÍ12ûy~Bˆž7@x@øJŠJèÉy»K, V_}e=%³ª„‰ž»ØF÷v ì-`wŽœ˜¡èA˜Zµo§<ÜûÜk«¢=|–›Vîý¾œÔ gxÝ_át›Üéß~(^"\á$½\H,o¬¾^½zÕ®bûÞÔØ«ë%Éäúýû÷­‘üïß_wåÏ¡ˆÓîï¦ œy§)¤“uŽ‘å‹ºi¦ÊÙŠ$5Æbce:ÎBÑó›¨yˆc„ð@#|ÁÿÞÈȈ} »I•_¡‰¥Qö¬”L·„ü¤ö€ dñà C¡š4@ˆ¯/ÛÜœÒäCl0û4ü=þ[«Ú-/#ЇœÛ3Ðä[°RmåÞbE»·ò¬Ôý¾_ÍÆxû1é\GÁu1Þ¬ö®ZµjÒ8r›¼«(.tÈåU眺ŒåÍõQV_y+ dîØ«£ §d²QÚßO@èTX~;P–œ:@±C¶ÛÅÿÌ5Ì9EùÄC†#Ö5@rç:y(ºÞt#Ë-Ñ—"•fÎX¨Órå–•é8?!Dû ÿ›8*NÔ¸ÚQPñ„°šÇÃ;ü;Âø ÍØØX4 wð@ ) OHÉd"çaz VÊ#Põ÷Or¾bëbÌ[5@PÜï pp ±jU^îw@h ~„M¼¹õ[Eiˑś}r~¤,±û‹òÃ[eÜ›„ØÈ뇣›1æêrhhhâ:õÊ+˜(ÍU ÒÀ[—Š|ŸœðXÞ´%G•±W×K“Iÿ"nŽAy÷ï'ßÔ½_9ýÉ­;ÅŽÿÃUk_ñø.\©U¤îo+ÕÉC™Ü&ëY(Ð\ÇÍ ÁJ¥™*gÝ~3ÆRceºÍBÑ~D1máM9(•B¡ùA!DÑxû¯øþý{vxˆBóƒBÈBÔ‚Pö.ðö ÿÇÎü·ùÇL¢›uP7íéÜnÝ*[SéöC[•ÍB!D!„B!D!„B!d€!„B!d€!„B!d€¨F„B!„2@„B!„2@„B!„Bˆ½Ä¬Y³T =ZOJ³ú@¯ôÃ^9yÒ8Bˆ GÑä\v4õÀà˜3gŽ™?¾Ù»w¯yùòec•õøñc³mÛ6ûãQóæÍ34ããã…寒ÿ²ïÕ#åÌaëÖ­Sä~üøÑìܹÓþÈç>|証˜µk×Ú:\¾|¹¹yóf²ÿÔé[©¶‚Ó§O›¹sçÚãÔ©S•Ú&u§—é¦õ³âË)’Y7ú2ãÏõåýû÷›/_¾Ô*— Þ4@dØ!d€ø“bâèö„ê§ñë×/síÚ5û+®M!(Ø=2ÿþµ¿{ìØ1«ä¶ZöÜïß»w/©èÂ;wÌæÍ›§ÈEñ?þ¼ùóç=Î;gÖ­[×1y/^¼0‹/6Ož<±£D9r¤r=ä|/ÕV7nÜ0[¶l1ß¾}³ Ÿå¦•{¿Œ™c€4¥üÿóŸÿ4>´cŒþ|éÒ%³aà ÓÈB  9Ÿ¡`/X°À®öáÑøùóg¥4®_¿nvïÞ]IæÉ“'­gÕÅ+W®dWÊÞ—N ëׯ7_¿~~‡²­X±Âz"B¹³gÏžò}ê¤SòöìÙcnß¾Ýr=ÔQ¶Âxp†pŽ‘•›Vîý¾œ‹/Z™::pà€5Œœ>|x£¹»Ž1å§õìÙ3³k×®)ùã#héÒ¥¶¬ƒ¯^½š¸þû÷o›.é“ .dÕeYÞÞ½{gV®\9åûô—7oÞ$Çi3Þ-Z4Ñ—ReHÉüüù³ígxä¸ÇŽ“<_uê€2¾ÿÞž3þø¾“ɸ ¼~[”yèrÊ–KjÜÖÍCQ›4]çxE׬Yc¯/[¶l’W´ŒTšM…~ÇB!¤ä³ááa;!³¢Ìjß¡C‡&­çÈÂ!‘+óÌ™3öáÅu&vŒ‘\xpvÊBZ<ÌR÷?~Ü\¾|¹ð:l¼(ãgÏžµŸ5%/„v¡Ž»a€„m…âBž}…ÏrÓʽߗƒaüãÇ{pî÷µ'NØ~ê_ç3@™_½zõDz($.Ô-T\PéË|EÉ_)'=ä¢<’m•S—±¼mܸÑ*RާOŸÚÏrÆiN%±2¤dROÏŸ?·÷r2£¬…uà—%UxÏFGGí9Š!JŸûûÖ­[æèÑ£…mQÔbeË5¤(³¦æËCQ›4]ç .´ÞJÀˆˆÍù¹i掅*ý ßDZBÈ)ùlÉ’%æÓ§O“Œ‰Øž‡²I×_éNÉ$$ˆ½ Uyýúµ}˜ÝÛ„‚R÷öíÛè}¬’mÚ´©ô:«†¬0ºUQÎ}J»åU-gîªõ[ÔVE2ªx³rï÷¿ï÷CòÂ*³ƒs?œ£è:ØÃBè a†ÍEùàÜ_ ½>¤A›ùí—S—±¼áqô?Îù,gì‘6JVXO±2T#¸ß_`¼‡íªŸöíÛgÏQ.Q¡¢Èõ\$V¶œy‚ƒºw™:sp,EmÒt³Ò×%g_Knš©rÖéý>Ž…BHÉgœãVv…ùÄä±*>ˆb2ëLܬòvQ>Ñn·}̳àÀXð“PîöíÛ­ÇÂß³QäÁiJ^7< emÕ HÌ`I]¿{÷® SñÃr•Þªc²JÞQF)7ãŽÃ×{­Î¬ŠG>œÂ^'ÍP¹Å¸¦VãþwŸ»~P§®«Î¤EÈ¿0Ðî9¸èz“uÎØ´F ýoeŠVÓlb,ôú8Bˆk€ð€ð•6•о©¨j¬¾úÊzJfUVìbÝÛm€°·€ Ü9rb„¢ÕÖÔª};å6ÐÉ= ±¶*ÚÃÁg¹iåÞïËI­œ†×ý•S·Éþí‡âUQL•SÒËõ€ÄòƪîÕ«Wí*¶ï I½º^Ò˜L®ß¿ß ÀÿþýuW¾ñ|ú4000ñ7íáþî”’3ÎÚm€t²ÎY0ðÇEÝ4SålÒÒ«ãX!f¬Â&jâ!<Ð_ð¿722bènre…ÈWhbi”½+%Óí!?©= (Y<øÂP¨& âëË67ç„4ùsÌ> φÿÖªvË Áˆâáéö 4ù¬T[¹·XÑî­¼+u¿/ÇÅms„±ã~L:×Qp]ì8«½«V­š4ŽÜ&ï*Š‹ ry`Õ9§.cys}”U]ÞŠ†™;öê(È)™l”ö÷:Öß”%§P‘íöCñ?s sNQ>ñ„áˆu U·W€6`CxÌØm%E×›®sd¹E úòR¤ÒÌ uúA?c!„èäÿ&ŽªJ"®vTÂ6¾ÿ>%”J¡q,„2@„m…Pö.ðö ÿGÔü·ùÇL¢›uP7íéÜnÝ*[?ÔiÙ8B B!„B!D!„B!D!„B!D!„B!d€!„B!d€!„B!„ !ºHί,‹îÔS§Òì…>Ð+ý°ÇC7ó¤ùA!¤ÅI´ìhjÒæ˜3gŽ™?¾Ù»w¯yùòec•õøñc³mÛ6ûNøyóæ™ƒšñññÂòW­¯Üú¤œ9lݺuŠÜ?š;wÚwÇspίèvRÞƒÌÚµkm._¾Üܼy3Ùêô­T[ÁéÓ§ÍܹsíqêÔ©Jm“º¿S ÆtS\úÙñåɬ›}™ñçúòþýûÍ—/_j•KÈÌ2@dØ!úÒùßÿýßèÑí‰ÏOãׯ_æÚµköÇ™š2BP°=zdþþýkøéرcVÉmµì¹ß¿wï^RÑ…;wî˜Í›7O‘‹âþüyóçÏ{œ;wά[·®cò^¼xa/^lžËM+÷~)3ÇiJùÿç?ÿi>|hÇýùÒ¥KfÆ 2@d€!Äô4@þçþ'z´ãá~†‚½`Á»Ú‡GãçÏŸ•Ò¸~ýºÙ½{w%™'Ož´žV¯\¹’]y(x_:e€¬_¿Þ|ýú5úʶbÅ ë‰åΞ={Ê÷S¿ðÛNy{öì1·oßn¹ê<¬Ã¶Âxp†pŽ‘•›Vîý¾œ‹/Z™: ½˜óÇOxT8w×1¦ü´ž={fvíÚ5%œc-]ºÔ–cðÕ«W×ÿþmÓ%}òqáÂ…¬º,ËÛ»wïÌÊ•+§|ŸþòæÍ›äØ#mÆÛ¢E‹&úRª )™Ÿ?¶ý ÷ïØ±c’ç«NPÆ÷ïßÛsÆßw2”×o‹2]NÙrIÛºy(j“¦ë¯èš5kìõeË–MòŠ–‘J³©±’Ç)¹ý:?!Dß ÃÃÃvâdE™Õ¾C‡MZ!Ï‘‡'C"Wæ™3gìËëLÀ#¹ðà씄´xè¤î;~ü¸¹|ùráuØx)PÆ9Ξ=k?kJ^íBwÃ Û Å…<û Ÿå¦•{¿/ÃøÇö÷Z*YTIDATàÜïk'Nœ°ýÔ¿Îg€2¿zõê‰ôP\¨[¨` Ò—ù. ¿RNzÈEy$ Ú*§.cyÛ¸q£UxOŸ>µŸåŒ=Ò&œ(4JbeHɤžž?nïå:eF© ëÀ/Kª𞎎Ús8”3÷÷­[·ÌÑ£G Û¢¨ÄÊ–kH3Q:댓TŠÚ¤é:_¸p¡õVFDlÎÏM3w,Té9rcc%%·_ç!„è{dÉ’%æÓ§O“Œ‰Øž‡²ÉÑ_éNÉ$$ˆ½ Uyýúµô‹îmÂA©{ûömô>V³6mÚTzUCVݪ(ç¾G¥Ýòª–3wGÕú-j«"U¼Y¹÷ûß÷û!ya•ÙÁ¹Ÿ?ÎQtìa!ô†0CŒæ¢|p†^Ò ÍüöË©ËXÞð8úŠç|–3öHe(¬§XªÎÜï/H0ÞÃvHÕáOûöí³ç((jÎÐF¡ãz®+[Î<ÁAÝ;L98–‡¢6iºÎY‘Çë’³¯%7ÍT9ëôƒÜ1ÇÓq~Bˆ¾7@8Çýëþ. ó‰Écõ&|ÅdÖ™`Yå%ì¢,|¢Ýîõ˜gÁ±à+&¡ÜíÛ·[…¿g£ÈƒÓ”¼nx@ÊÚª˜Á’º~÷î]¦â‡å*½UÇd•¼£ŒRnƇ;¯;öZ#X'<Ž|8…½Nš¡r‹qM'üÅýï>wý N]W+H‹Ða ÝspÑõ&뜱988hú7ÞÊ­¦Ùα’›cdöóü „=o€ð€ð•6•о©¨j¬¾úÊzJfU=+v±îí6@Ø[Àî91Bу0µjßNy¸÷;¹$ÖVE{8ø,7­Üû}9©Îðº¿Âé6¹Ó¿ýP¼* D¸ÂIz¹XÞX}½zõª]Åö½!©±W×K“Éõû÷ï[#øß¿¿îÊ7žBŸ&þ¦=Üß2@ZUjë(¡¬s üqQ7ÍT9[ñ€¤ÆXl¬LÇùA!zÞa5qŒh„/øß±t7 ²’ã+4±4ÊÞ‚•’éö€ŸÔ”,|a(T“ñõe››sBš|ˆ fŸ†¿gÃkU»å…`Dñs{š| Vª­Ü[¬h÷VÞ‚•ºß—ãâ«9Âo?&ë(¸.Æ›ÕÞU«VMGn“wÃ…¹<°êœS—±¼¹>Êê+oECÌ{uä”L6Jûû  ëÀoÊ’S(vÈvû¡øŸ¹†9§(ŸxHÂpĺ ¥‹é§ Ø3v[ÉCÑõ¦ëYnˆþƒ¼©4sÆB~+·l¬LÇùA!zÞÁÕŽ‚Š'„•iÞá÷xØÖÀwPhÆÆÆ¢i¸ƒMQXTJ&9ëÔ[°Rª¿’ó}[cÞª‚âà~ƒƒóXˆU«òŠp¿B[ð; lâÍ­ß*J[Ž,¹œß)ËGìþ¢ü:ãÞ$ÄF^?ØlŒ1W—CCCשW^Áì@áÀh®ª`Þ VÏÉùÉYIåÍA[rT{u½1™ô/òáæ Qÿ~òMÝûuÓŸÜj°Sìø?\µöåï•Z5@ðäQN7Ïý¦MuòP–Ÿ&ëY(Ð\ÇÍ ÁJ¥™*gÝ~3ÆRceºÍBÑväÿý¿ÿ=„ý «ê(•B¡ùAÑ3ˆbz·ðŠïß¿g‡‡!4?!„ !D-UaïoòìÌË‘Ì$ºYuÓžÎíÖ­²5•n?´UÙü „2@„B!„2@„B!„BˆB!„BˆB!„BˆjD!„B!D!„B!D!„B!d€ÑKÌš5K•УõÔ©4{¡ôJ?ìÅñ“'c!„èA„ɹìhêÁ1gÎ3þ|³wï^óòåËÆ*ëñãÇfÛ¶möÇ£æÍ›gtTÞƒÌÚµkm._¾Üܼy3Ùêô­T[ÁéÓ§ÍܹsíqêÔ©Jm“º¿SŠËtSˆúÙñåÉlG:Eã°J¹d€ô¦"ÃF!Äcø¿“bìèö„ê§ñë×/síÚ5û+®M!(Ø=2ÿþµ¿{ìØ1«ä¶ZöÜïß»w/©èÂ;wÌæÍ›§ÈEñ?þ¼ùóç=Î;gÖ­[×1y/^¼0‹/6Ož<±ùòÅ9r¤r=ä|/ÕV7nÜ0[¶l1ß¾}³ŠŸå¦•{¿Œ™c€4­ü—C ýo€!„ Áÿþ;Úñð ?CÁ^°`]¹Æ£ñóçÏJi\¿~ÝìÞ½»’Ì“'OZÏ+åW®\É®<”[¼/2@Ö¯_o¾~ýýe[±b…õD„rgÏž=åûÔI§äíÙ³Çܾ}»åz¨£„m…ñà !àå.7­Üû}9/^´2utàÀk98?|øð„G…swcÊOëÙ³gf×®]SòÇ9FÐÒ¥KmY1_½z5qý÷ïß6]Ò'.\Ȫ˲¼½{÷ά\¹rÊ÷é/oÞ¼IŽ=Òf¼-Z´h¢/¥Ê’ùùógÛÏðÈqÿŽ;&y¾êÔe|ÿþ½=güñ}'“qAyý¶(óÐå”­Î8,ëouòPÔ&M×9^Ñ5kÖØëË–-›ä-#•fSc¡ŸÇ±BÈ)ùlxxØNȬ(³¢~èСI+ä9òð„`HäÊ4ûöí³ç(—(€ÎÐFQäz®+[©qXuŽå¡¨Mš®sVúñº’Y—0ÍT9ëôƒ~ÇB!¤ä3Îq+»ƒ¿‹Â|bòX D1™u&nVy ‡( Ÿh·‚Û>æYp ¤¸P‘"¹Û·o· ÏF‘§)yÝð€”µU7< 1ƒ%uýîÝ»6LÅÊUz«ŽÉ*yG¥ÜŒ;w^wìµ:G°*Nxùpl4Cåãš>NXûß}îúAºÎ©ÿÔ8l÷\t½É:glZ£†þ·2E«i61z} !ÄŒ5@x@øJŠJè ßTT5 V_}e=%³ª„+v±îí6@Ø[Àî91BÑjkjÕ¾òèäX[íáà³Ü´rï÷å¤VNÃëþÊ©ÛäNÿöCñª(&áÊ)éåz@bycU÷êÕ«vÛ÷†¤Æ^]/iL&×ïß¿oàÿþº+ßx>˜ø›öp7i€Ô}³`» NÖ9 þ¸¨›fªœMz@zu !ÄŒ5@ØDÍC#„á þ÷FFFìÝM®¬ù M,²·`¥dº= ä'µ%‹_ Õ¤B|}ÙææYßDFÌ1û4ü=þ[«Ú-/#Ї§Û3Ðä[°RmåÞbE»·ò¬Ôý¾·ÍÆŽû1é\GÁu±ã¬ö®ZµjÒ8r›¼«(..tÈåU眺ŒåÍõQVuy+ dîØ«£ §d²QÚßO@èTX~;P–œ:@aD¶Û‡ÁÿÌ5Ì9EùÄC†#¶kå:÷ž:y(ºÞt#Ë-Ñ—"•fÎX¨Óúy !ÄŒ5@pµ£ â aeš‡wø=v„5ðš±±±¬•AH4EaQ)™< xX§Þ‚•Z‰¬ºJ™ó}[cÞª‚âà~ƒƒó*¡Uåá~„¶àw@ØÄ[u¥·]«Æ¼Ù'çw@Êò»¿(?¼­Æ½Iˆ¼~81ßc®.‡††&®S¯¼‚Ù"ƒÑ\Uq! ¼x©ÈùÉك˛ƒ¶ä¨2öêz b2é_äÃÍ1¢þý䛺÷ë §?¹Uf§0ò¸îË!Îß…+uË©“‡2ÙMÖ9²P̹Ž!›‚•J3Uκý ŸÇ±BôòŸÿ>b‡¢á <(•Bc!„èD1½ÀÛGØÆ÷ïß§„R !4Ž…Bˆ¢­ªÂÞÞäÿˆšÿ–#ÿ˜It³ê¦=Û­[eë‡:-ÇB!D!„B!d€!„B!d€!„B!d€!„B!„ !„B!„ !„B!„"„B!„"ÄL`Ö¬Yª„­§N¥Ù } Wúa/އnæIóƒBH‹“hÙÑÔ¤Í1gÎ3þ|³wï^óòåËÆ*ëñãÇfÛ¶möG©æÍ›gtTÞƒÌÚµkm._¾Üܼy3Ùêô­T[ÁéÓ§ÍܹsíqêÔ©Jm“º¿S ÆtS\úÙñåÉlG:Eã°J¹d€Ì,D†¢/ Y³†£G·'>?_¿~™k×®Ù_‡mÊAÁ~ôè‘ùû÷¯ýåÙcÇŽY%·Õ²ç~ÿÞ½{IEîܹc6oÞ<áQáÜ]ǘòÓzöì™Ùµk×”üqŽ´téR[VŒÁW¯^M\ÿýû·M—ôÉÇ… ²ê²,oïÞ½3+W®œò}úË›7o’c´o‹-šèK©2¤d~þüÙö3}ú4ɘˆíy(›ý•î”LB‚ØËP•ׯ_ÛI¿èÞ& ”º·oßFïc5kÓ¦M¥×Y5d…Ñ­Šrî{TÚ-¯j9s÷xT­ß¢¶*’QÅ›•{¿ÿ}¿’V™œûùãE×Á–K—.Ù0CŒæ¢|p†^Ò ÍüöË©ËXÞð8úŠç|–3öHe(¬§XªÎÜï/H0ÞÃvHÕÁÇ;}ûì9J Šš3´Q踞k€ÄÊVFjVƒcy(j“¦ëœy¼.„dÖ%L3UÎ:ý wŒÅÆñtœ„¢ï Îqÿºƒ¿‹Â|bòX½ D1™u&XVy ‡( Ÿh·‚{=æYp ¤¸P‘"¹Û·o· ÏF‘§)yÝð€”µU7< 1ƒ%uýîÝ»6LÅÊUz«ŽÉ*yG¥ÜŒ;w^wìµ:G°*Nxùpl4Cåãš>Nø‹ûß}îúAºÎ©ÿÔ8l÷\t½É:glZ£†þ·2E«i¶s,¤äæ™ýËM+÷~_Nj…3¼î¯pºMîôo?¯Š®p’^®$–7V_¯^½jW±}oHjìÕõ’ÆdrýþýûÖHþ÷ﯻò烨‰¿i÷w“HÝ7 ¶Ëéd³`à‹ºi¦ÊÙŠ$5Æbce:ÎBÑó›¨yˆc„ð@#|ÁÿÞÈȈ} »I•_¡‰¥Qö¬”L·„ü¤ö€ dñà C¡š4@ˆ¯/ÛÜœÒäCl0û4ü=þ[«Ú-/#ЇœÛ3Ðä[°RmåÞbE»·ò¬Ôý¾_ÍÆxû1é\GÁu1Þ¬ö®ZµjÒ8r›¼«(.tÈåU眺ŒåÍõQV_y+ dîØ«£ §d²QÚßO@èTX~;P–œ:@±C¶Û‡ÁÿÌ5Ì9EùÄC†#¶k…9÷ž:y(ºÞt#Ë-Ñ—"•fÎX¨Órå–•é8?!DÏ ¸ÚQPñ„°2ÍÃ;ü;Âø ÍØØXÖÊ $ 𢰍”L&rÖ©·`¥V"«®Ræ|ÅÖŘ·j€ 8¸ßÆàà¼JhGUyE¸ß¡-ø6ñV]émת1oöÉù²|Äî/Êo•qob#¯ŽFl6Ƙ«Ë¡¡¡‰ëÔ+¯`v p`4WU0Ho^*òA~rÂCbysЖUÆ^]/AL&ý‹|¸9CÔ¿Ÿ|S÷~äô'·ì;þW­}9Äã»p¥n uòP&»É:G 4×1dsB°Ri¦ÊY·䌱ÔX™nóƒB´ÝûOôBô/¼)¥R!4?!zÆBL/ðö^ñýû÷ìð!„æ!„"„¨¡*ì]àíAþùo9ò™D7ë nÚӹݺU¶¦Ò퇶*›„BˆB!„BˆB!„BÈB!„BÈB!„BÈQ!„B!d€!„B!d€!„B!„ !z‰Y³f©z´ž:•f/ô^釽8rò¤q,„=h€09—M=08æÌ™cæÏŸoöîÝk^¾|ÙXe=~üØlÛ¶ÍþxÔ¼yóÌÁƒÍøøxaù«ÖWn}RζnÝ:EîÇÍÎ;íLqpþáÇŽÊ{ðàY»v­­ÃåË—››7o&ûO¾•j+8}ú´™;w®=N:U©mR÷wJq™n Q? ¾œ"™uÓ©;Ÿ¶32@4Ž…¢cȬáYÑ£ÛªŸÆ¯_¿Ìµk×쯸6e„ `?zôÈüýû×þBì±cǬ’ÛjÙs¿ïÞ½¤¢ wîÜ1›7ož"ÅÿüùóæÏŸ?ö8wîœY·n]Çä½xñÂ,^¼Ø|x£¹»Ž1å§õìÙ3³k×®)ùã#héÒ¥¶¬ƒ¯^½š¸þû÷o›.é“ .dÕeYÞÞ½{gV®\9åûô—7oÞ$Çi3Þ-Z4Ñ—ReHÉüüù³ígxä¸ÇŽ“<_uê€2¾ÿÞž3þø¾“ɸ ¼~[”y+rÊÖ®þ^7EmÒtã]³f½¾lÙ²I^Ñ2Ri65úy !„ ’φ‡‡í„ÌŠ2+ꇚ´Bž#O†D®Ì3gÎØ‡×™Ø1FráÁÙ)iñ0KÝwüøqsùòåÂë<°ñR Œsœ={Ö~Ö”¼Ú…:î†¶Š yö >ËM+÷~_†ñ?ìÁ¹ß×Nœ8aû©Ïe~õêÕ顸P·PqA9¤/ó]¥ 6L2´‘‹òH´UN]Æò¶qãF«H9ž>}j?Ë{¤½ÿþ)FI¬ )™ÔÓóçÏí½\§Ì(kaøeIÕÞ³ÑÑQ{ŽbˆÒçþ¾uë–9zôha[õXÙb}‡”QŒ!Æ\Ýq’ÊCQ›4]ç .´ÞJÀˆˆÍù¹i掅*ý ßDZBÈ)ùlÉ’%æÓ§O“Œ‰Øž‡²I×_éNÉ$$ˆ½ Uyýúµ}˜ÝÛ„‚R÷öíÛè}¬’mÚ´©ô:«†¬0ºUQÎ}J»åU-gîªõ[ÔVE2ªx³rï÷¿ï÷CòÂ*³ƒs?œ£è:ØÃréÒ%fˆÑ\”ÎýÕØÐëC´™ß~9uËG_ñãœÏrÆi£d…õ+CÕ9‚ûý Æ{Ø©:xøð¡Ù·oŸ=G¹Dt†6Š"×s XÙrÀëÄ‚‰SjëÌÁ±<µIÓuÎJ?^B2릙*g~ÐïãX!d€”|Æ9newðwQ˜OL«Báƒ(&³ÎÄÍ*/aeáí6@pÛÇ< Œ*R$wûöívõÔß³QäÁiJ^7< emÕ HÌ`I]¿{÷® SñÃr•Þªc²JÞQF)7ãŽÃ×{­Î¬ŠG>œ['ÍP¹Å¸¦VãþwŸ»~P§®ëÌ?¬z“~]¤Ni²Î›ƒƒƒÖ¨¡ã­LÑjšMŒ…^ÇB1c ¾Ò†¢z@Â7UMƒÕW_YOɬêáŠ]l£{» ö°;GÑP´ÚšZµo§<Â:¹$ÖVE{8ø,7­Üû}9©•Óðº¿rê6¹Ó¿ýP¼*ŠI¸rJz¹XÞXÕ½zõª]Åö½!©±W×K“Éõû÷ï[#øß¿¿îÊ7žB&þ¦=ÜßÓÙéd³`à‹ºi¦ÊÙ¤¤WDZBÌX„MÔ<Ä1Bx ¾àoddÄ>ÐÝäÊ ‘¯ÐÄÒ({ VJ¦ÛB~R{@P²xð…¡PM Ä×—mnÎ iò!æ˜}þž ÿ­Uí–‚ÅÃÓíhò-X©¶ro±¢Ý[y Vê~_Ž‹ÛæcÇý˜t®£àº0V{W­Z5i¹MÞU:äòÀªsN]Æòæú(«º¼ 2wìÕQS2Ù(íï' t*¬¿(KN 0"Ûí‡âæ朢|b „áˆu ÊçVË)7ù÷ƒQ'E×›®sd¹E úòR¤ÒÌ uúA?c!„˜±®vTtTÞƒÌÚµkm._¾Üܼy3Ùêô­T[ÁéÓ§ÍܹsíqêÔ©Jm“º¿S ÆtS\úÙñåɬ›NÝù´yÒŸi˰Bô¥2<<+zt{âóÓøõë—¹víšýuئŒìG™¿ÿÚ_ž=vì˜Ur[-{î÷ïÝ»—TtáÎ;fóæÍS䢸Ÿ?ÞüùóÇçÎ3ë֭똼/^˜Å‹›'OžØ¿¿|ùbŽ9R¹r¾—j«7n˜-[¶˜oß¾Ù‹ÏrÓʽ_ŠÀÌ1@šRþÛyŸ ™e€!D_ ƒƒÿˆíxø…Ÿ¡`/X°À®\ãÑøùóg¥4®_¿nvïÞ]IæÉ“'­g•ò+W®dWÊ-Þ—N ëׯ7_¿~~‡²­X±Âz"B¹³gÏžò}ê¤SòöìÙcnß¾Ýr=ÔyX‡m…ñà !à#+7­Üû}9/^´2utàÀk98?|øð„G…swcÊOëÙ³gf×®]SòÇ9FÐÒ¥KmY1_½z5qý÷ïß6]Ò'.\Ȫ˲¼½{÷ά\¹rÊ÷é/oÞ¼IŽ=Òf¼-Z´h¢/¥Ê’ùùógÛÏðÈqÿŽ;&y¾êÔe|ÿþ½=güñ}'“qAyý¶(óVä”­]ý½nŠÚ¤é:Ç+ºfÍ{}Ù²e“¼¢e¤Òlj,¤äÆÆqJn¿ÎBÑ÷Èðð°8YQfEýСC“VÈsäá ÁÈ•yæÌûðâ:0ÆH.<8;å!-:©ûŽ?n._¾\x6^ ”q޳gÏÚÏš’B»PÇÝ0@¶Bq!ϾÂg¹iåÞïËÁ0þñã‡=8÷ûÚ‰'l?õ¯ó Ì¯^½z"=ê*(‡ôe¾‹B³aÆI†6rQIƒ¶Ê©ËXÞ6nÜhÇÓ§Oíg9c´÷ïß?Å(‰•!%“zzþü¹½—딥*¬¿,©:À{6::jÏQàPÎÜß·nÝ2G-l‹¢>+[¬ï°@‚Òˆ1Ę«;NRy(j“¦ë|áÂ…Ö[ ±9?7ÍܱP¥äÈ•”Ü~„¢ï %K–˜OŸ>M2&b{Ê&G¥;%“ ö2Tåõë×vÒ/º· ¥îíÛ·ÑûXÍÚ´iSéuV Yat«¢œû•vË«ZÎÜ=Uë·¨­ŠdTñfåÞïßï‡ä…Ufç~þ8GÑu°‡åÒ¥K6Ì£¹(œû«¦¡×‡4h3¿ýrê2–7<޾âÇ9ŸåŒ=ÒF ë)V†ªs÷û Œ÷°RuððáC³oß>{Žˆ¢æ m:®ç ±²å€×‰“\¥¶jŠÚ¤é:gE¯ !™u ÓL•³N?Èc±q<ç!„è{„sÜ¿îàï¢0Ÿ˜wý N]×™X&ýºH>Òd36­QCÿÆ[™¢Õ4Û9RrsŒÌ~ž„¢ç ¾Ò†¢z@Â7UMƒÕW_YOɬêa¢gÅ.¶Ñ½Ý{ ØÀ#'æA(z¦VíÛ)÷~'÷€ÄÚªhŸå¦•{¿/'µÂ^÷W8Ý&wú·ŠWEW8I/×Ë«¯W¯^µ«Ø¾7$5öêzIc2¹~ÿþ}k$ÿû÷×]ùÆóA(âÀÀÀÄß´‡û{: ¬s üqQ7ÍT9[ñ€¤ÆXl¬LÇùA!zÞa5qŒh„/øß±t7 ²’ã+4±4ÊÞ‚•’éö€ŸÔ”,|a(T“ñõe››sBš|ˆ fŸ†¿gÃkU»å…`Dñs{š| Vª­Ü[¬h÷VÞ‚•ºß—ãâ«9Âo?&ë(¸.̆ÕÞU«VMGn“wÃ…¹<°êœS—±¼¹>Êê+oECÌ{uä”L6Jûû  ëÀoÊ’S(vÈvû¡øŸ¹†9§(Ÿa8b]„ò¹UmÊMþÃý`EÔÉCÑõ¦ëYnˆþƒ¼©4sÆB~+·l¬LÇùA!zÞÁÕŽ‚Š'„•iÞá÷xØÖÀwPhÆÆÆ¢i¸ƒMQXTJ&9ëÔ[°RªïëÏù>Š­‹1oÕAqp¿ÁÁy,ĪUyE¸ß¡-ø6ñæÖo¥-GoöÉù²|Äî/Êo•qob#¯ŽFl6Ƙ«Ë¡¡¡‰ëÔ+¯`v p`4WU0Ho^*òA~rÂCbysЖUÆ^]/AL&ý‹|¸9CÔ¿Ÿ|S÷~äô'·ì;þW­}9Äã»p¥V Ð+ý°ÇCNž4Ž…¢ &ç²£©Çœ9sÌüùóÍÞ½{ÍË—/«¬Ç›mÛ¶Ùš7ož9xð /,ÕúÊ­OÊ™ÃÖ­[§Èýøñ£Ù¹s§ý‘)Î?|øÐQy<0k×®µu¸|ùrsóæÍdÿ©Ó·Rm§OŸ6sçεǩS§*µMêþN).ÓM!êgÄ—S$³•t^¿~m¶oßnÇÙ’%KÌèèh­rÉéMD†BˆÇÐÿŠÝžPý4~ýúe®]»fŵ)#ûÑ£Gæïß¿öb;f•ÜVËžûý{÷î%]¸sçŽÙ¼yó¹(þçÏŸ7þü±Ç¹sç̺uë:&ïÅ‹fñâſɓ'öï/_¾˜#GŽT®‡œï¥ÚêÆfË–-æÛ·oöÀÀâ³Ü´rï—‚1s ¦”ÿ·oßZcãþŒ!í ýo€!„ Á Fv<üÂÏP°,X`W®ñhüüù³Rׯ_7»wï®$óäɓֳÀJù•+W²+eïK§ õë×›¯_¿F¿CÙV¬Xa=¡ÜÙ³gOù>uÒ)y{öì1·oßn¹ê(a[a<8C8ÇÈÊM+÷~_ÎÅ‹­L8pÀFÎ><áQáÜ]ǘòÓzöì™Ùµk×”üqŽ´téR[VŒÁW¯^M\ÿýû·M—ôÉÇ… ²ê²,oïÞ½3+W®œò}úË›7o’c´o‹-šèK©2¤d~þüÙö3<Ü¿cÇŽIž¯:u@ß¿oÏ|ßÉd\P^¿-Ê÷÷­[·ÌÑ£G Û¢¨ÄÊV‹#xw1 P:Í÷ïßk“TŠÚ¤é:_¸p¡õVB®w'•fîX¨Òú} !„ ’ψmþôéÓ$c"¶ç¡lÒõWºS2 b/CUˆÉæaRtoJ¡±ûX%Û´iSéuV Yat«¢œû•vË«ZÎÜ=Uë·¨­ŠdTñfåÞïßï‡ä…ÒÁ¹Ÿ?ÎQtìa¹té’UD1š‹òÁ¹¿z}Hƒ6óÛ/§.cyÃãè+~œóYÎØ#m”¬°žbe¨:Gp¿¿ ÁxÛ!U>4ûöí³ç(—(€ÎÐFQäz®+[¬ï ôc¼sÿ¿ÿýo›n]$–‡¢6iºÎYéÇëBHf]Â4Så¬Óú} !„ ’Ï8g…Ïü]æ“ǪPø ŠÉ¬3q³ÊKØEYøD» Üö1Ï‚cÁ…ŠÉe+ ÏF‘§)yÝð€”µU7< 1ƒ%uýîÝ»6LÅÊUz«ŽÉ*yG¥ÜŒ;w^wìµ:G°*Nxùpl4Cåãš>NXûß}îúAºÎ©Êâ+¤Œ¡Tèd+õ[t½É:glâÕÁ¨¡ã­LÑjšMŒ…^ÇB1c ¾Ò†¢z@Â7UMƒÕW_YOɬêáŠ]l£{» ö°;GÑP´ÚšZµo§<Â:¹$ÖVE{8ø,7­Üû}9©•Óðº¿rê6¹Ó¿ýP¼*ŠI¸rJz¹XÞXÕ½zõª]Åö½!©±W×K“Éõû÷ï[#øß¿¿îÊ7žB&þ¦=ÜßM ´}h€ÄŒÝv ¬s üqQ7ÍT9›ô€ôê8Bˆk€°‰š‡¸{“ aþ÷FFFìÝM®¬ù M,²·`¥dº= ä'µ%‹_ Õ¤B|}Ùææœ&bŽÙ§áïÙðßZÕny!Q<<Ýž&ß‚•j+÷+Ú½•·`¥î÷常mŽ0vÜIç: ®‹gµwÕªU“Æ‘Ûä]Eqq¡C.¬:çÔe,o®²ªË[ÑP sÇ^9%“Òþ~B§Â:ðÛ²äÔ #²Ý~(þg®aÎ)Ê'’0±®Â~®0B8ÇbŸFŠ:y(ºÞt#Ë-Ñ—"•fÎX¨Óúy !ÄŒ5@pµ£ â aeš‡wø=v„5ðš±±±hîà„AS•’É‚‡uê-X)@Õß?Éù>Š­‹1oÕAqp¿ÁÁy,ĪUyE¸ß¡-xµ(›xsë·ŠÒ–#‹7ûäüHY>b÷凷ո7 ¹˜~Š%Ƙ«Ë¡¡¡‰ëÔ+¯`v È`4WU\Ho^*òA~rö Äòæ -9ªŒ½º^‚˜Lúùps †¨?ù¦îý:ÈéOn•Ù)Œü®†ûrˆówáJ­ @x£ë;ÿú׿²6¡×ÉCY~š¬sd¡˜sC6'+•fªœuûA?c!„èdü?ãÑCÑ¿ð”J!„ƱBôŒ"„˜^àí#lƒô0”J¡q,„2@„m…Pö.°‰Ùÿ5ÿ-Gþ1“èfÔM{:·[·ÊÖuZ6Ž…BˆB!„BÈB!„BÈB!„BÈB!„B B!„B B!„B!D!„B!Dˆ™À¬Y³T =ZOJ³ú@¯ôÃ^ÝÌ“æ!„ 'Ѳ£©I›cΜ9fþüùfïÞ½æåË—UÖãÇͶmÛìRÍ›7Ï|証˜µk×Ú:\¾|¹¹yóf²ÿÔé[©¶‚Ó§O›¹sçÚãÔ©S•Ú&u§Œé¦¸ô³âË)’ÙJ:¯_¿6Û·o·ãlÉ’%ftt´V¹d€Ì,D†¢/ ÿ34=º=ñùiüúõË\»vÍþ:lSF ö£GÌß¿í/Ï;vÌ*¹­–=÷û÷îÝK*ºpçγyóæ)rQüÏŸ?oþüùcsçΙuëÖuLÞ‹/Ìâŋ͓'Oìß_¾|1GŽ©\9ßKµÕ7Ì–-[Ì·oßìÅg¹iåÞ/E`æ M)ÿoß¾µÆ:Æ;ýCÚ72@d€!Ä´2@þ18=Úñð ?CÁ^°`]¹Æ£ñóçÏJi\¿~ÝìÞ½»’Ì“'OZÏ+åW®\É®<”¼/2@Ö¯_o¾~ýýe[±b…õD„rgÏž=åûÔI§äíÙ³Çܾ}»åz¨ó°Û ãÁBÀ9FVnZ¹÷ûr.^¼h dêèÀÖ0rp~øðá çî:Æ”ŸÖ³gÏÌ®]»¦äsŒ ¥K—Ú²b ¾zõjâúïß¿mº¤O>.\¸U—ey{÷îY¹rå”ïÓ_Þ¼y“{¤Íx[´hÑD_J•!%óóç϶Ÿá)àþ;vLò|Õ©Êøþý{{ÎøãûN&ã‚òúmQæ¡Ë)[ä7Çãö·:y(j“¦ëÃjÍš5öú²eË&yEËH¥ÙÔXHÉã”Ü~„¢ï ááa;q²¢ÌŠú¡C‡¢+}Eòð„`HäʤA›ùí—S—±¼áqô?Îù,gì‘6ÊPXO±2T#¸ß_`¼‡íªƒ‡š}ûöÙs”@5gh£Ðq=׉•-ÖwPú1Þ¹ÿßÿþ·M·®ËCQ›4]ç¬Èãu!$³.aš©rÖé¹c,6ާãü „}o€pÎ Ÿ;ø»(Ì'&Õ›ðA“Yg‚e•—°‹²ð‰v ¸×cžÆ‚ )’Ë&V<þž"NSòºá)k«nx@bKêúÝ»wm˜Š”«ôV“UòŽ2J¹wî¼îØkuŽ`Uœð8òá Ø:i†Ê-Æ5}œð÷¿ûÜõƒ:uSÿ”ÅWC©ÐÉVê·èz“uÎØÄ«ƒQCÿÆ[™¢Õ4Û9RrsÌ~„¢ç ¾Ò†¢z@Â7UMƒÕW_YOɬêa¢gÅ.¶Ñ½Ý{ ØÀ#'æA(z¦VíÛ)÷~'÷€ÄÚªhŸå¦•{¿/'µÂ^÷W8Ý&wú·ŠWEW8I/×Ë«¯W¯^µ«Ø¾7$5öêzIc2¹~ÿþ}k$ÿû÷×]ùÆóA(âÀÀÀÄß´‡û»I„¶ ˜±Ûn¤“u΂?.ꦙ*g+Ô‹•é8?!DÏ l¢æ!îÞäBÿ½‘‘û@w“ +9¾BK£ì-X)™nùIíAÉâÁ†B5i€__¶¹9'¤É‡Ø`öiø{6ü·Vµ[^F9·g É·`¥ÚʽŊvoå-X©û}9.¾š#ŒñöcÒ¹Ž‚ëb¼Yí]µjÕ¤qä6yWQ0\èË«Î9u˛룬¾òV4ÈܱWGANÉd£´¿Ÿ€Ð©°üv ,9u€b‡l·Šÿ™k˜sŠò‰‡$ G¬k€°ß„°+Œ±ا‘¢NŠ®7]çÈr‹@ôä¥H¥™3êôƒ\¹ece:ÎBÑó®vT|証˜µk×Ú:\¾|¹¹yóf²ÿÔé[©¶‚Ó§O›¹sçÚãÔ©S•Ú&u§—é¦õ³âË)’Y7ºó@;ó DãX!:g€ Å.O¨~¿~ý2×®]³¿âÚ”‚‚ýèÑ#ó÷ï_û ±Ç޳Jn«eÏýþ½{÷’Š.ܹsÇlÞ¼yŠ\ÿóçÏ›?þØãܹsfݺu“÷âÅ ³xñbóäÉû÷—/_Ì‘#G*×CÎ÷RmuãÆ ³eËóíÛ7{``ñYnZ¹÷KÁ˜9H§”ÿÜy@Hÿ B!Ägp0~´áá~ƃuÁ‚våÆÏŸ?+¥qýúu³{÷îJ2Ožù¸páBV]–åíÝ»wfåÊ•S¾OyóæMrì‘6ãmÑ¢E})U†”ÌÏŸ?Û~†GŽûwìØ1ÉóU§(ãû÷ïí9ãï;™Œ Êë·E™‡.§líšê桨Mš®s¼¢kÖ¬±×—-[6É+ZF*ͦÆB?c!„RòÙðð°YQfEýСC“VÈsäá ÁÈ•yæÌûðâ:;ÆH.<8;å!-f©ûŽ?n._¾\x6^ ”q޳gÏÚÏš’B»PÇÝ0@¶Bq!ϾÂg¹iåÞïËÁ0þñã‡=8÷ûÚ‰'l?õ¯ó Ì¯^½z"=ê*.(‡ôe¾‹¢´aÆI†6rQIƒ¶Ê©ËXÞ6nÜh)ÇÓ§Oíg9c´÷ïß?Å(‰•!%“zzþü¹½—ë”e-¬¿,©:À{6::jÏQ QúÜß·nÝ2G-l‹¢>+[n?çªsp,EmÒt/\¸Ðz+#"6ç禙;ªôƒ~ÇB!¤ä³%K–˜OŸ>M2&b±Îe“®¿Ò’IH{ªòúõkû0)º· ¥îíÛ·ÑûX%Û´iSéuV Yat«¢œû+©í–Wµœ¹{<ªÖoQ[ɨâÍʽßÿ¾ßÉ «ÌÎýüqŽ¢ë`Ë¥K—l˜!FsQ>8÷WcC¯iÐf~ûåÔe,ox}Ås>Ë{¤’ÖS¬ Uçî÷$ïa;¤êàáÇfß¾}öåÐÚ(Š\Ï5@beË¡h¨:ÇòPÔ&M×9+ýx]ɬK˜fªœuúA¿c!„Rò縕ÝÁßEa>1y¬ …¢˜Ì:7«¼„]”…O´ÛÁmó,80\¨H‘ÜíÛ·[…¿g£ÈƒÓ”¼nx@ÊÚª˜Á’º~÷î]¦â‡å*½UÇd•¼£ŒRnƇ;¯;öZ#X'<Ž|8¶Nš¡r‹qM'¬Æýï>wý N]Wé˹ó@«õ[t½É:glþ÷y‚QCÿÆË“¢Õ4› ½>Ž…bÆ < |¥ E%ô€„o*ªš«¯þC:%³ª„+v±îí6@Ø[Àî91BÑjkjÕ¾òèäX[íáà³Ü´rï÷å¤VNÃëþÊ©ÛäNÿöCpª(&áÊ)éåz@bycU÷êÕ«vÛ÷†¤Æ^]/iL&×ïß¿oàÿþº+ßx>E˜ø›öpwÂÉÚm€t²ÎY0ðÇEÝ4SålÒÒ«ãX!f¬ÂæIâ!<Ð_ð¿722bènre…ÈWhbi”½+%Óí!?©= (Y<øR!í4@ˆ¯/ÛÜœÒäCÌ1û4ü=þ[«Ú-/則§Û3Ðä[°RmåÞbE»·ò¬Ôý¾·ÍÆŽû1é\GÁu±ã¬ö®ZµjÒ8r›¼«(..tÈåU眺ŒåÍõQVuy+ dîØ«£ §d²QÚßO@èTX~;P–œ:@aD¶ÛÅÿÌ5Ì9EùÄC†#¶b€Äæ2êä¡èzÓuŽ,·DÿA^ŠTš9c¡N?èçq,„3ÖÁÕŽ‚Š'„•iÞá÷xØÖÀwPhÆÆÆ¢i¸ƒMQXTJ&Ö©·`¥<Uÿ$çû(¶.ƼUÅÁý6籫Våá~„¶àw@ØÄ›[¿U”¶Y¼Ù'çw@Êò»¿(?¼­Æ½Iˆ¼~81ßc®.‡††&®S¯¼zÕ"ƒÑ\Uq! ¼x©ÈùÉك˛ƒ¶ä¨2öêz b2é_äÃÍ1¢þý䛺÷ë §?¹Uf§0ò¸îË!Îß…+µÃ‰ÍeÔÉCY~š¬sd¡˜sC6'+•fªœuûA?c!„è·{ìBô-¼¥R¡q,„½c€!¦xûÛøþýû”P*!„ƱBÈB´BUØ»ÀÛƒüQóßrä3‰nÖAÝ´§s»u«lýP§eãX!d€!„B!„ !„B!„ !„B!„ !„B!„"„B!„"„B!„2@„B!„2@„˜ Ìš5K•УõÔ©4{¡ôJ?ìÅñÐÍ?_¿~™k×®Ù_‡mÊAÁ~ôè‘ùû÷¯ýåÙcÇŽY%·Õ²ç~ÿÞ½{IEîܹc6oÞù¸páBV]–åíÝ»wfåÊ•S¾OyóæMrì‘6ãmÑ¢E})U†”ÌÏŸ?Û~†GŽûwìØ1ÉóU§(ãû÷ïí9ãï;™Œ Êë·E™‡.§líšê桨Mš®s¼¢kÖ¬±×—-[6É+ZF*ͦÆBJnl§äöëü „}o€ Û‰“eVÔ:4i…}šdLÄbË&G¥;%“ ö2Tåõë×vÒ/º· ¥îíÛ·ÑûXÍÚ´iSéuV Yat«¢œû+©í–Wµœ¹{<ªÖoQ[ɨâÍʽßÿ¾ßÉ «ÌÎýüqŽ¢ë`Ë¥K—l˜!FsQ>8÷WMC¯iÐf~ûåÔe,ox}Ås>Ë{¤2ÖS¬ Uçî÷$ïa;¤êàáÇfß¾}ö%EÍÚ(t\Ï5@beË¡h¨:ÇòPÔ&M×9+òx]ɬK˜fªœuúAî‹ãé8?!Dß œãþu…ùÄä±z>ˆb2ëL°¬òvQ>Ñn÷z̳àÀXp¡"Er·oßn=þž"NSòºá)k«nx@bKêúÝ»wm˜Š”«ôV“UòŽ2J¹wî¼îØkuŽ`Uœð8òá Ø:i†Ê-Æ5}œð÷¿ûÜõƒ:u]¥/çέÖoÑõ&뜱9øß F ý/OŠVÓlçXHÉÍ12ûy~Bˆž7@x@øJŠJè ßTT5 V_ý‡tJfU=+v±îí6@Ø[Àî91Bу0µjßNy¸÷;¹$ÖVE{8ø,7­Üû}9©Îðº¿Âé6¹Ó¿ýœ* D¸ÂIz¹XÞX}½zõª]Åö½!©±W×K“Éõû÷ï[#øß¿¿îÊ7žB&þ¦=Üß0@rçv ¬s üqQ7ÍT9[ñ€¤ÆXl¬LÇùA!zÞaó$qŒh„/øß±t7 ²’ã+4±4ÊÞ‚•’éö€ŸÔ”,|©ˆv Ä×—mnÎ iò!6˜}þž ÿ­Uí–‚òÄCÎíhò-X©¶ro±¢Ý[y Vê~_Ž‹¯æc¼ý˜t®£àºoV{W­Z5i¹MÞU :äòÀªsN]Æòæú(«¯¼ 2wìÕQS2Ù(íï' t*¬¿(KN Ø!Ûí‡âæ朢|â! Ã[1@bó@uòPt½é:G–[¢ÿ /E*Íœ±P§äÊ-+Óq~Bˆž7@pµ£ â aeš‡wø=v„5ðš±±±hîà„AS•’ÉDÎÃ:õ¬”G êïŸä|ÅÖŘ·j€ 8¸ßÆàà<bÕª¼"Üï€Ðü›xsë·ŠÒ–#‹7ûäüHY>b÷凷ʸ7 ±‘×G#6cÌÕåÐÐÐÄuê•W¯:P80š«*¤·/ù ?9á!±¼9hKŽ*c¯®— &“þE>܃!êßO¾©{¿rú“[ vŠÿ‡«Ö¾âñ]¸R; Ø>^Xþªõ•[Ÿ”3‡­[·N‘ûñãG³sçNû#Sœøð¡£òmæÎkS§NUj›ÔýR\¦›BÔψ/§HfÝtêŽÛvæAˆÆ±BtÌLüëö„ê§ñë×/síÚ5û+®M!<ø=zdþþýk!öرcVÉmµì¹ß¿wï^RÑ…;wî˜Í›7O‘‹âþüyóçÏ{œ;wά[·®cò^¼xa/^lžËM+÷~)3ÇiJù¯;ne€ô"„2@4@r>CÁ^°`]¹Æ£ñóçÏJi\¿~ÝìÞ½»’Ì“'OZÏ+åW®\É®<”[¼/2@Ö¯_o¾~ýýe[±b…]! åΞ={Ê÷©“NÉÛ³g¹}ûvËõPG Û ãÁBÀ9FVnZ¹÷ûr.^¼h dêèÀÖ0rp~øðá çî:Æ”ŸÖ³gÏÌ®]»¦äsŒ ¥K—Ú²¢¤¾zõjâúïß¿mº¤O>.\¸U—ey{÷îY¹rå”ïÓ_Þ¼y“{¤Íx[´hÑD_J•!%óóç϶Ÿá)àþ;vLò|Õ©Êøþý{{ÎøãûN&ã‚òúmQæ¡Ë)[uÆmÝ<µIÓuŽWtÍš5öú²eË&yEËH¥ÙÔXèçq,„2@J>¶2+ʬô:thÒ yŽ<÷÷­[·ÌÑ£G Û¢¨ÄÊ3Ü«Œ³VòPÔ&M×ùÂ… ­·0"bs~nš¹c¡J?è÷q,„2@J>[²d‰ùôéÓ$c"¶ç¡lÒõWºS2 "ƺ*¯_¿¶“¢{›0@PêÞ¾}½U²M›6•^gÕF·*ʹïQi·¼ªåÌÝãQµ~‹ÚªHFoVîýþ÷ý~H^Xevpîçs]{X.]ºdà 1š‹òÁ¹¿z}Hƒ6óÛ/§.cyÃãè+~œóYÎØ#m”¬°žbe¨:Gp¿¿ ÁxÛ!U>4ûöí³ç(—(€Î@Qäz®+[UÇY+y(j“¦ëœ•~¼.„dÖ%L3UÎ:ý ßDZBÈ)ùŒsÜÊîàï¢ðƒ˜E˜ø›öp7i€Tgí6@:Yç,øã¢nš©r6ééÕq,„3Öa5qŒh„/øß±t7¹²Bä+4±4ÊÞ‚•’éö€ŸÔ”,|a(T“ñõe››sBš|ˆ9&~Ü%÷ߦÓny!Q<<Ýž&ß‚•j+÷+Ú½•·`¥î÷常mŽ0vÜIç: ®‹gµwÕªU“Æ‘Ûä]Eqq¡C.¬:çÔe,o®²ªËÛšP sÇ^9%“Òþ~B§Â:ðÛ²äÔ #²Ý~(þg®aÎ)Ê'’0Lª®Ruœµ’‡¢ëM×9²Ü"ýy)Ri挅:ý ŸÇ±BÌXW;N9¿R–ØýEùám5îMBläõÃшùÆsu9444qzå̌檊 ià­`õœ|Ÿœ•ôXÞ´%G•±W×K“Iÿ"nŽÁõï'ßÔ½_9ýÉ­2;…‘ÿÃÕp_qþ.\©U¤Î8«›‡²ü4YçÈB1ç:†lNV*ÍT9ëöƒ~ÇBÑ7ˆbúÂxP*…ÇB!DÑxûÛøþýû”P*!„ƱBÈB´BUØ»ÀÛƒüQóßrä3‰nÖAÝ´§s»u«lýP§eãX!d€!„B!„ !„B!„ !„B!„ !„B!„"„B!„"„B!„2@„B!„2@„˜ Ìš5K•УõÔ©4{¡ôJ?ìÅñÐÍù¸páBV]–åíÝ»wfåÊ•S¾OyóæMrì‘6ãmÑ¢E})U†”ÌÏŸ?Û~†§€ûwìØ1ÉóU§(ãû÷ïí9ãï;™Œ Êë·E™‡.§lEÔ·uóPÔ&M×9^Ñ5kÖØëË–-›ä-#•fSc!%76ŽSrûu~Bˆ¾7@†‡‡íÄÉŠ2+}‡š´Bž#O†D®Ì3gÎØ‡×™€1FráÁÙ)iñÐIÝwüøqsùòåÂë<°Y=Eç8{ö¬ý¬)y!´ uÜ $l+òì(|–›Vîý¾ ã?~؃s¿¯8qÂöSÿ:ŸÊüêÕ«'ÒCqp!8¡‚rH_æ»(46l˜dh#å‘4h«œºŒåmãÆVáq<}úÔ~–3öH{ÿþýSŒ’XR2©§çÏŸÛ{¹N™QªÂ:ðË’ª¼g£££öåÌý}ëÖ-sôèѶ(걲Š÷*㬕<µIÓu¾páBë­ŒˆØœŸ›fîX¨Òr䯯JJn¿ÎBÑ÷È’%ĶOŸ&±=e“£¿Ò’IH1ÖUyýúµô‹îmÂA©{ûömô>V³6mÚTzUCVݪ(ç¾G¥Ýòª–3wGÕú-j«"U¼Y¹÷ûß÷û!ya•ÙÁ¹Ÿ?ÎQtìa¹té’ 3Äh.Êçþªièõ! ÚÌo¿œºŒå £¯øqÎg9c´Q†ÂzŠ•¡êÁýþ‚ã=l‡T<|øÐìÛ·Ïž£¢¨9…Žë¹H¬leTg­ä¡¨Mš®sVäñº’Y—0ÍT9ëôƒÜ1ÇÓq~Bˆ¾7@8Çýëþ. ?ˆÉcõ&|ÅdÖ™`Yå%ì¢,|¢ÝîõœOŒ*R$wûöív%Õ%/òà4%¯²¶ê†$f°¤®ß½{׆©øá@¹JoÕ1Y%ï(£”›qÇáÎ뎽VçVÅ #Na¯“f¨Ü¢ôÓÇ qÿ»Ï]?¨S×9õ_uœµZ¿E×›¬sÆæàà 5jèßx+S´šf;ÇBJnŽ‘ÙÏóƒBô¼ÂÂWÚPTBHø¦¢ªi°úê+ë)™U= Lô¬ØÅ6º·Ûao¸säÄ<EÂÔª};åáÞïäX[íáà³Ü´rï÷å¤V8Ãëþ §ÛäNÿöCñª(á 'éåz@bycõõêÕ«vÛ÷†¤Æ^]/iL&×ïß¿ouàÿþº+ßx>E˜ø›öp7i€Tgí6@:Yç,øã¢nš©r¶âI±ØX™ŽóƒBô¼Â&jâ!<Ð_ð¿722bènd%ÇWhbi”½+%Óí!?©= (Y<øÂP¨& âëË67ç„4ùLü¸Kî¿M§ÝòB0¢xȹ=M¾+ÕVî-V´{+oÁJÝïËqñÕaŒ·“Îu\ãÍjïªU«&#·É»Š‚áB‡\XuΩËXÞ\eõ•·5¡@掽: rJ&¥ýý„N…uà·eÉ©;d»ýPüÏ\ÜS”O<$a˜T]¤ê8k%E×›®sd¹E úòR¤ÒÌ uúA®Ü²±2ç!„èyW;NÈOÎJz,oÚ’£ÊØ«ë%ˆÉ¤‘7Ç`ˆú÷“oêÞ¯ƒœþäVƒbÇÿ᪵/‡x|®ÔªRgœÕÍCY~š¬sd¡@sC6'+•fªœuûAÎK•é6?!DˆbºÂ›rP*…BóƒBˆ¢ðö^ñýû÷ìð!„æ!„"„¨¡*ì]àíAþùo9ò™D7ë nÚӹݺU¶¦Ò퇶*›„BˆB!„BˆB!„BÈB!„Bô®¢C‡:tèСC‡MˆB!„Bt‚ÿæôõÒúC IEND®B`‚Multiverse-multiverse-0.7.0/charts/boxing_overhead_line_narrow.png000066400000000000000000001066541174000617100256170ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔ€IDATxÚì]{LTé{nÒ4MÓ4ý§išþÑ4Mš¦išþѤiš¦ùe³¿l»f³7îOw¹‰€¸Šˆˆâ AQTÖ»¨(Þo "(—ä&ˆ€Š\”‹ˆ‚ (—äíy¿õ°Ã03ÌåÌ9sy^ò„9ç;̙眙áùÞïùÞï@ ¡hü.@ @ @ @  PýÃóG4 üÇLögFÿò/ÿBAAAÔÔÔär¯kŽ÷ …@¸•À2ÆŸüÉŸPQQþQB`…@ ùtèСûÿë¿þ ÿ(ñÞ @8òèÓ§O3öÿéŸþ).Þà€@@`!%ÖŸÿùŸ›üû††áÓúû¿ÿ{!Âx8ñïþîïľúúúYÇó~Ãç­©©™n«««›ÑÆÇZóÒTÛ¾}ûÄkâ×óÿø”’’bòõ'$$Ì8n×®]ÿc¶åšüÇüÇŒó¼xñbº¶ýû¿ÿû¬sµ´´Pxx8ýó?ÿ³ðÍñ¹þæoþ†|||¨ªªÊª{>::*žã/ÿò/giG®«=¯ëÂ… &½€ÿöoÿFQQQÔÛÛköšoß¾}ÆëÚ½{7…@¸žÀ2" œõ·GŽÿ-ù·80ãoøŸ9›çåö… N·ñcy?ÃÇÚ#°–/_nòµðë5Œ ˜<ÎÔß[¶^“ÔÔÔm,2Ì ¾'Æ‚„‘¥sÅÆÆÎyÏ ¯;¿vG¯«½¯+ Àâßüõ_ÿ5uvvÎú»ï¿ÿ^ñûˆ@ °E–)|ûí·4000ãï8 aìÑzóæ õ÷÷Óÿ÷Ïh3ÎX477‹Ì„ü35 Y˜p¶Œ±FšjûòË/ixxx–H4Ì]½zuV¿~†qVÉÚÌö\¾®œu1%d ³}|Ìû÷ïÍfû˜3gx&&&($$dF[VV–ÅëõOÿôO&gŠÚs]y],”Xpò5ãÐëõ”˜˜h6«iê>ÊלñŸÿùŸXáºë/þâ/¦‡\Ìe gÞ½{wFkÇŸnç¡$ÃlÃéÓ§­Î´™j+//Ÿþm¸ŸEóæÍ›Ñ–ŸŸ?ÝÆíùÇlï51ü»ý×ÞÏCc¦2}ÆÙ>F[[Ût›1ïßýîw¯×íÛ·­zoXs]y]Ö¼Gy˜Ñ0Œï£á5çÇXáKÎ:pæÊÜ‹.Ã6ölÉÁÙ cf*~üñÇéìŒ<¤äççgÓë4ÕføZÌý¥×o,¬ýÇlï5ÉÍÍ1DÇC£ü ‡Eû¥¬ÇÆh®ëåèuuäu±ï¿ì]3W2ÄÚknï}D X„ÓGww÷¬¡$9 ‡µLýã²ôOQ6|Ÿß”1ÞVeM›-¯ßÚÌö^œ™‘Û²³³äí¿ýÛ¿ó\sÁnJ\Wk_—ñPŸµ\œqáTeIØ’90•ÁâãeÌ_ýÕ_ 3?fÿ“Kí Ö\×dݺuÓm111´iÓ¦éí 6Ìy.~~¥î¹’×ÕÚ×ų ÿîĉV½d°,ÂíÏØ2' õ`mݺuÆŒ2ÃmÎXÆÃŸ†¯_m›Ì嶯¾úŠþïÿþozÛØðoê\.!°ì}]Æ3/åàr–^Ç7ß|…@¸Àb–ñ?/Ã\Æ3æ8%ÏÞâ™\æj]qTTTÌðáðL:†<³ÁÇ8S`Á1x–Ÿ£³Ï¹&òìEöÉ$sôÏÅCŒ,âäì ×âârüÔXö¾.ö]þßÎ@ aã×Y„áËxǸÐ#ãÌUóɸvÓ‡èþá¦Û###§Ûø±¼Ÿÿáò±ÎXl¨Vº~’=×D®'5W)[Ïåˆ/ÉÞëjÏë2®fX¶b®×ëŒzf pŠÀâ<$ÈÓà¹Z·9/ mq}#MìÑb°8â}œ­0CQ#×À’ðƒ O:S`qpåvùµóo.Ga<ãÏx¶Û\aë51Ÿ†¦m~l(2-‹' ðñò}ãaFv55iÀÙËÞ×Å™-ùx6öóqÖ¾^®Èo|máŠ@ °„“ãÒ¥K3þ)³(@ ,°"þçþ‡Î;'*­sp–Ž·åsâD ,0þâ˜Ã#ÄFsK(€ÀB £à™|¼L/OÃ>+Tìúâ‹/D*C@@`!@ °@ °@ °@ X@ X@ X@ ,@ ,@ ,„z±uëÖÛ\U{Ù²eŠÂÏéðFÞ¸×à Þà Þ–aüËKÖÏ?ÿLwïÞU¼Ü‰ÒÏéðFÞ¸×à Þà Þ–¥>|è•Noä{ Îà Îà …PI`…Þxƒ3xƒ3xã^C`!àÁ‚oœÁœÁœáÁB ƒ…Þ8ƒ78ƒ78#ƒ,ôúÀ¼Á¼Á,Ÿ33XBL™ i?z?à Þà ÞàŒ – ¬ÌÌLéÿ÷êèè°8KK7˜šeg<Ä6×ñ޶«}>,øÀ¼Á¼Á,›ƒ‹)׆2W'Ê”‡ÉÒñ޶«}>,ôúÀ¼Á¼Á,Õƒ ”zòù °u°Xèý€3xƒ3xƒ32X¬Ë 0~Îà Îà Îð`A`A`Ùˆ[å·h…ŸK5—Ðûgðgðgd° ° °”@Ia!½ýÙ•Pny.Æâx° ° °”èÔž?O–üH«ß,¥Û÷n£÷Îà Îà ÎÈ`A`A`)1ŽÝKw-¥°÷aTPZ€ñ{popop†  ËÑ^@i~>RúÝ51A…%…èý€3xƒ3xƒ32XXXŽâÑéÓ4´„bº×ÑÚ¾µ¤+Öal€Ë–¹êír Q\\œ(ðùÍ7ßPzzúœÏ™––f±2º£íZŸO‹ –ŒÞ©3~;­y»†6õn"Ý]z?à Þà ÞàŒ –«f°Ì ¬„„ÚµkMLL^¯§äädºuë–Ùç‘×öãuý,­ýgo»ÖçÓʃ%£,/ôþþTuå<…¿ §Ø—±¿gðgðgx°ÜM`q抅•ü8""Âìó°Xa+? S¬]ëóiÁb<>vŒ>††R~qý<ô3%u$¡÷Îà Îà ÎÈ`¹³ÀâLÖW_}eöy¸mjjjz›ïh»ÖçÓÒƒeˆþ¨(zžœLyey´tx)¥´¥`œ€Ë]V||¼d‘%~ùå—6=áñ޶k}>WÈ`1îß¼Iã~~Tuý:å”çPÐhh>€Þ8ƒ78ƒ78#ƒå‹Mî±±±"“5þ|ÊÌ̤yóæye‹o° ÃãÎò‹;ºýîÝ»9ï:q‚Þ‡…Ñú:zÐý€–Œ/¡c)r~­¶»Ûë·g»··×«øÊÛÌÛ›øzëûÛÚï3¼¿ñ}fiÛ#–qäåå ã»-ž(Þ§T»Öçs• –€NGï$qײ¿Ø¾V}üõþ”ÞŽÞ8ƒ78ƒ78#ƒåÊkïÞ½488(2;•••äããCÝÝÝfÿNž•ÇciÖž½íjŸÏU=X2*33iÜ×—*²³Åö¥—ÈÜŸÎ><‹q{,W¨ƒeªg¬xh‡###©½½}NaƵ¤,Õ•r¤]íó¹të3Ú÷ì¡·Ò½‘·Y\±Èb±…Þ8ƒ78ƒ78#ƒå†ÁÂË“Ïçju°L¡¸¨ˆ>H¯áÉ‘#Óûx˜‡ yØ5TÀ¼Á¼Áu°.®–ÁbÔ\¾Lz??*»ukzÞ-¦¬Š,ôúÀ¼Á¼Á,–=èܱƒÞlØ0c—nà\ÊãøpopopFË™BËT,Y²„222hrrRàÌ™3löyäµýx]?KkÿÙÛ®õùÜÁƒe®îÎUÞ¹Ú»qÛí{·iÙÇe”ü<cüKËÕ°Xa+? S¬]ëó¹SKÆÛÕ«Åz…¦ÚrËs)x$˜ö·ìG¯œÁœÁœ‘ÁRK`ÅÄĈ¬ÕÔÔ”@zzºØg.x‘“ƒó>¥Úµ>Ÿ;y°dTdgÓ¸¯/UffšlϾŸMctøÉaøÀ¼Á¼Á,5V__-\¸pÚ§Ålzž/¿üR±v­ÏçŽ,FËþýô.<œîêLÏ̬̤}¥5¦¡×Îà Îà ÎÈ`9[`EFFŠ –¡+""Â+3X|ƒeF¸$\XµËo,þíèvgçEŸïÅóçôqÕ*zvà€Ùão7ß&ÿqºÞv]q>ØÆ6¶±mlÛ»í‘ËT6ÇR†Ç”§‰÷)Õ®õùÔÈ`Õ×gHϺ€N)ú¼UׯӸŸÝ¿yÓì1çkϓ߸Ÿø^8ƒ78ƒ78#ƒå$Å3ÙweèÁ2œEhüwò¬¼ÁÁA‹³öìmWû|j ,W>49™FŸ>ù).²ž''ST”ÅcÎÔŸ™¬+5Wà[gðgðgx°­ƒeªVww·䙃 ~Ìû, 3®%e©®”#íjŸOM%‹«‘‘ÒÏÏüHq‘Åå>††Òc‰§¥ã؋Ş,öf¡×Îà Îà ÎÈ`©–J6xÂùÔX÷îÝÂzý/Fg;+ös»RoÔ/’ÞߟÊòò,dz yv!Ï2Du°n'°ä g¬¦¦ª§3XDÔÚzQñ7kW|<õnÚ4çq\‹ëdq½,ôúÀ¼Á¼Á,„Û ,C‘EtJ‚¿SÄ£$?ŸFƒ‚èÑéÓs˕޹âûm³hð-À«{ Þà ÞXMfNLDRUÕu§}ê32h40J%±5×±¼f!¯]Èk¢×Îà Îà ÎÈ`!ÜN`Éž¬ÎÎÎü0¼Š‰¡î¸8«ŽÝÒ³…""¨°¤ž,„û ,îpöJ¯ âbÓÞ´÷nß&}@ÕžŸ»î•ֿYOkûÖ’ÎI¯ =]ðgðgð†À‚ÀršÀ’DZ߿_A¥;õÑtâ ‡„PIáÜ™©¢â"Zóv mêÝ$| à Þà Þà ­2Xü»¹ùzóf½Ó?}ÑÑô")ɪc J (ü]8žŒE¯œÁœÁœ‘ÁB¸ÀúÍ‹uG½çä|å994îïOÕW¯ZuüÒ;ôóÐϔԑä•_"popoÜkd°Ì )k¢¬¬Ì¢‘×öãuý,­ýgo»ÖçSÛƒõkÙ†Ó44´\•Ç@DµîÝkõñ9å94DšÀ·Îà Îà{ e¯À ¡³í,VXÁÊÁÃÂÂk×ú|Zd°îÞÕÑØØbªªºæôGEVûúŠßÖþMVE-–^ß±ÇÇÐëgðgðÆ½†À²U`UVVRJJŠÅc¾úê+ššššÞæÇ¼O©v­Ï§¶KFGG"uv&¨òi•î1g²lù›kÕ×È_ïOé é^ù¥Àƒe·Àb!ÑÑÑaóó|ùå—Šµk}>m2Xw%q›éôšX2؃Å^¬§‡Ùôw—\"ÿq:ûð,z}à ÞàŒ{{ eÀâ‹3çóxr‹o° ÃãÎò‹;ºýîÝ»Yí?®¢††tEž®í—÷ïÓD@€˜]hËß³¸ ˜ ÒžR»ÎoüÛYü\i»··×«øÊÛÌÛ›øzëûÛÜ÷Þßø>³eÛ£û’ž¥Úµ>ŸV¬_kb¤7o¢Õ3+&%‰úX¶þòp!¢×Îà{{ ÞÈ`™‰††³Æoã¿“gå Zœµgo»ÚçS[`:Õ@Ë—ÑO?}¢eËF(-­ÉDM¬(\Ù+¼7¦¥Ùü·lxgã;àἺ–¹zX,:ª««­f\ÆÁR])GÚÕ>Ÿš‹ÅUPžêêÆÅó>{FúIÚÿÔ &ÖFUjbÉà5 y­B^³ÐÖ¿åÒ \ÂK9 ×Îà{ Îàí•,{ã÷¿ÿ½GŸOMÅ™«Æf<7‹¬+& jb¡¡¡ŸUýÀtÇÆÒ«˜»þ–‹r1R.JŠÚ1àŒ{{ Îà …P]`ùøL˜<ß?Ò¬šXÕÕ×TûÀ”æçÓh` ÕgdØõ÷¼œ/«ÃËë ×θ׸×à ÞXUÖŠèÑ£O³2X+W~šU««+AÕÍ£Ó§i4(ˆJ$±eÏßóÂм@4/ ?…PÕƒ2A¿‰+é©éâÅ5±ü©¸¸HÕ7xïÆÔo×ßêîêhSï&Zóv YxÝèé‚78ƒ78ƒ7–Sf®Z5*†—-›¢ƒ{M÷î]54œRõƒS–—Gzzpé’}"«XGkûÖÒú7ë…à‚o^ popo,„êu°ŽyL«W˜lçšX}}Ѫx;FCC©¸È¾ìYaI!E DЖž-èõ¡§ Îà Îà …PW` 1RXLþþzÊ̬šmDÏ ÷aatWgÿâÓ¹å¹<Lû D¢î•Îë¾¼‘3|9à ÎàíñËRw9ÚÛÛ)22R,‚¼`ÁÊË˳øœiii+£;Ú®õùÔ^‹0:ú ¥¦>3q×Ä ¤êê«ê$aõ.<œZö;–A˾ŸM‡ÃOSVe-~ø··|ÉœsërÑÓgðgðöÄ –9ÕÑÑA‹-¢ÊÊJšššköí—þ©š ym?^×ÏÒÚö¶k}>5=X2Î{HK—›é-$QW×vM>H•™™4îëKÙÙ=Ofe&èhÝÐ:!6bzc¼æËhó«Í‚ó®á]ðYh)°L­h _|ñ…"+11qÎŒ•a°Xa+?6\(ÚÑv­Ï§E‹ú‘22f÷ *+³H¯÷S½&–Œö={èmd¤ãå)NÑBé§NúY4µÈ+²XÌ‘¹2ç¥oËbe·d£wÞà Þ®#°X8œÀúòË/XóæÍ£¬¬,š?¾XI ™}FäL—ü˜÷)Õ®õùÔö`Éøå—fZ·®ÏLM¬•ÔÐpR“—kø ñräˆCÏÛK¤Žé‡ÅÖ/øI”~8˜ûÆ©4D?øYT½ç¢¬\3,æU mïÞ.–ÚÓ¾‡RŸ¥Š!Õ´Æ4:]šÎמ§«ÕWéFÅ Ê-Ë¥0ÜehÔ›†ƒáËgðv£!BÎ,q†‡íäût:"‹÷ïÚµ‹&&&H¯×Srr2ÅÅÅÙô<†bÏÑv-ÏÇ7X†a„‡‡‹7•¬Üù·£Û½½½3¶Ÿ=ë ?¿ ºyóþ¬ã;;Óixx›¢ç·e»YzN.^Leevý½î‰Ndp^I?ü›3;¼_ >jl×t×ކœù\~|™òšó¨èU]m¿JÇ›ŽÓ©ÎStæí:ðêíèÜA‰}’,ûH›ßm¦ÈHZõq­_IÁú`ò÷ÏËÕwÒ—-¦ecËhµ~5­ù°†Öö¯¥­[i÷‡Ý´ûÍnÚõb~y˜.¼½@tRê™­™Túª” ŸÒÍû7©¢¡‚Ú^´)Ê÷èn!°¶¾Ùê‘÷×ܶ oákîûÌø·¶¶z_y›y;ãùUXß~û­>ÆÁû¾ûî;EgsXX>7g²ÁRσ%cûö.JLìp©šX2:wì 768œ½’#õSªG{±Ø{µw|ï Î| ”òbñrD\ ƒÒõªëtéÁ%:ûð¬PG¥_š¡”ÖÚù|§¨G¶­gm|½Q°ˆÁZ>´œB†C„@ó‘Þ[˜ú-ü´P¸ÀÑ@ ý*j™­XMÑ}Ñ´¹w³Xo’ —ÞØ×²>=HÇšŽQú£t:WwŽ.×\~;θ±˜ô¦á`Ü,ƒÅ¢ÈœÀRʃŦoceI€˜ò4ñ>¥Úµ>ŸV,aϬ$ÿq*,,™ÕÖÛ«MM,%……4L §NÙôw·ÊoYBãvOû¢pWÎ<ô˜'‰øìŠl1$y¡ö‚¢ä¡J²ä¡Ë=m{ÄP&inyµE qòP'yòÐ'—åXþiù´ N•~¢¢½æŸ|9à Þn"°ØņläÌ £¿¿Ÿ–/_Nß|ó"‹‡!yXEƒ‡ Ìþ<+‡--ÍÚ³·]íó¹ŠKFdä[:|ø‰‰75×ÄZ¦íëÜ9[¼˜JïÜoœÍz¯Œ‡ƒy8“³ešP~i¾Çq¦ Ìïqpoö`™3¹Ù=+Ñ8Μ9# ÆÆÆÎ0¹›:žkIYª+åH»Úçs¥ #=½AÐC&kbŽRMÍUM?\=Û¶  ×Î&‡¹¶ÏþeêZ÷njôðCת¯y–À2.°¼]X"ƒåu°˜ ÿdñÃàǪÕϲäÇò„ó¹’KÂuw)(h”.^|`¢ç°S³šXÓ~°;wD«îÜ9ø›‡FsÊs„/,`,€V¾[)üb…Å…Xà Àƒ…¥r°TŽó{))­´iSï¬ýY4>î¯YM,ìÃb?û²Ðëg{x³IÿDã a¢÷—ÞÓlžç2®ðº¹4IYn®(´[{ñ"=:s†;FÏ~ù…Úwï¦ÎøxêÙ²…Þ¬[Gƒ…Æ„(Ö«÷÷“ÑÀ@ ¢áú*J  -_.–¥â•W­¢Õ«éíš5Ô¿v-õEGÓ›õëéõÆÔ»y3½Š‰¡éûéel,uoßN] bJGR½ØµK,ÒεëZSR¨eß>z–šJÍÒë~zð =9|˜9BMÇScZ5œ~|MXòu]²D\}@€¸6,½]`Áƒå+**JÌês´’;Â}2XŒ-[zh÷îöYûŸ>=D}}k5ÿ•Iÿ0ô~~âz}à¬Ä°ÏbäÙŠ+Þ¯ëWî’DE·/Sõ•+b‚E£$8X`´J‚…D·$X0°H`aÀb€3EŸ.`1Àû¸­_:¦wãFꎋËÏñT,üœ,lø,€JóóUåì©÷š¯= :Îü±ÀÄç¼]N`­[·nZL9ZÉá,W¯ÖÐâÅc¤ÓÕÄÊÿ\KûeW¸º;÷tyH`®ºœíiJKÙκp6ˆ³Bœ å, g‹8[ÂÎ"é}þ@ý¡ èÕ*z*²M¯¤Úœ}â¡0ÎFqVª!=] mqVˆ³Vö ]Ãì­ì½®ÈÊCª|Ï&~úIdÅXØr6ÑS¾/Î×ÇgÞÏz«©©åŒÏðÛ }!eggC yp‹±rå;JKk4Qk3µ¶îs‰Ÿ°ç½>pžëŸî@D„ð-±©3!Aø™ž8 ²ìszpñ¢ðûpÆCþ'|§ôލ¿µôãRQê œrUÜk÷æ{ÉHÔÜ!ãáE~°Ð¾ŸížëUÊKA4àûÌ šzÌõ°l­ƒ…p–ŒcÇšhÕªAoð³ôáC¨K|ØØSÂþÇß‚ws®¹zÕ©Ãeœ1àjô\yž×oäêõ¸×îÇ›íœyäáÝq1ŒËYÉG§OSI{^©Öž±=¸×î,°¸8¦\¾ ´´T<®®®†Ë 2XEEÅ §kתÌÔĺâ8ªaƒì]=|/äÌÙ öA¨âG⯹¢ü’Ñ%bÉŸCOQ~I>îµ;ò–¾3ØÇÉÙLþ™üé'1\ܺw¯˜ àªÙ+^VªvªVÕõ¶,–Çd°òóó)))I<ö—”¾¡kþüùPBìÁ’±sçsÚ¶í¥‰^Ä.êîŽsô%ÉÓÌy¸^/tÏÙ þþ³oŠËªêGÒI ^1ª?J¬¡ÈË÷𺌸?îëGâ:{ü¾božî§yM,l0÷ó3±ÐÃ÷\Îì§áÙw<¬ÃÆe.U`.s©&ïìûÙ”ô"‰ô´jpo:.þyâ^«çGrÆ¢Þl=à 9Ïåìwä¸Ì×'“ßw<û” Ø^«ºFê.ˆ2GŸ¥ý-ûi×ó]´½k»X¬|mßZ±f&/d΋œ³PâEÎYœóš+†VÐê·«iÃë ´õåVJìH¤”¶:Ø|N4 Œú ±˜ú©…Ô3Õ#þ7ðRPÞ–ÅB¬9ü\Öì7òÚ~Ÿ+y°dlØðšöïo™µPúGÒØxÂe>x<³«?* ä\ZP JpF araJWäÍ¢ŠÅ‹,[¼05‹/Ükç!¶?V¬˜Þ»Ÿƒ'3ܼ“®T_¡sÏÑÉÆ“bèw_ë>!œc»c%ѳ‘Ž”­ ‚´êŽXH ò=?ÐáÂ?Ъ×þbÄÊ÷+iMÿÚØ»‘âºãÄßòs~zX<繺sâ|.{ÖÅdïÕîÑÝ3þ?x[Ë£ê`¹šÀb±Â V~Ì R+Õ®õù\-ƒÅ¸p¡Ž‚ƒ‡Å2:3Ê$<9Lýýk]*»ÁÅ yVzøžÁ™gô½Ø¹Sd'¹@¥-uÏ´æÍÃ…x¢ ÷p•}.âŒRÖ,…ï37XYYYôí·ßÎ0µ/\¸^¿~­˜Àš7ož¨«å+½IyágKÁEOy£áŒFÞ§T»Öçs5–ŒeË>H÷¦Þ¨&VÁçšX®óÁæ©ö\ìÑS‹ z xú<圾xi®>î®\ØÏÙ6ij1žÿáçº@9wDôsùÁe!vX4-×/§_¤ŽéÇwÒWø”""„o‰ýK ÂÏtàÙáobŸÓÅ…ï)¯,O™¡\N òð!–åáDžxÁËÖÎp¶<¤ÈBï 75¹›ªÜ^[[+23J,ÃèêêÅM>lÓó=u´]Ëóñ –aááá"-*+wþíèvoo¯MÇ_ºÔO7¾ŸÕþJêå½|yDñ×çÈö›ädú˜˜h²]†+½^go·¶¶ºÍë­¾vbcéS@½Þ³G,ñbïó1oWãÇ¥¶¿ÝN~ŸühëÀVaÎVòù=åýý¸ó1Ýl¹)2P»Þì¢M#›(HD?~ú‘VŒ¬ øñbÿ"é‡}H²‰³Xº':Í_ç“'ôüüyQsm|Éš ¡þ;„¾¡ªJ‘óñû›¯Ï–Á-ø>S`[uŦö#GŽˆ¬‹¡À¦¯¿þZq%?7›Á‘Ár–è9”¯ï8egW¥kÏÑÇ¡.Õ)‘:£AA¢® <*îÁ™+l³Ž—8á±÷îÜñhÞ\¬”‡Ø·ÃEL¹˜)û€¼ÍƒÅæpÎãk±íå6á]ó÷§Ÿ&~Kq½±½m{ÅÐ\VEÖŒ!Vö^±ÿÈ0R?¥:äÅrÚ$©ãÀB.ÁÙ-. Á¥!ð·Ng÷½æL(×ec£=¾ÏÜ,ƒe(ªŒë^ÙZK)eÊÓd˜Ms´]ëó¹¢KF||'íØÑi¢&VÕÔ\v©!û Fg­í–k•ZàefÞIŸ‡©—ßüË/ŠzWÜå^Ÿ}x–Ö¿Y/þQníÙJW¨/犜Y±8âÙu<+ŽE‹'Q~z?!ªX\¥¶¤ ±Å¢Ë“ýH\Ì”Wàâ¦<–‹rÑS^ú«<7׿{Í× ôø>s3ÅCYccc³ÕàààœYkVbb"uww‹Ç}}}´yófJII1ûwò¬<~ –fíÙÛ®öùÜŃ% ¥Yäç7N……%3gï=w¡šXx#|<ð¸^©®¤Í¦`^º¤éØ1*Öé¼þº°(HnO M³á…§Ý)3QX\Hת¯ OùÜ@è‡P1¬8H‘o#)¾+^ kq9W^rHm¿!/ÛÃË÷ð2>ü™èرCÐ5^7Ñ«×t2oÕ›ÙC$…=00 ×ÂjiiÂk‰Ôã´µ–©:W\žŸ‹÷ó$û¯ôz½EaƵ¤,Õ•r¤]íó¹S‹ÕO‡=5ª‰•ý¹&–ký3à€<äÄ ñ"ƒå=÷–ÔT‘Y”:õ&†p1£î׌g{Ö¼]C~Òç*¡+A²]…³±ÑœgÜ‹êâü{]ß:±ŸÛyF™²Vv>¤Ž—óÂÔ¼ø8/TÝ¿v­X¸š°¶´RAaq¡g ,'¯Ð ºÀêèè0) —Ðqvð=j†Úçs–ŒÓ§I¯çƒÉšXMM'\îƒÉ…(9 /=Áƒ¥Ðåez??ꋎ3=á=³7*nÐŽÎb(mõÀj:ÑxÂâ¬7Ý+å2y÷òD¦‰3N\®€3Pœ‰âŒÔ²ËD†Š3U\“‹liXtØS?×<šËμڼYt- .åfeXdq&‹…Þ ×Xööø¸Vpð]¸Pk¢&V”K~8ùŸ:÷‘ÁRyè#'‡ºâãE©®­râtuO¯ ÅÙ .1À5šÆhçó”s?ÇdEóìjÛ ›:b4G–Öu„†ÇÃÂ3–#Ø·¯•6n|m²&Vyy®k~)y¡oA³Sׯ AŪ+!A-\åÀ>§Ø—±ä;á+†ãÎÔŸ¢‡ c²ÀJJTÅh¸–À⢩E.²t2X6Î"D ƒ5½¬Ä{b}ÂÜÜò™¦réK»µ5Å+?œÈ`Ý…ûÖ­C<$èŒÅq‘Õ˜é…:Ð|@ ×qS®H^;U+Ö¦;ÔvÈ«ŒæÈ`-‚™Å1–›,Wð#A`¹–Kƶm=”œü|f-£:®‰µËË¥2KÌàë™êok®hÎY,[½Xx»7gæá^WôÈ¡–‰¨¨¨ àà`Õf "ÜÃ%#<|Žo2ª‰•L/_ƺÀX½Z i±_ˆ³0ÝÛ·ÓÓC‡èÁ¥K.“‰q©"‰……ôìÀQ”«Q³@ÅuÑì½Ú=º{Æ[›³X¦¼X€gƒ×a<÷ð®…;,s%Œ×&Dx_‹‘–Ö$‰¬w3gŽÝçšX¾.UËš!²[·¨þÌjMI¡ÞÍ›EfæÓ¢E4,u0Þ¬_OíÉÉÔpêUdg{e—®á¥=x!m^ÒÆ°¶²Ú'u׊æ¸×ÊsæE­ãºãp¯ÝÅän–HFx¾‹ÁËÑÕ«Õ3ö DP“ ­ðnïø=yñâÃ<Ö¹c½]³†ÆDñ?^Þåel,58 ÌÝÆKòxŠ?¥<'Gp÷õ“¯|9à Þ®É9³*S”ñðäaBY‹P‰0WÁÝTð22Ö—––f±2º£íZŸÏ]2X 6ºoÝÚcTë(õ÷¯ñÜlN^=<{–Zöï冖/§ÉE‹Ä°Ï¢{±k5J÷¼òÆ »rÕšsef&õlÙ"†Ny¹¡û^š¹gðv7μxø…Ú ¸×ÞTk.áTPP@aaas'¯íǾ0KkÿÙÛ®õùÜɃ%†(n•‰’ ·oßûͧS’ÿ¹&Ö-ïù“„Òl:~\5åa4žU7ùãô~Å ê‘î)ϰ«;wN ·¹*—/‹!Ñq??!¹’4üà>Øõb—(Åkáâkbb‚æÏŸ¯ˆË’p‘þIûPOOÏœ‹Å +X9ø1 3¥Úµ>Ÿ»e°›6½ÅGgÖÄÚBmm)^ßÓe1Uwþ¼W=Û¶ ±5ùÓOB|±ëÄ‹2.Î鬭á\Ÿ‘A4¶x1µîÛG¥`ðGV¼½‘3¢åšg¸×..°xYCAåˆË’p:xð ]½zÕªL×W_}ESSSÓÛü˜÷)Õ®õùÜɃ%ãâÅZ ËèüVë< »^M,—ðjHBЇOœ ç;wŠ¥|xx‘‡y¸‘‡[$‘ÃÃJdÌr–^¯ÕÈç^º”ž>ìr¥àËgð¶3/º}ÉÅÊåÀƒeÂ䮓¾„9DØÖÖFË¥/xk‡MµŠ=GÛµ<ß`†.ÞT²rçߎn÷öö*ú|zºr¥mFûØXˆ¨‰¥Äó+µ-ÃU^áö£ª*a˜ï:y’†RRècd¤0ÔÒÈæÍôzÏz|ô(=ÍϧÒçÆÒóY2ö×?x@ýÒyÆ$Qõ>,ŒÚ/]¢ÏŸ»Üõpt»µµÕ£ø¸ûûÛ™ÛJŸ¹ûûûлC”ò:Å#ù3og<¿êKÉ™‚æ„‹«îîn«2X®‰Ã‡ŸÒš5ogìkow½šXî. Á%"¸Tû£†CBD .%Á3û¸´—˜(Ï͵ª4Ï„ä‘ìÃõÏWï µpõJîJ5'œÌÕÙ²ÅÅû”j×ú|îèÁb–Ÿß8ݸQiP릨‰URâ:5±<Å«ÁEP¹*Eåâ¨\$•K)Œûû‹â©–Võ•+ðå€3x{8ç Ñ ºR}÷ÚUVuu5ùK_؃ƒƒNŸEhî8ãmyV¿&K³öìmWû|žàÁ’±cG'ÅÇw™¨‰u^ •ÀËþpuuo_¾ðövÎ ”ô" ÷Ú•–¥êíöÌ"´%;eÀâàZR–êJ9Ò®öù<%ƒÅÈή _ßqÊÏ/™Þ÷øñzûv zºZWõr…¬x{3狵i© N4òê –¥êíZTrÿýï¯j½.µÏç),k×öÑÁƒÍ5± hb—ÊËs¼ò‹ -ÀÕÜ-¦ëU×q=<½Ð(µ–³zõ´lÙÇûzz¸&ÖôtÕXv,„ž.8ƒ·çpÞÞ½’Ÿ'ã^C`!Ü݃%#$d˜Î«›Þ®­åšX!ðj€3xƒ3x«Èù|Ýy ýŠ{íªu°ìiCxo‹‘šÚBë׿™±od$XZÑÓgðgðV‰3è(«2 ÷Ú]ÖÐд÷ÚU–¿þúkJHH þþ~‹Ï™––f±2º£íZŸÏS2X:]1ŽÑåË55±¶R{ûôtÁ¼Á¼Uâ\T\D¾Rç6Ç >{Ì,¾¾>:qâ}ÿý÷Ó"‰€fÁ0—2%´LETT”Xóprr’¦¦¦¤Æ—…À3òÚ~¼®Ÿ¥µÿìm×ú|žâÁ’±gO;Åļ2¨‰u‘†‡ƒáÕgðgðV‘óæÞ͔ڒŠ{í*Ë08{ÕÐÐ æ¬ &Î8………9$°L…¥åjX¬°‚•ƒ¾GÛµ>Ÿ'e°yyeäã3!ý¾7½–V5±ÐÓopooä|ªá…†ã^»¢À2ög%%%ÑüùóXœÁâÙ‰ÑÑÑfá¡K>Îðo KF8Ú®õù<Ƀ5ÝsÚÜK))m5±öPOÏ6Œû¨„Â’Bò™ð¡[e·p=\]`ÙãŲƫõÝwßQww·MÏc8ÛÑÑv-ÏÇ7X†a„‡‡‹´¨¬Üù·£Û,•|>KÛ¹¹ÏhéÒ ª«ûu»©©”>}ò§úúUÎo¸-C­ó¹Âvkk«Wñ•·™·7ñõÖ÷·ÚßgîüþÞøz#è:ï3Ûª,kŠŒÊõ±”XrvçÂ… ´|ùrd°<ă%cÅŠ÷têTÃôöÛ·«EÙx5À¼Á¼ÕáœÖ˜F¸×Ze°Œ‹ŠšX¶ÖȲŃeé¹MyšxŸRíZŸÏÓN§ˆÀJII¡žžñxxxX”10 Æ'ÏÊã×diÖž½íjŸÏùúŽSAAétM¬‘ukbÁ«Þà ÞÞÌ9¿4Ÿ~šü‰îÜ»ƒ{­¥Àš7ož¨ÙÄÂlÎfpQ6¡s¶ á¾K«_tt8ðÌ &Vˆ$´Î£§ Îà Îà­çµ}kéè“£¸×Z{°Ì™Ü‹ŠŠ „ÜX`i…³gÒÒ¥§·ÛÚ¸&ÖxT‘'G„ȵи«E^‡‡Îü¸±±*,»Á‹…?./Ï @—” § Îà Îà­gäaB.Ľö€B£x°düòË3Z·îAM¬5ôø±:éjx5ÀœÁœï £;Þq¯!° °<¨Ç—Ÿ_J¾¾ÂôÎÛMMÇi@¥âwèé‚78ƒ78ߥֿY{­•ÀâÙ‚¼Ö •Üð`".®[”m@M,õ‘W–'ŠŽ¨dÏ€Ë(.\8CPÂÖJîd° ÁG¹ðhaañçšXÛ¨½==]popo•8ó²9'Oà^k!°XHÙZ±–µˆŒKèðã.©R ^ ðgðçÏ~Øæ_Äи×,%²Tæ*¸ËQ[[Kb†â×_=«’»©HKK³XÝÑv­Ïç ,/þÌ‹@ÿVk)ÕÕ]@OœÁœÁ[ιå¹ä3áC…%…È`©-°¸$¯Ÿ§D˜XÑÑÑTSS#Š˜êõz:pà€\æB^Û_—¥µÿìm×ú|ÞâÁbètwiÉ’QºtéÁçšX)¨‰ "ÂÃéTÃ)x°ÔXÕÕÕäïï?gFÉe,´,eÎX¬°‚5¬ÓÅÕæ•j×ú|Þ”Áb¤¤´ÑæÍ½5±|¨¤$=]popo8ïoÙO›{7#ƒ¥ÅZ„æ`ë,BkVee¥Å ÖW_}%D˜¡ ã}Jµk}>oò`‰™,y÷ÈÇgBú]6]뉗p€W¼Á¼Áù7äÜÏ!ßq_**.‚Km“»9ØêϲF`µ··S@@õööÚô<†¯ÅÑv-ÏÇ7X†a„‡‡‹7•¬Üù·£Û|•|>G¶·oK'OŠí¦¦4úða­ÓÎ'CK¾jo·¶¶z_y›y{_o}»Ú÷™;¾¿×Œ­¡km×¼úûÌ­ Î%°êëëÉÇLJÚÚÚ,‡ –çáòå #®Ø &V6ü*`oë^ÚâåþWX¥¥¥ôÃ?PKKËœÏcÊÓÄû”j×ú|ÞæÁ’±rå{:y²ñsM¬XzþÜ95±àÕopopž‰ìŠlò÷#]±,5VCCƒ?<¬ÅàǼO)•™™)f+vttXõwò¬<6Þ[šµgo»Úçóv–ŒcÇSDÄ€AM¬%ðj€3xƒ3x«ÄyùÐr:ûð,~̳ü8ë¤FpR5CíóÁƒõvî|A±±/?SèÕ«ø#T@VeèHwWç•ü5©äÎ >Çää¤K,•ãY=¾œœròõ ;wJ©¼<×)5±ÐÓopop6Сt¾î<2Xj ,®®n,º °Ü[`¹ªgaýú7”šÚ"÷÷GÑ“'GàÕgðgðVsòódÚÞµ,5ÖÂ… EÕñþþ~Q^€ÁCCCÅð!,¥qî\…„ ‹ÇMM'hppzºà Þà Þ*p¾^u-véaBÉ`±‘Ýœ ½¹¹J,§`Ù²”‘QOÅÅ¿Ö΍@M,52B\„K2 ,¤8[ÅC‚ ~ q… –3qð`3­]Û'wwÇÑóç»ÐÓgðgðVsÒ‹$JèL@Ë "àÁ²ùù%äë;NÙÙTSs™FGƒ¤ý:ç  xƒ3xkÍùjÍU ß¹ð`A`A`yd/>¾‹vìèü\+T±šXèé‚78ƒ78[FÐH]–:·È`9Q`•””PBB¬ýIIITVV%–ÓpãF%ùùSaa µ¶î¥W¯6àvtî ÄŽDx°œ)°¾ýö[šµŸ÷ÍŸ?ߪç0WÁÝÚvS‘––f±2º£íZŸ¬_±fÍ[:|ø©$æo‰šX¥¥èé‚3xƒ3x;™ó¥—(x8,g ,K¢ç‹/¾P칬i—C^Û×õ³´öŸ½íZŸ¬ßžþHâ>dPë0¼à Þà Þ*p ¤kÕ×àÁr–À⌋á29rp-¬¯¿þZÅb…¬ü˜ku)Õ®õùÁú :Ý] ¡‹k©±Q™šXèé‚78ƒ78[áƒíЧÏw"ƒå,ÅÿØ9SÕÕÕ5]h´££Cˆ¡¹D‚³ÖW_}%^‡ü˜÷)Õ®õùàÁš‰}ûZiÓ¦×T\\Dãã~TQq 'ã|íyZúq)Ÿ³¶oß¾G¾¾“ÔØØE}};¥ý»z>®Ê×Û­­­^ÅWÞfÞÞÄ×[ßßîô}æNïﺇu0@EOмâûL“2 <ÈKæÈ…F-ZDƒƒƒŠú¹Á‚ËrÏ¢‡’“Û?×ÄZâPM,x5ÀœÁœ­C\wínß –«×Ár¦‹÷)Õ®õùàÁš+Wªiñâ1***¦—I¯ý,¼à ÞàŒ{íäsœ{xŽ~þð³WðöJe¼_ž•ÇY4K³öìmWû|ð`Y‡ððwtâDµ¶î£Þ^ÔÄpúD£»:òÓûÑ /ð¾j"°²²²D=,ò x°¬ŒÑµkÕÔ×·–ž>=¯8ƒ78ã^;õ´âý x°”Xßÿ=9rD³ Ï ´µµ–;öøvíz.]›—ÔØx’Þ½ GOœÁœq¯Ý¹-."ßq_ºyÿ&2XJ ,CQe\¹ÝÖJî×Xîˆ[·ÊÉÇg‚òóKh|ÜŸ**²p]œŒ˜W1´¯eØ^ =]ðgðgÛ±±w#¥>KEKÉ2 ,² +¹ÛR¢–3pèÐSŠŠê§–®‰µ ×ÀÉ8Ùx’"#àÁrÅB£d°”BAA ùùSnnñçšXwÐÓgðƽgg–ü:L˜W–‡ –'{:)>¾“úúÖÙT ^ ðgðg;'½Ù@›ƒ¥„ÀâÊyHƒ îß}÷ð_ýðÃV?‡¹ 톑––fS¥ó¹Žw´]ëó!ƒ57²³+È×wœêêNÛT =]ðgðgûÖ”F«ß®FK Jíííâqllì ±aÓs™XòZ}lš·f­¾¹Žw´]ëóÁƒe=؇uèÐÒëý¨²ò® €3í¥ôÓÄOtûÞmx°X\ëJ¯×‹ÇóçÏ"éÉ“'ÔÖÖfs%ws‹Å+R9øqXX˜Ùç™ëxGÛµ>2XÖãôézZ¶ìÃçšXIèé‚3î5î58;Ñ}ÑtøÉad°X†¢ˆk_ñöÄÄĬ£Ž,q¼üØRÓ¹Žw´]ëóÁƒe=tº»¢&Vf¦ŽÆÆ¬«‰¯xƒ3xƒ³ý8úø(EõGÁƒå¨ÀbÏg¬ººº„@š7ožØÏY-nSB`™ÚÏbΖç1<ÞÑv-ÏÇ7X†a„‡‡‹7•¬Üù·£Ûì¯Sòù´ÚÞ¿¿Eº^ƒÒ{rµ¶^ŸóxîÊמíÖÖV¯â+o3ooâë­ïoOú>s‡÷wUCù|ò¡ÊG•õ}¦ºÀẩ¡ï*22RìçÃÞ‘Árß –§àÎR±>amíqéKv#® €³ý¯ýQ"“–ƒñý÷ß‹áÀ Lï[´h‘è18˃ÅûlñDïh»ÖçƒËvlÛö’vïn±ª&¼à Îà ÎŽ=XìÅ‚ËEb®Y„¼€´©YvÆ7×ñ޶«}>x°ǵkÕ ¬æ9j´À«Þà Þàìx!Ï&Ì/ɇËÖøöÛo)..Îæ,Õ\u°ÌÕÃâÚPæêDÙz¼£íjŸ,e°jÕ ]¸p—Þ½ COœq¯Áœ ®‡Åu±Á²£þû„Xl°!; €jkkillLõ̯èÉçƒK¡xi´rå;Òëý©²2×À‰àŠî\Ù,;£¯¯Nœ8!|Xrö‰½X\™¼¿¿kÚ¸±Àò´ŸNWL‹Iâê8ut$¡§‹¬î5xƒ³‘[–+Ö&ä5 ‘Ár08{ÕÐÐ@þþþÓ5±¸Øè\E3®)°<ѳ°{w;mßþ\z¯.6[ ^ ðgðg…¬ƒ«èdãIx°”ög%%%‰ ïd°\¹¹e¢dCo絛?ƒž.²à ÞàìD¤>K¥M½›ÁB@`y6mê¥'îÑëר‰àLä”çü:LX\èö\TX¼,޼¡1l]* –¸xñÐø¸¯ÉšXèé‚78ƒ78+‡•ïVRú£td°l… ÎT†°´¼ ,-±|ù2Y ^ ðgðgå°¯eżŠËÖ`!¥Óé xÁr+>ü„Ö¯ï¦÷ïW¢§‹¬8ƒ78;7ïß$ßq_**.BË–@– ,wDaa ùû멳s-jb8+Þ¯ Œú x°l ®yÅË»83†††DÕx.ðùÍ7ßPzzúœÃu¸,UFw´]ëó!ƒå8;(5µ’::ÑÓEVœÁœˆ”¶Úúr+2X¶Duuµ¨{Åëè9+h×®]ÂP¯×ë)99™nݺeöxym?~–Öþ³·]ëóÁƒ¥ ²³ï“ŸŸ^ºæ¡3jbÁ«Þà Þà¬,²*²ÈOïG:3õáÁ2¦f*=‹3W,¬äàÇfg±Â V~lXìÔÑv­Ï‡ –rX·®nÜ8Oõõ§ÑÓEVœÁœˆŸ?üLçžCË“»9(åÏ2XœÉâuÍ·MMMMoócÃãm×ú|ð`)‡ŒŒ‡´bE?½~½×À‰ØÝ¾›âºãàÁr¥ˆÂ,²ä!BKâ³g–ÌøŽ¶ky>¾Á2 #<<\¤EeåοÝæJüJ>Ÿ«n/]ú‘â©³ó©Ø–á©|Mm·¶¶z_y›y{_o}{Ó÷™+¿¿ ŸRÀXÕ=¬sËï3Xlr™,.jš™™IóæÍC ,EšúŒvìxDÍÍ¿À«Þà ÞàìD,ý¸”.Ô^€ËÚàžøá‘uaðcÞç¬ÈËËÆw[ –»ˆ¬+>ˆaÁaÚ±£EÚ~MwîèÐÓopopVçëÎSè‡Pd° ƒ…“¼1?6K $#àÁrßÂÉ“:ZµªGY÷àÕopopVx˜0@@Y•Yð`i¼ ztt´X™Á{zz,þMZZšÅÊ莶k}>d°Ôéõ•”J÷£€Ö¬yE%èé‚78ƒ78+ˆØ—±´§m2XZÅ’%K(##CT‡gœ9s†‚ƒƒÍ/¯íÇëúYZûÏÞv­Ï–º¨ªºJû÷ߣµk_SQQ1® €BÈx˜Aˇ–Ãen¸Ðž6GÏa©J<‹V°rðc.†ªT»ÖçCKý^ß³g©ß@›6õ’N‡ž.xƒ3xƒ³"ÄÅ:ò÷£ìŠld°¬QCCCŠ ¬˜˜‘µ’+ŧ§§‹}悇ù89ø1ïSª]ëóÁƒ¥…oAGoÞ¬£uë:).®^ ðgðg…°¥g ímÝ –áL¹0—H°6úúúÄ’<òóò㋯Í8 ÷޶ky>¾Á2 #<<\¼©dåοÝfï›’Ïç.Û2ŒÛ»ºI‡Ÿ),l€öïåQü[[[½æþn3o¼¿½ƒ¿7~Ÿ¹ËûûZÛ5Š‹rùï3Õ––a”””PBB¬ýIIITVV¦ˆÀêîîC‚òbÒü˜÷Yò0q-)Ku¥iWû|È`¹^¯ïÁƒK4>îOׯß#?¿qºp¡=]ðgðg;QXRH>>t«ì2Xr|ûí·bÆ ©Y„óçÏW%Ãe©dƒ'œ,×D{ûn\EÉßœ®\Áº…öbãëôKó/ð`YÊæ(] –köútôî]8µµí¡´´& £7*ÑÓopop¶ii1 –<¤eªdB?}ýõ×PBn,°àÕ˜÷ïg‹¡ÂššËtð`3RNN9¼à Îà Î6¢ ¤€~šø‰òîåÁƒ%ÿcçLUWW×´ ½££Cd¶æªFŽ@Ëz}£áá*‘¾öìi§¥K?ÒíÛ÷ÐÓopop¶Ño¢éÐÓCÈ`É^+s…F‡‡‡¡„àÁò ôön¢—/·‰ÇññRçâ=åç—àÚØ€cMÇhÍÛ5ð`ruuy–ߢE‹DÉ2XÞÒë+-½C££K¨¡á”ØŽ‰yE«W¿u›Å¡q¯Á¼ÁÙ_šO?MþDwîÝA | ¿¢®îéõT^žK:]1­[×G6¼q‹Å¡q¯Á¼ÁÙU°¶o-}r,2Xèõ~°“èíçôvaa ­Z5HÛ¶½DO¼Á¼ÁÙJyrDˆ,d°¤ˆŠŠkç{°P¦,oCqq½¿‚ZZö‹í;wJiùò!JJzë`xx‡ y¸Ð«=XëÖ­›SÆK©u MèçÍ›gñoÒÒÒ,VFw´]ëó!ƒåº½¾ÊÊ4>îGÕÕ×Äv^^…„ Ó¾}­èé‚78ƒ78[6º³áÝëë`ÕÔÔˆÇrÆŠgnذ²³³’½á%x,‰ym?^×ÏÒÚö¶k}>x°\ß·ðôé!úøq•”Ší›7ïS`à(>ü^ ðgðç9À¥Ö¿YïÝ,ÃJÖ7ß|ãb²¸©,VXÁÊÁ kr9Ú®õùÁr^ß›7ÑÔÕ?½™YEz:uª=]ðgðg È+ËEG¹ø¨×f°XTqÖ…ƒK4”––ŠÇÕÕÕNñ`UVVRJJŠÅcØÆÏPìñ>¥Úµ>wÙ–¡Äóµ¶f ‘ÕØxºýìÙ‡0Aee=.ÿµµÕkîïÌûÓŠ÷·—ð÷Æï3wŸè:!€v•ï3MË4LNNÒ÷ß/2Wß}÷MLL(*®˜dLLÌœÇ!ƒ…ñ{WâÝÙO}}ëfì;y²Q ffVz$gxTÀ¼ÁÙQä–ç’Ï„~ö²¢–ƒ}IOž<™ó8Sž&Þ§T»Öçƒ˽| ÅÅ…ôáÃ2jn>8ÓÄyè©0¾çä܇W¼Á¼ÁÙÂÃéÔç2¼²–ÑÐÐ`Öøm<Ä&ÏÊãåz,ÍÚ³·]íóÁƒåþ¨ªº.J7TVfÎØ¿wo-]:Lyy÷pŒ°¿e?mîÝì,׿uå!BdòÃ?(*°Xt°qÞZ—q°TWÊ‘vµÏ‡ –gôúž=K¥¡¡å¢©áþ;:hÅŠ!ÊÏ/EO¼Á¼ÁÙ9÷sÈwÜ—ŠŒ¾7½"ƒJíííâqllì “{DD„*Ù-ž½¨f¨}>x°<Ç·Ðß¿†::gíß²¥Gú¼ Paa±Çq†GœÁœAØû0:óèŒ÷y°ØŒ­×ëÅcž5ÈŠ}Rmmmôõ×_cM7Xèé*²²[bA躺s3öó‚ÐÑÑo´X÷œÁœ]{[÷Ò–ž-ÞY˰´o˳±¡{ ,À9xô(FGéÞ½;3ösöгXœÍÂuøÙÙä7îGºbwy°Ø3Ä«®®®krV‹ÛÈ`¡×7/_ÆÒë×gígû±Ø—…ž.xƒ3xƒó¯X>´œÎ><ë],þÇn車ŒŒûy ”—´AÀƒßÂl””ÐððRzüøÈ¬6žQÈ3 y†!¼à Îà ÎwiOÛŠ•:¦^WK..º`Á‚é}‹-3 È`¡×g55WE醊ŠìÙ3gr~]ške¡§ Þà ÞÞÎ9«2‹ô¤»«óž ,À~´¶¦Ð»w+©Ø„·€«¼sµw®úŽk€·#ôC(¯;ï=,2Xèõ9 DÐóçÉ&Û/_®‹Cóú…èé‚78ƒ·7sN–¾'·wm÷ž Ï”Ë3³áÁ‚oan”—ç^ïG\4Ù~î\Y—/?€WC!œ:Õ@+V| Ÿ)Zºô#¥¥5áý Þàìâ¸^u-žs˜Ðc1±ŸÖ¯¥ššzEÎßÚÚê‘÷³¼¼QdýV¬¡àà Ú»·—Žo—DM‹,W¡¡S’Àš¤uë†„Ï ïoÏÛöÆï3þ\{"¿=¯÷Сw‡Tÿ>Ód-BsPj¡á‚ÒòÌEÎd!ƒ–'‚kbqm,®‘eî^zÆ7’ è“㺀×td°¼·×÷úõFêî¶¼ÀéíÛ÷D±Ì={Ú¼â^³¨(}Þ>Ð… uxƒ78kˆ¸î8ÚݾÛs3X<¤USS3mxçàá» 6Pvv6” ,x5\‰Ô߿ƪZOœeÉȨw[Î<{ïàÁ§’y'¸lßÞ-½v¥{}ìX-^%J7I—åôìYêœÇrf…K ð¬:wáÌCn§O×K‚嵌Žî£“'ÄLIW½×H>,£ââÂ9=zô±ÆÊήp)μŽ" )T,¬X`]¿^åö÷:=½‚‚FhíÚ>ºq£ïoðgQŸA+Þ¯ðü:X“““ôý÷ß‹ÌÕwß}' ‚"àÁ‚oAYôõ­£N+W“OMmõ¡nÝ*Ó”3Ÿ<Ù(*Ïó ò Ö³ñ”æÍUäwïnÆ;w¾ ‚‚¼¿ÁœùÝR\D¾ã¾tóþMÔÁB ƒ…^Ÿc(+Ë£±±ÅÒḛ̈êø;Ÿ‹Yo––~qg6§Ëå Ø´ÎæuWZ‚ÆY¼¹ê† ¯)0pT,Ûƒ÷7xƒ³óó*†öµìó¼ |Vð`ꣾþŒY÷îåY7Y9\^@ºQ\FaïÞ6Qü”ks±Àãr ÞxŸÎ{HË–}¤ˆˆ—÷À»"ýQ:­|·Òó>t«ü–ge°,X@ÃÃÃNX¶„¼¶Ïn´´öŸ½íZŸ,ø¼FáÇËèéÓCVû XmÞÜ;KøØËùüùZ齨#–¬‰ŒÆzWô¹Â½fsÿ–-= §Ã‡Ÿj&>ñ¹gOÄÆÞ”ú¹ŒÇx°***(88xºTƒ+,+¬`åàÇaaaеk}>d°Ðë“Q]}M”n¨¬¼aeí¦éýöNdRìå̳““Ÿ ó¥Úµ>wÙ–áN¯hh=½{wÄêãËÊiÙ² JLìõ¨||¦(,lœÎŸ>}üóç/(3³U )úúNJﹺpá¹(Eà)÷»µµUÓóWU5ˆl¢¿ÿ=û–êêêñþvÒ¶7~ŸiýþV{{Ëà:Ø|PðvÆó{E™ö|±,x°à[øåå¹bA躺 Vÿ —LX¸pJz<*ÞCÍÍS´té$¥¦¶RRRމòûöµPnnîµÁ3 y¦!/hÍ3ñþop¶iMi´úíjÒ½Ò¡–³–)OïSª]ëóÁƒß‚)44œ¢ÑÑ%TZzǪã9suïÞÌ *Ïž-YB”ÐEW¯Vã^« ®™Åµ³¸†ÖÍ›÷ñþop¶¥ôãä´@úɪÌòì:XJy°©»»[<îëë£Í›7SJJŠÙ!6yVÞàà ÅY{ö¶«}>x°kñòåVêíÝdÕ±\NÁTüø#áZjùO¢ DTg¯W…ç!Y\°K¤N& ¬˜ÞÏXCCCŠ ,^@z‰Ô­faÃKñ°ÿJ¯×[ô0q-)Ku¥iWû|È`¡×g}醡ÇÍy슨¡ajVkåÊO¸×.^Ï×5äõ yC¼¿Áœ-ƒ³V §Rô³hj‘âY,Õ–¥Ùƒ2æò)j;Õò|ð`Á·` jj.Óø¸?Ý¿Ÿmñ¸S§„窱ñ7q%½èÊ•nÜk¯Ù×à ÎfÀY«}“ûÄ÷ÙþÉýŠg±TXòLA¹ƒ18sõêU¬iãÆ =]÷E[Ûz÷.\z¬›SdEDŒ‰aAÎ\y“¸r§{ÍEbSRÚİabb”âs Þàl”½â¬Õ+釃+ÅR}ˆÐ¥®!°w†ŽWQ{ûn\ BNN9mÜØK‹‰¥‰pMà·ìg­ Cé,–WÌ"D ƒ…^ßܸÿ¦*|ðàñ¾p¡N”Ðà¼mí‰{ Ξ^ƒp…yB,g£¶ö"éõþT^žƒ{íá¼yLc´yó+ÊÍ-ǽF ¼!°ð`Á·àL<¾“"M–nÀ½ö,äç—RBB§(ë°o_«(ó —äðõ%Zµê]¿þ ÷œÁë·àedLUR7Ž´´4‹•Ñm×ú|È`¡×g+Š‹uôþýJjm݇{í%¼33«hõê·¢¬Cpð'¯.*‹ xC`Yˆ‚‚ ›S`ý{ßâTű­þ4ËÂâ”–u,SøC/AA""1p1>®ŒFO4záøF£1(Ñ‹Çh4è¡” "ˆ Ä@„ñ‚À^¿ù‡ ›½gÏ~?æû¨UÌkwÏšîYóõêÕÝúÚ~X×Ïlí?_χ;?Æ`Q|•;wþ%ïÞ­”úús|6’ŒŒ·ÒÒ2Û†ØmY$ …Ë FGG%))Iz{{=,0XØ1 ÔùpçG[}þÈLJäÍ›5róæu–µMôæÂÞô`Qo,·(--YzÇÁˆǟ‹ØbÛ¸.¢¿çÃc°·à¯¼xQ$==gYÛDoŒ,¼{wdŽ++k‚eM©· VGG‡f²fö=,WçKúø{>œù¡€u1"77WU*¹ã¿¿û}}}M/Zöu‰e}[ZîÈÄDºönWû-¶)_ã~{{»-ô­¨è”ŒŒ‰’r•žî´´ ùî»&[”·í™]ê·ó>ôFú1I°@®zzz,,z°(+nôoel,UZ[i5(A#]Çù\bX0Šž¬ÄÄ)Y³fTÊʨc˜ tïÞ§'(¥Pƒƒ „Ê•x…c:îüƒÅ¸…@v:‰21ñ•LM­´Éb\ÎôÒyyÃj]Ã~¸Í²¦ÎÔÛÎó`9“+ç}}TÞðð°é¨=_χ:?Æ`1n!ÒÜ|J#VI±úñ}-ºo;’Ÿœi÷ê‹/:eåÊqùúëV–5u¦Þ$Xî» 1—”Ù¼Rþœu~ô`±Õhùù竪[p|üjÖ·ê8γ¬í§3–ØY½ú­lßþ»\¿~“eM©·Ý–3,XÓù1‹,t葬\ùNJJ³¬©3õ&Á"Ábÿ=õö…d¡[°½ý̬ãuu¤»ûïÑJ–OÔu®Ö1dYǮΕ•ušmy-råÊÏ,kêÌ,,,¶~¨·7‚y±Ü»y³J~ýµT^¿Î”‘‘tyòä€ÔÔüIJ¶‰ÎׯßâânIK“Ó§aYSgz°H°H°(”@Ë/¿|'ýýEjôáï¿o“úúó|.6‘o¾¹/©©ãòùç]R]}ƒÏ„Â,,,¶~¨w u¾uë²<}ºGMT:<œ+|%7nü›eã:ÿøã-ÉÏ’œœ?äâÅÛ,kêL  ûï©w0t©zð L‘,-./–uìêŒ9³öïï””wj6x–5uf   [?Ô;ˆ:£»݆è>D7"ºYÖ±«óÙ³²zõ¨lÝÚ+UU7YÖÔ™,,, %˜‚xÂ# ñG <ŸMìIUU|úiŸddŒÈ÷ßsÎ, c°¢Ž`555©åc0ÁçÂ… eçÎ288hú›²²2Ó™Ñý=îüèÁb«/òu®VS;`ŠLõ€)êê*YÖ1¨ó‘#ÕœY>á{MéÁŠ&‚µqãF©¯¯—ÉÉIq8RQQ!™™™n¯××öú~fkÿùz>Üù1‹q Ѧ3&+Ť¥˜¼“˜N¯wXͲŽ!ÿõ¯:ÉÊz¥ÙëA¹r¥–ï5uf V´v‘™-W²«ÛÙÙÙ;îüèÁb«/ZuÆò;X†çåËuòömštt|!µµWXÖ1¢ó¿ÿ}C>ûì7ùðÃ1ùöÛ{|¯©3=XÑx°Î;'………n¯‰W׃c:îüƒE‰il¬çÏ7« xüol<Ëç#ròd³¤¦ŽÉ®]Ïéâ3 ­?Þ¢¼‰+VLJfæHTöd V˜0oÞ<%K–,‘žžÓ뜰óá̬‹¹¹¹Ê-ª3wü÷w¿¯¯/ éE˾.vÑûíííaˬÞÞjDkŒŒ¬W®ææ†ä½Y¿ƒ“߃ÝZCø¥¬[÷R;ÖvýíbÏ@®V¯×,cª±þø±h$kJ~øaöÌÏ}[x°ÊËË5vžEc°·S:W‡|¡i–upsf}ùe»š3ëèÑ6Öñ"[¶<—k×jXǃ(II³ì:V¬Öq¬¹Ø·oŸôööªí‘‘5‘€8w±é£ò†‡‡MGíùz>Ôù1‹bW‰å…¦í& V X Z \|&•ÊÊ»òÙgÏ$1Ñ!Ž9¬Ü\‘½{ŸÊ?Üæó"Áú555²jÕ*El/^,»wïVdÄ,† $Ìl^)·:?z°ØÒ¥ÎÁYhšez9zôê2D×!ºYÇ}—Ÿ~ª‘ÒÒ_%;û¥Zˆ{çÎßäàÁÇ’‘1!­­’+íó çÏÿ!Û·ÿ.ÉÉïäãÿ#ÇŽ=ˆÙô`…hʆXÈ1XŒÕ ÎJ šfY‡G.^¼£‚ßñ¡ÿñÇZÖq/ãÚNj–O?íWÝ/äĉíøY£óòÆT·`NΔTVöiïÈôùë×oÊáÃm²~ý°"ºÅÅÝùºË:N‚EЃŖ.už–@,4ͲŸÀ{‚i0¦u`÷<‘ëîÝ]’–6¦Ùû×ràÀºzÒy:Íé2á…7 Ë±Ž“`‘`1‹BQ MS¦’bbRLPÊ9³f ÈÎ?ÿùHrsÿPÞ¦¿ÿ½;(k>Âû/XAÁ€òŠ!Vî»ïšX$X$Xô`Qoê<-Þ.4ÝÒr‡eO –ØÁðªØ¹Ž£ ðôé{²ysŸ";Ÿ|2 _ÝêùôEçË—keÿþµ€7Û8Æ:N‚E‚ŘêMÅÊBÓ­­ßioNÂûuYÖ‘ X,‹Fcñh»ÕqÄ¥íÙóTV¯~+}ôF ð7>Í_áÅ‚7k:Ök`N¬c°H°H°èÉ¡Þ6ÖÙÕBÓ­­§ÅáHÑÞœã25µÒV$+ÒË]`ðœ|úi_@ã"Qïª*œ?”¼¼a5ºoÇŽž€Na(Q¥¥Tœ–¾R°<ô`ŒÁ¢P¢nN­é…¦GF°úJMÞ¿=÷mG²"?öè¦fãzeõêQ9{¶1æô+/ÿE¶nö }üñ š2áúõèˆ?ÈCŒÖ®Ù¬‘œbéèøB=ú§Ê»©éŒÜ¹s!èËAïh ìG`õçŸw©ÙÊ¿ùæ~Ä×ñ3gš™JNž þ£HÈV¬¿×Ó“ Þ“¢¢éIPñ“¢†rÆ~z°¼Daa¡444¨,ÇÇÇ¥¤¤D.wÐ×öú~fkÿùz>Üù1‹B‰²QSS¥‘§Icã-¯©:¤‘«}ÉÚ)ÏŸo–ÁÁ5òµN#a«42¶B‘23´¡¡|éïÿT‘789º_~)W$dÏê"ØÐÞ··oEmÌÙéÓ¿¨‰6i1K—.Ý’/¾˜žÞÝ€è¼tɾëþÁƒOÜùуEouŒDâܘ2³™WVÖ…µŽƒä••MÇ!Ác³ukoDMÐ)õ±Y¡\‘,?PWWgêÁŠW$ÌHÈp,PçÃc°D©·.¼G>ñá¥B`>ô¨€}îÃSçp|ædE¾UÇáM‘CåÕQ£wIÉc5gÖ¡CB^ÖaèQ„!/oHÍÛ…‘‘è¡}úôûˆ¹§P­ƒÈ,ÑÙÙ)©©©Ò××çöšyóæÍ9fôxù{>œù¡€u1"77WU*¹ã¿¿ûxÆL/Zöu±‹¾Øooo·•¾ú>ô¶ƒ¾•ïçýúsj ‘TyõêˆF¶kÿ?‘‰‰ íšåjü—/‹49(ÝÝÇÞ“¶›ZzO#N¿ªªG²fÍÍ˯¿þT{ÖÚÚ­‘ƒß%3óddŒËW_ k„´-ÂËû¸*ççψ¸úÙØØ#û÷÷©yµÖ¯‘3gåîÝûmÏbš`577KRR’Vy:L¯£‹B¡P\öëÝ®®s.»'ïÞ=¯â¼::öKoï6^¯ÓžšZ.oÞ¬‘ùí·ÏT<ؽ{§•÷,Ü^t?at—z*,SóÉ'ƒª póæçj›Pm{[θ¡’ÕÉt$y²œ0DË:ˆ1K°jjjdÙ²eòäÉ׺Ši±@w~ŒÁb<u¦Þþt¹"WžcêT7äƒÇԔϟo‘?þÈ‘ññ•j¤$Ö~|ñâ¿U¬ùˆ_[{9dº­\9®‚Ë] oʳÉcaetca¡etCrVyÿ»…¯«i@0úd±vèÆ€”ïÔ”ëî`”×À@¡*»îîéÚ«ýö ´µ–û÷O¨‘±wïþŸ"Í Û¡Ö+Pë +ö,& Vee¥$$$h/î3K]tú¨~D‘«ÖÖ>h½uë²òj55•+/W[ÛåõêìÜ«¼`ÏŸoU^1è©EpÿÓ£[—½Ÿ$MGW³/Þ3oÖA¹ÒcÏð?Ð$Ë–3¹cÒXÎ1X %dVt-¢‹ñõëÔ|`èzD—>È ðè€` «ÒªdݺwòÑG¢}x§íäãÇ¢í;äË/Û¥¸ø7EÂrr^jð_å§Ÿj|"ˆY¡Á:—˜<s–aªŒ?þÈ•ÑÑÕªûú`Z Ã9\ƒÑ›ðæá·HcÚëøî`_É•ÿ2=)/>^ÇÌ>¶q,PçÃc°( …Ba VÈ –«ëâââv>œù¡€u1"77W¹EuæŽÿþî÷õõ4½hÙ×Å.úb¿½½ÝVúêûЛõÛúÛÑžÙ±~Óž‘`уÅþ{êM©7u¦Þ,kz°Bƒ…c:îüƒÅ¸êL½©3õ¦ÎŒÁ :Ár>®Ê6µçëùPçÇ, …B¡PƒÔy°\͇åŠxa.)³y¥ü9êüèÁb«:SoêL½©3=X!Ç‚ b:?Æ`1n:SoêL½©3c°ˆ!XlýPgêM©7u¦Þ$X$Xì#§P( …‹ ‹­>êL½©3õ¦Îô`¶"Xì¿§ÎÔ›:SoêL½I°H°Øú¡ÞÔ™zSgêͲ&Á"ƒE¡P( c°z°Øú¡ÎÔ›:SoêL  ûï©7u¦Þ,k–5õ&Á²)ÊÊÊ8“;[}Ô™zSgêMéÁ"}-B¬Cȵ) …Ba €\qëÀvvv6=XlõQgêM©7u¦‹ðñññâp8fö±cŒÁbÜu¦ÞÔ™zSgÆ`>bÞ¼ysŽÅÅŹ%Vº‘ŸŸ¯ž¯5kÖ¨ÿþî4½hÙ×Å.úbÆ ¶ÒW߇ެßöÐߎöÌŽõ;˜öŒË&,‚ ‚ "$Xƒ…cAA`>BE8<‹|Ä" Ÿ‘DÚµ!122¢Ö>e ØÄJˆ–ºÀuÜ»w/ì^œPàÁ2Æ`…»‚‹ ÁzššY¶l™>^òóógÉ6^wóæMu®1¦ƒ…w±6ŽÇÅÅ©Eh«««çÜËùóçÕïæÏŸ/‹-R‹1;¯wõêUILLT÷’œœ,—/_žsßXÌ‹/\¸P凴Ћ‹¥µµ•N$XA¡%Y4õ÷÷‹Ãá˜!As®Ã»¸ÎˆææfE˜@ʆ††drrRöîÝ«®92¢¼¼|†¸¬á\«ãÎ;êXAA"^l;ß?î ûMMMjllL:ÜA$XAA°ºººfŽdé^&çëzzzæ¤RƒsF×ÄÄ„:–””äñ¾à…Ò‘““3ç~:;;çÜ?î ÒÑÑÁÂ%,‚ ˆÈ$XžŽ›Å@¡‹ÎU7¤3I+**R„ Ç]uY¢[ÐÊýè,~ƒ.É’’da ADô,Áóe» }%XˆÁÚµk—,Y²dQÑ"‚‹ "ê ‚Ûq®®®ÎôtO—t7:§kµ‹ÐÄ|ݺuKGA`A„ûÛßAz  V[[›=˜’’"ÝÝÝê‚Ó«ªªaÒïÒBŒÖ¦M›æ¤k rQRXX8çº7Jmm­JÀ(Fœ_»v- › H°‚ BtËa*«ÄÉ‚ Ø|Û¶m*¾ ×Ðaã´ _è&DüÕ²eËäÂ… .ÓÅ4 Ë—/WÞ(6ì;_‡twìØ¡tÒ§|@—!c°‚‹ ‚ ‚‹ ‚ ‚ Á"‚ ‚ Á"‚ ‚ Á"‚ ‚ Á"‚ ‚ H°‚ ‚ H°‚ ‚ H°‚ ‚ ,‚ ‚ ,‚ ‚ ˆØ"XùË_( …B¡P(Y‹ ‚ ‚ðÓsE‚EAA‚EAA‚EAA‚EDTaÞ¼y|A„ծЅ‰` ÉöíÛå¯ý«ÄÅÅINNŽÜºu+ ‡k HÑ¢E²cÇyòäIP+Ÿ.®Ð××'………¯Û½½½nÓkjj’¼¼.\%K–ÕšÝ^êS§NÉä䤒“'OJzzºÛt`Ôó—’’õÂúZÙ¼­”µµµ–^Úk×®IvvöœôwîÜ){ö쑉‰ uÿ{÷îeÌœñðáêµ gIDATCùàƒäÞ½{jppP8===ÛK—.©:úòåK%0î8f5/«¿§Khchchc"ÐÆD2Á²‡+!Á½xZ|f-[¶¨V®-((˜aÿVZî ÷âÅ‹²yóæYÇð‚£õƒ–ZC£££³Î>|Xµ²Ð 9þ¼Ï•jþüùsŽ!O«À‹êê¹Ëøedd(/€𬒒’T+Ù9}èâÛ®Œ·”wUU•ß÷ïËKíüla¸t# `Þj^VoLÆqÙ²eê>ðQìèè˜õìöíÛ7ÓZŶñÙºJïìÙ³êcrصkל²p—> Æ{oii™!&Î-\³{ÆGù"ÜGyy¹Oe£}£´{INÙ°Aäömk¿£¡¡™F²öòôôôÌxv‘¦^×ñ\ñ|y¹«ÿžÞùX¶Cá!XÞ7áСCÒßßïò|jjª´¶¶ªJ‰– ’¯­Kc+FLÇñãÇU¡¡€|Ð2¶hŽ;¦ /Σ p¾¾|x¹Ñ¢„N¸³qÌ*àÚö¦uéÊ=#ŽJˆ÷b–*»§|JKKåܹs.Ï;?ˆžâDPÁзl4h㇮ƒZÑÓêˆ.i¥ºܸ¡Œ0{¶®âpÌj^VoÕàãáÜô׃e–ž0‹÷ÅØãárn9"¿Pz°hchchcþ˜¥‡÷2%%eæZ"#Â[æwCè÷°mÛ¶Æ`ÑÆÐÆÐÆÌ&þ¨óz<þ£®¢ÎºÊËUý÷…`Å‚ Áòq!^T¸ÊáÖă52YœÇ%8*«ñ¡ _Vw·[iý b¡¯Ù• nRä…aÎÕÕճΣÀQÙ<ðñÔÒ‹¯Ï‹Á¶™1ðÔz³2çŒsk úá8ZÍÐËy$^R½?Þ_ã‡Ö¤ÿ‚® Ä!X©¸G”ʘ޶f½™¿È,-Œü²2G»û0û½· å„^wðañÔÕÑ2úÈ5}(»•ôP/1|^ €·† y †ÜîÇ“7ÅÉ‚'kÅŠiÏ•ÕQ„´1´1´12Çs£“üwö0yªÿ¾¬X±C¡'XA@ Av´C$XA ð`À-`dOÝšA±l‡H°‚Ðí†8tÑ9O2Ha';D‚EAA‚EAA‚EAA‚EAA`AA`AA`AA$Xa7„kÍ-‚ h_hÂ@°Ü­Ñ¬‡¯§õ‡-Z¤Ö 3[9Þ_455ͬ†µÅ°ät¥¿·ÏËêó„žV€uÁœÓÅŠæ………jR6¶±¼@(ÓÓ× Ã3Äza—/_öX|©[žÊ (++³´^˜;˜ý>Z V´JÚÚÚšÀ¼ç¾®ÉH{‚õPû‹ÔceÅû@/uCCƒZá3Æ–””¨+T• dZy¹®]»¦VµwNÆæÔ©S299©ääÉ“’žž²ô°â=нwïžÚæŠ÷žÊJ_±«Õû³â½§ßÓƒå ÞÐÖÐÖÐÖ„ØÖD2ÁŠiÖsí/AûÃÿ`š«UÈõºÑJÄ:CÞäqñâEÙ¼y³Wi>|XµÖ<­xï ¼P®VïVåÌÈÈ¡¡!Ók [RR’jÝ9§‹Uægªô¶lÙ"UUU~?_^f粂ÁÒ/€mv«yYý½1ÅeË–©ûÀÇ¡££cæ< ó¾}ûfZ©Ø6[öé={V}äñÌ—‰0Kã½·´´¨u¼\µlÍîybbBå‹üqXÍÞwC{_“Mhkhkhk|´5ÉÉÉÒÓÓ£¶Q~HS÷¦á¹âùórç¡óôîǾ= Á*Ñþ@°ð?FïøñãêÁ‚¥£•²gÏžY­+é¡u ãe5ÍcÇŽIAA:‚´ ¸ CÕªD^¨”ž~WZZ*çÎsyF-?ȉ'Ô±`¥ç ” žq8ŒžsY¡›÷l4Š8f5/«¿7¦ƒ.ê®…1ÊÌÌœ9EJQOGFF”àÃm¶p)ÒÃ5Æëu×,½®®.IMM¹*½»ÅÙ ™Ý3òCºø0"”½o ä*oëûÿ ´5´5´5>ØxÏ®\¹2ãùÑÐ÷¯^½*tùž{k¯bÛ…€`ÁkµBûûEûÃo½X¾½„„éïïŸeÀÌâÜ=++ËíùILLœi­`ÛØJ tzÞêi5îÁÛç몬\¥á‡Àêï×έܥK—κ?lÃ8š¥g¬×¸iXMq"ª« ~WzY¹gÔc}ðÞ Ýw"U÷½&Y´5´5´5Ó¨¯¯—ââbµ BÒ¡Qœ·J°ÌÞýصGA X .þе?Ýs…í74z؆{Oì»r ›¥öjlUzJÓ—hnnV®Vw.Ó@=¸OÍZk:` t÷°«tóóóU+ÐÇàªU¬ôÂѪtWVáð`yªûÞ6³ë=¯©©‘´´´Y] V ¯·ï¸8Y›¹rÄéšÍn®£­¡­¡­1³58ò‰g„®8ý¿~\OÇ—÷ØìYD¯= ƒK÷^é^+ç}_+&Œ±¢À@9·*G_x›â"ŒÂSšÞ¶*QÐlÜh£‡þvmZIǬUæêƒíé#Èôྠe\„YY¹ŠkÀ1«yYý½Õ—­/ç ¿,³ôô@Y¼/Æî o –s‹ùEŠ‹¶†¶Æ®¶ž+tµÍìã]×÷ƒE°bÃ…€`•¼ÿótÌÛŠ‰ÀI<  \–ÆëNŸ>­*þÀd´f%w#{<¥©ÇEà~<ÅETVV*#êì>¦ÑCÀŸ»€F+np#зØcƒq$N Ós 7^èsd§²ÒGæ ÜýÙãé÷Vƒ?€ØE+1X¸âó`–^kk«¤¤¤Ìz/á­AÓ»ô{ضm[ÄÄ`ÑÖÐÖØÕÖ€¤` …φÿ¨«¨³®ò‚‡Ë¹»Õ‚;ö(ˆkXûK0ùÃy_+&\§x)кÛG;_#W&®ÁÐÜêêjK­T(QW®tOi¢ QÉ<ìñÔÊòvN+×ãeÒûÍý5z0øú|-l›¹åýMÏô¹iP˜›—VŸ¯7FÏJZñeenw÷aö{o b ðПåþýû=vq`”Œ>b ÕÆëÍÒC9a¾8|ø½5hȱð$à>p?f^Ï$+p£ikhkìjktÏNRðßÙÃḏOz—¶?+¶ìQ=XAÞ#@.|Ç>D‚ "Ä‘`FÀ#wü«W¯}ºÜ½{ס÷üÇê9þê¯þjÐt†×±¼®'NXÍEú·û7Y°`455Ùä|õêÕƒ^×æÍ›)@h4F£I€ Áš9sæ°ÇîÝ»W-íåìÚµkÐc°ØEr»>40†ÛúyÜ÷‹‰ŽŽ¶úZðz-mòäÉVïgíñŽÚh9Ù±cÇ 1,Âm-Èñž ]°C0Ø›+55uÄ÷Ü’w¼vgyëë ³û˜¿ù›¿‘ºººaûúë¯]þ>Òh4F£yH€X×_~)­­­ƒ‡]ì¡9"¯^½’––ùïÿþïAcCw¼ŸZrŽÛ 4„F£Ñ|\€è†]kx>l…A”XŽ!gD7ìv0Öì›o¾ØÝ×CvBBBFõ:­Y¾[³÷ú‡.”]¸Ž•“+W® Bè^ƒe(×P‘€| GÄãP0_ÎòêÌëB>Þ=wÆVIhG9ëûH£Ñh 4ækhhª£›eص…½E£nHÈ:¿µÄõÑ GÆFóú]¸Ž•,𱳝egg+èÇ÷w7â\#a,›+xuôu ¥rôoqÇûH£Ñh 4æ%boÑ<šgkÜ_Ñÿë¿þk•`ŒÛÈ¿ð„ñ´d$N’““Æ–/_.K—.8^¼xñˆsáù]õž»’WG_ªeY>îÀ½z@h4F£ù‘AÅ![‹fgs@V®\9¨"’å1àî CÃË,_¿§s@`H×Ç&L˜ ÿ÷ÿ7p<4!ßÚ\™™™>!@Æúº†VÓ å|í½Ž/¾ø‚9 4„F£ÑüA€ dèâβÑЊOðfèÕ‡P‰ÈV¯Ø;wå  WÆpw Ë'Uªœ­žä '0½úòô[è‡Î….ˆ¼èE‚r¿x ž c}]Èû°|Þx0† Å¡¯ƒU°h4F£\€ØBd†6‚C˜ÌH=/†ö®x÷îüã?þãÀxRRÒÀnëç± Å}Ý%@`Hxvuÿˆ±p¢úiŒÔcc´s9“1V^Çòº†öC±,K<ÒëuG?F£¡Ñh4 , r…2§èvm+–¡CèïQâç°Û=Ô,ýzÝ,{hLçNCçsýµã7Ê ­X5´ZÓH6ZN,Å™eR5n[Š0{s¡@oãBX›µ¤~w ±¾.xFôû#ñ÷sôõ¢£ýÐ÷q4+F£Q€Ðh4ÍkvêÔ©A‹V,ši4F£¡Ñh4šSö?ÿó?rìØ1Õ©/ŽõŠ\#5ê£Ñh4„F£ÑhŽ‘£€Dp{94F£Q€Ðh4ÍaC%ªøøxùÝï~§ò< 8§ðÙgŸ©>–ù)4F£Q€Ðh4F£Ñh4 F£Ñh4F£¡Ñh4F£Ñh 4F£Ñh4FB£Ñh4F£Ñ(@h4F£Ñh4F£Ñh4F£Q€Ðh4F£Ñh4 F£Ñh4F£ñw[¹rå ctAž3gŽÇá­yä—Ü’_‚Ü’_rKø:¿C×¥ "@æÎ+?þø£ÇñâÅ ¯Ì( ¿ä–üä–ü’[Â×ù¥¡ñ(~úé'~èÉ/¹%È/¹%¿¹ `~)@(@‚ ‚ ‚„FA~É-ù%È-ù%·=   Œçd<'¹%È/¹%È/¹%¿ 4z@òKnÉ/AnÉ/¹%è¡Q€AA= ÜÍ È-ù%·ù%·ä—„Æ‚ü’[òK[òK[æ€ø–)++“ÄÄD?~¼|þùç’––&mmmƒî“‘‘!ÿû¿ÿ«°oß¾Ÿs¤û;;îíùèánAnÉ/¹%È/¹%裥¤¤È½{÷¤¿¿_zzzd×®]Jè–““#qqqÒÞÞ® ÎÙ²‘îï츷çcAAÁ„ȸqãޱ8‡ªÓ ·cccm>~¤û;;îíùèánAnÉ/¹%È/¹%èq¡•”” ò€L˜0A‰K‚s¶l¤û;;îíù˜ÂxN‚Ü’_rK_rK0ÄEVSS#aaaÒÔÔ4pî÷¿ÿý°ûYzH†ÚH÷wvÜÛóÑÂÝ ‚Ü’_rK_rKÐâ+//—éÓ§ËóçÏGåa$Þ`–¯”¯~ñá·»Žeòd›ðÄü<æ1yÌcó˜Ç<öcà ÂÂB™2eŠ<{öÌ¡ œMN†åý÷ö|Þö€(±aÍ´óÜàn¹%È/¹%¿¹¥ÄçHVV–¶v,µµµv«L¡4¯µ*QCC˜Fº¿³ãžž„ñœ¹%¿¹%¿ä–`ˆ zk°4ôưÕ'ÃZ…½û;;îéù(@¸›A[òK[òKn z@|ÈÐÀПç£!‚ ‚ |)@Ñ(@¸›A[òKn òKn z@h#@làRþq~ 0^–Üä—Ü’_‚Ü2„„Ä5¸\|Y&Ûù)_ýÉøy¿¸[DnÉ/y ·ä— ·ô€P€P€¸5«É£ßÈÊ_—Êõ‚ëüB ‚ ‚`ˆÕ¶É$Í‹’¥rÍL‰z?[ÎÝ=Ç&w‹È-ù%È-ù%È-=   î‹7ÌÏË“ÖÄD©Ú !æÙóx¿/KnÉ/AnÉ/¹%Ì¡¡qŸÚ.¼~]:¢£åÑ–•2»s¶,kZÆ,î‘[òK[òKn z@(@(@܇[¹¹Ò!w¤Ë²—Ë”aHAAs@¼n¶ºŸëÖÑÑ!«V­R ¿øâ 9|øðˆÏ™‘‘a·³¸³ãÞžÏ×= :nggK÷ŒòðûïeÏ£= Éân¹%¿¹%¿ä– ÄwÌ–Y»v­lܸQz{{¥§§G6mÚ$—/_¶ù<999'ííí ꜫƽ=Ÿ¯ç€ ÅÝsç¤'$D~þáåaHãeÉ-ù%È-ù%·s@|Z€Àóá¡n'&&Ú|,æ¡uÃíØØX—{{>#y@t”<)fM„à7„C²¸[DnÉ/AnÉ/¹%è1Œ'd„ 6ŸcýýýǸmygǽ=ŸQr@†xBàÁ1C²‚ ‚ ˜â“dÍš5*ì "DÁ7nܨžÇòþÎŽ{{>#z@t 9!È Á1C²¸[DnÉ/AnÉ/¹%èñ9‚$ôÔÔTå ™4i’deeÉĉÒ‚7X‡¥ÅÇÇ«Ø?ýâÃoO755úñ϶o—î¨(©«ªRǫެ’sŒÜx|ã¯ß×ÇÂ/;~ûö-ù ¿†<Æ÷ù ¿F<ú›üø¿~)@†Znn®JLMNιjÜÛóÙ2(•–¦ú„ _ˆ~Ž!YÜ-"·ä— ·ä—Üô€ø„Ùºu«´µµ)Ï@II‰LŸ>]l>N¯*…ÇØ«:5ÖqOÏç/9 Cñ«ö7 c::§ëç’EAÁö±Ö„^!+))IjjjF.è¥a¯¯†3ãžžÏ= &“¼JIQÀmý<«dq·ˆÜ’_‚Ü’_rKÐâÓaâÏó½ˆ=Àû/¼!CÇ’Åšéä–üä–ü’[Â÷ù Hˆæ?y ÈA^Èб@Éân¹%¿¹%¿ä– „FâÜÊ͕ΈU!kèC²‚ ‚ ˜B£q¹ÚFoôA¯kã’ÅÝ"rK~ rK~É-AÄñ†è’Žnéèšnm<ÐB²/KnÉ/AnÉ/¹%˜B£q³Ú.;yRÌšÁokã’ÅÝ"rK~ rK~É-AÄ€žxDl݇U²‚ ‚ ˜B£Äe@.rBbë>þ’ÅÝ"rK~ rK~É-Aăñ†¨Š…êX¨’eë>þ’ÅxYrK~ rK~É-Á7˜­èº555IJJŠL˜0A·í>gFF†ÝÎâÎŽ{{¾@ð€ | ÒÒTŸô ±w? Éân¹%¿¹%¿ä– ÄÍBÄš…‡‡Kff¦ôõõ)9rD"""l>ONNŽÄÅÅI{{»BBB‚:çªqoÏ9 CNé蘎Îéöîè ‚ ‚ (@\ @>ûì³açÆoóy°˜‡ Ô ·ccc]6îíùÍ¢`2É«”ܶw_ Éân¹%¿¹%¿ä– Ä dùòåÊëÑß߯pøðauΖ!L ÷Ó ·qÎUãÞž/r@,ï¼ ð†8rÉb¼,¹%¿¹%¿ä–`ˆÈëׯ%((h O·[[[Gõ<ãÆsÙ¸·ç HÈ<äƒ /Ä‘û=$‹»Eä–üä–ü’[‚/¤¤$å±ÌILL HÞ`–¯”¯~ñá·'Ž+*îxt>üFE¬î¨(y“™éÐý!z{§K__†|üâ‚.éè–Ž®éŽ>Æh!YŒ—%·ä— ·ä—ÜÌqský@TÈ*_¸sö„ ziØë«á̸§çó5¢‹®®Â?Îþ³×DHÙÉ“bÖD~;ú#UÉân¹%¿¹%¿ä– ÄÍ^I^˜Ï—HQÑUvÕÓ³sÈ+:ªÎcÜÓ=< ð„À#2šÇùcãB‚ ‚  š_ ÝGé€D$Lª«OzíÂG.rB2šÇùzHw‹È-ù%È-ù%·= ´€ –"Dä†P©­=äõÞ³íÛ¥3"BUÉÍã|9$‹ñ²ä–üä–ü’[‚9 4 !U°ZZ6Ë«W‹|ã×–¦ú„ _Èhë‹!YÜ-"·ä— ·ä—Üô€Ð(@†ä„Üîî0¹ÿ”O|Ñ)ÓÑ9}´5zãB‚ ‚  š_ ]m?y²KZ[}ãƒ`2É«”Üíã})$‹»Eä–üä–ü’[‚ˆ•xÃüü›Òա²|áCï¼ ð†Œõ9|!$‹ñ²ä–üä–ü’[‚9 4 j»ªj¿ttDk·M>ñADòA2ÖçðvHw‹È-ù%È-ù%·= 4 ›0)!â+FTÄBe,TÈës©q!AAˆf«ºµq'N´ûœv;‹;;îíù|Ñ¢WÆB(B²|åCÞ è‚^!Î<7B²¸[DnÉ/AnÉ/¹%èq³qÄnݺew‘ž““#qqqÒÞÞ® Î¹jÜÛóùbˆ%ŒŽ¤t_úP¢K:º¥£kº3Ïãé,ÆË’[òK[òKn æ€ø€‰ŒŒÔ¹­6DZ˜‡ Ô ·ccc]6îíù|Ù /Êò¢<¯/}0ËNž³&BðÛ™çñdHw‹È-ù%È-ù%·= ^ %%%’žžn÷>&LþþþcÜÆ9W{{>ßÍù hLøüùŸûpÂO<"Î>—/6.$‚ ‚ q±ÁB»¶¶vÔÏ3nÜ8—{{>_÷€%%YbÖçhTèkä‚ '¹!Î>—»C²¸[Ä8òK[òKn z@¼(@@ìòåËG|ö€à Öaiñññ*öO¿øðÛÇMMM6Çß½Û,ÍÍ[<úz=nØ·OÌšh«¼}ÛéçƒðXõf•ĘcäÆãã—Çο}û–|_Cã{|_#ýM~ü‡_¿ È‹xôèшÏc-§ç\5îíùŒàŠ‹sÄlV¿}2Y+-Mõ A¿W<Ÿ;B²¸[Ä8òK[òKn z@¼$@***l&f}œ^Uª­­ÍnÕ©±Ž{z>_ ‡UHtt‡L›öQæÌé’ŒŒ*«÷««['+}öÊNé蘎Îé®x>o7.$‚ ‚ e[ý@°(/--uX¸ L¯½¾ÎŒ{z>_ ááÝrÿ~·šûéS‘¨¨ÚùÇÃî‹ä‚ 'Ä'?4&“¼JIQÀmW<§+«dq·ˆ;qä— ·ä—Üô€ø ?Þ¯çó5χ.>tƒ‰‰éµzTÃBU,_ýÀÂû/¼!®|^W„d±fºCðÈ-ù%·ù%·ä—„f 2}z¯Õ×ôÍ7bõþ肾 èâ«Zä y!®|^gC²¸[Ä8òK[òKn z@h/@bbÞÉÏ?手ûhó1茎é¾üÁ½•›+òlûv—>¯'AAP€ÐüN€ $2²W*+Úôròd­í0§ü›ÒÕ!åå™>ýBoôA¯W?÷XB²¸[Ä8òK[òKn z@h/@t’ðA…]ÅÄ|”+z%//ßîcªªöKGG´vÛäÓ`tIG·ttMwõs6$‹ñ²ŒE&¿¹%¿ä–`ÄŠÚ^¸ðµlÞ\3ÂýMJ€@ˆøú‡¸ìäI1k"¿]ýÜ£ ÉânwâÈ/AnÉ/¹%è¡Q€XAvö 6k¿oÛ½B°Š…,_ÿ ÃO<"îx~w4.$‚ ‚ ¡„Ø´éIN~5âcŒŽ¤t#|  ‚œ䆸ãùG ÉânwâÈ/AnÉ/¹%è¡Q€Øˆ7ÌË+ðð.9r¤ÜîcPŽeyQž×hTÅBu,TÉrÇóÛ É2½4ñKÕM ·Œõ&·ù%·ä7€ˆ½èºÕÔÔHRR’L˜0A&Ož,¹ÚbОeddØí,î츷çóEpøp…DDtŽ˜ŽÆ„hPh˜uZšê‚~!îšchHÖ…’ 2YûÁo~±º:·W\!Üé$·ù%·ä7= ¶Hmm­L:UJJJ¤¿¿_ÚÚÚdûöí6Ÿ'''Gââ⤽½]!!!AsÕ¸·çóÅK,XÐ"[¶ØOH/)ɳ¶Ø.*ºj˜6:¥£c::§»kˬ•-+Õ"yyÓr~±ºð8ÛÉAAA€Xz,ìá³Ï>s‰Y¿~ýˆKÃb*P7ÜŽuÙ¸·çóepñâ§„ôK—ì'¤76®”ººuÆù€™Lò*%E·Ý5B²’_%Köó@û™Ú?•^{?À)¸ýFû¡ÄM…)že“î"“_‚ÜÒâ:aa [dܸq. 'N” .ȤI“düøñêìèè°ù<Ó‚§D7ÜÆ9W{{>_ͱĆ ¿È¢EöÒ‹‹sÄlV¿òá†÷^xCÜ9OjKªìÔ~`éÚÄÈdþ¸ìg½öÛ¥ý,é_"a=a2ëÃ,™ý~¶DwDKÜÛ8™×:O¶,”E¯}òHýºRVׯ–õµëeÓ/›dëó­²ãéÙýx·|ÿð{9Py@ÿ|XŽþtTN–”3¥g$«$K.ݾ$¹·råFá 1å›Fä1|qôä— ·Ìq[<ØÁGX”n­­­êœÉdr‰Áù7Joo¯ôôôȦM›dÕªU£zK1äì¸7çìÃÒâããÕ…§«_üöÄquuµÕñ{÷Ê%*ªW²²žÛ}|sóå ñÔëuÅ1ò@:µëûíÞ½ny~,Ú°3ÿRûá7vìï5Ü3?¾|lzdR\Zr ®¯þrUî7Ü—ë¯Ë©û§Ôîýµ¦krªæ”ì«Ú'GêŽÈ‰7'äû_¿—Í5›e[Ó6ÙÙ¾SÖ¿^/+^®•­+åÛÎo%¥#EÚ$¡3Aâzâdv÷l™Ñ=CBzCdZÿ4™Ò?EþÐÿ™Ö7MfôÍY=³$²3Rb»be~÷|YðnÌo™/Ëß.—uï×Éš–5²ªa•lÑ>'ûÞî“ï¿“í϶ËÁúƒröõY9þËq9\qXÎWŸ—_þ(¹OråüÝó’ÿ0_*ë+ånÅ]ÉËÏó8ßiïÒ”YÓ¶†×ŸŽñ½K>ȯuÿã×ãäË/¿TÂ`¨áÜW_}åo„‡åsÃBˆoæ€è@·ôÈÈN¹yÓvB:r@ ‚œ#í2 "*c¡B–;¼Ø™·´w0ÄE¹[Í[q ®=™ r3ÿ¦\+¼&WНHöl%Nß;-ÇËŽKæO™JPdTeÈ÷¾—ÝOv+Á±åùÙðËYW·N ’+diÓRIy•¢Kbk¢ÄµÇÉÜws• ™ùa¦„ô„(¡Á3Eû™Ú7U‚ÍÁJEtEÈœ÷s$¦#FâÛâ%éM’$¿N–ÅÍ‹eùËå’úkª¬©[#i/Ò> ®jMp=Ý© $@¬8(?”ÿ ÇS‚í\é9¹XrQrŠsÔßQÇðA‚ 怸M€@4Ø ®ÊARöPbon-§ç\5îíù|=dxBús»÷A5,TÅ2Ú‡ ½AÐ#½B\õœ—‹/Û Â8¿èÈí¨KÿhR!`CHBÃ"†P±c?“~þA…!”ì»Çß©Ð2„˜!Ô !g=CÜâW‹UhBÔâ߯«5„®…w…«P¶¹ýsôí'á]‚Y¼GO~ rË— äg aaWعZZZ$::Z¾øâ —„y!ì "@8ÖÚµkm>N¯*…°0{U§Æ:îéùŒ˜2 ~áSBzNŽí„tôA_ô1Ú‡]ÒÑ-]Ó/ËXY&øDþ„ ¼2ð¬ÀÃc­é&a2y²M~7[" s@l%¡ß¼ysÌUµ†Ú‘#G” AèUjjê $tk÷G/ {}5œ÷ô|Fö€|JH1bB::££Cº?ðe'OŠY!øÍÝ"î2V·®>¸³§¬|µR…iÁ«‚„†Í{3O¶=Û¦¼1äÎAbÍ(@(ðø½K¢DBs@ˆ·+++=Ö?Ä^>ˆ?ÌgÔ7n CúÉÌ´ýÁÈÏ¿)]]R^žiÈ=< ð„À#Â/A‚!nöC܃/䲄u‡©ð-ä¶ ŠX^Aù¤!¿Áš/š‘< ÀÁƒ#'¤WUí—ŽŽhí¶1K•"9!È ánwŠÈ¯ãü"‰öÈ)wdþ›ù²ãÙ¹pÇø ì7nÈ­+WäŽö½Pzîœò”–gfJåÁƒòpï^y²s§T§§Ë/7JÝÚµòë·ßJÓÒ¥ò:9YZ“’¤=.NÞÏ™cwÜ7uªôM›&½Ó§‹98Xm†ô„…©ï£3gʇY³¤+"B:##åýìÙêùÞiÿ3:¢£¥=&FÚccå-€ãã¥-1QZçÍ“7ÚÜ-óçKË…굨H‹K³†¦%K¤iÙ2y¹|¹4®X¡Ê’ÿšš* «VIýêÕR·fÔ­['µë×Ë‹´4y¡ým¿lÚ$5›7Ëó-[äùÖ­R½m›*âñtÇyºk—<Ñðx÷ny¼g<ÒxÁ÷iÕ¾}R•‘!•H…ÆWÅáÃj³§Ð8üéèQyp옔?®x½ê”Ü;}ZJÏœQ\ß=^J²²¤äâEÅÿíK—¤8'Gе÷…DŠ®^•ÂkפP{(@ø½K~)@h £‰7œ?ÿlÝj/!ݤ„ˆQ?üø‡ŠêXøçÆxYÆÊ2Œeôa,׊®©*`¨Æ…ÜTìB<ªn¹Ó;‚?EÚç‹T,\±˜Å·âÐ!y¨-„Ÿh‹c,šk´…t­¶¸nÐÜ/µE8æo´…ú[mñŽE=úXüCôO™"ƒ‚”(€Àâ ~ôz­-ì›5¡Ñ¨ ŽzmÁþbÃy® ‘§š y¤-Â+µ…7ÚX\cAmoŒ4ÒXPã» l,´ñ·`á}çµÇß……9ž uüX¸—8!´y~Òó?i ûò#GÔB ~,ü!  ÀÅ#Mà5>þî;Å „¾ÿÀ„„Ç/Úß!Aa¡ÁáÓ¨á¥&fÀ)X³&r xÀ/„„„8lKHP¼C¤W*¼Xà‚ ïGWx¸â‚ ï Þ6¼OpöøÅ{Žùç÷.ùõ1²`ÁU•ÊÙNè4ÿõ€/–ü1!½Øæ}‚…P,„dö @ûG‹„èÂÝ"î1Œeì»È¨Þ…²¾(û6VyG’_-ïÞ*×óN©E5ÒØÿY[,Wí߯ÅXcñ[«}´….¶X̶hÿ«°hÅç‹S,H±íÿä_ ¸sÃ}p_<»þØéÇsá9k´Åõ3mÁÝz̉¹ñðZðš°ø‡ È7™|–[Âq~q-|üæu]@4Vk â´H{É¿wɯ—Hrrò€Øp¶:Í?s@,‘–öB/n¶{$£#)ÝÈ_ØÑÃvUù¥Hp7Yî=+NœŸQ»ûØAÇ®9vʱû/vÁ±ó ï>?ØÕÆN6v¯±c oBÿ¦Hwð¤-bŠ4ÅþA^&†HsR”´ÌO’W‹©° ì¬ÃKoųmÛThvîáÍÀÂ;ÿðÀC¯AþÍ›Æà–IÒ^ϸFà9‚èÄõõ66VyOà]ÁuQ •«¼ßþŠãŽ“怸F€ jÓ½{÷ÔmÝã U‹/–ììl*z@†%¤ÏœùA޵ý8”ãEY^”ç5ì‡Ñdú3­áG'vA¹[Ä8YĽ‹ŠR¡2Ÿy­}.C€ðä= ÿ»ÊÈ@^ò#ãð „ !Œ » Aïš ¢WIL{ŒLë& _/”]Ov©^'¼v · <í»Bù*õÚu ™îEƒˆÆu Ñ 9þT¦)®<¸B>èqM#Bk·Ñd´}@hþò[Bz¥Ìžm?! Ñ ÐÈ_ð~`ÞÆË2VÖ_¼ „=!›aBh²ˆFŠKš–Hˆ9D5GDçø£?UÝçyížâ97È™AÎË›yóT™väà3‚>x︰X‰Q€F¦ ;7ò:cˆkšçéåi ÕíÒÒRæ€ÐbIIo$=½ÚæxII–˜µEDQÑUC ñÃÈ áN'wŠüðF ù‹«ÞiÓäUr²JPö•<xGÐå}㋪SûôÞé’ò:Ev?Þ-9Å9¼v ó‹p?$ô£"òŠºÃ¤78XmR!1Ÿäýh2ù%§ð~LíŸ*´4+¥„§Èum•¦-®`¡¡¡ƒr@&MšD¥À«ÈÊ9!½±q¥ÔÕ­ó‹Å*c!1–_„a¯ãË—UÉX,˜”èX´HíòX[ðÕ<…+·®ÈÞG{eqób 6KÔ»(Y_»^Ž=8æwÞÂ8y øL¡Ú &@ÄWy%¨ì…*a(GŒÄ|/‰’7Ôg'ûN¶j$ QŸYž)+ÊÞ‡{eç“’^.Ù(këÖÊ·¿~+K›–JòëdIjM’¸ö8™ó~ŽÌú0K‚>Ézí†f¥ô‚0Ä¥exûúúä믿Vž¯¾úJz{{ö¢Øê€>tÜÞý,-CûÇh¯³¸³ãÞžÏèO éµ²d‰í„ôââ1k‹…b?رDoÄ#V˜;Ü)2 еÅõØvTƒBøH%I}•_S¾IN”´i2÷Ý\åYôj‘ìy¼gP³D^»§€ß^ i¼zU•BF)c|ÞPFe‚Q9S(¨€jk–Nòòó$·(Wå>¿{^åF!ôðPÅ!Ù÷pŸì~²[¶Uo“M5›d]í:ImHUáP)¯RTÏôßÁg%¯QúÕæ¦ôOQ¢‚}懙*¤¹V‰­‰*×jióRù¶ñ[YS¿F6¼Ø éÏÓeçÓ²çÑɨÌPe³—W=~Ž–• þ y©ýÀð›^z@|ªˆ=2ËÉÉ‘8ÔooWHÐþy✫ƽ=ŸÑs@t\¿þ)!ýØ1Ûx@à ñ‡/tIG0v¼ëÍ8zŸÚwJÌb¢Mç^0ÊŠnFá¢â"b 1ˆ,ž VxíR[R•YÞ´Ü-â}n˜U’¥JLà wøçò¿j¿|÷ø;Ùþl»*;V›&«VËŠ—+de}Šì¾+çÎÌ’;éÁòkBôLŸ"¿,˜"y{¦HFîdÅ£odvÇ ‰ìŒTa‡ m ² eòú­h\¡ž Ϲ¥f‹jò‰ksbn¼¼¼&¼¶k…×\zíCìl5o´f¡„9 ~)@°˜‡ Ô ·ccc]6îíùüÅdd !ý½Í„tä€ 9!þð倪>HHÄoîtrÙg¼Á:,->>^¹Þtõ‹ßž8®®®vúùÒ+õVÇÑÄlž)…ÿûÜu\{ô¨ôΚ% ÜÎ/­755Üßÿ‚^[„tjßÍ}aaÒ²fjžV®}_“_ûÇÏ_<—‹ÕUißèÑö1L¾mýV•þ½]yÛ£¯ß ü<[?F.ĵ'×äróeɨÏPÞ,¼O ?,”ˆžå‰ë “ÄžDYòv‰ò8ìùud¶fÊTíÇ2O^xEŒÌØkë´×gÏÊ«Uh%Ý{##åí²eªYçó3g¤¾²Ò#¯GÇâ‹åHí^¿nâ×ó{\€ é|ïÞ½j×ÞR€tvvÊçŸîr¢?7’µé1vˆ%Ö¯GBz“ÍqtFG‡tÚ-@U,TDz×9—±ÞŒ£w%.¨.ÍÚw ® Ör*,½1ÎŽ{{>ÊœÞ-ÇŽ=°îZο)]]R^žé__iiªOH¡E)SÆz3ŽÞé‚Úâ;›ïæÌQ‹ „cütô¨G{ Òµ‹*D™?eªPžÙ³%ÔªÂtöUí“«nèeäÜBÀÛ¡€ ä@ Êò#¢ÞG)a1µoªJ²ž×:O „Ã!D‚Â…y Î…eV8 þ/¡ibOh¨ÊYlMJ’Zô*Ù¿_5YtÕµ‹$Áóÿs@Ædêîî&8ÚÚÚFÜÅwT€¬_¿^Ôíׯ_˲eË$==ÝæãôªRx öªNuÜÓóù{ˆŽª$*꽘LÖÒ«ªöKGG´vÛ¿vL°#(g~ 9E¿lÜ(T“³†U«Tª¿66óe î%IQ…IDZocÕ‚•†qDZþÙ·³U"7ªQ²¡OðÍ혫B£Ð/"¾-^u³Gè8Dò5’À¯¼)­‘«âU>,¿lÚ$¯.”î™3Uu<”æ®_»V•–¿{þ¼Ýï{ý„Ožƒ¯ô_ò¸A²ydd¤´¶¶*‚^ Ïž=SÂ$<<|Ô}@¬õù@wu<Î#ä ù===v… ziØë«á̸§ç Èo é­²mÛ3ã&%@ DüÍþ*%Eaè—8= Ü¡·4)C¸DçìÙªÏ š—•?×îo;û7Y]¿Z… ¡vï3ª2TIV£sk/©;¶=VºÃTˆÝ3Ô1Îc÷;Py@=îJñŸf¼víaÃåGŽÈó-[TCÒ®Y³¤ï›oT=l|<ÖÖh¥gÎ ´P‹ak¦ÿ®öÉ«“Ä¿~-@jkk­ »ùž°ñãÇ{´\°§ç „YYw%$Ä,W®XïŽ,„båûYõ x?à7„±Þ̱‡{gÏJmZšÊú0s¦Ú…Te}ÌÓÁk×F©×;T W„Á;‚`ôf@Ã6‡ý/=÷^#©x"à‘€gMèðº±x„ç x2àÑ€gcëó­*ü ½T+ã«ýTxíºE×®©0OTÖk^ºT:##UY`„Û[ ã³€ÎéädÌ"ž,̱”à¥S€¸c§hݺ:YºÔvB:’Ñ‘”îo_"ÈÁ—5âo¹Ç]ÎA¢ãôiƒÆ8zÿÔ)òëÞ‘~þA-ÚguÍRÞ4ƒgÍଠ˜?vêÎ.Íöé¤n~7Úÿ4xdí- !P-pˆ;pãF¡Ì˜Ñ-Ç[OH¿ÿ”tkÿ¨Qž×]Û¾ÏIxuk×*Á:þµë×+!BnüèDNØóÞÌSÞt³F¾úIè÷AWiõë}6©› F³CêqÞäŠ1WÁ¢Ñâ*ìß_%sæØNHGcB4(ä— á7»œ&“ ¥BHB«ÂoB®Èo–œ-¸.‡+«†wuBã¶%¯–¨|вþ2ùFû9ô蓺yíþÂü‚{ƒUãOòEb¨| ÿɱDbb«lßn=!½¤$KÌæ)òâ ç­‰Ž'N¨äq$‘¿Ÿ=[^lܨ’ËÉ/a x$b:bdÕÇUêë=+’û’ ‘ÔÍk— 䑼úÐhòI¾XËa›¬ýèËA£ÄåÿpÏJH¿|ù–ÕñÆÆ•Rç‡_XöÈ/6È£={ä§cÇävv¶Û›Éq—ÓM¢C{ÿP-=:P6%.U)KòKØJ^/¹ ¼ýêëºáqE.Ák×ÛÜ¢tu°9Øfîáû×®ÇÈ;w$""Âc¯hþŸ24!}Ù2ë éÅÅ9bÖ¾°ŠýÌmkO€ $§iéRy§vÌ?©¶ÄDy¹|¹ZÈ>úþ{ypü¸ÜÎÉa_©r¦½¨ƒ†€hî…5›7«nÄä‡pÈýØüaó ¯xAFÊ!£ÕÕ¶øihu ÀãÄV ^€ù!ô€8}]OH/³:˜Bó tˆŽøø·²k×ð„ô’’,1›C¤Èà_Z܉sƒ±òÃk—Üä×÷¸]þr¹lªÙDþè¡Q€øN¬¬žž›;=ÄÒàý¨¨¨ÐÐPå €Ç"66Ö)bÍà ±eXÌCê†Û–¯ÁÙqoÏGÈq¢šðˆ}+»wMH7)Re *܉#·ä— ·ä—ÜZD:^“`s°dßÉ&§ì±gÈIKK“I“&¹L€À‚êZ)))6ïƒÐ0ÜÏò1–%÷ö|ÌgÏÞ“ÉÍ-t!XÅBHy"‚ ãa}ízImH%˜âI€è!^_}õ•444Œêy,«u9;îÍùðë°´øøxåzÓÕ/~{⸺ºÚ£óæxÛ¶Y·®eØ8’ÑëëúÜë5¿F?Æ ù ¿F<Æ÷ù ¿F<ÖáìóUÖWJH_ˆäÞÊ%¿nàw,Ç Ž4!Ôûƒ¸R€èÞ'NHtt4= ̱‹«W?%¤Ÿ>=8!åxQ–åyÏÉXY‚ü’[‚üÛ•+eã‹ä5r@†6´%@FÛ#d49 öžÛZNιjÜÛó1d4 é%&¦}XB:¢A!ã9+K_rK_ãq›U’%!æ¹^pÜbHnn®Z,·µµ œkmmUçL&“KHzzº466ªÛªL­å}èãôªRxMöªNuÜÓó1Ĺ„ô¸¸vÙ½ûñ ó%Ú—Yûâ**ºJž‚ €H~•,ÛŸm'˜‚†„½½½ÃÎãr5ÆÒei………®ÎñÅ*±ÝRðX.)öúj83îéùèqgÎ|JHGH–åùÆÆ•RW·Ž»Ü)"È/¹%ȯ¹=uÿ”Ìü0Sõ!¿æÁbÜ–mÈXÍ^I^˜9 Î#5õWËsÅÅ9b6«ßŒçd¬,A~É-A~ÇmB[‚ì}¸—üþ`}@&Nœ¨zV ì ÉÓ"IÞ š £ìÁûŠ„ô{ƒÎÃOw3¸SD_rK_ãqûÃÏ?HÔ»(òˆ9 ¶’ÐoÞ¼I¥àçÄHøî»á éÈA.rBÈAAsÞÏQB„\Pˆ^µiòäÉ*4 ÀíÊÊJªz@|.!BÄò<ªa¡*w3¸SD_rK_ãq‹,„b‘_vB§1Ä',„bY&¤£ú‚ ?ã9+K_rK~Ƀ±¸E:’ÑOùàÿqæ€P€P€p§HáÛo‡'¤?y²KuHçnwŠòKnÉ/y0·(Ç›ò*…üŠAµ«I“&¹¤:9 žJHGY^”çÕÏåçß”®®)/Ï$GAa0 !!f1§30HPPÐ Áa‰ÑvB§Ñâ) 1!Z&¤WUí—ŽŽhí¶‰»Ü)"È/¹%¿„Á¸Ýðbƒ¬ôáÊ–ô€¸P€@hŒ¶ã99 ¾’¾gÏ#‹ó&%@ DÏÉXY‚ü’[òK‹ÛÜ[¹Ü,WН_ ®ðrØê€®[YY™$&&ª [Ÿþù°NèÖ,##Ãngqgǽ== ®HH¿/aa=ríÚo éÁB(V¾tUåN¹%¿¹%¿äÖq¤6¤ÊúÚõä×ßJî¶··»dWß–III‘{÷î©&‡===²k×.%HlYNNŽÄÅÅ©×$$$¨s®÷ö|ÌqåæWYµªaÐ9$£#)üA„±pñÎE 6˵ÂkäßHii©„††Žè‘pF€ 5{ž,æ¡-û” [»«Æ½== .t׿~JH?{ö·„t”ãEY^”çåNwŠòKnÉ/a,n7/–ôêtòëÏÄVô±TÁrT€”””Øõ€L˜0A‰KÁ‚s®÷ö|ÌquBúM¾”ŽÆ„hPÈXdÆÊä—Ü’_ÂXÜž¹wFftÏPýAȯ'¡ÛÂhóC 555&MMM£zË×âì¸7çìÃÒâããÕ…§«_üöÄquuµGçsÇ1„G\\§œ9óz`üÑ£›Ò×&w¼úúü__=Æwù ¿F<Æ÷ù ¿F<Öá‰ù’;’eÏã=ä×CdžnD8’)//—éÓ§ËóçÏíÞb´8ujxBzcãJ©«[G~‚ Â`È,ϔٳÅäC¥õ™b@RXX(S¦L‘gÏžø<Ör*pÎUãÞž9 îúð4ÊêÕ¿%¤çˆÙ¬~3™±²ù%·ä—0·s;æÊ¡ŠCä×_HEE…pç\%@²²²Tµ­ÚÚZ‡§W•Bb¼½ªSc÷ô|ÌñTBú- 5ËÙ³¥çàiôbS#Æ"“[òK[òKndžýUû%öm,ùõG‚ò¸¶’Ð!ÖëH¢»=á‚^öúj83îéùèñvî|"ññoދЮŠÙ"%%Yä—;Eù%·ä—0·¦|“„w…Ëñ²ãä×ß¼ ,ÖÖÖs¸*UðZxÂРГæéù˜âÁ/+ÓÝ!ßÿ[‡tTÃBU,òCAÆÂ®§»daËBráo!W½½½ÃÎ÷õõùÄBÝ_÷áäI=!½P£ú‚ ?ùåNA~É-ù%ŒÃm^Až„ö„Êù»çɯ¿ t'j% þ/@ü5VvÅ $¤×£3::¤“_ÆÊä—Ü’_ÂXÜnªÙ$Ë_.'¿þ$@‚‚‚T×î––U>Àí¨¨(žE£ÄÈ éçÎ}JHÏÏ¿)]]R^žI~¹SD_rK~ q{µèª÷KÎíòë/‰æ¶’ÄŸwî;ùþû‡ûÌeÏåȸn999'ííí ꜫƽ=s@¼—¾oß§„ô’’,1›C¤¨è*ùe¬,A~É-ù% ÄmL{ŒdTf_# ìØ·¶¶;^ Ÿþ¹WóPºá6z•¸jÜÛóÑâœ8Q&3ftËõëŸÒWJ]Ý:òË"‚ü’[òKˆÛƒ•%¦#†üY€`á OG}}ý@#ÂÚÚZ%FZD»K€L˜0A½Ýpç\5îíù˜âí„ô:u»¸8GÌæ`õ›ÜA„A¢~4IDg„ýé(ù0ªA®‡­F„^ Öî7nÜ8—{s>¼Á:,->>^¹Þtõ‹ßž8®®®öè|Þ>¾u«RBBÌ’—÷X77oQžòk¼ã¦¦&òA~ yŒïòA~x¬Ã^Ï¡ºC2ÿÍ|òë¢c¯”áE¸UPPÐ@#©S§J[[›KóIèaˆï$¤?“ÄÄO éÈA.rBÈ/ce òKnÉ/a nóòóTIÞ3¥gȯ= ®4wæ€àœ«Æ½=s@¼ž/sæ !½J£ªb‘_ÆÊä—Ü’_Â8ÜnÑþ/iZB~)@Æ&@†ž×«JÁ c¯êÔXÇ==s@|1!ýÁ@B:ú /úƒ‚ ‚0®^“`s°dßÎ&F .\Pý@,Ëî"$«¹¹yÔ}@¬õûpd|¨¡—†½¾ÎŒ{z>z@|Ë–5ɺuŸÒÑÒÉ/wŠòKnÉ/an×Õ­“Õ «É¯ÑÈõë×D¥)++1ŒÈU†¼Oš§çcˆoâÊ•b•~þü]ÉÏ¿)]]R^žI~+K_rK~ ƒp›Sœ#Á½Á’[”K~$@¾þúkÙ»w¯Jœ¶ ¨€5Ú> 4ã @ß)Ú¾ é­êvUÕ~éèˆÖn›È/wŠÈ/ù%·ä—0·+^®¿l$¿F –¢chçóÑvB§O€:>%¤¿—ýû«”ð€!7Aa dÝÍ’ž¹Qpƒ|E€ _Eww÷0Á„ê‘JÉÒèñ?þ)!ýÆB‚…P,„d‘_î‘_ò@nÉ/a n“_'ËŽ§;ȯQ’Í###¥µµU ¾¾>yöì™&áááT Ì ,]ú[B:’Ñ‘”N~+K~ɹ%¿„1¸=YvRÂ?„‹)ßD~ @jkkmvBGIY= ”ž•uW•ãEYÞ¸rÉ/¯]òK[òKn=ƒø·ñ²ïá>òk¢‹ËNè£)ÁKcˆ¿`Û¶g2oÞ§„t4&DƒBòBAÆÀáŠÃ2÷×S† 4z@ˆåæÍ|‰Šz/TIII–˜Í!RTt•ür§ˆüä–üàÖô£If¿Ÿ-GÊ_ s@ŒƒcÇÈÌ™è^ +¥®nùe¬,ù%È-ù% ÂížG{$Ñ …™âbÒÔÔ¤B®`H@ÿꫯTþÇ”)S~[Î--##cTÂGº¿³ãÞž_NHo–õëk¥¸8GÌæ`õ›ür§ˆüä–ü’[ßçöfþM™Ñ=CNß;M~}Y€DEEIMMºšš:HL$&&Žê¹l œœÕUIí@BB‚:gËFº¿³ãÞž9 ¾Ë—‹%8 é%ÊOy!‚ ƒätVo“E¯‘ _ èõÑÓÓ£nOš4I‰ˆGÉóçÏGÝ Ý–ÁâªN7ÜŽµù<#ÝßÙqoÏGˆÒ«eÞ¼7*¹ È !¿Ü)"¿¹%¿äÖ÷_çõÂël– w.__ –¢½?pÜÛÛ;¬1¡3"§¿¿à·í59éþÎŽ{{>æ€#!}öì÷’‘Q©ªa½ãN ùåµK~ rK~É­ç‘ö"M¾ýõ[òë«9 ðxÔ××+1qâDu^Œ¹B€X;±3šç±¼¿³ãÞœo°K‹Wž®~ñÛÇÕÕÕÏHÇ7o6ɬY=’—g³y¦46’_:Fþù ¿F<Æ÷ù ¿F<Öa„×{«ò–÷Kqe1ùuàØã;ï–yIIIê<^ :¤ÓâßÂ>–,i–´´ZÕ½Õ U5‚ "Nß?-3»gªþ ä×ú O‹q$L‡……IYY™tww{Üs2~üx¿ž9 ÆÇÑ£?ÉÌ™äþýã*+ß_dAAü¨:£ï}´—\øRÖëׯåÀ*D÷^ ½[ZZ„æß„;EŽcñb$¤¿PÉèHJ'¿Ü‰#¿¹%¿äÖ÷q¤üˆÌ~?[L£¡¦ă9 ð~TTTHhhè@O4#©©͸„±²£OHÏË»¬}V¤ àùe,2ù%È-ù%·ÀÜwsåðχɯ’Б’––¦:¤Óè!þ\%¤£1!’_îÄ‘_‚Ü’_rëûØ÷pŸÄ¿'¿þX‹Æ@HHŒì”cÇîˆÙ"EEWÉ AAø8Lù& ÿ.'ËN’_ ½½½ÊÃa­’zƒÐè!#3ó' ÿ uu«5¬#¿Ü‰#¿¹%¿äÖØñt‡$¿N&¿¾ @‚‚‚ K „Æb8-z%›7?³9XŠ‹sÈ/¯]òK[òKn}7 nH¨9T²îf‘_o  “ÉDE@1 \ºt[%¤?xð46®$¿¼vÉ/AnÉ/¹56þ²QV4® ¿Þ ôr0„¶ly. ¾R¹ %%Yä„ ‚ |¹E¹Ü,9v¢˜â‚žííín]lwtt¨®ëhøÅ_ÈáÇG| úØë,î츷ç£ÄÒ/]ÊRU±È/¯]òK[òKn}«Vɺr8éq³)--U}?ÚÚÚÜ&@Ö®]+7nT ï===²iÓ&¹|ù²ÍûçääH\\œF@BB‚:çªqoÏÇJH/—Y³ºäÝ»¹ÿùåµK~ rK~É­#ûN¶›ƒåZá5òë-b­ú•««`Áóá¡n'&&Ú¼?óPºá¶e3Dgǽ== þ…””WòÝwwU‡tòËk—üä–ü’[ßÇÒæ¥²Å~^ô€¸1 Ý\•2T€À2a›÷ÇXÿÀ1n[ÞßÙqoÏÇÿLH¯­]$åå™ä„ ‚ |gJÏHXO˜äåç‘ý´áš5kTØDˆ‚eOÜÀûb/YÞÙqo·7X‡¥ÅÇÇ+×›®~ñÛÇÕÕÕÏ_wïn”U«^Jggœvl"¿8njj"ä×Çø^ ä׈Ç:üåï™ÿf¾ª;D~µc¿ HBOMMUž4=ÌÊÊ’‰'Ò¿A^^¾DDtJQÑwRUµŸüòÚ%¿¹%¿äÖÇqô§£Ù)¦MÌñ†©¨¨)S¦¨]{·qÎ]–››«ÓG““s®÷ö|ÌñOüðC¹DF¾“öö9’Ÿ“üòÚ%¿¹%¿äÖÇÓ#+2ÄÓäÞ½{6“Ð]%B¶nݪªlÁ3PRR"Ó§O—††›!LzU)<Æ^Õ©±Ž{z>怒“_É‘#WäÉ“]äƒ ‚ |ªHl{,s@<-@àíX°`´¶¶œÃmT©BWy<z…¬¤¤$©©©1½4ìõÕpfÜÓóÑ8Èξ-!!ÝšÀž/74‡¼ðÚ%¿¹%¿äÖG𫈮9öà= žî„ŽªTC­¯¯O O˜§æñÖ|Ì ,lÞ\#«VUIcã ´úÔDÈ!òÂk—üä–ü’[Å®'»dAËæ€xZ€X–ȵ,•ë u5z@ü;!}Ë–:IIé’àà~™7¯KΣ'„×.ù%È-ù%·>ù» O•ä=WzŽO    Õ4¯¥¥Eåh¸¥Â³hþ-@×#+ë¶ö~öKeå§÷öéS¼¿½rê¹!‚ _Ä–š-²¬is@<%@hn+ ýÉ“'T ô€£@QÑUIIy; >tƒIHx£ÆÉ¯]òKnÉù%·¾…«ÚÿçàÞ`¹tû= ž*à ¡oB®Ü¦ø`16„†~´úžOú‘üðÚ%¿¹%¿äÖG±¦n¬®_ÍiDH£$×9Ìòð¡YæÌé ?¼vÉ/AnÉ/¹õQäÜÎQ^«^ŠV89 „ëpèP…DD˜åçŸ?U—{ô¨[BCû4Ò¢g‘#‚ ‚ðQ,¹\6Õlbˆ;ò;>ûì³Û¶ ß‡F1zóN…]EFvJFF•†{Þ!'Nä“#^»ä—Üä—Üú Îß=/¡=¡ª2= . (¿«ß¶ý>4怮á÷òåkÝ,6|X³eÓÂýtÃmœsÕ¸·çcãe!gåÍ›¹²xq&ZßJNÎmòÆk—ü’[‚ü’[/áW³;gKæO™Ìq¥±WýJÇH‹hGíõë×4ð¼¸ÝÚÚj÷µ 5Ë„xgǽ9Þ`–¯.<]ýâ·'Ž«««=:_ ;ÂoiéYéé™)™™eÆŒ^ùá‡ròçÀ1rËÈù5â1¾Èù5ⱎ@ù{÷<Þ#ÉÉÁ¯Çˆ^éJ/·;H¦>{ö¬KHRR’ò€Xæ€$&&ÒÂâ(-=§‰0¹r%[ºeÆb2‘‚ ‚ðnæß”Ý3ä̽3Ìqu–'JíZ›ÃÞ¼Ör*pÎUãÞž9 Œ—µ†»w?‰ÒRôV…+WŠÉ#¯]òKn òKn½„ôêtYܼ˜9 F¬‚…ŠWÈû°Ì±¬‚54„I¯*ÕÖÖf·êÔXÇ==s@/ë¸9/ÝÝaòðá^å7䨱ä’×.ù%·ù%·^ÀµÂkl–ì;ÙÌq¥)((µk×;Ÿ––&·nÝr‰ihhP!W¨|à6ÎÙË¡@/ {}5œ÷ô|ô€p·h4()ÉÒDÈ yüø;•Ö#›7×0$‹×.ù%·ù%·^ÀúÚõ’ÚJˆ+È—_~©*^Y«‚5iÒ$xHì•äõ‡ù˜BŒU„ 4z@¸[4rQ!35²SõA¯™3?ÈÉ“eä–×.ù%·ù%·ž\ 7®”/6Òâ*‚!k%q[ZZäóÏ?§RðsÂXYßæ÷Î òáÃLyút§:F×ôÐP³lÛVMnyí’_rK_rë!d•dIˆ9D®\gˆ+¾ðtÔ××$‰×ÖÖ*ÏÈHݼiô€îç÷ÎlM„„˳g;Ôqvö‰Žî””×ríZ¹%È/¹%È/¹õ’_%ËögÛéq…A®‡­F„T Ì!|ŸDÈ,M„lSÇyyù’šÚ áá]rúô=rDAnÆ©û§d懙ª?s@\`·Bwr½JÕÔ©SUIY= „ïð{ûö%éê —êê­çö﯒³ìÜù„Üä—Üä—ܺ m ²÷á^z@¸”§aæ€0^ÖU¸uë²¼?[›gps$ä‚,]Ú,sæ¼W9"ä– ¿ä–üäÖu@9Þ”W)ÌqÆ;aí6ú|ñÅn ‘‘‘V›ê†Å>çÞÊ•¾©¬¯4<¿^-ÃÛ××'_ýµò||õÕWÒÛÛëRñ?rùòå#ÞÆs2^vl(*Ê•wïæJ}ýZ«ãÛ¶UKh¨Yª ·ù%·ä— ·N"µ!UÖ[‰>`ˆò"=z4âý¬åTàœ«Æ½=s@/ë^rU::¢5²ÚêøÉ“e2sæY»¶NnÞÌ'·ù%·ä— ·cÄÅ;%Ø,× ¯1Ä­¢¢ÂfböÐ&½ªT[[›ÝªSc÷ô|Ì!¼#Bb¤¡a•ÕñÜÜ"™?ÿö™|«]«·ÉAAŒ‹›Kzu:s@Fcˆó ÁBèèS¦Lq©Á¢‰íŽæ` L¯½¾ÎŒ{z>z@¸[ärMÄ1ò믩ڱiظÉô£lÙR#¡¡=òÃåä– ¿ä–üäv 8sïŒÌèž¡úƒÐâ EEEIMMºšš:( =11Ñ#ÞTßò¤yz>æ€0^Ö[(,„‰ÓDÈJ«"8vì„…uˆ /”(!·ù%·ä— ·£CRk’ìy¼‡9 Ž’¥{zzÔmT½‚ð@žÆóçÏåóÏ?š îfø?¿!o߯Ic£mrùò-ILlU¸r¥˜Üä—Ü’_‚ÜŽ™å™2»s¶˜lüŸ¥ÄNøJÇâX¯~åŽ> 4æ€Þ!×5//_®°)Bàý€ÞxEÈAA8޹såPÅ!æ€8bÈY€Ç£¾¾^‰‰'ªóðŠ`ŒFáüÞ¶¶M„,·)B䃄…õÈæÍ5>’Åk—ü’[‚ü’[_Âþªýû6–GZæ}$%%©óˆC‹ŒŒ¤R`áGü\×DH¢45-³+BP+.î­ª”…ŠYä–×.AnÉ/AníÔo’ð®p9^vœ9 Ž˜Þ|pòäÉç¦Nª*dÑè!ü‹ß‚‚ÒÚ ²Dòóm‹ôA¯ô AïrËk— ·ä—Ü’ûØõt—,lYH„ †‹æ€¾'Bnjd¡‚#"$+«D¢¢ÞÉ’%ÍrãF!9ôÄÇwIeåàïªÇ?ÊìÙ]ä‡ b¸tû’›ƒåZÑ5æ€X3Wz9lÙúõëGôxXóPºávll¬Ëƽ== Ü-ò]’¢¼!ðŠŒ˜h—W +V¼”ÈÈN9w®”ܨzÒoõûjêÔ~rÄk—üäv”XÖ´L¶Ôl¡Äš! »öî447¼pá‚Ê5?~¼ú#;::lÞaZð”è†Û8çªqoÏÇÆËú²A>òBâÈcöìy¤B²ð›Üh2yæÌ=IO¯Vý^¦Më“èèþa§OEÂÂúå»ïËäŽ×.ù%·„ƒ8WzNÂzÂTe,æ€ ±ÒÒR UaQî2ä—lܸQ%¼£Ãú¦M›dÕªUvïoÏSãì¸7çìÃÒâããÕ…§«_üöÄquuµGç ´c#ò ÒÖ¶Bºº–Iyù=‡ýúcmñj–5kÞ¨Eª'^/úñzݱÉôHåî,_Þ¦‰ŠÕ-©©¿Ê‰¿È£Gurþ|Ì+"âcΜ~Ù¶­YV¬èÒ„f¯¬^]/7o>"ŸNã{|_#ë Ž/j_$'[Nú<¿ Öª_¹º ¼–•·à ¡„9 „¯zBLªGz…8ê A.ÈÒ¥ÍÚ‚õ½Ê!ÞGNN±ìÝûP/eæÌn™1£[–-kRÞ*t»·ö˜“'«eÁ‚>ù摘˜^9|ø·bÙÙ·eýúZMˆôHbb«8P©‰š|rMaÇ“ˆ®1ýhbÈÐ$t[pU~’²‡ { tk98çªqoÏÇÆËE„ [:º¦£{º£Ã;B²P-‹Üz¸ôãÕ"9x°R•KFnNp°Y’“_iïÉÓQ‹B{ü¢$ó¾}µï¹·JÔlÚô‹\¾\Ì÷€×.ù%·„Ä´ÇHFes@æ€0^Ö¸€Y¦]Û!×~ú„ _ÂX¬’[÷án™™å²n]­j‰<ŽyóÞHzúsõ ÏÃÝüž=[ª}Ÿý*Ó§÷Ê¢E¯äØ1.Pxí’_rKXâ`åA‰éˆaˆ7ìÈ‘#òÅ_¨Ð«ÔÔÔAIèÖr(ÐKÃ^_ gÆ=== Ü-2ºyùr¹&B¤°ÐqO:¦£s:Æè¤Nn]S©êäÉ2Ù´©FÚä›oú”bÆÚÂÿKÅÞhù½v­PvìxªšΞݩnã¿xí’_rðE?´ÿ£rô§£ô€XÚ‚ TH”·:¡ÛËñ‡ù˜Bø‡Y!o߯k"äú¨»m[µ„†šU“;ò8úJUð0€Ã ZdÚ´^™3ç¬][/‡ÿ,ׯûæ^xCàwäÌ™R¾ŸA4v?Þ-óßÌgˆnÉÉÉbc¨ñD@5z@¸[dDÒØ¸R!qš]c%ìÚÏœùA[8ש]|rk/Þ‘Ý»ŸÈâÅÍJ¸ÍšÕ%ß~Û¨rjrsoêÚE^òC'ûV¾ÿþ¡ÛBòø½@_rëËÈËÏS%yÏüÿöÎÅ»¦koÿïŸft0t0:ÞŽvðÃqI¥A‘ª¼”z)¥œF)‡j´JêRêDÝz¼÷ AI‚D·"ßßz¦®œmgggïdß÷çÉxFö^kíµV¾{f®ùÌïe–mÃ"(dèôéÓ é‚£fΜi»wïF)d¸!žûF+BnÝškE/Böî=âÖ›Ð@´« LÙhÛ_~9æº?ùä¶åæ>³œœV›5«Þ­»¡ªS™ÐvU)KÉñS¦Üw´TI+ayô ûbÛTæ5_جúYä€çC¾V)Yål< ûv!ó<2ÑŽÙå@Ô뀿¸j£FµÚ÷ßWd¥m•¡p´O?­sù Súè£[±¢Ê~úéTÆ·]UãÒZ"ªÐ¥°²ï¿?׫dyúˆ}±mÚôÿ¥ûmÄó¶ûøn< þJèÊ(--íX 0Q9 r@`ú±®n¾55I„ìëAŽÀï–“Óâ’§3}ðù믿Ù?œµÅ‹kmâÄG®R•ÖÐûñÇ3Y7ø¬à%/ÏøñM®bÚ²e5 1ƒÂdð³ŸÙ§uŸ’ràÀïÁ¸Ø½ÖŠè9 ï¼óJľ]òæÍO=2¡G"dÏž£n .* )Sl«p£-[Î8¡¿M‚#?ÿ‘×Ï^wBD‚„¶œ#tÆ-(o~ë=ýľØ6Yr¬ÄF¼a{ì¥ –¶¶6{÷Ýwçãí·ßv r@ ö /BÚãÇã=²·GUžä‘7D^‘tµíާlùò*J¥Aô¸qO\˜‘B­Òµm2ì«*+ÿ#>¼Û¶­ÛÒv{DåÉ"ˆ<#òÈS‚mi»Û&ŠŸÜýÄV¼\ážkE­EIñ‚$L€ø•®ür»ÁÔLþöíÛ d¶a6û&ƒ—/e--£íäÉŸ{$B&OnqaWò|üôÓlJÛAÒúÿ¹Üåˆ(WD9#ÊÁ¶´]ˆmãíý×ãŽ÷#èw2¼ ÁŠG©]>Âä‰UžyÏ!;±L)îÞ}ÜUÍRõ¬É“ïÛºu•®ª¶ÆÓûá#^¬¨‚ð€0[Å?þøGE¶¥íÆ›ZsíÚ‹VPðÐÞ{¯Å–.½æÖÁ¶´]l cÁ=Çö¸Äó®~´ÈØ7¼tiµ'BrìÔ©Ÿ°-m7e¹}{™[a]IëZ_F+¯c[Ú.¶…™b_„Ù f‹²P„|m­­!;°-m7¥¹©­XqÅÆŽ}â±Ù½Ö6lKÛŶ0í‹A€@˜•¼xñ•)+Û=`ZP^yCä‘wdÛ¶2ì!LK"@ Ìf0›‘µ¼paí_"d;¶¥í¦O÷žc.?Dy"ùùíë¯/ºülKÛŶ@€ω}ÓB„|ã‰QvúôvlKÛM+ªRÖ·ßVÚ”)÷]-UÒÚ½ûDÇ~¿„ôˆf……/Y¿†¶‹m!9 ‰BaaaȕȃQ\\veñÞîOöõð€0›Éu‰­Ø–¶›–Ô"ZKDkŠhm‘%K®±ˆ&mÛB< ÉÀÁƒ-??¿[RRRböèÑ#G‰m‹Õþd_»geå·žigÎlÅ0m©UÕµºúðá/íüùן!ZL;Aɉž>}êuÀÃíöíÛÝ  æ¥}资K¬ö'ûzx@˜Í€‘ñüy_„üˆmi»iM%ª‡Â°a†}h»Øâ‰V­ZeÛ·ow¯» ýû÷·öööŽ÷z­m±ÚŸìë‘B<'ŒF„|gÏŸòDÈlKÛM[N˜Ðd§N5wò€Œ÷Òöî=‚h»Ø’kÔÔÔx÷Ý Pûûöí³ýɼž¾`Ÿ˜4i’kx¾úÕïD¼¯®®Nèõ²í=öÍûššmÖÖöž7`+éØ÷îUìÇ÷õõõØ#†ï÷ì¹kyyÏíøñ¦ñ1vìK›6íù¾þú¡±GæÙ7#ˆÄG]]]Ä„0˜çÎmpžòòZEÅFï¿fóŽ`˜.T,yB† y鉧V\|ÁmW¥¬9sîxBä¹-]zÕ(Å^B< ½…G(F““¡m±ÚŸìë‘B<'ì+*6Ø‹#¬­íoÞïoìåË‘ˆÚnÆØV•³>þø®õÜŠŠjvÕÚúUÐÓn»öc'Ún&ÙvÛ¶2û裷ÂúŠW®®i»Øû"@¢D¿~ý2úzä€@;ˆ<ííe³QöâÅTknc7n,ð:ðMvøð¿±ÌnÝzÆ>üðžýÌV­ºlÿþ7BBˆi,@˜ÍÀ¾é*B̾ó˜cÕÕ*Ï{È-XxíÚçÖÔ4Á$ÃíÏ?gÚ¥K_ÛÑ£{±m7#l»eK¹Mž|ßrsŸÚêÕ—ìÐ!„mÛb_HCB<'öMW¢°«Wâ£óþcÇöØüæ{bäoöèQ]½úw++Û†ýh»ioÛM›~·I“Z^^³­]{Ñ"Ø”¶‹m±/àØ7î<þDDÇ>ü««žUW÷©=}šk--ïÙ­[s½Ï¯·ß~;ˆ-i»ikÛ+,?ÿ‘ûÄŠ‹+"´]l‹} €S‘§NýdÕÕEöàA¡«¨ÕØø¡]¹²ÒŽÿöiÉõëϹõEÆìÖÁ&BÀÂlLQÛ9²ß.\øÆêë?¶çÏGÚ“'Xmí"·Ø¡òJ°/í,lûí·•öÁOlâÄ&Û°áö…Øû"@9 ÄsÂÔ¶í!Oxlväñãqž á„É… k³²Ä/m7=m«0¬o¾¹`cÇ6[~þCûᇳØb[ì‹x@˜Í€é`[…d)4«±qš ÕRÈVMÍ2Â…}aªÛVBdÍš‹–—÷Ô ØæÍ¿c_ˆm±/B„éB%«+iýÖ­ÿµ––Ñ.™½®n¾KnW’;6‚©J•êýÇ?þ°ÜÜg6eÊ=Û²å vf‡)//·ÂÂB·à€láÂ…ÖØØö3ÅÅÅaWïíþd_³0}m«r¾*ë«ò¾*ó«r¿*û«ò¿Ø¦¢mµxáÊ•—ݪêÓ¦5ÚÖ­§±/ĶØ7³È´iÓ¼v™µµµY{{»×ñmµqãÆuy|II‰x÷GŽ/Ú«ýɾ9 ÄsÂ̱­:Ô‚‡ZøP j!D-ˆxæÌiÈNÛÍLÛþúëo¶bE•åä´ÚôéÚŽeØb[ì›=!Xò†t æ¥}èu~~~Ìö'ûzx@˜Í€™iÛÇÿíÝ×&»qc57±ÖÖQvçÎ'VY¹ÎJK`_˜2¶=xð7[¶¬ÚFjµ™3ïÚΧ°/Ķx@2W€È²}ûv›1cF—Çôïßßøm‹Õþd_³ƒ'N첪ªåvÿþT—È~ÿþ÷^Û±LèÓ§ãÛo¿muuua Fß¾}c¶?™×Óì3“&Mr®7_ýêw"ÞWWW'ôzÙöûÆï}}}}ZÝomíe»víGçyþü=ìÏ?ÿî<&åØ7‹Þ«_Hµû»|ù†­XqÇFŒxn Þó¶Õa_Þ»÷[·^µ1c^Ø©SÍn¼rùr»'B^ÚæÍ×±OŒßûLÆõ³Â²yófOIOÀBñœ0Km{ÈΜÙêrE”3¢Üå(—D9%Ø—¶›,îÛwÄ/®uBdÞ¼[VRrûf9åù8~¼éµ1Ë•+æmŽ}ÈI?„óH„ʩжXíOöõÈ!žbÛ@ªz–ªh©š–ªj©º–ªl©Úö¥í&ƒ{÷µÏ>»á ‘öé§7í—_Žaß,¤ª§ýíom!Ç1Æ™[o;‘’²(**²Û·o»×ÍÍÍ®Lmà=8„ɯ*õàÁƒ°U§zº?Ñ×#By"û¯n}‘ººOÝz#--ïÙ­[sÝ:$ZÁDRÂCDBdáÂN˜`—ÌæŽ§lùò*W®ùo{aÇ¿ôúëä™8Ñœ§LE ´ÖÌ¿þuû‘’Z(--µÜÜ\7ðë­·lñâÅn°.‡B"%ܺ½ÙŸèëáa6bÛžR+¯WW¹•Ø•ÈÞØø¡[¡]+µc_Ún¢XRrÌ…diÀ©-…jaßÌ „ÃêÕ—lÖ¬zWžùý÷ŸÙ'ŸÜ¶o¾¹à§ÐÇŽm³ÊÊÿˆoÈb?ýtÇ}VâC"Dmc̘fO°ÖÙúõç\ì‹$mKòfÂõÈ!žbÛXðÈ‘ýváÂ7V_ÿ±=>Òž<ùÀjkYyù?-ÖkŽÐvi»¡¸{÷q78Õ`sÉ’k¶)öM3J<®[Wée^^³)/ÆŸ¶jÕeûùç]VÁš<¹Å…]¼´mÛê:£p¬­[ϸªj……\è–~ÿýïWÝvµÈ)< Ìf@lÛÛDöòòÍN€<~<Î$#œ0¹pa­'Töa_Ún\¹k× W¶WƒW 8Si¶›¶û:µøäÆgmÑ¢Z›8±É ƒ©SïYQQµ'$NG% ¢±­Ú„sƒÈC‡cß^ðÀ ÐÏ»’ÈãÆ=±áÃ_Øôé ¶bÅ—i¶ÍÖp-< €aÆóðá{¼MvãÆknã ’÷½Þh¤ÇÓõLç!°WܼùwZ“—÷ÔÖ¬¹H%¤)ÏÑ?ÿù»-YrÝ Ú°am6yò«%‰»D ºÔÉi!\ ð€@ì‹m3Šªœ¥°+³5A½Õwn{SÓD»wïCç9¹}{®'ZÚµkK­ªj¹]º´Ú*+¿õ¾“ìôé­vòäÏvôè/ç›Ðv3Ÿ?üpÖ ¤5“­õ%â9hLGûÊÛ·—Ù—_VÛ‡Þsƒìñã›Üjô7V¤Lr*Ø6“õð€r@ öŶYÇŠŠÎãÑÞ^æú¥¶¶ß=·+WV¸µFÎ[o/®µË—WZMM‘ÕÖ.¶ººyV_?Û>r•·?ï’ÞU¸½}ˆw¾!ÖÚ:ÒÛ–ç½îߟìrPîÜ™íV{¿~ýs·ÐâåË«Ü'çÎmð®µÅUï:v¬ÄJKdœoܸ”µmìûï+\)Ø>xbß~[™Õ}ÃîÝ':ÂŒFzî¼DsçÞ²uë´àúÝ, ×"$Æ(//·É“'» Ði%ôP(..»²xo÷'ûzx@˜é„Ø6•EÈË—ë<ñ1¢×áW¿ýö«'$~±“'wº<¿²²Ø%ÁWU}i×®-±›7ØíÛŸØŸþ'P¦Ú£G]HXkkŽwC=!3Øå«<{6Ú-¾øðá$WnøîÝY®ÒWmíg.É^BéâÅ5îžÿ}“>½ÝNœØmGŽìµÃ‡¥Œ}Iðµ°ÝøñÝ,¿ŠÙÐ7HT_p"ãý÷ŸÚÈ‘­6kÖ«™{-ðH¿K¸cƌރà´÷i÷(­¶råJ'HºBII‰x¡GŽ………n[¬ö'ûzä€@S]„¤Ò YâA!bº7‰+W¾òÄÇN„HŒÜ½û±')Z Q¢E⥽ýÿ91#Q#q#‘#±óçŸ3ìÎOœ’ª®þÒ‰#‰$ÙA¢IâI"Jå{k×WBj5¹5 ‹‹+]ÉX­S¡P£Lúû6µaC… £’ÐÒ`øÃ]˜•­èk×"$ÁéÛ·o—û5˜— ô¡×ùùù1ÛŸìëáa–bÛTg&®RZzÐ…u)¼Ka^ß»°/…UW/sá` »sgŽ54Ìpáb Sø˜ÂÈN&!£ð²gÏÞwáf ;klüÈ­B¯p4…¥ÕÔ|áó+®¦°µßßì½ÿ‡[ ²©éWüC‘µk/Z^^³MšôÐ-–—Ž}ƒÕ ®Ùvͺ+q\y/Ÿ~Í%ã'£$1ýBz…ká‰3Nž<ÖÒ¿'R‹¶Åj²¯Gy Ûbßô­¦RÆJ´W½ï•€¯DüªªvõêR— û¶¼13]â¾øåQjoÿ,èIðƒÛ^_?Ç%ôÿñÇ*'XäåQ¿Ê"g—9l«W_²Üܧnï-[ÊS¾íþôÓ)W ÷£\i\•ÈU©\ hU:7=£ÕÕ[¨®EHú «W¯ZNNŽ×áÖwyLŸ>}:m ô˜ôv2¯§/Øg &Mšäž¯~õ;ï«««z½l{}ã÷^}öÀ¾écÏÎãXâØ,Ç)Åvóf±=|¸Æ+ŸzœjÏžMôŽÍñËпò^ ­¹yž54|þW¸Ùw¾?þøÕŽÙŸqö*/¯ðÄG£½ÿ~««õË/—£ú¼úÝxÝŸùÛ¸±Ö-zl£G?÷øÌ÷lçÎO4VfAûýεÛ{÷ögÜÿkYÙ9'—,i°‰ŸÛÈ‘/œ§dýúÞ17r?>“ñ÷g´©¨¨°áÇ[MMMØãð€@!ÌÔwýúönø•÷¢ d.»’Ç7n|æ gÙƒ“].‹Âº^¾fOŸ¾ïm›ä¼.7o.t!e S¾Œ¼5½Í_Iýõ°}õÕ·Ê·< Û¶%>obÿþRûöÛó6þrfÌøÓV®¼b»vÌÊêx¾xÎOH6T×ÊjHii© <Øë@«º=6TN…¶Åj²¯Gy ÛbßìNðïN|D—ÛrÀ%Ê+ìâů­¦f™'B>uUÅ>,pù*Ê_Q|sóX—Û¢Òɵµ‹\ؘî•süø¿\ˆYê ‘ßìË/«,'§ÕþçþtaOñj»=›6µÅ‹¯»Äx…åL™rß¾ø¢&£½“ =~¼ÄÊÊv8‘ª0B_PIlå1© ƒÖü‘Ð}>¸4dø ÚÓ£Gù^›šâÊkKߺ5׉àë×—¸¶¨B—.­ñ®±Îå]IP—•msÂXÅ^•ÚNípÃD…k%3Ç&#ÈÎ;mРA^£®(ʯ*¥R½áªNõt¢¯GqôÛb_è3Y뀨’˜œþñÇjWºøÖ­ynà¨<•––÷ÜÚ-ÏŸ²Ç?pù+*¬¤Ö~Q¼ò^ŽÛ“”ã¿YQQ+_ûñÇw½±ÅÉ^·] ·m;mË–ÕxBãÕ€Z§dÑ¢Z·x¢ÄOê¶¥C®Ä´òªÖ¦5täõR9j婲›ÖÛQ‘U…{òd¬«'1új}ž·Mû´ŽŠ/è3Êc’hйÔVôZž¶gÏ~ëð€´·tÅ$$$(**68qéÒ×Þñ+ð¸vís¯­/p‚DEÔÎ$T=*på´µ^Š;¨:Ù`÷[mO‚YûSYØÄ£ºÖÅ‹[œ¨»pá{H¬ (†Ë¡ÐZáÖÕèÍþD_³ÈÛb_˜¶=äoðIˆ46~è*i(¡"Á"á¢Á«„Œ®6 Jèhp!RjK—^õ„Ès›3çŽýüó«zÄNšIDATYã-[ªmÚ´6o0¨È„ÞñrÈÏïÚuÂV­ºì¼)~hͼy·Üˆûö%~ÀH½*­ªl û¥¥õ[ùW‹|Nu!x¯ÖÆYìÂð^•”þÖWçW8…öõ´„ô‹ßÄ©zÛ¡¿ªÔýb'NìJ;aÓÛp-‰ööQ.s¡\\ï*n•”Ù:ÞˆWëÒüì¼Y‰öB¥ç"š‰6Z[¨¬l¥'>z"÷º ÞjÓ§ßôÚàqûõ×ížý^655ë½ß;mÆŒv'ž§LyéÝ濾‹¬ Ù< ÌtBl‹}±m¦S³û0kþÂ…µn¡GÍ6k¦^IóZcE9…ø47繜ÍJ+Ù¾ªêK·N‹ÖQQ2~W3÷Zañ„s¹'~°ººìôéo¼1 ½&žÇo÷Úáò¿„&d !Îûb[ˆ}±m²YZºß-©Yv…¿h1ǺºùÞ`º›YV9by ´ä“'ãìÞ½)ÎKpýúbç!5ª-ä³vèЗæ ífNu-… †Ï&4ãx@ öŶØbÛdÏ:kHÍ6kÁF-Ü(A!11cÆíƒ¸—VXxÇyU2ÑAÛMªÂÈ‘í]ˆçv B!LUnÛvÈ{Ž>öDÅË¿ÄÇsïýCÛ²åö)Íüü'vþüë"äÂ…ç6vìSÀ±/¶Å¾Û¦º™1㺠¦5n#>h»iÁï¾;oï¿ßjgδ¸ñ`yùcËÍmq €ˆ}±-ö…Ø6Å™ž•šh»ˆó6aB“ »R ßD‹„Ù f‹ ¶Å¾ØR©‰¶‹} €!„B˜™Ìø•Ð#EqqqØ•Å{»?Ù×ÃÂlĶØÛBì‹m!‘HPRRböèÑ#ÇÂÂB·-Vû“}=r@ˆ—…Øûb[ˆ}±-Lû"@1iÒ$çzóÕ¯~'â}uuuB¯—mï±oüÞ×××cì›–ïÕ/`웎ï}b̳/ñœÄsBl‹}±-ľØûâIvˆ¶Åj²¯GñœÛb_l ±/¶…ä€$Q€o÷«J=xð lÕ©žîOôõÈB!„ä€$iPë„&ZK#ܺ½ÙŸèëáa6b[ì ±-öŶH ¡_¿~}=r@ˆç„ØûBl‹}±-$ @˜ÍÀ¾Øb_l‹}!¶Å‚A€@!„Bˆx@ öŶØb[ì‹m!†òâ9‰çĶûb[ˆ}±-öE€< ûb[ì ±-öŶ@€@!„BˆA€0›ÁlĶØÛBì‹m±/±/¶Å¾Ûb_ˆmÉA€¤Š‹‹Y b_l‹}!¶Å¾ØâñGII‰Ø£G Ý6r@ „B!9 æøjõ¡×ùùùx@ öŶØb[ì‹m!{ôïßßÚÛÛ;Þëµ¶‘±/¶Å¾Ûb_l É1GŸ>}:mëÛ·o—ÂÃg ¦Nê(ÏÉØ±cÝïD¼Ÿ2eJB¯—mï±oüÞOŸ>{`ß´|¯~{`ßt|ï{dž} Yâ I„ÊÑ6 æð«`=xð â*X @@¡µ?¢Y$¹!B!„&’0DÛàöŶØ`[ì‹mAvÛèL°/¶ØÛì‹m±/y@€  @@bѧOŸ‚Ø¢¼¼Ü&Ožlýúõ³ØâÅ‹Ý1 vöÕZ;¾}.\h&Æéâ×ïÒÿÆW¯^µ©S§ZÿþýmРA¶wï^ŒǶ;pà@ Ô××ÛŒ3\»õúöíÛù ˆ-Ôyœ>}ÚÚÛÛ­µµÕV®\é ˆ ¦M›feeeÖÖÖæl¼uëV7n†‰!}º­^½cĨ?X²d‰½xñÂ…¾.]ºÔæÏŸaâ€ñãÇ»7444Ø!C:žizÞ%@€¤(***\(‹u >ÐlÑæÍ›_4ƒžCv sôñEss³½ùæ›"Pò®„‡ B3c³gϦÅì|:A…ä ÌI‡¨ @€¤ JKKmðàÁVUU…1rlb×P© ’ŽPÕ¶`"Qb §¸t醈óó+ži€I1ìܹӕ€ÄE(öØ/Q¨œ*±`ú‡”‡¥}“Â.fÏžM,}Œ t…]I„ˆ ÇR‰n;œ?Þ [¨â•ò>s@¨‚2z`Á,gâl‹}cy—T¶P6}ë­·Xg’–m÷Ýwßuù³ö wPèŠú…^Í›7$ôC^&•@±…&%üµÃD½N‡¼F@€€@€@– ]ådñP@€È¡€A€@z‹@ï+--µ &X¿~ý¬ÿþ6uêT»}ûv§ã~ûí7wœŽ <ÏùóçmòäÉn{ß¾}-//Ï:Ôé^vìØá>÷ÆoØÀ­¨¨Èššš^;fß¾}6dÈw/#FŒ°={ötºï††[¸p¡ 0À]OçZ°`UVVò… @ªˆ®¶KTܽ{×ÚÛÛ;D˜1c:WXXèŽ DEE…-÷ïß·¶¶6[ºt©;^â!›7oî63:FÇú8qâ„Û6}út'LD½¾ݛޗ——»÷---Nðèþ¤¸¹~ýzÇ6‰ßK|\]]]§shЯ}“/^¸mÇïö¾äÅðQPPÐé~®^½ÚéþuobMM _. @¤›én{¸ …@… ó 1(3gÎt‚CÛC…„)ì*’ûñ= ¢>£¯•+WZcc#_6d²ñEƒ<'áà‹†À°¬ž å€,Z´ÈÞ~ûíׄŒ„ @€  J>×¾“'O†½ßSâCá\Áç4+Ê99vì˜Û¯kH2þû¿ÿÛ Ð•$krñâEWýjÔ¨QvóæM·MÉãp‚‡¼:‡Ä‚rDfÍšÕé¼IèÍÍÍŽ3fÌètÜ´iÓìèÑ£î<‚ªpiÿøñãù² ÙPØ“JÕF*,¢ ‚’ÁçÎëò;tœÊä–Å•8Q–ò?l»ví y^•á:t¨ófHÔè}ðq:ïüùóÝßä—ôUH9  @@€ & @@€ €$G€ü×ý„B!„Æ•¯ ˆ›ç@€ € ‹Ñ§OŒHj¿B?H9rÿþ}›7ož½ùæ›Ö·o_+((°cÇŽÅ´cÓ1¢Î?pà@›?¾UUUŵsö õõõ6cÆ ëß¿¿£^ß¾}»Ëó•——ÛäÉ“­_¿~6`À[¼x±=xð âë…»¿PŸ µ_v‹………Î×ÔÔäl®ûë­·lýúõÝžçäÉ“–››ë>3tèPÛ³gOØûó¯ÙÕ¾®lÓm…ââb×>ŵk×Fõ]w÷ùt é4  ¡¡éùÿw¨ë¦ŠAØ€é14PçÙÒÒbííívñâE›5kVÌ>t]»vÙÛo¿×B¸{ÓCoãÆÖÖÖæ¸aÃËËËëò<<œ>}ÚÙ§µµÕV®\éh=팣í´=ÑCíàÁƒ–ŸŸßéü .´%K–Ø‹/Üý/]ºôµ‡}0.]ºdï¾û®={Ö½oll´åË—Çåïìζ%%%®>zôÈQƒm‹ôZ‘~>ÝH:>†>†>&¶m  5È A]³hÆ0lΜ9nOÇNŸ>½cö(’Ù§®:¿Ý»wÛìÙ³_Û¦ fÏ4S¥Ù´§OŸ¾¶Íš5n–N³X;vìèq§ûÆotÚ¦kF =ÈBÙ-^ƒƒ1cƸYäp­†îfYƒÏ¯¿M^zjpãCß÷z}ÿ=yèÛVv"èµ@‘^+ÒÏžGƒ‡Áƒ»ûР±¦¦æ5ÛuÌvêu mCïÇtƒa}‹-êô]tu> œïýüùó÷àÒp÷¬A¡®«ëë>6oÞÜ£ïÆÃy÷d6b„Ù”)fÇGö9úúú˜WáýóÔÕչײ·Îé·uÙUö ¼VWí¿»ÿùL&@¢Ùu”«W¯¶»wï†ÜŸ““c•••®ÓÖLžÐêDz:;8K©‡¼ï¾ûÎujšAÒu4›8#¶nÝ:70Ñ~udºž>œôðÓŒ¤þ&QáÚ):Íìd¨ð rÔIë¤{ w-= º»ÎªU«lûöí!÷d? öº‚¾“ŒÁA°muŸúŽ¡î½«kEúùÀóh`ªv¦cõÐ7n\Ç~ý¯¨677;j€«máΧcl»áÎwýúu÷ÿçß¿è~Oðƒ?Ü=ëz:¯º†Úz´ßÄÇøñæõ¯Þ_¹òê}$"„>†>†>æä}Ù»w¯{­Áºâþû}ûöÙŠ+BþGÛOej?È ¢Ù=|ÞyçŽYA¹ÃÃÍ>Ô{:8žäÝkàEƒ‡À˜d¹ëW ºº®f\‡ Ò1«¤×ÝÍþù¸zõªëŒCÝK¤ƒƒ@ܼyÓ zºÄŽ÷FyµµµaϧY¦ &t¹Á‚.$B?<"ܬtwßi¤ñ×Ñ>\BÙ6Ô9¢™ŽôóǤ‚gKõxz­AD¸ó¶k¯sDz>Å«oݺՅi€êïŠäžÕæÛ´ß<¾øð!RXhô1ô1ô1ö1eeeÎV‚ü”ûÂTÿÚ© ÷?Ÿ©ý Ù$ÒP«(C²43¡XíÀf&åbÖŒŽÿ /èéà@× dhpâ³'׉ô1uêT7#Ÿ.\ÀGEE…s‘wåêîigªÙ ¹½ƒ!·w$³¦ú¾|·~¨ûP‚¨’€eW=vîÜ6á4³“]Ù6pÛz"hÂßÝþÒÒR=zôk¡‘P"ÝI×áÙ:Áû׉:ê“>†>&›ûí“U›Ð÷áÿö·ûçéÉÿo´!ŠéÐRM€„-D³½Ïªb:ÊWƒŽ¶n;•H:Åg>øtàÊ$ˆåìd¨cwqêê€Û.©5Öƒ…®(Y3’¿3ÒŠ0‚\þJí r“'2>;œmCÅWk[¤×Šôó‘>$5¸ žIì­$Üùü„Vý¿†ÉDó`žyÔõé¡¡¡ùäùP(ÛÌ™3;ÞëÜ/’ ý ƒˆñ׊U¬Ö¢„MUôð–û8°ÓÐC­»Ð‚H*ÔlÚ´ÉuÀ~¥Y–À8p?>[÷ÐÛølý}ú;ã³ÃU¨Ñlž/Áa ‘^/x»þ.I¯¾ƒàl%úu•ÈIøB –-[æì¦¿UñÏš œÅ †$zXè„xV¨éζ~…Ýo*Ôt÷ùH¢~³tša×à!’+Ç^‡;Ÿþ/GÕq¬…íƒßóðïaîܹ Í¡¡¡y]«Íûù4ú­¶ª6êZ¡ÚOH&ôC€T =¬‚¥‡…:O…"Èm¬Ž'p&DûU£]û5ƒ¤Î<°ÓP\¨ÎÉì™:^ź† 1ÐAnh]Ke,:ôÚ~uˆêŒ»«PÓÝLŒ~]xQ¯Ã=,»›ý‹¤æ~ðlœþ>m׬«þ®àJJzˆùñÀ½h6Ò¿Whˆâ #iºG}úþ• ílh4ë7„;—*ER£¿«û÷ùhˆ¾' ”ü¶£Ww¡$ªöâW^òK•Fr>µK•Gõ¡€ÈÑ>øu Åpk^÷¡ûén6¾+"OȰa¯<‘VÁ¢¡¡±N3ÿþ ^¿ƒ=ݵÿžL釩$@ B¨‚á@?@€âÍ€+ìAÉÂÝ…ý WPX“â̼Р HôéÓ#R¢¡?$U€¨êŠñ¼^ß¾}màÀ6þ|«ªªŠ›ËËËmòäÉÖ¯_?0`€-^¼Ø}ú4ªkìÞ½ÛfÏžÕ9׬Yãfû4{µcÇŽˆÿF=p4#š¨Î{̘1vÿþý°Çèo>|¸› >ïo¼ÑéxÙ$Qç›3gŽ8p ×vèÉÃ.ø»ÒÝœz­O¤×ŠôóçÑ aðàÁî>4xª©©éدKQQQÇ,§^k[¸óýøãn,›/Z´èµãÃO¦À{?þ¼Íš5«ÓßÛÝ=¿xñÂ]W××}lÞ¼¹‘syÍNêáé9×­[gÓ§OwûÕi€)äâOÔ¬¤®¥N»»Ï­ZµÊ¶oßr¿Êš9ÔR\¿~½Û¯óCß‹lœŒAAðw¥0Ýsà AÛ"½V¤Ÿ<¤jg:VëqãÆuì_½zµk§ÍÍÍŽØj[¸óé˜ÀãÛn¸ó]¿~Ýrrr:î_r?œ%øîžu=WG]Cß}Ïø9úoýë÷iúúúšô5ò¾ìÝ»×½Ö`]qÿý¾}ûlÅŠ!ÿÏ£í¯2»?$U€Èë1ÌûùÝûÑïh½ = 4ÈîÞ½ûÚ>\rWKàìSwç”›^ñÅÑâêÕ«®Ó õÙx Æoµµµa?§Ù  &t¹¿¡¡Á† Ò1ۥ׳œ±>_´g¤q×ÑÚ7ÔwêÑÌ0GúùÀãgƒgIßyç×îO¯5xw¾Àv­ãuŽHϧ8õ­[·ºP" ŒCý]‘ܳÚ@`{ˆþ.Htœ‹Z„Ð×Ð×Ð×¼BYY™-X°À½Ö€_ƒr_¨ið®ý‘ pÿû™Û*@…øYàýøž½ÔÅO,z-÷©O½åzw>Í~ÎJvwΞtPΕݕK:Öƒ¹§ÃÍöùÐÜw¿‡:ïÔ©SÝ,b`u¨YÕx/³’]}WÉð€t×ö£4áŽïnii©=úµH&Ñþ[PoÓ™_3»‹ãèkèkèkÂõ5Ú'q&)ÔÉÿío÷ÏÓ“ÿãp¶HßþT ßûá{=‚ß÷´ãÖÃ8°#ÕÒ‡§¿¬Øe –5hˆ$DÇŠÁ1×áÎWYYi£FzíÿRqØÑ>ðýðÿæÎ›29 ô5ô5ÙÚ×h¯B~>~«­ªÍ†º–<$Áál= ™Ó’"@x?ƒÂühO;n¹¦õÐÐì¤f‹Ô!§‡¸\Å:F¥:Ѭ™:\ 2B…*twNu„ê„»«LÓÝ,]´kDr¼6~ÜnoùõêE½öÐÛó…‚_›_ß…jó+12RûF3(ˆä\ªXImþ®î#Üç£ ŠmÖÉ·å²e˺ !Q•¿â’žw>}O*³êC Œ£}àëŠÝÖL´îC÷nVº{»*Xô5ô5ÙÚ×ø3ÿþ ^¿ƒ=×Pî…2Ø’Yý ázU®Ñà»çx‚)Ò €”„fôîÐÔÔÔmØÐ€€^AñïŠ/WUžàÅÇ€þ€ @ 6B!„BãɉÀÿ<úÆE‘¿Ü¬IEND®B`‚Multiverse-multiverse-0.7.0/charts/boxing_overhead_total_line_narrow.png000066400000000000000000000726631174000617100270240ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔuzIDATxÚìylTgÛÞ?éSU}ªªþSUŸúGUUªªªªúG¥OUUUèš(J”>HÀ6ƒY¼ „v „CØ·@lŒYlŒf36fßmöÅ€ÁØ`ð†ïžûÉ;~ÇöŒÇö™õÌï¶.yΜ3sæ:Ï,×s?×s?'AA„_ãï¸AA,‚ ‚ AA‹ ‚ ‚@`DÐ?<÷wð÷ÿ÷òÿðòßþÛ“‘#Gʵk×Âîu\sÞ7À"ˆˆXñ/þÅ¿cÇŽñC‰À‚A °‚°óôË/¿´»ÿÿïÿÍ%ï 8‹ ;?@?~lwÿ¿ü—ÿ’‹Å{À"Ÿë_ý«åññW®\1>­ÿøÿ£a:œøþÃ0÷]ºt©Óñz¿ûó–••µí»páB»}zlw~(=í[¶l™yMúzþóþϲdɯîܹíŽ[¸p¡íæž\“ú§jwžû÷ï·íÓÛîûþçÿüŸÎuçÎIII‘ÿú_ÿ«ñÍé¹þñÿQ†*çÎëV›øðÁ<Ç¿ù7ÿ¦¶s]{óºvîÜéÑ ø?þÇÿôôt©ªªòzÍgÏžÝîuýüóÏ,‚@`Dø ¬ŽC„#FŒèôصkךÁ®ü[«V­j÷ý1Wó¼kÿàÁƒÛöém×ýzŒÛ5nÜ8¯E_¯{ 8ÐãqžßÝèé5Y±bE»}*2¼ m“Ž‚DQWçš9s¦Ï6w¿îúÚí^×Þ¾®¸¸¸.óïþÝ¿“‡vzÜW_}å÷v$E~XžðùçŸËëׯÛ=N³=Z/^¼êêjù?ÿçÿ´Û×1cqëÖ-“™pý k¦Fá&š-Ócº#=íëÛ·¯Ô××w‰î ½{÷vÚ§¯_Ñ1«ÔÝæÞ\½®šuñ$dݳ}zLmm­×lŸrÖ Oss³Œ5ªÝ¾œœœ.¯×ù/ÿÅãLÑÞ\W;¯K…’ N½f2þ|¯YMOíèºæŠÿõ¿þ‹ X¾ë_ÿëÝ6äâ-ûã>Ëð?þh·OíëׯoÛ¯CIîن͛7w;ÓæißéÓ§Û~ ÝïWQçŠO?ý´Ý¾‚‚‚¶}z»7?̽½&îûïÿý¿·Ý¯Ccž2}³}ŠÊÊʶ}y÷éÓ§ËëuäÈ‘n½7ºs]í¼®î¼Gu˜Ñ=:¶£û5×Û,‚@`DX,WhÖA3WÞ†¨Tt¹ïSÏ–+4[ÑQ yН¿þº-;ãRЉ‰éÑëô´Ïýµx{\W¯¿£èîso¯É¡C‡Ú ÑéШ¾÷¡ÆŽ"HýRÝǯëe÷ºÚy]êÇÓöwy×¼• éî5ïm;À"ˆ€ ,ÇwJr…û°–§®®~]¡†ïŽç÷dŒï©Àêξž¼þîþ0÷öš¨(ÐÌŒk_nn®kûßÿûïó\¾Ðnþ¸®Ý}]‡úºË%íH‹ *°º=ÉxÊ`éñ.Ì¿ý·ÿÖ˜õ¶úŸ‚!°‚ÁòuM&OžÜ¶oúôéòÃ?´mO:Õç¹ôùýÕæþ¼®Ý}]:ÛÐýq6lèÖë ƒE,‚ˆ8¥3¶¼‰»¬Ÿ~ú©ÝŒ2÷mX‡?Ý_°=Xj2wíëß¿¿ü¿ÿ÷ÿÚ¶;þ=këÖ­a!°zûº:μt…–{èêu|öÙgx°E‘#°ÔƒÕñÇË}WÇsšrÍÞÒ™\Þj]iœ={¶GgÒ)\3 zL –ûœBgùÙ}fçšh¸f/ªÿÈåAòVA¿ã¹tˆQEœ+;¨µ¸´„¾†` ¬Þ¾.õ]¹?NÛG3P…pÇ×Á,B‚@`DD,oÐ!œŽ…uÇWÍ§Žµ›Þ¾}+ÿé?ý§¶ý&LhÛ§·]÷ë®(¥¡†j×OêÍ5q…Ö“òUcª§ç²ãKêíuíÍëêX̽l…¯×ˆzfA °" K uHP§Ákµno^ÚÒúF*šÔ£¥Pq¤÷i¶¢c¸‹W ,W¸×ÂRháÉ@ , ­Üîzíú_ËQtœñ×q¶›¯èé5qŸî¦m½í.2»:—N@Ðã]í¦ÃŒ:ìêiÒ@ Vo_—f¶\Ç«±_ëîëÕŠüÛ±'\ ‚@`àØ½{w»eA,‚ ˆnÄÿý¿ÿW¶oßn*­kh–N·]3}â$‚@`AtüâðáR£yW(‚ AD‡Ð™|ºL.O£>+TêúË_þbêP¹û XAA‹ ‚ EAÀ"‚ ‚ XAA,‚ ‚ AAÀ"‚ ‚@`AA °ˆð‰Ÿ~ú©Ý¶VÝ3fŒ_ˆç gD_ÚÎð…3|ÿ†Ž¿«,–‰±cÇÊüáWèr(þ~ÎpF´ñ¥á _8Ã÷o@`AX/^Œªm´ñ¥á _8ÃE„@`ÑA‹^ œá gøÒÆ,>8ÃÎð…3,¿GŸ>}Úà)ÊËË%--Múõë'Ÿ|ò‰dddHMMM»c²²²dÀ€™™™>Ïéëx»ûC}>2Xôá _8×6&ƒÕ&´<Å”)S¤¬¬LZ[[¥±±QV­Ze—+òòò$99Yjkk RSSÍ}ÞÂ×ñv÷‡ú|x°–OÕ1ThõíÛ·m[Ň*VWèí¤¤$¯÷u¼Ýý¡>,zp†/œáK#°z,°JJJÚe°ú÷ïoD—»Óû¼…¯ãíîõùð`ác€3|á _ÚÕ#u÷î]‰‹‹“ªªª.çžáêÎyÜ·»?”çÓ7€ î¡•mõMçRöúßî¶¶?Ÿ/Ü·£¯nWTTÀ×áÛ.À×¹Ûú¾†¯ýmG ¬K—.ÉСC¥²²²G"2Xx°2X¢¸¸X $wîÜé–ÇIïë‰'Êýx»ûC}>8ÃÎð…s€g âÁ"È`Ñ „3|á _8ûyH  °9$ˆ‹ ƒE/Îð…3|áà¡d°Î×ñv÷û|x°DË,AŒ…÷vâ¬÷ÿ~î÷¨˜%ˆ‹ ƒEÏÎð…3|ý‚W7JLSŒ¬¿¶Þ#矞ü$K+–FÅ ,ÛX\¹X†7 —Ýçw{`W6JÚë4G âÁ"È`Ñó…3|á _ÿ™ÙÊ´ªiÆs•w&¯KÎG‹Ê7-ߘÿN/J‹ÀƒÅ¸>œá gøöÎÌ~ê$½I’)/¦HÁ‰‚nqÖ –f²œ>KA‹^œá gøöûJ÷Iü‡xɸŸ!Eu›ó’Š%Æ‹åô!A2X,=¦+›$¶)V2¯göø±:‹PgFëZ‚,‚ =_8ÃÎðí×'»Êwùœá gøúıãÇäÇg?ʘ·cäÀ™ÝzŒSžÂºóé¹´1‹ ƒEÏÎð…sôò=|갤ԤȤ—“<ÎìÀêª\mŒÀ"ð`€£¡ž©ø÷ñ2ÿÁün™Ù»+°¼•k,‚ =_8ÃÎŽæ»ùòfcf_{cmwüØ1¹–™é3ƒÕ±\mŒÀ"ð`áÝ€3|áìh¾Ëï,—¸Æ8ÙQ¾£Û9uð Ü[´Hââ¤&5µKå^®6F`d°èù¾pv4_5³Ïx:Cß%JîÙÜn=æüîÝRõÃÒ}ú´Á[deeÉ€ 25ýÙÃýþ~¾p?,ˆ9yDÒjÒ$½:] Š»®Mu¼°P®¯]+µãǡøx©X²DN9Ò£ó©ÀR¡Åµ’ –7•——'ÉÉÉR[[kššjîëî~?_¸Ÿ =}8ÃΑÃ7û\¶$¼O9çtif?m}ïß_°@ccåuZš\ùõWù£¨¨WœuˆPëjÑÆQ.°T\ès…ÞNJJêö~?_¸Ÿ^8ÃΑÁw륭ÆÌþËÍ_¼S¾s§<Ÿ:Õ >™9SÎýþ»mÎjrwj¹œá çðç»âö ‰mŒ•í¶wÚw¢°ÐT[¯³¾»ß'$Èeˤ8?ßoœµLƒSË5ÁêÀòtß¾}»½ßßÏÎçÓ7€ î‘’’bT½ë§ÿÙf›m¶Ùþvù¥rYR·DÆ~+ûÏîo·ÿÌò|éRi>\ê¾ûN.oÚ$/\Èë™ôv’ÉdÑ>ÝÛ&ƒE‹ =}8ÃÎaÊWÍìß¾þV&¾š(ùÅËH]ؾ]^X‚ªyØ0y¯Ýç ·ó‘Á¢§gøÂ9¼ùn»¸Mbcdõ­Õr67WΛ'M11Rž.—¶léÖlÀ@pvb¹2X^ê`y«‡¥µŸºªÕÕ~?_¸:X¾Xuk•WG³—ÊËI“¤iØ0y4w®œÍÉ }m'—k@`!úõëçèó‘Á¢§gøÂ9üøê0`ÆÝ™²õ@¬ÔIw£GË­•+åD†{ËÙ‰åÈ`/°ðnÀ¾p†¯gøMޝ—úáƒåù”t¹¸m[Xrvb¹œá çHã[Tdª«¿š0AcbäAF†œÎ; sÍ5 6g—dG$g'•kÀƒEÁ¢WgøÂ9BøžÌÏ—ŠeËäýÈ‘R7nœY'P× ÔjìéÕéÆÇ¤UÚ#•³“Ê5Á"ð`@˜ãÜï¿Ë“™3¥yèPy>uª”ïÚÕ¶/÷l®$¾K4âäØñcÍÓ‰åX,zúp†/œÃ‰oQ‘\Ù¸Q^§¥Ic\œÜ_¸PN<Øî˜å;$®1N–ßYîÎN*×@‹ÀƒÅ¸>œá ç0â{òÈ©\ºT>ÄÇKíøñr}Ý:9~¬sfjÍ5Û+[.oqT;¥\,‚ ½"8ÃÎA€ 躿tï^yúãf°jÚ49¿{·Çç)ú£Hæ=˜'ñïã#ÊÞÝ6vJ¹2X,–ÀòÖý5©©Ò'÷-’S†;¡Mz9IRjRäð©Ã޼NN+×€À"È`ÑÓ‡3|á"umýzÀî8pæ€$¾M”Ÿþ‘föž´±Ê5Á"ð`1®gøÂ9ÄË×cw•ï2föeË¢¢P®A‹^œá ç0X뮯3föM—7EM;¡\,'î±ÀR3{Æý ‰ÿ/ûJ÷EÕõrR¹A‹ž>œá ç lï^ù0r¤ÏY„î(8Q “_L–ä7ÉrèÔ¡¨lãH/×@‹ÀƒÅ¸>œá çázf¦4ÅÄÈ5ëwùæÉ“±oÇÊ´gÓ¤ðxaÔ¶q¤—kÀƒEÁ¢WgøÂÙÏ8^T$çÎ5™«Òß~ë6ßÝçwËð†á²¸rqÔ·q¤—k ƒEàÁ?û­^û­¼ž0ÁÜîîãÖ_[/1M1ލbî/8¡\‹ ƒEOÎð…³ŸüVçÍ3Y,oÇåÞÉm·½àÞ#&~+ý6vH¹2X=ˆºº:™5k–ôë×O>ûì3Ù´iS§c²²²dÀ€™™™>ŸÓ×ñv÷‡ú|x°ðªÀ¾ÑÂٛߪ#rJrd õwèÂ!9zâ¨L}1U’j“äÐéC´±ƒÊ5àÁêAÌ;W.\(ÍÍÍÒØØ(‹-’ƒ¶íÏËË“ääd©­­5HMM5÷y _ÇÛÝêó‘Á¢§gøFg_~«ŽPóº ¬Œ÷2®nœ|_õ½ž(¤V® VB3W*¬\¡·ÓÒÒÚ¶U|èu…ÞNJJòú|¾Ž·»?ÔçÃÀoÕ9{5¤uˆ\°þ¾¶þ–>]Êutx¹V/–f²ú÷ïß¶­·[[[Û¶õ¶ûþŽáëx»ûC}>2Xôôá _'sî®ßªcöêç–ŸÍ÷á*ëoaýBÚØ¡åÈ`õ æÌ™c†Ud¹†ûöíÛ¶¿OŸ>㾿cø:ÞîþPžOß.¸GJJŠ—v½ñô¿Ýí7oÞøõùÂ};ÚøêvUU|¾Ýñ¸¿^õ[5ÇÆÊËœœn?¾èF‘ ¶þžYú_³XÅwŠ£¢½õ}Ý›ÇÞ,4¢…¯¯mÇšÜgΜi2Y_~ù¥dgg˧Ÿ~J‹ =}8Ã7J8÷Ôoå-šÑšÑî;1š²XvÚ8Ë5Á²‡6Æ÷®È5vh¹V7béÒ¥RSSc27%%%2tèPyüøq§YvzŒ§Yv‡Ø|ow°ÏG‹ž>œáëTνñ[)tvàw/¾“ÔšTÉ/Χ{ùØH,×@«‡+Ô! VæîÝ»ŽÑÚPÞêDyò0uu¼ÝýÁ>u°¨gø:‘swë[u„ *V*°:®)H;¿\u°‚< ÑÉç#ƒEOÎðug;~«¼Óy’ø6Qf=že†icûœ#­\,"â„‹ßJ‘}.[â?ÄË⻋¹–~D¤–k@`d°èéþp¶á·Rì*ß%±±²æÆÚØÏœu¡Î&$ƒ…À"ð`áÏ3|#ŒsoýVŠM—7ILSŒùO†s$•kÀƒEÁ¢§gøF=g;~+Åš›kLæj×ù]´q9GR¹2X,~«^ú­?ßýÙx®²K²¹žF$–k@`d°èéþQÇÙŽßJgÎ|<ÓÌÔYƒ´qà9GR¹†ˆÎ`i§îà/ù J>8ÃÎ~ó[y+ Jžs¤”kˆh– 'wxX]-€LÁ¢§gøFg»~«® ˆÒÆç)åãÁÒ*ë®e\\ñúõks_‘õa"ð`€]¿•¯¢ ðˆ´r /°>ÿüsinnît¿Þ÷Å_ tÈ`Ñ „3|£œ³¿•¿ ˆÒÆÎ/×à˜ –zXx°ð`ác€3|£›³¿UO ˆÒÆÁá åSëÓO?•¤¤$3,ØÚÚjP]]-ãÆ“Ï>û ¥C‹^ œá…œíú­zZ@”6çH(×à(–7“û±cÇP:x°ø­^@‘T®Áu°T-8Púõëg ·¯^½ŠÊ!ƒE/Îð2ÎvýV. J;¿\•Ü }ºÉZ¹Ö:Ü´i“¹Ï:l¨÷»Boë}ÞÂ×ñv÷‡ú|d°èù¾þàì/¿U0 ˆÒÆ¡áŽå¨äÞƒxùòe»rz[—vÏ¢õÄ|ïëx»ûC}>ÇÎ/×à˜ –§ªå®øË_þ‚ÒÁƒ…Îð 2J÷î•ññò`þ|ù£¨È6çH( Ê{:<8‡C¹Çx°té÷er\¡µ°>ùä”,zp†oquóXóõn.Öì‹s¤å=œÃ¡\ƒc2Xú홪Gµ}ðàÉliR (*’{ JÈR¶g_ž3’ ˆ‚ð@8•kˆx¥^+o…FëëëQ:d°è¾Ɖ‚y1eŠÔZÚÓ‡Ùæìä¢|Ž_®ÁQu°t8P—Ìq2dˆÔÔÔ rð`ác€3|Œ3¹¹òvÌy6}º/,´Í9R ˆòžΡ.×@,‚ ½@8Ã×.ìØ!qqR±lY¯Ÿ#÷N®# ˆòžΡ.×@%w ×¸µzµ)ziË–^?GNIŽ ´þô¤á…p(×à•““cêa¹—eÐ!ÃçÏŸ£tÈ`Ñ „3|ý\<ôñÌ™R?j””dÛ3ŸÏ¬žiÖwÕßEMQ>ÇÎ/×à˜ VAAA›©Ý]`•——Krr2J>8Ã×O8©ÅCÓÒäÕĉ]ínöjHë¹`ýý³õ·¤r m gG”kpŒ뫯¾’µkךò îKgR‹ ½@8Ã×OÅC÷í“÷ññòpÞ<ŸÅC»ƒj~•ÖŸÆòËezÕtÚÎŽ(×à˜ –»¨êX¹Jîx°öqå×_MñÐëÖÙ~®-—·Hò›dlý=³þ4ô¿f³4«ÅõN)×ñ«oß¾ÒÐÐÐIPi™†þýû£tÈ`Ñ „3|màîÏ?KÃðár~÷î^?‡–^X}kµŒ~7ÚÙÓߦË*ëÏ=V|\Y,>ÇÎ/×à˜ –šÙGe–ËQÕÒÒ"wîÜ1Â+>>¥ƒ œáÛ›â¡GÊó©S¥nüx9×»bŸ‡N’÷HLcŒ¤W§ËÖ‹[åàéƒÆØîíO÷ÓÆpŽär Žñ`¹–Åñ„ÚÚZ¿ˆOÏýé§Ÿ¶;&++ˬ‹¨ÈÌÌôùœ¾Ž·»?Ôç#ƒEÏΑË÷ÌRg}f«~øANô¢xèo¥¿É´gÓdhóP™ñdF—KÝÐÆpvZ¹GÕÁR‘å^É=Ð%N:ÕNdäY½;±¨‚N‘ššjî󾎷»?ÔçÃ@ä¢|çNS<´riϦ¸kíªMW6ßK\Cœ)¹pøäa®)­o)„å(4Ú‹p IºBŇ*VWèí®šöu¼Ýý¡>,z¾pŽL¾7׬‘¦ØX¹¼iS·Sp¢@VÝ^% õ 2¶n¬¬½¾VŽ?FÃ7,8‡¢\•Ü{%%%²dÉ’v÷©™^ËD¸Bowe°÷u¼Ýý¡>,¼pŽ,¾Ç‹ŠäÑìÙò>!AÎu³x¨V^Ÿÿ`¾Ä4ÅȤ—“dû…í´1|ÃŽs(Ê58ƃUUUe†5ÔàþÅ_Ô Aƒ"°T(èdG–§Ù]yºº:ÞîþPžOß.¸GJJŠyÓ¹”½þ·»­mïÏç ÷íhã«Ûð ðöÉ#G¤nòdyÿý÷råìYŸÇï)Û#3^ÏØ±²àåÙ_²ßÖù]ˆ†öF¾º­ïëPžÒÛI’÷8;ï™]kä݈!’•ÿµüPõƒYÖ†6†/œƒ[®Á1u°º õgedd˜ ï,zpv*_]h9wW¢ÔŒ$[ÿøÁ,ÄLÃΡ)×À,B ]²fÝu’üzŒœZö¼H.'ó²¹6„I¹†ˆXº,Žk ÂŽðçR9,zp¾‡O–Ÿïþ,q q2ý~²¼H%/¾ûNNÐÆð…s”kpLkðàÁí•;Ô‡EàÁÂÇçHAÑ3ïFôìsÙ2ãÉ ÚŸÏ×ñv÷‡ú|d°èù¹ý”ðئXYu«óL@2X|Žáì¬r Žªä® >wŒ––éׯŸ_ÄÕƒdÈ!RRR"­­­¦æÖòåËÛöçååIrr²)xªHMM5÷y _ÇÛÝêóáÁ»ç?QôG‘Ì0_F4Œ]çwy<&ÚŸc8;­\ƒcýôSÉÉÉ‘/¿üÒˆ6%YWW×¶_‡ õ¼®ÐÛzŸ·ðu¼Ýý¡>,íØs~1ÏÎ{8OŠŽyW{ö˜¢—7mâšàÀr /°ÔÈîÍä~ëÖ-¿,}®… š¬˜fË-Z$³fÍj·ßSf­«çëêx»ûCy>}¸à)))&mêRöúßîvUU•_Ÿ/Ü·£¯nWTTDÜë×…™c›cåÀ‹^¿u䈴 .w-‘é|ín»_çnëû:œ__áÍBÕ<*ìù†¤Lƒ )ÍVivI¡·ý%®\÷aÈŽÃd°ð`áÝ€³Î üñé2º~´dŸËöz\éo¿™êìW7l ùÃÙåU+С¦îŽË]`xò(é}=ñD¹ow¨Ï‡ ïF´qÎ=“+ãêÆÉw/¾“‚âïâjß>iŒ‹“kYY´1Ÿc8;´\•Ü{jp×aAY .œ;wn§Yv:»ÐÓ,»ŽCl¾Ž·»?Øçâ[/m5KÞ¨£«ãÎýþûŸâ*3“ë@”kˆH¥BsvÝö×1þˆ-[¶ÈgŸ}f†gΜÙÎ䮡µ¡¼Õ‰òäaêêx»ûƒ}>2Xô£‘³–`X|w±Ä5ÆÉö‹]/Æ|.;[,qu}íZÚ˜Ï1mìðr ÁRáä2YëmoèÊøÌðW¹ˆp=,| ÑÆ9¿8_&¿œ,IµI’w&¯ËcKrr¤aøp¹±f m gÚ8 Ê5àÁ""^`Ñó…s(°ïÜ>I¨O™OfJáñÂ.=«âjĹùË/´1œiã()×€‹ˆx@°±þÚz‰iŠ‘µ7Öú<öln®|°ÄÕ­U«¸vDt¡Î&¤–Ûpaoöd°è¹»8vü˜Ìy4GF~){Ëöú<þŒŠ«øx¹½bm gÚ8‚8û£\ƒc2XÞD”šÐXx°ð1ÀÙ.>$)5)2ñÕD9ròˆoquà€¼·ÄÕåËic8ÓÆÆÙå"ÞƒÕÕìA|Ã$È`Ñ „sWØY¾S†7 —…÷šYƒ¾Ž?—'ï¤béRÚÎð@Îþ(×ñ,×LAW9†ŽÐr{÷îEéàÁ WXq{…Ä4ÆÈ¦ËÝ[+ðôÁƒRo‰«ÊÅ‹¹~D(üY®!â‡Ã¥A‹^ 38=qT~¨úAß&JÎÙœn=攊«Q£äîÏ?ÓÆp†o„s¶[®Y„,| pîT*¬T`©Ðê–¸:|XÞ-÷.¤á _p¶[®Á1u°Nœ8ÑnÙWdddÈ©S§P:d°è¹[Øte“Ä6Åš¡Áî>ƈ«1cä¾õ}CþÎàl·\ƒc2XŸþy§ek\³¿üòK”,º„š×ÕÄ®fv5µw÷q'‘·ÖûúÁüù\G”kˆxåiÝ=ê`‘Á¢çî@Ë.hù-ÃpðÔÁ‰«ºqãäáœ9´1œáë@ÎvÊ58&ƒ¥³_¿~Ýéþêêjùä“OP:x°ð1ÀÙ#~+ûÍûh®)$ÚÝÇççKÝøñòhölÚÎðu(g;åãÁÒnÍT=zôHZ[[ ,zÁä¼ëü.Ñ0B2d˜…›{+®žO*¯&N4ævÚÎð…soË58²VKK‹|õÕW&sõÅ_Hss³ßÖ§Ÿ~jLóÆ “-[¶´Û¯3uHÒ}xRï󾎷»?ÔçÃ…!XœWÞZ)±M±öª-[âJË0¼ž0!¤âŠ6†/œQ®:X½ ]óPg.®Y³¦Ë WW3}ow¨ÏG‹^` 9ëÌÀéϦKâ»DÉ)ɱ%®žM›&¯ÓÒLAQÚÎð…³Ýr Tr·ºÆ¡š½É`yV.¸GJJŠQõ®7žþg›íÞlçžÍ•¤÷I2çÝ)½\Úûç»wO^Í+5©©r¹´”ëË6Ûl{ÝÎ{ž'éué!}=AXUUUfBס jÆeРAAXžö>‹uoÁy7z´œ sqEv¾p¨É]ÍîÔÁ"ð`ˆÁ¾Ò}&ý>°‹¿ƒ§öè9ï.Z$õ*®ä‚Z®EÁ¢rl¸¶AbšbdÝõu~ã\¹x±Ô%§¢á _8­\ƒc2X:cÐUž¡#Âe! |=Cë[Í0ßd®ö”íñçŠ%Kä}B‚œÎË£á _8µ\ƒc>^ÎD˜¸"»_8;£\ƒc2X*¤ŠŠŠP4x°@„}A%¼OÙgû¥¾• ·W¬#GÊ™¸Î€–kˆxE–Š ½À›…su£ñ[­¹±Æ¯œo­\)FŒ³¹¹´1œá ç•kpLKK3èúx,| áï·Zx¡Œh!»Ïïö+盫WKƒŠ«ýûic8ÃÎ!-×àVii©ÄÆÆš…ˆ 2XôÃÔoUœ/“ª'IÊ›9xê _9ß\³F†—’œÚÎð…sÈË58j-Bo`!,zdŸË–Qõ£dæ“™~õ[)n¬[' qqR’͵„U¹G˜Ü½,z¡Å¯W~•ئXùåæ/~ç|=3S-quî÷ßic8ÃÎaS®Jî,| õ[-º·H†7 —]å»üÎùÚúõF\•îÛGþp«r ŽZ‹ ƒE/0|PP\ S^N‘äÚä/mÓÎW7lÆØX)Ý»—6†3|ávå•ÁJOO—þýûãÁƒBŒœ’ýn´üôô')<^è÷翲q£4ÆÄHÙo¿q½a]®!âÖäÉ“ÛÄTG…‹ ½ÀàaóåÍÆoµêÖª€p¾²iÓŸâjÏÚÎð…sØ–kpLkÀ€RVVÖfxר««“©S§Jnn.J>† `ñÝÅ×';ÊwØ~.8Ð+ÎïÞMþpër Žñ`i¦ÊÓíÖÖVùì³ÏP:d°èøËå»ßÉøÚñ’wÚ?kÿ1å)¬ûic8ÃÎá^®ÁQu°\•Üûõë'ÅÅÅæ¶ Ń… Ðou6Gß%ÊôgÓ¥ð„ÿüVÑ,°Î)×ñ«  @222Ìm­èîîÁúòË/Q:d°è[.m‘˜ÆYq{…ߟ› Ù øÂ9’Ë58²VKK‹|õÕW&sõÅ_Hss³ß…Cjjj»¡HWdee?˜"33Óçóø:ÞîþPŸ–s} K+—J\cœl¿°= ÏÍ |áù娃Ջ8zô¨$%%uXyyy’œœl†**Âô>oáëx»ûC}>2XÎì=qT¦>Ÿ*ãêÆÉ3üþü'¬Ï×ÃyóÈ`‘Ý€/œ#º\ƒc2XÁòY½ÿ^†*OŸ>í$°T|èu…ÞV!æ-|ow¨Ï‡ËyÈ=›+cÞŽ‘iUÓüê·ráÒÖ­ò>>^žOÚå,BÚ)å"^`©±=±zõjÙ»wo§ÙŠZäTg-ºÏ`Ôû¼…¯ãíîõùÈ`9«¸íâ6‰mŒ•ew–ùý¹O>,ϦO—#FÈåM›hc²ð…sÄ—kpLk Õ«­¯¯¨¸ª¬¬”qãÆy,ái[£«"§¾Ž·»?”çÓ7€ î‘’’bÆ¥]o<ýowûÍ›7~}¾pßßuOÖq•S‘ã÷癓#MÇËãY³äò¹s¯ªªŠšöF¾žþÃ×yÛú¾Ž¾“ÞN2™¬@ñ ºÀ:{ö¬$$$´•jD¨¸züø±WÁA‹ –Óz: øCÕ2öíX3<èÏç>sà€T§§Ë»Ñ£¥|×.Ú˜ì|áì¨r Žªƒå þògy{þ®,çôµô‚–`О˜?Ÿ·tß>©MJ’7))r.;›6†/m gGB— hýéÂ÷”iðƒÀÒÐÚPÞêDõôx»ûƒ}>ê`9£–Œ Õâ¡[/mõÛs/,”û HSLŒÜZ¹Òd±hcøÒÆ´±S‘PŸ`ÖŒ—3XÁˆ`Ít ÕùÈ`Ev/PýVºÜ͘wcdÿÙý~{Þ ;wJý¨Qòròd9—GÃδ±£¡Y«nýg9Þz\†´ñ{+¬ê`±¡³°¼3y2¾n¼Y°¹àD_ž³8?_žÌ˜! qqr5+‹ë ˆ L{6MæÔÎ1¿y«¬?g±ÂF`ÕÕÕ!°È`Ñ ì;/ì4~«Å•‹ýöœW6n”†áÃå©Õþ'-¡EÃδq4pÖlÕàƒåÞ‡{æ7ï™õçï,VÐVW³]ðUJ€ˆl…w£÷Xyk¥ñ[m¾¼Ù/ÏwúàAy1eмOH Û·ÓÆð…3|£Š³f¯æ¾™ÛîwÏßY¬  ,×LAW9†ŽP3¶«ò:A‹^à_ýVÇ åǧ?Êèw£ýÖ³º¹zµ4ÅÆÊƒŒ 9QXHÃÎð*ÎO4Ævoº?"‡UŠÀƒå8¿Õé=_øÂ¾p&ƒE °¢w\ZÕ4™Ý4Û\ÇUÖߢ÷‹zôøÓyyòrÒ$©5JÊwìÀË_8ÃÎx°Vt÷Š2¯gÊ ëï‰õ§ñÌúÓ,–z±ºSzáöªUÒ#÷.”ã……ôá gøÂ™ VøDyy¹¤¦¦J¿~ýä“O>‘¹sçJuuu»c²²²dÀ€™™™>ŸÓ×ñv÷‡ú|x°ìáð©ÃÆwõuË×2¯q^»kÙ,ֹߗ7))R›œ,çöí㚬ð‹ôôt)--•––imm•={öHbbbÛþ¼¼“ŒŒ #6ÜCE—·:Qž2XÞ±æÆ‰mŒ•YgI~qÏÖÿ»¸};,z¾p†/œá‹À"ð`¹ðû¹ß%¥&EÆÕ“=e{ºý8-z=3Sê¬ë¥kF»À»gøÂ¾,‚ –=qTæ?˜/1M1²âö ¯5­:Õ²ÊÏ—Š%K¤aÄ©IM•+›6™*ì]Í"¤'_8ÃÎd°X,Ǩ6]Þ$ñâeêó©—±ñ­¸þhî\³´Íóï¿—²={¢îË‹ ƒÕ ygòdò‹É’ð>A¶\ÚÒ­Çœ·„”Ö±RaõpΜn-mCϾp†/œÉ`!°XŽ÷`/’eËLM«…÷JቮkZéß•_5C€:X±t©ÄÇgÚ¾p†/‹ ƒea×ù]2öíXI{&Ù%Ù]{¢°Pn­ZeLëuãÆ»šÙé™6¦á _Ë‘“GdÆ“×'뮯ëòØS‡ɽ ¤1&FªÓÓMÙ|X,7¬½¾Ö«™OfJþIïC{ç²³å©Å¿yèPy:c†Ù¦gøÂ™6†/‹ÀƒåÔ¡@Ô¡Á® ƒj¦J3Vš¹Ò >8w¿þzEÆ+C‡¶Ê¸q ²aÃuÚ¾p†/‹pfKMë î/0&öew–S»¯Â ·V¯6ž+zp9²ÑâÚl>+·o‹ŒÓ*›6Ý¢á gø"°gy°´ÜÂÈ÷#eÊ‹)¦ Cw ƒâ=Ÿqurþ|C»Ï‹Š¬ñ㛹>ጠVÞé.²m[¥Ûñ§dË–K²dI…L›V%cƼ•!C>Z«—ï¾{!‹Ý5^®Üܳ´1|áL …À -ò‹óeÖãYÛ+kn¬ñ{aPºVú_·]F÷ääzK4µïÕöíw}>×±cÇeß¾RÉ̼.óæ=”‰_I\\ƒ|óM³õ\odæÌ'²jÕ-Ùµ«\ йþàÁ"Xï%¬¿¶^ââäǧ?šâ¡‘P”ž¯ó„U ø>|R¶m»(Ë—ß‘éÓŸý!-ÿ^&O~) Þ—¬¬«²‰ÑÆð…3,å‡qîý%ûåÛWßʘwcdgù΀ÅÇçî «@óU!•}NÖ¯¿&÷%=½ZFŒø _Ý"ãÇ×ZŸ×§²bÅmÙ¾ý‚ä矤á g×ò@ß|óQF~'YY×xOþÑ&°ÊËË%--Múõë'Ÿ|ò‰dddHMMM»c²²²dÀ€™™™>ŸÓ×ñv÷‡ú|¡ô`iM«•·VJlS¬¬ºÇðE`¹Å”)S¤¬¬LZ[[¥±±ÑêÁ­2‚Ëyyy’œœ,µµµ©©©æ>oáëx»ûC}¾` ¬Ü;¹îÛ[¶WÆ×Ž—…—ÆÈ£éCZ”^ s9j(Ð)m¬EPµªEÕâ¨Z$uذ&‰m2ÅSÝë~¹âÆ=ú=ïiÁU~D13æ=YJ–ïP¡Õ·oß¶mzA]¡·“’’¼>Þ×ñv÷‡ú|X2p WÌ~8KŸýFžL%F yaP€Ç ´‡.û£Ëÿ Öêñ{Cë€qœ#®Fn‘«WÿlÛ[·ZeÔ¨æ¨Y¬^FIII» Vÿþýèr`zŸ·ðu¼Ýý¡>_À–§°î9~¨ÔŽëØÂ d°œ/¬¢¥¿ý¶±í‡×ZÁ~äÈænù·xO‡?RS?xlãÄÄ|o!°<ÇÝ»w%..NªªªÚîëÓ§O§ãÜ3\Ã×ñv÷‡ú|¡XáVCäsvÆ*ZÚxÛ¶›f9 ×ðŸ?¼­Ö}o%!á½)„Ê{:²ó1j³”x°z—.]’¡C‡Jeee2DÑ”ÁÒ7€ î‘’’bÞt.e¯ÿ{³Ý•ÀòÇó‡ó¶Šz'óó´]QQ’óŸSOË_?Çx~Ç ¬ââb4hܹs§['½¯'ž(÷ãíîõùB•ÁbŒà±r´ך57døð™2å…ää”p]"GŽœ”ùó˜ S¦¼2YI÷,¥z²´¨­ÖWÓÚj£G×ËâŕƛÇõ‹Ò Vvv¶õû=P pŸ‘Im¬fÅŠ;fAïÉ“_öZÄú“³Oª^Mñú¹V“¼šåñ`!°X6±eËu3æc»©¿cÆ´5££½©¢¢"ëË瘕ÇZ?ÜG­/ö£²ÿQÉÎ>*{÷ÊîÝ…²cG‘Õó*’M›Ž[½íbY·î”¬^}F–/?'K–”ÉÂ…eîÜ+2sæuëÇá¶Õ;¬” ZÂê©õÿõÅöNZ[›:]_­´bÅ5É̼.»v•[ç?EvÃCd°ì®]%ô¿nÓÆ½­«VÝ6Csš-Ú³§,,9«˜Ö2£G¿3e´üCNÎY2X,Vo S~=¯3¦É|°öí+µ¾ Î[Âæ‚I)뛦’Õ»jÕ-Y¶ìŽù@.\xߌíëÌ$í©QSͳúe¢=#õwhUi­ÓÿÁ¤Æ55=xðG4HÌÝÖûGŽü`ŽS€>N¯Ï£©tMiëóë‚·z>ýÐó«—@_öÄôõéëÔ׫=1}ýš‚×9II¯,¾ø¦¦Šõ˜C2gÎ5IN®6?*C†´˜/šI“ªÍùôú¼zMÔ;Ç DôGW3YšÑÒÌ–Ó—Þñ·°Z½ú¦ŒñÁêà½2 vGÊkW¨ß{j¼×ïaý~Õº\x°–Íå–€ ¼¼ÓæÃì1ÿ?Lmj—±Ó%F´êµ%Þ»·PêêÆ™áʇ’¢¢ßdóærYº´BfÎ|,'¾’Q£ê-ñõÑS“’j-1ù\22îË/¿Ü”mÛ.šš5á:«»=A§+2Xþƒg©7+Ü–Þ Ç6.*:n:¡úªß›:‰ R9«HÔïMýÞÿæ›fó_·ƒ)´É`)°’“ëåÊ•ÖN'/ ª_'~0š¹Rq¥+ ¸súô!¹yóyùrŠ%¶¾‘ÚÚ$¹{w‘”•ímÖT‘¨ÂQÅäÂ…÷ŒèLIyc†4#7rä{«×úZfÌxjħ N™‡‡®èËËà´Œ,ÿCgŽóÖtºü-"½õ{aíÚëF„¦¦ÖÈöíÅY;ÅÚNN~c2[:b¡ßix°–±1jTs›Èºyó£ÙކÒÝ­ƒuüx¡1Ì?z4[Þ¿) ÃåéÓÆHâDW3kvv‰lÞ|YV®¼-sæ<”É“_˜aRí*ôö”)/Í>zÑcušv ³zÞz‚N $ƒ8!.Kï„CëõÈ̼f²Û*>4“ítÎj! Ö=d°ˆˆX.‘•”ôÎ,¿0zô{êBù@II¶TT,•šš4iiùF^½š(·o¯³gs{ÔÔžŸ^kýbúé§'&Û¥Y/Í~é—fÃ4+¦_bš%SœfÍz3ü¨m<~ü[ùúë?}e®6ÆcìΊsÚÒ;=V6\3Ÿ©ñãk£¶†X¤.уÀ".°¢µ·ï¾ÅÅù¦,„–¥hjŠ•wïF˃óLyˆãÇ‹zý¥­>®íÛ/_—ú»Ôç¥~/5«ÿK{Êê›9ó‰ñ‡iý¢½{Ë<ÎôRq•Ð$—.µ˜÷εkM–k2~:§ +2XÁA(—Þ UoÜxÅ •ŽW'›6]æ}ýGà–è!ƒED¼ÀŠ6¿ŠÿùIyù.ëy3L ¯¦¦aòüù÷rýz¦)ªêÏêÏ:Y@…“N*P¤3ß™ •þÈé—¾šQçÍ{`ý4vš)zýºXb­Ùñ+.õsùk!ì]»*¬Þb‹©ý•”Ô"[¶Ü¡áTjéóݱ£Üüèkù?}dáQ¹þoâªì¯¿—Ⱥys£ù9uê%@ò¬NZ®YwUg;ë¬Z»O‹(ë÷‰N¾¹xq›/š=×R3W¯n0uô;H×rÕúÚÙәѺÆkEÅ’¿®7»È¬ýúàA†YöÑ£9fMXÍÄëú°ÏžM7kÅ>>Õ¬ûòå$³†ì«WÌz²55)fmÙÚÚñÆ£úîݳæìû÷ Öã'Êo¿í±®ûc7î¹ìÝ»ÃzÝóÍpbû¢Ð¿%~ó´"°2XQ”ÝЙ‡º°¶ÎD|÷.ÑÌLÔŠú¨3icøF:g/½ã/¾»v7ËÙè²6º¼M¸, ¤µö.]Úl†[[WwøeXmî×bÈMM1ÒØ' jAi„‹ ˜·o¥®n¬6*pjjRàQá£èåËÉF©0ÒïJ*˜T8=~<ÛRs RauïÞSpY—–ª¹sg¹b*ÈT˜Ý¸±Ö5ý¾ºzu£p*äTÐ]¼¸Ý|·©Ð++Û#¥¥¿¨BðìÙý–p:`â￟’9stÝX-‚]ÙÉÚ”Ô@‹Àƒüa”ϵ¾TVšZ[:”¨_ŽúÅvî\6×D4Âeé]sO½@#F4ÈÊ•·B*¬´uáÂv“9Òl–}ùøñk³|׫WéÖío¬ï3æ7àýû³¤—Š'¾?Ô£ÕÚÚy‚ŽfáX,zú~îÉ5_¦ZE^«ÉkUyíajïP«Í;qöïiçs¶»ôNoùªÀ›4é¥ÄÅ5˜LZaap…•sép]eåR“=ª¯O°ÄÓ“iÒì‘f„ÊÊ~³>ÛÇ:™¾×9Z\)´0²§eÜ’“?"°þ¯¥[’M'I½O:ñ¥;ʼn]e œþ9Ö:£G·tð`‰dgW!°2XôôƒýWÿËSMÏV‡Ô/¡æV5Ê«¸RC¬Î>úø1&jD¬ÈBo–Þé._]çsêÔçÓ(K–TÈÑ£VÚÁ¹|y“1…«¿I=Qú™Ôá}õ3]¿¾î¯Cü½ŸÀ-™è-[®ËĉÍfX0%¥ÕÞÏ-zEàÁ¡2Ê3CΑúúQÖ—ûpëÓnöQ4‰¬hƒ?W ü¹ôŽfÃtÉ–ØØ?ŸËŸkäiY•+W6šÙujW“¹Î~ýú[c W³wIÉ~¿Íõ}úôiƒ·ÈÊÊ’dffú|N_ÇÛÝêó‘Á¢§ßÛ[NY×áµÅܯFZýq¸uk¥\çÏï63yz»Ž"mZ8mø¨;KïxkãýûÏšÙŠ11M²hÑ=Ûe!t1÷«W³Ìl:§3|c̽OËôdÁwÞסçëè –7•——'ÉÉÉR[[kššjî󾎷»?ÔçÃ…WÅî®f¬\¬ÖÖKÖöPSkK§W«ÀzúôGÓ×ú4Ú omýgë¬Ù®®žhöG¢‹¦÷ôßÚùWc„vR†ÒÓÒ;êÑÑ57‡mµî¯o+œ« ¥ÿøãS“ýZ¸ð¾%¬Nöð|ERR’c²Oš…Ò’ÍÍä¡!Î|Fôs ×6Ey_—oT ,ªX]¡·“’’¼>¯ãíîõùÈ`Ñ ö¯ 'PêáÒc#UˆE‹WÅ“ˆvšÈR¸–Þ3FÖ¢“u†ï­[­2jT‹¤§¿6Â*#ã9r²[bêܹß/J gªOJ'ŒèRVêŸÒšOê§ò6q„ï.2X'°ú÷ïß®þ…ÞÖû¼…¯ãíîõùð`p> g!æâ{ÿþÞ°÷ÌéP®ZÔ‹çÏï2¯] 5Þ¸±ÎÔA«¬\b2ŽÍ6×N'3èuÔ¥–´ mWÃÀº_«hk{h9}¼Š ½þZ¥[ÛL†¶ƒz÷´-µø£¶ÇŸÅmÃ+K©uª´h~~ç)ü‰‰½ãõ½¥3õtÆžV ×|:“OgôéÌ>-ž©3ýtÂßx°+°<Ýß·oß=ûñv÷‡ò|úpÁ=RRRLÚÔ¥ìõ¿Ýíªª*¿>_¸oG_ݾ{÷JHÎéÒëGý²õc~Èü?z´ÑúË´~ôç˜þ÷»ø6!¦ÛïßO7ûU|#uuº”È$©¯ÿI^¿ž!OžÌ°¸ÿl‰¤õÖíuÖ5\m½–mÖ}‡¬sí7U±>ÜúW¾í—QÑ릂©¢b¿¹~ú8TOž¬±žoõš6U»kj~²^ßÖy'šªß £M{haËÖÖA-poîW‘üöís¼>îOÁ·È´§>¯>ÿƒÛÌù**rÌùoÜ8fÚÿòå#Øì¾Ÿ† kñø}é*ByéR¹õºN[×åWSSª¾>Õâñõú­×õ½yUU…Ö{±$"?ÏQñ}h¾d°È`áÁÂÇ5œý‘Óéñ?k'6Td=~¼Íˆ]²ãÊ•MfI+ˬÇ,´~ŒçZ?¼?™5!uµšš4#vt&¦vÕ©özÞ›eI>|ˆ7ë©ÕÖ&Ë«WßZ"cŠSšyð`¾©Q¦bëæÍ5ríÚK\l‘òòf‰]D3%*ÖüuíWŠ£HŠ‹ L»hfKÛæÏkøë_¯á*“ Ó² Z†@›fÊ´½tÈM›.Û¢íÖÒòµlú_·õ~mÞfØRS«-‘û±S+5µÅœO«Ÿkt]úE«¢ë|ÊÏ1|ñ`yð(é}=ñD¹ow¨Ï‡ œ»'ÄtV¤‹}ü8¿Ã'h[‡á²‰n?æ³­Ç.0Ãp·o¯2Ãr:<§Ãt:\§¾Óa<÷ªÚáˆÈ(&kO°éÚz.ÜØ©¥Ïu˜OW=às _V³ôjjj<βëø8_ÇÛÝìóáÁÀž÷êÏb«EQY÷Ë u°ºÓÆ%%Kdòä3,˜šÚj ¶#Ôv,÷:XÞêaim(ou¢zz¼ÝýÁ>,zpöÈÒ5Û¢­¨*mL× V¯£_¿~Ž>,| p¦è&mLÓÆx°‡,zEpv¢¥mLÃE„±Àð`!°XôŠà gøÒÆ´1|X,| p†/œá g|8ªÚøÓO?utûVUUÉ”)SLû*ôöÓ§OXDä}x£%ôCZVVf–(jll”U«VÁåÔHOO—ÒÒRiii1œ÷ìÙ#‰‰‰QÑÖG5ëŽEƒÀжxðà 2DJJJÌûZ;IË—/þ§NêU ÅHŠøøxÙºu«ùîRlÙ²EX_Бúåìm±m§†f³œïß¿—¡C‡š/Ëy1þ|Gg¬|ŨQ£äõë×Žæø—¿ü%¬¾»X_Ð= í;9ƒÕQLîÝ»×dñœ«W¯6\£áýí.Ҏ°aÃLOßé¡|srräË/¿4?ºZ+©®®.j¾³–,YâxžÓ§O7ïeýÞRlÚ´É܇À"Xêላ‹3cýÑÐÆŠ/¾øB?~ìh®•••2nܸ¨|?zôH&Ož,kÖ¬qüûyáÂ…ÒÜÜl†ú-Z$³fÍŠŠ6;v¬"uz¼|ùRÜöÝ¥·C™µC`¬nÆ¥K—Ì’þGKh/pçÎíćCù¹‹Èh{×××›uNjzVaå ZÑ0ô}ñâÅfq‚:A3Xî¬PŽ6 °V7¢¸¸X $wî܉ÊövºçÌÓŒ«hzGƒÀÒÙ¡–Š.§‡NÚ¸qãFÔ~O…ò» E °|Dvv¶™Ò )v õj¸¦6ë¯ÎšóõàÁ»_× ,€ªðÉ'ŸXD“ÐËm`=}úÔ>=ØÖÖf^¼xa·irúÈȈ5˜ò.)Cš£uðàÁñú“ÜlèééYqÜW_}eîß¿oãzŠQû;::(l ,€ê a9½Ê ÔpÊb` M6ïïï·ó«tœ :½FÁm‚Œ/ jþUSS“¹uëVl¼zMî]»¬7JF›¾GS¼Gޱ¿É½òAC†ÌÁÀÀÀÀÀÀ , , ,ÀÀÀÀÀÀ , ,€Ú6°>øà@ BÂ2 Vé¹ÂÀÀÀÀÀÀÀ€šâÃ?$`MuZ#k~~Þ>|Ø|üñÇfóæÍfÿþýæÁƒe-8£ øÌ‘#GÌo¿ýVÑÊçBüñ‡ééé1[¶l±AŸÿý÷’ñ™/¾øÂ|ôÑGfëÖ­æ›o¾1¯_¿¾^Rúâ΋ۯ| áÀ+â{óæÍs¥Û¶mæÂ… ©ñ<|øÐ|öÙgöœ]»v™¡¡¡Äô¹k–ÚW*oÒòVœ={ÖÖO…ï¿ÿ>SY§_«V- &ƒÆ 1ùÛwÜu׋U«†[Õ ,‰*ÇÛ·oÍ»wïÌÓ§OÍÁƒË.~]çÖ­[fûöíÀ¤´©Q_ºtÉ,--ÙpñâE³wïÞ’ñH?~lóçï¿ÿ6ƒƒƒ¶Áæ­lY+åýû÷ƒíÝ»wÍ矾"þ¯¿þÚ;vÌ,..Úô?~|™˜Eyöì™Ù¹s§yòä‰ýþêÕ+óí·ßVäw¦åí?ü`ëèŸþiƒÄ]ÛB¯z>,ƒÆ 1hÌ:Ô˜õl`m Vccé‚z|I¼|ùÒ:tÈöÂtlwwwÑúé=”*ÜÛ·o›¾¾¾eÛÔÀÕûQOC½¡¿þúkÙþ3gÎØ^–z!7nÜÈ]©6mÚ´b›®Šj\¾UJüÚÛÛ­ åUKK‹í%Gã×o“°8ô9N¼*ï‘‘‘U§?O£Žæ­„ˉ°Ðg |èµBÏ÷ã‘8655Ùtè¦855µ,ïNœ8Qì­ê³Ÿ·qñ]½zÕÞìUG]Q¥âÓÁOûÄÄDÑ0‰öp“Ò¬›ž®«ë+W®\ÉU6…{T!MÆ´¶óå—ÆüôSØyh ƒÆ¼§µÐxfgg‹ž]ÅéêºòUùë_«TýOkóõ¬Ckc`eÙðÝwß™¹¹¹Øý»wï6“““¶Rª'&R&åí]ú½L‰˜ãüùó¶ÐÔÐuÔò{4çγ«ý*(¥#oãSãVR¿IAîlm E®í,½Ë8÷¼D\•P NiIº–*{ÚuNŸ>m®_¿»?*~Ê?ÝÌJ¡rÑ1k!~ѼU:UF¾8Æ¥½ÔµBÏ÷ãÑWõLÇJ”öíÛWܯ¶¢zº°°`ƒnàÚ–ŸŽñ÷ënR|333¶ý¹ôK°Ü0STØ’Ò¬ë)^Ý u Õõ¬e#㪣ôàý÷_}ÿ=ÄÈBcÐ4æ=òžÝ¹s§èù’¡á¾›S§NŶï¬:U¯:Ts–¬g5®;v{ur×&Yÿ¾hå¿h϶±V_€%Žþœ¹“5¯¡nQõ˜›››‹½}Në½9¦§§me‹KK¨øù¼xñŠz©›tGá.öüùóÄøÔKèìì,¹``Àºì%€Î}ŸäUH+ÓÐùYO\ÞÆÅ‘¥gz¾¼£ˆövÕNüôé³D2)>¿^ëxÅŸæ‹\»vÍyɈû]!iV÷ëÖ²‘çÊWY4Ac5æÑ£G6¯„ ÎðV»ÐþP+©Í׫UÇÀ  Ì8d(ËRs%ü†¤ž¥\ ²È]%÷ÝßyÅO×ŠŠ¨Ä×…<× m]]]¶GçÏHrg;ÆÇÇ­ ·”+6oe‘5/·l¹eCz½*/çvŽK‡& j’±òU•üæÍ›‰Z×¢wY*o׃•´-Á–t|Úþ{÷î™={ö,ZàÐý!ÒQ¸'­ Ðt2ÏJ@cИ¬1Ú'c[uBåáþ»í.ž<í7ëz-èPÍ{°Bz}zâGὨ.¥fZH&j~„ß°uè“>åì]ÆÝÓæ‰¨‚il9iÒl¹ÅOC+š ò;CŸ¨rIkRj)䯭æüˆ¤¼›ß m¡× =?TtóˆöWëÁJŠÏM˜U{ñ‡q²W´ç¨ëUÓƒ…Æ 1hÌÿ‘çJC­½½½Åïjãî{¥ ¬zСš3°TÑýùš+à?í¢ ¡zùúåÞô3E6Íõò„ÏåË—ms +ÙŸ‡áæG( «¡ß§ßéÏHzÂG½1‰sÔž×…¬ßåzú½*ƒèM$,5Q2ĽîsòäI›oú­š ^œß ‰"ÁUcPD%ŸðIË[÷„ŽÒ¿š'|ÒÎ 7@7,yH$Ž!s°t¬BtîCR|j—mmmÅc5Yó!² ›†pièïï¯ê,4Ac–þªón>›þ«®ªÎÆ]+®þç1°êA‡ÖÎÀÊù¡ƒ*‡\årk*c}KVûõŽíW@•ÕÏË:w{HïGKcÍq.p  Ü¤º–s]¶_®Ê–ö„OZOK ß½EAŸ“Ä ­÷òΙhoJ¿OÛÕkÖïŠ>‰¦FêÆãW+~êMºù/ºÐ<„z¡4ª,Tþš€™µ7›åýEIqéɯwÔ”JGÒùY ,•“n®îèÆ’6Ô¡§eÜ“kîQöøT/õø¼CB' «°éšC!ŠÒ¡ô¤ySJYòd}úé{ÏUèS„h ƒÆ˜žg¤èÔÔVÿóXõ¢CÕ7°Ñ@226¢a`@ÙCnyMFNÖ¨gÂÀ€²¡a7ÍóÐ]ô%ƒI‡0°0°0°0°   0°6kµæ /èÑX¥ÖhªT滸µþPCCƒ]/,iåøÕ266V\Lk‹i$-È÷û³æWh~êw† uÁ¢ñjEóžžûR6}ÖòՌϭ¦<ÔzaCCC©õ'OÝJ++qöìÙ õÂJ‘t~­Xµ"”h ZƒÖ”§ç]“=*ƒõ¬ð·^3&dÅûr¢Fýøñc»Â»Þ;88hVµ*§È i\wïÞµ«ÚGã•Ø\ºtÉ,--ÙpñâE³wïުŧïµPì“'Oì÷J®xŸVVnÅz­V¿šïÓÎǃ•…ÿ¢5h ZSe­YÏV]{°þSøk,üé¥ -nr·B·z‰Zg(Ë5nß¾múúú2ÅyæÌÛ[K[ñ>ŠTÜêÝ•ªœíííf~~>ñý¶––Û»‹Æ«Uæ£(Oªß¡C‡ÌÈÈȪó!OcŽ–•ˉ¯Ðg {èµBÏ÷ã‘(655Ùtèæ055UÜ/a>qâD±—ªÏIË>(¾«W¯Ú›¼ò<ºLDR|º!øiŸ˜˜°ëxÅõl“Ò¼¸¸h¯«ë+ZÍ>¿ÐþR…ð­AkКœZÓÚÚjfggíg•ŸâtÞ4å«ò׿V)]ZÛ¯=ª‚5Xø“¥ÿÕ½óçÏÛŒ••®^ʱcÇ–õ:BâSïRâç¹sçLww·Ý¯’†"tµz•º–*eÚy§OŸ6ׯ_Ý/ÑQÏO pá»­RñEQ¹(×Bô¢e¥a¥ÙEm ½Vèù~<ºáªžéX‰Ñ¾}ûŠûµH©êé‚ ºq'-\ªøtŒ¼_w“â›™™1»wï.¦_Bå†[¢‚–”f]OñêÆ¨k¨ìó šŒ«Ýj­ÿüŒÖ 5hM­‘÷ìÎ;EÏ— ÷}xxØœ:u*¶gÕ«úÖ£*XòZ}ZøûwáOÿ³z±òˆ^cc£™››[&`IóJežß{H‹SndïgezzÚVЏs+!zæùóç‰çÉšïìì,¹ÿåË—¦¹¹¹Ø[Ñg¿—Zîø²þÎÐyYó7®¬ââÈâ!=ß?ÞïÑE{¹;vìX–>}–8&Åç×k¯8BãÓ<‘k×®Ù¡.Ýøã~WHšUüú]Ð~‰U¿d6²Ð´­yÏ£GÌÀÀ€ý,ƒFF‡3Deœh¨•ÔöëW*``5Æü þœçJŸKü•SôôYî=ô=Î5œŸ¬W¿W™gž·®ÖR.Ór‹žÜ§I½5‡ʹ‡ãâíêê²½@C\¯¸Rñ­E¯²TY­…+­îg5Ø’ŽOÛïÞ=³gÏžeC ¡Â›µ›ˆÚ¬ ÿŠÓWâ8´­Ak’´Fûd|*4çþ»í.ž<í8)/jWÖÀƒå¼WÎkýž·bJlüŠ"Šö*£O_d½†æEø‘gÖ^¥*‚Æ€“&·–[ô4Þ®I›!ñ$õÊânØi7ñrÆ'÷m5çE$•Uܼm ½Vèù¡_½¯hpµ¬¤øÜDYµ8(‹`E{ŒºÞzñ`¡5hÍFÕy®4ÔÚÛÛ[ü®¶î¾WÊÀª=ª‚5øÏ_Ú¶¬S'Uð> ‘\–þq—/_¶•Àe’,YMZ ¹F©'{Òâtó"”ž´y7oÞ´"uŸWRô4á¯Ô„Æ7¸Æ¶5wÁŸÇà?‰Sîø¢H¸Õô›D%ŸìI++÷dŽÊ}5Oö¤*nþ€æÈ(†ÌÁÒ± Ñ9IñMNNš¶¶¶eíRó ² š~pièïï_7s°Ð´f£jŒ=háæ³é¿êªêlܵä኷æ1°êG*h`½.ü5&üiÞŠ)ש…z—²öUàÑã$Rreê=š;::ÔëQ…’ˆÆ¹ÒÓâTA«’¥=Ù“ÖËÊúNžã՘ܸùjEO‚ïÞ×¢ ÏInùÕÆ‡{7ÊBï¦ÑÄËÐüÍ"z!q鉯wÓ”JGÒùY ,Í-Ð ÀååÉ“'S‡8ô”Œ{bMªýã“âS9é1|‡N7þ¬‚¦khî„< J‡Ò“äUH7²Ê÷!ZƒÖlT­qžg¤èÔÃä_CsŸÜöj ¬úÒ£ z°²¢'d\äç¿d"¬=ÂÀ€5D¹ãß¼y“:¬ Pz„eGóO4¿CO5E_.°ô   `cX@ „Õ‡¢åãÖ\mÕõQIEND®B`‚Multiverse-multiverse-0.7.0/charts/boxing_overhead_total_line_wide.png000066400000000000000000001112771174000617100264370ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix€IDATxÚìkLUY›ç;™L&“ɤ¿t:“ùЙLÒ™t:ùÐɤәt*o4:U©T¥*Vë[rDPä&¢ŠXˆ"Š ¢Šx¯ˆ7‘k¢"x¿ßð†ŠŠ * âë3<ë}9 ÷s…óûŸüÂÙgoö>þÏò°Ÿõ¬g­¿„B!„r’þ B!„B !„B!„B!„"A!„B€ „S¾Ìþ꯾à?ü‡ÿ ÿù?ÿgùÇüG™9s¦\»vÍíÞ'ÂsÚ Bˆ!„ÆIÒ—ÿøÿ£”——s#I¿!„@BÈ17h¿ýö[¯×ÿõ_ÿ•IÚÿ„"A!ÇÜ ýéOêõúúOÿ ³hüBˆ!„œ€ü—ÿò_úýý+W®˜:‘ÿñ?þ‡ Rt¸ÖßýÝß™×.]ºôÅñúºõyëëë{ö]¸p¡×>=v87’ýíKMM5ïIßÏßÿýßKJJJ¿ïåÊ•½Ž[³fÍ7®#ñäÿüŸÿÓë:<èÙ§Ï­÷ýó?ÿó׺s玄……É?üÃ?˜º½ÖûoÿM¦OŸ.gÏžÖgþáÃsŽ¿þë¿îhÚâëhÞ×Þ½{û­EúßÿûKTT”455 èy|||¯÷µvíZ„B¥¤ï,??¿/~wÓ¦Mæ&q°ú‘7öú½ÙÕâvËþ©S§öìÓç–×õ=v4Hppp¿ïE߯µ¦L™Òïqýýþp5ROÒÒÒzíÓ›ðnÈõ3é{îÃ`׊‹‹ò3·ö]ß»­¾Žö}ùúúú;û·+=úâ÷~üñG»Ž!D‚BN @úã»ï¾“–––^¿§½Ø}kD^¼x!ÍÍÍòÿïÿíµ¯o÷­[·L϶å†W{úË»f[ô˜áJýí›0a‚´··DYgòòò¾Ø§ï_雕îëhG„"A! ƒÝ4¤ç¹¿ ˆo£ÿ7ó7¦ÀXŸký…3gg@†òdáÂ…=û–.]*K–,éÙŽŽŽòZz~{}æöôu¸ïKg˲þ½­[·ë}A€ „Ð8 @tÆ¡nšm­Y¶lY¯‘¬·õÜÑHßáeÖïßÙ5 *-·ì›4i’ü¿ÿ÷ÿz¶ûä÷w­œœ·@Fû¾úÎf‘Nç;ØûøöÛo©A€ „Ðx@´¤ïÍõ D}g|Òl†eö!‰h µ>TgΜéU 3A)–™±=Æ‘ˆõ'Eg©²uö$[¬O?Í`ô û¾fÁB€ „Ð@B‡Èô]N‡É µæEßµ+Þ¾}+ÿóþÏžý‘‘‘=ûô¹åu½!Õc€¨´àÙÞëGŒÆ‹t=¡ÖØéµl©‹­¯£y_}×C±ž–x¨÷ëˆõ\Bˆ!„œ€è ¤¹ÒiNuµëÆòëÐ!]ßAƒ ­Q4xÐ×´·»¯¬oú-k€Xd½ˆ¢ Ó92QéÊç–÷®?uºá¾3Võ­i(Ôëà̺¨ZŸ[aƒ]K'Ðã-Ÿ›ãÒamýõ;:íûÒ̈åx-¼×ã†û~uEû¾ŸãHþ­!D‚BÈeÚ¿¯›V½iF!„@BÙ¤û·“Ý»w›•ÊUšåÑmËŒ\C-Ô‡B€ „þù5 Z>X B!D‚BhØÒ™¨ÂÂÂäŸþéŸL‡Z§ð‡?üÁ¬Ãa]Ÿ‚B€ „B!„@B!„Bˆ!„B!D‚B!„B !„B!„B!„B!„B€ „B!„@B!„BˆÄÓµlÙ²^ÛºJòìÙ³Ž«®ë à-¾â+à-¾â-¸ƒ¯}ï; @@ŒæÌ™#¿ÿþ»ÓyðàK®ë à-¾â+à-¾â-¸ƒ¯ È­‹/ò¥€·ø øŠ·ø x;Ž}%An€Àø†‘¡§ð_ñðoñ•Qx‹¯ø x‹¯€·Ô€¸EòÕW_õПΟ?/2qâDùúë¯%11QZ[[{“••%“'O6dffyÍ¡Ž·u¿«¯G„žÀW|Å[ÀW¼ÅWa"ýiÑ¢ER__/Ÿ?–ÎÎNÙ¸q£ H,*((ÐÐPikk3„‡‡›×ÒPÇÛºßÕ×£@l@úJ‘ &ôlë͹F}éó¨ãmÝïêë‘¡§ð_ñðoñ•ÄŽHmmm¯ ȤI“LPb èki¨ãmÝïêëQÂXOÀW|Å[ÀW¼ÅW; âëë+MMMƒþžu†d8×±>ÞÖý®¼ž6 ÖÒÕ1µaZ¢cýéŒí»wï:õzž´­ÿðÃþÛðƒö:V¶õ{?øûÅ÷Û®üû5®K—.ÉôéÓåÞ½{#Ê0¡È€Œ(©®®–Ÿ~úIîܹ3¬ }m$5ÖÇÛºßÕ×£„±ž€¯øŠ·€¯x‹¯ 6 ‡–)S¦ÈÇeJ§æío–¨¾çêx[÷;ûzÔ€0Öð_ñðoñ•d”ë€ô·Hûû£kc ´NFÍ`ÇÛºßÙ×#BOà+¾â-à+Þâ+ˆI0Ï×£Àó)S„ylB/Þâ+à+Þâ+à­þD‚<9aœ'Þâ+à+Þâ+à-½ô ¾â+Þ¾â-¢†¦º¸˜€ÐË·ø øŠ·ø xëXªÊÊänJŠtz{€ Æyâ-¾¾â-¾Þ:†Êòr¹µaƒt̘!/-’³2 "¡—oñðoñðÖÎTTÈõM›ä½¿¿´DFʹýûÝÎWD À8àê¶mò.0PÚBCåâîÝnû> @z_ño_ñv s)'GÚæÎ•·³gË•;ÜÞWD ch_ño_ñv r~ß>iˆ÷r-3Ó ¿ ¾€ 2 ô ¾â+Þ¾âí¢./Oš,??¹™ž.•#<È€ µGŽÈóÅ‹¥ÓÇGš)vÇ⿃‘¡ ð_ñðoݘÓÇŽÉÓî{µ^^Ò”$Õ¥¥cÚWD ch_ño_ñÖ ©)*’Ç+V˜ÀãaB‚œk–\ë¾Oû}«—“q“@d4û $44TÚÚÚ áááæµ4Ôñ¶îwõõ¨a -à+¾â-à+Þ:†ú¤yþ|ùàç'732¤ÒÅ5 . @ôæ\£>‹ôyHHÈ€çêx[÷»úzd@èA|ÅW¼|Å[ûR{ø°¼ˆŽ63[ÝIK“ʲ2|õädÒ¤Iòùóçžm}®¯ ¤¡Ž·u¿«¯G €}8Ÿ/Ïbc壷·4$'KUI ¾€ôÿú„ FtëãmÝïêë‘¡ ð_ñðom£¦°PããÍêåådq1¾€(ð°`­°°036ÐÒ8õ§3¶›ššœz=OÚ~ýú5~8`»ïOü¡½ºû¶~Ïâ¿ø>°ßö£7¤iÝ:x¼\³F_½Ê߯!¶©ùK„¾6’š ëãmÝïêë‘¡ ð_ñðoG†­jX»Ö µz+§ÃW2 CÏ‚ÕÚÚÚï,Q}o¨ãmÝïìëQ0:´˜üÎúõ¦¸üyt´)6Ç@¬×ùèo½¡ö«tmŒÖÉéñ¶îwöõȀЃøŠ¯x øŠ·# <**äæo¿™ét›£¢¤>/_=1â(Mœ8q\_u@<¼ÅW|¼Å×±HÅ3¯›Ñx\Û²Å, Øn¤Í€ q€Ðƒ„·ø øŠ·ø ŽÔ‘)ÝýéŠë_Þ±CÞvß½ –KÙÙ´Y4 Ë_-7H̳§^÷ÂîÝò:4TÞÊÕ­[ù,@À[|ÅWÀ[|õ„ìÇ´ÏÓäB÷C:# RŸ›+¯"#åÃÌ™rcÓ&3üŠ6K‚¨¼ÅW|¼ÅWOÈ~´,—ÝUòÇd‡fAÎ:$/-’__¹½aƒT–—Óf @À[|ÅWÀ[|õÒn§É´îdzî‡J:" r&?_žÅÄÈG¹—’"U¥¥´YD x Ï”ˆ–™óiNOöâ”λeANJc\œY½üÁêÕR]\Œÿ ˆ à-¾â+>à-¾z 'NžøÆxñùè#kÖšÂó…§ G}“'NÈÄx<^±BjŠŠh³ ˆÆÐâ-¾¾â-¾z ¿WHú­tñéô‘_Ÿþ*E5Eýz»áÖYôrѨ¯S]R"÷“’Làñ´ûžçtAm–DBÞâ+à+Þâ«'±÷ü^™ófŽ„¾•ÜúÜA½-©.¯./)85²À¡ª¬LJ§<_²DjÅ{2 ˆ< "–4-‘3dóõÍÃþ½¸'q²úþêa«³XÝJO—??y¹`Ôååá=5 ˆ„$¼ÅWÀW¼ÅWO¢¬²LR×G/Yõp•”V—ŽÈÛƒuMÐRQ9ÈÚr=3SÞHKD„œß·ïÉ€ ÆÐ2>__ñ_=—wHÀû‰jŽ’£µGGí­×Úvu[¿Ç]Ù¾]ÞIÛܹr1'ß©A ô Ñ;‡¯€¯x‹¯ž†®Û¡A‡;/ï´Ù[²ÙÙ{ÿ®]Ò"ﺃ+Û¶á;Dž†'j@=Hôtà+à+Þâ«'°ëâ. |(-rðìAÛÏYQ!ç÷쑇 ò.0pÈDƒ­39Pw€öG€0†–±žø øŠ·ø:^É?/¿¼øEü?øËÖ«[m:—¥º¶e‹4ÅÄÈG//³†ÇƒÄD³xàPˆ’t?I–=YFû£€ÐƒDO¾¾â-¾Ž7túÛ5÷טiuõÆ_·GsžÚ£GåNjªY¥üÓÏ?Ë«ùóåö† rúرaÏ‚e9¦àTLïš.ÅÕ£“q‚¾úê«RVV–Lž<Ù™™9âýö>Ÿ»_謫Yâ÷ÁÏd>42’ß­¬¨ »wË£•+¥}Ö,éôõ•§±±fÁÀª’›ßÛ¢‹dÃí |NÔ€87éO*mmm†ððpóÚp÷Ûû|î~=2 ôt¾â+Þ¾öEk;´Æ#è]©ùîïýÕ¬ï1àЪòr¹¸k—<^±BÞH‡­úõW¹²c‡T•–:ÕÛÔ»©²¸i1í ˆkþ^Ÿ0a°÷Ûû|î|=m¬f"cKãÔŸl³Í6Ûl³ÍöøÜ.¸S sÞÌ‘yïæIÍÓš~?YT$srä]wÐñÉËKÞ˳ äiMKßÿG7Äë“— ˜ø<ÇÆ62 d@èé|ÅW¼õUg’ZҴĬ©±ùúæ/öŸ=tHÈë°0éúùgy¹`ÜLO—S……nåm̳I¹—B[$â^5 úÚp÷Ûû|î~=j@ë øŠ¯x žåkYe™¹a×iuW=\%¥Õ¥=C«.åäHc|¼¼÷÷—??y'—w²2·õvß¹}âÿÞß #£=RâÒY°Z[[%j ý}ÏkëùÜízd@èé|ÅW¼ÏõuÇåð>@¢š£ähíQ©)*’òâ—_¤kúti›;WÖ®•ºÆ”·sÞΑìËÙ´G2 Ž_d õ@tí‹ÁÖÁl¿½Ïçn×cÏãHíthðq´l£4$'K[h¨ZõbáB¹Ù„Ô8qh•½Ñú/ðYX ½Mœ8q\_ =€¯øŠ·à9¾–T—Èꆕ’XÿG¹˜*üü䃿¿4._.—²³¥ÒEC«ìí­#óêò’c§Ñ&É€ ± j@ë øŠ¯x ãËW“ÍØ+õ«§Éï—–°`“õ¨;xpÜz×'«¬¦MR‚@虣w__ñ_A}^ž4$%É«° yïóïr~µ—œÙ¹ÚÔyx‚·ºz»o§¯”W–Ó.É€ °7:3Õå;äɯ¿JÇŒÒ>ÓONo ’ÄóÓ%ãúFœ*ìu˜l½¶•öA "¡gŽÞ9||Å[|µºÇ­ôt³&ǧŸ6ktÜMI–ìS«Äû£·Ä?Ž—â“ÅëmæõL‰h‰ ]’A ŒMf|2¾¾â-¾ŽzhUn®Ü_³Æ¬>Þåå%Ï££åúæÍròÄ Ùuq—¾ 47Ý:ÉÓ½Õ5N¼;½åpíaÚ&5 ˆ„ž9z=ñðoñuXC«JKåÊöíò´ûïs‡¯¯¼Ç+WÊÅ]»ÌbzLþé|ùåÅ/âÿÁ_¶^ÝŠ·VèâŠ+¯ m’A 0§ äÖ† Òe†Vµ†‡ËÝuë¤öpïžü²ª2YsYÅ<é~’ÙÆ¿ÞäŸÉ7þà 5 ˆ„ž9z=ñðoñÕBE…œÛ¿_¬^-o»ÿî~Ô¡UK–ȵÌL9YÜ GÖÕ,ñûàg2šÁÛ™ÿj¾dÜÈ }’A ŒMfÜ7¾¾â­çúZ]Z*W·m“§±±Òéë+í³fÉ£„¹°{·TV @¢š£ähíQüu³ÚgÉî »ñ‚DBÏÞâ+à+ÞŽêòò¤%2RÚÌ*åë?ŽÔ1A‡;/ïÄ_·ÙõwÖKôóhü$‚@›Œ·ø øŠ·îÏ©ÂÂ?¯Ûáí-·ÓÒ¤²¼|Ô¾–T—HÂÃ3ÜJ‡]•W–ã±Ú¬Ng¬ÅèÇkŽã)5 ˆ„ž9¼ÅWÀW¼uOªJJäþš5f…r],ðä SèÇ×M×7™ó˜¦)4ð°HŸGDDôlë͹šn‘> ð|Coë~W_ð¸óî@£!9Ù˜?Ž—“EE£:f?¦}ž&ºì~„w†ËÖ«[ñ؉oŒ—ć‰xA ˆcÍ„Lš4©g[Ÿþü¹g[Ÿ[ïï«¡Ž·u¿«¯G„žÀW|Å[O*0¿¾y³|ðó“ Jí‘#6Og´Jú”dþvnì~¬n_M;só6{èì!ñíôõø)É€ØY+V¬0î4± Áš0aBÏþ¯¾úê‹ß±ÞßWCoë~W^O€k………™±–Æ©?±ÝÔÔäÔëyÒöëׯñÃÛ}âíÕÝ·õ{ÖSÿývï–öÐPé˜7Oîüef+[Ηu-Kþ½ûñ¬û¡ÒŸš¹ðìíÍÍ¿æ¿/[®máï—‹®?n‹ÐãââL&ä‡~ÇË7ß|C„ =ø€¯øŠ·è­f9^.Zd²×33MÄ–óWKÜ“8™ö§i²öÓÚ^?5 ¢µ ´5÷n³|„·†ã+Ç©¨¨È¦V#¡¯¤&Ãúx[÷»úzÔ€ÀxDë:ããMǽädS÷aë9·^Ûj\Ò´Äžô`¡A÷F‡_éôÈ: ?@ì¢uëÖIkk«éù¯­­•éÓ§Kccã³Dé1ýÍÕwÓPÇÛºßÙ×#BOà+¾âíxFg²ºÛ}/ 3[é W:Ó•­ç}$ýVºÉ‚Ðf=»Íî¾°[fµÏÂ×ñ€è:Ãáø‘5 |Ùâ-¾¾z¸·Õ%%ò01ј?èþYm§s%ûr¶Ìü0S?_,…5…´YÚlïe÷ÅÝø:^ ,¬(™0a‘¾lñ__=Ô[ÍpÜÚ¸Ñd<4ó¡»ó?uÜ ³Ñàc祴YÚìh-Pô‹h|C°t•òÐÐPimmíy­¥¥Å¼VÑýѨÏãòΦÆCk=´æÃ^çÕáU:ÌJ‡[%¾Ž§€0†oñðuü{{öÐ!iŽŠ’÷þþrmëV»Ÿÿpía‰h9o昱û´YÚ¬½ˆ/«®ÂWDð_ñÆ‚·5ÇË“¸8ùèí-wSS¥²¬Ì¾=Ô•e’t?ÉôR§ÞM•ŠÊ Ú,mÖîÁ­fÕ´­áë8@t¶«~ø•Ð @`œQÕh4$'›óÇññr²¨Èîרsa¶Ê‚ærìô1|‡Ñ!™×3ñb< S§NípXÃJè ô á-¾¾ŽAo+*äúæÍòÁÏO^,\(µGŽØý'Nž0k4Ìè˜!YW³h³´Y‡³õÚV³Ž ¾ŽƒD V<'a -Þâ+àëøðöÂîÝò&8XÞÌ+öìqÈ{Ö^hßN_‰kŒ3«UÓfi³Î ¼²Ü´»ƒgâëX@Èr€ÐƒDï¾¾Ž}o5ËñrÑ"“õ¸ž™i² ö~¯GÏ•y¯æIÐÛ Ùwnm–6ëtV?X-Ë—ãëX@tÊݶ¶6‡ÞL755É¢î/ÅI“&ôùÓ§O{“••%“'O6dvq¥¡Ž·u¿«¯G  ­ëhŒ7u÷’“M݇#zž“ï%›"ó”{)fïÁh‘W——”T•àÇX@êêêÄÇÇGZ[[€øûûKNNŽ|úôÉ-=û $44ÔBJxx¸ym u¼­û]}=2 ô ¾â+Þ…ÎduwÝ:3³•Îp¥3]9âýí;¿Of¿›-‘¯"M„6 ®övÁË’~+_Çr2Ð*èöœ«¿ó肇é͹šn‘> ð|Coë~W_ÆÐ¾â+ÞƵ¬,³–‡®é¡k{8â}imGÜ“83æ~,Îþlرc‡yÍ"–¥¯[¤Ïõµ4Ôñ¶îwõõȀЃøŠ¯xÛç÷í3«—¿íþ›pq×.‡Î6¤³[-{ºÌÌvE›wò¶â÷ ñïïöuHd@\¬—/_öšîWŸ·´´ôÊÂŒ¤8~¨ãmÝïêëQÖœÉÏ—çÑÑÒ1c†ÜÈÈpH¹e|}Ts”Y×cï…½xn‹Ö"-}¶/@Vdd¤É€X×€DDD ð°`­°°0“š³DÇúÓÛwïÞuêõÛ( Ƽ¿üýßß§¯ž–é]ÓåÌ•3üý²Ã¶K+W®ÈO?ýdzå}®¯ÙKýõö[¿Ö_„¾6’š ëãmÝïêëQÂZÀW|õlo+ËËåNZštz{ËÓØX9UXè°ëçÖçÊœ7sÌ*ÓGjÐfaÌx»äùI½›Š¯c1R__?`º½‚ñJë>¬k@ú›Kgâêo–¨¾C˜†:ÞÖýξ5 Œ¡|ÅWÏB¦L+Û¶I{÷ßÈWóæI]^žÃÞCIu‰Ä?ŽŸNɸ‘A›…1ç­ hÀ×±€h¶#**ªWM†>×!RºFˆ=ÔØØhΧ3_)ú\_³–®1Ð:ýÕP v¼­û}=j@<0éq.y(—³³zýíW¶‹_‡ŸÄ<‹‘¢š">³½ ’œ‹9x1Ö ÕÕÕõÅëZ«a=U®+åì÷áÿn2 ô ¾â«g •*0W NÈ %à}€ìº¸‹6 cÞÛ ·7È¢‹ðu, _¼®A‰» ž(j@C øŠ¯ž€8jÚÒ´ÛiâýÑ[V?X-eUe´YÞêz5ZŒ^xª_ÇR¢Sâê¢xÍÍÍ=5ú<((È ÏBd@ø²Å[||»Ⱥ2·m®„½“CgÑfaÜy»ìÉ2IºŸ„¯c)ÑBóŠÐoݺE$àáØsû÷K[HˆSÒªRIx” >}$ýVºÉ‚ðÀx$¯>Ï,œYQI3ˆJ ÍvXŠÄõ9Á=Hx‹¯€¯öáTA4ÅÄH‡¯¯YHp°Y°ìq½ìËÙ2óÃLYü|±ÖÒfaÜ{Ò"Û®lÃ×±€ ÆÐâ-¾¾ÚŸª²2iHJ’^^òpÕ*©.)q¨·ÇO—èçÑ&øØyi'm–6è1Þnº±I"_Eâ+"x‹¯øê¹\ËÊ’~~òbáB9sô¨C½ÕáU:ÌJ‡[%7W^‡…ÉÛÙ³åâîÝ¿ž–k¹šçÕåñ€Ç²âÑ S÷„c ùî»ïäÍ›7_¼®¯ýðÃDd@ø‰·ø ø: j åil¬túøÈ­ôtù}˜ëyŒÖ[íñM|hz}uŠ]ŠÌi³žîí‘Ú#& XVY†¯î€ô·ê·EøÃˆ¨áËoñðu*ËÊä^JŠ©óx´b…T;Ü[]DPÔØtqA>Ú,Þþ™y-ódóõÍøêîÈäÉ“¥¥¥å‹×u-¯¿þšH€ _¶x‹¯€¯peÛ6y?s¦4GEIíáÃ÷¶¨¦HbšbÄl¿²Ï€6‹·}Øzu«„¾ÅWw@ôÆV3?îYˆðáÇ&3¢ "j@ 7uJKD„¼ ”KÙÙN¹fÆ ñîô–WHi5EæýNÈPY!¾¾r°î ~¸s¢µ-DØÞÞN$@„ÿ˜x‹¯€¯–:¢"y'}|ävZšTVT8ÜÛõ‡%¢5Bæ¼™#¹õ¹|´Y¼‚Õ÷WKÜ“8|uçÄ2ÜjêÔ©= N›6MZ[[‰@C‹·ø øªuåår'5U>z{KãòåròÄ ‡{«…´I÷“Ä룗¤ÞMe•gÚ,Þ­‹òêò’’ê|uç€Ðƒ„·ø øÚ?—wìöY³äÕ¼yröÐ!»Ÿ?ÿNþ¯í¹°GÛeAó9vúm6‹·#dÑËE²ñÖF|%AÔ€ŒÎ>,¯æÏ—ö€¹Ò„8â:mè”î‡þÔí'OHìÓX™Ñ1C²®fñ9Œ’œK92ûíl¼pçäÈ‘#f=ëiwuHÖóçωÈ€ðoñ<ÊW^õ8>Þ ·º›šj†_9êZqÍq&YÚ´T2¯gŠo§¯Ä5ÆIqu1íŽ6‹·¶£ÿ^a¦ªÞw~¾ºcRRRÒStn€œ?^BCC‰¨áËoñ<ÂW-(¿½aƒtvOº¿ƒµàÜ‘×ӬǴÏÓäB÷cj÷# ½ûféÜ>ÚmoíDÊÝ3m5¾ºaòã?ʦM›Ìô»ÖˆÎ€Å:  ô á-¾‚'øz)'GÞIkD„Ôåå9¥HvþÛù²¡û¡Jýœ*KŸ/¥­ÑfñÖŽ,’é]ÓÍO|u³Ä:èè»ò9+¡€Œgj•— È{¹ºu«C¯uèì!YÛ°Væ¶Í•韦˴îdzî‡Jj6ÄR öA3 š Á 7 @&L˜ _: ï¤I“ˆÈ€ðoñƯÕÅÅò(!A>zyɽäd©*+sÈô½öÊÊG+ÍXt¿?YÞ¸ÜÇþÚü«lì~X+íOi¦„öF›Å[û¡5 úÿOÿ?â« Zl>kÖ,iii1ȧOŸäÎ;&0ñ÷÷' „/[¼ÅW?¾VTÈÍôtéôõ•gK—Ê©ãÇízþ²ª2Ù~e»Ä>‹Ÿ>ô6HV?XÝkÁÂS…¦ð| ‡î§ÍÑfñÖ~èlXøã« >p%ô¶¶6»ÜL÷wîo¾ù¦×1YYY2yòdCffæçêx[÷»úzd@èA|ÅWûra÷nyÛý]ú:4Têsí·¢¸Ž/ϸ‘! _.”Ÿ»~–ðÖpI½“*ùgòi³´Y¼u6ÜÚ`ÖÁW7 @,AˆõJ莞‚·¦¦¦×MxAA™qK%<<ܼ6†:ÞÖý®¾5 öãL~¾¼øåùàç'×¶l±Ë9ž9jV'×`Cƒ½¹ÙtcÓ˜)vð$tEt]]'À7 @œ-Ë/‹ôæ\£>‹ôyHHÈ€¿?Ôñ¶îwõõȀЃøŠ¯v¨ó(-•‰‰¦Îã~R’TuoÛr>F¥Ã©f¿›-ÞÞfÁ@n¥Ã®h³´Y¼uoâžÄÉêû«ñÕSÚÚZIIIéõš»ë4ÀéóÁ à‡:ÞÖý®¾5 Œ¡|ÅWÛêÞÖý®¾5 Œ¡|Å×á¡uZß¡uZïQ=Ì:ëEµ8uÉó%²åÚS¬Š·´YŸÞj½–Ní® ~zT ˆõð ¤Û]]]v_ ýÊ•+^[f‰ÒÅû›%ªï¦¡Ž·u¿³¯G ch_ñuä\ËÌ43[é W:ÓÕ`Ƕ( Özà-m<ÃÛ„G ²âÑ |uu¢ëRhVâñãǽÖçЬˆî³—ô¦»®®nÀý:-ï@ëdôWC1Øñ¶îwöõȀЃøŠ¯Ãç\n®YËC×ôе=ëíjQ@¼¥Í‚gy{äÌñþèmóìud@ìPn]÷i^×(L§ËuéÚ$ãùzÔ€ Í©ÂB³z¹®b~ó·ßú­ó°uQ@ÿD¾Š4ëöà…‹§áýñÇÍp«)S¦ô¼6mÚ43Ëòì„$¼ÅWpµ¯UeeÒœlê<%$Huqq¯ýc}Q@Ú,¾â­sÙve›„¶…â««DÂZ¼ÅWpG_¯nÝ*fΔ— HíÑ£=¯;jQ@Ú,mÆ¿·ºˆ® r î¾:;ùî»ïdùòåd9@èA¢ _Áí|­;p@ZÃÃå]P\ÌÉqÚ¢€´YÚ,x†·I÷“dÙ“eøêìD×ÿÐ)xµîCg¿òõõ•óçÏKGGwÿ .¡æøqyúë¯Òéí-×ÓS%ëJ¦,~¾ØL•«Sæ&7$›)tñ lA×ù™Þ5Ý,>Š.‚õòåKÙºu«©±¢k-HVV–477 á?&Þâ+8Ü×Êòr¹»n]wàá%S"$æñ}Ìâe•½‡P €àm_ñv<¢ßƒºžÑáÚÃd@€Ô××X„NBãâêbS`îõÑK%HñÉâ~#OdÕÃU²âñ j@€h¶#**JZZZz^Óçf{©¡¡A"##eÒ¤Iæ¼EEE½ögeeÉäÉ“ ™™™Cžo¨ãmÝïêë‘¡ ðÕ3[¥ÝNŸN‰iŠrºIÚ,¾‚'z›&ßtДU•yŒ¯.Y ½««ë‹×?}ú$'N´KðñðáC™6mšÔÖÖÊçÏŸÍš#ëׯïÙ_PP ¡¡¡fAD%<<ܼ6†:ÞÖý®¾5 Œ¡|µ7ZT©+–Ï{5OÔ ½FÇå; @h³ø ëíüWó%ãF5 Ž @:;;¿x]ƒ{ «V­ú"ãa-½9רÏ"}2êãmÝïêë‘¡ ðÕ^칰ǬZ>çíɹ”3äñ:•nãòåÒáç7è,XxK›ÅW¼Ïl¿²Ý|w’qP2uêTs3ÜÜÜl²Š> 2óì¡o¾ùFŽ9"?üðƒ jôùæÍ›žý:,K¯k‘>××ÒPÇÛºßÕ×£låÐÙC²àåñûà'›®oê™Ùj0êòòä]` ¼ˆŽ–“'Nà#x,ú©ßŸ¹õ¹Ô€8"ÑBóŠÐoݺe—DϵfÍ“UÑlKRR’,_¾¼×þþ23ƒo°ãmÝïÊëi°`­°°0“š³DÇúÓÛwïÞuêõÞÖý®¾5 Œ¡|ÉÌVooßN_YÜ´ØÌÞ2Üß½ºm›túøÈý5k¤²¢_i³ø xÛ‡èÑfö@j@Æ`¢è:ìJƒE‡c­\¹ò‹Y¢tv¬þf‰ê;„i¨ãmÝïìëQ£aÛÕmÐ`VíÉ8åêÒRy+ïýýåü¾}x 0».î’ÀwÔ€Ø#Ñì?üá=ÏÂrŒ=”-ß~û­z׫]¥kc ´NF5ƒoë~g_ =H€¯#aïù½ò:D‚ÞIöåìýî¹ýûå}@€<‹‰‘ê’|¥Íâ+àíÌjŸ%»/ì&bk¢…¥ZŸÄ`…ÙΔ½¦v×ëQÂZÀ×áp¸ö°,z¹Hü:üÌüôÙ٪‡Š iX»V>úøÈµ-[ð•6‹¯€·Ãdýõý<š±6 Ý„$¼ÅW×SXS(qOâÄû£·$ßKñê¼§óóåuX˜´†‡ËécÇð•6‹¯€·#@'õÐbôã5ÇÉ€€€À8ŸÙªªD’î'™™­âÇKÑÉ¢Ÿãzf¦ÉzÜKI1Y|9±ÏbM5 v @«ó°g "x‹¯Ã£¢²BÒo¥›™­4íôÌÑŸ£º¸Xš/–öY³¤>7_i³ø xk¹çrÅÿƒÿȆ¾’y¢Eâ  Œ¡Å[|u.Û¯l7á­áæÞhÎqaï^ùàï/O~ýUªJKñ•6‹¯€·v øM°ì¸¼ƒ[Áf¿²0Ôbyˆ à-¾Ú‡}çöIØë03ÝãhÿÀU–—˃ÄDéôõ•+Û·ã+m_ñoíÈo7“¨æ(2 ¶ –™®,ÓíöE§‹ÍËË# ÈÑÚ£òË‹_dFÇ óÇm´éýÚ£G¥mî\y5¾œ:~oP—§5yù§óÇÝ¿ÍéC°Üeª]D„$ð$_‹jŠdyãróÇlmÃZ)­ýP©›¿ý&½½åNZí•6 øŠ·$¾1^&’áV„qžŒ¡…±ã«phࡈ"£=×É¢"y±p¡¼ ’ºƒi¯´YÀW¼u0‡Î2„”W–Sb‹ªªªdåÊ•_¼ž˜˜(555Dd@ø²Å[|µÇÌV¿W˜!V:ÔJ‡\éÐ+›þ99Ò1c†<^±BªÊÊh¯´YÀW¼u:IÈ–k[Æ•¯N@¾ûî;3ãU³`ýðÃDÔ€€hQ¹—‡µ†™bs[ÎUÙl<ê:4ø¸Ô„à/€sÑàCƒj@l¡³½x‹¯ögÿ¹ýæT`{ ™^×Öó=tHÞΞ-/.”š¢"Ú+mðo]€¿òéô1ñȀŒR:ÛUKK˯777Ë×_M$@ _¶x‹¯#ÙêÌQ³€ o‡¯YPP´õœ·ÓÒL¡ùÍôtÚ+mðo]Œ¢kA:5 £”ÞØj¦ãñãÇòùógÃÇMf$$$„H€ _¶x‹¯#˜Ù*þq¼)0OºŸd¦l´õœ5……Ò<¾¼ –ÚÇi¯´YÀW¼ut*^ý®·eC΀h­Ç@ ¶·· PCPVU&É÷’Í£¸'qRXSh—ó^Þ±Ã,*ø01Ñ,2ˆ×îƒ.J¨“‹P2Jép«©S§Êĉ Ó¦M“ÖÖV¢z9ð_‡˜Ù*ãF†™Ùjá‹…r¸Ö>ŠªÒRy'üüäÂîÝ´WÚ,à+Þºé#Áo‚É€ Æy2†_ãköål™ýn¶„¾•}ç÷Ùí¼õH{` <_¼XNÓ^i³€¯xë¦h'”ÿÉ=—K "¡—ƒ$|uÜùsës%¢%BfµÏ’mW·ÙïÜr7%Åš_ß´‰öJ›|ÅÛ1@rC²Ä>‹%2EEEɤI“¾¨a^øKÁá™|Yò|‰Ywí v]÷tA´DDÈëÐP9“Ÿßc„ã5Çez×t)>Y<¦ÿN@.\Ølô @&L˜@$@„/¼õh_OœÚ+mðoÇ(»/ì6Ãr©¬WB·~®ë|ûí·v¹™îoŠß¾ÊÊÊ2Á’™™9ä9‡:ÞÖý®¾zÀ5¾jQáæ›Å,x¹@ŸµÿÚp¼Ÿ9SžÅÆJui)í•6‹øŠ·cœÀw²ûâî1ë«K¶¶6ó\§à­®®6ÏëêêìVÒ_Àa­‚‚ 5ïC 7¯öx[÷»úzÔ€¸†œK92çí i ‘½öÚýü•r?)É ¹ºš•…çã„´Ûiý"š᪤¤DÍsŸ^YŠ~øÁ)ˆÞœkÔg‘>lö¡Ž·u¿«¯G„$p®¯yõy2ïÕ< x YWhq¹™k±ù©‚Ú+à-¾âí8¢¸ºØ£Û2\×c×ùôé“üøã&óñý÷ßKWW—Ýo¾ùƵ{yyIvvv¯ý:—ù²þ¥¯ ¤¡Ž·u¿«¯G chÁ9¾;}LbšbħÓÇô^Ùsf+ktZ]^÷îºun]hN{Å[|¼=±OcemÃZj@ÜQ?63oedd š!l®¡Ž·u¿«¯G„$p¬¯:³U£3³UâƒDÓsåˆ÷¢ >Ž6 ÖçåÑ^oñoÇ1ºN”Öj-!7T{{»)Æ&ÒàaÁZaaa&2¶4NýÉ6ÛllûÜ¥s’z7U|»|%ém’œ¼vÒa×{V^.3gJc\œ\ª¯Ç¶Ùf›mØo—ãϹ÷ïô¤©©I¦NÚ3K‡^iýO?ýä´¤¿ }m$5ÖÇÛºßÕ×#BŒžü;ùýÎl•y=Sü?øKTs”:{Èaׯì<®Z%¾¾ryÇÚ+à-¾â­‘q#Cæ7Ï'2”‚‚‚¤¡¡Á<‹‹ëU„a—€cU÷ãÆÆFóüåË—#)))_ÌÕÚÚÚï,Q}‡0 u¼­û}=j@C öáHí™ÒýП–×v]Ü%sÞÌ‘¹oæš¹ÚyýÚÇåMp°4GEIMa!íð_ñÖÃÐ5¤txoþ™|j@“êìì4ÏuÖ+½ù¾qã†Ü»wO¾þúk» :µ¯¿¿¿9·¹ký‡åšéÚ­“Ñ_ Å`ÇÛºßÙ×#B؇__þjýy°î Ì5_üßûË–k[~í[éé¦Ðüö† ´WÀ[|Å[&þq¼¬z¸Š Èp§ÈÕÂhݶÌ~e¯u@l•®O2ž¯Ç: öÉ~Lû"##Íë:mÖ¬YD€0ÎoÝ-0O¹—b²Ϻ*ý©ÙëZ{RÕl<Ž—Ž3äbNíð_ñz±õÚV {F È`²,>8eÊ”ž×¦M›ffÈBd@ø"Á[weï…½ü&Xf}œ%»ÖÒm­±÷5ë”w³gË‹E‹ä䉴WÀ[|Å[øþëÛé+Ï$‚@Æ:»Hô‹hñëð“ ·7˜Âó…§ì7ÕõëM¡ùÍŒ >”ÕVËòÆåÔ€ z9èAË”T—HâÃDS`¾æþ)­*uН§ åUd¤´Í+µGÒ^oñoñaHŽ>&^]^RRUB¤¯tÆ+Ëô»}q—Y°@¨a -u¿Ýüͤ³cšb¤àtÓ|½²}»túøÈƒÕ«Í"ƒ´WÀ[|Å[¼. ^.ô[éÔ€ô•®‚npX£Óò"2 |à­+ÑÅç¼#!¯Cdÿ¹ýN󵪤Džtÿ?üàï/ç÷졽Ò^ñ_oGLöåló7Œ Hi QQQÁ?€[qôÌQYôb‘ø}ð“Ìk™N½v}n®´Ïš%MK–Huq1ŸŒ:ƒ¯ âî;·k‘å ¡—ƒ$w¢¸ºX&˜:¤†$)«*sž¯r/9Y>úøÈõÌL>Ú+Þâ+à­ÍèTñKŸ-%b-z·­­;~Æyâ­Ë{‰tœ¬ÖyèuÁ©§úzúØ1i —Ö°09ŸÏgB{Å[|¼µ E5E2½kºœ8y‚‹êêêÄÇÇGZ[[¹ë'¡—o]®‹»döÛÙfѦÜú\§ûzmË“õhHN6Y>Ú+Þâ+à­=Yò|‰¤ÞM%bQ³_1 €Sêpºpn@{5 ÖEèA}½xë¨:•Vš:ä†ä×yØÃ×ó{÷ʇ™3åi÷ÿ5ñŠ6I{Å[|¼u$Aï‚$çbDÂ8OÆÐ:µÎ£²B6ÜÚ >>û4VŽŸ:ît_++*äþêÕfm«Û¶Ñi¯x‹¯€·NaÃí fvGj@½ô 9‰œK9¦÷'¼5\Ôp‰¯gŽ‘¶i‰Œ”S´CÚ+Þâ+à­S³ÿZŒ^xª ˆ***J&MšD €Ý9\{X4/0ó o½ºÕeïãFF†|ôö–;©©š€knôŸ,“¤ûIÔ€,\¸°'Øè€PBB/ÞŽnpÅã¦ÎCç@/«,s‰¯'Oœ¿ü"ï¥./¶G{Å[|¼uyõy2£c†’ìÑÉ“'K}}}OAºêÍ›7-ùùùDÔ€ð…·#®óH»&ÞÞòëÓ_åxÍq‡_S¦L??iŒ—ª²2ÚíoñðÖå„´…ȶ+Û<»D3ý=ÿüù³|ûí·Dd@ø²ÀÛa³óÒN |(-’Wç¼lƒ 6úS÷ë—³³io´W¼ÅWÀ[·aÓMù*Ò³3 tXVBŸ8q¢TWW›çº@!5  êó8{Xæ7Ï—€÷ýöê¸2áówB§ž÷þè-GÎñÜ’’ILL4ÏuEtë~øH€ _x;hG|c¼ù"]ww”W–»ä}€Ð^ñðoÇ+­„G ž= –EŸ>}’üÑd>¾ÿþ{éêê²ûuxxx¯¡^eee™z%33sÈó u¼­û]}=j@CëÎh ±þÎzñùè#qO⤨¦Èeïåž= ´W¼|ÅÛ1Å‘Ú#æo¨õ-¬â •––JHHÈHAA„††š¡`Š)úÚ@êx[÷»úzd@èArgv\Þ!³ÚgIdK¤¬;èš÷QQ!׺ƒú¶¹så}@ío_ñvÌ1¯ežl¾¾Ù33 Ϊóxÿþ½LŸ>]ž>}úE¢7çjºEú\•4Ôñ¶îwõõ¨wäÐÙC¦h. =@v\Ùá’÷PUR"wÒÒäÃÌ™òºûÿYɼ;l,>;pGtm¬ÐסžY¢…çÎPzzºäåå}1Û–JAÔY·¬gàÒ×ÒPÇÛºßÕ×#B’;¡Ã«âãLGêT—Ôyœ:~\$&š…_,\(ç÷í£ÍÒ^ñðoÇ4:m½o‡oÏhÊ€L™2EÚÛÛ|Ü»wO‚ƒƒûî·¿mÕ`‹ u¼­û]y=m¬fÆZ§þtÆvSS“S¯çIÛ¯_¿vë÷×ð°A67n6Çê—«åú£ëN?7ËÊäil¬|òò’7))rý/+˜öû}ÒÞ<£½ŽåmýžÅþ~ñ}à™Û럭—”7).ÿûåôäÌ™3Ð3¯#¤ÁGccã€7äd@ȀЃä^l¿²Ý µšÿj¾zåtovï–æ¨(éôñ‘ûIIRSTD›¥½â-à+ÞŽ; NˆW——”T—xÞ: a¯úÎ?X„¾6’š ëãmÝïêëQ®BÓÀZ§Eæ;/ïtêµ+µ°<3SÞKû¬Yr+=ÕË`ܳèå"Ùxk£ì¹°Ç³ŠÐb°aI¶$ýÍ2ÕÚÚÚï,Q#=ÞÖýξzÜ¡Îã×'¿š)Óî¤9µÎ£Z ËSS僟Ÿ¼ “+Û·›ÂrÚ,ío_ñÖȹ”c:þ¦t?tz^¦áuú«‰Ðµ1Z'c¤ÇÛºßÙ×cæQw:ÿ¸. ¨uñãÍ‚N+,ï®Z%½¼äÅ/¿È¹ýûi³´W¼|Å[Ï+Fÿ½B~þô³ @bŸÇ€¸‹œ5S—«®G„$W°íê6™ù~¦D5GÉ᳇vݺƒåÙÒ¥ÒÕx4._.gŽ¥ÍÒ^ñðo=Ízüûç—Úϵ2íó4—dAÜjg­‚¨çq î€D´FHà»@ɾ”í¼?X99òjþ|éôõ•†µkåä‰|àñÄ<‹‘UïV™û½´?¥¹$ â6È›7o@@èåGÞÖʲ§ËÄ»Ó[6ÜÞ`æwxayy¹\ß¼YÞv·ßöÀ@¹ùÛo/,§Íâ+Þ¾âíXÊ~LýÓTiüôçÙbŸu?\‘qZ2ØìW†š*ÿ„qžcß[­óH¹—"^½dåã•R|²Øñ…åÅÅrwÝ:éðó“Öðp¹¼c‡M…å´YÆ|ã-à+ÞŽ×ìGâÛÄ^÷|®È‚8-±Ìte™n·/Z,mY¹‘±émÖÕ,™ùa¦,x¹À)½)§ äQB‚),-çrsi³´WÀ[|Å[èod©BSx>ÐC÷Û!XŽšjQ.¬ó¨? a­a2ûÝlɹ˜ãøÂò¤)&Æ–?Ž—3ùù|cfÁBd@èA²©7%öY¬øtú˜Etj?Gþ.egKKd¤tøúʽäd·(,§Íâ+Þ¾â-¾€ j@ÀÁÞ–U•IrC²©óHx” ÅÕŽ«óÐÂò›6ÉÛ  y×ÍŒ ©t£Ëi³øŠ·€¯x‹¯ ˆ 8ÐÛ-×¶ˆÿYôr‘9ã¸:“ÅÅr/%E:fÌ–ˆ¹œMíð_ñÈ€ ðrÏåJØë0™ýv¶ì¾¸Ûq…åÇŽÉã•+M}GÓâÅRàþP‚@èå𔞎‚SfÚ>ßN_I¿™î°:úÜ\y¾d‰™ÑJ DèA¢½Þâ+à-ÆyzÈXO­óHjHúsÇCÇÕy\Þ¹Ó ±Ò¡V÷Ö­3kz0†ðoñð–z9<¨§#óz¦ø}ð“_^ü"ùgì?Å­‘ßÌÈw¦¸üÆæÍ¦Øœ$ÀW¼ÅWÀ[2   àAì?·_BÛBeΛ9²û‚ýëøûËõ륺´Ï€D%uuuòéÓ'ùüù³äææJPPPÏþ‚‚ •¶¶6ƒ+úÚ@êx[÷»úzd@Æ>ZX¾äù™Þ5]–=Y&ëJá©BSx>ÐC÷§°üÖÆÒ o‚ƒåÚ–-RYQç´Y|Å[ÀW¼ÅW¡¤Ù‹ôæ\M·HŸ‡„„ ø»Coë~W_±IYU™)&×Ù¬üßûKêÝT9qò„]¼­)*’ûkÖH§··4wôvïÆsÚ,¾â-à+Þâ+Èp¤¼¼]žÆÆÊÙC‡ðœ6‹¯x øŠ·øJ2\}õÕW†ï¿ÿ^{½ÞW&Lô<ƒoë~W^O€k………™ÈØÒ8õ'Û®Ý.V.K[—ŠW——¬~¹ZêŸÔÛíüw ¤]y˜(WkjðŸm¶Ùf›m¶ÙvȶGd@öîÝ+ÁÁÁd@È€Œ9J«J%ýfº½ ’Yí³$ívšWUq™2e@´°üêÖ­Ò*ïýýåvZšT•”à;m_ñðoñ• ˆ=dè¯FB_IM†õñ¶îwõõ¨q?òÏäK£ñþè-QÍQ’}){T š`£?u¿þ> @ÚæÎ•kÝAÈï–Ófño_ñ_ @F¯””yúô©yÞÞÞn¦¡µ¾·ÌÕÚÚÚï,Q}‡0 u¼­û}=2 îKÎ¥Yðrx}ô’•WÊÑ3Gm:ß`È…½{ù¦Íâ+Þ¾â-¾€ØCÕÕÕâïïonì¿ýö[ILL47ãÖÒ d u2ú«¡ìx[÷;ûz¬â^”T—ȆÛ$°=P‚ÞIú­t)©²ÏP¨Á¼7œ²w<^ ˆ{ «‘Ç?Ž7ÙŽ…/Êî‹ö™êVg®jX»Ö ¯"¡Íâ+à-¾â-An)j@œƒÖq츼C濚/>}dÕÃUrìô1ÛÎ[Qa†S=Z¹ÒÔutøùIãòår)'‡„6‹¯€·øŠ·@ "ñÄ^¹*õNª¼9oæHÆÍ ³àhϧ+”_Ù¾]žÅÆÊGy$V¯–úÜÜáςŗ/m_ñðoñ•yz2Þ8töÄ=‰“é]Ó%úy´ì=?úÂï“EEr##C^.\(]?ÿ,­áár'5UÎäçã5P‚@<µ—C‡Ym»ºM"Z"Ä·ÓWÖªKJð–1´ÐÛ·_‘¹sßÊôéŸ%8¸C¶n½Ž/´Y|Å[| €xF/GYe™)$ׂrÿþ²îÞ:9qòÄà¿7È¢€ZëA=H0xð1sfg·§]æ{èöm‘Ù³?ËŽ·ð‡6‹¯x d@ÈøE§Ì]ý`µ™BW§ÒÝve›™Zw ã‡»( Npð9w®£×w‘!sçvá5 ˆdüEã{Îï1‹zuy™ÅuÁŽ‹‹Òƒ„¯îÎôéŸúý~š6Mdõêû’‘qCvï¾(ùù§¥¢¢Ïh³øŠ·@€Œ½ñˆeUe’q3Cæ¼#ïdýõR\]Üï±ö\1´Œ¡…¿Ì(W^);v\–%KšdêÔÏrîÜç~2 ’ÄÄæ˜ÐÐ×2cFG÷±’™3?HDD«,]úL’’îËæÍ7dÏž RP  ÞÒfñoDâFÑø±ÓÇ$áa‚ø|ô‘ù¯æËÎË;ûfå¨EéA¢É“Ñà`÷îÿßÞ¹xÇt¶ýÿýÓ¬.KW×ÛÕ.JÊCTU)Õ:”òPÇRê¡U‡ªÓ#<”Šz‰Sq(‘!Ò¤ ÑDb®ßþÞ±ó›L&sH&ÉLòùf]+3{ïÙ{ϵï¹îû{_‡ûªÍŸÿÈÞÿ¥G*jlíÚbÛ¸ñ¦÷ÒŠŠ-äÃ3E¶cGIÛɃ§,;;϶o/´õëoÛ’%÷mΜ w®Ñ£A7î…MŸ^eŸ^n_}Uj›6Ý´]»®Ø‘#çú4A¡Í¢Wt‹àn”;,ëi–¥½L³/ʾ°ì¼ìVû»kQ@鋲gO¾-^üÀy0&N|n+V”Ú¡CÚ$¢gdÔÙðá—û±sgiǼ›'NÛmÛ¶köõ×·íË/ØìÙO¼sÖØ¨Q/½ó‹ ÔÙŒzöï‘w/%öïß°Ÿ~ºl?ÿ|–ç… x@:.ÇO·u·×Ù„çlBÝ[wgåäæ´ìï+‹2ƒ„^{BȳeË~wƒý±c_ØÒ¥÷mÿþ‹=®×ãÇOÛþsÑ…­]{Ç-z`YYO\"|ZšJ“M˜Pg}Ti <²U«JlË–‰ºlGž¡Í"èÝ¢W ¤­d_ȶÅe‹·ãã§Ûö‚í-ûzzQ@bhÑk¯®$wø¼­\y׳#µ.ê‹/:ÏB*éõøñ\(]r™5kнïPf³f=õ¾“Ö(i´#š,=ý¹}üq¥-\øÐV¯¾kß}wÝöîÍ·_~9C›Å è½B@@_ñ€(ã‡ÂlfåL{ÿåûöåƒ/íÐ…æÊTÉ´( 3Hèµ·ÉÑ£g]¨ÓÔ©Õ΃ðùçØöíεHv½ŠdìÛ—ïH‡È‡H–ȈBËDNDR&N|æH‹È‹HŒÈ̾}—¼ÏæÒf±ºÅ©ž¢ÊUk‹×Ú¸ºq6ñÙD[ÿÛz;q*'iDÞ ò(q\aJ#F4ÚìÙÞ€¼È%ˆCÈθœ…mÉ´`ÁC§§ ž»ð.‘4yˆö¥ð/…)Lái £}!B’¤lüÀŶðáB·vÇ'O>±Ýù;X$ôÚ…"r¡Y%t‹tÌœYiß~{ÓrrrÑk¢D÷Ý»/»Äw%À«"˜âǯs òJ”ÿðÃZ§g%Я[wÇ%Ô+±^ ö¹¦<0~øÌ{n¯Ú¼ù¿aÚ,ºE¯DáÊ•+6mÚ40`€ <Ø–.]jÕÕÕ­ŽÙ¼y³ 4ÈɦM›¢ž3ÚñÝßÓ×K¥…Y}_ô½Í¨šaï7¼o«o.²‚Í«SjQ@bhÑk*‰Â¨TîVaUii–™Yí ˆowi2v_n¯Ò·JÿôÓW:X%„çÍ+w%…UZX%†•[3eJó:©±Jë©4q8”ȇJ6/öXTTo|Ð ¡Í¢[ô I²²²,??߀544xå:GH|>|Ø222¬¦¦ÆI¦7`Õ¶öíøÎîïéë%9TÜ>i8v昭º»Ê>øûû¼t¢Û2Ǫ2§¦ä¢€Ì ¡×T €•Û Á®ªC­Zu×%˜£×ž'(z»v]u‹/jF‘C-ʨÅEPTêX‹6ΙóØ-☞Þв¾Š[·Téë:¥Í&­ˆ8OúÂFŽ ØÄ‰/ Ìx@R ""ýû÷oy¯Á¹”îC¯§L™Òîç£ßÙý=}½ž& 6dH»¢ýû/í·ùåóíÓâöë–t«žüAÊ/ ˆ É*ªü¤R¹È*H%tUJݤA9e‡w‹=nØpËþõ¯ß---Öök½t†$£lÛvÓ#ίìúõæ¶zûvÀyñ !䀤 òòòZy@èHI0AѶöíøÎîïéë% oûús-çÛ÷¬öƒö|üXdv½v…çñÐ棲²š9×b*'‹^{LŸÞÐ2ó¡•æG x$ó^›!Úl2¶Ùß~{…×Hj ´´ÔFm?nÙÖ¯_¿6Ç{HBíøÎîïéë%3©˜ö•¬øª×- H -zíù$ès®4¬òÞÿ¥K‚þñÇ«.›‹^“[vìøÍ³ëÖ2 ù˜81`«W—¸uLT•kÚ´*—sÒÑ$wlm6‘"rÆh£ä€$7 mäÈ‘VRR—‡¡/y@Ô| ÆÔ©S]ÃôÙ±þwÕûH¤;®ßWÞ‹„£Ä¿÷%î7/¯È¾ùæ7ûøãZt¼² ªì‡®Ù•+…´×>ðþàÁG6sf“½÷žBu_ÙîÝZöß½{ß# ÷lúô?½¶Ñh+WÖÚÑ£·Ñ_ïïÞ½‹>:ù^ ÙÙwmùòg6y²…ñ€˜Ë9ò•gÇžyÇ•ÚáÃÅÞ8ý¥ZÿÕk Hnn® :ÔŠ‹‹cʱжxr2‚ïìþž¾^2{@˜¡@ÎINÎiWêU â©lnVÖSCÍ "Òžü÷¿ç]b»ò€ÒÓŸ9O™šD7HWÉÞ½—\¹i…€jÏU«JlË–»ÎKìµ?¾ÑÙ/-æ¹uk‘-^\æWž¹Å??úèO8—Øž=—“Æ“‹ô1ȼ±ë»ÿ~Ä*S*Í®JThS´ã;»¿»¯!ÖéÝzýõ×SnQ»O?}ìVäž1£Ê6løÍ­Þ^‘Xu«AÜŽ®’–ÚÑ'ŸM¤ñ€€>M@|òÑÐpÎ]»¡!’@i^È©ÒÒÒþöžk55Ô{h]­Ï1n\û­Ûº€ Ýê·eË {Ÿ–Öèf›wフnçÑØ¾½Ð ø¥ kZ“F¹Ép^päãÓO+)™;÷GR”Å3„€€^N@Μ9¦dp|Dæ¶74¤Y}ý?íÅ‹±VW7Þž?Ÿhµµ“­¦F9.™VU5Ã*+gÚÓ§YöäÉl{üøSûãÏíÑ£ùöðáöàÁb»©ýþû2+-]awï®´ââ5vûö×öÛoßØÍ›íÆÛõëßÙµk[ºzu§]¹ò“åçï±K—ö[^Þ»pá;wØÎž=j¹¹¿ØéÓ9vêÔÉ” &¼ô¾_ƒ§Ï&ï;Ÿ÷­Ï!!)8ƒ¤¼•+ïz¿ÍZ×aj…òŸ~ºŒ^‘¤Ð­Ú§Ö’ùàƒ.õê»öóÏgÑk“fl™³Q²Uj‡ŸKzÝ8pÑ…gÉ;£p-…mÍ›Wî¸T²œ6 ½ÐrëÖno ¿Þ²²^ZZšÙôéMÞ`ÿ{»sg«÷ÿg;þ¿ 8h/þÇ;n¯]¾¼Û#?z?œaøÁyJ®_ß쑉MÞ¹6zƒìõÞg¿öˆÆj+)YéåvïÞ¿<"ò¥••-òˆÉB+/Ÿï•Ϭ¢âS¸|â˜íÏ??òÍ4û믩ÁùО=›äž ùgÿ=Æ#C£íåË4,°W¯†[ 0ÔÓÔPïõ0·MûtŒŽÕgôYCçÒ9un]C×Ò5+*æx÷0×»—yÞ=-p÷¦{Ô½êžuïwï®ö¾ËZ0­÷¾Û÷õ]õõÝ¥ƒ«Ww9äçïs:’®¤3éî£^„)cxÞ&Nü‹X ÄЪòÐ×_+^ºÚÅKþù¶}{AŸH¨$ž>uu«\¤¹s›×gÍzâ "huvôÚ[“É›2?¾ÎUNS~P¢ó,ºS·²¯J\W»ÂÆÔŽEª,xèÝ•ðN›…€€^@@TåbâÄWmÈúî»[)áfþõדvâįNŽ?a¿ürÂ3P9öóÏ9vøðqûïsìàÁ;p Çöïϱ½{OØîÝ'l×®^G}ÒûþÿçuЧ¼ï{Ú3n¹¶iÓÛ¸ñœ­_Þ֮ͳU«ò=ã~Ù–-+°/¿¼f‹_÷ áMo0zÛ>ý´Ø>ù¤Ôfμï·‡–‘ñ‡MžüÄ3–Ú”)å6ztÛ…œ­ðÒë$~óÎwßÍP}ûíM7°UOo2®©8ƒtüx®÷üozä±ÒÅKÏž]áâ¥Oœ8…^‘”Ò­ÂmÖ¯¿m~XãÙ¢zWå(;;½öiž¹ãõ39Á‚¼>íJ¯Ô­úy•öU‰_…ªä¯Jÿ.ZTæJ'KX‰S¦M«o3K/2iÒKçúT<æÁƒynFeß¾|c¼k×UWò‡ ]˜ÑæÍ×Ý ¾Š1U‡·ví7°–ÁÐBEÿú×=7Ø–ÁÐ,†\«Š÷Tš\®šåaQœªªs¨Ã”Ѭ‡\±~Òšf¡e|† {eC‡š'>ü•Û¦}~,©>£Ïê:—Ωs뺖®©ØSÅÇ*nZ¥uoºGÝ«îY÷®yŪ*6UßQßUßYß]:øñÇ+N'ª£.IWÒ™t—•£ÛFàUzFs‹G8vyçý?ÔÜðHL¹wÏÏÜlVšUR³*ÞÌœYé‘r7«%½*|KUK4Ð`™]"’4E@¯{dã‰#Ò¹HaNúEz‡È6-ZôÀ¬68{([}ü8‰ë©$*4 $Ù'õšÑ<ždòÞ’û$²¥~Zýºúõóê¿·m+¤]C@@ª­Èÿø‡¹ÎJa%Úʽ«E±4(Ö¬‹ª¯h}C-®&c(·¿ËšQ•UR‚®vUhÕª»®4©Êj] ò´H› PÒœÂ~ú銋eUµ%üÊŬ8VÍúh¶CU=R! æçŸŸxÏÒZy—ÒÓ_¶ä€œ9ó‹Ë{)-ýÊ…†Õ×+Ìì}«¨˜eW¯nð¾ïaO'—©ÓÂdÒ«B*¤=“áÛœÈí®²¯z:FÇê3š¹Wž‚ê½÷Ö…ï::ƒä'i*¬J ¼jÏj—x ð€ôfÝjð&{ëbe¯eoÑk²zùO¹É.?¤núô?]Õ³îž|JfݪoÛ¹³ÀgÜsäú½÷šÜM&j{2÷}x@@Ÿ& uVThãIOÿ›ÁB'åÔ©SŽ„ÈòÞ{æ‡ú¨¡mJ¶WRþýûK\ÞJcãH—×¢¼•’’U.I?77§Uȼ!òJ©"޼$ò–h`¡A†¿n€¼FêÀD$5ØaI\±¢Ä‘Á~¸f{÷æÛ‘#çR*^<ÞZ ¶”@.o™t#R¬^Ú+ñô}M·ú­ë÷¯jn² Zý:•~{S›•W½¹Ôrƒ}øa­­YSÜ£Ï&•t+ˆM@N4nÜK»v­ÙrûvÀ댩Ԕ`éø: ']%0U S¿’ꛚ†»${%òß¹³ÎU ;uê×â†Ï¸P …Ž)œLar_~ùÀÍ®ifM.y½þñ€û¯u-äåÒ~—Œù*±Ì É“&Oœ<`&¼€|$½gåWG:TÎX$äùótGJDNDRnÝúÖ‘‘—Žºý5;ªœŸmÛ®¹xqÍ”jFNžyP4ïÉ|¿ÍÊÝ®|ŸÐ6ëW†IOîîOá€òðÐ~$r†o¾ùÍ…yÊK¨‰•HE7]¦{Ö…%k¦^“>ÊGìÍ当#ÿŒ«¦%]«ïðI·r>U}«/T9„€€¤! Ìz¦¾n–¥ð,­µ¢p­¿ÿë·Æ¥p.…u)¼«+¸•c¢‘‚îÈWñ½vî÷rãÆK÷þ›on»P…)Sj\e˜ùó9ÔW:lºM¤ˆxˆ€ˆˆèw,b’Ì…/RE¯*n!O²fá5ø3ç± MæÐ×ÞlŽ9ë’ûUFž'õYYO\šD—3Æ Ä}÷ ÝjáF-ðøûïÿrk (Á]k¥(á]‰ïJ€×b”Ý9»šˆ|å'…Ë[1ÂìÓO›;ó¾V[€n»2q]¤ß_“A¡Zú £×øt(»¤ê‹Ò¡È‡Â`S¥bS_²Ê TÕKµs¿§*vªfvö…„^ëÁƒ[aÖ³oèV«Êkõù¹µˆ£n|üxŽ[¥^«ÐŸ>}")Üäí嫌û;R!m [€n»v¶XÉêšÐl±&±ÒvoÕ«Š^(ÔGáUòÌjÒ%W¨ïxcêËÁƒùyôKýk‘•Üïèy5h6Ä®_ß ¤/ÊI»ti¿ýöÛ7öèÑ<«­d¯^½çV‘×{m×þŽæ“t…´·vÍäÉ/yžÒƒky/5£/¦Êûâyü?—8®ò>xáÊfšè™óî”ÒÒì('ch¢Â³´ž˜ÂµDĵ¶™Â¸b­T&òÑÔ”fÀwžŒêÝB@f=“Nä‘'DyFêêÆ9O‰<&òœÈƒ"OJOÝß¶m7mâÄ@«õUô>Z‰c[€n»¦ì© UhíÍô«Úªäõ%½jà©$f…‘j–\!£ª°”ê϶™|Œöäû('³(¿P‰ëzö~ˆ¢Ûµà²ÝÃUŠù¸xñ+ËÊzniifÓ§ÿmçÎ}Ýíº…€r@ˆûN ioÑDå–(ÇD¹&gÏþÜm÷óãwì£_¯¯Òä‘’bÚíÝö°(ÇKë/Œ]ï*;©À„Ê öF½*§Ma8*a®§ÂCµþD*­£ùÈ=2¹æHÈÍ›[,7÷¸ëΜ9êìþ¹sGìüùÞ² Z^ÞAW‰ñâÅÿ8z~þ>W¹ñòåÝnrëêÕ]®hJAÁׯ\»¶Íõ!EEß»‚)7nlq]7onrUoÝÚà¼ñ·o¯w¥çïÜYë&ÈîÞ]íÖÇ*)Yáú¦ß_ež,uÅW<øÒÊÊ{ò…«ùèÑ+/ŸïÉ箂äãÇsÝ$[EÅlW¼åÉ“Y®«¬œéú¶?ÿœî ¹TWgº ¸¿þšâªMÖÖNvQÏž¥»’øuuã](s]ÝÞ½Î÷HÉO -ôù ›9óž}÷ÝO˼cÿééa‰+<6iR½§»¯º5'ð€0뙲è•öŠô Ýj¾uë5W ÏœïÜy5åõª3­)¡Â#F4‡žýûß7,'çtÊ?3ÙêK—ö9›®¼Â®Ì6„ŒVVºí*ûÞØ8“´×ÅMF¹I©úú1®xñbìëùx7@×@]v Ü5€×@^z ìÕwh ¯¿þ""êGD DDDD,"!B!b!¯¼ˆ†ú!MˆéþEHDLTRDE„EÄEåëEdDhDlDpDtDxD|ôýE„DˆDŒDD”ÔŸ‰8‰@‰H‰P‰X‰`‰h‰p‰x):àüùÿºþQmïÞ ¶bE±#ªZƒd̘çÞù+Û„øá < €éh>I¢MD¤wÈÑ£g] …¦(/Bëó¨ÒP*}‡¼âʆ+æ?#ã/[·îŽû^©ö,TñòåŸÜ€[ƒt ìÿú+ÃåþÉVWV~Üâ1xõj¤—ܸ¤¶ö¬›dÒàœvÝ1Q‰ù‘#_%EÀ¬g¯–®^4±/Wg¡½¢ÛT­4oÞ#KKk.E«rÜZK(õª*|*>vìßyªsÄI œ&û$B¡ vº~yäIPq‘‰¼OžÌvûtŒföõ™p6ØO–®¯ßùHddÔ…-¢¢Pb A·]ìêOÄ¢‰~C:EÚ+ºM-QÈÒ·ßÞrëüÈ« ¤m%óö´^URxÕª».F_y,‹=°½{ó“nR'//Û®]ûÁ…É[¡Ð¥ºº öêÕp·Ö“¼ü1×y9äíPÈÂ:S.;›Ñš:éé¯Br@Ìöì)ƒ€< ºí‰Ð€xMÔûW¯ÞwÕYôŸÎ‘öŠnS5qý‚ó4hRU‘RxÓ/¿œé6½*I^ œN›Vå<3Z€nûöWá(ò1”O§¼‡ªªén²æÕ«aÞÿÜûG滉§ãOŸ>Þ%÷ƒ§9±²}û­–"*S§lÿþòn¿ AÚ‘öM”§$HkU‚¤NE¹cè¡’¦Û¶]së+(q] ¿i!Ò®  ûúî»"w-%“«„êæÍ7\Œ~2æcÈÓ¡„hy>È¡C í _¿~-Ò6oÞlƒ r²iÓ¦¨çŒv|g÷÷ôõð€0ë‰Äß|åÊ®×ÕY6†üŠv¸íÕÕÓ\åUIQEU?Q¥‘“«W´‹÷»’‘§N@Ÿ´×nÂYbM\?ckÖ[zú3—ƒ¡Åü¢­:­ÍŠÈ¨×üùå––öÒ¦N­ve‚;Óeö*‘ùØì,$"‡¶ŒŒ «©©q’™™é¶µ‡hÇwvO_⾑øqòxøÕYš= iÙXåf 5£¨CÍ*jöP3‹Š‘VéG•…lhÐg‡¹døúúº‘*ùôi–+ó¨’Ž*ߨR*ËXP°Ýòó÷º÷ªO{E:Ón6¨Ä^HHl²gO¾«@%Ò R¦*{ì©PL½B·FŽ x„¥Îy2‚?¿ÿ%·6ɘ1{ûŸÛŠ%QÉL²æc`°³N ÎÅú|èõ”)SÚ=O´ã;»¿§¯‡„™¤sƒ¹Ž†_)ÎZõÚUË]uÞE6D:D>DBDFT^äD$EdE¤%ø‡#1"355nÀ!’£Á‡ˆh !2¤ Pš'SF¿Ä|wU{m  !!(aºiÓÍ×¹/má‡ÎK2vl½]¼XçôzûvÀ&Lh²õë‹måÊçAQnÉ—_>èp’{²åcÐ1.€€t€ 8Ð3¾–÷z­mí!ÚñÝßÓ×#AR+œEá[çÎýìŸÒÂTº¾Â¼/…) L‹k)ÄB‹r)ÜBÄEÿõ^Û«ªf$e¸˜¯×{÷öõ‰°¾Ó§s\^†*¯i!1-,¦Yj…Ãþà”"” ‘¹Ô ³´t¹Ý¿¿Ô#‹ÜÀS3Ü ¥QÑ=Wå,é+Ž¿¾~ìë°ÁoC,ÿ6·] ·é8¯Ï©Ýèÿ¼ÜvîŒ-‡„| „>@@Âmïß¿\ç >¾³û{òzj¾cêÔ©Î5ç³cýïŽ÷wïÞíÖëõ¥÷?F]ð^3õ©s¿WÝ@÷æÍ“V^žk%%ûÝ€çáÃÍV]ýoo»Ì |jjf{ƒÖ™ÞÀ4½%\,a/_Ž}½¢ðGVW·À¨.~í©ùÆýä œv¹p±Û·yç,ðIã¾ß`Ï’ÙhGBºS?"z¦eeלžDîÜùÙÓËI§/‘{÷vxßwÓ›ÈÀ¬ó‹<ý-wdàÏ?zÆ/¼msxþ|†§GÍXOr³Õ/_þóußpï;u¡2z¯í"‡:NÇësÍdbŽ÷z‘wÞ/Ðut=]Waee›½ûÙëî«y–|¿·ïWwߺ}§Oz×ÕªpB ð¾#ÚÿèÑw¼H>ÿäÉaw>‘}Ϫª­Þ9¿~G°Ì#+_y÷³À娽üý÷lï§¹Õ¦ÕnÇ{2Ú­V­öÓü=ßó¾cškG/_Nô¾kóªÔjO/^hÀ=×#=ŸºvU[»Ú{½Â»‡e®}ýùçvï{~ïÖíQ;«¨8ê}÷l·*ôíÛ¿x÷Éû§½üÏ®ÝÝ»WÚ-¿/%«‡ƒª µ>þw¬åº|Œ¶zßõï7÷™ËÇ'JÏ¿®.ÑȊŠU®}|Ãq•þ‹þ«KÞûÒ×Ç‚„b=ôšábz­\šàA²HHYÙ]âPŒ¼¼B eñÉ€Þk»È@°g@ŸoëXä®§ëŠ Ü¹óµw?Ü}éþtŸº_Ý·î_ßCžÁÓ§OtkXܵk;^“ž(}Òµ!Íô«iñOµ%µ'•ÀV›ÁP»*.^ãÚ–Êb«}iÑPµ±Çç¸v¦RÙjkÍ&ÝU§S›Sù즦÷¼ï9Ôµ=U®Sû“—GmPI¹Xªd§¶(¥öX^>ßµI,µK…:©M©mùÏRm´õ³Ì¶ÌÌJo_[HffS¯ÍÇÀ΢W< ÌѶxr2‚ïìþž¾9 Äz"èµ§ÃŪª2]8P ðeØêb¡aB©NzJDBúJ,…'åæþâÚŸJj« *DLíPž6é@!dj )S›Tˆ™Ú¥Jo«M©m©©­)4­5ão‰×_6´YÔMž‹ÒÒe½2;‹^! ¬‚U]]¶JTèç¢ßÙýÝ}=r@IÖœšæÒ 'Y_¥ …u@ÛfóòVÙ¬Y .ì*33àžc´Yé‹$xöÖÑÚí­“ïñÝßÝ×ÃÂL‚^“„44| ù ÍÒfÚ,Ôó€t èÕ×#„XO½R]Œ6‹Ðfi³è Ìr [ôмÖ¡ÍÒfÚ,AAA ‚nÑ+zEÐ-zE·!ΓXOôŠ Wt‹^t‹^! 3zE¯è= Wt‹^ñ€‚ ‚ BÂ,3zE¯èA¯è½B@9 ºE¯èA·èÝ"䀳Ìt W½¢[ôŠ [ô ä€ ‚ ‚ 䀳è½"èÝ¢WÝâ€@@È!ÖA¯èÝ"èÝ¢WÀ‚ [ôŠ^t‹^Ñ-‚@@AAð€ è½¢WÝ¢Wt‹àâ<Ñ-zEÐ+ºE¯º%ÁÂL‚^Ñ+ºEÐ+ºE¯@‚ ‚ B€€0ËÁLzE¯èÝ"èÝ¢W A·è½"è½¢[„Ð}ؼy³ 4ÈɦM›ð€ è½¢WÝ¢Wt‹à]ƒÃ‡[FF†ÕÔÔ8ÉÌÌtÛÈAAAÈ ‡È‡X­½ž2e f:ÐzE¯ºE¯èÁZ hy¯×ÚF±žè½¢WÝ¢Wt‹Ž~ýúµÙÖ¿ÿv‰‡/Á˜1c†yN&L˜àþwÇûéÓ§wëõúÒûY³f¡.xï ú ½¦Ê{ÙYôAÿ…=à}Oö_< $- )€p9 Ú$~¬êêꘫ`†ÖþˆgPç† ‚ ‚ H"’ñ6H€nÑ+zè½¢[лõ üÐ-@¯èÝôŠnÑ+Ðû@@€€€äB¿~ýZ$W®\±iÓ¦Ù€lðàÁ¶téR·> è¼^µ¾Ž¯×Å‹[ee%ŠI0¤clBâm,¶6ñ(--µ3fØÀmÈ!vôèQ”ÒmöÍ7ßD1 ÀãÇ-++˵W‰^———C@@ß68 qQÉÏÏ·@ ` ¶nÝ:GH@ç0sæL»té’5559ÝîÙ³ÇÒÓÓQL‘““cS¦LÁ&`[“÷ïß·áÇ[^^ž³šäY³f ŠI0Ξ=Û¡uÍ@[Œ;Ö¶oßîú0ɶmÛlܸq@' ºêû÷ï"ºò†€ÄàÅ‹6räH7#‡MÀ¶&;–,Y‚Ç£0~üx«ªªB Ào¼‘r}ÐI¦04C‡$ñ¤nß¾}ÎÛƒõë×;bk[¾¢ ˆ´´47ã é5;;ÛÞyç7ˆÓÚ µµµ(&Á}×Ê•+QD‚ðÙgŸ9 þK²uëV·  áPŒòèÑ£]ì'H\{•¼ýöÛöðáC’”””ØäÉ“± ]ˆ²²2›5k–mذe$È,[¶Ì]¨ëòåËmáÂ…(&˜4i’ u‰ÁÓ§Omذa-}˜^'»w  )ˆÂÂBÒ¢ÁH,4{´k×®VƒfÐqHÁd›Ð5¨««³Aƒ¡ˆ@I¼">DDÉL ’~v>Õ ‚ ò€ç€${t@@R ¹¹¹6tèP+..F]rkg¨ØI%¨Z[()‰ŠQܺu Etq•ì}@@Rp%!q]'ŠEöKj §Ê,(›´P¢´ïYRøÅܹs‰©O”€®°+‘‰Â±TštEEEŽ€€ÄB¯”÷œB,ÐgÌxv^Ñmç!¯’ÊJ—o½õë«@@RªÍ¾ûî».ÿ#xÖt a‘-PèÕ‚ HBOä]RÉsXh2Â_#L¢×ÉžÇ@@€€ @@€€è£H•…8Y0 zÑ€€€€@@ µÉG°„îËÍ͵ɓ'Û€làÀ6cÆ +//osÜéÓ§Ýq:&ø£¯uëÖYee%z3ñIƒ<'‘à“†à°¬Žå€,Y²ÄÞ~ûíVDFD @/& J>×¾¼¼¼ˆ÷à{J|(œ+ô¼±†`C9'çÎsûu €€=Œÿýßÿut%‰'š€Ü¼yÓU¿5j”•••¹mJ?~ü¸#>äÐ9D”#2gΜ6ç NB¯««s’••Õæ¸™3gÚÙ³gÝyUáÒþI“&ñ° §¡°'•ª•XÄC@%ƒÏ›7Ïåwè8•É .‹+r¢0,å :Ô²³³ÃžWex‡î¼"5zzœÎ»páB÷ü’¾ É"€î! ÿó?ÿƒ ‚ ‚ Ò¥ÒŠ€@—y> ú0úõë‡=jW°C€¤# UUU¶`Á4hõïßß222ìܹs 5l:F¢ó¿ùæ›¶páB+..îRãìK8<~üز²²làÀNôº¼¼¼Ýó]¹rŦM›f °ÁƒÛÒ¥K­ºº:æëEº¿pŸ ·_z‹™™™mÎW[[ët®ûë­·lëÖ­QÏ“——gcÇŽuŸ>|¸9r$âýù×lo_{º‰¦[aóæÍ®}J6mÚ׳ŽöùT% ©4 ÀÆ`c°1ÿ}‡»n²ˆ CƒÏúúz vóæM›3gNÂ>tììl{ûí·»t€éÞÔém߾ݚššœlÛ¶ÍÆ×îy4xÈÏÏwúihh°uëÖ¹­£Æ8^£}öìÙ˜:µœœ›2eJ›ó/^¼Ø–-[fîþ—/_Þª³Å­[·ìÝwßµ‚‚÷¾²²ÒÖ¬YÓ%ß3šn>ìÚhMM ~´-ÖkÅúùT# ©l 6“Ø6†dÈö% 4c OŸ>µÏ>ûÌÍâéØY³fµÌÅ2ûÔžñ;tèÍ;·Õ6u€š=ÓL•fÓ^¼xÑjÿÆÝ,f±öïßßa£ûÆo´Ù¦kÆ udáôÖUƒƒñãÇ»YäH®FŽéfYCϯ年ׇ^‡ÜøÐó>~üx§ï¿#^¨nÕ±ûƒA¯5ŠõZ±~>ø<< :Ô݇%%%­t·råÊ–ÙN½Öm¸óíÞ½Û †õ–,YÒæY´w> œ‚ィ¨¨eà:Céž5(Ôuu}ÝÇ®]»:ôl¼1œwOfiifÓ§›?Ûç°1ØlL3Ò¼ÏÇÝké[çôÛºô*ý_«½öí7ß›í ÙH<Ûƒ C¹a먨»ôèÑvýúug´5“§ZF¤£³“Á³”êä}|ÿý÷ΨiI×ÑlZðŒØ–-[ÜÀDûeÈtíœÔùiFRßI¢pm‹ ˆgv2\øƒ92Òêt/‘®¥Î ÚuÖ¯_oûöí »?tp ýi°×ô\tLO Bu«ûÔ3 <„»÷ö®ëçƒÏ£©Ú™ŽU§žžÞ²_¿µÓºº:'àj[¤óé˜àãƒÛn¤óÝ»wÏýþüûW‡î‡ñ„vü‘îY×Óy5€Ô5ÔÖã}6"“&™g šßß¹Óü>‚ÁÆ`cš!ïËÑ£GÝk Ö5÷ß;vÌÖ®]ö÷¯ê­vЋˆf_Ôù¼óÎ;-³‚r‡Gš= îÔ;:8âÝkðEƒ‡à˜d¹ëWÚ»®f\‡ Ö2«¤×Ñfÿ|”––:cî^b£¬¬Ì zÚÄNòFy÷ïßx>Í2Mž<¹Ýý‹-r! øá‘f¥£=ÓXã¯ãí\Âé6Ü9♎õóÁǤBgKõ; ¾?½Ö "Òù‚ÛµŽ×9b=ŸâÕ÷ìÙãBŠ4@÷½b¹gµùàöﳑçÃ'>DB23 ƒÁÆÄhc.]ºät%hÀ¯A¹OLõ»ÐþX H¤ß|oµC€ž& ±†ZÅ’¥™ Åjw4š™”‹Y3:~'^ÐÑÁ®:ÈÐàÄ—Ž\'ÖcÆŒnF08>;R¸€ÂÂBç"oÏÕÝQcªÙ ¹½C!·w,³¦z^¾[?Ü}(ATIÀÒ«:DL8í‰ÙÉötÛHÛ:Bh"mnn®3¦UèF¬”X÷Çb:¼1[x?¸£>±1ؘ¾lc´OdTmBÏÃÿïo÷ÏÓ‘ßo¼!Š©`‡ÉF@ÂâÙ¡³†ªX#CÙ<èhŠjTb12ŠÏîøtÐÊ$ÁHäìd¸c´8u`ŶFJjMôà@¡+JÖŒå{ÆZFË_I£íAnòîŒÏޤÛpñÕÚëµbý|¬¤W¡3‰õ€D:ŸŸÐªßKp˜L<{èÌ£®×l 6óÿ!χBÙfÏžÝò^¿qÿ}WÞ`‡½ˆ€¨#Ž¿V¬rpµ%lª‚ˆ Î[îã`£¡N-ZhA,jvîÜé °o 4ËîÇgë:Ÿ­ï§ïŸ©Bfó4x Sˆõz¡Ûõ½üY$}_=ƒÐl%úµ—ÈKøB0V­Zåô¦ïªøgÍÏb…Buº¡++ÔDÓ­_aF÷ß™ 5Ñ>k'êÇ1k@§v bÉѱ’ÐØëHçÓïrÔ¨Q-Ç*QXñØñvü~˜‡óæÍëÖl 6Óš«Íûù4ú¯¶ª6îZáÚGHo°C€d$ ¬‚¥ÎBÆS¡rËðÏ„h¿j´k¿fd̃†âBýp†XfÏdxë.Ä@¹¡u-•±"}>^¢ç¤’ßv4ðŠJ¢j/~å%¿Ti,çS»TyTh€oǯk(†[3ðºÝO´ÙøöHˆ9996eÊ”6çUg¼}ûvkjjr²mÛ67n\·ïÖ­[öî»ïZAA{_YYikÖ¬‰[±íY>|Ø222¬¦¦Æ‰=Úëµbý|ªžÅsl ¶[ÓͶ&™  ?¼¿!ÞŸþw•Q ݦNï­·Þr³Iše|ñâE\×8tèÍ;7®snܸÑÍöiöjÿþý1Gu8ší.ã=~üx«ªªŠxŒ¾ÛÈ‘#Ýì`èyßxã6ÇK'Ýu¾Ï>ûÌŽ?Þi=t¤³ }VêÐýÁ‰ ×øÄz­X?| †êîCƒ§’’’–ý¸¬\¹²e–S¯µ-ÒùvïÞíÁÒù’%KZé|0ß{QQ‘Í™3§Í÷vÏ¾îc×®]ˆ\ódˆ'ùØl ¶¦ƒ¶&--Í>|è^ëù霾7Fz•~ƒ¯Õž‡'Úo¿÷Û#@uÞŸˆþwÇ àûï¿w†G³<šåZ¶lY«Y«XΧÙIusË–-6kÖ,·_L„X!wÍJêZ2ÚÑ>·~ýzÛ·o_Øýê”5s¨R²uëV·­«Î =é¸'¡ÏJaºçàAƒ¶Åz­X?| HÕÎt¬:ëôôô–ý6lpí´®®Î‰¶Úé|:&øøà¶é|÷îݳѣG·Ü¿:r?œ%´ÃtϺžÎ«£®¡gß±_äc´~­¯ÿçck°5ØšØy_Ž=ê^k°®¸ÿþرc¶víÚ°¿óxíUï¶G€% òz¼çý]õþô?^/HGC† ±ŠŠŠV|¤8äöŒKðìS´sÊM¯øâxQZZêŒf¸ÏvÅ `Ò¤IvÿþýˆŸÓlÐäÉ“ÛÝÿôéS6lXËl—^Ïr&ú|ñ~ÏXã®ãÕo¸gîñÌ0ÇúùàãƒgCgIßyçV÷§×þ«­ªÍ†»–<$¡ál! ½Çz„€T{C"üiG ·\Óê44;©Ù"ÄÐãÔ‰ËU¬cTzñäÉ“1ÍšÉàj.T!Ú9ee„£U¦‰6Kïš±¯ÎÆÛíì @"¿^½D¯#…=tö|áà׿׳Pm~%Fƪßx±œK‹b©ÍßÞ}Dú|¼D±Í ùº\µjUÔUyñ+.)á9øøHçÓsR™Uh`o‡¯k(v[3ѺÝO¤Yéè$$qU°°5Øš¾jkü™¯ÿ¡Šàk(÷Âì é]öÐí:U®Ñà»ãxŽIb@RB3ú w¨­­6Ø# Ð)(þ]ñåªÊºø`€€@@C@AAAºRZtþT‹ FÕIEND®B`‚Multiverse-multiverse-0.7.0/charts/contended_counter_line_narrow.png000066400000000000000000001075221174000617100261510ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔ€IDATxÚì}iLTÙ›þ$“Éd2ùg¾Î‡Éd2Éd2æÃd¾L&“É/î8icºÓF[dUDqADEÔm¥ÝÜ@÷¡EEPT6DÙKž½Ç_ÑEQµAmÏkžÔ¹÷Ü:§žºWê9ïyÏ{þ4F£Ñh4‡Ú_ð+ Ñh4F£À¢Ñh4F£À¢Ñh4F£À¢Ñh4F£Q`ÑhöX[[bccñ§?ý ÿïÿý?üå_þ%þæoþÿüÏÿŒ¹sç"55•_’-`þâ/FÁÕûãs@£Ñ(°h4Ùùóçñw÷wc~œ§Z¸šXñ6å.Ï7=?4æÆâÊðGçþápíÚ5|ùòEÕ777+¯ÅÿþïÿòÒƒ–;=X4æÒÖÔÔ¤¦ô?8â½xûö- ½L`¹Ûs@E£Q`Ñh.m[¶lõƒ³qãF«Û(//Ç‚ ðOÿôOøë¿þküÕ_ýþñÿQ+++³ø‡nïÞ½ª yÿ¿üË¿ !!aÜë-™ºªªªBxx8þíßþMÅI»ÿ÷???|XA›ûÑ:xðà„?DK—.5ù^iß–È´´4õƒfîZö~.½Íœ9Óäu¦Þoh¶~N[ûsõçÀÖ:W}~æÌ™3R–ï‡F£À¢Ñ¼Äddnøƒ ·±ÄdoøÞÿþïÿFKK‹Z…füƒm<â7þ!úöÛoÑÓÓƒC‡:ÿŸÿùŸÿèêíÉ“'cÚ–ø¡¡¡!,\¸pTÄÙû¹.]ºdò{ü×ý׸ŸÙÖÏikîðØZçªÏÏ¿þë¿âùóçüCC£À¢Ñ¼ÍdÚÃÖ˜”Y³fzoNNÎHݽ{÷FÕɵæ~ˆ ÕùQçå‡ßÚHC¯ ¦¦f¤Î¸}IE`ïçš>}ú¸ßƒ”Çû̶~N[ûsõçÀx ÍåªÏÏ;wøG†FE£ÑƒeçÂ0(Úø½2Ú7¬“kÍý¾×V¯†Þ,I3`é°%ŸËÜ÷`üƒlø>[?§­ý¹ús`Àr‡ç‡F£À¢Ñ¼È쉽™ÈëaX'×Úúãií¤ñç²&°Ù–:k¾sï³ôsÚÚŸ«?ö,wx~h4 ,Í‹ì×_õƒ ÇŽð\{R&ò`9òÒøsÉg±ø }ÛêQ²õsN†Ëžà piÃYk²ž‹Fó"³'ÿ‘#c°ùiü¹¬ÙÚÅ–¾g̘aSL”­ŸÓÖþ\ñ90öéÅŒqàüT ¬Éz~h4 ,ÍËL–¤gð¾råʘ Þ2dhÆ?‚²‚M¿šMV’™›r²õGPò™[•fêsÉ{ä‡^ï‘|M’2@>¯#–­«úlýœ“±ŠÐYÏÁüÇŒª?vì˜Ê5mÚ´IQÎ|~h4 ,Í ÍÖ=èŽ?>aþ#Y:ï!#eÑg³äsY¿d®ÎØëai^*[?§­ý¹Ús ï3u­$çœ åÌç‡F£À¢Ñ¼Ô$o‘$Oüæ›oð·û·êF¦pþùŸÿY-]?}ú´É÷IžÉ$×Éõɨ-çd´oò??âAÏøïÿþïWë?—ä"’k…Lƒ‰wDbŒLe·gziûöí#ß¼ZšYÝ–ÏiO®ôˆíß¿ä=’ùÝîøüÐhX4F£Ñh4 ,F£Ñh4 ,F£Ñh4 ,F£Ñh4F£Ñh4F£Ñh4F£Ñh4‹F£Ñh4‹F£Ñh4‹F£Ñh4FE£Ñh4FE£Ñh4FE£Ñh4FEs“ë -<<‹/v8&«]W‡·òæ=ç='or'wÛ`ü»Lå!kÉ’%¸wïžÃñæÍ›Ii×Õá­¼yÏyÏÉ›ÜÉÝ6P`Q`Y…§OŸzå@oåÍ{Î{NÞäNîXXS °‚ ‚ À¢Àâ(‡¼É¼É¼É,c°Ÿ@îäMîäMîŒÁ¢ÑƒÅ¹“7¹“7¹“;AAŒÁ2²ææf¬]»Ó¦MSrSSÓ¸×ÿéOcKNNÆÿýßÿ)=zÔêzG·gmô`qtGîäMîäMîô`ÙeÁÁÁHMM…V«UHIIAHHˆYeÎnÞ¼‰åË—ãÓ§O +V¬Pç,­wt{ÖöÇ,Æ';y“;y“;c°ì¶o¾ùf̹ï¾ûÎf%bF¬Þ¤fq½£Û³¶?z°8º#wò&wò&wz°ì¶7*¯Õðð°Â©S§Ô9skúôéøöÛoáïï¯Þkh2Í(íèMÊrÎÒzc³·=kûc AA0ËnkmmÅœ9sF⩤ÜÞÞnÑ{…¤¤$³.c–Ö[â1³¦=kû›J•^•ι“7¹“7¹“»' ¬U«V)/”a VDD„ÅïïééQÁãžàÁ’¨‡¡Éæ•2¯¬päÕÞã’ÆÌÒý»VtÍ!í¹Ó±,¬ð&¾†ÇƯÞ¿³³Ó+ï·7?ïÂÛï7Ÿ÷ÉyÞÝR`™òæLäá1'°LÅ<É9Kë-‰Á²¦=kû›*ÖöÎíJ`mlÞȹ“7¹“7¹“»§y°dÅ Ä]Æ`®"4žb‹EccãÈôbtt4ƬÚëèè0»ªo¼zãþìmo¢zg¬ë®c®îßÝ?ŸaåÅâ;AAxÀ±$S‚²rP e½€2%xòóóUj9?sæL5000êÉ5e.zS1Sö´gIýT ,ñ^ÔýÛ§Ýçu^,ŽîÈ›ÜÉ›ÜÉÝãÖDf.eƒ'ô7ÕKï½z¯û'&¯ÞæÅbŽò&wò&wr÷zÅ­r+° ½Wzó6/GwäMîäMîäNEå0u«ð– lïŸÔs® ‚ (°(°¬DEÅï(.NÀÚµ=ð÷V®ìCaá~”—Ÿä‡ÜÉ›ÜÉ›ÜÉ‹ËZÜ¿%%±ºötBëkÛ¯_Kû½xð`·ªç=¹“7¹“7¹“;–•X¹²{D\éíÕëX¼¸“#r'or'or'w , ,[8l²Ï9s¾pž ‚ (°(°lÁêÕCcεA„'¬U«V)–a VDD„Wz°äêaháááÊí©Wæòjë±9µ©c“Ýí»ÃquuµGó3w¬‡·ñ—Å4Þx¿½ùyÞÞx¿ù¼OÎóî–Ë”7Çœ‡ÇTL“œsT½³ûs¦+x0€sôäNÞäNÞäNîžàÁ’ƒweƒe¸ŠÐxŠM¿*¯££Ãìª=[맺?WXó´sqãÁ ÎÑ“;y“;y“;¹»»ÀjllTS‚²rP e9g.†IrI™Ë+eOýT÷çJ«·úãèó£œo'‚ wX™¹” žÐŸ³ó`u„‡ãÁÁ4÷âê—9ˆy·™#r'or'or'wOXÜ*gò–ÌUWíÝ‹¦èð÷BÞ»(,ï]À9zr'or'or'w , ,{”þƒôt  rU+®Þ¸ßáŸq7ÿ.G8äNÞäNÞäNîXXö K×~ÚÆlìÞ]‰uZœyz†sîAAEeÒ¯GåšX±¢'¿ÌABýŽpȼɼÉÜ)°(°ì™«~tå úæÍ‡¯¯YáXß½˜sôäNÞäNÞäNîXXö*ýžl®À­ü|ùš{ŽpȼɼÉÜ)°(°ìAýŽÈ =Š#Gʰløg\~t™óîAAEeÒ|þ<Ú— :º{µsq¬nG8äNÞäNÞäNîXXvÍUk4è œèùոй;>-ã=¹“7¹“7¹“»» ,ÙšÆÓ§O·êzcKNN6»5ÍDõŽnÏÚþœáÁ4nÝŠss."ãY–j}8Â!wò&wò&wr÷VAAYbJPš~seÙXÙÜæËãÕ;º=kûsV –z0ÏœÁ[ßH¤ž)AfãNá-νAŒÁòµpáB´··Û,°D̈‚Õ›”ÃÂÂ,®wt{ÖöçLV®LúáPL6k}q¾6#r'or'or§ËÝVQQ&œR”)Äo¿ýþþþHIIU?mÚ4 KYÎYZolö¶gmN‹Áú3ªVnÃå‹Hî ÇÁÎ0ÎÑ“;y“;y“;c°Ü]`‰¨¯¯·øú††DEE!))ɬ‡KĘ¥õ–x̬iÏšþäêaháááê¡Ñ+syuÄquuõ˜úÇGRñâçM¸÷ñ$ÖkýÚŸ« oOâcͱÞÆ¿¹¹Ù+ï·7?ï¦þ¾ñyçónë±[ ,!±qãF«ß×ÓÓ£‚ÇéÁr ò²³Ñ;;éï³pï~çß ‚ Æ`¹«À’¸¤ÊÊJ»–©˜'9gi½%1XÖ´gmÎŒÁÒ£|þväDŸÅ*­/nW{^ãÈ›ÜÉ›ÜÉÝ+Vyyù¸ßÆSl±±±hllTåÖÖVDGGŠÛÒ¯Úëèè0»ªo¼zãþìmo¢zW‹ÁÜÙx¯æoÆžOaHí\Î9zr'or'org –; ,ÅÅÅ ¬üü|«ó3gÎTñW£®‘4æòN™«73eO{–Ô»šëêï…è›íß_íDœÖ—#r'or'or§ËÓ2¹÷ÝwÝŸ«Å` rrrñôçm(:žˆ…˜Â›œƒ'‚ ƒÅ­r¸U޽J?-$o"~Å‚/sPèaqXÝ‘7¹“7¹“;Ö”Ç` öny~Ÿlm_‚tË‡Åøò&wò&wr§À¢ÀrŠëøñ Ôú¯ÃŒõ8òe.G8äNÞäNÞäN–½¸y³©>×P³+¿üŒââËœ‡'‚ ƒEEe¯Ò j@¿ üuëyíŽpȼɼÉ, , ,{çª×¯oAëüåH,ûŸ–qŽžÜÉ›Üɛ܃EEe¯Òß»·še'P|` Ò¾ÌAnnG8äNÞäNÞäN–=8w®[¾DwH~òÅ“'g9OA0k2–d:·ß|ó •’›{°²³sáã£Å爮žƒº7qá;y“;y“;=X“!°D8b<õí·ßÚ,ئOŸnö=ÉÉÉf·ž±·ÞÙý¹J –`Ù²Ox¾~n¥úâùçPÎÑ“;y“;y“;c°&{Š0##cd#c½µ··«sƦ6 ÌŠýæÉ²q²¹Í•m­wv®äÁÄÄ4àìf ZÂüñÅùù™á;y“;y“;=X“)°~øá 9/ç~üñG›Ú\¸p¡i㙈ùõ&å°°0‡Õ;»?WŠÁ;öQkZð9ØÉõ¨¨8Áùx‚ ‚1X“)°d:oRžysPüa.<¸Á¹“7¹“7¹Óƒ5™y°„̬Y³ðÝwß)H¹¢¢ÂêvÄVYY9áu¦bšäœ£êÝŸ«Å` jÓˆç±KpÿZ ^¾Lâœnà·ñ›~Už¬\4·jÏÖú©îÏQérÏïFÕ&|øð G8äNÞäNÞäN–« ,ÅÅÅÇ@Isy¥ì©Ÿêþ\=–àîÝ<•p4ón&zg¡§ÍOw^Ã<)äNÞäNÞäÎgÎ|øðJÉÃb°¡¡ŸqáÂcDtDàÓ ´æEq~ž ‚` –£ƒÜMen/--pCcC«­­ÅªU«TFxÙ,:##ÃìÊEc[rr²Ù­i&ªwt{Öö窬¯Yöï¯BÜ›8žXŠ¡c~á;y“;y“;=XŽXÔ~øða•÷ÊP`õôôàûï¿·¨úúzøøø ¨¨Hµ#›"ïÛ·Ï¢Ü[¦L¿¹²¤0·ùòxõŽnÏÚþ\9KpèÐKlØð§žÂÎçË0¼x6>[·nµè½ jÃ餤$³.ç'ª·ÄcfM{Öô'7PC WnO½2—WGWWWÛôþ¨¨.ܺõÛÚ¶árøYW_çðÏ7YÇÂÛ•?ßdëámü›››½ò~{óónëß7>ï|ÞMO¹À’ø)SAç†[èLdâÍa¥7ZâɲÔ$ÞK‚ÇéÁšº¹ê]»Þ 6¶I•Iø¥y=†Cf£<óãȼɼÉ1XŽJÓ "K‰á€Ù¸Ÿ‘Áùz‚ ‚1XöØx)Œ÷&¤yžK£ÉUîð¾ìÓ2œ}šŠá]?ãõÑÝ‘;y“;y“;=Xö¹sÉ;iîƒ%X±¢))ϰ½a;v×îF÷­ÅèŠ^Æør'or'org ,[!ÉF%éhrE2V·­Fmùn ûÿŒü»w9º#wò&wò&wz°hŒÁ²'O–cåʸUx þCþxT| _¶øàùñ㜳'‚ ƒe«IÖuÙ¤™1XÞéÁ’ ŸeãgI8º o®<º‚¡[¾hÝÅѹ“7¹“7¹Óƒe«É¶8†‚Š1XÞƒ%X° W®<Â/Í¿ ñe"Z^GAëïƒÜœÆ';y“;y“;c°l r×h4TD^êÁlØð‡½Ä×°ñýFTV&a0ÊÏRR8º#wò&wò&wz°l1Gy©jkk±jÕ*µÉ³$/•ý ÍYrr²Ù­gì­wvîƒ%Ø¿¿J÷y›p±ø"ö,ă7¡½âƒ¦_7qÞž ‚` –-&bÈÞ$£õõõðññAQQ†‡‡Õ¦Èûöí÷zýæÉÒ¯¹Í•m­wvîæÁ:þ1/þ Í= |‡|‘QÞº` úážFÃѹ“7¹“7¹Óƒe­#00P‰"[-66vB•¡‰X‘/PoR sX½³ûs·¬œœ\Ì«Eff>V¶¯ÄÉò“hlÜŠåx’–Æør'or'org –½ÙÛmYE8}út\»vM­F”–…DWW׸×Ë4¢xºô&e9ç¨zg÷çn,ÁòåHM}Šu;[‹rÈê=Œ†mÛ8º#wò&wò&wz°ìÍÞnË*Bc»víR)­[·š½Þ\,˜½õÎìOn †®T¹þÁ‘WW:Þ½»ÇwàJÍ„w†ãÙ³"|©óÅ@È—ü¼<æ1yÌc[sì–‰FÅ›#ÂÊ0·–x²èÁrÖñãÏÙ†ÌüLÌÕÎENn:;Ã0°0%/rtGîäMîäMîô`MµIз±À2'@LÅ4É9GÕ;»?w‹ÁܼYˆ€€AUíÅùÇçumïB×Á¥x³s'ãȼɼÉ1XÖNÚRghà.Ó‚"²2]¸}ûöq§Øô«ò$°Þܪ=[맺?Oð` æÍëÇõëEØün3öVïÅ“'iè}‚Ï¡¡Ý‘;y“;y“;=XŽX¤nÍV9)))˜1c†šܲe˨ wS1L’KÊ\^){ꧺ?wσ¥Çºu-8|ø¿8Œu-ë››ƒ¡A_ ¢èÚ5æQ!‚ ˜Ë+ 'Š3²ÔÌÅcM†MužâÁúí·j8~‡ë¯#¨?Hkk‹DûΕ¨IHàèŽÜÉ›ÜÉ›ÜéÁ²t%¡©=⩹té÷¼ñ‚½õHK+Õ}Î.UDúÃtTUíÃGÍj|Z¶Œñ äNÞäNÞäά©Þ*‡æþ¬ìì<øøhq÷n¢Z¢pôÅQ+..NmâLóŽ,µ‚0p@'´`ÇÛˆ¯‹Wç>^„ºS»Ðºf çò ‚ Æ`ÑèÁ²kÖ´âØ±ç8Q~«>®Rçbðæy´¾¾ÈËÊâèŽÜÉ›ÜÉ›ÜéÁ²%ɨ>?Í»b°{öÔ &¦· nÃoÈš{”—ŸBGGÚW®DEr2ãȼɼÉ1Xã%5L6j –æÈ2õ^{¯— {s[ÓLTïèö¬íÏ=XgÏ>EXØ'Ué ÁåâËÈÏÏ‚V;U‰ûÐüË/Ý‘;y“;y“;=XæL6jÖod¬·öövuN£ÑX,°¬õ ™3ýæÊ²±²¹Í—Ç«wt{Ööçî1XYY_Žfgç"ú}4¾:¨Îwv†ãEÁ•t47'‡súAc°Ì%s^ÎýøãNX"fDÁêMʆ+'ªwt{Ööçî,Á’%Ý8w®‰¯Ý­ÎÕÕíÂÛ·ÛñIǽìôiŽîȼɼÉ,sbgÜÉ›Üɛ܃5މÐoŒL ŠpH‚Ñ¥K—bÆŒV·×ÐЀ¨¨($%%Ù|½)—a<ØDõ–x̬iÏšþäêaháááê¡Ñ+syuÄquuµCÛÓŸ>]˜˜Ïxòô‰ t/¨(ÐÕ×@«õÇã[ç14oÞÔÕ9œ¥ÇÂ{*ûs¥c=¼¿¤ñÆûíÍÏûdý}ãóîÏ»Sb°Æ rÏÉɱ©Ížž nëõô`9W¯aþü>U^ýq5NTœPåÖÖ5xñâ(>/^ŒÒßç¼>AÁ¬ñLÔlóÝwß)H¹¢¢ÂæöìX¦bžäœ¥õ–Ä`YÓžµýyB –Àß·n"¾6ÛßnW窪öãýûMx³k¶og|¹“7¹“7¹3k²,66ª,{FGG#!!aÜ)¶‰®×¯Ú“•æVõWoÜŸ½íMTï‰1XÊsµú#Nœ¨À™§gÖ¦Î=zt}}óQréú,`|¹“7¹“7¹3k²,??ÁÁÁJØÈ¦ÑO5000®à™èz1É5e.zS1Sö´gI½'z°âãë°cÇ[ÜÍ¿«6~–  å|ÿ<]U«øâEŽîȼɼÉ,S«e¯ÁÉÌä.ÓŽSiSÝŸ'Æ` RSËÞù5mCפ•¦©òû÷Ñxýú€š"”©BÎíAŒÁ2²9sæŒT†°4“;Í3=X™™ù˜;W‹œœ\lmÜŠßj~Sç_¼8‚ÖÖ(ÐÏ¡#ç;:ÂñìÙiT$'£}Õ*ŽîȼɼÉ,c°,E\Ü…œÜÌÕÎEf~¦:/1X‹•—•­¯/îß¹Ãy~‚ ‚1X4z°,Á©SÏÑ®Ê+:VàtÙiU–U„²šPÊ­kÖ òÈŽîȼɼÉ,½•——cöìÙjJP e9gO×D–œœlvë{ëÝŸ§Ä` 22î«8,‰ÇŠ­ÅÎ7;ÕùÜ\ʇ%y±*“’ÐÅør'or'org –XIIɸAî–Š,K•¡é7O–ôæ6W¶µÞÙýyšK + eEá©òSˆh9/Ý%³»Lùú"ïî]ŽîȼɼÉ,ñVEFF¢½½}䜔#""TެÉX"Vä Ô›”ÃÂÂVïìþ<-KÝŒÄÄWȸŸ_­/4¹uþõëýxÿ~£*·ëž™Š'8×OA0K¦eÃgcÓjµoš,kúôéª-¤¤¤˜½~Ú´i9–²œsT½³ûóDÖÁƒ¯±qã{U^سK.ªrQÑUô÷Ïû*¶öïGó† Ý‘;y“;y“;=X"ŠÆœÑe©À2´††DEE!))É*—aJ{ëÙŸÜ@= -<<\Í+ëyuÄqss³CÛïøÎWX¶lPojÚ„äÆä‘úþþù¨¬ÌFógШ䣓ýy„÷d¶ïÊÇÆ¯Þ¿³³Ó+ï·7?ïSõ÷Ï»w<ïS.°æÌ™£¦»ÚÚÚ”gF åÐÐP5}h‹õôô¨`pz°<ǃ¥ÑäÂ×W‹ÌÌû8ôò6|øÃSõþý&TUíWåOË–¡,%…£;r'or'or÷n–²äþêÕ«IX¦bšäœ£êÝŸ'Æ` ÂÃ;pút®>ºŠù}óGοxq­­kT¹fϼۼ™óýAó`‰o•L ¤l¸ŠEcc£*·¶¶":: ãN±éWåÉþ‡æVíÙZ?ÕýyƒK°cG=víªSeÿAÜ,üºÿ`AÁm•®AÒ6]»†  ÜÓh8º#wò&wò&wï΃e¯åçç#88X ›™3gªø+ø.S1L’KÊ\^){ꧺ?Oσ¥Ç‰X½ú£*G¶E"ùyòH]w÷b”–¦©òçE‹Pš–Æ1äNÞäNÞäî½y°¦Âl –w§þ¼Åƒuûv!üý¿&ÝS»1 1#uoßnC]]ü×ÿ;wâíöíÝ‘;y“;y“»÷z°òòò°]÷chlqqq(((àž7..°¦ÁÁ}¸zõÎ>9‹eŸ–œ/+;ÎÎpU.¹x½ pΟ ‚ðÞ¬~ø]]]cÎ˹Ÿ~ú‰J‰¬QX¿þ’’*q7ï.|´>ÈÎËVçótÇZí\äçg©ã¾à`_ºÄѹ“7¹“7¹{§Ë\öo¾ù†JÉÅÖTÏÓïÛW¥ãöN•—u-Sž,}]GÇ <{vJ•¶mCÝ®]ŒO wò&wò&wïŒÁ’ mÃmrô&¹°¾ÿþ{*%z°FáܹÇ íVe‰ÁÚS³g¤®¶v7þ—õä÷ßÑÊѹ“7¹“7¹{§K~øÅS%Øõ‰Fëëë•gk¢ýöhÞƒ•““ -îÞÍW«e5¡¾îñãóøüyÑ×cxxíçþ ‚ ï‹Á’X«ñJÂP=XÆX¾üΜyªò`I>¬?ê4òGaá-uܤûª8º#wò&wò&wï̃%Ó²eŽ>ѨJªIc –)lÛÖ€={jUY2º_-º:R×Ò…ÊÊ#ªüìôit†…1>ÜÉ›Üɛܙ‹FÖDHN~Ž5kÚTù—¿¨½ õu¯^@ss´*çfgcÈÏ…·nqtGîäMîäMîÞçÁ¢1Ëܸñƒª¼ÿõ~ljÚ4RWTtýýA#Ç~ù¯àü?Aá]1Xb×®]Sù° Ó2ȔᇬnKöé3—úAŸÂÆ–œœlvkš‰êÝžµýy²KÔë×âbÉE,êY4ª®¯o>=º¢ÊÏÇÇ•+9º#wò&wò&wïò`eeeˆCUZZª68¶ÆîÞ½«VZ"°Ì™~seÙXÙÜæËãÕ;º=kûóô,ATT ŽyM®¾Z_ܹg¤®©iªªö©r¾î™Ðúúâ~f&ãȼɼÉÝ{b°dsæÃ‡«ô †KVZ“«··~~~º×&»–ˆQ°z“²aʈ‰êÝžµýyƒ+!¡[·6ªrD{Ný9Á¨òZ=?†6ƒô mkÖà…îãèŽÜÉ›Üɛܽƃe(ªŒ3·[“É=11—.]²H@IýôéÓñí·ßÂßß)))£ê§M›¦ŸÞ¤,ç,­76{Û³¶?OÁ¤¥=ÁÒ¥]ª¼óÍNÄÕÇÔd`hȹ¹9ê¸2) -QQŒ ‚ ¼'KDNÿA%i&z«©©ÑýØ.µØCeh’à4J÷㛤û6÷~ùœ–Ö[â1³¦=kú“¨‡¡…‡‡+·§^™Ë«#Ž«««Úž¥Ç%%eðõV¯)ÏR°º{õ¨úÞÞ0¼ÿõ}÷32 õóC}U•ÃúÞSÉוŽõð6þÍÍÍ^y¿½ùywÖß7>ïžù¼O¹À’`ö… ªírD`iµZTé~E@[Ô†ˆ«ÆÆF›–~:R‚ÇéÁr¯yzñ`‰'+ó~¦ŠÃÊù³ÇJðöíÔÕí9nˆ@ʼnŒO wò&wò&wïˆÁÒo‹c Ðm‰÷~[–©˜'Àû‰ê-‰Á²¦=kûó†,Ä`I,–”C?‡âüãó#uee©èìü#ÉèëýûÑÍør'or'or÷ž/Z„Òsç@Axv –¤ÐÇ?ýôÓOJXUVVªÜVÖdr§y§ëÌYQùI•«ù [ ¦--ëtÏSҮ߸8¼Ý±ƒ£;r'or'or÷l–a@¸ä¾’ã¡¡!«3¹Ó¼3+++>>Zäääâ÷Òß±¤k4ÏW¯ÑÜüËÈqÉ… è a|¹“7¹“7¹{v –¬Š•dT×oa#&^-ÃÜT4z°ÆChh7ΟŒì¼løh}p7ÿîHÝÇ×uÏRШëûæÏGñåËÝ‘;y“;y“»çz°ä‡ß0îjÕªUê¼(HÉðNc ÖDؼ¹ ûöU©òòOËqæé™Qõ½½Á(.þCP5ÄÄ .>ž1A„gçÁ’\T28kÖ¬‘s>>>j…!¬‰”T‰õë?¨ò¶·Û_;Z<55mFuõÞ‘ã'gÏ¢{ñbŽîȼɼÉy°hŒÁW¯>BppŸ*Ÿ¨8ÕWªþ<mmç4 âaz:ãȼɼÉݳb°~øálݺ•^*z°ì†FsþþC¸}»· nÁoÈš{人?Cm›“k°tÓ¦M¨Þ»—£;r'or'or÷,–ä¿’ w%«ƒ‚‚PZZŠþþ~»„…ìÓgÉFÏÉÉÉf·ž±·ÞÙýyS –`Õª8q¢B•ô.ÀåG£ƒØ»º–âÉ“³#ÇÏNBçòåŒ ‚ <3K6[>~ü¸ŠÃÒºK,–ж¶6«Úº{÷.ÂÂÂ&XúÍ“eãds›+ÛZïìþ¼Íƒ%ص«;vÔ«rts4_%Žª¯¯Å›7q#ǹÙÙòóCáíÛÝ‘;y“;y“»gÇ`‰÷ª¼¼#9±$Ù¨ˆ¦‰¬··~º̦¦¦ –ˆùõ&eÃ>ì­wvÞƒ%8}ºL'<;TùÀ«ˆ~mô&U'NÃFû°~=^%&2>ÜÉ›ÜÉ›Ü=/–9“ø¬¸¸8•á}"KÔýP^ºtiLòÒñ²ÇKYÎ9ªÞÙýy£+3ó>|}µÐhrq¹ø2BzG'ÍËËVqXùù™¿;†«VqtGîäMîäMî\EhÊd[¥K—šÌ?QöxÃ,òŽªwfrõ0´ððp¥Êõ޼zÚñ²eƒ¸sç• p÷×úãùÛç£ê{{A]Ýù‘ãúW¯ õõÅýÌLü>xÌcó˜Ç®s<åK¶ÅÑïAh K·ÊqÕØØh±À¢Ë3G97¾ÇÁƒ¯UyåÇ•8Q~bT}MM‚î9Ù2ê\[d$^9Âѹ“7¹“7¹{–kΜ9£•!Ìy…Œ=D¦`ML”œsT½³ûóÆ,Abâ+DG7«r|]²ò³0W;Ù¹£…Ó‡ëñòeÒ¨s:ÁZ~âó´Až“Kr^‰Wf2í»ï¾›Ò û©î¬?ÑŽS§ž©ò’î%8Wznô”àËDÈúeÔ¹ªýûñ>:š£;r'or'or÷Vqq±Ê{%Ó_4÷X®6OW;¿~¦-ï¶à·êßFÕ?|˜Ž5]¨?÷àÆ úû#7'‡ñ äNÞäÎ{Nîž!°Æ P·f!,=N*ÇÊ•íª|äÅDµD¹¦·7D'ì/Ž:×µt)ž¦¦rtGîäMî¼çäî9Aîãa2â³(°<ðóRñXéÓ44æšwï6£ÚȳU»g·laœAÁD£4z°LaÁ‚^\¾üH•E`]x}T}EÅq|ü8:ƒû£«WѤc GwäNÞäÎ{NîX4Æ`ã—_š‘˜øR•×¶¬Åá‡GÕß¿Gm›“k´Â°gÑ"<>wŽñ äNÞäÎ{Nîž!°dƒçÙ³g«)A”å,[°ÿklÚÔ¤Ê{«÷ª`wãkºº–é>ûÙQçêãâðvÇŽîȼÉ÷œÜÝ_`•””ŒäN‘Å,[páB -ú¬ÊçŸChwè˜kêëã Ï=¾p½!!Œ ‚ Ü_`‰·*22ííí#礡rdÑèÁ²99¹˜;W‹ÌÌ|ä俍„£™ù™FŸû >}Z6æ½ýóçãÑåËÝ‘;y“;ï9¹»·À’)AÙðÙØ´Z­K$ì¤ÀrÏyúððN¤¦–}-w†«­s ë%þJâ°$Ëð|cL êâãŸ@îäMî¼çäîþk```Ìy]– ¬ÒÒRµ?Ÿ\ÿý÷ßcûöíhkk³*÷–±%''›Ýšf¢zG·gmÞìÁìØñññu_Ëõ;°³nç˜kd%¡¬(4<÷äìYt[ð]qtGÞäNÞäNî.-°æÌ™ƒ°°0%ˆ†‡‡¤ª¦-1™b”Œðâõ’÷_¸pA½ßœÀ2gúÍ•e s›/Wïèö¬íÏÛc°ÇW`õê6U>Y~«ÚW¹¦º:ïŒàs5 âaz:c‚ ÷XÈ>^û«W¯lnל÷k"%bF¬Þ¤,"ÐÒzG·gmô`ÝÓ ÐBøûªrFA|‡|¡¹7:Ç•ds—¬îÆï}¿iª÷îåèŽÜÉ›÷œ÷œÜÝ;Mƒ)ñV‰(HÙVq%¬K—.aíÚµfÖôéÓÕô¤¿¿?RRRFÕO›6Mµcئœ³´ÞØìmÏÚþƒõóç÷áêÕ"Ué ÁE£íqd?BÙ—ðÁƒÑÞªg§N¡3<œñ äNÞ¼ç¼çäîÞËQ¦÷|ýøãhll´è= ˆŠŠBRR’Y—á¶=Õ[â1³¦=kú“¨‡¡…ëƒ<4ze.¯Ž8®®®vh{Ž<މù¬Ïõê8æc Ò>¦¹¾½ýW¼|™8êýyÙÙÐê„wCEŸí oWã;UÇzxÿææf¯¼ßÞü¼»òß7>ïî÷¼»}&wñ¥aéÒ¥¿§§§GÓƒåYØ»·[¶¼SåDˆú¥ù—1×¼|y>¬sþÃúõx•˜È¸‚ Â}QåÕm«‘\‘<æIÕPSóÛ˜óm‘‘x¡û®9º#wÞsÞsr'w¯r·%eƒ'ôǬñÓ€={jTywínloØ>暊Šh7‘'ëå¡ChY·Ž±A„û ,sqVöÄ`q«z°ÇŽ=Çš5­ª|öéY„} sÍýû™jÛœ¼¼ìQç 220äë«VrtGî¼çäMîäî«««‹Ë –«ÏÓ§§?@`à€*gåeÁGëƒì¼±‚é“Nx=}š:æ|ÇŠ(?y’ñ äÎ{NÞäNîî!°Ì­Ôc¢T4z°,APЀNh=Tå¥]K‘ö$ÍĨ8Ô×ÇŽ9_µoÞoÜÈѹóž“7¹“»{,ýJA}:cH0·dd§1Ë^¬]ÛŠ£G_|ÉjŒABM˜kž<9‹.ø“ÆáÆ úû«= C@A¸Í¡5ùªhô`Ù‚„„ÄÄ4~Éz~ kZ׌¹&77GÅaÝ¿gL]×Ò¥xzæ Gwôfðž“7¹“;WR`1KIÓ é¤|óÁM¨Ä¢c¯ûøq5ž??>æ|íîÝhܺ•ñ ŒÇá='or'w÷Xyyyؾ}û˜ó’˪  €J‰,»q÷nžJ8š§Žç÷Ïǵ¢kc®«®Þ‹¦¦ÍcÎ?ºrýóæqtGoï9y“;¹»Àúá‡ÔŠAS«úé'*%Æ`9K–t!-­T•×X¤Ê¤1×_Foo°É÷÷,\ˆÇçÏ3Ž€ ‚pe*ë¹µy°JKKÕö1’àóûï¿W±¶¶6³ïINN6›ÝÞzg÷GÖhȦϲù³”÷WíǯM¿š¼n` ^s¾>6V£;z3ȼÉÜÝB`‰`hoos^’ˆ%K,22ÅÅÅÐjµÆ… :îõú½ýd_?s{ÿÙZïìþƒ5GŽTbݺU¾Pr‹>/2y]só/xõ*qÌyñ^õ„„0>ñ8äNÞäNîî!°ä‡_ïîô÷Ï»ë?ï“hÔœ‡ÇTL“œsT½³û£Ë4RSå{ëTe‰¿’8,‰Ç2¾®¼ü$ÚÛ#L¶!ûVíÝËÑy“;y“;¹»¾KVŠGÆ8ËÒ4 hjjRe‰Û’4†ÄxŠM¿*O¦!Í­Ú³µ~ªûc –eÈÌÌÇܹZäääªcYIxÁÄT`~~¦Ú6'//{¬ø:yááŒ' ‚ \[`EEEˆ)ceé>…ùùùVï™1c†ÊoÃe*†ID˜¹¼RöÔOuô`YŽÐÐϸpá±*ojÚ¤rb™º®³3 ee©£ÎaÖ¬qÁÑy“;y“;¹»\¬’’’Q‰Eeeáúõ둞žîéBs)&æº?æÁ²æoÂþýUª,ÙÜ%«»i^»ðö펱Ë”y™ÀbN$r'or'w7X†Þòr‹7ŠæÚËÝF9‡½Ä† TùjÑUµ/¡©ëž45m²H`U?Îøò&wò&wr÷ÜD£4z°&®]o[¯ÊiOÒ°´k©Éë=ºŒ¾¾`‹Vö.X rdågfrtGÞäNÞäNîXXÞ‡Ó§Ÿ!"¢C•³ó²á£õÁݼ»&¯BQÑõ ÛÌ¿{M›6¡O'´ž¤¥ñ{&‚ œ+°$%½ìC¨Ÿ"”©A‰¿š={6U=X“‚;wîÃ×W«â±äxÙ§e8ûô¬Ék››£ñêÕ‹yK"Ò  ÔÇÆ"7'‡£;ò&wò&wrwŽÀ Emm­*oÙ²eT{DD•c°& öàâÅbUÞÞ°»kw›¼®²òZZ¢¬â]pëÚ"#Ñ­ûÎ]¹Âøò&wò&wrŸz%[ä ¨²¬aUYY‰šš|ÿý÷TJô`M ¢£ßãàÁWªœ\‘ŒÕm«M^WXxCCþº²ÆjÞ¯1€ª}ûpO£á莼ɼÉ,ç$•­qäX¿zÐÒ-[†öU«Pxó&¿{‚ Æ`MÀÁ «††%t¦OŸ®Î‹WKê,±µkתív$û»¼ïàÁƒf§M *CÓo®, PÍm¾<^½£Û³¶?z°&†LÊ4¡þxAß\ydz:¯¡!µFSˆÖðÎÕhP€¬_ûwîpdKÞäNÞäN–õ&S{2íEsOåîóôçÏ?ÆâÅŸGŽC»Cq~œ¬í]E_ßü)á—Æ­[Ñ/éRS›AÞäNÞäÎ,문¸f·¶¡Ñƒ5YÈÉÉÅܹZdfæ«ãÍï6coõÞq¯ï¢¢«SÆ»,%ýóæ¡aÛ6%º8²%or'or§Ë®ø)kWÒƒe+–/ïDjê×ÿP‡_ƺ–uã^ûþ}4^¿>0¥Ÿï~FZÖ­ÃçE‹PréïAc°, rSŸEÅQζmo±{w­*_xAýAã^ûâÅ´¶F9…wåáÃ*CMB‚SÓ9ЛAîäMîäîe‰FiŒÁ²Ç?GddÛÈqà@ Ò¦›¼¶°ð¶J×ðöís§|ÖééèWx˜žÎØ ò&wò&wÆ`ÑèÁrMܼYˆ€€Á‘㨖(5“Ž¡¯o,ÏÀË—gœó™5åÅo–xµ8²%or'or§ˤEFFª­_ƒÅ,gaÞ¼~\¿^¤Ê¿Uÿ†-ﶘ:/KÅð°Ÿî=©{ tžÈÒ¡øâE—%ñY§ÅûHÁ¬“–õbÊX`1‹¬©Âºu-8|ø…*Ÿ+=‡%ÝKLŠ«/_tßfÉŸ¿ÕgNY²²PVÊJòӧ9²%or'or§ë«Ifò’’’‘€w±®®.¬_¿éééTJŒÁšüö[5¶ly§ÊÙ¹ÙðÑú +?ë•|÷ï¨iA­öÑ7}F—z§þAHMU9³$wÖd§s`<¹“7¹“»›¤i0UÆŒ3,j£´´*ƒú÷߸¸¸ ój%''›ÝzÆÞzg÷G–uHK+Õ}G]¤nè\ŽÔ²Ô1,­Ö…,?”—Ÿp ’õ]²¿KxÉÏ‘-y“;y“»—çÁÒgr$ûêZƒµvíZåQ&{ Q~«>®7Ð]¦ËËO"77[%íî^‚n¸ —7n ]7ÈèÔ=;¯_ç='or'or÷æžr%íŽ0 ŽŸ={6ªªª&¼ÖTL“œsT½³û£Ëv =ý*'¾JDts´Õ¼%eC{{>~\­{.3]Šß“³gÑ7>ÞmÞŒ¼¬,Þsò&wò&wOõ`Íš5 ===vµqõêUÕN}}½EStúUy’ÊÁܪ=[맺?Æ`9kÖ´âØ±¯û Êôà‚Þ6ñÎÍÍAcãµÊ°¨èšKqÌÏÌDó† è Áãóç›AÞäNÞäî‰1X>Dˆî½>Uƒ­©LÁ\ “ä’2—WÊžú©î,ÇaÏžÄÄ4¨²¸K û­‚[6ó~õê t×§º×çÉÉ@]|úâ(¢Z£&…÷ƒ7uƒ‰¥hnþyyÙ.ù]T?þUL™NdǸ r'or'wWXú•‚út Æ|O—.]¢R¢Ë)X½ú#Nœ¨Pån ` `ÒxçåÝŇëñéÓ2ÞtÉ#zò&wrw³)B¦b` –+">¾;v¼9ž×?׋®OjŸµµñjÊðñã XAŒÁ¢ÑƒåyÿRSËÞ9r¼®eWžtÞ'TðûóçG)°8¢'wò&wz°œk¦¶Ç±6þËØ’““ÍnM3Q½£Û³¶?Æ`Ù‡ÌÌ|Ì«ENÎׄ£ûªöá×w¿N ïââ‹è뛯ë#N¥upuuÿÎÆe;y“;¹{²ËeÎô›+Ëþˆæ6_¯ÞÑíYÛ=XŽÁ¢EŸqáB‰*Ÿ|¡ŸC§ŒwAÁmtv†£µ5 ùùw]C`ƒÞ•¤”£Zr'or'w ,³õ"fä Ö›”ÃÂÂ,®wt{ÖöÇ,Ç`Ó¦&ìßÿZ•srs0W;™ù™SÖ¿l©ÓÔ´ Ÿ?/ÆÃ‡é.û=U&%©mv*NœàsCáíkúôé*ÀÞßß)))£ê%=Äðððȱ” SFLTolö¶gmô`9‰‰/±aCóÈñŠŽ8]vzÊyWUíÅÀ@ž<ùÝeGwÏŸGÿ¼y¨Û¹SímÈQ-¹“7¹“» ,Ckhh@TT’t£psí®vœ¨Þ’ÏeM{ÖöÇ,Çàòåb„„ôŽÇÖÇbç›Ná]¦vƒƒxù2ÑéßËxÜ oßFçòåh]³F%)e\¹“7¹“» ,±žž<î ,¹zZxx¸zhôÊ\^q\]]íÐö\鸮î üü´ÈÈ(PÇ·?ÜFdW¤ªÞSýyÞ½+A¨nP£\Oœöýèaª¾¬´M›7£oñb4–”xÔóÐÜÜìQ|¬9vÆóî Çžü÷ÏûÔ?ïXãÄ<É9Kë-‰Á²¦=kûc –ã°re;N*WåŒûðÕúB“ë¼)°û÷ïàãÇ• RvÕïíÕÁƒ ijӧùAxªËø|ll,U¹µµÑÑÑHHH³j¯££Ã쪾ñêû³·½‰êƒ5yˆ‹{£ ?^سK.:•w®Nà‰«§'EEW§¬ßS§*tÏ^üü†uÏS’“Ÿ›½^6Œ BÍž=ñ,0&…¼Éܽ:–©¼VÆÇùùùVçgΜ©â¯F]#¹¦Ìå2WoJèÙÓž%õŒÁš,Qñ í¬,lÚ„ý¯÷»ï—/©¸¬²²É÷¥¤¼ÀâÅè¨øú<½~ ,\84¡Èz t-[†–õë‘—•Ÿ r'org –'erÿî»ï<º?z°&÷áë;æëñ!¨ÙðaƒËð–•…²ÂPVNîTéÀˆ¸ÒÛË—_°hQï„ïÍËÎFst4º/ÆÃôtŽjɼÉ,n•írˆ{j%¡¬(”òÕGW1¿o¾K}>É‘%¹²$g–äΚŒ>‡M>g>>Ö§›Ø·xzæ Ÿ+‚ ƒEEåí£œèèf$&¾9öôÇùºó.õ%Û»d}—ìï’ÞmÊ6A§O?S¹À–.… 0oÞàˆwÏ¢çE'®Dd‰Øâ¨–ÜÉ›ÜéÁ¢À¢Àòâyúƒ_cãÆ÷£ŽÎÒý»VtÍÅ>«Fí_(ûÊ~†¶´!bé÷ߟ`óæwDXØ'ìß_…ãÇ_‰Á ÑbáÂݳÕ3g,ÿƒ$Ó„2](Ó†2}Șr'org –Žr.^,Á¢E=#ÇKº—(µ¹u³K~ÞçÏbp0@'†NXÅqÇŽ·˜?¿¡¡Ÿ±{w-ÒÓš\E(Ó‚‹÷¸ËkppÖ¬iÅÕ«Eõ'ïÖ¯G×Ò¥*ž#zr'or§‹‹ËË ÑäÂ×W‹ÌÌûÊk5gxJuÿ|†}\Ћõ_@ÿ<ÔÖÆ{͵kEˆ¯S^¨ ú[?kf-²³óPÿAÄÄ4àÎû½OR8H*IéÀg Æ`Q`Q`yÙ('<¼§O—!ú}4võíRßéÝ¿•Ý+‘þÀ5WÆÞħOËðáÃzäåÝUçnÞ,ÄÞ½ÕXº´ غµçΕ:ìžß¾] {öÞéÚľ}U*Žk¢ö$©$%•ä¤Ñ“;y“;=XXX^4O¿cG=¶-Áœ/sÐ4ܤ¾Ó÷ºstÿü‡ü±øóbĽ‰Ã¹Çç ¹ç:›çåe£®.7nœÅÊ•mð÷Rñd©©eÊ37Y÷\{A0Ë™6Þ9æ,99ÙìÖ3öÖ;»?z°Y)wõê#«xgÞÏıçÇðKó/*Ö’®%ØY·J.8H¼ÜS)D¸H€yxx§J+‘‘Q`òúââËèë[€úú*­ÃTÞsY$°}û[õ9e•¢Æwmʼn @eRGôäNÞäN–+-KL¿y²lœlnse[ëÝc°&âJJª´™·&Wƒ³OÎbÛÛmé AP67mÆ©g§g]>¨óç«ÕzAA*Õo¿ÕàÆ½·  +ÐÖ‰üüÌ)¿ç×®=ÄÚµ-˜?¿OMcŽ—¨ôÑ•+è ACL r5ÎkcL y“;¹S`M`"VD¡êMÊaaa«wvô`MdUœ¬sï«EW‘P€ðŽp5•¸¦u _&âv¡éø£+WaçÎ7jë”õ5k![ê¼{÷+>^„‡¯;åžKBSY͸lÙ'¤¥™^ÉxÿÎ|\½(ÈÈàˆžÜÉ›ÜéÁre5mÚ4 ÿ±·š”圣êÝc°&çÎ=Fhh÷¤´}çþyqë[ÖÃoÈË>-C|m>ZµBo2yߺ“­ÉE˜õ³çucnâ=¬É=…ÓOS›= ÷0U'²ðêÕ§Ýó¬¬<ìÚU§â³$áiffþ˜kž;¦â²ä•#zr'or§‹¬)íOn †®æ•õ޼:⸹¹Ù¡í¹úqDÄgT.¼Ù~QÑ3\ºÔŠuëºÔ À_mÇ­[PZZ†Ë.ãPÓ!DöGÂO뇨–(¤¼MÁó·ÏÖÿ‹ .Ekkœš>4w½ñ«#¿ßû÷Ÿ#:ú½ÚDúܹ6xpÝÝKðþ}4rs³QV–ª{šf©mwœÅG¦ eE™:”69'{ʆ²—¡ìiÈgÜÉ›ÜéÁ¢¹µÀò6qµh‘_¿Óׯå{…îü•„4,쓚>ܲåJ¢9^†rgC¶é‘ízdÛÙ¾gÇ 8úü¨ÚÖÇÔõyyYhiY‡žžP|ùâgƒ;14äçT‘%X¶Å‹?«`x ŠÏÍÉAÓæÍèY´E×®ñ™%‚1X4z°ÜaaŸu¢bxÔ÷*"K÷{Žèèfœ>ýLÅ ¹§›…7ÕFÔ²!µL%ÊÕ²QµlXmx]YY †‡}ñ_7½®ë»ã"KD¬,-ƒ$½ƒÄµ½:xƒxvú4Ÿur'or§‹Æ,W‡¿¿Öäwíãà—•—…å'°©i±¨gvÔïÀ¥²ÓjZ8‚ƒº"°äõË—#ê¼l íìÏ.‰I%ÞM•JÂÒâÔs BÍž=|ÖɼÉ1X4z°\Ë–uãÉ“Á1¬¥K=Ž«æžçŸCÜ›8„v‡â„v%š„¹ºOtÿæÂMÃ~øô)L­6ì––õ¨ªÚ‡ÇÏ«d¥ÎøÜ²ÕŽl¹#[ï¤î+§¥ÿ¿½sqŠâhßöïOKYIùV,KË Š(ˆ "‚(¨ÅWBT¢A j 1¨¨DÅ`<c@D!(h"ˆy¾¹;ïð ëîÌìƒî}muíÎÌN÷tÏ¡ïyúéîµògjª\­«ãµÎ¼3ßÌ;-X„>X³ÕkÕª7"ëßæÁ1))yðÁçýôÓ’ùÏfe¹’+ëFCdÓŸ›dg÷N)ìÊ’Šžr£?Yz†VËèØyñbtuíR͈׮MïDÍ“H¯‹~.‰ò÷š5Òxú4¯cú`Z°f«È‚%+8x\¢¢^«Gý!ßßÿô½²^=Õ>ßAãAÊ_k_û>Ù¡‰«dM\Åü£šƒÆË*í;éu¸ìÖ¾¿~,ßÿ³L~Œ—úÎl¹rû5¨éT7FÆ-߯9)#ˤåøq^ëÌ;óͼӂEèƒEÿ„Ù2_dNX¯töí—ôÞtçCC\¹(ß7~¯†‚À`§{;öHf_ª¤½Š’øBeÅx &×$F^)šËHìßwJÁ¯rôîQ5hª'¤:=–‹WÕЙK[äÕ’pù%ï žsæùfÞéƒEhÁâÛÝ̆šë5ʱÝÕÛ=‰÷ʳrùa\Ô„WÍP¤œ|»X FCeëH¸ÄŒ„IÈØ  –HmÛúõ’þ4]vwî–‡…Rz§TÍ¿øCƒý1¯Î».y©÷¤kñi[›)W.¸ç'vúÑi¾Ñ3ßÌ;óNe†ÕÔ:àðáæSÓXm÷u|î¦G,†÷-À1òp”‡Ãüˆ&´^þ*wäÜ“t9òû.ÉíÊVB ‚  léèRYýjµlx¾A¶=Ù&¹s¥è—"9ÖzL\áê…É•–_—æå»åqÐFùöËk¶Ž­úfµ“øæ¹b`` À2Xfè“+cbe³É—]m÷u|î¦G ßî>”¼ß¸qVîß?$ÝÝŸË_­•1MPáËX‘æÑ”ˆ&EŒV1½²5–Ö›&ñƒñ²jx•½ Rª®ù{$=K’Œ?2doÇ^¹¸3[GȾ¸rª²Ñô8Òž¦)µãùžsæ›ygÞ)°<X3(`ü޵½Ý×ñ¹›}°èŸð¡æýêÕ‹rûö7ÒÞ¾Wúû7Ú"âܵsjû¯î}%ù¿æË®ßwÉæ¾Íràêy"_.;-AEeÍÉÊYNûpÞÇ÷iÍãÍ<ì—V,ÞçÌ;óNe[`Í›7O>þøc •ÒÒÒIÛçÎ+ããÿÄnüÆ:»Ûñ6>wÓ£‹owþ”÷›šàik+–?þØ&¯^­‘17‡ˆÀ´:G¬–¦è=²lÙl)n’¼_¾ÌîL5 Ų–Iòxòÿ†§(è±hI|ž¨¬ZY]Y²_v‡îRýh’tÇ/ŒçœùfÞiÁú`Ü»»»%99YŠŠŠL-\cv·Û±˜¹Ÿ;éáêÁȺuë”*×/|s™Ëârƒ&pÚÛ¿“ÁÁƒò×_ÉjJŸ‘‘Õò÷ßYÚýþ•y¾¥åö¤ýïܼ)CÚ=ó"nƒd$vHDÄ©®þSêÛê%¤)O6¦¼Õ^ÆDÖ¯ɽñ£ýý¨œzvJ ž(kWú‹tÙ8²Q"Gþõ [òv‰DFÉúWë%åÏÉîÏ–’Áµš2kÖÊî;r»õ6Ï—¹ì'Ë~Ù‹phhH9Ó‚Å·æûCÌ{½UÈÓ§i2<¡D×À@¢<~¼[ͳQv¹¾^ïÞ-#+VHmÁ9ížù[–¯’ˆ5ÿ¼3ÁwÑeó2¨k¨SM‰°jÁº+¬]pЇõ þ`/lñøbYöf™-6[Åüµ%ïsæ, ,g>OXgw»,wâs7=ú`Ñ?y7h6Dó!šשfE4/>y²]º+wÈèòPiúz¿§tÊ{o'ÝKYkãG=žÂê¯Ô«xàËÖ_ÈžŽ=Ê*ËWÜ‹8娫ÂÊá•j¶eôd¨ÿbì‹80y7âôeYùsJÞçÌ;–›deeIOOúÝßß/iii’——÷N¯½ÁÁAÓ^}®¶;6éyŸÕvZ°øvǼûvˆˆ7a2»X$ ÀeøüónÙ·ï79tè¾”—7Ë™37äÒ¥+SvŒ3eÛÞ¿] ,WƒÊòZgÞ™w ¬ dåÊ•J}öÙgÊÿêÍ›7“þƒ±¦ÌÆ2ÛîÌgÊ›øìlç8X ¾ Í?žøWL9C[_]]&ÅÅõ²kW«$%uɪU/%(hLûþKŸÈöí´·VM€5jìŠ&À~úú³rãÆ÷rýzöª“©˜.È—V±¯î~¥zNb‚ïàñ ŽÆÀ@5³|òÉ'Éo8ÌûÌÖ­[ߪ!#îhBcrý¢‰’‡óµu_ÊÕ«¥š úVÊÊjåÀ•KN~,‘‘ƒ<ª}ȦMdÏžòÕW5RUU¦¥W¤•mŽ<~œ.þ™¤…yú4]z4aÔÕ•%šð… é =¤{ûv™v§TOJOD›™UÌÌz‡ío,ÿQ¾”Ü/‘oš¿QS#9êú¾}ÎÑ¥KßJL̈vŽÚxŸ3ïX„>XôO`Þ§C`½—¡ÈHù{Íy¹v­ ÆÇËóÄDé߸QúRSåizºü±}»tþ¹teeÉãœiß»WíÏ—;y_Jãî¯åâç'äô¶jùfÓrpýUÙÝ,éa¿J|вaE·¤ÅwÈ®­÷å‹ÿ6É×__ÔD[…&¤jB.K`Õpÿ½F†‡WÉ›7Ë•/™H õÍ›ej=¶¿x'ÏŸ'º%ÚÌò^øK¡1ƒ¶¦ô§HìËX ®Æ ÃÈúe½b¬±Ý;Õ˜b˜“òXË15Å‘¯æ™œ²sî"ð>gÞ)°-X|»cÞ§X`5ž>-?}÷Üúö[i>qBZŽ—;_-÷JJäÁÁƒòËòë_Èoÿý¯tìÙ#»wËï»vIÏŽòdëVéݲEþÜ´Iž%%ÉÀúõòbÝ:ù+&F^­^-ëVÉë°pYºLþ Z*o˸Þ.•¿WÈÀâÕò4 Vz'H×’$yš"+6KÇêtéˆÝ&¶I÷–tyš™&½¹iòtŸö}@ ‡¶Hï×[¤¯%'NHåâ29|DÎ…’–‹aûårø¹º*[">—Wo—ë«7ËOkR¤yM’Ü]³^Ú¢ãå·èXé\#=k¢¥oõjy¾:R^DDÈß«VÊ«•+e8|…¼[.#Ë—Ë?¡!2²Ô4ß«ÖJod¢ü•*Öl—;kvkiî—+Qå\ä1©XU!GÃÎIaèɺ%[ïË–¥¿JjøcÙ´F+÷ø§²)¥O¶n}"™™¿Ëž=’Ÿÿ«<ø@޽£ÎÓwßý$55×åâÅ«¼Þg(ܽÛHEèƒEÿæùžf&4V®|-‘‘Cj0Ö¸¸—’0(6<×Z¿lÙñT22þÐDD·dgwJnn‡äåý¦ÄĿȗ_>Çï)Qqüx‹JûÔ©[J\œ>ݨÆùó?º-2ê®×Èéær9ùà EoHôŠDïÈq²q(R¢ß,—eoƒ%x.å‹+¤tÉi9²¼V¯º(£¯È— פ8å¦oÿYг[äËýwåÐÁ{RZÚ*'Oþ,UU7¥¶öšGC†°yô²´¶“6 PãäQ`Z°hÅaÞ™oZ3ܯ^T½Ñûñð½ÃjpôŠœè=éBdøâ8 ¡¯$b0@bŸHÒãIk ÌæÙ{=@ /HIM€”UHå±ÅRs D.å†ÉõŒpiNY)âWÊã¨py&ƒ!ËäuD[ Œ,^"/‚VÈÓ hy¼8QÚ·ÈíÅ;äÆÒ]r),Gj"÷HeÜ^)KÚ+%[s¥0+Göæï’Ì#;$½"]6Ö%›æã¬a8Œ­†!=PVú½N1´z bxôFÅè™ ?:43bØôX­¿\ï××;ƒò)Z½zlÒ4A‘‘£røð} Ëi·^ ½™nÜ8£†ãÀ´OC„ÀÚKËý{åak¡´ÿ¼O:³¥»ásyZ¿Uþ8“&¿ŸH“Ç%éÒQ&¿å¤É£ í{óù-1UÚצHçêÒ¾^úV¯5XÏÃ#åiðZé^ºN‡®—GaåAxŠÜ‰H•Ÿ×l‘ÆØ­Ò°M.%m“ó›·Ëé­òíçÛäxÎv)Éß*…Åi²÷ÈfÉ-O•ÝߥÈî³É²û¢~Ü »o%Êž{ ²¯}½ä÷$HÑŸëäð@‚”>K’š˜û®w‹œùc›üнSê;³åzÇ^iz”/-¿ɽûµk´D•zÁbê«––ãª7lss¹*+ôŠE¹ýôÓwª O«òÄÐ&(Ûò\>ø­\.8!Wþû\Í-•«»ŽJCF‰\ÛzH®o.– åfb¾4ÅÿW~^»GnGeËÈL¹¿j‡´…m•_—o–öPMÜ-M”?‚ã¤/(Zž/Ž”¿WÈë€P ’·‹e$ D­Ã¶^í?ÝÁ±Ò’ ¿,Û w4÷sÄ&¹µY®®Ý"—֥˶ɹ”mrfËvù~G†TíÚ.U{µðÅ6©>´M¾ÿ:]Δo‘ÚêT¹P›,W¯$JcS¼Üÿ%Ú4ï?úhX , ,ú¥0ßÌ;óí—yGS–Yóž/柜Íy7Óž÷K—åRÍ%¹T}Q.œøA.;/¾:'uEgäÂßË…¼*¹¸»B.|~B.l/“ [J]ê!¹R,—’ ¤>aŸ\‰Ý#?ÆdË5™òSD†4¯Ü*wVl‘ËRäQÈé\¯ ¼µòçâ(Z°ü™Ã‡ÏÊ©rhÍ`Þ™oæùfó(‡d¡Àz/Ñ'{ÆDϳm²g†/ü8‹GÛ§À">â oR:øK ßl™wæ›yg¾™w_5º¾j¥Àš…Ì;WÆÇÇ'–ñëèƒEŸæùfÞ™oæýýÈ;Ö,ä£>zgÝÇìRXéÁÈúõëUX»v­DDD¨o_,'$$ø4¾÷eùö§ü—õàoù߸q£_žo¾ÞýõùÆë}j®w ¬Ä‚E!„÷ ¬òÁÂ:B!„P`Ñ{ÚîEH!„ ,bƾrg,GŒ¾Y Ó(°ˆ[ÂùfÞ™oæùfÞ™wZ°oBæ›yg¾™wæ›y§À"„Bñ'(°!„B(°!„B(°!„B(°È‡ ¦îу¿ÑÜܬ¦Qøä“OäÓO?•ììl5>™?äã¯éùÎÌÌ”gÏžùÝùGøËuo¼Ïýñ~ïèèÄÄD5kF@@€ÔÖÖúíyŸ7oÞŸïÞÞ^IIIQ翟ŸsæÌ™uÏ8 , ,¿o¸þ`Ár•Êšç/ª<ûÓu¯7 á"44T½Ñû Èwuuµ,Z´HU²鯿þòËç[^^ž_ä5==]]ãx¾!=zT­£À"X3|4ÂÂÂTÛ½?s„… JOO_ä¹½½]bbbüúºïîî–ääd)**ò›ë<''GFGG•+@nn®ìرÃïÎ{tt´j.õúûû%((hâ‡ß3m¹£À¢ÀòKZ[[U“*_owååå“DLJ òi“þzÝ ©¹Pý89CXé@hùS“8hii™q Ît‚ °`}°fºu‚‹ËïhhhÀÀ@yôè‘_Ÿñ=s֫ʯ}Xè-ê(° ºü tèhkkóëçÙL?ã(°(°üŠªª*ÕeÛ_Ìæ:ðÃл,£¢E¯¢¸¸8^÷0pôÖ-wh>IKKó8¸£Y" Í…šÄ_¸{÷®Xþz ÂïÊèƒÅ^„dV¼ÑûsÞý!ÿ°Ú¡3ò:þ|¿ÿËŸ–ñœöÙgÊÿÊhÕùÐA®u4 fddø•“;,x–ÅŸÀË„>Æ!~Ï´Ÿ)!„B!„B!„B!„B¡À"„B¡À"„B¡À"„B!X„B!X„2ƒ¼/Ïúët?„P`BÈ{(P(°!X„BE¡À"„Ù#NœÍE©/c¿˜˜5§Ùܹs%11qb²lãÿ®^½ªþ‡ÿãÁd»˜ ë?þøc5él}}ý;ÇRYY©ö›3gŽÌ›7OMÆì8gÞùóç%((HKhh¨ÔÔÔ¼sܘÌ“úé§*=ĵsçN¹wïO8!X„2½"ËÕzˆ¦¾¾>ŸA‘‘‘ïü“êâFZ[[•`‚(±±1ÉÍÍUÿ‡82R^^>!Ü ÖðüW§±±Q­KNNV ¿Ç†åææfµ<22¢ŽBE!³B`uvvN¬ƒÈÒ­LŽÿëééy'ˆl3Z¼FGGÕºËã‚J'..îãéèèxçøqlííí<¹„P`BÈìXVëÍ| ÐDç¬ÒQ¤A€¥¦¦*A…õΚ,Ñ,hçxt öA“dAA<{öŒ'› ,Byÿ–.Š`ù2CEÆfCO|°²²²dáÂ…“„„!„‹BÞ{çvl»yó¦é1è–.47:Æk·‰Ð|¾®_¿®¶# B!„L ,PNè¾Xäš éƒE!„B!„B¡À"„B¡À"„B¡À"„B!X„B!X„B!X„B!X„B!„‹B!„‹B!äÃXÿ÷ÿÇÀÀÀÀÀÀÀÀàƒ0I`B!„/-WX„B!X„B!X„B!X„YÏG}Äãšc˜­åNñS500 òŸÿüG>þøc‰‹‹“ëׯûô¡†ÿ þyóæÉŽ;äÑ£GSú Õƒ3z{{%%%EæÎ«~?yòÄe|ÍÍÍ’ Ÿ|ò‰|úé§’-ƒƒƒ¶·;ãðáêÌ<èòøÍòa7¿îÆnÞ¼)+W®Ty –ššÓøô8]ms•¦²³[Vž”µ·¹³t§º¢÷4~«ãžŽ\°` M:OXÑê W÷ªUÙxó0æ /oxIÀs†B¼Xî¬7€Ê¦¨¨Húúúœn “{÷î©*¬=x¸áÁí©ËhÉÂRçÈ‘#Êr†6ÒÉÉÉ™d5)))QâÛQyà8<­à! `µBžŽ=ªÖÙÍgf*ÇíŽÇ±Št•Öÿ *}«7BÊ*>Gp^PÆ3!°ËΪ¬¬Ò²»?€õ¬¶¶vÂòa¢/Ÿ?^òóóŠgÇa€ké8ˆÃ2‹{Ϊ¡#®ÒhllT÷¨®îU;׉§Ïc<YØ×ªC!„‹%B™q`ჟ&!„P`Bˆ€å-<<Ü´—1!„P`BˆMôæLÜI¡À"„B!X„B!X„B!X„B!XX„B!X„B!X„B!X„ًݹ§:ŽÙ| ³!„ ¬)X˜Ð5##CÍí…yË0/áõë×}ú ÔçˆCüóæÍSs'zžŠ‡·«yé@oo¯¤¤¤¨¹ðûÉ“'.ãknnž˜»óŸegg«¹Îìnw¦ñf~=wòën|@Ÿ‹yÂ\„555¦ñéqºÚæ*M;eg·¬<)koŧs0z›Ætˆ ,B–@P¡‘ññqyðàšðÙ×Ké`òÚ… N©È2;6‡cÇŽÉØØ˜ ˜“ëºìÖ­[ª|0]HAAv·;röìYUî/_¾T!>>^­ó¶ò1XîÐÖÖ¦&…niiQ˘“»ŸÿY•UYY¥ew_^cÓmÁ¢À"„)XZ¥UV"¡¡"ë׋ܸa/!X•Ìèïï—ôôteéÁ“““', v­"ζaÊ´´´Ië`]˜?¾²fÀÊ5<<§Ûôx漢4¬=x`¢2ðÔ‚e´dá¡«säÈe9C%€trrr&YMJJJ”¸ÃvTH8O+xX­'„£GªuvAó™™…Êq»ãq@¬"]cˆuÆÿ£RB¥†JÇ겊Ïœ”ñL,Dz³*+«´ìî`=«­­°|AìèËçÏŸ—üü|§‚ÇÙ±@làZEz'Ož”¨¨(—yƵŒ— ˆ"ü6X™™™“„Œã1JYYÙÄ2šaSSS¦mv_YåÛ{V?榦&%®pÞ !dÖ ,X®tq¥‘oÞÐóòòÔ±þŠ&!3 ƒQy*°­g“DDÂðò…EV¹   ‰·~ü†ÅÂJtº:gÛÃÙq¹²xuww«J "Ø–*gñ¹]+w–²sUV«²Fe¿sçNõ‚@Þ¸/°Ý®ÀBs§]‹&®mãµü› ,GK”ã1 .\Óº°Ü·oŸÔ××»LÛÕµl•oîYÝ:†ÿ<|øO|BÈìXÚsmRÐê¤wÐ^(ßù‚x+†?VLLÌÄ:X¯ÐÌ‚·~½"56±y*°–£PƒÀÓƒ'騭t•Çèƒef‘ÒimmUÍD®š{¬¶{bU°jÀAÛW#«øf‚åªì¦Ó‚…m&¸&P>ú·¾^Ç'ww›ÐÍ–ý!uQ…r5–/ËÓ{Û`M…õ˜B>H –Ëz¢²ùW¸¹ÕÃÉÕàoal–C:f=ï|iÁrfM°òEkhhP¾(®ó­¶qæ?þÐ IDAT„u³E`¡‰j:}°ÌÊÎnY¹ãƒeVÖ°\UTTL4©a–c›¯–»,;q£,Ñü ¹¹¹ÝWViysÏêþmY(oB™•Ë,T¦F+¼Q{ÔÁ½¼ˆhB1>dQQ[5¯ÙéEŸTbh¾p66úzéþ8o}°?äÓèƒeÖ‹°ªªJU&]]]mw<½gòâ¬gò­;[£X°ê"@Ô¹#°\݃ÈwRR’²ºÂ쾲ʇ7÷¬¶¡YŽý„2ë–.²`ÉZ²ä_Ë•Ý^„p.Ѧ}4àán|›ÆvŒƒ„í°2 B4>dO:5Ñ<`VÑꕚ/œ5£á¦¤…¡ýFà7„ÊĪ¡•*}ì%üÖˆÝø+=«íŽ ÷•«±™`ÑAþ±¬È·ÑÆ™O—Y~­âsu]`œ œ8yÛͯ»ÖM«¸ÌÊÊÎq˜íï®}ÄÑÙÙ©–ñeã=auý»[p‡÷‡U/BG\݃ê~²ÂÕ}e'žÞ³Æx ²°¯Uç B™E!F`ƒO%!„ ,Bˆ€…2<<Ü´G0!„P`Q`Bl¢7}sàNB¡À"„B¡À"„B¡À"„B¡À¢À"„B¡À"„B¡À"„B¡À"„B!X„ø'vçlôÇãšÊc˜­åNñ#åj¸©z@éqcεyóæ©9 >ûšæææ‰91Zvv¶š÷ÌYþÝ-/»å‰|ºSþÞÄg“›Åg}NB”!æ$¬©©±¼~<¹¶¬ÎÀ´/væ$t…ÙþÞVäžÎÅ8BÂ긧#X„÷N`µiŸÙúP2¦122"ÕÕÕ²páÂ)Y)))rëÖ-WS‡¨JÜÛ¼Ûýÿµk×L+rwÓµŠOçÂ… k*m]Kmmjrè––µŒiWöïßïvˆ+½ië}µ`¹:WÓiÁÂ6ˆXNp>ôo}½'NîVûE†/–;qØÍD¦.ªp®Œåj÷¼{ûl±Šá£G²&!„xgÁÒ­WºÕÊqÙÓJ4ãÃbÈÑ‚åØÓËÝ4àaVqºkÁjhhP~fŽô¾Xð탸¯–Ýø|mQBsÒtú`™+g>TXg7-»ûëÀr…¦V½ù ˰Š›Ã¼X°`9Z—Œ,«ûo*,Xvò€ó£_“¹¹¹Ý«v¬ãž>tŸ9ˆ,½¹œB<XÿûX­s·„S5PxÈã…7Wãÿà‹ §¿¿_-Ãz‡Z;i¸êEh§î{ã±òÁªªªRjǦµ©XwïÞué<í¸ò¥[œ_G?+wâ³»Ý^„80•½­Î•Þ çÝ›^„Vû…?¬õ ߸VqÍ:K ÂØ±‚•ˆ0úGA:Ve ‹ ò‡õx#G¾Œ~)îÆgµÝ“ñÎôq°p.0œ¼§Âbf'.ô*³3–«ã0ÛßX}Ggg§ZÆ7–Ö c§Nšhʲ+"p®!Xõf0ø3›d­î?gi:‚øà ަGÜsV½q•Fcc£ºG­pu¯Ú¹N<}ãȾfH!X„2+€…·B!„øXÞÂÃÃU“1!„P`Bˆ—èÍ™¸“BE!„B(°!„B(°!„B(°!„B(°X"„B!X„B!X„B!X„Ù‹»s\NU³ùfCþ!XSòp³;Ÿœ/ÓühóæÍSs'zö5ÍÍÍ’ FÄ|eÙÙÙjn2gùw·¼ì–'òéNù{ŸÌahŸ]ô¹Q†˜‹°¦¦ÆòúñäÚ²:WS³Ø™‹Ðfû{+<ƒÑÛ4¦C¬P`B(°¯fíƒÎ˜ÆÈȈš¼váÂ…S&²RRRäÖ­[2>>®¦÷(((P•¸·y·ûÿk×®™Väî¦kŸÎ… $66ÖTÚ¡­­MMBÝÒÒ¢–15 &'v7;ÿ³:WgÏž•¸¸8yùò¥ Xg7-»ûûR(L·‹‹B¦L`ÝÑB€nMYá¸þüùó•å©ááa·ÒÀ”iiinÅY\\¬,9°tTVVÚÎ#*oXϦK`EFFÊÀÀ€Ï*«øÊ*$$Dž¼¹gõcnjjRâ çBf‘Àºã ªî¸-²<XÒ××7I,Yù9Ãh©°ŠáÞÞ^· ´££Cœî;+::Zºººlï×ÝÝ­*¡¢¢"ãƒU!&&Æ2=_ #»>Vî–¯³så,w¬‘v÷×+û;wªß°æ l·+°ÐÜéÊ*ç®mãµü› ,GK”ã1 ®    a¹oß>©¯¯w™¶«ûÊ*Þܳºu ÿyøð!Ÿü„™XN—ÿIsñ?ß ,üF“€°Œæ wÒÀ¸Ñ‚e§'ÖÖÖVÕ¬ãªyÆ× ÍOz…ì°ZÀÛÓø ®ô¦­÷Õ‚åê\M§ Û L`Áùпõõz<ž8¹›•…ûÍݸ!uQ…r5–/ËÓ{Û`½=zô(Ÿú„ÿ±`á!i| C 9Z°{z¹›ü-ŒâÁ*Nw-X ÊwÄÌ‘Þ× ¾=p÷•À²Ÿ¯-Jh¢šN,³så̇ ëì¦ewX®ÐÔª7©a–c›¯–»,;q£,õë'77×£ûÊŽ%ÛÓ{V÷oƒÈÒ›¶ !d ,£¨òœªñЃÈÂCoÃÆÿÁ¿N¿Z†õNºvÒpÕ‹Ð*NÝŸÇcåƒUUU¥þŽMkS)°îÞ½ëÒyÚq?äK·8!¿4Ž~VîÄgw»;½áDcSÙ‹Ðê\é½qÞ½éEhµ¿QøÃi[¯ôñk׬³´ Œ; ¸+°t,¼È @Ô¹#°œƒ..“’’”uÐf÷•U>¼¹gõx° ÍÂpì'„Y&°t‘å»^„h¦A!X²`Y@åâø?<\Ñl‚ÿ`¼$W>ŽT^lΚí¬â„Ÿ*«^„VwÇÿ²óTܺŽUÃbƒüa=Þò‘/£¯‹»ñYm÷d¼3},œ Œƒ'ï©°˜Ù‰ =Õ쌃åê8Ìöw–$ÄÑÙÙ©–ñe£…ɘƩS§&šÇ<Xp‡î«^„Ž8;ÐØØ¨î'+\ÝWvòáé=kŒ" ûšuö „XàK2¬qd•B§Ê!„øXDÃÃÃUó.!„ ,Bˆ—è½ú8p'!„P`B!„P`B!„P`B!„P`ý»ÀÀÀÀÀÀÀÀÀà}˜X„B!Äwü?=mÇC4§´IEND®B`‚Multiverse-multiverse-0.7.0/charts/contended_counter_line_wide.png000066400000000000000000001174351174000617100255750ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix€IDATxÚìiLTÙ›ÿ'™L&“É?óv^L&“_2™Ì‹y1™7“ÉdÒéh4m:ÝÑèO›UQÄV67l[´Å Ú—QÄ Ü÷A@@Ü@QQYlAA@(äù×9þª, ª¨‚ªŠÏÓù„{î¹÷žò[·nßç<ç9ç¯Ã0 Ã0 Ã0l„ì¯Ã0 Ã0 Ã0 Ã0 Ã0 Ãp@0 Ã0 Ã0 Ãp@0 Ã0 Ã0 ÃÁ0 sÖÞ¼y#±±±òÕW_ÉÿûÿOþú¯ÿZþîïþNþô§?É?ü ©©©ˆ4˜þ_ýU/ܽ=î Ã0 ða·'NÈ?üÃ?ô{yé—gw{™kˆ§ÜcéþÁ0 ÃÁ0Ì+Ë—²ú§’óçÏ˧OŸt}}}½îõþ¿ÿû?^ ½Øñ¤ûÃ0 Ã0µºº:=ÌÆôB¦z¿_¼xÁ äs@<í>ÀÁ0 ÃÁ0ÌC-&&¦× ÙÊ•+¾Fii©Ìž=[þå_þEþöoÿVþæoþFþùŸÿYï+))qøEpÛ¶múêüýוøøx›Ç;24¨¼¼\ÂÃÃåßÿýßuƒºî?þã?Н¯¯Ü¹sÇ%ŸËÒÖ®]Ûë¸Í›7;ôÒ;˜Ï9”öÜý>l;Þ??~Ô×PÒÃ0 ð1oÿû¿ÿÛë…©¨¨È©ówïÞ­“”í½ÔíܹsÀµùóç[=W]0/ÇŽÓ/|öŽU/ÝCý\&›2eŠÕã¬oiƒýœƒmÏÝïƒÁÖ¹ëý3}útó¶ÒÃ0 ð1oªg×ò…É4ÞßS½À–çþÏÿü444èY”ú¾Ðöí1îû¢6nÜ8ioo—]»võÚÿ_ÿõ_¿”šìÞ½{ý®­ò ƒ÷ªS9Cý\§OŸ¶ªƒâ¿ÿû¿m~æÁ~ÎÁ¶ç ÷Á`ëÜõþù·û7yôè Ãp@0 ÃL¦†• vLüÔ©S{›m®»víZ¯:u¬½µ7nèý½ö«cg_ -{•••溾×WSÍõsMš4ɦjÛÖgìçl{î~ô¢äŒâ®÷Ï•+WxÈ`†‚afiCéù¶LZî{®ê-¶¬SÇÚ{Q³øÏÿüÏ^õ{÷îÕkgL˜0aXœŒÑ¼0 Ãp@0 Ã,ìĉ%ßöµ}ûö ¸þƒšÕ/úÊ¢¢¢úlŽ|.gó'ìÕõí5wt]ŽÁ~ÎÁ¶çn÷:ÏÚ±jñ¾áp@FóþÁ0 ÃÁ0 ëcjݵ¸Ú×_-ÿ÷¯_ÀÔ™?ýéOzjÒC‡Y=O­s ÖGPÇ©ãjEjµOõ[}òRõ@«Ïøÿñ&?›>—Z‹A«þ=j˜‘ê]W9ÖVçÊðõë×›5P]™|0Ÿs(í¹Ó} lÇŽæsÔÊéŽü;<ñþÁ0 ÃÁ0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ãp@0 Ã0 Ã0 ÃÁ0 Ã0 Ã0 ÃÁ0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ãp@0 Ã0 Ã0 Ãp@0 Ã0 Ã0 ÃÁ†Û~ùå—^åððp™7oÞ¨0šmÐÑÐ}Ñ?lôEc@_4F_@c4ÆÁ]p@p@èµ ÇÐ}ÑÐÑ#ÐÑÐ}ÑÈÁÁ¡×‚^!4ôEcôE4Fcr@€Œ /ú¢1ú£1ã6³ hŒ¾h è‹ÆhŒâÕ××˲eËd„ µ]WWg󸝾úª}-99Y&Nœ¨IJJrºÞÕ×s¶=" ôX£/ 1ú¢1& ’ÔÔTéîîÖ¤¤¤Èœ9sì: ö,--M¤¥¥E¡÷9Zïêë9Û9 @È0Ú×_Ýoßøñã퀨—}åšLm‡††:\ïêë9Ûz,ÑÐ}ш€ £­\¹RG=zzz4Ôûì9 “&M’qãÆ‰ŸŸŸ>×ÒÔ0.u“©mµÏÑú¾6Ôë9Û9 ŒÙ4F_@côEc d­±±Q¦OŸnÎçPÛMMM[SS#QQQ’˜˜h7B¢œG뉸8s=gÚS_  K ×7–É»UGª|±ü∶7ÖÊ&ÐcøÊè¾]V¹’辞\VÏ ôðÞ÷ t@-Z¤£–9 ‘‘‘ŸßÞÞ®“»‰€¸ž‹…eªñ¿ó·ÏÓ»Þ± °‘ȱ–s¡ö9ZïHˆ3×s¶=wr@6´lÐÈÊú•üÀ‹Æ€¾hŒ¾€Æh숚ñJå}Xæ€X΂ÕwSll¬ÔÖÖš‡oEGGK|||¿Y§š››íÎJe«¾o{C½Þ@õîꀨèÇÆÿîÿ›Ñ3ƒ(ãbÑÐÑнÃQ΄r¥f¾R¨m“ƒaÍ!ÈÏÏ×S÷ªýS¦LÑù½ŽQkmØ[wÃ^½µœ¡\Ï‘zwt@Tôc§ñ?e;>í B¯ú¢1ú£±w8 ™½)y½¡=wt@LÑWÆÿ”©¿DA`L8 cÑFÛ±Œ~˜Œ(½Bh è‹Æè hŒÆ8 8 .çòË:ñÜÖªž:ãbÑÐÑÐq@p@\FIIª|úä/==…ºý†ž,éêö‘ÒÒüÈéBc@_4F_@c4ÆÁqׯ_1¶8UŠŠÒeÙ2??‘… E®\ÕûU=?tÀÁq]úÅÆ6?ÊÇŸP|ö쓱üNŽÏá‡F¯ú¢1ú£1ˆk‰Œì0:½?Sɳ6 žÛΜq±h è‹Æè hŒÆ8 8 ®%  Çêçš>ã?rz…ÐÐÑÐq@p@\Ë¢E]ý" Ïž‰„6ñ#×rôè3c›bvB”ó2¯S|ó“œkäÐ+„Æ€¾hŒ¾€ÆhŒ‚2 NˆŠ„üðƒÈìÙ=rýúoüa¶œ,:Éq±h è‹Æè hŒÆ8 8 ÃçQvÊãÇ›$¾i¡lªÚÄ^!4ôEcô4FcÏu@êëëeÙ²e2aÂÚ®««³{Nrr²Lœ8Q“””äòúÑnÏEtô+Ù¿ÿ†´Í“°–0~èà¹HPP¤¦¦Jww·&%%EæÌ™cóø´´4 “––MDD„ÞçªúÑnÏ™:Õ&>Ý?Húõt~pô ¡1 /£/ 1{¦òõ×_÷Û7~üx›Ç«—y%²ÉÔvhh¨ËêG»=·q@¬™qÿÊ÷!’ô8‰;ãbÑÐÑÐ=ÓY¹r¥Žzôôôh<¨÷Ù25LKg2µ­ö¹ª~´Ûswä\ûlYQ¿‚;½Bh è‹Æè hŒÆžé€466ÊôéÓ嫯¾Ò¨í¦¦&›Ç«cúÚ¸qã\V?ší©/Є¥…‡‡kÏÖts©¿ÃY¶ç€¼2øH`·¿<ÿãùˆ}Ê”)S¦L™2eÊîYöHdÑ¢E:b™IÄM# õõѲ 3@Žß=N½Bh è‹Æè hLÄókÑ{ k9jŸ«êG»=ww@nÜ8!{;eãùÁ3.}Ñ}Éñ<DÍx¥ò>,s@,gÁê;„É4«Tss³ÝY§[?ÒíyÚ,X»w?–ûYО^!4ôEcô4&âyHmm­r¥f¾R¨mµÏ^…ZKÃÞºC©éöz…Ð}ÑИˆëÇ^ÏÈÐÉè«"ÿ}ûÉõÆeÞÈŸq±hŒ¾€Æè hLÈðxÔ¯V®”ëK÷ɪUuR|ÿ°Ììù³¤ÝHãÇO¯£/ 1úÁÁq=ÅÇËûYÁ2kæGc9G¶|š!{«6óã dx<ê¶Ùè_$gÎÜ‘sM %¦}.?@z…Ð}ÑИÈðŒ)|öÛoòhözÙ¶­B®?8 =Ó$;7›ãbÑ}ÑИ×{ÔùÒùƒŸ¬ŠøCÃZÖ3]N•íâ@¯£/ 1úÁÁjWü"Çfœ‘«WódoK¨ì4€·w@¾úê«~Lš4É©ãûZrr²Lœ8Q“””ät½«¯çl{îQÜ=qB§ÿ(‡–È¥'»$âÓt~„ô ¡1ú£/ 1Ï‹€Ø}I·æpXZZZš„……IKK‹&""Bïs´ÞÕ×s¶=OÈ1ñ:0BGeIε ê™&Y%‡x0.ÑÐ}Éñ,$88Xššš퀨—}åšLm‡††:\ïêë9Ûž§D@t$v¯Üý!NoǾŸ+ÇÞ.æ!@¯£/ 1úñäöíÛ?à-5Dkܸqâçç')))½ê'L˜ ===æ²ÚVû­ïkC½ž³íyJˆ"ïJ†¼Ÿ('®JJÕfYßýr@<ÇQ/ÚÕÕÕ_SS#QQQ’˜˜h7B¢œG뉸8s=gÚS_  K ס5“w«þŽTÙ„­ú;³·ÊÝûåñ‹Çâ/ÓäÖÝc#úù<½<¾”‡^®¨¨@ôõèr}}=z ¯G—Õs=¼÷}£õX¹r¥Óçµ··ëän" £3¦ð̦,iú!D®åäÈ’Ž@¹Ú𽌋Ecô4F_@cr@ÜßQyeeeCv@¬å\¨}ŽÖ;’âÌõœmÏ“r@—/HÕ´¥rÿ`Šì¨]#{ ><‹Æè hŒ¾€Æä€¸·RZZj31»ï¦ØØX©­­ÕÛÝ+oÄ4ëTss³ÝY©lÕ÷mo¨×¨Þ“s@Lž•&5á+ädÑI íù³Ü½{œ‡9 î뀨—òÂÂB‡üü| Òû§L™¢ó?:;;{£¦ñµ·î†½zk9C¹ž#õžQlYÿL>ÎFÇ*¨ÛGî¿ú…$½BhŒ¾€Æè hLÄ3WB?~¼W·çé9 Š#GîI¾ÿNy¾i“Ä4FɃ¯qÆÅ¢1ú£/ 19 žç€ŒEó´Hvv®üìS!fÉþ‡ûdM÷R\|”½BhŒ¾€Æè hLdxˆŠj”†ÙRœ’,¾Ÿ¦Ëó—1<ÈÁÁú·ßžÊ™ÐsÒ¸t©,lY w ~ âWÑÐ}‰€à€à€ Ϙ‹oÉl¿Véòõ“¤{q²«ËOîÝ;ÂCq±hŒ¾€Æè‹Æè@ÈðxÔsæ´KÅOäñ¶™k𕗠âWÑÐ}щ€à€à€ k×ÖÊ¡5Ò1s¦Ìù(Ï»˜ €aò¨| ááÍÒ²`ÍX,§:fÏOåÇI¯£/ 1ú¢1ÁÁqý˜Â«WóÄǧ[þ¶G^ü<_~ú0GêêVó``\,£/ 1ú¢1‚‚2<õÂ…Mrhï}éò÷“°×?Hk—¿äæfóp WÑÐ}ш€à€à€¸ž­[+ŒŸÿ¥Ô®Y#Wɵö9RR’ÂÀ×{ÔgÎJPÐG)ÜÇ•q±hŒ¾€Æè‹Æ@Èèšz)/,,t8CMÓko]¡Ôt{Þš¢X¾üµìÚõDogîõ•?v…ICÃrŒ‹Ecô4F_4r@ÜׯïÕíykD‘˜øD~úésÈ®¢ò>è1tøH^^& z…Ð}Ñæ.æ 9 Š´´âçgœœ\I-I•ò>ÒvužÒX¿”9 ÎçƒØr@È!bbÉ’7²wï#½=÷ý\iX|ˆAH/‚‚>ÈéÓ…’›-¾_y¾ñùtpº\¿~…9 ˆk=ꘘ—²uk¥Þ^Ö°LŽÄ˧YÓåé£ôXððBcô4F_4" ˆkÇ8P*‘‘Mz{ד]²¼a¹¼ ‘¶ôÆlòàDcô4F_4r@·%K–È„ X ˆ]23óõt¼™™y’v#Mü ~òhÿnéY5M Òé±4F_@côEc 2°EEE™¡¬„^UU%‹-ÒŽŒÊ!QÉíö¦þíK_KNN–‰'j’’’œ®wõõœmÏs@Írð`©Þþ±íG9~÷ˆ| š.Ïolæá@ÈÀ¦^¨‹ŠŠô¶)âÑÚÚ*Ë—/—‹/:têêj™1c†Ü¾}[Oã«VUß¾}»]Äž¥¥¥é•Ø[ZZ4zŸ£õ®¾ž³íykD±eK¥¬YS«·ãªã$¶:V·EÉÇ=³è±4F_@côEc âØB„Ö¶•#áè: ±±±v#Î: êe_} –³t©µJ­wõõœmÏ[s@§OÉœ9ôöÑâ£Ò"w.ž š&7ó.2fÐ}ÑÕ«¯LMÁ›ŸŸ¯· ÎQ‹ž?^&Ož¬¯¡þ*Šb¯MuŽâåçç')))½êÕ0.åY:CjŸ£õ}m¨×s¶=oŽ€(Ôz .Ü’œÜñëòÓù +åÕÉ•ôX£/ 1ú¢1±o™™™§·zåe(‡ÂQ'fãÆb0¤³³S6mÚ$kÖ¬qèÜšš‡’˜˜h7Bb™2P½#g®çL{ê 4aiáááÚ³5Ý\ꯧ–££ë%9¹F—iþEž$Èë [äÓ ?¯ø÷Q¦L™2eÊ”)¥ò¨NÃÛÝÝ-S¦LÑ‘ï¿ÿ^;Ž˜Š(ÇÃdê< qÔÚÛÛu. Ï𨓒ËÒ¥oôöž²=²¬q™ä_Ë ž&÷.¡ÇÐ}ÑÈðšJÊîë€ ô‚nϱ–s¡ö9ZïHˆ3×s¶=oÎQ¤§ˆA²³så÷‚ßõªèjuô÷{C¤ykc6ÑÐ}ÑÈ^S èjØ•rBj8ÖúõëmaRIëµµµz»±±Q¢££%>>¾ß¬Sj6-{³RÙªïÛÞP¯7PýX‹€(,h•Ç?_wAË9|ÿ°<ÉO”ž™–¼¬,z,ÑÐ}ш€Ø6•@þÝwßõJ:Ÿ>}º¼~ýÚák¨Dr5k–zÓ+ ½¯C ݃‚‚ô~5äKåXFP”©µ6ì­»a¯ÞZÎÆP®çHýXYÄD\ܲaCµÞþõù¯²îÅ:ÉÍÍ–žµ–ò}Ûyx£’„nmåóâââ‡9jÎäƒxb{c1rôh±Ì›×¦·OÜ=!sÛçêíæŒ…òqI=€Æè hŒ¾h D@¬›Š@ìÞ½['V[: */ã›o¾ÌóáS˜““+¾¾ùý÷’s-Gºäâ­‹òàÞé þ³Ü9s†1›€Æè hŒ¾h ä€ô7K§£ïºŽ®‚½ˆbÙ²IL,ÓÛÑõѲóÙN= ëÓ‘òj}4=€Æè hŒ¾h D@Äêzý•píÌLVØØÊQ$$<•Ÿ~­·“%É’7KôöëG?KwÀ’wõ*r@z›J6–¦¦&퀨µ@ÊË˵c¢Å1" ¶¸t馸ûwINÎ5¹rýŠøtûHV^–±½T1¬ñ‘²ÄDz,ÑÐ}ш€ô¶êêê^«Ÿ[¢¦œÅȱÇܹírâÄ]½ö.L•’ÜÜ1Üò•ÖðÇăq±hŒ¾€Æè‹Æ@È œ Q³G)œ‚›źu5²iÓs½½¹j³¬­]«·_Ö¬Ãl)<}š @côEc4F_4" 9 ®áС {§·O’9æèí{÷ŽHgj€ÔÆÄðP „™®ˆ€¸†¬¬<ññé–ŒŒëºØ(çoŸ7nçH×+1øûJ^f&=€Æè‹Æè€¾h D@ÜgÑ>ÏS¸hÑ[IN~¨·W½Z%ÛË?¯„^[»FÚWΑ'»v1fÐ}ÑÐÏ6uêT½è Fd°lÛV.«VÕéíä‡É²èí"½]\|T>Ì’– è±4F_4FôEc òÙnݺ%sæÌaÆ+r@ÍÙ³wdÖ¬½‘Ÿ¡§ãÍÌËÔð:>ΔΠ)Éèä€8`¶¦àU8“RUU%‹-Ò‹ª¨JzzºÝã“““eâĉš¤¤$—×v{c)¢˜5ë£vDÔvDs„,=¨·kjÖIóÞy¹z5=€Æè‹Æ€¾h D@>'¡ÛB-Fèè4¾3fÌÛ·oKOO^E}ûöí6OKK“°°0uQDDDè}®ªíöÆZˆbõê:Ù¶­BoÇWÆKÌËϳ_ݽ{\>¼œ#??É÷Ò•Ñ‹Æè hŒ¾h 䀌°ÅÆÆñ°4õ2¯¼<“©íÐÐP—Õv{c1²oßCY¸ð­Þ>SxFf}œe®ûhÜn^!Oè±4F_4ôEcëWؤI“äüùó2yòd=«–úG´¶¶Ú<^ ÓR‘“©mµÏUõ£ÝÞXËѹùz:^5-¯’Õ1KÎÞ9«·_¼Ø W–Këüù<`ÆzˆÁ`ÐŽÃPr@Ô±7nÔ×êìì”M›6Éš5kìß×,‡{ µ~4ÛS_  K ס5“w«þŽTÙÄp·Õ!gÎTêò†7äPÓ!½¿¨è¤t| Cp°|˜-/wÄH&£3.ÑÐ}ÑÈq2 =''gH×PIÙ}{/èÖr*Ô>WÕv{c1Dqòä] n×ÛWó¯~žŽ7ÿó*èÕÕ±òòaŒ|}%ßËVFg\,£/ 1ú¢1â„9å°g*] »RNˆB ÇZ¿~½Í!L¦Y¥ÔlYöflýH·GÈgrr®I@@—\¼xS—5-’ý÷ëíÂÂSòñc4.[&OwîäA0Vs@Ôš®X„0%%E¾ýö[=ô*&&¦Wºµ µ–†½u5†R?ÒíùН%!á©ÞÞV±MVÕ­2×µ·Kù©íÒæeνBhŒ¾€Æè‹Æ@Ä +,,”€€Ý»?\f/ÄÚ#ä {ö”ITTƒÞ>wûœÌì˜iñ9~•šëäcPÜ=y’1›€Æè‹Æ€¾h c%ÄÞêçƒ] #¢¸|¹@|} ’«ËA‚äTá)½}çÎé0:$U›7IݪUôX£/ú¢1Œ•ˆ½ÕÏ3 Fˆ%?þØ&ÇŽÝÓÛkj×È–ª-æº÷ïçʃüŸ“Ñ32xàŒµŒˆ«‰­–¸¸ÏaÄCIø»psÝó盤¶v­4,[&ϼ$^!4F_@côEc ‚ဌâ˜Â#GîÉüù­z;+/KOÇ{åú]¾}ûœtvJIjŠ´Í›Ç˜M@côEc@_4†kcpÁÔaD@l¡ò?|| ’ž^ Ë‹ß,–½öšëÛÚBä^ñaù ’ѧÇÐ}ÑÐÑx,E@l9j]r@ËÒ¥²gÏc½½ãÙ‰~m®«ªÚ,/_ÆHå–-òjåJ:c!Ä‘Y°ì­fޱÇÎÏ$:º^o_¸uA:$çZÎ_†a]ÎN)¸|Ù+’ÑéBcô4F_4" NÌ„ešn·/jÁ½Ó§OãI2(.^¼%zutUn–“w¿¬ýÑÚú£ñ‡–* ?ý$Ïvì`Ì& 1ú¢1 /£ñX‚ÅT»D@†‹9s>È©SEz{]Í:Ùô|“¹®²2^êêVËýÔTyïáÉèô ¡1ú£/ì»ï¾“5kÖH}}=Þ9 Ú5µ²eK•ÞN-I•ЖPsÝ­[¥«Ë_r¯eɇ9s¤Ø ’Ñȱc!!!:ÇC ÁRQÀÀ@)..–ŽŽ¼" .áàÁѬ·³r³ÄÇà#ééæú––RR’"•[·Ê«èhz,Ñ}ÑÇÂ¬ÆÆFÙ·oŸL™2Åœ|>uêTINN–7oÞ :¡}¨Ç«öUŠ"))ÉézW_ÏÙöÆzˆ"33O||ºó?όոTö<Þc®¯¨Ø&¯^­’‚ôtŒ~ýÊÆl£/ú¢1{»bi*úQZZ*:*¢ƒo¾ùFBCCt(œËž¥¥¥IXX˜´´´h"""ô>Gë]}=gÛ#ò…ÈÈ&Ù¿¿To'ˆ³VSS#QQQ’˜˜8èã­EH,§ ¨Þ‘ˆ‹3×s¦=õš°´ððp=¶Ïts©¿#Uîûw¤Û ììì2]Þòz‹Äýg®ôèº ~RRrWš’¦5kFüóyº¾c¡¬¢±è¾ž\~÷îz ¯G—Õs=¼÷}bD¾‹Úr@»FH{{»NÖìñD@¼«×båÊW²cG¹Þ>rïˆÌoß«¾¹9\JKxl2:½BhŒ¾€Æè‹Æ@Ä K7¾ô©‡ææf󾦦&½/''gTk9jŸ£õŽä€8s=gÛ#¤7{÷>’Å‹ßèíìÜlñ5øÊï7~7×?{ö›¼þKrúë+¤|Û6DÞꀨ C¿ýjß÷ßïÐ5bcc¥¶¶Ö<­ott´ÄÇÇÛÂ4Ðñ¦Y§”SdoV*[õ}Ûêõª'bŸ+W®ëéx³²ruù§†Ÿ$±,Ñ\_PpÙx¿ùJ^^–Ü;rDÚ=,^!4F_@côEc âd>ˆ-ÄÑüü| Ò×R뉨|ŽÎÎN›Á@Ç+SkmØ[wÃ^½µœ¡\Ï‘zÖ±Ohh‹¤¦–èíÄ'‰Ú ±¬ojŠ”‡÷}NFÖŽˆ§<0˜ÑÐ}Ñ’——©“Ðu2ºñÞäàeˆ)©zêÔ©:r PÛ>Ä‹ â2rr®‰Ÿ_—¤¥ÝÐe5ï†ê ½Žyûv¡Œ~Þà€J@@€477ã5–,y#{÷>ÒÛ'îžàöÞÓíªY°Ô0,5+–*?Û±CÜ8^!4F_@côEc â„ÙZY°È.vì(—•+_ém5¯§¿\¼u±×1j=µ.ˆNFÏÈøœŒþûïŒÙd\, /ú¢1{Cº-Í±æ¼ dÉÉÉ2qâDMRR’ËëG»=" ¶9þ¶v˜ËÑõÑòÛ³ßz£VDW+£›Ê¯V®”Ê-[è± WÐ}Ñ=Ýq…9âpXZZZš„……éÜEDD„ÞçªúÑn™=û£œ9S¨·÷%o–ôªÏËû< « àó¼wU2zP['£â¦ˆz™W^žÉÔvhh¨ËêG»=" óR¶n­ÔÛW®_ŸnÉÊËê3 k¹<µX¨°mÞ<)IM¥Ç‚^!@_4ôEc4öt¤´´T¦M›¦‡\)Ô¶ÚçŒ2iÒ$}®ŸŸŸ¤¤¤Ø=~„ ÒÓÓc.«mµÏUõ£Ý9 ³©DF6™ËaïÂ$åAJ¯c>L–¦¦HsùÙÎÒ°lc6 è‹Æ€¾hŒÆžì€ÙLBwÆ 1YMMDEEIbb¢SË|“¡Öf{ê 4aiáááúÆ2y·êïH•MŒVûÖÊwî<_ßORXø@—wÖí”m­Ûz_]]!ÝÝ~RPpY—_<}*ÝF÷Æï¿»Õ¿Çõõ¶rEEz ¯G—ëëëÑ}=º¬žèá½ï#hÇ’%K¤©©É¼OmGFFê5Bcííí:Y›9 öˆˆh–ƒ?; §‹NËì³ûóúõ yf‘ ^·j•T¹i2:9 ®„n0úíïîî–ñãÇ‹b-§BísUýh·GˆclÙR)kÖÔšËrþöù^Ç”–î—ææpsùî‰òqöl·JFg\,£/ 1ú¢1â¤ÒÙÙÙo¿rJu@bcc¥¶¶Vo766Jtt´ÄÇÇÛÂdšUJ-~hoÖ©ÁÖt{ä€ ŽS§ŠdΜæòªºU²½|{ŸÙ°²Œ÷¢¯Ü¸‘ö%ݨeÉ¡CŒÙd\, /ú¢1{¢2}út=£Ó›7oôÐ"…Ú Ñó±üü| Ò/þS¦LÑù–Nµ µ–†½u5†R?Òí99×$  S.\¸¥Ëûî“…k˜¨¯–r ÇäéÎÒèFÉèô ¡1ú£/'gÀ²•„þôéS—LÓ;Ø¡\žÒ9 ƒ':º^vî|¦·3ò3ôt¼™y™½Žyðà ¼{j.çgfê•Ño¤¥¡!€§9 Ê”£¡¢êÅ]¡¶]å|ŒU#âIIeéÒÆ/‰éÍr ô@¯crs³¥«ËOnÞ¼ô%}õj©Ú´‰^!z…}ÑÐÑØÌ»w·™ž^ >>ÉÎÎÕå­•[eõËÕýŽ{õj•TTl3—‹Nž”³f¹E2:ãbÑ}Ñ ăz-æÏo•#G>Æ3wÎȬ³úSRrHZZôÚ×:¾ÊÉèô ¡1ú£/'ÌÚ”µ&ûúë¯ñ$ÈvrrrÅ×× ¿ÿ~C—Uzds¤•fªÑ1žßkßËÕ«åù('£3.ÑÐ}ÑÈqÂÔºMMMýö«µ@¾ùæ< " #BTTƒìÞ]¦·Õ4¼j:^5-oïaX9ÒÙ©†a}Y-½èôiéådtz…Ð}ш¦^ŒU¤£¦¦Æ¼auuµŽŒ¨ 1r@F‚„„§²bÅksyQÓ"½0aßã^¾Œ‘ªªÍ½öµ,X ¥¢#€'8 *×ÃÖB„íííxD@F„K—nŠ¿—^]•·•o“Uu«úwïÞik›×kß“]»äÍ’%èK¯ /£/ 1{‚bn5}útóB„3fÌææf¼r@F”¹sÛåäÉ»zûÜísØhå85 +PnëMûòÔÊè~~róÒ%ôe\, /£/ 1{‚‚qÖ®­‘M›ªÌåÙfËé¢ÓýŽ«­]#ÏŸ÷N<#Ïý}éôEcô4Fã±æ€DDDØYË4óV_úZrr²NW$%%9]ïêë9Û9 ÎsèP‰„‡¿3—×-U[úW\|TÞ¿ŸÛk_¡JFŸ9SrÝ`etr@°óçÏëõ@,§ÝUC²^¿~íÔu®^½ª×q@ìYZZš„……IKK‹F95jŸ£õ®¾ž³íYYyâãÓ-ùºœò EÂß…[†ÕÑ1SîÜ9Ó;Ýxï•8€¾ô ú¢1ú£±;; ™™™æ(„¥R\\¬_ºµ>ˆ¯¯¯ÔÕÕ ÙQíª/ÁdjÛrF®ê]}=gÛ#dð,ZôVöí{øÙ!ÉËÒÓñ^¹~¥ßq55ëŒÿ®ÞC®ÊåÍâÅè˸X@_4F_@c4vgdÊ”)²{÷n=ý®¥¢fÀrf„„9}ú´C†ªŸ4i’Œ7Nüüü$%%¥Wý„ ôç1™ÚVû­ïkC½ž³í<Û¶Uµ«3——¼Y"{ííwÜÝ»Ç÷hp¯}yW¯J—JF¿x}éôEcô4Fcwu@,޾+Ÿ;ºzee¥ÌŸ?ßᇥ©õG¢¢¢$11ÑîùÊYq´Þ‘ˆ‹3×s¶=r@ÏÙ³wdÖ¬æòŽg;$º>Úê±?Î’ÂÂS½Ô׬‘?ââÐÀ]õ"ÝÑÑÑÏáPÓðÔËo2å|ÔÖÖÊ1E[Tr·7D@ÔhÂÒÂÃÃuhÍäݪ¿#U61Zí;[ž5«C®^-ÓåÜǹâßé/÷îßëw|KK‚Ô×oíuþ“ÌLé ”’{÷Ð׋Êè¾]®¯¯Gôõè²zN ‡÷¾OŒ¸¢’̓ƒƒ¥©©I; ÝÝÝR^^®“   ‡®ak!ÃÁ: Ör.,óQªw$Ä™ë9Û9 CõÂëdÛ¶rs9¸=XNÜ=Ñ︢¢“òáÃì~ûß¿›‡û÷£/ãb}Ñ}ÑØ# ÕÕÕ65ãÓ`¬¯óÑ·kŽ˜466Jtt´ÄÇÇ÷›uJEaìÍJe«¾o{C½Þ@õ䀸–ää‡:ÝT^_³^6õY÷Är@”#Ò+}÷ny;‚É茋Ecô4F_4r@á„X®„>˜)xq@òóóutEíWIð*ÿ£³³³×1j­ {ënØ«·}Êõ©'Äudd\×ÓñªiyU9õ~ª,hY`õØêêXyñbCïdô¬,Œ~k„“ÑÈqSN7·GÄõ„…½Ó ªíìÜlñ1øHzAz¿ãTúÇAýö׬]+Õ#”ŒN¯£/ 1ú¢1Áp@<|Üæ¦MU²vm¹Õ%»ï¶z¬šŽWMËk¹ïÎÙ³Ò(¹ÙÙè˸X@_4F_@c4v'DÍ¡†\)S èßÿ½Â4mÚ4¼" £Æ‰weîÜvs9ái‚üüúg?Ø_¥¦f}ÿdôðpy˜œŒ¾ô ú¢1ú£±;9 !!!RUU¥·cbbz%¡GFFâIxâ‰ää\ÿ.¹té¦.§ÝL¿.?ɹ–ÓïØ;wÎHGÇLãvïºÇ{öHÓ¢Eè àNˆZÏ”>yòdíx”••éÅY #âj~þùµ$$<5—罟'ÇŠY=öýû¹R\|´2º¿¿Üºp}éôEcô4Fcwq@,gŒRk¨²Á`pj%tŒá`÷î2‰Šj0—7To¸?¬'–?¾Ijk×öOF_·NªccÑ—q±€¾hŒ¾€Æhì.ˆšVVEWÕv{䀸– nïÉN½:º*/>®%´u|KË))Ié·_9ÍÌθXîaô4F_4r@\d*?$..N¯>}øðA|}}¥®®n@D½Ì+/ÏdjÛÒÉjýh·GÄõÌ™óANŸ.ÒÛ9×rįËO.ݼdõØŠŠmòêÕª~ûÕZ j–Ž…¾ô ú¢1ú£±‡Ï‚•`|A<Ýouuk¦rOzzzÌeµ­ö¹ª~´Û#Äõ¬YS+[¶TšË+^¯„§ V½itLºŒеaX*ýźuh 0ZˆÁ`ÐËÅM¨µA±ÊÊJ™?¾¹<b­^ ùrUýh·GÄõ<ø@""šÍåÝwËÒÆ¥6÷.T<8Ø?ýÂ=%¯+“ÑéâF_@côEc â„MŸ>½—ÃaÉ@/Ù&SÎGmm­Ãˆ7G@ÔhÂÒÂÃÃõØ>ÓÍ¥þŽT¹ïß‘nßåÂÂâëûIîÜyð9Êñð¦ø}ò“»%w­_[›$mm±V¯×´p¡üqø0úzPY Eôõäò»wïÐ}=º¬žèá½ïk#î€(G#''gH×°=±ç„XË©Pû\U?Úí"#›äÀRsyAËI-Iµzìib0¨aXý#öí“f£Cˆ¾ô ú¢1ú£ñ(D@r8ëØ+›f•jnn¶;ëÔ`ëGº=r@F†­[+%&楹¼éù&YWc;Ÿ£¹9\JKXOF;.NF ÄSk~¨—ê‘t@”©µ4ì­«1”ú‘nÈÈpæL¡}0—OÞ=)ÁíÁ6öì7yýz…ÕºêØX©qQ2:½BÜÃè hŒ¾h D@œ°ÂÂB½î‡êÝ.?~üˆÎÈ5Òí±ÈÈØ!çÏßÖÛj:^ÿN¹xë¢Õc .‹Áà+yyý‡aÝRÉèþþ’ç‚dtæFçF_@côEcðdGܱ•¿áÌ,X‘båÊW²cÇ3s9úU´ìx¶ÃæñMM‘òðá>«uo.”Ç»w£/½B苾hŒ¾€ÆD@F: ÝÑ‚CaïÞG²dÉ›/åG{eñ›Å6ú4A–[­{¸oŸ¼sa2:9 ˆ—õZ\¹r]||º%++÷sùúñéö‘¬¼,ðÒÅ`𑼼LëÉèrçìYô¥W}ÑÑИã6­³`A‹¤¦~ù‘†¿ —CÙ<þíÛ…òèÑ^ëÚÄÅIíÚµè˸XôE4F_@cr@FÒ)--•iÓ¦é!W µ­öaD@Ü‘_}.6¼0—·Tm‘5µklÿäÉ.ihˆ²ZwëâEéòóR2:½BÜÃè hŒ¾h D@œ°¢¢"›Iè8!䀸#Ç˼yïÍåS…§dö‡Ù6¿~ýІ•ŸŸi=B²x±”¹ €LE;–,Y"MMMæ}j;22R¯‚q7rr®‰ŸŸAÒÒn˜÷vʹ۶|óf±<~œd=}ÿ~yоô ¡/ 1ú D ¹2 ýöwww»Åz8 ŒÛ´ÆO?5HbâsyUÝ*ÙV¾Íæñee»¥±q©ÕºÜœé ”Â3gЗq±è hŒ¾€Æä€Œ„ÒÙÙÙo¿rJp@ˆ€¸+»v=‘åËÌåý÷Ë¢¦E6ÏÏÏøË0¬ ë?ú_•Ú5kЗ^!ô4F_@c" Ãí€LŸ>]BCCåÍ›7ÒÓÓ£QÛ!!!zxFˆ;¢†_ùùuéáXªœat,Ôt¼™y™6ÏQ ±VwóÒ¥ÏÉèW¯¢/2œˆJ4·•„þôéS< " nKHÈ{n*G6GÊÒ6üxα™'²d‰ÈqwÖ­{!7>7—ã+âå——¿Ø†•©‡a©Y±¬Õ—8 -  /ãbÑÐ}Éq÷…‹‹‹%""B;/ß|ó¬_¿^ã²eÖ¢-}-99Y&Nœ¨IJJrºÞÕ×s¶=" ÃOjj‰„†¶˜ËgYgÙ=G­¢Ö±™Œ>s¦ž:…¾ô ¡/ 1úqgDMã[XX¨gÎR9$'OžÔ9$ö{–––&aaaÒÒÒ¢QÎÚçh½«¯çl{䀌 YYyâãÓ-W®\7ïSÈ™;¶g³R+¢«•ÑmÕ?߸Q^ÆÄ /âJD9_ýµÍh„ Ó1ƒ1{3h 䀨—}åšLm«DyGë]}=gÛ#2r,^üFöî}d.ǼŒ‘­•[mŸ—÷yVAAºõdt£ciPÉè™™èK¯ú£/ 1W9 ʱPÓïš¶ma:ÆSÓ§O˲eËì: “&MÒ×÷3¾ì¥¤¤ôªŸ0a‚¾Žå5Õ>GëûÚP¯çl{䀌Û·—˪U¯Ì僥%¢9b€aXËåéÓÛÉèK—Ê“]»Ð—q±è hŒ¾€Æä€¸ë¬¾¹ßÿ½ÔÖÖ:tNMMDEEIbb¢Ý‰¥34P½#g®çL{ê 4aiáááúÆ2y·êïH•MŒVûÃYÎÎ.“™3;ÌåÂ…z:ÞÛnÛ<ÿáÃdik[j³þÁÁƒÒîÄ÷åÍúºK¹¢¢=Ð×£Ëõõõè¾]VÏ ôðÞ÷5v@LÑcÇŽÉüùó>§½½]'wÁôQΜ)4—¾](ÉF'Ãö0¬,1|¥ à²õcrräã¬YRäd2:9 ÇL#+¬Ö±–s¡ö9ZïHˆ3×s¶=r@F–Õ«_J||Å—aYåÛeÕ«UvÏyýz…<{ö›ídôM›äå/¿ /ãbÑÐ}É)¤µµÕa$>>^êêêÌ΄š¦Öò½ï¦ØØXó­ÆÆF‰ŽŽÖ×è;ëTss³ÝY©lÕ÷mo¨×¨žÑeÿþ‡²pa“¹|þöy ì ´{Nié~ã÷n³þÆ_’ÑóXq±ÜÃè hŒ¾h ä€8‘¯a†™,??_‚‚‚ô9ß~û­ÄÅÅé—u[åñS¦LÑù½ŽQNŒ½u7ìÕ[ËÙÊõ©'2zddäëéx33óÌûæ|˜#§‹N8 ëÆ4›Ç4FEÉÓ„z…èyC_@côEc4&â Ä4Ó•iºÝ¾¨m5›•+ÌÞ”¼Ãa#Ý9 £Oxx³<øÀ\^[»V6Wm¶{N}}´”—o·YÿàÐ!i?}€WÁÌT»˜q3¶l©’5kjÍåC%‡$ì]˜Ýs<8(ïÞ…Ú>Æ”Œ~ò$½Bô¼¡/ 1ú¢1:q×Y°0r@FƒS§ŠdΜvs9+/KOÇ{åú›çäæfKW—ŸÜ¼yÉæ1U›7KÝÉ茋åF_@côEc Ä ËËË“õë×÷Û¯ò8 ð$ˆ€x99×Äß¿S.^¼eÞ·äÍIz”d÷¼W¯VIEÅ6ÛÉè—/‹Á×Wò32è¢ç }ш+ï¾ûNÏxem¬É“'ãIâ1DG×Ëo¿=5—{ö›D×GÛ=§¤ä´´,°{LƒJFÿí74r@\á€X›1Êë€à€iöìy,K—6šËo]”€®É¹–3À0,¹e<Ö¦“’’"mv¾?z…¸‡ÑÐ}ш€8aj¶«¦¦¦~ûß¼y#ß|ó ž9 Czzøú$;;×¼onû\9q÷„Ýóêê~‘ÊÊxûÉè³gËÝ'Ë=Œ¾€Æè‹Æ@ÈP_”Õ‹±ŠtÔÔÔHOO¦ººZGFBCCñ$ˆ€xóç·Ê‘#÷Ìåu/ÖÉÆçÐ'UZ[íO·[¹e‹Ô­ZE¯÷0ú£/¡¾(«\[ ªUÍ1r@<‰¸¸?$6¶Ú\>|ÿ°, Ç#77G:;Õ0¬ó6)p €M ·š>}º^ÀO1cÆŒ^+™cD@<…£Gïµn3—³s³ÅÇà#éévÏ{ù2FªX¸°á§Ÿä™•dtz…¸‡ÑÐ}ш€`8 ctܦÊÿPy —/˜÷E5FÉž²=vÏ»wµÍ³?cVjª´…„0.–{}Ñ „^‹/,[Ö({ö”™Ë Odùë圧†aÊíÛçì&£˜=[ЧWˆ{}ÑÈPlÉ’%2a„~9 ŽNÃ[\\,zø–š9K-l¨†uÙ³ääd=—"))Éåõ£Ý9 £GBÂSY±âµ¹œv3MüºüìNÇ«¨­]#ÏŸo²ŸŒ/¯V®Dg d°ev6ú: ãÆsØ),,”îîn=‹ÖÉ“'%$$Äæñiii&---弨}®ªíöˆ€Œ./Þ”€€.½:ºi_H[ˆ+>f÷¼ââ£òþý\»Çüþ»NF¿n‘ŒN¯÷0ú£/'×)**êµð škùò对‹ƒ¾®Š†Ø2õ2¯D6™Ú¶œòw¨õ£Ý9 £Opp»Ñ¾k.ÇVÇJÜqÃêè˜)w{ÜkãoãÙŽŒ‹åF_@côEc d¨+¡[n«HÆ·ß~ëôõÔy§OŸ–eË–ÙÈõ‡×ížÿìÙeioðúsçÊ«Ü\ô¦L™2eÊ”){|yÄÌÌL‰‹‹ÓÛ½r@&Ož<¨ȱcÇdþüùD@ˆ€ŒW¯æ‰O·ddä›÷ýÔð“ìz²kÀs?~œetÀOÙ=¦">^꣣éâF_@côEc 2SIäS¦LÑ‘Å0 ƒ¾–½ˆ„µœ µÏUõ£Ý9 îÁÂ…oeß¾‡ærbY¢,kX6ày/^lêjûù"é韓ѯ\a\,÷0ú£/9 #mñññRWW§·ÛÛÛõ4µ–/è}‡0™f•R«­Û›uj°õ#Ý÷dÛ¶ Y½ºÎ\¾\pY| ¾zut{ç”fxý×?ÿ,åÛ·Ó+Ä=Œ¾€Æè‹Æ@d¤Må镸®†t©—u{9ÊI±·®ÆPêGº=ÖqOΞ½#³f}ìµo~ë|9rïÈ€ç*D9"¶êeêT› =x#î€Ô××ËôéÓÍC°ÔÐ+õ?mÚ4—9(ö¦äéöˆ€¸/³fuȹswÌå_ÿøU6¼Ø0àyÕÕ±z(–]Äšá€p£/ 1ú¢1±ojÁÀªª*½Ó+ =22R0Ïw@Æò¸ÍU«êdÛ¶rsùxñq y2ày* ýãÇ ÆÅ¢/ 1ú“âjDÍæÔÙÙ©·Õ¬WÊñ(++“ÊÊJùæ›oð$ˆ€x4ûö=’ŋߚË9×rįËO.ݼ4à¹j:Þ»wã€Ð󆾀Æè‹ÆhLd¸"T3W©²iö+g×ÁÈq722®ëéx³²òÌûV¼^!;Ÿît 'âW©©Yï´’›ö@ˆ-SIÕ*âQSS£I“&éý**¢ê0" žNhè;II)1—÷<Þ#K—xÞ;g¤£c¦q;Ç)äÜ9òpß>hÜÃè hŒ¾h D@¬™z1¶ÌûX´h‘ޯơãIâñlÚô\Ö­«1—Ó ÒÅÇà#Y¹Yžûþý\).>êÔ,X%))Ò"ïBC¥øøqªÜÃè hŒ¾h ä€ô5ÓâƒS-zug̘¡gȈ€x:'NÜ•¹sß÷ŽŠ´„JjIê€ç>¾Ijk×:¯oNŽ”%&JÇÌ™ÒðÓOrû®ÜÃè‹Æ€¾h D@0r@Æ99×ÄϯK.]ºù%*bt,ÖÕ¬ðÜÛ·ÏIgg ÕaXŽwõªTmÞ,]~~R»v­^AïÆtFd,ðóϯ%!ቹ|²è¤·;tn[[ˆÜ³³x¡#úüþ»ÔÆÄhG¤rËÉËÊâÇ=Œ¾h è‹Æ06# jÆ+Óô»}a,r@¼…ÄÄ2Y¶¬áKTäZŽtÈ…[ªªÚ,/_ƸDßÛçÎIã²eÒ1k–”íÞ­‡jñÐåF_4ôEcS9 jtK‡Ã5-/Fĸ|ù†øú$''×¼/úU´ìx¶ÃaX¤³Óßæ0¬Áè[|ô¨´„†J›ñ¾(IMåÁË=Œ¾h è‹ÆhGë]}=gÛ#Ä=9|ø¾,XÐÚk_ø»p9øàà€çÞºuQººü%77{Øô½ž‘!Õ6èDõ?ŒN|~f&ß÷0ú¢1 /£±÷9 ………`7bá¬)GÄ^de D½ì+/Ðdj;44ÔázW_ÏÙöˆ€¸'ÙÙ¹âãcôôó¾-•[dMí‡ÎoiY %%)îïÍK—¤>:Z:å™Ñ™Wz…¸‡Ñ}ѽƱ6j¨³`ݾ}{ÀȤI“´“âçç')))½ê'L˜ K‡Fís´¾¯ õzζGˆû²téIJzl.Ÿ.<-A‚:·¢b›¼zµjÄ>kÑ©SÒdüµKéþý|à=Iè¶L~HUU•:¼ŠzMMDEEIbb¢Ý‰åg¨Þ‘ˆ‹3×s¦=õš°´ððpZ3y·êïH•MŒVûîTNN®‘èèW½êgvÌ”ì²ìϯ©¹/ÃçaX#©ïƒC‡äãüùòqéRyöûïcòû«¨¨àþE_.«ÿ'¢úzrY='ÐÃ{ß×GëÉqæzζGˆ{3gÎ9uªÐ\Þÿp¿,lZèйååÛ¥¾>zÔôÍËÌ”ç›6éDõšuëäzz:ãb}Ñ}ÑÑØó%K–èýÁ怜;wNϦU]]íÐ¨ØØX©­­ÕÛ-ñññýfR‰ñöf¥²Uß·½¡^o zr@<‹˜˜ZÙ²¥Ò\ÎÌÏÔÓñ^Í¿:à¹7n¤‰Áà'¹¹Y£úo(¸|Y^®^-]þþR¹u«äeeñÝ€g8 *ÿÂälôu@ͱ•ÄnË!PÑ’   ½Ê”):ÿCMßkij­ {ënØ«·–³1”ë9ROÄs8x°ÔèD6÷ÚÙ)ûKKônn—ÒÒn¡ï£ó߸t©|œ5KïÙ£‡jÑ+è‹Æè hŒÆn퀨jµ†‡)!]Ykk«,_¾\.^¼è’áYj‘´‘nÏâêÕ|ññéÖMû¶Vl•_^þâÐùÏžý&¯_¯p+}ï9"­ HëüùrÿðaÆÅú¢1ú£±û: ¶"*ÑúÛo¿Ìóz-úÙ$”šËgY³þTpY _ÉûË êî¤ï£¤$ù8{¶¼Y²Dîœ9C¯ /£/ 1»§bZ ]EÔð(Ó…ƒ]#Ä݉¯”˜˜—½ö} ’3…޽´75EÊÇûÜòß–›•%Û¶IW@€Ôï×/ó€û8 ™™™§·ÕŠè–9“'OÆ“ ╜>](AAz'§¿Œ‘øÊx‡Îú4A–»µ¾×¯\‘ë×볞ÿú«ä_½J¯ /£/ 1»Ç,X&ëîîÖIá*òñý÷ß‹Á`À“ ÄkQë\¸pûKrzéA‰hŽppVºñ÷á#yy™n¯ï­‹åõŠÒ(O$×Õ¹‡Ñ}ѽÔÁˆ€Œ%V®|%;v<û’œžwUOÇ›‘ŸáÐùoß.”GözŒ¾wOž”æˆiŸ;WJ¤WÐÑÐGÇ!σ±JRÒ#Y²äM¯}‹Þ.’}Ëíxòd—44DÉõëW<êß­œå„(gD9%Ü ä€Œ¨âSÖâ€Ðk1¤§_×Óñfeåš÷m/ß.«^­r,ÇÂèxtwÿ`üv§ÊãÇ)õoWðÔp,5,K ÏRôè¢× Ð}‰€Œˆ¢V0oooÇc dL²`A‹>üåáö ì tèÜ’’Téé™a$ÙH€Ç9! •˜®ÔU¢ú‹uëtâ:ãbw hŒ¾€Æä€ «rëÖ-™3gŽy*^ŒÈXbãÆ?dƽöÍù0GNÐùèîö“OŸnüå~à±NˆBMÕ«¦ìUS÷ª)|ÕT¾ô ÑëhŒ¾€ÆD@†m[Bˆ·sìX±„„´õÚ·¶f­l®Úlwè•ve0$ôùÖëýž–bɳgõ"†j1Cµ¨á5œ1 < ÝãÆÃ“ âÕää䊟ŸAÒÒn˜÷*9$¡ïBŠ€ ·Ì©¨Øí½0‡KëüùÒº`Ü;r„ž7zÝÑш{MÃ[\\,‘‘‘:¡ý›o¾Ñ 677Û='99Y&Nœ¨IJJryýh·GˆçðÓO ’˜Xf.gåeééx¯ É09!==ûõð«úúõÒÕågtB¶ë½ r“#÷úÇY³¤qéR¹sî÷0ãŽÑ÷p@–-[&EEEÆ—°éìì”;wj‡Ä–¥¥¥IXX˜Î;QDDDè}®ªíöˆ€x»v=‘åË_÷Ú·äÍIzœäP"ºå,X·n7:߯û$TîÜ9çúäeeIE|¼tùûËËÕ«¥àòeîazÝÑÈð¬2ØåˆØ¾¥^æ•È&SÛ¡¡¡.«íöÈñ,ÒÒnŠŸ_—ää|Ù·óÙN‰®vèüþ99òìÙ ©¬Œ—Ü\ïÈ£P3dÕ¬[§gÌz¾i“äefrÿâ:¤µµuÐÈíÛ·íF@&L˜ K‡EísUýh·GÄó˜;÷½?~×\¾xó¢tHŽC©lé{ëÖEijŠ”––rçÎY¯ÑêÖ… òzùré ”'»vH¢:÷0ú¢1 /£±8 öf¿21ÐK¶5«ªª’@ã‹I}}½Ý¶ûšeÄd¨õ£Ý9 žÇºu/dӦ罒÷såÄÝCÖ÷éÓߤ«ËßøÛØâ5ÑÅÝ'ä]x¸¼ ‘‡q3îÐ}ÑÈqlö+Ót»}QÉÖ§OŸvêš%%%âëë+•••vóæˆúMXZ¸ñEMÝX&ïVý©²‰ÑjßÊçÎUÊ’%½êw¶ì”í¯¶»DßÇóäÇŸ¥½=L Ïx•~¥û÷KǼyòqùryú—… ]Ý^EE÷ë0–ÑwøËªS=ÐדËê9Þû¾6âC°\5Õn~~¾L›6MÊËË<ÖZN…ÚçªúÑnÏ#++O||ºåÊ•ëæ}‡ï–­ \ÚÎÓ§ ‰†l’ÜÜl¯Ñ/7;[žíÜ)*ú¹b…ܼt‰û €á³sçÎÉÔ©S¥ººÚ¡!P¦Y¥ÔT½öflýH·Gˆw°xñ[IN~d.g_ƒ¯ü^ð»Kõ½yó’¼}»HÚÚ~”ÂÂÓ^¥a~f¦ü§Õ_lØ ×32¸‡w hŒ¾h 䀸ÞlåØË¡PkiØ[Wc(õ#Ý9 ÞÁöíå²jU]¯}Ë—Éî²Ýâï“'»t4äùó^ QÜ0:è¯V­’N)ß¾]GH¸‡wŒÆè€¾h c<d$M-PèÍíñλ-3gvôÚ—ð$A–¿^>lúÞ¼™&oÞ,–¶¶yRTtÊë4-Κ%Ë–Éís縇éuCc@_4" ˜7: ŒÛtœýûÊ¢EM½öÅVÇJ\u܈éûøñnéìôÿÿí‡SÙ÷öß?ÍÚrKk·¶vë»e@%HFÉ” Š (*¢(‚"ˆ QT%ƒ"A’ˆ` ¢"*H’çísw‡ß€ÀÌÀ}>ÔÑ™î™îžÓÝçösùx­í3??wÅù¸ 7-ÇŽ©êíAA(¾{—×0ûvÓÇ4ú—>¦9„°äç´û÷ U:Þœœ‚ñe)U)ØöeÛ‚ú·¤ä.zz¤5Ä OŒ˜ q9Zqv6ÚTB¤õèQääðfŒ iô/}LS€ŽùùÌã—.=/ã?,G,Õx…>–††ØÿZCBQP»"ý]~ëÞíÝ‹Á­[Ñ£ºjñ:¤Ñh4„°ä§±£G[qð`û„e¾ï|qæÙ™Eñoqñ¼{çƒþ~i I]±~¯LMÅ'ww|qvFÍ¥KÀºuÓ¯SÆú˜FÿÒÇô1áciipp蟰,¦1>šXLÿÖןÇÐ5Þ¼9¼b[CÄêâã1ààð¯Ø˜ Æú˜FÿÒÇô1a ÈJ²¼¼`e5„Ì̲ñewŠï¨YÑN‘"w!ý[\|ïÞíE¿#*+Wn:[™¸„1‚>¦Ñ¿ô1}LB8ä§1ÿ.œ:Õ4aÙöÏÛ‘\¼$ޝ¾>CC6hk AAAΊ< 4F£Q€¶€ü4völ||z&, ŽÃo/ÿg£»Û¨ªJ¡¡1FÐÇô/>¦)@(@8d¹ÚÝ»ÅØ²eæ/K}’ §¯NKοuuþk 9ˆ‚‚?…yuäòssy­2FÐÇ4ú—>¦V²jÕªq3õóÓ}/..k×®UkòzsoÏÔý±dùÛ¶mŸ‘œ\õcCþɃհn—Þ^rþ-*ÊFW—ìQU•¼rÈ4Ö³{7úœTæ,^«Œô1þ¥é㟸Ä2YYYpwwG__Ÿ2OOOµÌØõæÞž©ûã•aaa¯úzÂ2?í!ÿTÓ©%{̵µ18hƒöö`æ¬èóSþ<†llÐvð srxÍÒh4F2ûÏÉþ¨@òÚÍÍÍèõæÞž©ûc ÈÊ0iýVýe± ±Øý~÷’öoQÑ=tuàÛ7{íØ.¯èZ¡¢ìlth¿ÕÎ5II¼n#ècú—FÓÇ Óî÷ßÇêÕ«aii‰ÄÄÄ ë׬Yƒ±±±ñ÷òZ–»~2sÝž©ûã•a2þCÆÈxݲì¢llÙŒÜüÜ%ïß§O08¸oß¡°py 1äã§Z ùfk‹Î}ûPtï¯_Æú˜þ¥ÑÇô1Èô´µµÁÇÇ1113nGÄŠ±ë9.S¶gêþزrL2aIF,ýeî}îHªIZþ-*ºÎÎ}øöÍN;Τ]+TøàÚƒƒU·¬º¸8^¿Œô1ýK£éc ééïïWƒ»WB ˆœ@éãáá¡”­îâ’ÿù~é¿¿p¡ ~~]ÖG´F ü]ø²ú=--×12â€÷ðþŠ>•W®à›³3úƒ‚PWTÄë™ïùžïùžïùÞÀ{ iÆ\È2c×3Ĕ홺?¶€¬“ÙЭ­‡ÕìèºeiipèwXvþáÑшoßlQS“¸¢k… rsñ:, ÃÖÖxvæ ¯eÆú˜þ¥ÑÇôñÏÖ2yyhh(ÚÛÛÕëžž 22ò‡¬S½½½3f¥šnýäýÍu{†Ös ÈÊ6GÇ~¤¥UŒ¿—t¼6C6È(ËX–þñ!"DĈˆ’•Ü/öñµkø¬Ý{½½Q–™Éë™1‚>¦iô1}¼Rˆ¡y=&¿/,,„Zþ÷ß«ñCCC>#smÌ4ïÆLë§BsÙž1ëÙ²ríàÁv=Ú:aÙ¾Î}ˆjŽZ¶þý·5ämñôé¥%{œ—.ÕÃËk[¶ŒaûöAÄÅÕ›¼ü¼<´DFbØÒÍ'Nàí=¯kÆú˜þ¥ÑÇôñ i™Ž_ýuEïó€¬l»té)<<>MXW‡v®€`—¤¨Ë@u°¾”Ž-1±..c¨«û÷zþpvþ>+"Vž‘^OOô¹ºâѼ¶i4F[Éäg„- +Çrr °yó(îß/_v_{Xß<º99ËÞ¿’¢WRõJÊ^IÝ»TŽËÛ{h\|èââ28ûíæå¡):ÃVVxŽü‡y3FÐÇô/>f ûm.=Û±ã#.\¨›°Ì£× ÚûJñ¯LZ(“Ê$†2™áb‹ ú·²›òÞ²°›óöK³²ð~×.|uvÆ“«WÙï˜1‚>¦iô1Ç€P€P€°ÖbiÙ‰/´súv²c-ÇÔ´¢ü[X˜ƒöö` Ú ¶öâ‚îûÖ­2DG7aÏžw°´ƒÃØ- ÏžA[÷ññušHÉŸó>bc1dm¶îÝ+B\\vvv°±‚¿ΞmDVV .^¬…“Óè¸ijÓDÉjƒ»{Ÿ:Ç·¨íÌå8г³Ñíï;;T'%ñz§Ñh4Ç€P€P€°ÖbiØÖ­ƒHO/Ÿ°ÌzÈë´¿Û·WÜï-(x€¶¶ƒ²ÑDÀ…9oïáÃ|$'W!,ì\]ûÔ¸š;?¨Ö¥7Où!îîýªÛ•³ó· Я^}¢Ë–-#JÄܼùhNÇ÷4!ƒ¶¶è DÑýû¬u£ÑÇô/>f ûm.®vàäÉæ Ë” û¶bwUU ´ßÙÝí‹âbÓZC¤åèĉfMh¼W‚cûöÏ }Ë—«‘››o–køîÝ9òRµ x{DBB턉#Mꂦ ·AA´ÑD×… ?͵ÍAÓ¿4ú˜c@(@(@Xk±->¾^ÕØëÞg”g`ãØFTi›´¿•Ø ò­!9hk Q­!õõñ3гgÐ¥ ‚AØÙ}Óî…Õr‘]4¯×°šsç•ȱ·PbQ?s™I¢+9ýx·w/ŠïÜa­>¦écú˜-   ´…7k µø¹¹ê}@gŽ Sç7ZûÛ7¼çëÏãvéÊ"••)èïwÄ»wÚƒyñ]•¢81ñ)BBÚàâòUu‡Ú³§ÑÑÏqëVù¢gJJ%|}ÿÌÜŽŒ Ó¥ 7¯CC1de…ƘÞ4Fã  ÖZ,¼¹¹}BRRjý°³@§ö'ÈÿÒ ²·w/¬†¬°up+öjé'^œ@je*rósWÄï—®Mׯ?BBBžv×k‚cXMÒñ©©•fÉLeÎk8+«Tuù²¶VÝÀkLÞFEZ¾h÷ïoo”ef²ÖFÓ¿ô1- |Ô§a¿Í…3yЖÚ~iýˆŠœpŽ¥D7$£,çÏ!èm\¾¸ÀbÔnŸÜò&ñuñ¸[rwÙüæÌÌRœ>ýì¿…a8:ö«V…ÔÔB|øàŽwï|P\|gI_ÃÒjuæÌ38;QÇ/-499ÆwÏ’ [ð¥%š£¢Ô„†ìwL£é_ú˜Æ1 „„µón’yÉa×[5ð|º¿;%?>Œ?(|€¤ê$D´F`燰±T)|ý»ýõ< iiÈË_µ2nB&] z ‡Õzàçט˜gªEaâØ\¼~Š¡!+44Ä.‹k89¹>>=JL:ôFXeF·<=Ÿ<<ÐçîŽG7o²ÖFÓ¿ô1- „„6ÿ]äÁuòƒ¸ÉÛù'7ÝÄ™ggا¯NØ<ºž½ž{†„ÚdÏÓü“MÒ㦤T!<ü•š_CƹÈÌï2ÇÆõëFe”zòä*¾j¿¡§g7JJ–Ç m"@ä|Š abÔwóòðüÔ) [Y¡5"BµŽðÞ Ñh4Ç€,0«V­7c‰‹‹ÃÚµk•ÅÆÆš}ýbï- +×|}»Uwsû÷^Ñ=\zz G^×G/lÙ ‡~ìë܇ÓM§Õć"\̱¯ôôGˆŠjÆîÝ’wD»>¿àðá7j|‹n½©–ŸŸ‹W¯Âþk 9»l®á T—,éš%éåÜãƒÒÛ·ñaçN|qvÆ“´4ÖºÑècú—>¦±d±„ˆ1deeÁÝÝ}}}Ê<==Õ2s­_ìýq Èʶ˜˜FìÝûnÞý+bãÚãk8Õt ]jΑ-#[àýÁG^AbM"î7a^vv±&œ°o_§šPÑÖvÚ²zµÎœÇ]Q‘†¯_]ðþ½´†d-«kX©Ë`uév&ƒ×iéj8{VeÊz‚‚œö;¦ÑÇô/}Lã¥(@äa^Tžyíææf¶õ‹½?¶€¬l»s§D¥wÕe|ZHÿfgãbíE~}½Ø4º Î_q ãbc^ž>>èZZ3¤UCZ7$=îîÝ=ˆŠzþÃlîóaùùµ@zÃÃÖhlŒYv×°¤í•öržeðý•+•3~¾øî]tûúbÀÁÕÉɬu£ÑÇô/}Lc ÈR kÖ¬ÁØØØø{y-Ë̵~±÷Ç1 +ß$›’Ì5±ØÇñP{ÐO{’†ÏObÇ“(l¹~‚j±Ár¶;ß"àäS$¦>Rã<ãø**®ãËi Ù‰ÒÒ¬ewže@¾Lh(ƒñe‚óggœÁ½öâE nÝŠŽÔ¬ê¼Wh4Æ1 KD€Lõ¹Õ«W›mýbîON ÎôñððPMk:u+ÿ/Ô{-ÖþWâûcǺqîܧEõouu.]z£2TÙØŒÀÅEº õàLb’ž]GT_<¿zªÀîî8þù8.¿ºŒÌ²Ì=^i éìŒÂè¨ Þ¼I˜Õö^¼x±¨ç»ªªwïvÃÇç3¬­‡4QÒ‰ºº¶)?/Âãýáñ·GëcC–úõ¼ØþýÞwuuÑôï²~/q‚þX¹Ïkla ûm.»|¹®®} êß qñb­ê$¦%{“t’9:d®Žé¾—[‹”ÊD¾ˆ„Ï;Ø Ù(ÛÓ³G-»RyE}f¾ÿñci Ù†v ÔÄÙâ—Ò5|óæ#8ðVukó÷ïR©™§lJONV]²¤k–tÑb¿cöí¦è_ú˜Æ1 Kl ˆ,3×úÅÞÇ€¬|“n8’=*;»hÞü+cLdvq™üPf—ô¸^^qìX ÒÒŒK;m Ú²LÄ6Ä"¸=Û>oûw¢Ä>7j;„øúxd•ÌOw)i imÀð°ššN/ëkøÞ½"•ªØÖö›J_,ú'wu“AéoVƒÔe°:û³o7þ¥i²@dòr]V©ÞÞÞ³NÍvýBïc@~NÛµë½zè4÷àçS§ž«y)¤†]ÆšÈ\—.Õ '§`Þ~˃‚H®NƱÖcØõ~,‡-aû;ݾ8Ù|WŸ\UãMÌ×rŸ?oÇÇÞ(-Í\Ö×Åøø:-.ôª cG¶þYLÒôJº^IÛ+é{yÿÐh4c@Ì8ÈTóL%Ld.™æÕ˜Ëú…Þ[@~N“ŒRsò¯´ œ?_ÀÀU“nc3¨¶yî\îÜ)^Ôß'µ$³–dØ’L[’qË㓇ÊÀu¡öîÏ­[Q~~Z5ÁóokÈ)mYÞ²¿†¯]{¬Ò‹x””Çò~ü÷>|¨&.” ŸGE© YëÆšMýKÓØ2Oüúë¯+zòsÚ­[åš`2É¿ÒuKÆÈ’UIºqIKŠdZ’±K:#Tá}5÷HøËp5‰ÌIb?`¯æ(‰~­æ,™ÍD‰ÝD_Ÿ+>~ôBYY抸†¥DZB¤EDZF¤…D—¶ùÑÍ›øäæ†O(OOgßnöí¦Ñ¿ô1c@ÈÊ ¬µ˜“á›7×lLƒˆ‹›º;Öõëqüø ìØñAãÁëaa¯œ\µhéqÍÒõH2;»ÌÒ.³µ;ö;bóèf5‹»Ìæ.³ºËìîÆ¶†´´DbxØÏŸGýÐR[[¶,}$çWZ¸dŒˆ´pɘ;"­ÍQQ¶´Dë±cªu„5›¬Ù¤Ñ¿ô1}LBVŒ¡Íø°·Ò‚Å¿ÙÑž?\\ÆÐ„¬¬5[ºŸ_—JÙjo? ²&I-¸zø\Á~É.ÊFÂÓ„½ƒW¯—$NýNìÄ™ggpóÑÍ[I=JG_Ÿz{=QV–¡–=}zX§‰‹ËÚ7’-K²fI÷¬ýûߪ¯²ÌL|ðöÆ->Tü—²—F£Ñh4 ÂÚ&ݧž<œpŽE„89©ô¸{ö¼CttnÝ*û©ý”—Ÿ‡´Š4D=‚·?ì¿ÙÃrÄ;?ìDÄË$U'áAáƒIßËËÇUkÈÛ·Ñ1f¥ÉuxûÝrÙ‹±»wKpäÈKÕ}ÏÛû£&ZkÑ£2e½>|¹¹Œ¬Ù¤Ñ¿ô1}LB8„6Ñ,-G§<ï›6aNéq»[rê. äMÜ?¹«À._\pàíœk<‡[å·ÔçššÎiµD4‚•‰ÆA|ÿnµ"Dˆn<йsJÌJ+YlDº||ÕÜ!UÉÉŒìÛM£écú˜„°„öæêú55£?´€¸¹Ò?¦Ž“ȈÔ'©8ñâö¾Û‹­ƒ[á2l¥yt:q›´¿*íOþïDŒZþìÙYÕ]KÆŽ¬¤¤TªI%--Gºó.¾YoÅÛ  5«:ck6iô/}LS€Ž¡©1 è«û?ñ¡b\¾ÜBÿ˜Án—ÞÆWaˆÒDG´ö¯­‰‘(lÀå!kœüf‡+ÖÈÛ€â[T~Ø…ÚסxZ{῱#ËS˜de•ª iÎVŸP¶õ¾ZÙãiB¯ F£Q€¶€Ðþ!°°ƒ«ë›é3ZFy,Æ6¢SûäÿšàˆnŠÆ©ç§¦ ”À.øô¹Ámp+l¾[hre=\´ÏøŽ­GèÈœêwÄù÷;‘ôæ0RbÕ øûE÷—üoÏÍ-À™3Ïi÷ï6lG“ë!äß¾ÏÁšMýKÓÇ „c@hôï|Ù¾®}89zrÂ}tlð:¦p/ÈEfY&®Ö$"¹õ(.vû"æËvD Y#ðûFxhÂÄR³ÍšHq¶ÂŽ/.ðïñAH[Ž¿8ŽXM¤$W%«q(99K©—£Àá,>­wÀÍÈÌ,ã5Ì8A£écú˜„°„5ôƒ9íNÉ5ð|º?Y?›íg£JušØ¨îöGùWgü3º 75;;¸‡ì±S3Ç!lÔ‹L¶(i„en™p1ôu(¢š£W‡ÔÊTÕULư,„O /¦£ÛÒ•BphG3’“«y 3NÐè_ú˜>¦!B£-G+ÑMMM^¼8ŽŽ@53ûèèf|´A]Ÿ;rz|p¥sN½=€`m½öÞõ³«0¿ql#¬‡­U&/I/,sž„¿ W]Å.Ö^TiˆE0å™a\ŠLXØM6H²¾m._TW-é²ÅóH£Ñh4  ¶€°Æ‚¶Ì}\Zš‰§OÔ,í]]øòe¾ß„oßlñþý.¼~} çP ‰—ë•©Jpˆð"Bdçûئ}GŠ,"\v÷ìFÐÛ D´F æY .Õ\R³ÊËDޯף7ÐçêŠ.çõl„µõ°¼.ƒØgó;3›3y1Nп4ú˜- +[€¬Zµê›L\\Ö®]«,66ÖäõæÞž©ûãöÙ¤­T硼<uuЪ ˆîn_|ýê¤  8 §gv¼a¨¯?Gn ÿ¿.ZÒUKºlI×­øºxÕ•KºtI×.ïÞpÒ¶!]¾¤ë—LØ(s¤HZâƒm©  ³ gq¹ú2ÒËÓÿ¼1/Í'N`ØÒõ‡Oá`ЕÆWÒù^¹RiÒ`éÖ–ù˜"„q‚þ¥ÑDzÂÈLdeeÁÝÝ}}}Ê<==Õ2c×›{{¦î- ¬± ý|>¡!‚C„Ç«WG”éïwPÂDŠ•—/#”p3]ª`ü.ƒàe0|l}¬šEÉûjß÷èõ€ƒ&rdòÆÍ£›á m?ø…;š¬ÑéeÄÜpì‹/ÅV§Ïpqû„3çêÕ„‡3· êú9”×ãýK£Ùòó yØ—“ C^»¹¹½ÞÜÛ3uB£ÑtVP‹ŠŠkhh8«ºlI×­oßìTW.éÒÕÕå––cª«WY™ñ­÷ ï«´ÂI5I8Ûx÷R÷à«­rãàÕã«ÒãX\ƒõŸ`•” ÏWØ×¹O¥/–4Æ2½´ÄHװʱJ5Ñ#[Ah4c@V´ùý÷ß±zõjXZZ"11qÂú5kÖ`lllü½¼–eÆ®ŸÌ\·gêþØÂ }l0«Uaž<¹ŠgÏΠ­í>|ðÆà ü.ƒà;;Õ x_R’eÜ`ú;wðÎÇýŽŽ¨¼rE |OÉ,ÄÞl²‚Û¡&ì/LÄþ·û±ûýnl*; «=oµ8 ØxÀ¶’KØöy›Êú%Ý¿tÀaM4ÓÒé¦Óˆ¯GRu’X/éŽEåý“Çk”q‚þ¥ilY^´µµÁG+0cbbfl!±bìzcZ\LÙž)û“¨3}<<ÝÅ%ÿ/ÔûÉÿ/ôþWú{úwþßwuuý4¿·¨èš›ok‚$==aèíõÄȈ5¾·Æ×¯;ðöí´·Çi>yˆººÒ)·÷2%£vvè9r…¨åo´8û¶¶ßàåõqo°~[žÔ ªõìùwXoûаkù¸Ùrï2ßc­Çp´û("¾D àS¼z½à:à ÇGÕ lÃØXXÁeÄýðÖ„ÔþÞý8öùŽwGä‹H$¼IÀíw·qëÅ-\{| õhzÝôS]ÏŸ>}âýLÿ.ë÷‡é•û<ñSfÁêïïWƒ»ÙÂZ ÖXÐèã©­¸ø®æ‡Ëš89‰ŽŽÚ—›&L¶`hÈ?zi¢ä ššN£²2……÷Qtï:÷íÃ7[[âãë°Á­ ·«Ú&Ä©çϯ&W^~²‹³ÕàøÔ'©H|š¨&tŒz¥²|Éøéú%™¿d ‹óWg• LƱˆx‘ a2–ŵÏU¥1öïöGP{޼:¢Æ¿Ä4ÆàBí\©º¢2…e•d-™I"™iŒ1‚>¦±d ©Æ\È2c×3Ĕ홺?Ž¡Ñh —*8 Oµ‡þ/"Ñ©=èþ¼££›0¨=äÐèßåîŰ£>íBÉýÛê;2/Éz›~Œj“±Ø4ÿˆg8rä%NŸnBBB-ÒÒ*p÷n‰&^Ì{ì¹ù¹¸[rWeIÑ„SÂÓœk<‡“šÈ ®2€I–°]ïw©¬`’)Ìæ¿I"ÅäµL馉1ùŒ|ö &ÄŽ¼<¢¶!ÛJ¨MÀ•Ê+j²/ÙçBŸ#]¦± •|€×,FãE!44íííêuOOùCÖ©ÞÞÞ³RM·~r—©¹nÏÐz¶€°Æ‚~ —–塬ìjk/¢µõÞµùa8Ö p\¡¬´¸»;wv¢®îû- ßqêT“&@^!0°Cûܸ¸|QslÜ8›Alßþ»w÷àÀ·ˆˆx©&C¼té)®]{¬ •b³ •)ÅKA®j ‘Vi‘9X¤µDZM¤õ$¸=Xµ¦H«Š[ŸûÇçcÙô}“j…‘ÖOªuFZiµBÄËÕz#­8—ž^Ri“¥uGZyf;ë}`w  ’qŒ×&c}Lc È"QXX;;;%þþûo5þchhhÂgd®™æÝ˜iýTc6æ²=cÖsæí¦ÑÇKݪ®¦`ÀÅ_mÖ­›Öúµ‡õ>í¡]ºv‰XéÖä¥Û—dñª©9£ Œdddd!!¡QQÕ8tè||:´8÷ VVCšPù®Æš¸ºöaÏžµãèÑV-Ö7"1±7n¹ŠË5—a1f*íOþg+c}L[Š>æLèfà×_åL謵 écÚ–Ÿ›‹WGŽü+6¦B[þøñu5–D2pɼ%’B¸©é^¼8Ž—/ÃñæÍa¼ÕÒevøwï|ðáÃ|úä®Ò ËdŒ_¿Ú£³ÓÏžù£´ô23/ib% Ç—"0ðÜÝ;am= ‹8;ÄîÝm8xðNœx‚¸¸"¤¦æjß¹£ t”—§©laÝÔ¶u[ ÒÏ_„nTúé%صŠk*#˜d“ a2Y¤d “Ìa’AL2‰Í$ò¤ÕE„‹LFy\ó«¤R–.h"Zdûj²I^¯Œô1}LB–«¡Ñh´É6“1ç~d”ââl5ÇÉãÇ741‘ª²Iª{XMÍMT$!'' éé™HLÌÁ™3% «Ÿ_ \]ßÁÒr›7i¯»áïß„ÈÈRMÌÜFF† ¬?ªª0´´ø£§ÇKAÿŽ{Ñ€Œ‡ioR­62¤¤4–Aú ±Ú¾/¨c¨¬LUÇ$Ç&ÇX`æÁí3ùXæ`á"­&2ÖůË;4!·ýóvÕÂ"ƒôeœ‹t“ÖïÞªUFº–I71™ËEZZ.W_VÝÐd|Ël»ˆ-ëkxã=N£Q€P€°„54úx Q ŒnÞŒ‘-[0li‰akk ÙØ`pëV•U뛽=Ô|#ýNNøêìŒ/..ø¬Å¹Ï®®èssÃ'7çá^OO|ôòÂoo|عïwíBÏîÝj¾’w{÷¢Û×Ýþþè PY»:ÑqàÞ¡=8íâupš Þ/U>Q(óŽA¾ÛyëãâP§ßZí<×jçüé¥K¨Ó®¹ª´ëB&ʬԮ•'W¯¢B»nk×ÏcíZ’kJ®­ò[·Ôµ&ל\{%wïªkQ®I¹6å¥YXËë䤣BBÂZ ÖXÐÇ4ÖÏÊîÝ+Ráe@¼ Œ—ò2P^Ì»¹õ©ô2ÞÒrÎÎ_áíý }¨¨çj•ÔÔJܾ]ЇógåãG…×QYœŠêâ˨-I@}Éy4–œÁóÒ(¼(=Ž—ex]ж²ƒx[¶eþxW¾ïËwãc¹7zË=ÐWîŠ/å.è/wÄ·r{ •kâ¨Ì£e›ñ½t#ÆJ4qS´ß 4Q“§‰™–ÊÖ„L–-¾Ý²ÇÀMG|NsDOªÚSÑ’ìˆÆËöšX´Ç“K¶(½`‹B%±[‘³÷NÛàî)kÜ?®- w@áa”»âq *ý¼ñÔg'êvîF£×mp@ßz;|Y¿ýë­1°Î ƒë¶Ìèßö^hÝ´M[Pg}ÕvGPáteÛN¡Øã vÄ㟽—ð0𠾆œˆ›È9u ÎeáÁ¥lä^{€‡Y¹øç!c…SI³„„„F£ÑØ~¾k{óþAvv±J-,)†%Õ°¤ z«R»º~ÆÖ­ƒ*5±¤(–TÅ’²80°aa¯ý|Æd™WEÌ­[å¸yó‘ÚÏÕ«OpåJ%._®ÖöY£æ`±[³gqúô3œ:õ'O6ãøñ%œÂÃ_)atèзkeÏ[ìÛ× ?¿.ìÝû>>ï°kWvlïáåõàîþÛ·÷jÇÜGÇϰ³ûªý–5ÞfÓ¦alØðë×Cûm£Ø¼yVVš(û¢}ö“ö÷pu놻w;ˆ»ƒÑÚw"Ó‘z ¹ûS盈‚ÝQä‹R×3xì|Uöᨵ9„FËýhÙ¬ $‹èÞè†ÞõJè|_·Ãë6iâÇï7¸ c£^mÚæ-þ¨· BxeKÓØIDATm(ž8C¹KJÜÏ¢Ð;ù{·/¹¯"7ürNjÂ&æ6rî"÷ê}<ÌÌEÞƒ‡Œ4Ž!l¡Ñ¿ô1ýK›P1!“5Š`ÉÃÃ_âÀŽÞ$]±;»íÁ¾_{°ÿªæWqw—¹¦z±cÇG%||zàëûþþ]J܈À¡!‚C„‡L)BD‰>"–ÎkTÂEŒ—´ö$'W#%¥R <"|22Ê”’ß -C99…3¶êgy(,ÌQû%sYé£ȯN½†Xd¼8Ô×aHè8€3ïöâèG/ü¼¾ð²ÃèfXŒ­Çæ± pÝ„#[°Ø CÖ8;¸W4»=hƒ’!ËȰö™ŒóÛ7{ô÷Kf6g|þ¼M¥—–d’bZHšiIZ ©¦%q¤›noF[Û!•ÀàÕ«#hn8††ò“¨É‰Æ“tM¸\9‡²óšˆ9¥YD,J‚Ï¢Ôÿ ÊvGã‘çI\>ˆë¸½;9žûPä⇠û½¨µÙfK/MܸáÝF'|^¿UµÖH«´Þ|Ü`‹mx¹ÙC5;Qmëƒ2'_üã€ìû±7©q)4çNìÃÉXIöEðMø=Ø¥î3 {MÜ9õ;a›&ìÜ?¹«ÔÓ’ø@ÒPt¨”ÔÛªôÔá/Ãq¬å˜J¢ ÙßÎ5žS)¬jT:ë”Ê•láæ£›ê¼KV7Iy»ˆ)·¶V&  Ön²ö˜FÓ¿+À.^¬…ƒÃ0jjFU9P_? {û!ÄÅÕÓ?f—`1¶x¥üÛ©ýmÒþîVÝ]&¿!O¥©.Ô´¥µ¨¤$K¥„./OÇ£G7PQqM¥­®ªº¢Ý£—ñôi¢J_]¯=¸K:鯯•Zúùó(47Ÿ@KK$Z[#Ðúâ^ÔF ©, ¹á¨ÏŠ@mZ8j.…£úl8ªŽAUhªƒBQã‚§»¢Î# .h²÷CËÖ=xm¹]n3 ϶¶jŒNÏFtYlÇÛMîx½Ù ­Úw›­vá™êm÷¢FÛf¥So D©Û~yÀ?;‚³+Ù{ƒq; 7÷#-8É¡A¸tt?Ο Ä™MÅùãh¢/ÂS|q$Í¡7ýšå‹{~Éñá|ÍJüqèQBªöãp]B"ìEÂZBUÊj™`4Jó‘L6«ùM&Q+“¦jþ• IÓ5ŸKƹlí<ˆøÍËÏ[X²Z™(@(@h4¶‚Dˆ«ë5¨]ºZQ|˜Ï:päë‘ em´öÞNÿ,ÀÃqþ­LÜLGþÕë(¸r …—SQté Šâ“P›ˆâ˜”DÇ£äDJCé‘”>²àS(ß…GûN Â?{Ž¢rwªvAµ—&ŠÜCP몉"— Ô;îG£ý>4ÙùáùV_¼°öA«&n^oñFÛfOth¢§[’ltFïz{Õ $­?º– ±uëÕkY&I z7Øk‚ÉÚwÚ7¹áÕf¼°ôÆ3«¨·Þ…[Õº$-EÅÛü‘ÈñÞ{;÷ãí„[û‚‘~@Nâzè!\‹8Œ´ã¡H‹:‚«gÂq56WãŽâjB$Ò.ŸÀµ”S¸~õ4®_ÁÍôóHϼ€Ì;IȺw•„°„FÿÒÇô/>^v§äΌݛd=ý4wÏôp¼,|œ—‡üœägßCþí,dÜBÁõ›(HÕÓ•«(JÒDÓÅË(:¯‰¦s—Præ"J¢âQzüx¦ ›–;ðr‹'Þh‚çí&WtotÁ‡ ŽèÛj;£‹ŠîQ€Ž¡Ñ¿ô1ýK£é_fËã tvÁ¢Y âââ°víZe±±±l¡Ñ¿ô1ýK£éߟÆjkËè  …$++ îîîèëëSæéé©–q F£Ñh4mNÝܦ±…ìæF²ñ!µ+:äµ››[@hô/}LÿÒècú—>¦-ûV& %Èš5k0666þ^^Ë2Ž¡Ñ¿ô1ýK£é_ú˜¶Ü}L²YµjÕËV¯^=­ðЙ>;vìP&-'NNNêÿ…z¯³ÅÚÿJOÿÎÿ{oooúƒþ]Öï}||èúwY¿—8A¬Üç ÒB!„BÈJ„d˜j ˆ,#„B!„„˜]¬ÞÞ^£³`B!„BBfÌýaÊ< “ÑB£Ñh4F£-%£!fÅÔ‹ŠÐ¿ô1ýKècú—ÐÇô1aРécBÿÒÇ„þ¥éc B!„BÈÏ!„B!„„B!„BB!„B! ļ¬ZµjÜÈüPYY ///üúë¯øí·ß¦æŠ!æó¯Ì¹£óoHHÞ¿OÇÌâkÆ‹ù‹ÃŒÇóGkk+vìØ5kÖ`ݺuÈÎΦSæñþý÷ßé3ÒÕÕ…={ö¨ëWL^wttP€å<Èü A¢¢¢cccBtt´$Ä<ìÚµ ?Æèè¨òqZZœé˜y ''nnnŒŒ¿ËŽ×¯_ÃÂÂååå*NH%ÐÉ“'é˜y¢¸¸xVs¡‘é±³³CRR’*ëÄáàà@BXãÂoõêÕtÄ<"­!ļ `Ë–-ªÆñ‚ñw¹ÊÄÑÑ?~¤#ÌÈ/¿ü²,Ë: Âp‰ 5pl™?qwýúuÕêDÌËéÓ§•o/æ'þJw©˜°´´T5›Ä¼ˆ322ð¿ÿýO=´É< Ÿ?¦c橌‹ŒŒ¤#Ì̾}ûTlrN,!!A-£! Ä ÒÙÆÆFõå$濆Åþúë/´··Ó!f¤¥¥Û·og¼XÚÚÚàãヘ˜:ÃÌñ!<<###ª+lDD‚ƒƒé˜y`Û¶mªË1/===ظqãxY'¯—C+¡YdjjjTy˜#óƒÔ ¥¤¤LxX&sGü©/ê/æ—þþ~¬]»–Ž0#2hW„‡"ìªi~ª««—E­ürD(H ˆþåЛ‚„P€,"………X¿~=š››éŒ€cl̘©‰d9#ÙÛ& %ļH’ŠÆÆF:bʵåPÖQ€ E"==]¥|d“ôü }u©åÁM2¯¸»»Ó1ŒË ­ka’nìCofdºt»"&ݱ$e71µµµJ€ùA2^ɸý1 Ì‚E–õƒk5ÞÇô³ùÖ%IO(>ýã?8Ï Ȳ¾†ÿþûo5þC¿¶ž˜é²"1Bº^qº™‘V&I‰N橤ÐÍ)&&¯—ÃxG B!„B!„B!„„B!„B(@!„B! „B!„BB!„B¡!„B!„P€B!„B!„Êr™œ““ˆB!„ 4(@!„„B¡¡!„ B!Ë[|èÛäu………ؾ};~ýõW¬Y³;vì@GGÇŸ+((PŸ“Ïèo§¶¶^^^jùêÕ«áàà€¼¼¼ŽåÆê{¿üò ~ÿýwDFFâóçÏ>sïÞ=lܸQ‹¥¥%îܹóÃq÷ôô $$¿ýö›ÚŸlëСC¨««ã '„ B!KE„L·\DEww7ÆÆÆÆE‚££ãŸóôôTŸÓ§¦¦F -?~Äèè("""ÔçE<è“’’2.lDÌÈgä³:ÊÊÊÔ2%LÄäõäã—c“÷•••êýàà '‚GÒäê§Åq"ݰdüÇúõë‘‘‘1åv% ¯………jÍQ#ï'N¶¬~“.¥¯tÉâB¡!„B!„P€B!„B(@!„B!„„B!„BB!„B! „B!„ B!„B!„B!„P€B!„B(@!„B!„„B!„²4ÈÿûÿF£Ñh4F£ÑæÕ&B!„B™·– B!„B!„B!„„B!„B(@ùÉXµjkŽa©ú²8÷3c!KX€|üøAAAX»v-V¯^ www”””˜õψÉöÿýw£¹¹y^oJMEWWöìÙƒ5kÖ(“×Ón¯²²^^^øõ×_ñÛo¿!,, ½½½F¯ŸŠ¸¸8ås±ØØØi¦ßaìï5u{Byy9ìììÔo²°°À;wfÜžn›Ó­›nŸÆøÎX_ÍÆ×s úSíw¾ …ÙnßÐq/ÄoX©…1ã(ã(ãèÒ‹£Œy„,a"¥–ÁÁAŒ¡¡¡~~~f/8uÈ~222ð×_Íká9Ó±I””„ÑÑQe‰‰‰ppp˜v;R°VTT(ÿ !::Z{c×O&++Kù½¯¯O™§§§ZfÎ̹©ÆÆFüý÷ߨ®®Vïß¿“'Oš¼=c>gÈw†|eh_Æ~ßœ×Ør ‹U°­Ô˜q”q”qtéÅQÆ©å’AnòÙÖÜé×àÉͤãâÅ‹ªÆPnnÙOxxø„Ú¢øøxUhËz 4r³ ÜR0Hmü&±„„µÌX¤Y}¦š¹Éë'‡<„È~õ›,Óÿ¼ VÌåXçR@ÚÞd伈£àœì;C¾2´/c¿/H­avvöxŸbº÷÷îÝCTTÔ”ÙTÇ"…ˆ\«²¿«W¯ÂÙÙy|½Üor­Ká&&²ÌØÚ@cü*÷‡lW3Æ!!! ½Éû8}ú4’““ÇßK—__ß)÷=Ó½jÈ7s‰ºc~üø±*ˆåZ2U|lÛ-Þýûþùóß#BGGG6Ž2æÍ=沨Dj&¤Vjtê[šŠgªYÑ/ðf[pN®5\§«~á-«{rsIŸcsÔdImäÆÇk;äµÔÔCkk«z˜˜îX¦Z?ù8¦:®éjúÚÚÚTð1ô€j치j{¦nÇØ¾É¦œÆøn:_™â“é|-AüСCêµèuTr_Èzc Nýɵ‘r¯éÿFy-…´9ˆÜ/ú÷“ìc¦Âxr­Þä}ȶä>Ñ=„?~yyyÓî{ºûÃoæt5ò™¦¦&“ƒ®´|èć!žž`ee]bq”1oî1Óˆ±]­Lì’%µÒyûöíãˤÖNš_¥¶C õ›Þg[pʾ&ÀRpël6û16˜îرCÕ^é÷]ž©&NGMMj>ž®ØÐúÙÔ& R›#]uÌUSfh{‹Qs7ï²æNÖI#ׄøG÷¿n¹n;³ׂSjÉ'×Ôé·€Há£_ÐÉCæ|·€óäüHW#\1«{Õоæt}Í¥@–sh*siaee]Ø8ʘ7÷˜GÈ¢  ’ú}“EIëg2‘Q’]C ]šVõo À†šÝÉÞ"}-%8I³¾ ƒØôûHëúAÊ1̵ï²ü>ùú}—gÊÞ’žž®‚Äëׯgµ~òqè2ŠÈo™*£ˆünÝ >ñ‡œ#éÞaèwM·ÜÐö&#ÁV’kkkÕûùÌÞbÈw†|eh_Æ~_ÿN®y]0—ÿåZ•kvª}Muý*pôû*‹¸ÂY¿+‡£££Ú¯\›rÜR gê=§Û‡l_·S ãéö!¾Üµk—ªiŽ™îUC¾™KÐmGÖI„j sÂ8Ê8Ê8º°q”1oî1óYfÁ’AKrƒI­«4©ÊM«_‹ ë%¹¬—Ú tú7OZZÚx³áLTg”äjªæu¹¥‰Vö%)'÷·”‡4 †²·êW+7¸.gº˜¼Ö,Ænor03´~2’õbºœêR“%¿_¾'µò»gÊ’dè÷ÚÞt×…|GÎ…œÊÊÊÔ=jˆéîUc®“ÙÆýíH,ß54Px*"-!›6ýÛòal,ÆQÆQÆÑ…£Œyæ‰y„ÌM€BÈ 5›2¾Bó¡!„yEj{mmmgÌîD!Œy„P€BÈœÑu³á$W„Æ÷·zõjüþûïFssó¼9±²²^^^j2¡ß~û aaaèííò÷›ê/cý)¿ÓÿÏe{úxzzθ=c)//‡ò¡……îܹcðú™Íµeè\ qqqX»v­²ØØX“ÛLߟk°Ÿj¿ó]Ìvû†Ž{!~ÃJ,„OOO—vWRØé nA^ËC±û2öû‚¥¥%ÚÛÛÕkñ·lSW{(~ÿêïkºIy-…òúõëÕoqpp@KKËøzy0ˆŒŒ¯E”ײ̘ûÏØö‘‘„††ª{INSRR¦­”×r?ýïÿÃ/¿üòÃ>äÚúóÏ?Ñßß?á<É2y™ŠéîUC¾™KÐÿMò0.}gLç©fë4«`¡FǘíIÍÜDÆn3>>>>>j½¹Eš¿ªÆNö%”3}O×@‚éÄÄÄ9mO8}ú4®_¿>ãqû{弈£Àœ|®Ö¬Y£¾~ð—eÆîËØï«û(:ÙÙÙã5}RxéÞß»wQQQS`S‹r­Êþ®^½ ggçñõ111êZ—BMLe™±÷Ÿ1~•ûC¶«¿™ á …Ýä}Èõ•œœ<þ^ºzøúúN¹ï™îUC¾™KÐóãÇU,×ÒìćÉÿW0ž2ž2ž.áxÊØg®ØG(@L Òê±Iû«ÒþäS[AfS`®[·ÝÝÝ ?C}t§B¿fÆÐ6å¦êêê2Ù¡­­­°±±™ò»óQ`nÛ¶ ¯_¿6ú{mmm*¨è?€šº=©EÙ¾}»Áý™« 3¶O²©þê\Mµ Sj_ý¾.x:tH½–‚@¼Ô^ RpÈzc LýɵRÛ¦ÿåµÎæ r¿èßO²™ áɵy“÷!ÛÚ¸qãøÃÇñãÇ‘——7í¾§»W ùf.q@WÃ(Ÿijjšƒø¨˜æ=ã)ã)ãéR‹§Œ}æˆ}„ ë¦ø;¤ýéZ>äõºiþÌY`Êki"Ô™¼—æKSö!5ú5v†¶9›ÚŸššÕÌ;]s­¹ LiŽÖXSZéŠ3ÛíIa©kê^®5vÓ«…¬±“uRÐH퓜ÝÿºåºíÌfФ¡ïèDæ ¦lÃØß  º‚WΕ¾_=ïs-†¶-5à F^u린s“>0ÍçOOO—B¤¢~a`h›¦Öت¾–3 Ì4w)}aeÀ¡¹ Lc·gî4i²^È>Ë3«©úË2c÷eì÷uHMt½Ð5±Ë{©YÒorŸk)- “kèô[@ ÝóÑbÌoó£»&#""fu¯Ó0Û8 ëc.±®ûŒiÌO ã)ã)ãéüÅSÆ>sÄ>BL ÑÿýZfjP“AzrK¡)µ¨ýÏIH ===ê½ÔÉ /cö1]ÖCÛÔõ”ã1Ôg9==]ÝÌ“›Úç³À¬­­v0ÞäïÉïÒÕ°Éï•jr¿dS¶gìzS²¶ÈC²ƒ0ŸY[ +]Ö9ïsÉÚbèûúr2PÄå¹Våšj_ò 3y@«¡‚F¿²<ŒJ¡¬ßeÄÐý7Õ>'£Û‡l_·S áéö!¾Üµk—ªaŽ™îUC¾™KÐmGÖI×|:{b¾1 Œ§Œ§Œ§óOûÌûˆ‘¤Wû[7߬ŸmP“f[ÉÐ 5wR“"Ábòçäf‘fTùŒä7Ÿ®Oää% FROÕŒoh›ò&ÁÁPÖC5X¦æë7æóˆu}Z ùXj¨ä÷Ér©Õߥß7ÔÔíZ?›ù tyëå\HÞz485„ÆlK2ƒ“·~ºã˜éû“‘š3ÙÆ«W¯Ô{ù_Þëרéï#--m¼¹ÜØ‚Fε<€èšÚ¥O±~ C÷ßTûœŒlO1J×.¹ç e‚™Ìtû(++S÷¨!¦»W¹Nfô·#±|w¦É3‹óeÁbm\€B!„BÈBðÿ_¢Ì9{.;°IEND®B`‚Multiverse-multiverse-0.7.0/charts/contended_counter_update_bar.png000066400000000000000000001375241174000617100257450ustar00rootroot00000000000000‰PNG  IHDR ôÅ@Ix€IDATxÚ콫MMÿÿýi'yG$"¢È‰H—ˆ$"ÑED$."‰ˆÄ‡\å.‘Žˆ[âMä&rr™ïû15ç;{]k~­½÷9χVö^³gÖ̬™5¯ç¼fÖùÃüüñ‡B!„Bˆná4Ç B!„B !„B!„ˆBŒ}}}¿ÜuÅ2ýLyè¥|!„ˆÇÿþïÿF:>|ø`6nÜhÆoÆŽk–.]jnܸÑÑßpþĉͦM›Ì“'Oº:H¹£Ž7oÞ˜Õ«W›qãÆÙƒÏ¯_¿¦w÷î]³|ùró?ÿó?f„ fëÖ­fhh(;¼ŽƒÚ:ç8pà@0ÿ±rä–·4=¸uë–™?¾-Ó¬Y³ÌÅ‹£é¹4Ca¡kæÔ]n]5©kíÝ/KNû-!Õ6¶û“ª«N\wÙ²eÙét+ê#Bñ‹ 6D:h_¾|1?~ü0>4k×®í¸qpsçΙ)S¦tU„Äò†ñrìØ1óýûw{=zÔ,X° ˜åÎ;¶~¾~ýjöìÙcæÜð*.\°õþñãG{`p®ÝA6&@Jxôè‘™6mš´ßß¿ovíÚUœ^ÎïRu—ª«Ôµrã˸½²”ü¶Sm³WïO7Œÿ¿ÿþÛ,Y²DD!Dï¼1Þ½{gÖ¯_o=üvÕªUÃ3Ô¹³êuaçÏŸ7ëÖ­k9Çìô¤I“ìÌ&^’ÏŸ?·„ïß¿ßzP˜)?sæLãÁj̘1ÿ8Ç5sÁXŽÕ[*ƒØPÀg „^ Üï+W®´m4)GµîRu•ºVnüœv†@Ú±cǰ7…ÏœË5ÜøŒø™1c†-#¢÷éӧɾëü–µ´ Î! sÚf¬ŒíüezkÖ¬Én›±2¶óœqù¼}û¶´Õxó.]ºd?c¼cD»ï—/_6»wï®­ŸÒ2Å .OŸ>Ýv¿Íi»ÕûšªëÔØ’jWˆR¼§€pñÓBÑã„73Ì\¹Y*–5„`°ð…CSþL÷ôéÓ[D£ÙÁ€ÏÞB×eæ37ËÇgf(sxöì™8Cy© ¯æ£._!ÉË—/­A”2tsïE]z¥éäîñ( 9uª«’:‰y§bíŒ>â‡ñ£²D€ø…ª·§.~ª_/·?Ä®Ÿ*_¬Îü</&@ªù­–›´è“N8îܹÓ\½z5»mÆÊØÎsÆyøÍãÇ“õ‚PÙ¼y³ýŒ!ŽAí&:xΞ+@be ‡bñâÅ™8Èi»ÕûšªëÔØ’jWxcðºÄÆ+!„=*@|˜½b?ˆ?h1CÅ2f¡é»Ø› ®U2 w4¹N®QºbÅ ëð÷€Ä<Ž{÷îÙå ¡å©pGé¬<³,‰iZÞÒôF껑ö€”.%L ˆ’ Æ¡ðNõ‹&×Ï1tKÒͪèNtÐ.Ü=lÒ6«×oZŸ„áAÄcšyFHñŒ¡¿¹ÿÝyW¦&õ“sßyŽ»%` n»MÆÿÏ Æ5D ÷%å‘BÑ£¤Îè`‹·b1xÿ—¼á&ôÖNûËž¸NìÍQô€ÔU)CëÚµkvÆ-´q>îS·/s½"@Xê0’{@bu—[W%{@buò€Tgd}Æ“/vÙí T¿è¤I•/Vg%œ|ÑXʦóíÛ··Õ6ýsíž¹m So¥ÊÓ$u᩺N-©vEZN,ÒFHO!Ä(6ýÅŽ:p[3Ð3{‹+œ‡¼?ëD8ïÚ'œYj F8uêÔ°{=g&ŽAìn™K¸¯ÊuK0C Ž©·`¥fýÝßžà೿T¡t&1'¼ o‡ ým <”ŸxÌRîØÛ–RåM¥jÄá^pÿÙ4›[Þƒ''­X]åä#¿ŽP;£Î0v]»ao‚¿ˆ6u}#³D€„úR¬_tR€¤Ê‚ß°Á/"ý;õ¬*¡rß¼yÓ–»´m¦ÊÝô9㧃ÁLÜÔ x–ïùóçö;ÿóÝƦÚÀH &y¥«ëÔØ’jW¤5wî\ÎÛ°´K!FI€!įÞö¤ !„BD!º Þfµõ†#!„BDÑÃøoò^M7v­Øùûê¼›×Í< !„B!„B !„B!„ˆB!„BD!„B!$@„B!„ B!„B!"„B!„Bcúúú”‡ˇB1ªdèêÕèQLJÌÆÍøñãÍØ±cÍÒ¥KÍ7::óÒŸ8q¢Ù´i“yòäIW wÔñæÍ³zõj3nÜ8{ðùõë×ÁôîÞ½k–/_nÿPׄ ÌÖ­[ÍÐÐPvx´uÎqàÀ`þcåÈ-oizpëÖ-3þ|[¦Y³f™‹/FÓsi†ÂB×Ì©»ÜºjR×2îÃy¨ËOÓ<6iƒÎƒˆBÑò¯ÿû;ê@p` }ùòÅüøñÃ<|øÐ¬]»¶ãÄÁuÎ;g¦L™ÒUˆõ±cÇÌ÷ïßíqôèQ³`Á‚`:”;wîØúùúõ«Ù³g5šsë\¸pÁÖûÇí±lÙ2{®F^' ¥G™iÓ¦™ÁÁAûýýû÷f×®]Åéåü.Uw©ºJ]+7¾ ÚîÿŒ'"„Büä¯DŒwïÞ™õë×[O¿]µjÕð uîŒf]ØùóçͺuëZÎ1;=iÒ$;Ž—äóçÏ-áû÷ï·fÊÏœ9ÓØ@3fÌ?ÎqÍ\0–cõ– Ç vÆ=ðyÉ’%=#@¸ßW®\iÛðjRŽjÝ¥ê*u­Üø9í ´cÇŽao Ÿ9—k,óñ3cÆ [FDïÓ§O“})Ö/ø-yœ:ujm»vÌ™3ǼzõÊ~ÆëI<×ñþÍž=»%¿¡üÄÊÐé¶Ð4¡:‰Õcì9ß¾}36.“''NœhÉÃyóæÙð™3g¶x …B cûöí3oß¾­ ïïï7<°†!ÞŒ3ââî7xB0ð‡¶žf©¹Î¶mÛZfÝ:dÂ1ÈGS£C¯eâ8räˆ=— ÆFÌÃQ ¯æ#‡ëúF7çüßcca8’×v„F*½*Üêx4HµîRu•ºVnüœvF?¡~úôÉhΕ _Ò&'Ož4‹-ŠÆOõ âlÙ²åb½ ž¥K—.ÙÏïÑîûåË—ÍîÝ»kó[WžXbm¡¤ ¶“‡º:IÕcê9Çwî·ïý¼Mž<Ùzòáâ§-„BH€T`°d&—ÙB73È’› оph*@ÀŸéž>}z‹B `°8XÄÞB×e¶“YJ7³Êgf…sxöì™5VBy© ¯æ£._!ÉË—/­Aœ2tsïE]z¥éäîñ( 9uª«’:‰y§bíŒ>â‡ñC¾D€ø“ª·§.~ª_£:ÅíÛ·ÍæÍ›íg q j'ºéó„ç XrÈiƒíä¡®NRõ˜zÎÑ.üøÜ{?oxcðºÄžB!„H ̲dñâÅÃç˜d ³ÆÎÐô—54 \«*d@îhr\£tÅŠvÖßóh8îÝ»g—ª„–œ¤Â¥³ò̸²ä§iyKÓ H¨îFÚRº”0% J6u‡Â;Ñ/(7B›öνwÿ»ó®ŽšlBoÒ7ÛiÓݨÇ&Ï9ÿívÆ VÔàáÁ“'„BH€¼²·ê™à­X,Àÿ©Á>Ç``ˆ¿ì‰ëÄÞÕIHÝŒmj÷Úµkv–3´q>îS·/s½"@X^2’{@bu—[W%{@buò€TgÁ}«/vÙí T¿(1þñ|œ>}Ú¬Y³fø;˱Ü÷_Y€¤ê1õœKy@ªbš¶"„BH€Ʀ¿ö™ýþ¡Ø´é¯mf‡?ðbD¤–/å¼ëøñãÖby°aÖ_ƒíÖæ“‡v÷€P>ÊéëìÙ³Ö@yñâE£ðj>Ü›™(KÝ›™(·Û0L}pX&—*Wè|*½*¼ êþýûö{7ß‚•ª»T]¥®•?§ùûðþ2¢… ZŸ6E|–6•ôu})Õ/JŒD?ý™<ÿÓé¹ùi*@JÛ`;y¨ OÕcê9çî=÷ÝÝ{?œ´œpE€žBñ[ÁÿcG,À@cö–å ¬þLáü™¥Æ`ôÞS§N /iˆ¢î``Æ0«[¦„‘Àr®Å«r¯Vþv ÆIê-X©ý îoOpðÙG¹éU žTxÞÈúÛx(?ñ˜y¥Ü±·-¥Ê›J/Ô.ˆÃ½àþ³Q9·¼%†iNZ±ºÊÉG,~¡vF!Ä\»Ù¹sgËR5Ú4BÖõ ûêK±~Q"@è×üþùóçö;ÿóÝïï©ü4½ÏMÚ`Ó<„ò«ÇÔsŽûÌÆu<¥<êoÁ"­¹sçÚpÞ†¥%XB!~"„B!„ B!„B !į…ÿ¦'ÿèåkfž…B!"„B!„B!„BH€H€!„B!$@„B!„ B!„B!"„B!„B!„BH€H€!z™¾¾¾_b™~¦<ôR>„BÄãêÕ¡èQLJÌÆÍøñãÍØ±cÍÒ¥KÍ7:: ðÒŸ8q¢Ù´i“yòäIW)wÔñæÍ³zõj3nÜ8{ðùõë×ÁôîÞ½k–/_nÿ8Ú„ ÌÖ­[ÍÐÐPvx´uÎqàÀ`þcåÈ-oizpëÖ-3þ|[¦Y³f™‹/FÓsi†ÂB×Ì©»ÜºjR×2Ú»_–œö[Bªmþl÷'UWM¯Û¤ßw:ê#Bñ?þøWô¨ÁöåËóãÇóðáC³víÚŽ ×9w2eJWEH,o/ÇŽ3ß¿·ÇÑ£GÍ‚ ‚é PîܹcëçëׯfÏž=ÖhÎ ¯ráÂ[ï?~´Ç²eËì¹N´=zd¦M›fí÷÷ïß›]»v§—ó»TÝ¥ê*u­Üø2®F¯,%¿íTÛìÕûÓi2ÚyPB ÚñJÄx÷îY¿~½õðÛU«V ÏPçήՅ?Þ¬[·®å³Ó“&M²3›xI>þܾÿ~ëAa¦üÌ™3«1cÆüã×Ìc9Vo©p bg@Ÿ—,YÒ3„û}åÊ•¶€&å¨Ö]ª®R×ÊŸÓÎH;vìö¦ð™s¹†Ÿ?3f̰eDô>}ú4Ù—bý‚ß’Ç©S§Ö¶ëj^B×Ï)_ˆoß¾™›?&Nœ8œÕ¯æ·ZnÊ6yòdóéÓ§–6Á9dNÛŒ•±çŒ_&OB<ÇBÌ™3ǼzõÊ~ÆÓL|÷ìÄã:{öì–tCm §LêMój‡±ºŽ-9í OؼyóløÌ™3[|Øz^02¸Î¶mÛZf6:d(˜ÈGÓ˜A¯eâ8räˆ=— _ÌÃQ ¯æƒ—ëúçüßc1(cÄ×v„F*½*Üêx4HµîRu•ºVnüœvF?¡bs  9W"@0ÂH›|œcT–ߣPõöÔÅOõ â`àåö‡ØõSå‹Õ™ŸGâÅH5¿Õr“}Ò Ç;wš«W¯f·ÍXÛyÎ8/¿yüøq²^*›7o¶Ÿ1Ä1¨ÝDÏYÂsH¬L9äôûvòPw_Su[Rí o ^—Øx%„¢Gˆ³WìY¼xñð9f¨XÆÂ¬±34}{SµªBäŽ&×É5JW¬Xagý= 1†ãÞ½{vÙDhùC*ÜQ:+ÏìKbš–·4½Ñð€„ên¤= ¥K S¢dƒq(¼Sý¢Éõs Ý’ts…*º´ w›´Íêõ›Ö'axð˜æ@žR³ø%Æe]_Jõ‹N TùB¸xÄqñJHèÂ}[¹r¥5.Ûi›þ¹vž3.ÂX*ȦèL´ð u‚…ÿyöñ ÌmMHi¿o'u᩺N-©vEZN,ÒFHO!Ä(¾¾ÁèQnkzfoq…ó÷gç]û„3KÁè§Nv¯Ç w0H`˜Õ-SbÀbi×âU¹n †cˆÁ1õ¬ÔþB÷·'8øìêÜôªƒo*¼ o‡ ým <”ŸxÌRîØÛ–RåM¥jÄá^pÿÙ4›[Þ#)'­X]åä#¿ŽP;£Î0v]»ao‚¿ˆ6u}#³D€„úR¬_tR€¤Ê‚ß°Á/"ý;õ¬*¡rß¼yÓ–»´m¦ÊÝô9㧃ÁLÜÔÆnž¥Ä{þü¹ýÎÿ|÷Ÿ±©6дo5é÷MóÊO¬®ScKª]‘Öܹsm8oÃÒ,!„%"„¿ xØ“&„B !„è*ÌÔ3«­7 !„ BˆÆëôjº±kÅþÈßïPçݼöhæY!„ˆB!„BH€!„B!$@„B!„ B!„B!"„B!„B!„B !„B!„ˆBÓ××§<ôX>„BˆQ ýç¯èQLJÌÆÍøñãÍØ±cÍÒ¥KÍ7::óÒŸ8q¢Ù´i“yòäIW wÔñæÍ³zõj3nÜ8{ðùõë×ÁôîÞ½k–/_nÿPׄ ÌÖ­[ÍÐÐPvx´uÎqàÀ`þcåÈ-oizpëÖ-3þ|[¦Y³f™‹/FÓsi†ÂB×Ì©»ÜºjR×2îÃy¨ËO;y|öì™Y±b…ísÓ§O7—.]jT' B!D ?þõGô¨ÁöåËóãÇóðáC³víÚŽ ×9w2eJWEH,oÖÇŽ3ß¿·ÇÑ£GÍ‚ ‚é PîܹcëçëׯfÏž=ÖhÎ ¯ráÂ[ï?~´Ç²eËì¹v ›˜)áÑ£GfÚ´ifppÐ~ÿþ½ÙµkWqz9¿KÕ]ª®R×Ê/ƒ¶»Æÿ‹/¬EØr¯™~›’B!~#‚W"Æ»wïÌúõëí¬%¿]µjÕð uî¬z]ØùóçͺuëZÎ1;=iÒ$;Ž—äóçÏ-áû÷ï·fÊÏœ9ÓØ@3fÌ?ÎqÍ\0 bõ– Ç vÆ=ðyÉ’%=#@¸ßW®\iÛðjRŽjÝ¥ê*u­Üø9í ´cÇŽao Ÿ9—k,óñ3cÆ [FDïÓ§O“})Ö/ø-yœ:ujm»vÌ™3ǼzõÊ~ÆëI<×ñþÍž=»%¿¡üÄÊc`` ËãQ­»&yÕI¬cÏ9øöí›-q™<9qâDKžVóæÍ³á3gÎlñ !„ 0ÆöíÛgÞ¾}[Þßßol=/ÌRsmÛ¶µÌ:tÈ„c ¦0†^ÊÄqäÈ{.Œ˜‡£^ÍF×õnÎù¿ÇÆÂp$¯íTzU¸/ÔñhjÝ¥ê*u­Üø9íŒ~Býôé“=М+ ¾¤M>NžÜ›™(KÝ›™(·Û0L}pX&—*Wè|*½*¼ êþýûö{7ß‚•ª»T]¥®•?§ùûðþR¶… Zß½å‰%F%}]_Jõ‹‚è§?“Gàú!ý17?MûMXv…á`9û4R4ÉC]xªSÏ9wï¹ïîÞûá¤å„+„ô„BˆßB€ôÿ»?zÔÁR 4fo™‘d`õgúçõ™„3KÁè¼§N^Ò3DÝÁÀŒaV·L #å \‹Wå^½zµ%cƒ$õ¬ÔþŒ÷·'8øì ôÜôªO*¼ oä ým <”Ÿx̼RîØÛ–RåM¥jÄá^pÿÙ¨œ[ÞÃ4'­X]åä#¿ŽP;£Îb®Ýìܹ³e©m!ëú †}‰ õ¥X¿( ôk~ÿüùsûÿùî÷÷T~ÚÙëÃRG÷*þöPÎ&ô&yå'V©ç÷Ñ„§”2Tß‚EZsçεἠKK°„Bü6D!„B!$@„B!„ Bˆ_ ÿMOþÑË×Í< !„BD!„B!"„B!„‘B!„BH€!„B!$@„B!„BD!„B!"„B!„‘Bô2}}}¿ÜuÅ2ýLyè¥|!„ˆÇþóWô¨ãÇfãÆfüøñfìØ±féÒ¥æÆø éOœ8ÑlÚ´É}º¹téR£rJ€!„HP€üë_D:h_¾|1?~ü0>4k×®í¸qpsçΙ)S¦tU„Äò†ñrìØ1óýûw{=zÔ,X° ˜åÎ;¶~¾~ýjöìÙcæÜð*.\°õþñãG{,[¶Ìžkw =zd¦M›fí÷÷ïß›]»v§—ó»TÝ¥ê*u­Üø2®F¯,%¿íTÛìÕûÓIãÿÅ‹V !Øè_{¿®$@„BŒšÁ+ãÝ»wfýúõvß®Zµjx†:wV½.ìüùófݺu-瘞4i’ÙÄKòùóç–ðýû÷[ 3ågΜiµ´ Î! sÚf¬Œíp¹®o`qÎÿ=ƒ2F ymGh¤Ò«Â}¡ŽGC€Të.UW©kåÆÏigôÚ(Æ1šs%#Œ´ÉÇÉ“'Í¢E‹¢ñSý‚8[¶lù‡º±ë§ÊlüÖ ÕüV˽wï^süøñáï,Ó[³fMvÛŒ•±çŒËçíÛ·­ø ­ÆÀ›çÆ;F´û~ùòe³{÷îÚú)-Sú<ÞfDFú† ÌÿûßFý6§íVïkª®ScKª]!JñžB®wG!DÜÌtºAŠA†e !,|áÐT€€?ÓÍúd_!P@ øìÝ(Í«ƒ™7fÌÜ,Ÿ™¡Ì5Õ œ¡¼Ô…WóQ—¯ÇäåË—Ö Jº¹÷¢.½Òtr÷x” œº ÕUIļS±vFñÃøŒQY"@|BÕÛS?Õ/ˆƒ—Ûb×O•/Vg~‰ ÕüVËMZôI'wîÜi®^½šÝ6celç9ã¼üæñãÇÉzA¨lÞ¼Ù~ÆÇ v ÈÇ4òŒâCsÿ»ó®LMê'ç¾ÓÎ}Ñ@½å,5m’‡&m·ÉØâŸãYWQÃ}Iy¤„Bô¨©3:˜Åâ­X žÀÿ%o¸ ý†µÓþ²'®{sT'= uFUÊкvíšq mœO…ûÔíKà\¯–:ŒäXÝåÖUÉX]§< ÕYßC€ñä‹Dv»$Õ/:)@Rå‹ÕY‰$'_´–‡²éœ™ûvÚ¦®çŒÛñ{úôé¬:ÇóÁoÝ2¾ãEqß»)@xáBU€ÄÄw§Hª®ScKª]U'0h¿B!~€î¯ÃevÏ#ýu¶,)ð ÙÔò¥œ·`±æ›A™åQÀæM=°[›MÚÝBù(§¿$ö¬³gÏÚÁ’·Ê4 ¯æÃ½™‰²Ô½™‰r»Í«Ô÷ˆer©r…Χҫ‚ÑÇ`~ÿþ}û½›oÁJÕ]ª®R×ÊŸÓÎü5éˆ ŒI)ÛÂ… ­±éÞ8Ä,~‰qY×—Rý¢“$U¾.q\¼z†pßV®\iËvÚ¦®çŒK‡0– ²):-|07n4ãÇ7cÇŽ5K—.57nÜèè Ìo8HâĉfÓ¦MæÉ“']5 ÜQÇ›7oÌêի͸qãìÁçׯ_Ó»{÷®Y¾|¹ýC]&L0[·n5CCCÙáuǬ ËX˜5v†¦¿¬¡©áZU!ƒrG“ëä¥+V¬°^HÌ£á¸wïž]ªZr’ w”ÎÊ3ãÊ’Ÿ¦å-Mo4< ¡ºiHéR”€(ÙÔ ïD¿ ÜmÚ;÷Þýïλ:j² ½ä>³®ÄÛØ$Mê±ÉsÎ?G»Ý°aƒ5xñò!„ ¤Î¨bæ·ba°ÿ§ûƒ= ¾!ÂuboŽê¤¤nÆ65‹{íÚ5;ËÚ8Ÿ ÷©Û—À¹^ ,/É= ±ºË­«’= ±ºNy@ª³à¾ƒÕ;ˆìvHª_”ÿx>NŸ>mÖ¬Y3üåXîûH–|ò’ƒ‘ ©zL=çRª˜¦­!„ ‚±é¯}f?„ÿF(6múk›YÆá¼²9›I¡·`?~ÜB,6Ìúk°ÝÚ|òÐîÊG9ý= ±·`={Ö(¡e#©ðj>Ü›™(KÝ›™(·Û0L}pü5ó¥K°RéUÁ@Ä€ºÿ¾ýÞÍ·`¥ê.UW©kåÆÏigþ>ļ¿”Õø´)â³´©Ä ¯ëK©~Qbü#úéÏäøŸ~HÌÍO;„ö”z@•&y¨ OÕcê9çî=÷ÝÝ{?œ´œpE€žBñ[÷ÿ;zÔÁR 4foY~ÀÀêÏôÎß œYj Fà=uêÔ𒆘!êf ³ºeJ ,áZ¼*÷êÕ«-á{$©·`¥ö'`|¸¿=ÁÁgg ç¦W5xRáUx#OèoSà üÄcæ•rÇÞ¶”*o*½P» ÷‚ûÏFåÜò–¦9iÅê*'±øu„Úu†sífçÎ-KÕhÓY×W0ìKH¨/ÅúE‰¡_óûçÏŸÛïüÏw¿¿§òÓŽAü¹½&¹4ÉC(?±zL=ç¸Ïl\ÇSÊ3¬ú,Òš;w® çmXZ‚%„â· B!„B!"„B!„BüZøozò^¾öhæY!„ B!„B !„B!„ˆˆB!„BD!„B!"„B!„ B!„B !„B!„ˆˆ¢—éëëûå®û+–égÊC/åC!$@<þúÏ¢G>|07n4ãÇ7cÇŽ5K—.57nÜèè€Ào8HâĉfÓ¦MæÉ“']¤ÜQÇ›7oÌêի͸qãìÁçׯ_Ó»{÷®Y¾|¹ýãh&L0[·n5CCCÙáuMö¥X¿à·äqêÔ©µíºš—ÐõsÊâÛ·of``À扅'Ngõ«ù­–›²Mž<Ù|úô©¥Mp™Ó6celç9㗃ɄϱsæÌ1¯^½²Ÿñ4ß=;ñ¸Îž=»%ÝPÈ)S .´ùHµ‘&yµÃX]ÇÆ–œv…'lÞ¼y6|æÌ™-ž0!„=.@0ÆöíÛgÞ¾}[Þßßol=/\gÛ¶m-3›‡²á L䣩Ì ‡×ƒ2q9rĞ˅/æá¨†WóÁ€Ëu}‹sþï1€”1bÈk;B#•^î u<¤Zw©ºJ]+7~N;£ŸÐF1Ž9М+ a¤M>Nžoß¾mÅm5Þ¼K—.ÙÏïÑîûåË—ÍîÝ»kë§´L¹ý AÙ´ßæ´Ýê}MÕujlIµ+D)ÞS@¸øi !„èqƒ›‰™+7KŲ† ¾ph*@ÀŸéž>}z‹B øë•ðÙ»QBèºÌ¼1cæfùøœšt<{öÌœ¡¼Ô…WóQ—¯ÇäåË—Ö Jº¹÷¢.½Òtr÷x” œº ÕUIļS±vFñÃøŒQY"@|BÕÛS?Õ/ˆƒ—Ûb×O•/Vg~‰ ÕüVËMZôI'wîÜi®^½šÝ6celç9ã¼üæñãÇÉzA¨lÞ¼Ù~ÆÇ váÌRc0úƒÀ©S§†Ýë1ÃÇ fuË”°XšÀµxU®[‚áÀbpL½+µ?Ðýí >;=7½êà› ¯ÂÛaB›å'³€”;ö¶¥TySé…Úq¸Ü6Íæ–·ÄHÊI+VW9ùˆÅ¯#ÔΨ3Œ]×nØ›à/¢M#d]_ÁÈ, ¡¾ë ©ò…à7l0Æ‹HÿN½«J¨Ü7oÞ´å.m›©r7}Îøé`07õBž¥Ä{þü¹ýÎÿ|÷Ÿ±©6ÐŽAp»½&¹4ÉC(?±ºN-©vEZsçεἠKK°„b”ˆBü*à=`OšB!$@„¢«àaV[o8B!$@„=ŒÿÖ!ÿèÕtc׊ý‘¿ß¡Î»yíÑ̳B !„B!„B!„BH€!„B!$@„B!„BD!„B!"„B!„ B!„B !„0¦¯¯Oyè±|!„£*@þúë¯èQLJÌÆÍøñãÍØ±cÍÒ¥KÍ7::óÒŸ8q¢Ù´i“yòäIW wÔñæÍ³zõj3nÜ8{ðùõë×ÁôîÞ½k–/_nÿPׄ ÌÖ­[ÍÐÐPvx´uÎqàÀ`þcåÈ-oizpëÖ-3þ|[¦Y³f™‹/FÓsi†ÂB×Ì©»ÜºjR×2îÃy¨ËOÓ<–ö¹näAD!„肉¡ÁÁöåËóãÇóðáC³víÚŽ ×9w2eJWEH,oÖÇŽ3ß¿·ÇÑ£GÍ‚ ‚é`,ݹsÇÖÏׯ_Íž={¬Ñœ^åÂ… ¶Þ?~üheË–Ùsí61R£GÌ´iÓÌàà ýþþý{³k×®âôr~—ª»T]¥®•_mwÿÒ>'"„Bü¯DŒwïÞ™õë×ÛYK~»jÕªáêÜYõº°óçÏ›uëÖµœcvzÒ¤Iv6/ÉçÏŸ[Â÷ïßo=(Ì”Ÿ9s¦±0f̘œãš¹`,Çê-ŽAìŒ{àó’%KzF€p¿¯\¹Ò¶áÕ¤ÕºKÕUêZ¹ñsÚiÇŽÃÞ>s.×Xæ3âgÆŒ¶ŒàOŸ>Mö¥X¿à·äqêÔ©µíÚ1gÎóêÕ+û¯'ñ\?Æ1{öì–ü†ò+CŒ&}®iBu«ÇØs¾}ûfl\&ONœ8Ñ’'<†óæÍ³á3gÎlñ !„ 0ÆöíÛgÞ¾}[Þßßo|Øz^˜¥æ:Û¶mk™u?tè5 Ç M ` f`)Ç‘#Gì¹\06bŽjx59\×7º9çÿCѼ¶#4RéUá¾PÇ£!@ªu—ª«Ôµrãç´3ú môÓ§Oö@@s®D€`ø’6ù8yò¤Y´hQ4~ª_gË–-ÿëUð,]ºtÉ~ÆxLjvß/_¾lvïÞ]›ßºòÄʵMú\“<ÔÕIªSÏ9¾s¿ý{ïçmòäÉÖ“?m!„B¤ƒ%3¹Ìº™A–Ü„`€ö…CSþL÷ôéÓ[D£ÙÁ’ Ö‘—º.³ÌRºzá3³Â9<{öÌ+¡¼Ô…WóQ—¯ÇäåË—Ö Nº¹÷¢.½ÒtrÛW©É©»P]•ÔIÌ;kgô?ŒÏò%Ä÷˜T½=uñSý‚8Õ)nß¾m6oÞl?cˆcP;@Ÿ'Ç``ˆ¿ƒëÄÞÕIHÝŒmj÷Úµkv–3´q>îS·/s½"@X^2’{@bu—[W%{@buò€TgÁ}«/vÙí T¿(é×x>NŸ>mÖ¬Y3üåXî{7H“>×I’ªÇÔs.婊iÚŠB!,16ýµÏ¬ÍößNæMm3Ë8ü´0dSK)rÞ‚uüøqk±TØ0ë¯ÁvkóÉC»{@(åô×£ÇÞÈsöìYk ¼xñ¢Qx5îÍL”¥îÍL”Ûm¦>¸G,“K•+t>•^Þ‚…uÿþ}û½›oÁJÕ]ª®R×ÊŸÓÎü}ˆ x)ÛÂ… ­O›">K›J úº¾”ê%ÑO&ÀÿôCúcn~š Ò>×NêÂSõ˜zι{Ï}w÷Þ'-'\ ¤'„Bü¤Éßa©³·,?``õgúçï@Î,5£?ðž:ujxICÌu3†YÝ2%Œ–ƒp-^ÛyõêÕ–pŒ= ’Ô[°Râ ãÃýí >;=7½ªÁ“ ¯ÂyB›å'3¯”;ö¶¥TySé…Úq¸Ü6*ç–·Ä0ÍI+VW9ùˆÅ¯#ÔΨ3„˜k7;wîlYªF›Æ¨v}þD€„úR¬_”ú5¿þü¹ýÎÿ|÷û{*?MïsiŸk'¡üÄê1õœã>³q¯ ϰê[°Hkîܹ6œ·ai –BˆßF€!„B!„ˆB!„BDñká¿éÉ?zùÚ£™g!„BH€!„B!$@„B!„  B!„B !„B!„ˆB!„BH€!„B!$@„B!„  Bˆ^¦¯¯ï—»î¯X¦Ÿ)½”!„ñùë¯øQÇÌÆÍøñãÍØ±cÍÒ¥KÍ7:: ðÒŸ8q¢Ù´i“yòäIW)wÔñæÍ³zõj3nÜ8{ðùõë×ÁôîÞ½k–/_nÿ8Ú„ ÌÖ­[ÍÐÐPvx´uÎqàÀ`þcåÈ-oizpëÖ-3þ|[¦Y³f™‹/FÓsi†ÂB×Ì©»ÜºjR×2Ú»_–œö[Bªmþl÷'UWM¯[úœëFÔG„âw <œcG  ´/_¾˜?~˜‡šµk×v\€8¸Î¹sçÌ”)Sº*BbyÃx9vì˜ùþý»=Ž=j,XL‡ûÎ;¶~¾~ýjöìÙcæÜð*.\°õþñãG{,[¶Ìžkw =zd¦M›fí÷÷ïß›]»v§—ó»TÝ¥ê*u­Üø2®F¯,%¿íTÛìÕûÓIã¿ô9'"„bÄ^‰ïÞ½3ëׯ·3hüvÕªUÃ3Ô¹³êuaçÏŸ7ëÖ­k9Çìô¤I“ìÌ&^’ÏŸ?·„ïß¿ßzP˜)?sæLãÁj̘1ÿ8Ç5sÁXŽÕ[*ƒØPÀç%K–ôŒá~_¹r¥m# I9ªu—ª«Ôµrãç´3ÒŽ;†½)|æ\®áÆgÄÏŒ3l1Ÿ>}šìK±~ÁoÉãÔ©SkÛu5/¡ëç”/Ä·oßÌÀÀ€Í 'NœÎêWó[-7e›â‡ñ£²D€ø…ª·§.~ª_/·?Ä®Ÿ*_¬Îü</&@ªù­–›´è“N8îܹÓ\½z5»mÆÊØÎsÆyøÍãÇ“õ‚PÙ¼y³ýŒ!ŽAíÏYÂsH¬L!š>çšä¡î¾¦ê:5¶¤ÚÞ¼.±ñJ!D f¯Ø²xñâásÌP±Œ…Yc7ù.ö¦„kU… ÈM®“k”®X±ÂÎ úk£c ǽ{÷첉Ðò‡T¸£tVžÙ?–Ä4-oiz£á ÕÝH{@J—¦DÉãPx§úE“ëçº%éæ U t':hî6i›Õë7­OÂð âIÈçšä¡IÛm2¶øçxVlذÁŠîKÊ#%„¢GHÑÁ,oÅbþ/yÃMè7¬ö—pØ›£:é©3ªR†Öµk×ìŒ[hã|*ܧn_çzE€°Ôa$÷€Äê.·®Jö€Äê:å©ÎÈúŒ'_ì ²Û ©~ÑI’*_¬ÎJ< 9ù¢-°<”MçÛ·oo«múçÚyθ=»§OŸÎªs<üÖ-!ã;^÷½›¤És®“$Uש±%Õ®ª´_!„?‰a@÷×á2»ç¿)… „þ:[–øƒ†lÊ­Ÿó,Ö|3(³lؼé¯vk³ÉC»{@(åô×FÇÞsöìY;X¾xñ¢Qx5îÍL”¥îÍL”Ûm^¥>¸G,“K•+t>•^Œ>óû÷ïÛïÝ| VªîRu•ºVnüœvæ¯IG\`LúKÙ.\hMÚñ™Å/1.ëúRª_tR€¤ÊÂÅ#Ž‹W"@BÏîÛÊ•+­qÙNÛôϵóœqéÆRA6E§`¢…g¨,üϳg`nh*@JŸsíä¡.bñëµ3ê c×µö&øËhÓx®¯`d–P_Šõ‹N TùBð63»NÿN½«J¨Ü7oÞ´å.m›©r7}Îøé`07õBž¥Ä{þü¹ýÎÿ|÷Ÿ±©6дo•>çÚÉC(?±ºN-©vEZsçεἠKK°„b´ˆBü"à=`OšB!$@„¢«àaV[o8B!$@„=ŒÿÖ!ÿèÕtc׊ý‘¿ß¡Î»yíÑ̳B !„B!„B!„BH€!„B!$@„B!„BD!„B!"„B!„ B!„B !„øÿéëëSz,B!Ĩ¿þŠugèèÖ@Í1vìX3qâD³iÓ&óäÉ“®UÖÝ»wÍòåËíØš0a‚Ùºu«ª-IþC¿¯«GÊ™“^]º¥éù,[¶,š^.·nÝ2óçÏ·u8kÖ,sñâÅdûiÒ¶R÷ þ\tóçÏ›uëÖ¥¹ÿ~ë `¦üÌ™3Ù•‡q‹÷e¤ÈÂ… ͇:f¸¤ÒêjöìÙæõë×m õë×›+W®´ÿ&Zõ^!œ>#²r¯•?§!vìØ1ìMá3çrû Ÿ?3f̰e\°`yúôépXÈKëü–mÍýïλ:j² ½tYU'H§ëïËõhNP§êÙ?G»Ý°aƒ5x5ñä !„ <¯o´!ªꛊJ¯Á߸N¥Yê¹víš•Œmtï´ao¸;%@rÓë´G‚å%#¹$v¯êöpp.÷Z¹ñsÚê,¸ïIõ›&†sª_”´a<,Ó[³fÍðw–c¹ï¿²IÕ#á7nܰ øßO'婊iÚŠB!R0À³éCcŠA›%þïŽ?n6n³ïþzéØ5BoÁJ¥éÖæ“ŸÔ³gÏZƒ¢ºt©›äþýûÁÍÍÕx”Ëy,(/uŸGIz¹á%oÁ€"ÐÍ·`¥î•{‹÷½·`¥âç´3âÞ_:—ê7)ÃZ}Ù@ª_”´aD?›°Ý^!þ§Òsó3Ò¤IêÂSõH½ø{8X®æ§ãî=÷ÝÝ{?œ´œpE€žBñK Ò¿’ÌYNÀ›e˜Ñef¥ú;t–nðþ^ÄÕ«W£×p3†Yݲ¨Tš{$©·`¥<¥ÿ$ç÷¶n}ªŽ™ñ§|œgf•rùkÚKÓK…7ù{/îï€p/ø; lTέßc3'-Þ^”ów@BùˆÅ¯#ÔθG1·ŒgçÎ-KÕRý&UG§N^”Û/J zfðùýóçÏíwþç»?³ŸÊO'ïsMòJ;V´wÚ¹»wc?î3×YrÇ3¬ú,Òš;w® çmXZ‚%„â— B!„B!"„B!„Büšøozò^¾öhæY!„ B!„B !„B!„ˆB!„BH€!„B!$@„B!„BD!„B!"„B!„‘Bô2}}}¿ÜuÅ2ýLyè¥|!„ÈÿñWâ_ÝC"„¿°éKüíº/_¾˜sçΙ)S¦tM„¬^½ÚܹsÇüøñÃ|ýúÕìٳǹí–=÷÷ׯ_º¥×M¥çøûï¿Í’%K¢B)‡G™iÓ¦™ÁÁAûýýû÷f×®]Åéäü.u¯.\¸`–.]j>~ühçr¯•_ÆÕè•¥ä·j›½zºaüK€!„ø)HÎ9 âI“&ÙYH<Ÿ?.ºÆùóçͺuëŠÒÜ¿¿õ0S~æÌ™ìÊøÅû2RdáÂ…æÃ‡DSéu5{ölóúõë¶ÈúõëÍ•+WÚÎc¡z¯ÎØ>#²r¯•?§!vìØ1ìMá3çrû Ÿ?3f̰e\°`yúôépXhÆ:Ö/ø-yœ:uª3fLò~„®ŸS¾ß¾}36L,œ8q"8«_ÍoµÜ”mòäÉæÓ§O-m‚sÈœ¶+c;Ï¿Lž „xŽ…˜3gŽyõê•ýLÿ%¾óîÑOé¯~º¡6S¦NŠÁ&yµÃX]¿{÷ÎÞÏqãÆÙ4W­ZÕâýLµ+ݼ}û¶EL¤ö<ÔáÏt§ÒdÀóæMqÅ={öÌtuq»!@þüóOóâÅ‹ìx/_¾´OÈÐËI™ÈÅ‹'¯×)á»Ç£´~ëîU]%Þ¬Üø9íŒÙ]?ŒÏ•%Ä÷(T½=uñSý‚8x¹÷5výTùbuæç‘x1RÍoµÜ¤ÅŒ¶Ž;wî4W¯^Ín›±2¶óœq^~óøñãd½ T6oÞl?cˆcP3ãó„ç X™FJ€¤Únõ¾–ޤéOJ¥ÚÞ¼.,ÃBñ>ãövßcË?êÒc¦ÌlRi6™M¿wïž]æZ®ÐiÂòg`”ÀìK^𦇸pK=:!@FúW#í‰å9%frúM“ðNõ‹&×Ï1tKÒÍ}Þ` ;ÑA»p÷°IÛ,yv¥î?Ë#GŽdÕ7yFH1»Oÿvÿ»ó®LMê§[{lÚJÛ.Þ–HÒÝ$Fê^øçxVlذÁŠîKÊ#%„¢Çƒ€o´!ªꛊJ¯ÁÚi߸N¥Yê¹víš!‹mtï´ao›d;%@rÓë´G‚¥#¹$v¯êöpp.÷Z¹ñsÚ‚ꌬï!Hõ›&F\ª_tR€¤Ê«³HN¾h ®ýoß¾½­¶YòìJy@ˆ‹±ë–;¦ÀóÁoÝ2¾ãEqße’ªkÂoܸa…ð¿ŸNª]U'0h¿B!~b¦gMŒ)f#ýß±>›”M„À컿v7vÐ[°RiºµÙä'µäìÙ³vp«.]ꦹÿ~pss5år Ê‹QUÝçQ’^nxÉ[°ÌÉtó-X©{åÞbÅ}oç-X©ø9íÌ_“ޏÀ˜ô—Î¥úMʈC„V_6ê ©ò…pñˆã╺r;ñ¸råJk\¶Ó6Kž]±ûïÒ!Œ¥‚lŠNÁD ›°`áž}<sÛÀH &y¨ OÕ5õâïá`¹Z]{ µ+Òrb‘6BzB!FP€”þÔÀ‚k›·œ0£ËÌ4ƒeõw .,#à7¼“ß-—]à fuË¢Rib 18¦Þ‚•ò”þý“œßcغ5Ý©:fÆŸòqžY>ÊU}ÛPIz©ð&ïÅý­îkM³¹õ[bøä¤Å›trþH(±øu„Ú÷c×-)ao‚¿(ÕoRutêÔ©á¥*¹ý¢“$U¾ü† Æ,×¢§Þ‚U%Tî›7oÚr—¶ÍT¹›>güt0˜‰{0ƒO¼çÏŸÛïüÏwf?Õ:Ù·rh’‡PÚ±ºæ>rÿ\a2ÂO'Õ®Hkîܹ6œ·ai –BŒ°Bˆ_ ¼üI!„BH€!DWÁì¶Þp$„BH€!zÿ­CþÑ«éÆ®û#¿CwóÚ£™g!„ B!„B!"„B!„B!„BH€!„B!„ˆB!„BD!„B!$@„B!„ BaL__ŸòÐcùB!FI€ $Žœ¡£[5ÇØ±cÍĉͦM›Ì“'OºVYwïÞ5Ë—/·Xk„ fëÖ­fhh¨¶ü%ùý¾®)gNzué–¦ç³lÙ²hz¹ÜºuËÌŸ?ßÖá¬Y³ÌÅ‹“í§IÛJÝ+8xð ?~¼=8P\¶X|÷á<Ôå§isîsnH€!„=!@úÇè¢þ5¾|ùbÎ;g¦L™Ò5²zõjsçÎóãÇóõëW³gÏkü´[öÜß_¿~=jè–^7•žãï¿ÿ6K–,‰ ¥=zd¦M›fí÷÷ïß›]»v§“ó»Ô½ºpá‚Yºt©ùøñ£=XœË½Vn|´Ý5þsû¤ˆBñ› œsÄ“&M²3šx4>þ\tóçÏ›uëÖ¥¹ÿ~ë `õÌ™3Ù•‡Ñƒ÷e¤ÈÂ… ͇:f¸¤ÒêjöìÙæõë×m õë×›+W®´ÿ&Zõ^!œ>#²r¯•?§a8ïØ±cØ›ÂgÎåö>#~f̘a˸`ÁóôéÓá°7'Ö/ø-yœ:uª3fL°LsæÌ1¯^½²ŸiKÄsÚ mÇÏo(?±2´sŸCí§IBu«ÇwïÞÙv?nÜ8›æªU«Z<4ß¾}36.“''NœhÉÃyóæÙð™3g¶x …B Ç›µk×Úåïß¿›mÛ¶µÌ礇'/7ÍC‡Y£€pŒŒÄ\0Fʵ0LcñÜ’*  ãG¶•ìݻל>}:šÏÜòr_¨ãÑ Õ{…Aˆ±ê®œË½Vnüœv¶oß>ÛF?}úd4çJ†/i““'OšE‹Eã§úq¶lÙ<—.]²Ÿ1Þ1¢Ý÷Ë—/›Ý»w׿·®<±2´Û'sŸE©z¬ÖIªûûû̓lz„sß¾(å~û÷ÞÏÛäÉ“­‡.±ç¡B!Ò@€LŸ>ݼ}û¶EL¤ö<ÔáÏ€¦ÒdIЛ7oŠ+îÙ³gÖ¸¨‹Û ò矚/^dÇ{ùò¥5x}C¶4=f/^œ¼^§„CîÒú­»Wui”x³rãç´3fÔý0>cÈ—ßcRõÔÅOõ â`T§¸}û¶Ù¼y³ýŒ!ŽAÍŒ?`Ìž+@beh·Oæ>‹RõX­“Ògiú$´ ?>y÷ó†7¯ Ë…B .>³ÔÀ|-ÿ¨KÙI€O¥Ùd6ýÞ½{viIh‰H§Ë{œQW3ª,éišâÃ-¯é„ Hè^´$–甘Éé7MÂ;Ñ/(7Kƒ˜Ý§­¹ÿÝyWGM6¡wâ>wúùTZx?X®GÛp‚:UÏþ9ʳaÃ+jðjâáB!$@ x^ßhC,T= 9o°‰]ƒ= ¾qJ³ÔríÚ5;+ÛèÞiÂÞ6pwJ€ä¦×iËKFrHì^Õíáà\îµrãç´3< ÕYpß’ê7M çT¿(iÃx>X¦·fÍšáï,Çrß»-@rúd·Hª ¿qã†fÀÿ~:)HUdÑV„B ‚žMÏ*S Ú,Ñðwüøqk´°q˜}÷×KÇ®z V*M·6Ÿü¤ö€œ={ÖÕ¥KÝ ÷ïßnn®Æ£\ÎcAy1ø«û~ühçr¯•_ÆÕè•¥ä·j›½z:iüç>%@„Bô„É9‡A}:òæÄú¿%S§N5cÆŒIÞÐõsÊâÛ·of``À扅'Ngõ«ù­–›²Mž<Ù|úô©¥Mp™Ó6celç9㗃ɄϱsæÌ1¯^½²Ÿé¿Äwú)ýÕO7ÔrÊÔÎs°ZMòj‡±º~÷î½ŸãÆ³i®ZµªÅC“jWxÂæÍ›gÃgΜÙâ Bñ Ç›µk×Zƒàû÷ïfÛ¶m-³9éá a€ÏMóСCv€"œ #!ª‘ò€p- ·X<·¤ŠA#åèÑ£m¥{÷î5§OŸŽæ3·¼Üêx4Hõ^aœ`8ùFçr¯•?§í۷϶QŒc4çJFi““'OšE‹Eã§úq¶lÙȽ~ª|1ÁÆoýx1RÍoµÜ´åãÇg)Ñš5k²Ûf¬Œíoß¾mÅm5‡K—.ÙÏïÑîûåË—ÍîÝ»kë§´Lí>sŸÿ©¶[½¯©ºîïï7<°éN]#8rÛ¢ \bcBˆ_@€LŸ>ݼ}û¶EL¤ö<ÔáÏÆ¥ÒdÀóæMqÅ={öÌtuq»!@þüóOóâÅ‹ìx/_¾´OÈÐËI™ÈÅ‹'¯×)á»Ç£´~ëîU]%Þ¬Üø9íŒÙ]?ŒÏ•%Ä÷(Tg¤ëâ§úq0ðrïkìú©òÅêÌÏ#ñb¤šßj¹I‹m'wîÜi®^½šÝ6celç9ã¼üæñãÇÉzA¨lÞ¼Ù~ÆÇ fÆ0æ Ï ±2µûÌ}þ§Únõ¾–ޤéOJ¥ÚÞ¼.,ÃBñ>ãövßcË?êÒc¦ÌlRi6™M¿wïž]æZ®ÐiÂòg`”ÀìK^𦇸pK=:!@FúW#í‰å9%frúM“ðNõ‹&×Ï1tKÒÍ}Þ` ;ÑA»p÷°IÛ,yv¥î?Ë#GŽdÕ7yFH1»Oÿvÿ»ó®LMê§}«ÓcBiÛÅûÁIú£›ÄHÝ ÿåÙ°aƒ5Ü—”GJ!D ßhC,T= 9oS‰]ƒµÓ¾qJ³ÔríÚ5;CÛèÞiÂÞ6ÉvJ€ä¦×iKFrHì^Õíáà\îµrãç´3<ÕYßCê7MŒ¸T¿è¤I•/Vg%œ|Ñ\ûß¾}{[m³äÙ•ò€c×-wLçƒßº%d|Ç‹â¾w[€ä<»%@RuMø7¬0þ÷ÓIµ«ªÈ¢ý !„ø‰›ž41¦@˜ôÇúlP6³ïþÚÝØ5BoÁJ¥éÖf“ŸÔ³gÏÚÁ­ºt©›äþýûÁÍÍÕx”Ëy,(/FUuŸGIz¹á%oÁb0'ÐÍ·`¥î•{‹÷½·`¥âç´3M:âcÒ_:—ê7)#Z}Ù@ª_tR€¤ÊÂÅ#Ž‹W"@êÊíÄãÊ•+­qÙNÛ,yvÅî¿K‡0–3±):-lÂv‚…ÿyöñ ÌmMHîs0ç~4 ©º¦^ü=,W«k¡vEZN,ÒFHO!ÄH ÿ—8 \Û¼å„]fÏ,«¿cpa¿áün¹Dèî`À0«[JcˆÁ1õ¬”G ôïŸäüÃÖ­éNÕ1³’”óÌòQ®êÛ†JÒK…7ù{/îo-p/ø[ lšÍ­ß#)'-Þ¤“ów@BùˆÅ¯#ÔθG»nI {üå@©~“ª£S§N /UÉí ©ò…à7l0f¹ý;õ¬*¡rß¼yÓ–»´m¦ÊÝô9㧃ÁLÜØ $€|â=þÜ~ç¾û3û©6Ð;UG“<„ÒÕ5÷‘ûçú ‚ÉO'Õ®Hkîܹ6œ·ai –BŒ´Bˆ_ ¼üI!„BH€!DWÁì¶Þp$„BH€!zÿ­CþÑ«éÆ®û#¿CwóÚ£™g!„ B!„B!"„B!„B!„BH€!„B!„ˆB!„BD!„B!$@„B!„ BaL__ŸòÐcùB!FE€ $Žº3ttk æ;v¬™8q¢Ù´i“yòäI×*ëîÝ»fùòåökM˜0ÁlÝºÕ Õ–¿$ÿ¡ß×Õ#åÌI¯.ÝÒô|–-[M/—[·n™ùóçÛ:œ5k–¹xñb²ý4i[©{4ãÇ·ÇŠË‹/ã>œ‡ºü4Í#÷™¶éîó–-[²þÊy'ó "„BtP€ô%ŽÑDýk|ùòÅœ;wÎL™2¥k"dõêÕæÎ;æÇæëׯfÏž=ÖÈm·ì¹¿¿~ýzÔÐ-½n*=Çßÿm–,YJ9|è˜á’J¨«Ù³g›×¯_·-@Ö¯_o®\¹Òvþ›hÕ{…xpBøŒÈʽVnüœv†@Ú±cǰ7…ÏœËí7|Fü̘1ÖqÁ‚æéÓ§Ãa!oN¬_ð[ò8uêT3f̘`™æÌ™c^½ze?Ó–ˆç¥ê±Z'¥Ï,Òô'Hh~|îýÿ×Þû¸èðýÿÿ¯?åó§lRD""ŠVD"¢g¢m/Q6"­¼ÚD´_¢ö]›H¶UÞ¯yÙ¼‹ˆœïëvêlgç=s~Ì5×þzÞoÛ´×53çÌù5s÷ó8g.?mxc𺤬kB!$@j>3ÕÀm|Mÿ(‹ÑI¿ƒÅYg4}xxØN-©š"Ò´az3êr`D•)=uãC|øÆÜLô€TÕÕd{@Biމ™”û¦Îñ&î òÍÔ F÷ikî¿ÛïʨÎ"ôÜûˆk1…ÉÍM?ŸrËïÓõhN$ÅÊÙßG»íîî¶¢¯&ž|ØŒ•æ?·¼RË“|æ”+ñùlß¾=_*>4ëׯ·e¸jÕ*sëÖ­hû©Ó¶buçÎ3óçÏ·ÛÙ³g³ó /£½ýy‰å+7ß±¶9Óê'VVu¯Ë½ÅóÀÝ[4Ÿ?®•O !„ù?ä¿ÿû¿ƒÛT?ÐýküøñÃ\¿~Ý,Y²¤m"d÷îÝæñãÇæÏŸ?æçÏŸæäÉ“ÖÈm5ï©çß¿?hèæ^7ŸãÞ½{fëÖ­A¡”ÂóçÏͲeËÌÓ§OíwŒ–ãÇgÇ“r^¬®nÞ¼i¶mÛf¾~ýj7 *ö¥^+5¼Œ«©ËKιMµÍéZ?Mÿ;wî4=2¿ÿ¶÷ו+W̦M›$@„B4#@þë¿þ+¸5ÑÙ÷a/Z´ÈŽ®áÑøþý{Ö5nܸaöîÝ›ç™3g¬'€Ñ¼k×®%/Þ—É 7n4_¾|i¬Å”ÕêÕ«Íû÷ï[ ûöí3wïÞm9ýuŒ…b]!œ± |Fd¥^+5|J;C ;vlÜ›Âgö¥Þ7|Fü¬X±ÂæqÆ æÕ«WãǪ¼9¡û‚sIãÒ¥KÍœ9s¢õQuý”üUñë×/sèÐ!›>.]ºT9ª_Lo1ßämñâÅæÛ·oÚû)m3”ÇVž3~>dÜëׯmGW¶dóæÍæÍ›7ÉáÞ¾}k ž*C/%>F"·lÙ½^SÂ!uGnù–ÕUY9Þ¬Ôð)íŒÑ]ÿŸ1*sˆïQ(z{ÊÂÇî Â`à¥Ökèú±ü…ÊÌO#áB¤˜Þb¾‰‹m'{zzÌÀÀ@rÛ å±•çŒóp΋/¢å‚P9pà€ýŒ!ŽA͈?`ÌsY¤IAÙTÛåøÐÐfÀ?žX»*`Ð~…BÌ`¢g:MŒ):F#ýó˜ŸMÊ"B`ôÝŸ»ºFÕ[°bqº¹Ù¤'¶¤¿¿ßvnÅ©Kí ###•‹›‹áÈ—óX_Œªâ:œøR缋Μ4@;ß‚«+÷+꽕·`ŧ´3N:âcÒŸ:»obF"´ø²Ø}Ѥ‰å¯ Ž0.\Ž)Ë·¼É 㲕¶™óì Õ¿‹‡cLÄ£ƒa;Áž}<SÛ@]Â3…Åînƒá!ñÝJÊŽÇÊšrñ×p0]­¬=Vµ+ârb‘6B|B!f°ÁµÍ[NÑedšÎ²x Ó8‡wò»éU×p†YÙ´¨XœCtޱ·`Å<¹¿’r>†­›Ó+cFüÉûå#_Å· åÄ;^ç÷^Üo-PüÖ‹fSË7ÇHJ‰ Ã)åw@ªÒ _FU;£Ž0vÝ”Ö&øÓb÷M¬ŒxMª›ª’z_4)@bù«‚sX`Ìè:÷wì-XEªòýàÁ›ïܶËwÝçŒ3aC/Fð 7::j¿óŸïþÈ~¬ Ô½·üç õRö;eÔICUzBeM=Rî~a0Â'Ö®ˆ«³³ÓçmXš‚%„“,@þçþ'¸ !ÄLï?")„Bˆi(@„b67†Qm½áH!„BLcü·ùÛt7t­ÐüýʼמÊ4 !„B!„B !„B!„ˆB!„BD!„B!$@„B!„ B!„B!"„B!„Bc:::”†i–!„bF:Ϊ­]5ÛܹsÍÂ… ÍþýûÍË—/ÛVXOž<1;vì°?¬µ`Ásøða366VšÿÜòJ-Oò™Sþ­Äç³}ûö`|©<|øÐ¬_¿Þ–áªU«Ì­[·¢í§NÛŠÕœ;wÎÌŸ?ßngÏžÍÎ[(¼Œûê4”¥§‰4–µÑœ2‘B!¦éýOGÚ¦ºõ¯ñãÇsýúu³dÉ’¶‰Ý»w›Ç›?þ˜Ÿ?š“'OZ#·Õ¼§žÿþý ¡›{ÝX|Ž{÷î™­[·…R ÏŸ?7Ë–-3OŸ>µß?þlŽ?žOÊy±ººyó¦Ù¶m›ùúõ«Ý0^Ù—z­Ôð2h'ÇøµQ !„b†îÿ|mMtðÅ}Ä‹-²#×x4¾ÿžu7n˜½{÷fÅyæÌë `¤üÚµkÉ…‡q‹÷e²ÈÆÍ—/_3\bñeµzõjóþýû–Ⱦ}ûÌÝ»w[N­XWˆ'„€Ï°©×J ŸÒÎHÇŽ÷¦ð™}©÷ Ÿ?+V¬°yܰaƒyõêÕø±*oNè¾à\Ò¸téR3gΜÊ<­Y³Æ¼{÷Î~¦-Îyšh3´?½Ué å!FJ-–]4T•I¨?}údÛý¼yólœ»víšà‰ûõë—9tè ËàÉ¥K—&¤ áºuëìñ•+WNð !„ ÞÞ^³gÏ;¢üû÷osäÈ‘ #ä)ñá ÁÀKóüùóÖ(à8ÆFb*“åáZ¦¡pnJ††áÅ‹[ŠN:e®^½Lgj~©Êx*H±®0%¾@a_êµRç´³Ó§OÛ6úíÛ7»! Ù—#@0|‰›t\¾|ÙlÚ´)>v_æàÁƒÁÀ³tûömûã#Ú}¿sçŽ9qâDizËòÊCˆ”6šú,Š•c±Lbå¸víZóìÙ3Ç©w‡/J©o¿îý´-^¼Øzòáz !„ 5ÈòåËÍÇ'ˆ‰Øš‡2ü‘îXœL úðáCvÁ½~ýÚeaÛ!@6oÞlÞ¼y“îíÛ·Öàõ ÙÜøýݲeKôzM ‡Ô5¹å[VWeqäx³Rç´3FÔýc|ÆÏ ¾Ç¤èí) »/ƒQãÑ£GæÀö3†85#þ€1ÏñTÊC©m4õY+Çb™ä>³ˆÓ ¡]øá©{?mxcðº0]Q!„iƒá3S ÜÆ÷Ðô²øô;øXœuFÓ‡‡‡í”ª)"M ¦÷8£.FT™ÒS7> ;7½¦ 2ªºšlH(Í11“rßÔ9ÞÄ}A¾™Äè>mÍýwû]ÕY„ž’†Ô6ÚÔó)·ñ~0]¶áu¬œý}´Ûîîn+jðjâÉB!$@2:x:^ßhC,= Å7å^ƒ5 ¾q‹3×288hG%C Ý› ¬-`wS$5¾¦=L/™Ì5 ¡º*[ÃÁ¾Ôk¥†Oigx@Š£à¾$vßÔ1œc÷ENÆóÁ¨®®®ñïLÇrßÛ)@ê¾u¯)+GŽ Yaü÷ã‰y@Šbš¶"„BH€dtð,zÆPÁ˜¢ÓfІ^__Ÿ5ZX¸ Œlúó¥Cרz V,N77ŸôÄÖ€ô÷÷[ƒ¢8u©ddd¤rqs1ùr£Á䃿¸Î#'¾Ôã9oÁ€" Ðη`ÅêʽŊzoå-X±ð)íÌ_€¸À€÷§ÎÅáŒ-¾l v_ä´aD?‹°Ý: þsr?¦¦§©·R¥†©“†²ã±r¤\ü5LWóãquO½»º÷—®âB!$@2 ¦ðfFt™Æ@)žG‡ÎÔ Îá÷"‚×p3†YÙ´¨Xœ{$±·`ÅF[sGbSÎǰuóècë?ùc?#«äËŸÓž_ìx‘g÷; Ô¿ÂBåÔòÍ12SââíE)¿R•ŽPø2ªÚu„sÓxzzz&LU‹Ý7±2ºråÊøô Ôû"ÇøgŸóGGGíwþóÝÙ¥g²H4TÅ*GÚ;íÜÕÂØ‡zfá:Sîx†ß‚E\ö8oÃÒ,!„³^€üû?_hB!„BˆÆˆB!„BH€!&ÿMOþ6¯=•iB!„ˆB!„BD!„B!"„B!„ B!„B !„B!„B!„BH€!„B!$@$@„Ó™ŽŽŽYwÝÙ˜§™”†é”!„©ù¯ÚÚÕi°Í;×,\¸Ðì߿߼|ù²m…õäɳcÇûcf ,0‡6ccc¥ùÏ-¯Ôò$Ÿ9åßJ|>Û·oÆ—ÊÇÍúõëm®ZµÊܺu+Ú~ê´­X]Á¹sçÌüùóívöìÙì¼…ÂËho^bùÊÍw¬mδú‰•U×-{.ääSD!$@þéèè nSý@÷¯ñãÇsýúu³dÉ’¶‰Ý»w›Ç›?þ˜Ÿ?š“'OZ#·Õ¼§žÿþý ¡›{ÝX|Ž{÷î™­[·…R ÏŸ?7Ë–-3OŸ>µß?þlŽ?žOÊy±ººyó¦Ù¶m›ùúõ«Ý0¤Ø—z­Ôð2®¦./9ç6Õ6§ký´Ãø=$@„BÔ ÿøGwpk¢³)îà ^´h‘…Ä£ñýû÷¬kܸqÃìÝ»7+Î3gÎXO#å×®]K.<Œ[¼/“%@6nÜh¾|ùÒX'‹(«Õ«W›÷ïß·,@öíÛgîÞ½Ûrúë źB<8cøŒ1•z­Ôð)í tìØ±qo ŸÙ—zßðñ³bÅ ›Ç 6˜W¯^«òæ„î Î%K—.5sæÌ‰ÖGÕõSòWů_¿Ì¡C‡lúX¸téRå¨~1½Å|“·Å‹›oß¾MhìC@¦´ÍP[yÎøù`ð!Äs¬Š5kÖ˜wïÞÙÏÜ¿„wÞ=îSîW?Þª6’§Vž Åò«“†ªv*ëOŸ>Ùúœ7ožs×®]¼Ÿ±v…'lݺuöøÊ•+'x„BÌBÒÛÛköìÙc ‚ß¿›#GŽL…L‰O|jœçÏŸ·Çé˜0R¡£š,×Âp …sSªèt1R.^¼ØR|pêÔ)sõêÕ`:SóK½PÆS!@Šu…q‚ê£ìK½Vjø”vvúôiÛF1ŽÙÐìË aÄM:._¾l6mÚ »/sðàÁà@êõcù 6ÎõÃ…H1½Å|Ó–ûúúÆ¿3M¯««+¹m†òØÊsÆ¥óÑ£GV|ÐVCàÍ»}û¶ýŒñŽí¾ß¹sÇœ8q¢´|ró"å¹úüµÝb½ÆÊzíÚµæÙ³g6>ŽSÖŽÔv…(Å{ —P$„båË—›?N±5eø#ݱ8éð?|ø]p¯_¿¶]YØvÍ›7›7oÞ$‡{ûö­5xª ½”ø‰Ü²eKôzM ‡Ô5¹å[VWeqäx³Rç´3Fwýc|ƨÌ ¾G¡èí) »/ƒ—Z¯¡ëÇò*3?„ bz‹ù&.F´pìéé1Ém3”ÇVž3Î À9/^¼ˆ– BåÀö3†85#þ€1ÏñTÊS©Ï…Ôç¬íë5·Ÿ NP*Ö®ðÆàuažBˆ¿á3no·ñ=4ý£,>FÊüÎ&gÑôááa;ý jºBÓ„é=ÎÀÈÑ=¦¼Ô#ÃMõhìÆK?IDATB€L…¤ª®&ÛJsL̤Ü7uŽ7u_Ô¹~Š¡›oêó݉Ú…«Ã:m3çÙ«<–.\H*oÒŒbtŸûÛýwû]žê”OJ½§>šêrÛ.Þ¦Hr?ºAŒX]øûxVtww[QC½Ä¥ùsÒ“þÔ¹Ø}3â¡Å— Äî‹&H,U¸p„qárHY¾xܹs§5.[i›9Ï®Pý»x8ÆTAEÇ` …EØN°ðŸgÏÀÔ6ÐÔ[©RÃÔICÙñXYS.þ¦«•µÇªvE\N,ÒFˆO!Ä  ¸¶yË #ºŒLÓYÏ£saçðN~7]"6G'aV6-*'Æcì-X±‘¿ÜQÁ”ó1lÝœîX3âOþØÏ(ù*¾m('¾Øñ:£ î·¨ ~kE³©å›cð¤ÄÅ›tR~¤*¡ðeTµ3êc×M)am‚?(vßÄÊèÊ•+ãSURï‹&H,Up Œ™®Åý{ V‘ª|?xðÀæ;·mÆò]÷9ãǃÁLØÐ $€|ÂŽŽÚïüç»?²k“-@ꤡ*îPYSÔŸ»_Œð㉵+âêìì´Çy–¦` !Ä$ 7!„˜ià=àG$…B1 ˆBÌ&ðÆ0ª­7 !„ BˆiŒÿÖ!›®ñ†®ú‘¿¿C™·óÚS™f!„ B!„B!"„B!„B!„BH€!„B!„ˆB!„BD!„B!$@„B!„ BaLGG‡Ò0ÍÒ!„BÌBÇYµµ«£f›;w®Y¸p¡Ù¿¿yùòeÛ ëÉ“'fÇŽö‡µ,X`>lÆÆÆJóŸ[^©åI>sÊ¿•ø|¶oߌ/•‡šõë×Û2\µj•¹uëV´ýÔi[±º‚sçΙùóçÛíìÙ³Ùy …—q_†²ôÔMcÝgM“iB! ½Ámª;Qÿ?~ü0ׯ_7K–,i›Ù½{·yüø±ùóçùùó§9yò¤5r[Í{êù÷ïߺ¹×Åç¸wïžÙºukP(¥ðüùs³lÙ2óôéSûýóçÏæøñãÙñ¤œ««›7ošmÛ¶™¯_¿Ú žÔk¥†—AÛ^ã¿Ép B!Ä4 ÿèþGpk¢ƒ/îà ^´h‘¹Æ£ñýû÷¬kܸqÃìÝ»7+Î3gÎXO#å×®]K.<Œ[¼/“%@6nÜh¾|ùÒ˜á‹(«Õ«W›÷ïß·,@öíÛgîÞ½ÛrúëhźB<8!|Fd¥^+5|J;C ;vlÜ›Âgö¥Þ7|Fü¬X±ÂæqÆ æÕ«WãǪ¼¡û‚sIãÒ¥KÍœ9s*ó´fÍóîÝ;û™¶D8çi¢ÍÐvüôV¥'”‡¦ÛBÝ4T•I¨?}údÛý¼yólœ»víšà‰ûõë—9tè ËàÉ¥K—&¤ áºuëìñ•+WNð !„ ÞÞ^³gÏ;¢üû÷osäÈ‘ #ä)ñá ÁÀKóüùóÖ(à8ÆFb*“åáZ¦¡pnJ††áÅ‹[ŠN:e®^½Lgj~©Êx*H±®0%¾@a_êµRç´³Ó§OÛ6úíÛ7»! Ù—#@0|‰›t\¾|ÙlÚ´)>v_æàÁƒÁÀ³tûömûã#Ú}¿sçŽ9qâDizËòÊC¨-¤¶ù”gQ¬‹e+ǵkךgÏžÙø8N½#8|QJ}ûuï§mñâÅÖ“—ÐóP!„©!@–/_n>~ü8ALÄÖ<”átÇâdJЇ² îõë×Ö¸( Û²yófóæÍ›äpoß¾µ¯oÈæÆÇèï–-[¢×kJ8¤®ñÈ-ß²º*‹#Ç›•>¥1¢îã3†|Žñ=&EoOYøØ}AŒê=2°Ÿ1Ä1¨ñŒyާ PRˆµù”gQ¬‹e’ûÌ"N€„vᇧîý´áÁëÂtE!„B¤ „ÏL5pßCÓ?ÊâctÒïàcqÖM¶SKª¦ˆ4-@˜Þ㌺QeJOÝønzMd*< Uu5ÙPšcb&復s¼‰û‚|35ˆÑ}Úšûïö»2ª³½Î½YÕæ›z>å–#Þ¦ëÑ6œ Ž•³¿vÛÝÝmE !„B$ÃHd:o–aD—‘i ”âytèLÝà~/b`` x ·Ñ1c˜•M‹ŠÅ‰±‡A{ VÌ#û›)çcغyô±2fÄŸü±Ÿ‘UòåÏiÏ/v¼Îo0¸ß¡.ø*§–oŽašo/Jùªt„—QÕΨ#„˜›ÆÓÓÓ3aªZ쾉•Ñ•+WƧ¥Þ9„|εßùÏwd?–žºõœÒæË¨“†ªô„Ê‘öN;wu‡0ö㡞Y¸Î”;žaÅ·`Wgg§=ÎÛ°4K!Ĭ ÿnB!„BјB!„B !Ĥâ¿éÉߦóµ§2ÍB!„B!„BH€!„B!$@„B!„BD!„B!"„B!„ B!„B !„B!„ˆˆb:ÓÑÑ1ë®;ó4“Ò0Ò!„ 5âU[»: ¶¹sçš… šýû÷›—/_¶­°žµß?þlŽ?žOÊy±ººyó¦Ù¶m›ùúõ«ÝXìK½VjxWS——œs›j›Óµ~š SÝ#B1‹Hw÷?‚[Mqñ¢E‹ì($ïß¿g]ãÆfïÞ½Yqž9sÆz)¿víZráaÜâ}™,²qãFóåË—Æ:ÑX|@Y­^½Ú¼ÿ¾e²oß>s÷îÝ–Ó_ÇX(ÖâÁ›ÀgDVêµRç´3Ò±cÇÆ½)|f_ê}ÃgÄÏŠ+l7lØ`^½z5~¬j¤:t_p.i\ºt©™3gN´>ª®Ÿ’¿*~ýúe:dÓÇÀÂ¥K—*Gõ‹é-曼-^¼Ø|ûömB›`2¥m†òØÊsÆÏƒ'!žcU¬Y³Æ¼{÷Î~æþ%¼óîqŸr¿úñVµ”<5uÿÕMCU; •õ§OŸl}Λ7ÏÆ¹k×® ÞÏX»Â¶nÝ:{|åÊ•5ÎóçÏÛŠãtL ©ÐQM–„ka¸…¹)Utº)/^l)>8uꔹzõj0©ù¥^(ã© źÂ8ÁõQö¥^+5|J;;}ú´m£ÇlhöåŒ0â&—/_6›6m †Ý„9xð`p õú±ü…çúáB¤˜Þb¾iË}}}ãß™¦×ÕÕ•Ü6Cylå9ãÒùèÑ#+>h«!ðæÝ¾}Û~ÆxLjvßïܹcNœ8QZ>¹y •Eês&åùk»Åz•õÚµkͳgÏl|§¬©í QŠ÷.¡>H!Ä, Ë—/7?~œ &bkÊðGºcqÒáøð!»à^¿~m;º²°í ›7o6oÞ¼I÷öí[kðTz)ñ1¹eË–èõš©kv_/µ^C×å/Tf~  ÅôóM\Œh;áØÓÓc’Ûf(­FÊüÎ&gÑôááa;Í¡jºBÓ„é=ÎÀÈÑ=¦¼Ôñá¦z4!@¦ÂRUW“í ¥9&fRî›:Ç›º/ê\?ÅÐ͉7õyƒîDíÂÕa¶™óìŠÕ?ž„ .$•7iFH1ºÏýíþ»ý.OuʧÎó°ê9ÓTŸÛvñ~0E’ûÑ bÄêÂßdz¢»»ÛŠê%æ‘B1Í€o´!Š⛊r¯ÁÜi߸ŽÅ™ë´#d¡…îM Ö°H¶)à 5¾¦=Lu˜Ì5 ¡º*[ÃÁ¾Ôk¥†OigxŠ#²¾‡ vßÔ1âb÷E“$–¿P™åx@RÒE[píÿèÑ£-µÍœgWÌBXŒ]7Ý1žÎuSÈøŽÅ}ŸÍ$Vֲ øïÇkWÅ Ú¯Bˆ,@XôL§‰1EÂh¤ó³é@YDŒ¾ûswCרz V,N77›ôÄÖ€ô÷÷Ûέ8u©ddd¤rqs1ùr ò‹QU\ç‘_êñœ·`Ñ™“hç[°buåÞbE½·ò¬Xø”væÏIG\`LúSZb÷M̈Ã8,¾l v_4)@bù«Â…#Œ —#@ÊòíÄãÎ;­qÙJÛÌyv…êßÅÃ1¦ ²(:-,Âv‚…ÿ<ûx¦¶º$å9SF4”•5åâ¯á`ºZY{¬jWÄåÄ"m„ø„BÌ`‚k›·œ0¢ËÈ4eñ<:¦pïäwÓ%ª®á6: ³²iQ±81†ècoÁŠyrߟr>†­›Ó+cFüÉûå#_Å· åÄ;^ç÷Üo-PüÖ‹fSË7ÇHJ‰‹7é¤üHU:Bá˨jgÔÆ®›RÂÚ:P쾉•Ñ•+WƧª¤ÞM Xþªà3]‹û;ö¬"Uù~ðàÍwnÛŒå»îsƃ™°±…ÝŒànttÔ~ç?ßý‘ýX¨{o¥Û·oÆ—ÊÇÍúõëm®ZµÊܺu+Ú~ê´­X]Á¹sçÌüùóívöìÙì¼…Â˸¯NCYzZIãëׯÍ_ýeæÍ›g–/_nnß¾]«L$@„Bˆi @zþ_Op›êNÔ¿Æ?Ìõë×Í’%KÚ&BvïÞm?~lþüùc~þüiNž âE‹Ù‘k<ß¿ϺÆ7ÌÞ½{³âæoüøq‚˜ˆ­y(ÃéŽÅÉ” >dóÎ1.ʶC€lÞ¼ÙN7I ÷öí[kðú†ln|ŒþnÙ²%z½¦„CêÜò-««²8r¼Y©áSÚƳŒÏò9Ä÷˜½=eác÷a0ªc¥ùëðþÔ¹Ø}3œ¡Å— Ä6Œèg¶[+ÄîCîÇÔôÔ ¬7aÚ"„éX¬ÓˆQ' eÇcåH¹øk8˜®æÇãêžzwuï'.'\ Ä'„BH€d‰L'àÍ2Œè22R<©œÃïE ¯á6:f ³²iQ±81ö0HboÁŠyrÿ$å| [7>VÆŒø“?ö3²J¾üÑáÜøbÇëüÞ‹ûê‚×§²P9µ|s Ó”¸x{QÊï€T¥#¾ŒªvF!ÄÜ4žžžž SÕb÷M¬Œ®\¹2>=(õ¾È Œàsþèè¨ýξû#û±ô´âYãe î-Tÿüç?“¡×ICUzBåH{§»ºCûñPψ&¦Ü‘‡â[°ˆ«³³ÓçmXš‚%„bÖ ±7!„B!„hL€!„B!„ˆbRñßôäoÓùÚS™f!„BH€!„B!$@„B!„ B!„B!"„B!„B!„B !„B!„ˆB!„BDD1éèè˜u×yšIi˜NéB šñª­]ÛܹsÍÂ… ÍþýûÍË—/ÛVXOž<1;vì°?f¶`Ásøða366VšÿÜòJ-Oò™Sþ­Äç³}ûö`|©<|øÐ¬_¿Þ–áªU«Ì­[·¢í§NÛŠÕœ;wÎÌŸ?ßngÏžÍÎ[(¼Œööç%–¯Ü|ÇÚæL«ŸXYµrÝׯ_›¿þúËÌ›7Ï,_¾Üܾ}»V>%@„Bäÿÿ×Óܦúî_ãÇæúõëfÉ’%m!»wï6?6þü1?þ4'Ož´Fn«yO=ÿþýûAC7÷º±ø÷îÝ3[·n ¥ž?n–-[fž>}j¿þüÙ?~<;ž”óbuuóæM³mÛ6óõëW»!°Ø—z­Ôð2®¦./9ç6Õ6§ký4iü¿yóÆ 4÷ÂÞ/+ !„- tw·&:›â> âE‹ÙQH<ß¿ϺÆ7ÌÞ½{³âª®Ÿ’¿*~ýúe:dÓÇÀÂ¥K—*Gõ‹é-曼-^¼Ø|ûömB›`2¥m†òØÊsÆÏƒ'!žcU¬Y³Æ¼{÷Î~æþ%¼óîqŸr¿úñVµ”<•A¤x<ŠåW' Uí0TÖŸ>}²õ‰w†8wíÚ5ÁûkW«uëÖÙã+W®œà B1 Hoo¯Ù³g5~ÿþmŽ9Y+‹O|jœçÏŸ·Çé˜0R¡£š,×Âp …sSªèt1R.^¼ØR|pêÔ)sõêÕ`:SóK½PÆS!@Šu…q‚ê£ìK½Vjø”vvúôiÛF1ŽÙÐìË aÄM:._¾l6mÚ »/sðàÁà@êõcù 6ÎõÃ…H1½Å|Ó–ûúúÆ¿3M¯««+¹m†òØÊsÆ¥óÑ£GV|ÐVCàÍsã#Ú}¿sçŽ9qâDiùäæ© ž1x›éÝÿé þ÷ÿ·Ö}›Òv‹õ+ëµkךgÏžÙø8NY#8RÛ¢ï)¤zw„BÌ`Â\â?N±5eø#ݱ8éð?|ø]p̦£+ Û²yóf;õ!5ÜÛ·o­ÁSeè¥ÄÇHä–-[¢×kJ8¤®ñÈ-ß²º*‹#Ç›•>¥aÈùÇøŒQ™#@|BÑÛS>v_/µ^C×å/Tf~  ÅôóM\Œh;áØÓÓc’Ûf(­FÊüÎ&gÑôááa;Í¡jºBÓ„é=ÎÀÈÑ=¦¼Ôñá¦z4!@¦ÂRUW“í ¥9&fRî›:Ç›º/ê\?ÕÐM7õyƒ¡ìDíÂÕa¶™óìŠÕ?Ë .$•7iFH1ºÏýíþ»ý.OuÊ'¥Þiç¾h ÜÈs«õÙTÛÅûÁIÒé1buáïãYWQC½ÄòU|ÛPN|±ãu~ïÅýÖuÁ«U%õ¾hR€ÄòWç`Ü2]‹û;ö¬"Uù~ðàÍwnÛŒå»îsƃ™°¡H#ø„µßùÏwd?ÖZñf’>÷ªþóŸI‹Ð뤡*=¡²¦©?w¿0áÇkWÄÕÙÙió6,MÁBˆI ÿþOgÚ„b¦÷€‘B!Ä4 B1›Àè¶Þp$„BH€!¦1þ[‡ümºÆºVèGþþeÞÎkOeš…BH€!„B!„ˆB!„BD!„B!"„B!„ B!„B !„B!„B!„BH€!„1JÃ4K‡B1#gÕÖ®ŽšmîܹfáÂ…fÿþýæåË—m+¬'Ož˜;vØÖZ°`9|ø°+Íny¥–'ùÌ)ÿVâóÙ¾}{0¾T>|hÖ¯_oËpÕªUæÖ­[ÑöS§mÅê Î;gæÏŸo·³gÏfç-^Æ}uÊÒS7uÛt“iB!š ==ámŠ;Qÿ?~ü0ׯ_7K–,i›Ù½{·yüø±ùóçùùó§9yò¤5r[Í{êù÷ïߺ¹×Åç¸wïžÙºukP(¥ðüùs³lÙ2óôéSûýóçÏæøñãÙñ¤œ««›7ošmÛ¶™¯_¿Ú žÔk¥†—A;¹Æj›–B!¦«éîo tðÅ}‹-²#×x4¾ÿžu7n˜½{÷fÅyæÌ;jÊHùµk×’ ãïËd 7š/_¾4f¸ÄâÊjõêÕæýû÷- }ûö™»wï¶œþ:Z±®NŸY©×J ŸÒÎHÇŽ÷¦ð™}©÷ Ÿ?+V¬°yܰaƒyõêÕø±*oNè¾à\Ò¸téR3gΜÊ<­Y³Æ¼{÷Î~¦-Îyšh3´?½Ué å¡é6]7 Ue*ÇOŸ>Ùv?oÞ<ç®]»&xâ~ýúe:dÃ2xréÒ¥ iÂc¸nÝ:{|åÊ•<†B!„H¤··×ìٳǎ(ÿþýÛ9rdÂyJ|xB0ðRã<þ¼5 8Ž1€‘˜ ÆÁdy@¸†i(œ›~‚¡ƒaxñâÅ–âƒS§N™«W¯Ó™š_ê…2ž R¬+ BD‰/PØ—z­Ôð)íìôéÓ¶~ûöÍnhöå _â&—/_6›6m †Ý„9xð`pð,ݾ}Û~ÆxLjvßïܹcNœ8QšÞ²ü„òZÇÅ6û|Š•c±Lbå¸víZóìÙ3Ç©w‡/J©o¿îý´-^¼Øzòáz !„ 5ÈòåËÍÇ'ˆ‰Øš‡2ü‘îXœL úðáCvÁ½~ýÚeaÛ!@6oÞlÞ¼y“îíÛ·Öàõ ÙÜøýݲeKôzM ‡Ô5¹å[VWeqäx³Rç´3FÔýc|ÆÏ ¾Ç¤èí) »/ƒQãÑ£GæÀö3†85#þ€1ÏñTÊC em:÷ù+Çb™ä>³ˆÓ ¡]øá©{?mxcðº0]Q!„iƒá3S ÜÆ÷Ðô²øô;øXœuFÓ‡‡‡íÔ’ª)"M ¦÷8£.FT™ÒS7>ć›^Ó„™ HU]M¶$”昘I¹oêoâ¾ ßL btŸ¶æþ»ý®Œê,BÏ©çÜ{¤îó)·ñ~0]¶áu¬œý}´Ûîÿ44d…ðß'æ)ŠiÚŠB!’ÑÁ³@CcŠN›)þy}}}Öhaá&0úîÏ—]£ê-X±8ÝÜ|Ò[Òßßo ŠØ4&ÈÈÈHåâæb8òå<䃿8'>'¾Ôã9oÁ€" Ðη`ÅêʽŊzoå-X±ð)íÌ_€¸À€÷§ÎÅáŒ-.ÌŽÝ9mÑÏ"l·Vˆÿ܇ܩéiE€„ÚtuÒPvŸíÛ·ãKåáÇfýúõ¶ W­Zenݺm?uÚV¬®àܹsfþüùv;{ölvÞBáe´·?/±|åæ;Ö6gZýÄʪîuë>GšLƒî!„˜Å¤§'¼MõÝ¿Æ?Ìõë×Í’%KÚ&BvïÞm?~lþüùc~þüiNžª®Ÿ’¿*~ýúe:dÓÇÀÂ¥K—*Gõ‹é-曼-^¼Ø|ûömB›`2¥m†òØÊsÆÏƒ'!žcU¬Y³Æ¼{÷Î~æþ%¼óîqŸr¿úñVµ”<5õ©›†ªv*ëOŸ>Ùúœ7ožs×®]¼Ÿ±v…'lݺuöøÊ•+'x„BÌBÒÛÛköìÙc ‚ß¿›#GŽL…L‰O|jœçÏŸ·Çé˜0R¡£š,×Âp …sS!èt1R.^¼ØR|pêÔ)sõêÕ`:SóK½PÆS!@Šu…q‚ê£ìK½Vjø”vvúôiÛF1ŽÙÐìË aÄM:._¾l6mÚ »/sðàÁà@êõcù 6ÎõÃ…H1½Å|Ó–ûúúÆ¿3M¯««+¹m†òØÊsÆ¥óÑ£GV|ÐVCàÍ»}û¶ýŒñŽí¾ß¹sÇœ8q¢´|ró”z_Ÿ#¹}B¬íë5VÖk×®5Ïž=³ñqœ²Fp¤¶+D)ÞS@¸„ú !„³@€,_¾Ü|üøq‚˜ˆ­y(ÃéŽÅI‡ÿáÇì‚{ýúµíèʶC€lÞ¼Ù¼yó&9ÜÛ·o­ÁSeè¥ÄÇHä–-[¢×kJ8¤®ñÈ-ß²º*‹#Ç›•>¥1ºëã3FeŽñ= EoOYøØ}A ¼Ôz ]?–¿P™ùi$\H€Ó[Ì7q1¢í„cOOHn›¡<¶òœq^ÎyñâE´\*°Ÿ1Ä1¨ñŒyާ PžR({Žäö ±¶[¬×Ü~‚8ýA©X»Âƒ×…ixB!þ„ϸ½ÝÆ÷Ðô²ø)ó;›XœuFÓ‡‡‡í4‡ªé M ¦÷8#F÷˜òR7>ć›êÑ„™ HU]M¶$”昘I¹oêo꾨sýC7'ÞÔç º´ W‡uÚfγ+Vÿx,/\¸TÞ¤!Åè>÷·ûïö»<Õ)ŸœzÏ}.ÕírÛ.Þ¦Hr?ºAŒX]øûxVtÿ§ƒCÔP/1”Bˆi.@è|£ ±Pô€ßT”{ æNûb,Î\Èàà ! -toZ€°¶€E²M ÔøšöH0Õa2×€„êªl ûR¯•>¥á!(ŽÈú‚Ø}SLj‹ÝM XþBe–ãIImÁµÿ£G¶Ô6sž]1a1vÝtÇx>8×M!ã;^÷}2Hîs©)+kŽ Yaü÷㉵«âíW!Ä  ,V¤ÓĘ¢a4Ò?ùÙt ,"Fßý¹»¡kT½+§››Mzbk@úûûmç›rФ©\Ü\ G¾œÇ‚übTçgçÄ—z<ç-Xtæ¤Úù¬X]¹·XQï­¼+>¥ùsÒ“þÔ¹Ø}3â¡ÅE±û¢IË_.a\¸R–o'wîÜiËVÚfγ+Tÿ.Ž1UEÑ1ha¶,üçÙÇ30µ ´"@BÏ‘*ꤡìx¬¬) ÓÕÊÚcU»".'i#Ä'„b \Û¼å„]F¦é,‹çѹ0€sx'¿›.Qu ·ÑI`˜•M‹ŠÅ‰1Dç{ VÌ#ûû')çcغ9ݱ2fÄŸü±ŸQ>òU|ÛPN|±ãu~ïÅýÖuÁo-°h6µ|sŒ¤”¸x“NÊï€T¥#¾ŒªvFaìº)%¬Mð§Åî›X]¹re|ªJê}Ѥ‰å¯ Îa1Óµ¸¿coÁ*R•ïØ|ç¶ÍX¾ë>güx0˜ z0‚O¸ÑÑQûÿ|÷Göcm zŽTQ' Ué •5õHý¹û…Á?žX»"®ÎÎN{œ·ai –BL²ÁËÚ„b¦÷€‘B!Ä4 B1›Àè¶Þp$„BH€!¦1þ[‡ümºÆºVèGþþeÞÎkOeš…BH€!„B!„ˆB!„BD!„B!"„B!„ B!„B !„B!„B!„BH€!„1JÃ4K‡B1#gÕÖ®ŽšmîܹfáÂ…fÿþýæåË—m+¬'Ož˜;vØÖZ°`9|ø°+Íny¥–'ùÌ)ÿVâóÙ¾}{0¾T>|hÖ¯_oËpÕªUæÖ­[ÑöS§mÅê Î;gæÏŸo·³gÏfç-^Æ}uÊÒS7>|0»wï6óæÍ³Ÿß¿_«L$@„Bˆi @º#S݉ú×øñㇹ~ýºY²dIÛDÆÍãÇÍŸ?ÌÏŸ?ÍÉ“'­‘ÛjÞSÏ¿ÿ~ÐÐͽn,>ǽ{÷ÌÖ­[ƒB)…çÏŸ›eË–™§OŸÚïŸ?6ÇÏŽ'å¼X]ݼyÓlÛ¶Í|ýúÕn,ö¥^+5¼ ÚöÿˆÙýë_æ÷ïßv»xñ¢Ù°aƒˆB!’¾ƒxÑ¢EväÆ÷ïß³®qãÆ ³wïÞ¬8Ïœ9c=Œ”_»v-¹ð0nñ¾L–Ù¸q£ùòåKc†K,> ¬V¯^mG•[ ûöí3wïÞm9ýu ´b]!œ>#²R¯•>¥!Ž;6îMá3ûRï>#~V¬XaóˆþêÕ«ñcUÞœÐ}Á¹¤qéÒ¥fΜ9•yZ³fy÷îýL["œó4Ñfh;~z«ÒÊCˆ²´‘ŸXû©“†ª2 •ã§OŸl»Ç;Cœ»víšà‰ûõë—9tè ËàÉ¥K—&¤ áºuëìñ•+WNð !„ ÞÞ^³gÏ;¢Ìhæ‘#G&Œ§Ä‡'/5ÎóçÏ[£€ã‰©`L–„ka˜†Â¹)U:†Œ·œ:uÊ\½z5˜ÎÔüR/”ñTb]a"J|¾Ôk¥†Oig§OŸ¶môÛ·ovC@³/G€`ø7é¸|ù²Ù´iS0|ì¾ ÌÁƒƒ€géöíÛö3Æ;F´û~çÎsâĉÒô–å'”‡¨¥†íÂ… v_6”RŽÅ2‰•ãÚµkͳgÏl|§Þ¾(¥¾ýº÷Ó¶xñbëÉ„Kèy(„BH€Ô Ë—/7?~œ &bkÊðGºcq2%ˆyä¹¼~ýÚeaÛ!@6oÞlÞ¼y“îíÛ·Öàõ ÙÜøýݲeKôzM ‡Ô5¹å[VWeqäx³Rç´3FÔýc|ÆÏ ¾Ç¤èí) »/ƒQãÑ£GæÀö3†8µóO ¡Üôš&ÈTx@ªêj²= ¡4ÇÄLÊ}Sçx÷ùÆègtŸ¶æþ»ý®Œê,BOIÃ_ýe= þ2¯dSϧÜrÄûÁt=Ú†I±rö÷Ñn»»»­¨Á«‰'O!„Éèàéx}£ ±Pô€ßT”{ Ö€øÆu,Î\Èàà • -toZ€°¶€ÜM ÔøšöH0½d2×€„êªl ûR¯•>¥á)Ž‚ûØ}SÇpŽÝ9mÏÓôºººÆ¿3Ë}o§)ó’¤xNš ±räøÐÐGÀ?ž˜¤(¦i+B!„HFÏ¢g Œ):m¦høçõõõY£…iÀè»?_:tª·`ÅâtsóIOl H¿5(ŠS—Ú)@FFF*7Ñ/ç± ¿üÅu9ñ¥Ïy i€v¾+VWî-VÔ{+oÁŠ…Oigþ:ļ?u.vßÄ gDhqZRì¾ÈiÈ~a»µBüç>ä~LMO]ÂBqÖ}øk@RÞ‚U' eÇcåH¹øk8˜®æÇãêžzwuï'.'\ Ä'„BH€d‰L'À8`D—‘i ”âytèLÝà^±900¼†Ûè˜1ÌʦEÅâÄØÃ ‰½+æÈýý“”ó1lÝ<úX3âOþØÏÈ*ùòç´çÆ;^ç÷^Üï€Pü •SË7Ç0M‰‹·¥üHU:Bá˨jgÔBÌMãééé™0U-vßÄÊèÊ•+ãÓƒRï‹Â>玎Úïüç»?²KOÝzÆàw¿÷ÂÆgÚ`uÒP•žP9ÒÞiç®îÆ~<Ô3 ×ñÚð +¾‹¸:;;íqÞ†¥)XB!f½B!„B !„B!„ˆbvâ¿éÉߦóµ§2ÍB!„B!„BH€!„B!$@„B!„BD!„B!"„B!„ B!„B !„B!„ˆˆb:ÓÑÑ1ë®;ó4“Ò0Ò!„ 5âU[»: ¶¹sçš… šýû÷›—/_¶­°ž˜Ý»w›yóæÙÏïß¿¯•O !„) Ý‘mjèþ5~üøa®_¿n–,YÒ6BGûøñcóçÏóóçOsòäIkä¶š÷Ôóïß¿4ts¯‹ÏqïÞ=³uëÖ PJáùóçfÙ²eæéÓ§öûçÏŸÍñãdzãI9/VW7oÞ4Û¶m3_¿~µ‹}©×J /ãjêò’snSmsºÖO“Æ?"í_ÿú—ùýû·Ý.^¼h6lØ "„bz ”}Ä‹-²£x4¾ÿžu7n˜½{÷fÅyæÌë `¤üÚµkÉ…‡q‹÷e²ÈÆÍ—/_ëDcñeµzõj;Â٪ٷoŸ¹{÷nËé¯c,ë ñàŒMà3"+õZ©áSÚ騱cãÞ>³/õ¾á3âgÅŠ6ƒ¯^½?VåÍ ÝœK—.]jæÌ™­ªë§ä¯Š_¿~™C‡Ùô1°péÒ¥ÊQýbz‹ù&o‹/6ß¾}›Ð&؇€Li›¡<¶òœñóÁà BˆçXkÖ¬1ïÞ½³Ÿ¹ ï¼{ܧܯ~¼Um %Oe”µòk#uÒPÕCeýéÓ'[Ÿxgˆs×®]¼Ÿ±v…'lݺuöøÊ•+'x„BÌBÒÛÛköìÙc FÖŽ92a2%>v_æàÁƒÁ€ÔëÇòlœë‡ bz‹ù¦-÷õõgš^WWWrÛ å±•çŒKç£G¬ø ­†À›wûömûã#Ú}¿sçŽ9qâDiùäæ)4À³…0l.\°ûêÜ·)m·X¯±²^»v­yöì™ã”5‚#µ]!JñžÂ%Ô !„˜dùòåæãÇÄDlÍCþHw,N:|æ4çòúõkÛÑ•…m‡Ù¼y³yóæMr¸·oßZƒ§ÊÐK‰‘È-[¶D¯×”pH]ã‘[¾euUGŽ7+5|J;ct×?ÆgŒÊâ{ŠÞž²ð±û‚0x©õº~,¡2óÓH¸)¦·˜oâbDÛ Çžž300Ü6Cylå9㼜óâÅ‹h¹ T8`?cˆcP;€1ÏñTÊSx(Gwò9æI­›†²zÍí'ˆÓ”е+¼1x]˜†'„âo @øŒÛÛm|Mÿ(‹‘2¿³‰ÅYg4}xxØNs¨š®Ð´azOÊcF÷˜òR7>ć›êÑ„™ HU]M¶$”昘I¹oêo꾨sýC7'ÞÔç º´ W‡uÚfγ+Vÿx,ñ$¤@š1úÝçþvÿÝ~—§:å“Rïýõ—õ€øk@Ê<ÁMõ ¹mïS$¹HŠÕ…¿gEww·5ÔKÌ#%„bš :ßhC,= Å7å^ƒ¹Ó¾q‹3×288hGÈB Ý› ¬-`‘lS$5¾¦=Lu˜Ì5 ¡º*[ÃÁ¾Ôk¥†OigxŠ#²¾‡ vßÔ1âb÷E“$–¿P™åx@RÒE[píÿèÑ£-µÍœgWÌBXŒ]7Ý1žÎuSÈøŽÅ}o§)MʦÚ.LJ††¬8þûñÄÚUqƒö+„b =ÓibLÑ0éŸÇül:P\üÀè»?w7tª·`Åâts³IOl H¿íÜŠS—Ú)@FFF*7Ñ/ç± ¿UÅu9ñ¥Ïy 9i€v¾+VWî-VÔ{+oÁŠ…OigþœtÄƤ?u.vßÄŒ8DhqŠLì¾hR€ÄòW… G.G€”åÛ‰Ç;wZ㲕¶™óì Õ¿‹‡cLdQt ZX„í ÿyöñ Lmu ÅñÖøk@RÞ‚U' eÇceM¹øk8˜®VÖ«Úq9±H!>!„3X€àÚ¦£bD—‘i:Ëâyt.L#à^÷è¦KT]ÃmtfeÓ¢bqb Ñ9ÆÞ‚óäþþIÊù¶nNw¬Œñ'ìg”|ß6”_ìxß{q¿µ@]ð[ ,šM-ß#)%.Þ¤“ò; Ué…/£ªQG»nJ küé@±û&VFW®\Ÿª’z_4)@bù«‚sX`Ìè:÷wì-XEªòýàÁ›ïܶËwÝçŒ3aC/Fð 7::j¿óŸïþÈ~¬ Ô½·0øÝoì°ñÙŸªYE4T¥'TÖÔ#õçî#üxb트:;;íqÞ†¥)XB1éD!fxøI!„BH€!D[Áè¶Þp$„BH€!¦1þ[‡ümºÆºVèGþþeÞÎkOeš…BH€!„B!„ˆB!„BD!„Bñw Ú´iÓ¦M›6mÚ´iÓÖÎm\€!„B!ÄdðÿÝÞÌÖ’|5ñIEND®B`‚Multiverse-multiverse-0.7.0/charts/mono_read_bar.png000066400000000000000000000544441174000617100226430ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxXëIDATxÚíÝŒUw~üHUUUUUUªªªTU¥ªêUUm²Ùl6â@f ¥(ìâØÙﺌùå˜àµ³…ydoÝ5ÁY3ÅYƒ“xãeíé.‹]³ËމƒÑd¨›}0<F˜YxÀ²Ç£¡|Ÿó9øNî 3wîsïÅÌë-}4÷Þsî=g¾÷Ü{Îë~ÏŸK""""""-ÊÏi‘Ù—ÂÏýܸªwùx¼—×Ãô&>ïßý»7å¸1l&,ÿǨ¿ówþNúûÿïçm°råÊtüøqË ˆˆˆˆyi QõWuÍxñØdã΀L¬øÿá¤íäs#""" RãÆöêÕ«¯﮻‰üßÿûÓÝwß=îñÿøÿ£ePDDD@¤Q€ü³öÏò îRâö?ù'ÿdF$2<<<îñØ%Ë2("""3 “ ûú׿žþå¿ü—éïþÝ¿›þõ¿þ×é‘G™ôuOŸ>¾ò•¯¤OúÓù†UŒÿþÑ?JŸûÜçÒ_þå_^3þk¯½–ºººò×þ{ïïåãÿ‹ñ/òÇŽ9Rõ¼Wš¿jv…™ØÇŽË­ÿ·ÿöߎý±A½|ùòtèСBæ«<ø‡8n¼¯}íkU½—õÌg#Ó« Q{ö짯¯¯ª¶oå²Ñèôêý–?Ó™,õ¼·O?ýô¤Çœüûÿïóž—³g϶l™© wÞyç¤?þø¸çÅæ?øÿ êüx~l UëÖ­ÓÎûtóW+@b#.6@+»qãÆ†ç«”Å‹O:ÞdÏŸ¸±YÏ|Ö;½Z–¹Ï|æ3ù߀g) ,È œN7V-N¯žÏáûï¿?îñO~ò““B¢ž÷ö¶Ûn«øœúOÿi:uêTK– º2{öì|£éÿøÇ=þ‰O|bì9ñëqürZyâ‰'Òèèh¾ëMüb9¥Äýò׊ҿù›¿IçÎÛx-ÕÄ_{뙿jÛeâAÒñÚñ«qü+V¬7,ÀÕè|íÚµkÒvˆúÔ§>5å<×;ŸõN¯Öeî©§žûuÿ½÷ÞËß×Ò~iØTÓiõ²ÑÈôjýÆgaíÚµãß½{waË`|ƶlÙ’Ïddd$=øàƒãž=:åiÖ2!"""R7@~üãmÌLµïzìR>,v{©”%K–Œÿ‡?üáØ°ýèGã†Å¸Î_µí²téÒq㔟&uâëÏš5«áùš7oÞ”í·§šçzç³ÞéÕºÌņö?ÿçÿ|¬·!6Šãv<Ã*M§ÕËF#Ó«¥M&Öøÿ!½ð ….ƒÕÌKìÆUžf-" " u¤ü@⩞Çy”?~ñâÅŠó§jñKïÄS•6:Õ¶ËÄÿ£RMœjæ«R;LÜØ¬ÔÞÕÎg½Ó«g™ûêW¿šßþìg?›ïf·ï¿ÿþiß‹V/L¯€Äµ@&;.ª‘eððáÃé·û·ÇŽc™ì99iÖ2!"""3(÷eŸnã(Ư'¥”ï~UÍFÊtãWÚ`ªÕlHMœ¯Z\oF»Uû¼jç³ÞéÕ8!Aù²·KAWšN«—F¦Wk›LÜÝ)6þò“Ÿ² N|íj—Ûf-" "2ƒ2ñÍø³<ÕœîWäj†ÙÒŒù«vCjº¶«uƒsºaõþú\ï|¶²$R¾;QÜ®¦­Z½l42½zÚdâ._qœIË`œ-«üyq VÑí " "2i~ó7sÜÃÄýÌ_|ñÅqÃ˯w#®Ç€ ‰óL7 óçϯkÿûzç³ÞéÕû¿¿ôÒKc•ïnÔªc@êA³Ž)åÍ7ß¼fX|&}o§êùŒÓùVj—f-" "2ƒ2q£)®PÚÍ#þÆý©68ê݈ûë¿þëq»rľ饳`EâìAå§dxæ¡8ÛNéÌ;OÓûµŒ8øvº3Mœ¯xN´g$~޳}ÅéXc~‹H½g ªw>[u¬FÆoõ²ÑÈôêý'žö¶¼¤Þ÷6Žû(Þw¿ûݼ£túã©æÅY°D@D¤<ôÐCUí ã±!‰S‚NÜ£Òø”鮽§O-jþî¹çžÂæ«Ö}åkùÅ¿Úk0Ô;ŸõN¯UiDzQïôêý‡—÷ÕóÞ–Î46±¾ð…/´e™‘˜¸zs\7 z<¢G¢Ô3÷ãñZ®&]í†ã™3gÆ] =ÆùÇÿøç½¥S¢–'zNb^þÕ¿úWyJTü’ÅFZ‘ó¿ÇÅÛâìCÓx[š¯óoþM>nl ®:::ò³;MÖv´ÛæÍ›ÇÚ þV{êzæ³‘éµ ­^6ê^#ÿãÄž‰‰§Ô­ç½ž‘ÒøqÊã¯Úö.z™¹‘200V¯^æÌ™“æÎ›zzzÒ… Æsâĉ´víÚÔÑÑ‘–,Y’žþùН¹}ûöÔÙÙ™WoooáÃÛ==©3ëׯO‡NW®\I###iëÖ­9HJ9yòdZ¶lY:xð`>NàäÑGòõvïÞº»»ÓÅ‹óZµjUþXQÃÛ==)0ŒÙ³gÝðÁ§íñ(OlÌŽÝÛ+W®,lx»§ùêW¿:îþ]wÝ•¾ô¥/)¥”RJ)ÕÒš¸]ú±Hôt”÷€Ì›7/õõõ¥E‹å»iÅ?yéÒ¥)Ÿ»ibÊA5¼ÝÓ› _þò—Ó~ô#¥”RJ)¥ZZ{€Ä±·Ýv[:{öìØc³fÍJ=ôPÍwÑzøá‡Ó¦M›¦|bÊ{TÞÎéÅ\ª‰= CCCyïI,ñ×}÷Ýwß}÷Ýwß}÷›}ÿc #GޤåË—§ãÇ_ÓÃð(% =!z@ô€(¥”RJ)= ueÿþýéæ›oNÇŽ»fX”= •6Ð';¦"+jx»§ J)¥”R @ÈsÏ=—ŸZ7Îv5YâôØí*»cmÞ¼yÊ]˜Jg•гeU:ëT½Ã[==QJ)¥”RR`bƒ~²*ÏÎ;Óüùóó]¯6nÜ8î ôÉŽ¡ˆkiTº®F#Ã[==QJ)¥”Rr¥Òñ 7ÂôD)¥”RJˆˆRJ)¥”¥”RJ)¥DD)¥”RJˆMyQJ)¥”R @@”RJ)¥€€(¥”RJ) â ”RJ)¥DD)¥”RJ€ˆRJ)¥”R"¢”RJ)¥Däc[?üaúÞ÷^Éþ¾’^yå•ôƒ¼’¾ûÝ¿­VªÝ»ÿ¶¾ÿý¿­={®Vܾ:ü€¶UJ)¥”Q×V ã·;¥ï|çj[ýÅ_¤´dIJ¿õ[)}îs)ÝrKJ·ÞšÒ¾Òí·§tÇ)ÝygJ+W¦´jUJkצô{¿—Òïÿ~JwݕҊ)}éKÃÚV)¥”R @¤Ý5ôÐCih÷î444tõoÜøá4ôµ¯¥¡GICÿ㤡¯= mÙ’†þèÒÐc¥¡?þã4ôo¤¡mÛÒPooÚ¾ýêýž=@”RJ)¥DdÒJ7ß|u ¿Ñ-ý¸ÿ»¿›BÒ¾êîþÿÒ·¾5œ†‡‡Ó®]ÃY §®®áì­ÎÛàÎ;‡³q†³vÎÚi8k§átÏ=ÃiÆátß}Ãéþ`8mÜxõþš5ÃÙr:œ¾÷=»¯)¥”R" 5äŽ;>H/¼ð¸º¿Pög…¾ùûáËZ)¥”© ¿ó;ò÷ Tø‡ ¢”RJ€È;wŽ«}ûö€\×µcÇÿÉþÏ£éèÑ£éùç¦o|ãhzüñ£iÛ¶£©·÷húŸÿóhÚ¾ýhz≣éOþähúæ7¦'Ÿ<š=ïh¶ŒMO=u4k÷«÷cxŒß×w°°ù;üío§¡ÇOC{÷V>^ëÑG¯¯µuëÕãµâجx^éX­¸þþõôú7¿i%¬”R rc¤|C?ê‡?ü!€|Œrÿý[òö*ÕóÏ?õ۪U24Ón1ü¶ÛR˜¢æïh‰´fMÊò™Œ7*&úÅ/–zJé¿þ׫3Ï»ûî«3¸zõÕa¿ó;é?ø+a¥”ë ÷Þû?Ƶ]#9õÀi¸·7?H~øå—ÓðýQÎfh¸«+ gÎ>ÃÙ†ópöÆ gËÃëÖ¥ál¦†7lHÃ_ùJ¾ÿþ4¼qãÕû٠ǸýÄ J)¥D@äÚzç¾ûRz챫3øã§ôßÿ{}Òe[úG@D)¥Ôl=¶:Í™3'Í;7õôô¤ .L:îªl8kÖ¬i_sûöí©³³3¯ÞÞÞ‡·{z 2³òÐC‡²×ú‹±jäÌkÍÈÿ“=þÄOŒÕ3ÏHË—/OgΜ™ ±1?888v?n\ŠÞîé€Hó²;›é|p¬ž~úi¥”R7:@ÿè=‰!þ¶ã~«RËüµ <ðÀuÑþEßïêi @꿟mÚÔ€Ô:ëÖ½×t€ô÷÷×ýþžÚ±£é‰köÜhŸ÷Ýwß}÷'¿ÿ±È‘#Gòݬå |œ>}ºj€èÑ¢Dˆ_È׿þVúoÿm8íÝ;œŸZy×®á|ìêΖŸáì{n8›áìs8œMz8ƒÞpÖVÃiÆáô•¯ §ûïN7gËØÕa+W§-[Þòë¤RJé™<û÷ï϶]oNÇŽ›´‡a²ªå˜Œx¬¨á힀€È‡Jë×§ôâ‹…ÍVúÚ׆l(¥€\›çž{.[É,I'Ož¬jü‰ø˜x¿tV©8•o¥³NÕ;¼ÕÓQJ))0µöpLH\K£Òu5Þê退€(¥€\G‰ ÞÈÓú²jÕþ´yóæ±Ú±c‡…6Ô`öE2˜½±±‹qþ÷OÿôêcþçWëé§Óà·¾uµ²7~ð™g®V¶œîÚ•³/ð¼â~ ¯ãôØJ)i:@V®üѸùŠ«´ÛX¸1Ö ÚU)6T_ßÁôä“GÓÞ½GÓÑ£G³·õhÖþGÓãMÛ¶M½½G³åñhÚ¾ýhöÿMò'GÓ7¿y4ÎŽGÓÎG³åühöY¿z?Æyê©ÿ J)¹‘2»|t=Œ¢vOøË^ÀF´CéÜ%~ÇÅ8wß}@”R"r#d8&þä“Åm±fã`@@nT€|ï{ßW6•ëvÝ ”¹N²jÕߤgžyf¬úúúD)  R /e€ßÉþéRíÝ»@@¤*€Ü~ûÿ;®Ý¾þõ¯ˆR @@¤2@¾™=V>ÿëý/QJˆ€€€€(     ¢”Q @@@@nh€ÄBó gŸ¥¢¾L†³q@>nõ­o ¤ÿý¿ó‹ç¾øâ`úÓ?ÌÖƒéÏÿüj=ýô`6ÎÕú‹¿LϾZq?†Çø?øÁKÚ@@@@@DµfÝëjm     ÒÆøÖ·Òà /ä= ƒÙ#–Á¸ÆÓàŸÿùÕzúé4ãDeí:øÌ3W+û~ܵ+ f+¾¼â~ ÏÆÿËìõDˆ€€€€L¾nر£¸v»Ž/R;òíoN{ö»ëÚ÷¿ÿcê¿L.dÿÐÆÇêk_û€ÈŒÈSO½ž}öÙ±Ú·oß ÷~6cÝðøãGD@@@jHùü=ôÐC 3 × /°«€ˆ€€€€´ û|\OÃ~ðæäã²nêÖ <2ž{î¹±z1û¹î× 3 Y®NsæÌIsçÎM===éÂ… UŸ,Û·oOyõöö>¼ÝÓ:³>[ã>|8]¹r%ŒŒ¤­[·æà¨vøÄìξ…»»»ÓÅ‹óZ•½S»KßÌ o÷ô@@@@@¤À4fÏž]÷ðؘs,—·WÆ;XÐðvO@@@@@@ ÌÁƒ+öpL7¼££#GJ9Xâ±¢†·{z     RPNœ8‘5èméìÙ³u Ìš5ëšÇÊ{LÞÎé•/då¹+[k å½'ùŠ2ûÛŽû­ZÉÔ2­È<ÐPûtu5 ‡ªyþººFZz—·ŸmÚÔ€Ô:ëÖ½×ô•LÝËÛ©Ø i2@vîÜYóümÙr¶%©wy{«¯¯%©uþvì8Õt€lÛ¶­¡õC+Ö q¼h;×Í¸ß €Ä:µÖù[±b´éë†Üpïg+²gÏž¶ük€9r$-_¾<?~¼®áz@ô€èÑ¢Dˆ= z@ô€èÑRUöïߟ}?ÝœŽ;V×ðéŽÉˆÇŠÞî退€€€H‰ §,ÉÞ…“'OÖ5|â.L¥³JÅ©z+uªÞá­ž€€€€€€˜Ø Ÿ¬j>1q-J×Õhdx«§      ×Qâ…7òô@@@@@D@@@@@@@@@@@@@@@@@@lÊ€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ˆ€€€€€€€€€€€€\ÍÀÀ@Ö€«Óœ9sÒܹsSOOOºpá¸q¶oßž:;;óêííö5§¿Ñá힀€€€€€Ô™õÙçðáÃéÊ•+idd$mݺ5I)»³oÕîîîtñâżVe-¿»ôM;I¦¿Ñá힀€€€€€˜€ÈìÙ³ÇîÇÆùàààØý¸½2Þ‘)2Ýøo÷ô@@@@@¤À~£ÃÛ=== z@ô€èÑ¢DÈõÙòƒü`¬öîÝ«Dˆf삱±\~ÚÜóçÏçíÛ·¯ª×xî¹ç²7aI:yòdųLÅ4&;KÔÄ]˜¦¿Ñá­ž€€€€\ÿ™¬w@@š ¤ÑÑÑkÇ.\ØÐ.]å‰kcLuŒÉŽ¡¨4~£Ã[==)ÛŸ µRo↭L«§      eÞ¼yù5+b·«8x:êܹsY£Ý™æÏŸŸ@@@@@@ =dª]¨âË@@@@@@¤Ðë€ÄY›â òØ5)*n¿þúë”      ÅD@@@@@@@@@@dFä'ÙzálßyçôÎþýélýë‹wî¿?½“½ö;›6¥w²õö;›7§w|0½ÓÓ“ÞÉ>{ïdëwy$½“-ïïlÙrõ~ ËÆý«§Ÿë wgßúqåîF¯„.    Ò@š±n8úøãr=äž{îÃF#WB™6qá¼Ã‡ç·K=—.]J6lÈ>Üß%) åW/¿×qù¸ä‡ðÙK>6VßÉ6*¤Í¹xñb~;NÁ»ÿþüö«¯¾êùØdâºáO³ïi#@^ÌÖ===ùí[³–+?dÑ¢E¤      Í9 ïåË—ÓâÅ‹óž… ¦ÑÑQRæD@@@@@@@@@@@äÆH___Z°`Á¸ƒÎ—.]š~úÓŸ’€€€€€€{údW>HÝÝݤ      Å$:üñÇóë~”äý÷ßOsçÎ%) åè˜xÝ×B2{öìôá‡^Ž .¤ŽŽR⛯ÈÞ¼óçÏç‰k;v,‡Éã) 'OžwõóòºxñbU¯QþœÉröìÙl¥´>ïQ‰ŠÛgΜ©øšÛ·oOyõöö>¼ÝÓ™±§á „DOÈœ9sòª÷¼S$zRb# zW¢vîÜ™½9·Où:»³oá8W(jUöNí.}30¼ÝÓq!Â2@&;˜= 3Ubc~pppì~Ü^ï`AÃÛ==gÁj"@î¿ÿþ¼×#Nõõd¶¡M•ØM+Æ+%n—ßèðvO@@@@@dƤRODQy÷ÝwóݺJljÄí8轖׉ƒâ‹Þî退€€€ÌX€,ÉZ/.:ØL€¬ÍZ=z@ÊYk˜ØR¾•ç®ìÛohh(ß}+_QfÛq¿U+™Z毉•L#í7ÒÕÕt€:t¨æùëêi @ê]Þ~¶iSKRëü­[÷^ÓW2ýýýu/o§bƒ¦É‰ïéZçoË–³-H½ËÛ[}}-H­ó·cÇ©¦dÛ¶m ­Z±n¨iþúûßh @Y¿¶ ±N­uþV¬múºáÀu/oïõô4}Ýðl¶àÔ:­Èž={Ú²ý×r€¼òÊ+ùáÕžñª€LÖP©‡`²c*â±¢†·{zz@ô€èÑ¢Dˆ= z@ô€ÌØ©NÁUëñ!S$€Ç}”R~¬‰Ï+U*.†Xé¬Sõoõô@@@@@¤ì ô©jºã*!¦<§OŸÎw¹*æ7nÇc•à×Ò¨t]F†·zz     r¥Èá¯Ç退€€€ˆ€€€€€H«2::š-ZTÈ1       S~}Žz©ú ô}ûö€€€€€€4 z9@@@@@¤e‰+¡qBióꫯf vk~=ÂRéêç΂      …¤ÒÕÏ @@@@@@š¶ –€€€€€€€€€€€Èyz† €€€€€€K—.€€€€€€j΂ÕÑÑA      Ò8@Jgº*nwbuvv¦]»v‘€€€€€€· –S퀀€€€HÓ²`Á‚´iÓ¦töìYæäŽì?c:åëìξ…»»»ÓÅ‹óZ•½S»KßÌ o÷ô@@@@@f@ª¹aéú EäÁœ¶Ç£<±1?888v?n—ïÖèðvO@@@@@dFdâE§H­×™ óæÍK}}}ù®\sæÌÉÿÉK—.Mù:±›Vô””·Ë¯ÊÞèðvO@@@@@dÆî‚ñ ~ìUÊùóçóÇöíÛW@âñøRM###éá‡ίARËë”c¨Ñáíœ^ùBVž»²o¿¡¡¡¼÷$_QfÛq¿U+™Z毉•L#í7ÒÕÕt€:t¨æùëêi @ê]Þ~ß-H­ó·nÝ{M_Éô÷÷×½¼Š š&dçÎ5Ïß–-g[z—··úúZZçoÇŽSMȶmÛZ?´bÝ—¨eþúûßh @Y¿¶ ±N­uþV¬múºáÀu/oïõô4}Ýðl¶àÔ:­Èž={Ú²ý×r€Ä -\¸°€Do@À£üµ£'Dˆ= z@ô€èÑ¢Dˆ= 3¬$Ð0@Š:$ÊžJè“S5¼ÝÓ™±‰ã3â€éØí*~¹Š Þ™µÚüùó Hl ÄnW¨ø‚Þ¼yó”Ï+U*v «tÖ©z‡·zz     R†ƒ©B/ƒzϪ51±?q€&v½Ú¸q㸃Ð'?®¥Qéº oõô@@@@@¤,±ËP\0p·_ýõ–]?¤Òñ 7Âô@@@@@D@@@@@@@@@@@ä†Hœ‘*.XÄ•Ð@@@@@@*féÒ¥ãÀQ^µ^ ]@@@@@¤bµ^ñ\@@@@@¤®èå–$N¹Ïi:@^}õÕ¬Ánͯâ-     ÒT€LutgÁ¦„>U9>@@@@@@ ˆ€€€€€€€€€€€È ×^{-ûn¹9ßå**nÇc      …äðáÃS„!     R(@¢·ãîì:þüØcq{uöFÅ5B@@@@@@ Hìr5::zÍã—/_NsæÌ!) ###×<() K—.Íge:wî\ºråJ^qûެeb÷,šOuúO~òRbOÃЈގØå**nÀ€€€€€4 ¦¼×dº¬ÊZ½šñ¶oßž:;;óêíí-|x»§      @¤RöîÝ›o2Ýx»³oáîîîtñâż-»KßÌ o÷ô@@@@@f,@^z饴yóækïééI/¿üraùàƒÒòåËÓ™3g¦HlÌŽÝÛ—¢†·{z     3 ,H—.]ºæñxlÑ¢E…ä±lAÚµkWU=%ùÙ¸J‰ÛñXQÃÛ== J¸é¦› y­ãÇgoÂUïª5Ùð¸^IQÃÛ9½ò…¬¼ÝÓ™‘»`½ûî»ùzRBD ÔçΫû”¾åYŸ­‘>œ®\¹’Ÿ]këÖ­/r¸;ûîîîN/^ÌkUöNí.}30¼ÝÓq H–èýxíµ×²¼uìš Ñc±2Z¯€LL@$^ªÄÆüàààØý¸]>o÷ô@@@@@d’Äñ!±»T\!½H€JôLįöíL\ ðFž€€€€€€|”W_}5¿îÇtW&i SíUÏY°@@@@@@¦=}ª*âø ¯½öZ~‘ÀØå**nÇc      …äðáÃS„!     R(@¢·ãîì:þüØcq{uöFÅ5B@@@@@@ Hìr5::zÍã—/_¾..Ø      7@FFF®yþ‰ã;nºé¦±ÛSUiº°ˆÓï–nOU¥q@@@@@@ì‚      "     2åîXõ ) —.]ª å®O•íÛ·§ÎÎμz{{§}ÍéÆotx»§     2£RéìW¥êèè¨ù5'Ëîì[µ»»;]¼x1¯UYËï.}ÓÖ1~£ÃÛ==Ò™®J§ÛXñKþ®]» HlœŽÝÛ+ã™"ÓßèðvO@@@@@dÆî‚Uä©v§Hô¤\¹reì~ܮԻ2Ýøo÷ô@@@@@œ«‰™ìñJð™nüF‡·szå Yyîʾý†††òÞ“|E™ýmÇýV­dj™¿V$V2´ßHWWÓrèСšç¯«k¤%©wyûÙ¦M-H­ó·nÝ{M_Éô÷÷×½¼Š š&dçÎ5Ïß–-g[z—··úúZZçoÇŽSMȶmÛZ?´bÝ000PÓüõ÷¿Ñ€4²~m@bZëü­X1ÚôuÃê^ÞÞëéiúºáÙlÁ©uþZ={ö´eû¯åyé¥—ÒæÍ›¯y¼'{ó_~ùe= z@ô€èÑ¢Dˆ= z@ô€è) ,ÈÏx5ÙY°-ZÔ´c@â±ZŽÉ(¿Ñá힀€€€€ÈŒH¥SçÖzé΂uáÂ…IÏ5ñyÓßèðVO@@@@@@>Jœíêüùó×<~îܹ4wîܺOé;1qmŒ©®“Qëøoõô@@@@@¤lÃ7z:Þ~ûíüØ…¨“'OæéÓJ¶¨Ì™3§¥Ë·zz     Rv¬ÇT"|ÿý÷“€€€€€H¡§áÝ­–.]š÷ D-[¶,?žA@@@@@亽ˆ€€€€€ˆ€€€€€Èõ»³7*.œ7ñZOÃ+     R1÷ÜsÏ6&döìÙ¤      Å$®[qøðáüv©Ç#ÎŒµaÆìÃý]RâR~Q¾òÛq=ùóç“€€€€€€ ‹/æ·ã¼û÷ïÏo¿ú꫎bòb¶¦èééÉoßšµ\ù1 ‹-"iÎix/_¾œ/^œ÷|,\¸0ŽŽ’€€€€€€4             7@Ξ=›–.]:¶ VìzÇÜ_6      E䎬Nœ8‘ßÞ¸q㸃ÐWÇZ@@@@@@¤(€ttt¤‘‘‘üvœõ*àñæ›o¦ãǧ¹sç’€€€€€€ò‹Ξ=;¿_:û•뀀€€€€H¡éììÌ{<Þ~ûíóæÍË^‘&     R@b÷ü¸µÑBY†††²÷t)€€€€€H±§á-]|pI´äGY¶lY~†,BÒìdÖgk¥8à=*nŸ9s¦âs¶oßžïÕÛÛ[øðvO@@@@@@š”/f HlÄuF¢vîÜ™½9·O9þîì[¸»»;]¼x1¯UÙ;µ»ôÍ\ÀðvO@@@@@dÆ$ÎxU:ýîÄ*ê,X“½Îœ9s¦?6æÇîÇí•ñ4¼ÝÓ™±‰« —ƒ£¼â´¼EäþûïÏ{=®\¹’דنZïrg¾ŠŠÛñX¥c(âZ•®«ÑÈðVO@@@@@@ÊBŸªZq|Èt§ä½¦                  74@îÎÞ¨8ml³ŽÉsÏ=÷Œac"@Zu €€€€€€Ì€ÄY›>v*^¦¤ü´»Ëñ!     RøAèSÕìÙ³I@@@@@@œ†@@@@@@D@@@@@¤ò.Xõ ) —.]* 'NœÈmêèèÈOýû|iÅ9E¶oßž:;;óêíí-|x»§     2£RéìW¥ ,‘“'O¦eË–¥ƒ¦+W®¤ .¤G}tÊñwgßÂÝÝÝù©£VeïÔîÒ7sÃÛ==Ò™®J§ÛXñKþ®]» ȃ>8mGybc~pppì~Ü^ï`AÃÛ==» V+Nµ;oÞ¼Ô××—-Z”æÌ™“ÿ“±‹×T‰ž—è))%n—÷Æ4:¼ÝÓq¬&&zYâKytt4ŒŒ¤‡~8mÚ´©âø• ÔèðvO@@@@@@š˜è x”‰ž™ØR¾•ç®ìÛohh(ß}+_QfÛq¿U+™Z毉•L#í7ÒÕÕt€:t¨æùëêi @ê]Þ~?D´ µÎߺuï5}%Óßß_÷òv*6hš ;wÖ<[¶œm @ê]ÞÞêëk @j¿;N5 Û¶mkhýЊuÃÀÀ@Mó×ßÿFKÒÈúµ‰uj­ó·bÅhÓ× ¨{y{¯§§éë†g³§Öùk@öìÙÓ–í¿ qPöD€TÁdÇTÄcE o÷ôô€èÑ¢Dˆ= z@ô€èÑÒÄÄJìv‰Š/èÍ›7O¹ Sé¬Rq¶¬Jgªwx«§      -NtçÏŸ??ßõjãÆãBŸìЏ–F¥ëj42¼ÕÓë(•޹¦                  "     bS@@@@@@D@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@ä:Ϊ¬ÕgÍš5íxÛ·oOyõöö>¼ÝÓ&gïÞ½Ù±rZ€ìξ…»»»ÓÅ‹ó ´ì.}30¼ÝÓ&çƒ>HË—/OgΜ™ ±1?888v?n\ŠÞî退€€€H“óX¶ íÚµ+¿=@:::Ò•+WÆîÇíx¬¨á힀€€€€€41ÇÏÞ„;ÇîOɆϞ=»°á힀€€€€€41Ó§OW ¹¤|!+Ï]Ù·ßÐÐP¾ûV¾¢Ìþ¶ã~«V2µÌ_++™FÚo¤««é9tèPÍó×Õ5Ò€Ô»¼ýlÓ¦–¤Öù[·î½¦¯dúûûë^ÞNÅM“²sçΚçoË–³-H½ËÛ[}}-H­ó·cÇ©¦dÛ¶m ­Z±n¨iþúûßh @Y¿¶ ±N­uþV¬múºáÀu/oïõô4}Ýðl¶àÔ:­Èž={Ú²ýwC$À1YÕrLF“6dŸ¤{ï½7Ý—}šÖ~âiMVkáÒÚO~2­ýÅ_Lk²ZûK¿”Ö~úÓií/ÿrZ“=gí¯üJZûÙϦµ¿ú«iMÖùýž=gîܹiÞ¼yé?ý§ÿ”ÿýÝìÛª–ùû¾œ~õWï;oîËçkÙ²ßOŸøÄÚôó?¿6ýÂ/¬MŸüäšô‹¿¸6}êSkÓ/ýÒÚôéO¯I¿üËkÓg>³6ýʯ¬MŸýìšìùkÓ¯ýÚÕû¿ôKk²ê›Ÿ˜¿ùóç7Ô~nº)Ý÷Q»Eû­‹öúùŸÏÛmÍGí¶öSŸÊÛmÍGí¶ö£v[óQ»­ýµ_»z?†gãßü¿16ñ÷Î웬Öù»é¦ iéÒ ù|ÝrË}y›}âk>j·µy»ýâ/®ù¨ÝÖ~Ônk>j·µy»Íšuõ~ çtt,÷~vuuÕ½¼ýÞþÏiâEW—·l¹ø½ìõòåí£¶‹ågMYÛåË[´ÝTË[6ËçïóŸÿ|Íó×Ù¹>k·«ËÛç>·!k¯»ë^ÞbxŒÿë¿þùqïgésPÏò¶6ûŸîëìL÷f[è6lHë—.Í?«Ñnk¢íÊ–¹5µÛØòmUZÞ²6Ì—·l¼®ìñòù+µ[-ó·dÉÝÙò±!ûÌfïg¶ñ[¿uO¾¼ýmÛ]]ÞJmíöË¿|íò·cXŒ÷«¿úÛãÞÏ¥ÙÿZïò¶:Ú+[^îÍ6^bþ~Ù²k—·h»Òò–µÍš²¶ËÛ«ì³ã¬ÌÆ-Ÿ¿ Ô<ŸÿüÚô¿q_¶1roþ~.]º~ì;îç~ÍØgõj»­)û¬Æ2¶f¬íb™‹Ïo´íg>ó¥qïçoe[I¬îËþß{³e"æ/þV\ÞʾãÖ”}V£ÝÖ”­Êç/Ú/ö¨eþ~÷wïÊþ÷ ÙwÛÕå->«—·ø¼þígõêòö·ŸÕh·5eë†hã•ãÞÏøÛÈúõžXÞ²e6æ/o·h¯z—·ž¿dΜqë¯Ùx­ó7{öW²öºº¼}þó÷~´¬Õ¾¼ÅýÒº¡³sá¸÷3~X­wyûýßüÍtïù/W—·ìÿû½ìõ&Ý)[7T\Þ²q?÷ë¿>nþnÍ´PëüýÆoÜYüêòíö ¿°®îå-†Ç÷á¯ÿúçÆ½Ÿ_ÌPÕŽí?™!= """""ÇÈuÉŽ‰ÇDDDDDD Oé,X.\¨ú,X""""""u'®ýQËu@&fâÁxJ)¥”RJµªDfTj]èE»i7m§Ý´›h7í¦Dć^»i7m'ÚM»i7í """""""""""""""""" """"" """"" """""""r5³fÍ+©-iõêÕiΜ9iîܹ©§§']¸pAÃTÑn«V­k·Í›7§sçÎi˜íç3[ûwœïºÚrâĉ´víÚÔÑÑ‘–,Y’žþyRç27oÞ< 3MΞ=›Ö¯_Ÿ/oQqûÌ™3@äFÿ”Ú_އNW®\I###iëÖ­9H¤rî¾ûîôꫯ¦Ë—/çm÷Ì3Ϥ;î¸CÃT™½{÷¦•+WúÌúnkjNž<™–-[–<˜NãÇ•G}TÃÔ‘—_~9õööjˆiòÅ/~1=õÔSùº!jçÎéöÛo×0"VÒR)±’ž={¶†¨#Ñ"Óçƒ>HË—/Ïô™õÝÖÌ<øàƒz< ÊŠ+Òùóç5Ä4¹é¦›¬D¬¤¥ÖÄ/…z@jGÛ®]»òÞ$™>=öXÞ^>³µ}·Åî/ñãÀ-·Ü’ÿª*Ó'Ú¬¯¯/-Z´(ߌ«S_ºtIÃÔ±^xä‘G4D¹ÿþûóÏg¬¢ž|òÉü1™"±¯ôm·Ý–ïÃ*Õ/sQ .L§OŸÖ ÓäøñãéÎ;ïô™m o¿ývºçž{Ò7¾ñ QÅçó¡‡J£££ù.¦?üpÚ´i“†©1_þò—óÝÙdú¼ûî»iéÒ¥c놸­ç@@dŠ9r$ß-&6¥¶Ä¯\O?ýô¸ k™<ÑFåPó™­/ï¿ÿ~êììÔÓ$x”±;Lmô ~ ‰DHù1 ö*™$û÷ïO7ß|s:vì˜Æh Ž©î3êŒNҪęÖ&$P"Õ'Nñæ›ojˆÖÖ ""òÜsÏ姦Խ^[bèÒ©cc0ÎÓÝÝ­a|f›’8˜ºÔs»xÜwß}öɯ"qzìv‰ŠÝ±â”ÙR]^{íµ R}âŒWqÜGù1 ΂ roÄøEµ¸¶Ó~Ó'zât‹ÑVóçÏwýiÙò¶xñâüøò_öeêÄ.0ñ]¯6nÜè ô=Hqºq©>ñCAéÚZQqÛñ"""""""""""""""""" """"" """""""""""""""""""""""" """"" """""""""""""""""" ""ò±É¬Y³ò2Ÿ"""""Òô x‘7>Êkâ°ýû÷§;ï¼3Í™3'utt¤µkצ3gÎ\3ÞK/½”㔿Îk¯½–V¯^?>{öìtûí·§}ûö]3/ßùÎwòçÝtÓMiÞ¼yé‘GI—.]7Î /¼–.]šÏË-·Ü’¾ÿýï_3ßï¾ûnÚ¼ysš;wn>½x­x ½þúëÞp‘ë!S=¨øéOš®\¹2†„+V\3ÞªU«òñÊsäÈ‘–óçϧ˗/§‡~8?ðPž§Ÿ~z 6™'Æ-å•W^É»çž{r˜DÅí‰óó÷òû~øaž˜?¹Î2444öX ¤ÔK1q¼Ó§O_ó±ÑÃÊ{LFGGóÇ–/_>í|E/F)ÝÝÝ×Ìω'®™ÿ˜·¨ãÇ{sEDDDD>n™îñJÇ`Ä.P“íæ51” 6äàˆÇ'Û%,v»ªf~J= QñœØåkëÖ­éܹsÞl‘ %4DÏI¥”ÐP¾[V½‰c@|ðÁ´páÂq ˆˆˆˆˆˆÈ 8ø<†gâç @@D¤â–S¬<¾ño¤Ÿþô§“¿í¶ÛÒ믿ž¯Èâ×ÈØhyðÁkZ)N6Nür>¥|ó›ßÌ{^âWµ˜ÎC=4îWÂ'žx"ÇO Íç£Þvlįªñ?E=ùä“ùcÕ&v§¨ÔÃ1qx¥]C¦Êc=–víÚ5éx“Ý ÉØÐ¸å–[òÿ­ÒI¼nüR:Uâ}‰6nÇÓĶ øÆ<—ÏÛ é>Ÿ>O"" Õn9¥«»Äñ å+×èýˆn÷ø•«´b,ßE¢^€Ä´&B&Tªz¦SíJtíÚµù/¬åû˜WsÌÆ‘#GòÝ.b¤žáÕÎ_´9jýßßÿýüÑ©ùôÓO{'¦¿ØNÕv3¡dºeÿzùOÕ,ßEmà×óùl%@jý|ÎÄÏ€€ˆHÅ-§X9–ãû[—Ÿq&b³ªDbƒæ·rŠ Ýév_ªæ¬=ög–6lØï~‰_Ë5)í³óÐè1 ñÿÅÿY¾y¥³ì<÷ÜsùÝÉ“'ë^ï.#S7ñ~´SéÙh¿xOc·ºRâvé4¦“88¹ÒFxœµ'vÉ{íµ×òûÍôÈs.žsž9çÌ<ï÷ý¾ß÷'|ÅOø0X, À`a|þä'ƒ˜ì>`x\Ël8^èÿýË¿üKÄ}µ-î¿PâýÑÙŸþ韺Ϡ¸¸ØÚÛÛ¹À` fƒ¿™8zôèmûi]¸}óÅ`…òÏÿüÏÃ~N<7`° ƒ…Á kÊËËoÛ¯´´4o –ðÃ?Ø¢E‹­ÿßÿý_îA0Xƒ…ÁÂ`Åg°þæoþÆ zýWõWym°„ï¿ÿ~Ðzur€Áy`°ÂmûÕ¯~eÿ÷oüÇlÿøÿhk×® û¾çγxÀþë¿þËýphÿ¿ø‹¿°;ï¼ÓÞÿýÛöommµ{ï½×½÷ŸüÉŸ¸ýÿîïþέkii‰ûÜ£_<]5¡ŸA[[›‹¶üó?ÿ󀆂‚ûè£|9¯`<òÈ#ƒö{â‰'⺖ɜg*ÇKÄ`‰o¾ùæÀ>{öì‰ë³O网êñ’}ƒ×ë8á̵ݹsgØœ¯ý×u‘³®®®´Ý`°+†Áš?~ØÅM›6 ú?ý€þÙŸýYÜ&Fÿ¯€hû¯_¿>æ¹Ç:¿D –~¤ômßåË—§|^&Ožv¿pÿúcšÌy&{¼Dî¹ÿþïÿve¬=L˜0Á­“ùŽuœtÝ©/™çðÚµkƒÖÿÇüGX£”̵-**Šú?ý×m_|ñEZî 0XƒÃ`9Òý(<óÌ3ƒÖÿû¿ÿû Ö¿Z¾Þ6­Í›7[__ŸëR‹[_â´ü^úѽxñ¢]¾|yàÇÙchk=™ó‹÷s MÂÖ{«Õ/³gÏ´M†2ÕóÚµkWØÏAüÏÿüψçœìy&{¼Dï¹íÛ·Dg¾ýö[w]=ãm‹tœtß©/ÑçPÏBEEÅ õuuu¾ÝƒzÆžzê)wþBoo¯­ZµjÐÿ("Œ¡º'À` V ƒõÁ |YGÊQ·Eð6uËDÔ)SíÿÎ;ï l{÷ÝwmÓ¾©ž_¼ŸË´iÓí<Œ>ôýGŒ‘òy7.âç ×‘Î9ÙóLöx‰Þs2û·;-Ò¾^k¶E;NºïTŽ—ÈgÊû·³·ÞzË×{0žsQ7c0†êžƒ0X1 Vp¢r¤ÿSžUðúžžž¨ç¨á鑎¡–zèPöTÏ/ÞÏ%TG4Æ2pñœW´Ï!ôÇ4Úçïy&{¼dzȽþŸÿù× ¦×Ë–-‹y-Ò}o¤r¼T –ja…ËKLåljj²3f ä‘…ûŸÐœ¯¡º'À`œCh.I¬/ퟬùòÜ=Ï—p¬ý£ý $k¢âù¡=¯Dã‡âs‹÷ÿâ=Ïd—ŒÁÒ€‡à{Q¯½$ëhÇI÷½‘ÊñýLB»ãdnNŸ>íË=úÞñÞ·CuO€Á9‡Ð©Z¡Ám•ÆŠijÍÏÖPœ_¼?±>»d#‡~G°’=ÏtF°„àî.½Žç³J÷½‘Êñ’ùLB»$•çåÇ=¨Ñ†Áÿ§H¿?o À`¼Æÿýßÿ úB ÍóØ¿ÿ íÁÉçÉþHe2ËOƒz^JÈJƒ5~üø¤ò_’=Ïd—¬öƒ¬ îKWV2†g¨r°<œ:uê¶mz&S½¶‘"×*÷ísª{ È9„þ(¨Ž× ¡¿ZŽô…šìÔ‰'u5(7ÄE(hôUðýБ[­ä\ Ư¼?L”’{c =/ý>OA-{–Ôp}¯+Ù\ÉžgºF¦²ºïTŽ—¬ÆÐ²ÁQ¬d¯­ò®‚ÿoïÞ½.å•Ljt.Œ",ÀêÕ«ãÊÅÐ~~ACÆC»¢í/«ö†×ûu~‹/öí¼ÍUI$bo ¢dÏ3Ùã¥Ë`eâÞHöxÉj”I ÝáKæÚz#5CyÏ=÷d䞃rª>­º9ŠX)¢äE–´¬õ‰TÃŽ÷‡ñüùóƒ*¹kŸ¿üË¿tÑ+oÈ|0ùÒ¹üÃ?üƒ‹€‰j‰k~„ü{÷Ýw}åçŸîû{æ£n®5šÑftGç°7Xʵ***²®®®u#FŒ°Õ«W[__ŸëB\³f­X±"â{hÿPGÄRÝžÉãé{ `é¦RôK7‚þ¦º¬kàçû —eù¢WËgΜÉ+½Þ²tsç‡þ|ü>ËÇû{(¿Ï†µÁjii±‚‚koo¿-B$cåAFK‘,"XCÁ‚Bá0`544ØÔ©S­­­í¶mJú5XÑ H¸œ&­ók{¦—.ƒå¹÷|c>êæZ£ÝhFw¬Ý»w»Ò -JpW· L–¨î•+WFìbóFåi´a´Q{ÉnO÷ñÈÁ"oÍèF3ºÑLVÂa Ç`lÛ¶ÍÆïº—/_>(É=\“jIE«+•Êöt­>4£ÍèF3¬´#Z>V.,!„,#‹ÖšÑft£Ý, ý÷èF3ºÑŒn®5 Á¢Õ‡ft£Ýh&‚òÊ`A!„ƒ…Á¢õƒn4£ÍèæZc°9Xä- ÝhF7šÉÁD°hý ÝhF7š‰`a°0XB!Ä`Œ¬-[ŽÛÂ…½v×]šò{å•s´~ÐŒn4£ÍD°0X¬diS¦D$ý÷hF7šÑfr°0X¬d V8äÁڱ㫨¸iýV\|Óž{î->t£ÝhF7 ƒ5´ëž{¾·Ù³¯ŽõmÀ€ôXYY·Ýÿ×VYyÉ–,¹`Ë–}eË—i+WžµêêN[³æ3[»öŒ=õÔ§¶aÃ'¶iÓI«­=n[¶|lÛ·³^h¶—_n²×^ûÈ~ûÛÃVW÷½õÖûööÛ­¾>½ä¶m'mÞ¼~;~üG¹Ÿ~j6wîó=Aî„B kè ÖÞ½‡’)Ú¹³Ùvì8æÌ’LÓ¯}Òžyæg¦dªÖ¬é˜¬ÏÙ’ézðÁ¯ì.83&SV^ÞíLšÌšLÛÌ™ß[aa¯ôÙ´i?ØÔ©æþjYë‡ÚÜ•—÷˜+2YóæÝ Å‡n4£ÍèÆ`a°†Î`]\¼ØN<û¬Ü¿?-‰"YŠh½ñÆCnî ÂËþéOÍíWZúMà/[UÕÅÀû·G9뎱vm»=ýô§s8eÏ=w<`ÞZìÅo¯¾ú‘½þú‡îüßy罬ý"úÍoZmþü«®[tîÜky±Ë÷ÏS§nÌÕMß":2Eûör&IfI]”2O›7ŸpfJ¦JæJ&kÅŠsÎtUV^´… ¿vflÞ¼ïœ9›1ã¦3k2m2o2qŠÂÉÔ)2'“§hÝC}éÌßêÕŸ93(S(s(“øüóÇœiÌ×HN¾,! dÀ`%Ú 8ôÆöéSOYwi©õÝu—u-]joÙbï½óΰ4YÅÅßÙôéŠä\Ïêî2u;ªûQÝê:U·¤º'ÕM©îÊõë?uÝ—êÆTw¦º5«ª.¸nÎÒÒn×íÍh<õT›3€{ö¶úú!î⬯w‘Ð÷ßzË>¨«³Ã¿ý­}ôÚkÖôòËÖü vlûvwO¯­µ“›6Ù's¯{îÌÚµöÙš5ÖY]mgW®´/—/·¯–-³ K–Ø¥ÊJûúþû­»¬ÌzŠ‹íÛÀóqmölûþž{ˆ`Õ@3º1X ³+Ñ~lý8¶­[gß~ÐnÌÖù´–mÛì½À(ý÷Ã+’³î­ºä¤=Tø‰-ûéI{âî&«]ðž½²¨Îö/{É>|t‹µ®y&i“Ó[X袟?L›fÑ ¿ZÖúïgÎtûiÿž’ë./wï£÷S´ô«À}¥ãèxŸŽÛ8¾ÎC¦KÝØ'ýkgÆdÊŽíØaÍ;w:³&ÓvxïÞ¨ºO¯_o iÊ1äþF7šÉÁD°懯¿ng~ùK»º`Ý üh~8_ýؽ; ÌV>´úd"¢`“óMq‰]\Pag﫲¶¹ÛdzªíÃÂ_Ùé›ìõŸn±ºÛì­9Ûìí²­vpÉV;üØ;úÔæ¨&çƒ7Þp«LäðEÓ-§H¬ Ü‘W_¥un4£ƒ…ÁÊÞ¹õƒÚþä“îÇZŠs¯£/¼0,ÌV®ðýßýÎZfç‹•+é½uç¾t•íßÐå”)—ìÉ';\¹Œ’’olÆŒ^›>ý–Íû­ýâ]n™rÍ”°ÿƇ²z¡"±Ÿ=þ¸Ý(*²oJJ\Dì½Ì!Ì3ƒÕÜÜlååå6jÔ(;v¬UWW[wwwØ}ËÊÊlĈ1ß³6Ðz3fŒcMMïÛ3}¼l`Ebãž=ÖñÄöݼyîìì#Xó‹/f•ÙÊ…VßûûöÙñçžsŸ¯Œí­ŸýÌ JPwÞÑçŸw‘£¡ÎEúÝï\2}MÍ 7âòºlÁ‚7šòg?ëså!”öøãŸ»¼±_l¶}ûÞÏšk­[½Ú®Í™c7î¹Ç¾xôQûýK/‘·½ù¦˜s+V8ó*CõuE…3³J7è “£• ¯Ä|€•Á’Ñ’á’ñ’““!“1ÓèÇ—_þ½3l™ºÖj(çëæŒ.Ìš¦XòrÐŒî<î"”Ñ9rä uׯ_·‚‚;þ|Lƒ%³"ëA¯eÌüÚžéã çV$*ßE Ë×gͲïï½×:{Ìš^y…V_”'kj\n› ªÄ//Zdí¿ü¥3©‰þøg“fÕúR u)ªkQ]Œóæ}kwÞyËu=ª R]‘*k¡‘žê¢TWe"ÇØºõD wÃX?ÿFÜ#Fù;µq£õ,XàJ°W>­{t£™Ö°0X·E°6lØ`»vír¯c¬Ñ£G;“lشίí™>ÞpËÁJ”2V«V9£%Ã%ã•« lj 8õë_»‘™úL4JóÒÏng~õ+—<ž/ùlš¯Ru¼T×ë±Ç¾°Å‹/Ùœ9*­ñƒÝpS(©$…JT¨d…*ê‡f•¹ wRV-Ë¡ûôüÃ;s{ñ¿øqy*’ƒ•­«££#ðEYd]]]ëÚÛÛ­Ìù˱ V¸íÁ±T·gòxºÀƒQZZꢞs×ßT—u ü|¿d–?}óM×uØ0[7,°¯Ö­s]‹Cy|™Ðë-Ÿ ðràüë+܈¾¾À3q-ðúܳÏÚ‘@CãØÑ£¾ïÌ™3Õ›êòÑ£ºfçìµ×θ`kÖhJ£ën.If½÷Þ^«ªúÞV­ºl ô…wRë“9~Ãï~gçjkífq±Ý˜7ÏÚ¦·õðá¬ý¼²áþÎÄr6|Ÿ¥{YÏu>éêï³am°ZZZ\7  U0d®Î;·Á"‚•›ý÷J†WÒ¶’ã•g¤ü"åÆä‚îÆÝ»]uü®%KìÆÝw[o@ã…ª*ûtýzg(ÉÕHž*”ª‚©*œªªwÝÕö™Ò¼“>ú…«ª¯è—ò¾ñ¨Ñ±ª¦¨–êeCN!y9ä`¡;Ï#X 6uêTkkk ! ÇDr¢´Î¯í™>^.æ`%Zù[?d*÷ ²%§2*1\tË4É<ÉDÉL)Ÿ§ëœÉ’Ù"WcènÞIE°fμiO>Ùîæ…Ô”Cªv¯„û#`×ÝTDK—v¹êøê¢Üºõc{õÕ#a“ï5è@÷¤¢W D@=˜%LÉËA3ºóÈ`íü L™2Å:;;ãÚ?Ô\….{£òTê!Ú¨½d·§ûxù–ƒ•¨ÙRî‹’½5”^5žTàT9KÙtŽG^yÅU¹¿¸x±‰¦ü2E8”0í—1„ñQS")çÊ3YšäZóPFÊÁ:pà`à;ªÑMEôÌ3Ÿ¸ù•ç¥Éº5¤’ï5úQ“xßÿ×öðÃç]þ¦M§ìùGíà /Ø¥û¹¼¹s<’–ˆ$ÌüHYHVV¬D#T± – ZRÑêJ¥²=ÝÇ#‚5r®eûv—®3M³"S£wiÕ8%ž+]‰èª ®Ät—æÒË*ó—§-]™¬’’knÞɹs¿OyÞI•ÐhF½ïÓOêF?jÒíÒÒoìž{¾wQ°…3ÎÛ›E[íêô{íó»au¼f›kZ]ý/%ï××s­ÓYµŸHº©äT 4—GVfëwÜ4-_-]ê Î7¥¥n®ºCq ©OT·Žõû_´öµkíòý÷»ü•Nøòá‡íDÀ,‡aüäj uØ# e¦ž{¶ÕÞXúš3Y2[ûж8ó%&3&S&söØcάɴíÚÕäL\ª¦R¥)ƒ••ý`¯½ö‹ûÝ,@+³õöÛ®0d×’UÑ\“úÚ·/©®*ïT’ý× º¢žJºW‘OûTþ ->tÇ›‹§nCWvãþE®;ñ…çºÊöêf|è¡/]·£º úÜôCê–T÷äƒ~åº+Õm©îKucª;3žnQ圾2rÖd©Û]Ï|4ƒ5Üê—ñ\Á9d°r‘*©éO.VUYŸª ’£}ë4½Œ¦™‘9“¡ºø¼Ï>ú¨›ŽF“óÙ”îËýûÝ}¨„x%Æ+A>œQWB½j{iD¤í•p¯Ä{%àÏšuÝÕSb¾ôþóË.a_‰û³f}o­­ý·%ö—”ü0¬?7ͱ©/Ÿ>ý´‹S\ìžk4ÖLÑžk™ZåBªá¥'*Âü¨ƒˆ`ùô£vâÙg]ây´/bMŒ¬ÊÝš‹NÝŽª{D‹ÝCE•vÐE[UòÁMŒž`%|Í©R*9¡ÒÊ5 Íù=\ºüUlX³¨±f-ÐÈ[ïÙT~£ò-Bï‡F¦#uÌ”"ˆŸlØà>oåIê3—1ScêØöíÖpà÷7º1X,r°†*W£!K†×“«‘_º•i¸6{¶}7gŽË!LÖÜkžÇ?¼z[kþü›Ù7kA]}¼u«ËiTtéÛ¹sí‡éÓíZÀ©b¾Ì"LJU/FÄ)ÑQ„Jh ¼·SŠ†Ý WÑj×ý0wÙ8@…çš,@‹dXZºèNö{Âyä¬ËÝzíµ†´|ÊG»wÛ‰ÚZ7¯¨ŒŠrŸ¼èºçTÒD%V ƒÄsÍ¡Ï]Ý’Š,*'S†ðóÇ·–­[s2…b°0X´~(HȵÎÝÓ¢Qr_ß¿+\{våʸgÕ¼qã)›1ã¦ËÙJõ¼dd”d˜T"Eê‡;ï´ë3g:c%"£åÎ5Í‘Ÿ¡ºÖêÊUn¦rúËÊ\^˜F+é^uï2YH˜çƒÈÁ"oÍèN¶$Áoër†\×ÚÂ…n”¬’ÂÑüÒK¿·»ï¾a?þY\O8àºî4òQ]yŠà¨ûL#ód2Ôå§®?ufK¢xº®µ«‹÷ÒKÎdª[WSa‰++Ý:m‹v}¸¿ÉÁD°hý ÝYVïM£ìTTWe >{üq—0o„öÍ7?°’’oÜ<Œó+Ö×[cÀÀ)©ü³Õ«IÐh;%+ù\óg*ýãmÛž1!Ÿ®µ¢XŠf)ª¥ÏMQ.åœ)ê¥è×P•zá¹Æ`r° „>R% ¾\¾Ü%_ŠQ†d «kß>kÞö¼½Y²Ó ž¶+óJœøþž{\Y™¸ï®L®RyZÊ×R—©W[O³?(¯Kù]©Nø®|;Mj^PÐo¥¥·ì¥—¾àsÇ`"XD5ÐŒnß~Èp³D3Xªû¤.,èü¦¤ÄEYÞ]²Í¹ë¸½°ù×:ÑÇ?Ì_ª‘‰¡¨A êrUÞšF0jæˆD3Ìšuó¶ªý¯¾zžçƒÈÁ"/ÍèN×(Y%Ë&{çΣVTÔë*Ás­3Pìõ×]í-å³i°€F]ª6—òíÔeiJ®|°C ‚EKÍèÎú2$uuÚ‚W­ªê¢íßkáh¤ªË«Ðª¢Žª‰¦|8•¹Ð€U¥WÎ\´k­)”4™¸æ·üÅ/.Ú²e_Ù#œ³êê΀‘î°§žúÔ*­­=n[·¶Ø /4Û®]Gì·¿=ìfxûíì¾vìøÄ**nº®Ñââ›¶eËi   B˜uÞô£ªùçÍûÖöî=Ìç™E¥:4âé§Ÿvƒ T[L9wÑ®µ¦Pzþù£ãñ±«ƒ¶aÃ'ö«_µÙš5öØc_Øòå_ºk]YyÉM(^\Üã&Ÿ9ó{7Ç¥j¨ýô§ýnâq:ÕÄ㪭VVÖíæ¾\²äBà·é¼­\yÖV¯þÜ~ùËv{úéÓ¶iÓI{î¹VÛ¾ý˜½øâï]ݵ×_ÿй}ç÷|ù<¶l9¸Gûujù¹çNa°,ZºhFwöÖyÓ¼†……½¶cÇ1®uRFe㪖!/š¬ãÈÉ É(©Ä‡î ¨_ÿú¤3Tkמq%?d´~ø¼3^2`š”\†LÆLMFM†MÆMîž{¾w†NÆnáÂ+ÎèÉðÉøÉ®Yó™3„2†55'œQ”a”q,)¹1`®<ü˜Ö‹Áä`‘«ftg·fýÊdÉlq­³‡»v5¹î¿ŠŠ¯‡å¬Š’îÛwÈEHÕ%¹sg³ë¢TW¥º,Õu©\@ueªKóÁ¿r]œêêT—§´ÿìgáek¢s  ‚EKÍèÎzÍúTw¡" Ùž““ë×úí·ß ˜ŽÏ¦÷¦3"±ºƒ‡ªÞV6°¤äZØÖ¼y70X€,áð Þ«ª.¸î%Â󙤟ꚛ3ç;W¶®îƒ¸ºƒ•ï’ásðóPyŠÙ³û¬µµßý&~òÉn¹¶ö Á¢¥‹ft/Íê¶Q)•tàZ§¯;måÊ/\W­òѬ"¦š»RerÕdçº5¡¹Ÿæ ƒ…Á"gÝhFwZ5oÝú±ë¢Z¿þ4×zˆù GmÖ¬ë.z¨œ¥d4k.Äwßí¦RJ÷„ÛÔÁÊš››­¼¼ÜFecÇŽµêêjëîîŽ{{8ÔÖÖÚ˜1ckjj|ßžéãÁ¢¥‹ftg‹æ={mΜknĘ_Ãî¹ÖÿŸ4Øòå笨è†=÷Üñ”5ðæ›®j¿*ÅkÚîñ6X•••ÖÔÔdýýýÖÛÛh ­w†*Þí¡¨««³’ÀÍÓÓÓãXVVæÖùµ=ÓÇ# B˜mÔÑÊÒ„Ñš8šÏÄnßÞâêP©(¨Ê#øõ¾šOòüû9÷ìá³Î—.B©‘#G&½]fEÖƒ^û¶=ÓÇ#‚EKÍèÎFÍõõïºúGªq¤$l®u*†õ}{ðÁó®6Ô¶m™fÍU©y?Þº•{< VcccÔU¬í£Gv&,Øi_Û3}üð—.28ÔšîÜé&ünòIîñ\6XV¸Ð]]]ImFŒqÛºàˆWªÛ3}<"X´tÑŒîl׬*ßJÈ~䑳V_ÿ×:*q}É’.»÷ÞëöüóÇÒªùú:»º`]¬ª²ƒû÷sçšÁjii±‚‚kooOj{>D°t=£´´Ô¹vïÆÒ_–Yf™åL.>Üêªm/Zô­8ñŸO”åßþö¢Ý}÷MgHù8#çÓÒÔd]K—Úõ€Ñ:wô(×'dyج††›:uªµµµ%µ=VN”Öùµ=ÓÇ#‚EKÍè.š•—õØc.Q[Sºp­S/¾èæç{ñÅæ¬ÐܶnõÚ±;¸Ç‡{k÷îÝ6eÊëììLj{h›7*O¥¢ÚKv{ºG¹hF÷p×üì³'\^–þr­ä¯}*ð™ôÚªUC2íP*še®d²d¶¸Ç‡±Á’a ÇD¶‡Bµ¤¢Õ•Je{ºG‹–.šÑ šÁR$K-E¶òõZkz¡ûï¿lsç~k/¿Ü”µšïÝkßÎ›çº ¾ý6¬|¬ä®¤¹|<ê`As…Jä./ïv¹Y~Öu.ܰᴋä­YóYÖe ¦Þ/TUÙÕùó]"{üq»q÷Ýöû—^"‚…ÁÂ`‘Ÿ‚n4s­³ùüÖ¯?m……7mëÖ‡•nÄÕ«?s9e)˜/×úøsÏÙÍ3ìÔÆä`a°0X´îÑf®u6sçΣVTÔkO>Ù>,t«–Õ¼yßÙ¢E—]«|»Ö½öš]Ÿ5ËÎ>òˆ½W_O ƒ…Á‚Âl¥ŒŠJTU]´ýûfå9ªúºª°«û¦M'óúz½ÿÖ[öõý÷[wy¹Ú·, ‹Ö=º¹ÖhÎVÊÀ,]Úeóæ}›r>“ߺwîlvóVV^´7Þ8ĵþC^VçcÙ÷3gZÓ®]D°°*,òSÐ͵Fs6Su¤ {mÇŽc×­hšŠ¤ª sóæ\ë0<ñì³./KÉÁ,Z÷D5¸ÖhÎbÊ\ÉdÉleJ·ÎaæÌë¶dI—íÛ÷>×: ÁR$K­wÓœ—E ƒ!„ PÝ„ê.T·¡ºÓu\Õæzè¡/]AÔ-[Z¹qR¹XÊÉRn–r´ÈÁ,¢hF7š³”ꢫªºàjM%2b/YÝ*qÏ=7ìÁÏ»"¨Ùp­5ªP£ 5ÊP£ ‰` y9hF7š³˜*á <(•t Ýo½õ¾-]ú•Íœù½mßÞµN‘ª“¥¼,ÕÍ" Á"ªft£9‹©è’Š’ª8©Ÿº5ùtQÑ [±âœ8ÐÀµö‰ªø®Êïª?”yYD°9XB˜"5­Ž¦×Ñ4;ª¦žÊ{½ùæ!WwkÖ¬ëö Gù|‡€š»Psj.CÍiH ‚E ÍèFs–R¹Qš(ZFkâèdt×Ôœt£{ì‹´&Ðçãµ~ïwìüÃÛµ9s¬qÏ"X€,rTÐŒn4g+ëëßµÇÿÌô{é¥ßÇ­»®îgÎæÌù.ìÿq­‡Ž§×¯·›……öñÖ­ä`"X´ðÑŒn4g3•?¥ —7n<S÷ÆŸ¸®ÇÿÜÞ~û=®uxtçNë-*²ö'Ÿ$‚ÈÁ‚Âlæk¯}äò¨Tqý¹çZmÁ‚oíÎ;o¹(Umí Û»÷C[¸ðëÀ÷æ·öÊ+GøÌ2Ìëêìê‚v±ªÊîßO–Ÿhnn¶òòr5j”;Öª««­»»{Ð>µµµ6fÌÇššš˜ïkÿT·gúxD°há£ÝhŽ^fá¾û®Zaa¿µ´Ürß“'NÜ´»ï¾e?ûÙ-{≎”“â¹ÖþñàÛo[×Ò¥öí¼yvxï^"X~¡²²Òššš¬¿¿ßz{{mýúõÎpy¨ ¸Û’’ëééq,++së"!Öþ©nÏôñÈÁ"GÍèFsl–”\³ÖÖÁß­­ývï½ßs­³”mëÖYoa¡Û±ƒ¬¡€ŒÖÈ‘#–e>äH=èuqqqÄÿµªÛ3}<"X´úÐŒn4ÇæŒ?„ýþœ>½ŸkÍç0W2Y2[D°|Fccã ÖèÑ£é 6`Z ±öOu{¦G„ÆæÂ…½vüøàïÎO?5›7ïŸO–SÝ„ê.T·¡ºÉÁòVTTd]]]ëFŒqÛ~Á®PÄÚ?Õí™>,Z}hF7šcsÇŽOß6`²~4Wý.Ñk= ò²öï· UUvuþ|—O+´´´XAAµ··'!ʧ–.°Ç`”––º~gïÆÒßT—¿ùæ_ßo¸,‡þÍýjÐä“^oYº¹¿s[ï‹/ž±E‹nÙw*ãÛ¶­û{˜-Ÿæ»5s¦µ½þzF¿ÏÒb°q‰‡wÜqGÜïÙÐÐ`S§Nµ¶¶¶¸rœ´.‘œ¨àýSÝžéãÁ¢Õ‡ft£Ýù¤YÅHU”TÅIs:‚%ãÌH+V7—‡Ý»wÛ”)S¬³³3ê(=•n7Ê.´‹-Öþ©nO÷ñÈÁ‚B˜ïÔ´:š^GÓìhºœÏÁÚ·o߀9ðpåÊ·®¾¾>¥ˆX0T*R¨p9LÑöOu{ºG‹VšÑft£ù]7A´&ŠÖ„Ñš8:§s°&L˜`}}}·­×º‰'¦%wKJÓ‰t:XÔŽA3ºÑŒn4ÿõõöÙãÛ»ï¶ß¿ôRîÖÁR4'’ÁJ$ dŸÁ¢¥‹ft£ÝhÎVî9»9c†Ú¸17#XãÆsE1Õ-¨ÑoâåË—mþüù6~üxœÐ06XBa6ó£×^³ë³f™M™‘Ã:+RÕ;#"‚E«ÍèF3ºÑ4£ÍèF3 ƒ…Á‚B1XÙm°-Zä¦vI¥’; ‚E«ÍèF3ºÑŒÁú/^<`¦’­äÈÁ"oÍèF3ºÑœ’ÁʵQ„ª<ÞÔÔä^{««W¯ZUU•íÝ»'D‹VšÑft£yØëÎH¡Ñp¯U‹:Xä`A!„¹ÀŒ,MP,¨DCCCƒ{}äÈr°ˆ`ÑúA3ºÑŒn4ÁJû÷ï·êêj÷º°°pPÖ¤I“pBä`‘·€ft£Ýhöº3Z¦áÖ­[6yòd¹ÒDÏáæ(D°hõ¡ÝhF7š‰`r° „Br°0X,Z?èF3ºÑ̵æZ{ƒµgÏ›0a ¤öiÓ¦Ù… pBä`Ñft£Ýh&+™$÷p•Û›››­¤¤'D‹ÖšÑft£™V¢PRû¦M›\Ý«`ƒuíÚ5;v,Nˆ,!„¬DlªBë^Q‹­4£ÍèF3¬$ ùoܸq›¡êîîv@r°è¿G3ºÑŒn4“ƒ• ”Ì>{öl»råŠ3Xª…ÕÖÖæŒ×Ì™3qBD°hý ÝhF7š‰`%ŠÎÎÎAÕÛƒéM¡ Áÿ]]]VYYé"b¢^Ÿ?>ê{ÖÖÖº‰¨Åššß·gúxä`A!„9^K&K‘,ÍE(&[¢!’ÁR$lûöí.:&nÛ¶ÍfÍšñ}êêêÜF<±¬¬Ì­ók{¦G‹VšÑft£9ê`ù…H+\²¼Œ\$Ȭèö ×ÅÅžmÏôñÈÁ"oÍèF3ºÑœã9X~ŽŒd°–-[æ¢V*!nٲŭ‹u#j?zœpŸêöL­>4£ÍèFsŽG°¢E’ü2X—.]rÝŽ^ž–^+©>‘÷QÒ½_Û3y<]`Á(--u®Ý»±ô—e–Yf™e–Yög9íkÊ”)®¨èP¬ŠŠ Á ÎÁ*//'‚E‹VšÑft£97#X‡v çñŽLÆ`…‹æD‹(…Ëi ž¶'Õí™>9Xä- ÝhF7šs<+R‰†Ð¹ S1X2pÊ» ÎÁ EúÞ¨<;6j/Ùíé>,Z}hF7šÑæ<‹`ÉDEb´(S,“Œsçι.A¯ „^k]4c¦ZRÑêJ¥²=ÝÇ£„B˜‡u°2 ?í³ñxD°hõ¡ÝhF7š©ƒrÄ`Ñft£ÝhFw† V__ŸMš4É—,@‹VšÑft£™–Ù úTÉæ`ì4XB!Ì`’{}}=އ­4£ÍèF3,¿ Q*r°è¿G3ºÑŒn4“ƒå³ÁR%w?ŠŒ"X´úÐŒn4£ÍD°þ€#GŽXaa¡+’ ÈÁ‚BÉÁJÒ`E«ÞÎ(B"X´~ÐŒn4£ÍD°’Ll‡äg‘ƒEÿ=šÑft£™,€Á¢õCKÝhF7šÑÁÂ`‘ƒ!„æd¬d¶"X´úÐŒn4£ÍD°4QW¯^Å`‘ƒEÿ=šÑft£™,¿GŽ='D‹ÖšÑft£™V¢# ÃÍA(Ž3ÆvíÚ…" B!$+QPŠ­4£ÍèF3,Ÿ Ö„ lÅŠÖÕÕ…Û!‹þ{4£ÍèF39X~¬¹sçº+u*ŠUTTdÍÍÍvãÆ Ü,Z?hF7šÑf"X©àÒ¥K¶yóf›`zÜM™êöL,!„0s°B‹ŠF2X‰ÖÈŠd°Æg{öìq]£Fr"5O$¨Q‘.z\U>Õí™>,Z}hF7šÑæÏÁRdIuÛy¸råŠ[W__ï‹ÁÒúÕ«W[__ŸõööÚš5k\ ®DÞ'Øì¥º=“ÇÓöŒÒÒR×ïìÝXú›êò7ß|ãëû —åпù _ù’ù¤×[–nîïüПßgùxå÷YÚ – ŽÊø„Bë&Nœè‹ÁR4GÆ*ø½É"‚E‹VšÑft£9'#X2E‘ –_9XJú5XÑ H¸œ&­ók{¦G„B˜ãu°”¥„lu *ò"ªÀèüùómüøñ¾,uCª[P&KTwáÊ•+#þŸ7*OÝ–ÑFí%»=ÝÇ#‚E«ÍèF3ºÑœ‡9X‘’Üßyç¤G%†bÛ¶mΰ©kpùò僒ÜÃí¯ZRÑêJ¥²=ÝÇ£µcÐŒn4£ÍyXKnQÅ?e~D½>~üxÚêgEËÇÊ…ãÁ¢Õ‡ft£ÝhγÈ]ƒ!„B ‹ÖºÑŒn4£›kK#úTÔJî » ý÷hF7šÑftgÈ`M›6m¡ f¢•Ü,Z}hF7šÑf"Xöã´9‰Vlä`A!„ä`EQ*"X´~ÐŒn4£ÍD°|6X*ɠ☀,úïÑŒn4£Íä`ùd°Ž9b………ƒ&{D°hý ÝhF7š‰`¥€HUÜEH„BHV Iî‘H~,Z?hF7šÑf"XƒEÿ=¹èF3ºÑŒn ‹ºÑŒn4£Í9Ájmmµ©S§º.AQ¯µƒ!„’ƒ•ššš"&¹c²ˆ`ÑúA3ºÑŒn4ÁJŠV-Z´È®\¹2°N¯ËËË],@ý÷hF7šÑfr°„º5ás(nݺe£F Á¢õƒft£Ýh&‚•ŒÁêíí½m½L‹,!„¬$0mÚ4+..¶Ë—/[¿£^Ï;×u"X´~ÐŒn4£ÍD°’A)ÉýôéÓ8!r°è¿G3ºÑŒn4“ƒ• d¤­R— ¨×˜+"X´~ÐŒn4£ÍD°2ˆà¨W,”••ŵ_mm­3Ʊ¦¦Æ÷í™>9XBaç`ùm´¢áÀ.ß+Ö~uuuVRRb===Ž2eZç×öL­>4£ÍèFsŽG°(ɽ¼¼'Dý÷hF7šÑfr°…j]õööº×“&MrÆêÔ©SÖÞÞN%w"X´~ÐŒn4£ÍD°’ •Õ¾Òr__Ÿ[¦’;9XB!9XI`̘1.buöìYg®ÆçÖ+ª¥m€­4£ÍèF3¬¡öà¼«ŠŠ ·^} ªðÈÁ¢ÿÍèF3ºÑLV˜Á¯T·gòxºÀƒQZZêú½KS]þæ›o|}¿á²ú7ôëyÊ'½Þ²tsç‡þ|ü>ËÇû{(¿ÏÒn°4-Ž7a(*'–Ájii±‚‚7Ïa4Á¢õƒn4£Í\k®õ°Ž`M›6m¡ f´¨O¢«¡¡Á¦Njmmm1ß'\N“Öùµ=ÓÇ# B!Ìñ,©úúú!í"ܽ{·™ØÙÙ×ÿy£òTÊ!Ú¨½d·§ûxD°hõ¡ÝhF7šó,‚•h”*V¬põ°ÂmÞ'œ1S-©hu¥RÙžîãQ‹Ú1hF7šÑæ<«ƒ¥È’¢.™„ æòñˆ`ÑêC3ºÑŒn4çYëÈ‘#®îU¬Êê`ø,!„fÈ`Eê¾Kf! ‚E«ÍèF3ºÑLëIî‘èG~ ‹¼4£ÍèFsÞå`"X´~ÐŒn4£ÍD°0X,!„f¿ÁÒÏ*ª.AQ¯µÁ¢õƒft£Ýh&‚•ššš"&¹c²ÈÁ¢ÿÍèF3ºÑLVP´jÑ¢EvåÊ•uz]^^îjd"X´~ÐŒn4£ÍD°„º5ás(nݺ•91XB!–«··÷¶õ2],"X´~ÐŒn4£ÍD°’À´iÓ¬¸¸Ø._¾lýýýŽz=wî\×}ÈÁ¢ÿÍèF3ºÑLV##%¹Ÿ>}'D‹ÖšÑft£™V2‘R´J]‚¢^c®ÈÁ‚BÉÁ,Z?´tÑft£Ý, 9Xä- ÝhF7šs&KùUšÌÙ{‰Þ>€­4£ÍèF3¬qRyïu$zûr° „Br°‹ÖšÑft£Ý, 9XèF3ºÑŒn®uÎÔÁŠ–gE,Z?hF7šÑf"X>¬«W¯Æm°‚ã#¡¶¶ÖÆŒãXSSó=cíŸêöL,!„0s°¢ô8zôè„ß3êêꬤ¤ÄzzzËÊÊܺHˆµªÛ3}<"X´úÐŒn4£Í9ÁòF zåB©HÌ®]»|1X2úÀ<èµæ?Œ„Xû§º=ÓÇ#‹¼4£ÍèFsŽç`ùYŠ!’ÁR$L“H{ÐëhѱXû§º=ÓÇ#‚E«ÍèF3ºÑÌ(” V¸õÑŒ]¬ýSÝžÉãé{ Fii©síÞ¥¿,³Ì2Ë,³Ì²?Ëi7X´•+WÞ¶¾ººÚ:D‹­4£ÍèF3¬D1aÂ7b0Ü(ÂI“& Y–Ö%’¼ªÛ3}„Bµ¡"Õ‰JtÿT·§ûxÔÁ‚Bó¤Vð»"UgÏžu¹Cbgg§3!±J ø…Q£F¥5?ÝÇ#‚E«ÍèF3ºÑœg,åZE*4zíÚ5æ´Æ‹þ{4£ÍèF3º3X¦AÝÓ¦Ms‘qúôé.ŸÁ¢õƒft£Ýh&‚0XB!Ä`a°ˆ`¡ÍèF3ºÑœ“¬E‹¹Â˜¡9X‰–iä`‘·€ft£Ýh&+€Å‹˜©Pƒåç<…€­>4£ÍèFs^ÕÁjjjTXT# «ªªlïÞ½8!r° „Br°EpÑÍàת‡5~üxœ,Z?hF7šÑf"XÉ,Mïâàlhhp¯9B9XôߣÝhF7šÉÁJû÷ï·êêj÷º°°pPV¢“="X´úÐŒn4£ÍD°BpëÖ-›Ý0D°hý ÝhF7š‰`e!dÔ*++]B½¨×çÏŸú?µµµ®‹R¬©©ñ}{¦Gy hF7šÑæÎÁJfΜiÛ·owu¶ÄmÛ¶Ù¬Y³"î_WWg%%%nj±¬¬Ì­ók{¦G‹VšÑft£9Ç#X1è•g¥_£ýϨQ£"î/³¢؃^û¶=ÓÇ# B!Ìñ,Uq6TÁTÙ?°lÙ2µêïïwܲe‹[­6—öó ×Zç×öL­>4£ÍèFsŽG°d¤êë뇴‹ðÒ¥KƒŒœ^_¹r%®Ú\Á5ºüÚžé㑃EÞšÑft£9Çs°üŠREƒJ?(‚œƒmž\Ž`é{ Fii©»©<箿©.kpŸï7\–=æ‹^-Ÿ9s&¯ôzËÒÍýúóñû,ïï¡ü>K»ÁRi%f%™¸hÆ.\N“Öùµ=ÓÇ# B!Ìñ¬#GŽXaa¡uww™ÁÒˆAå]ç`" íbóFå霢ÚKv{ºGy hF7šÑæ<ËÁ 7zÐïQ„çÎs]‚9(êµÖEËaR-©hu¥RÙžî㑃EÞšÑft£9Ïr°BGÅ(ÂXˆV²!ŽG‹VšÑft£9Ï"X w „B1X,Z?èF3ºÑŒn®uî¬E‹¹²C•ƒÈÁ"oÍèF3ºÑœW9X‹/0S¡+]9X,"XèF3ºÑŒn4çTK£ÞšššÞ…«W¯ZUU•íÝ»'D„BHV2e½V½ªñãÇㄈ`ÑúA3ºÑŒn4ÁJÆ`y•ÜU¾ ¡¡a )9Xä`Ñft£Ýh&+ ì߿ߪ««ÝkUtÎÁš4iNˆ­4£ÍèF3¬T ‰˜'Ožì"W'N´¾¾>œ9XB!9XƒE뇖.ºÑŒn4£;Ë<+r°è¿G3ºÑŒn4“ƒå³Áʆyù0XD°Ðft£ÝhΩÖ”)SìÚµk8r° „Br°ü2X‡¶Y³f ”jD°hý ÝhF7š‰`ùP+ÉÏ"‹þ{4£ÍèF39XI&¹G"sÁ¢õƒft£Ýh&‚0XB!Ä`a°ˆ`¡ÍèF3ºÑœWu°ÈÁ"‹þ{4£ÍèF39X>¬«W¯b°ˆ`ÑúA3ºÑŒn4Áòkô ÇÑ£Gûf(:::¬¢¢Â½§joíÛ·/êþµµµ6fÌÇššß·gúxä`A!„9˜ƒåôÊ1„RFa×®]¾˜«ÎÎN›>}º566Z¿uwwÛºuë"î_WWg%%%®6—XVVæÖùµ=ÓÇ#‚E«ÍèF3ºÑœã9Xé(ŰjÕª˜«`Ȭèö ×ÅÅžmÏôñÈÁ"oÍèF3ºÑœã9XéÀ¸qãlÏž=6iÒ$7÷¡D*Ç+Ô¨H—½î®Lu{¦G‹VšÑft£™:X)CÝ«W¯¶¾¾>ëííµ5kÖØŠ+¢î-Ò–êöL,!„:X)CÑ+2ZŠdåcKØc0JKK]XÔsîú›êrWW—¯ï7\–=æ‹^-Ÿ9s&¯ôzËÒÍýúóñû,ïï¡ü>ËIƒ¥¤ïPƒÍð„ËiÒ:¿¶gúxä`‘·€ft£Ýh&+e(Á]Ý‚2Y¢º W®\±‹Í•§Ñ†ÑFí%»=ÝÇ#‹¼4£ÍèF39XC‚mÛ¶Ùøñã]×àòåË%¹‡ËaR-©hu¥RÙžî㑃!„’ƒ•vDËÇÊ…ãÁ¢Õ‡ft£Ýh&‚rÄ`Ñft£ÝhF7 ƒEëÝhF7šÑ͵Æ`ì6XB!Ä`a°hý ÍèF3º¹Ö,@y hF7šÑfr°,Z?hF7šÑf"X, „B1X€­>4£ÍèF3,@ý÷hF7šÑfr°0X,Z?èæZs­Ñftc°9XB!9X€­4£ÍèF3,€Á¢ÿž\ t£ÝhF7 ƒE‹VšÑft£™  B!$ Á¢õƒft£ÝhF7 ƒEÿ=ºÑŒn4£›kÁD°hõ¡ÝhF7š‰`r° „Br°0X,Z?èF3º¹ÖhF7 ƒEÞšÑft£™¬´¡¬¬ÌFŒs¿ÚÚZ3fŒcMMïÛ3}<"X´úÐŒn4£ÍD°|Á¬¸¸8¦Áª««³’’ëééq”)Ó:¿¶gúxä`A!„ä`ù‚ëׯ[AA?>¦Á’Y‘ƒõ ×2f~mÏôñˆ`ÑêC3ºÑŒn4Áò6l°]»v¹×± ÖèÑ£­¿¿`Y¯µÎ¯í™>9Xä- ÝhF7šÉÁJííí6þüåX+Üö‘#Gú¶=“ÇÓöŒÒÒRwSyÎ]S]îêêòõý†Ë²Ç|Ñ«å3gÎä•^oYº¹¿óC>~Ÿåãý=”ßg9i°d®Î;·Á"‚!„B"X1 CމäDi_Û3}4£ÍèF3,@„BH ‚EëÍèF3ºÑŒn ‹þ{t£ÝhF7׃ˆ`ÑêC3ºÑŒn4Áä`A!„ä` {ƒÕÜÜlååå6jÔ(;v¬UWW[wwwÔÿ©­­µ1cÆ8ÖÔÔø¾=ÓÇ#‚E«ÍèF3ºÑL+%TVVZSS“õ÷÷[oo¯­_¿Þ®H¨««³’’ëééq,++sëüÚžé㑃EÞšÑft£™,ß!£5räȈÛeVä`=èuqq±oÛ3}<"X´úÐŒn4£ÍD°|GcccÔÖèÑ£ 6dZç×öL,!„,_ÑÑÑaEEEÖÕÕqŸ#Fܶ.8â•êöLOØc0JKK]XÔsîú›ê²>c?ßo¸,{̽Z>sæL^éõ–¥›û;?ôçã÷Y>ÞßCù}–Ó«¥¥Å ¬½½=ê~D°è¿G7šÑf®5ךVhhh°©S§Z[[[Ì}Ãå4i_Û3}4£ÍèF3,W‹þ{4£ÍèF3º1X,Z?èF3ºÑŒn®5 ƒ!„’ƒˆ`ÑúA3ºÑŒn4ÁÂ`a°è¿G7šÑ͵æZ£ƒˆ`ÑêC3ºÑŒn4Áä`A!„ä`a°0X´~Ð͵æZ£ÍèÆ`r°È[@3ºÑŒn4“ƒˆ`ÑúA3ºÑŒn4Á,!„b°0XD°hõ¡ÝhF7š‰`r°È[@3ºÑŒn4“ƒˆ`ÑúA3ºÑŒn4£ƒ…Á‚B! Á¢Õ‡ft£Ýh&‚ÈÁ¢ÿÍèF3ºÑLk ¶¶ÖÆŒãXSSC‹VšÑft£™HuuuVRRb===Žeeen9XB!9X IÈ\Éq{Ðëââb"X´úÐŒn4£ÍD°@²=z´õ÷÷,ëµÖ‘ƒEÞšÑft£™,$FŒqÛº‘#GF4VƒQQQa÷ß¿‹†Í;×ýMuyñâž¾ßpYö˜/zµ¼pá¼Òë-K7÷w~èÏÇï³|¼¿‡òû ƒ•',d/0XYšƒ¥uÀ`$á"ìîîŽ{!0X Tû*‘:X¡ÎÍ‚B¡ÿÄ`_èÍ„n4£ÍèF3º1X€‡Ý\k4£ÍèÆ` `°0X, Èohêù‚ææf+//·Q£FÙØ±c­ººÚÕ%Ëݪ»æé^¹r¥]¾|9o®»´çË}ü\çÓóÝÑÑá¦ÓìS¦L±}ûöååµ7n\Nkîêê²ÊÊJwE½>þ< dïCš/ÐÃØÔÔä¦)êííµõë×;ÕëX´h‘9rÄnݺ崿üòËnî­|À¬¸¸8¯ V¾¡³³Ó¦OŸnîþV£iݺuy÷9:t(©úŠÃ 3gδíÛ·»ï2qÛ¶m6kÖ, à 9Û /ãHnç:ÍÊu\¿~Ý \ ƒ•»XµjU^D¬baöìÙvåÊ•œÖxÇwdÝw ð…jñæC+ÔTîÚµËEór6lpZóé>÷º‰Ôp¸ë®»\ ?×!½{öì±I“&¹[ÕGºzõjÞ}—­]»6çu.[¶ÌÝÓú·lÙâÖa°+‹ œ¢¢"×§ŸO×Zœ8q¢;w.§µ¶··Ûüùóóú>?{ö¬-^¼Ø6nܘó÷õêÕ«­¯¯Ïuý¯Y³ÆV¬X‘W×ú¾ûîs]¥¹ŽK—.Ù´iÓ¾Ëô:ÓQ; À`¡¥¥ÅuéG8ß VßÎ;™\„ô›È|mH\»vÍÍ}šËP²³Œ•­|è÷pìØ±ŒGqÒ dP+8+Ó½,€ÁúlêÔ©ÖÖÖ–××=×sϰÊG“•K£DC –LW¾@ƒ8N:•·ß[™þ.Ã` V»wïvC¸ó!” åfxC™õƒ«‘F%%%Üç9%|{‘;u§,]º4çss”à®nA™,QÝ…*E’hmmu+_ ƒÊ» ÎÁb!-ü|ÔœºµÓðfi?~|ÞÔÿÊGƒ|­'Ožìò¯‚£;¹ uéÞV×àòåËó&É]Ñ;•`ɨñàÕ2õ:Óù¤,  ƒ0X, À``° ‹0\ Îæët?`°` ƒ, ²Çœ„›ƒÒ[Ö<~óçÏwsœ=Ú***&ÉÞïàÁƒn?íü>šxWs£iýÈ‘#Ý$´õõõ·Ë«¯¾êþïŽ;î°qãÆ¹É˜CçÎ{ë­·lÚ´iî\îºë.{ã7n;oMæ¬IÇŽ뎧÷zôÑGíøñã\p0X^“i½LÓ… ¬¿¿ÀÍž=û¶ý4Á®ö FKK‹3L2eW®\±[·nÙš5kÜþ2GÁعsç€q“YÓ>Ú×ÃáÇݺŋ;ã%êuèùëÜ´ÜÜÜì–oܸá ΀Á€¬0XŸþùÀ:™,/ʺ߹sçn{™m Žxõõõ¹u1ÏKQ(%%%·OGGÇmç¯sÛÛÛ¹¸`° ; V¬õÑr ÔE®2ԤɀUUU9C¥õáº,Õ-Ïùx,Qÿ£.Éõë×ÛåË—¹Ø`°`ø,Ï)ò ž) î6LÖ`)kÕªU6qâÄAFMF €Á€ao°”Ü®mQÏÁ‹tyPwcèûÆÛE å|}ðÁn»ŽÀ`@Z0aÂg@”„î·Á:yò¤=XXXhgÏžu딜¾ÿ~g˜<(º¤÷RŽÖ’%Kn{ßà$÷k×®9VVV޶ߢE‹ìСCî}bÔöû  ÒuË©”A¼Æ)ƒ%(Ùü¡‡rùUÚO†Ne‚Ë&È|©›PùWS§Nµ={ö„}_•i˜>}º‹FÉ´i9t?½ïŠ+œ&¯äƒº ÉÁƒ€Á,  ƒ0X, À``°0X äƒüÉO „ÂaO€ÁÊ:ƒð[0XÜ”¿e,nJ€ß2 7%Ào pSà· `°rþ¦¼råŠ-_¾ÜÆŒc#GŽ´’’ûàƒâþÿ#Fĵ¨÷7nœ­X±ÂÚÚÚ†L“w¼HçÖÕÕe•••6zôhG½>þ|Ä÷knn¶òòr5j”;Öª««­»»;î퉞_0ÊÊÊbîü~áÞWç§÷ñÎoåÊ•vùòå¨ïÙØØh3gÎtÿ3}út{ã7¢Ï;f¤m‘4ÄóÙÕÖÖºûS¬©©Iø³ŒöÿC‰D? ¿Ž—®ç,ÖµKT¯ßÏm¬÷óûü}nóñ9Ã`a°òÊ`ÉPéÁ¸qã†õ÷÷ÛÉ“'mÉ’%¾,:Ξ={lâĉCúåíÜô…¶}ûv»uë–ã¶mÛlÖ¬YßG_äMMMîóéííµõë×»/«x·'ûÙ8pÀŠ‹‹ã2XѰhÑ";räˆÓªs|ùå—mîܹ÷?uê”Mž<ÙŽ;æ–eÆÖ­[—Ð5w¿XŸ]]]»G{zzõÃ¥uñ+ÞÿO‡ÙJç1ÒñœÅ{ß'ªÝ¯ç6Þãûu~‰>·ùøœa°0XÃÏ`M™™1 Ön4\ºtÉ–-[æZŒÚwñâÅ-Ÿx[åá¶íÝ»×–.]:hZ=ãÇw­,µ¾¯_¿>hû¦M›\Ë\-°W_}5é/ž;î¸ã¶u:f¼Ð—T´Ï-Ööx¾¥½  ÀµÐýþˆ¥W×{ÿþý)/™ó ýìô¥íý z­¯xïÿÇBà·)ð#ev×]f š}øaê+žu±ž‰lxÎbÝ÷~˜dŸÛt¬DžÛ||Î0X¬ái°Y=7n´ .„Ý^TTdÇw¤Zúò]µjUҬ඾À=üæ7¿q‘3µ~tœÕ«WjÍmÞ¼Ù™;mïëësç‘ì¾ØÔú•&qË–-n]¼PX?Z„*t{´.ŠHذaƒíÚµ+ì~á–õƒ¨/Ì»@Ú¢}±ê}Õ¢]}Æ™øâýìdìuÎÁç¯uñ+Þÿe®î»ÏÏÁËŸ~úãr"&+ƒë™È–ç,Ösá—‰õÜ&óœ%óÉ>·ÿ`”¨ök×®¹DÓHyç΃®q6´¬#}v™ˆ`…>2……·ïsófbW2+Ö3‘-ÏY¬ûÞ/ƒ•ìs›®.ÂDŸÛ||Î0X¬¼Š`ÅÓâÕ¨B}¡ úú#Ì€rC‚Ãû:N´‘w~F°Âµ¬bE5lêÔ©†cmO´…œÊȳh+½ÊÙIgnH´Ï.\n‡ÖÅ{¬xÿ?,›à%™¡ÐV´g"ž³xî{¿ L2Ïm: V¢Ïm>>g, V^,=äÁ9VÊk™£dX>ôÅüè£zÈôC«{-žÑMÏ?ÿ¼UUU¹nA-Áà\//7Dçj–ôIgp.G´ÑH»wïv?LImO¶ë"Ò~¡Ëúœ¼–³>?]SuûzÐko8»Ì—’œ£™ nR—qkk«[ÊÑM±>;ot’®{*£›bý4 UÖìÙ³]¾ŽîAŸºçƒ÷‹õLdú9‹uíü60±žÛlÈÁJd¿||Î0X¬ái°’E¨dG=jM+¤«Øà mW}mWëGjðC¦!ÿ^WC´/2lú! × /åUèX’]__?h»òŠdèbnŠÕŠÔŠWFÔëX9IÑÞ3ží‰œ_¢K-S}^Z¯„>' Å·]Ÿ¬:]Þu×ÿèZèú¿õÖ[ ·Ô©‘í½dã©Ïé<¢ý"&K‘¬;ïü1råÇ(B=2Þ³%Cº_¬g"Ûž³XÏE¢÷B"Ïm¢ÏY<Ûý|nyÎ0X¬áh°~Ë0X€›¿eƒÅM ð[†Áâ¦ø-Ã`nJü– 7%Àokß”Báp'À`d%þ–æØì–6IEND®B`‚Multiverse-multiverse-0.7.0/charts/mono_read_line_wide.png000066400000000000000000000606331174000617100240330ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxabIDATxÚì{l”å›þ¿Éf³Ùl6›M6›Íþ±Ùl²Ùì›Íf“Íf³ÙÓ¦]…€T T9XÄž,'AQA Š  ØoQE”ŠEÓW*H¥V*çC«¬EjK«Jkïß\NÓ¡3Nß™ét>Wò 3óNû×¼3}¯÷~îçù!„B!„Pœô;,@!„B@B!„B„B!„"€ „B!„ ¡$ûRøÝïzísPr¼—CaÁ?÷/ÿò/!Ÿ«m©püÿÅýÑÙŸþéŸ:òòò¬®®Žc!DA@8™'€ 6€ˆ/¿üòŽçé±¾ž›*$˜?ÿó?ïÓ'>7!BˆB!€ ðd»¨¨èŽç¤l‘~ùå›;wn¯Çÿ÷ÿ—c!DA@ Á¿ù›¿q'Ü~éö_ýÕ_¥t‘nÞ¼Ùëq ÉâD@B)@úÚ¶fÍûû¿ÿ{ûã?þcûÇüG[½zuŸ¿÷òåËöè£Úý×¹+=ÿ/þâ/ìž{î±O?ýôŽçŸ8q¦OŸî~÷ŸüÉŸ¸çÿÝßý{¬¶¶6â×îõE2&؃ .¸«õÿüÏÿÜóÿÐ uvv¶}þùçž¼®@=õÔS½ž÷ì³ÏFô^Fó:³¿ñÑGõ<§¼¼<"ïãyl vÑ~×~úR4ïíÖ­[ûì9ù×ýWWyijjŠÛ1"€ „ QÙ³g÷yÒ¸aÆ^?§Ì?û³?‹ø$_?¯¤pÏ_·n]¿¯½¿×7Т“8€†{î’%Kýºü?~|ŸÏëëçƒO6£yÑîo ÇÜÿ÷»<ý3fŒ{Lá´¿ýÄëØìþ¢ù^¿~½×ãÿñÿÑgˆæ½ÍÉÉ û3ý×mß~ûm\Ž „!D‰:€¤¥¥¹“¦—^z©×ãÿþïÿÞó3ºz¬+§þm "7n´ÎÎN7ôFWlu’ã—îþ.”þðÃÖÜÜÜsòê'øjo4¯/R_‚›¤õ»uÕXÿ™3göÚ¦À5Ø×µ}ûö>}ÿùŸÿò5Gû:£Ýß@¹-[¶ô\Ýÿé§ŸÜûê?Á÷o µŸxƒÙß@?‡ú,÷z¼¢¢Â³cPŸ±^xÁ½~©££ÃV¬XÑëgTÑ T¬Ž „!D‰:€9r¤çd&ÔØu ܦa/á4a„^Ï?pà@϶?üὶ鹃}}‘ú2iÒ¤^Ï œ&5ø÷1bЯkÔ¨Q!}ÐíP¯9Ú×íþzÌéDûoÿöo{ª :)Öm=¦máöïcc0ûˆ'ÁüÛ¿ý›íÙ³ÇÓc0’×¢a\ŠÕ1"€ „ QÀFâP?§>ÀÇÛÚÚ¾FM?jºÒ–¾~&¸ç$VÇBˆ‚J!eïïäHÏ6œø8ü*’“”þžî„)ÚɉTðëHãz,|‹ôç"}Ñî/š¢ EÝö7A‡ÛO¼Áìo žwÒÉÿ¹sç<9ƒw¤Çm¬Ž „!”B ¾¢©«˜ ¾ªÙßUäH¶yY‰Åë‹ôDª?ïzÂÙß¶h¯>Gû:ãY‘‡év$^ÅûØÌþ¢ñ$xÈ—úL¼85[VàÏ©Ëk¿ !B¨Oýßÿý_¯†àqæ{÷îíµ=°9<Ú“¸Dö€x@‚_—¦c@FÕøûh_g´û‹öÿ~èСžÇ‡Å«$š@«¿Îœ9sÇ6}&ûÞ†ª|j:ßp¾Äê˜@@B)¤à“&­àæ¡u?Ô G´'q§Nê5”CcÓý³`Iš=(pJÖà™‡4ÛŽæàiZ5®Ý‹¡æÛþf4 ~]úù)éʰfûÒt¬z½^hg ŠöuÆk¬Ánçή‚áŸþ8Ôka,„!ä‰V®\ÑXp=Ï‹iIS‚ç÷|”þÖ^Ðô©^½¾ùóç{öº:V~ Wü#]ƒ!Ú×íþâ@qlD»¿hÿ ÁÛ+DѼ·þ™Æ‚¹ÿþûrL „ ¡”VoÖºªx¨"á¯Lè¾ÈjÒ‘ž8666öZ ]ÏùË¿üKWýðO‰(UNôZþáþÁUP„®äê1¤yùútõX‹·iö¡þoý¯ëŸþéŸÜsu2¨p•‘‘áfwêË»Áø¶|ùòôo¤«PGó:³¿xxÑîo0ÿÇàÊDð”ºÑ¼·ªŒøŸ¯)õ¼Hýöú˜@@B!„Bˆ‚B!„"€ „B!„!„B!DA!„B@B!„Bˆ‚B!„"€ „B!„!„B!DA!„B@B!„Bh8šš+**²ôôt9r¤•””Xkkk¯çÔ××[qq±eddØ„ l÷îÝagYY™eff:JKK=ßžèý!„B!D‰R ,°êêjëîî¶ŽŽ[·n $~544XVV–UUU¹ç(œ¬]»6ä﫨¨°üü|kkksºÇ¼Úžèý!„B!DñP iii=÷W¬XÑoÅ#P:™?~üxÏ}ÝÎËËól{¢÷'=ñĽîجY³âN¢ö›*à/Þâ/à-þâ- uƒÏK“2€¨ÒX5j”•——Û¸qãÜ0-ý'ÛÛÛCþ¼†i)Ä=æÕöDﯯòàƒÚþð‡¸óÍ7ß$d¿©þâ-þÞâ/ÞÂP÷7éˆz=rrr¬©©©ç±#FØÊ•+­³³Ó ÑZµj•-]º4äïÐóƒXQìöDîOo°Ÿà ˆ€ô%ˆg¼ñÆY+.¾mÙÙÝ–—wÛ^{í,¾p%oño "€©SoÛ}÷ݲéÓoÚÌ™×mÖ¬ŸmöìvßIt›´Ú÷؜9Í6þU{ä‘lÑ¢&[¼ø{ßÿç;[ºô²-[ö­­XÑ`+W~cÏ>[oÏ?_gk×^°_m%SjlÝÌ#öjÞ{gÎGV±è};ðÄVûlÙ&;þÌ+vvõ‹19¡ïÌ殬,ëVÐĉÖ=i’»¯Ç;¦LqÏ»1mšû9ý¼~O›ï³ÓZXh-ÅÅn?Úß ZÓ£Ú÷?î^^—^Ÿ^ç×Ï<ã^·^¿‚ÉùuëììK/Ù™W^qÁEFA¦vóf;þæ›V³u« : < >GËË]R 篪Ÿê Óï:´w/Ç#ß ø‹·@"€ ´­+¼µ[¶¸¹Ö¢"רþ“ïäJ'M§~ÿ{;²kW3 rt½G:‘w‚ê„þZ^¾5ç=lß?4ß¾}p‘]Ì}ÂNÏ\f_N[iGsÖØ'Ùëm÷ÝeöáÝ›¬"ûuûèþ×mOîë¶¿p³ýaþëöéã¯Ûѧ_³š5¯Ú‰ e:¡W¥CŸõV%{À;öÞ{.ä(uýVõÔ0LúÂø^À_¼* ˆ2äÐÉWÍÛo»“—æyó¬sòd»1}º»ª|öå—ݾxÀ?¼ï«×_wÇŠ&>øÉ÷¹øåž{ì¦/T4ÏÓ!B{÷VÚŽUnšåW^9ífH{ê©Knúæüük®¯ÅßçòÀ×­¨¨Å{¬ÉÍžö ¬¬ì¤½ýv›•M3µ çY°*?þرÆÇ·[99.ôéƒ*ž Á $.ª©©ñý1.²ôôt9r¤•””XkkkŸÏ-,,´#Fôû;ËÊÊ,33ÓQZZêùöDïo8W@"¹¢­«©Ë~eáBwÕºÃw£á-^xÁª·owÏájÆðEÃöT=ÐûÝøä“v-/ï×aIS§º¡M—žzÊ #úÂ\UAJMÒêsQ‹úZÔÏ¢iœÕ¿¢©šz¨ÝMǬ5k´FͬY?Ùœ9?Úã7ºµfÖ­;çúƒ¶m«¶]»Ž é)“rìªúS÷Üsv­ à×êÈœ9î½U5ˆãïüÅ[ -X°Àª««­»»Û:::|d×¹@¬}¾‰<߉F¤¢¢Âòó󭭭͡ТǼڞèý ·/8ºs§k²ÕU ŸÑɨNbê}'5_nÝêšwÏ™|TîÝëª_jžV¨hñ}/tüÖ¡>!õ3œ÷¨*Œ(”x=ƒ["›òµF‚†‡‚‡ˆ‚ˆÖ“yðÁŸ\@QPQ`QpQ㽂Œólptvïþ4©Ž]õ|*+sN]X¸1c†{ïÕTOu„ïüÅ[ $fRIKKëõØ7,ÛwÒÑØØØoÑɼR _º­àâÕöDï/å+ ‘\!ÿè#7ÄC'.í>oÔØ®†ßoJJ܉Le’4¶§ÊÕ"D]×ìhjŒÖp) ›RõÞ? §Ò°* ¯Ò0+¼ý ÕÒ- ÝÒb™Ê¥!]ÚõðÃ-nö/ÿTǦ¡`¦¡a«W×Ù† §Ý1 Ó2/^Ó믟²¢¢[n¡ÇÙ³o n·ƒÝTÝj’W•KÕª~ê¢W9ñ¨€x¦ªªª;* ëׯ·íÛ·»ÛýŒŒ bój{¢÷—j= ^]IWðPQQ щ­Êɲ2Xð)¾ á_¯Zå†Í©bõ‹/h\àw_k{•†ß°FŒ'h±GMm¬)KKOÙš5mùòKnÊâ‚‚V›1ã†eeuÙ½÷vùn«?¥Õ-j²§ŸþÖ÷Ü öûߟ²­[¿´;ºé’Ã…Y³º{Òô/ôèÕ4ÒjÊ×Ì\ ¤š4@ÇŽfÏÓ¤ŸP €D«úúzËÉɱ¦¦¦žÇêêêlöìÙ=÷û }m¬¨ v{"÷§7ØO  tuÿ›ozÒ¯þÇý‹/Æu^ݯýâ ûÞ÷oãK/¹©J»&O¶Û¾@ò£ïdFC¹NòÉx½Éê¯þ½ä£nûvW¹hYºÔ: {ÂÛ.´k>ï¿yã ;æ{ŽÞx¿>}Ç$“Ÿñ¸ÿùç'ìý÷?÷qѶo¿j/½ÔhK—^¶Ç»fsæÜ²éÓ;\5eÊ”NËÏ¿móç·»µWÖ¬i²·ÞúÑ÷=ÔÕ>üRyðÁï_ï×_Ûù>rõºŽ-ßgøÚ¢EnÑÓS‡ ë÷Kß ¯ø›Œ÷ýàÇðó7©Hmm­f¥À(…Ë—/G@¨€0ž3ª¡¾a5¾ê*¼Æž«¹]Mî÷D\O£mg,rr¢þ”ݻۻïs 6jáF-àøÄß™/ô)-c¢&û'žhtCÄTÑð¯Í›¿r}.;w~æª4ƒ=5„Oë­Üž2Å-rúíÓO»E“ecŽ]üÅ[ $Ϊ¬¬´‰'Ú… ú¬0ôÅ@z2ô˜WÛ½?z@⃦÷Õ4¿j†U#¬¦ÿÕøóºÕ«]ctzÅ­V¯†ú_gþúÅ »ÿþ›nõúââ}Ïir«Ük¦°õëÏÙ«¯žtCÁÔ³¢æú³€<èŽU­%¤µ\tŒ^]°À»G**ç ø‹·øK1ß“6aÂkhhˆèùÁá#ø¾V)MånÖ©h·Ç{ô€ ´¢fçÑzZQ ±Z(Q'9ƒ>”®î'[C8 4c—z>ü!äܹn›9³3â}û*]ŸÉ;ï|áª+/¿|Æžþ¢=ýtƒ=þø÷n¦¯üü6׳¢æú»ïþuºb5Û¶Ú‚?Ø“O~g%%ßØÚµ¬´ô´mÙRk¾yÈŽ¯-³¦GÚíÉ“í§Ü\wlé Ëí:Ñ‘,3äÐâ¡Záè/€HZK#ܺƒÙïýQ¢íìNÓ‰Œ*®±ý¡‡\SìÉW_õ¤ SS¼!œ+q± !ùù×-+«ÛrsozÖ€j0MW¬é†5›—šå_xá¼­\ùµ-YrÙ5ÙkÁÇY³~¶œœ7mñä{oÛÓ÷°Ý÷m²Ë÷>l7îžbgf>e{yÇ6­ùuÚcÍ*¦¦ý?þ”c7•H‚×â =PI2iÃá¼?z@’­Q +ªš2ôÇâbë¼÷^w"¯¾ˆÓ6DU-ðÊßþVWˆ:í ¾jO•Ù„8vSÓß?®táB!CaC¡CáãôŒ§\Q(Q8Y>µÖ……………™… páæ™g¾vaG¡GáG!H‹CÆr{½^Mq¬^›ÂÂ_ìÝw/s¬@ø^z@Pê®f„ÊôÛÖ¬±æÏwÓ†Þ¼ÿ~×$«™z>ÿý>« ƒ ¬ á»ø;T>³_¾õ– 䦥áZM,r÷4ŒKù4¬Kûžyæ7ÜKëªhø—†M™Òᆅix˜†‰i¸Ø¼yÍnø˜¦4^½ú¢V¦áeföÁG#^%xxÛ¯³‹™½ÿþ÷o}Ÿ°£|à&(Ð÷á7Ï<6€hfÄ/|ßå©þÉ÷.þ@= ÉÚØ¾c‡k„Uâæôéîçê¼yvñùçí‹wÞq#¹7܆dßWE…ûŒé‚>[jhWÏ—>{¡†$ª1~ÏžO]£¼æÕ8¯úçž«w õj¬Ÿ3çG×h¯†{5Þ«_øjÈ×’‹]qúš]Lû7žò…vâD÷ þùù¿ð^E0ô{­ ÀnÝ¿ý2i’»¤5¡ô¸ÞÓpß»š Q}ªëçüíbÎ9ß±¡ÀÊw,„ÂÕŒ¤;ÁÑÂjß-Yb?ÿÖØî! á»ø›¸“ZzMíûóoÕ‘+>ê&kì ¨¦ ÖŠöš’øõ×kÝÅZ²¤¤ÁM]¼`ÁU7¬/ùΉ  Íh¨çݹ³Ï‰"‚å Ú¯zÿô½«Û~«2kêgí_.¬]kµ›7óÌ÷.„ñœÉVz÷‡Â9vñwh “K ¥TSý^m=d_ûNtUÉŒÅçS“Ï>k¿£’›Ûz:bFÜfÁÒ,‰Ç·lq•g]PÒ ‰ZOJ•49‰»XôÜsvâÕW]%ü“ýç{—„«4Cr¥ð׋æýûÝɧfÀÓÄ·§Nu'œªnꢂW èÓ¦Ýê !¿NqÜå 7\8yë­/ CðØÕû_³u«û~»l™5Ï™ãªØšmP•4Í6¨ÿß©ß&94Ì'á{— „ˆ:I>ÿâ‹nȤ®€k2ˆúU«Ü¤ƒ©Ž(„(l¨gD=!þ)ŽÕ¯~5ÄkFÌš¸oŸUk½%_ðø¦¤Äõ)¼Ê›Ó§»cGÃýä‹›4äãùl= ˆÂÕŒÄâØÅßáq¢¹¿ëPÓòõ3ܰõhQÓO£<©ìËÛýû¹Uæ'O¾ínÔtÃŒä;våÍçZŸéÕWÝ”îš5Qý~Zgê–ïØÑ„#Z ÷üºu¿N2²kß @Ñø‹·€¿aª#åå®OàÇ9s~­ŽøNÒëŸ{ÎŽ½û®'ÞVT±Å‹¿wk—hö­húCR½‚1$݃í3Ÿ·špäâš5ÖøøãnÆCM†ÐéCU6=¦mzŽÞ‡¡Ø+È÷= W3¸š·ø€¿ ®ŽèdQW´5ìFW¸u©É&‚‡Ü ´2ªµ ®YnîO¶eËqÆ0>vUQ5DUKZóIÇRÏl‰‹¹jŠŽ+­?•È÷ï*  !4;’¦pÕ:ªŽ´ZÝêÕvì½÷Ô0*—l±²ß°êûžµæÙEŒB!Vý#g|ï­úIšçÍsAWï¿úMÔw¢þM%­~”C1\hQýK……7-;»ÛŒ»ì­·¾æ=¢@¸šÁÕ ¼üRÕ‘½{íĦMnJWÍš.€ôWÁ¨/Ye{yÇ–ß{Ü^|ü+ûø£CxœÂÇ®*ošqëÔïo_ûŽÍÄ¥¹43—Ž5 ÔŒnªŽi¯ÁÎä¦ð1sf§<ùÿ§ö²ØÛo7p¼QAÆs2žo“qv¼H+»v¶'Ÿl´)S:ì…ÎÛÁƒŸà-Çîÿ¯œ<èÖ™:ñÚknÍ…W­a¢j\ÇÔ©®"§@¬&M;­…t™X…c—BáJW3oñ7È@×öíǬ¨¨ÅxàºmÞüþrìöËg¾°¡ÙÜ4DP«½«º¦õn´ ¼áÔÌnZ^U»£A‹å†;v§O¿é;vÓKçç_³‡n±yóšÝ”Ò=Öä;×ùΞzê’­XÑ`«V}mÏ?_çÂóúõgí•WNÛÆ'mÓ¦¯ì7ŽÛÛoר»ï³;ªìÃ?³Ý»Û¾}•)´ßxã¬ßvCÜòònÛ«¯ž!€ z@`èÀ¡13fܰ9s~´÷ßÿŸaà ð»wÛ—o½eçÖ¯wSMÿX\üë0À{fͲ†‡{ì–—µ÷Þ;fï¼ó…[LsóæZßÉó +-=e/¿|ÆÖ­;okÖ\´gŸ­·’’olÙ²omÉ’ïìñÇ¿·E‹®ØüùW}'Þ?Zaa«=ôP›Íšõ³;¦ï»ï–›’:+«Ë&Nì¶»ïî¶{ïí²©So»5sfμî;oúÉw²Þæ ã­¾Ï@³-Xðƒïw6ù~w£-]zÙž~ú[[¹ò{î¹:[»ö‚ﵜ³ θõw6m:a[¶Ôú^s›ðAŸ­ÁóÑGGÜØû÷Ç/ôlÞ|Ú÷ÿîî5Ä-7÷—žu‚ ˆ à/Þâ/D@b0ŒåÀOÜ Þ”)·}'v—ÝUcŽ]ŽÝÁ ©ŸßØXc«F¦7®€œ;×m¹¹7 ˆHÔœ®&u 3QÓ:ž@0GÜð$ 1R?Æ»ïVxøàéÒR7e´¦v«·ãkT½\šæøÄ‰nw>xæL—͘q›Dðoñ’Ï[ ŸÑ°kâ‰F7/þ‚ªdêY˜<¹Óžzê²ë©Œ·Z—¤~Õ*»=y²5<ý´[@ŸBòò~vîxàFÜÄÂXYÆ"Þâ/ÞzÊž=ŸÚ²e—Ü•n5æîßSÍR5wn³MÚáúvïþÔSoµ®ˆ¦óíÈÉq³j çþáxì&e©©©±¢¢"KOO·‘#GZII‰µ¶¶F¼½/•••Yff¦£´´Ôóí‰Þ®tÞâ/ÞÆ“òò*›7ïª[»aãÆSø›"3Z½úêI7]­ú‚^|ñÜ h$ÞVoÛf× ì§Ü\·à!ïCr»I@,X`ÕÕÕÖÝÝm¶nÝ:8"ݬ _ŠÎÏÏ·¶¶6Gaa¡{Ì«í‰Þ= (´è[nîOn6MeŠ'Ã… MG«Ð¡õ58FâùNmÜh7§O·«óæ¹Úy_†6Ãb–‚FZZZÔÛu2¯è—nçååy¶=Ñû£ÂÕ À[üÅÛD_× jNN‡ëPC2þ&?n§5(ô¾j­ ­9‘HoÕR÷Üs®?äÒ²eöéž=|P‰ªªªÂV8úÛž‘‘áBJ``Ñc^mOôþèa<'à-þâíP@S°>ýtƒëQ_À¾}‡ð7 Ñ:ZwBåZwB‹Ü %oïÚeO>iS¦Øù^°Oè¡ÄkÕ×+yçXSSSTÛ¥#FÜñX`Åd°Û½?* \ͼÅ_¼Jh&¤GùÁ­­èð79ÐÂx‹5¹©U¸+*>ÒÞÛ¾ÝZŠŠìúØW›7ó}@ÄÕÖÖZvv¶ÕÕÕEµ=* zƒýª  À%_ÿÁ§¹Ï}îsŸûÜç}Í””ŸÝæÌ¹å;™=?Côþ¾}M¶`A»åäܲ—^j´³g¿Mª×e×.»å !?Ιcg÷ïçý÷“6€TVVÚĉíÂ… Qmï¯'Cyµ=Ñû£ÂÕ À[üÅÛ¡Y3—iѺxÏhKo<@DHLøn €D$Ð÷Å@¶Kki„[Wc0Ûã½?* \ͼÅ_HVoUQ%DUFuò›jÇîî݇måÊolêÔÛ6þU{ûíšaííçï¿ï†dݘ1ÃN¼öß ØK çý±$;:Ö‚v³g·»^<‰ ååGmÉ’ïÜŒVO<Ñh;vT¥Ôÿ_ÍéjRW³ºšÖ9& h®râ/Þþâí@Ð,Yš-K³fiö,üõ†mÛ¾pžjÈÛŠ öÑGGRÖ[MÓ«éz5mo£ï|IÓøòÝ@AÃ(€0ÎñðoŠVÚ^µªÞ,k­'‚¿Ññúë_YQQ«/Ôݲ5k.ÚÞ½•»¿¡… µ€¡2Ô‚†ZØï¢ø‹·ø )ì­VP×JêZy[+«…þdð÷ÀOì•WÎØ¬Y?[nîO¶aÃi÷ÇnßT•—ÛÕyóìæôévjãF¾ ˆHu¶m«v34édzËÂkè­*]•CÕU=6oþ _r‚þÆöSn®]+(°êmÛð„‚¨€þâ-þBª{»qã)7]ì¼yW­¼¼ Cýêëе… pý»Qrð [¿Þ:rrìûÅ‹íHEß Dà/Þâ/¤²·êyî¹:w²½lÙ%Û³çÓ”õW3X=þx£›ÑjÉ’ËöÁG9v=¢òã­áé§]È׫VÙ¡}ûøn € * €¿x‹¿ÊÞîÚuØž|²Ñ¦Lép éi%ïTñwëÖWÒÏ<óµ[Óƒc76ݹÓ~xä»yÿývº´ ˆHu¶o?fEE-öÀׇuσðµJy~þ57 M¡kß¾CqâË·Þ²öÙ³­-/ÏjÞ~O ˆ W:oñRÝ[œÏ˜qÃæÌùÑÞÿóaãïþýŸØK/µ™3¯»EÿûSq«öpìÞÙræå—íÖ}÷Ù•GµÏ>ü ˆÆzÞâ/¤²·šjV³@M™rÛõDÄbhR¼üýøãO]¯‹¦ ..þÑÞxã8ÇîPéٷϾyæ×¢+“¤?„Dðoñð6F(x(€(ˆ(x¹F¬ý­¨øÌ–-ûÖ5Ù?úh“bƱ;4QD•UDTQ… z@ …ÑP, ÉÒÐ, Ñʯõ½÷ŽÙc5¹­4»×‡~Æ{˜$¨'D½!êQ¯ž@ T@¸Zx‹¿x›â¨9]MêjVlEÁkß|ó¸/$5»¡VÏ>[÷i…9v½C³di¶,Íš¥Ù³ð—B¡„ñ²€·ø‹·)Œ·5s”¦í}â‰F7o¢üÕŒVZTñ¡‡ÚmÆŒë¶~ý9·¾ Çnò»‡öï·úU«\ˆÖÑz"øK!€p5ƒ«E€·ø‹·)Œ* ⤠5yôÄ0þj_ëÖ·éÓoX~~›½úêIFx_†ß±«Ôµ’ºVT×ÊêC¡?„ ¢ ”—W¹Åü´¦†ª±mŠÿÔV­úÚU_æÍk¶­[¿ä=Hª·m³köSn®ß²…„«\-¼Å_¼Mu4½mnîOVPpͶm«öÔß;ÚÒ¥—]cùãÓõI8v‡6§6n´›Ó§ÛÕy󬪼œ „ÂxNÆËÞâ/Þ¦vÈ\†Á/þÞ**Ž Ê_™… ¯¸a^O?ýmØß©sìª?¤î¹ç\È¥eËìÓ={è!€@¸šÁÕ"À[üÅÛTæã+}¡Á ™Ú·ïЀüݼ¹Ö~¸Åî»ï–­^}Ñý>|åØ æð®]Öøä“Ö1eŠáû$Ný!T@= C zä‘ìþûoZiéi÷˜Öy衟ìž{ºì~¶²²_ûF´È¡ž3kÖOîñ—_>ãé‡0|9¶}»µÙõ°¯6o¦d¨šš+ò½Aééé6räH+))±ÖÖÖ^Ï)++³ÌÌLGiii¿¿³¿çv{¢÷G„«E€·ø‹·08ÞzëK›=»ÝfμnÓ§wZmm—û›zâÄ-ßý_‡k)¤´Ú¦M_1£ÇnTœxí5»1c†ý8gŽ}þþûT@†JY°`UWW[ww·uttغuë\ ñ«¢¢Âòóó­­­ÍQXXè ¥þž?Øí‰Þ= Œ—¼Å_¼ïúCrs;|¡£÷ßÙ¯¾2ËÎî²wÞùŸ8vÍ'ØÅ5kìö”)vyÉ;¼{7= CM "iii=÷ur®Tç—nçåå…üùþž?Øí‰Þ®Þâ/Þ‚wL™òKŸk³²ºñ‡c×Ûþ_ðPQQ Q0¡2DTUUÕ«’‘‘áBI`@Ñc¡Ôßó»=Ñû£À;~¸ÃNžìýwöüy³Y³náÄ ÅÒ, ÍÒ-z@¬úúzËÉɱ¦¦¦žÇFŒqÇó+$ÁêïùƒÝžèýQájà-þâ-xÇoœõýµžòkøèîiDŽÝX¡æt5©«Y]MëT@ ÚÚZËÎζºººUR©¢7ØO  ÜØ?ÿÁ§ãq_A1žûKµûø»û×®]ÃüMÊûú^ÀïïðÁw6wn—Ýs†Fÿbï¼ó-þx|?ø_üùí~}½].+sÓö6/_n—|I8ÙüKÑûH¸ë®»"þ•••6qâD»páBD=zl =ÏìöDï W‹oñoñvx¡… µ€¡2Ô‚†ZØ H€, @úFä׎;l„ ÖÐÐv–)MÍÛ×,QÁC˜ú{þ`·Ç{ô€¤UååvuÞ<»9}ºÚ¸‘¾´{÷îž“g¿ZZZÜcTE%PZ#Ô:}õP„{þ`·Ç{T@¸Zx‹¿€·ø‹·)æ×oØO¹¹v­ Àª·m£¨1cÆXggçë±±cÇÆ¥wD ÆSñÞ뀤.ø‹·ø x‹¿x›ÂI à/Þâ/à-þÞRñ.€¨é|Æ nÝÀrýúu9r$I Ä»:‚×ý`* €¿x‹¿€·ø xKÄÓ’––f·nݺ#p´¶¶ZFFIÀ_¼Å_À[ü¼¥Ä»¢fó™3gZKK‹ Z äÂ… .˜L›6¤@ðoñðo©€x@z­~H[[[D¿#ðgúRSS“-X°ÀUT„n766†ýeee–™™é(--õ|{¢÷G¤dˆ?„¨’žžîˆv ÞPD•”-[¶¸êŠØ¼y³Í˜1#ä難¨p3p)‰ÂÂB÷˜WÛ½?* \ͼÅ_¼üÅ[HÙ ˆ— @újfWÐ %ÌëMðK·óòò<ÛžèýÑÂxNÀ[üÅ[À_¼…”íñr¦«PdñâŮꡩ~ŦM›Üc¡¤aZzž_ºØ?Øí‰Þ®fÞâ/Þþâ-¤l$\%«rõêU7¬Ëß'¢ÛjzÈïQS¼WÛ¹?½Á~UPPà’¯ÿàÓ¿Üç>÷¹Ï}îsŸûÜç~¬ïÇ=€L˜0Á-:ËR\\ì* = EEET@¨€p5ðñðo!Õ* Gu á‘ÎxMé«®"ÑWO…ój{¢÷Gã9oñoñR¶$Ô¼b ý!¡ˆŽú>{@gÁ þ9ÿ¬RZ 1ܬSÑn÷þ¨€p5ðoño H@z(ÂU)ú 1º|ù²råŸæW·õX¸à¢µ4­«1˜íñÞë€ÀP%©§á ðCqT@¸šx‹¿€·ø‹·@@ω¿x ø‹·ø xKH¼Hgg§7ΓDðoñðñ¨€„UàúÑö€ ä @HÜ›ÐñÜ_ªÝÇßØÝ¿ví~àoRÞ×÷~ào2Þþ†¿q ZPÁ XzlìØ±žU<·*!T@¨€p5ðñðo!Å* ¡ˆW= jÊ áNÐûê©Ðc^mOôþ耔ê îÏPô†]éʽЄ³g϶ѣG{@4ÌKîB„†c-_¾<äÏùg•Ò°°p³NE»=Þû£ÂÕ À[ü¼Å_¼* á Tú¢žU+X›7ovFC¯–,YÒ« ½¯çk-pëj f{¼÷Ç: © þâ-þÞâ/ÞÂP÷7!ë€(qiq@…¡Û'OžŒÛú!áúA†Ãþ¨€p5ðoño "€= W3¸šx‹¿x ø‹·ø;lˆf¤Ò^¬„Ž’/€0žñðoñð–¸I“&õ  t%tDðoñðñ¨€„•‚Æ@Wxø‹·€¿x‹¿€·T@â@4å®ÏCô€þâ-à/Þâ/à-= 1 ÇŽ³©S§ºU¼À_¼üÅ[ü¼¥ÓjtfÁ¢è‰Iz(è¡ø‹·ø x‹¿€·T@< ˆ>ôø‹·€¿x‹¿€·ô€@ \Íàjà-þâ-à/Þâïð 'Nœ°‰'º!WB·õ¢èñ4€TWW‡lB'„PüÅ[ü¼Å_À[* žU;æÎk---=évQQ‘[#Ñø‹·ø x‹¿€·ô€x@4䪳³óŽÇ»ºº,==¤@ðoñðo©€x@:::îx\¡„BÐâi™4i’åååYss³uww;t;77× ÏBT@ñoñð– ˆgD桚ÐÏ;GR ðoñðoéñv^ U;4äJè6რà/Þâ/à-þÞR‰I¬«&ý©°°0¢ç•••Yff¦£´´Ôóí‰Þ= ’= ^‘pÚ·oŸë7éïy–ŸŸommm…=æÕöDï W3oñoñR¶rèÐ![¾|ù—””ØáÇ= 7nܰììlkllì7€èd^o‚_º­àâÕöDïÆsÞâ/Þþâ-¤lȘ1c¬½½ýŽÇõظqã< ëׯ·íÛ·GT)ÉÈÈp³qù¥ÛzÌ«í‰Þ®fÞâ/Þþâ-¤l$\¸ë®»<ù]uuu6{ö숇jõµ]ë•xµ=‘ûÓì'P.ùú>ýË}îsŸûÜç>÷¹Ï}îÇú~܈š¦[ZZîx\kŒ9Ò“¢ðqùò刮fp5ðñðoñw˜V@tâ«JÇ¥K—z"lhhp!¡¿>†HH¨uFÒ“¡Ç¼ÚžèýÑÂxNÀ[üÅ[À_¼…”íQ¯G¨€pýúuOgÁ õ¼àûþY¥Z[[ÃÎ:íöxï W3oñðñ¨€ ·š4iRÏB„YYYîd:šu@"Y¤¿"i-pëj f{¼÷Ç: 0TIêu@¢•BÏpÞ®fÞâ/à-þâ-PAÆsâ/Þþâ-þÞÒ’ˆR^^îÖ œvWC²®\¹BR ø‹·ø x‹¿€·T@¼ {÷îíéÛ 555ýÎä„’?€= q ãÇ· 6¸éwˆfÀè: ˆ à/Þâ/à-þâ-P «Àмòù@WBGô€þâ-þÞâ/Þ= a•––f·nݺ#phÞþVóFT@ñoño È€¤fó™3gZKK‹ ]]]váÂL¦M›FR èñ.€444„\ ]«z#* €¿x‹¿€·ø xKÄÓixBWBg ^z@ññoñð–˜Dðoño©€@ Ã+€455¹!W’ÐÇŽëú?&NœHJ ø‹·ø x‹¿€·T@¼ ¹¹¹V__ïn/Y²¤WzQQIÀ_¼Å_À[ü¼¥Ä»¢µ>:::ÜíqãÆ¹àqæÌ«««c%t* €¿x‹¿€·ø xKÄÛ¢Àá—ÖþÐýÎÎNwŸ•Ðéz@< ™™™®âqéÒ%>FåWUDÛÀ_¼Å_À[ü¼¥âYщo`ßGqq±{\ãдB:¢ðoñðoéñtÞñãÇ»áV&Lèy,++ËÍ…¨€þâ-þÞâ/à-Ö!€$O3fŒ-]º”*>xø‹·€¿x‹¿€·T@b@´þ‡¦àU߇f¿ÊÉɱšš»uëVT3iùéKú½ZS$==ÝMí[RRb­­­agYY™k‚¥¥¥žoOôþèa<'à-þâ-à/ÞBJö€\½zÕ6nÜèú@ü!B½ :¡nnnŽzJß@-X°Àª««­»»ÛÍ®µnݺ°‹VTTX~~¾µµµ9 Ýc^mOôþ¨€p5ðñðoŸTý8qâ„M:µgMU,òòò@‚¥ ¢ßJ:™×›à—n¾†ÁnOôþ耔ë‰DêÑp)­îe©ªª [ÑÐ0…”ÀÀ¢Ç¼ÚžèýQájà-þâ-à/ÞI©¯¯wý&ášßûú=“ÁnOäþôû TAAûç?øôo<îë}ˆçþRí>þÆîþµk×ð“ò¾¾ð“ñ~ð¿ø3|ü{éììtŽÀFr?ZÄËR[[kÙÙÙVWWöyT@¸šÁÕ À[üÅ[À_¼ÅßaZ™4iR¯ÀH¸ªÁ@Hee¥Mœ8Ñ.\¸Ðïïé«§Byµ=Ñû£R¶DAãàÁƒ1‚µcÇ7³VCCCD?çŸUJSõ†›u*ÚíñÞ®fÞâ/à-þâ-P‰ 7"šu@úZ¤¯íÏé+¸h-pëj f{¼÷Ç: © þâ-þÞâ/ÞÂP÷7îD• ]µO¤´@ápÞ®fÞâ/à-þâ-PùMÇŽsë~ô·29žè‰k 5<*šY°À_¼Å_À[üÅ[ Òoz(¼èAô€0žðoñoDájþâ-à/Þâ/à-þ@ Ã<€œ8qÂ-¨!WB·õ¢ø‹·ø x‹¿€·T@< ÕÕÕ!›Ð !ô€þâ-þÞâ/à-= žU;æÎk---=évQQ‘[#QüÅ[ü¼Å_À[* ž ¹êìì¼ãñ®®®!±``˜ŽŽŽ;W(!€PüÅ[ü¼Å_À[* žI“&Y^^ž577[ww·C·sssÝð,Dà/Þâ/à-þÞÒâYQ£y¨&ôsçΑ¨€þâ-þÞâ/à-o§áUÐPµCC®„n>èz@b@À_¼üÅ[ü¼¥B!€0ž“ñœ€·ø‹·€¿x‹¿É@Ôßq×]wõÜ…ÿ9ˆ à/Þâ/à-þâ->P‰:€(Xhú]ÿíPøŸƒèz@‚EájW3ððoñ ˆÀ_¼Å_À[üÅ[ $äp¬h¶!* €¿x‹¿€·ø‹·@ijÒÞÞq l\¥²²2ËÌÌt”––öû;û{þ`·'zô€@Jõ€„›ýÊOFFÆ€g_ª¨¨°üü|kkksºÇB©¿çv{¢÷G„«€·ø‹·€¿x )WñÏtåŸn7]Éß¾}»'D'ç2Õ/ÝÎËË ù{ú{þ`·'zô€0žðñðo!e{@¼œj7TQ%¥»»»ç¾n‡«®ô÷üÁnOôþ¨€p5ðñðoY°b@úz<\ðéïùƒÝžÈýé ö¨‚‚—|ýŸþå>÷¹Ï}îsŸûÜç>÷c}?îäСC¶|ùò;/))±Ã‡S¡ø‹·ø x‹¿€·T@¼ cÆŒq3^õ5 Ö¸qãbÖ¢ÇÒ“øüÁnOôþèa<'à-þâ-à/ÞBÊö€„›:w ë€ô7 VkkkŸ³Dÿ\Ïìöxï W3oñðñ¨€ü&ÍvÕÒÒrÇãÍÍÍ6räȨ§ô –ÖÆµNÆ@Ÿ?ØíñÞë€ÀP%îD'¾ªt\ºtÉõ.ˆ††w’ÞßT²^)===®ÍòñÞ®fÞâ/à-þâ-P èõµáõë× ïÂxNüÅ[À_¼Å_À[z@â> ¯†[Mš4ÉUDVV–ëg@T@ñoñð– È]%_z@ ®fp5ðñðoñwø¹s纅ó‚{@: /¢ðoñðñè «ùóç÷„à’––FR ø‹·ø x‹¿€·T@¼]¤ººº×ƒškáÂ…¶sçN’= @ˆw$pQ¾ÀÛZdôèÑ$* €¿x‹¿€·ø xKÄÛÒÖÖÖ³@_ee¥»}ìØ1z@èüÅ[ü¼Å_À[z@¼ {÷îµ’’w{êÔ©½z@ÆGR ø‹·ø x‹¿€·T@b3 oWW—?ÞU>ÆŽk$z@€Ö!€p5ƒ«x‹ø‹·€¿x‹¿Dà/Þâ/à-þâ-ÐZMMM6iÒ¤ž!Xz¥þ‰'’¨€þâ-þÞâ/à-oHnn®Õ××»ÛK–,éÕ„^TTDR èñ.€dddXGG‡»­Y¯<Μ9cuuu6räH’À_¼Å_À[ü¼¥âí: ~¥¥¥¹ûþÙ¯X„À_¼Å_À[ü¼¥ÄÓ’™™é*—.]rácÔ¨QîqUE´ QüÅ[ü¼Å_À[* žøö}»Ç•ÂfΜIR èñv^ÿâƒ&Lèy,++ËÍ…¨€þâ-þÞâ/à-¤ZDAfÁ‚®á]èvcccØŸ)++sCÀDii©çÛ½?z@Ï x‹¿x ø‹·’= ñдiÓlË–-n±yóf›1cFÈçWTTX~~¾µµµ9 Ýc^mOôþ¨€p5ðñðo!e+ šñÊ?ýn0^Í‚Õ×ïIOOù|ÌëMðK·óòò<ÛžèýÑ)Û¢UÐG š–× -^¼ØU=º»»›6mr…[›DÏóK·õ˜WÛ½?* \ͼÅ_¼üÅ[HÙ ˆ‚ÆÁƒc:ëêÕ«½‚Žn·´´D´6Ià%^mOôþèa<'à-þâ-à/ÞBÊö€xUå'Mí« H`HQQQJV@ôû TAA;ðüéWÿÆãþÅ‹㺿T»¿±»¯É-ð“ñ¾¾ð“ñ¾ü~þÆ=€hê]5NÇR}…œpÁ§¯ž =æÕöDïHÙcÇŽÙÔ©S­µµ5fD3^©ï#°$p¬à!LþY¥ôšÂÍ:íöxïÆsÞâ/à-þâ-Ðp2 ¯fÁº|ù²r¥™¯„në±p=ZK#ܺƒÙïýÑÂxNÀ[ü¼Å_¼z@šÐCþþ¦äû£ÂÕ À[ü¼Å_¼* ˆô€@ \Íàjà-þâ-à/Þâï° sçÎuÓÆÆªÑÂxNÀ[ü¼Å_¼z@œæÏŸß6‚H¼z@ T@¸šx‹¿x ø‹·ø›"D³6UWW÷4¤Kííí¶páBÛ¹s'I ÄÛixûº­õ:FMR ø‹·ø x‹¿€·T@¼ þ•Ð5=meeeÏ…ô€Ðø‹·ø x‹¿€·ô€x@öîÝk%%%î¶VDì7nI à/Þâ/à-þÞR‰Í4¼]]]6~üxWù;v¬uvv’èz@X„ÂÕ ®fà->à/Þþâ-þ&a¡Ïƒ>ôø‹·€¿x‹¿€·ô€Ä-€¨ñQüÅ[À_¼Å_À[* q &L°ëׯ“èz@b@Ž=j3fÌ虊QüÅ[À_¼Å_À[* 1]$ô‡Ðø‹·ø x‹¿€·ô€xÞ„Š´´4’À_¼Å_À[ü¼¥Â4¼¢ø‹·ø x‹¿x T@¢[„z@ñoñð–¸öövÀ_¼Å_À[ü¼¥âM 7û•ŸŒŒ ÏN¸ëëë­¸¸ØýN­=²{÷î°Ï/++³ÌÌLGii©çÛ½?z@ ¥z@ü3]ù§Û F'ÒÛ·o÷$|444XVV–UUUYww·µ¶¶ÚÚµkC>¿¢¢ÂòóóÝÚ$¢°°Ð=æÕöDï W3oñoñR¶$Sí®X±¢ßŠG t2¯7Á/ÝÎËËól{¢÷Gã9oñoñR¶$5j”•——Û¸qã,==Ýý'ÕcJ¦¥J‰_º8l°Û½?* \ͼÅ_¼üÅ[HÙ H<¤a^+W®´ÎÎNëèè°U«VÙÒ¥KÃ>?\¥f°Û½?z@ åz@â)U<üRQ%$+ zƒýª  À•ÞüéWÿÆãþÅ‹㺿T»¿±»ßÔÔ„ø›”÷õ½€ø›Œ÷ýàÇðówX5ep ¯ž =æÕöDïÆsÞâ/Þþâ-ÐC©]îB„†c-_¾<ä&ÿ¬Rš-+ܬSÑn÷þèa<'à-þÞâ/Þ= qÖæÍ›môèÑnèÕ’%Kz5¡÷ÕC¡µ4­«1˜íñÞ= @ÈR¸~á°?* \ͼÅ_À[üÅ[ ‚ ŒçÄ_¼üÅ[ü¼¥„BájW3oñoñ hX „BájW3oñoñ ˆÀ_¼Å_À[üÅ[ @¸šÁÕ ¼üÅ[À_¼Å_¢èA®fà/Þþâ-þÞâ/„ÂxNÆsÞâ/Þþâ-þ@À_¼Å_À[üÅ[| B!€@À_¼Å_À[üÅ[ ‚ ŒçÄ_¼üÅ[ü¼Å_„ W3oñoñ ˆ „BájW3oñoñ ˆÀ_¼Å_À[üÅ[ @¸šÁÕ"¼üÅ[ü¼Å_„ QüÅ[üÅ_¼Å_À[* ã9Ï x‹¿x ø‹·øK  mĈý>¯¬¬Ì233¥¥¥žoOôþ¨€p5ðñðo HŒµoß>ËËËë7€TTTX~~¾µµµ9Zô˜WÛ½?z@€ëÆ–mýÌ+ú¥Û .^mOôþ¨€p5ðñðo HŒµ~ýzÛ¾}»»Ý_ÉÈȰîîîžûº­Ç¼ÚžèýÑÂxNÀ[üÅ[À_¼z@b¨ºº:›={vÏýþH_ÛÓÒÒ<ÛžÈýé ö¨‚‚wàùÓ¯þÇý‹/Æu©vcw¿©© ?ð7)ïë{?ð7ïûÁáçï° —/_Ž8€P µ8úb =zÌ«í‰Þ= Œç¼Å_¼üÅ[ $Î$Ü}ÿ¬R­­­agŠv{¼÷Gã9oñðñèÂDÒZáÖÕÌöxï W3oñðñ¨€ !¥§§ëýÑô€ W3ðoño©€@ Œçd<'à-þâ-à/Þâ/QüÅ[ü¼Å_¼* œÊ@ ˆ à/Þâ/à-þâ-PAÆsâ/Þþâ-þÞâ/„ÂÕ ®fÞâ/Þþâ-þ@= @„ÂÕ ®fà->à/Þþâ-þ@= €¿x‹¿€·ø‹·@"€p5ñðoñð z@€Dðoñðo©€@ Œçd<'à-þâ-à/Þâ/QüÅ[ü¼Å_¼* ˆ@!€Pájà-þâ-à/ÞDà/Þþâ-þÞÒB!€p5ƒ«€·ø‹·€¿x‹¿DÐ2ÄTSScEEE–žžn#GŽ´’’kmm û3eee–™™é(--õ|{¢÷G„«€·ø‹·€¿x T@b¤ Xuuµuww[GG‡­[·Î’Pª¨¨°üü|kkksºÇ¼ÚžèýÑÂxNÀ[üÅ[À_¼z@â(‘´´´Ûu2¯è—nçååy¶=Ñû£ÂÕ À[üÅ[À_¼* qTUUUØ HFF† )Eyµ=Ñû£è‰“êëë-''ÇšššB>gĈw<X1ìöDîOo°Ÿ@¸Ò›?ýêßxÜ¿xñb\÷—j÷ñ7v÷õ‚ø›Œ÷õ½€ø›Œ÷ýàÇðówXÚÚZËÎζººº°Ï£ÂxNÆsÞâ/Þþâ-þR”*++mâĉváÂ…~ŸÛWO…ój{¢÷Gã9oñoñ艡vìØa&L°†††ˆ†@ùg•ÒT½áfŠv{¼÷GÐGé„¿/ÂõPh-pëj f{¼÷G„«€·ø x‹¿x T@†´@ápÞ= Œç¼Å_À[üÅ[ @¸š¿x ø‹·ø xK„B € * €¿x‹¿€·ø‹·@„Syã9ω·€¿x ø‹·øKAT@ñoño "€@ \Íàjà-þâ-à/Þâ/Ñø‹·ø x‹¿€·ô€@ \ÍàjÞâþâ-à/Þâ/Ñô€ W3ðoñoñ—B¡„ñœ€·ø‹·€¿x‹¿ô€ * €¿x‹¿€·ø xK„B € * €¿x‹¿€·ø‹·@@ÏÉxY¼üÅ[ü¼Å_„ W3oñoñ¨€ z@€„«\ͼÅ_¼üÅ[ü%€ z@ñoñow•••Yff¦£´´” à/Þâ/à-þâ-PA±QEE…åçç[[[›£°°Ð=FЂ<—‡R«_º——Gðoñðñ¨€ ï•‘‘aÝÝÝ=÷u[Ñø‹·ø x‹¿x ô€ Ï5bĈ;KKK <üª¸¸ØæÌ™ãª)¹¹¹îßxÜøá‡ãº¿T»¿±»?þ|üÀߤ¼¯ïüÀßd¼ï?†Ÿ¿©€ „B!”Œ"€ õÕ¢ÇB!„"€ Ï埫µµ5âY°B!„"€ ¨¥µ?²H°{Câ ÅM=àþâ-þ"¼Å_¼E©í/ñe‚¿x‹ðoþâ-þ@B!„BÃO„B!„!„B!DA!„B!НFŒÑòV555VTTdééé6räH+))qkÄ ïüÕZ;~—/_nÍÍÍã±ä1ß±ûÞåû×{Õ××[qq±eddØ„ l÷îݘÃcwÔ¨QãšššlÁ‚î¸ºÝØØHAÃÿKy+}yTWW[ww·uttغuë\ AÞhîܹvìØ1ëêêroÛ¶Írss1ÆCíÛ·Ïòòòø~àû6iÔÐÐ`YYYVUUå¾tÑgíÚµ#>|8ª5ÏК6mšmÙ²ÅýM›7o¶3f@Ñà¤?†iiiC©‚¼Ñ7,;;Û]ãûïÛdÑŠ+¨xÄQ3gδ––Œð@wÝuWRþM#€ þ qéŠØ…»íÛ·»ªòFëׯwžòý›ï[ [щɓ'»+ÈÉ×òòr7nœ;yÓz ííí£¿i«W¯Æ´xñb÷] ¿gbÓ¦Mî1"€ ¨¥1É999nŒ'òþØcÇŽµË—/cˆª««³Ù³góý]ºtÉæÏŸo/¿ü2fxô}°råJëììtC_W­ZeK—.ŘèÁtCÞ7ºzõªMš4©çošn'Cu‰‚ CTµµµn(‹NêPl¤«E[·níuÒŒ¢—| s|?ÄVׯ_·ÌÌLŒð@jÞUððKA„¡™ÞëøñãIqu>™¤‰T ìI†QD‚ª¬¬´‰'Ú… 0#¢ÇÆ»ïfj"€$£4k[pQ(AÞJ“Sœ9s#bü÷+þ¦@dˆiÇŽn HJÔ±‘Æû§(Ô œfbÉÏÏǾ†¼Ô(í¯0iØÅc=ÆXz¤t »RŽ¥)º‘w:qâ„ È[iÆ+õ}ö€0 Ö'\匟·øëT]Ò´…òtôèѬ³BIÊcwüøñ®ÿ#ðª=œ4tEß zµdÉšÐ=–ªLšy+]”ð¯&t;ú !„B!B!„Bˆ‚B!„B„B!„!„B!„ !„B!B!„Bˆ‚B!„B„B)¢dY”“ÅCBˆ‚Bh B@B!!„ !„’;|¼­²²ÒfÏžmééé–‘‘aÅÅÅÖØØxÇó:äž§çþž'NXQQ‘{<--Íf̘a¼ãµ¼÷Þ{îçîºë.5j”­^½ÚÚÛÛ{=gÏž=6iÒ$÷Z&Ožl»víºãu_½zÕ–/_n#GŽtûÓïZ¶l™„"€ „BC<€|óÍ7=)„ø«ÁÏ»|ùò¿C'ýÚX1éììtegg÷ûºTÅð+??ÿŽ×S__Çë×kuuu¼¹!DA!”l¤¿ÇÃõ`hT_ü‚CŒÊÂ… ]àÐã} Ó°«H^¿"ô3òµnÝ:knnæÍF@B¡á@ü¡A•“pò‡†ÀaYÑõ€¬X±ÂÆŽÛ+È(ˆ „!„ÆDÍçÚVUUö5ø+%~i8WðïtV ÔsräÈ·]û@!B!”`3Æ «IÜërúôi7ûÕÔ©SíÒ¥Kî15ïÝ»× ¿TÐïPXPÈ¢E‹îø½Mèׯ_w,X°àŽçÍ;×>ì~¤Y¸´ýÁäÍF@B¡DKÞ4Um¤Áb DR3øO<áú;ô<M“8-®Â‰†a©ÿcâĉV^^ÞçïÕ4¼YYY®š¡P£ûÁÏÓï]ºt©û?ù§ôÕ,z@B„B!„"€ „B!„ !„B!DA!„B@B!„B,@!„B@B!„B„B!„"€ „B!„ !„B!DA!„B@òäÀþÝï’„ %QA!„ø[†!¾´B!þ–!B|i#„Bü-Cˆ‚_Ú!„ø[†!¾´B!þ–!DA(æ_Ú---¶dÉËÌÌ´´´4ËÏÏ·#GŽDüó#FŒˆè9B¿Ô¨Q¶téR»páBÌþOþý…zmMMM¶`ÁËÈÈpèvcccÈßWSScEEE–žžn#GŽ´’’kmmxû@__  û}^àïëë÷êõé÷ø_ßòåË­¹¹9ìשׁª²iÓ¦¹ŸÉÊʲ]»v…ÝŸŸ¡¶…ú?Dâ]YY™;>Eii逽 ÷ó±Ô@½ðjñúœõ÷Þ ôÿëõç¶¿ßçõëèç6?gDAˆâ¤À¡?·nݲîîn;}ú´-Z´Èóâ—öS^^ncÇŽéÉQ¸×¦?ø[¶l±®®.ÇæÍ›mÆŒ!Ntª««?¶nÝ:÷Ç<ÒíÑz·oß>ËËË‹(€„ÓܹsíØ±cîÿª×¸mÛ6ËÍÍ ùü3gÎØøñãíøñãî¾ÂÊÚµkôžGú¼þ¼«¨¨pÇh[[›C'vz,Ò}Eúóñ#ñÜG<>g‘÷ý¿{õ¹tÿ^½¾~nSñsFA„†S™0!4ýHWKÃéêÕ«¶xñbwÅQÏ?~Ï•³H¯êöµmçÎöØcõzLWÍFí®Òéêí7zmß°aƒ»²«+xï½÷^Ô˜ïºë®;Ó>#•þˆ‡ó­¿í‘œ8èÿží®ðz}ÕßÿWï÷Þ½{½¿h^W°w:©ñŸ Iº­“»H÷éÏ÷'ß¹›ï$Îlòd³‡6ûì³ÁHëï31>gý÷^àGû¹gÈç6?gDAh¸< ý‘xùå—íÊ•+}nÏÉɱ“'Oº?Xºê¨““+V è__ÏÑZàøõÚk¯¹Ê‹®ži?+W®ìu5pãÆ.üh{gg§{ÑþaÖ~]=ÕÿIlÚ´É=©4l"\…#x{¸! ¡´~ýzÛ¾}{ŸÏëë¾NuB1Ùw†¬ÿ[¸ý^] %½/ò8'FÁÞ)øê5¾~=é¾"ýùþÂǃšïsðëýóç½?Méï31T>gý}.¼:ÁïïsÍç,šŸ‹ösË猂 @~“ª«W¯¶qãÆõ\ × ?,'4Ñ)ð Üßk A:qÒIµ_ª 1à^œÈ¨ª3iÒ¤žÊn«&Õ××»Pêµôµ} '2uuu6{öì°#”.]ºäN *ûڟаœË—/G}BéØóžEêÝ@®²Gúó᤬æ~)„Æ6€ô÷™*Ÿ³þ>^þ>·‰ ý}nùœ@¡ÿ×ÞÙ#§Cat—iÒ±:z¶ÂPÒRQ°†°š4ysüFáýaþÂ93š2Ø–}}õIW7¯-@JC­*C²`=HìD™ý`zѬàãPˆV¾úBJË~Jål6ëFRãXò’5ûý¾ ¯ £ÑR_z|´,jÏýt:u A/ ÈÕjuvû+ÝWé÷SÜj„ŽÜiC,ôg@R6ñ vVrßÕÁo±Û{ Z»}G;S€ˆDDòãã5ÄUÇ™eX¬Jö ã²X,ΜÝ\øRIvžårù=ŸÏ»0 `$1^kbÓ9†k×€p~œgKžÊ¦³^¯»ŽÛñxlªo ¹´]ÿ=íF^i?®)au^‡t¥ˆ!§:ádç!$ïp8tïo™'×v!»×ýšì<¹ï§¸ÕétÚ­àäøŒ·ËÙÄ£í,wíÆîàçìöÖ€Ôl÷Žv¦ˆÈ_ Y°XŒˆã`4–)s¨Æ1âÔ“ŸžzFÏpd±"¥kåH9ÈP4t´†Â5è×;H¹¹ÝnÏêY×€àÉeçÉBÒé 9ñ)¼Î­‰HýfI}ÍñÕ F6i/>g›v"ÕæP=íŸû?%áºó®×³ÙŸoMǨä·L%ÿŸàÒq¤¾_#B˜ ùøø?ó1F,l€t°-C»œM<›åì¢ö^¨±ÛZ;+©Ónµ3ˆ(@Dþ–Ñ—‰(@D|h‹ˆˆèËD"âC[DDD_&¢ñ¡-""ú2ˆˆm}™ˆD|h‹ˆˆèËD "7yh[,‹ÅòêED""""""rÿ¢¡*á¤úIEND®B`‚Multiverse-multiverse-0.7.0/charts/uncontended_mono_update_bar.png000066400000000000000000000523141174000617100255720ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxT“IDATxÚíÝ}Œ]å}'ðHUUUUUUªªªTU¥ªêQÿèn·Ûív½¬ggd×k×^S“’À–@IX¿`—âšÂf™ÄëYèº!‚O'-6IRFdpˆ À®]wXÓà,Ø5`yM1YSFvçÙó;ögîܹ÷̽¶Ïç+ý4÷ÞsçžsÏË<ç3ÏyùHiS>bˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆtpÿÈG.ªfß#WƲ¼Æ7ù÷>úÑNûÞV…õïrÜm÷" " WñÎ|•õw÷w—¼/^›ê½¶Ã+ P#""" —@n¿ýöKÞ·zõj±ã ¦¹|€üÔOýTúçþç‰÷ÄãŸø‰Ÿ;>™qØç?ÿùô³?û³éðÓÏÿüϧ͛7Où¹ÇŽKôG”~í×~-ýðÿpþþû±KûØÇÒw¾óKÞðàÁôÉO~2ÿìú¡Êßÿ3?ó3ùk¯¼òJÃÓ^oú¦Úái'øõ×_Ïÿ[ÿ‹¿ø‹ß#v¨¯¿þúô7ó7¥LW1Ÿýìg/zßÿñ7´,›™ÎVÆ7€Díܹsâ=ƒƒƒ Íûv®­Ž¯ÝÛa,§ø1m1±ËZ¾Û·o¿hØüÀäëÔ/ýÒ/¥;î¸#8q¢¡e^öv%"""Èm·Ý6åŽÅÃ?|ÑïÅæüÈ4¼3¿;9õÞÿàƒÎ8í3Mßlw”bG,v@ë½÷Þ{ïmyºjY¶lÙ”ï›ê÷'ï063ÍŽo6ëܯÿú¯ç?žµ,^¼8-p:ÓxÚµn´:¾Ëa;ŒåYÆò½ñÆë~ÿŸüÉŸLo½õVÓiv}‘ dþüùéÌ™3éOÿôO/zý—ù—'~'þ{ÿͬ ˆ|éK_JgϞͽ‰ÿnw”âyñ³b§ôÿñÓÉ“''v^k5ù?£ÍL_£óeòIÒñÙñŸßø·ÜrËEÃ\­N׎;¦œQ¿ú«¿:í47;ÍŽo¶ëÜ£>šÿŒuâý÷ßÏ—km¿6lºñ´{Ýhe|íÜëMWìÜ·º|cûü¾¿7266–6mÚtÑû£7¨™ïÙÊv%"""ÈK/½4±CR|=¡¨%¡(‹Ã^êeùòå½ÿÙgŸöíoû¢añÞV§¯Ñù²bÅŠ‹Þsøðá‰a“?Þ¼y-O×Â… §ñxºinv:›ßl×¹@çOÿôOOô6ÄŽm<Ž×bX½ñ´{Ýhe|íÜëMW,×¹Z¾“Ïëiæ{¶²]‰€ˆHR<‘xºß‹ó<Š¯ŽŽÖÆýÑvñ_Ñâ°xo«Ó×è|™ü=êÕLÀidºê͇É;fõæw£ÓÙìøšYç>ó™Ïäã7~#ýʯüJþøž{î™qY´{Ýhe|Ú§›®V–ïþýûÓ'>ñ‰‰s`¦Z—¢G«™ïÙÊv%"""W@&Ë>ÓŽO¼¿Ù¢ZЇ_5²ã:Óûëíô4‹ŒFv”&O×lN°‹ùÖèï5:ÍŽ¯™í¸ Aq]ŒÇµ™ë§ÝëF+ãëÔv8Ýt5»|'ºÕè:ߎíJDDD®€Lþ/hü糘Éÿ é¿È +³d.¦¯Ñ¥™æÝlwÂgÖ쬛Îvö€DЇÞÄãFæU»×VÆ×Îí°‘éjvùÆU©Š¯Çù[Í@h.¶+¹ò[¿õ[5öO?ýôEÃwíÚU÷*:ÍìÄuò22yºâ„é¹È¢E‹š:f¿Ùélv|Í~÷^xaâµâe˜ÛuH#Ãæê²·ÃFÎivùN×[—Í- ­lW" "rdòÎI\Çÿ{ßû^>,~ÆóévRšÝ‰ûû¿ÿû‹³ˆã¸kWÁŠÄÕƒŠ—d|塸BOíj=“/ÓǦ—Œ8v¦+Mž®ø˜Ÿ‘øor\í+.ÇÓ[@š½jQ³ÓÙ®«`µòþv¯­Œ¯Ûa½éú«¿ú«––oœ÷Q|ýÉ'ŸÌ{)j—N®·lçz»‘+$÷Ýw_CÇZÇûÊØ‘ŽÄå3'jQïý”™î½—O-kúî¼óÎÒ¦k¶ÿ žÍü½oC³ÓÙìøÚN¬ÍޝÛát÷™Ü+ÓÌò­]¥lrýîïþîŒËj®·+¹‚woŽkìÇZ£G¢Ö3ÏãõÙÜMºÑÇãÇ_t'ôxÏÿøç½µK¢='1-?÷s?—÷ Ôîð¯ÅEËœ¾øOkÜèì£ýèŒ'ëÖ¦ë~áò÷ÆŽS઻»;¿ºÓTó®•ù¶qãÆ‰y?½3y3ÓÙÊøÚv¯ÍޝÝÛa,§âr‹õ¹xžG+Ë7z jëQ\.9ÖŸFæÛ\oW" """ÒŽ†ZÏ€ˆˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆH³‰»‘KD@DDDDDDDDDDDDDDDDDDDDDDDD@DDDDD@DDDDDDDDDDDDDDDDDD@DDDDD@¤~>ó™Ï\ô|õêÕéSŸú”RJ)¥”Rm­Éû¥R€|úÓŸNßþö·•RJ)¥”jk€(¥”RJ)  J)¥”R @@”RJ)¥”¥”RJ)  J)¥”RJ€ˆRJ)¥”†2oÞ¼‰š.GŽIëÖ­KÝÝÝiùòåéßøFÝÏH===yõ÷÷—>¼Ó㥔RJ) %@dª¼ùæ›éºë®K{÷îMãããidd$=ðÀÓ~ÎÐÐPZµjUÍkÍš5ùke ïôøD)¥”RJÈdÓ¦M3öx;óÃÃÃÏãñÊ•+KÞéñˆRJ)¥”9ÈÂ… Óàà`ZºtiêêêÊ¿äéÓ§§ýœ8L+zJj‰ÇñZYÃ;=>QJ)¥”R2‡‰×ï»ï¾töìÙ466–î¿ÿþÔÛÛ;«Ï™?~iÃ;=>QJ)¥”R2‡‰Þ€€G-‘è ©bH,àZ³zõêtôèÑüð­Xâ§çž{î¹çž{î¹çžÏõó« qRöd€ÔÁTçTÄke ïôøô€(¥”RJ)= s8=» „DÅáX7nœö÷jW•Š«eÕ»êT³ÃÛ=>QJ)¥”R2G÷™î~ Û¶mK‹-ʽº÷Þ{/: }ª÷ǽ4êÝW£•áí€(¥”RJ)¹ŒRï|«a|¢”RJ)¥DD©׋߸FÚ34”ö<ýtÚó­o¥=Ùk{¾ó´gÏžó?ŸþüëßüfÚóÔSiÏ“OÖ¯¯½~ŸêUŒ£^íÜ9ußSû¬âx³iÛ½k—e®”R @@&×Èš5iäsŸK#[¶¤‘¯}-d;#ßû^~~ËÈÿù?çŸÇë1<Þï¯Õí·§‘uëÎ×ïÿ~¹ãŽ4òp¾î¼3¬_ŸFþðÏ׆ iä®»ÒÈýÑùºûî4rÏ=iä¿ý·ó•ÍŸ‘ÿþßÓȽ÷ž¯ÞÞ4òÙÏžgÔÆiäü4²iÓùêëK#÷Ýwþq ‹÷ÆïÅgÅgÇøbü1-Ùô½“ÛœÎ×ÿÍ–Mú½ßK)[¦éÑGSÊÀ‘Ž=¿Q¼ývJ/½”Ò_ýUJÿ륔­_iùòóuíµ)ýöo§´bEJ×]—ÒÇ>–ÒïüNJ×_ŸÒ'>q¾n¸!¥oLé¿ü—”~÷wSºé¦”>ùÉ”n¾ùü8£n½5¥O}*6À”n»-¥ÿú_SŠ›ˆÆE$²u:¯ïÚµ)eëMÊÖë”­×)[R¶N§l]ΟÇðÕ«Ïÿ~|Þ-·œgLCLS6‡¾øEË\)¥€€L®|ç.v¸þøÏïø½øbJo½ÕøáäÁ|æÁØY›ig0vîÙŒÇ1,Þ¿ŸŸã‹ñÇôdÓ÷OÙ¸ýÁQJ)¥@@@”RJ) ­äྞ~úé‰úÖ·¾ePJ)  UÈh6M›7ož¨ÏþóþÈœä‰ì³b»¯Õ_ÿõ_[”RJˆHU2’M[qgð³Ÿý¬?@rÅäoÝzþbœG¶oO#Ï=—F^{­ñ‹EdÓÛÔ#â‚3]0".Ñè#bx\`"~?>+Æ1é‚]SJ) Hì”çŸŸí¸§¿ø‹”2€¤ø‡«c¾·ÕlfX±­(¥€€È¤:ðÕ¯¦áÇKÃO>™†¿ùÍ4œíHïÙ“†‡‡ÓðÞ½iø…Òð®]iøë_OÃÙŽçð—¿|¾¾ò•ï×_þåŵ}ûÅã(V¶.ª±b<ÅÚ±ãâzüñ‹+^‹÷Õ~?>3ÆSLS6/”x(¥€€HõOñbzÿçÿL)ÛQOßùNJo¾yåηø¬øìWŒ;¦%¦-Ûq›ê€ˆRJˆ€€ÈU½Ùï~á _˜¨¯~õ«v”R @@@@æ ßÎ>¿8ß¾ô¥/ÙYPJ)*äé _ûÚ×&êÙgŸ¥”¹ÈŸÜu×Eóîßø€€(¥€´7óæÍ›¨™†×{_1©§§'¯þþþÒ‡wz|   J) %@d6¯O—¡¡¡¬[•FGGóZ“5fñZYÃ;=>¥”Ë ±3÷O¨%¯ŒÆ­¤á€€€ˆRJÈdáÂ…iþüùY›òñ´mÛ¶ºŸÓÝÝÆÇÇ'žÇãx­¬á€€€ˆRJȤ˜·³Æñάúb4 ³øœÀKYÃ;9¾bCZÌê¬>šíxEïI¬ñ³Ï« Ïe;À­Ì¿±ø.H³ëÛ{½½•ÈóÙwmv}{këÖJ¤S=÷ÜsϯÖçW=@"gΜÉOÖÖ¢Dˆ= z@ô€\þëÜ¡mÛÒ¡;Ò¡l›?´{w:ô·›:tþg<×cx¼/Þ_«‡N‡¶lù~õ÷¿þìÏÎ×ÀÀ÷+[Æõç~¾²õ|¢yäû•a<¯g­²¿%õå/§C_ùÊùÇ1,Þ¿ŸŸã‹ñÇ´dÓö÷Ö/¥¤º™êœŠx­¬á€€€È•TmC¬S±nÅ:v¶ ÿ”»Ìùvà«_MÃ=–†Ÿ|2 ó›i8z>÷ìÉ÷†÷îMÃ/¼†wíJÃ_ÿzÎþ& g`Ê+CÓDemÊEµ}ûÅã(V¶.ª±b<ÅÊÐxQ=þøÅ¯Åûj¿Ÿã©?¦)›Î¾õ-Û €\^Ù´iS:vìXþøÝwßMwg;›7ožö÷jW•©{Õ©f‡·{|   R=€T©mØ“!˶ »ÈT÷ùؽ{w¶mÜ”¿¾lÙ²üü±±±ºp‰{iÔ»¯F+ÃÛ=>Qr¥««ëª€€€€\þmÃÿ˦ã/³¿áµúêW¿ªm¹ZRÅ€€€Èå…DmCcm÷¶oOOf©ÕsÙß%Û€€€€ˆiKÛðôÓOÛvD@@@€€(Q" Q¢m  @@@@@DÛ "   @@€€€€€€( €€(Q"    ÚQ ¢®Z€Ì›7o¢fÊšl%nä}©§§'¯þþþÒ‡wz|    ¢¤ˆÔË3Ï<“­¿+g|ßÐÐP¶}¬J£££yZâµ²†wz|    ¢dŽòÁdÛÎõéøñã3$v懇‡'žÇã€KYÃ;=>Q2Çy衇Ҏ;ê)éîîNãããÏãq¼VÖðN@@@@@€Ì!@>œ­û·5|¨ÖTÃçÏŸ_ÚðN@@@@@€Ì!@ÇŽk WsHqã,fuöÇàh¶ã‡oÅŠ?;ñ¼ª‰F¦•ù7ߥÂiv}{¯··²y>û®Í®oomÝZi€têïc•ŸW ­Ì¿*äå—_¶ý\AϯJ€¯’Õȳ¦:§"^+kx§Ç§Dˆ= z@ô€èÑ¢DéiÃU°¦{ßä絫JŒŒÔ½êT³ÃÛ=>Q2G÷iä~ 3$÷Ò¨w_V†·{|    ¢ä2JWW×U=>Q"   @@@@@@@@€€ˆF@@@´  vå@@@€€(Q"   @@€€€€€€( €€€h@@@@D€ˆÛ€€€€ˆ      @@D#  @´     ¢@DU óæÍ›¨©ràÀlÝ]“ºººÒ‚ ÒÆÓÉ“'ë~æÀÀ@êééÉ«¿¿¿ôက€€€()"SåŽl…Þ·o_:wî\O=öX¶]Ü:íç eÛǪ4::šWà%^+kx§Ç     @æ S%zC¦KìÌO<Ç+cÅ/ix§Ç     @ÚèÙ±cGZ¿~ý´ïéîîÎßWüx­¬á€€€€€(i@jç‰,Y²$;vlVŸ3þüÒ†wr|ų˜ÕÙƒ£ÙŽWôžÄŠ?;ñ¼ª‰F¦•ù7ߥÂiv}{¯··²y>û®Í®oomÝZi€têïc•ŸW ­Ì¿*äå—_¶ý\AÏ+Ѳ}ûöl[¸Mˆ= z@ô€èÑ¢Dˆ¥¤=ç€Ô둘꜊x­¬á€€€€€(™C€lÞ¼9?~<|æÌ™ü2µÅôÉ¿W»ªÔÈÈHÝ«N5;¼Ýã st©î²{÷îlÛ¸)}Ñ¢E©¯¯/ßY¯—@J½ûj´2¼Ýã —Qê]’÷j€€€€€(©@^zê©thË–t([×}íkéP¶ƒth÷îtèoÿ6:tèüÏxž­Ó‡vìH‡¶mËçõD=üðù߯Uÿ÷ëÏþì| |¿²i¨?ÿóó•-¯‰zä‘ï×Ö­ç+ÆY«˜ÎZ}ùËéÐW¾rþq ‹÷ÆïÅçÄçÇøbü1-Ù´ýïì= ¢D@@¤ƒÎvâóïÓñùϧl!¤ôòËççÙ•´­Î4ßâo\ö9 ¢D@@@@DU S4>U]sÍ5¤ ¢‘m€Hk Xk:€Ô»W‡€hd@äòÈ;Ùçÿeö·¨V?þ8€€¨Ëç¬Øy¨Ýâ–S§Nå¯=š€hd@äŠÈ?dÓQœoŸÏ¾/€€¨Ë ‹/NgÏž½äõxmÉ’%¤ ¢‘m€Hy‰C­¦ˆs@@42  ¢m) .ÌÖ©•ùaWãããyQ•Hì0ïß¿?\ëñ8}útÚ°aCzòÉ'g}O‘©²~ýú|q‰ß±±±ôàƒæ ™.CCCùØGGGóZ“­øñZYÃ;=>™º^ÌÚ•=Ù~Ôžì3ö|ë[iOöÚžlÞíÙ³çüϬ­È_ÿæ7Óž§žJ{²ýÕºõõ¯×¯W½ŠqÔ«;§®â{jŸUo6m»wíªî§zX˜í}@¦ÈäÄg×ë]‰ù¸2Wñ*]q¯’²†wz|    2CÛ°qãù¶á…®Ú¶!þžW ñ_ûH"µ{÷îüñ¾}ûf}H£Ù»woÝ8%RK¼VÖðN@@@@@¤²ÙµkW~NFä†l†ÏçXºtié9räH¶ÜoL'Nœ˜Õç{LZÞÉñ7ÎbVg+èÑlãŠÞ“¼¡Ì~vâyUL+óo,¾K…Òìúö^ooeò|ö]›]ßÞÚºµÒiv}{cp°²Ù²eKKíC•ÒJûZe€¼œm[Í®oïÇ~iEÏ/‡ý¿Ž^†÷ܹsiÙ²eyÏÇ’%KÒÙ³gKÈ+¯¼’ÍïëÓáÇë¾Oˆ= z@ô€èÑ¢Dˆ« ÿàƒyg@­ž}öY÷iå|’ɉC»®ÍVŒ×_}ÆÏ™êœŠx­¬á€€€€€H™m€LÊO<‘­˳mî͆~¯vU©¸To½«N5;¼ÝãBÓâÅ‹/:é|E¶ðÞyçYßdªûL5|º«oÕ÷Ò¨w_V†·{|     R8 }ª;ŸÇÍg:Œ¨¬ÄÕ·Ú™v@@@@@@.$N:øá‡ó§‹9sæL~×rÑÈ€€ˆ¶@¤4€Ñ1ù¾³½ˆ€€€€h@ê&îWñá‡^Ž8¡z¦KÉ €ˆF@@@´  ³Jœl~K6CN:•$î—Ê ˜Ü E@42  ¢m) qiÜé®R—” €€€h@J½ o $zBâêPQ³¹¯€€€€h@@@@@@@.ï«` €ˆF@@@@dNr9Ü”@@@@@@*åÙ‹› €ˆF@@@@dβgÏžlžßìŠW ¹Èt—àr~€ˆF@@@´  ¥Ÿ„>]ÅÍ@D#   ÚËê2¼Å^“f†O•ÔÓÓ“WéÃ;=>)"­ ¯ehh([Æ«òóR¢Öd '^+kx§Ç     RY€œ={6-]º´”s@ÊHìÌO<Ç+cÁ—4¼Óã©,@Vd ©ŽVÎ) ÝÝÝi|||ây<Ž×ÊÞéñ€€€€€Tú$ôç¢ñºŒÁšê}E µ:¼Óã©,@ʼҕ™ÇW\ÉŠY­ G³+ßÊÊìg'žW ÑÈ´2ÿÆâ»T Í®oïõöV ÏgßµÙõí­­[+ f×·7+ -[¶´Ô>T ­´¯UÈËÙ¶Õìúö~__e²sçÎŽìÿuäNèeÝ„p.ω×ÊÞéñéÑ¢Dˆ= z@ô€èÑRÙ}ûöeóá†422Ò1€L~½vU©˜¦zWjvx»Ç     Ri€Ô»ûy3WÁšêwg;|râ^õî«ÑÊðv@@@@@¤Ò©w÷óNÜ ½«««­÷+i÷ø@@@@@‚%        «ú> Í  €€€h@JÈéÓ§@D#   ÚrÒÈU°êݼO@42  ¢m™õ•°j—Û\q9Ù;v€ˆF@@@´  å‚Õ®Kí €€€€€H…²xñâÔÛÛ›Nœ8A     2·¹5›¹qŽG‚½ 7f ãÀéÃ?¤ €€€€ÈÜ‚õî»ïæЗ-[6qòùòl! ¤“'O’€ˆF@@@´  夘èý8xð`6_nÈ{E# ,ÈæùJbÑÈ€€ˆ¶@dnï„ç‡ôõõ¥¥K—€ˆF@@@´  s ÑÈ€€ˆ¶@¤e€4rÂÚýA@D#   Ú–2ù¦ƒÓ¤Ñ{„gºÄIíqsèþþþ?s¦÷·:¼Óã©ä!X±ó°*›¡###¯:u*í¹hÔfÙ³2U†††òÏÍkM6³ãµé2Óû[Þéñ€€€€€T qC³gÏ^òz¼¶dÉ’R;çÃÃÃÏãq½+kÍôþV‡wz|     •H a:€Ìöé7<Ÿxãµé2Óû[Þéñ€€€€€T .Ìÿ[‡]ÅŽsTÜ€ð¶l†/Z´¨€Lõz½óKfz«Ã;9¾âJVÌêl=šm\Ñ{’7”ÙÏN<¯*@¢‘ieþÅw©0@š]ßÞëí­,@žÏ¾k³ëÛ[[·V Í®oo V [¶li©}¨2@Zi_« —³m«Ùõíý¾¾ÊdçÎÙÿëÈ9 Ó„þì³ÏêѢĹô€èÑ¢Dˆ¶AˆrïúYž-¸®®®¼âñ«¯¾ÚÔá\žc¯Í朌âû[Þéñ€€€€€¸a ™é*Xq¥­©®5ù÷fz«ÃÛ=>)“krâÞÓÝ'c¶ïoux»Ç      …«]-]º´£wBþڙv@@@@@@.dE¶Šà(V£wBm€HC hÌöŽç ¢‘m€HSÑË      mH\r7®Ü$ 9Ⱦ}û²ùpC~ YÑÈ€€€€Ì)@¦» z;¯‚      : }ºr~€ˆF@@@´  ¥D@@@@@@@@42   W'@<˜-³kóC®¢âq¼& Ñ6€” ýû÷O{:„€hd@@DÛ R*@¢·ãŽl&:ujâµx|{6cã! ¢‘m€Hi‰C®Îž={ÉëçÎK]]]¤ ¢‘m€H¹»äõ@IY9}útêííÍ?oÑ¢Eé‘G™ñwROOO^ýýý¥ïôø@@@@@* ÙBZ™ÍÔ“'O¦ñññ¼âñ­ÙÌóÊÈÆlºï¾ûrÔvî¿ÿþôÔSOMûþ¡¡¡l¯J£££y­ÉN¼VÖðN@@@@@¤²‰ͧ; ý{ßû^)‰žb/K<ŽsL¦KìÌO<Ǥ²†wz|     •¾ o@#z; Qñ¸,|Lè éîîžöý1,zbj‰ÇÅ÷·:¼Óãq#Â9LlÀqØU ¤vVœ{2]¢÷eªsUÊÞéñ€€€€€È&NB¿÷Þ{óž¥K—¦'žx"-\¸°’= Å•¬˜ÕÙ z4Û¸â𭼡Ì~vâyUL+óo,¾K…Òìúö^ooeò|ö]›]ßÞÚºµÒiv}{cp°²Ù²eKKíC•ÒJûZe€¼œm[Í®oï÷õU ;wîìÈþ_ÛòB¶Pã$ñÉéËþ‹±ó9‰–©ÆYx­¬áŸ= z@ô€èÑ¢Dˆ= •íY¼xqÞC1U¯EôV”‘?ù“?I###yÏÀÞ½{³y~}:vìØ´‡0Õ®*¿SïªSÍo÷ø@@@@@¤Îù µ\sÍ5¥õxfâ¬uÙ‚:räÈŒÓ÷Ò¨w_V†·{|     r!±Ã|êÔ©K^{,X° -爴ûŽë—ÃÞ@@@@@* ØñžŽ·³Z»á›Ùƽ3ÝËB@42  ¢m™õª¦»á™3gH@D#   Úr/Ç[­ÈVíF„×e3$N¨ €€€h@®¸û€€€€€€€€€€€€€´ ƒƒƒùý@Š—ÝC²ÞyçRÑÈ€€ˆ¶@¤<€ìÚµkâ¤ó"@80ãݼ@D#   ÚYeÙ²eéá‡Î/¿[H\«]÷ФˆŽÉw>/ëNè      yæÏŸŸ>üðÃKÀ—áíîî& €€€h@ÊHœl~K6CN:•äܹséõ×_ÏarS,ÑÈ€€ˆ¶@¤,€¼™mÓÝ }tt”@42  ¢m)÷2¼âÐ]‚@D#    2g¹jrâĉ´~ýúü¤ö¨x|üøñº¿300zzzòêïï/}x§Ç     RI€â«Hœ€¾dÉ’üükc!–”8™ýÑlŠÏÚ¶m[¶œožöýCCCùM㔨5Ù‰×ÊÞéñ€€€€€T ·f3ùÈ‘#ùã{ï½÷¢“Ðo™[B¦ºŸHœk2]bg~xxxây<^ ¾¤á€€€€€He‡Då—.]šÃãµ×^K‡.íNè÷ÜsOÞëw[zä‘Gò×êMS¼¯–x\¼'I«Ã;=>Ê$ÀQ¼)a„©vU©‘‘‘ºWjvx»Ç      m̱cÇòC®jwZÇñZ½s(â^õî«ÑÊðv@@@@@¤òY¼xqêíí-­—£•Ô»$ïÕ0>Ê$îÿ'JGo@œqc¶08>üðÃ$ 99+.‘Ðã<Ú‰èq.ÈÀÀ@:yò$)€hd@@DÛ 27ç€DïÇÁƒ³ùrÃÄ=Aâf„3ÝÕ[@@@@´  -'ÎéëëËï. Ñ6€|Ä®<€€€€€€\19{ölÞÃQ¼a­âÞ  ¢‘m€HiY‘-¤"8ŠUïnå ¢‘m€È¬Ðx./ÑÈ€€€€Ì5@ôr€€€€€HÛ÷ü% €€€€ÈÜdß¾}ù}?FFF¨@D#    2·™êêW®‚ ¢‘™³“Ч+燀hd@@DÛ R*@@@@@@@®*€Lux×Â… ëþÎÀÀ@êééÉ«¿¿¿ôက€€€HerðàÁl™]›r㵹ʋÙNm½ô¡¡¡l¯Ê¯Îµ&[8ñZYÃ;=>ÊdÿþýÓž„>W¹%[§NšvxìÌO<Ç+cÁ—4¼Óã©,@¢·ãŽl&AoÏflÜ#¤ììÝ»7mÞ¼¹î{º»»ÓøøøÄóx¯•5¼Óã©ôÐÏž={ÉëçÎK]]]¥$v´ß¬m|uΙj:ËÞÉñW²bVg+èÑlãŠÞ“¼¡Ì~vâyUL+óo,¾K…Òìúö^ooeò|ö]›]ßÞÚºµÒiv}{cp°²Ù²eKKíC•ÒJûZe€¼œm[Í®oï÷õU ;wîìÈþ_G266vÉë’²_òž{î™ñ}z@ô€èÑâ¿\z@ô€èÑ¢DÈUÚ²"[Hq¾ÂÉ“'óç¨x|k6óãð¬2ãyíµ×f|ßTçTÄke ïôø@@@@@* 8Ñ|º“п÷½ï•†Ït'fO>„©vU©‘‘‘ºWjvx»Ç      …4¢·#¹ŠŠÇeâ#;åûöíkøŒ¸Lo½ûj´2¼ÝãË(sq²ûå4>i@â¤k®¹fâñtU{€hd@@DÛ Ò4@µûTÄãéªÞ½3@D#   Ú©{ž‡s@@42  ¢mi @NŸ>  Ñ6€”zW¿ªUww7)€hd@@DÛ Ò:@jWºª]nwrŽwìØA  Ñ6€”w–K퀀€€€ˆ«`€€hd@@@®>€¼-Ô±€'¥¯¯/Û÷|‘@42  ¢m) ‹/ίx5ÕU°–.]J  Ñ6€”8 }¶—èm&GŽɖѺüÊZ˳•$vZêe`` ?>ª¿¿¿ôက€€€H%;̧Nºäõ“'O¦ ”‚7³íºl&ïÝ»7§‘‘‘ôÀLûþ¡¡¡l¯J£££y­ÉN¼VÖðN@@@@@¤²‰ßèéx;[ ƒ¨CôŒ¬Œ™]B6mÚ4cG1±3?<<<ñ<§¥Õက€€€HeçzLw#Â3gΔ… ¦ÁÁÁüœ’®®®üKNuÞI-q˜V@¨–x\¼)b«Ã;=>J_†7·Z‘-¬ÀAT.‡I••ÀÌ}÷ݗΞ=›ÆÆÆÒý÷ߟz{{gu^Jñ~%­ïôø@@@@@Üd½Z"*ö€W²bVg+èÑlãŠÃ·ò†2ûÙ‰çUH42­Ì¿±ø.H³ëÛ{ñˆŠäùì»6»¾½µuk¥ÒìúöÆà`e²eË––Ú‡*¤•öµÊy9Û¶š]ßÞïë«,@vîÜÙ‘ý¿« qRöd€ÔÁTçTÄke ïôøô€èÑ¢Dˆ= z@ô€è©tÈÙL L>¤¬ËðÆJv‰ŠÃ±Š7?œ|SíªRqX½«N5;¼Ýã ¹3›Q5lLÈLç1Ì&Û¶mK‹-ʽº÷Þ{/: }ªs(â^õî«ÑÊðv@@@@@@ ÷Ù¿ÿE7 lذ!=ùä“m9D«Þù WÃø@@@@@dŠÞ€âã8‘:z,@D#   ÚRç-ÔzvïÞ?Þ·o_i瀀€€€€€äÙµkWê‹Ë¥˜7\tHÜ8P@42  ¢m™“Ëðž;w.-[¶,ïùX²dI~¹\ÑÈ€€ˆ¶@䊺ˆ€€€€€ˆ€€€€€H{râĉl9­˜8+½Šó?®…( Ñ6€” [³™|äÈ‘üqÜ °xúí1s@D#   Ú²ÒÝÝÆÆÆòÇqÕ«€Çk¯½–>œ,X@  Ñ6€”âÍçÏŸŸ?¯]ýÊ}@@42  ¢m) ===yÇÛÙ |,\¸0=zEb˜€hd@@DÛ R@bÇ·xÞǺ˜‘)–óÑl>ÝB  Ñ6€”{ÞÚÍ—Ç»벙WÈ €€€h@Jˆ€€€€€ÈUâ!^µš)ù9(Qýýý¥ïôø@@@@@* ¸âUíò»“«¬«`5Žb†††²e¼*ŽŽæµ&[8ñZYÃ;=>Ê$î‚^G±â²¼HìÌO<Ç+cÁ—4¼Óã©,@ÏEã5LJ`Åå}4Ï6žmÛ¶Õ}Üq|||ây<Ž×ÊÞéñ€€€€€T eõr4š¸ßÈÙÂùb4 ³è1)Ng«Ã;9¾âJVÌêlKGïIÞPf?;ñ¼ª‰F¦•ù7ߥÂiv}{¯··²y>û®Í®oomÝZi€4»¾½18XY€lÙ²¥¥ö¡Êi¥}­2@^ζ­f×·÷ûú* ;wvdÿ¯í‰KïÆy íÌ™3gêÞäPˆ= z@ü—Kˆ= z@ô€è¹J{@öí͇ۗÒÈÈÈe©Î©ˆ×ÊÞéñ€€€€€T S]ýªì«`mÚ´);v,üî»ï¦»³kóæÍÓÂT»ªT ¨ÞU§šÞîñ€€€€€Há$ô骬óCvïÞ-ß›òÿ¸ëzœÿ166V÷Џ—F½ûj´2¼ÝãË(]]]Wõø@@@@@D@@@@@¤¹#›IqÕ¦¹:D@@@@@$OÜ“£†Éi÷=B@@42   W9@â¤éýû÷Oœ9}útÚ°aCzòÉ'I@D#   Úr/Ã;Õ㸙ޢE‹H@D#   ÚrR»z\*.™‰:@D#   ÚR²k×®Ô××—?Ž;¢ÏYºt))€hd@@DÛ 27—á=wî\~£ÀèùX²dI:{ö,)€hd@@DÛ 27 €€€€ÈœÄy     Ò6€Ä‰ç      mÈòl9s†@42    s={ödóüæ‰Kñ €ˆF@@@@dÎR¼ìîäš‹óCÖd3ºxÃÃé200ߥ=ª¿¿¿ôက€€€HeOBŸ®æÏŸ_*>žyæ™lù­œ CCCÙ2^•÷ÊDZâµ²†wz|     .Ã;Çùàƒ²y}}:~üøŒ‰ùááá‰çñ8àRÖðN@@@@@@æ8=ôPÚ±cÇÄa_õÒÝÝÆÇÇ'žÇãx­¬á€€€€€ˆû€Ìá=B>œ-¿Û.:ïd¦óR&§x8X«Ã;=>™”Ó§O—ÀDZcÇÈÕÜR\ÉŠY­ G³+ßÊÊìg'žW ÑÈ´2ÿÆâ»T Í®oïõöV ÏgßµÙõí­­[+ f×·7+ -[¶´Ô>T ­´¯UÈËÙ¶Õìúö~__e²sçÎŽìÿµ õ®~U«™#ju\³9'#^+kx§Ç§Dˆ= z@ô€èÑ¢DHåz@jWºª]nwrÅådkçl”Éø˜ü¼vU©‘‘‘ºWjvx»Ç     â¬ÏUè@"q/z÷Õhex»Ç      —Qººº®êñ€€€€€ˆ€€€€€€€€hd@@@D@42  ¢m±+      "     "             ¢‘m€€€€€€€hD@@@@@D@@@@@@@@@@@@@D#   ÚÑ6HÝ8p [VkRWWWZ°`A¶>mL'Ož¬û;©§§'¯þþþÒ‡wz|     2G¹#[ûöíKçÎKãããé±ÇË–í­Ó¾hh([Æ«Òèèh^—x­¬á€€€€€€´9Ñ2]bg~xxxây<^ ¾¤á€€€€€€´)ѲcÇŽ´~ýúißÓÝÝ¿¯ø;ñZYÃ;=>iCæÍ›—×’%KÒ±cÇê¾oræÏŸ_ÚðNޝ¸’³:[AfWôžä eö³Ï« hdZ™cñ]* f×·÷z{+ ç³ïÚìúöÖÖ­•H³ëÛƒƒ•È–-[Zjª VÚ×*äålÛjv}{¿¯¯²Ù¹sgGöÿ*Ѳ}ûölyÞ¦Dˆ= z@ô€èÑ¢Dˆ= íI½‰©Î©ˆ×ÊÞéñ€€€€€ÈfóæÍéøñãùã3gÎä—©-î O>„©vU©‘‘‘ºWjvx»Ç      mÌîÝ»³å{S¾ã¿hÑ¢Ô××—ï¬×;‡"Rï¾­ o÷ø@@@@@ä ¹$ïÕ0> €€€€€ˆF@@@´  vå@@@@@@@@@@@@@@@@@@@@@@@@D@42  ¢mm€€€€€€€€€€€€€€€€€€€ˆ€hd@@DÛ       Ú©›dËéöÔÕÕ•,XúúúÒÈÈHÝßH===yõ÷÷—>¼Óã9ÊúõëÓþýûÓøøxK>ø`’é244”-ãUitt4¯5Ù‰×ÊÞéñ€€€€€H™?þ´Ãcg~xxxây<^ ¾¤á€€€€€€´1{÷î­ÛÒÝÝ#¥–x­¬á€€€€€€´)GŽÉ–ûéĉÓ¾gÞ¼y—¼Vì1iux'ÇW\ÉŠY­ G³+zOò†2ûÙ‰çUH42­Ì¿±ø.H³ëÛ{½½•ÈóÙwmv}{këÖJ¤ÙõíÁÁÊdË–--µUH+ík•òr¶m5»¾½ß×WY€ìܹ³#ûW5@^yå•l~_Ÿ>\÷}z@ô€èÑâ¿\z@ô€èÑ¢Dˆ–²{÷îl½¸6½þúë3¾wªs*âµ²†wz|     2‡yâ‰'²õby¶Í½ÙÐ!Pµ«JÅ¥zë]uªÙá퀀€€€€´1±Ã?UÕ;‡"î¥Qï¾­ o÷ø@@@@@ä2JÜ ðj€€€€€€€€€€€€€€ˆF@@@@@D#   Ú»ò                        " Ñ6€€€€€€ˆ¶@@@@@@@@@@@@@@@@@@@D@42  ¢m¹22oÞ¼‰j4©§§'¯þþþÒ‡wz|     Òˆ4’¡¡¡l¯J£££y­ÉN¼VÖðN@@@@@@.#€ÄÎüðððÄóx¼2|IÃ;=>¹ŒÒÝÝÆÇÇ'žÇãx­¬á€€€€€€\F™ê}óçÏ/mx§Ç      z@Ú2¾âJVÌêl=šm\qøVÞPf?;ñ¼ª‰F¦•ù7ߥÂiv}{¯··²y>û®Í®oomÝZi€4»¾½18XY€lÙ²¥¥ö¡Êi¥}­2@^ζ­f×·÷ûú* ;wvdÿ@¦9§"^+kx§Ç§Dˆ= z@ô€èÑ¢Dˆdò뵫JŒŒÔ½êT³ÃÛ=>éÐ}@¦ºÈT0‰{iÔ»¯F+ÃÛ=>¹ŒÒÕÕuU@@@@@@@@@@@@@@D#     ¢‘m€ˆ]y €€€h@@@@@@DÛ                   " Ñ6€€€€€€ˆ¶@*ŸÔÓÓ“W?€€€€€€ÈÜdhh(['W¥ÑÑѼÖd+S¼      RzÃÃÃÏãñÊXQ@@@@@DÊNwwwŸxã5‘Ò3oÞ¼K^›?þ´ð¨U1ë²ø÷³8zSnÍVüøÙ‰çwýú¯§ ]]é®ßú­twö‡n]Vk³1¦o]ö¾üùÒ¥i]OOZ÷¿‘Öýò/§µYÅÏuÿâ_¤uÿò_¦µ~®û•_ÉkmüüWÿê|ýꯦµ~®û×ÿ:¯µñó×~í|ý›“Ö^ø¹.›–¨µñóßþÛó•sí…ŸëþÝ¿ËkmüÌ–ÁºÿïÏ?añžø½ø¼øü_Œ7¦'›¾UÙãßüÍßL .L ,H‹-jiþm¸æšt÷üé®Å‹Ó†ìÊïgäòù•Í·µæÛºeËòù–OmžÕæ_̯ µ¶0ïbš'æ×…Z[˜w1Ï&æ×…Z[˜w1&æ×…Z[˜w1ßÖÆ¼‹ÇæÛÚ ó-_±|.Ì·|ú²y·8ÃuÌ·Úüûdö‡»ÙõíþÓJ²åvWöóøƒìò¬Ö·¬&Ö· ómmaÞ]2ÿ&¯o“ç_m}+¬sÍ¿ÚúVXçÖæ]þûæ[m[{aÚ~ç?ü‡‰õ-~þ^ö=›]ßÖeóêîl»+[²w}Ö˜®»0ßZß óì¢õ­¸½N·¾ÕæßTë[|ÿ¶zÉúV›¶Õ|xíwãsbù¶Õ˜¾Odï)®o+²‹f×·Û³Ž Ù¸îÊæËÝÿù?§?ÌvNÖÆ¼º°­ÆÏµ…y—O_aÞ5½¾Ö¹9_ß.Ì·Oe¯×·ßÎvÊZiîÎÆwWö7nCö7î®lý[wa¾­Ív°ÖÖ¹µ…mµåõ­¸½N·¾Õæ]£ë[¡mȗǤõmeö³¸¾ÅÏVÚ×;³åvW¶?pwÖ¦Þ•­o뮆õ­°Î­-´ K²ïP[ßb¾Å?V›]ßþ0æWö7nCö9wemj´ ñ7®áõírÙ©½·ÎþÈDzïYܹ)Q'öÿ¤"= """""Wbä2ÈTç€Äk""""""¥§v¬‘‘‘†¯‚%"""" ÒtâÞ³¹ÈäÏ QJ)¥”Rª R©Ìv¥óÍ|3ïÌ7óMÌ7óMˆˆÞ|3ßÌ;1ßÌ7óÍ|9ŸyóæM”Ì.H·ß~{êêêJ ,H}}}iddÄŒi`¾­Y³fb¾mܸ1~ü¸ rµÿÁ”Ù%þ8îß¿?§±±±ôàƒæ ‘ú¹ãŽ;Ò¾}ûÒ¹sçòy÷Øc¥[o½ÕŒi0Ï<óLZ¹r¥mÖß¶9Í›o¾™®»îº´wïÞ|;®<ðÀfLyñÅS¿1Cnºé¦ôè£æmCÔ¶mÛÒÍ7ßlƈh¤¥^¢‘ž?¾ÑD¢7DfÎ|®¿þúü¿‚¶YÛæ2›6mÒãQRn¹å–têÔ)3b†\sÍ5Ú´Ì6ñŸB= ³GÛŽ;òÞ$™9=ôP>¿l³³ûÛ‡¿Ä?>þñçÿU•™ólpp0-]º4ß Œ»SŸ>}ÚŒi¢]ؼy³Ñ@î¹çž|ûŒv!ê‘GÉ_‘iÇJßxãù1¬Òø:µdÉ’tìØ13d†>|8ÝvÛm¶ÙòöÛo§;ï¼3}ñ‹_43Ø>ï»ï¾töìÙüÓûï¿?õööš1³Ì§?ýéüp6™9ï¾ûnZ±bÅDÛõˆˆL“W^y%?,&vev‰ÿrmß¾ý¢k™:1ŠP³Í6—3gΤžž3b†ÄIÀZ"‡™]†‡‡ý‰ DHñGˆˆL‘Ý»w§k¯½6½þúëfF qîLcÛ¨+:H»WZ› @‰4ž¸XÄk¯½fF´ÐhDD&å‰'žÈ/M©{}v‰ã¡k—VŒÁ¸:̪U«ÌÛìœ$N¦®õÅ!wß}·còHœ€‡]B¢âp¬¸d¶4–ƒæ‘ÆW¼Šó>Šç€¸ €ÈU¼ã?ªåÍ;óoæD¯Q\n1æÕ¢E‹Ü?@Ú¶¾-[¶,?ÿ£øŸ}™>qLl£qèÕ½÷Þë$ôY$zârãÒxâµ{kEÅc爈ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆÈ“yóæåe:EDDDDdÎwàDD@DDD@DDDDD®l|kò°Ý»w§Ûn»-uuu¥îîî´nݺtüøñKÞ÷ /äï‹÷?çàÁƒéöÛoÏ_Ÿ?~ºùæ›ÓsÏ=wÉ´<þøãùï]sÍ5iáÂ…ióæÍéôéÓ½çé§ŸN+V¬È§åãÿxzê©§.™îwß}7mܸ1-X° _|Öç>÷¹ôꫯZà" """— B¦{=PñÎ;ï¤ñññ $ÜrË-—¼oÍš5ùûŠyå•WrPZN:•Î;—î¿ÿþüý‡b¶oß>›ÀL¼'Þ[Ëž={ò×î¼óÎ&QñxòôÇ´ÅóäÏ?üðÃ<1}"""""r™äèÑ£¯Bj½“ßwìØ±K>#vúcX±ÇäìÙ³ùk×_ýŒÓ½µ¬Zµê’é9räÈ%ÓÓuøða WD@DDäJÈL¯×;#šê0¯Éˆ  lذ!G¼>Õ!aqØU#ÓS뉊߉C¾|ðÁtòäI [DDDDäjH ÑsR/54Ëj qȦM›Ò’%K.‚L@DD@DDD®b€ÄÉç1lïÞ½u§¡ÖSRKÎ5ùs=«˜8ç䥗^ʇÇ8DDDDD¤ÃY¼xq¾ƒ'‰— ï~÷»ùÕ¯n¸á†ôöÛoç¯ÅÉã»víÊAQKôNÄgâ‘»îºë’Ï-ž„~æÌ™¼Ö¯_Éûî¸ãŽôâ‹/柉«pÅðOúÓ¶ˆˆˆˆH§‡=Å¥j…Ål‰“Á?ó™ÏäçwÄûù}ñ¹½½½ùwª]Ò7Érˆˆˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆY """"""""""""""""" """"" ""³þÃô‘(¥J*i "b[±Ó$b[±Ó$"¶%;M"¶%;M"¶%)m§éÔ©SéÞ{ïM===iþüùiÕªU饗^jø÷çÍ›×Ð{¢âó.\˜z{{Ó믿>gó¥6¾é¦íĉiýúõ©»»;¯x|üøñi?ïÀéöÛoO]]]iÁ‚©¯¯/ŒŒ4<¼™Ï[³fÍÄð7¦“'O6ôÝã÷&ï™æÇTÙ»woºé¦›òi¸îºëÒSO=5åçMþìé†M7îFæÝÀÀ@¾~Fõ÷÷Ïú»Õû}i ˗ׯ)àˆ´?ü0§ï~÷»é®»î* µÄxÓ’%Kæ!õ¦-v¬}ôÑtîܹ¼¶mÛ–n¾ùæi?'€²ÿþ|þŒ¥|0ßintøl?ïŽ;îHûöí˧-ÞóØc¥[o½uÆïûÌ3Ϥ•+WNû½Èk¯½––-[–†‡‡óçŸx`ÖŸÓÈûfšCCCù::::šW+^kt\þ>€ˆ€ˆˆ´ Ñ+Q/ï¾ûnºçž{òž‚xïwÞ9ñêFþÃ=ÝÎá“O>™î¾ûî‹^‹ÿN/Z´(ÿoxô’|ðÁ øá‡ó”øOùã?Þôð5×\sÉk1ÎF;ËõæÛLÛyÿLÓóêúë¯Ï{rZH,ï]»vµ‹Ù¼¯Þ¼<Ô ‰Ç¬FÇÕèˆˆH›;c_üâÓ;ï¼3åðo¼1½úê«ùŽaüG>°iÓ¦YídNõžè HÔòñyÏKü—:Æsß}÷]ô_÷/}éK9~bøÙ³góéhv8v°£×#¾SÔ#<’¿Öhâð¤z=“‡Ï4ê}^Lߎ;òž‚zŸ÷ÐCåï«7¾FAË%æq'2y^|cçG¼Öè¸ý}i@¢7cóæÍiéÒ¥=õÎ7ˆ¸"šH¤øŸîåÙô@‰ÞŽZâ 8wc6™n¼Ñ«³bÅŠ‰ž›xçÂ4’#GŽä(›nZ¦^oÕû¼ÚôÅájÇŽ›öó>œn»í¶ÇW=Çc¶itÞMÕ[4›ï<ÕˆˆH›RLÆçƒwf£÷#c‰ÿ×v4‹‡05 ×dÈ€jÕÌxÝ)]·n]ÞR<¤^F-¯¼òJ~˜Sìð73¼™÷ø¶oß~Ñ2™œV(³‡è™n^蹊RË䞉¸*Vì¨Gâgqg¯Y€Ä9 ÅÞb<õ®UfÈTÿŸéŒÝ»w§k¯½vÚçgÞêûëM_Ù=qnN;Ï©7/¦:‡#^kt\þ>€ˆ€ˆˆ´ ±³Y<Ç#·(^*N «EŸûÜç.ÚÙ‹K›ÎtøR#WÁúÊW¾’6l؉ÿèÏ5©ÓÐê9 ñýâ{Ï©w¬'žx"Ò›o¾ÙÔðÉÓ1Óûã¸ÚeÏœ9“Ÿœ_Üinä©V@WÁŠCò<˜?ŸË«`Í4/jW±ŠåÞÊU°fú}i@â¤ßØA‹ÃâД8¼x.F û@Äðø/uì0wöâ±µC¦êíˆÖ*@ç™LuØQ $ÎLjqÅ¥rŸ{†ÇÉòž™®‚5So@à¦vx\<„©‘Ï›Ü 4ÓðÙ|^ôÄ÷¯Í¯É÷Ƙ-@½'Çäõ"¦!–E,ÿ§Ÿ~ºáéŸ @ù¬X#÷™n:êý>€ˆ€ˆˆ´±-‰€ˆˆØi±-‰ˆˆˆØiÛ’ˆˆˆˆ&Û’ˆˆ¿L"b§IĶ$" "b§IDlK" ""mÙiRJ•S""""""""•ÍÿÕ)³sM³IEND®B`‚Multiverse-multiverse-0.7.0/charts/uncontended_mono_update_line_narrow.png000066400000000000000000000464471174000617100273570ustar00rootroot00000000000000‰PNG  IHDRXôáPSÔLîIDATxÚílUç}ÿ+MÓ4MÓ4iš¦ý1M“¦iTûcÒ4MÓ„"[¶l!È:hĉã_!Ž ¤…„â@CC …Üš†@SšÔBM`Ð8Å„˜8¡$¡)Ø Á¡&¸vLj‚k×Ï×ïg=þ_î=÷×ñ=÷žózKoùžóßç¾ï9÷Þ÷óy>Ïç|É_ñ%Þ  ƒ0X @.¨/}i³=ǹ,„þâÿïË_þrÒcÕ…ë¯?‡|î ?.El°Ä·ß~û–ã´/ѱ|‹×`aÚ `°0X¬<¬ÆÆÆ[Ž«¯¯Ç`a°À`¾Ø1X¬l ÖßüÍߘßÿþ÷SÇèñ_ýÕ_a°0X`°@4¿Øµ=õÔSæïÿþïÍÿñ›üÇ4[¶lIø¼}}}æ‘G1ÿñÿaþôOÿÔÿñæ«_ýªyíµ×n9þܹsæ®»î²Ïý'ò'öø¿û»¿³ûΞ=›ök÷z}‰~ÐSýÈ_¸pÁF[þùŸÿyJ‡ Ãâŋ͛o¾éËërã±Ç›vÜ·¾õ­´Îe6¯3—þ21XâË/¿ý8¿K—.õÔÿ×ý׿ã?ÎÚ`e{½€Á¡5X%%%fddÄ|÷»ß¶ÿ_ÿõ_§þ5uÚd´víÚeÆÆÆìÔF§îm»ŸK?ºŸ~ú©˜úqv?²Íæõ¥û¾Ä'aë¹5r—Ž+VLk“¡Ìõuµµµ%|Äÿ÷Oúš³}Ùö—é5·wï^ûW×ÄçŸnÏ«c`œ¶dýäûÚÈ¥¿|~½^—ÌK®çWŸÏ§Ÿ~Ú+ŒŽŽš7N;^Ѽltæò¹ƒBk°N:5õ…ëÞ¯¿…øÝmš–ñBUUÕ´ã_yå•©¶W_}uZ›ŽÍõõ¥û¾,\¸pÚ1===SmñÏ?kÖ¬œ_WeeeÒ÷A“½æl_g¶ýezÍÉTÿíßþíT´H?Üz¬}jóê'ß×F.ýåósèõºt^gêüÆçÕe£3—Ï,ZƒåNTNöʳrïö|þçž´jÝm:6××—îû¯Ã‹© \:¯Ëë}ˆÿáñz¿Ó}Ùö—Í5÷õ¯Ý>þ¯ÿú/óoÿöoöñÚµkSž‹|_¹ôÔç0ÙëÊåüž9sÆÜqÇS9h‰®%E$³Ñ™Ëç (Äç’¤úb×ñÙ~é;pO¦óÜêx¯/õlMT:?ñ¯+“Þ™xßÒý¿t_g¶ýec&´àÁ}-걓(íÕO¾¯\ú ês˜ìue{~ã§Ó½æóñ¹ƒ ñ£X\݈ɦФӿgk&^_º?©Þ»l#~G°²}ùŒ` î©!=Nç½Ê÷µ‘Kùü¦óº²=¿ZÕçÞ¯üÉlŒÞL|®À`‚Áÿ÷Oû2;zôè´öcÇŽy®BÊæG*È,? VüëRBöL¬Ù³gg•3“íë̶¿lµŸ8qbjŸ»LG¾r°Òi›©,¿?‡éä`e{~“EÛTVÁƒ•Ëç (ÄùªŽÍ|`ÛôWÛɾ„³ý‘zï½÷¦M(ÂYE(hõ•{É~üÊ-­prV;Å/ãWnˆ&J º©V„Å¿.ýÞOAÑ­–Ôr}½^? V¶«¾²}ùZE˜Ëñù¾6ré/ŸŸC¯×õ /ät~•wåÞèÐ!erJkxÛ™þ\€Á…M›6¥•ë ãü0 ‚–WÇOx/–ªö–×ûõúš››}{]™Žä3‰Ø¤[·(Û×™mù2XA\Ùö—ÏÏa²:XñQµlί³Ê3žwÞygÊs5ÓŸ+0X à êÓª1£‘²"JNdIÛÚŸI5ìt¯\¹2­’»ŽùË¿üK½r–Ì»¡È—^Ë?üÃ?ؘS¡Zû4ªõóõi¤¬B†_þò—S&;¯ëŸþéŸì±úay,++³«ã½w¹¼o6l˜zô7ÝÊêÙ¼Î\úË—ÁÊ÷µ‘mùþê<¹Ï›®gwžU.çW$ç:R9 ]?é¼o3ý¹ƒÀ¿";`°`°À`À`€Á%¨šº›  ƒ0X, À``°0X,PO{{»©««3ÃÃÖ vŸ_íA÷Gy hF7šÑfr°r6X7nL±rCfEÖ×ÖÖúÖtD°õ¡ÝhF7š‰`ål°*++ÍÁƒͼyóLii©yýúõ¤Ï£iDEºè±öùÕtä`A!„ä`ål°´Ó¦MfllÌŒŽŽšÍ›7›õë×gô<%%%¾µÝ,F}hF7šÑf"X9,Esd¬Èh)’Å–N°C7tsKÍ;;–þæºýÙgŸùú|Ųÿ7 úûûû#¥×Ù–n®ïhèâ÷Y¯ï™ü> ¥ÁRÒw¼Áò2<‰rš´Ï¯ö û#‚ŨÍèF3ºÑL+gƒ¥wM Êd‰š.ܰaCÒÿsVåiµ¡×ª½lÛóÝ9XB!9X9ÕÁJVkÏž=föìÙvjpݺuӒܯZR^u¥riÏwù4X¦ª*)ý„‹œk¢èF3º#ÁÊ^ùXaè/ï+"ô£•Ú1œkj#¡ÍèÆ` £> çÍèF3,>ƒõáæÍæü3Ϙ·÷í3§ÚÛÍ«ÌËO>lºô#ó~,fz'Ï¥×¹¾ÖÜl®L^c—ZZÌŧž2ïïÜiÎ>÷œ9óâ‹æõŸþÔœøÙÏxO!„ä`a°0X~,ýØ^}øa3|ß}fôŽ;Ìï-2#+V˜ß<ð€ùdÝ:Óóío›÷ví²?¯=Êè'Ï]½Ú\úæ7=Ïõ»­­æƒï|Çšj=ÎûàÊ•æóÉëìæ×¾f~¿p¡}Î/î¼Ó>§®þ5kÌåÇ7½O>i~¹}»y÷ûß7Ý?ü¡9}àÀÿ]hȉj ÍèÆ`‚›"ž4o¿^»Öš;½¶wÝeÆ/6_ùŠ]²Ä¾¡†óéCYcþѦMöÚx/3ïìÝk_¯"¤?å’ûÉËA7šÉÁ!2X>ýø(j¡h–¢ZŠnéÇT?þ222І]UDeãFóÁöíæìäìÎØk¡ú^;rļ¥÷ì{ß3=O>i®|ãfðþû­IQÔHÑ£Ïêëm´èÃIcr~çά§lóm4tNO>lºÚÚ¬‘’Æ_M+,]2\2^¿­®¶FL†L&]ÚeÔšš¬q“Óõ$C'c÷Ö~d^"IîQ "Xœk (ƒ•ÏhŒL¦”ߣ©(ýxêVÓN2ú«míKþ—r—Þ¿Úƒî,òÐ<óºUïLUõU,–sn4£ƒ5 ™9Xz\[[ë[{ÐýÁbÔ‡æüè>yø°¹±|¹-T˹&·’sM+”«²²Ò”””˜Ûo¿ÝìÙ³ÇóyÊÊÊÌÄÄÄÔ¶kŸ_íA÷G„ùã‡Ùû¾ÿÌ3¼¬†ä`…Ë`¹qùòeÓÜÜlvìØ‘ÑóÈœùÕtD°õ¡9¿ºU¥_·@úÅîÝœk Q;"Xá4XÂÈȈMbK'Ø¡õõõvÞÙ¹°ô7×íÏ>ûÌ×ç+–íø¿QÐßßß)½Î¶t§{ü¯;;ÍØ¤Éz{ß>®ï"Ùö2Xcwßm¾¨®¶yv¿ml4_<ôžä§“øÁo|Ã|¾y³¹ÖÒb>Þ°Áô?õ”ÚµË|òÌ3æWßùŽùø¹ç̵̇/¼`~±g¹øÒKöúøåÑ£æôäþ÷Nœ0—ß{ÏüâÍ7íªÔ|ê÷ÒÌ÷YnÛ¬$9MÚçW{ÐýÁb„æ`tŸÝ»×ünÒduýøÇœë"`½1iŠÞüÉOì=KuÛ¬w&Ï­n¯û—žŸ4Rlßnsïz¶l±·ÓÒ=KUˆö“Ióõë5kì}L¯=ø ùÍý÷Û§×ï»Ïüöž{lΞ¦”wÇö¾¥_ùŠ™X°À>Ö½LÕ¦ct?SýÏg“ÿ«çÐs}:ùœzîO&¿ßÕ—úüpÓ&ûtÏS½&½¶÷Z[íkÕõ(Ã/ вJÓ¢D°22X'/²¾¾>ûøÚµkfÍä¸eò‚KöΪ¼¡¡!ÏU{Ù¶ç»?r° ,êÇíæÒ¥æôäïGa×3+³¡×Òyì˜9yäˆyý§?µQ®®¶6óÖ~dÞ~þy{÷ûß7ïÅbæ—;v˜_mÛf.>õ”½êGOù¤ùíÝw›×Žå\تO—¾uëÌÏ]•ø£rc°¨ƒŠÀ`Õ@3º½ùñã›áÚZsâØ1ÎuPSn£K—Ú|¥¨^ã^Q»×'Í'Ÿk (ƒ!LÍ_¯]k“”Ãzsè¢ÉÛµË&–Ÿ A)™ L§’ëO½ü2ï Áb„æÂ×­i¨kÍÍvX1Ü:ŒçºçÉ'íê¼3«;ù\¿jWCj¥c±MkÁä`1æˆê¶7‡nh°Kø9×ù]÷ëGµ«èR-8àsý¼¼aƒÖî<~œÏ5 Áb„æÂ×­•k×kjÌG--œëY·ŽÏ5 Áb„æâÐýÖ‹/Z3 [¡p®sgïæÍ62¨[Ìpû§ÙæNþ~\*ðÜA"X€,áÿÿ¢ÿÁ¬ÉÒÍxy?²_)Ø¿f]@pêðaÞ“™Ê¼ûn{SiÞ ‹#|4…nÝÄWÓ…ºÁ/ç:ó•‚*¡:c¹VËçsíM•¹Ðý5?ضÏ5 ƒE9*h.Ý¿üîwíôÖëpsèb9×§µRpùr{;"?’°ù\§±:óàA[°õýXŒÏ5 ƒE‹hš‹CwÏ·¿m§a^;r„s‚oÿð‡ftÉóÁöí\ãyÖܵ¿}ï‹ù–CD°9XFŒ—¾ùMsý¾ûLgÝ:ß|çN›·vvÏÞ€øÖ /Øs BÞ"7X³fÍšb*444¤u\kk«)//·ŒÅb¾·Ý,¢9h.NÝNíŸTE»Ïõ‡Oý‡›C«ê{¨5wt˜&¤oh¥àO~Â5^„šuchåÌéFÑä`…ha²ãâ·UyCCCž«ö²mÏwä`A~žùÃÍ¡ÃZ{H ìWW¯6Óßu'.¶ s3Éý‘ä`Q¬têa¥2X‚jIyÕ•Ê¥=ßýÁ"šƒæhè~ûùçÿ¯öÐ Þ:Í'_~Ù+¬Ôÿ*zÍ?Ÿ4Y×|Юü,ÄÅ D°|Diii¨û#‹|$4GG÷¹gŸµÓ…oÎÐÍ¡ó­YSZ¦©Á Œù\û‘ ªÔ9X è Q 4£;¸$p{sèŸþ´¨5+‰]9éá\‡Osçñãf¸¶Ö\Þ° ƒ!,^|ê)3²bEÑæ+iU¤V jÚ“ó^¾vô¨ùí=÷˜7o& ƒ…Ábćn4‡nM«]¯©ñuYüŒkîè°ÅSo,_nWGr®Ã¯ùÔË/Ûó}aëV"X, 9 èæ\‡îO¾ñ 3ÔØè[røŒæå?nﱨeü…yãs=ÃõÜ27ï¼³ ¦ƒÉÁD°ˆj ÝiE„>]½Ú\kn¶«· U³¢ºY³nÚüó€V r«yªž[k+,  BXøT½¡ßÜ¿ùõÚµùúºöï·IùnÚÄùŠz=·ÿØ.l8»g9XX #>ts®‹ Pç±cvÅÖÇ?^PšÏ>÷œýA}ÿ™g8×h¶ìþáÍïî¸Ãþ%‚0Xä,«Á¹.Ž[wßmzž|² 4°m›4WoïÛǹFótã½g5ÞŠh‘ƒ0XŒø颻àyJ7‡¾ë.óÁöíÁiîè°‘´­|é%Î5šR¹XÊÉÊ÷jR"X€,avÉÄ“¦ææä×{$kªR ÷C 6¢Æù€^ÔªB­.Ô*Cr°‹¨šÑ]ðìr’‰÷îÍ›fEÏT—ë×kÖÝ~ù\GÕÇR,­4%‚0Xäå ÝOå>)™ø­ýhÆ5ËÐi¥`﷾ŹFsÆT¥wU|ÏGÔ“,@‹QšÑ3±{·M4sÿþÓ¬>-{ï{ßã\£9kêž…Z «{Áä`A ž*‘pók_3oÌ@žË¯ž~Ú&*wg%ƒ0¯<ú¨ôñÎä`¥À¬Y³¦˜ÝÝݦ¡¡Á”––šŠŠ ³aÒ x>gkk«)//·ŒÅb¾·Ý,FºhF÷´<—I#¤<—“‡û£¹£Ãô=ö˜¹ûnóF‘¬ä/ͺ3ÁC™k>èË ˆ`e`´¡©©Étuu™ññq311a^|ñES]]ôyÚÛÛM]]¶”9Ó>¿Úƒî,r5ÐŒî„y.OŸü.ðº9t:š5…30ù½«HÃk>ÞhšsfÑÞ™àLÿ#XÃEV€+ÍJ™9Xz\[[ë[{ÐýÁb¤‹ft'cßúõf¨¾>éL*ͯOîdÒ4•Sl+¹Æ‹G³n ®›‚²n¬B1XŠ`µµµ™U«V%=¦¬¬Ìçþíó«=èþÈÁ‚zMÁ\}ä3 )˜ ’ªn+—+—Jñ¦KEZ¯Oþv]ji!+hƒåäiÍ;×ôõõeô<%%%¾µÙŸN°C7ê'G ‹:Î]sÝîïï÷õùŠeÛaTôjûâÅ‹‘ÒëlKwõíî67Ö¬1ƒë×[ÕÎõ}õða3¦•‚»v…ò|Gñû¬®ï“GŽ˜/î¹Ç >ûlÁŸE"‚µoß>SSSC‹,r5ÐŒn¯)˜º:sù±ÇRj¾ðÔSv¥à[/¼À¹FsÞ9uû§mÛÈÁ*„,¯ˆR¢œ&íó«=èþÈÁ"WÍèN‡*êøyuµéݼ9¡f­âRŒn †[™p¯æ7´ÓÓïÇbä`åÓ`mÙ²Å\¹rÅ>±e Ü$þÿœUyCCCž«ö²mÏwä`A³Ž¼ü²1UUIù›ûï÷\ua¾Øµ¿-š{n÷nr°f¢V¢zXfÙ²evÿìÙ³MKK‹5#^ÆL&Ì«®T.íùî£>4£;Z3•“ûôRs]üš5M­»¼óƒÁ*x•lCä`‘·€ftÏ”Áâ\£¹àŒá¤¹’ÉÊ6',Pð‹¨šÑÁâ\£9žûÃ=6»Ò¼Ç&,PT BˆÁ‚0(*áÝÞcóàAr°,F}hF7‹sf¿¨Ò *á RD°9Xä- Ý…g°’sæBgÏ–-ö¦ã*Jú¬D«þñ¶Ûnà ÁbÔ‡ft£ÝhΉºÎõ72EKÆÉÍdË«(  B!L—*Š«Dë.‘ÈÁ:räÈT‘Lƒƒƒv_GGNˆ£>4£ÍèFsîœôý4£ÍèF³Ÿ<ñ³Ÿ™ÁÆFsåÑGÃÁª¬¬4µµµvZpbbÂr``ÀÔÔÔØÛÚr° „B?Ùyü¸žô—7lwV²$÷W^y'D‹QšÑft£Ùw¾vô¨ùí=÷˜7oo,‰©ªª²÷èõøÝwßÅ‘ƒEÞšÑft£yÆxêå—ÍåËÍ…­[׃ˆ`1êC3ºÑŒn4Å×ÊK1]  B!Œóq;¨@ VSS“)++˺’»û¡»»Û466ÚéÇŠŠ ÓÒÒ2­îV"´¶¶šòòrËX,æ{{ÐýÁbÔ‡ft£Ýh±Ájnnž2S¹VrOf°V­ZeΜ9cW(ŽŽŽšmÛ¶YÕ ííí¶Ðéðð°eCCƒÝçW{Ðý‘ƒEÞšÑft£9äK™Á‰X]¿~ݬ^½ÚÒ¼¨+2Z^æMfEÎÝ„¯R~µÝ,F}hF7šÑæ,·)r?– Ê´VºëôéÓž,MWª÷kÑ>¿Úƒî,!„0KÓZ‚r¤:;;íã®®®Œ+¹§c°z{{ÍÒ¥KMFÏãŽxåÚd:Áݨ¯¯·á`gÄ¢¿¹në=öóùŠeÛaTôjûâÅ‹‘ÒëlK7×w4ôGñû,J×·×*B¿úË»Á:vì˜M:–,Y2-kÞ¼y¾¬³gϚŋ›žžÏãˆ`1n4£ÍœkÎuhê`›ùóçÛÈ•nôœè…Ù,EÆ,X`.\¸òyå4iŸ_íA÷Gy hF7šÑæüê.ê:XÉ ÖluøK—.¥õΪ<•rðZµ—m{¾û# B! –Ei°ÝÇ0U{²äzª%åUW*—ö|÷G‹QšÑft£9‚¬ƒš9sæLKj_¸p¡¹zõj^ š’ëó‰|÷Gy hF7šÑæˆå`)É=QåvU_O•G Û`1úA3ºÑŒn4£; ƒ¥¤ö;wÚ•onƒ522bokŠ×`A!„0 ƒå6Uñu¯2­ƒˆ`1êC3ºÑŒn4ÁúCAÌ›7oÞb¨´".U-'@y hF7šÑfr°@Éì+V¬0ƒƒƒÖ`©–jUÉx-[¶ 'D‹ÑšÑft£™V¦Pmªdeœ[èr° „Br°²0YŠd©|˜Ï ,"XèF3ºÑŒn4‡² ‹ù{4£ÍèF39X3´ŠÁbôƒft£Ýh&‚åƒÁ*„ªæ,r° „ÂPå`é&Ì** ˆ`1úA3ºÑŒn4ÁòÉ`½ñÆfùòå¬$‹ù{4£ÍèF39X~¬d%âïMˆ`1êC3ºÑŒn4ÁÊ É=Ulƒ!„’ƒÜQ¯lÚ¡µµÕ”——[Æb1ßÛƒî£>4£ÍèF3u°Ò6Z¹´;hoo7uuu6/Llhh°ûüjº?r°È[@3ºÑŒn4‡<kllÌÌ›7Ï—,¿ –ÌŠ¬=®­­õ­=èþˆ`1êC3ºÑŒn4‡<‚¥Û⸠U.9X~¬²²23111µ­ÇÚçW{Ðý‘ƒ!„†<KFª£££ ¦ç6{¹¶ÙŸN°C7êëëmXÔqîú›ëv¿¯ÏW,Û£¢WÛ/^Œ”^g[º¹¾£¡?ŠßgQ¼¾gòû,ïËÏ•‚D° +‚Åü=šÑft£ÝE°TÉݯ"£3™ƒ¥}~µÝ9Xä- ÝhF7šCžƒÕÕÕe–,Yb†††3XñûUyzM^«ö²mÏwä`A!„ÈÁòªÞžÍ*ÂDÿ›i{4£ÍèFs"X^ÕÛƒ¨ä^ZZš×z]ùî,òÐŒn4£ÍËÁá5XŒ~ÐŒn4£ÍèÆ`a°˜#‡BÃS+›6@‹QšÑft£™V†&êúõë,r°˜¿G3ºÑŒn4“ƒå÷JÂTÅ2,F}hF7šÑf"X V&º¡¨rmmm8!r° „Br°2E¾J1"XŒúÐŒn4£Í¡`Í™3Ǭ_¿ÞÞ@ƒÅü=šÑft£™, VuuµÍ±Ò¡¢XK—.5ÝÝÝææÍ›¸"XŒ~ÐŒn4£ÍD°rÁµk×Ì®]»Ìüùó§’ÛuèÖÖV300€" B!$+(zuîÜ9{ógEµd¶***Lmm-Žˆ£>4£ÍèF3,? ü¬––3oÞ<9Xä- ÝhF7šÉÁ,F?hF7šÑftçÑ`¥SdÔ©•éó%ƒrºT[KŒÅb)Ÿ3Õñ¹¶Ý9XBaÈr°â‹Š&3X™ÖÈJf°ÚÛÛM]]¶lhh°û’!Õñ¹¶Ý,F}hF7šÑæç`9rÄšƒ¡¡¡©}ƒƒƒv_GG‡/KÏ¥7Ì{%Χ:>×ö û#‹¼4£ÍèFsÈs°Tptllì–ýÚ7wî\_ –êmMLLLmë±×}SŸk{ÐýÁbÔ‡ft£ÝhyK¦(™ÁJ7+•ÁJ´ßkú1Õñ¹¶Ý9XBaÈë`UVVÚé,M *ò"ªÀhMM™={6,ŸûÓ vèF}}½ ‹:Î]sÝV™ ?Ÿ¯X¶FE¯¶/^¼)½Î¶ts}GC¿Ï¢x}Ïä÷Y 9XÉ’Ü_yå•ËÁÒ¾Lr¢ÜÇçÚtä`‘·€ft£ÝhŽ@,ݧ´´ÔRß}÷ݬ¦½Vé)‘>Ñ*»øÿKu|®íùî,òÐŒn4£ÍËÁò‰¢_ñPm¨du¢2=>×ö|÷G„B±¬B€¢faî£>4£ÍèFsÄ"XZ-¨{ æRɦÁbþÍèF3ºÑŒî€ ÖÂ… §*73­äˆ`1êC3ºÑŒn4ÁúÃms2­ØŠÃ`A!„0 ƒE”Š£4£ÍèF3,Ÿ –J2¨´ ‹ù{4£ÍèF39X>¬®®.³dÉ’i7{D°ý ÝhF7š‰`ù\ÊU„ä`A!„ä`å˜äžŒägÁbôƒft£Ýh&‚0XÌß“«n4£ÍèÆ`a°ˆ`¡ÍèF3ºÑÊÖ¹sçÌ‚ ì” ¨ÇÚÈÁ‚BÉÁÊgΜIšäŽÉ"‚ÅèÍèF3ºÑL+ (ZÕÔÔd§öéqcc£­‘ÈÁbþÍèF3ºÑLV†Ð” nøññqSZZŠ"‚ÅèÍèF3ºÑL+ƒ5::zË~™.¿ Öõë×ÍúõëíóÍž=ÛìÞ½;åÿ´¶¶šòòrËX,æ{{Ðý‘ƒ!„†8káÂ…¦¶¶Ö ˜‰‰ K=®®®¶Ó‡~`Æ fÓ¦MÖ´ÉÌmÞ¼Ù>|8éñííí¦®®ÎÞÂGlhh°ûüjº?"XŒúÐŒn4£Í!`)‘=Y’û|à‹ÁRäÊ%Ócåx%ƒÌŠÞ`z,èW{Ðý‘ƒEÞšÑft£9u°d¤­’õØ/s•È`)’UVV–ôxµ)’æ@ÝÇçÚtD°õ¡ÝhF7š#Pk¦ñøãÛiA™,gŠÐë6<Šž%Êó«=èþÈÁ‚BCžƒ•(É}ݺu6’5oÞ¬ƒÚzXî² š2¼zõ*Nˆ£4£ÍèF3¬LqìØ±©¤v·ÁêîîNYƒ!„’ƒ•óçÏ7;wî´åÜK+óU ƒE ÝhF7šÑæPE°Ü¦*¾r»_•Ü9Xä- ÝhF7š#•ƒURRbnÞ¼y‹¡R™†²²2œ,F?hF7šÑf"X™BÉì+V¬°·Ë‘Á7.\°ÆkÙ²e8!r° „Br°2…s[œDÆ Ábôƒft£Ýh&‚•­ÉrWr§D9XÌߣÝhF7šÉÁ,F?Œt9×hF7šÑ-ƒÕßßoV­Ze“æE=¾råŠçÿ´¶¶šòòrËX,æ{{Ðý‘ƒ!„†8KæGS‚‚ÜçÎkó¯,Xà›ÁR²üÞ½{íó‹{öì1Ë—/Oz|{{»-rª0±¡¡Áîó«=èþˆ`1êC3ºÑŒn4‡<‚U]]mz{{íãuëÖMKrollôÅ`%ª§¥\¯dYÑì@kkk}kº?r°È[@3ºÑŒn4‡<KSv£££öñ¼yó¬±:þ¼éééñ­’ûÚµkmÔJÕâÅÝ»wÛ}^¯IÇ9ÐcwM®\Ûƒî£>4£ÍèFsÈ#X2TÚKyÊ×®]³ÓNdLUw+×ä~m~µÙŸN°C7êëë­kw.,ýe›m¶Ùf›m¶ýÙλÁRR¶"V—/_¶F¡²²ÒîWTKm~`åÊ•6‚åÎÁòš~$‚ÅèÝhF7š9ל뢎`é‡Ýw%3$Èí©Â»HÍñŠ(%ÊiÒ>¿Úƒî,òÐŒn4£Í¨ƒ5þ|;XUU5µoÑ¢Ev…¡ЊAå]¹s°Ü«ã§ØœUyº¢×ª½lÛóÝ,F}hF7šÑfê`ù޾¾>;%èTŠ×cíóÊaR-)¯ºR¹´ç»?ê`A!„©ƒ5gγ~ýzߢT¹À«dCú#‚ŨÍèF3ºÑ‘–ê_)[ÑåC-]ºÔtww››7or›,æïÑŒn4£ÍèhŠP%víÚeó°œDwåbéÖ/8!"XŒ~ÐŒn4£ÍD°r¢WçÎ3K–,™ª‰¥b£©ª’ƒÂ4XB!,À$wågµ´´Ø >4£ÍèF3,@ó÷hF7šÑftc°t[ç„ñôëV9€£>4£ÍèFs¤"Xî{ÊP¹éUmƒ!„’ƒ•2R8"XŒ~ÐŒn4£ÍD°ü2XD©ÈÁbþÍèF3ºÑL–ÏK5¯tÿ<@‹ÑšÑft£™–O«««ËÖ½ÒŠ9XB!9X>¬D«YEH‹ÑšÑft£™VŽIîÉH~9XÌߣÝhF7šÉÁ,F?ŒtÑft£ÝÑ0X‰¦+++=ÿG7›.//·ŒÅb¾·Ý9XBaˆs°ÝàyÁ‚vJPÔcí›)œm¶lÙâyLYY™™˜˜˜ÚÖcíó«=èþˆ`1êC3ºÑŒn4‡<‚¥)AÝð9ãã㦴´Ôwƒ%#qéÒ¥”9[‰^§_íAö§ìÐúúzëÚ KÙf›m¶Ùf›m¶1X£££·ì—éòÛ`IäÚµkSG‹ÑºÑŒn4s®9×EÁZ¸p¡Í°Æ@Ôãêêj;}è'ÔÏùóçS—(§Iûüjº?r°È[@3ºÑŒn4‡<K‰ìÉ’Ü?øàßÌ•úI–ø?Åæ¬ÊÓí{¼VíeÛžïþˆ`1êC3ºÑŒn4G°–Œ”¢UšõØOs%Èt辇éæ@©ŒƒW]©\ÚóÝu° „ÂÖÁ 3‘L_HýÁbÔ‡ft£ÝhŽ` „Ó`1ft£ÝhFw –¦Èt3çd·±qèˆ`1úA3ºÑŒn4ÁJ'§N“'£Wí(Pø B!„Lb°ý ÍèF3º9×,@y hF7šÑfr°’LfÓˆ`1êC3ºÑŒn4ÁÊÐD]¿~ƒE„BHV¦+ S1Õýô,F}hF7šÑf"Xq‘+Ñ)ÇOU$okkà ‘ƒÅü=šÑft£™¬LA)"XŒ~ÐŒn4£ÍD°XEˆÁ‚Baa¬'N˜ 6ܲ¿¥¥ÅœV}*w’{cc#Nˆ,!„¬Lá¾O V ÊX?Þôôô˜ŠŠ œ,F?hF7šÑf"XÙÔÁr [ãhÛY=H,r°˜¿G3ºÑŒn4“ƒ•tkE¬._¾lÍUee¥Ý¯¨–Ú,F?hF7šÑf"XB?ì•+WÚýr+V¬À ‘ƒ!„’ƒ• œâ¢UUUSû-ZdW"XŒ~ÐŒn4£ÍD°‹ù{4£ÍèF3º1X,"XèF3ºÑŒn4‡*‚¥ƒNy†xúµŠ0Ñs§Bkk«M²c±˜ïíA÷G„Bâ,Uqw*7U¶Á/ƒ• ÚÛÛM]]¶lhh°ûüjº?"XŒúÐŒn4£Í!`ÉHuttÌètX¦KfEo°=®­­õ­=èþÈÁ"oÍèF3ºÑò,¿¢T© –êk©¯Ûo¿ÝìÙ³ÇóxU—Ÿ˜˜˜ÚÖcíó«=èþˆ`1êC3ºÑŒn4‡<‚¥Ò šÖÊTд¹¹ÙìØ±#£ˆ—ÛæÚd:Áݨ¯¯·®Ý¹°ô—m¶Ùf›m¶Ùög;ï«««Ë,Y²Ä åÍdŒŒxV‰'‚ÅèÝhF7š9ל뢎`%Záç÷*ÂL V¢œ&íó«=èþÈÁ"oÍèF3ºÑò¬ø•ƒ3±ŠpãÆ¦¯¯Ï>¾víšY³fÙ²eKÒ)6gUž¢j^«ö²mÏwD°õ¡ÝhF7š#ÁÊ:;;Ͳeˬ±Ñmy”¥›I{å0©–”W]©\ÚóÝu° „ˆÕÁ*”––†º?"XŒúÐŒn4£ÍŒ`555Ù¤ì|å`r°È[@3ºÑŒn4‡:K%3o°òQ# ƒE ÝhF7šÑæÐE°”3tæÌ™©„wáúõëfõêÕæÐ¡C8¡"6XB! °LC¢Çªå4{ölœ,F?hF7šÑf"XÙ,§’»’¿µâÏ)@J9XÌߣÝhF7šÉÁÊÇŽ3---ö±*º»s°æÍ›‡"‚ÅèÍèF3ºÑL+ŒÛ:UŠ\Í;׌á„ÈÁ‚BÉÁ,F?ŒtÑft£Ý,ò¬ÈÁbþÍèF3ºÑL–Ï«ªšc°ˆ`¡ÍèF3ºÑªVUU•Áñƒ!„’ƒå—Ázã7Ìòå˧J5"XŒ~ÐŒn4£ÍD°|¨ƒ•Œäg‘ƒÅü=šÑft£™¬,“Ü“‘{Ábôƒft£Ýh&‚Uhhh˜vKždhmmµ÷Ic±˜ïíA÷G„BH,_püøqS[[›Ò`µ··›ºº:›&Ê”iŸ_íA÷G‹QšÑft£9Âu°üÌÁºqã†Y¼x±¹råJJƒ%³¢7Ø˘ùÕtä`‘·€ft£ÝhŽ@V"\¿~ÝWƒµ}ûvÓÖÖ6•Xï…²²23111µ­ÇÚçW{ÐýÁbÔ‡ft£ÝhiËkõ ÃT&!]ôôô˜ššši}§zmñp'ÜçÚd:Áݨ¯¯·®Ý¹°ô—m¶Ùf›m¶Ùög;oËY)è”cˆ§’µˆS®¹êëëKÛ`Ábôƒn4£ÍœkÎuQOæ£C²Y&9QÚçW{Ðý‘ƒEÞšÑft£9ä9XA Þ\Åo;«ò†††4£ÍèF3,ƒÅü=šÑft£Ý, £t£ÝhF7çƒ Û`A!„ƒ…Ábôƒn4£Íèæ\c°9Xä- ÝhF7šÉÁD°ý ÝhF7š‰`a°0XB!Ä`"XŒúÐŒn4£ÍD°9XÌߣÝhF7šÉÁÂ`a°ý ›s͹F7šÑÁä`A!„ä`"XŒ~ÐŒn4£ÍD°‹ù{r5Ðft£Ý2XÝÝݦ¡¡Á”––šŠŠ ³aÃ300àù?­­­¦¼¼Ü2‹ùÞtD°õ¡ÝhF7š‰`儦¦&ÓÕÕeÆÇÇÍÄÄ„yñÅMuuuÒãÛÛÛM]]¶”9Ó>¿Úƒî,!„¬¢YÉ ³"ë@kkk}kº?"XŒúÐŒn4£ÍD°|…"XmmmfÕªUI)++³Ç¹ÿGûüjº?r°È[@3ºÑŒn4“ƒåfÍše9wî\Ó××çy\4£ÍèF3¬‚*Ù†þ¨ƒ!„R „Ä`1úA3ºÑŒn4£ƒ…ÁbþÝhF7šÑ͹Æ`"XŒúÐŒn4£ÍD°@¤ „B1X,F?èF3ºÑŒnÎ5 ƒEÞšÑft£™,@‹ÑšÑft£™ ƒ!„B  ‚ŨÍèF3ºÑL ƒÅü=šÑft£™, ‹Ñº9לkt£Ý,@„BH ‚ÅèÍèF3ºÑL `°˜¿'WÝhF7šÑ!ƒÕÝÝmMii©©¨¨0---fhhÈóZ[[Myy¹e,ó½=èþˆ`1êC3ºÑŒn4ÁÊ «V­2gΜ1fttÔlÛ¶Í®dhoo7uuufxxز¡¡Áîó«=èþÈÁ‚BÉÁò2Z%%%IÛeVä`èqmm­oíA÷G‹QšÑft£™–ï8}ú´g«¬¬Ìš0·!Ó>¿Úƒî,òÐŒn4£Íä`ùŠÞÞ^³téRÓßߟô˜Y³fݲÏñʵ=èþˆ`1êC3ºÑŒn4Áò gÏž5‹/6===žÇ…9‚¥ìÐúúzëÚ KÙf›m¶Ùf›m¶Ck°:;;Í‚ Ì… R›(§Iûüjº?"XŒúÐŒn4£ÍD°rÆLUU•¹téRZStΪ<•rðZµ—m{¾û#‹¼4£ÍèF39X¾C†&½r˜TKÊ«®T.íùî£>4£ÍèF3¬¼CHÃÜu° „Bê`,F?hF7šÑftc°0XÌߣÍèF3º9×,@‹QšÑft£™ˆ”Á‚B! ƒÅèÝhF7šÑ͹Æ`r°È[@3ºÑŒn4“ƒˆ`1úA3ºÑŒn4ÁÂ`a° „BˆÁD°õ¡ÝhF7š‰`r°˜¿G3ºÑŒn4“ƒ…ÁÂ`1úA7çšsn4£ƒÈÁ‚BÉÁD°ý ÝhF7š‰` ó÷äj ÍèF3º#d°fÍš5ÅtÑÚÚjÊËË-c±˜ïíA÷G‹QšÑft£™–oF+´··›ºº:3<4£ÍèF3¬¼¬²²23111µ­ÇÚçW{Ðý‘ƒEÞšÑft£™¬¼¬DÇ•””øÖd:Áݨ¯¯·•ãÜõ7×íþþ~_Ÿ¯X¶FE¯¶/^¼)½Î¶ts}GC¿Ï¢x}Ïä÷‹„B‰`å'Kûüjº?r°È[@3ºÑŒn4“ƒ5ã+~¿³*ohhÈsÕ^¶íùî,òÐŒn4£Íä`Íh¬Dõ°/Õ’òª+•K{¾û#‚ŨÍèF3ºÑL+ï(-- uä`A!„ä`,F?hF7šÑftc°0XÌߣÍèF3º9×,@‹QšÑft£™ˆ”Á‚B! ƒÅèÝhF7šÑ͹Æ`r°È[@3ºÑŒn4“ƒˆ`1úA3ºÑŒn4ÁÂ`a° „BˆÁD°õ¡ÝhF7š‰`r°˜¿G3ºÑŒn4“ƒ…ÁÂ`1úA7çšsn4£ƒÈÁ‚BÉÁD°ý ÝhF7š‰` ó÷äj ÍèF3º1X¡Bkk«)//·ŒÅbD°õ¡ÝhF7š‰`\ÐÞÞnêêêÌðð°eCCƒÝG„BHÈ2WrÜô¸¶¶–£>4£ÍèF3,-ÊÊÊÌÄÄÄÔ¶k9Xä- ÝhF7šÉÁYbÖ¬Y·ì+))Ij¬º±råJóÀØhXuuµý›ëvss³¯ÏW,Û£¢WÛ÷ߤô:ÛÒÍõ ýQü>‹âõ=“ßg¬ˆD°P¸À`h–öƒ²„³Šphh(íU„À`Pí«Lê`ÅÛ!„Bÿ‰Á¾ Ó‹ ÝhF7šÑftc°Nts®ÑŒn4£ƒP À``°0X,mèÖ=£‚îînÓØØhJKKMEE…iii±uÉ¢ [u×Ý6l0‘9ïÒ•ëÜý¹ŽÒç»··×ÞJLwǨªª2Gމ乮¬¬ µæþþ~³jÕ*{žE=¾rå  î‡4*ЇñÌ™3ö6E£££fÛ¶mÖp…MMM¦««ËŒ[í/¾ø¢½÷VpüøqS[[)ƒ5\ºtÉ,Z´Èœ>}Ú^ß4mݺ5rïÃÉ“'³ª¯XLX¶l™Ù»w¯ý.÷ìÙc–/_ŽÁ|!ôeœì†Ûa‡¢YaÇ7ÌâÅ‹íƒ^lܸ1«TX±b… µÆÛn»­à¾Ë0X€/äЈ7 ¬xSÙÖÖf£yaÇöíÛ­Ö(]çÎ4‘·ß~»á‡Ò{ðàA3oÞ<ûc«úHׯ_ÜwÙ–-[B¯síÚµöšÖ÷˜¸{÷n»ƒ0Xål,]ºÔÎéGé\‹sçÎ5}}}¡ÖÚÓÓcjjj"}_¾|Ù477›;v„þºÞ´i“³Sÿ›7o6ëׯԹ¾÷Þ{íTiØqíÚ5³pá©ï2=:j‡Á,Ξ=k§Žô#5hÔ·oß¾iæ#Œ>·‰Œê@bddÄÞû4ÌP²³Œ•­(L;xçwâä ZÈ –;+èY À`ýfÁ‚æÂ… ‘>ïaÏ=K´Â*Š&+ K«Dã –LWT EçÏŸì÷VÐße,€ÁšÄìî(„ÒÝPn†³”Y?¸ZiTWWÇuB(áÛ‰Üi:eÍš5¡ÏÍQ‚»¦e²DMªIpîÜ9k°¢­TÞ•;‹U„ (FøQÔÝŠÚiy³´Îž=;2õ¿¢h°Üçzþüù6ÿÊÝ +4U¤k[SƒëÖ­‹L’»¢w*ÁhðàÔ2õ8è|R  ƒ€Á,  `°0XP@(–‚³Q½Ý,(Bƒ‚Á`°ƒÀ`@ᘓD÷ t¶u¿šš{³²²2³råÊ©›d»;qâ„=NǸŸG7ÞսѴ¿¤¤ÄÞ„¶££ã–ײÿ~û·Ýv›©¬¬´7cŽ¿wÞÑ£GÍÂ… ík¹ýöÛÍáÇoyݺ™³nj\QQaûÓs=þøãæÝwßå„€Á€üš¬dûeš®^½j&&&¦LЊ+n9N7ØÕqnœ={Ö&™²ÁÁA3>>n6oÞl—9rcß¾}SÆMfMÇèXo¼ñ†Ý×ÜÜl—¨Çñ¯_¯MÛÝÝÝvûæÍ›ÖÐéõ0XPë£>šÚ'“åD™âëëë»å9djÔæŽxÙ}‹/Nùº…rPWWwËëéíí½åõ뵉===œ\0XP˜+Õ~¯(MÑ%š†Œ7i2`«W¯¶†JûMYjZ0×ãD°Dý¦$·mÛf8Ù`° ø –cŠùò‚cŠÜÓ†Ù,å`mܸÑÌ;wšQ“Ñ`° è –’ÛÕvúôiÏ×àDºhº1þyÓ"tC9_§N²íê€Á€¼`Μ9Ö€( ÝoƒõþûïÛÕƒK–,1—/_¶û”œ~ìØ1k˜(º¤çRŽÖÃ?|Ëóº“ÜGFF,W­ZuËqMMMæäÉ“öy­bTû½÷ÞËɃù¦åTÊ ]㔉Á”lþõ¯ÝæWé8:•Qp—MùÒ4¡ò¯,X`<˜ðyU¦aÑ¢E6%Ó¦íøãô¼ëׯ·šœ’š2$  `°0X, À``°0Xƒ€ÁÀ`Pôÿ—¾!œa€Á ‚ Àg |ùÀg |ùÀg |ùøŒ€Á€/øŒ€Á ô_þƒƒƒfݺu¦¼¼Ü”””˜ºº:sêÔ©´ÿÖ¬Yi#êù+++ÍúõëÍ… fL“Ó_²×ÖßßoV­ZeÊÊÊ,õøÊ•+IŸ¯»»Û466šÒÒRSQQaZZZÌÐÐPÚíÙ<_CCÃTû† ÌÀÀ@ZÚõñºS½‰púôi³lÙ2û-Zd>œðùâŸ;Y[²¾ÓyïZ[[íõ)Æb±Œµyý? À`Íd¨ôtóæM311aÞÿ}óðÃûn°¨Ÿƒš¹sçΨÉòzm2{÷î5ããã–{öì1Ë—/Oú<2`gΜ±ïÏèè¨Ù¶m›5é¶gú|MMM¦««Ë¾6óâ‹/šêêê”z?njkk“êN×`?ÞÌŸ?ß¼óÎ;v[ænëÖ­?O:Ç¥z/ÚÛÛí5:<ÕëÓ{µxñb‰ËÕ`é|;v,'ã”Éq^ï…Ì‘cô=–‰L·¯tÿƒ0X`°¬Lö» ›;v˜«W¯&l_ºt©y÷ÝwíŸ"*297nÌèG4Ñ1ŠdÉ(9xöÙgmäLQõ³iÓ¦iQ“]»vYs§ö±±1û:²ý—PÔJšÄÝ»wÛ}éBÓg^ªøöTï‘×óéõµµµÙH×ómß¾ÝçÕ_º†GçEïq+þ½±×{à~?´/ݾÒý À`€ÁòÕ`)µeË3oÞ¼©È‘W¾~ ÜÆ([ƒ%¸#U“¯ÕmòdÀ­r )+åNe‚dý**·pá©ț+-ôööZÓ™ìµ$j÷z¼žÏy}šNíëëKú|===¦¦¦&e~£ts¬25Xé¾w‰¢}™hNôÿ,€Áƒ•þT`†S†šfR>–ûÇZÑ+M³hÔïüº§Ø²5Xê+Þ¨Éà9̦ŸttW®\i#Xî,¯ˆ”ƒ³gÏÚi8šlÚ³9^†vß¾}ÓÎI<ÔæeÀ2}ƒˆ`%{/ˆ`€Á +‘‘Êd ÄG–´ªPFDÐ_÷Y¶K9Xîi9õãµòÎÏV¢Fª¨ÎÎN³`Á‚¤‰ù©Ús=ÞëõùQRn\>s°¼Þ‹D9TÚ—n_éþ? `°À`ùj°ôcêαR>’{E’εÊKzüñǧý˜ié{ªéµtV>ÿüófõêÕvúNPDÆëåä`é5䚃%}ÒéÎÁòZExàÀk/]º”U{üëHu¼¦l²###6ùßm Ò™ÂËÅðh¡¦ŒÏ;g·graª÷ÂY¨óžË*ÂTÿÁ,0X‰T–«•T¬ MÇiêD‰æî\(µ«’ÚeТûÇL%œ)½t",2lÊóJ4-&“¥|(õ¥R ÓÚ•Œ/C—jaªhŽÌ›S{IÔc÷[¦¢tÚ3y>Et¤ßy¿âkCej°Ò­I]è5è\èü=ztF"fé<— f:u°’½¯ÿÇ`€Á,Ÿ10XðåŸ10XðåŸ10Xðåà3 ¾üà3 ¾üà3 €P~ùCg–`°€/øirïÉX IEND®B`‚Multiverse-multiverse-0.7.0/charts/uncontended_mono_update_line_wide.png000066400000000000000000000515241174000617100267670ustar00rootroot00000000000000‰PNG  IHDR ôÅ@IxSIDATxÚíÝmŒ”×™çÿH«ÕjµZ­FZ­Vûbµiµš£}±ÒjµZ­E«[ d 3Ø3$L?`ÌÀر›@pBâÄŽ=öÄÁIÿ¾Îlõ¿hº«Ÿîªêîúü¤Ÿºî‡®Sý­»ªïë\ç:版ˆˆˆˆ¨FúDDDDD$!"""""‘„ˆˆˆˆˆ DTÇø>p'zM÷r*´7ô÷þøÿxÄsãX#\SñsèsOD"€Ìà›ùF@Â?þño8/ö w®Ïáô @5D$!"ˆdJ k×®½á¼öövˆ„ˆ DäÆGâ5€üûÿïÓïÿûÁsâñ¿ý·ÿV"!"¹ñùÀ¨Ç>ûÙϦÿôŸþSúçÿüŸ§ÿüŸÿsÚ±cǰÏ{æÌ™ô±},ýÏÿù?Ó¿ü—ÿ2ŸÿoþÍ¿Iò'’~ðƒÜpþ±cÇÒ‡?üáüÜÿâ_ü‹|þüÿ1ï;zôè˜_{¥×7Ü ïh7Áo½õVî­ÿ£?ú£Á¿#n¨—-[–~ô£òºÊuß}÷]wÞ§>õ©1½—y“io<Hø;ßùÎà9{öìûZ^“m¯ÖŸÃxŸâoˆ×¯3ÞÇ¢Þß'Ÿ|òºcÿìŸý³|Mý×ÿú_ÓúõëSOOϘÞó¢?WD$!¢ @Ö¬Y3ìÅ£>zÝïÅ æ¿úWÿjÌ7#ñûq“Séü‡zhÔ×>ÚëïR܈Šh¥s7mÚ4é×UÒÂ… ‡=o¸ßzÃ8‘×9ÑöÆsÍý¯ÿõ¿òÏŸŸûÜçò¹¡+W®¤­[·^w~dƒ&òwNæsED"jÀäå—_¼!)ßC(JŠ!åÇbØK%-Z´èºó_xá…ÁcßûÞ÷®;çNöõ•Ë’%K®;çĉƒÇ†>ÿ¬Y³&ýºæÎ;"‡x<Òkžèëœh{ã½æ"èüÿá? fâÆ6Ǿ8V©Z_“i¯–ŸÃJ¯+Þ×j½¿Cëz&òwNæsED"jÀ¤¼x¤ß‹:òý}}}_ã¿þ×ÿzÄ6¢W´üXœ;Ù×7V.CÿŽJ-ÀËëªÄaèY%Þc}mo"×ÜÇ?þñüøÿïÿþûÿïùñ=÷Ü3ê{Qëkc2íÕës8ÒëšÌû{øðátë­·ÖÀ w-EFk"çd>WD$!¢i ¡cÙG»ñ‰ó'zSTRùð«±Ü¸Žv~¥›ž‰c¹QúºÆS`[ ncý½±¾Î‰¶7‘›í˜ üZŒÇ¥BæJíÔúÚ˜L{õúŽôº&úþº5Ök¾Ÿ+"€Ñ4ÐÐ^Ðèù,×ОÐÑz‘Çr¬È H5^ßXo”Fc7Þ›ðÑŽM´Çz¢¯³–PùЛx<Vµ¾6&Ó^-?‡cy]}cVªòýQ¿5‘@¨Ÿ+"€Ñ4Ðÿù?ÿçºöÏ>ûìuÇ÷íÛWq‰ÜÄÕ³¤Èdè늂éj óæÍ›Ð˜ý‰¾Î‰¶7Ñ¿ýÅ_ÜW> s­j@Ær¬Z5 EÇR2Ñ÷w¤lML›[D2™Ï @ˆhhèÍIÌãÿæ›oæcñ3¶GºI™èMÜO~ò“ë†YÄ8îÒ,X¡˜=¨|JÖ¡3Å =¥Ùz†NÓcÓ‹2¢€v´†¾®øàŠÞä˜í+¦c×[D2ÑY‹&ú:k5 Ödίõµ1™öjù9¬ôº¾þõ¯OêýºòýO?ýtÎR”¦N®ôÞVûsED"š&Ú¾}û˜ÆZÇyEÜH‡búÌ¡C-*Êhk/Äô©E½¾ 6öºÆÛ<žÿ±®Û0Ñ×9Ñöj€ÔãÚ˜h{µüŽ´ÈЬÌDÞßÒ,eCý¡}hÔ÷ªÚŸ+"€Ñ4R¬ÞsìGOkd$J™‰ØŽýãYMz¬7ŽgÏž½n%ô8çþàrö£4%j¹"s¯åÿðs¥´Âsì‹^Ñ"__ô´ÆBgüÇ•¿oq=—×yLæý Dé:Šé’ãú ·j®ˆHBDDDµøG-3@D"""€ @ˆˆˆ DD"""š¨b5òr @ˆˆˆˆˆˆ DDDDD$!"""""‘„ˆˆˆˆˆ DDDDDD"""""€ @ˆˆˆˆˆHB•õñüºíöööô‘|¤æ®W»b|±Å—±Å[žê|‡Þ— @$ùèG?š¾÷½ïÕÜo¿ýv]Úmã‹-¾Œ-¾ØòTç+€ÔÔ¯¾úª=¾Ø2¾ØâËØ60_ˆ„™™™™YB2 Œ/¶ø2¶øbË2 ˆñœÆsbËøbËøb‹¯„d@_lñelñÅ–e@HÂÌÌÌÌ<½Y³f z$OwwwjkkK}}}Ùy_QÇëÝžã9[|±e|±e5 U @¶nÝ:jÆ£\q3Q`Iñ¸µµµ°ãõnODoc‹/¶Œ/¶,RÅdîܹiÏž=iÁ‚©©©)ÿ‘/^ñyb˜VdJJŠÇ±¯¨ãõnO 3333«©bû·oßž®^½š®\¹’xà´yóæq=ÏìÙ³ ;^ïöd@ôf0¶øbËøbË2 U @"GIˆD&¤3 ñ—\®ööö<ö¯tñÅÏZl÷ôôÔ´½FÛÆ·zÛï½÷øNËíø^Àßé¸=ô'>3‡ïŒ @¢({hR) ®¦"öu¼ÞíÉ€èÍ`lñÅ–ñÅ–e@ª€Dz »Š $ñ¶lÙ2âï•f•ŠÙ²*Í:5ÑãµnO 3333«©Ò: #­²sçÎ4oÞ¼<ôjÓ¦Mסw~¬¥Qi]ɯu{S-I‹hB½ESÙ®]×.¶Œ/¶ø @ Q¥z™ÐÞ” @†“›¸ÂmÎt×®k—±Å[žê|2iD @ôf°k×µ‹-ã‹-Ë€Pà =wÝ•NoÙ’NìØ‘ÞxôÑtôË_N‡wíJ/?óLúþþý¾ ¸º¸Æ^úÎwÒ¡o~3}â‰ôÆ_ÿu:>p-¾sÿý©çc«xíöµ¶¦_¯[—~õ—™ÎÞ{o¾ŽþÀé­L?}ä‘ôÚcåçüû¯=ܽ;½<Ð΋Ï?933«€@ê€DÐqâ3Ÿù§¾`äÂí·§ß~ä#éwË—§þÿûóÏß®^÷ VôÕ?Ø»7ýh ¨xõ+_I¯wv¦ãŸýlzçŸH¿¼ûî4üfàú¿²bÅ?]c·Ü’~ûg–.¬]›ÞklàZÌר@QéÚ=òµ¯¥¸2ðüo>üp¾ŽßÞ¶-Ù¼9·snÆÔ;ðœ׬Iïßv[ºrë­é÷K– ¶ùþp~½ííéü_üE¾¾±iS:µuk:ñéO§Ÿ}þóéõ€èØ—¾”~üÕ¯¦CßøFzåé§Óž}vF^ï®]lñele@ ºc‰›¬è5ޝ6+=^öÏ=—~´{w¾ÿÉ¿˜3 q³þË{ïMçï¸#ßè_þàSÿÀMþÕeËÒ¥U«RoGGz÷Î;Ó™ûîK'nêú…/¤xüñtø©§ÒËÝÝéû/¼Pó!XÑæKÒ+{öä×ñêÀßsìoþ&_§?ûÜçÒÉO}*K¿øÌF@Û{AJ\ëÿø¡å¿-®÷kK—æ *þ΋þçùºÿÕ@ÐóË{îI§þÞ··oÏ×O‚£ŸtuåÏÀ‘¿ýÛô£o}+ÿíöíSäoœ7ã‹-¾šÁH•o2+Ó³·(n‚܈ÿøÉ'ÓO{,߀GáìÀõY¾ë¸éŽÌÁµ?ýÓœIˆ›ñötfÓ¦tòrö!²1Ôé‡÷wéûßýnCÜ xþùHD@ÅÑ;s AV?ÿä's ɯ6nÌ×zðŒ€%—`ú/ÎM0ŽÏÇ{mm9à‰ - „" zkà}‰ÏFJ‘UŠÀéà·¿©ÉðVcã{_ÆVD"i Vªë¨sxeàæ4nŠ_¸a}óóŸÏ7ÿø«¿ÊÃ’únrcøÑïÿäOòMðû+Wæ}çn’㜟oßž'~7ž#†©¨Þg!†tãøâsÅöq¼úĹ?êhb¨\\+ñ™‰bý_Ýyg®Ã‰ SâÚÅ—±•€@Œçœ†ÁÊ„kl^x!ý°»;§‰éºÃm¢Ç:n£8:†ë䚃 "ê+¢Îâüúõ¹îâÔ¶mùæ2ê1¢ç<÷œ±²l–k_Æ_É€Ìä`¥â,c<’‡ÑD-@4ÇИ˜ñ©4t&jb8ͯï¸#ÏÜtêŸÈõ1sTŒõú‚¢ã=síÖ:‰€#×.¾Øâ "€ð V*®³ò±¥w‚•XÛâõȬ<ñD^ó"Ї¿§f…§ð,X¿»õÖœ]É™Y ˆD¢7Ã0=E\u¾140&(ˆ:£"g6ÖñÅ–e@H  @Œ•åaùÆÚ/1;ZÔÅL]8¹vñÅ–Õ€DoÆÆ‚kw&𺤨ƒŠذríâ‹-Ë€„™¹êŽ5abzç¨im{ffVR¸fÍš5èÑŽW:¯\]]]©¥¥%»³³³ðãõnODoc;Ýùþ`ïÞ6lØyä‘q=O/E¯w{2 z3ÛËwÿþœ‰lHdE°tí @d—X¤îHèÒ¥K¹X»3 ñ—\®ööö<ö¯tñÅÏZl÷ôôÔ´½FÛÆ·zÛï½÷S˜ï»Ï=—~÷Á¦“ŸúTzõÇ?Æ·l;¾ð(v»Rru ¾úá§+«V¥KþÇ?ÿótåöÛÓo×®M½é↠éý{ïMïÝ}wúÕw¦ ›6¥ßlßžÎoÝšÎÜw_zwà~ï‘GÒ/?÷¹\ïô‹Ç¿~â‰tú±ÇÒO¿ð…tjàñ¯öìI?ÿú×Ó?<þx:þ­o¥ž@ügÝÝyÏŸîÛ—~qøpzýûßO/ì{í‡?Lï¼ùfú‡}ß8oªó-¸sý·=ôg-Û€ŒPSûŠ:^ïöd@ôf0¶À7fÆzoà»0fÊŠ³puíÖ#Ãøw—~ûÛéGÁÁ¡o|#ýý@°päk_K¯~å+yò„XÓæµ®®ôzggzãÑGÓO~8ýìóŸOo}ö³éÄŽéääÌÞ©O|"¾ÿþtfóætö¯þ*ýòž{Ò»ûXúÕ_þe:÷‘¯õ‚ø^{{êt~3ð¿ý·ögéýÛnËÓV_†~wË-éÚŸþiúýÒ¥©ñâ”üû%Kò¾8çĹñ;ñ»ññ\ñœñÜÑF´m¾{×]é—ÓÙ{Š3S¼¶xñZã5Çku{~6<½9ð7½1<ÅßküÍñ·ƒ?ùdfrx×®Ì(X³`'»$2m­Ñ‹pæL~|îܹt÷À‡eÇÀ‡b¤ß+Í*ÕÛÛ[qÖ©‰¯u{j@˜¹Qk„ÄZ!qCk‡`ÂE:n’ÏmÜ8½o’÷ïO/~÷»éÀsÏ¥—õÈ’¼òôÓéàîÝéÐ7¿™³(ñÙ‰!GŸx"gY^û›¿I?ùâÓë, o>ôPzk È8þ™Ïä,ÍÏ·oO§¶mËŸ½Ó÷Ý—~1œœ½÷ÞÔ3pÿõîwffçׯOÖ­ËY ˜Jûâš5é7«Wç,Ñû+W¦Ëü`ºrë­5 ÓcáÖù8pà@Z9p1Çþ… æú+W®T \b-JëjLæx­Û“Ñ›ÁØ6:ßèmÕÓ£7[×î¤Ûö¸ÑŽŒÁÏx@‚úß œ™¨šššft{Ö1§7c‹ï÷r¯nô²Fïëž{[ž# pé¶Ûrþ+ßþ6¾u @~ôÍob4C¾2iDÉ€èÍ`l‘oô\ÇXõâCK°åñ ·Šº‡üð‡sF ßúÏ‚õ»[oÍCÀp’!3ó”wŒ_›—7?ÿyÇyf&|§ÞµGÌĈ!Y2 $1ÙXolyÊóÞì_Þ{o¾É<Ô 7/®ÝÑ3AÅlM1{ZÌø„ïÔ¿vcŠ_C²Ô€DO‘žNlyÚð-ݼ¼Ñ7/®ÝÊíb*Ù<ÜjÛ¶ôâ2cøÖïÚ5$K„ ÌÌÓÊ‘‰LHdD^l !Yüÿn¾¾úÕ¼ðޯ׭ËÃó0™ž6$K  @ôééÄ–§ߨ‰•¥û‘ÌØ›P×îáVÏ<“ßó<ܪ« ßrí’%BceõÆ–§ߘ+n^b¶,lgèp«ýûó”1ÜêÔÖ­… ÙÁwê\»†d©!ˆž"|±åiÅ7Ö ‰õBbÝïÏ ©W]»ßK?þÚ×r–ëÂí·§œéÂwj]»†dÉ€„™yZ9VL•ÓcõXI“i>Üê;ßɽá—?øÁ™ÝbC²Ô€DO‘žNly†ðÍCu–/¯¸6¶S{¸Õ[>˜o@ßùÄ'ªºî‹ï†©{í’%BceñÅ–§ß#û·¹Pù-[òt­ØNùÚ×Òo>ò‘Ô»vmúÑ·¾…oƒ/’¥„ zŠðÅ–§ßìÝ›~}Çé½ÖÖôÃînl§°_úÎwÒ/ï¹çŸ†[uvâë{Á,€03OSïߟN~úÓéÊòåéè—¿ŒÇ|~ö¹Ïå›ËÓ[¶¤†Ú°!Yj@ª¡Y³f z4uttŒé¼®®®ÔÒÒ’ÝÙÙYøñz·'¢7ƒ±Åw’3)}õ«éòŠéíO~2ßôb;5†ÉýfàÿYo{{^X_ß †dÉ€Ô$©¤çŸ>µ¶¶Žz^wwwjkkK}}}ٴľ¢Ž×»=5 Æs2¶ø4Ìç™gÒ…µk³c†%lëô>ìÝ›ÎÞ{oº2¾þׯïC²Ô€Läý÷ßOË–-KgÏž5‰›ùˆKŠÇ¸u¼ÞíÉ€èÍ`lñ-vÈOdA"YlkË>/¹|y:}ß}éÀsÏáë{Á,©€<üðÃi×®]cÊ”477§þþþÁíxûŠ:^ïöÔ€03降ø“ŸúÔ´’5]ý÷_ÿz^Ÿå½n5ðÿ6$K È” @Nœ8‘Ö |Iu¨ÖpÇgÏž]Øñz¶opÉåjøÔ[)úŸµØ>~üxMÛk´m|«·ÝÓÓƒ¾7lÇÌX¿½ýöôþÀ ̱þpJ¾Þø^˜Î×Gp½8äýîƒLo<ú(¾ ´]r-Ú{gçÎZ7æË_Æ·Û32‰àãÌ™3c@d@Œ•5ž“±Åw¢Ž5Bb­X3$Š¢±-p¸Õç+7…g6oΫԻv}/’¥dÊ å³deƬáj*b_QÇëÝžã9[|«ïX5=jbul'çÃO=•úþüÏSßÀÿ¶ÃS|¸•Ŷ‘†d©©Ò,X#7t»4«ToooÅY§&z¼Öí©af®_yúé\§pnãÆ)Ûc?•ýƒgŸM¿Ø´)¯¹’g'R[Ãu²Y² cÊpL& ÅZ•ÖÕ˜ÌñZ·'¢·ˆ±Å·ŽC²¾ûÝtfà&úý•+sO>¶cnõÓ/|!€D âÚåz³éC²d@j¬¦¦¦Ýžãe[|ëïŸ|ñ‹¹5¦Å¶Âp«o|#µŠ!WS!`síbÛ(C²Ô€Pà zŠðÅ–‰ïÁÝ»ÓoV¯NïÞuW:ðüóØ–·zî¹\\Eæ?}øái;ÜÊwCc°‰C²d@¨afæFó‹ßýnúå½÷¦K«V¥CÖ¼™‹5T~1ð¿é{÷bÂÓ¾p¡„d@_lñ¦E­oÔ¸u*±=ôo¤÷ÚÚr¡~,,èÚåéÆv& É’!5 Œ/¶ø6ÀßÈ„DFäÅ Éš lÄp«ûîËÓ¿ùÐC3jv+ß Év& ÉRB2 Œ/¶ø6Èßµ ï~ìcé·ùH®™él_ôÑ<Üêì@ÐõÒ n廡qÙN÷!Y2 ¤„™¹Á³cEjÌ–5S³=½ííéâÀÿ›¿Ÿ‚+Ä3’¥„d@_lñm8Ç´³±^H¬ë‡Ì¶1Üêôý÷çáV?‹)ˆgøb‚¾°®C²d@H ã‹-¾ ú·Çt´±rzfÇJêÓ™íëéòŠé—÷Ü“^úÎw\»ÜPl§Û,5 $Âøb‹oƒ38þÙÏæ¬Á±/}iÚ±ýÑ·¾•z;:Òoþ·yòI×.7,Ûé4$K„Ô€03s:ò·›þñCJïlÙ’¾ÿ S¿ ~àf+^k =yësŸKߟáí˜i–,É€0¾ØâÛ(C²öîM¿¾ãŽô^kkúaw÷”eÅó—?øÁ<Üä¥gžqí2¶ÓlH– ©a|±Å‡ÿßû÷§“Ÿþtº²|y:úå/O)¶?Ú½;]X»6O#üãnåÚÅv& ÉRB2 Œ/¶øâpƒüÕ¯æ¢î·?ùÉ Ï&UÛ¸‘:õ‰OüÓp«Ï~Öp+×.¶Ó|H– ©afæaÛ"ã~¹N3K½ÖÕ•.èC©ç®»ÒË <ÜŠ¹‘fÉ€ ѬY³=œŽ9’:::RSSSš3gNÚ²eK:þ|ÅçìørmiiÉîìì,üx½Û“Ñ[ÄØâ;½‡dE$²!‘©ÛX©ý×·ßž~;pÓ4Þv]»ŒíÔ’%2‰@d8­_¿>:t(]»v-õ÷÷§§žz*­^½zÄçéîîNmmm©¯¯/;‚—ØWÔñz·§ÄxYÆß™á¨¹2„œüÔ§Æ<$k"l_|þùtjÛ¶ô»[nIÇ?ó™i1#—k[C²Ô€Ô5N‘ Iq3Q`Iñ¸µµµ°ãõnODoc‹ïÌqÌŒõÞÀÿ˜)+fÌ*šíkó7y*àwï¼3½\À,\®]ÆvjÉ’©b]»v¥7ŽxNsss>¯üwb_QÇëÝžfæ™åÈHÄú(ÄÚ!E<çÁo;5qCôêW¾‚3sƒÏ’%™`Rª™?~:sæÌ¸žgöìÙ…¯g{ñ—\®öööœz+E¿ñ³Ûǯi{¶oõ¶{zzðÀwÊmǪéWW¬Hvîñüø^¨ô|GNïýõ_§«·ÞšNìØ‘Ž9‚ï8¶Gãk{âÛ%7ÂßûÎÀg8†d½óå/7߆Ȁ<ùä“iÍš52 j@Œ—elñq~åé§ÓÅÿqç6nL?xî¹q±æW®L¿úË¿,dÑC×.c;}†d©©A H¥ŒÄp5±¯¨ãõnO ˆñ²Œ-¾3|HÖw¿›ÎlÚ”Þ&?õÔ¨l_ùö·ÓùõëÓ¥U«ÒÑ'žÀе‹mÉRRp²cÇŽtöìÙüøÒ¥KyšÚòô¡¿WšUª···â¬S=^ëöÔ€037¦òÅ/æaiÑ¢ýóíÛóìV'>ýi³[1›%K2‘u@†[äÀiåÊ•yÿ¼yóÒ¶mÛòÍz¥À%‚”JëjLæx­Û“Ñ[ÄØâÛ¸Žµ;r°1œöÿjÆôÿû;¬\»Ø6ø,«Ò”¼3¡=5 ÆË2¶ø6¶+ ø¸v±5$K 5T¢§_l_ˆk—±­ÿ,j˜„™™ Ì<õgÉ€ ã‹-¾,qíbkHVaC²d@H ã‹-¾8€Œ`|\»Ø’Õ5 ÃÍZ5œoºé&‘‚ ã‹-¾Œ-¾Œm•‡dÍø Hå)©´X ©afffæÚÌ’5£†`íÝ»wp½’.\¸÷íß¿_¤ Âøb‹/c‹/c[å!Y UróÍ7§«W¯Þ°?öÍŸ?_¤ „ñÅ_Æ_ƶÊC²jj5R¢D„ñÅ_Æ_ƶúC²*2wîÜÔÚÚš‡]õ÷÷gŸ?>­Y³&Í›7O¤ „™™™™ë¢ìò"ù˜*¸¨ãõnODoc‹/¶Œ/¶Ü°HyÐPþ8‚„ñ®2ÖäàÁƒ3 1,Ú/-±¯¨ãõnO 33337tÆBQ£qàÀüøÐ¡Cã^ },ÈÉ“'ÓŠ+ROOϸž§Rñ{I±–F¥u5&s¼ÖíÉ€èÍ`lñelñÅ–e@Ê´gÏžtóÍ7_Wt¾dÉ’ôî»ïÖ$€‰â÷ZªÖí©1ž“±Å—±Å[VRV„>ÜÊç±zùhu 4ý½øbËøb‹/c+RÓ$ŠÎ}ôÑ‘Y°†ûÝñªXK£Òº“9^ëöd@ôf0¶ø2¶øbË ©´úy=VBojjªéz%µnO ˆñœŒ-¾Œ-¾Ø²€èÍÀ[Æ[|[ˆ„™™™™yÆ •ê<Æ»:É€0¾ØâËØâ‹-Ë€L(¹xñ¢D ã‹-¾Œ-¾Œ­b±Ì‚5Úbz$Âøb‹/c‹/¶,2®™°JÓíuL'»k×.‘‚ffffVRܬZMµK2 z3[|[|±å΀Ü|óÍióæÍ©§§G4 „ñÅ–ñÅ_ÆV HuÕ«Wç‚Y+V¤#GŽ¤Ë—/‹d@_lñÅ[|[ê Á:wî\zì±ÇÒÂ… ‹Ï-Z”ºººÒùóçE j@˜™™™Y HqH¹"ûqìØ±´|ùòœ‰`dΜ9©µµUÄ Âøb‹/c‹/¶,RݕУ>dÛ¶miÁ‚"5 Œ/¶ø2¶øbËj@ª€ ã‹-¾Œ-¾Œ­ Ȥ±,BXZd¼Ï7’¢¦$Ö wvvŽúœ£?ÙãõnO 33337L ÈÐEG @Æ»FÈHHwwwjkkK}}}ÙyßHíüɯw{2 z3[|±e|±å†­Ù»wo¾yîííÜwáÂ…¼oÿþý… ñ\µ¤x\©°}´ó'{¼Þí©1ž“±Å[Æ[nØXðêÕ«7ì}óçÏ/$‰õFúûû·ãqìI£?ÙãõnODoc‹/¶Œ/¶Ü°F @ÆZ2Z2ÜþJûF;²ÇëÝžffffn¨rÍ;7ŠaWÑsŽ׬Y“æÍ›'Rp{ñ—\®öööœz+E¿ñ³Ûǯi{¶oõ¶cšp<ðŽÛñ½€¾Óq»dõ÷÷gÇãÕ«WçáYEhË–-iûöí9¨‰`çHÏ<ó̈çwww§¶¶¶Ô××—ÝÑÑ‘÷u¼ÞíÉ€èÍ`lñÅ–ñÅ–6…æ#¡¿ùæ›… ‘ù(ϲÄã¨1Iq3oBIñ8‚¤¢Ž×»=5 Æs2¶øbËøbË [Š@#²(„ãqQÁÇpHdBš››G~üxMÛk´m|«·ÝÓÓƒ¾Ór;¾ðÀw:n—ŒÇÌã[óäÅ_ÌEâCµmÛ¶ôÒK/U% Ù»wï°mVª©ˆ}E¯w{j@ŒçdlñÅ–ñÅ–¶äæ›oΊᲑ­(BŸùÌgRoooÎ ¸&H,F8ÚªÞ4}ffffV2eŠÐ£>dÛ¶my…t’a|±Å—±Å[–ù€[yˆñœÆsbËøbËøb‹ï´ @®^½š3å‹–kƒ ã‹-¾Œ-¾Œ­ HaÈ’%K® 8Ê]iµrRÂÌÌÌÌj@Æ­4öïß/"a|±e|±Å—±•©~"Ë¡ć_l_lñelÕ€Ô,‰5?úúúD2 Œ/¶Œ/¶ø2¶2 Õ@:”×ýèíí¨affff5 Õ @†›ýÊ,X2 Œ/¶øâ€-¾Œ­ HÕŠÐG²ú5 Œ/¶ø2¶ø2¶j@ @Hć_l_lñele@fT2Üð®¹sçVü®®®ÔÒÒ’ÝÙÙYøñz·§„™™™™²$tìØ±´xñâ<ä*c_µôÒK/U¼IïîîNmmmyv®pGGGÞWÔñz·'¢7ƒ±Å[Æ[nØ ÈáÇG,B¯V²jÕªtáÂ…ÇÍ|¼ %ÅãÖÖÖŽ׻=5 Æs2¶øbËøbË [ÙŽõë×_Äãµk׿5BŠÖÁƒÓŽ;*žÓÜÜœúûû·ãqì+êx½Û“Ñ›ÁØâ‹-ã‹-7l$†\]½zõ†ý×®]KMMM… q£}êÔ©QkF†{E¯g{ñ—\®öööù–.¾øiÛ¶mÛ¶mÛ¶mÛvµ·ë€\¹rå†ý”€ÄyÏ=÷Œzž ˆÞ ½Œ-¾Ø2¾Øâ;C3 K–,Éõ çÏŸÏ7Îáx¼zõê<<«HE;o¼ñƨç WSûŠ:^ïöÔ€ÏÉØâ‹-ã‹-7l HšT„þæ›o|D;#fÂTšUª···â¬S=^ëöd@ôf0¶ø2¶øbË2 eŠ@#²1ä*‹ >BqS~èС1×`Ä4½•ÖÕ˜ÌñZ·gffffžªnȕЫQì>•Ú“Ñ›ÁØâËØâ‹-Ë€ÄxN|±e|±Å—±UR‹$† ÝtÓMƒGré’a|±Å—±Å[d@&€D`QZ§"äJkgÐÌ@˜™™™Y ˆ!X½z3[|±e|±ÅWBj@_lñelñÅ–Õ€LJ•ê<ԀȀ0¾ØâËØâËØÊ€Ô$¹xñ¢D 3333«)&©4ûUÉÍÍÍ"Æ[|[|[É ¥™®JÓíu¬è½k×.‘‚Æ[|[|[5 Å Á2Õ® ˆ=¾Ø2¾ØâËØÊ€˜KÂÌÌÌÌ<ó_|1mÙ²å†ýÛ¶mK/½ô’HA„ñÅ_Æ_ÆV¤¸äæ›oÎ3^ 7 Ö‚ D j@_lñelñelÕ€€Dºu@d@_l_lñele@j€ÄlW.\¸aÿùóçÓœ9s »á>yòdZ·n]žÚwÑ¢EiïÞ½Ïïêêʯ-ÜÙÙYøñz·§„™™™™²$n|#ÓqúôéÔßߟ}êÔ©œimm-$øˆç[ºti:xð`~þÞÞÞôàƒŽx~wwwjkkK}}}Ùy_QÇëÝž ˆÞ Æ_l_l¹a3 Që1ÒB„—.]*$Ùºuë¨rÅÍ|¼ %Åãò`h²ÇëÝžã9[|±e|±å†­) ·Z²dIjjjÊŽlEd)ŠÒܹsÓž={rQ{<ü‘þ—ô"SRR<._•}²ÇëÝž ˆÞ Æ_l_l¹a3 µPdS¶oßž®^½š®\¹’xà´yóæqÆ—/˜8Ùãõl/Þà’ËÕÞÞž#ßÒÅ?mÛ¶mÛ¶mÛ¶mÛ®ööŒ @"GIˆD&DDDoc‹/¶Œ/¶Ü€õë×çæ¡5 EMÃEÙCJ7èÃÕTľ¢Ž×»=5 Æs2¶øbËøbË [²aÆÁ`chRiØÒxè1ì*‚p Ç*_}}è¦Ò¬RQ‡RiÖ©‰¯u{2 z3[|[|±e²u@>|݃Q ~çw¦§Ÿ~º°aX;wîLóæÍËC¯6mÚt]úp5±–F¥u5&s¼ÖíY„™™™™§ªëºzùã¨cˆ€¡ªT2Ú“Ñ›ÁØâËØâ‹-Ë€”1l¨tc~àÀüøÐ¡C…Õ€ã9[|[|±e5 YûöíKÛ¶mË—/_~] H¬ÛA2 Œ/¶ø2¶ø2¶2 U™†÷ÚµkiáÂ…9ó1þü<[Íì„™™™™Õ€Ì¸u@HDoc‹/c‹/¶,Bã9ñÅ–ñÅ_ÆV Hmžžž´dÉ’Á!X1ô*ê?/^,Ja|±Å—±Å—±•)6Y½zu:yòd~ës”¡¯]»V¤ „™™™™Õ€€477çÕÉC1ëUo¼ñF:qâDš3gŽHA„ñÅ_Æ_ÆV¤Øu@Jš={vÞ.Í~e5 Œ/¶ø2¶ø2¶j@ @ZZZrÆãôéÓ9ø˜;wnÞY‘8F2 Œ/¶ø2¶ø2¶2 … qã[^÷±nݺ¼?¢°U«V‰Ô€0333³b§á-->¸hÑ¢Á}K—.Í3d‘ ã‹-¾Œ-¾Œ­ ˆu@ Æsω-øbËøb‹¯„d@_lñelñÅ–e@FTÌxUš~w¨‹šk¸çM]]]¹>ÜÙÙYøñz·§„™™™™²$VA/8ÊÓò€ŒGÝÝÝ©­­-õõõewttä}E¯w{2 z3[|±e|±å†Í€D ±ÿþª7o7óñ&”[[[ ;^ïöÔ€ÏÉØâ‹-ã‹-7l HQYŽÑX_$Úºå–[ÒÎ;+ž«³÷÷÷nÇãØWÔñz·'¢7ƒ±Å[Æ[nØ HL½Æj¥XðpÆ é‘GWƤæÏŸŸ®^½*RPÂÌÌÌÌj@fÖ: ½Œ-¾Ø2¾ØâÛ ˆ:5 >ôøbËøb‹/c«¤fÈTX\"¢7ƒ±Å[Æ[|$Y´hQºté’ˆ@ 3333«©~òÊ+¯¤Ûn»mp*^’a|±e|±Å—±•©ê: #Y}ˆÆ[|[|[5 …¡äÙ³g‹d@_lñelñele@¦ï4¼9»2šºººRKKKvgggáÇëÝžffffnÈZêùçŸO­­­£ ÝÝÝ©­­-×¥„#h‰}E¯w{2 z3[|±e|±å†Í€Tªó(²äý÷ßOË–-KgÏž5‰›ùxJŠÇ¸u¼Þí©1ž“±Å[Æ[nèátñâÅB‡~8íÚµk°ð½’š››Sÿàv<Ž}E¯w{2 z3[|±e|±å†Ë€TšýªäÑn¢Çª'N¤5kÖ\×öh¯m¨Ê â'{¼žíÅ\r¹ÚÛÛsä[ºøâ§mÛ¶mÛ¶mÛ¶mÛÕÞ®YRšéª4ÝîPG1u)c1YEðqæÌ™1 2 z3ôf0¶øbËøb‹ï ‚U‹©vGʰŒ§&#öu¼Þí©1ž“±Å[Æ[nØzhhð1t»4«ToooÅY§&z¼ÖíÉ€èÍ`lñelñÅ–e@¦pе4*­«1™ãµnÏ: ÌÌÌÌùdZ³fMCf@â .¹\ííí9ò-]|ñÓ¶mÛ¶mÛ¶mÛ¶íjo7L H¥ Áp5±¯¨ãõnODoc‹/¶Œ/¶,REíØ±#={6?¾téRž¦¶ü}è¦Ò¬R½½½gšèñZ·§ÄxNÆ_Æ_lY H uàÀ´råÊ|ã?oÞ¼´mÛ¶|³^©†"‚”JëjLæx­Û“Ñ›ÁØâËØâ‹-Ë€L“)ygB{Öafffæ©ê† @Q2 z3[|±e|±ej¸ÄxN|±e|±Å—±U"€èÍЛÁØâ‹-ã‹-¾RÂÌÌÌÌj@H¢7Co¶Œ/¶Œ/¶ø @H ˆñœøb‹/c‹/¶¬„ z3ðÅ–ñÅ_Æ_ˆÄ‡™™™™ $Âøb‹/c‹/¶8È€@ Æsω-ã‹-ã‹-¾’a|±Å—±Å[–!3333³D"¢7ƒ±Å[Æ[| ¤„ñÅ_Æ_ÆV È4 @Ž9’Ö®]›šššÒœ9sÒ¶mÛRoooÅßéêêJ---Ù…¯w{2 z3[|±e|±e*iãÆéðáé¿¿?]¹r%=ôÐC9 IÝÝÝ©­­-õõõewttä}E¯w{j@˜™™™Y H ÈìÙ³G<7ó–[[[ ;^ïöd@ôf0¶øbËøbË2 5ÔÁƒ+f@š››sR°Ä¾¢Ž×»=5 Æs2¶øbËøbËj@j¤“'O¦+V¤žžžÏ™5kÖ ûÊ3&“=^ïöd@ôf0¶øbËøbË2 5ÐÑ£GÓ²eËÒ‰'*ž7“3 ñ—\®öööù–.¾øiÛ¶mÛ¶mÛ¶mÛvµ·glràÀ´xñâôÖ[ozîp5±¯¨ãõnODoc‹/¶Œ/¶,REíÞ½;-Z´(:ujLC J³JÅT½•fšèñZ·§ÄxNÆ_Æ_lY H 7üùR E¬¥Qi]ɯu{2 z3[|[|±e)¤X p&·gffffžªnȤ%¢7ƒ±Å[Æ[–¡† @ŒçÄ[Æ[|[5 ˆÞ ½Œ-¾Ø2¾Øâ+!5 ÌÌÌ̬„ z3ôf`ËøbËøb‹¯„Ô€ω/¶ø2¶øbËj@H¢7_l_lñelñ€@|ø˜™™™YB2 Œ/¶ø2¶øb‹ƒ ˆDb<§ñœØ2¾Ø2¾Øâ+!Æ[|[|±e€03333 @ 2 z3[|±e|±ÅWBj@_lñelñelÕ€LÃdÖ¬Yƒ«ºººRKKKvgggáÇëÝž ˆÞ Æ_l_lY¤ÈXÔÝÝÚÚÚR___vGGGÞWÔñz·§„™™™™Õ€L¡$næ# ,)·¶¶v¼ÞíÉ€èÍ`lñÅ–ñÅ–e@¦PÒÜÜœúûû·ãqì+êx½ÛSb<'c‹/¶Œ/¶¬d  Ã7{öìŽ׳½xƒK.W{{{¾ðJÑoü¬ÅöñãÇkÚ^£mã[½ížž<ð–Ûñ½€¾Óq»d @hŠ1É+V¬Èc<©øk7<þütæÌ@ Љ'Òš5k|?Ô@§OŸN6lH<ò}lß¾=]½z5}}àÒæÍ›©‚>úÑæ!oTŒÎ;—–,Y2ø?-O‡ì’„ STGÍCY⦎ª£è-zòÉ'¯»i¦‰+8–s¾ª«K—.¥–– PïFàQR"†f¯W_}uZôÎO'ÅÄ ‘)¯™£& $™‚:pà@Z¼xqzë­·À¨ÔØ÷}`¦&ÈtTÌÚ64‰ „ŠULNñÆoQåÿ_Óáš„ SL»wïÎS@JQWG1ö¸4EaÜÀÅL,mmmÀø~˜òŠBéR†)†]Ü}÷ÝÆÒ¤(@aW„„c8VLÑMÅ騱c9¡b3^EÝGy ˆY°hFßXèå¬[|‹Sd—bÚÂ`:oÞ<ë¬@¦åµ»páÂ\ÿQÞkO“S ]‰ï„zµiÓ&Eè+²L1:«è”(­ŽÇÓ¡®QBDDDDD"""""€ @ˆˆˆˆˆHBDDDDD$!""""" @ˆˆˆˆˆˆ DDÔ š.‹rZ<”ˆHBDD3 Ѐ @ˆˆˆ ""Mïà£ÜC8p ­Y³&555¥æææ´nݺtöìÙÎ{ñÅóyqNùó;v,­]»6ïŸ={vºí¶ÛÒþýûox-ßüæ7óïÝtÓMiîܹiÇŽéâÅ‹×óì³Ï¦%K–ä×rË-·¤gžyæ†×}îܹ´eË–4gΜÜ^<×ý÷ߟ^{í5o8 @ˆˆˆ¦J2Òþ*Þ}÷ÝÔßß?$¬Zµê†ó:::òyå:zôh("h¹páBºvíZzàòù<”ëÉ'Ÿ l"˜‰sâÜ’^y啼oÆ 90 Ç㡯?^[l9r$o_¾|9<ñúˆˆ DDDS<yûí·÷ERÊR =ïÌ™37W®\I=ôP¾iëññ>ßúõëÓ¡C‡òk‹sžzê©´zõêQÿÞçŸ>µ¶¶Žøw5yã7ÒÂ… Ó«¯¾š·#øyðÁÇý#T…Ç,E¡î¿ÿþënöbjÓц/e¬¯~õ«éÎ;ïÌãBÑ£_^kRª‰×0Ùøûâï,¯©4 ÖîÝ»s€têÔ© ú:F;?†Ä•¦¾téR.Î/¿iË©É1 V É;vìXÞ®æ,X£±(ÍbïûdfÁí÷ D$!"o2ÁY°¢è7nÐb¸S M‰BðòZŒ8ë@Äñ襎Æò›½˜"¶4dªÒhÉÐDÉpÃŽ"‰zŒh+¦ÊÝ¿ÿuÇ£X>žÑfÁ-ÁMií‰p<.Â4–çšíøxž/2ñ÷—x ]c¼ÈX×äz]Äkˆ÷"ÞÿgŸ}v̯<ÈXž+°±¬2Òë¨ôû"€¹9"ò#"‘›#"Ÿ1""¹9""Ÿ1"€¹9"ò#"€‘›#"ò#"‘›#"Ÿ1""ßFD4enŽ˜¹º&"€QCéÿ{ àˆêIEND®B`‚Multiverse-multiverse-0.7.0/gradle.properties-template000066400000000000000000000001211174000617100232260ustar00rootroot00000000000000codehaus_loginname=yourloginname codehaus_password=yourpassword processorCount=8 Multiverse-multiverse-0.7.0/multiverse-core-drivers/000077500000000000000000000000001174000617100226505ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/pom.xml000066400000000000000000000041621174000617100241700ustar00rootroot00000000000000 4.0.0 jar multiverse-core-drivers The Multiverse Code (so API and implementation) The Multiverse core drivers for benchmarking org.multiverse multiverse 0.7.0-SNAPSHOT ../pom.xml maven-resources-plugin 2.4.2 ${sourceEncoding} org.apache.maven.plugins maven-compiler-plugin 2.3.2 1.6 1.6 org.multiverse multiverse-core ${project.version} junit junit 4.10 org.mockito mockito-all 1.9.0 Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/000077500000000000000000000000001174000617100234375ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/000077500000000000000000000000001174000617100243635ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/000077500000000000000000000000001174000617100253045ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/000077500000000000000000000000001174000617100260735ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/000077500000000000000000000000001174000617100302725ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/000077500000000000000000000000001174000617100312605ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/000077500000000000000000000000001174000617100323425ustar00rootroot00000000000000000077500000000000000000000000001174000617100344005ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarksAccountDriver.java000066400000000000000000000175051174000617100400230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnDoubleCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnDouble; import org.multiverse.stms.gamma.GammaStm; import java.util.Random; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class AccountDriver extends BenchmarkDriver { public static final int WARMUP_PHASE = 1; public static final int TEST_PHASE = 2; public static final int SHUTDOWN_PHASE = 3; private GammaStm stm; private int accountCount; private Bank bank; private int threadCount; private BenchmarkThread[] threads; private int readFrequency; private int writeFrequency; @Override public void setUp() { stm = new GammaStm(); bank = new Bank(accountCount); threads = new BenchmarkThread[threadCount]; for (int k = 0; k < threads.length; k++) { //threads[k] = new BenchmarkThread(k, ); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { //To change body of implemented methods use File | Settings | File Templates. } class BenchmarkThread extends TestThread { final private int id; final private int nb; final private int max; final private int readThreads; final private int writeThreads; int transferCount; int readCount; int writeCount; final private Random random; volatile private int phase; private int steps; BenchmarkThread(int id, int nb, int max, int readThreads, int writeThreads) { phase = WARMUP_PHASE; steps = 0; this.id = id; this.nb = nb; this.max = max; this.readThreads = readThreads; this.writeThreads = writeThreads; transferCount = readCount = writeCount = 0; random = new Random(); } public void setPhase(int phase) { this.phase = phase; } public int getSteps() { return steps; } public void doRun() { while (phase == WARMUP_PHASE) { step(WARMUP_PHASE); } while (phase == TEST_PHASE) { step(TEST_PHASE); steps++; } } protected void step(int phase) { if (id < readThreads) { // Compute total of all accounts (read-all transaction) bank.computeTotal(); if (phase == TEST_PHASE) readCount++; } else if (id < readThreads + writeThreads) { // Add 0% interest (write-all transaction) bank.addInterest(0); if (phase == TEST_PHASE) writeCount++; } else { int i = random.nextInt(100); if (i < readFrequency) { // Compute total of all accounts (read-all transaction) bank.computeTotal(); if (phase == TEST_PHASE) readCount++; } else if (i < readFrequency + writeFrequency) { // Add 0% interest (write-all transaction) bank.addInterest(0); if (phase == TEST_PHASE) writeCount++; } else { int amount = random.nextInt(max) + 1; Account src; Account dst; if (s_disjoint && nb <= bank.accounts.length) { src = bank.accounts[random.nextInt(bank.accounts.length / nb) * nb + id]; dst = bank.accounts[random.nextInt(bank.accounts.length / nb) * nb + id]; } else { src = bank.accounts[random.nextInt(bank.accounts.length)]; dst = bank.accounts[random.nextInt(bank.accounts.length)]; } try { bank.transfer(src, dst, amount); if (phase == TEST_PHASE) transferCount++; } catch (OverdraftException e) { System.err.println("Overdraft: " + e.getMessage()); } } } } public String getStats() { return "T=" + transferCount + ", R=" + readCount + ", W=" + writeCount; } } static volatile boolean s_disjoint = false; static volatile boolean s_yield = false; class Bank { private final Account[] accounts; private final TxnExecutor addInterrestBlock = stm.newTxnFactoryBuilder().newTxnExecutor(); private final TxnExecutor computeTotalBlock = stm.newTxnFactoryBuilder().newTxnExecutor(); private final TxnExecutor transferBlock = stm.newTxnFactoryBuilder().newTxnExecutor(); public Bank(int accountCount) { accounts = new Account[accountCount]; for (int k = 0; k < accounts.length; k++) { accounts[k] = new Account("user-" + k, 0); } } public void addInterest(final float rate) { addInterrestBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { for (Account a : accounts) { a.deposit(a.getBalance() * rate); if (s_yield) Thread.yield(); } } }); } public double computeTotal() { return computeTotalBlock.execute(new TxnDoubleCallable() { @Override public double call(Txn tx) throws Exception { double total = 0.0; for (Account a : accounts) { total += a.getBalance(); if (s_yield) Thread.yield(); } return total; } }); } public void transfer(final Account src, final Account dst, final float amount) throws OverdraftException { transferBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { dst.deposit(amount); if (s_yield) Thread.yield(); src.withdraw(amount); } }); } } public class Account { private final String name; private final TxnDouble balance; public Account(String name, double balance) { this.balance = stm.getDefaultRefFactory().newTxnDouble(balance); this.name = name; } public String getName() { return name; } public double getBalance() { return balance.get(); } public void deposit(double amount) { balance.incrementAndGet(amount); } public void withdraw(double amount) throws OverdraftException { if (balance.get() < amount) throw new OverdraftException("Cannot withdraw $" + amount + " from $" + balance.get()); balance.incrementAndGet(-amount); } } public class OverdraftException extends Exception { public OverdraftException(String reason) { super(reason); } } } AntWorldDriver.java000066400000000000000000000007701174000617100401550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; public class AntWorldDriver extends BenchmarkDriver { @Override public void run(TestCaseResult testCaseResult) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void processResults(TestCaseResult testCaseResult) { //To change body of implemented methods use File | Settings | File Templates. } } ArrayUpdateDriver.java000066400000000000000000000031141174000617100406370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; public class ArrayUpdateDriver implements GammaConstants { private GammaStm stm; private int refCount = 1; @Before public void setUp() { stm = new GammaStm(); } @Test public void test() { final long txCount = 1000 * 1000 * 1000; FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(new GammaTxnConfig(stm)); GammaTxnLong[] refs = new GammaTxnLong[refCount]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnLong(stm, 0); } long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { for (int l = 0; l < refs.length; l++) { refs[l].openForWrite(tx, LOCKMODE_NONE).long_value++; } tx.commit(); tx.hardReset(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); //assertEquals(txCount, ref.volatile_value); //assertEquals(txCount+initialVersion, ref.version); } } AtomicGetDriver.java000066400000000000000000000065401174000617100403000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class AtomicGetDriver extends BenchmarkDriver implements GammaConstants { private transient GammaStm stm; private transient GetThread[] threads; private int threadCount; private long transactionsPerThread; private boolean sharedRef; private boolean weakGet; @Override public void setUp() { System.out.printf("Multiverse > Threadcount %s\n", threadCount); System.out.printf("Multiverse > Transactions/Thread %s \n", transactionsPerThread); System.out.printf("Multiverse > WeakGet %s \n", weakGet); System.out.printf("Multiverse > SharedRef %s \n", sharedRef); stm = new GammaStm(); threads = new GetThread[threadCount]; GammaTxnLong ref = sharedRef ? new GammaTxnLong(stm) : null; for (int k = 0; k < threads.length; k++) { threads[k] = new GetThread(k, ref == null ? new GammaTxnLong(stm) : ref); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (GetThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); double transactionsPerSecond = BenchmarkUtils.transactionsPerSecond( transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second/thread\n", format(transactionsPerSecondPerThread)); System.out.printf("Multiverse > Performance %s transactions/second\n", format(transactionsPerSecond)); testCaseResult.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); } class GetThread extends TestThread { private long durationMs; private final GammaTxnLong ref; public GetThread(int id, GammaTxnLong ref) { super("AtomicGetThread-" + id); setPriority(Thread.MAX_PRIORITY); this.ref = ref; } public void doRun() { long startMs = System.currentTimeMillis(); final long _transactionsPerThread = transactionsPerThread; if (weakGet) { for (long k = 0; k < _transactionsPerThread; k++) { ref.atomicWeakGet(); } } else { for (long k = 0; k < _transactionsPerThread; k++) { ref.atomicGet(); } } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse > %s is finished in %s ms\n", getName(), durationMs); } } } AtomicIncrementDriver.java000066400000000000000000000061041174000617100415010ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class AtomicIncrementDriver extends BenchmarkDriver implements GammaConstants { private transient GammaStm stm; private transient IncThread[] threads; private int threadCount; private long transactionsPerThread; private boolean sharedRef; @Override public void setUp() { System.out.printf("Multiverse > Threadcount %s\n", threadCount); System.out.printf("Multiverse > Transactions/Thread %s \n", transactionsPerThread); System.out.printf("Multiverse > SharedRef %s \n", sharedRef); stm = new GammaStm(); threads = new IncThread[threadCount]; GammaTxnLong ref = sharedRef ? new GammaTxnLong(stm) : null; for (int k = 0; k < threads.length; k++) { threads[k] = new IncThread(k, ref == null ? new GammaTxnLong(stm) : ref); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (IncThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); double transactionsPerSecond = BenchmarkUtils.transactionsPerSecond( transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second/thread\n", format(transactionsPerSecondPerThread)); System.out.printf("Multiverse > Performance %s transactions/second\n", format(transactionsPerSecond)); testCaseResult.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); } class IncThread extends TestThread { private long durationMs; private final GammaTxnLong ref; public IncThread(int id, GammaTxnLong ref) { super("IncThread-" + id); setPriority(Thread.MAX_PRIORITY); this.ref = ref; } public void doRun() { long startMs = System.currentTimeMillis(); final long _transactionsPerThread = transactionsPerThread; for (long k = 0; k < _transactionsPerThread; k++) { ref.atomicIncrementAndGet(1); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse > %s is finished in %s ms\n", getName(), durationMs); } } } AtomicLongIncrementDriver.java000066400000000000000000000055441174000617100423300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import java.util.concurrent.atomic.AtomicLong; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class AtomicLongIncrementDriver extends BenchmarkDriver { private transient IncThread[] threads; private int threadCount; private long transactionsPerThread; private boolean sharedRef; @Override public void setUp() { System.out.printf("Multiverse > Threadcount %s\n", threadCount); System.out.printf("Multiverse > Transactions/Thread %s \n", transactionsPerThread); System.out.printf("Multiverse > SharedRef %s \n", sharedRef); threads = new IncThread[threadCount]; AtomicLong ref = sharedRef ? new AtomicLong() : null; for (int k = 0; k < threads.length; k++) { threads[k] = new IncThread(k, ref == null ? new AtomicLong() : ref); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (IncThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); double transactionsPerSecond = BenchmarkUtils.transactionsPerSecond( transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second/thread\n", format(transactionsPerSecondPerThread)); System.out.printf("Multiverse > Performance %s transactions/second\n", format(transactionsPerSecond)); testCaseResult.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); } class IncThread extends TestThread { private long durationMs; private final AtomicLong ref; public IncThread(int id, AtomicLong ref) { super("IncThread-" + id); setPriority(Thread.MAX_PRIORITY); this.ref = ref; } public void doRun() { long startMs = System.currentTimeMillis(); final long _transactionsPerThread = transactionsPerThread; for (long k = 0; k < _transactionsPerThread; k++) { ref.incrementAndGet(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse > %s is finished in %s ms\n", getName(), durationMs); } } } AtomicSetDriver.java000066400000000000000000000056331174000617100403160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class AtomicSetDriver extends BenchmarkDriver implements GammaConstants { private transient GammaStm stm; private transient GetThread[] threads; private int threadCount; private long transactionsPerThread; private boolean sharedRef; @Override public void setUp() { System.out.printf("Multiverse > Threadcount %s\n", threadCount); System.out.printf("Multiverse > Transactions/Thread %s \n", transactionsPerThread); System.out.printf("Multiverse > SharedRef %s \n", sharedRef); stm = new GammaStm(); threads = new GetThread[threadCount]; GammaTxnLong ref = sharedRef ? new GammaTxnLong(stm) : null; for (int k = 0; k < threads.length; k++) { threads[k] = new GetThread(k, ref == null ? new GammaTxnLong(stm) : ref); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (GetThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second/thread\n", format(transactionsPerSecondPerThread)); System.out.printf("Multiverse > Performance %s transactions/second\n", BenchmarkUtils.transactionsPerSecondAsString(transactionsPerThread, totalDurationMs, threadCount)); testCaseResult.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); } class GetThread extends TestThread { private long durationMs; private final GammaTxnLong ref; public GetThread(int id, GammaTxnLong ref) { super("AtomicGetThread-" + id); setPriority(Thread.MAX_PRIORITY); this.ref = ref; } public void doRun() { long startMs = System.currentTimeMillis(); final long _transactionsPerThread = transactionsPerThread; for (long k = 0; k < _transactionsPerThread; k++) { ref.atomicGet(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse > %s is finished in %s ms\n", getName(), durationMs); } } } BasicPerformanceDriver.java000066400000000000000000000116711174000617100416300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.junit.Ignore; import org.junit.Test; import org.multiverse.MultiverseConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.utils.ToolUnsafe; import sun.misc.Unsafe; @Ignore public class BasicPerformanceDriver { public static void main(String[] args) { BasicPerformanceDriver driver = new BasicPerformanceDriver(); driver.casPerformance(); } @Test public void test() { GammaStm stm = new GammaStm(); GammaTxnLong ref = new GammaTxnLong(stm); final long transactionCount = 1000 * 1000 * 1000; final long startMs = System.currentTimeMillis(); for (long k = 0; k < transactionCount; k++) { ref.arriveAndLock(1, MultiverseConstants.LOCKMODE_EXCLUSIVE); //ref.orec = 0; ref.departAfterUpdateAndUnlock(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(transactionCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); } @Test public void casPerformance() { final long transactionCount = 1000 * 1000 * 1000; final long startMs = System.currentTimeMillis(); Cas cas = new Cas(); final long t = transactionCount / 10; for (long k = 0; k < t; k++) { cas.atomicInc(); cas.atomicInc(); cas.atomicInc(); cas.atomicInc(); cas.atomicInc(); cas.atomicInc(); cas.atomicInc(); cas.atomicInc(); cas.atomicInc(); cas.atomicInc(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(transactionCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); } @Test public void volatileWritePerformance() { final long transactionCount = 1000 * 1000 * 1000; final long startMs = System.currentTimeMillis(); final Cas cas = new Cas(); final long t = transactionCount / 10; for (long k = 0; k < t; k++) { cas.volatile_value++; cas.volatile_value++; cas.volatile_value++; cas.volatile_value++; cas.volatile_value++; cas.volatile_value++; cas.volatile_value++; cas.volatile_value++; cas.volatile_value++; cas.volatile_value++; } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(transactionCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); } @Test public void basicWritePerformance() { final long transactionCount = 1000 * 1000 * 1000; final long startMs = System.currentTimeMillis(); final Cas cas = new Cas(); for (long k = 0; k < transactionCount; k++) { cas.volatile_value++;//lock cas.volatile_value++;//version cas.volatile_value++;//value cas.volatile_value++;//unlock } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(transactionCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); } @Test public void basicWritePerformanceWithNonVolatileVersionAndValue() { final long transactionCount = 1000 * 1000 * 1000; final long startMs = System.currentTimeMillis(); final Cas cas = new Cas(); for (long k = 0; k < transactionCount; k++) { cas.volatile_value++;//lock cas.value++;//version cas.value++;//value cas.volatile_value++;//unlock } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(transactionCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); } class Cas { protected final Unsafe ___unsafe = ToolUnsafe.getUnsafe(); protected final long valueOffset; { try { valueOffset = ___unsafe.objectFieldOffset( Cas.class.getDeclaredField("volatile_value")); } catch (Exception ex) { throw new Error(ex); } } volatile long volatile_value; long value; void atomicInc() { final long oldValue = volatile_value; final long newValue = oldValue + 1; ___unsafe.compareAndSwapLong(this, valueOffset, oldValue, newValue); } } } BoxingOverheadDriver.java000066400000000000000000000077411174000617100413340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class BoxingOverheadDriver extends BenchmarkDriver implements GammaConstants { private GammaStm stm; private boolean withBoxing; private long transactionsPerThread; private int threadCount; private UpdateThread[] threads; @Override public void setUp() { System.out.printf("Multiverse > Transactions/thread %s \n", BenchmarkUtils.format(transactionsPerThread)); System.out.printf("Multiverse > ThreadCount %s \n", threadCount); System.out.printf("Multiverse > With Boxing %s \n", withBoxing); stm = new GammaStm(); threads = new UpdateThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (UpdateThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); double transactionsPerSecond = BenchmarkUtils.transactionsPerSecond( transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second/thread\n", BenchmarkUtils.format(transactionsPerSecondPerThread)); System.out.printf("Multiverse > Performance %s transactions/second\n", BenchmarkUtils.format(transactionsPerSecond)); testCaseResult.put("transactionsPerThreadPerSecond", transactionsPerSecondPerThread); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); } class UpdateThread extends TestThread { private long durationMs; public UpdateThread(int id) { super("UpdateThread-" + id); } public void doRun() { FatMonoGammaTxn tx = new FatMonoGammaTxn( new GammaTxnConfig(stm) .setReadLockMode(LockMode.Exclusive) .setDirtyCheckEnabled(false)); long startMs = System.currentTimeMillis(); final long _transactionCount = transactionsPerThread; if (withBoxing) { GammaTxnRef ref = new GammaTxnRef(stm, new Long(0)); for (long k = 0; k < _transactionCount; k++) { ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); tx.hardReset(); } assertEquals(_transactionCount, (long) ref.atomicGet()); } else { GammaTxnLong ref = new GammaTxnLong(stm); for (long k = 0; k < _transactionCount; k++) { ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); tx.hardReset(); } assertEquals(_transactionCount, ref.atomicGet()); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse > %s is finished in %s ms\n", getName(), durationMs); } } } ContendedCounterDriver.java000066400000000000000000000065601174000617100416710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class ContendedCounterDriver extends BenchmarkDriver { private int threadCount; private LockMode lockLevel = LockMode.None; private long transactionsPerThread; private boolean dirtyCheck; private GammaStm stm; private GammaTxnLong ref; private IncThread[] threads; @Override public void setUp() { System.out.printf("Multiverse > Thread count %s\n", threadCount); System.out.printf("Multiverse > Transactions per thread %s\n", transactionsPerThread); System.out.printf("Multiverse > Dirty check %s \n", dirtyCheck); System.out.printf("Multiverse > Pessimistic lock level %s \n", lockLevel); stm = new GammaStm(); ref = stm.getTxRefFactoryBuilder().build().newTxnLong(0); threads = new IncThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new IncThread(k); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (IncThread t : threads) { totalDurationMs += t.getDurationMs(); } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); double transactionsPerSecond = BenchmarkUtils.transactionsPerSecond( transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second/thread with %s threads\n", format(transactionsPerSecondPerThread), threadCount); System.out.printf("Multiverse > Performance %s transactions/second with %s threads\n", format(transactionsPerSecond), threadCount); testCaseResult.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); } class IncThread extends TestThread { public IncThread(int id) { super("IncThread-" + id); } @Override public void doRun() throws Exception { final long _incCount = transactionsPerThread; TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadLockMode(lockLevel) .setDirtyCheckEnabled(dirtyCheck) .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); } }; for (long k = 0; k < _incCount; k++) { executor.execute(callable); } } } } FatMonoUpdateWithTransactionDriver.java000066400000000000000000000046441174000617100441770ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaTxnExecutor; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import static org.junit.Assert.assertEquals; public class FatMonoUpdateWithTransactionDriver implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public static void main(String[] srgs) { FatMonoUpdateWithTransactionDriver driver = new FatMonoUpdateWithTransactionDriver(); driver.setUp(); driver.testNoLocking(); } @Test public void testNoLocking() { test(LockMode.None); } @Test public void testReadLock() { test(LockMode.Read); } @Test public void testWriteLock() { test(LockMode.Write); } @Test public void testExclusiveLock() { test(LockMode.Exclusive); } public void test(LockMode writeLockMode) { final long txCount = 1000 * 1000 * 1000; final GammaTxnLong ref = new GammaTxnLong(stm, 0); long initialVersion = ref.getVersion(); final GammaTxnExecutor executor = stm.newTxnFactoryBuilder() .setFat() .setDirtyCheckEnabled(false) .setWriteLockMode(writeLockMode) .newTxnExecutor(); final TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.openForWrite((FatMonoGammaTxn) tx, LOCKMODE_NONE).long_value++; } }; long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { executor.execute(callable); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); assertEquals(txCount, ref.long_value); assertEquals(txCount + initialVersion, ref.version); } } IntrinsicLockStackDriver.java000066400000000000000000000106501174000617100421620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class IntrinsicLockStackDriver extends BenchmarkDriver { private int pushThreadCount = 1; private int popThreadCount = 1; private int capacity; private PushThread[] pushThreads; private PopThread[] popThreads; private Stack stack; @Override public void setUp() { System.out.printf("Multiverse > Pop threadcount %s\n", pushThreadCount); System.out.printf("Multiverse > Push threadcount %s\n", popThreadCount); if (capacity == Integer.MAX_VALUE) { System.out.printf("Multiverse > Capacity unbound\n"); } else { System.out.printf("Multiverse > Capacity %s\n", capacity); } stack = new Stack(); pushThreads = new PushThread[pushThreadCount]; for (int k = 0; k < pushThreadCount; k++) { pushThreads[k] = new PushThread(k); } popThreads = new PopThread[popThreadCount]; for (int k = 0; k < popThreadCount; k++) { popThreads[k] = new PopThread(k); } } @Override public void run(TestCaseResult testCaseResult) { startAll(pushThreads); startAll(popThreads); joinAll(pushThreads); joinAll(popThreads); } @Override public void processResults(TestCaseResult result) { long pushCount = 0; long totalDurationMs = 0; for (PushThread t : pushThreads) { pushCount += t.count; totalDurationMs += t.getDurationMs(); } long popCount = 0; for (PopThread t : popThreads) { popCount += t.count; totalDurationMs += t.getDurationMs(); } int threadCount = pushThreadCount + popThreadCount; long count = pushCount + popCount; System.out.printf("Multiverse > Total number of transactions %s\n", count); double transactionsPerSecond = (count * 1000.0d) / totalDurationMs; System.out.printf("Multiverse > Performance %s transactions/second with %s threads\n", format(transactionsPerSecond), threadCount); result.put("transactionsPerSecond", transactionsPerSecond); } public class PushThread extends TestThread { private long count; public PushThread(int id) { super("PushThread-" + id); } @Override public void doRun() throws Exception { while (!shutdown) { stack.push("item"); count++; } for (int k = 0; k < popThreadCount; k++) { stack.push("end"); } } } public class PopThread extends TestThread { private long count; public PopThread(int id) { super("PopThread-" + id); } @Override public void doRun() throws Exception { boolean end = false; while (!end) { end = stack.pop().equals("end"); count++; } } } class Stack { Node head; int size; public synchronized String pop() { while (head == null) { try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } if (capacity != Integer.MAX_VALUE) { size--; notifyAll(); } Node node = head; head = node.next; return node.value; } public synchronized void push(String value) { if (capacity != Integer.MAX_VALUE) { while (size == capacity) { try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } size++; head = new Node(head, value); notifyAll(); } } static class Node { final Node next; final String value; Node(Node next, String value) { this.next = next; this.value = value; } } } JucLockStackDriver.java000066400000000000000000000114301174000617100407360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class JucLockStackDriver extends BenchmarkDriver { private int pushThreadCount = 1; private int popThreadCount = 1; private int capacity; private PushThread[] pushThreads; private PopThread[] popThreads; private Stack stack; @Override public void setUp() { System.out.printf("Multiverse > Pop threadcount %s\n", pushThreadCount); System.out.printf("Multiverse > Push threadcount %s\n", popThreadCount); if (capacity == Integer.MAX_VALUE) { System.out.printf("Multiverse > Capacity unbound\n"); } else { System.out.printf("Multiverse > Capacity %s\n", capacity); } stack = new Stack(); pushThreads = new PushThread[pushThreadCount]; for (int k = 0; k < pushThreadCount; k++) { pushThreads[k] = new PushThread(k); } popThreads = new PopThread[popThreadCount]; for (int k = 0; k < popThreadCount; k++) { popThreads[k] = new PopThread(k); } } @Override public void run(TestCaseResult testCaseResult) { startAll(pushThreads); startAll(popThreads); joinAll(pushThreads); joinAll(popThreads); } @Override public void processResults(TestCaseResult result) { long pushCount = 0; long totalDurationMs = 0; for (PushThread t : pushThreads) { pushCount += t.count; totalDurationMs += t.getDurationMs(); } long popCount = 0; for (PopThread t : popThreads) { popCount += t.count; totalDurationMs += t.getDurationMs(); } int threadCount = pushThreadCount + popThreadCount; long count = pushCount + popCount; System.out.printf("Multiverse > Total number of transactions %s\n", count); double transactionsPerSecond = (count * 1000.0d) / totalDurationMs; System.out.printf("Multiverse > Performance %s transactions/second with %s threads\n", format(transactionsPerSecond), threadCount); result.put("transactionsPerSecond", transactionsPerSecond); } public class PushThread extends TestThread { private long count; public PushThread(int id) { super("PushThread-" + id); } @Override public void doRun() throws Exception { while (!shutdown) { stack.push("item"); count++; } for (int k = 0; k < popThreadCount; k++) { stack.push("end"); } } } public class PopThread extends TestThread { private long count; public PopThread(int id) { super("PopThread-" + id); } @Override public void doRun() throws Exception { boolean end = false; while (!end) { end = stack.pop().equals("end"); count++; } } } class Stack { final Lock lock = new ReentrantLock(); final Condition isNotEmptyCondition = lock.newCondition(); final Condition isNotFullCondition = lock.newCondition(); Node head; int size; public String pop() { lock.lock(); try { while (head == null) { isNotEmptyCondition.awaitUninterruptibly(); } if (capacity != Integer.MAX_VALUE) { size--; } isNotFullCondition.signalAll(); Node node = head; head = node.next; return node.value; } finally { lock.unlock(); } } public void push(String value) { lock.lock(); try { if (capacity != Integer.MAX_VALUE) { while (size == capacity) { isNotFullCondition.awaitUninterruptibly(); } } size++; head = new Node(head, value); isNotEmptyCondition.signalAll(); } finally { lock.unlock(); } } } static class Node { final Node next; final String value; Node(Node next, String value) { this.next = next; this.value = value; } } } Latch.java000077500000000000000000000021561174000617100363050ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; /** * A once reusable blocking structure. Other threads can wait for it while it is still closed, and once it * opens all waiting threads can continue. * * @author Peter Veentjer */ public final class Latch { private volatile boolean isOpen = false; public Latch() { this(false); } public Latch(boolean open) { isOpen = open; } public boolean isOpen() { return isOpen; } public void open() { if (isOpen) { return; } synchronized (this) { isOpen = true; notifyAll(); } } public void await() { if (isOpen) { return; } synchronized (this) { while (!isOpen) { try { wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } @Override public String toString() { return "Latch{" + "isOpen=" + isOpen + '}'; } } LeanFixedLengthGammaBenchmark.java000066400000000000000000000060111174000617100430200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; public class LeanFixedLengthGammaBenchmark implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void testRead1() { final long txCount = 1000 * 1000 * 1000; GammaTxnRef ref1 = new GammaTxnRef(stm); LeanFixedLengthGammaTxn tx = new LeanFixedLengthGammaTxn(stm); long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { ref1.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); System.out.println(ref1.toDebugString()); } @Test public void testRead2() { final long txCount = 1000 * 1000 * 1000; GammaTxnRef ref1 = new GammaTxnRef(stm); GammaTxnRef ref2 = new GammaTxnRef(stm); LeanFixedLengthGammaTxn tx = new LeanFixedLengthGammaTxn(stm); long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { ref1.openForRead(tx, LOCKMODE_NONE); ref2.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); System.out.println(ref1.toDebugString()); } @Test public void testRead3() { final long txCount = 1000 * 1000 * 1000; GammaTxnRef ref1 = new GammaTxnRef(stm); GammaTxnRef ref2 = new GammaTxnRef(stm); GammaTxnRef ref3 = new GammaTxnRef(stm); LeanFixedLengthGammaTxn tx = new LeanFixedLengthGammaTxn(stm); long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { ref1.openForRead(tx, LOCKMODE_NONE); ref2.openForRead(tx, LOCKMODE_NONE); ref3.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); System.out.println(ref1.toDebugString()); } } LeanMonoGammaBenchmark.java000066400000000000000000000037471174000617100415440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; public class LeanMonoGammaBenchmark implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void testRead() { final long txCount = 5L * 1000 * 1000 * 1000; final GammaTxnRef ref1 = new GammaTxnRef(stm); final LeanMonoGammaTxn tx = new LeanMonoGammaTxn(stm); final long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { ref1.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); System.out.println(ref1.toDebugString()); } @Test public void testWrite() { final long txCount = 1L * 1000 * 1000 * 1000; final GammaTxnRef ref1 = new GammaTxnRef(stm); final LeanMonoGammaTxn tx = new LeanMonoGammaTxn(stm); final long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { ref1.openForWrite(tx, LOCKMODE_NONE).ref_value = "foo"; tx.commit(); tx.hardReset(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); System.out.println(ref1.toDebugString()); } } LeanMonoReadWithTransactionDriver.java000066400000000000000000000044311174000617100437670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxnFactory; import static org.junit.Assert.assertEquals; public class LeanMonoReadWithTransactionDriver implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public static void main(String[] srgs) throws Throwable { LeanMonoReadWithTransactionDriver driver = new LeanMonoReadWithTransactionDriver(); driver.setUp(); try { driver.test(); } catch (Throwable e) { e.printStackTrace(); throw e; } } @Test public void test() { final long txCount = 1000 * 1000 * 1000; final GammaTxnRef ref = new GammaTxnRef(stm, null); long initialVersion = ref.getVersion(); final LeanGammaTxnExecutor executor = new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(stm)); final TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { Object x = ref.openForRead((LeanMonoGammaTxn) tx, LOCKMODE_NONE).ref_value; } }; System.out.println("Starting"); long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { executor.execute(callable); } long durationMs = System.currentTimeMillis() - startMs; System.out.println("finished"); String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Duration %s ms\n", durationMs); System.out.printf("Performance is %s transactions/second/thread\n", s); //assertEquals(txCount, ref.long_value); assertEquals(initialVersion, ref.version); } } LeanMonoUpdateWithTransactionDriver.java000066400000000000000000000046361174000617100443450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxnFactory; import static org.benchy.BenchyUtils.operationsPerSecondPerThreadAsString; import static org.junit.Assert.assertEquals; import static org.multiverse.stms.gamma.GammaTestUtils.assertGlobalConflictCount; public class LeanMonoUpdateWithTransactionDriver implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public static void main(String[] args) { LeanMonoUpdateWithTransactionDriver driver = new LeanMonoUpdateWithTransactionDriver(); driver.setUp(); driver.test(); } @Test public void test() { final long txCount = 1000 * 1000 * 1000; final GammaTxnRef ref = new GammaTxnRef(stm, null); long initialVersion = ref.getVersion(); final LeanGammaTxnExecutor executor = new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(stm)); final TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.openForWrite((LeanMonoGammaTxn) tx, LOCKMODE_NONE).ref_value = "foo"; } }; System.out.println("Starting"); long startMs = System.currentTimeMillis(); long globalConflictCount = stm.getGlobalConflictCounter().count(); for (long k = 0; k < txCount; k++) { executor.execute(callable); } long durationMs = System.currentTimeMillis() - startMs; System.out.println("finished"); String s = operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Duration %s ms\n", durationMs); System.out.printf("Performance is %s transactions/second/thread\n", s); //assertEquals(txCount, ref.long_value); assertEquals(txCount + initialVersion, ref.version); assertGlobalConflictCount(stm, globalConflictCount); } } MonoReadDriver.java000066400000000000000000000065621174000617100401340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class MonoReadDriver extends BenchmarkDriver implements GammaConstants { private GammaStm stm; private ReadThread[] threads; private int threadCount; private long transactionsPerThread; private int lockMode = LOCKMODE_NONE; @Override public void setUp() { System.out.printf("Multiverse > Thread count is %s\n", threadCount); System.out.printf("Multiverse > Transactions/thread is %s\n", transactionsPerThread); stm = new GammaStm(); threads = new ReadThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new ReadThread(k, transactionsPerThread); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (ReadThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); double transactionsPerSecond = BenchmarkUtils.transactionsPerSecond(transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second/thread\n", format(transactionsPerSecondPerThread)); System.out.printf("Multiverse > Performance %s transactions/second\n", format(transactionsPerSecond)); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); testCaseResult.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); } class ReadThread extends TestThread { private final long transactionCount; private long durationMs; public ReadThread(int id, long transactionCount) { super("ReadThread-" + id); this.transactionCount = transactionCount; } public void doRun() { GammaTxnLong ref = new GammaTxnLong(stm); FatMonoGammaTxn tx = new FatMonoGammaTxn( new GammaTxnConfig(stm) .setReadLockMode(LockMode.Exclusive) .setDirtyCheckEnabled(false)); long startMs = System.currentTimeMillis(); final long _transactionCount = transactionCount; for (long k = 0; k < _transactionCount; k++) { ref.openForRead(tx, lockMode); tx.commit(); tx.hardReset(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse > %s is finished in %s ms\n", getName(), durationMs); } } } MonoUpdateDriver.java000066400000000000000000000041411174000617100404720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import static org.junit.Assert.assertEquals; public class MonoUpdateDriver implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public static void main(String[] srgs) { MonoUpdateDriver driver = new MonoUpdateDriver(); driver.setUp(); driver.testNoLocking(); } @Test public void testNoLocking() { test(LockMode.None); } @Test public void testReadLock() { test(LockMode.Read); } @Test public void testWriteLock() { test(LockMode.Write); } @Test public void testExclusiveLock() { test(LockMode.Exclusive); } public void test(LockMode writeLockMode) { final long txCount = 1000 * 1000 * 1000; final FatMonoGammaTxn tx = new FatMonoGammaTxn( new GammaTxnConfig(stm) .setDirtyCheckEnabled(false) .setWriteLockMode(writeLockMode)); final GammaTxnLong ref = new GammaTxnLong(stm, 0); long initialVersion = ref.getVersion(); long startMs = System.currentTimeMillis(); for (long k = 0; k < txCount; k++) { ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); tx.hardReset(); } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); assertEquals(txCount, ref.long_value); assertEquals(txCount + initialVersion, ref.version); } } MultipleReadDriver.java000066400000000000000000000001231174000617100410020ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; public class MultipleReadDriver { } MultipleUpdateDriver.java000077500000000000000000000100201174000617100413510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.stms.gamma.GammaTestUtils.makeReadBiased; /** * @author Peter Veentjer */ public class MultipleUpdateDriver extends BenchmarkDriver implements GammaConstants { private GammaStm stm; private long transactionsPerThread; private int refCount; private int threadCount; private WriteThread[] threads; @Override public void setUp() { System.out.printf("Multiverse > Multiple update transaction benchmark\n"); System.out.printf("Multiverse > Running with %s ref per transaction\n", refCount); System.out.printf("Multiverse > %s Transactions per thread\n", format(transactionsPerThread)); stm = new GammaStm(); threads = new WriteThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new WriteThread(k, refCount); } } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (WriteThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); double transactionsPerSecond = BenchmarkUtils.transactionsPerSecond( transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second with %s threads\n", format(transactionsPerSecondPerThread), threadCount); System.out.printf("Multiverse > Performance %s transactions/second with %s threads\n", format(transactionsPerSecond), threadCount); testCaseResult.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); } @Override public void run(TestCaseResult testCaseResult) { System.out.printf("Multiverse > Running with %s threads\n", threadCount); startAll(threads); joinAll(threads); } class WriteThread extends TestThread { private final int refCount; private long durationMs; public WriteThread(int id, int refCount) { super("WriteThread-" + id); setPriority(Thread.MAX_PRIORITY); this.refCount = refCount; } public void doRun() { GammaTxnLong[] refs = new GammaTxnLong[refCount]; for (int k = 0; k < refCount; k++) { refs[k] = makeReadBiased(new GammaTxnLong(stm)); } GammaTxnConfig config = new GammaTxnConfig(stm, refs.length); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); long startMs = System.currentTimeMillis(); final long t = transactionsPerThread; for (int iteration = 0; iteration < t; iteration++) { for (int k = 0; k < refs.length; k++) { refs[k].openForWrite(tx, LOCKMODE_NONE).long_value++; } tx.commit(); tx.hardReset(); if (iteration % 100000000 == 0 && iteration > 0) { System.out.printf("Multiverse > %s is at %s\n", getName(), iteration); } } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse > %s is finished in %s ms\n", getName(), durationMs); } } } RawUpdateDriver.java000066400000000000000000000052401174000617100403140ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaObjectPool; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; public class RawUpdateDriver implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public static void main(String[] srgs) { RawUpdateDriver driver = new RawUpdateDriver(); driver.setUp(); driver.testNoLocking(); } @Test public void testNoLocking() { test(LockMode.None); } @Test public void testReadLock() { test(LockMode.Read); } @Test public void testWriteLock() { test(LockMode.Write); } @Test public void testWriteCommit() { test(LockMode.Exclusive); } public void test(LockMode writeLockMode) { final long txCount = 1000 * 1000 * 1000; final FatMonoGammaTxn tx = new FatMonoGammaTxn( new GammaTxnConfig(stm).setWriteLockMode(writeLockMode)); final GammaObjectPool pool = tx.pool; final GammaTxnLong ref = new GammaTxnLong(stm, 0); final int lockMode = writeLockMode.asInt(); final Tranlocal tranlocal = new Tranlocal(); final long initialVersion = ref.getVersion(); final long startMs = System.currentTimeMillis(); if (lockMode == LOCKMODE_EXCLUSIVE) { for (long k = 0; k < txCount; k++) { ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); ref.orec = 0; //ref.releaseAfterUpdate(tranlocal, pool); } } else { for (long k = 0; k < txCount; k++) { ref.load(tx,tranlocal, lockMode, 1, false); ref.tryLockAndCheckConflict(tx, tranlocal, 1, LOCKMODE_EXCLUSIVE); //ref.releaseAfterUpdate(tranlocal, pool); ref.orec = 0; } } long durationMs = System.currentTimeMillis() - startMs; String s = BenchyUtils.operationsPerSecondPerThreadAsString(txCount, durationMs, 1); System.out.printf("Performance is %s transactions/second/thread\n", s); //assertEquals(txCount, ref.long_value); //assertEquals(txCount + initialVersion, ref.version); } } SimpleStackDriver.java000066400000000000000000000176041174000617100406460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnBooleanCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnInteger; import org.multiverse.api.references.TxnRef; import org.multiverse.stms.gamma.GammaStm; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class SimpleStackDriver extends BenchmarkDriver { private int pushThreadCount = 1; private int popThreadCount = 1; private int capacity = Integer.MAX_VALUE; private boolean poolCallables = false; private LockMode readLockMode = LockMode.None; private LockMode writeLockMode = LockMode.None; private boolean dirtyCheck = false; private GammaStm stm; private PopThread[] popThreads; private PushThread[] pushThreads; private Stack stack; @Override public void setUp() { System.out.printf("Multiverse > Pop threadcount %s\n", pushThreadCount); System.out.printf("Multiverse > Push threadcount %s\n", popThreadCount); if (capacity == Integer.MAX_VALUE) { System.out.printf("Multiverse > Capacity unbound\n"); } else { System.out.printf("Multiverse > Capacity %s\n", capacity); } System.out.printf("Multiverse > Pool Callables %s\n", poolCallables); System.out.printf("Multiverse > LockLevel %s\n", readLockMode); System.out.printf("Multiverse > DirtyCheck %s\n", dirtyCheck); stm = new GammaStm(); stack = new Stack(); pushThreads = new PushThread[pushThreadCount]; for (int k = 0; k < pushThreadCount; k++) { pushThreads[k] = new PushThread(k, stack); } popThreads = new PopThread[popThreadCount]; for (int k = 0; k < popThreadCount; k++) { popThreads[k] = new PopThread(k, stack); } } @Override public void run(TestCaseResult testCaseResult) { startAll(pushThreads); startAll(popThreads); joinAll(pushThreads); joinAll(popThreads); } @Override public void processResults(TestCaseResult testCaseResult) { long pushCount = 0; long totalDurationMs = 0; for (PushThread t : pushThreads) { pushCount += t.count; totalDurationMs += t.getDurationMs(); } long popCount = 0; for (PopThread t : popThreads) { popCount += t.count; totalDurationMs += t.getDurationMs(); } int threadCount = pushThreadCount + popThreadCount; long count = pushCount + popCount; System.out.printf("Multiverse > Total number of transactions %s\n", count); double transactionsPerSecond = (count * 1000.0d) / totalDurationMs; System.out.printf("Multiverse > Performance %s transactions/second with %s threads\n", format(transactionsPerSecond), threadCount); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); } class PushThread extends TestThread { private final Stack stack; private long count; private final TxnExecutor pushBlock = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(dirtyCheck) .setReadLockMode(readLockMode) .setWriteLockMode(writeLockMode) .newTxnExecutor(); public PushThread(int id, Stack stack) { super("PushThread-" + id); this.stack = stack; } @Override public void doRun() throws Exception { if (poolCallables) { runWithPooledCallables(); } else { runWithoutPooledCallables(); } } private void runWithoutPooledCallables() { while (!shutdown) { pushBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push(tx, "item"); } }); count++; } for (int k = 0; k < popThreadCount; k++) { pushBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push(tx, "end"); } }); } } private void runWithPooledCallables() { final PushCallable pushCallable = new PushCallable(); while (!shutdown) { pushCallable.item = "item"; pushBlock.execute(pushCallable); count++; } for (int k = 0; k < popThreadCount; k++) { pushCallable.item = "end"; pushBlock.execute(pushCallable); } } class PushCallable implements TxnVoidCallable { String item; @Override public void call(Txn tx) throws Exception { stack.push(tx, item); } } } class PopThread extends TestThread { private final Stack stack; private long count; private final TxnExecutor popBlock = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(dirtyCheck) .setReadLockMode(readLockMode) .setWriteLockMode(writeLockMode) .newTxnExecutor(); public PopThread(int id, Stack stack) { super("PopThread-" + id); this.stack = stack; } @Override public void doRun() throws Exception { if (poolCallables) { runWithoutPooledCallable(); } else { runWithPooledCallable(); } } private void runWithPooledCallable() { boolean end = false; while (!end) { end = popBlock.execute(new TxnBooleanCallable() { @Override public boolean call(Txn tx) throws Exception { return !stack.pop(tx).equals("end"); } }); count++; } } private void runWithoutPooledCallable() { PopCallable popCallable = new PopCallable(); boolean end = false; while (!end) { end = popBlock.execute(popCallable); count++; } } class PopCallable implements TxnBooleanCallable { @Override public boolean call(Txn tx) throws Exception { return !stack.pop(tx).endsWith("end"); } } } class Stack { private final TxnRef> head = stm.getDefaultRefFactory().newTxnRef(null); private final TxnInteger size = stm.getTxRefFactoryBuilder().build().newTxnInteger(0); public void push(Txn tx, final E item) { if (capacity != Integer.MAX_VALUE) { if (size.get(tx) == capacity) { tx.retry(); } size.increment(tx); } head.set(tx, new StackNode(item, head.get(tx))); } public E pop(Txn tx) { E value = head.awaitNotNullAndGet(tx).value; if (capacity != Integer.MAX_VALUE) { size.decrement(tx); } return value; } } static class StackNode { final E value; final StackNode next; StackNode(E value, StackNode next) { this.value = value; this.next = next; } } } UncontendedLeanUpdateBenchmark.java000066400000000000000000000113701174000617100432710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchyUtils; import org.multiverse.TestThread; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import java.util.Arrays; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.stms.gamma.benchmarks.BenchmarkUtils.*; public class UncontendedLeanUpdateBenchmark implements GammaConstants { private GammaStm stm; public static void main(String[] args) { UncontendedLeanUpdateBenchmark test = new UncontendedLeanUpdateBenchmark(); test.start(Long.parseLong(args[0])); } public void start(long transactionCount) { int[] processors = generateProcessorRange(); System.out.printf("Multiverse> Uncontended update lean-transaction benchmark\n"); System.out.printf("Multiverse> 1 GammaTxnRef per transaction\n"); System.out.printf("Multiverse> %s Transactions per thread\n", format(transactionCount)); System.out.printf("Multiverse> Running with the following processor range %s\n", Arrays.toString(processors)); Result[] result = new Result[processors.length]; System.out.println("Multiverse> Starting warmup run"); test(1, transactionCount); System.out.println("Multiverse> Finished warmup run"); long startNs = System.nanoTime(); for (int k = 0; k < processors.length; k++) { int processorCount = processors[k]; double performance = test(processorCount, transactionCount); result[k] = new Result(processorCount, performance); } long durationNs = System.nanoTime() - startNs; System.out.printf("Multiverse> Benchmark took %s seconds\n", TimeUnit.NANOSECONDS.toSeconds(durationNs)); toGnuplot(result); } private double test(int threadCount, long transactionsPerThread) { System.out.printf("Multiverse> ----------------------------------------------\n"); System.out.printf("Multiverse> Running with %s thread(s)\n", threadCount); stm = new GammaStm(); UpdateThread[] threads = new UpdateThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k, transactionsPerThread); } startAll(threads); joinAll(threads); long totalDurationMs = 0; for (UpdateThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecond = transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse> Threadcount %s\n", threadCount); System.out.printf("Multiverse> Performance %s transactions/second/thread\n", BenchyUtils.format(transactionsPerSecond)); System.out.printf("Multiverse> Performance %s transactions/second\n", transactionsPerSecondAsString(transactionsPerThread, totalDurationMs, threadCount)); return transactionsPerSecond; } class UpdateThread extends TestThread { private final long transactionCount; private long durationMs; public UpdateThread(int id, long transactionCount) { super("UpdateThread-" + id); setPriority(Thread.MAX_PRIORITY); this.transactionCount = transactionCount; } public void doRun() { GammaTxnLong ref = new GammaTxnLong(stm); //FatArrayTreeGammaTxn tx = new FatArrayTreeGammaTxn(stm); //FatArrayGammaTxn tx = new FatArrayGammaTxn(stm,1); FatMonoGammaTxn tx = new FatMonoGammaTxn( new GammaTxnConfig(stm) .setReadLockMode(LockMode.Exclusive) .setDirtyCheckEnabled(false)); long startMs = System.currentTimeMillis(); for (long k = 0; k < transactionCount; k++) { ref.openForWrite(tx, LOCKMODE_EXCLUSIVE).long_value++; tx.commit(); tx.hardReset(); //if (k % 100000000 == 0 && k > 0) { // System.out.printf("%s is at %s\n", getName(), k); //} } assertEquals(transactionCount, ref.atomicGet()); durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse> %s is finished in %s ms\n", getName(), durationMs); } } } UncontendedMonoUpdateDriver.java000066400000000000000000000067231174000617100426710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import static org.benchy.BenchyUtils.format; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; public class UncontendedMonoUpdateDriver extends BenchmarkDriver { private GammaStm stm; private UpdateThread[] threads; private int threadCount = 1; private int transactionsPerThread = 100 * 1000 * 1000; private boolean dirtyCheck = false; private LockMode lockMode = LockMode.None; @Override public void setUp() { System.out.printf("Multiverse > Thread count %s \n", threadCount); System.out.printf("Multiverse > Transactions per thread %s \n", transactionsPerThread); System.out.printf("Multiverse > Dirtycheck %s \n", dirtyCheck); System.out.printf("Multiverse > Locklevel %s \n", lockMode); stm = new GammaStm(); threads = new UpdateThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult testCaseResult) { long totalDurationMs = 0; for (UpdateThread t : threads) { totalDurationMs += t.durationMs; } double transactionsPerSecondPerThread = BenchmarkUtils.transactionsPerSecondPerThread( transactionsPerThread, totalDurationMs, threadCount); double transactionsPerSecond = BenchmarkUtils.transactionsPerSecond(transactionsPerThread, totalDurationMs, threadCount); System.out.printf("Multiverse > Performance %s transactions/second/thread\n", format(transactionsPerSecondPerThread)); System.out.printf("Multiverse > Performance %s transactions/second\n", format(transactionsPerSecond)); testCaseResult.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); testCaseResult.put("transactionsPerSecond", transactionsPerSecond); } class UpdateThread extends TestThread { private long durationMs; public UpdateThread(int id) { super("UpdateThread-" + id); } public void doRun() { final GammaTxnLong ref = new GammaTxnLong(stm); FatMonoGammaTxn tx = new FatMonoGammaTxn( new GammaTxnConfig(stm) .setReadLockMode(lockMode) .setDirtyCheckEnabled(dirtyCheck)); long startMs = System.currentTimeMillis(); final long _transactionCount = transactionsPerThread; for (long k = 0; k < _transactionCount; k++) { ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); tx.hardReset(); } assertEquals(transactionsPerThread, ref.atomicGet()); durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse > %s is finished in %s ms\n", getName(), durationMs); } } } UncontendedMultipleReadBenchmark.java000077500000000000000000000353301174000617100436430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarkspackage org.multiverse.stms.gamma.benchmarks; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import java.util.Arrays; import java.util.concurrent.TimeUnit; import static org.benchy.BenchyUtils.format; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.stms.gamma.GammaTestUtils.makeReadBiased; /** * @author Peter Veentjer */ public class UncontendedMultipleReadBenchmark implements GammaConstants { private GammaStm stm; private final long transactionCount = 100 * 1000 * 1000; public static void main(String[] args) { //should be a power of two. int refCount = Integer.parseInt(args[0]); UncontendedMultipleReadBenchmark test = new UncontendedMultipleReadBenchmark(); test.start(refCount); } public void start(int refCount) { int[] processors = BenchmarkUtils.generateProcessorRange(); System.out.printf("Multiverse> Uncontended multiple read transaction benchmark\n"); System.out.printf("Multiverse> Running with the following processor range %s\n", Arrays.toString(processors)); System.out.printf("Multiverse> Running with %s transactionalobjects per transaction\n", refCount); System.out.printf("Multiverse> %s Transactions per thread\n", format(transactionCount)); Result[] result = new Result[processors.length]; System.out.printf("Multiverse> Starting warmup run\n"); test(1, 1); System.out.printf("Multiverse> Finished warmup run\n"); long startNs = System.nanoTime(); for (int k = 0; k < processors.length; k++) { int processorCount = processors[k]; double performance = test(processorCount, refCount); result[k] = new Result(processorCount, performance); } long durationNs = System.nanoTime() - startNs; System.out.printf("Benchmark took %s seconds\n", TimeUnit.NANOSECONDS.toSeconds(durationNs)); BenchmarkUtils.toGnuplot(result); } private double test(int threadCount, int refCount) { System.out.printf("Multiverse> Running with %s processors\n", threadCount); stm = new GammaStm(); ReadThread[] threads = new ReadThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new ReadThread(k, refCount); } startAll(threads); joinAll(threads); long totalDurationMs = 0; for (ReadThread t : threads) { totalDurationMs += t.durationMs; } double readsPerSecond = BenchmarkUtils.transactionsPerSecondPerThread( transactionCount * refCount, totalDurationMs, threadCount); System.out.printf("Multiverse> Performance %s reads/second with %s threads\n", format(readsPerSecond), threadCount); return readsPerSecond; } class ReadThread extends TestThread { private final int refCount; private long durationMs; public ReadThread(int id, int refCount) { super("ReadThread-" + id); setPriority(Thread.MAX_PRIORITY); this.refCount = refCount; } public void doRun() { switch (refCount) { case 1: run1(); break; case 2: run2(); break; case 4: run4(); break; case 8: run8(); break; case 16: run16(); break; case 32: run32(); break; default: throw new IllegalStateException(); } } public void run1() { GammaTxnLong ref1 = newReadBiasedLongRef(stm); GammaTxnConfig config = new GammaTxnConfig(stm, 1) .setReadonly(true); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); long startMs = System.currentTimeMillis(); for (long iteration = 0; iteration < transactionCount; iteration++) { ref1.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse> %s is finished in %s ms\n", getName(), durationMs); } public void run2() { GammaTxnLong ref1 = newReadBiasedLongRef(stm); GammaTxnLong ref2 = newReadBiasedLongRef(stm); GammaTxnConfig config = new GammaTxnConfig(stm, 2) .setReadonly(true); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); long startMs = System.currentTimeMillis(); for (long iteration = 0; iteration < transactionCount; iteration++) { ref1.openForRead(tx, LOCKMODE_NONE); ref2.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse> %s is finished in %s ms\n", getName(), durationMs); } public void run4() { GammaTxnLong ref1 = newReadBiasedLongRef(stm); GammaTxnLong ref2 = newReadBiasedLongRef(stm); GammaTxnLong ref3 = newReadBiasedLongRef(stm); GammaTxnLong ref4 = newReadBiasedLongRef(stm); GammaTxnConfig config = new GammaTxnConfig(stm, 4) .setReadonly(true); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); long startMs = System.currentTimeMillis(); for (long iteration = 0; iteration < transactionCount; iteration++) { ref1.openForRead(tx, LOCKMODE_NONE); ref2.openForRead(tx, LOCKMODE_NONE); ref3.openForRead(tx, LOCKMODE_NONE); ref4.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse> %s is finished in %s ms\n", getName(), durationMs); } public void run8() { GammaTxnLong ref1 = newReadBiasedLongRef(stm); GammaTxnLong ref2 = newReadBiasedLongRef(stm); GammaTxnLong ref3 = newReadBiasedLongRef(stm); GammaTxnLong ref4 = newReadBiasedLongRef(stm); GammaTxnLong ref5 = newReadBiasedLongRef(stm); GammaTxnLong ref6 = newReadBiasedLongRef(stm); GammaTxnLong ref7 = newReadBiasedLongRef(stm); GammaTxnLong ref8 = newReadBiasedLongRef(stm); GammaTxnConfig config = new GammaTxnConfig(stm, 8) .setReadonly(true); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); long startMs = System.currentTimeMillis(); for (long iteration = 0; iteration < transactionCount; iteration++) { ref1.openForRead(tx, LOCKMODE_NONE); ref2.openForRead(tx, LOCKMODE_NONE); ref3.openForRead(tx, LOCKMODE_NONE); ref4.openForRead(tx, LOCKMODE_NONE); ref5.openForRead(tx, LOCKMODE_NONE); ref6.openForRead(tx, LOCKMODE_NONE); ref7.openForRead(tx, LOCKMODE_NONE); ref8.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse> %s is finished in %s ms\n", getName(), durationMs); } public void run16() { GammaTxnLong ref1 = newReadBiasedLongRef(stm); GammaTxnLong ref2 = newReadBiasedLongRef(stm); GammaTxnLong ref3 = newReadBiasedLongRef(stm); GammaTxnLong ref4 = newReadBiasedLongRef(stm); GammaTxnLong ref5 = newReadBiasedLongRef(stm); GammaTxnLong ref6 = newReadBiasedLongRef(stm); GammaTxnLong ref7 = newReadBiasedLongRef(stm); GammaTxnLong ref8 = newReadBiasedLongRef(stm); GammaTxnLong ref9 = newReadBiasedLongRef(stm); GammaTxnLong ref10 = newReadBiasedLongRef(stm); GammaTxnLong ref11 = newReadBiasedLongRef(stm); GammaTxnLong ref12 = newReadBiasedLongRef(stm); GammaTxnLong ref13 = newReadBiasedLongRef(stm); GammaTxnLong ref14 = newReadBiasedLongRef(stm); GammaTxnLong ref15 = newReadBiasedLongRef(stm); GammaTxnLong ref16 = newReadBiasedLongRef(stm); GammaTxnConfig config = new GammaTxnConfig(stm, 16) .setReadonly(true); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); long startMs = System.currentTimeMillis(); for (long iteration = 0; iteration < transactionCount; iteration++) { ref1.openForRead(tx, LOCKMODE_NONE); ref2.openForRead(tx, LOCKMODE_NONE); ref3.openForRead(tx, LOCKMODE_NONE); ref4.openForRead(tx, LOCKMODE_NONE); ref5.openForRead(tx, LOCKMODE_NONE); ref6.openForRead(tx, LOCKMODE_NONE); ref7.openForRead(tx, LOCKMODE_NONE); ref8.openForRead(tx, LOCKMODE_NONE); ref9.openForRead(tx, LOCKMODE_NONE); ref10.openForRead(tx, LOCKMODE_NONE); ref11.openForRead(tx, LOCKMODE_NONE); ref12.openForRead(tx, LOCKMODE_NONE); ref13.openForRead(tx, LOCKMODE_NONE); ref14.openForRead(tx, LOCKMODE_NONE); ref15.openForRead(tx, LOCKMODE_NONE); ref15.openForRead(tx, LOCKMODE_NONE); ref16.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse> %s is finished in %s ms\n", getName(), durationMs); } public void run32() { GammaTxnLong ref1 = newReadBiasedLongRef(stm); GammaTxnLong ref2 = newReadBiasedLongRef(stm); GammaTxnLong ref3 = newReadBiasedLongRef(stm); GammaTxnLong ref4 = newReadBiasedLongRef(stm); GammaTxnLong ref5 = newReadBiasedLongRef(stm); GammaTxnLong ref6 = newReadBiasedLongRef(stm); GammaTxnLong ref7 = newReadBiasedLongRef(stm); GammaTxnLong ref8 = newReadBiasedLongRef(stm); GammaTxnLong ref9 = newReadBiasedLongRef(stm); GammaTxnLong ref10 = newReadBiasedLongRef(stm); GammaTxnLong ref11 = newReadBiasedLongRef(stm); GammaTxnLong ref12 = newReadBiasedLongRef(stm); GammaTxnLong ref13 = newReadBiasedLongRef(stm); GammaTxnLong ref14 = newReadBiasedLongRef(stm); GammaTxnLong ref15 = newReadBiasedLongRef(stm); GammaTxnLong ref16 = newReadBiasedLongRef(stm); GammaTxnLong ref17 = newReadBiasedLongRef(stm); GammaTxnLong ref18 = newReadBiasedLongRef(stm); GammaTxnLong ref19 = newReadBiasedLongRef(stm); GammaTxnLong ref20 = newReadBiasedLongRef(stm); GammaTxnLong ref21 = newReadBiasedLongRef(stm); GammaTxnLong ref22 = newReadBiasedLongRef(stm); GammaTxnLong ref23 = newReadBiasedLongRef(stm); GammaTxnLong ref24 = newReadBiasedLongRef(stm); GammaTxnLong ref25 = newReadBiasedLongRef(stm); GammaTxnLong ref26 = newReadBiasedLongRef(stm); GammaTxnLong ref27 = newReadBiasedLongRef(stm); GammaTxnLong ref28 = newReadBiasedLongRef(stm); GammaTxnLong ref29 = newReadBiasedLongRef(stm); GammaTxnLong ref30 = newReadBiasedLongRef(stm); GammaTxnLong ref31 = newReadBiasedLongRef(stm); GammaTxnLong ref32 = newReadBiasedLongRef(stm); GammaTxnConfig config = new GammaTxnConfig(stm, 32) .setReadonly(true); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); long startMs = System.currentTimeMillis(); for (long iteration = 0; iteration < transactionCount; iteration++) { ref1.openForRead(tx, LOCKMODE_NONE); ref2.openForRead(tx, LOCKMODE_NONE); ref3.openForRead(tx, LOCKMODE_NONE); ref4.openForRead(tx, LOCKMODE_NONE); ref5.openForRead(tx, LOCKMODE_NONE); ref6.openForRead(tx, LOCKMODE_NONE); ref7.openForRead(tx, LOCKMODE_NONE); ref8.openForRead(tx, LOCKMODE_NONE); ref9.openForRead(tx, LOCKMODE_NONE); ref10.openForRead(tx, LOCKMODE_NONE); ref11.openForRead(tx, LOCKMODE_NONE); ref12.openForRead(tx, LOCKMODE_NONE); ref13.openForRead(tx, LOCKMODE_NONE); ref14.openForRead(tx, LOCKMODE_NONE); ref15.openForRead(tx, LOCKMODE_NONE); ref15.openForRead(tx, LOCKMODE_NONE); ref16.openForRead(tx, LOCKMODE_NONE); ref17.openForRead(tx, LOCKMODE_NONE); ref18.openForRead(tx, LOCKMODE_NONE); ref19.openForRead(tx, LOCKMODE_NONE); ref20.openForRead(tx, LOCKMODE_NONE); ref21.openForRead(tx, LOCKMODE_NONE); ref22.openForRead(tx, LOCKMODE_NONE); ref23.openForRead(tx, LOCKMODE_NONE); ref24.openForRead(tx, LOCKMODE_NONE); ref25.openForRead(tx, LOCKMODE_NONE); ref26.openForRead(tx, LOCKMODE_NONE); ref27.openForRead(tx, LOCKMODE_NONE); ref28.openForRead(tx, LOCKMODE_NONE); ref29.openForRead(tx, LOCKMODE_NONE); ref30.openForRead(tx, LOCKMODE_NONE); ref31.openForRead(tx, LOCKMODE_NONE); ref32.openForRead(tx, LOCKMODE_NONE); tx.commit(); tx.hardReset(); } durationMs = System.currentTimeMillis() - startMs; System.out.printf("Multiverse> %s is finished in %s ms\n", getName(), durationMs); } } private GammaTxnLong newReadBiasedLongRef(GammaStm stm) { return makeReadBiased(new GammaTxnLong(stm)); } } 000077500000000000000000000000001174000617100353305ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarks/orecOrecCommitLockUpdateDriver.java000066400000000000000000000054261174000617100433730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarks/orecpackage org.multiverse.stms.gamma.benchmarks.orec; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GlobalConflictCounter; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.benchy.BenchyUtils.*; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; public class OrecCommitLockUpdateDriver extends BenchmarkDriver implements GammaConstants { private GammaTxnLong ref; private GlobalConflictCounter globalConflictCounter; private GammaStm stm; private int threadCount; private long operationCount = 1000 * 1000 * 1000; private UpdateThread[] threads; @Override public void setUp() { System.out.printf("Multiverse > Operation count is %s\n", operationCount); System.out.printf("Multiverse > Thread count is %s\n", threadCount); stm = new GammaStm(); ref = new GammaTxnLong(stm); globalConflictCounter = stm.getGlobalConflictCounter(); threads = new UpdateThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); } @Override public void processResults(TestCaseResult result) { long durationMs = result.getDurationMs(); double transactionsPerSecond = operationsPerSecond(operationCount, durationMs, threadCount); double transactionsPerSecondPerThread = operationsPerSecondPerThread(operationCount, durationMs, threadCount); result.put("transactionsPerSecond", transactionsPerSecond); result.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); System.out.printf("Performance : %s update-cycles/second\n", format(transactionsPerSecond)); System.out.printf("Performance : %s update-cycles/second/thread\n", format(transactionsPerSecondPerThread)); } class UpdateThread extends TestThread { public UpdateThread(int id) { super("id-" + id); } @Override public void doRun() throws Exception { final long _cycles = operationCount; final GammaTxnLong _orec = new GammaTxnLong(stm); for (long k = 0; k < _cycles; k++) { int arriveStatus = _orec.arriveAndLock(0, LOCKMODE_EXCLUSIVE); if ((arriveStatus & MASK_UNREGISTERED) != 0) { _orec.arriveAndLock(0, LOCKMODE_EXCLUSIVE); } _orec.departAfterUpdateAndUnlock(); } } } } OrecNormalNormalUpdateDriver.java000066400000000000000000000057261174000617100437360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarks/orecpackage org.multiverse.stms.gamma.benchmarks.orec; import org.benchy.BenchmarkDriver; import org.benchy.TestCaseResult; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GlobalConflictCounter; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.benchy.BenchyUtils.*; import static org.multiverse.TestUtils.*; public class OrecNormalNormalUpdateDriver extends BenchmarkDriver implements GammaConstants { private GammaTxnLong ref; private GlobalConflictCounter globalConflictCounter; private GammaStm stm; private int threadCount; private long operationCount = 1000 * 1000 * 1000; private UpdateThread[] threads; @Override public void setUp() { System.out.printf("Multiverse > Operation count is %s\n", operationCount); System.out.printf("Multiverse > Thread count is %s\n", threadCount); stm = new GammaStm(); ref = new GammaTxnLong(stm); globalConflictCounter = stm.getGlobalConflictCounter(); threads = new UpdateThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k); } } @Override public void run(TestCaseResult testCaseResult) { startAll(threads); joinAll(threads); assertEqualsDouble(0, globalConflictCounter.count()); } @Override public void processResults(TestCaseResult result) { long durationMs = result.getDurationMs(); double transactionsPerSecond = operationsPerSecond(operationCount, durationMs, threadCount); double transactionsPerSecondPerThread = operationsPerSecondPerThread(operationCount, durationMs, threadCount); result.put("transactionsPerSecond", transactionsPerSecond); result.put("transactionsPerSecondPerThread", transactionsPerSecondPerThread); System.out.printf("Performance : %s update-cycles/second\n", format(transactionsPerSecond)); System.out.printf("Performance : %s update-cycles/second/thread\n", format(transactionsPerSecondPerThread)); } class UpdateThread extends TestThread { public UpdateThread(int id) { super("id-" + id); } @Override public void doRun() throws Exception { final long _cycles = operationCount; final GammaTxnLong orec = new GammaTxnLong(stm); final GammaTxnLong _ref = ref; for (long k = 0; k < _cycles; k++) { int arriveStatus = orec.arrive(0); if ((arriveStatus & MASK_UNREGISTERED) == 0) { orec.lockAfterArrive(0, LOCKMODE_EXCLUSIVE); } else { orec.arriveAndLock(0, LOCKMODE_EXCLUSIVE); } orec.departAfterUpdateAndUnlock(); } System.out.printf("Orec : %s\n", orec.___toOrecString()); } } } OrecNormalReadsDriver.java000066400000000000000000000036151174000617100423740ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarks/orecpackage org.multiverse.stms.gamma.benchmarks.orec; import org.benchy.BenchmarkDriver; import org.benchy.BenchyUtils; import org.benchy.TestCaseResult; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GlobalConflictCounter; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; public class OrecNormalReadsDriver extends BenchmarkDriver implements GammaConstants { private GammaTxnLong ref; private GlobalConflictCounter globalConflictCounter; private GammaStm stm; private long operationCount = 1000 * 1000 * 1000; private GammaTxnLong orec; @Override public void setUp() { System.out.printf("Multiverse > Operation count is %s\n", operationCount); stm = new GammaStm(); ref = new GammaTxnLong(stm); globalConflictCounter = stm.getGlobalConflictCounter(); orec = new GammaTxnLong(stm); } @Override public void run(TestCaseResult testCaseResult) { final long _cycles = operationCount; final GammaTxnLong _orec = orec; for (long k = 0; k < _cycles; k++) { int arriveStatus = _orec.arrive(0); if ((arriveStatus & MASK_UNREGISTERED)==0) { _orec.departAfterReading(); } else { _orec.arriveAndLock(0, LOCKMODE_EXCLUSIVE); _orec.departAfterUpdateAndUnlock(); } } } @Override public void processResults(TestCaseResult result) { long durationMs = result.getDurationMs(); double transactionsPerSecond = BenchyUtils.operationsPerSecond(operationCount, durationMs, 1); result.put("transactionsPerSecond", transactionsPerSecond); System.out.printf("Performance : %s read-cycles/second\n", transactionsPerSecond); System.out.printf("Orec : %s\n", orec.___toOrecString()); } } OrecNormalUpdateDriver.java000066400000000000000000000034511174000617100425560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarks/orecpackage org.multiverse.stms.gamma.benchmarks.orec; import org.benchy.BenchmarkDriver; import org.benchy.BenchyUtils; import org.benchy.TestCaseResult; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GlobalConflictCounter; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; public class OrecNormalUpdateDriver extends BenchmarkDriver implements GammaConstants { private GammaTxnLong ref; private GlobalConflictCounter globalConflictCounter; private GammaStm stm; private long operationCount = 1000 * 1000 * 1000; private GammaTxnLong orec; @Override public void setUp() { System.out.printf("Multiverse > Operation count is %s\n", operationCount); stm = new GammaStm(); ref = new GammaTxnLong(stm); globalConflictCounter = stm.getGlobalConflictCounter(); orec = new GammaTxnLong(stm); } @Override public void run(TestCaseResult testCaseResult) { final long _cycles = operationCount; final GammaTxnLong _orec = orec; for (long k = 0; k < _cycles; k++) { _orec.arrive(1); _orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); _orec.departAfterUpdateAndUnlock(); } } @Override public void processResults(TestCaseResult result) { long durationMs = result.getDurationMs(); double transactionsPerSecond = BenchyUtils.operationsPerSecond(operationCount, durationMs, 1); result.put("transactionsPerSecond", transactionsPerSecond); System.out.printf("Performance : %s update-cycles/second\n", BenchyUtils.format(transactionsPerSecond)); System.out.printf("Orec : %s\n", orec.___toOrecString()); } } OrecReadBiasedReadDriver.java000066400000000000000000000034171174000617100427440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarks/orecpackage org.multiverse.stms.gamma.benchmarks.orec; import org.benchy.BenchmarkDriver; import org.benchy.BenchyUtils; import org.benchy.TestCaseResult; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GlobalConflictCounter; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; public class OrecReadBiasedReadDriver extends BenchmarkDriver implements GammaConstants { private GammaTxnLong ref; private GlobalConflictCounter globalConflictCounter; private GammaStm stm; private long operationCount = 1000 * 1000 * 1000; private GammaTxnLong orec; @Override public void setUp() { System.out.printf("Multiverse > Operation count is %s\n", operationCount); stm = new GammaStm(); ref = new GammaTxnLong(stm); globalConflictCounter = stm.getGlobalConflictCounter(); orec = new GammaTxnLong(stm); } @Override public void run(TestCaseResult testCaseResult) { final long _cycles = operationCount; final GammaTxnLong _orec = orec; for (long k = 0; k < _cycles; k++) { int arriveStatus = _orec.arrive(0); if ((arriveStatus & MASK_UNREGISTERED) == 0) { _orec.departAfterReading(); } } } @Override public void processResults(TestCaseResult result) { long durationMs = result.getDurationMs(); double transactionsPerSecond = BenchyUtils.operationsPerSecond(operationCount, durationMs, 1); result.put("transactionsPerSecond", transactionsPerSecond); System.out.printf("Performance : %s update-cycles/second\n", transactionsPerSecond); System.out.printf("Orec : %s\n", orec.___toOrecString()); } } OrecWriteLockUpdateDriver.java000066400000000000000000000034571174000617100432370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core-drivers/src/main/java/org/multiverse/stms/gamma/benchmarks/orecpackage org.multiverse.stms.gamma.benchmarks.orec; import org.benchy.BenchmarkDriver; import org.benchy.BenchyUtils; import org.benchy.TestCaseResult; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GlobalConflictCounter; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; public class OrecWriteLockUpdateDriver extends BenchmarkDriver implements GammaConstants { private GammaTxnLong ref; private GlobalConflictCounter globalConflictCounter; private GammaStm stm; private long operationCount = 1000 * 1000 * 1000; private GammaTxnLong orec; @Override public void setUp() { System.out.printf("Multiverse > Operation count is %s\n", operationCount); stm = new GammaStm(); ref = new GammaTxnLong(stm); globalConflictCounter = stm.getGlobalConflictCounter(); orec = new GammaTxnLong(stm); } @Override public void run(TestCaseResult testCaseResult) { final long _cycles = operationCount; final GammaTxnLong _orec = orec; for (long k = 0; k < _cycles; k++) { _orec.arriveAndLock(0, LOCKMODE_WRITE); _orec.upgradeWriteLock(); _orec.departAfterUpdateAndUnlock(); } } @Override public void processResults(TestCaseResult result) { long durationMs = result.getDurationMs(); double transactionsPerSecond = BenchyUtils.operationsPerSecond(operationCount, durationMs, 1); result.put("transactionsPerSecond", transactionsPerSecond); System.out.printf("Performance : %s update-cycles/second\n", BenchyUtils.format(transactionsPerSecond)); System.out.printf("Orec : %s\n", orec.___toOrecString()); } } Multiverse-multiverse-0.7.0/multiverse-core/000077500000000000000000000000001174000617100211745ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/generate.groovy000077500000000000000000000235501174000617100242450ustar00rootroot00000000000000import org.apache.velocity.Template import org.apache.velocity.VelocityContext import org.apache.velocity.app.VelocityEngine @Grab(group = 'org.apache.velocity', module = 'velocity', version = '1.6.4') class TxnCallable { String type String name String typeParameter } class TxnExecutor { String name boolean lean } class TxnObject { String type//the type of data it contains String objectType//the type of data it contains String initialValue//the initial value String typeParameter // String parametrizedTranlocal String functionClass//the class of the callable used for commuting operations String incFunctionMethod boolean isReference String referenceInterface boolean isNumber String predicateClass } VelocityEngine engine = new VelocityEngine(); engine.init(); def refs = createTxnObjects(); def txnCallables = createCallables();TxnCallable def txnExecutors = [new TxnExecutor(name: 'FatGammaTxnExecutor', lean: false), new TxnExecutor(name: 'LeanGammaTxnExecutor', lean: true)] generateRefFactory(engine, refs); for (def param in refs) { generateRefs(engine, param) generatePredicate(engine, param) generateFunction(engine, param) } for (def closure in txnCallables) { generateTxnCallable(engine, closure) } generateTxnExecutor(engine, txnCallables) //generateOrElseBlock(engine, atomicCallables) generateGammaOrElseBlock(engine, txnCallables) generateStmUtils(engine, txnCallables) for (def txnExecutor in txnExecutors) { generateGammaTxnExecutor(engine, txnExecutor, txnCallables) } List createCallables() { def result = [] result << new TxnCallable( name: 'TxnCallable', type: 'E', typeParameter: '' ) result << new TxnCallable( name: 'TxnIntCallable', type: 'int', typeParameter: '' ) result << new TxnCallable( name: 'TxnLongCallable', type: 'long', typeParameter: '' ) result << new TxnCallable( name: 'TxnDoubleCallable', type: 'double', typeParameter: '' ) result << new TxnCallable( name: 'TxnBooleanCallable', type: 'boolean', typeParameter: '' ) result << new TxnCallable( name: 'TxnVoidCallable', type: 'void', typeParameter: '' ) result } List createTxnObjects() { def result = [] result.add new TxnObject( type: 'E', objectType: '', typeParameter: '', initialValue: 'null', referenceInterface: 'TxnRef', functionClass: 'Function', isReference: true, isNumber: false, predicateClass: "Predicate", incFunctionMethod: '') result.add new TxnObject( type: 'int', objectType: 'Integer', referenceInterface: 'TxnInteger', typeParameter: '', initialValue: '0', functionClass: 'IntFunction', isReference: true, isNumber: true, predicateClass: "IntPredicate", incFunctionMethod: 'newIncIntFunction') result.add new TxnObject( type: 'boolean', objectType: 'Boolean', referenceInterface: 'TxnBoolean', typeParameter: '', initialValue: 'false', functionClass: 'BooleanFunction', isReference: true, isNumber: false, predicateClass: "BooleanPredicate", incFunctionMethod: '') result.add new TxnObject( type: 'double', objectType: 'Double', referenceInterface: 'TxnDouble', typeParameter: '', initialValue: '0', functionClass: 'DoubleFunction', isReference: true, isNumber: true, predicateClass: "DoublePredicate", incFunctionMethod: '') result.add new TxnObject( referenceInterface: 'TxnLong', type: 'long', objectType: 'Long', typeParameter: '', initialValue: '0', functionClass: 'LongFunction', isReference: true, isNumber: true, predicateClass: "LongPredicate", incFunctionMethod: 'newIncLongFunction') result.add new TxnObject( type: '', objectType: '', typeParameter: '', initialValue: '', functionClass: 'Function', referenceInterface: '', isReference: false, isNumber: false, predicateClass: "", incFunctionMethod: '') result } void generateTxnCallable(VelocityEngine engine, TxnCallable callable) { Template t = engine.getTemplate('src/main/java/org/multiverse/api/callables/TxnCallable.vm') VelocityContext context = new VelocityContext() context.put('callable', callable) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File("src/main/java/org/multiverse/api/callables/${callable.name}.java") file.createNewFile() file.text = writer.toString() } void generateGammaTxnExecutor(VelocityEngine engine, TxnExecutor txnExecutor, List closures) { Template t = engine.getTemplate('src/main/java/org/multiverse/stms/gamma/GammaTxnExecutor.vm') VelocityContext context = new VelocityContext() context.put('txnExecutor', txnExecutor) context.put('callables', closures) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File("src/main/java/org/multiverse/stms/gamma/${txnExecutor.name}.java") file.createNewFile() file.text = writer.toString() } void generateTxnExecutor(VelocityEngine engine, List closures) { Template t = engine.getTemplate('src/main/java/org/multiverse/api/TxnExecutor.vm') VelocityContext context = new VelocityContext() context.put('callables', closures) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File('src/main/java/org/multiverse/api/TxnExecutor.java') file.createNewFile() file.text = writer.toString() } void generateOrElseBlock(VelocityEngine engine, List closures) { Template t = engine.getTemplate('src/main/java/org/multiverse/api/OrElseBlock.vm') VelocityContext context = new VelocityContext() context.put('callables', closures) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File('src/main/java/org/multiverse/api/OrElseBlock.java') file.createNewFile() file.text = writer.toString() } void generateGammaOrElseBlock(VelocityEngine engine, List closures) { Template t = engine.getTemplate('src/main/java/org/multiverse/stms/gamma/GammaOrElseBlock.vm') VelocityContext context = new VelocityContext() context.put('callables', closures) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File('src/main/java/org/multiverse/stms/gamma/GammaOrElseBlock.java') file.createNewFile() file.text = writer.toString() } void generateStmUtils(VelocityEngine engine, List callables) { Template t = engine.getTemplate('src/main/java/org/multiverse/api/StmUtils.vm') VelocityContext context = new VelocityContext() context.put('callables', callables) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File('src/main/java/org/multiverse/api/StmUtils.java') file.createNewFile() file.text = writer.toString() } void generatePredicate(VelocityEngine engine, TxnObject transactionalObject) { if (!transactionalObject.isReference) { return } Template t = engine.getTemplate('src/main/java/org/multiverse/api/predicates/Predicate.vm') VelocityContext context = new VelocityContext() context.put('transactionalObject', transactionalObject) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File('src/main/java/org/multiverse/api/predicates/', "${transactionalObject.predicateClass}.java") file.createNewFile() file.text = writer.toString() } void generateFunction(VelocityEngine engine, TxnObject transactionalObject) { if (!transactionalObject.isReference) { return } Template t = engine.getTemplate('src/main/java/org/multiverse/api/functions/Function.vm') VelocityContext context = new VelocityContext() context.put('transactionalObject', transactionalObject) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File('src/main/java/org/multiverse/api/functions/', "${transactionalObject.functionClass}.java") file.createNewFile() file.text = writer.toString() } void generateRefs(VelocityEngine engine, TxnObject transactionalObject) { if (!transactionalObject.isReference) { return; } Template t = engine.getTemplate('src/main/java/org/multiverse/api/references/TxnRef.vm'); VelocityContext context = new VelocityContext() context.put('transactionalObject', transactionalObject) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File('src/main/java/org/multiverse/api/references/', "${transactionalObject.referenceInterface}.java") file.createNewFile() file.text = writer.toString() } void generateRefFactory(VelocityEngine engine, List refs) { Template t = engine.getTemplate('src/main/java/org/multiverse/api/references/TxnRefFactory.vm'); VelocityContext context = new VelocityContext() context.put('refs', refs) StringWriter writer = new StringWriter() t.merge(context, writer) File file = new File('src/main/java/org/multiverse/api/references/TxnRefFactory.java') file.createNewFile() file.text = writer.toString() } Multiverse-multiverse-0.7.0/multiverse-core/pom.xml000066400000000000000000000050101174000617100225050ustar00rootroot00000000000000 4.0.0 jar multiverse-core The Multiverse Code (so API and implementation) The Multiverse core org.multiverse multiverse 0.7.0 ../pom.xml maven-resources-plugin 2.4.2 ${sourceEncoding} maven-surefire-plugin **/*LongTest.java **/*longTest.java **/*StressTest.java **/*stressTest.java **/*PerformanceTest.java **/*performanceTest.java **/*Test.java once org.apache.maven.plugins maven-compiler-plugin 2.3.2 1.6 1.6 junit junit 4.10 test org.mockito mockito-all 1.9.0 test Multiverse-multiverse-0.7.0/multiverse-core/readme.txt000066400000000000000000000000671174000617100231750ustar00rootroot00000000000000To generate the sources, call 'groovy generate.groovy' Multiverse-multiverse-0.7.0/multiverse-core/src/000077500000000000000000000000001174000617100217635ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/000077500000000000000000000000001174000617100227075ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/000077500000000000000000000000001174000617100236305ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/000077500000000000000000000000001174000617100244175ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/000077500000000000000000000000001174000617100266165ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/MultiverseConstants.java000066400000000000000000000035251174000617100335220ustar00rootroot00000000000000package org.multiverse; import static java.lang.Boolean.parseBoolean; import static java.lang.Integer.parseInt; import static java.lang.System.getProperty; /** * An interface containing global constants. It is a final instead of something mutable so * that the JIT can completely remove code if some condition has not been met. The advantage is that you don't have to * pay to price for adding some kind of check, if it isn't used. The problem is that the scope is all classes loaded by * some classloader, share the same configuration. So one STM implementation with sanity checks enabled and the other * not, is not possible. *

* It is an interface so that is can be 'implemented' for easier access. * * @author Peter Veentjer */ public interface MultiverseConstants { /** * Indicates of the bugshaker is enabled (for more information see the * {@link org.multiverse.utils.Bugshaker}. If disabled, no overhead because it * can be removed by the JIT. */ boolean SHAKE_BUGS = parseBoolean(getProperty("org.multiverse.bugshaker.enabled", "false")); /** * Indicates if tracing (so seeing what is going on inside transactions) is * enabled. Normally this causes overhead of not used, with this flag the complete * tracing logic can be removed by the JIT if disabled). */ boolean TRACING_ENABLED = parseBoolean(getProperty("org.multiverse.tracing.enabled", "false")); /** * Indicates how often the system should yield when it is spinning. When a thread is * yielded, it gives the opportunity to another thread to make progress. */ int SPIN_YIELD = parseInt(getProperty("org.multiverse.spinYield", "32")); final int LOCKMODE_NONE = 0; final int LOCKMODE_READ = 1; final int LOCKMODE_WRITE = 2; final int LOCKMODE_EXCLUSIVE = 3; } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/000077500000000000000000000000001174000617100273675ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/BackoffPolicy.java000066400000000000000000000022101174000617100327400ustar00rootroot00000000000000package org.multiverse.api; /** * A policy to be used when {@link Txn} or an atomic operation can't make any progress, e.g. * because there a {@link org.multiverse.api.exceptions.ReadWriteConflict}. If the next attempt would * be done without waiting, the contention is going to increase. It can be better to back off to give the * contending Transactions some time to complete so that the chance increases that the failing Txn * can complete at a next attempt. * * Of course when there is a lot of contention, the BackoffPolicy isn't going to help and the Txn * could start to suffer from a livelock/starvation. * * @author Peter Veentjer. */ public interface BackoffPolicy { /** * Delays the calling Thread. * *

The implementation is free to make this a no-op call. * * @param attempt * @throws InterruptedException */ void delay(int attempt) throws InterruptedException; /** * Delays the calling Thread without being interrupted. * *

The implementation is free to make this a no-op call. * * @param attempt the */ void delayUninterruptible(int attempt); } DefaultBackoffPolicy.java000077500000000000000000000043321174000617100342000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/apipackage org.multiverse.api; import java.util.Random; import static java.util.concurrent.locks.LockSupport.parkNanos; /** * A {@link BackoffPolicy} that does an 'exponential' backoff. So each next attempt, the calculated delay is increased * and randomized (so the next value can be smaller than the previous, but overall they will increase). * * @author Peter Veentjer. */ @SuppressWarnings({"CallToThreadYield"}) public final class DefaultBackoffPolicy implements BackoffPolicy { public final static BackoffPolicy MAX_100_MS = new DefaultBackoffPolicy(); private final long minDelayNs; private final long[] slotTimes; /** * Creates an ExponentialBackoffPolicy with 100 nanoseconds as minimal delay and 100 milliseconds as maximum * delay. */ public DefaultBackoffPolicy() { this(1000); } /** * Creates an ExponentialBackoffPolicy with given maximum delay. * * @param minDelayNs the minimum delay in nanoseconds to wait. If a negative or zero value provided, it will be * interpreted that no external minimal value is needed. * @throws NullPointerException if unit is null. */ public DefaultBackoffPolicy(long minDelayNs) { Random random = new Random(); slotTimes = new long[1000]; this.minDelayNs = minDelayNs; double a = 100; double b = -4963; for (int k = 0; k < slotTimes.length; k++) { slotTimes[k] = Math.round(random.nextDouble() * f(k, a, b)); } } private int f(int x, double a, double b) { int result = (int) Math.round(a * x * x + b * x); return result < 0 ? 0 : result; } @Override public void delay(int attempt) throws InterruptedException { delayUninterruptible(attempt); } @Override public void delayUninterruptible(int attempt) { long delayNs = calcDelayNs(attempt); if (delayNs >= minDelayNs) { parkNanos(delayNs); } else if (attempt % 20 == 0) { Thread.yield(); } } protected long calcDelayNs(int attempt) { int slotIndex = attempt >= slotTimes.length ? slotTimes.length - 1 : attempt; return slotTimes[slotIndex]; } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/GlobalStmInstance.java000066400000000000000000000135421174000617100336100ustar00rootroot00000000000000package org.multiverse.api; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.logging.Logger; import static java.lang.String.format; import static java.lang.reflect.Modifier.isStatic; /** * A singleton that can be used for easy access to the {@link Stm} that is used globally. Once it has * been set, it should not be changed while running the system. * *

Using the GlobalStmInstance imposes some limitations (like 1 global Stm instance that is used by everything) but makes the * system a lot easier to use. But if the GlobalStmInstance should not be used, but a 'private' Stm, you need to carry around * the Stm reference yourself and just ignore this GlobalStmInstance. * *

Initialization

* *

The default implementation is the GammaStm for now. It can be configured through setting the System property: * 'org.multiverse.api.GlobalStmInstance.factoryMethod'. This method should be a no arg static method that returns a * {@link Stm} instance. * * @author Peter Veentjer */ public final class GlobalStmInstance { private static final String KEY = GlobalStmInstance.class.getName() + ".factoryMethod"; private static final String DEFAULT_FACTORY_METHOD = "org.multiverse.stms.gamma.GammaStm.createFast"; private static final Logger logger = Logger.getLogger(GlobalStmInstance.class.getName()); private static final Stm instance; static { String factoryMethod = System.getProperty(KEY, DEFAULT_FACTORY_METHOD); logger.info(format("Initializing GlobalStmInstance using factoryMethod '%s'.", factoryMethod)); try { Method method = getMethod(factoryMethod); instance = (Stm) method.invoke(null); logger.info(format("Successfully initialized GlobalStmInstance using factoryMethod '%s'.", factoryMethod)); } catch (IllegalAccessException e) { String msg = format("Failed to initialize the GlobalStmInstance through System property '%s' with value '%s'." + "Reason: factory method '%s' is not accessible (it should be public)').", KEY, factoryMethod, factoryMethod); logger.severe(msg); throw new IllegalArgumentException(msg, e); } catch (ClassCastException e) { String msg = format("Failed to initialize GlobalStmInstance through System property '%s' with value '%s'." + "Reason: factory method '%s' is not accessible (it should be public)').", KEY, factoryMethod, factoryMethod); logger.severe(msg); throw new IllegalArgumentException(msg, e); } catch (InvocationTargetException e) { String msg = format("Failed to initialize the GlobalStmInstance through System property '%s' with value '%s'." + "Reason: factory method '%s' failed to be invoked.", KEY, factoryMethod, factoryMethod); logger.severe(msg); throw new IllegalArgumentException(msg, e); } } private static Method getMethod(String factoryMethod) { int indexOf = factoryMethod.lastIndexOf('.'); if (indexOf == -1) { String msg = format( "Failed to initialize the GlobalStmInstance through System property '%s' with value '%s'. " + "Reason: It is not a valid factory method, it should be something like 'com.SomeStm.createSomeStm()').", KEY, factoryMethod); logger.info(msg); throw new IllegalArgumentException(); } String className = factoryMethod.substring(0, indexOf); Class clazz; try { clazz = Thread.currentThread().getContextClassLoader().loadClass(className); } catch (ClassNotFoundException e) { String msg = format("Failed to initialize the GlobalStmInstance through System property '%s' with value '%s'." + "Reason: '%s' is not an existing class (it can't be found using the Thread.currentThread.getContextClassLoader).", KEY, className, factoryMethod); logger.info(msg); throw new IllegalArgumentException(msg, e); } String methodName = factoryMethod.substring(indexOf + 1); if (methodName.length() == 0) { String msg = format("Failed to initialize the GlobalStmInstance through System property '%s' with value '%s'." + "Reason: the factory method is does not exist, it should be something like %s.createSomeStm.", KEY, className, factoryMethod); logger.info(msg); throw new IllegalArgumentException(msg); } Method method; try { method = clazz.getMethod(methodName); } catch (NoSuchMethodException e) { String msg = format("Failed to initialize the GlobalStmInstance through System property '%s' with value '%s'." + "Reason: the factory method does not exist. Remember that it should not have any arguments.", KEY, factoryMethod); logger.info(msg); throw new IllegalArgumentException(msg, e); } if (!isStatic(method.getModifiers())) { String msg = format("Failed to initialize the GlobalStmInstance through System property '%s' with value '%s'." + "Reason: the factory method is not static.", KEY, factoryMethod); logger.info(msg); throw new IllegalArgumentException(msg); } return method; } /** * Gets the global {@link Stm} instance. The returned value will never be null. * * @return the global Stm instance. */ public static Stm getGlobalStmInstance() { return instance; } //we don't want instances. private GlobalStmInstance() { } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/IsolationLevel.java000066400000000000000000000151461174000617100331720ustar00rootroot00000000000000package org.multiverse.api; /** * With the IsolationLevel you have a way to provide declarative control to guarantee isolation between transactions. * The transaction is free to provide a higher isolation than the one specified. *

* The dirty read isn't added since atm we already have an extremely cheap read using the atomicWeakGet on the * refs. Using the atomicWeakGet you have extremely cheap access to committed data. * *

The following isolation anomalies have been identified: *

    *
  1. Dirty Read
  2. *
  3. Unrepeatable Read
  4. *
  5. Inconsistent Read
  6. *
  7. Write Skew
  8. *
* *

Dirty Read

* *

The DirtyRead isolation anomaly is that one transaction could observe uncommitted changes made by another transaction. * The biggest problem with this anomaly is that eventually the updating transaction could abort and the reading transaction * sees changes that never made it into the system. * *

Currently the Dirty Read anomaly is not possible in Multiverse since writes to main memory are deferred until commit * and once the first write to main memory is executed, the following writes are guaranteed to succeed. * *

Unrepeatable Read

* *

The Unrepeatable Read isolation anomaly is that a transaction could see changes made by other transactions. So at one * moment it could see value X and a moment later it could see Y. This could lead to all kinds of erratic behavior like * transaction that can get stuck in an infinitive loop. * *

Such a transaction is called a zombie transaction and can cause serious damage since they are consuming resources * (like cpu) and are holding on to various resources (like Locks). So the unrepeatable read should be used with care. * *

Inconsistent Read

* *

With the inconsistent read it is possible that a value is read depending on a previous read value that has been updated * by another transaction. E.g. there are 100 refs all initialized with the same value and there is an updating transaction * that increments all value's by one, and there is a reading transaction that reads all refs, then it should see the same * values for all values. * *

Writeskew

* *

With the writeskew problem it is possible that 2 transactions commit.... * *

Example 1: there are 1 person that has 2 bank accounts and the invariant is that the sum of both bank accounts is * always equal or larger than zero. If user has has 50 euro on both accounts (so the sum is 100) and there are 2 transactions * that both subtract 100 euro from the bank accounts, and the first sees account1=50 and account2=50, the subtraction is allowed * and subtracts it 100 from the first account, and the second transaction sees exactly the same and subtracts 100 from the second * account, it could be possible that the person ends up with -50 on both accounts (so a sum of -100), clearly violating the * contract that the the sum should never be smaller than 0. * *

Example 2: * *

Isolation Levels

* *

The following isolation levels are currently defined in Multiverse: *

    *
  1. Read Committed
  2. *
  3. Repeatable Read
  4. *
  5. Snapshot
  6. *
  7. Serialized
  8. *
* The read uncommitted is currently not defined since currently there is no need to do a dirty read, there will always be committed * data available for reading (the write is deferred till commit, so you won't have to see transactions in progress). * * * *
* * *

Implementation and isolation level upgrade

* *

An implementation of the {@link Txn} is free to upgrade the isolation level to a higher one if it doesn't support that specific isolation * level. This is the same as Oracle is doing with the ReadUncommitted, which automatically is upgraded to a ReadCommitted or the RepeatableRead which is * automatically upgraded to Snapshot (Oracle calls this the Serialized isolation level). * *

Isolation: pessimistic or optimistic

* *

Isolation through locking

* * * * * @author Peter Veentjer. * @see TxnFactoryBuilder#setIsolationLevel(IsolationLevel) */ public enum IsolationLevel { /** * With the RepeatableRead isolation level you will always see committed data and next to that once a read * is done, this read is going to be repeatable (so you will see the same value every time). */ RepeatableRead(false, true, true), /** * The default isolation level that allows for the writeskew problem but not for dirty or unrepeatable * or inconsistent reads. *

* This is the 'serialized' isolation level provided by MVCC databases like Oracle/Postgresql * (although Postgresql 9 is going to provide a truly serialized isolation level) and MySQL with the InnoDb. * All data read. contains committed data and all data will be consistent. *

* A transaction that is readonly, gets the same isolation behavior as the Serializable isolation level * since the writeskew problem can't occur (nothing can be written). */ Snapshot(false, false, true), /** * Provides truly serialized transaction at the cost of reduced performance and concurrency. This is the highest * isolation level where no isolation anomalies are allowed to happen. So the writeSkew problem is not allowed to * happen. */ Serializable(false, false, false); private final boolean allowWriteSkew; private final boolean allowUnrepeatableRead; private final boolean allowInconsistentRead; IsolationLevel(boolean allowUnrepeatableRead, boolean allowInconsistentRead, boolean allowWriteSkew) { this.allowUnrepeatableRead = allowUnrepeatableRead; this.allowInconsistentRead = allowInconsistentRead; this.allowWriteSkew = allowWriteSkew; } /** * Checks if the writeskew problem is allowed to happen. * * @return true if the writeSkew is allowed to happen. */ public final boolean doesAllowWriteSkew() { return allowWriteSkew; } /** * Checks if the dirty read is allowed to happen (so reading data that has not been committed). * * @return true if the dirty read is allowed to happen. */ public boolean doesAllowUnrepeatableRead() { return allowUnrepeatableRead; } /** * Checks if the inconsistent read is allowed to happen. * * @return true if the inconsistent read is allowed to happen. */ public boolean doesAllowInconsistentRead() { return allowInconsistentRead; } @Override public String toString() { return "IsolationLevel." + name(); } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/Lock.java000066400000000000000000000243041174000617100311250ustar00rootroot00000000000000package org.multiverse.api; /** * The Lock provides access to pessimistic behavior of a {@link TxnObject}. STM normally is very optimistic, but * in some cases a more pessimistic approach (one with less retries) could be a better fitting solution. *

* There are 4 different types of lockmodes: *

    *
  • LockMode.None: it doesn't do any locking
  • *
  • LockMode.Read: it allows multiple transactions to acquire the read lock, but transaction acquiring the write-lock * or exclusive lock (needed when a transaction wants to commit) is prohibited. If the read lock is acquired by a different * transaction, a transaction still is able to read/write, but it isn't allowed to commit the changes (since and exclusive * lock is required for that). *
  • *
  • LockMode.Write: it allows only one transaction to acquire the write lock, but unlike a traditional * write-lock, reads still are allowed. Normally this would not be acceptable because once the write-lock * is acquired, the internals could be modified. But in case of STM, the STM can still provide a consistent view * even though the locking transaction has made changes. This essentially is the same behavior you get with the * 'select for update' from Oracle. Once the write lock is acquired, other transactions can't acquire the Lock. *
  • *
  • LockMode.Exclusive: it allows only one transaction to acquire the commit lock, and readers are not * allowed to read anymore. From an isolation perspective, the exclusive lock looks a lot like the synchronized * statement (or a {@link java.util.concurrent.locks.ReentrantLock}} where only mutually exclusive access is * possible. The exclusive lock normally is used by the STM when it commits.
  • *
* *

Lock duration and release

* *

Locks atm are acquired for the remaining duration of the transaction and only will always be automatically * released once the transaction commits/aborts. This is essentially the same behavior you get with Oracle once * a update/delete/insert is done, or when the record is locked manually by executing the 'select for update'. For * this to work it is very important that the {@link org.multiverse.api.exceptions.ControlFlowError} is not caught * by the logic executed in an transactional closure, but is caught by the TxnExecutor itself. * *

Blocking

* *

Atm it isn't possible to block on a lock. What happens is that some spinning is done * {@link TxnFactoryBuilder#setSpinCount(int)} and then some retries * {@link TxnFactoryBuilder#setMaxRetries(int)} in combination with a backoff * {@link TxnFactoryBuilder#setBackoffPolicy(BackoffPolicy)}. In the 0.8 release blocking will * probably be added. * *

Fairness

* *

Atm there is no support for fairness. The big problem with fairness and STM is that the locks are released * and the transaction needs to begin again. It could be that a lower priority transaction is faster and acquires * the lock again. This is a topic that needs more research and probably will be integrated in the contention * management. * *

Lock upgrade

* *

It is possible to upgrade a lock to more strict version, e.g. to upgrade a read-lock to a write-lock. * The following upgrades are possible: *

    *
  1. LockMode.Read->LockMode.Write: as long as no other transaction has acquired the Lock in LockMode.Read
  2. *
  3. LockMode.Read->LockMode.Exclusive: as long as no other transaction has acquired the Lock in LockMode.Read
  4. *
  5. LockMode.Write->LockMode.Exclusive: will always succeed
  6. *
*

* The Txn is allowed to apply a more strict LockMode than the one specified. * *

Lock downgrade

* *

Downgrading locks currently is not possible and downgrade calls are ignored. * *

Locking scope

* *

Locking can be done on the Txn level (see the {@link TxnFactoryBuilder#setReadLockMode(LockMode)} and * {@link TxnFactoryBuilder#setWriteLockMode(LockMode)} where all reads or all writes (to do a write also a read * is needed) are locked automatically. It can also be done on the reference level using * getAndLock/setAndLock/getAndSetAndLock methods or by accessing the {@link TxnObject#getLock()}. * *

Lock escalation

* *

In traditional lock based databases, managing locks in memory can be quite expensive. That is one of the reason why * different Lock granularities are used (record level, page level, table level for example). To prevent managing too many * locks, some databases apply lock escalation so that multiple low granularity locks are upgraded to a single higher granular * lock. The problem with lock escalations is that the system could be subject to lock contention and to deadlocks. * *

The GammaStm (the main STM implementation) doesn't use lock escalation, but keeps on managing locks on the transactional object * (ref) level. * *

Deadlocks

* *

2 Ingredients are needed for a deadlock: *

    *
  1. Transactions acquiring locks in a different order
  2. *
  3. Transactions that do an unbound waiting for a lock to come available
  4. *
* The problem with applying locks in the same order is that it places an extra borden on the developer. That is why atm the second * ingredient is always missing if the GammaStm (the default STM implementation) is used. Therefor a developer doesn't need to worry about * deadlocks (although it shifts the problem to an increased chance of starvation and livelocks). * * @author Peter Veentjer. * @see TxnFactoryBuilder#setReadLockMode(LockMode) * @see TxnFactoryBuilder#setWriteLockMode(LockMode) */ public interface Lock { /** * Returns the current LockMode. This call doesn't look at any running transaction, it shows the actual * state of the Lock. The value could be stale as soon as it is received. To retrieve the LockMode a * a Txn has on a Lock, the {@link #getLockMode()} or {@link #getLockMode(Txn)} need * to be used. * * @return the current LockMode. */ LockMode atomicGetLockMode(); /** * Gets the LockMode the transaction stored in the the {@link TxnThreadLocal} has on this Lock. * To retrieve the actual LockMode of the Lock, you need to use the {@link #atomicGetLockMode()}. * * @return the LockMode. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the transaction. The transaction is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The transaction * is guaranteed to have been aborted. * @see #atomicGetLockMode() * @see #getLockMode(Txn) */ LockMode getLockMode(); /** * Gets the LockMode the transaction has on the Lock. This call makes use of the tx. To retrieve the actual * LockMode of the Lock, you need to use the {@link #atomicGetLockMode()} * * @param txn the Lock * @return the LockMode the transaction has on the Lock. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the transaction. The transaction is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The transaction * is guaranteed to have been aborted. * @see #atomicGetLockMode() * @see #getLockMode(Txn) */ LockMode getLockMode(Txn txn); /** * Acquires a Lock with the provided LockMode. This call doesn't block if the Lock can't be upgraded, but throws * a {@link org.multiverse.api.exceptions.ReadWriteConflict}. It could also be that the Lock is acquired, but the * Txn sees that it isn't consistent anymore. In that case also a * {@link org.multiverse.api.exceptions.ReadWriteConflict} is thrown. * *

This call makes use of the Txn stored in the {@link TxnThreadLocal}. * *

If the lockMode is lower than the LockMode the transaction already has on this Lock, the call is ignored. * * @param desiredLockMode the desired lockMode. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the transaction. The transaction is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The transaction * is guaranteed to have been aborted. * @throws NullPointerException if desiredLockMode is null. If an alive transaction is available, it will * be aborted. */ void acquire(LockMode desiredLockMode); /** * Acquires a Lock with the provided LockMode using the provided transaction. This call doesn't block if the Lock can't be * upgraded but throws a {@link org.multiverse.api.exceptions.ReadWriteConflict}. It could also be that the Lock is acquired, * but the Txn sees that it isn't consistent anymore. In that case also a * {@link org.multiverse.api.exceptions.ReadWriteConflict} is thrown. * *

If the lockMode is lower than the LockMode the transaction already has on this Lock, the call is ignored. * * @param txn the Txn used for this operation. * @param desiredLockMode the desired lockMode. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the transaction. The transaction is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The transaction * is guaranteed to have been aborted. * @throws NullPointerException if tx or desiredLockMode is null. If an alive transaction is available, it will * be aborted. */ void acquire(Txn txn, LockMode desiredLockMode); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/LockMode.java000066400000000000000000000040561174000617100317340ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.MultiverseConstants; /** * Using the LockMode one can control the pessimistic nature of a {@link Txn}. * *

Normally transactions are very optimistic (e.g. fail during execution or at the end because some read or * write conflict was detected), but in some cases a more pessimistic approach is better. For more information * see {@link Lock}. * * @author Peter Veentjer. * @see TxnFactoryBuilder#setReadLockMode(LockMode) * @see TxnFactoryBuilder#setWriteLockMode(LockMode) * @see TxnConfig#getReadLockMode() * @see TxnConfig#getWriteLockMode() * @see TxnObject#getLock() * @see Lock */ public enum LockMode implements MultiverseConstants { /** * No locking is done. */ None(LOCKMODE_NONE), /** * The LockMode.Read prevents others to acquire the Write/Exclusive-lock, but it allows others to acquire the * Read lock. Unlike a traditional read/write-lock, it doesn't have to mean that other transactions can't write, * it only prevents others from committing. */ Read(LOCKMODE_READ), /** * The LockMode.Write prevents others to acquire the Read/Write/Exclusive-lock. Unlike a traditional read-write lock, * it doesn't have to mean that other transactions can't read or write, they only can't commit since the Exclusive lock * is acquired for that (managed by the STM). */ Write(LOCKMODE_WRITE), /** * The ExclusiveLock can be compared with the writelock of a traditional read/write lock. once the Exclusive lock is acquired * no other transaction can acquire any lock or can do any reading/writing (unless the transaction previously has read the * transactional object). * *

The ExclusiveLock is the Lock acquired by the STM once a Txn is prepared for writing changes to a TxnObject. */ Exclusive(LOCKMODE_EXCLUSIVE); private int lockModeAsInt; private LockMode(int lockModeAsInt) { this.lockModeAsInt = lockModeAsInt; } public int asInt() { return lockModeAsInt; } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/OrElseBlock.java000066400000000000000000000221051174000617100323760ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.MultiverseConstants; import org.multiverse.api.callables.*; /** * The OrElse is responsible for executing the either block, or in case of a retry, the orelse block is executed. *

* Another useful features of this design is that for certain primitives it doesn't require any form of boxing. * It also provides an atomicChecked for a TxnVoidCallable which doesn't force a developer to return something when * nothing needs to be returned. * * @author Peter Veentjer. */ public interface OrElseBlock extends MultiverseConstants { /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. *

* If in the execution of the closure a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException * if no transaction is found on the TxnThreadLocal. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if a checked exception is thrown by the closure. */ E execute(TxnCallable either, TxnCallable orelse); /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws Exception if the atomicChecked call fails. */ E executeChecked(TxnCallable either, TxnCallable orelse) throws Exception; /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. *

* If in the execution of the closure a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if a checked exception is thrown by the closure. */ int execute(TxnIntCallable either, TxnIntCallable orelse); /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws Exception if the atomicChecked call fails. */ int executeChecked(TxnIntCallable either, TxnIntCallable orelse) throws Exception; /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. *

* If in the execution of the closure a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if a checked exception is thrown by the closure. */ long execute(TxnLongCallable either, TxnLongCallable orelse); /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws Exception if the atomicChecked call fails. */ long executeChecked(TxnLongCallable either, TxnLongCallable orelse) throws Exception; /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. *

* If in the execution of the closure a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if a checked exception is thrown by the closure. */ double execute(TxnDoubleCallable either, TxnDoubleCallable orelse); /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws Exception if the atomicChecked call fails. */ double executeChecked(TxnDoubleCallable either, TxnDoubleCallable orelse) throws Exception; /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. *

* If in the execution of the closure a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if a checked exception is thrown by the closure. */ boolean execute(TxnBooleanCallable either, TxnBooleanCallable orelse); /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. * * @param either * @param orelse * @return the result of the execution. * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws Exception if the atomicChecked call fails. */ boolean executeChecked(TxnBooleanCallable either, TxnBooleanCallable orelse) throws Exception; /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. *

* If in the execution of the closure a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either * @param orelse * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if a checked exception is thrown by the closure. */ void execute(TxnVoidCallable either, TxnVoidCallable orelse); /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. * * @param either * @param orelse * @throws NullPointerException if either or orelse is null. * @throws TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws Exception if the atomicChecked call fails. */ void executeChecked(TxnVoidCallable either, TxnVoidCallable orelse) throws Exception; } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/OrElseBlock.vm000066400000000000000000000036541174000617100321070ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.*; import org.multiverse.api.closures.*; /** * The OrElse is responsible for executing the either block, or in case of a retry, the orelse block is executed. * * @author Peter Veentjer. */ public interface OrElseBlock extends MultiverseConstants{ #foreach($closure in $closures) /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. * * If in the execution of the closure a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either * @param orelse #if(${closure.type} ne 'void') * @return the result of the execution. #end * @throws NullPointerException if either or orelse is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the closure. */ ${closure.typeParameter} ${closure.type} execute(${closure.name}${closure.typeParameter} either, ${closure.name}${closure.typeParameter} orelse); /** * Executes the either, or when it is retried, the orelse block. This operation makes composable blocking operations * possible. * * @param either * @param orelse #if(${closure.type} ne 'void') * @return the result of the execution. #end * @throws NullPointerException if either or orelse is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException if no transaction is found on the TxnThreadLocal. * @throws Exception if the execute call fails. */ ${closure.typeParameter} ${closure.type} executeChecked(${closure.name}${closure.typeParameter} either, ${closure.name}${closure.typeParameter} orelse)throws Exception; #end } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/PropagationLevel.java000066400000000000000000000025371174000617100335140ustar00rootroot00000000000000package org.multiverse.api; /** * With the PropagationLevel you have control on how the {@link TxnExecutor} reacts on the existence or the non existence * of a {@link Txn}. * * @author Peter Veentjer. * @see TxnFactoryBuilder#setPropagationLevel(PropagationLevel) * @see TxnConfig#getPropagationLevel() */ public enum PropagationLevel { /** * Indicates that a new transaction always is started, even when there is an active transaction. The * active transaction is postponed and used again after the nested transaction commits. It could be that * the outer transaction conflicts made on changes by the inner transaction. */ RequiresNew, /** * Indicates that a new transaction will be used if none exists. If one exists, the logic will lift on that * transaction. This is the default propagation level. */ Requires, /** * Indicates that a transaction should always be available. If not, a * {@link org.multiverse.api.exceptions.TxnMandatoryException} is thrown. */ Mandatory, /** * Indicates that it the logic can either be run with or without transaction. */ Supports, /** * Indicates that no active transaction should be available. If a transaction is found, * a {@link org.multiverse.api.exceptions.TxnNotAllowedException} is thrown. */ Never } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/Stm.java000066400000000000000000000116711174000617100310030ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.api.collections.TxnCollectionsFactory; import org.multiverse.api.references.TxnRefFactory; import org.multiverse.api.references.TxnRefFactoryBuilder; /** * The main interface for software transactional memory. The main tasks are done by the following structures: *

    *
  1. {@link TxnObject}: the structure where state and identity are separated and where state change * is coordinated through a transaction. An example of the TxnObject is the {@link org.multiverse.api.references.TxnRef}, * but it could just as easily by a more complex transactional datastructure that is enhanced by instrumentation. *
  2. *
  3. {@link Txn}: responsible for making sure that all changes on transactionalobjects are atomic, isolated and consistent. *
  4. *
  5. {@link TxnExecutor}: responsible for starting/committing/aborting/retrying transactions. The TxnExecutor executes an * {@link org.multiverse.api.callables.TxnCallable} (there are different tastes for return values). The TxnCallable contains * the logic that needs to be executed atomic, isolated and consistent. *
  6. *
* *

Pluggability

* *

The Stm interface provides a mechanism to separate the contract from the implementation. So it is possible to change the * Stm implementation without changing the code that uses it. The idea is that for example a TL2 (MVCC) based implementation can * be replaced by a Sky-STM or a lock based STM. Of course every Stm implementation will have its strong and weak * spots. * *

All functionality like TxnExecutors, Refs, Txn etc can be customized by providing a custom implementation of the * factory/builder interfaces: *

    *
  1. {@link org.multiverse.api.references.TxnRefFactoryBuilder} a builder for creating {@link org.multiverse.api.references.TxnRefFactory}
  2. *
  3. {@link TxnFactoryBuilder} a builder for creating an {@link TxnExecutor}/{@link Txn}. *
  4. {@link org.multiverse.api.collections.TxnCollectionsFactory} a factory for creating transactional collections
  5. *
* *

Multiple Stm instances

* *

It is important that an TxnObject only is used within a single Stm. If it is 'shared' between different * stm instances, isolation problems could happen. This can be caused by the fact that different stm instances * probably use different clocks or completely different mechanisms for preventing isolation problems. It depends on the * implementation if any checking is done (the GammaStm does check if there is a conflict). * *

Thread safe

* All methods on the Stm are of course thread safe. * * @author Peter Veentjer. */ public interface Stm { /** * Gets the {@link TxnFactoryBuilder} that needs to be used to execute a {@link Txn} created by this Stm. * See the {@link TxnFactoryBuilder} for more info. The TxnFactoryBuilder also is responsible for creating * the TxnExecutor since the Txn and TxnExecutor can be tightly coupled. * * @return the TxnFactoryBuilder that is used to execute transactions on this Stm. */ TxnFactoryBuilder newTxnFactoryBuilder(); /** * Starts a default Txn that is useful for testing/experimentation purposes. This method is purely for easy to use access, * but doesn't provide any configuration options. See the {@link #newTxnFactoryBuilder()} for something more configurable. * In mose cases this is not the method you want to use to manage transactions. * *

Transactions returned by this method are not speculative. * * @return the new default Txn. */ Txn newDefaultTxn(); /** * Returns the default {@link TxnExecutor} that is useful for testing/experimentation purposes. * This method is purely for easy to use access, but it doesn't provide any configuration options. * See the {@link #newTxnFactoryBuilder()} for something more configurable. * *

Transactions used in this Block are not speculative. * * @return the default TxnExecutor. */ TxnExecutor getDefaultTxnExecutor(); /** * Creates an OrElseBlock. * * @return the created OrElseBlock. */ OrElseBlock newOrElseBlock(); /** * Returns the default {@link org.multiverse.api.references.TxnRefFactory} that can be used for easy and cheap access to a reference factory * instead of setting one up through the {@link org.multiverse.api.references.TxnRefFactoryBuilder}. * * @return the default TxnRefFactory. */ TxnRefFactory getDefaultRefFactory(); /** * Gets the {@link org.multiverse.api.references.TxnRefFactoryBuilder}. * * @return the TxnRefFactoryBuilder. */ TxnRefFactoryBuilder getTxRefFactoryBuilder(); /** * Gets the default {@link org.multiverse.api.collections.TxnCollectionsFactory}. * * @return the default {@link org.multiverse.api.collections.TxnCollectionsFactory}. */ TxnCollectionsFactory getDefaultTxnCollectionFactory(); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/StmUtils.java000077500000000000000000001004711174000617100320240ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.api.callables.*; import org.multiverse.api.collections.*; import org.multiverse.api.exceptions.*; import org.multiverse.api.lifecycle.*; import org.multiverse.api.references.*; import java.util.*; import java.util.concurrent.Callable; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.getRequiredThreadLocalTxn; /** * A utility class with convenience methods to access the {@link org.multiverse.api.Stm} or * {@link Txn}. These methods can be imported using the static import for a less * ugly syntax. * * @author Peter Veentjer. */ public final class StmUtils { private final static TxnRefFactory refFactory = getGlobalStmInstance().getDefaultRefFactory(); private final static TxnExecutor defaultTxnExecutor = getGlobalStmInstance().getDefaultTxnExecutor(); private final static OrElseBlock orelseBlock = getGlobalStmInstance().newOrElseBlock(); private final static TxnCollectionsFactory txnCollectionsFactory = getGlobalStmInstance().getDefaultTxnCollectionFactory(); /** * Creates a new committed TxnList based on a double linked list. * * @return the created TxnList. */ public static TxnList newTxnLinkedList(){ return txnCollectionsFactory.newLinkedList(); } /** * Creates a new committed unbound TxnStack. * * @return the created TxnStack. */ public static TxnStack newTxnStack(){ return txnCollectionsFactory.newStack(); } /** * Creates a new committed bound TxnStack. * * @param capacity the maximum capacity of the stack. Integer.MAX_VALUE indicates that there is no bound. * @return the create TxnStack * @throws IllegalArgumentException if capacity smaller than 0. */ public static TxnStack newTxnStack(int capacity){ return txnCollectionsFactory.newStack(capacity); } /** * Creates a new committed unbound TxnQueue. * * @return the created TxnQueue. */ public static TxnQueue newTxnQueue(){ return txnCollectionsFactory.newQueue(); } /** * Creates a new committed bound TxnQueue. * * @param capacity the maximum capacity of the queue. Integer.MAX_VALUE indicates that there is no bound. * @return the created TxnQueue * @throws IllegalArgumentException if capacity smaller than 0. */ public static TxnQueue newTxnQueue(int capacity){ return txnCollectionsFactory.newQueue(capacity); } /** * Creates a new committed unbound TxnDeque. * * @return the created TxnDeque */ public static TxnDeque newTxnDeque(){ return txnCollectionsFactory.newDeque(); } /** * Creates a new committed bound TxnDeque. * * @param capacity the maximum capacity of the deque. Integer.MAX_VALUE indicates that there is no bound. * @return the created TxnDeque. * @throws IllegalArgumentException if capacity is smaller than 0. */ public static TxnDeque newTxnDeque(int capacity){ return txnCollectionsFactory.newDeque(capacity); } /** * Creates a new committed TxnSet that is based on a 'hashtable'. * * @return the created TxnSet. */ public static TxnSet newTxnHashSet(){ return txnCollectionsFactory.newHashSet(); } /** * Creates a new committed TxnMap. * * @return the created TxnMap */ public static TxnMap newTxnHashMap(){ return txnCollectionsFactory.newHashMap(); } public static void atomic(final Runnable runnable){ if(runnable == null){ throw new NullPointerException("runnable can't be null"); } atomic(new TxnVoidCallable(){ @Override public void call(Txn txn) throws Exception { runnable.run(); } }); } public static E atomic(final Callable callable){ if(callable == null){ throw new NullPointerException("callable can't be null"); } return atomic(new TxnCallable() { @Override public E call(Txn txn) throws Exception { return callable.call(); } }); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

This method doesn't throw a checked exception, but if the callable does, it is wrapped inside an * InvisibleCheckedException. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The callable {@link TxnCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if the callable throws a checked exception. */ public static E atomic(TxnCallable callable){ return defaultTxnExecutor.execute(callable); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The {@link TxnCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws Exception is the callable throws an Exception */ public static E atomicChecked(TxnCallable callable) throws Exception{ return defaultTxnExecutor.executeChecked(callable); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either the either block * @param orelse the orelse block. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ public static E atomic(TxnCallable either, TxnCallable orelse){ return orelseBlock.execute(either,orelse); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * @param either the either block * @param orelse the orelse block * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ public static E atomicChecked(TxnCallable either, TxnCallable orelse)throws Exception{ return orelseBlock.executeChecked(either,orelse); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

This method doesn't throw a checked exception, but if the callable does, it is wrapped inside an * InvisibleCheckedException. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The callable {@link TxnIntCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if the callable throws a checked exception. */ public static int atomic(TxnIntCallable callable){ return defaultTxnExecutor.execute(callable); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The {@link TxnIntCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws Exception is the callable throws an Exception */ public static int atomicChecked(TxnIntCallable callable) throws Exception{ return defaultTxnExecutor.executeChecked(callable); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either the either block * @param orelse the orelse block. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ public static int atomic(TxnIntCallable either, TxnIntCallable orelse){ return orelseBlock.execute(either,orelse); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * @param either the either block * @param orelse the orelse block * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ public static int atomicChecked(TxnIntCallable either, TxnIntCallable orelse)throws Exception{ return orelseBlock.executeChecked(either,orelse); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

This method doesn't throw a checked exception, but if the callable does, it is wrapped inside an * InvisibleCheckedException. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The callable {@link TxnLongCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if the callable throws a checked exception. */ public static long atomic(TxnLongCallable callable){ return defaultTxnExecutor.execute(callable); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The {@link TxnLongCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws Exception is the callable throws an Exception */ public static long atomicChecked(TxnLongCallable callable) throws Exception{ return defaultTxnExecutor.executeChecked(callable); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either the either block * @param orelse the orelse block. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ public static long atomic(TxnLongCallable either, TxnLongCallable orelse){ return orelseBlock.execute(either,orelse); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * @param either the either block * @param orelse the orelse block * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ public static long atomicChecked(TxnLongCallable either, TxnLongCallable orelse)throws Exception{ return orelseBlock.executeChecked(either,orelse); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

This method doesn't throw a checked exception, but if the callable does, it is wrapped inside an * InvisibleCheckedException. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The callable {@link TxnDoubleCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if the callable throws a checked exception. */ public static double atomic(TxnDoubleCallable callable){ return defaultTxnExecutor.execute(callable); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The {@link TxnDoubleCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws Exception is the callable throws an Exception */ public static double atomicChecked(TxnDoubleCallable callable) throws Exception{ return defaultTxnExecutor.executeChecked(callable); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either the either block * @param orelse the orelse block. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ public static double atomic(TxnDoubleCallable either, TxnDoubleCallable orelse){ return orelseBlock.execute(either,orelse); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * @param either the either block * @param orelse the orelse block * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ public static double atomicChecked(TxnDoubleCallable either, TxnDoubleCallable orelse)throws Exception{ return orelseBlock.executeChecked(either,orelse); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

This method doesn't throw a checked exception, but if the callable does, it is wrapped inside an * InvisibleCheckedException. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The callable {@link TxnBooleanCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if the callable throws a checked exception. */ public static boolean atomic(TxnBooleanCallable callable){ return defaultTxnExecutor.execute(callable); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The {@link TxnBooleanCallable} to execute. * @return the result of the execution * @throws NullPointerException if callable is null. * @throws Exception is the callable throws an Exception */ public static boolean atomicChecked(TxnBooleanCallable callable) throws Exception{ return defaultTxnExecutor.executeChecked(callable); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either the either block * @param orelse the orelse block. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ public static boolean atomic(TxnBooleanCallable either, TxnBooleanCallable orelse){ return orelseBlock.execute(either,orelse); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * @param either the either block * @param orelse the orelse block * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ public static boolean atomicChecked(TxnBooleanCallable either, TxnBooleanCallable orelse)throws Exception{ return orelseBlock.executeChecked(either,orelse); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

This method doesn't throw a checked exception, but if the callable does, it is wrapped inside an * InvisibleCheckedException. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The callable {@link TxnVoidCallable} to execute. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if the callable throws a checked exception. */ public static void atomic(TxnVoidCallable callable){ defaultTxnExecutor.execute(callable); } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The {@link TxnVoidCallable} to execute. * @throws NullPointerException if callable is null. * @throws Exception is the callable throws an Exception */ public static void atomicChecked(TxnVoidCallable callable) throws Exception{ defaultTxnExecutor.executeChecked(callable); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either the either block * @param orelse the orelse block. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ public static void atomic(TxnVoidCallable either, TxnVoidCallable orelse){ orelseBlock.execute(either,orelse); } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * @param either the either block * @param orelse the orelse block * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ public static void atomicChecked(TxnVoidCallable either, TxnVoidCallable orelse)throws Exception{ orelseBlock.executeChecked(either,orelse); } /** * Creates a committed {@link TxnInteger} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value of the TnxInteger * @return the created TnxInteger. */ public static TxnInteger newTxnInteger(int value) { return refFactory.newTxnInteger(value); } /** * Creates a committed {@link TxnInteger} with 0 as initial value using the {@link GlobalStmInstance}. * * @return the created TxnInteger. */ public static TxnInteger newTxnInteger() { return refFactory.newTxnInteger(0); } /** * Creates a committed {@link TxnLong} with 0 as initial value using the {@link GlobalStmInstance}. * * @return the created TnxLong. */ public static TxnLong newTxnLong() { return refFactory.newTxnLong(0); } /** * Creates a committed {@link TxnLong} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value of the TxnLong. * @return the created TnxLong. */ public static TxnLong newTxnLong(long value) { return refFactory.newTxnLong(value); } /** * Creates a committed {@link TxnDouble} with 0 as initial value using the {@link GlobalStmInstance}. * * @return the created TxnDouble. */ public static TxnDouble newTxnDouble() { return refFactory.newTxnDouble(0); } /** * Creates a committed {@link TxnDouble} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value. * @return the created TnxDouble. */ public static TxnDouble newTxnDouble(double value) { return refFactory.newTxnDouble(value); } /** * Creates a committed {@link TxnBoolean} with false as initial value using the {@link GlobalStmInstance}. * * @return the created TxnBoolean. */ public static TxnBoolean newTxnBoolean() { return refFactory.newTxnBoolean(false); } /** * Creates a committed {@link TxnBoolean} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value * @return the created TxnBoolean. */ public static TxnBoolean newTxnBoolean(boolean value) { return refFactory.newTxnBoolean(value); } /** * Creates a committed {@link TxnRef} with null as initial value using the {@link GlobalStmInstance}. * * @param the type of the TxnRef. * @return the created Ref. */ public static TxnRef newTxnRef() { return refFactory.newTxnRef(null); } /** * Creates a committed {@link TxnRef} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value of the TxnRef. * @param the type of the TxnRef. * @return the created TxnRef. */ public static TxnRef newTxnRef(E value) { return refFactory.newTxnRef(value); } /** * Does a retry. This behavior is needed for blocking transactions; transaction that wait for a state change * to happen on certain datastructures, e.g. an item to come available on a transactional blocking queue. * *

Under the hood the retry throws an Retry that will be caught up the callstack * (by the {@link TxnExecutor} for example). The Retry should not be caught by user code in almost all cases. */ public static void retry() { Txn txn = getRequiredThreadLocalTxn(); txn.retry(); } /** * Prepares the Transaction in the TxnThreadLocal transaction. * *

For more information see {@link Txn#prepare()}. * * @throws TxnMandatoryException if no active transaction is found. * @throws IllegalTransactionStateException if the active transaction is not in the correct * state for this operation. * @throws ControlFlowError */ public static void prepare() { Txn txn = getRequiredThreadLocalTxn(); txn.prepare(); } /** * Aborts the Transaction in the TxnThreadLocal transaction. * *

For more information see {@link Txn#abort()}. * * @throws TxnMandatoryException if no active transaction is found. * @throws IllegalTransactionStateException if the active transaction is not in the correct * state for this operation. * @throws ControlFlowError */ public static void abort() { Txn txn = getRequiredThreadLocalTxn(); txn.abort(); } /** * Commits the Transaction in the TxnThreadLocal transaction. * *

For more information see {@link Txn#commit()}. * * @throws TxnMandatoryException if no active transaction is found. * @throws IllegalTransactionStateException if the active transaction is not in the correct * state for this operation. * @throws ControlFlowError */ public static void commit() { Txn txn = getRequiredThreadLocalTxn(); txn.commit(); } /** * Scheduled an deferred or compensating task on the {@link Txn} in the TxnThreadLocal. This task is * executed after the transaction commits or aborts. * * @param task the deferred task to execute. * @throws NullPointerException if task is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException if no transaction is set on the {@link org.multiverse.api.TxnThreadLocal}. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not in the correct state to accept a compensating or deferred task. */ public static void scheduleCompensatingOrDeferredTask(final Runnable task) { if (task == null) { throw new NullPointerException(); } Txn txn = getRequiredThreadLocalTxn(); txn.register(new TxnListener() { @Override public void notify(Txn txn, TxnEvent event) { if (event == TxnEvent.PostCommit || event == TxnEvent.PostAbort) { task.run(); } } }); } /** * Scheduled an deferred task on the {@link Txn} in the {@link TxnThreadLocal}. This task is executed after * the transaction commits and one of the use cases is starting transactions. * * @param task the deferred task to execute. * @throws NullPointerException if task is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException * if no transaction is set on the {@link org.multiverse.api.TxnThreadLocal}. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not in the correct state to accept a deferred task. */ public static void scheduleDeferredTask(final Runnable task) { if (task == null) { throw new NullPointerException(); } Txn txn = getRequiredThreadLocalTxn(); txn.register(new TxnListener() { @Override public void notify(Txn txn, TxnEvent event) { if (event == TxnEvent.PostCommit) { task.run(); } } }); } /** * Scheduled a compensating task on the {@link Txn} in the {@link TxnThreadLocal}. This task is executed after * the transaction aborts and one of the use cases is cleaning up non transaction resources like the file system. * * @param task the deferred task to execute. * @throws NullPointerException if task is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException * if no transaction is set on the {@link org.multiverse.api.TxnThreadLocal}. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not in the correct state to accept a compensating task. */ public static void scheduleCompensatingTask(final Runnable task) { if (task == null) { throw new NullPointerException(); } Txn txn = getRequiredThreadLocalTxn(); txn.register(new TxnListener() { @Override public void notify(Txn txn, TxnEvent event) { if (event == TxnEvent.PostAbort) { task.run(); } } }); } //we don want instances private StmUtils() { } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/StmUtils.vm000066400000000000000000000420751174000617100315270ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.api.callables.*; import org.multiverse.api.collections.*; import org.multiverse.api.exceptions.*; import org.multiverse.api.lifecycle.*; import org.multiverse.api.references.*; import java.util.*; import java.util.concurrent.Callable; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.getRequiredThreadLocalTxn; /** * A utility class with convenience methods to access the {@link org.multiverse.api.Stm} or * {@link Txn}. These methods can be imported using the static import for a less * ugly syntax. * * @author Peter Veentjer. */ public final class StmUtils { private final static TxnRefFactory refFactory = getGlobalStmInstance().getDefaultRefFactory(); private final static TxnExecutor defaultTxnExecutor = getGlobalStmInstance().getDefaultTxnExecutor(); private final static OrElseBlock orelseBlock = getGlobalStmInstance().newOrElseBlock(); private final static TxnCollectionsFactory txnCollectionsFactory = getGlobalStmInstance().getDefaultTxnCollectionFactory(); /** * Creates a new committed TxnList based on a double linked list. * * @return the created TxnList. */ public static TxnList newTxnLinkedList(){ return txnCollectionsFactory.newLinkedList(); } /** * Creates a new committed unbound TxnStack. * * @return the created TxnStack. */ public static TxnStack newTxnStack(){ return txnCollectionsFactory.newStack(); } /** * Creates a new committed bound TxnStack. * * @param capacity the maximum capacity of the stack. Integer.MAX_VALUE indicates that there is no bound. * @return the create TxnStack * @throws IllegalArgumentException if capacity smaller than 0. */ public static TxnStack newTxnStack(int capacity){ return txnCollectionsFactory.newStack(capacity); } /** * Creates a new committed unbound TxnQueue. * * @return the created TxnQueue. */ public static TxnQueue newTxnQueue(){ return txnCollectionsFactory.newQueue(); } /** * Creates a new committed bound TxnQueue. * * @param capacity the maximum capacity of the queue. Integer.MAX_VALUE indicates that there is no bound. * @return the created TxnQueue * @throws IllegalArgumentException if capacity smaller than 0. */ public static TxnQueue newTxnQueue(int capacity){ return txnCollectionsFactory.newQueue(capacity); } /** * Creates a new committed unbound TxnDeque. * * @return the created TxnDeque */ public static TxnDeque newTxnDeque(){ return txnCollectionsFactory.newDeque(); } /** * Creates a new committed bound TxnDeque. * * @param capacity the maximum capacity of the deque. Integer.MAX_VALUE indicates that there is no bound. * @return the created TxnDeque. * @throws IllegalArgumentException if capacity is smaller than 0. */ public static TxnDeque newTxnDeque(int capacity){ return txnCollectionsFactory.newDeque(capacity); } /** * Creates a new committed TxnSet that is based on a 'hashtable'. * * @return the created TxnSet. */ public static TxnSet newTxnHashSet(){ return txnCollectionsFactory.newHashSet(); } /** * Creates a new committed TxnMap. * * @return the created TxnMap */ public static TxnMap newTxnHashMap(){ return txnCollectionsFactory.newHashMap(); } public static void atomic(final Runnable runnable){ if(runnable == null){ throw new NullPointerException("runnable can't be null"); } atomic(new TxnVoidCallable(){ @Override public void call(Txn txn) throws Exception { runnable.run(); } }); } public static E atomic(final Callable callable){ if(callable == null){ throw new NullPointerException("callable can't be null"); } return atomic(new TxnCallable() { @Override public E call(Txn txn) throws Exception { return callable.call(); } }); } #foreach($callable in $callables) /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

This method doesn't throw a checked exception, but if the callable does, it is wrapped inside an * InvisibleCheckedException. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The callable {@link ${callable.name}} to execute. #if(${callable.type} ne 'void') * @return the result of the execution #end * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException * if the callable throws a checked exception. */ public static ${callable.typeParameter} ${callable.type} atomic(${callable.name}${callable.typeParameter} callable){ #if(${callable.type} eq 'void') defaultTxnExecutor.execute(callable); #else return defaultTxnExecutor.execute(callable); #end } /** * Executes the callable transactionally on the GlobalStmInstance using the default TxnExecutor. If a * Transaction already is active on the TxnThreadLocal, this transaction will lift on that * transaction (so the propagation level is Requires) and will not commit this transaction. * *

If you want to get most out of performance, it is best to make use of a customized {@link TxnExecutor} instead * of relying on the default TxnExecutor that will always provide the most expensive transaction available. * * @param callable The {@link ${callable.name}} to execute. #if(${callable.type} ne 'void') * @return the result of the execution #end * @throws NullPointerException if callable is null. * @throws Exception is the callable throws an Exception */ public static ${callable.typeParameter} ${callable.type} atomicChecked(${callable.name}${callable.typeParameter} callable) throws Exception{ #if(${callable.type} eq 'void') defaultTxnExecutor.executeChecked(callable); #else return defaultTxnExecutor.executeChecked(callable); #end } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param either the either block * @param orelse the orelse block. #if(${callable.type} ne 'void') * @return the result of the execution. #end * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ public static ${callable.typeParameter} ${callable.type} atomic(${callable.name}${callable.typeParameter} either, ${callable.name}${callable.typeParameter} orelse){ #if(${callable.type} ne 'void') return orelseBlock.execute(either,orelse); #else orelseBlock.execute(either,orelse); #end } /** * Executes the either block, or in case of a retry, the orelse block is executed. * * @param either the either block * @param orelse the orelse block #if(${callable.type} ne 'void') * @return the result of the execution. #end * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ public static ${callable.typeParameter} ${callable.type} atomicChecked(${callable.name}${callable.typeParameter} either, ${callable.name}${callable.typeParameter} orelse)throws Exception{ #if(${callable.type} ne 'void') return orelseBlock.executeChecked(either,orelse); #else orelseBlock.executeChecked(either,orelse); #end } #end /** * Creates a committed {@link TxnInteger} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value of the TnxInteger * @return the created TnxInteger. */ public static TxnInteger newTxnInteger(int value) { return refFactory.newTxnInteger(value); } /** * Creates a committed {@link TxnInteger} with 0 as initial value using the {@link GlobalStmInstance}. * * @return the created TxnInteger. */ public static TxnInteger newTxnInteger() { return refFactory.newTxnInteger(0); } /** * Creates a committed {@link TxnLong} with 0 as initial value using the {@link GlobalStmInstance}. * * @return the created TnxLong. */ public static TxnLong newTxnLong() { return refFactory.newTxnLong(0); } /** * Creates a committed {@link TxnLong} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value of the TxnLong. * @return the created TnxLong. */ public static TxnLong newTxnLong(long value) { return refFactory.newTxnLong(value); } /** * Creates a committed {@link TxnDouble} with 0 as initial value using the {@link GlobalStmInstance}. * * @return the created TxnDouble. */ public static TxnDouble newTxnDouble() { return refFactory.newTxnDouble(0); } /** * Creates a committed {@link TxnDouble} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value. * @return the created TnxDouble. */ public static TxnDouble newTxnDouble(double value) { return refFactory.newTxnDouble(value); } /** * Creates a committed {@link TxnBoolean} with false as initial value using the {@link GlobalStmInstance}. * * @return the created TxnBoolean. */ public static TxnBoolean newTxnBoolean() { return refFactory.newTxnBoolean(false); } /** * Creates a committed {@link TxnBoolean} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value * @return the created TxnBoolean. */ public static TxnBoolean newTxnBoolean(boolean value) { return refFactory.newTxnBoolean(value); } /** * Creates a committed {@link TxnRef} with null as initial value using the {@link GlobalStmInstance}. * * @param the type of the TxnRef. * @return the created Ref. */ public static TxnRef newTxnRef() { return refFactory.newTxnRef(null); } /** * Creates a committed {@link TxnRef} with the provided value using the {@link GlobalStmInstance}. * * @param value the initial value of the TxnRef. * @param the type of the TxnRef. * @return the created TxnRef. */ public static TxnRef newTxnRef(E value) { return refFactory.newTxnRef(value); } /** * Does a retry. This behavior is needed for blocking transactions; transaction that wait for a state change * to happen on certain datastructures, e.g. an item to come available on a transactional blocking queue. * *

Under the hood the retry throws an Retry that will be caught up the callstack * (by the {@link TxnExecutor} for example). The Retry should not be caught by user code in almost all cases. */ public static void retry() { Txn txn = getRequiredThreadLocalTxn(); txn.retry(); } /** * Prepares the Transaction in the TxnThreadLocal transaction. * *

For more information see {@link Txn#prepare()}. * * @throws TxnMandatoryException if no active transaction is found. * @throws IllegalTransactionStateException if the active transaction is not in the correct * state for this operation. * @throws ControlFlowError */ public static void prepare() { Txn txn = getRequiredThreadLocalTxn(); txn.prepare(); } /** * Aborts the Transaction in the TxnThreadLocal transaction. * *

For more information see {@link Txn#abort()}. * * @throws TxnMandatoryException if no active transaction is found. * @throws IllegalTransactionStateException if the active transaction is not in the correct * state for this operation. * @throws ControlFlowError */ public static void abort() { Txn txn = getRequiredThreadLocalTxn(); txn.abort(); } /** * Commits the Transaction in the TxnThreadLocal transaction. * *

For more information see {@link Txn#commit()}. * * @throws TxnMandatoryException if no active transaction is found. * @throws IllegalTransactionStateException if the active transaction is not in the correct * state for this operation. * @throws ControlFlowError */ public static void commit() { Txn txn = getRequiredThreadLocalTxn(); txn.commit(); } /** * Scheduled an deferred or compensating task on the {@link Txn} in the TxnThreadLocal. This task is * executed after the transaction commits or aborts. * * @param task the deferred task to execute. * @throws NullPointerException if task is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException if no transaction is set on the {@link org.multiverse.api.TxnThreadLocal}. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not in the correct state to accept a compensating or deferred task. */ public static void scheduleCompensatingOrDeferredTask(final Runnable task) { if (task == null) { throw new NullPointerException(); } Txn txn = getRequiredThreadLocalTxn(); txn.register(new TxnListener() { @Override public void notify(Txn txn, TxnEvent event) { if (event == TxnEvent.PostCommit || event == TxnEvent.PostAbort) { task.run(); } } }); } /** * Scheduled an deferred task on the {@link Txn} in the {@link TxnThreadLocal}. This task is executed after * the transaction commits and one of the use cases is starting transactions. * * @param task the deferred task to execute. * @throws NullPointerException if task is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException * if no transaction is set on the {@link org.multiverse.api.TxnThreadLocal}. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not in the correct state to accept a deferred task. */ public static void scheduleDeferredTask(final Runnable task) { if (task == null) { throw new NullPointerException(); } Txn txn = getRequiredThreadLocalTxn(); txn.register(new TxnListener() { @Override public void notify(Txn txn, TxnEvent event) { if (event == TxnEvent.PostCommit) { task.run(); } } }); } /** * Scheduled a compensating task on the {@link Txn} in the {@link TxnThreadLocal}. This task is executed after * the transaction aborts and one of the use cases is cleaning up non transaction resources like the file system. * * @param task the deferred task to execute. * @throws NullPointerException if task is null. * @throws org.multiverse.api.exceptions.TxnMandatoryException * if no transaction is set on the {@link org.multiverse.api.TxnThreadLocal}. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not in the correct state to accept a compensating task. */ public static void scheduleCompensatingTask(final Runnable task) { if (task == null) { throw new NullPointerException(); } Txn txn = getRequiredThreadLocalTxn(); txn.register(new TxnListener() { @Override public void notify(Txn txn, TxnEvent event) { if (event == TxnEvent.PostAbort) { task.run(); } } }); } //we don want instances private StmUtils() { } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TraceLevel.java000066400000000000000000000016331174000617100322630ustar00rootroot00000000000000package org.multiverse.api; /** * Using the TraceLevel you get some feedback on what is happening inside a transaction. * *

For tracing to work, you need to look at {@link org.multiverse.MultiverseConstants#TRACING_ENABLED}. If not enabled, * the JIT will remove dead code because we don't want any overhead. * * @author Peter Veentjer * @see TxnFactoryBuilder#setTraceLevel(TraceLevel) * @see TxnConfig#getTraceLevel() */ public enum TraceLevel { None, Coarse; /** * Checks if the provided level is higher than this TraceLevel. * * @param level the TraceLevel to check * @return true if level is higher or equal than this TraceLevel. * @throws NullPointerException if level is null. */ public boolean isLoggableFrom(TraceLevel level) { if(level == null){ throw new NullPointerException(); } return compareTo(level) >= 0; } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/Txn.java000077500000000000000000000221761174000617100310160ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.api.lifecycle.TxnListener; /** * The unit of work for {@link Stm}. The transaction make sure that changes on {@link TxnObject} instances are: *

    *
  1. Atomic: all or nothing gets committed (Failure atomicity)
  2. *
  3. Consistent :
  4. *
  5. Isolated: a transaction is executed isolated from other transactions. Meaning that a transaction won't see changed made by * transactions executed concurrently, but it will see changes made by transaction completed before. It depends on the * {@link IsolationLevel} or {@link LockMode} used how strict the isolation is.
  6. *
* *

Thread-safety

* *

A Txn is not thread-safe (just like a Hibernate Session is not thread-safe to use). It can be * handed over from thread to thread, but one needs to be really careful with the {@link TxnThreadLocal} or other * thread specific state like the stackframe of a method (this is an issue when instrumentation is used since the stackframe * is likely to be enhanced to include the Txn as a local variable. * *

TxnListener

* *

It is possible to listen to a Txn when it aborts/prepares/commits/starts. There are 2 different flavors of * listeners: *

    *
  1. normal listeners: are registered during the execution of a transaction using the * {@link Txn#register(org.multiverse.api.lifecycle.TxnListener)} method. If the transactions aborts/commits * these listeners are removed. So if the transaction is retried, the listeners need to be registered (this is easy since * the logic inside the transactional closure that did the register, is executed again. *
  2. *
  3. permanent listeners: are registered once and will always remain. It can be done on the * TxnExecutor level using the {@link TxnFactoryBuilder#addPermanentListener(org.multiverse.api.lifecycle.TxnListener)} * or it can be done on the Stm level. Permanent listeners are suited for products that want to integrate with Multiverse and always * execute some logic at important transaction events. Registration of permanent can also be done on the {@link Stm} level. See * the implementations for more details. Permanent listeners are always executed after the normal listeners. *
  4. *
* *

Storing transaction references

* *

Txn instances should not be stored since they are likely to be pooled by the STM. So it could be that the same * transaction instance is re-used to execute a completely unrelated piece of logic, and it can also be that different instances * are used to execute the same logic. * * @author Peter Veentjer. */ public interface Txn { /** * Returns the TxnConfig used by this Txn. * *

Because the Txn can be reused, the TxnConfig used by this Txn doesn't need to be constant. * * @return the TxnConfig. */ TxnConfig getConfig(); /** * Returns the status of this Txn. * * @return the status of this Txn. */ TxnStatus getStatus(); /** * Gets the current attempt (so the number of tries this transaction already had). Value will * always be equal or larger than 1 (the first attempt returns 1). The maximum number of attempts for retrying is determined based * on the {@link TxnConfig#getMaxRetries()} * * @return the current attempt. */ int getAttempt(); /** * Gets the remaining timeout in nanoseconds. Long.MAX_VALUE indicates that no timeout is used. * *

The remaining timeout only is decreased if a transaction blocks on a retry or when doing * a backoff. * * @return the remaining timeout. */ long getRemainingTimeoutNs(); /** * Commits this Txn. If the Txn is: *

    *
  1. active: it is prepared for commit and then committed
  2. *
  3. prepared: it is committed. Once it is prepared, the commit is guaranteed to * succeed.
  4. *
  5. aborted: a DeadTxnException is thrown
  6. *
  7. committed: the call is ignored
  8. *
* *

Txn will always be aborted if the commit does not succeed. * *

Commit will not throw a {@link org.multiverse.api.exceptions.ReadWriteConflict} after the transaction is prepared. * So if prepared successfully, a commit will always succeed. * *

If there are TxnListeners (either normal ones or permanent ones) and they thrown a {@link RuntimeException} * or {@link Error}, this will be re-thrown. If a listener fails after the prepare/commit the transaction still is * committed. * * @throws org.multiverse.api.exceptions.ReadWriteConflict * if the commit failed. Check the class hierarchy of the ReadWriteConflict for more information. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the Txn is not in the correct * state for this operation. */ void commit(); /** * Prepares this transaction to be committed. It can lock resources to make sure that no conflicting changes are * made after the transaction has been prepared. If the transaction already is prepared, the call is ignored. If * the prepare fails, the transaction automatically is aborted. Once a transaction is prepared, the commit will * always succeed. * *

It is very important that the transaction eventually commits or aborts, if it doesn't no other transaction * reading/writing the committed resources, can't commit. * * @throws org.multiverse.api.exceptions.ReadWriteConflict * if the transaction can't be prepared. * @throws org.multiverse.api.exceptions.DeadTxnException * if the transaction already is committed or aborted. */ void prepare(); /** * Aborts this Txn. This means that the changes made in this transaction are not committed. It depends on * the implementation if this operation is simple (ditching objects for example), or if changes need to be rolled * back. If an exception is thrown while executing the abort, the transaction is still aborted. And example of * such a situation is a pre-abort task that fails. So the transaction always is aborted (unless it is committed). * *

If the Txn already is aborted, the call is ignored. * * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the Txn is not in the correct state for this operation. */ void abort(); /** * Retries the transaction. This call doesn't block, but if all goes well a {@link org.multiverse.api.exceptions.RetryError} * is thrown which is caught by the {@link TxnExecutor}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if the transaction is not in a legal state for * this operation. * @throws org.multiverse.api.exceptions.ControlFlowError * */ void retry(); /** * Signals that the only possible outcome of the Txn is one that aborts. When the transaction prepares or * commits it checks if the transaction is marked as abort only. If so, it will automatically aborted and an * {@link org.multiverse.api.exceptions.AbortOnlyException} is thrown. * *

This method is not threadsafe, so can only be called by the thread that used the transaction. * * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not active. * @throws org.multiverse.api.exceptions.ControlFlowError * */ void setAbortOnly(); /** * Checks if this Txn is abort only (so will always fail when committing or preparing). * *

This method is not threadsafe, so can only be called by the thread that used the transaction. * * @return true if abort only, false otherwise. * @throws org.multiverse.api.exceptions.DeadTxnException * if the transaction is committed/aborted. */ boolean isAbortOnly(); /** * Registers a TxnListener. Every time a transaction is retried, the listener needs to * be registered again if you want the task to be executed again. If you want a permanent listener, have * a look at the {@link TxnFactoryBuilder#addPermanentListener(org.multiverse.api.lifecycle.TxnListener)}. * *

If a TxnListener is added more than once, it is executed more than once. No checks * are made. The permanent listeners are executed in the order they are added. * *

If a TxnListener throws an Error/RuntimeException and the transaction still is alive, * it is aborted. For compensating and deferred actions this is not an issue, but for the PrePrepare state * or the state it could since the transaction is aborted. * * @param listener the listener to add. * @throws NullPointerException if listener is null. If the transaction is still alive, it is aborted. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not in the correct * state (e.g. aborted or committed). * @throws org.multiverse.api.exceptions.ControlFlowError * */ void register(TxnListener listener); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TxnConfig.java000066400000000000000000000154051174000617100321360ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.api.lifecycle.TxnListener; import java.util.List; /** * Contains the transaction configuration used by a {@link Txn}. In the beginning this was all * placed in the Txn, adding a lot of 'informational' methods to the transaction and therefor * complicating its usage. So all the configurational properties of the transaction are contained in * this structure. *

* The same TxnConfig is used for multiple transactions. Each TxnFactory has just a * single configuration and all Transactions created by that TxnFactory, share that configuration. * * @author Peter Veentjer. */ public interface TxnConfig { /** * Returns the Stm that creates transactions based on this configuration. * * @return the stm. */ Stm getStm(); /** * Checks if the {@link org.multiverse.api.exceptions.ControlFlowError} is cached or a new one is used. *

* Exception creation can be very expensive, so by default the ControlFlowError is reused, but this can * be problematic when debugging. * * @return true if the ControlFlowError is reused. * @see TxnFactoryBuilder#setControlFlowErrorsReused(boolean) */ boolean isControlFlowErrorsReused(); /** * Gets the IsolationLevel used. With the IsolationLevel you have control on the isolated behavior between * transactions. * * @return the IsolationLevel. * @see TxnFactoryBuilder#setIsolationLevel(IsolationLevel) */ IsolationLevel getIsolationLevel(); /** * Returns the total timeout in nanoseconds. Long.MAX_VALUE indicates that there is no * timeout. * * @return the total remaining timeout. * @see TxnFactoryBuilder#setTimeoutNs(long) */ long getTimeoutNs(); /** * Returns the PropagationLevel used. With the PropagationLevel you have control on how the transaction * is dealing with nesting of transactions. * * @return the PropagationLevel used. * @see TxnFactoryBuilder#setPropagationLevel(PropagationLevel) */ PropagationLevel getPropagationLevel(); /** * Returns the TraceLevel. With the TraceLevel you have control on the logging. * * @return the TraceLevel. * @see TxnFactoryBuilder#setTraceLevel(TraceLevel) */ TraceLevel getTraceLevel(); /** * Returns the BackoffPolicy used by the Stm when a transaction conflicts with another transaction. * * @return the BackoffPolicy used. * @see TxnFactoryBuilder#setBackoffPolicy(BackoffPolicy) */ BackoffPolicy getBackoffPolicy(); /** * Checks if speculative configuration is enabled. When enabled the STM is able to select better * performing/scalable implementations at the cost of some * {@link org.multiverse.api.exceptions.SpeculativeConfigurationError}. This will be caught by the * TxnExecutor and the transaction will be retried, so in most cases this is not something to worry * about, but it can be confusing in the beginning because of unexpected failures in the execution * of transactions. * * @return true if speculative configuration is enabled. * @see TxnFactoryBuilder#setSpeculative(boolean) */ boolean isSpeculative(); /** * Returns the family name of this Txn. Every transaction in principle should have a family name. This * information can be used for debugging/logging purposes but also other techniques that rely to know something * about similar types of transactions like profiling. * * @return the familyName. The returned value can be null. * @see TxnFactoryBuilder#setFamilyName(String) */ String getFamilyName(); /** * Checks if this Txn is readonly. With a readonly transaction you can prevent any updates or * new objects being created. * * @return true if readonly, false otherwise. * @see TxnFactoryBuilder#setReadonly(boolean) */ boolean isReadonly(); /** * Returns the maximum number of times the transaction is allowed to spin on a read to become * readable (perhaps it is locked). * * @return the maximum number of spins * @see TxnFactoryBuilder#setSpinCount(int) */ int getSpinCount(); /** * Gets the current LockMode for all reads. * * @return the current LockMode for all reads. * @see TxnFactoryBuilder#setReadLockMode(LockMode) */ LockMode getReadLockMode(); /** * Gets the current LockMode for all writes. * * @return the current LockMode for all writes. * @see TxnFactoryBuilder#setWriteLockMode(LockMode) */ LockMode getWriteLockMode(); /** * Checks if dirty check is enabled on writes when a transaction commits. Turning of saves time, * but forces writes that cause no change. * * @return true of dirty check is enabled. * @see TxnFactoryBuilder#setDirtyCheckEnabled(boolean) */ boolean isDirtyCheckEnabled(); /** * Checks if this transaction does automatic read tracking. Read tracking is needed for blocking transactions, * but also for writeskew detection. Disadvantage of read tracking is that it is more expensive because * the reads not to be registered on some datastructure so that they are tracked. * * @return true if the transaction does automatic read tracking, false otherwise. * @see TxnFactoryBuilder#setReadTrackingEnabled(boolean) */ boolean isReadTrackingEnabled(); /** * If an explicit retry (so a blocking transaction) is allowed. With this property one can prevent * that a Txn is able to block waiting for some change. * * @return true if explicit retry is allowed, false otherwise. * @see TxnFactoryBuilder#setBlockingAllowed(boolean) */ boolean isBlockingAllowed(); /** * Checks if the Txn can be interrupted if it is blocking. * * @return true if the Txn can be interrupted if it is blocking, false otherwise. * @see TxnFactoryBuilder#setInterruptible(boolean) */ boolean isInterruptible(); /** * Returns an unmodifiable list containing all permanent TxnListener. * * @return unmodifiable List containing all permanent TxnListeners. * @see TxnFactoryBuilder#addPermanentListener(org.multiverse.api.lifecycle.TxnListener) */ List getPermanentListeners(); /** * Returns the maximum number of times this Txn be retried before failing. The returned value will * always be equal or larger than 0. If the value is getAndSet high and you are encountering a lot of * TooManyRetryExceptions it could be that the objects are just not concurrent enough. * * @return the maxRetries. * @see TxnFactoryBuilder#setMaxRetries(int) */ int getMaxRetries(); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TxnExecutor.java000066400000000000000000000273501174000617100325310ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.*; import org.multiverse.api.callables.*; import java.util.concurrent.Callable; /** * An TxnExecutor is responsible for executing an atomic callable. It is created by the {@link TxnFactoryBuilder} * and this gives the {@link Stm} the opportunity to return different implementations based on the * {@link TxnFactory} configuration. And it also gives the opportunity to provide Stm specific transaction handling * mechanism. In the Multiverse 0.6 design and before, a single TransactionTemplate implementation was used that should * be used by all Stm's, but that design is limiting. * *

Another useful features of this design is that for certain primitives it doesn't require any form of boxing. * It also provides an execute for a transactional Callables which doesn't force a developer to return something when * nothing needs to be returned. * *

Transactional Callables

* *

The TxnCallable is the functionality that needs to be executed isolated, consistent and atomically. There * are different tastes of TxnCallables but essentially the only difference is the return type. There are primitive closures * that prevent unwanted autoboxing and there also is a {@link org.multiverse.api.callables.TxnVoidCallable} that prevents * returning a value if none is needed. And last but not least there also is the general purpose * {@link org.multiverse.api.callables.TxnCallable} that returns an Object reference. * *

Automatic retries

* *

If a transaction encounters a {@link org.multiverse.api.exceptions.ReadWriteConflict} or a * { @link org.multiverse.api.exceptions.SpeculativeConfigurationError} it will automatically retry the * the TxnCallable until either the next execution completes or the maximum number of retries has been reached. * To prevent contention, also a {@link BackoffPolicy} is used, to prevent transactions from causing more contention * if there already is contention. For configuring the maximum number of retries, see the {@link TxnFactoryBuilder#setMaxRetries} * and for configuring the BackoffPolicy, see {@link TxnFactoryBuilder#setBackoffPolicy}. * *

It is very important to realize that automatically retrying a transaction on a conflict is something else than the * {@link Txn#retry}. The latter is really a blocking operation that only retries when there is a reason to retry. * *

Configuration

* *

The {@link TxnExecutor} can be configured through the {@link TxnFactoryBuilder}. So see that for more details since * there are tons of settings to choose from. * *

Thread-safety

* *

TxnExecutors are threadsafe. The TxnExecutor is designed to be shared between threads. * *

Reuse

* *

TxnExecutor can be expensive to create and should be reused. Creating an TxnExecutor can lead to a lot of objects being * created and not reusing them leads to a lot of object waste (so put a lot of pressure on the garbage collector). * *

It is best to create the TxnExecutor in the beginning and store it in a (static) field and reuse it. It is very * unlikely that an TxnExecutor is going to be a contention point itself since in almost all cases only volatile reads are * required and for the rest it will be mostly immutable. * *

This is even more important when speculative transactions are used because speculative transactions learn on the * TxnExecutor level. So if the TxnExecutor is not reused, the speculative mechanism will not have full effect. * *

execute vs executeChecked

* *

The TxnExecutor provides two different types of execute methods: *

    *
  1. execute: it will automatically wrap the checked exception that can be thrown from an TxnCallable in a * {@link org.multiverse.api.exceptions.InvisibleCheckedException}. Unchecked exceptions are let through as is. *
  2. *
  3. execute checked: it will not do anything with thrown checked of unchecked exceptions and lets them through *
  4. *
* If an exception happens inside an TxnCallable, the Txn will be always aborted (unless it is caught by the logic * inside the TxnCallable). Catching the exceptions inside the callable should be done with care since an exception could * indicate that the system has entered an invalid state. * *

In the future also a rollback-for functionality will be added to let a transaction commit, even though certain types * of exceptions have occurred. This is similar with the Spring framework where this can be configured through the * 9.5.3: Rolling back * *

Atomic operation composition/nesting

* *

Using traditional concurrency control, composing locking operations is extremely hard because it is very likely that * it is impossible without knowing implementation details of the structure, or because of deadlocks. With Stm transactional * operations can be composed and controlling how the system should react on existing or missing transactions can be controlled * through the {@link TxnFactoryBuilder#setPropagationLevel} where the {@link PropagationLevel#Requires} is the default. * *

Normally the system uses a flat-nesting approach, so only the outermost commit is going to lead to a commit. But if a commit * is done before the outer most TxnExecutor completes, that commit is leading. * *

If the transaction is committed (or aborted) manually, operations on the transaction will fail with a * {@link org.multiverse.api.exceptions.IllegalTxnStateException} exception. So in most cases you want to let the TxnExecutor * be in charge of committing/aborting. If also allows for a correct flattening of nested transactions. If a transaction should * not commit, but you don't want to disrupt the code, the {@link Txn#setAbortOnly} can be called, to make sure that the * transaction is not going to commit (or prepare) successfully. * *

The configuration of the outer most TxnExecutor is leading. So if the outer TxnExecutor is not readonly and the inner is, * the transaction will not be readonly. If this becomes an issue (e.g. for security) it can be implemented that some form of * runtime verification is done to prevent this behavior. * * @author Peter Veentjer. */ public interface TxnExecutor extends MultiverseConstants{ /** * Returns the {@link TxnFactory} that is used by this TxnExecutor to create transactions used to execute * transactional closures. * * @return the TxnFactory used by this TxnExecutor. */ TxnFactory getTxnFactory(); /** * Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ E execute(TxnCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ E executeChecked(TxnCallable callable)throws Exception; /** * Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ int execute(TxnIntCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ int executeChecked(TxnIntCallable callable)throws Exception; /** * Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ long execute(TxnLongCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ long executeChecked(TxnLongCallable callable)throws Exception; /** * Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ double execute(TxnDoubleCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ double executeChecked(TxnDoubleCallable callable)throws Exception; /** * Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ boolean execute(TxnBooleanCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ boolean executeChecked(TxnBooleanCallable callable)throws Exception; /** * Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param callable the callable to execute. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ void execute(TxnVoidCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ void executeChecked(TxnVoidCallable callable)throws Exception; } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TxnExecutor.vm000066400000000000000000000172251174000617100322320ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.*; import org.multiverse.api.callables.*; import java.util.concurrent.Callable; /** * An TxnExecutor is responsible for executing an atomic callable. It is created by the {@link TxnFactoryBuilder} * and this gives the {@link Stm} the opportunity to return different implementations based on the * {@link TxnFactory} configuration. And it also gives the opportunity to provide Stm specific transaction handling * mechanism. In the Multiverse 0.6 design and before, a single TransactionTemplate implementation was used that should * be used by all Stm's, but that design is limiting. * *

Another useful features of this design is that for certain primitives it doesn't require any form of boxing. * It also provides an execute for a transactional Callables which doesn't force a developer to return something when * nothing needs to be returned. * *

Transactional Callables

* *

The TxnCallable is the functionality that needs to be executed isolated, consistent and atomically. There * are different tastes of TxnCallables but essentially the only difference is the return type. There are primitive closures * that prevent unwanted autoboxing and there also is a {@link org.multiverse.api.callables.TxnVoidCallable} that prevents * returning a value if none is needed. And last but not least there also is the general purpose * {@link org.multiverse.api.callables.TxnCallable} that returns an Object reference. * *

Automatic retries

* *

If a transaction encounters a {@link org.multiverse.api.exceptions.ReadWriteConflict} or a * { @link org.multiverse.api.exceptions.SpeculativeConfigurationError} it will automatically retry the * the TxnCallable until either the next execution completes or the maximum number of retries has been reached. * To prevent contention, also a {@link BackoffPolicy} is used, to prevent transactions from causing more contention * if there already is contention. For configuring the maximum number of retries, see the {@link TxnFactoryBuilder#setMaxRetries} * and for configuring the BackoffPolicy, see {@link TxnFactoryBuilder#setBackoffPolicy}. * *

It is very important to realize that automatically retrying a transaction on a conflict is something else than the * {@link Txn#retry}. The latter is really a blocking operation that only retries when there is a reason to retry. * *

Configuration

* *

The {@link TxnExecutor} can be configured through the {@link TxnFactoryBuilder}. So see that for more details since * there are tons of settings to choose from. * *

Thread-safety

* *

TxnExecutors are threadsafe. The TxnExecutor is designed to be shared between threads. * *

Reuse

* *

TxnExecutor can be expensive to create and should be reused. Creating an TxnExecutor can lead to a lot of objects being * created and not reusing them leads to a lot of object waste (so put a lot of pressure on the garbage collector). * *

It is best to create the TxnExecutor in the beginning and store it in a (static) field and reuse it. It is very * unlikely that an TxnExecutor is going to be a contention point itself since in almost all cases only volatile reads are * required and for the rest it will be mostly immutable. * *

This is even more important when speculative transactions are used because speculative transactions learn on the * TxnExecutor level. So if the TxnExecutor is not reused, the speculative mechanism will not have full effect. * *

execute vs executeChecked

* *

The TxnExecutor provides two different types of execute methods: *

    *
  1. execute: it will automatically wrap the checked exception that can be thrown from an TxnCallable in a * {@link org.multiverse.api.exceptions.InvisibleCheckedException}. Unchecked exceptions are let through as is. *
  2. *
  3. execute checked: it will not do anything with thrown checked of unchecked exceptions and lets them through *
  4. *
* If an exception happens inside an TxnCallable, the Txn will be always aborted (unless it is caught by the logic * inside the TxnCallable). Catching the exceptions inside the callable should be done with care since an exception could * indicate that the system has entered an invalid state. * *

In the future also a rollback-for functionality will be added to let a transaction commit, even though certain types * of exceptions have occurred. This is similar with the Spring framework where this can be configured through the * 9.5.3: Rolling back * *

Atomic operation composition/nesting

* *

Using traditional concurrency control, composing locking operations is extremely hard because it is very likely that * it is impossible without knowing implementation details of the structure, or because of deadlocks. With Stm transactional * operations can be composed and controlling how the system should react on existing or missing transactions can be controlled * through the {@link TxnFactoryBuilder#setPropagationLevel} where the {@link PropagationLevel#Requires} is the default. * *

Normally the system uses a flat-nesting approach, so only the outermost commit is going to lead to a commit. But if a commit * is done before the outer most TxnExecutor completes, that commit is leading. * *

If the transaction is committed (or aborted) manually, operations on the transaction will fail with a * {@link org.multiverse.api.exceptions.IllegalTxnStateException} exception. So in most cases you want to let the TxnExecutor * be in charge of committing/aborting. If also allows for a correct flattening of nested transactions. If a transaction should * not commit, but you don't want to disrupt the code, the {@link Txn#setAbortOnly} can be called, to make sure that the * transaction is not going to commit (or prepare) successfully. * *

The configuration of the outer most TxnExecutor is leading. So if the outer TxnExecutor is not readonly and the inner is, * the transaction will not be readonly. If this becomes an issue (e.g. for security) it can be implemented that some form of * runtime verification is done to prevent this behavior. * * @author Peter Veentjer. */ public interface TxnExecutor extends MultiverseConstants{ /** * Returns the {@link TxnFactory} that is used by this TxnExecutor to create transactions used to execute * transactional closures. * * @return the TxnFactory used by this TxnExecutor. */ TxnFactory getTxnFactory(); #foreach($callable in $callables) /** * Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception * is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the * getCause method. * * @param callable the callable to execute. #if(${callable.type} ne 'void') * @return the result of the execution. #end * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ ${callable.typeParameter} ${callable.type} execute(${callable.name}${callable.typeParameter} callable); /** * Executes the callable. * * @param callable the callable to execute. #if(${callable.type} ne 'void') * @return the result of the execution. #end * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ ${callable.typeParameter} ${callable.type} executeChecked(${callable.name}${callable.typeParameter} callable)throws Exception; #end } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TxnFactory.java000077500000000000000000000016261174000617100323430ustar00rootroot00000000000000package org.multiverse.api; /** * A Factory responsible for creating a {@link Txn}. To set properties on Transactions you need to look * at the {@link TxnFactoryBuilder}. It could be that over time different types of transactions are returned, * e.g. because the speculative behavior is enabled. * *

Thread safety

* *

A TxnFactory is thread-safe and it is expected to be shared between threads (doesn't impose it, but it * is the most logical use case). It also is expected to be re-used instead of recreated. * * @author Peter Veentjer. * @see TxnFactoryBuilder */ public interface TxnFactory { /** * Gets the {@link TxnConfig} used by this TxnFactory. * * @return the TxnConfig. */ TxnConfig getConfig(); TxnFactoryBuilder getTxnFactoryBuilder(); /** * Creates a new {@link Txn}. * * @return the created Txn. */ Txn newTxn(); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TxnFactoryBuilder.java000077500000000000000000000312161174000617100336500ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.api.lifecycle.TxnListener; /** * A Builder for creating a {@link TxnFactory} and {@link TxnExecutor}. This builder provides full control * on transaction settings. * *

Since the {@link Txn} and {@link TxnExecutor} are very closely integrated, both of them are created * by this TxnFactoryBuilder. * *

Instances of this class are considered immutable, so when you call one of the modifying methods, make sure * that you use the resulting TxnFactoryBuilder. Normally with the builder implementation the same * instance is returned. In this case this isn't true because a new instance is returned every time. * * @author Peter Veentjer * @see TxnFactory * @see TxnConfig */ public interface TxnFactoryBuilder { /** * Returns the {@link TxnConfig} used by this TxnFactoryBuilder. * * @return the used TxnConfig. */ TxnConfig getConfig(); /** * Sets if the {@link org.multiverse.api.exceptions.ControlFlowError} is reused. Normally you don't want to reuse them * because they can be expensive to create (especially the stacktrace) and they could be created very often. But for * debugging purposes it can be quite annoying because you want to see the stacktrace. * * @param reused true if ControlFlowErrors should be reused. * @return the updated TxnFactoryBuilder. * @see TxnConfig#isControlFlowErrorsReused() */ TxnFactoryBuilder setControlFlowErrorsReused(boolean reused); /** * Sets the {@link Txn} familyname. If an {@link TxnExecutor} is used inside a method, a useful familyname could * be the full name of the class and the method. *

* The transaction familyName is useful debugging purposes, but has not other meaning. * * @param familyName the familyName of the transaction. * @return the updated TxnFactoryBuilder * @throws NullPointerException if familyName is null. * @see TxnConfig#getFamilyName() */ TxnFactoryBuilder setFamilyName(String familyName); /** * Sets the {@link org.multiverse.api.PropagationLevel} used. With the PropagationLevel you have control * on how the transaction deals with transaction nesting. The default is {@link PropagationLevel#Requires} * which automatically starts a transaction is one is missing, or lifts on a transaction if available. * * @param propagationLevel the new PropagationLevel * @return the updated TxnFactoryBuilder * @throws NullPointerException if propagationLevel is null. * @see TxnConfig#getPropagationLevel() * @see PropagationLevel */ TxnFactoryBuilder setPropagationLevel(PropagationLevel propagationLevel); /** * Sets the {@link Txn} {@link LockMode} for all reads. If a LockMode is set higher than {@link LockMode#None}, this transaction * will locks all reads (and writes since a read is needed for a write) and the transaction automatically becomes * serialized. * * @param lockMode the LockMode to set. * @return the updated TxnFactoryBuilder. * @throws NullPointerException if lockMode is null. * @see TxnConfig#getReadLockMode() * @see LockMode */ TxnFactoryBuilder setReadLockMode(LockMode lockMode); /** * Sets the {@link Txn} {@link LockMode} for all writes. For a write, always a read needs to be done, so if the read LockMode is * *

Freshly constructed objects that are not committed, automatically are locked with {@link LockMode#Exclusive}. * *

If the write LockMode is set after the read LockMode and the write LockMode is lower than the read LockMode, * an {@code IllegalTxnFactoryException} will be thrown when a {@link TxnFactory} is created. * *

If the write LockMode is set before the read LockMode and the write LockMode is lower than the read LockMode, * the write LockMode automatically is upgraded to that of the read LockMode. This makes setting the readLock * mode less of a nuisance. * * @param lockMode the LockMode to set. * @return the updated TxnFactoryBuilder. * @throws NullPointerException if lockMode is null. * @see TxnConfig#getWriteLockMode() * @see LockMode */ TxnFactoryBuilder setWriteLockMode(LockMode lockMode); /** * Adds a permanent {@link Txn} {@link org.multiverse.api.lifecycle.TxnListener}. All permanent listeners are always executed after all normal * listeners are executed. If the same listener is added multiple times, it will be executed multiple times. * *

This method is very useful for integrating Multiverse in other JVM based environments because with this * approach you have a callback when transaction aborts/commit and can add your own logic. See the * {@link org.multiverse.api.lifecycle.TxnListener} for more information about normal vs permanent listeners. * * @param listener the permanent listener to add. * @return the updated TxnFactoryBuilder. * @throws NullPointerException if listener is null. * @see TxnConfig#getPermanentListeners() */ TxnFactoryBuilder addPermanentListener(TxnListener listener); /** * Sets the {@link Txn} {@link TraceLevel}. With tracing it is possible to see what is happening inside a transaction. * * @param traceLevel the new traceLevel. * @return the updated TxnFactoryBuilder. * @throws NullPointerException if traceLevel is null. * @see TxnConfig#getTraceLevel() * @see TraceLevel */ TxnFactoryBuilder setTraceLevel(TraceLevel traceLevel); /** * Sets the timeout (the maximum time a {@link Txn} is allowed to block. Long.MAX_VALUE indicates that an * unbound timeout should be used. * * @param timeoutNs the timeout specified in nano seconds * @return the updated TxnFactoryBuilder * @see TxnConfig#getTimeoutNs() * @see Txn#getRemainingTimeoutNs() */ TxnFactoryBuilder setTimeoutNs(long timeoutNs); /** * Sets if the {@link Txn} can be interrupted while doing blocking operations. * * @param interruptible if the transaction can be interrupted while doing blocking operations. * @return the updated TxnFactoryBuilder * @see TxnConfig#isInterruptible() */ TxnFactoryBuilder setInterruptible(boolean interruptible); /** * Sets the {@link Txn} {@link BackoffPolicy}. Policy is used to backoff when a transaction conflicts with another {@link Txn}. * See the {@link BackoffPolicy} for more information. * * @param backoffPolicy the backoff policy to use. * @return the updated TxnFactoryBuilder * @throws NullPointerException if backoffPolicy is null. * @see TxnConfig#getBackoffPolicy() */ TxnFactoryBuilder setBackoffPolicy(BackoffPolicy backoffPolicy); /** * Sets if the {@link Txn} dirty check is enabled. Dirty check is that something only needs to be written, * if there really is a change (else it will be interpreted as a read). If it is disabled, it will always write, and * this could prevent the aba isolation anomaly, but causes more conflicts so more contention. In most cases enabling * it is the best option. * * @param dirtyCheckEnabled true if dirty check should be executed, false otherwise. * @return the updated TxnFactoryBuilder. * @see TxnConfig#isDirtyCheckEnabled() */ TxnFactoryBuilder setDirtyCheckEnabled(boolean dirtyCheckEnabled); /** * Sets the maximum number of spins that are allowed when a {@link Txn} can't be read/written/locked * because it is locked by another transaction. * *

Setting the value to a very high value, could lead to more an increased chance of a live locking. * * @param spinCount the maximum number of spins * @return the updated TxnFactoryBuilder. * @throws IllegalArgumentException if spinCount smaller than 0. * @see TxnConfig#getSpinCount() */ TxnFactoryBuilder setSpinCount(int spinCount); /** * Sets the readonly property on a {@link Txn}. If a transaction is configured as readonly, no write operations * (also no construction of new transactional objects making use of that transaction) is allowed * * @param readonly true if the transaction should be readonly, false otherwise. * @return the updated TxnFactoryBuilder * @see TxnConfig#isReadonly() */ TxnFactoryBuilder setReadonly(boolean readonly); /** * Sets if the {@link Txn} should automatically track all reads that have been done. This is needed for blocking * operations, but also for other features like writeskew detection. * *

Tracking reads puts more pressure on the transaction since it needs to store all reads, but it reduces the chance * of read conflicts, since once read from main memory, it can be retrieved from the transaction. * * The transaction is free to track reads even though this property is disabled. * * @param enabled true if read tracking enabled, false otherwise. * @return the updated TxnFactoryBuilder * @see TxnConfig#isReadTrackingEnabled() */ TxnFactoryBuilder setReadTrackingEnabled(boolean enabled); /** * With the speculative configuration enabled, the {@link Stm} is allowed to determine optimal settings for * a {@link Txn}. * *

Some behavior like readonly or the need for tracking reads can be determined runtime. The system can start with * a readonly non readtracking transaction and upgrade to an update or a read tracking once a write or retry * happens. * *

It depends on the {@link Stm} implementation on which properties it is going to speculate. * *

Enabling it can cause a few unexpected 'retries' of transactions, but it can seriously improve performance. * * @param speculative indicates if speculative configuration should be enabled. * @return the updated TxnFactoryBuilder * @see TxnConfig#isSpeculative() */ TxnFactoryBuilder setSpeculative(boolean speculative); /** * Sets the the maximum count a {@link Txn} can be retried. The default is 1000. Setting it to a very low value * could mean that a transaction can't complete. Setting it to a very high value could lead to live-locking. * *

If the speculative configuration mechanism is enabled ({@link #setSpeculative(boolean)}), a few retries * are done in the beginning to figure out the best settings. * * @param maxRetries the maximum number of times a transaction can be tried. * @return the updated TxnFactoryBuilder * @throws IllegalArgumentException if maxRetries smaller than 0. * @see TxnConfig#getMaxRetries() */ TxnFactoryBuilder setMaxRetries(int maxRetries); /** * Sets the {@link IsolationLevel} on the {@link Txn}. * *

The {@link Txn} is free to upgraded to a higher {@link IsolationLevel}. This is essentially the same * behavior you get when Oracle is used, where a read uncommitted is upgraded to a read committed and a repeatable * read is upgraded to the Oracle version of serialized (so with the writeskew problem still there). * * @param isolationLevel the new IsolationLevel * @return the updated TxnFactoryBuilder * @throws NullPointerException if isolationLevel is null. * @see TxnConfig#getIsolationLevel() * @see IsolationLevel */ TxnFactoryBuilder setIsolationLevel(IsolationLevel isolationLevel); /** * Sets if the {@link Txn} is allowed to do an explicit retry (needed for a blocking operation). One use case * for disallowing it, it when the transaction is used inside an actor, and you don't want that inside the logic * executed by the agent a blocking operations is done (e.g. taking an item of a blocking queue). * * @param blockingAllowed true if explicit retry is allowed, false otherwise. * @return the updated TxnFactoryBuilder */ TxnFactoryBuilder setBlockingAllowed(boolean blockingAllowed); /** * Builds a new {@link TxnFactory}. * * @return the build TxnFactory. * @throws org.multiverse.api.exceptions.IllegalTxnFactoryException * if the TxnFactory could not be build * because the configuration was not correct. */ TxnFactory newTransactionFactory(); /** * Builds a new {@link TxnExecutor} optimized for executing transactions created by this TxnFactoryBuilder. * * @return the created TxnExecutor. * @throws org.multiverse.api.exceptions.IllegalTxnFactoryException * if the TxnFactory could not be build * because the configuration was not correct. */ TxnExecutor newTxnExecutor(); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TxnObject.java000066400000000000000000000122461174000617100321370ustar00rootroot00000000000000package org.multiverse.api; /** * The interface each transactional object needs to implement. * *

A TxnObject is an object where all reads/writes are managed through a {@link Txn} (unless an atomic * method is used). * *

Each TxnObject belongs to 1 {@link Stm} instance. * *

All methods are threadsafe. * * @author Peter Veentjer. */ public interface TxnObject { /** * Returns the {@link Stm} this TxnObject is part of. Once a TxnObject is created using some * Stm, it will never become part of another Stm. * * @return the Stm this TxnObject is part of. Returned value will never be null. */ Stm getStm(); /** * Gets the {@link Lock} that belongs to this TxnObject. This call doesn't cause any locking, it * only provides access to the object that is able to lock. The returned value will never be null. * *

This call also doesn't rely on a {@link Txn}. * * @return the Lock * @throws UnsupportedOperationException if this operation is not supported. */ Lock getLock(); /** * Returns the current version of the transactional object. Each time an update happens, the value is increased. It depends * on the stm implementation if the version over references has any meaning. With the MVCC there is a relation, but with the * SkySTM isn't. * *

This method doesn't look at the {@link TxnThreadLocal}. * * @return the current version. */ long getVersion(); /** * Does an ensure. What is means is that at the end of the transaction (so deferred), the transaction checks if no other * transaction has made an update, if this TxnObject only is read. The ensure is a way to prevent to writeskew * problem on the ref level (see {@link IsolationLevel} for more detail about the writeskew problem} * *

This can safely be called on an TxnObject that already is locked, although it doesn't provide much value * since with a locked TxnObject, since the writeskew problem can't occur anymore because it can't be changed. * *

Unlike the {@link Lock#acquire(LockMode)} which is pessimistic, ensure is optimistic. This means that a conflict * can be detected once the transaction commits. * *

This method has no effect if the {@link Txn} is readonly, because a writeskew is not possible with a * readonly transaction. * *

This call lifts on the {@link Txn} stored in the {@link TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * * @throws org.multiverse.api.exceptions.ControlFlowError * * @see #ensure(Txn) */ void ensure(); /** * Does an ensure. What is means is that at the end of the transaction (so deferred), the transaction checks if no other * transaction has made an update, if this TxnObject only is read. The ensure is a way to prevent to writeskew * problem on the ref level (see {@link IsolationLevel} for more detail about the writeskew problem} * *

This can safely be called on an TxnObject that already is locked, although it doesn't provide much value * since with a locked TxnObject, since the writeskew problem can't occur anymore because it can't be changed. * *

Unlike the {@link Lock#acquire(LockMode)} which is pessimistic, ensure is optimistic. This means that a conflict * can be detected once the transaction commits. * *

This method has no effect if the {@link Txn} is readonly, because a writeskew is not possible with a * readonly transaction. * * @param self the Txn this call lifts on. * @throws NullPointerException if self is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * * @throws org.multiverse.api.exceptions.ControlFlowError * * @see #ensure() */ void ensure(Txn self); /** * Returns a debug representation of the TxnObject. The data used doesn't have to be consistent, * it is a best effort. This method doesn't rely on a running transaction. * * @return the debug representation of the TxnObject. */ String toDebugString(); /** * Returns a String representation of the Object using the {@link Txn} on the {@link TxnThreadLocal}. * * @return the toString representation * @throws org.multiverse.api.exceptions.TxnExecutionException * * @throws org.multiverse.api.exceptions.ControlFlowError * */ @Override String toString(); /** * Returns a String representation of the object using the provided {@link Txn}. * * @param txn the Txn used. * @return the String representation of the object. * @throws NullPointerException if tx is null. * @throws org.multiverse.api.exceptions.ControlFlowError * */ String toString(Txn txn); /** * Returns a String representation of the object using the provided transaction without looking * at a {@link TxnThreadLocal}. The outputted value doesn't need to be consistent from some point * in time, only a best effort is made. * * @return the String representation. */ String atomicToString(); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TxnStatus.java000077500000000000000000000015211174000617100322110ustar00rootroot00000000000000package org.multiverse.api; /** * An enumeration of all possible states a {@link Txn} can have. * * @author Peter Veentjer */ public enum TxnStatus { /** * When a Txn is running. */ Active(true), /** * When the Txn has been checked for conflicts and all resources have been claimed to make sure * that a commit is going to succeed. */ Prepared(true), /** * When a Txn failed to commit. */ Aborted(false), /** * When a Txn successfully committed. */ Committed(false); private final boolean alive; TxnStatus(boolean alive) { this.alive = alive; } /** * Checks if the Txn still is active/prepared. * * @return true if the TxnStatus is active or prepared. */ public boolean isAlive() { return alive; } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/TxnThreadLocal.java000066400000000000000000000067321174000617100331160ustar00rootroot00000000000000package org.multiverse.api; import org.multiverse.api.exceptions.TxnMandatoryException; /** * A {@link ThreadLocal} that contains the current {@link Txn}. The {@link Stm} and the {@link Txn} * should not rely on threadlocals, they are only used for convenience to reduce the need to carry around a * Txn. * *

This TxnThreadLocal has an optimization that prevents accessing the threadlocal too many times. * The Container wraps the Txn, so if a Thread gets a reference to that container and holds it, it * can modify the current transaction with a direct field access instead of another threadlocal access. It should * be used with extreme care, because the Container should not leak to another thread. It is very useful for the * {@link TxnExecutor} for example because a get/getAndSet/clear needs to be called otherwise. * * @author Peter Veentjer. */ public final class TxnThreadLocal { public final static ThreadLocal threadlocal = new ThreadLocal() { protected Container initialValue() { return new Container(); } }; /** * Gets the threadlocal {@link Txn}. If no transaction is set, null is returned. * *

No checks are done on the state of the transaction (so it could be that an aborted or committed transaction is * returned). * * @return the threadlocal transaction. */ public static Txn getThreadLocalTxn() { return threadlocal.get().txn; } /** ThreadLocalTransaction * Gets the ThreadLocal container that stores the Txn. Use this with extreme care because * the Container should not leak to another thread. It is purely means as a performance optimization * to prevent repeated (expensive) threadlocal access, and replace it by a cheap field access. * * @return the Container. The returned value will never be null. */ public static Container getThreadLocalTxnContainer() { return threadlocal.get(); } /** * Gets the threadlocal {@link Txn} or throws a {@link org.multiverse.api.exceptions.TxnMandatoryException} if no transaction is found. * *

No checks are done on the state of the transaction (so it could be that an aborted or committed transaction is * returned). * * @return the threadlocal transaction. * @throws org.multiverse.api.exceptions.TxnMandatoryException * if no thread local transaction is found. */ public static Txn getRequiredThreadLocalTxn() { Txn txn = threadlocal.get().txn; if (txn == null) { throw new TxnMandatoryException("No transaction is found on the TxnThreadLocal"); } return txn; } /** * Clears the threadlocal transaction. * *

If a transaction is available, it isn't aborted or committed. */ public static void clearThreadLocalTxn() { threadlocal.get().txn = null; } /** * Sets the threadlocal transaction. The transaction is allowed to be null, effectively clearing the * current thread local transaction. * *

If a transaction is available, it isn't aborted or committed. * * @param txn the new thread local transaction. */ public static void setThreadLocalTxn(Txn txn) { threadlocal.get().txn = txn; } //we don't want any instances. private TxnThreadLocal() { } public static class Container { public Txn txn; public Object txPool; } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/blocking/000077500000000000000000000000001174000617100311575ustar00rootroot00000000000000DefaultRetryLatch.java000077500000000000000000000113641174000617100353410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/blockingpackage org.multiverse.api.blocking; import org.multiverse.api.exceptions.RetryInterruptedException; import static java.lang.String.format; /** * A Cheap {@link RetryLatch} implementation based on the intrinsic lock. * * @author Peter Veentjer */ @SuppressWarnings({"SynchronizeOnThis", "WaitOrAwaitWithoutTimeout"}) public final class DefaultRetryLatch implements RetryLatch { private volatile long era = Long.MIN_VALUE; private volatile boolean isOpen = false; @Override public void open(final long expectedEra) { if (isOpen || expectedEra != era) { return; } synchronized (this) { if (isOpen || expectedEra != era) { return; } isOpen = true; notifyAll(); } } @Override public void await(long expectedEra, String transactionFamilyName) { if (isOpen || expectedEra != era) { return; } try { synchronized (this) { while (!isOpen && era == expectedEra) { wait(); } } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); throw new RetryInterruptedException( format("[%s] Was interrupted while waiting on the retry", transactionFamilyName), ex); } } @Override public void awaitUninterruptible(final long expectedEra) { if (isOpen || expectedEra != era) { return; } boolean restoreInterrupt = false; synchronized (this) { while (!isOpen && era == expectedEra) { try { wait(); } catch (InterruptedException e) { restoreInterrupt = true; } } } if (restoreInterrupt) { Thread.currentThread().interrupt(); } } @Override public long awaitNanosUninterruptible(final long expectedEra, long nanosTimeout) { if (isOpen || expectedEra != era) { return nanosTimeout; } if (nanosTimeout <= 0) { return -1; } boolean restoreInterrupt = false; try { while (true) { long startNs = System.nanoTime(); try { synchronized (this) { while (!isOpen && expectedEra == era) { if (nanosTimeout <= 0) { return -1; } long ms = nanosTimeout / 1000000; int ns = (int) (nanosTimeout % 1000000); wait(ms, ns); nanosTimeout -= System.nanoTime() - startNs; } return nanosTimeout; } } catch (InterruptedException ex) { restoreInterrupt = true; nanosTimeout -= System.nanoTime() - startNs; } } } finally { if (restoreInterrupt) { Thread.currentThread().interrupt(); } } } @Override public long awaitNanos(final long expectedEra, long nanosTimeout, String transactionFamilyName) { if (isOpen || expectedEra != era) { return nanosTimeout; } if (nanosTimeout <= 0) { return -1; } try { synchronized (this) { while (!isOpen && expectedEra == era) { if (nanosTimeout <= 0) { return -1; } long ms = nanosTimeout / 1000000; int ns = (int) (nanosTimeout % 1000000); long startNs = System.nanoTime(); wait(ms, ns); nanosTimeout -= System.nanoTime() - startNs; } return nanosTimeout; } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); throw new RetryInterruptedException( format("[%s] Was interrupted while waiting on the retry", transactionFamilyName), ex); } } @Override public long getEra() { return era; } @Override public void reset() { synchronized (this) { if (!isOpen) { notifyAll(); } else { isOpen = false; } era++; } } @Override public boolean isOpen() { return isOpen; } @Override public String toString() { return format("DefaultRetryLatch(open=%s, era=%s)", isOpen, era); } } RetryLatch.java000077500000000000000000000076341174000617100340410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/blockingpackage org.multiverse.api.blocking; /** * A blockingAllowed structure that can be used to create blocking transactions. When a transaction blocks, a * 'listener' is added to each read transactional object. This listener is the Latch. Each transactional object * can have a set of listeners. *

* The Latch can safely be created once by a Txn and reused by the same Txn because it works based on * an listenerEra. So of opens happen with an older listener-era, the open is ignored. So even though the Latch could * be attached to an older ref that didn't get updated, but is updated eventually even though the latch is notified * by another ref, there is no problem. *

* By resetting it, the listenerEra-counter is incremented, so that call to open or await are ignored. * * @author Peter Veentjer. */ public interface RetryLatch { /** * Checks if the Latch is open. * * @return true if the Latch is open, false otherwise. */ boolean isOpen(); /** * Opens this latch only if the expectedEra is the same. If the expectedEra is not the same, the call is ignored. * If the Latch already is open, this call is also ignored. * * @param expectedEra the expected era. */ void open(long expectedEra); /** * Gets the current era. * * @return the current era. */ long getEra(); /** * Awaits for this latch to open. This call is not responsive to interrupts. * * @param expectedEra the expected era. If the era is different, the await always succeeds. */ void awaitUninterruptible(long expectedEra); /** * Awaits for this Latch to open. There are 3 possible ways for this methods to complete; *

    *
  1. the era doesn't match the expected era
  2. *
  3. the latch is opened while waiting
  4. *
  5. the latch is interrupted while waiting. When this happens the RetryInterruptedException * is thrown and the Thread.interrupt status is restored.
  6. *
* * @param expectedEra the expected era. * @param transactionFamilyName the name of the transaction (only needed for creating * a usable message in the RetryInterruptedException). * @throws org.multiverse.api.exceptions.RetryInterruptedException * */ void await(long expectedEra, String transactionFamilyName); /** * Awaits for this latch to open with a timeout. This call is not responsive to interrupts. *

* When the calling thread is interrupted, the Thread.interrupt status will not be eaten by * this method and safely be restored. * * @param expectedEra the expected era. * @param nanosTimeout the timeout in nanoseconds * @return the remaining timeout. A negative value indicates that the Latch is not opened in time. */ long awaitNanosUninterruptible(long expectedEra, long nanosTimeout); /** * Awaits for this latch to open with a timeout. This call is responsive to interrupts. *

* When the calling thread is interrupted, the Thread.interrupt status will not be eaten by * this method and safely be restored. * * @param expectedEra the expected era * @param nanosTimeout the timeout in nanoseconds. Can safely be called with a zero or negative timeout * @param transactionFamilyName the name of the transaction (only needed for creating * a usable message in the RetryInterruptedException). * @return the remaining timeout. A 0 or negative value indicates that the latch is not opened in time. * @throws org.multiverse.api.exceptions.RetryInterruptedException * */ long awaitNanos(long expectedEra, long nanosTimeout, String transactionFamilyName); /** * Prepares the Latch for pooling. All waiting threads will be notified and the era is increased. */ void reset(); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/callables/000077500000000000000000000000001174000617100313115ustar00rootroot00000000000000TxnBooleanCallable.java000066400000000000000000000015541174000617100355730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/callablespackage org.multiverse.api.callables; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; /** * A transactional callable contains the logic that needs to be executed transactionally and normally is executed by the * {@link TxnExecutor}. * * This transactional callable is optimized for retuning a primitive type: boolean. Using this TxnBooleanCallable instead of * the {@link TxnCallable} is that no object wrapper needs to be created and there is no reason to deal with a potential * null value. * * @author Peter Veentjer. */ public interface TxnBooleanCallable{ /** * Executes the callable. * * @param txn the Transaction. Depending on the txn {@link org.multiverse.api.PropagationLevel}, this could * be null. * @return the result of the execution. */ boolean call(Txn txn)throws Exception; } TxnCallable.java000066400000000000000000000012541174000617100342700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/callablespackage org.multiverse.api.callables; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; /** * A transactional callable contains the logic that needs to be executed transactionally and normally is executed by the * {@link TxnExecutor}. * * This transactional callable is optimized for returning an object reference. * * @author Peter Veentjer. */ public interface TxnCallable{ /** * Executes the callable. * * @param txn the Transaction. Depending on the txn {@link org.multiverse.api.PropagationLevel}, this could * be null. * @return the result of the execution. */ E call(Txn txn)throws Exception; } TxnCallable.vm000066400000000000000000000023711174000617100337720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/callablespackage org.multiverse.api.callables; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; /** * A transactional callable contains the logic that needs to be executed transactionally and normally is executed by the * {@link TxnExecutor}. * #if(${callable.type} eq 'E') * This transactional callable is optimized for returning an object reference. #elseif(${callable.type} ne 'void') * This transactional callable is optimized for retuning a primitive type: ${callable.type}. Using this ${callable.name} instead of * the {@link TxnCallable} is that no object wrapper needs to be created and there is no reason to deal with a potential * null value. #else * This transactional callable is optimized for returning void. Useful if no value needs to be returned. #end * * @author Peter Veentjer. */ public interface ${callable.name}${callable.typeParameter}{ /** * Executes the callable. * * @param txn the Transaction. Depending on the txn {@link org.multiverse.api.PropagationLevel}, this could * be null. #if(${callable.type} ne 'void') * @return the result of the execution. #else * @throws Exception if unable to compute a result #end */ ${callable.type} call(Txn txn)throws Exception; } TxnDoubleCallable.java000066400000000000000000000015501174000617100354220ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/callablespackage org.multiverse.api.callables; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; /** * A transactional callable contains the logic that needs to be executed transactionally and normally is executed by the * {@link TxnExecutor}. * * This transactional callable is optimized for retuning a primitive type: double. Using this TxnDoubleCallable instead of * the {@link TxnCallable} is that no object wrapper needs to be created and there is no reason to deal with a potential * null value. * * @author Peter Veentjer. */ public interface TxnDoubleCallable{ /** * Executes the callable. * * @param txn the Transaction. Depending on the txn {@link org.multiverse.api.PropagationLevel}, this could * be null. * @return the result of the execution. */ double call(Txn txn)throws Exception; } TxnIntCallable.java000066400000000000000000000015341174000617100347440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/callablespackage org.multiverse.api.callables; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; /** * A transactional callable contains the logic that needs to be executed transactionally and normally is executed by the * {@link TxnExecutor}. * * This transactional callable is optimized for retuning a primitive type: int. Using this TxnIntCallable instead of * the {@link TxnCallable} is that no object wrapper needs to be created and there is no reason to deal with a potential * null value. * * @author Peter Veentjer. */ public interface TxnIntCallable{ /** * Executes the callable. * * @param txn the Transaction. Depending on the txn {@link org.multiverse.api.PropagationLevel}, this could * be null. * @return the result of the execution. */ int call(Txn txn)throws Exception; } TxnLongCallable.java000066400000000000000000000015401174000617100351060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/callablespackage org.multiverse.api.callables; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; /** * A transactional callable contains the logic that needs to be executed transactionally and normally is executed by the * {@link TxnExecutor}. * * This transactional callable is optimized for retuning a primitive type: long. Using this TxnLongCallable instead of * the {@link TxnCallable} is that no object wrapper needs to be created and there is no reason to deal with a potential * null value. * * @author Peter Veentjer. */ public interface TxnLongCallable{ /** * Executes the callable. * * @param txn the Transaction. Depending on the txn {@link org.multiverse.api.PropagationLevel}, this could * be null. * @return the result of the execution. */ long call(Txn txn)throws Exception; } TxnVoidCallable.java000066400000000000000000000013251174000617100351110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/callablespackage org.multiverse.api.callables; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; /** * A transactional callable contains the logic that needs to be executed transactionally and normally is executed by the * {@link TxnExecutor}. * * This transactional callable is optimized for returning void. Useful if no value needs to be returned. * * @author Peter Veentjer. */ public interface TxnVoidCallable{ /** * Executes the callable. * * @param txn the Transaction. Depending on the txn {@link org.multiverse.api.PropagationLevel}, this could * be null. * @throws Exception if unable to compute a result */ void call(Txn txn)throws Exception; } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collections/000077500000000000000000000000001174000617100317055ustar00rootroot00000000000000TxnCollection.java000066400000000000000000000273341174000617100352670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collectionspackage org.multiverse.api.collections; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import java.util.Collection; /** * * @param * @author Peter Veentjer. */ public interface TxnCollection extends TxnIterable, Collection { /** * Returns the STM that manages this TxnCollection. Returned value will never be null. * * @return the STM that manages this TxnCollection. */ Stm getStm(); /** * Returns true if this collection contains no elements. * * @param txn the transaction used for this operation. * @return true if this collection contains no elements */ boolean isEmpty(Txn txn); /** * Returns the number of elements in this collection. If this collection * contains more than Integer.MAX_VALUE elements, returns * Integer.MAX_VALUE. * * @param txn the transaction used for this operation. * @return the number of elements in this collection */ int size(Txn txn); /** * Returns true if this collection contains the specified element. * More formally, returns true if and only if this collection * contains at least one element e such that * (o==null ? e==null : o.equals(e)). * * @param txn the transaction used for this operation. * @param o element whose presence in this collection is to be tested * @return true if this collection contains the specified * element * @throws ClassCastException if the type of the specified element * is incompatible with this collection (optional) * @throws NullPointerException if the specified element is null and this * collection does not permit null elements (optional) */ boolean contains(Txn txn, Object o); /** * Returns true if this collection contains all of the elements * in the specified collection. * * @param txn the transaction used for this operation. * @param c collection to be checked for containment in this collection * @return true if this collection contains all of the elements * in the specified collection * @throws ClassCastException if the types of one or more elements * in the specified collection are incompatible with this * collection (optional) * @throws NullPointerException if the specified collection contains one * or more null elements and this collection does not permit null * elements (optional), or if the specified collection is null * @see #contains(Object) */ boolean containsAll(Txn txn, Collection c); /** * Removes a single instance of the specified element from this * collection, if it is present (optional operation). More formally, * removes an element e such that * (o==null ? e==null : o.equals(e)), if * this collection contains one or more such elements. Returns * true if this collection contained the specified element (or * equivalently, if this collection changed as a result of the call). * * @param txn the transaction used for this operation. * @param o element to be removed from this collection, if present * @return true if an element was removed as a result of this call * @throws ClassCastException if the type of the specified element * is incompatible with this collection (optional) * @throws NullPointerException if the specified element is null and this * collection does not permit null elements (optional) * @throws UnsupportedOperationException if the remove operation * is not supported by this collection */ boolean remove(Txn txn, Object o); /** * Removes all of the elements from this collection (optional operation). * The collection will be empty after this method returns. * * @param txn the transaction used for this operation. * @throws UnsupportedOperationException if the clear operation * is not supported by this collection */ void clear(Txn txn); /** * Ensures that this collection contains the specified element (optional * operation). Returns true if this collection changed as a * result of the call. (Returns false if this collection does * not permit duplicates and already contains the specified element.)

*

* Collections that support this operation may place limitations on what * elements may be added to this collection. In particular, some * collections will refuse to add null elements, and others will * impose restrictions on the type of elements that may be added. * Collection classes should clearly specify in their documentation any * restrictions on what elements may be added.

*

* If a collection refuses to add a particular element for any reason * other than that it already contains the element, it must throw * an exception (rather than returning false). This preserves * the invariant that a collection always contains the specified element * after this call returns. * * @param txn the transaction used for this operation. * @param e element whose presence in this collection is to be ensured * @return true if this collection changed as a result of the * call * @throws UnsupportedOperationException if the add operation * is not supported by this collection * @throws ClassCastException if the class of the specified element * prevents it from being added to this collection * @throws NullPointerException if the specified element is null and this * collection does not permit null elements * @throws IllegalArgumentException if some property of the element * prevents it from being added to this collection * @throws IllegalStateException if the element cannot be added at this * time due to insertion restrictions */ boolean add(Txn txn, E e); /** * Adds all of the elements in the specified collection to this collection * (optional operation). The behavior of this operation is undefined if * the specified collection is modified while the operation is in progress. * (This implies that the behavior of this call is undefined if the * specified collection is this collection, and this collection is * nonempty.) * * @param txn the transaction used for this operation. * @param c collection containing elements to be added to this collection * @return true if this collection changed as a result of the call * @throws UnsupportedOperationException if the addAll operation * is not supported by this collection * @throws ClassCastException if the class of an element of the specified * collection prevents it from being added to this collection * @throws NullPointerException if the specified collection contains a * null element and this collection does not permit null elements, * or if the specified collection is null * @throws IllegalArgumentException if some property of an element of the * specified collection prevents it from being added to this * collection * @throws IllegalStateException if not all the elements can be added at * this time due to insertion restrictions * @see #add(Object) */ boolean addAll(Txn txn, Collection c); /** * Adds all of the elements in the specified collection to this collection * (optional operation). The behavior of this operation is undefined if * the specified collection is modified while the operation is in progress. * (This implies that the behavior of this call is undefined if the * specified collection is this collection, and this collection is * nonempty.) * * @param c collection containing elements to be added to this collection * @return true if this collection changed as a result of the call * @throws UnsupportedOperationException if the addAll operation * is not supported by this collection * @throws ClassCastException if the class of an element of the specified * collection prevents it from being added to this collection * @throws NullPointerException if the specified collection contains a * null element and this collection does not permit null elements, * or if the specified collection is null * @throws IllegalArgumentException if some property of an element of the * specified collection prevents it from being added to this * collection * @throws IllegalStateException if not all the elements can be added at * this time due to insertion restrictions * @see #add(Object) */ boolean addAll(TxnCollection c); /** * Adds all of the elements in the specified collection to this collection * (optional operation). The behavior of this operation is undefined if * the specified collection is modified while the operation is in progress. * (This implies that the behavior of this call is undefined if the * specified collection is this collection, and this collection is * nonempty.) * * @param c collection containing elements to be added to this collection * @return true if this collection changed as a result of the call * @throws UnsupportedOperationException if the addAll operation * is not supported by this collection * @throws ClassCastException if the class of an element of the specified * collection prevents it from being added to this collection * @throws NullPointerException if the specified collection contains a * null element and this collection does not permit null elements, * or if the specified collection is null * @throws IllegalArgumentException if some property of an element of the * specified collection prevents it from being added to this * collection * @throws IllegalStateException if not all the elements can be added at * this time due to insertion restrictions * @see #add(Object) */ boolean addAll(Txn txn, TxnCollection c); String toString(Txn txn); } TxnCollectionsFactory.java000066400000000000000000000011051174000617100367660ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collectionspackage org.multiverse.api.collections; import org.multiverse.api.Stm; /** * A factory responsible for creating Transactional collections. * * @author Peter Veentjer. */ public interface TxnCollectionsFactory { Stm getStm(); TxnStack newStack(); TxnStack newStack(int capacity); TxnQueue newQueue(); TxnQueue newQueue(int capacity); TxnDeque newDeque(); TxnDeque newDeque(int capacity); TxnSet newHashSet(); TxnMap newHashMap(); TxnList newLinkedList(); } TxnDeque.java000066400000000000000000000016641174000617100342350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collectionspackage org.multiverse.api.collections; import org.multiverse.api.Txn; import java.util.Deque; public interface TxnDeque extends TxnQueue, Deque { boolean offerFirst(Txn txn, E e); E pollLast(Txn txn); E pollFirst(Txn txn); E peekFirst(Txn txn); void putFirst(E item); void putFirst(Txn txn, E item); E takeFirst(); E takeFirst(Txn txn); boolean offerLast(Txn txn, E e); E peekLast(Txn txn); void putLast(E item); void putLast(Txn txn, E item); E takeLast(); E takeLast(Txn txn); void addFirst(Txn txn, E e); void addLast(Txn txn, E e); E removeFirst(Txn txn); E removeLast(Txn txn); E getFirst(Txn txn); E getLast(Txn txn); boolean removeFirstOccurrence(Txn txn, Object o); boolean removeLastOccurrence(Txn txn, Object o); void push(Txn txn, E e); E pop(Txn txn); TxnIterator descendingIterator(Txn txn); } TxnIterable.java000066400000000000000000000006551174000617100347200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collectionspackage org.multiverse.api.collections; import org.multiverse.api.Txn; /** * * @param * @author Peter Veentjer. */ public interface TxnIterable extends Iterable { /** * Returns an iterator over a set of elements of type T. * * @param txn the Txn used for this Operation. * @return an Iterator. */ TxnIterator iterator(Txn txn); @Override TxnIterator iterator(); } TxnIterator.java000066400000000000000000000033411174000617100347550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collectionspackage org.multiverse.api.collections; import org.multiverse.api.Txn; import java.util.Iterator; public interface TxnIterator extends Iterator { /** * Returns true if the iteration has more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @param txn Txn used for this operation * @return true if the iterator has more elements. */ boolean hasNext(Txn txn); /** * Returns the next element in the iteration. * * @param txn Txn used for this operation * @return the next element in the iteration. * @throws java.util.NoSuchElementException * iteration has no more elements. */ E next(Txn txn); /** * Removes from the underlying collection the last element returned by the * iterator (optional operation). This method can be called only once per * call to next. The behavior of an iterator is unspecified if * the underlying collection is modified while the iteration is in * progress in any way other than by calling this method. * * @param txn Txn used for this operation * @throws UnsupportedOperationException if the remove * operation is not supported by this Iterator. * @throws IllegalStateException if the next method has not * yet been called, or the remove method has already * been called after the last call to the next * method. */ void remove(Txn txn); } TxnList.java000066400000000000000000000010151174000617100340730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collectionspackage org.multiverse.api.collections; import org.multiverse.api.Txn; /** * * @param * @author Peter Veentjer. */ public interface TxnList extends TxnCollection { int indexOf(Object item); int indexOf(Txn txn, Object item); int lastIndexOf(Object item); int lastIndexOf(Txn txn, Object item); E get(int index); E get(Txn txn, int index); E set(int index, E element); E set(Txn txn, int index, E element); E remove(int index); E remove(Txn txn, int index); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collections/TxnMap.java000066400000000000000000000337621174000617100337720ustar00rootroot00000000000000package org.multiverse.api.collections; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import java.util.Map; public interface TxnMap extends Map { /** * Returns the {@link Stm} that manages this {@link TxnMap}. * * @return the Stm that manages this map. */ Stm getStm(); /** * Returns the number of key-value mappings in this map. If the * map contains more than Integer.MAX_VALUE elements, returns * Integer.MAX_VALUE. * * @param txn * @return the number of key-value mappings in this map */ int size(Txn txn); /** * Returns true if this map contains no key-value mappings. * * @param txn * @return true if this map contains no key-value mappings */ boolean isEmpty(Txn txn); /** * Removes all of the mappings from this map (optional operation). * The map will be empty after this call returns. * * @param txn * @throws UnsupportedOperationException if the clear operation * is not supported by this map */ void clear(Txn txn); /** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. *

*

More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) *

*

If this map permits null values, then a return value of * {@code null} does not necessarily indicate that the map * contains no mapping for the key; it's also possible that the map * explicitly maps the key to {@code null}. The {@link #containsKey * containsKey} operation may be used to distinguish these two cases. * * @param txn * @param key the key whose associated value is to be returned * @return the value to which the specified key is mapped, or * {@code null} if this map contains no mapping for the key * @throws ClassCastException if the key is of an inappropriate type for * this map (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys (optional) */ V get(Txn txn, Object key); /** * Returns true if this map contains a mapping for the specified * key. More formally, returns true if and only if * this map contains a mapping for a key k such that * (key==null ? k==null : key.equals(k)). (There can be * at most one such mapping.) * * @param txn * @param key key whose presence in this map is to be tested * @return true if this map contains a mapping for the specified * key * @throws ClassCastException if the key is of an inappropriate type for * this map (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys (optional) */ boolean containsKey(Txn txn, Object key); /** * Returns true if this map maps one or more keys to the * specified value. More formally, returns true if and only if * this map contains at least one mapping to a value v such that * (value==null ? v==null : value.equals(v)). This operation * will probably require time linear in the map size for most * implementations of the Map interface. * * @param txn * @param value value whose presence in this map is to be tested * @return true if this map maps one or more keys to the * specified value * @throws ClassCastException if the value is of an inappropriate type for * this map (optional) * @throws NullPointerException if the specified value is null and this * map does not permit null values (optional) */ boolean containsValue(Txn txn, Object value); /** * Associates the specified value with the specified key in this map * (optional operation). If the map previously contained a mapping for * the key, the old value is replaced by the specified value. (A map * m is said to contain a mapping for a key k if and only * if {@link #containsKey(Object) m.containsKey(k)} would return * true.) * * @param txn * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with key, or * null if there was no mapping for key. * (A null return can also indicate that the map * previously associated null with key, * if the implementation supports null values.) * @throws UnsupportedOperationException if the put operation * is not supported by this map * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map * @throws NullPointerException if the specified key or value is null * and this map does not permit null keys or values * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map */ V put(Txn txn, K key, V value); /** * Copies all of the mappings from the specified map to this map * (optional operation). The effect of this call is equivalent to that * of calling {@link #put(Object, Object) put(k, v)} on this map once * for each mapping from key k to value v in the * specified map. The behavior of this operation is undefined if the * specified map is modified while the operation is in progress. * * @param txn * @param m mappings to be stored in this map * @throws UnsupportedOperationException if the putAll operation * is not supported by this map * @throws ClassCastException if the class of a key or value in the * specified map prevents it from being stored in this map * @throws NullPointerException if the specified map is null, or if * this map does not permit null keys or values, and the * specified map contains null keys or values * @throws IllegalArgumentException if some property of a key or value in * the specified map prevents it from being stored in this map */ void putAll(Txn txn, Map m); /** * Removes the mapping for a key from this map if it is present * (optional operation). More formally, if this map contains a mapping * from key k to value v such that * (key==null ? k==null : key.equals(k)), that mapping * is removed. (The map can contain at most one such mapping.) *

*

Returns the value to which this map previously associated the key, * or null if the map contained no mapping for the key. *

*

If this map permits null values, then a return value of * null does not necessarily indicate that the map * contained no mapping for the key; it's also possible that the map * explicitly mapped the key to null. *

*

The map will not contain a mapping for the specified key once the * call returns. * * @param txn * @param key key whose mapping is to be removed from the map * @return the previous value associated with key, or * null if there was no mapping for key. * @throws UnsupportedOperationException if the remove operation * is not supported by this map * @throws ClassCastException if the key is of an inappropriate type for * this map (optional) * @throws NullPointerException if the specified key is null and this * map does not permit null keys (optional) */ V remove(Txn txn, Object key); /** * Returns a {@link TxnCollection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. If the map is * modified while an iteration over the collection is in progress * (except through the iterator's own remove operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding * mapping from the map, via the Iterator.remove, * Collection.remove, removeAll, * retainAll and clear operations. It does not * support the add or addAll operations. * * @return a collection view of the values contained in this map */ TxnCollection values(); /** * Returns a {@link TxnCollection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. If the map is * modified while an iteration over the collection is in progress * (except through the iterator's own remove operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding * mapping from the map, via the Iterator.remove, * Collection.remove, removeAll, * retainAll and clear operations. It does not * support the add or addAll operations. * * @param txn * @return a collection view of the values contained in this map */ TxnCollection values(Txn txn); /** * Returns a {@link TxnSet} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own remove operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the * Iterator.remove, Set.remove, * removeAll, retainAll, and clear * operations. It does not support the add or addAll * operations. * * @return a set view of the keys contained in this map */ TxnSet keySet(); /** * Returns a {@link TxnSet} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own remove operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the * Iterator.remove, Set.remove, * removeAll, retainAll, and clear * operations. It does not support the add or addAll * operations. * * @param txn * @return a set view of the keys contained in this map */ TxnSet keySet(Txn txn); /** * Returns a {@link TxnSet} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own remove operation, or through the * setValue operation on a map entry returned by the * iterator) the results of the iteration are undefined. The set * supports element removal, which removes the corresponding * mapping from the map, via the Iterator.remove, * Set.remove, removeAll, retainAll and * clear operations. It does not support the * add or addAll operations. * * @return a set view of the mappings contained in this map */ TxnSet> entrySet(); /** * Returns a {@link TxnSet} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own remove operation, or through the * setValue operation on a map entry returned by the * iterator) the results of the iteration are undefined. The set * supports element removal, which removes the corresponding * mapping from the map, via the Iterator.remove, * Set.remove, removeAll, retainAll and * clear operations. It does not support the * add or addAll operations. * * @param txn * @return a set view of the mappings contained in this map */ TxnSet> entrySet(Txn txn); String toString(Txn txn); } TxnQueue.java000066400000000000000000000007171174000617100342540ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collectionspackage org.multiverse.api.collections; import org.multiverse.api.Txn; import java.util.Queue; /** * * @param * @author Peter Veentjer. */ public interface TxnQueue extends TxnCollection, Queue { int getCapacity(); E remove(Txn txn); E element(Txn txn); boolean offer(Txn tx, E item); void put(E item); void put(Txn txn, E item); E take(); E take(Txn txn); E poll(Txn txn); E peek(Txn txn); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collections/TxnSet.java000066400000000000000000000002011174000617100337660ustar00rootroot00000000000000package org.multiverse.api.collections; import java.util.Set; public interface TxnSet extends TxnCollection, Set { } TxnStack.java000066400000000000000000000006711174000617100342340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/collectionspackage org.multiverse.api.collections; import org.multiverse.api.Txn; /** * * * @param * @author Peter Veentjer. */ public interface TxnStack extends TxnCollection { int getCapacity(); void push(E item); void push(Txn txn, E item); boolean offer(E item); boolean offer(Txn txn, E item); E pop(); E pop(Txn txn); E poll(); E poll(Txn txn); E peek(); E peek(Txn txn); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptions/000077500000000000000000000000001174000617100315505ustar00rootroot00000000000000AbortOnlyException.java000066400000000000000000000016201174000617100361230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link IllegalTxnStateException} thrown when a {@link org.multiverse.api.Txn} is configured * as abort only and a prepare/commit is executed. * * @author Peter Veentjer. * @see org.multiverse.api.Txn#setAbortOnly() * @see org.multiverse.api.Txn#isAbortOnly() */ public class AbortOnlyException extends IllegalTxnStateException { private static final long serialVersionUID = 0; /** * Creates a new AbortOnlyException with the provided message. * * @param message the message. */ public AbortOnlyException(String message) { super(message); } /** * Creates a new AbortOnlyException with the provided message and cause. * * @param message the message * @param cause the cause. */ public AbortOnlyException(String message, Throwable cause) { super(message, cause); } } AtomicOperationException.java000066400000000000000000000022321174000617100373070ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link TxnExecutionException} thrown when an atomic operation has failed (e.g. because the ref * was locked). * * @author Peter Veentjer. */ public class AtomicOperationException extends TxnExecutionException { private static final long serialVersionUID = 0; /** * Creates a new AtomicOperationException. */ public AtomicOperationException() { } /** * Creates a new AtomicOperationException with the provided message. * * @param message the message */ public AtomicOperationException(String message) { super(message); } /** * Creates a new AtomicOperationException with the provided message and cause. * * @param message the message * @param cause the cause of the message */ public AtomicOperationException(String message, Throwable cause) { super(message, cause); } /** * Creates a new AtomicOperationException with the provided message and cause. * * @param cause the cause of the exception. */ public AtomicOperationException(Throwable cause) { super(cause); } } ControlFlowError.java000077500000000000000000000071571174000617100356330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link Error} thrown to regulate control flow inside multiverse {@link org.multiverse.api.TxnExecutor}. Normally * it would be a very bad thing to regulate control flow using an exception/error, but to make seamless integration in the Java * language possible, there is no better alternative. So these exceptions should not catch unless you really know know what you * are doing. So catching all Throwable instances (including Error) is a bad practice. *

* There current are 3 different types of ControlFlowErrors: *

    *
  1. {@link ReadWriteConflict}: used to indicate read and write conflicts
  2. *
  3. {@link RetryError}: used for blocking
  4. *
  5. {@link SpeculativeConfigurationError}: used for guessing the most optimal configuration for transactions
  6. *
* *

Why it is an Error

* *

It is an Error instead of a RuntimeException, to prevent users trying to catch the error inside a * try/catch(RuntimeException) block and consuming important events like a ReadWriteConflict. In most cases these events can * be solved by retrying the transaction. * *

It is an Error instead of a Throwable, because a Throwable needs to be propagated, so making the code a lot more * awkward to work with. * *

Instance Caching

* *

Normally ControlFlowErrors are cached to be reused because they can be thrown very often to be caught by the TxnExecutor * and discarded. Especially the stacktrace is very expensive to create. By default all ControlFlowErrors are reused * but with the {@link org.multiverse.api.TxnFactoryBuilder#setControlFlowErrorsReused(boolean)} this behavior * can be changed. It also can be configured on the Stm level, depending on the Stm implementation. For the * {@link org.multiverse.stms.gamma.GammaStm} you need to look at the * {@link org.multiverse.stms.gamma.GammaStmConfig#controlFlowErrorsReused}. * *

The constructors also expose configuration options to have the StackTrace filled. Especially for an Error that is * reused, not filling the stacktrace is very important because else the developer is looking at code where the exception * very likely didn't happen. * * @author Peter Veentjer */ public abstract class ControlFlowError extends Error { private static final long serialVersionUID = 0; private final boolean fillStackTrace; /** * Creates a new ControlFlowError. * * @param fillStackTrace true if the StackTrace should be filled, false otherwise. */ public ControlFlowError(boolean fillStackTrace) { this(fillStackTrace, null, null); } /** * Creates a new ControlFlowError with the provided message. * * @param fillStackTrace true if the StackTrace should be filled, false otherwise. * @param message the message of the exception. */ public ControlFlowError(boolean fillStackTrace, String message) { this(fillStackTrace, message, null); } /** * Creates a new ControlFlowError with the provided message and cause. * * @param fillStackTrace true if the StackTrace should be filled, false otherwise. * @param message the message of the exception. * @param cause the cause of the exception. */ public ControlFlowError(boolean fillStackTrace, String message, Throwable cause) { super(message, cause); this.fillStackTrace = fillStackTrace; } @Override public StackTraceElement[] getStackTrace() { if (fillStackTrace) { return super.getStackTrace(); } else { return new StackTraceElement[0]; } } } DeadTxnException.java000077500000000000000000000016331174000617100355500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link IllegalTxnStateException} thrown when an action is executed on a * {@link org.multiverse.api.Txn} that is either committed or aborted. * * @author Peter Veentjer. */ public class DeadTxnException extends IllegalTxnStateException { private static final long serialVersionUID = 0; /** * Creates a new DeadTxnException. */ public DeadTxnException() { } /** * Creates a new DeadTxnException with the provided message. * * @param message the message of the exception. */ public DeadTxnException(String message) { super(message); } /** * Creates a new DeadTxnException. * * @param message the message of the exception. * @param cause the cause of the exception. */ public DeadTxnException(String message, Throwable cause) { super(message, cause); } } IllegalCommuteException.java000066400000000000000000000025221174000617100371170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link TxnExecutionException} thrown when {@link org.multiverse.api.Txn} access is done while * a commuting function is being evaluated. * *

The reason why Txn access is not allowed, is that once other reads/writes are done while executing the commuting * behavior, you can have read/write inconsistencies. E.g. in Clojure the same commuting function can be executed more than * during the execution of a transaction once on a reference, leading to different values every time executed (e.g. the value it * already had inside the transaction, and the most recent committed value when the commuting operation is calculated during * transaction commit. * * @author Peter Veentjer. */ public class IllegalCommuteException extends TxnExecutionException { private static final long serialVersionUID = 0; /** * Creates a new IllegalCommuteException with the provided message. * * @param message the message */ public IllegalCommuteException(String message) { super(message); } /** * Creates a new IllegalCommuteException with the provided message and cause. * * @param message the message * @param cause the cause. */ public IllegalCommuteException(String message, Throwable cause) { super(message, cause); } } IllegalTxnFactoryException.java000066400000000000000000000017001174000617100376040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link IllegalStateException} thrown when a {@link org.multiverse.api.TxnFactory} can't be created because * the {@link org.multiverse.api.TxnConfig} is not correct. * * @author Peter Veentjer. */ public class IllegalTxnFactoryException extends IllegalStateException { private static final long serialVersionUID = 0; /** * Creates a new IllegalTxnFactoryException. * * @param message the message of the IllegalTxnFactoryException. */ public IllegalTxnFactoryException(String message) { super(message); } /** * Creates a new IllegalTxnFactoryException with the provided message and cause. * * @param message the message of the IllegalTxnFactoryException. * @param cause the cause of the IllegalTxnFactoryException */ public IllegalTxnFactoryException(String message, Throwable cause) { super(message, cause); } } IllegalTxnStateException.java000077500000000000000000000020011174000617100372530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link TxnExecutionException} thrown when an operation is executed on a * {@link org.multiverse.api.Txn} when it is not in a valid state for that operation. * * @author Peter Veentjer */ public class IllegalTxnStateException extends TxnExecutionException { private static final long serialVersionUID = 0; /** * Creates a new IllegalTxnStateException. */ public IllegalTxnStateException() { } /** * Creates a new IllegalTxnStateException with the provided message. * * @param message the message of the exception. */ public IllegalTxnStateException(String message) { super(message); } /** * Creates a new IllegalTxnStateException with the provided message and cause. * * @param message the message of the exception. * @param cause the cause of the exception. */ public IllegalTxnStateException(String message, Throwable cause) { super(message, cause); } } InvisibleCheckedException.java000066400000000000000000000013011174000617100374010ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link RuntimeException} thrown when a checked exception is thrown but can't be rethrown. * The original checked exception can be retrieved by calling the {@link #getCause()}. * * @author Peter Veentjer */ public class InvisibleCheckedException extends RuntimeException { private static final long serialVersionUID = 0; /** * Creates a new InvisibleCheckedException with the given cause. * * @param cause the cause of the Exception. */ public InvisibleCheckedException(Exception cause) { super(cause); } @Override public Exception getCause() { return (Exception) super.getCause(); } } LockedException.java000066400000000000000000000021731174000617100354170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link AtomicOperationException} thrown when an atomic operation was executed on a * {@link org.multiverse.api.TxnObject} while it was locked. E.g. when an atomicGet was done on a TxnRef * that already has an exclusive lock or that a TxnRef.atomicSet while a readlock already was acquired. * * @author Peter Veentjer. */ public class LockedException extends AtomicOperationException { private static final long serialVersionUID = 0; /** * Creates a new LockedException. */ public LockedException() { } /** * Creates a new LockedException * * @param message the message */ public LockedException(String message) { super(message); } /** * Creates a new LockedException. * * @param message the message * @param cause the cause */ public LockedException(String message, Throwable cause) { super(message, cause); } /** * Creates a new LockedException * * @param cause the cause */ public LockedException(Throwable cause) { super(cause); } } PanicError.java000066400000000000000000000014651174000617100344060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link Error} thrown when the state of the {@link org.multiverse.api.Stm} has been compromised. Normally this exception should * never happen. * * @author Peter Veentjer. */ public class PanicError extends Error { private static final long serialVersionUID = 0; /** * Creates a new PanicError with the provided message. * * @param message the message of the PanicError. */ public PanicError(String message) { super(message); } /** * Creates a new PanicError with the provided message and cause. * * @param message the message of the PanicError. * @param cause the cause of the PanicError. */ public PanicError(String message, Throwable cause) { super(message, cause); } } PreparedTxnException.java000077500000000000000000000015661174000617100364620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link IllegalTxnStateException} thrown when an operation is executed on a * {@link org.multiverse.api.Txn} while the transaction is prepared. * * @author Peter Veentjer. */ public class PreparedTxnException extends IllegalTxnStateException { private static final long serialVersionUID = 0; /** * Creates a new PreparedTxnException with the provided message. * * @param message the message of the exception. */ public PreparedTxnException(String message) { super(message); } /** * Creates a new PreparedTxnException with the provided message and cause. * * @param message the message of the exception. * @param cause the cause of the exception. */ public PreparedTxnException(String message, Throwable cause) { super(message, cause); } } PropagationException.java000066400000000000000000000017771174000617100365120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link IllegalStateException} throw when there is a conflict with the {@link org.multiverse.api.Txn} * propagation. For more information {@link org.multiverse.api.PropagationLevel}. * * @author Peter Veentjer. */ public class PropagationException extends TxnExecutionException { private static final long serialVersionUID = 0; /** * Creates a new PropagationException. */ public PropagationException() { } /** * Creates a new PropagationException with the provided message. * * @param message the message of the exception. */ public PropagationException(String message) { super(message); } /** * Creates a new PropagationException with the provided message and cause. * * @param message the message of the exception * @param cause the cause of the exception. */ public PropagationException(String message, Throwable cause) { super(message, cause); } } ReadWriteConflict.java000077500000000000000000000025341174000617100357130ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link ControlFlowError} thrown when a reading or writing a {@link org.multiverse.api.TxnObject} * failed, e.g. because it was locked or because a read or write conflict was detected. *

* A ReadWriteConflict can in most cases be solved by retrying the {@link org.multiverse.api.Txn} (this will * automatically be done by the {@link org.multiverse.api.TxnExecutor}). * * @author Peter Veentjer. */ public class ReadWriteConflict extends ControlFlowError { private static final long serialVersionUID = 0; public final static ReadWriteConflict INSTANCE = new ReadWriteConflict(false); /** * Creates a new ReadWriteConflict. * * @param fillStackTrace if the StackTrace should be filled. */ public ReadWriteConflict(boolean fillStackTrace) { super(fillStackTrace); } /** * Creates a new ReadWriteConflict. * * @param message the message of the ReadWriteConflict. */ public ReadWriteConflict(String message) { super(true, message); } /** * Creates a new ReadWriteConflict. * * @param message the message of the ReadWriteConflict. * @param cause the cause of the ReadWriteConflict. */ public ReadWriteConflict(String message, Throwable cause) { super(true, message, cause); } } ReadonlyException.java000077500000000000000000000015301174000617100357720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * An {@link IllegalTxnStateException} thrown when a write action is executed using * a readonly {@link org.multiverse.api.Txn}. * * @author Peter Veentjer. * @see org.multiverse.api.TxnFactoryBuilder#setReadonly(boolean) */ public class ReadonlyException extends IllegalTxnStateException { private static final long serialVersionUID = 0; /** * Creates a new ReadonlyException. * * @param message the message of the exception. */ public ReadonlyException(String message) { super(message); } /** * Creates a new ReadonlyException. * * @param message the message of the exception. * @param cause the cause of the exception. */ public ReadonlyException(String message, Throwable cause) { super(message, cause); } } RetryError.java000077500000000000000000000016571174000617100344670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link ControlFlowError} thrown when an explicit retry is done on a {@link org.multiverse.api.Txn}. * With the {RetryError} it is possible to create blocking transactions. * *

An example is a transaction wants to pop an item from an empty queue. The Retry is caught by the transaction * handling logic (e.g the {@link org.multiverse.api.TxnExecutor} and blocks until either a timeout happens or * an item is placed on the queue. * * @author Peter Veentjer. * @see org.multiverse.api.Txn#retry() */ public class RetryError extends ControlFlowError { private static final long serialVersionUID = 0; public final static RetryError INSTANCE = new RetryError(false); /** * Creates a new Retry Error. * * @param fillStackTrace if the StackTrace should be filled. */ public RetryError(boolean fillStackTrace) { super(fillStackTrace); } } RetryException.java000066400000000000000000000017541174000617100353270ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link TxnExecutionException} thrown when retrying a transaction for another attempt fails. * E.g. because an explicit retry is not used, or when there are too many retry attempts. * * @author Peter Veentjer. */ public abstract class RetryException extends TxnExecutionException { private static final long serialVersionUID = 0; /** * Creates a new RetryException. */ public RetryException() { } /** * Creates a new RetryException with the provided message. * * @param message the message of the RetryException. */ public RetryException(String message) { super(message); } /** * Creates a new RetryException with the provided message and cause. * * @param message the message of the RetryException. * @param cause the cause of the RetryException. */ public RetryException(String message, Throwable cause) { super(message, cause); } } RetryInterruptedException.java000066400000000000000000000023151174000617100375470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link RetryException} thrown when the blocking operation on a {@link org.multiverse.api.Txn} * using the retry has been interrupted. * *

Unlike the {@link InterruptedException} this exception is not checked. A checked interrupted * exception is quite nasty to have since either you need to deal with it, or you need to propagate it. * *

When this exception is thrown, the interrupted status on the Thread always is restored. * * @author Peter Veentjer. * @see org.multiverse.api.TxnFactoryBuilder#setInterruptible(boolean) */ public class RetryInterruptedException extends RetryException { private static final long serialVersionUID = 0; /** * Creates a new RetryInterruptedException with the provided message. * * @param message the message */ public RetryInterruptedException(String message) { super(message); } /** * Creates a new RetryInterruptedException with the provided message and cause. * * @param message the message * @param cause the cause of this exception */ public RetryInterruptedException(String message, Throwable cause) { super(message, cause); } } RetryNotAllowedException.java000066400000000000000000000022271174000617100373140ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link RetryException} thrown when a {@link org.multiverse.api.StmUtils#retry()} or {@link org.multiverse.api.Txn#retry()} * is done while the {@link org.multiverse.api.Txn} doesn't allow blocking transactions. *

* For more information see {@link org.multiverse.api.TxnFactoryBuilder#setBlockingAllowed(boolean)} * and {@link org.multiverse.api.TxnConfig#isBlockingAllowed()}. * * @author Peter Veentjer. * @see org.multiverse.api.TxnFactoryBuilder#setBlockingAllowed(boolean) */ public class RetryNotAllowedException extends RetryException { private static final long serialVersionUID = 0; /** * Creates a new RetryNotAllowedException with the provided message. * * @param message the message */ public RetryNotAllowedException(String message) { super(message); } /** * Creates a new RetryNotAllowedException with the provided message and cause. * * @param message the message * @param cause the cause of this exception. */ public RetryNotAllowedException(String message, Throwable cause) { super(message, cause); } } RetryNotPossibleException.java000077500000000000000000000017701174000617100375120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link RetryException} throw when a {@link org.multiverse.api.StmUtils#retry()} or {@link org.multiverse.api.Txn#retry()} * done on a {@link org.multiverse.api.Txn} without the possibility of progress, for example when the readset of a transaction * is empty. * * @author Peter Veentjer. */ public class RetryNotPossibleException extends RetryException { private static final long serialVersionUID = 0; /** * Creates a new NoRetryPossibleException with the provided message. * * @param message the message of the exception. */ public RetryNotPossibleException(String message) { super(message); } /** * Creates a new NoRetryPossibleException with the provided message and cause. * * @param message the message of the exception. * @param cause the cause of the exception. */ public RetryNotPossibleException(String message, Throwable cause) { super(message, cause); } } RetryTimeoutException.java000066400000000000000000000026441174000617100366750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link RetryException} thrown when a transaction times out while it blocks on a retry (so waits for an update). * *

On a transaction the maximum timeout can be set. When it is set to a bound value (so smaller than Long.MAX_VALUE) * all retries that need to block the transaction (so wait till some write happened) will decrement the * remaining timeout. When the transaction eventually times out, this Exception is thrown. * *

For more information see: *

    *
  1. the remaining timeout: {@link org.multiverse.api.Txn#getRemainingTimeoutNs()}
  2. *
  3. reading the configured timeout: {@link org.multiverse.api.TxnConfig#getTimeoutNs()}.
  4. *
  5. configuring the timeout: {@link org.multiverse.api.TxnFactoryBuilder#setTimeoutNs(long)}
  6. *
* * @author Peter Veentjer. */ public class RetryTimeoutException extends RetryException { private static final long serialVersionUID = 0; /** * Creates a new RetryTimeoutException. * * @param message the message of the exception. */ public RetryTimeoutException(String message) { super(message); } /** * Creates a new RetryTimeoutException. * * @param message the message of the exception. * @param cause the cause of the exception */ public RetryTimeoutException(String message, Throwable cause) { super(message, cause); } } SpeculativeConfigurationError.java000077500000000000000000000050331174000617100403660ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link ControlFlowError} thrown for dealing with the speculative configuration mechanism. * *

Multiverse uses a speculative configuration mechanism if enabled makes certain optimizations possible. E.g. one of the optimizations * is to use different {@link org.multiverse.api.Txn} implementations that are optimized for certain transaction lengths. As * long as the speculation is not violated, you will get better performance than when a more heavy weight transaction/configuration. * *

So ControlFlowErrors are not something bad, but just a way for the STM to figure out what the cheapest settings are for * performance/scalability. * *

Unexpected retries

* *

Because a transaction can fail on a speculative failure more than once, it could be that the transaction is retried. Normally * this is not an issue, since the transaction will be retried, so is invisible. And once the {@link org.multiverse.api.TxnExecutor} * has learned, it will not make the same mistakes again, but if you do io (e.g. print to the System.out or do logging) you can expect * to see aborts, even though there is no other reason to. * * Speculative behavior can be turned of (either on the Txn or STM level) but you will not get the best out of performance. For * the speculative behavior to learn, it is important that the {@link org.multiverse.api.TxnExecutor} is reused. * * @author Peter Veentjer. * @see org.multiverse.api.TxnFactoryBuilder#setSpeculative(boolean) */ public class SpeculativeConfigurationError extends ControlFlowError { private static final long serialVersionUID = 0; public final static SpeculativeConfigurationError INSTANCE = new SpeculativeConfigurationError(false); /** * Creates a SpeculativeConfigurationError. * * @param fillStackTrace if the StackTrace should be filled. */ public SpeculativeConfigurationError(boolean fillStackTrace) { super(fillStackTrace); } /** * Creates a SpeculativeConfigurationError with the provided message. * * @param message the message of the exception. */ public SpeculativeConfigurationError(String message) { super(true, message); } /** * Creates a SpeculativeConfigurationError with the provided message and cause. * * @param message the message of the exception. * @param cause the cause of the exception. */ public SpeculativeConfigurationError(String message, Throwable cause) { super(true, message, cause); } } StmMismatchException.java000066400000000000000000000020011174000617100364350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link TxnExecutionException} thrown when a transaction encounters encounters a transactional object * that belongs to a different Stm instance. * *

Normally this exception is not thrown because only a single Stm instance, stored in the {@link org.multiverse.api.GlobalStmInstance} * is used. * * @author Peter Veentjer. * @see org.multiverse.api.GlobalStmInstance */ public class StmMismatchException extends TxnExecutionException { private static final long serialVersionUID = 0; /** * Creates a new StmMismatchException with the provided message. * * @param message the message */ public StmMismatchException(String message) { super(message); } /** * Creates a new StmMismatchException with the provided message. * * @param message the message * @param cause the cause */ public StmMismatchException(String message, Throwable cause) { super(message, cause); } } TodoException.java000077500000000000000000000011351174000617100351230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link RuntimeException} thrown when some part of the implementation is missing. Normally they should never be * thrown in releases. * * @author Peter Veentjer */ public class TodoException extends RuntimeException { private static final long serialVersionUID = 0; /** * Creates a new TodoException. */ public TodoException() { } /** * Creates a new TodoException. * * @param message the message of the exception */ public TodoException(String message) { super(message); } } TooManyRetriesException.java000077500000000000000000000017221174000617100371440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link RetryException} thrown when a {@link org.multiverse.api.Txn} is retried too many times. Uncontrolled * retrying could lead to liveness problems like livelocks and starvation. * * @author Peter Veentjer. * @see org.multiverse.api.TxnFactoryBuilder#setMaxRetries(int) */ public class TooManyRetriesException extends RetryException { private static final long serialVersionUID = 0; /** * Creates a new TooManyRetriesException with the provided message. * * @param message the message of the exception. */ public TooManyRetriesException(String message) { super(message); } /** * Creates a new TooManyRetriesException with the provided message. * * @param message the message of the exception * @param cause the cause of the exception */ public TooManyRetriesException(String message, Throwable cause) { super(message,cause); } } TxnExecutionException.java000066400000000000000000000025441174000617100366550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link RuntimeException} thrown when something fails while executing a {@link org.multiverse.api.Txn}. * *

This exception is not caught by the {@link org.multiverse.api.TxnExecutor}. * * @author Peter Veentjer. */ public class TxnExecutionException extends RuntimeException { private static final long serialVersionUID = 0; /** * Creates a new TransactionalExecutionException. */ public TxnExecutionException() { super(); } /** * Creates a new TransactionalExecutionException with the provided message and cause. * * @param message message of the exception. */ public TxnExecutionException(String message) { super(message); } /** * Creates a new TransactionalExecutionException with the provided message and cause. * * @param message the message of the exception. * @param cause the Throwable that caused the exception. */ public TxnExecutionException(String message, Throwable cause) { super(message, cause); } /** * Creates a new TransactionalExecutionException with the provided cause. * * @param cause the Throwable that was the cause of this TransactionalExecutionException. */ public TxnExecutionException(Throwable cause) { super(cause); } } TxnMandatoryException.java000066400000000000000000000030601174000617100366420ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; import static java.lang.String.format; /** * A {@link PropagationException} thrown when no {@link org.multiverse.api.Txn} is available while it is mandatory. A typical * cause of this exception is that the {@link org.multiverse.api.PropagationLevel#Mandatory} is used. * * @author Peter Veentjer * @see org.multiverse.api.TxnFactoryBuilder#setPropagationLevel(org.multiverse.api.PropagationLevel) */ public class TxnMandatoryException extends PropagationException { private static final long serialVersionUID = 0; /** * Creates a new TxnMandatoryException. */ public TxnMandatoryException() { } /** * Creates a new TxnMandatoryException with the provided message. * * @param message the message of the exception. */ public TxnMandatoryException(String message) { super(message); } /** * Creates a new TxnMandatoryException * * @param clazz the class of the method where the transaction was required * @param method the name of the method where the transaction was required. */ public TxnMandatoryException(Class clazz, String method){ super(format("%s.%s is missing a required transaction", clazz.getName(),method)); } /** * Creates a new TxnMandatoryException with the provided message. * * @param message the message of the exception. * @param cause the cause of the exception. */ public TxnMandatoryException(String message, Throwable cause) { super(message, cause); } } TxnNotAllowedException.java000066400000000000000000000021261174000617100367560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/exceptionspackage org.multiverse.api.exceptions; /** * A {@link PropagationException} thrown when a {@link org.multiverse.api.Txn} is found, but is not allowed. * A typical cause of this exception is that the {@link org.multiverse.api.PropagationLevel#Never} is used and * a transaction is available. * * @author Peter Veentjer. * @see org.multiverse.api.TxnFactoryBuilder#setPropagationLevel(org.multiverse.api.PropagationLevel) */ public class TxnNotAllowedException extends PropagationException { private static final long serialVersionUID = 0; /** * Creates a new NoTransactionAllowedException with the provided message. * * @param message the message for the exception. */ public TxnNotAllowedException(String message) { super(message); } /** * Creates a new NoTransactionAllowedException with the provided message and cause. * * @param message the message of the exception. * @param cause the cause of the Exception. */ public TxnNotAllowedException(String message, Throwable cause) { super(message, cause); } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functions/000077500000000000000000000000001174000617100313775ustar00rootroot00000000000000BinaryFunction.java000066400000000000000000000001611174000617100351130ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functionspackage org.multiverse.api.functions; public interface BinaryFunction { public E call(E val1, E val2); } BooleanFunction.java000077500000000000000000000015621174000617100352570ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functionspackage org.multiverse.api.functions; /** * A {@link Function} for primitives that accepts an argument of type boolean and returns a new * value of the same type. * *

The reason why {@link BooleanFunction} is an abstract class instead of an ordinary interface, is that * this class doesn't cause any unwanted boxing of primitives version of the call method is used instead of the one that * accepts and returns a/an Boolean). * *

This class is generated. * * @author Peter Veentjer. */ public abstract class BooleanFunction implements Function{ /** * Calculates the new value based on the current value. * * @param current the current value. * @return the new value. */ public abstract boolean call(boolean current); @Override public final Boolean call(Boolean arg) { return call((boolean) arg); } } DoubleFunction.java000077500000000000000000000015501174000617100351070ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functionspackage org.multiverse.api.functions; /** * A {@link Function} for primitives that accepts an argument of type double and returns a new * value of the same type. * *

The reason why {@link DoubleFunction} is an abstract class instead of an ordinary interface, is that * this class doesn't cause any unwanted boxing of primitives version of the call method is used instead of the one that * accepts and returns a/an Double). * *

This class is generated. * * @author Peter Veentjer. */ public abstract class DoubleFunction implements Function{ /** * Calculates the new value based on the current value. * * @param current the current value. * @return the new value. */ public abstract double call(double current); @Override public final Double call(Double arg) { return call((double) arg); } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functions/Function.java000066400000000000000000000007401174000617100340300ustar00rootroot00000000000000package org.multiverse.api.functions; /** * A Function that accepts an argument of a certain type and returns a new value of the same type. * *

Can be used for commuting functions or for the Ref.alter methods. * *

This class is generated. * * @author Peter Veentjer. */ public interface Function{ /** * Evaluates the function. * * @param value the value to evaluate. * @return the result of the evaluation */ E call(E value); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functions/Function.vm000066400000000000000000000033241174000617100335320ustar00rootroot00000000000000package org.multiverse.api.functions; #if(${transactionalObject.type} eq 'E') /** * A Function that accepts an argument of a certain type and returns a new value of the same type. * *

Can be used for commuting functions or for the Ref.alter methods. * *

This class is generated. * * @author Peter Veentjer. */ public interface ${transactionalObject.functionClass}${transactionalObject.typeParameter}{ /** * Evaluates the function. * * @param value the value to evaluate. * @return the result of the evaluation */ ${transactionalObject.type} call(${transactionalObject.type} value); } #else /** * A {@link Function} for primitives that accepts an argument of type ${transactionalObject.type} and returns a new * value of the same type. * *

The reason why {@link ${transactionalObject.functionClass}} is an abstract class instead of an ordinary interface, is that * this class doesn't cause any unwanted boxing of primitives version of the call method is used instead of the one that * accepts and returns a/an ${transactionalObject.objectType}). * *

This class is generated. * * @author Peter Veentjer. */ public abstract class ${transactionalObject.functionClass}${transactionalObject.typeParameter} implements Function<${transactionalObject.objectType}>{ /** * Calculates the new value based on the current value. * * @param current the current value. * @return the new value. */ public abstract ${transactionalObject.type} call(${transactionalObject.type} current); @Override public final ${transactionalObject.objectType} call(${transactionalObject.objectType} arg) { return call((${transactionalObject.type}) arg); } } #endFunctions.java000066400000000000000000000170751174000617100341450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functionspackage org.multiverse.api.functions; /** * A utility class for {@link Function} functionality. * * @author Peter Veentjer. */ public final class Functions { private static final IntFunction incOneIntFunction = new IncIntFunction(1); private static final LongFunction incOneLongFunction = new IncLongFunction(1); private static final IntFunction decOneIntFunction = new IncIntFunction(-1); private static final LongFunction decOneLongFunction = new IncLongFunction(-1); private static final DoubleFunction incOneDoubleFunction = new IncDoubleFunction(); private static final DoubleFunction identityDoubleFunction = new IdentityDoubleFunction(); /** * Returns an {@link Function} that returns its input. * * @return the identity function. */ public static Function identityFunction(){ return identityFunction; } /** * Returns an {@link DoubleFunction} that returns its input. * * @return the identity function. */ public static DoubleFunction identityDoubleFunction() { return identityDoubleFunction; } /** * Returns a {@link DoubleFunction} that increments the input with one. * * @return the increment function. */ public static DoubleFunction incDoubleFunction() { return incOneDoubleFunction; } /** * Returns an identity {@link IntFunction} (a function that returns its input value). The instance is cached. * * @return the identity IntFunction. */ public static IntFunction identityIntFunction() { return identityIntFunction; } /** * Returns an identity {@link LongFunction} (a function that returns its input value). The instance is cached. * * @return the identity LongFunction. */ public static LongFunction identityLongFunction() { return identityLongFunction; } /** * Returns an {@link IntFunction} that increments the input value by one. The instance is cached. * * @return the increment IntFunction. */ public static IntFunction incIntFunction() { return incOneIntFunction; } /** * Returns an {@link IntFunction} that decrements the input value by one. The instance is cached. * * @return the decrease IntFunction. */ public static IntFunction decIntFunction() { return decOneIntFunction; } /** * Returns a {@link LongFunction} that increments the input value by one. The instance is cached. * * @return the increment LongFunction. */ public static LongFunction incLongFunction() { return incOneLongFunction; } /** * Returns a {@link LongFunction} that decrements the input value by one. The instance is cached. * * @return the decrement LongFunction. */ public static LongFunction decLongFunction() { return decOneLongFunction; } /** * Returns a {@link IntFunction} that increments with the given amount. For the -1, 0 and 1 * a cached instance is returned. In the other cases a new instance is created. * * @param amount the value to increment with. A negative value does a decrement. * @return the increment IntFunction. */ public static IntFunction incIntFunction(int amount) { switch (amount) { case 0: return identityIntFunction; case 1: return incOneIntFunction; case -1: return decOneIntFunction; default: return new IncIntFunction(amount); } } /** * Returns a {@link BooleanFunction} that inverts the argument. * * @return the function */ public static BooleanFunction inverseBooleanFunction() { return inverseBooleanFunction; } /** * Returns a {@link BooleanFunction} that returns the argument. * * @return the function. */ public static BooleanFunction identityBooleanFunction() { return identityBooleanFunction; } /** * Returns a {@link LongFunction} that increments with the given amount. For the -1, 0 and 1 * a cached instance is returned. In the other cases a new instance is created. * * @param amount the value to increment with. A negative value does a decrement. * @return the increment LongFunction. */ public static LongFunction incLongFunction(long amount) { if (amount == 0) { return identityLongFunction; } if (amount == 1) { return incOneLongFunction; } if (amount == -1) { return decOneLongFunction; } return new IncLongFunction(amount); } private static final BooleanFunction inverseBooleanFunction = new BooleanFunction() { @Override public boolean call(boolean current) { return !current; } }; private static final BooleanFunction identityBooleanFunction = new BooleanFunction() { @Override public boolean call(boolean current) { return current; } @Override public String toString() { return "IdentityBooleanFunction"; } }; private static final IntFunction identityIntFunction = new IntFunction() { @Override public int call(int current) { return current; } @Override public String toString() { return "IdentityIntFunction"; } }; private static final LongFunction identityLongFunction = new LongFunction() { @Override public long call(long current) { return current; } @Override public String toString() { return "IdentityLongFunction"; } }; private static final Function identityFunction = new Function() { @Override public Object call(Object value) { return value; } @Override public String toString() { return "IdentityFunction"; } }; private static class IncIntFunction extends IntFunction { private final int value; public IncIntFunction(int value) { this.value = value; } @Override public int call(int current) { return current + value; } @Override public String toString() { return "IncIntFunction{" + "value=" + value + '}'; } } private static class IncLongFunction extends LongFunction { private final long value; public IncLongFunction(long value) { this.value = value; } @Override public long call(long current) { return current + value; } @Override public String toString() { return "IncLongFunction{" + "value=" + value + '}'; } } private static class IncDoubleFunction extends DoubleFunction { @Override public double call(double current) { return current + 1; } @Override public String toString() { return "IncDoubleFunction{value=1}"; } } private static class IdentityDoubleFunction extends DoubleFunction { @Override public double call(double current) { return current; } @Override public String toString() { return "IdentityDoubleFunction{}"; } } //we don't want instances. private Functions() { } } IncIntFunction.java000066400000000000000000000015161174000617100350600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functionspackage org.multiverse.api.functions; /** * A {@link IntFunction} that increased the value with the supplied amount. * * @author Peter Veentjer. */ public final class IncIntFunction extends IntFunction { public final static IncIntFunction INSTANCE = new IncIntFunction(); private final int inc; /** * Creates an IncIntFunction that adds one. */ public IncIntFunction() { this(1); } /** * Creates an IncIntFunction with the specified * * @param inc the number to increment with. */ public IncIntFunction(int inc) { this.inc = inc; } @Override public int call(int current) { return current + inc; } @Override public String toString() { return "IncIntFunction{" + "inc=" + inc + '}'; } } IntFunction.java000077500000000000000000000015321174000617100344270ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functionspackage org.multiverse.api.functions; /** * A {@link Function} for primitives that accepts an argument of type int and returns a new * value of the same type. * *

The reason why {@link IntFunction} is an abstract class instead of an ordinary interface, is that * this class doesn't cause any unwanted boxing of primitives version of the call method is used instead of the one that * accepts and returns a/an Integer). * *

This class is generated. * * @author Peter Veentjer. */ public abstract class IntFunction implements Function{ /** * Calculates the new value based on the current value. * * @param current the current value. * @return the new value. */ public abstract int call(int current); @Override public final Integer call(Integer arg) { return call((int) arg); } } LongFunction.java000077500000000000000000000015241174000617100345750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/functionspackage org.multiverse.api.functions; /** * A {@link Function} for primitives that accepts an argument of type long and returns a new * value of the same type. * *

The reason why {@link LongFunction} is an abstract class instead of an ordinary interface, is that * this class doesn't cause any unwanted boxing of primitives version of the call method is used instead of the one that * accepts and returns a/an Long). * *

This class is generated. * * @author Peter Veentjer. */ public abstract class LongFunction implements Function{ /** * Calculates the new value based on the current value. * * @param current the current value. * @return the new value. */ public abstract long call(long current); @Override public final Long call(Long arg) { return call((long) arg); } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/lifecycle/000077500000000000000000000000001174000617100313265ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/lifecycle/TxnEvent.java000077500000000000000000000010071174000617100337450ustar00rootroot00000000000000package org.multiverse.api.lifecycle; /** * An enumeration for all possible events for the {@link org.multiverse.api.Txn} life-cycle. * * @author Peter Veentjer. * @see TxnListener */ public enum TxnEvent { /** * Just before starting. */ PreStart, /** * Just after starting. */ PostStart, /** * Just before preparing */ PrePrepare, /** * Just after aborting. */ PostAbort, /** * Just after committing. */ PostCommit } TxnListener.java000077500000000000000000000011711174000617100343740ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/lifecyclepackage org.multiverse.api.lifecycle; import org.multiverse.api.Txn; /** * A listener tailored for listening to events in the {@link org.multiverse.api.Txn} life-cycle. * * @author Peter Veentjer * @see TxnEvent * @see org.multiverse.api.TxnConfig#getPermanentListeners() * @see org.multiverse.api.Txn#register(TxnListener) */ public interface TxnListener { /** * Notifies that a certain {@link TxnEvent} happened inside a {@link org.multiverse.api.Txn}. * * @param txn the {@link org.multiverse.api.Txn} where the event happened * @param e the event */ void notify(Txn txn, TxnEvent e); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/predicates/000077500000000000000000000000001174000617100315125ustar00rootroot00000000000000BooleanPredicate.java000066400000000000000000000020401174000617100354720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/predicatespackage org.multiverse.api.predicates; /** * A predicate that checks if some value leads to true or false. * * @author Peter Veentjer. */ public abstract class BooleanPredicate implements Predicate{ public static BooleanPredicate newEqualsPredicate(final boolean value) { return new BooleanPredicate() { @Override public boolean evaluate(final boolean current) { return current == value; } }; } public static BooleanPredicate newNotEqualsPredicate(final boolean value) { return new BooleanPredicate() { @Override public boolean evaluate(final boolean current) { return current != value; } }; } /** * Evaluates the predicate * * @param current the current value. * @return true or false. */ public abstract boolean evaluate(boolean current); @Override public final boolean evaluate(Boolean arg) { return evaluate((boolean) arg); } } DoublePredicate.java000066400000000000000000000013571174000617100353370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/predicatespackage org.multiverse.api.predicates; /** * A predicate that checks if some value leads to true or false. * * @author Peter Veentjer. */ public abstract class DoublePredicate implements Predicate{ public static DoublePredicate newEqualsPredicate(final double value) { return new DoublePredicate() { @Override public boolean evaluate(double current) { return current == value; } }; } /** * Evaluates the predicate * * @param current the current value. * @return true or false. */ public abstract boolean evaluate(double current); @Override public final boolean evaluate(Double arg) { return evaluate((double) arg); } } IntPredicate.java000066400000000000000000000040221174000617100346470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/predicatespackage org.multiverse.api.predicates; /** * A predicate that checks if some value leads to true or false. * * @author Peter Veentjer. */ public abstract class IntPredicate implements Predicate{ public static IntPredicate newEqualsPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(int current) { return current == value; } }; } public static IntPredicate newNotEqualsPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current != value; } }; } public static IntPredicate newLargerThanPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current > value; } }; } public static IntPredicate newLargerThanOrEqualsPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current >= value; } }; } public static IntPredicate newSmallerThanPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current < value; } }; } public static IntPredicate newSmallerThanOrEqualsPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current <= value; } }; } /** * Evaluates the predicate * * @param current the current value. * @return true or false. */ public abstract boolean evaluate(int current); @Override public final boolean evaluate(Integer arg) { return evaluate((int) arg); } } LongPredicate.java000066400000000000000000000040541174000617100350210ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/predicatespackage org.multiverse.api.predicates; /** * A predicate that checks if some value leads to true or false. * * @author Peter Veentjer. */ public abstract class LongPredicate implements Predicate{ public static LongPredicate newEqualsPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current == value; } }; } public static LongPredicate newNotEqualsPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current != value; } }; } public static LongPredicate newLargerThanPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current > value; } }; } public static LongPredicate newLargerThanOrEqualsPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current >= value; } }; } public static LongPredicate newSmallerThanPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current < value; } }; } public static LongPredicate newSmallerThanOrEqualsPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current <= value; } }; } /** * Evaluates the predicate * * @param current the current value. * @return true or false. */ public abstract boolean evaluate(long current); @Override public final boolean evaluate(Long arg) { return evaluate((long) arg); } } Predicate.java000066400000000000000000000005201174000617100341730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/predicatespackage org.multiverse.api.predicates; /** * A predicate that checks if some value leads to true or false. * * @author Peter Veentjer. */ public interface Predicate{ /** * Evaluates the predicate. * * @param value the value to evaluate. * @return true or false. */ boolean evaluate(E value); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/predicates/Predicate.vm000066400000000000000000000121271174000617100337610ustar00rootroot00000000000000package org.multiverse.api.predicates; /** * A predicate that checks if some value leads to true or false. * * @author Peter Veentjer. */ #if(${transactionalObject.referenceInterface} eq 'TxnRef') public interface ${transactionalObject.predicateClass}${transactionalObject.typeParameter}{ /** * Evaluates the predicate. * * @param value the value to evaluate. * @return true or false. */ boolean evaluate(${transactionalObject.type} value); } #else public abstract class ${transactionalObject.predicateClass} implements Predicate<${transactionalObject.objectType}>{ #if(${transactionalObject.referenceInterface} eq 'TxnLong') public static LongPredicate newEqualsPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current == value; } }; } public static LongPredicate newNotEqualsPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current != value; } }; } public static LongPredicate newLargerThanPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current > value; } }; } public static LongPredicate newLargerThanOrEqualsPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current >= value; } }; } public static LongPredicate newSmallerThanPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current < value; } }; } public static LongPredicate newSmallerThanOrEqualsPredicate(final long value) { return new LongPredicate() { @Override public boolean evaluate(final long current) { return current <= value; } }; } #elseif (${transactionalObject.referenceInterface} eq 'TxnInteger') public static IntPredicate newEqualsPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(int current) { return current == value; } }; } public static IntPredicate newNotEqualsPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current != value; } }; } public static IntPredicate newLargerThanPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current > value; } }; } public static IntPredicate newLargerThanOrEqualsPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current >= value; } }; } public static IntPredicate newSmallerThanPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current < value; } }; } public static IntPredicate newSmallerThanOrEqualsPredicate(final int value) { return new IntPredicate() { @Override public boolean evaluate(final int current) { return current <= value; } }; } #elseif (${transactionalObject.referenceInterface} eq 'TxnBoolean') public static BooleanPredicate newEqualsPredicate(final boolean value) { return new BooleanPredicate() { @Override public boolean evaluate(final boolean current) { return current == value; } }; } public static BooleanPredicate newNotEqualsPredicate(final boolean value) { return new BooleanPredicate() { @Override public boolean evaluate(final boolean current) { return current != value; } }; } #elseif (${transactionalObject.referenceInterface} eq 'TxnDouble') public static DoublePredicate newEqualsPredicate(final double value) { return new DoublePredicate() { @Override public boolean evaluate(double current) { return current == value; } }; } #end /** * Evaluates the predicate * * @param current the current value. * @return true or false. */ public abstract boolean evaluate(${transactionalObject.type} current); @Override public final boolean evaluate(${transactionalObject.objectType} arg) { return evaluate((${transactionalObject.type}) arg); } } #end Predicates.java000066400000000000000000000020541174000617100343620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/predicatespackage org.multiverse.api.predicates; /** * Predicate utility class. * * @author Peter Veentjer. */ public final class Predicates { private final static Predicate IsNullPredicate = new Predicate() { public boolean evaluate(Object value) { return value == null; } }; private final static Predicate IsNotNullPredicate = new Predicate() { public boolean evaluate(Object value) { return value != null; } }; /** * Creates a Predicate that checks if the passed object is null. You will get an existing instance. * * @return the Predicate. */ public static Predicate newIsNullPredicate() { return IsNullPredicate; } /** * Creates a Predicate that checks if the passed object is not null. You will get an existing instance. * * @return the Predicate. */ public static Predicate newIsNotNullPredicate() { return IsNotNullPredicate; } //we don't want instances. private Predicates() { } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/references/000077500000000000000000000000001174000617100315105ustar00rootroot00000000000000TxnBoolean.java000066400000000000000000000557171174000617100343640ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/referencespackage org.multiverse.api.references; import org.multiverse.api.*; import org.multiverse.api.functions.*; import org.multiverse.api.predicates.*; /** * A Transactional Reference comparable to the Clojure Ref. * If a method is prefixed with atomic, the call will always run under its own txn, no * matter if there already is a txn available (so the propagation level is {@link PropagationLevel#RequiresNew}). * For the other methods, always an txn needs to be available, else you will get the * {@link org.multiverse.api.exceptions.TxnMandatoryException}. * *

ControlFlowError

* *

All non atomic methods are able to throw a (subclass) of the {@link org.multiverse.api.exceptions.ControlFlowError}. This error should * not be caught, it is task of the {@link TxnExecutor} to deal with. * *

TransactionExecutionException

* *

Most of the methods can throw a {@link org.multiverse.api.exceptions.TxnExecutionException}. * This exception can be caught, but in most cases you want to figure out what the cause is (e.g. because * there are too many retries) and solve that problem. * *

Threadsafe

* *

All methods are threadsafe. * * @author Peter Veentjer. */ public interface TxnBoolean extends TxnObject { /** * Gets the value using the provided txn. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ boolean get(); /** * Gets the value and applies the lock. If the current lockMode already is higher than the provided lockMode * the Lock is not upgraded to a higher value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param lockMode the LockMode applied. * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ boolean getAndLock(LockMode lockMode); /** * Gets the value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @return the value stored in the ref. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean get(Txn txn); /** * Gets the value using the provided txn and acquired the lock with the specified LockMode. * * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used * @return the value stored in the ref. * @throws NullPointerException if txn is null or if lockMode is null. If LockMode is null and a running txn is available * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean getAndLock(Txn txn, LockMode lockMode); /** * Sets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean set(boolean value); /** * Sets the new value and applies the lock. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param lockMode the used LockMode. * @return the new value. * @throws NullPointerException if lockMode is null (if the txn is alive, it will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean setAndLock(boolean value, LockMode lockMode); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @return the old value * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean set(Txn txn, boolean value); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @param lockMode the lockMode used. * @return the old value * @throws NullPointerException if txn is null or lockMode is null. If the lockMode is null and the txn * is alive, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean setAndLock(Txn txn, boolean value, LockMode lockMode); /** * Sets the value the value and returns the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean getAndSet(boolean value); /** * Sets the value, acquired the Lock with the specified Lockmode and returns the previous value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @param lockMode the LockMode used. * @throws NullPointerException if LockMode is null. If a running txn is available, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean getAndSetAndLock(boolean value, LockMode lockMode); /** * Sets the value using the provided txn. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean getAndSet(Txn txn, boolean value); /** * Sets the value and acquired the Lock with the provided LockMode. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used. * @return the old value. * @throws NullPointerException if txn or LockMode is null. If the txn is running, and the LockMode is null, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean getAndSetAndLock(Txn txn, boolean value, LockMode lockMode); /** * Atomically gets the value. The value could be stale as soon as it is returned. This * method doesn't care about any running txns. It could be that this call fails * e.g. when a ref is locked. If you don't care about correct orderings, see the * {@link #atomicWeakGet()}. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicGet(); /** * Atomically gets the value without providing any ordering guarantees. This method is extremely * cheap and will never fail. So even if the ref is privatized, this call will still complete. * *

It is the best method to call if you just want to get the current value stored. * * @return the value. */ boolean atomicWeakGet(); /** * Atomically sets the value and returns the new value. This method doesn't care about any * running txns. * * @param newValue the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicSet(boolean newValue); /** * Atomically sets the value and returns the previous value. This method doesn't care about * any running txns. * * @param newValue the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicGetAndSet(boolean newValue); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function to apply to this reference. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(BooleanFunction function); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param txn the {@link Txn} used for this operation. * @param function the function to apply to this reference. * @throws NullPointerException if function is null. If there is an active txn, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(Txn txn,BooleanFunction function); /** * Atomically applies the function to the current value in this ref and returns the new value. This method doesn't care about * any running txns. * * @param function the Function used * @return the new value. * @throws NullPointerException if function is null. */ boolean atomicAlterAndGet(BooleanFunction function); /** * Alters the value stored in this Ref using the provided function and returns the result. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the new value. * @throws NullPointerException if function is null. The Txn will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean alterAndGet(BooleanFunction function); /** * Alters the value stored in this Ref using the provided function and lifting on the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the new value. * @throws NullPointerException if function or txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean alterAndGet(Txn txn,BooleanFunction function); /** * Atomically applies the function to alter the value stored in this ref and returns the old value. This method doesn't care about * any running txns. * * @param function the Function used * @return the old value. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicGetAndAlter(BooleanFunction function); /** * Alters the value stored in this Ref using the provided function amd returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the old value. * @throws NullPointerException if function is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean getAndAlter(BooleanFunction function); /** * Alters the value stored in this Ref using the function and returns the old value, using the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the old value * @throws NullPointerException if function or txn is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean getAndAlter(Txn txn, BooleanFunction function); /** * Executes a compare and set atomically. This method doesn't care about any running txns. * * @param expectedValue the expected value. * @param newValue the new value. * @return true if the compareAndSwap was a success, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicCompareAndSet(boolean expectedValue, boolean newValue); /** * Awaits for the value to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the value to wait for. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(boolean value); /** * Awaits for the reference to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * * @param txn the {@link Txn} used for this operation. * @param value the value to wait for. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn,boolean value); /** * Awaits until the predicate holds. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(BooleanPredicate predicate); /** * Awaits until the predicate holds using the provided txn. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * * @param txn the {@link Txn} used for this operation. * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null or txn is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn, BooleanPredicate predicate); } TxnDouble.java000066400000000000000000000650211174000617100342040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/referencespackage org.multiverse.api.references; import org.multiverse.api.*; import org.multiverse.api.functions.*; import org.multiverse.api.predicates.*; /** * A Transactional Reference comparable to the Clojure Ref. * If a method is prefixed with atomic, the call will always run under its own txn, no * matter if there already is a txn available (so the propagation level is {@link PropagationLevel#RequiresNew}). * For the other methods, always an txn needs to be available, else you will get the * {@link org.multiverse.api.exceptions.TxnMandatoryException}. * *

ControlFlowError

* *

All non atomic methods are able to throw a (subclass) of the {@link org.multiverse.api.exceptions.ControlFlowError}. This error should * not be caught, it is task of the {@link TxnExecutor} to deal with. * *

TransactionExecutionException

* *

Most of the methods can throw a {@link org.multiverse.api.exceptions.TxnExecutionException}. * This exception can be caught, but in most cases you want to figure out what the cause is (e.g. because * there are too many retries) and solve that problem. * *

Threadsafe

* *

All methods are threadsafe. * * @author Peter Veentjer. */ public interface TxnDouble extends TxnObject { /** * Gets the value using the provided txn. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ double get(); /** * Gets the value and applies the lock. If the current lockMode already is higher than the provided lockMode * the Lock is not upgraded to a higher value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param lockMode the LockMode applied. * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ double getAndLock(LockMode lockMode); /** * Gets the value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @return the value stored in the ref. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double get(Txn txn); /** * Gets the value using the provided txn and acquired the lock with the specified LockMode. * * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used * @return the value stored in the ref. * @throws NullPointerException if txn is null or if lockMode is null. If LockMode is null and a running txn is available * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndLock(Txn txn, LockMode lockMode); /** * Sets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double set(double value); /** * Sets the new value and applies the lock. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param lockMode the used LockMode. * @return the new value. * @throws NullPointerException if lockMode is null (if the txn is alive, it will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double setAndLock(double value, LockMode lockMode); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @return the old value * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double set(Txn txn, double value); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @param lockMode the lockMode used. * @return the old value * @throws NullPointerException if txn is null or lockMode is null. If the lockMode is null and the txn * is alive, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double setAndLock(Txn txn, double value, LockMode lockMode); /** * Sets the value the value and returns the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndSet(double value); /** * Sets the value, acquired the Lock with the specified Lockmode and returns the previous value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @param lockMode the LockMode used. * @throws NullPointerException if LockMode is null. If a running txn is available, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndSetAndLock(double value, LockMode lockMode); /** * Sets the value using the provided txn. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndSet(Txn txn, double value); /** * Sets the value and acquired the Lock with the provided LockMode. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used. * @return the old value. * @throws NullPointerException if txn or LockMode is null. If the txn is running, and the LockMode is null, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndSetAndLock(Txn txn, double value, LockMode lockMode); /** * Atomically gets the value. The value could be stale as soon as it is returned. This * method doesn't care about any running txns. It could be that this call fails * e.g. when a ref is locked. If you don't care about correct orderings, see the * {@link #atomicWeakGet()}. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ double atomicGet(); /** * Atomically gets the value without providing any ordering guarantees. This method is extremely * cheap and will never fail. So even if the ref is privatized, this call will still complete. * *

It is the best method to call if you just want to get the current value stored. * * @return the value. */ double atomicWeakGet(); /** * Atomically sets the value and returns the new value. This method doesn't care about any * running txns. * * @param newValue the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ double atomicSet(double newValue); /** * Atomically sets the value and returns the previous value. This method doesn't care about * any running txns. * * @param newValue the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ double atomicGetAndSet(double newValue); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function to apply to this reference. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(DoubleFunction function); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param txn the {@link Txn} used for this operation. * @param function the function to apply to this reference. * @throws NullPointerException if function is null. If there is an active txn, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(Txn txn,DoubleFunction function); /** * Atomically applies the function to the current value in this ref and returns the new value. This method doesn't care about * any running txns. * * @param function the Function used * @return the new value. * @throws NullPointerException if function is null. */ double atomicAlterAndGet(DoubleFunction function); /** * Alters the value stored in this Ref using the provided function and returns the result. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the new value. * @throws NullPointerException if function is null. The Txn will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double alterAndGet(DoubleFunction function); /** * Alters the value stored in this Ref using the provided function and lifting on the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the new value. * @throws NullPointerException if function or txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double alterAndGet(Txn txn,DoubleFunction function); /** * Atomically applies the function to alter the value stored in this ref and returns the old value. This method doesn't care about * any running txns. * * @param function the Function used * @return the old value. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException */ double atomicGetAndAlter(DoubleFunction function); /** * Alters the value stored in this Ref using the provided function amd returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the old value. * @throws NullPointerException if function is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndAlter(DoubleFunction function); /** * Alters the value stored in this Ref using the function and returns the old value, using the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the old value * @throws NullPointerException if function or txn is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndAlter(Txn txn, DoubleFunction function); /** * Executes a compare and set atomically. This method doesn't care about any running txns. * * @param expectedValue the expected value. * @param newValue the new value. * @return true if the compareAndSwap was a success, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicCompareAndSet(double expectedValue, double newValue); /** * Atomically increments the value and returns the old value. This method doesn't care about * any running txns. * * @param amount the amount to increase with. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ double atomicGetAndIncrement(double amount); /** * Increments the value and returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increment with. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndIncrement(double amount); /** * Increments the value and returns the old value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double getAndIncrement(Txn txn, double amount); /** * Atomically increments the value and returns the old value. This method doesn't care about any * running txns. * * @param amount the amount to increment with. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ double atomicIncrementAndGet(double amount); /** * Increments and gets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increment with. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double incrementAndGet(double amount); /** * Increments and gets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with. * @return the new value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ double incrementAndGet(Txn txn, double amount); /** * Awaits for the value to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the value to wait for. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(double value); /** * Awaits for the reference to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * * @param txn the {@link Txn} used for this operation. * @param value the value to wait for. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn,double value); /** * Awaits until the predicate holds. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(DoublePredicate predicate); /** * Awaits until the predicate holds using the provided txn. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * * @param txn the {@link Txn} used for this operation. * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null or txn is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn, DoublePredicate predicate); } TxnInteger.java000066400000000000000000001016071174000617100343700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/referencespackage org.multiverse.api.references; import org.multiverse.api.*; import org.multiverse.api.functions.*; import org.multiverse.api.predicates.*; /** * A Transactional Reference comparable to the Clojure Ref. * If a method is prefixed with atomic, the call will always run under its own txn, no * matter if there already is a txn available (so the propagation level is {@link PropagationLevel#RequiresNew}). * For the other methods, always an txn needs to be available, else you will get the * {@link org.multiverse.api.exceptions.TxnMandatoryException}. * *

ControlFlowError

* *

All non atomic methods are able to throw a (subclass) of the {@link org.multiverse.api.exceptions.ControlFlowError}. This error should * not be caught, it is task of the {@link TxnExecutor} to deal with. * *

TransactionExecutionException

* *

Most of the methods can throw a {@link org.multiverse.api.exceptions.TxnExecutionException}. * This exception can be caught, but in most cases you want to figure out what the cause is (e.g. because * there are too many retries) and solve that problem. * *

Threadsafe

* *

All methods are threadsafe. * * @author Peter Veentjer. */ public interface TxnInteger extends TxnObject { /** * Gets the value using the provided txn. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ int get(); /** * Gets the value and applies the lock. If the current lockMode already is higher than the provided lockMode * the Lock is not upgraded to a higher value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param lockMode the LockMode applied. * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ int getAndLock(LockMode lockMode); /** * Gets the value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @return the value stored in the ref. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int get(Txn txn); /** * Gets the value using the provided txn and acquired the lock with the specified LockMode. * * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used * @return the value stored in the ref. * @throws NullPointerException if txn is null or if lockMode is null. If LockMode is null and a running txn is available * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndLock(Txn txn, LockMode lockMode); /** * Sets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int set(int value); /** * Sets the new value and applies the lock. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param lockMode the used LockMode. * @return the new value. * @throws NullPointerException if lockMode is null (if the txn is alive, it will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int setAndLock(int value, LockMode lockMode); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @return the old value * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int set(Txn txn, int value); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @param lockMode the lockMode used. * @return the old value * @throws NullPointerException if txn is null or lockMode is null. If the lockMode is null and the txn * is alive, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int setAndLock(Txn txn, int value, LockMode lockMode); /** * Sets the value the value and returns the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndSet(int value); /** * Sets the value, acquired the Lock with the specified Lockmode and returns the previous value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @param lockMode the LockMode used. * @throws NullPointerException if LockMode is null. If a running txn is available, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndSetAndLock(int value, LockMode lockMode); /** * Sets the value using the provided txn. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndSet(Txn txn, int value); /** * Sets the value and acquired the Lock with the provided LockMode. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used. * @return the old value. * @throws NullPointerException if txn or LockMode is null. If the txn is running, and the LockMode is null, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndSetAndLock(Txn txn, int value, LockMode lockMode); /** * Atomically gets the value. The value could be stale as soon as it is returned. This * method doesn't care about any running txns. It could be that this call fails * e.g. when a ref is locked. If you don't care about correct orderings, see the * {@link #atomicWeakGet()}. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ int atomicGet(); /** * Atomically gets the value without providing any ordering guarantees. This method is extremely * cheap and will never fail. So even if the ref is privatized, this call will still complete. * *

It is the best method to call if you just want to get the current value stored. * * @return the value. */ int atomicWeakGet(); /** * Atomically sets the value and returns the new value. This method doesn't care about any * running txns. * * @param newValue the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ int atomicSet(int newValue); /** * Atomically sets the value and returns the previous value. This method doesn't care about * any running txns. * * @param newValue the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ int atomicGetAndSet(int newValue); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function to apply to this reference. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(IntFunction function); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param txn the {@link Txn} used for this operation. * @param function the function to apply to this reference. * @throws NullPointerException if function is null. If there is an active txn, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(Txn txn,IntFunction function); /** * Atomically applies the function to the current value in this ref and returns the new value. This method doesn't care about * any running txns. * * @param function the Function used * @return the new value. * @throws NullPointerException if function is null. */ int atomicAlterAndGet(IntFunction function); /** * Alters the value stored in this Ref using the provided function and returns the result. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the new value. * @throws NullPointerException if function is null. The Txn will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int alterAndGet(IntFunction function); /** * Alters the value stored in this Ref using the provided function and lifting on the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the new value. * @throws NullPointerException if function or txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int alterAndGet(Txn txn,IntFunction function); /** * Atomically applies the function to alter the value stored in this ref and returns the old value. This method doesn't care about * any running txns. * * @param function the Function used * @return the old value. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException */ int atomicGetAndAlter(IntFunction function); /** * Alters the value stored in this Ref using the provided function amd returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the old value. * @throws NullPointerException if function is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndAlter(IntFunction function); /** * Alters the value stored in this Ref using the function and returns the old value, using the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the old value * @throws NullPointerException if function or txn is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndAlter(Txn txn, IntFunction function); /** * Executes a compare and set atomically. This method doesn't care about any running txns. * * @param expectedValue the expected value. * @param newValue the new value. * @return true if the compareAndSwap was a success, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicCompareAndSet(int expectedValue, int newValue); /** * Atomically increments the value and returns the old value. This method doesn't care about * any running txns. * * @param amount the amount to increase with. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ int atomicGetAndIncrement(int amount); /** * Increments the value and returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increment with. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndIncrement(int amount); /** * Increments the value and returns the old value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int getAndIncrement(Txn txn, int amount); /** * Atomically increments the value and returns the old value. This method doesn't care about any * running txns. * * @param amount the amount to increment with. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ int atomicIncrementAndGet(int amount); /** * Increments and gets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increment with. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int incrementAndGet(int amount); /** * Increments and gets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with. * @return the new value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ int incrementAndGet(Txn txn, int amount); /** * Increments the value by one. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(); /** * Increments the value by one using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(Txn txn); /** * Increments the value by the given amount. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increase with * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted.ControlFlowError */ void increment(int amount); /** * Increments the value by the given amount using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(Txn txn, int amount); /** * Decrements the value by one. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(); /** * Decrements the value by one using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(Txn txn); /** * Decrements the value by the given amount. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to decrement with * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(int amount); /** * Decrements the value by the given amount using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to decrement with * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(Txn txn, int amount); /** * Awaits for the value to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the value to wait for. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(int value); /** * Awaits for the reference to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * * @param txn the {@link Txn} used for this operation. * @param value the value to wait for. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn,int value); /** * Awaits until the predicate holds. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(IntPredicate predicate); /** * Awaits until the predicate holds using the provided txn. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * * @param txn the {@link Txn} used for this operation. * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null or txn is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn, IntPredicate predicate); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/references/TxnLong.java000066400000000000000000001017021174000617100337450ustar00rootroot00000000000000package org.multiverse.api.references; import org.multiverse.api.*; import org.multiverse.api.functions.*; import org.multiverse.api.predicates.*; /** * A Transactional Reference comparable to the Clojure Ref. * If a method is prefixed with atomic, the call will always run under its own txn, no * matter if there already is a txn available (so the propagation level is {@link PropagationLevel#RequiresNew}). * For the other methods, always an txn needs to be available, else you will get the * {@link org.multiverse.api.exceptions.TxnMandatoryException}. * *

ControlFlowError

* *

All non atomic methods are able to throw a (subclass) of the {@link org.multiverse.api.exceptions.ControlFlowError}. This error should * not be caught, it is task of the {@link TxnExecutor} to deal with. * *

TransactionExecutionException

* *

Most of the methods can throw a {@link org.multiverse.api.exceptions.TxnExecutionException}. * This exception can be caught, but in most cases you want to figure out what the cause is (e.g. because * there are too many retries) and solve that problem. * *

Threadsafe

* *

All methods are threadsafe. * * @author Peter Veentjer. */ public interface TxnLong extends TxnObject { /** * Gets the value using the provided txn. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ long get(); /** * Gets the value and applies the lock. If the current lockMode already is higher than the provided lockMode * the Lock is not upgraded to a higher value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param lockMode the LockMode applied. * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ long getAndLock(LockMode lockMode); /** * Gets the value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @return the value stored in the ref. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long get(Txn txn); /** * Gets the value using the provided txn and acquired the lock with the specified LockMode. * * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used * @return the value stored in the ref. * @throws NullPointerException if txn is null or if lockMode is null. If LockMode is null and a running txn is available * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndLock(Txn txn, LockMode lockMode); /** * Sets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long set(long value); /** * Sets the new value and applies the lock. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param lockMode the used LockMode. * @return the new value. * @throws NullPointerException if lockMode is null (if the txn is alive, it will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long setAndLock(long value, LockMode lockMode); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @return the old value * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long set(Txn txn, long value); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @param lockMode the lockMode used. * @return the old value * @throws NullPointerException if txn is null or lockMode is null. If the lockMode is null and the txn * is alive, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long setAndLock(Txn txn, long value, LockMode lockMode); /** * Sets the value the value and returns the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndSet(long value); /** * Sets the value, acquired the Lock with the specified Lockmode and returns the previous value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @param lockMode the LockMode used. * @throws NullPointerException if LockMode is null. If a running txn is available, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndSetAndLock(long value, LockMode lockMode); /** * Sets the value using the provided txn. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndSet(Txn txn, long value); /** * Sets the value and acquired the Lock with the provided LockMode. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used. * @return the old value. * @throws NullPointerException if txn or LockMode is null. If the txn is running, and the LockMode is null, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndSetAndLock(Txn txn, long value, LockMode lockMode); /** * Atomically gets the value. The value could be stale as soon as it is returned. This * method doesn't care about any running txns. It could be that this call fails * e.g. when a ref is locked. If you don't care about correct orderings, see the * {@link #atomicWeakGet()}. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ long atomicGet(); /** * Atomically gets the value without providing any ordering guarantees. This method is extremely * cheap and will never fail. So even if the ref is privatized, this call will still complete. * *

It is the best method to call if you just want to get the current value stored. * * @return the value. */ long atomicWeakGet(); /** * Atomically sets the value and returns the new value. This method doesn't care about any * running txns. * * @param newValue the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ long atomicSet(long newValue); /** * Atomically sets the value and returns the previous value. This method doesn't care about * any running txns. * * @param newValue the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ long atomicGetAndSet(long newValue); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function to apply to this reference. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(LongFunction function); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param txn the {@link Txn} used for this operation. * @param function the function to apply to this reference. * @throws NullPointerException if function is null. If there is an active txn, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(Txn txn,LongFunction function); /** * Atomically applies the function to the current value in this ref and returns the new value. This method doesn't care about * any running txns. * * @param function the Function used * @return the new value. * @throws NullPointerException if function is null. */ long atomicAlterAndGet(LongFunction function); /** * Alters the value stored in this Ref using the provided function and returns the result. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the new value. * @throws NullPointerException if function is null. The Txn will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long alterAndGet(LongFunction function); /** * Alters the value stored in this Ref using the provided function and lifting on the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the new value. * @throws NullPointerException if function or txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long alterAndGet(Txn txn,LongFunction function); /** * Atomically applies the function to alter the value stored in this ref and returns the old value. This method doesn't care about * any running txns. * * @param function the Function used * @return the old value. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException */ long atomicGetAndAlter(LongFunction function); /** * Alters the value stored in this Ref using the provided function amd returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the old value. * @throws NullPointerException if function is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndAlter(LongFunction function); /** * Alters the value stored in this Ref using the function and returns the old value, using the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the old value * @throws NullPointerException if function or txn is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndAlter(Txn txn, LongFunction function); /** * Executes a compare and set atomically. This method doesn't care about any running txns. * * @param expectedValue the expected value. * @param newValue the new value. * @return true if the compareAndSwap was a success, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicCompareAndSet(long expectedValue, long newValue); /** * Atomically increments the value and returns the old value. This method doesn't care about * any running txns. * * @param amount the amount to increase with. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ long atomicGetAndIncrement(long amount); /** * Increments the value and returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increment with. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndIncrement(long amount); /** * Increments the value and returns the old value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long getAndIncrement(Txn txn, long amount); /** * Atomically increments the value and returns the old value. This method doesn't care about any * running txns. * * @param amount the amount to increment with. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ long atomicIncrementAndGet(long amount); /** * Increments and gets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increment with. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long incrementAndGet(long amount); /** * Increments and gets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with. * @return the new value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ long incrementAndGet(Txn txn, long amount); /** * Increments the value by one. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(); /** * Increments the value by one using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(Txn txn); /** * Increments the value by the given amount. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increase with * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted.ControlFlowError */ void increment(long amount); /** * Increments the value by the given amount using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(Txn txn, long amount); /** * Decrements the value by one. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(); /** * Decrements the value by one using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(Txn txn); /** * Decrements the value by the given amount. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to decrement with * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(long amount); /** * Decrements the value by the given amount using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to decrement with * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(Txn txn, long amount); /** * Awaits for the value to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the value to wait for. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(long value); /** * Awaits for the reference to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * * @param txn the {@link Txn} used for this operation. * @param value the value to wait for. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn,long value); /** * Awaits until the predicate holds. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(LongPredicate predicate); /** * Awaits until the predicate holds using the provided txn. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * * @param txn the {@link Txn} used for this operation. * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null or txn is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn, LongPredicate predicate); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/references/TxnRef.java000066400000000000000000000665541174000617100336010ustar00rootroot00000000000000package org.multiverse.api.references; import org.multiverse.api.*; import org.multiverse.api.functions.*; import org.multiverse.api.predicates.*; /** * A Transactional Reference comparable to the Clojure Ref. * If a method is prefixed with atomic, the call will always run under its own txn, no * matter if there already is a txn available (so the propagation level is {@link PropagationLevel#RequiresNew}). * For the other methods, always an txn needs to be available, else you will get the * {@link org.multiverse.api.exceptions.TxnMandatoryException}. * *

ControlFlowError

* *

All non atomic methods are able to throw a (subclass) of the {@link org.multiverse.api.exceptions.ControlFlowError}. This error should * not be caught, it is task of the {@link TxnExecutor} to deal with. * *

TransactionExecutionException

* *

Most of the methods can throw a {@link org.multiverse.api.exceptions.TxnExecutionException}. * This exception can be caught, but in most cases you want to figure out what the cause is (e.g. because * there are too many retries) and solve that problem. * *

Threadsafe

* *

All methods are threadsafe. * * @author Peter Veentjer. */ public interface TxnRef extends TxnObject { /** * Gets the value using the provided txn. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ E get(); /** * Gets the value and applies the lock. If the current lockMode already is higher than the provided lockMode * the Lock is not upgraded to a higher value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param lockMode the LockMode applied. * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ E getAndLock(LockMode lockMode); /** * Gets the value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @return the value stored in the ref. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E get(Txn txn); /** * Gets the value using the provided txn and acquired the lock with the specified LockMode. * * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used * @return the value stored in the ref. * @throws NullPointerException if txn is null or if lockMode is null. If LockMode is null and a running txn is available * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E getAndLock(Txn txn, LockMode lockMode); /** * Sets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E set(E value); /** * Sets the new value and applies the lock. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param lockMode the used LockMode. * @return the new value. * @throws NullPointerException if lockMode is null (if the txn is alive, it will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E setAndLock(E value, LockMode lockMode); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @return the old value * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E set(Txn txn, E value); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @param lockMode the lockMode used. * @return the old value * @throws NullPointerException if txn is null or lockMode is null. If the lockMode is null and the txn * is alive, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E setAndLock(Txn txn, E value, LockMode lockMode); /** * Sets the value the value and returns the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E getAndSet(E value); /** * Sets the value, acquired the Lock with the specified Lockmode and returns the previous value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @param lockMode the LockMode used. * @throws NullPointerException if LockMode is null. If a running txn is available, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E getAndSetAndLock(E value, LockMode lockMode); /** * Sets the value using the provided txn. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E getAndSet(Txn txn, E value); /** * Sets the value and acquired the Lock with the provided LockMode. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used. * @return the old value. * @throws NullPointerException if txn or LockMode is null. If the txn is running, and the LockMode is null, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E getAndSetAndLock(Txn txn, E value, LockMode lockMode); /** * Atomically gets the value. The value could be stale as soon as it is returned. This * method doesn't care about any running txns. It could be that this call fails * e.g. when a ref is locked. If you don't care about correct orderings, see the * {@link #atomicWeakGet()}. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ E atomicGet(); /** * Atomically gets the value without providing any ordering guarantees. This method is extremely * cheap and will never fail. So even if the ref is privatized, this call will still complete. * *

It is the best method to call if you just want to get the current value stored. * * @return the value. */ E atomicWeakGet(); /** * Atomically sets the value and returns the new value. This method doesn't care about any * running txns. * * @param newValue the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ E atomicSet(E newValue); /** * Atomically sets the value and returns the previous value. This method doesn't care about * any running txns. * * @param newValue the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ E atomicGetAndSet(E newValue); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function to apply to this reference. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(Function function); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param txn the {@link Txn} used for this operation. * @param function the function to apply to this reference. * @throws NullPointerException if function is null. If there is an active txn, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(Txn txn,Function function); /** * Atomically applies the function to the current value in this ref and returns the new value. This method doesn't care about * any running txns. * * @param function the Function used * @return the new value. * @throws NullPointerException if function is null. */ E atomicAlterAndGet(Function function); /** * Alters the value stored in this Ref using the provided function and returns the result. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the new value. * @throws NullPointerException if function is null. The Txn will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E alterAndGet(Function function); /** * Alters the value stored in this Ref using the provided function and lifting on the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the new value. * @throws NullPointerException if function or txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E alterAndGet(Txn txn,Function function); /** * Atomically applies the function to alter the value stored in this ref and returns the old value. This method doesn't care about * any running txns. * * @param function the Function used * @return the old value. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException */ E atomicGetAndAlter(Function function); /** * Alters the value stored in this Ref using the provided function amd returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the old value. * @throws NullPointerException if function is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E getAndAlter(Function function); /** * Alters the value stored in this Ref using the function and returns the old value, using the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the old value * @throws NullPointerException if function or txn is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E getAndAlter(Txn txn, Function function); /** * Executes a compare and set atomically. This method doesn't care about any running txns. * * @param expectedValue the expected value. * @param newValue the new value. * @return true if the compareAndSwap was a success, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicCompareAndSet(E expectedValue, E newValue); /** * Checks if the current value is null. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @return true if null, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean isNull(); /** * Checks if the current value is null using the provided txn. * * @param txn the {@link Txn} used for this operation. * @return true if the value is null, false otherwise. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean isNull(Txn txn); /** * Atomically check if the current value is null. This method doesn't care about any running txns. * * @return true if null, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicIsNull(); /** * Awaits for the value to become not null. If the value already is not null, * this call returns the stored value. If the value is null, a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @return the stored value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E awaitNotNullAndGet(); /** * Awaits for the value to become not null using the provided txn. If the value already is not null, * this call returns the stored value. If the value is null, a retry is done. * * @param txn the {@link Txn} used for this operation. * @return the stored value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ E awaitNotNullAndGet(Txn txn); /** * Awaits for the value to become null. If the value already is null, * this call continues. If the reference is not null, a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void awaitNull(); /** * Awaits for the value to become not null using the provided txn. If the value already is null, * this call continues. If the value is not null, a retry is done. * * @param txn the {@link Txn} used for this operation. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void awaitNull(Txn txn); /** * Awaits for the value to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the value to wait for. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(E value); /** * Awaits for the reference to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * * @param txn the {@link Txn} used for this operation. * @param value the value to wait for. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn,E value); /** * Awaits until the predicate holds. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Predicate predicate); /** * Awaits until the predicate holds using the provided txn. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * * @param txn the {@link Txn} used for this operation. * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null or txn is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn, Predicate predicate); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/references/TxnRef.vm000066400000000000000000001173131174000617100332700ustar00rootroot00000000000000package org.multiverse.api.references; import org.multiverse.api.*; import org.multiverse.api.functions.*; import org.multiverse.api.predicates.*; /** * A Transactional Reference comparable to the Clojure Ref. * If a method is prefixed with atomic, the call will always run under its own txn, no * matter if there already is a txn available (so the propagation level is {@link PropagationLevel#RequiresNew}). * For the other methods, always an txn needs to be available, else you will get the * {@link org.multiverse.api.exceptions.TxnMandatoryException}. * *

ControlFlowError

* *

All non atomic methods are able to throw a (subclass) of the {@link org.multiverse.api.exceptions.ControlFlowError}. This error should * not be caught, it is task of the {@link TxnExecutor} to deal with. * *

TransactionExecutionException

* *

Most of the methods can throw a {@link org.multiverse.api.exceptions.TxnExecutionException}. * This exception can be caught, but in most cases you want to figure out what the cause is (e.g. because * there are too many retries) and solve that problem. * *

Threadsafe

* *

All methods are threadsafe. * #if(${transactionalObject.referenceInterface} eq "Ref") * @param #end * @author Peter Veentjer. */ public interface ${transactionalObject.referenceInterface}${transactionalObject.typeParameter} extends TxnObject { /** * Gets the value using the provided txn. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ ${transactionalObject.type} get(); /** * Gets the value and applies the lock. If the current lockMode already is higher than the provided lockMode * the Lock is not upgraded to a higher value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param lockMode the LockMode applied. * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. * @see #atomicGet() */ ${transactionalObject.type} getAndLock(LockMode lockMode); /** * Gets the value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @return the value stored in the ref. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} get(Txn txn); /** * Gets the value using the provided txn and acquired the lock with the specified LockMode. * * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used * @return the value stored in the ref. * @throws NullPointerException if txn is null or if lockMode is null. If LockMode is null and a running txn is available * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndLock(Txn txn, LockMode lockMode); /** * Sets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} set(${transactionalObject.type} value); /** * Sets the new value and applies the lock. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param lockMode the used LockMode. * @return the new value. * @throws NullPointerException if lockMode is null (if the txn is alive, it will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} setAndLock(${transactionalObject.type} value, LockMode lockMode); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @return the old value * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} set(Txn txn, ${transactionalObject.type} value); /** * Sets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param value the new value * @param lockMode the lockMode used. * @return the old value * @throws NullPointerException if txn is null or lockMode is null. If the lockMode is null and the txn * is alive, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} setAndLock(Txn txn, ${transactionalObject.type} value, LockMode lockMode); /** * Sets the value the value and returns the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndSet(${transactionalObject.type} value); /** * Sets the value, acquired the Lock with the specified Lockmode and returns the previous value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @return the old value. * @param lockMode the LockMode used. * @throws NullPointerException if LockMode is null. If a running txn is available, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndSetAndLock(${transactionalObject.type} value, LockMode lockMode); /** * Sets the value using the provided txn. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndSet(Txn txn, ${transactionalObject.type} value); /** * Sets the value and acquired the Lock with the provided LockMode. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the new value. * @param txn the {@link Txn} used for this operation. * @param lockMode the LockMode used. * @return the old value. * @throws NullPointerException if txn or LockMode is null. If the txn is running, and the LockMode is null, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndSetAndLock(Txn txn, ${transactionalObject.type} value, LockMode lockMode); /** * Atomically gets the value. The value could be stale as soon as it is returned. This * method doesn't care about any running txns. It could be that this call fails * e.g. when a ref is locked. If you don't care about correct orderings, see the * {@link #atomicWeakGet()}. * * @return the current value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ ${transactionalObject.type} atomicGet(); /** * Atomically gets the value without providing any ordering guarantees. This method is extremely * cheap and will never fail. So even if the ref is privatized, this call will still complete. * *

It is the best method to call if you just want to get the current value stored. * * @return the value. */ ${transactionalObject.type} atomicWeakGet(); /** * Atomically sets the value and returns the new value. This method doesn't care about any * running txns. * * @param newValue the new value. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ ${transactionalObject.type} atomicSet(${transactionalObject.type} newValue); /** * Atomically sets the value and returns the previous value. This method doesn't care about * any running txns. * * @param newValue the new value. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ ${transactionalObject.type} atomicGetAndSet(${transactionalObject.type} newValue); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function to apply to this reference. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(${transactionalObject.functionClass}${transactionalObject.typeParameter} function); /** * Applies the function on the ref in a commuting manner. So if there are no dependencies, the function * will commute. If somehow there already is a dependency or a dependency is formed on the result of * the commuting function, the function will not commute and will be exactly the same as an alter. * *

This is different than the behavior in Clojure where the commute will be re-applied at the end * of the txn, even though some dependency is introduced, which can lead to inconsistencies. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param txn the {@link Txn} used for this operation. * @param function the function to apply to this reference. * @throws NullPointerException if function is null. If there is an active txn, it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void commute(Txn txn,${transactionalObject.functionClass}${transactionalObject.typeParameter} function); /** * Atomically applies the function to the current value in this ref and returns the new value. This method doesn't care about * any running txns. * * @param function the Function used * @return the new value. * @throws NullPointerException if function is null. */ ${transactionalObject.type} atomicAlterAndGet(${transactionalObject.functionClass}${transactionalObject.typeParameter} function); /** * Alters the value stored in this Ref using the provided function and returns the result. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the new value. * @throws NullPointerException if function is null. The Txn will also be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} alterAndGet(${transactionalObject.functionClass}${transactionalObject.typeParameter} function); /** * Alters the value stored in this Ref using the provided function and lifting on the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the new value. * @throws NullPointerException if function or txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} alterAndGet(Txn txn,${transactionalObject.functionClass}${transactionalObject.typeParameter} function); /** * Atomically applies the function to alter the value stored in this ref and returns the old value. This method doesn't care about * any running txns. * * @param function the Function used * @return the old value. * @throws NullPointerException if function is null. * @throws org.multiverse.api.exceptions.TxnExecutionException */ ${transactionalObject.type} atomicGetAndAlter(${transactionalObject.functionClass}${transactionalObject.typeParameter} function); /** * Alters the value stored in this Ref using the provided function amd returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param function the function that alters the value stored in this Ref. * @return the old value. * @throws NullPointerException if function is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndAlter(${transactionalObject.functionClass}${transactionalObject.typeParameter} function); /** * Alters the value stored in this Ref using the function and returns the old value, using the provided txn. * * @param function the function that alters the value stored in this Ref. * @param txn the {@link Txn} used for this operation. * @return the old value * @throws NullPointerException if function or txn is null. The txn will be aborted as well. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndAlter(Txn txn, ${transactionalObject.functionClass}${transactionalObject.typeParameter} function); /** * Executes a compare and set atomically. This method doesn't care about any running txns. * * @param expectedValue the expected value. * @param newValue the new value. * @return true if the compareAndSwap was a success, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicCompareAndSet(${transactionalObject.type} expectedValue, ${transactionalObject.type} newValue); #if(${transactionalObject.isNumber}) /** * Atomically increments the value and returns the old value. This method doesn't care about * any running txns. * * @param amount the amount to increase with. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ ${transactionalObject.type} atomicGetAndIncrement(${transactionalObject.type} amount); /** * Increments the value and returns the old value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increment with. * @return the old value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndIncrement(${transactionalObject.type} amount); /** * Increments the value and returns the old value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with. * @return the old value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} getAndIncrement(Txn txn, ${transactionalObject.type} amount); /** * Atomically increments the value and returns the old value. This method doesn't care about any * running txns. * * @param amount the amount to increment with. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException */ ${transactionalObject.type} atomicIncrementAndGet(${transactionalObject.type} amount); /** * Increments and gets the new value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increment with. * @return the new value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} incrementAndGet(${transactionalObject.type} amount); /** * Increments and gets the new value using the provided txn. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with. * @return the new value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} incrementAndGet(Txn txn, ${transactionalObject.type} amount); #if(${transactionalObject.incFunctionMethod} ne '') /** * Increments the value by one. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(); /** * Increments the value by one using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(Txn txn); /** * Increments the value by the given amount. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to increase with * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted.ControlFlowError */ void increment(${transactionalObject.type} amount); /** * Increments the value by the given amount using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to increment with * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void increment(Txn txn, ${transactionalObject.type} amount); /** * Decrements the value by one. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(); /** * Decrements the value by one using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(Txn txn); /** * Decrements the value by the given amount. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param amount the amount to decrement with * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(${transactionalObject.type} amount); /** * Decrements the value by the given amount using the provided txn. * *

This call is able to commute if there are no dependencies on the value in the * txn. That is why this method doesn't have a return value. * * @param txn the {@link Txn} used for this operation. * @param amount the amount to decrement with * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void decrement(Txn txn, ${transactionalObject.type} amount); #end #elseif(${transactionalObject.referenceInterface} eq "TxnRef") /** * Checks if the current value is null. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @return true if null, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean isNull(); /** * Checks if the current value is null using the provided txn. * * @param txn the {@link Txn} used for this operation. * @return true if the value is null, false otherwise. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ boolean isNull(Txn txn); /** * Atomically check if the current value is null. This method doesn't care about any running txns. * * @return true if null, false otherwise. * @throws org.multiverse.api.exceptions.TxnExecutionException */ boolean atomicIsNull(); /** * Awaits for the value to become not null. If the value already is not null, * this call returns the stored value. If the value is null, a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @return the stored value. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} awaitNotNullAndGet(); /** * Awaits for the value to become not null using the provided txn. If the value already is not null, * this call returns the stored value. If the value is null, a retry is done. * * @param txn the {@link Txn} used for this operation. * @return the stored value. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ ${transactionalObject.type} awaitNotNullAndGet(Txn txn); /** * Awaits for the value to become null. If the value already is null, * this call continues. If the reference is not null, a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void awaitNull(); /** * Awaits for the value to become not null using the provided txn. If the value already is null, * this call continues. If the value is not null, a retry is done. * * @param txn the {@link Txn} used for this operation. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void awaitNull(Txn txn); #end /** * Awaits for the value to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param value the value to wait for. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(${transactionalObject.type} value); /** * Awaits for the reference to become the given value. If the value already has the * the specified value, the call continues, else a retry is done. * * @param txn the {@link Txn} used for this operation. * @param value the value to wait for. * @throws NullPointerException if txn is null. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn,${transactionalObject.type} value); /** * Awaits until the predicate holds. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * *

This call lifts on the {@link org.multiverse.api.Txn} stored in the {@link org.multiverse.api.TxnThreadLocal}. * * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(${transactionalObject.predicateClass}${transactionalObject.typeParameter} predicate); /** * Awaits until the predicate holds using the provided txn. If the value already evaluates to true, the call continues * else a retry is done. If the predicate throws an exception, the txn is aborted and the * throwable is propagated. * * @param txn the {@link Txn} used for this operation. * @param predicate the predicate to evaluate. * @throws NullPointerException if predicate is null or txn is null. When there is a non dead txn, * it will be aborted. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the txn. The txn is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.ControlFlowError * if the Stm needs to control the flow in a different way than normal returns of exceptions. The txn * is guaranteed to have been aborted. */ void await(Txn txn, ${transactionalObject.predicateClass}${transactionalObject.typeParameter} predicate); } TxnRefFactory.java000066400000000000000000000020711174000617100350320ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/referencespackage org.multiverse.api.references; /** * A Factory for creating references. * * @author Peter Veentjer. */ public interface TxnRefFactory { /** * Creates a committed TxnRef. * * @param value the initial value. * @return the created TxnRef. */ TxnRef newTxnRef(E value); /** * Creates a committed TxnInteger. * * @param value the initial value. * @return the created TxnInteger. */ TxnInteger newTxnInteger(int value); /** * Creates a committed TxnBoolean. * * @param value the initial value. * @return the created TxnBoolean. */ TxnBoolean newTxnBoolean(boolean value); /** * Creates a committed TxnDouble. * * @param value the initial value. * @return the created TxnDouble. */ TxnDouble newTxnDouble(double value); /** * Creates a committed TxnLong. * * @param value the initial value. * @return the created TxnLong. */ TxnLong newTxnLong(long value); } TxnRefFactory.vm000066400000000000000000000007671174000617100345450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/referencespackage org.multiverse.api.references; /** * A Factory for creating references. * * @author Peter Veentjer. */ public interface TxnRefFactory { #foreach($ref in $refs) #if(${ref.isReference}) /** * Creates a committed ${ref.referenceInterface}. * * @param value the initial value. * @return the created ${ref.referenceInterface}. */ ${ref.typeParameter} ${ref.referenceInterface}${ref.typeParameter} new${ref.referenceInterface}(${ref.type} value); #end #end } TxnRefFactoryBuilder.java000066400000000000000000000010051174000617100363350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/api/referencespackage org.multiverse.api.references; /** * A Builder for creating a {@link TxnRefFactory}. Atm it doesn't provide functionality, but in the future it will * contains similar configuration mechanism as the {@link org.multiverse.api.TxnFactoryBuilder}. *

* A TxnRefFactoryBuilder is considered immutable. * * @author Peter Veentjer. */ public interface TxnRefFactoryBuilder { /** * Builds a TxnRefFactory. * * @return the build reference factory. */ TxnRefFactory build(); } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collections/000077500000000000000000000000001174000617100311345ustar00rootroot00000000000000AbstractTxnCollection.java000066400000000000000000000074321174000617100361770ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collectionspackage org.multiverse.collections; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.collections.TxnCollection; import org.multiverse.api.collections.TxnIterator; import org.multiverse.api.references.TxnRefFactory; import java.util.Collection; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public abstract class AbstractTxnCollection implements TxnCollection { protected final Stm stm; protected final TxnRefFactory defaultRefFactory; protected AbstractTxnCollection(Stm stm) { if (stm == null) { throw new NullPointerException(); } this.stm = stm; this.defaultRefFactory = stm.getDefaultRefFactory(); } @Override public Stm getStm() { return stm; } @Override public boolean isEmpty() { return isEmpty(getThreadLocalTxn()); } @Override public boolean isEmpty(final Txn tx) { return size(tx) == 0; } @Override public int size() { return size(getThreadLocalTxn()); } @Override public void clear() { clear(getThreadLocalTxn()); } @Override public boolean contains(final Object item) { return contains(getThreadLocalTxn(), item); } @Override public boolean containsAll(Collection c) { return containsAll(getThreadLocalTxn(), c); } @Override public boolean containsAll(Txn tx, Collection c) { if (c == null) { throw new NullPointerException(); } if (c.isEmpty()) { return true; } if (isEmpty(tx)) { return false; } for (Object item : c) { if (!contains(tx, item)) { return false; } } return true; } @Override public boolean remove(Object o) { return remove(getThreadLocalTxn(), o); } @Override public boolean add(final E item) { return add(getThreadLocalTxn(), item); } @Override public boolean addAll(final Collection c) { return addAll(getThreadLocalTxn(), c); } @Override public boolean addAll(final Txn tx, final Collection c) { if (c == null) { throw new NullPointerException(); } if (c.isEmpty()) { return false; } boolean change = false; for (E item : c) { if (add(tx, item)) { change = true; } } return change; } @Override public boolean addAll(final TxnCollection c) { return addAll(getThreadLocalTxn(), c); } @Override public boolean addAll(final Txn tx, final TxnCollection c) { if (c == null) { throw new NullPointerException(); } if (c.isEmpty(tx)) { return false; } boolean change = false; for (TxnIterator it = c.iterator(tx); it.hasNext(tx);) { if (add(tx, it.next(tx))) { change = true; } } return change; } @Override public TxnIterator iterator() { return iterator(getThreadLocalTxn()); } @Override public String toString() { return toString(getThreadLocalTxn()); } @Override public Object[] toArray() { throw new UnsupportedOperationException(); } @Override public T[] toArray(T[] a) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } } AbstractTxnIterator.java000066400000000000000000000007631174000617100356750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collectionspackage org.multiverse.collections; import org.multiverse.api.collections.TxnIterator; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public abstract class AbstractTxnIterator implements TxnIterator { @Override public boolean hasNext() { return hasNext(getThreadLocalTxn()); } @Override public E next() { return next(getThreadLocalTxn()); } @Override public void remove() { remove(getThreadLocalTxn()); } } AbstractTxnMap.java000066400000000000000000000057141174000617100346220ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collectionspackage org.multiverse.collections; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.collections.TxnCollection; import org.multiverse.api.collections.TxnMap; import org.multiverse.api.collections.TxnSet; import org.multiverse.api.references.TxnRefFactory; import java.util.Map; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public abstract class AbstractTxnMap implements TxnMap { protected final Stm stm; protected final TxnRefFactory defaultRefFactory; public AbstractTxnMap(Stm stm) { if (stm == null) { throw new NullPointerException(); } this.stm = stm; this.defaultRefFactory = stm.getDefaultRefFactory(); } @Override public final Stm getStm() { return stm; } @Override public int size() { return size(getThreadLocalTxn()); } @Override public boolean isEmpty() { return isEmpty(getThreadLocalTxn()); } @Override public boolean isEmpty(Txn tx) { return size(tx) == 0; } @Override public void clear() { clear(getThreadLocalTxn()); } @Override public V get(Object key) { return get(getThreadLocalTxn(), key); } @Override public V put(K key, V value) { return put(getThreadLocalTxn(), key, value); } @Override public V remove(Object key) { return remove(getThreadLocalTxn(), key); } @Override public TxnSet keySet() { return keySet(getThreadLocalTxn()); } @Override public boolean containsKey(Object key) { return containsKey(getThreadLocalTxn(), key); } /* public boolean containsKey(Txn tx, Object key) { TxnIterator> i = entrySet(tx).iterator(); if (key == null) { while (i.hasNext()) { Entry e = i.next(); if (e.getKey() == null) return true; } } else { while (i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) return true; } } return false; } */ @Override public boolean containsValue(Object value) { return containsValue(getThreadLocalTxn(), value); } @Override public void putAll(Map m) { putAll(getThreadLocalTxn(), m); } @Override public void putAll(Txn tx, Map m) { for (Map.Entry e : m.entrySet()){ put(tx, e.getKey(), e.getValue()); } } @Override public TxnCollection values() { return values(getThreadLocalTxn()); } @Override public TxnSet> entrySet() { return entrySet(getThreadLocalTxn()); } @Override public String toString() { return toString(getThreadLocalTxn()); } } NaiveTxnCollectionFactory.java000066400000000000000000000030261174000617100370210ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collectionspackage org.multiverse.collections; import org.multiverse.api.Stm; import org.multiverse.api.collections.*; public final class NaiveTxnCollectionFactory implements TxnCollectionsFactory { private final Stm stm; public NaiveTxnCollectionFactory(Stm stm) { if (stm == null) { throw new NullPointerException(); } this.stm = stm; } @Override public Stm getStm() { return stm; } @Override public NaiveTxnStack newStack() { return new NaiveTxnStack(stm); } @Override public TxnStack newStack(int capacity) { return new NaiveTxnStack(stm, capacity); } @Override public NaiveTxnLinkedList newQueue() { return new NaiveTxnLinkedList(stm); } @Override public NaiveTxnLinkedList newQueue(int capacity) { return new NaiveTxnLinkedList(stm, capacity); } @Override public NaiveTxnLinkedList newDeque() { return new NaiveTxnLinkedList(stm); } @Override public NaiveTxnLinkedList newDeque(int capacity) { return new NaiveTxnLinkedList(stm, capacity); } @Override public NaiveTxnHashSet newHashSet() { return new NaiveTxnHashSet(stm); } @Override public NaiveTxnHashMap newHashMap() { return new NaiveTxnHashMap(stm); } @Override public NaiveTxnLinkedList newLinkedList() { return new NaiveTxnLinkedList(stm); } } NaiveTxnHashMap.java000066400000000000000000000166531174000617100347310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collectionspackage org.multiverse.collections; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.collections.TxnCollection; import org.multiverse.api.collections.TxnSet; import org.multiverse.api.exceptions.TodoException; import org.multiverse.api.references.TxnInteger; import org.multiverse.api.references.TxnRef; import java.util.Map; public final class NaiveTxnHashMap extends AbstractTxnMap { static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The load factor used when none specified in constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * The maximum capacity, used if a higher value is implicitly specified * by either of the constructors with arguments. * MUST be a power of two <= 1<<30. */ static final int MAXIMUM_CAPACITY = 1 << 30; private final TxnInteger size; private final TxnRef[]> table; private final TxnInteger threshold; /** * The load factor for the hash table. * * @serial */ final float loadFactor; public NaiveTxnHashMap(Stm stm) { super(stm); this.size = defaultRefFactory.newTxnInteger(0); this.threshold = defaultRefFactory.newTxnInteger((int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR)); this.loadFactor = DEFAULT_LOAD_FACTOR; TxnRef[] entries = new TxnRef[DEFAULT_INITIAL_CAPACITY]; for (int k = 0; k < entries.length; k++) { entries[k] = defaultRefFactory.newTxnRef(null); } table = defaultRefFactory.newTxnRef(entries); } public float getLoadFactor() { return loadFactor; } @Override public void clear(Txn tx) { if (size.get(tx) == 0) { return; } TxnRef[] tab = table.get(); for (int i = 0; i < tab.length; i++) { tab[i].set(null); } size.set(0); } @Override public int size(Txn tx) { return size.get(tx); } @Override public V get(Txn tx, Object key) { NaiveEntry entry = getEntry(tx, key); return entry == null ? null : entry.value.get(tx); } private NaiveEntry getEntry(Txn tx, Object key) { if (key == null) { return null; } if (size.get(tx) == 0) { return null; } int hash = key.hashCode(); for (NaiveEntry entry = table.get(tx)[indexFor(hash, table.get(tx).length)].get(tx); entry != null; entry = entry.next.get(tx)) { Object k; if (entry.hash == hash && ((k = entry.key) == key || key.equals(k))) { return entry; } } return null; } @Override public V put(Txn tx, K key, V value) { if (key == null) { throw new NullPointerException(); } int hash = key.hashCode(); int i = indexFor(hash, table.get(tx).length); for (NaiveEntry entry = table.get(tx)[i].get(tx); entry != null; entry = entry.next.get()) { Object foundKey; if (entry.hash == hash && ((foundKey = entry.key) == key || key.equals(foundKey))) { V oldValue = entry.value.get(tx); entry.value.set(tx, value); //entry.recordAccess(this); return oldValue; } } addEntry(tx, hash, key, value, i); return null; } void addEntry(Txn tx, int hash, K key, V value, int bucketIndex) { NaiveEntry e = table.get(tx)[bucketIndex].get(tx); table.get(tx)[bucketIndex].set(new NaiveEntry(hash, key, value, e)); size.increment(tx); if (size.get(tx) >= threshold.get(tx)) { resize(tx, 2 * table.get(tx).length); } } void resize(Txn tx, int newCapacity) { TxnRef[] oldTable = table.get(tx); int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold.set(Integer.MAX_VALUE); return; } TxnRef[] newTable = new TxnRef[newCapacity]; for (int k = 0; k < newTable.length; k++) { newTable[k] = defaultRefFactory.newTxnRef(null); } transfer(tx, newTable); table.set(tx, newTable); threshold.set(tx, (int) (newCapacity * loadFactor)); } void transfer(Txn tx, TxnRef[] newTable) { TxnRef[] src = table.get(tx); int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { NaiveEntry e = src[j].get(tx); if (e != null) { src[j] = null; do { NaiveEntry next = e.next.get(tx); int i = indexFor(e.hash, newCapacity); e.next.set(tx, newTable[i].get(tx)); newTable[i].set(tx, e); e = next; } while (e != null); } } } static int indexFor(int h, int length) { return h & (length - 1); } @Override public V remove(Txn tx, Object key) { throw new TodoException(); } @Override public String toString(Txn tx) { int s = size.get(tx); if (s == 0) { return "[]"; } throw new TodoException(); } @Override public TxnSet> entrySet(Txn tx) { throw new TodoException(); } @Override public TxnSet keySet(Txn tx) { throw new TodoException(); } @Override public boolean containsKey(Txn tx, Object key) { return getEntry(tx, key) != null; } @Override public boolean containsValue(Txn tx, Object value) { throw new TodoException(); } @Override public TxnCollection values(Txn tx) { throw new TodoException(); } private class NaiveEntry implements Map.Entry { final K key; final int hash; final TxnRef value; final TxnRef> next; NaiveEntry(int hash, K key, V value, NaiveEntry next) { this.value = defaultRefFactory.newTxnRef(value); this.next = defaultRefFactory.newTxnRef(next); this.key = key; this.hash = hash; } public final K getKey() { return key; } public final V getValue() { return value.get(); } public final V setValue(V newValue) { V oldValue = value.get(); value.set(newValue); return oldValue; } public final boolean equals(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) { return true; } } return false; } public final int hashCode() { V v = value.get(); return (key == null ? 0 : key.hashCode()) ^ (v == null ? 0 : v.hashCode()); } public final String toString() { return getKey() + "=" + getValue(); } } } NaiveTxnHashSet.java000066400000000000000000000040541174000617100347370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collectionspackage org.multiverse.collections; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.collections.TxnIterator; import org.multiverse.api.collections.TxnSet; import org.multiverse.api.exceptions.TodoException; import java.util.Map; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public final class NaiveTxnHashSet extends AbstractTxnCollection implements TxnSet { private final NaiveTxnHashMap map; public NaiveTxnHashSet(Stm stm) { super(stm); this.map = new NaiveTxnHashMap(stm); } @Override public boolean add(Txn tx, E e) { return map.put(tx, e, this) == null; } @Override public boolean contains(Object item) { return contains(getThreadLocalTxn(), item); } @Override public boolean contains(Txn tx, Object o) { return map.get(tx, o) != null; } @Override public boolean remove(Object item) { return remove(getThreadLocalTxn(), item); } @Override public boolean remove(Txn tx, Object item) { return map.remove(tx, item) != null; } @Override public int size(Txn tx) { return map.size(tx); } @Override public void clear(Txn tx) { map.clear(tx); } @Override public TxnIterator iterator(Txn tx) { return map.keySet(tx).iterator(tx); } static class It extends AbstractTxnIterator { private final TxnIterator> iterator; It(TxnIterator> iterator) { this.iterator = iterator; } @Override public boolean hasNext(Txn tx) { return iterator.hasNext(tx); } @Override public E next(Txn tx) { return iterator.next(tx).getKey(); } @Override public void remove(Txn tx) { iterator.remove(tx); } } @Override public String toString(Txn tx) { throw new TodoException(); } } NaiveTxnLinkedList.java000066400000000000000000000350651174000617100354500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collectionspackage org.multiverse.collections; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.collections.TxnDeque; import org.multiverse.api.collections.TxnIterator; import org.multiverse.api.collections.TxnList; import org.multiverse.api.exceptions.TodoException; import org.multiverse.api.references.TxnInteger; import org.multiverse.api.references.TxnRef; import org.multiverse.api.references.TxnRefFactory; import java.util.NoSuchElementException; import static org.multiverse.api.TxnThreadLocal.getRequiredThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; /** * A LinkedList implementation that also acts as a TxnQueue, TxnDeque. * * @param */ public final class NaiveTxnLinkedList extends AbstractTxnCollection implements TxnDeque, TxnList { private final int capacity; private final TxnInteger size; private final TxnRef> head; private final TxnRef> tail; public NaiveTxnLinkedList(Stm stm) { this(stm, Integer.MAX_VALUE); } public NaiveTxnLinkedList(Stm stm, int capacity) { super(stm); if (capacity < 0) { throw new IllegalArgumentException(); } this.capacity = capacity; this.size = stm.getDefaultRefFactory().newTxnInteger(0); this.head = stm.getDefaultRefFactory().newTxnRef(null); this.tail = stm.getDefaultRefFactory().newTxnRef(null); } @Override public int getCapacity() { return capacity; } @Override public E set(int index, E element) { return set(getThreadLocalTxn(), index, element); } @Override public E set(Txn tx, int index, E element) { return entry(tx, index).value.getAndSet(tx, element); } @Override public int size(Txn tx) { return size.get(tx); } @Override public int indexOf(Object item) { return indexOf(getThreadLocalTxn(), item); } @Override public int indexOf(Txn tx, Object item) { if (item == null) { return -1; } int index = 0; Entry node = head.get(tx); while (node != null) { if (node.value.get(tx).equals(item)) { return index; } node = node.next.get(tx); index++; } return -1; } @Override public int lastIndexOf(Object item) { return lastIndexOf(getThreadLocalTxn(), item); } @Override public int lastIndexOf(Txn tx, Object item) { if (item == null) { return -1; } int index = size.get(tx) - 1; Entry node = tail.get(tx); while (node != null) { if (node.value.get(tx).equals(item)) { return index; } node = node.previous.get(tx); index--; } return -1; } private Entry entry(Txn tx, int index) { if (index < 0) { throw new IndexOutOfBoundsException(); } int s = size.get(tx); if (index >= s) { throw new IndexOutOfBoundsException(); } if (index < (s >> 1)) { int i = 0; Entry node = head.get(tx); while (true) { if (i == index) { return node; } node = node.next.get(tx); i++; } } else { int i = s - 1; Entry node = tail.get(tx); while (true) { if (i == index) { return node; } node = node.previous.get(tx); i--; } } } @Override public boolean contains(Txn tx, Object o) { return indexOf(tx, o) != -1; } @Override public boolean remove(Txn tx, Object o) { return false; //To change body of implemented methods use File | Settings | File Templates. } @Override public void clear(Txn tx) { if (size.get(tx) == 0) { return; } size.set(tx, 0); head.set(tx, null); tail.set(tx, null); } // ==================== needs sorting ===================================== @Override public E element() { return element(getThreadLocalTxn()); } @Override public E element(Txn tx) { return getFirst(tx); } @Override public E pop() { return pop(getThreadLocalTxn()); } @Override public E pop(Txn tx) { return removeFirst(tx); } @Override public void push(E e) { push(getThreadLocalTxn(), e); } @Override public void push(Txn tx, E e) { addFirst(tx, e); } // =============== remove ============== @Override public E remove(int index) { return remove(getThreadLocalTxn(), index); } @Override public E remove(Txn tx, int index) { Entry entry = entry(tx, index); throw new UnsupportedOperationException(); } @Override public E removeFirst() { return removeFirst(getThreadLocalTxn()); } @Override public E removeFirst(Txn tx) { E element = pollFirst(tx); if (element == null) { throw new NoSuchElementException("NaiveTxnLinkedList is empty"); } return element; } @Override public E removeLast() { return removeLast(getThreadLocalTxn()); } @Override public E removeLast(Txn tx) { E element = pollLast(tx); if (element == null) { throw new NoSuchElementException("NaiveTxnLinkedList is empty"); } return element; } @Override public E remove() { return remove(getThreadLocalTxn()); } @Override public E remove(Txn tx) { return removeFirst(tx); } @Override public boolean removeFirstOccurrence(Object o) { return removeFirstOccurrence(getThreadLocalTxn(), o); } @Override public boolean removeFirstOccurrence(Txn tx, Object o) { throw new TodoException(); } @Override public boolean removeLastOccurrence(Object o) { return removeLastOccurrence(getThreadLocalTxn(), o); } @Override public boolean removeLastOccurrence(Txn tx, Object o) { throw new TodoException(); } // =============== gets ============== @Override public E getFirst() { return getFirst(getThreadLocalTxn()); } @Override public E getFirst(Txn tx) { E result = pollFirst(tx); if (result == null) { throw new NoSuchElementException("NaiveTxnLinkedList is empty"); } return result; } @Override public E getLast() { return getLast(getThreadLocalTxn()); } @Override public E getLast(Txn tx) { E result = pollLast(tx); if (result == null) { throw new NoSuchElementException("NaiveTxnLinkedList is empty"); } return result; } @Override public E get(int index) { return get(getThreadLocalTxn(), index); } @Override public E get(Txn tx, int index) { return entry(tx, index).value.get(tx); } // ============== adds ================ @Override public void addFirst(E e) { addFirst(getThreadLocalTxn(), e); } @Override public void addFirst(Txn tx, E e) { if (!offerFirst(tx, e)) { throw new IllegalStateException("NaiveTxnLinkedList full"); } } @Override public void addLast(E e) { addLast(getThreadLocalTxn(), e); } @Override public void addLast(Txn tx, E e) { if (!offerLast(tx, e)) { throw new IllegalStateException("NaiveTxnLinkedList full"); } } @Override public boolean add(Txn tx, E e) { if (!offer(tx, e)) { throw new IllegalStateException("NaiveTxnLinkedList full"); } return true; } // ================ puts ========================== @Override public void putFirst(E item) { putFirst(getThreadLocalTxn(), item); } @Override public void putFirst(Txn tx, E item) { if (!offerFirst(tx, item)) { tx.retry(); } } @Override public void put(E item) { put(getThreadLocalTxn(), item); } @Override public void put(Txn tx, E item) { putLast(tx, item); } @Override public void putLast(E item) { putLast(getRequiredThreadLocalTxn(), item); } @Override public void putLast(Txn tx, E item) { if (!offerLast(tx, item)) { tx.retry(); } } // ================== takes =============================== @Override public E take() { return take(getThreadLocalTxn()); } @Override public E take(Txn tx) { return takeLast(tx); } @Override public E takeFirst() { return takeFirst(getThreadLocalTxn()); } @Override public E takeFirst(Txn tx) { E item = pollFirst(tx); if (item == null) { tx.retry(); } return item; } @Override public E takeLast() { return takeLast(getThreadLocalTxn()); } @Override public E takeLast(Txn tx) { E item = pollLast(tx); if (item == null) { tx.retry(); } return item; } // ================== offers ======================== @Override public boolean offerFirst(E e) { return offerFirst(getThreadLocalTxn(), e); } @Override public boolean offerFirst(Txn tx, E item) { if (item == null) { throw new NullPointerException(); } int s = size.get(tx); if (s == capacity) { return false; } Entry node = new Entry(defaultRefFactory, item); if (s == 0) { head.set(tx, node); tail.set(tx, node); } else { node.next.set(tx, head.get(tx)); head.get(tx).previous.set(tx, node); head.set(tx, node); } size.increment(tx); return true; } @Override public boolean offerLast(E e) { return offerLast(getThreadLocalTxn(), e); } @Override public boolean offerLast(Txn tx, E item) { if (item == null) { throw new NullPointerException(); } int s = size.get(tx); if (s == capacity) { return false; } Entry node = new Entry(defaultRefFactory, item); if (s == 0) { head.set(tx, node); tail.set(tx, node); } else { node.previous.set(tx, tail.get(tx)); tail.get(tx).next.set(tx, node); tail.set(tx, node); } size.increment(tx); return true; } @Override public boolean offer(E item) { return offer(getThreadLocalTxn(), item); } @Override public boolean offer(Txn tx, E item) { return offerLast(tx, item); } // ================ polls ======================= @Override public E pollFirst() { return pollFirst(getThreadLocalTxn()); } @Override public E pollFirst(Txn tx) { int s = size.get(tx); if (s == 0) { return null; } E item; if (s == 1) { item = tail.get(tx).value.get(tx); head.set(tx, null); tail.set(tx, null); } else { Entry oldHead = head.get(tx); item = oldHead.value.get(tx); Entry newHead = oldHead.next.get(tx); head.set(tx, newHead); newHead.previous.set(tx, null); } size.decrement(tx); return item; } @Override public E pollLast() { return pollLast(getThreadLocalTxn()); } @Override public E pollLast(Txn tx) { int s = size.get(tx); if (s == 0) { return null; } E item; if (s == 1) { item = head.get(tx).value.get(tx); head.set(tx, null); tail.set(tx, null); } else { Entry oldTail = tail.get(tx); item = oldTail.value.get(tx); Entry newTail = oldTail.previous.get(tx); tail.set(tx, newTail); newTail.next.set(tx, null); } size.decrement(tx); return item; } @Override public E poll() { return poll(getThreadLocalTxn()); } @Override public E poll(Txn tx) { return pollLast(tx); } // =============== peeks ================= @Override public E peekFirst() { return peekFirst(getThreadLocalTxn()); } @Override public E peekFirst(Txn tx) { Entry h = head.get(tx); return h == null ? null : h.value.get(tx); } @Override public E peekLast() { return peekLast(getThreadLocalTxn()); } @Override public E peekLast(Txn tx) { Entry t = tail.get(tx); return t == null ? null : t.value.get(tx); } @Override public E peek() { return peek(getThreadLocalTxn()); } @Override public E peek(Txn tx) { return peekFirst(tx); } // ================ misc ========================== @Override public TxnIterator iterator(Txn tx) { throw new TodoException(); } @Override public TxnIterator descendingIterator() { return descendingIterator(getThreadLocalTxn()); } @Override public TxnIterator descendingIterator(Txn tx) { throw new TodoException(); } // ================ misc ========================== @Override public String toString(Txn tx) { int s = size(tx); if (s == 0) { return "[]"; } StringBuffer sb = new StringBuffer(); sb.append('['); Entry node = head.get(tx); do { sb.append(node.value.get(tx)); node = node.next.get(tx); if (node != null) { sb.append(", "); } } while (node != null); sb.append(']'); return sb.toString(); } static class Entry { private final TxnRef> next; private final TxnRef> previous; private final TxnRef value; Entry(TxnRefFactory refFactory, E value) { this.next = refFactory.newTxnRef(null); this.previous = refFactory.newTxnRef(null); this.value = refFactory.newTxnRef(value); } } } NaiveTxnStack.java000066400000000000000000000116741174000617100344530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/collectionspackage org.multiverse.collections; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.collections.TxnIterator; import org.multiverse.api.collections.TxnStack; import org.multiverse.api.references.TxnInteger; import org.multiverse.api.references.TxnRef; import java.util.NoSuchElementException; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public final class NaiveTxnStack extends AbstractTxnCollection implements TxnStack { private final int capacity; private final TxnRef> head; private final TxnInteger size; public NaiveTxnStack(Stm stm) { this(stm, Integer.MAX_VALUE); } public NaiveTxnStack(Stm stm, int capacity) { super(stm); if (capacity < 0) { throw new IllegalArgumentException(); } this.capacity = capacity; this.head = stm.getDefaultRefFactory().newTxnRef(null); this.size = stm.getDefaultRefFactory().newTxnInteger(0); } @Override public int size(Txn tx) { return size.get(tx); } @Override public int getCapacity() { return capacity; } @Override public void clear(Txn tx) { int s = size.get(tx); if (s == 0) { return; } size.set(tx, 0); head.set(tx, null); } @Override public boolean offer(E item) { return offer(getThreadLocalTxn(), item); } @Override public boolean offer(Txn tx, E item) { if (capacity == size(tx)) { return false; } push(tx, item); return true; } @Override public E poll() { return poll(getThreadLocalTxn()); } @Override public E poll(Txn tx) { if (size.get(tx) == 0) { return null; } return pop(tx); } @Override public E peek() { return peek(getThreadLocalTxn()); } @Override public E peek(Txn tx) { Node h = head.get(tx); return h == null ? null : h.value; } @Override public void push(E item) { push(getThreadLocalTxn(), item); } @Override public void push(Txn tx, E item) { if (item == null) { throw new NullPointerException(); } if (size.get(tx) == capacity) { tx.retry(); } head.set(tx, new Node(head.get(tx), item)); size.increment(tx); } @Override public E pop() { return pop(getThreadLocalTxn()); } @Override public E pop(Txn tx) { if (size.get(tx) == 0) { tx.retry(); } Node node = head.get(tx); head.set(tx, node.next); size.decrement(tx); return node.value; } @Override public boolean add(Txn tx, E e) { if (!offer(tx, e)) { throw new IllegalStateException("NaiveTxnStack full"); } return true; } @Override public TxnIterator iterator(Txn tx) { return new It(stm, head.get(tx)); } @Override public boolean contains(Txn tx, Object o) { if (o == null) { return false; } int s = size.get(tx); if (s == 0) { return false; } Node node = head.get(); while (node != null) { if(node.value.equals(o)){ return true; } node = node.next; } return false; } @Override public boolean remove(Txn tx, Object o) { throw new UnsupportedOperationException(); } static class It extends AbstractTxnIterator { final TxnRef> node; It(Stm stm, Node node) { this.node = stm.getDefaultRefFactory().newTxnRef(node); } @Override public boolean hasNext(Txn tx) { return node.get() != null; } @Override public E next(Txn tx) { Node n = node.get(tx); if (n == null) { throw new NoSuchElementException(); } E value = n.value; node.set(tx, n.next); return value; } @Override public void remove(Txn tx) { throw new UnsupportedOperationException(); } } @Override public String toString(Txn tx) { int s = size.get(tx); if (s == 0) { return "[]"; } StringBuffer sb = new StringBuffer("["); Node node = head.get(); while (node != null) { sb.append(node.value); node = node.next; if (node != null) { sb.append(", "); } } sb.append("]"); return sb.toString(); } static class Node { final Node next; final E value; Node(Node next, E value) { this.next = next; this.value = value; } } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/commitbarriers/000077500000000000000000000000001174000617100316405ustar00rootroot00000000000000CommitBarrier.java000066400000000000000000000737641174000617100352040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.TodoException; import org.multiverse.utils.StandardThreadFactory; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import static java.lang.String.format; /** * A CommitBarrier is a blocking structure like the {@link java.util.concurrent.CyclicBarrier} but * tailored to work with transactions. Based on this functionality, it is possible to create * a 2-phase commit for example. * * @author Peter Veentjer. */ @SuppressWarnings({"OverlyComplexClass"}) public abstract class CommitBarrier { private static int corePoolSize = 5; private static boolean runAsDaemon = true; private final static ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor( corePoolSize, new StandardThreadFactory(Thread.NORM_PRIORITY, runAsDaemon)); private volatile ScheduledExecutorService executorService = EXECUTOR; protected final Lock lock; protected final Condition statusCondition; private volatile Status status; private volatile int numberWaiting = 0; //for all non final non volatile variables; they only should be accessed while the lock is acquired. private List onAbortTasks = new LinkedList(); private List onCommitTasks = new LinkedList(); /** * Creates a new CommitBarrier. * * @param status the initial status of the CommitBarrier. * @param fair if waking up threads is going to be fair. * @throws NullPointerException if status is null. */ public CommitBarrier(Status status, boolean fair) { if (status == null) { throw new NullPointerException(); } this.status = status; this.lock = new ReentrantLock(fair); this.statusCondition = lock.newCondition(); } protected final Status getStatus() { return status; } /** * Returns the number of Transactions that have prepared and are waiting to commit. Value eventually * becomes null after a commit or abort. * * @return the number of transactions prepared. */ public final int getNumberWaiting() { return numberWaiting; } /** * Checks if this CommitBarrier is closed. This is the initial status of the barrier. * * @return true if closed, false otherwise. */ public final boolean isClosed() { return status == Status.Closed; } /** * Checks if this CommitBarrier already is committed. * * @return true if committed, false otherwise. */ public final boolean isCommitted() { return status == Status.Committed; } /** * Checks if this CommitBarrier already is aborted. * * @return true if aborted, false otherwise. */ public final boolean isAborted() { return status == Status.Aborted; } /** * Only should be made when the lock is acquired. * * @return the List of onCommitTasks that needs to be executed (is allowed to be null). */ protected final List signalCommit() { numberWaiting = 0; status = Status.Committed; statusCondition.signalAll(); onAbortTasks = null; List result = onCommitTasks; onCommitTasks = new LinkedList(); return result; } /** * Only should be made when the lock is acquired. * * @return the List of onAbortTasks that needs to be executed (is allowed to be null). */ protected final List signalAborted() { numberWaiting = 0; status = Status.Aborted; statusCondition.signalAll(); onCommitTasks = new LinkedList(); List result = onAbortTasks; onAbortTasks = new LinkedList(); return result; } /** * Aborts this CommitBarrier. If there are any prepared transactions that are waiting for this CommitBarrier * to complete, they are aborted as well. *

* If the CommitBarrier already is aborted, this call is ignored. * * @throws CommitBarrierOpenException if this CommitBarrier already is committed. */ public final void abort() { List postAbortTasks = null; lock.lock(); try { switch (status) { case Closed: postAbortTasks = signalAborted(); break; case Aborted: return; case Committed: String commitMsg = "Can't abort already committed CommitBarrier"; throw new CommitBarrierOpenException(commitMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } executeTasks(postAbortTasks); } /** * Executes the tasks. Can be called with a null argument. * * @param tasks the tasks to execute. */ protected static void executeTasks(final List tasks) { if (tasks == null) { return; } for (Runnable task : tasks) { task.run(); } } /** * Awaits for this barrier to open (commit or abort). This call doesn't influence the state of this * CommitBarrier. * * @throws InterruptedException if the calling thread is interrupted while waiting. */ public final void awaitOpen() throws InterruptedException { if (status != Status.Closed) { return; } lock.lockInterruptibly(); try { while (status == Status.Closed) { statusCondition.await(); } } finally { lock.unlock(); } } /** * Awaits for this barrier to open (commit or abort). This call doesn't influence the state of this * CommitBarrier. *

* This call is not responsive to interrupts. */ public final void awaitOpenUninterruptibly() { if (status == Status.Closed) { lock.lock(); try { while (status == Status.Closed) { statusCondition.awaitUninterruptibly(); } } finally { lock.unlock(); } } } /** * Waits for this barrier to open (abort or commit). This call doesn't influence the state of this * CommitBarrier. * * @param timeout the maximum amount of time to wait for the barrier to close. * @param unit the TimeUnit for the timeout argument. * @return true if the wait was a success, false if the barrier still is closed. * @throws InterruptedException if the thread is interrupted while waiting. * @throws NullPointerException if unit is null. */ public final boolean tryAwaitOpen(final long timeout, final TimeUnit unit) throws InterruptedException { if (unit == null) { throw new NullPointerException(); } if (status == Status.Closed) { long timeoutNs = unit.toNanos(timeout); lock.lockInterruptibly(); try { while (status == Status.Closed) { timeoutNs = statusCondition.awaitNanos(timeoutNs); if (timeoutNs <= 0) { return false; } } } finally { lock.unlock(); } } return true; } /** * Tries to await the close of the barrier. This call doesn't influence the state of this * CommitBarrier. *

* This call is not responsive to interrupts. * * @param timeout the maximum amount of time to wait for the barrier to be closed. * @param unit the timeunit for the timeout argument. * @return true if the wait was a success, false otherwise. */ public final boolean tryAwaitOpenUninterruptibly(final long timeout, final TimeUnit unit) { if (unit == null) { throw new NullPointerException(); } if (status == Status.Closed) { long timeoutNs = unit.toNanos(timeout); lock.lock(); try { while (status == Status.Closed) { timeoutNs = awaitNanosUninterruptible(timeoutNs); if (timeoutNs <= 0) { return false; } } } finally { lock.unlock(); } } return true; } private long awaitNanosUninterruptible(long timeoutNs) { boolean restoreInterrupt = Thread.interrupted(); try { while (true) { long startNs = System.nanoTime(); try { return statusCondition.awaitNanos(timeoutNs); } catch (InterruptedException ex) { timeoutNs -= (System.nanoTime() - startNs); restoreInterrupt = true; } } } finally { //restore interrupt if needed if (restoreInterrupt) { Thread.currentThread().interrupt(); } } } /** * Sets the ScheduledExecutorService to be used by this CommitBarrier for the timeout. This method can always * be called no matter the state of the CommitBarrier. * * @param executorService the ScheduledExecutorService this CommitBarrier is going to use for timeout. * @throws NullPointerException if executorService is null. */ public void setScheduledExecutorService(ScheduledExecutorService executorService) { if (executorService == null) { throw new NullPointerException(); } this.executorService = executorService; } /** * Sets the timeout on this CommitBarrier. If the barrier hasn't committed/aborted before the timeout * it automatically is aborted. This is a function that typically is used when initializing the CommitBarrier. *

* The timeout starts running when this method is called. * * @param timeout the maximum amount of time this barrier is allowed to run. * @param unit the TimeUnit of the timeout parameter. * @throws NullPointerException if unit is null. * @throws CommitBarrierOpenException if the CommitBarrier already is aborted or committed. */ public final void setTimeout(final long timeout, final TimeUnit unit) { lock.lock(); try { switch (status) { case Closed: Runnable command = new Runnable() { @Override public void run() { try { abort(); } catch (IllegalStateException ignore) { } } }; executorService.schedule(command, timeout, unit); break; case Committed: String commitMsg = "Can't set a timeout on an already commit CommitBarrier."; throw new CommitBarrierOpenException(commitMsg); case Aborted: String abortMsg = "Can't set a timeout on an already aborted CommitBarrier."; throw new CommitBarrierOpenException(abortMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } } /** * Registers a task that is executed once the CommitBarrier aborts. *

* The task will be executed after the abort and will be executed by the thread that does the actual abort. *

* The tasks will be executed in the order they are registered and will be executed at most once. If one of the * tasks throws a RuntimeException, the following will not be executed. * * @param task the task that is executed once the CommitBarrier commits. * @throws NullPointerException if task is null. * @throws CommitBarrierOpenException if this CommitBarrier already is aborted or committed. */ public final void registerOnAbortTask(final Runnable task) { lock.lock(); try { switch (status) { case Closed: if (task == null) { throw new NullPointerException(); } if (onAbortTasks == null) { onAbortTasks = new LinkedList(); } onAbortTasks.add(task); break; case Committed: String commitMsg = "Can't register on abort task on already committed CommitBarrier"; throw new CommitBarrierOpenException(commitMsg); case Aborted: String abortMsg = "Can't register on abort task on already aborted CommitBarrier"; throw new CommitBarrierOpenException(abortMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } } /** * Registers a task that is executed once the CommitBarrier commits. *

* The task will be executed after the commit and will be executed by the thread that does the actual commit. *

* The tasks will be executed in the order they are registered and will be executed at most once. If one of the * tasks throws a RuntimeException, the following will not be executed. * * @param task the task that is executed once the CommitBarrier commits. * @throws NullPointerException if task is null. * @throws CommitBarrierOpenException if this CommitBarrier already is aborted or committed. */ public final void registerOnCommitTask(final Runnable task) { lock.lock(); try { switch (status) { case Closed: if (task == null) { throw new NullPointerException(); } if (onCommitTasks == null) { onCommitTasks = new LinkedList(); } onCommitTasks.add(task); break; case Committed: String commitMsg = "Can't register on commit task on already committed CommitBarrier"; throw new CommitBarrierOpenException(commitMsg); case Aborted: String abortMsg = "Can't register on commit task on already aborted CommitBarrier"; throw new CommitBarrierOpenException(abortMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } } /** * Adds a waiters. *

* Should only be called when the main lock is acquired. * * @throws IllegalStateException if the transaction isn't closed. */ protected final void addJoiner() { if (status != Status.Closed) { throw new IllegalStateException(); } numberWaiting++; } /** * Finishes a Txn. *

* Can be called without the mainlock is acquired. * * @param tx the transaction to finish */ protected final void finish(final Txn tx) { if (tx == null) { return; } if (isCommitted()) { tx.commit(); } else if (isAborted()) { tx.abort(); throw new IllegalStateException( format("[%s] Didn't expect to encounter an aborted CommitBarrier", tx.getConfig().getFamilyName())); } } /** * Ensures that a transaction is not dead. *

* Can be called without the mainlock is acquired. * * @param tx the transaction to check. * @param operation the name of the operation to checks if this transaction is not dead. Needed to provide * a useful message. * @throws org.multiverse.api.exceptions.DeadTxnException if tx is dead. * @throws NullPointerException if tx is null. */ protected static void ensureNotDead(final Txn tx, final String operation) { if (tx == null) { throw new NullPointerException(); } if (!tx.getStatus().isAlive()) { throw new DeadTxnException( format("[%s] Txn can't be used for %s since it isn't alive", tx.getConfig().getFamilyName(), operation) ); } } /** * Joins this CommitBarrier with the provided transaction. If the CommitBarrier can't commit yet, the method * will block. *

* If the CommitBarrier already is aborted or committed, the transaction is aborted. *

* This method is responsive to interrupts. If the waiting thread is interrupted, it will abort itself and * this CommitGroup. * * @param tx the Txn to commit. * @throws InterruptedException if the thread is interrupted while waiting. * @throws NullPointerException if tx is null. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the tx is no in the correct * state for this operation. * @throws CommitBarrierOpenException if this VetoCommitBarrier is committed or aborted. */ public void joinCommit(final Txn tx) throws InterruptedException { ensureNotDead(tx, "joinCommit"); List tasks = null; lock.lock(); try { switch (status) { case Closed: tx.prepare(); addJoiner(); if (isLastParty()) { tasks = signalCommit(); } else { while (status == Status.Closed) { try { statusCondition.await(); } catch (InterruptedException ex) { signalAborted(); tx.abort(); throw ex; } } } break; case Committed: String committedMsg = format("Can't await commit on already committed VetoCommitBarrier " + "with transaction %s", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(committedMsg); case Aborted: String abortMsg = format("Can't await commit on already aborted VetoCommitBarrier " + "with transaction %s", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(abortMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } //todo: the the thread is interrupted, tx is not aborted. finish(tx); executeTasks(tasks); } /** * Joins this CommitBarrier with the provided transaction. If the CommitBarrier can't commit yet, this * method will block without being interruptible. *

* If the CommitBarrier already is aborted or committed, the transaction is aborted. * * @param tx the Txn to join in the commit. * @throws NullPointerException if tx is null. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the tx is not in the correct * state for the operation. * @throws CommitBarrierOpenException if this VetoCommitBarrier is committed or aborted. */ public void joinCommitUninterruptibly(final Txn tx) { ensureNotDead(tx, "joinCommitUninterruptibly"); List postCommitTasks = null; lock.lock(); try { switch (status) { case Closed: tx.prepare(); addJoiner(); if (isLastParty()) { postCommitTasks = signalCommit(); } else { while (status == Status.Closed) { statusCondition.awaitUninterruptibly(); } } break; case Aborted: tx.abort(); String abortedMsg = format("Can't call joinCommitUninterruptible on already aborted " + "CountDownCommitBarrier with transaction %s ", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(abortedMsg); case Committed: tx.abort(); String commitMsg = format("Can't call joinCommitUninterruptible on already committed " + "CountDownCommitBarrier with transaction %s ", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(commitMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } finish(tx); executeTasks(postCommitTasks); } /** * Tries to joins this CommitBarrier with the provided transaction. If the CommitBarrier can't commit yet, the * transaction and CommitBarrier will be aborted. So this method will not block (for a long period). *

* If the CommitBarrier already is aborted or committed, the transaction is aborted. * * @param tx the Txn that wants to join the other parties to commit with. * @return true if CountDownCommitBarrier was committed, false if aborted. * @throws CommitBarrierOpenException if tx or this CountDownCommitBarrier is aborted or committed. * @throws NullPointerException if tx is null. */ public boolean tryJoinCommit(final Txn tx) { ensureNotDead(tx, "tryJoinCommit"); List postCommitTasks = null; boolean abort = true; lock.lock(); try { switch (status) { case Closed: tx.prepare(); addJoiner(); if (isLastParty()) { postCommitTasks = signalCommit(); abort = false; } else { postCommitTasks = signalAborted(); } break; case Aborted: String abortMsg = format("[%s] Can't call tryJoinCommit on already aborted " + "CountDownCommitBarrier", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(abortMsg); case Committed: String commitMsg = format("[%s] Can't call tryJoinCommit on already committed " + "CountDownCommitBarrier", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(commitMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); if (abort) { tx.abort(); } else { tx.commit(); } } executeTasks(postCommitTasks); return isCommitted(); } /** * Tries to joins this CommitBarrier with the provided transaction. If the CommitBarrier can't commit yet, this call * will block until one of the following things happens: *

    *
  1. the CommitBarrier is committed before timeing out: the transaction also is committed
  2. *
  3. the CommitBarrier is aborted before timeing out: the transaction also is aborted
  4. *
  5. the thread is interrupted: the transaction and commit barrier also is aborted
  6. *
  7. the thread times out: the transaction and commit barrier are aborted
  8. *
*

* If the CommitBarrier already is aborted or committed, the transaction is aborted. *

* This method is responsive to interrupts. If the waiting thread is interrupted, it will abort itself and * this CommitBarrier. * * @param tx the Txn that wants to join the other parties to commit with. * @param timeout the maximum time to wait. * @param unit the TimeUnit for the timeout argument. * @return true if CountDownCommitBarrier was committed, false if aborted. * @throws CommitBarrierOpenException if tx or this CountDownCommitBarrier is aborted or committed. * @throws NullPointerException if tx or unit is null is null. * @throws InterruptedException if the calling thread is interrupted while waiting. */ public boolean tryJoinCommit(final Txn tx, final long timeout, final TimeUnit unit) throws InterruptedException { ensureNotDead(tx, "tryJoinCommit"); long timeoutNs = unit.toNanos(timeout); List postCommitTasks = null; lock.lock(); try { switch (status) { case Closed: tx.prepare(); addJoiner(); if (isLastParty()) { postCommitTasks = signalCommit(); } else { while (status == Status.Closed) { try { timeoutNs = statusCondition.awaitNanos(timeoutNs); if (timeoutNs <= 0) { signalAborted(); tx.abort(); return false; } } catch (InterruptedException ex) { signalAborted(); tx.abort(); //for the time being.. needs to be replaced with a really uninterruptible version throw ex; } } } break; case Committed: String commitMsg = "Can't await commit on an already committed VetoCommitBarrier"; throw new CommitBarrierOpenException(commitMsg); case Aborted: String abortMsg = "Can't await commit on an already aborted VetoCommitBarrier"; throw new CommitBarrierOpenException(abortMsg); default: throw new NullPointerException(); } } finally { lock.unlock(); } finish(tx); executeTasks(postCommitTasks); return true; } /** * Tries to joins this CommitBarrier with the provided transaction. If the CommitBarrier can't commit yet, this call * will block until one of the following things happens: *

    *
  1. the CommitBarrier is committed
  2. *
  3. the CommitBarrier is aborted
  4. *
*

* If the CommitBarrier already is aborted or committed, the transaction is aborted. *

* This method is not responsive to interrupts. * * @param tx the Txn that wants to join the other parties to commit with. * @param timeout the maximum time to wait. * @param unit the TimeUnit for the timeout argument. * @return true if CountDownCommitBarrier was committed, false if aborted. * @throws CommitBarrierOpenException if tx or this CountDownCommitBarrier is aborted or committed. * @throws NullPointerException if tx or unit is null is null. */ public boolean tryJoinCommitUninterruptibly(final Txn tx, final long timeout, final TimeUnit unit) { ensureNotDead(tx, "tryJoinCommitUninterruptibly"); long timeoutNs = unit.toNanos(timeout); lock.lock(); try { switch (status) { case Closed: tx.prepare(); addJoiner(); while (status == Status.Closed) { try { timeoutNs = statusCondition.awaitNanos(timeoutNs); if (timeoutNs <= 0) { signalAborted(); tx.abort(); return false; } } catch (InterruptedException ex) { signalAborted(); tx.abort(); //for the time being.. needs to be replaced with a really uninterruptible version throw new RuntimeException(ex); } } break; case Committed: String commitMsg = "Can't await commit on an already committed VetoCommitBarrier"; throw new CommitBarrierOpenException(commitMsg); case Aborted: String abortMsg = "Can't await commit on an already aborted VetoCommitBarrier"; throw new CommitBarrierOpenException(abortMsg); default: throw new NullPointerException(); } } finally { lock.unlock(); } finish(tx); throw new TodoException(); } protected abstract boolean isLastParty(); enum Status { Closed, Committed, Aborted } } CommitBarrierOpenException.java000066400000000000000000000014141174000617100376640ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; /** * An IllegalStateException that indicates that an operation was executed on the CommitBarrier while it * already is opened. * * @author Peter Veentjer. */ public class CommitBarrierOpenException extends IllegalStateException { /** * Creates a new CommitBarrierOpenException with the provided message. * * @param message the message */ public CommitBarrierOpenException(String message) { super(message); } /** * Creates a new CommitBarrierOpenException with the provided message and cause. * * @param message the message * @param cause the cause */ public CommitBarrierOpenException(String message, Throwable cause) { super(message, cause); } } CountDownCommitBarrier.java000066400000000000000000000242021174000617100370240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.multiverse.api.Txn; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.api.lifecycle.TxnListener; import java.util.List; import static java.lang.String.format; /** * A synchronization aid that allows a set of threads and transaction to all wait for each other to reach a common * barrier point; once this barrier is opened, all transaction atomically commit. A CountDownCommitBarrier is useful * in programs involving a fixed sized party of threads/transactions that must occasionally wait for each other. *

* The CountDownCommitBarrier looks a lot like the {@link java.util.concurrent.CountDownLatch}. So if you have * experience with that functionality, this one should feel familiar. *

* A {@code CountDownCommitBarrier} is initialized with a given count. The * {@link #joinCommit(org.multiverse.api.Txn)} await} methods block until the current count reaches * zero due to invocations of the {@link #countDown} method, after which all waiting threads are released. Unlike the * CountDownLatch, it isn't allowed for a new transaction to call one of the join methods after the barrier has * aborted or committed. *

* This functionality is useful for two phase commit related functionality. *

* The CountDownCommitBarrier can't be reused, so it is not cyclic like the {@link java.util.concurrent.CyclicBarrier}. *

* A CountDownCommitBarrier is thread-safe to use of course. * * @author Peter Veentjer. * @see VetoCommitBarrier */ public final class CountDownCommitBarrier extends CommitBarrier { private volatile int parties; /** * Create a new CountDownCommitBarrier that uses an unfair lock. * * @param parties the number of parties waiting. If the number of parties is 0, the VetoCommitBarrier is created * committed, else it will be closed. * @throws IllegalArgumentException if parties is smaller than 0. */ public CountDownCommitBarrier(int parties) { this(parties, false); } /** * Creates a new CountDownCommitBarrier. * * @param parties the number of parties waiting. If the number of parties is 0, the VetoCommitBarrier is created * committed, else it will be closed. * @param fair if the lock bu this CountDownCommitBarrier is fair. * @throws IllegalArgumentException if parties smaller than 0. */ public CountDownCommitBarrier(int parties, boolean fair) { super(parties == 0 ? Status.Committed : Status.Closed, fair); if (parties < 0) { throw new IllegalArgumentException(); } this.parties = parties; } /** * Returns the number of parties that want to join this CountDownCommitBarrier. * * @return the number of parties. */ public int getParties() { return parties; } protected boolean isLastParty() { return getNumberWaiting() == parties; } /** * Signal that one party has returned. If this is the last party to returned, all transactions * will commit. *

* If the all parties already have returned, this call is ignored. This is the same behavior * as the {@link java.util.concurrent.CountDownLatch#countDown()} method provides. */ public void countDown() { List onCommitTasks = null; lock.lock(); try { switch (getStatus()) { case Closed: addJoiner(); if (isLastParty()) { onCommitTasks = signalCommit(); } break; case Aborted: break; case Committed: break; default: throw new IllegalStateException(); } } finally { lock.unlock(); } executeTasks(onCommitTasks); } /** * Adds 1 additional party to this CountDownCommitBarrier. * * @throws CommitBarrierOpenException if this CountDownCommitBarrier already is committed or aborted. * @see #atomicIncParties(int) */ public void atomicIncParties() { atomicIncParties(1); } /** * Atomically adds additional parties to this CountDownCommitBarrier. *

* Call is ignored when extra is 0. *

* This method is not transactional, so be very careful calling it within a transaction. Transactions can be * retried, so this method could be called more than once. This means that the number of added parties could * be completely bogus. For a transactional version see {@link #incParties(org.multiverse.api.Txn, int)}. * * @param extra the additional parties. * @throws IllegalArgumentException if extra smaller than 0. * @throws CommitBarrierOpenException if this CountDownCommitBarrier already is open. */ public void atomicIncParties(int extra) { if (extra < 0) { throw new IllegalArgumentException(); } lock.lock(); try { switch (getStatus()) { case Closed: if (extra == 0) { return; } parties += extra; break; case Aborted: String abortMsg = "Can't call countDown on already aborted CountDownCommitBarrier"; throw new CommitBarrierOpenException(abortMsg); case Committed: String commitMsg = "Can't call countDown on already committed CountDownCommitBarrier"; throw new CommitBarrierOpenException(commitMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } } /** * Increases the number of parties that need to return before this CommitBarrier can open. * The parties are only increased after the transaction has committed. *

* If extra is 0, this call is ignored (unless the Txn is not active, then a * IllegalTransactionState will be thrown. *

* This is the call you want to use when you are doing an atomicIncParties inside a transaction. * A transaction can be retried multiple times, and if number of parties is incremented more than * once, you run into problems. That is why a transaction can be passed where a compensating * tasks is registered on, that removes the added parties when the transaction is aborted. * * @param tx the transaction where this operation lifts on. * @param extra the number of extra parties * @throws NullPointerException if tx is null. * @throws IllegalArgumentException is extra smaller than zero. * @throws org.multiverse.api.exceptions.IllegalTxnStateException * if the transaction is not in the correct * state for this operation (so not active). */ public void incParties(Txn tx, int extra) { if (tx == null) { throw new NullPointerException(); } if (tx.getStatus() != TxnStatus.Active) { if (tx.getStatus() == TxnStatus.Prepared) { tx.abort(); throw new PreparedTxnException( format("[%s] Can't call incParties on non active transaction because it is %s", tx.getConfig().getFamilyName(), tx.getStatus())); } else { throw new DeadTxnException( format("[%s] Can't call incParties on non active transaction because it is %s", tx.getConfig().getFamilyName(), tx.getStatus())); } } if (extra < 0) { throw new IllegalArgumentException(); } lock.lock(); try { switch (getStatus()) { case Closed: if (extra == 0) { return; } parties += extra; tx.register(new RestorePartiesCompensatingTask(extra)); break; case Aborted: String abortMsg = format("[%s] Can't call incParties on already aborted CountDownCommitBarrier", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(abortMsg); case Committed: String commitMsg = format("[%s] Can't call incParties on already committed CountDownCommitBarrier", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(commitMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } } /** * A TransactionLifecycleListener that is responsible for restoring the the number of * parties after the transaction that increased them, was aborted. */ private class RestorePartiesCompensatingTask implements TxnListener { private final int extra; RestorePartiesCompensatingTask(int extra) { this.extra = extra; } @Override public void notify(Txn tx, TxnEvent event) { //todo: in the 0.6 release of multiverse this was pre-abort.. but since the pre-abort doesn't //exist anymore.. if (event != TxnEvent.PostAbort) { return; } List onCommitTasks = null; lock.lock(); try { if (getStatus() == Status.Closed) { parties -= extra; if (isLastParty()) { onCommitTasks = signalCommit(); } } } finally { lock.unlock(); } executeTasks(onCommitTasks); } } } VetoCommitBarrier.java000066400000000000000000000112321174000617100360200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.multiverse.api.Txn; import java.util.List; import static java.lang.String.format; /** * The VetoCommitBarrier is a synchronization primitive that makes it possible to execute a 2 phase commit; * so all transaction within a VetoCommitBarrier commit, or they all abort. The VetoCommitBarrier is useful if * there is a veto situation; so one transaction is able to commit all others. *

* This structure is thread-safe to use. *

* * @author Peter Veentjer. */ public final class VetoCommitBarrier extends CommitBarrier { /** * Creates a new VetoCommitBarrier that uses an unfair Lock. */ public VetoCommitBarrier() { this(false); } /** * Creates a new VetoCommitBarrier. * * @param fair if the lock should be fair. */ public VetoCommitBarrier(boolean fair) { super(Status.Closed, fair); } @Override protected boolean isLastParty() { return false; } /** * Veto's the commit so that all prepared Transactions in this VetoCommitBarriers should commit. This call doesn't * block (for a long time). *

* It could be that this method finishes before the other parties have completed their commit. In most * cases this won't be an issue, because the other parties have prepared their transactions, so all * needed resources are locked. *

* If the VetoCommitBarrier already is committed, this call is ignored. *

* After the commit completes, the onCommitTasks are executed. * * @throws CommitBarrierOpenException if the VetoCommitBarrier already is aborted. */ public void atomicVetoCommit() { List postCommitTasks = null; lock.lock(); try { switch (getStatus()) { case Closed: postCommitTasks = signalCommit(); break; case Committed: //ignore it. return; case Aborted: String abortMsg = "Can't veto a commit on already aborted VetoCommitBarrier"; throw new CommitBarrierOpenException(abortMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } executeTasks(postCommitTasks); } /** * Veto's the commit of this VetoCommitBarrier including the provided transaction. If all goes well all * pending transactions and the provided transaction are going to commit. *

* It could be that this method finishes before the other parties have completed their commit. In most * cases this won't be an issue, because the other parties have prepared their transactions, so all * needed resources are locked. *

* If the VetoCommitBarrier already is aborted or committed, the transaction is aborted. * * @param tx the Txn to commit. * @throws NullPointerException if tx is null. * @throws org.multiverse.api.exceptions.DeadTxnException * if the Txn already is aborted or committed. * @throws org.multiverse.api.exceptions.ReadWriteConflict * if the commit was not executed successfully. * @throws CommitBarrierOpenException if the VetoCommitBarrier already is open. */ public void vetoCommit(Txn tx) { ensureNotDead(tx, "vetoCommit"); List postCommitTasks = null; lock.lock(); try { switch (getStatus()) { case Closed: tx.prepare(); postCommitTasks = signalCommit(); break; case Aborted: String abortMsg = format( "[%s] Can't veto commit on already aborted VetoCommitBarrier", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(abortMsg); case Committed: String commitMsg = format( "[%s] Can't veto commit on already committed VetoCommitBarrier", tx.getConfig().getFamilyName()); throw new CommitBarrierOpenException(commitMsg); default: throw new IllegalStateException(); } } finally { lock.unlock(); } tx.commit(); executeTasks(postCommitTasks); } public String toString(){ return format("VetoCommitBarrier(isClosed=%s)",isClosed()); } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/000077500000000000000000000000001174000617100276045ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/000077500000000000000000000000001174000617100306665ustar00rootroot00000000000000AbstractGammaTxnExecutor.java000066400000000000000000000014751174000617100364000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.BackoffPolicy; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; /** * An abstract {@link GammaTxnExecutor} implementation. * * @author Peter Veentjer. */ public abstract class AbstractGammaTxnExecutor implements GammaTxnExecutor { protected final GammaTxnFactory txnFactory; protected final GammaTxnConfig txnConfig; protected final BackoffPolicy backoffPolicy; public AbstractGammaTxnExecutor(final GammaTxnFactory txnFactory) { if (txnFactory == null) { throw new NullPointerException(); } this.txnFactory = txnFactory; this.txnConfig = txnFactory.getConfig(); this.backoffPolicy = txnConfig.backoffPolicy; } } FatGammaTxnExecutor.java000066400000000000000000001770331174000617100353530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.*; import org.multiverse.api.exceptions.*; import org.multiverse.api.callables.*; import org.multiverse.stms.gamma.transactions.*; import java.util.concurrent.Callable; import java.util.logging.Logger; import static java.lang.String.format; import static org.multiverse.api.TxnThreadLocal.*; /** * The {@link TxnExecutor} made for the GammaStm. * * This code is generated. * * @author Peter Veentjer */ public final class FatGammaTxnExecutor extends AbstractGammaTxnExecutor{ private static final Logger logger = Logger.getLogger(FatGammaTxnExecutor.class.getName()); public void execute(Runnable runnable){ throw new UnsupportedOperationException(); } public E execute(Callable callable){ throw new UnsupportedOperationException(); } public E executeChecked(Callable callable)throws Exception{ throw new UnsupportedOperationException(); } private final PropagationLevel propagationLevel; public FatGammaTxnExecutor(final GammaTxnFactory txnFactory) { super(txnFactory); this.propagationLevel = txnConfig.propagationLevel; } @Override public GammaTxnFactory getTxnFactory(){ return txnFactory; } @Override public final E executeChecked( final TxnCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } public E execute(final TxnCallable callable){ if(callable == null){ throw new NullPointerException(); } TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } try{ switch (propagationLevel) { case Requires: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level and no txn found, starting a new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level, and existing txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); } case Mandatory: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level, and no txn is found", txnConfig.familyName)); } } throw new TxnMandatoryException( format("No txn is found for TxnExecutor '%s' with 'Mandatory' propagation level", txnConfig.familyName)); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level and txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); case Never: if (tx != null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level, but txn [%s] is found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } throw new TxnNotAllowedException( format("No txn is allowed for TxnExecutor '%s' with propagation level 'Never'"+ ", but txn '%s' was found", txnConfig.familyName, tx.getConfig().getFamilyName()) ); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level and no txn is found", txnConfig.familyName)); } } return callable.call(null); case RequiresNew: if (tx == null) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagation level and no txn is found, starting new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } GammaTxn suspendedTransaction = tx; tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; try { return execute(tx, transactionContainer, pool, callable); } finally { transactionContainer.txn = suspendedTransaction; } } case Supports: if(TRACING_ENABLED){ if(tx!=null){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } }else{ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } } return callable.call(tx); default: throw new IllegalStateException(); } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } private E execute( GammaTxn tx, final TxnThreadLocal.Container transactionContainer, GammaTxnPool pool, final TxnCallable callable)throws Exception{ Error cause = null; try{ boolean abort = true; try { do { try { cause = null; E result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final int executeChecked( final TxnIntCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } public int execute(final TxnIntCallable callable){ if(callable == null){ throw new NullPointerException(); } TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } try{ switch (propagationLevel) { case Requires: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level and no txn found, starting a new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level, and existing txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); } case Mandatory: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level, and no txn is found", txnConfig.familyName)); } } throw new TxnMandatoryException( format("No txn is found for TxnExecutor '%s' with 'Mandatory' propagation level", txnConfig.familyName)); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level and txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); case Never: if (tx != null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level, but txn [%s] is found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } throw new TxnNotAllowedException( format("No txn is allowed for TxnExecutor '%s' with propagation level 'Never'"+ ", but txn '%s' was found", txnConfig.familyName, tx.getConfig().getFamilyName()) ); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level and no txn is found", txnConfig.familyName)); } } return callable.call(null); case RequiresNew: if (tx == null) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagation level and no txn is found, starting new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } GammaTxn suspendedTransaction = tx; tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; try { return execute(tx, transactionContainer, pool, callable); } finally { transactionContainer.txn = suspendedTransaction; } } case Supports: if(TRACING_ENABLED){ if(tx!=null){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } }else{ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } } return callable.call(tx); default: throw new IllegalStateException(); } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } private int execute( GammaTxn tx, final TxnThreadLocal.Container transactionContainer, GammaTxnPool pool, final TxnIntCallable callable)throws Exception{ Error cause = null; try{ boolean abort = true; try { do { try { cause = null; int result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final long executeChecked( final TxnLongCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } public long execute(final TxnLongCallable callable){ if(callable == null){ throw new NullPointerException(); } TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } try{ switch (propagationLevel) { case Requires: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level and no txn found, starting a new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level, and existing txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); } case Mandatory: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level, and no txn is found", txnConfig.familyName)); } } throw new TxnMandatoryException( format("No txn is found for TxnExecutor '%s' with 'Mandatory' propagation level", txnConfig.familyName)); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level and txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); case Never: if (tx != null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level, but txn [%s] is found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } throw new TxnNotAllowedException( format("No txn is allowed for TxnExecutor '%s' with propagation level 'Never'"+ ", but txn '%s' was found", txnConfig.familyName, tx.getConfig().getFamilyName()) ); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level and no txn is found", txnConfig.familyName)); } } return callable.call(null); case RequiresNew: if (tx == null) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagation level and no txn is found, starting new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } GammaTxn suspendedTransaction = tx; tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; try { return execute(tx, transactionContainer, pool, callable); } finally { transactionContainer.txn = suspendedTransaction; } } case Supports: if(TRACING_ENABLED){ if(tx!=null){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } }else{ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } } return callable.call(tx); default: throw new IllegalStateException(); } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } private long execute( GammaTxn tx, final TxnThreadLocal.Container transactionContainer, GammaTxnPool pool, final TxnLongCallable callable)throws Exception{ Error cause = null; try{ boolean abort = true; try { do { try { cause = null; long result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final double executeChecked( final TxnDoubleCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } public double execute(final TxnDoubleCallable callable){ if(callable == null){ throw new NullPointerException(); } TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } try{ switch (propagationLevel) { case Requires: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level and no txn found, starting a new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level, and existing txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); } case Mandatory: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level, and no txn is found", txnConfig.familyName)); } } throw new TxnMandatoryException( format("No txn is found for TxnExecutor '%s' with 'Mandatory' propagation level", txnConfig.familyName)); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level and txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); case Never: if (tx != null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level, but txn [%s] is found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } throw new TxnNotAllowedException( format("No txn is allowed for TxnExecutor '%s' with propagation level 'Never'"+ ", but txn '%s' was found", txnConfig.familyName, tx.getConfig().getFamilyName()) ); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level and no txn is found", txnConfig.familyName)); } } return callable.call(null); case RequiresNew: if (tx == null) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagation level and no txn is found, starting new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } GammaTxn suspendedTransaction = tx; tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; try { return execute(tx, transactionContainer, pool, callable); } finally { transactionContainer.txn = suspendedTransaction; } } case Supports: if(TRACING_ENABLED){ if(tx!=null){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } }else{ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } } return callable.call(tx); default: throw new IllegalStateException(); } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } private double execute( GammaTxn tx, final TxnThreadLocal.Container transactionContainer, GammaTxnPool pool, final TxnDoubleCallable callable)throws Exception{ Error cause = null; try{ boolean abort = true; try { do { try { cause = null; double result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final boolean executeChecked( final TxnBooleanCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } public boolean execute(final TxnBooleanCallable callable){ if(callable == null){ throw new NullPointerException(); } TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } try{ switch (propagationLevel) { case Requires: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level and no txn found, starting a new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level, and existing txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); } case Mandatory: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level, and no txn is found", txnConfig.familyName)); } } throw new TxnMandatoryException( format("No txn is found for TxnExecutor '%s' with 'Mandatory' propagation level", txnConfig.familyName)); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level and txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } return callable.call(tx); case Never: if (tx != null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level, but txn [%s] is found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } throw new TxnNotAllowedException( format("No txn is allowed for TxnExecutor '%s' with propagation level 'Never'"+ ", but txn '%s' was found", txnConfig.familyName, tx.getConfig().getFamilyName()) ); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level and no txn is found", txnConfig.familyName)); } } return callable.call(null); case RequiresNew: if (tx == null) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagation level and no txn is found, starting new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; return execute(tx, transactionContainer, pool, callable); } else { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } GammaTxn suspendedTransaction = tx; tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; try { return execute(tx, transactionContainer, pool, callable); } finally { transactionContainer.txn = suspendedTransaction; } } case Supports: if(TRACING_ENABLED){ if(tx!=null){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } }else{ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } } return callable.call(tx); default: throw new IllegalStateException(); } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } private boolean execute( GammaTxn tx, final TxnThreadLocal.Container transactionContainer, GammaTxnPool pool, final TxnBooleanCallable callable)throws Exception{ Error cause = null; try{ boolean abort = true; try { do { try { cause = null; boolean result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final void executeChecked( final TxnVoidCallable callable)throws Exception{ try{ execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } public void execute(final TxnVoidCallable callable){ if(callable == null){ throw new NullPointerException(); } TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } try{ switch (propagationLevel) { case Requires: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level and no txn found, starting a new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; execute(tx, transactionContainer,pool, callable); return; } else { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level, and existing txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } callable.call(tx); return; } case Mandatory: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level, and no txn is found", txnConfig.familyName)); } } throw new TxnMandatoryException( format("No txn is found for TxnExecutor '%s' with 'Mandatory' propagation level", txnConfig.familyName)); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level and txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } callable.call(tx); return; case Never: if (tx != null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level, but txn [%s] is found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } throw new TxnNotAllowedException( format("No txn is allowed for TxnExecutor '%s' with propagation level 'Never'"+ ", but txn '%s' was found", txnConfig.familyName, tx.getConfig().getFamilyName()) ); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level and no txn is found", txnConfig.familyName)); } } callable.call(null); return; case RequiresNew: if (tx == null) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagation level and no txn is found, starting new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; execute(tx, transactionContainer, pool, callable); return; } else { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } GammaTxn suspendedTransaction = tx; tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; try { execute(tx, transactionContainer, pool, callable); return; } finally { transactionContainer.txn = suspendedTransaction; } } case Supports: if(TRACING_ENABLED){ if(tx!=null){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } }else{ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } } callable.call(tx); return; default: throw new IllegalStateException(); } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } private void execute( GammaTxn tx, final TxnThreadLocal.Container transactionContainer, GammaTxnPool pool, final TxnVoidCallable callable)throws Exception{ Error cause = null; try{ boolean abort = true; try { do { try { cause = null; callable.call(tx); tx.commit(); abort = false; return; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } } GammaConstants.java000066400000000000000000000020621174000617100343710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.MultiverseConstants; /** * Contains the constants for the {@link GammaStm}. * * @author Peter Veentjer. */ public interface GammaConstants extends MultiverseConstants { int FAILURE = 0; int MASK_SUCCESS = 1; int MASK_UNREGISTERED = MASK_SUCCESS * 2; int MASK_CONFLICT = MASK_UNREGISTERED * 2; int REGISTRATION_DONE = 0; int REGISTRATION_NOT_NEEDED = 1; int REGISTRATION_NONE = 2; int TRANLOCAL_CONSTRUCTING = 1; int TRANLOCAL_WRITE = 2; int TRANLOCAL_COMMUTING = 3; int TRANLOCAL_READ = 4; int TX_ACTIVE = 1; int TX_PREPARED = 2; int TX_ABORTED = 3; int TX_COMMITTED = 4; int TYPE_INT = 1; int TYPE_LONG = 2; int TYPE_DOUBLE = 3; int TYPE_BOOLEAN = 4; int TYPE_REF = 5; int TRANSACTIONTYPE_LEAN_MONO = 1; int TRANSACTIONTYPE_LEAN_FIXED_LENGTH = 2; int TRANSACTIONTYPE_FAT_MONO = 3; int TRANSACTIONTYPE_FAT_FIXED_LENGTH = 4; int TRANSACTIONTYPE_FAT_VARIABLE_LENGTH = 5; int VERSION_UNCOMMITTED = 0; } GammaObjectPool.java000066400000000000000000000276011174000617100344630ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.CallableNode; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import java.util.ArrayList; /** * A pool for tranlocals. The pool is not threadsafe and should be connected to a thread (can * be stored in a threadlocal). Eventually the performance of the stm will be limited to the rate * of cleanup, and using a pool seriously improves scalability. *

* Improvement: atm there is only one single type of tranlocal. If there are more types of tranlocals, * each class needs to have an index. This index can be used to determine the type of ref. If the pool * contains an array of arrays, where the first array is index based on the type of the ref, finding the * second array (that contains pooled tranlocals) can be found easily. *

* ObjectPool is not thread safe and should not be shared between threads. *

* This class is generated. * * @author Peter Veentjer */ @SuppressWarnings({"ClassWithTooManyFields"}) public final class GammaObjectPool { private final static boolean ENABLED = Boolean.parseBoolean( System.getProperty("org.multiverse.stm,gamma.GammaObjectPool.enabled", "true")); private final static boolean TRANLOCAL_POOLING_ENABLED = Boolean.parseBoolean( System.getProperty("org.multiverse.stm.gamma.GammaObjectPool.tranlocalPooling", String.valueOf(ENABLED))); private final static boolean TRANLOCALARRAY_POOLING_ENABLED = Boolean.parseBoolean( System.getProperty("org.multiverse.stm.gamma.GammaObjectPool.tranlocalArrayPooling", String.valueOf(ENABLED))); private final static boolean LISTENER_POOLING_ENABLED = Boolean.parseBoolean( System.getProperty("org.multiverse.stm.gamma.GammaObjectPool.listenersPooling", String.valueOf(ENABLED))); private final static boolean LISTENERSARRAY_POOLING_ENABLED = Boolean.parseBoolean( System.getProperty("org.multiverse.stm.gamma.GammaObjectPool.listenersArrayPooling", String.valueOf(ENABLED))); private final static boolean ARRAYLIST_POOLING_ENABLED = Boolean.parseBoolean( System.getProperty("org.multiverse.stm.gamma.GammaObjectPool.arrayListPooling", String.valueOf(ENABLED))); private final static boolean CALLABLENODE_POOLING_ENABLED = Boolean.parseBoolean( System.getProperty("org.multiverse.stm.gamma.GammaObjectPool.callableNodePooling", String.valueOf(ENABLED))); private final boolean tranlocalPoolingEnabled; private final boolean tranlocalArrayPoolingEnabled; private final boolean listenersPoolingEnabled; private final boolean listenersArrayPoolingEnabled; private final boolean arrayListPoolingEnabled; private final boolean callableNodePoolingEnabled; private final Tranlocal[] tranlocals = new Tranlocal[100]; private int lastUsedGammaTxnRef = -1; private final Listeners[] listenersPool = new Listeners[100]; private int listenersPoolIndex = -1; private final ArrayList[] arrayListPool = new ArrayList[10]; private int arrayListPoolIndex = -1; private final CallableNode[] callableNodePool = new CallableNode[100]; private int callableNodePoolIndex = -1; public GammaObjectPool() { arrayListPoolingEnabled = ARRAYLIST_POOLING_ENABLED; tranlocalArrayPoolingEnabled = TRANLOCALARRAY_POOLING_ENABLED; tranlocalPoolingEnabled = TRANLOCAL_POOLING_ENABLED; listenersPoolingEnabled = LISTENER_POOLING_ENABLED; listenersArrayPoolingEnabled = LISTENERSARRAY_POOLING_ENABLED; callableNodePoolingEnabled = CALLABLENODE_POOLING_ENABLED; } /** * Takes a Tranlocal from the pool for the specified GammaTxnRef. * * @param owner the GammaTxnRef to get the Tranlocal for. * @return the pooled tranlocal, or null if none is found. * @throws NullPointerException if owner is null. */ public Tranlocal take(final BaseGammaTxnRef owner) { if (owner == null) { throw new NullPointerException(); } if (lastUsedGammaTxnRef == -1) { Tranlocal tranlocal = new Tranlocal(); tranlocal.owner = owner; return tranlocal; } Tranlocal tranlocal = tranlocals[lastUsedGammaTxnRef]; tranlocal.owner = owner; tranlocals[lastUsedGammaTxnRef] = null; lastUsedGammaTxnRef--; return tranlocal; } /** * Puts an old Tranlocal in this pool. If the tranlocal is allowed to be null, * the call is ignored. The same goes for when the tranlocal is permanent, since you * can't now how many transactions are still using it. * * @param tranlocal the Tranlocal to pool. */ public void put(final Tranlocal tranlocal) { if (!tranlocalPoolingEnabled) { return; } if (lastUsedGammaTxnRef == tranlocals.length - 1) { return; } lastUsedGammaTxnRef++; tranlocals[lastUsedGammaTxnRef] = tranlocal; } private Tranlocal[][] tranlocalArrayPool = new Tranlocal[8193][]; /** * Puts a GammaTranlocal array in the pool. * * @param array the GammaTranlocal array to put in the pool. * @throws NullPointerException is array is null. */ public void putTranlocalArray(final Tranlocal[] array) { if (array == null) { throw new NullPointerException(); } if (!tranlocalArrayPoolingEnabled) { return; } if (array.length - 1 > tranlocalArrayPool.length) { return; } int index = array.length; if (tranlocalArrayPool[index] != null) { return; } //lets clean the array for (int k = 0; k < array.length; k++) { array[k] = null; } tranlocalArrayPool[index] = array; } /** * Takes a tranlocal array from the pool with the given size. * * @param size the size of the array to take * @return the GammaTranlocal array taken from the pool, or null if none available. * @throws IllegalArgumentException if size smaller than 0. */ public Tranlocal[] takeTranlocalArray(final int size) { if (size < 0) { throw new IllegalArgumentException(); } if (!tranlocalArrayPoolingEnabled) { return new Tranlocal[size]; } if (size >= tranlocalArrayPool.length) { return new Tranlocal[size]; } if (tranlocalArrayPool[size] == null) { return new Tranlocal[size]; } Tranlocal[] array = tranlocalArrayPool[size]; tranlocalArrayPool[size] = null; return array; } /** * Takes a CallableNode from the pool, or null if none is available. * * @return the CallableNode from the pool, or null if none available. */ public CallableNode takeCallableNode() { if (!callableNodePoolingEnabled || callableNodePoolIndex == -1) { return new CallableNode(); } CallableNode node = callableNodePool[callableNodePoolIndex]; callableNodePool[callableNodePoolIndex] = null; callableNodePoolIndex--; return node; } /** * Puts a CallableNode in the pool. * * @param node the CallableNode to pool. * @throws NullPointerException if node is null. */ public void putCallableNode(CallableNode node) { if (node == null) { throw new NullPointerException(); } if (!callableNodePoolingEnabled || callableNodePoolIndex == callableNodePool.length - 1) { return; } node.prepareForPooling(); callableNodePoolIndex++; callableNodePool[callableNodePoolIndex] = node; } // ====================== array list =================================== /** * Takes an ArrayList from the pool, The returned ArrayList is cleared. * * @return the ArrayList from the pool, or null of none is found. */ public ArrayList takeArrayList() { if (!arrayListPoolingEnabled || arrayListPoolIndex == -1) { return new ArrayList(10); } ArrayList list = arrayListPool[arrayListPoolIndex]; arrayListPool[arrayListPoolIndex] = null; arrayListPoolIndex--; return list; } /** * Puts an ArrayList in this pool. The ArrayList will be cleared before being placed * in the pool. * * @param list the ArrayList to place in the pool. * @throws NullPointerException if list is null. */ public void putArrayList(ArrayList list) { if (list == null) { throw new NullPointerException(); } if (!arrayListPoolingEnabled || arrayListPoolIndex == arrayListPool.length - 1) { return; } list.clear(); arrayListPoolIndex++; arrayListPool[arrayListPoolIndex] = list; } // ============================ listeners ================================== /** * Takes a Listeners object from the pool. * * @return the Listeners object taken from the pool. or null if none is taken. */ public Listeners takeListeners() { if (!listenersPoolingEnabled || listenersPoolIndex == -1) { return new Listeners(); } Listeners listeners = listenersPool[listenersPoolIndex]; listenersPool[listenersPoolIndex] = null; listenersPoolIndex--; return listeners; } /** * Puts a Listeners object in the pool. The Listeners object is preparedForPooling before * it is put in the pool. The next Listeners object is ignored (the next field itself is ignored). * * @param listeners the Listeners object to pool. * @throws NullPointerException is listeners is null. */ public void putListeners(Listeners listeners) { if (listeners == null) { throw new NullPointerException(); } if (!listenersPoolingEnabled || listenersPoolIndex == listenersPool.length - 1) { return; } listeners.prepareForPooling(); listenersPoolIndex++; listenersPool[listenersPoolIndex] = listeners; } // ============================= listeners array ============================= private Listeners[] listenersArray = new Listeners[100000]; /** * Takes a Listeners array from the pool. If an array is returned, it is completely nulled. * * @param minimalSize the minimalSize of the Listeners array. * @return the found Listeners array, or null if none is taken from the pool. * @throws IllegalArgumentException if minimalSize is smaller than 0. */ public Listeners[] takeListenersArray(int minimalSize) { if (minimalSize < 0) { throw new IllegalArgumentException(); } if (!listenersArrayPoolingEnabled) { return new Listeners[minimalSize]; } if (listenersArray == null || listenersArray.length < minimalSize) { return new Listeners[minimalSize]; } Listeners[] result = listenersArray; listenersArray = null; return result; } /** * Puts a Listeners array in the pool. *

* Listeners array should be nulled before being put in the pool. It is not going to be done by this * GammaObjectPool but should be done when the listeners on the listeners array are notified. * * @param listenersArray the array to pool. * @throws NullPointerException if listenersArray is null. */ public void putListenersArray(Listeners[] listenersArray) { if (listenersArray == null) { throw new NullPointerException(); } if (!listenersArrayPoolingEnabled) { return; } if (this.listenersArray != listenersArray) { return; } this.listenersArray = listenersArray; } } GammaOrElseBlock.java000066400000000000000000000137031174000617100345650ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.*; import org.multiverse.api.callables.*; import org.multiverse.api.exceptions.*; import static org.multiverse.api.TxnThreadLocal.*; public class GammaOrElseBlock implements OrElseBlock{ @Override public E execute(TxnCallable either, TxnCallable orelse){ try{ return executeChecked(either,orelse); }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } @Override public E executeChecked(TxnCallable either, TxnCallable orelse)throws Exception{ if(either == null){ throw new NullPointerException("either callable can't be null"); } if(orelse == null){ throw new NullPointerException("orelse callable can't be null"); } Txn txn = getThreadLocalTxn(); if(txn == null){ throw new TxnMandatoryException("No txn is found, but one is required for the orelse"); } try{ return either.call(txn); }catch(RetryError retry){ return orelse.call(txn); } } @Override public int execute(TxnIntCallable either, TxnIntCallable orelse){ try{ return executeChecked(either,orelse); }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } @Override public int executeChecked(TxnIntCallable either, TxnIntCallable orelse)throws Exception{ if(either == null){ throw new NullPointerException("either callable can't be null"); } if(orelse == null){ throw new NullPointerException("orelse callable can't be null"); } Txn txn = getThreadLocalTxn(); if(txn == null){ throw new TxnMandatoryException("No txn is found, but one is required for the orelse"); } try{ return either.call(txn); }catch(RetryError retry){ return orelse.call(txn); } } @Override public long execute(TxnLongCallable either, TxnLongCallable orelse){ try{ return executeChecked(either,orelse); }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } @Override public long executeChecked(TxnLongCallable either, TxnLongCallable orelse)throws Exception{ if(either == null){ throw new NullPointerException("either callable can't be null"); } if(orelse == null){ throw new NullPointerException("orelse callable can't be null"); } Txn txn = getThreadLocalTxn(); if(txn == null){ throw new TxnMandatoryException("No txn is found, but one is required for the orelse"); } try{ return either.call(txn); }catch(RetryError retry){ return orelse.call(txn); } } @Override public double execute(TxnDoubleCallable either, TxnDoubleCallable orelse){ try{ return executeChecked(either,orelse); }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } @Override public double executeChecked(TxnDoubleCallable either, TxnDoubleCallable orelse)throws Exception{ if(either == null){ throw new NullPointerException("either callable can't be null"); } if(orelse == null){ throw new NullPointerException("orelse callable can't be null"); } Txn txn = getThreadLocalTxn(); if(txn == null){ throw new TxnMandatoryException("No txn is found, but one is required for the orelse"); } try{ return either.call(txn); }catch(RetryError retry){ return orelse.call(txn); } } @Override public boolean execute(TxnBooleanCallable either, TxnBooleanCallable orelse){ try{ return executeChecked(either,orelse); }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } @Override public boolean executeChecked(TxnBooleanCallable either, TxnBooleanCallable orelse)throws Exception{ if(either == null){ throw new NullPointerException("either callable can't be null"); } if(orelse == null){ throw new NullPointerException("orelse callable can't be null"); } Txn txn = getThreadLocalTxn(); if(txn == null){ throw new TxnMandatoryException("No txn is found, but one is required for the orelse"); } try{ return either.call(txn); }catch(RetryError retry){ return orelse.call(txn); } } @Override public void execute(TxnVoidCallable either, TxnVoidCallable orelse){ try{ executeChecked(either,orelse); return; }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } @Override public void executeChecked(TxnVoidCallable either, TxnVoidCallable orelse)throws Exception{ if(either == null){ throw new NullPointerException("either callable can't be null"); } if(orelse == null){ throw new NullPointerException("orelse callable can't be null"); } Txn txn = getThreadLocalTxn(); if(txn == null){ throw new TxnMandatoryException("No txn is found, but one is required for the orelse"); } try{ either.call(txn); return; }catch(RetryError retry){ orelse.call(txn); return; } } }GammaOrElseBlock.vm000066400000000000000000000032731174000617100342670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.*; import org.multiverse.api.callables.*; import org.multiverse.api.exceptions.*; import static org.multiverse.api.TxnThreadLocal.*; public class GammaOrElseBlock implements OrElseBlock{ #foreach($callable in $callables) @Override public ${callable.typeParameter} ${callable.type} execute(${callable.name}${callable.typeParameter} either, ${callable.name}${callable.typeParameter} orelse){ try{ #if(${callable.type} eq 'void') executeChecked(either,orelse); return; #else return executeChecked(either,orelse); #end }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } @Override public ${callable.typeParameter} ${callable.type} executeChecked(${callable.name}${callable.typeParameter} either, ${callable.name}${callable.typeParameter} orelse)throws Exception{ if(either == null){ throw new NullPointerException("either callable can't be null"); } if(orelse == null){ throw new NullPointerException("orelse callable can't be null"); } Txn txn = getThreadLocalTxn(); if(txn == null){ throw new TxnMandatoryException("No txn is found, but one is required for the orelse"); } try{ #if(${callable.type} eq 'void') either.call(txn); return; #else return either.call(txn); #end }catch(RetryError retry){ #if(${callable.type} eq 'void') orelse.call(txn); return; #else return orelse.call(txn); #end } } #end }Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/GammaStm.java000066400000000000000000000365671174000617100332600ustar00rootroot00000000000000package org.multiverse.stms.gamma; import org.multiverse.api.*; import org.multiverse.api.collections.TxnCollectionsFactory; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.collections.NaiveTxnCollectionFactory; import org.multiverse.stms.gamma.transactionalobjects.*; import org.multiverse.stms.gamma.transactions.*; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import static org.multiverse.stms.gamma.transactions.ThreadLocalGammaTxnPool.getThreadLocalGammaTxnPool; @SuppressWarnings({"ClassWithTooManyFields"}) public final class GammaStm implements Stm { /** * Creates a GammaStm implementation optimized for speed. This method probably will be invoked * by the {@link GlobalStmInstance}. * * @return the created GammaStm. */ @SuppressWarnings({"UnusedDeclaration"}) public static GammaStm createFast() { return new GammaStm(); } public final int defaultMaxRetries; public final int spinCount; public final BackoffPolicy defaultBackoffPolicy; public final GlobalConflictCounter globalConflictCounter = new GlobalConflictCounter(); public final GammaTxnRefFactoryImpl defaultRefFactory = new GammaTxnRefFactoryImpl(); public final GammaTxnRefFactoryBuilder refFactoryBuilder = new GammaTxnRefFactoryBuilderImpl(); public final GammaTxnExecutor defaultxnExecutor; public final GammaTxnConfig defaultConfig; public final NaiveTxnCollectionFactory defaultTransactionalCollectionFactory = new NaiveTxnCollectionFactory(this); public final int readBiasedThreshold; public final GammaOrElseBlock defaultOrElseBlock = new GammaOrElseBlock(); public GammaStm() { this(new GammaStmConfig()); } public GammaStm(GammaStmConfig config) { config.validate(); this.defaultMaxRetries = config.maxRetries; this.spinCount = config.spinCount; this.defaultBackoffPolicy = config.backoffPolicy; this.defaultConfig = new GammaTxnConfig(this, config) .setSpinCount(spinCount); this.defaultxnExecutor = newTxnFactoryBuilder() .setSpeculative(false) .newTxnExecutor(); this.readBiasedThreshold = config.readBiasedThreshold; } @Override public final GammaTxn newDefaultTxn() { return new FatVariableLengthGammaTxn(this); } @Override public final GammaTxnExecutor getDefaultTxnExecutor() { return defaultxnExecutor; } @Override public final GammaOrElseBlock newOrElseBlock() { return defaultOrElseBlock; } public final GlobalConflictCounter getGlobalConflictCounter() { return globalConflictCounter; } private final class GammaTxnFactoryBuilderImpl implements GammaTxnFactoryBuilder { private final GammaTxnConfig config; GammaTxnFactoryBuilderImpl(final GammaTxnConfig config) { this.config = config; } @Override public final GammaTxnFactoryBuilder setFat() { if (config.isFat) { return this; } return new GammaTxnFactoryBuilderImpl(config.setFat()); } @Override public final GammaTxnConfig getConfig() { return config; } @Override public GammaTxnFactoryBuilder addPermanentListener(final TxnListener listener) { return new GammaTxnFactoryBuilderImpl(config.addPermanentListener(listener)); } @Override public final GammaTxnFactoryBuilder setControlFlowErrorsReused(final boolean reused) { if (config.controlFlowErrorsReused = reused) { return this; } return new GammaTxnFactoryBuilderImpl(config.setControlFlowErrorsReused(reused)); } @Override public final GammaTxnFactoryBuilder setReadLockMode(final LockMode lockMode) { if (config.readLockMode == lockMode) { return this; } return new GammaTxnFactoryBuilderImpl(config.setReadLockMode(lockMode)); } @Override public final GammaTxnFactoryBuilder setWriteLockMode(final LockMode lockMode) { if (config.writeLockMode == lockMode) { return this; } return new GammaTxnFactoryBuilderImpl(config.setWriteLockMode(lockMode)); } @Override public final GammaTxnFactoryBuilder setFamilyName(final String familyName) { if (config.familyName.equals(familyName)) { return this; } return new GammaTxnFactoryBuilderImpl(config.setFamilyName(familyName)); } @Override public final GammaTxnFactoryBuilder setPropagationLevel(final PropagationLevel level) { if (level == config.propagationLevel) { return this; } return new GammaTxnFactoryBuilderImpl(config.setPropagationLevel(level)); } @Override public final GammaTxnFactoryBuilder setBlockingAllowed(final boolean blockingAllowed) { if (blockingAllowed == config.blockingAllowed) { return this; } return new GammaTxnFactoryBuilderImpl(config.setBlockingAllowed(blockingAllowed)); } @Override public final GammaTxnFactoryBuilder setIsolationLevel(final IsolationLevel isolationLevel) { if (isolationLevel == config.isolationLevel) { return this; } return new GammaTxnFactoryBuilderImpl(config.setIsolationLevel(isolationLevel)); } @Override public final GammaTxnFactoryBuilder setTraceLevel(final TraceLevel traceLevel) { if (traceLevel == config.traceLevel) { return this; } return new GammaTxnFactoryBuilderImpl(config.setTraceLevel(traceLevel)); } @Override public final GammaTxnFactoryBuilder setTimeoutNs(final long timeoutNs) { if (timeoutNs == config.timeoutNs) { return this; } return new GammaTxnFactoryBuilderImpl(config.setTimeoutNs(timeoutNs)); } @Override public final GammaTxnFactoryBuilder setInterruptible(final boolean interruptible) { if (interruptible == config.interruptible) { return this; } return new GammaTxnFactoryBuilderImpl(config.setInterruptible(interruptible)); } @Override public final GammaTxnFactoryBuilder setBackoffPolicy(final BackoffPolicy backoffPolicy) { //noinspection ObjectEquality if (backoffPolicy == config.backoffPolicy) { return this; } return new GammaTxnFactoryBuilderImpl(config.setBackoffPolicy(backoffPolicy)); } @Override public final GammaTxnFactoryBuilder setDirtyCheckEnabled(final boolean dirtyCheckEnabled) { if (dirtyCheckEnabled == config.dirtyCheck) { return this; } return new GammaTxnFactoryBuilderImpl(config.setDirtyCheckEnabled(dirtyCheckEnabled)); } @Override public final GammaTxnFactoryBuilder setSpinCount(final int spinCount) { if (spinCount == config.spinCount) { return this; } return new GammaTxnFactoryBuilderImpl(config.setSpinCount(spinCount)); } @Override public final GammaTxnFactoryBuilder setSpeculative(final boolean enabled) { if (enabled == config.speculative) { return this; } return new GammaTxnFactoryBuilderImpl( config.setSpeculative(enabled)); } @Override public final GammaTxnFactoryBuilder setReadonly(final boolean readonly) { if (readonly == config.readonly) { return this; } return new GammaTxnFactoryBuilderImpl(config.setReadonly(readonly)); } @Override public final GammaTxnFactoryBuilder setReadTrackingEnabled(final boolean enabled) { if (enabled == config.trackReads) { return this; } return new GammaTxnFactoryBuilderImpl(config.setReadTrackingEnabled(enabled)); } @Override public final GammaTxnFactoryBuilder setMaxRetries(final int maxRetries) { if (maxRetries == config.maxRetries) { return this; } return new GammaTxnFactoryBuilderImpl(config.setMaxRetries(maxRetries)); } @Override public final GammaTxnExecutor newTxnExecutor() { config.init(); if (isLean()) { return new LeanGammaTxnExecutor(newTransactionFactory()); } else { return new FatGammaTxnExecutor(newTransactionFactory()); } } private boolean isLean() { return config.propagationLevel == PropagationLevel.Requires; } @Override public GammaTxnFactory newTransactionFactory() { config.init(); if (config.isSpeculative()) { return new SpeculativeGammaTxnFactory(config, this); } else { return new NonSpeculativeGammaTxnFactory(config,this); } } } @Override public final GammaTxnRefFactory getDefaultRefFactory() { return defaultRefFactory; } private final class GammaTxnRefFactoryImpl implements GammaTxnRefFactory { @Override public final GammaTxnRef newTxnRef(E value) { return new GammaTxnRef(GammaStm.this, value); } @Override public final GammaTxnInteger newTxnInteger(int value) { return new GammaTxnInteger(GammaStm.this, value); } @Override public final GammaTxnBoolean newTxnBoolean(boolean value) { return new GammaTxnBoolean(GammaStm.this, value); } @Override public final GammaTxnDouble newTxnDouble(double value) { return new GammaTxnDouble(GammaStm.this, value); } @Override public final GammaTxnLong newTxnLong(long value) { return new GammaTxnLong(GammaStm.this, value); } } @Override public final GammaTxnFactoryBuilder newTxnFactoryBuilder() { final GammaTxnConfig config = new GammaTxnConfig(this); return new GammaTxnFactoryBuilderImpl(config); } @Override public final TxnCollectionsFactory getDefaultTxnCollectionFactory() { return defaultTransactionalCollectionFactory; } @Override public final GammaTxnRefFactoryBuilder getTxRefFactoryBuilder() { return refFactoryBuilder; } private final class GammaTxnRefFactoryBuilderImpl implements GammaTxnRefFactoryBuilder { @Override public GammaTxnRefFactory build() { return new GammaTxnRefFactoryImpl(); } } private static final class NonSpeculativeGammaTxnFactory implements GammaTxnFactory { private final GammaTxnConfig config; private final GammaTxnFactoryBuilder builder; NonSpeculativeGammaTxnFactory(final GammaTxnConfig config, GammaTxnFactoryBuilder builder) { this.config = config.init(); this.builder = builder; } @Override public TxnFactoryBuilder getTxnFactoryBuilder() { return builder; } @Override public final GammaTxnConfig getConfig() { return config; } @Override public final GammaTxn newTxn() { return newTransaction(getThreadLocalGammaTxnPool()); } @Override public final GammaTxn newTransaction(final GammaTxnPool pool) { FatVariableLengthGammaTxn tx = pool.takeMap(); if (tx == null) { tx = new FatVariableLengthGammaTxn(config); } else { tx.init(config); } return tx; } @Override public final GammaTxn upgradeAfterSpeculativeFailure(final GammaTxn tailingTx, final GammaTxnPool pool) { throw new UnsupportedOperationException(); } } private static final class SpeculativeGammaTxnFactory implements GammaTxnFactory { private final GammaTxnConfig config; private final GammaTxnFactoryBuilder builder; SpeculativeGammaTxnFactory(final GammaTxnConfig config, GammaTxnFactoryBuilder builder) { this.config = config.init(); this.builder = builder; } @Override public GammaTxnFactoryBuilder getTxnFactoryBuilder() { return builder; } @Override public final GammaTxnConfig getConfig() { return config; } @Override public final GammaTxn newTxn() { return newTransaction(getThreadLocalGammaTxnPool()); } @Override public final GammaTxn upgradeAfterSpeculativeFailure(final GammaTxn failingTx, final GammaTxnPool pool) { final GammaTxn tx = newTransaction(pool); tx.copyForSpeculativeFailure(failingTx); return tx; } @Override public final GammaTxn newTransaction(final GammaTxnPool pool) { final SpeculativeGammaConfiguration speculativeConfiguration = config.speculativeConfiguration.get(); final int length = speculativeConfiguration.minimalLength; if (length <= 1) { if (speculativeConfiguration.fat) { FatMonoGammaTxn tx = pool.takeFatMono(); if (tx == null) { return new FatMonoGammaTxn(config); } tx.init(config); return tx; } else { LeanMonoGammaTxn tx = pool.takeLeanMono(); if (tx == null) { return new LeanMonoGammaTxn(config); } tx.init(config); return tx; } } else if (length <= config.maxFixedLengthTransactionSize) { if (speculativeConfiguration.fat) { final FatFixedLengthGammaTxn tx = pool.takeFatFixedLength(); if (tx == null) { return new FatFixedLengthGammaTxn(config); } tx.init(config); return tx; } else { final LeanFixedLengthGammaTxn tx = pool.takeLeanFixedLength(); if (tx == null) { return new LeanFixedLengthGammaTxn(config); } tx.init(config); return tx; } } else { final FatVariableLengthGammaTxn tx = pool.takeMap(); if (tx == null) { return new FatVariableLengthGammaTxn(config); } tx.init(config); return tx; } } } } GammaStmConfig.java000066400000000000000000000303741174000617100343150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.BackoffPolicy; import org.multiverse.api.DefaultBackoffPolicy; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.api.PropagationLevel; import org.multiverse.api.TraceLevel; import org.multiverse.api.lifecycle.TxnListener; import java.util.LinkedList; import java.util.List; import static java.lang.String.format; /** * Contains the default configuration for all transactions created by the GammaStm. With the TxnFactoryBuilder, * this behavior can be overridden. *

* Once the GammaStm has been created, changes on this structure are ignored because the content of this configuration * is copied. * * @author Peter Veentjer. */ @SuppressWarnings({"ClassWithTooManyFields"}) public final class GammaStmConfig { /** * Contains the permanent TxnListeners that should always be executed. Null references are not allowed. */ public List permanentListeners = new LinkedList(); /** * The default propagation level for all transactions executed by the Stm. */ public PropagationLevel propagationLevel = PropagationLevel.Requires; /** * The default isolation level for all transactions executed by the GammaStm. */ public IsolationLevel isolationLevel = IsolationLevel.Snapshot; /** * The default isolation level for all reads. Putting this to a level higher than LockMode.None has the same * effect as putting the isolationLevel to IsolationLevel.Serialized although the former approach will be * pessimistic and the later be optimistic. */ public LockMode readLockMode = LockMode.None; /** * The default isolation level for all writes. For a write also a read is acquired, so the highest one wins. *

* Putting it the LockMode.Write gives the same behavior as you have with Oracle. Reads are still allowed (even * though a WriteLock is allowed) only other transactions are not able to acquire a lock on it (whatever the lock * should be). */ public LockMode writeLockMode = LockMode.None; /** * The default behavior if blocking transactions are allowed. */ public boolean blockingAllowed = true; /** * The default behavior for blocking transactions if they are allowed to be interrupted. */ public boolean interruptible = false; /** * The default timeout for a transaction if it blocks. A Long.MAX_VALUE indicates that there is no timeout. */ public long timeoutNs = Long.MAX_VALUE; /** * The default readonly behavior. Setting this to true would be quite useless. */ public boolean readonly = false; /** * The default number of spins a transaction is allowed for a read/write/commit if something is locked. */ public int spinCount = 64; /** * The default behavior for writing 'dirty' changes for an update transaction. If it is set to true, a change needs to * be made. If there is no change, it will not be written (and essentially be seen as a read). */ public boolean dirtyCheck = true; /** * The minimal size for the internal array for a variable length transaction. A variable length transaction internally uses * an array to store its content and when the transaction grows, the array will grow accordingly. */ public int minimalVariableLengthTransactionSize = 4; /** * If reads should be tracked by the transaction (this is something else than (semi)visible reads). The advantage of readtracking * is there is less overhead once it has been read, but the disadvantage is that the transaction needs to track more changes. */ public boolean trackReads = true; /** * The default number of retries a transaction is allowed to do if a transaction fails for a read/write conflict. The GammaStm also * uses a speculative configuration mechanism that can consume some, so setting it to a very low value in combination with * speculativeConfigEnabled is not recommended. */ public int maxRetries = 1000; /** * The GammaStm makes use of a speculative mechanism to select the optimal transaction settings/implementation for executing a transactional closure. * An TxnExecutor will start cheap and grow to use more expensive transaction implementations (see the Lean/Fat transactions) and * use the automatic retry mechanism of the STM to rescue itself from a situation where the speculation was incorrect. Setting it to false * reduces the number of unwanted conflicts (once the TxnExecutor has learned it will not make the same mistakes again, so you only need * to pay the price of speculation in the beginning) at the cost of overhead. */ public boolean speculativeConfigEnabled = true; /** * The maximum size size of a fixed length transaction. A fixed length transaction is very cheap compared to a variable length, but * the big problem of the fixed length is that it needs to do a full transaction scan to see if the desired data is there. So there is * a point where the full scan gets more expensive (O(N) vs O(log n)) expensive. *

* Atm there has not been put much research in finding the optimal size and it could differ from machine to machine. *

* It also is important that the fixed length transactions are able to put a frequently read ref in a hot spot, making the overhead * of searching lower. */ public int maxFixedLengthTransactionSize = 20; /** * If a transaction fails for a read/write conflict it should not hammer the system by trying again and running in the same conflict * The default backoff policy helps to back threads of by sleeping/yielding. */ public BackoffPolicy backoffPolicy = DefaultBackoffPolicy.MAX_100_MS; /** * With the trace level you have control if you get output of transactions executing. It helps with debugging. If the * org.multiverse.MultiverseConstants.___TracingEnabled is not set to true, this value is ignored and the whole profiling * stuff is removed by the JIT since it effectively has become dead code. */ public TraceLevel traceLevel = TraceLevel.None; /** * If control flow errors should be reused. Normally exception reuse would be a very very very bad thing to do. But if they are * used to regulate control flow, they can be thrown thousands of times a second and this puts a lot of pressure on the gc. The most * expensive part is building the StackTrace. *

* For more info about the control flow errors see the subclasses of the {@link org.multiverse.api.exceptions.ControlFlowError} like * the {@link org.multiverse.api.exceptions.ReadWriteConflict}, {@link org.multiverse.api.exceptions.RetryError} and the * {@link org.multiverse.api.exceptions.SpeculativeConfigurationError}. */ public boolean controlFlowErrorsReused = true; /** * Should only be used internally to select fat instead of lean transactions. Normally the speculative configuration takes care of this * but for testing purposes you want to control it manually. */ public boolean isFat = false; /** * The maximum size of a transaction that is allowed to do a full conflict scan instead of arrive/depart operations. Arrive/depart * is more expensive since it increased the pressure on refs that a full conflict scan for short transactions, but at a certain length * of the transaction only needing to do a full conflict scan when the global conflict counter increases, becomes cheaper. */ public int maximumPoorMansConflictScanLength = 20; /** * The number of times a transactional object is only read before becoming readbiased. The advantage of a readBiased transactional object * is that you don't need to arrive/depart (richmans conflict scan), but the disadvantage is that it could cause transactions to do * full conflict scans even though they are not required. */ public int readBiasedThreshold = 128; /** * Checks if the configuration is valid. * * @throws IllegalStateException if the configuration isn't valid. */ public void validate() { if (timeoutNs < 0) { throw new IllegalStateException( "[GammaStmConfig] timeoutNs can't be smaller than 0, " + "timeoutNs was " + timeoutNs); } if (readBiasedThreshold < 0) { throw new IllegalStateException( "[GammaStmConfig] readBiasedThreshold can't be smaller than 0, " + "readBiasedThreshold was " + readBiasedThreshold); } if (readBiasedThreshold > 1023) { throw new IllegalStateException( "[GammaStmConfig] readBiasedThreshold can't be larger than 1023, " + "readBiasedThreshold was " + readBiasedThreshold); } if (maximumPoorMansConflictScanLength < 0) { throw new IllegalStateException( "[GammaStmConfig] maximumFullConflictScanSize can't be smaller than 0, " + "maximumFullConflictScanSize was " + maxFixedLengthTransactionSize); } if (readLockMode == null) { throw new IllegalStateException( "[GammaStmConfig] readLockMode can't be null"); } if (writeLockMode == null) { throw new IllegalStateException( "[GammaStmConfig] writeLockMode can't be null"); } if (writeLockMode.asInt() < readLockMode.asInt()) { throw new IllegalStateException( format("[GammaStmConfig] writeLockMode [%s] can't be lower than readLockMode [%s]", writeLockMode, readLockMode)); } if (isolationLevel == null) { throw new IllegalStateException("[GammaStmConfig] isolationLevel can't be null"); } if (isolationLevel.doesAllowWriteSkew() && !trackReads) { throw new IllegalStateException( format("[GammaStmConfig] isolation level '%s' can't be combined with readtracking" + "is false since it is needed to prevent the writeskew problem", isolationLevel)); } if (blockingAllowed && !trackReads) { throw new IllegalStateException( "[GammaStmConfig] blockingAllowed can't be true if trackReads is false"); } if (spinCount < 0) { throw new IllegalStateException( "[GammaStmConfig] spinCount can't be smaller than 0, but was " + spinCount); } if (minimalVariableLengthTransactionSize < 1) { throw new IllegalStateException( "[GammaStmConfig] minimalVariableLengthTransactionSize can't be smaller than 1, but was " + minimalVariableLengthTransactionSize); } if (maxRetries < 0) { throw new IllegalStateException( "[GammaStmConfig] maxRetries can't be smaller than 0, but was " + maxRetries); } if (maxFixedLengthTransactionSize < 2) { throw new IllegalStateException( "[GammaStmConfig] maxFixedLengthTransactionSize can't be smaller than 2, but was " + maxFixedLengthTransactionSize); } if (backoffPolicy == null) { throw new IllegalStateException("[GammaStmConfig] backoffPolicy can't be null"); } if (traceLevel == null) { throw new IllegalStateException("[GammaStmConfig] traceLevel can't be null"); } if (propagationLevel == null) { throw new IllegalStateException("[GammaStmConfig] propagationLevel can't be null"); } if (permanentListeners == null) { throw new IllegalStateException("[GammaStmConfig] permanentListeners can't be null"); } for (int k = 0; k < permanentListeners.size(); k++) { TxnListener listener = permanentListeners.get(k); if (listener == null) { throw new IllegalStateException( format("[GammaStmConfig] permanentListener at index %s can't be null", k)); } } } } GammaStmUtils.java000066400000000000000000000032611174000617100342030ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.stms.gamma.transactionalobjects.GammaObject; import org.multiverse.stms.gamma.transactions.GammaTxn; import static java.lang.String.format; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public final class GammaStmUtils { public static String toDebugString(GammaObject o) { if (o == null) { return "null"; } else { return o.getClass().getName() + '@' + System.identityHashCode(o); } } public static GammaTxn getRequiredThreadLocalGammaTxn() { final Txn tx = getThreadLocalTxn(); if (tx == null) { throw new TxnMandatoryException(); } return asGammaTxn(tx); } public static GammaTxn asGammaTxn(final Txn tx) { if (tx instanceof GammaTxn) { return (GammaTxn) tx; } if (tx == null) { throw new NullPointerException("Txn can't be null"); } tx.abort(); throw new ClassCastException( format("Expected Txn of class %s, found %s", GammaTxn.class.getName(), tx.getClass().getName())); } public static boolean longAsBoolean(long value) { return value == 1; } public static long booleanAsLong(boolean b) { return b ? 1 : 0; } public static double longAsDouble(long value) { return Double.longBitsToDouble(value); } public static long doubleAsLong(double value) { return Double.doubleToLongBits(value); } //we don't want instances. private GammaStmUtils() { } } GammaTxnExecutor.java000066400000000000000000000005501174000617100347050ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; /** * An {@link org.multiverse.api.TxnExecutor} tailored for the GammaStm. * * @author Peter Veentjer. */ public interface GammaTxnExecutor extends TxnExecutor { @Override GammaTxnFactory getTxnFactory(); } GammaTxnExecutor.vm000066400000000000000000000335561174000617100344220ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.*; import org.multiverse.api.exceptions.*; import org.multiverse.api.callables.*; import org.multiverse.stms.gamma.transactions.*; import java.util.concurrent.Callable; import java.util.logging.Logger; import static java.lang.String.format; import static org.multiverse.api.TxnThreadLocal.*; /** * The {@link TxnExecutor} made for the GammaStm. * * This code is generated. * * @author Peter Veentjer */ public final class ${txnExecutor.name} extends AbstractGammaTxnExecutor{ private static final Logger logger = Logger.getLogger(${txnExecutor.name}.class.getName()); #if(!${txnExecutor.lean}) private final PropagationLevel propagationLevel; #end public ${txnExecutor.name}(final GammaTxnFactory txnFactory) { super(txnFactory); #if(!${txnExecutor.lean}) this.propagationLevel = txnConfig.propagationLevel; #end } @Override public GammaTxnFactory getTxnFactory(){ return txnFactory; } #foreach($callable in $callables) @Override public final ${callable.typeParameter} ${callable.type} executeChecked( final ${callable.name}${callable.typeParameter} callable)throws Exception{ try{ #if(${callable.type} eq 'void') execute(callable); #else return execute(callable); #end }catch(InvisibleCheckedException e){ throw e.getCause(); } } #if(${txnExecutor.lean}) @Override public final ${callable.typeParameter} ${callable.type} execute(final ${callable.name}${callable.typeParameter} callable){ if(callable == null){ throw new NullPointerException(); } final TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } Throwable cause = null; try{ if(tx != null && tx.isAlive()){ #if(${callable.type} eq 'void') callable.call(tx); return; #else return callable.call(tx); #end } tx = txnFactory.newTransaction(pool); transactionContainer.txn=tx; #transactionLogic() } #else ## end of txnExecutor.lean public ${callable.typeParameter} ${callable.type} execute(final ${callable.name}${callable.typeParameter} callable){ if(callable == null){ throw new NullPointerException(); } TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } try{ switch (propagationLevel) { case Requires: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level and no txn found, starting a new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; #if($callable.type eq 'void') execute(tx, transactionContainer,pool, callable); return; #else return execute(tx, transactionContainer, pool, callable); #end } else { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Requires' propagation level, and existing txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } #if($callable.type eq 'void') callable.call(tx); return; #else return callable.call(tx); #end } case Mandatory: if (tx == null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level, and no txn is found", txnConfig.familyName)); } } throw new TxnMandatoryException( format("No txn is found for TxnExecutor '%s' with 'Mandatory' propagation level", txnConfig.familyName)); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Mandatory' propagation level and txn [%s] found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } #if($callable.type eq 'void') callable.call(tx); return; #else return callable.call(tx); #end case Never: if (tx != null) { if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level, but txn [%s] is found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } throw new TxnNotAllowedException( format("No txn is allowed for TxnExecutor '%s' with propagation level 'Never'"+ ", but txn '%s' was found", txnConfig.familyName, tx.getConfig().getFamilyName()) ); } if (TRACING_ENABLED) { if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'Never' propagation level and no txn is found", txnConfig.familyName)); } } #if($callable.type eq 'void') callable.call(null); return; #else return callable.call(null); #end case RequiresNew: if (tx == null) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagation level and no txn is found, starting new txn", txnConfig.familyName)); } } tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; #if($callable.type eq 'void') execute(tx, transactionContainer, pool, callable); return; #else return execute(tx, transactionContainer, pool, callable); #end } else { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } GammaTxn suspendedTransaction = tx; tx = txnFactory.newTransaction(pool); transactionContainer.txn = tx; try { #if($callable.type eq 'void') execute(tx, transactionContainer, pool, callable); return; #else return execute(tx, transactionContainer, pool, callable); #end } finally { transactionContainer.txn = suspendedTransaction; } } case Supports: if(TRACING_ENABLED){ if(tx!=null){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } }else{ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info( format("[%s] Has 'RequiresNew' propagationLevel and existing txn [%s] was found", txnConfig.familyName, tx.getConfig().getFamilyName())); } } } #if($callable.type eq 'void') callable.call(tx); return; #else return callable.call(tx); #end default: throw new IllegalStateException(); } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } } private ${callable.typeParameter} ${callable.type} execute( GammaTxn tx, final TxnThreadLocal.Container transactionContainer, GammaTxnPool pool, final ${callable.name}${callable.typeParameter} callable)throws Exception{ Error cause = null; try{ #transactionLogic() } #end ##end of txnExecutor.lean #end ##end of for loop over closures #macro( transactionLogic ) boolean abort = true; try { do { try { cause = null; #if(${callable.type} eq 'void') callable.call(tx); #else ${callable.type} result = callable.call(tx); #end tx.commit(); abort = false; #if(${callable.type} eq 'void') return; #else return result; #end } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); #end ##end of macro } GammaTxnRefFactory.java000066400000000000000000000011701174000617100351520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.references.TxnRefFactory; import org.multiverse.stms.gamma.transactionalobjects.*; /** * A {@link org.multiverse.api.references.TxnRefFactory} tailored for the GammaStm. * * @author Peter Veentjer. */ public interface GammaTxnRefFactory extends TxnRefFactory { @Override GammaTxnRef newTxnRef(E value); @Override GammaTxnInteger newTxnInteger(int value); @Override GammaTxnBoolean newTxnBoolean(boolean value); @Override GammaTxnDouble newTxnDouble(double value); @Override GammaTxnLong newTxnLong(long value); } GammaTxnRefFactoryBuilder.java000066400000000000000000000005341174000617100364640ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.references.TxnRefFactoryBuilder; /** * A {@link org.multiverse.api.references.TxnRefFactoryBuilder} tailored for the GammaStm. * * @author Peter Veentjer. */ public interface GammaTxnRefFactoryBuilder extends TxnRefFactoryBuilder { @Override GammaTxnRefFactory build(); } GlobalConflictCounter.java000066400000000000000000000031701174000617100356750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import java.util.concurrent.atomic.AtomicLong; /** * The GlobalConflictCounter is used as a mechanism for guaranteeing read consistency. Depending on the configuration of the * transaction, if a transaction does a read, it also makes the read semi visible (only the number of readers are interesting * and not the actual transaction). If a updating transaction sees that there are readers, it increased the GlobalConflictCounter * and forces all reading transactions to do a conflict scan once they read transactional objects they have not read before. *

* This mechanism is based on the SkySTM. The advantage of this approach compared to the TL2 approach is that the GlobalConflictCounter * is only increased on conflict and not on every update. *

* Small transactions don't make use of this mechanism and do a full conflict scan every time. The advantage is that the pressure * on the GlobalConflictCounter is reduced and that expensive arrives/departs (requiring in most cases 1 or 2 cas operations) * are reduced as well. * * @author Peter Veentjer. */ public final class GlobalConflictCounter { private final AtomicLong counter = new AtomicLong(); /** * Signals that a conflict occurred. */ public void signalConflict() { final long oldCount = counter.get(); counter.compareAndSet(oldCount, oldCount + 1); } /** * Gets the current conflict count. The actual value is not interesting, only the change is important. * * @return the current conflict count. */ public long count() { return counter.get(); } } LeanGammaTxnExecutor.java000066400000000000000000000602231174000617100355100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.multiverse.api.*; import org.multiverse.api.exceptions.*; import org.multiverse.api.callables.*; import org.multiverse.stms.gamma.transactions.*; import java.util.concurrent.Callable; import java.util.logging.Logger; import static java.lang.String.format; import static org.multiverse.api.TxnThreadLocal.*; /** * The {@link TxnExecutor} made for the GammaStm. * * This code is generated. * * @author Peter Veentjer */ public final class LeanGammaTxnExecutor extends AbstractGammaTxnExecutor{ private static final Logger logger = Logger.getLogger(LeanGammaTxnExecutor.class.getName()); public void execute(Runnable runnable){ throw new UnsupportedOperationException(); } public E execute(Callable callable){ throw new UnsupportedOperationException(); } public E executeChecked(Callable callable)throws Exception{ throw new UnsupportedOperationException(); } public LeanGammaTxnExecutor(final GammaTxnFactory txnFactory) { super(txnFactory); } @Override public GammaTxnFactory getTxnFactory(){ return txnFactory; } @Override public final E executeChecked( final TxnCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } @Override public final E execute(final TxnCallable callable){ if(callable == null){ throw new NullPointerException(); } final TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } Throwable cause = null; try{ if(tx != null && tx.isAlive()){ return callable.call(tx); } tx = txnFactory.newTransaction(pool); transactionContainer.txn=tx; boolean abort = true; try { do { try { cause = null; E result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final int executeChecked( final TxnIntCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } @Override public final int execute(final TxnIntCallable callable){ if(callable == null){ throw new NullPointerException(); } final TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } Throwable cause = null; try{ if(tx != null && tx.isAlive()){ return callable.call(tx); } tx = txnFactory.newTransaction(pool); transactionContainer.txn=tx; boolean abort = true; try { do { try { cause = null; int result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final long executeChecked( final TxnLongCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } @Override public final long execute(final TxnLongCallable callable){ if(callable == null){ throw new NullPointerException(); } final TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } Throwable cause = null; try{ if(tx != null && tx.isAlive()){ return callable.call(tx); } tx = txnFactory.newTransaction(pool); transactionContainer.txn=tx; boolean abort = true; try { do { try { cause = null; long result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final double executeChecked( final TxnDoubleCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } @Override public final double execute(final TxnDoubleCallable callable){ if(callable == null){ throw new NullPointerException(); } final TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } Throwable cause = null; try{ if(tx != null && tx.isAlive()){ return callable.call(tx); } tx = txnFactory.newTransaction(pool); transactionContainer.txn=tx; boolean abort = true; try { do { try { cause = null; double result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final boolean executeChecked( final TxnBooleanCallable callable)throws Exception{ try{ return execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } @Override public final boolean execute(final TxnBooleanCallable callable){ if(callable == null){ throw new NullPointerException(); } final TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } Throwable cause = null; try{ if(tx != null && tx.isAlive()){ return callable.call(tx); } tx = txnFactory.newTransaction(pool); transactionContainer.txn=tx; boolean abort = true; try { do { try { cause = null; boolean result = callable.call(tx); tx.commit(); abort = false; return result; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } @Override public final void executeChecked( final TxnVoidCallable callable)throws Exception{ try{ execute(callable); }catch(InvisibleCheckedException e){ throw e.getCause(); } } @Override public final void execute(final TxnVoidCallable callable){ if(callable == null){ throw new NullPointerException(); } final TxnThreadLocal.Container transactionContainer = getThreadLocalTxnContainer(); GammaTxnPool pool = (GammaTxnPool) transactionContainer.txPool; if (pool == null) { pool = new GammaTxnPool(); transactionContainer.txPool = pool; } GammaTxn tx = (GammaTxn)transactionContainer.txn; if(tx == null || !tx.isAlive()){ tx = null; } Throwable cause = null; try{ if(tx != null && tx.isAlive()){ callable.call(tx); return; } tx = txnFactory.newTransaction(pool); transactionContainer.txn=tx; boolean abort = true; try { do { try { cause = null; callable.call(tx); tx.commit(); abort = false; return; } catch (RetryError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a retry", txnConfig.familyName)); } } tx.awaitUpdate(); } catch (SpeculativeConfigurationError e) { if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a speculative configuration error", txnConfig.familyName)); } } abort = false; GammaTxn old = tx; tx = txnFactory.upgradeAfterSpeculativeFailure(tx,pool); pool.put(old); transactionContainer.txn = tx; } catch (ReadWriteConflict e) { cause = e; if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Encountered a read or write conflict", txnConfig.familyName)); } } backoffPolicy.delayUninterruptible(tx.getAttempt()); } } while (tx.softReset()); } finally { if (abort) { tx.abort(); } pool.put(tx); transactionContainer.txn = null; } }catch(RuntimeException e){ throw e; }catch(Exception e){ throw new InvisibleCheckedException(e); } if(TRACING_ENABLED){ if (txnConfig.getTraceLevel().isLoggableFrom(TraceLevel.Coarse)) { logger.info(format("[%s] Maximum number of %s retries has been reached", txnConfig.familyName, txnConfig.getMaxRetries())); } } throw new TooManyRetriesException( format("[%s] Maximum number of %s retries has been reached", txnConfig.getFamilyName(), txnConfig.getMaxRetries()), cause); } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/Listeners.java000066400000000000000000000064111174000617100335030ustar00rootroot00000000000000package org.multiverse.stms.gamma; import org.multiverse.api.blocking.RetryLatch; /** * A Listeners object contains all the Latches of blockingAllowed transactions that listen to a write on a * transactional object. Essentially it is a single linked list. *

* This is an 'immutable' class. As long as it is registered to a transactional object, it should not be mutated. * But as soon as it is removed as listener, only a single thread has access to this Listeners object. This means * that it can be pooled. *

* Setting the Listeners and removing the it should provide the happens before relation so that all changes made * to the Listener before it is getAndSet, are visible when it is removed. * * @author Peter Veentjer */ public final class Listeners { public Listeners next; public RetryLatch listener; public long listenerEra; //public String threadName; /** * Prepares this Listeners object for pooling. This is done by: *

    *
  1. setting the next to null
  2. *
  3. setting the listener to null
  4. *
  5. setting the listenerEra to Long.MIN_VALUE
  6. *
*

* This call is not threadsafe and should only be done by a transaction that has exclusive access to * the listeners. The most logical place would be in the object pool when the Listeners is placed there. */ public void prepareForPooling() { next = null; listener = null; listenerEra = Long.MIN_VALUE; } /** * Opens all latches. *

* All Listeners are put in the pool. The Latches are not put in the pool since no guarantee can be given * that the Latch is still registered on a different transactional object. *

* This call should only be done by the transaction that removed the listeners from * the transactional object. So it is not threadsafe, * * @param pool the GammaObjectPool to store the discarded Listeners in. */ public void openAll(final GammaObjectPool pool) { Listeners current = this; do { Listeners next = current.next; current.listener.open(current.listenerEra); pool.putListeners(current); current = next; } while (current != null); } /** * Opens all the listeners. As soon as in the array a null element is found, it signals the end of * the list of listeners. This makes is possible to place an array that is larger than the actual * number of writes. *

* The call safely can be made with a null listenersArray. In that case the call is ignored. * * @param listenersArray the array of Listeners to notify. * @param pool the GammaObjectPool to pool the Listeners and the array containing the listeners. */ public static void openAll(final Listeners[] listenersArray, final GammaObjectPool pool) { if (listenersArray == null) { return; } for (int k = 0; k < listenersArray.length; k++) { Listeners listeners = listenersArray[k]; //we can end as soon as a null is found. if (listeners == null) { break; } listenersArray[k] = null; listeners.openAll(pool); } } } ThreadLocalGammaObjectPool.java000066400000000000000000000010561174000617100365620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; /** * A ThreadLocal that contains the {@link GammaObjectPool}. * * @author Peter Veentjer. */ public final class ThreadLocalGammaObjectPool { public final static ThreadLocal threadlocal = new ThreadLocal() { protected GammaObjectPool initialValue() { return new GammaObjectPool(); } }; public static GammaObjectPool getThreadLocalGammaObjectPool() { return threadlocal.get(); } private ThreadLocalGammaObjectPool() { } } 000077500000000000000000000000001174000617100350235ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectsAbstractGammaObject.java000066400000000000000000000644621174000617100415370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.Lock; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.PanicError; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.utils.ToolUnsafe; import sun.misc.Unsafe; import static java.lang.String.format; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; @SuppressWarnings({"OverlyComplexClass"}) public abstract class AbstractGammaObject implements GammaObject, Lock { public static final long MASK_OREC_EXCLUSIVELOCK = 0x8000000000000000L; public static final long MASK_OREC_UPDATELOCK = 0x4000000000000000L; public static final long MASK_OREC_READBIASED = 0x2000000000000000L; public static final long MASK_OREC_READLOCKS = 0x1FFFFF0000000000L; public static final long MASK_OREC_SURPLUS = 0x000000FFFFFFFE00L; public static final long MASK_OREC_READONLY_COUNT = 0x00000000000003FFL; protected static final Unsafe ___unsafe = ToolUnsafe.getUnsafe(); protected static final long listenersOffset; protected static final long valueOffset; static { try { listenersOffset = ___unsafe.objectFieldOffset( AbstractGammaObject.class.getDeclaredField("listeners")); valueOffset = ___unsafe.objectFieldOffset( AbstractGammaObject.class.getDeclaredField("orec")); } catch (Exception ex) { throw new Error(ex); } } public final GammaStm stm; @SuppressWarnings({"UnusedDeclaration"}) public volatile Listeners listeners; @SuppressWarnings({"VolatileLongOrDoubleField"}) public volatile long version; @SuppressWarnings({"VolatileLongOrDoubleField"}) public volatile long orec; //This field has a controlled JMM problem (just like the hashcode of String). protected int identityHashCode; //it is important that the maximum threshold is not larger than 1023 (there are 10 bits for the readonly count) private final int readBiasedThreshold; public AbstractGammaObject(GammaStm stm) { assert stm != null; this.stm = stm; this.readBiasedThreshold = stm.readBiasedThreshold; } @Override public final long getVersion() { return version; } @Override public final GammaStm getStm() { return stm; } @Override public final Lock getLock() { return this; } public final Listeners ___removeListenersAfterWrite() { if (listeners == null) { return null; } Listeners removedListeners; while (true) { removedListeners = listeners; if (___unsafe.compareAndSwapObject(this, listenersOffset, removedListeners, null)) { return removedListeners; } } } //a controlled jmm problem here since identityHashCode is not synchronized/volatile/final. //this is the same as with the hashcode and String. @Override public final int identityHashCode() { int tmp = identityHashCode; if (tmp != 0) { return tmp; } tmp = System.identityHashCode(this); identityHashCode = tmp; return tmp; } public final int atomicGetLockModeAsInt() { final long current = orec; if (hasExclusiveLock(current)) { return LOCKMODE_EXCLUSIVE; } if (hasWriteLock(current)) { return LOCKMODE_WRITE; } if (getReadLockCount(current) > 0) { return LOCKMODE_READ; } return LOCKMODE_NONE; } @Override public final LockMode atomicGetLockMode() { switch (atomicGetLockModeAsInt()) { case LOCKMODE_NONE: return LockMode.None; case LOCKMODE_READ: return LockMode.Read; case LOCKMODE_WRITE: return LockMode.Write; case LOCKMODE_EXCLUSIVE: return LockMode.Exclusive; default: throw new IllegalStateException(); } } @Override public final LockMode getLockMode() { final GammaTxn tx = (GammaTxn) getThreadLocalTxn(); if (tx == null) { throw new TxnMandatoryException(); } return getLockMode(tx); } @Override public final LockMode getLockMode(final Txn tx) { return getLockMode((GammaTxn) tx); } public final LockMode getLockMode(final GammaTxn tx) { final Tranlocal tranlocal = tx.locate((BaseGammaTxnRef) this); if (tranlocal == null) { return LockMode.None; } switch (tranlocal.getLockMode()) { case LOCKMODE_NONE: return LockMode.None; case LOCKMODE_READ: return LockMode.Read; case LOCKMODE_WRITE: return LockMode.Write; case LOCKMODE_EXCLUSIVE: return LockMode.Exclusive; default: throw new IllegalStateException(); } } private static void yieldIfNeeded(final int remainingSpins) { if (remainingSpins % SPIN_YIELD == 0 && remainingSpins > 0) { //noinspection CallToThreadYield Thread.yield(); } } public final boolean waitForExclusiveLockToBecomeFree(int spinCount) { do { if (!hasExclusiveLock(orec)) { return true; } spinCount--; } while (spinCount >= 0); return false; } public final boolean hasWriteLock() { return hasWriteLock(orec); } public final boolean hasExclusiveLock() { return hasExclusiveLock(orec); } public final int getReadBiasedThreshold() { return readBiasedThreshold; } public final long getSurplus() { return getSurplus(orec); } public final boolean isReadBiased() { return isReadBiased(orec); } public final int getReadonlyCount() { return getReadonlyCount(orec); } public final int getReadLockCount() { return getReadLockCount(orec); } /** * Arrives. The Arrive is needed for the fast conflict detection (rich mans conflict). * * @param spinCount the maximum number of times to spin if the exclusive lock is acquired. * @return the arrive status. */ public final int arrive(int spinCount) { do { final long current = orec; if (hasExclusiveLock(current)) { spinCount--; yieldIfNeeded(spinCount); continue; } long surplus = getSurplus(current); final boolean isReadBiased = isReadBiased(current); if (isReadBiased) { if (surplus == 0) { surplus = 1; } else if (surplus == 1) { return MASK_SUCCESS + MASK_UNREGISTERED; } else { throw new PanicError("Surplus for a readbiased orec can never be larger than 1"); } } else { surplus++; } final long next = setSurplus(current, surplus); if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { int result = MASK_SUCCESS; if (isReadBiased) { result += MASK_UNREGISTERED; } return result; } } while (spinCount >= 0); return FAILURE; } public final int upgradeReadLock(int spinCount, final boolean exclusiveLock) { do { final long current = orec; int readLockCount = getReadLockCount(current); if (readLockCount == 0) { throw new PanicError(format("Can't update from readlock to %s if no readlocks are acquired", exclusiveLock ? "exclusiveLock" : "writeLock")); } if (readLockCount > 1) { spinCount--; yieldIfNeeded(spinCount); continue; } long next = setReadLockCount(current, 0); if (exclusiveLock) { next = setExclusiveLock(next, true); } else { next = setWriteLock(next, true); } if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { int result = MASK_SUCCESS; if (exclusiveLock) { if (isReadBiased(current) || getSurplus(current) > 1) { result += MASK_CONFLICT; } } return result; } } while (spinCount >= 0); return FAILURE; } /** * Upgrades the writeLock to an exclusive lock. * * @return true if there was at least one conflict write. */ public final boolean upgradeWriteLock() { while (true) { final long current = orec; if (hasExclusiveLock(current)) { return false; } if (!hasWriteLock(current)) { throw new PanicError("WriteLock is not acquired"); } long next = setExclusiveLock(current, true); next = setWriteLock(next, false); if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { return isReadBiased(current) || getSurplus(current) > 1; } } } /** * Arrives and tries to acquire the lock. If one of them fails, there will not be any state change. * * @param spinCount the maximum number of times to spin to wait for the lock to come available. * @param lockMode the desired lockmode. It isn't allowed to be LOCKMODE_NONE. * @return the result of this operation. */ public final int arriveAndLock(int spinCount, final int lockMode) { assert lockMode != LOCKMODE_NONE; do { final long current = orec; boolean locked = lockMode == LOCKMODE_READ ? hasWriteOrExclusiveLock(current) : hasAnyLock(current); if (locked) { spinCount--; yieldIfNeeded(spinCount); continue; } long currentSurplus = getSurplus(current); long surplus = currentSurplus; boolean isReadBiased = isReadBiased(current); if (isReadBiased) { if (surplus == 0) { surplus = 1; } else if (surplus > 1) { throw new PanicError("Surplus is larger than 1 and orec is readbiased: " + toOrecString(current)); } } else { surplus++; } long next = setSurplus(current, surplus); if (lockMode == LOCKMODE_EXCLUSIVE) { next = setExclusiveLock(next, true); } else if (lockMode == LOCKMODE_READ) { next = setReadLockCount(next, getReadLockCount(current) + 1); } else if (lockMode == LOCKMODE_WRITE) { next = setWriteLock(next, true); } if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { int result = MASK_SUCCESS; if (isReadBiased) { result += MASK_UNREGISTERED; } if (lockMode == LOCKMODE_EXCLUSIVE && currentSurplus > 0) { result += MASK_CONFLICT; } return result; } } while (spinCount >= 0); return FAILURE; } /** * Tries to acquire the exclusive lock and arrive. * * @param spinCount the maximum number of spins when it is locked. * @return the arrive-status. */ public final int arriveAndExclusiveLock(int spinCount) { do { final long current = orec; if (hasAnyLock(current)) { spinCount--; yieldIfNeeded(spinCount); continue; } final long currentSurplus = getSurplus(current); long surplus = currentSurplus; boolean isReadBiased = isReadBiased(current); if (isReadBiased) { if (surplus == 0) { surplus = 1; } else if (surplus > 1) { throw new PanicError("Surplus is larger than 2: " + toOrecString(current)); } } else { surplus++; } long next = setSurplus(current, surplus); next = setExclusiveLock(next, true); if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { int result = MASK_SUCCESS; if (isReadBiased) { result += MASK_UNREGISTERED; } if (currentSurplus > 0) { result += MASK_CONFLICT; } return result; } } while (spinCount >= 0); return FAILURE; } /** * Arrives and tries to acquire the lock. If one of them fails, there will not be any state change. * * @param spinCount the maximum number of times to spin if a lock is acquired. * @param lockMode the desired lockMode. This is not allowed to be LOCKMODE_NONE. * @return the status of the operation. */ public final int lockAfterArrive(int spinCount, final int lockMode) { assert lockMode != LOCKMODE_NONE; do { final long current = orec; if (isReadBiased(current)) { throw new PanicError("Orec is readbiased " + toOrecString(current)); } boolean locked = lockMode == LOCKMODE_READ ? hasWriteOrExclusiveLock(current) : hasAnyLock(current); if (locked) { spinCount--; yieldIfNeeded(spinCount); continue; } final long currentSurplus = getSurplus(current); if (currentSurplus == 0) { throw new PanicError("There is no surplus (so if it didn't do a read before)" + toOrecString(current)); } long next = current; if (lockMode == LOCKMODE_READ) { next = setReadLockCount(next, getReadLockCount(current) + 1); } else if (lockMode == LOCKMODE_EXCLUSIVE) { next = setExclusiveLock(next, true); } else { next = setWriteLock(current, true); } if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { int result = MASK_SUCCESS; if (lockMode == LOCKMODE_EXCLUSIVE && currentSurplus > 1) { result += MASK_CONFLICT; } return result; } } while (spinCount >= 0); return FAILURE; } /** * Departs after a successful read is done and no lock was acquired. *

* This call increased the readonly count. If the readonly count threshold is reached, the orec is * made readbiased and the readonly count is set to 0. */ public final void departAfterReading() { while (true) { final long current = orec; long surplus = getSurplus(current); if (surplus == 0) { throw new PanicError("There is no surplus " + toOrecString(current)); } boolean isReadBiased = isReadBiased(current); if (isReadBiased) { throw new PanicError("Orec is readbiased " + toOrecString(current)); } int readonlyCount = getReadonlyCount(current); if (readonlyCount < readBiasedThreshold) { readonlyCount++; } if (surplus <= 1 && hasAnyLock(current)) { throw new PanicError("There is not enough surplus " + toOrecString(current)); } surplus--; final boolean hasExclusiveLock = hasExclusiveLock(current); if (!hasExclusiveLock && surplus == 0 && readonlyCount == readBiasedThreshold) { isReadBiased = true; readonlyCount = 0; } long next = setIsReadBiased(current, isReadBiased); next = setReadonlyCount(next, readonlyCount); next = setSurplus(next, surplus); if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { return; } } } /** * Departs after a successful read is done and release the lock (it doesn't matter which lock is acquired as long is * it is a read/write/exclusive lock. *

* This method increases the readonly count of the orec and upgraded from update-biased to * readbiased if the READBIASED_THRESHOLD is reached (also the readonly count is set to zero * if that happens). */ public final void departAfterReadingAndUnlock() { while (true) { final long current = orec; long surplus = getSurplus(current); if (surplus == 0) { throw new PanicError("There is no surplus: " + toOrecString(current)); } int readLockCount = getReadLockCount(current); if (readLockCount == 0 && !hasWriteOrExclusiveLock(current)) { throw new PanicError("No Lock acquired " + toOrecString(current)); } boolean isReadBiased = isReadBiased(current); if (isReadBiased) { throw new PanicError("Orec is readbiased " + toOrecString(current)); } int readonlyCount = getReadonlyCount(current); surplus--; if (readonlyCount < readBiasedThreshold) { readonlyCount++; } if (surplus == 0 && readonlyCount == readBiasedThreshold) { isReadBiased = true; readonlyCount = 0; } long next = current; if (readLockCount > 0) { next = setReadLockCount(next, readLockCount - 1); } else { next = setExclusiveLock(next, false); next = setWriteLock(next, false); } next = setIsReadBiased(next, isReadBiased); next = setReadonlyCount(next, readonlyCount); next = setSurplus(next, surplus); if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { return; } } } public final void departAfterUpdateAndUnlock() { while (true) { final long current = orec; if (!hasExclusiveLock(current)) { throw new PanicError( "Can't departAfterUpdateAndUnlock if the commit lock is not acquired " + toOrecString(current)); } long surplus = getSurplus(current); if (surplus == 0) { throw new PanicError( "Can't departAfterUpdateAndUnlock is there is no surplus " + toOrecString(current)); } if (isReadBiased(current)) { if (surplus > 1) { throw new PanicError( "The surplus can never be larger than 1 if readBiased " + toOrecString(current)); } //there always is a conflict when a readbiased orec is updated. surplus = 0; } else { surplus--; } if (surplus == 0) { orec = 0; return; } final long next = setSurplus(0, surplus); if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { return; } } } /** * Departs after a transaction fails and has an arrive on this Orec. It doesn't matter what the lock level * is, as long as it is higher than LOCKMODE_NONE. This call can safely be made on a read or update biased * ref. */ public final void departAfterFailureAndUnlock() { while (true) { final long current = orec; //-1 indicates write or commit lock, value bigger than 0 indicates readlock int lockMode; if (hasWriteOrExclusiveLock(current)) { lockMode = -1; } else { lockMode = getReadLockCount(current); } if (lockMode == 0) { throw new PanicError( "No lock was not acquired " + toOrecString(current)); } long surplus = getSurplus(current); if (surplus == 0) { throw new PanicError( "There is no surplus " + toOrecString(current)); } //we can only decrease the surplus if it is not read biased. Because with a read biased //orec, we have no idea how many readers there are. if (!isReadBiased(current)) { surplus--; } long next = setSurplus(current, surplus); if (lockMode == -1) { next = setExclusiveLock(next, false); next = setWriteLock(next, false); } else { next = setReadLockCount(next, lockMode - 1); } if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { return; } } } /** * Departs after failure. */ public final void departAfterFailure() { while (true) { final long current = orec; if (isReadBiased(current)) { throw new PanicError("Orec is readbiased:" + toOrecString(current)); } long surplus = getSurplus(current); if (hasExclusiveLock(current)) { if (surplus < 2) { throw new PanicError( "there must be at least 2 readers, the thread that acquired the lock, " + "and the calling thread " + toOrecString(current)); } } else if (surplus == 0) { throw new PanicError("There is no surplus " + toOrecString(current)); } surplus--; long next = setSurplus(current, surplus); if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { return; } } } public final void unlockByUnregistered() { while (true) { final long current = orec; //-1 indicates write or commit lock, value bigger than 0 indicates readlock if (!isReadBiased(current)) { throw new PanicError( "Can't ___unlockByReadBiased when it is not readbiased " + toOrecString(current)); } int lockMode; if (hasWriteOrExclusiveLock(current)) { lockMode = -1; } else { lockMode = getReadLockCount(current); } if (lockMode == 0) { throw new PanicError("No Lock " + toOrecString(current)); } if (getSurplus(current) > 1) { throw new PanicError("Surplus for readbiased orec larger than 1 " + toOrecString(current)); } long next = current; if (lockMode > 0) { next = setReadLockCount(next, lockMode - 1); } else { next = setExclusiveLock(next, false); next = setWriteLock(next, false); } if (___unsafe.compareAndSwapLong(this, valueOffset, current, next)) { return; } } } public final String ___toOrecString() { return toOrecString(orec); } public static long setReadLockCount(final long value, final long readLockCount) { return (value & ~MASK_OREC_READLOCKS) | (readLockCount << 40); } public static int getReadLockCount(final long value) { return (int) ((value & MASK_OREC_READLOCKS) >> 40); } public static long setExclusiveLock(final long value, final boolean exclusiveLock) { return (value & ~MASK_OREC_EXCLUSIVELOCK) | ((exclusiveLock ? 1L : 0L) << 63); } public static boolean hasWriteOrExclusiveLock(final long value) { return ((value & (MASK_OREC_EXCLUSIVELOCK + MASK_OREC_UPDATELOCK)) != 0); } public static boolean hasAnyLock(final long value) { return ((value & (MASK_OREC_EXCLUSIVELOCK + MASK_OREC_UPDATELOCK + MASK_OREC_READLOCKS)) != 0); } public static boolean hasExclusiveLock(final long value) { return (value & MASK_OREC_EXCLUSIVELOCK) != 0; } public static boolean isReadBiased(final long value) { return (value & MASK_OREC_READBIASED) != 0; } public static long setIsReadBiased(final long value, final boolean isReadBiased) { return (value & ~MASK_OREC_READBIASED) | ((isReadBiased ? 1L : 0L) << 61); } public static boolean hasWriteLock(final long value) { return (value & MASK_OREC_UPDATELOCK) != 0; } public static long setWriteLock(final long value, final boolean updateLock) { return (value & ~MASK_OREC_UPDATELOCK) | ((updateLock ? 1L : 0L) << 62); } public static int getReadonlyCount(final long value) { return (int) (value & MASK_OREC_READONLY_COUNT); } public static long setReadonlyCount(final long value, final int readonlyCount) { return (value & ~MASK_OREC_READONLY_COUNT) | readonlyCount; } public static long setSurplus(final long value, final long surplus) { return (value & ~MASK_OREC_SURPLUS) | (surplus << 10); } public static long getSurplus(final long value) { return (value & MASK_OREC_SURPLUS) >> 10; } private static String toOrecString(final long value) { return format( "Orec(hasExclusiveLock=%s, hasWriteLock=%s, readLocks=%s, surplus=%s, isReadBiased=%s, readonlyCount=%s)", hasExclusiveLock(value), hasWriteLock(value), getReadLockCount(value), getSurplus(value), isReadBiased(value), getReadonlyCount(value)); } } BaseGammaTxnRef.java000066400000000000000000001657361174000617100406540ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.blocking.RetryLatch; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.api.functions.*; import org.multiverse.stms.gamma.GammaObjectPool; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmUtils; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import static java.lang.Math.max; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; import static org.multiverse.stms.gamma.GammaStmUtils.asGammaTxn; import static org.multiverse.stms.gamma.GammaStmUtils.getRequiredThreadLocalGammaTxn; import static org.multiverse.stms.gamma.ThreadLocalGammaObjectPool.getThreadLocalGammaObjectPool; import static org.multiverse.utils.Bugshaker.shakeBugs; @SuppressWarnings({"OverlyComplexClass", "OverlyCoupledClass"}) public abstract class BaseGammaTxnRef extends AbstractGammaObject { public final int type; @SuppressWarnings({"VolatileLongOrDoubleField"}) public volatile long long_value; public volatile Object ref_value; protected BaseGammaTxnRef(GammaStm stm, int type) { super(stm); this.type = type; } @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) public final boolean flattenCommute(final GammaTxn tx, final Tranlocal tranlocal, final int lockMode) { assert tranlocal.mode == TRANLOCAL_COMMUTING; final GammaTxnConfig config = tx.config; tx.initLocalConflictCounter(); if (!load(tx, tranlocal, lockMode, config.spinCount, tx.richmansMansConflictScan)) { return false; } tranlocal.setDirty(!config.dirtyCheck); tranlocal.mode = TRANLOCAL_WRITE; if (!tx.isReadConsistent(tranlocal)) { return false; } boolean abort = true; try { CallableNode node = tranlocal.headCallable; while (node != null) { evaluate(tranlocal, tx, node.function); CallableNode newNext = node.next; tx.pool.putCallableNode(node); node = newNext; } tranlocal.headCallable = null; abort = false; } finally { if (abort) { tx.abort(); } } return true; } private void evaluate(final Tranlocal tranlocal, GammaTxn tx, final Function function) { tx.evaluatingCommute = true; try { switch (type) { case TYPE_REF: tranlocal.ref_value = function.call(tranlocal.ref_value); break; case TYPE_INT: IntFunction intFunction = (IntFunction) function; tranlocal.long_value = intFunction.call((int) tranlocal.long_value); break; case TYPE_LONG: LongFunction longFunction = (LongFunction) function; tranlocal.long_value = longFunction.call(tranlocal.long_value); break; case TYPE_DOUBLE: DoubleFunction doubleFunction = (DoubleFunction) function; double doubleResult = doubleFunction.call(GammaStmUtils.longAsDouble(tranlocal.long_value)); tranlocal.long_value = GammaStmUtils.doubleAsLong(doubleResult); break; case TYPE_BOOLEAN: BooleanFunction booleanFunction = (BooleanFunction) function; boolean booleanResult = booleanFunction.call(GammaStmUtils.longAsBoolean(tranlocal.long_value)); tranlocal.long_value = GammaStmUtils.booleanAsLong(booleanResult); break; default: throw new IllegalStateException(); } } finally { tx.evaluatingCommute = false; } } public final Listeners commit(final Tranlocal tranlocal, final GammaObjectPool pool) { if (!tranlocal.isDirty) { releaseAfterReading(tranlocal, pool); return null; } if (type == TYPE_REF) { ref_value = tranlocal.ref_value; //we need to set them to null to prevent memory leaks. tranlocal.ref_value = null; tranlocal.ref_oldValue = null; } else { long_value = tranlocal.long_value; } version = tranlocal.version + 1; Listeners listenerAfterWrite = listeners; if (listenerAfterWrite != null) { listenerAfterWrite = ___removeListenersAfterWrite(); } releaseAfterUpdate(tranlocal, pool); return listenerAfterWrite; } public final Listeners leanCommit(final Tranlocal tranlocal) { assert type == TYPE_REF; if (tranlocal.mode == TRANLOCAL_READ) { tranlocal.ref_value = null; tranlocal.owner = null; return null; } ref_value = tranlocal.ref_value; version = tranlocal.version + 1; Listeners listenerAfterWrite = listeners; if (listenerAfterWrite != null) { listenerAfterWrite = ___removeListenersAfterWrite(); } departAfterUpdateAndUnlock(); tranlocal.ref_value = null; tranlocal.lockMode = LOCKMODE_NONE; tranlocal.owner = null; tranlocal.hasDepartObligation = false; return listenerAfterWrite; } @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) public final boolean prepare(final GammaTxn tx, final Tranlocal tranlocal) { final int mode = tranlocal.getMode(); if (mode == TRANLOCAL_CONSTRUCTING) { return true; } if (mode == TRANLOCAL_READ) { if (!tranlocal.writeSkewCheck) { return true; } return tryLockAndCheckConflict(tx, tranlocal, tx.config.spinCount, LOCKMODE_READ); } if (mode == TRANLOCAL_COMMUTING) { if (!flattenCommute(tx, tranlocal, LOCKMODE_EXCLUSIVE)) { return false; } } if (!tranlocal.isDirty) { final boolean isDirty = type == TYPE_REF ? tranlocal.ref_value != tranlocal.ref_oldValue : tranlocal.long_value != tranlocal.long_oldValue; if (!isDirty) { if (!tranlocal.writeSkewCheck) { return true; } return tryLockAndCheckConflict(tx, tranlocal, tx.config.spinCount, LOCKMODE_READ); } tranlocal.isDirty = true; } return tryLockAndCheckConflict(tx, tranlocal, tx.config.spinCount, LOCKMODE_EXCLUSIVE); } public final void releaseAfterFailure(final Tranlocal tranlocal, final GammaObjectPool pool) { if (type == TYPE_REF) { tranlocal.ref_value = null; tranlocal.ref_oldValue = null; } if (tranlocal.headCallable != null) { CallableNode node = tranlocal.headCallable; do { CallableNode next = node.next; pool.putCallableNode(node); node = next; } while (node != null); tranlocal.headCallable = null; } if (tranlocal.hasDepartObligation()) { if (tranlocal.isConstructing()) { tranlocal.setLockMode(LOCKMODE_NONE); } else if (tranlocal.getLockMode() != LOCKMODE_NONE) { departAfterFailureAndUnlock(); tranlocal.setLockMode(LOCKMODE_NONE); } else { departAfterFailure(); } tranlocal.setDepartObligation(false); } else if (tranlocal.getLockMode() != LOCKMODE_NONE) { unlockByUnregistered(); tranlocal.setLockMode(LOCKMODE_NONE); } tranlocal.owner = null; } public final void releaseAfterUpdate(final Tranlocal tranlocal, final GammaObjectPool pool) { if (type == TYPE_REF) { tranlocal.ref_value = null; tranlocal.ref_oldValue = null; } departAfterUpdateAndUnlock(); tranlocal.lockMode = LOCKMODE_NONE; tranlocal.owner = null; tranlocal.hasDepartObligation = false; } public final void releaseAfterReading(final Tranlocal tranlocal, final GammaObjectPool pool) { if (type == TYPE_REF) { tranlocal.ref_value = null; tranlocal.ref_oldValue = null; } if (tranlocal.hasDepartObligation()) { if (tranlocal.getLockMode() != LOCKMODE_NONE) { departAfterReadingAndUnlock(); tranlocal.setLockMode(LOCKMODE_NONE); } else { departAfterReading(); } tranlocal.setDepartObligation(false); } else if (tranlocal.getLockMode() != LOCKMODE_NONE) { unlockByUnregistered(); tranlocal.setLockMode(LOCKMODE_NONE); } tranlocal.owner = null; } public final boolean load( final GammaTxn tx, final Tranlocal tranlocal, final int lockMode, int spinCount, final boolean arriveNeeded) { if (lockMode != LOCKMODE_NONE) { final int result = arriveAndLock(spinCount, lockMode); if (result == FAILURE) { return false; } tranlocal.owner = this; tranlocal.version = version; if (type == TYPE_REF) { final Object value = ref_value; tranlocal.ref_value = value; tranlocal.ref_oldValue = value; } else { final long value = long_value; tranlocal.long_value = value; tranlocal.long_oldValue = value; } tranlocal.lockMode = lockMode; tranlocal.hasDepartObligation = (result & MASK_UNREGISTERED) == 0; tx.commitConflict = (result & MASK_CONFLICT) != 0; return true; } while (true) { long readLong = 0; Object readRef = null; long readVersion; if (type == TYPE_REF) { do { readVersion = version; readRef = ref_value; if (SHAKE_BUGS) shakeBugs(); } while (readVersion != version); } else { do { readVersion = version; readLong = long_value; if (SHAKE_BUGS) shakeBugs(); } while (readVersion != version); } if (SHAKE_BUGS) shakeBugs(); int arriveStatus; if (arriveNeeded) { arriveStatus = arrive(spinCount); } else if (waitForExclusiveLockToBecomeFree(spinCount)) { arriveStatus = MASK_SUCCESS + MASK_UNREGISTERED; } else { arriveStatus = FAILURE; } if (arriveStatus == FAILURE) { return false; } if (SHAKE_BUGS) shakeBugs(); if (version == readVersion) { tranlocal.owner = this; tranlocal.version = readVersion; tranlocal.lockMode = LOCKMODE_NONE; tranlocal.hasDepartObligation = (arriveStatus & MASK_UNREGISTERED) == 0; if (type == TYPE_REF) { tranlocal.ref_value = readRef; tranlocal.ref_oldValue = readRef; } else { tranlocal.long_value = readLong; tranlocal.long_oldValue = readLong; } return true; } //we are not lucky, the value has changed. But before retrying, we need to depart if the arrive was normal if ((arriveStatus & MASK_UNREGISTERED) == 0) { departAfterFailure(); } } } public final Tranlocal openForConstruction(GammaTxn tx) { if (tx == null) { throw new NullPointerException(); } final int type = tx.transactionType; if (type == TRANSACTIONTYPE_FAT_MONO) { return openForConstruction((FatMonoGammaTxn) tx); } else if (type == TRANSACTIONTYPE_FAT_FIXED_LENGTH) { return openForConstruction((FatFixedLengthGammaTxn) tx); } else if (type == TRANSACTIONTYPE_FAT_VARIABLE_LENGTH) { return openForConstruction((FatVariableLengthGammaTxn) tx); } else { throw tx.abortOpenForConstructionRequired(this); } } private void initTranlocalForConstruction(final Tranlocal tranlocal) { tranlocal.isDirty = true; tranlocal.mode = TRANLOCAL_CONSTRUCTING; tranlocal.setLockMode(LOCKMODE_EXCLUSIVE); tranlocal.setDepartObligation(true); if (type == TYPE_REF) { tranlocal.ref_value = null; tranlocal.ref_oldValue = null; } else { tranlocal.long_value = 0; tranlocal.long_oldValue = 0; } } public final Tranlocal openForConstruction(FatMonoGammaTxn tx) { if (tx.status != TX_ACTIVE) { throw tx.abortOpenForConstructionOnBadStatus(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortOpenForConstructionOnBadStm(this); } if (config.readonly) { throw tx.abortOpenForConstructionOnReadonly(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForConstructionWhileEvaluatingCommute(this); } final Tranlocal tranlocal = tx.tranlocal; //noinspection ObjectEquality if (tranlocal.owner == this) { if (!tranlocal.isConstructing()) { throw tx.abortOpenForConstructionOnBadReference(this); } return tranlocal; } if (tranlocal.owner != null) { throw tx.abortOnTransactionTooSmall(2); } tx.hasWrites = true; tranlocal.owner = this; initTranlocalForConstruction(tranlocal); return tranlocal; } public final Tranlocal openForConstruction(FatVariableLengthGammaTxn tx) { if (tx.status != TX_ACTIVE) { throw tx.abortOpenForConstructionOnBadStatus(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortOpenForConstructionOnBadStm(this); } if (config.readonly) { throw tx.abortOpenForConstructionOnReadonly(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForConstructionWhileEvaluatingCommute(this); } final int identityHash = identityHashCode(); final int indexOf = tx.indexOf(this, identityHash); if (indexOf > -1) { final Tranlocal tranlocal = tx.array[indexOf]; if (!tranlocal.isConstructing()) { throw tx.abortOpenForConstructionOnBadReference(this); } return tranlocal; } final Tranlocal tranlocal = tx.pool.take(this); tranlocal.owner = this; initTranlocalForConstruction(tranlocal); tx.hasWrites = true; tx.attach(tranlocal, identityHash); tx.size++; return tranlocal; } public final Tranlocal openForConstruction(FatFixedLengthGammaTxn tx) { if (tx.status != TX_ACTIVE) { throw tx.abortOpenForConstructionOnBadStatus(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortOpenForConstructionOnBadStm(this); } if (config.readonly) { throw tx.abortOpenForConstructionOnReadonly(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForConstructionWhileEvaluatingCommute(this); } Tranlocal found = null; Tranlocal newNode = null; Tranlocal node = tx.head; while (true) { if (node == null) { break; } else if (node.owner == this) { found = node; break; } else if (node.owner == null) { newNode = node; break; } else { node = node.next; } } if (found != null) { if (!found.isConstructing()) { throw tx.abortOpenForConstructionOnBadReference(this); } tx.shiftInFront(found); return found; } if (newNode == null) { throw tx.abortOnTransactionTooSmall(config.maxFixedLengthTransactionSize + 1); } newNode.owner = this; initTranlocalForConstruction(newNode); tx.size++; tx.shiftInFront(newNode); tx.hasWrites = true; return newNode; } // ============================================================================================ // =============================== open for read ============================================== // ============================================================================================ public final Tranlocal openForRead(final GammaTxn tx, final int lockMode) { if (tx == null) { throw new NullPointerException(); } final int type = tx.transactionType; if (type == TRANSACTIONTYPE_LEAN_MONO) { return openForRead((LeanMonoGammaTxn) tx, lockMode); } else if (type == TRANSACTIONTYPE_LEAN_FIXED_LENGTH) { return openForRead((LeanFixedLengthGammaTxn) tx, lockMode); } else if (type == TRANSACTIONTYPE_FAT_MONO) { return openForRead((FatMonoGammaTxn) tx, lockMode); } else if (type == TRANSACTIONTYPE_FAT_FIXED_LENGTH) { return openForRead((FatFixedLengthGammaTxn) tx, lockMode); } else { return openForRead((FatVariableLengthGammaTxn) tx, lockMode); } } public final Tranlocal openForRead(final LeanMonoGammaTxn tx, int lockMode) { if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } if (lockMode != LOCKMODE_NONE) { throw tx.abortOpenForReadOrWriteOnExplicitLockingDetected(this); } final Tranlocal tranlocal = tx.tranlocal; //noinspection ObjectEquality if (tranlocal.owner == this) { return tranlocal; } if (tranlocal.owner != null) { throw tx.abortOnTransactionTooSmall(2); } final GammaTxnConfig config = tx.config; if (config.stm != stm) { throw tx.abortOpenForReadOnBadStm(this); } if (type != TYPE_REF) { throw tx.abortOpenForReadOnNonRefTypeDetected(this); } tranlocal.mode = TRANLOCAL_READ; tranlocal.owner = this; for (; ;) { //do the read of the version and ref. It needs to be repeated to make sure that the version we read, belongs to the //value. Object readRef; long readVersion; do { readVersion = version; readRef = ref_value; if (SHAKE_BUGS) shakeBugs(); } while (readVersion != version); //wait for the exclusive lock to come available. int spinCount = 64; for (; ;) { if (SHAKE_BUGS) shakeBugs(); if (!hasExclusiveLock()) { break; } spinCount--; if (spinCount < 0) { throw tx.abortOnReadWriteConflict(this); } } if (SHAKE_BUGS) shakeBugs(); //check if the version is still the same, if it is not, we have read illegal memory, //In that case we are going to try again. if (readVersion == version) { //at this point we are sure that the read was unlocked. tranlocal.version = readVersion; tranlocal.ref_value = readRef; break; } } return tranlocal; } public final Tranlocal openForRead(final LeanFixedLengthGammaTxn tx, int lockMode) { if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } if (lockMode != LOCKMODE_NONE) { throw tx.abortOpenForReadOrWriteOnExplicitLockingDetected(this); } if (tx.head.owner == this) { return tx.head; } //look inside the transaction if it already is opened for read or otherwise look for an empty spot to //place the read. Tranlocal found = null; Tranlocal newNode = null; Tranlocal node = tx.head; while (true) { if (node == null) { break; } else if (node.owner == this) { found = node; break; } else if (node.owner == null) { newNode = node; break; } else { node = node.next; } } //we have found it. if (found != null) { tx.shiftInFront(found); return found; } //we have not found it, but there also is no spot available. if (newNode == null) { throw tx.abortOnTransactionTooSmall(tx.config.maxFixedLengthTransactionSize + 1); } final GammaTxnConfig config = tx.config; if (config.stm != stm) { throw tx.abortOpenForReadOnBadStm(this); } if (type != TYPE_REF) { throw tx.abortOpenForReadOnNonRefTypeDetected(this); } int size = tx.size; if (size > config.maximumPoorMansConflictScanLength) { throw tx.abortOnRichmanConflictScanDetected(); } //load it newNode.mode = TRANLOCAL_READ; newNode.isDirty = false; newNode.owner = this; while (true) { //JMM: nothing can jump behind the following statement long readVersion; Object readRef; do { readVersion = version; readRef = ref_value; if (SHAKE_BUGS) shakeBugs(); } while (readVersion != version); //wait for the exclusive lock to come available. int spinCount = 64; for (; ;) { if (SHAKE_BUGS) shakeBugs(); if (!hasExclusiveLock()) { break; } spinCount--; if (spinCount < 0) { throw tx.abortOnReadWriteConflict(this); } } if (SHAKE_BUGS) shakeBugs(); //check if the version and value we read are still the same, if they are not, we have read illegal memory, //so we are going to try again. if (readVersion == version && readRef == ref_value) { //at this point we are sure that the read was unlocked. newNode.version = readVersion; newNode.ref_value = readRef; break; } } tx.size = size + 1; //lets put it in the front it isn't the first one that is opened. if (tx.size > 1) { tx.shiftInFront(newNode); } //check if the transaction still is read consistent. if (tx.hasReads) { node = tx.head; do { final BaseGammaTxnRef owner = node.owner; //if we are at the end, we are done. if (owner == null) { break; } if (SHAKE_BUGS) shakeBugs(); if (node != newNode && (owner.hasExclusiveLock() || owner.version != node.version)) { throw tx.abortOnReadWriteConflict(this); } node = node.next; } while (node != null); } else { tx.hasReads = true; } //we are done, the load was correct and the transaction still is read consistent. return newNode; } private static void initTranlocalForRead(final GammaTxnConfig config, final Tranlocal tranlocal) { tranlocal.isDirty = false; tranlocal.mode = TRANLOCAL_READ; tranlocal.writeSkewCheck = config.isolationLevel == IsolationLevel.Serializable; tranlocal.version = -1; } public final Tranlocal openForRead(final FatMonoGammaTxn tx, int lockMode) { if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortOpenForReadOnBadStm(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForReadWhileEvaluatingCommute(this); } lockMode = config.readLockModeAsInt <= lockMode ? lockMode : config.readLockModeAsInt; final Tranlocal tranlocal = tx.tranlocal; //noinspection ObjectEquality if (tranlocal.owner == this) { //we have found the tranlocal we are looking for. int mode = tranlocal.mode; if (mode == TRANLOCAL_CONSTRUCTING) { return tranlocal; } if (mode == TRANLOCAL_COMMUTING) { if (!flattenCommute(tx, tranlocal, lockMode)) { throw tx.abortOnReadWriteConflict(this); } return tranlocal; } if (lockMode > tranlocal.getLockMode()) { if (!tryLockAndCheckConflict(tx, tranlocal, config.spinCount, lockMode)) { throw tx.abortOnReadWriteConflict(this); } } return tranlocal; } if (tranlocal.owner != null) { throw tx.abortOnTransactionTooSmall(2); } initTranlocalForRead(config, tranlocal); if (!load(tx, tranlocal, lockMode, config.spinCount, tx.richmansMansConflictScan)) { throw tx.abortOnReadWriteConflict(this); } return tranlocal; } public final Tranlocal openForRead(final FatFixedLengthGammaTxn tx, int desiredLockMode) { if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortOpenForReadOnBadStm(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForReadWhileEvaluatingCommute(this); } Tranlocal found = null; Tranlocal newNode = null; Tranlocal node = tx.head; while (true) { if (node == null) { break; } else if (node.owner == this) { found = node; break; } else if (node.owner == null) { newNode = node; break; } else { node = node.next; } } desiredLockMode = config.readLockModeAsInt <= desiredLockMode ? desiredLockMode : config.readLockModeAsInt; if (found != null) { final int mode = found.mode; if (mode == TRANLOCAL_CONSTRUCTING) { return found; } if (mode == TRANLOCAL_COMMUTING) { if (!flattenCommute(tx, found, desiredLockMode)) { throw tx.abortOnReadWriteConflict(this); } return found; } if (desiredLockMode > found.getLockMode()) { if (!tryLockAndCheckConflict(tx, found, config.spinCount, desiredLockMode)) { throw tx.abortOnReadWriteConflict(this); } } tx.shiftInFront(found); return found; } if (newNode == null) { throw tx.abortOnTransactionTooSmall(config.maxFixedLengthTransactionSize + 1); } tx.size++; initTranlocalForRead(config, newNode); final boolean hasReadsBeforeLoading = tx.hasReads; if (!hasReadsBeforeLoading) { tx.localConflictCount = config.globalConflictCounter.count(); tx.hasReads = true; } if (!load(tx, newNode, desiredLockMode, config.spinCount, tx.richmansMansConflictScan)) { throw tx.abortOnReadWriteConflict(this); } //if (hasReadsBeforeLoading && !tx.isReadConsistent(newNode)) { if (!tx.isReadConsistent(newNode)) { throw tx.abortOnReadWriteConflict(this); } tx.shiftInFront(newNode); return newNode; } public final Tranlocal openForRead(final FatVariableLengthGammaTxn tx, int desiredLockMode) { if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortOpenForReadOnBadStm(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForReadWhileEvaluatingCommute(this); } desiredLockMode = config.readLockModeAsInt <= desiredLockMode ? desiredLockMode : config.readLockModeAsInt; final int identityHash = identityHashCode(); final int indexOf = tx.indexOf(this, identityHash); if (indexOf > -1) { final Tranlocal tranlocal = tx.array[indexOf]; final int mode = tranlocal.mode; if (mode == TRANLOCAL_CONSTRUCTING) { return tranlocal; } if (mode == TRANLOCAL_COMMUTING) { if (!flattenCommute(tx, tranlocal, desiredLockMode)) { throw tx.abortOnReadWriteConflict(this); } return tranlocal; } if (desiredLockMode > tranlocal.getLockMode()) { if (!tryLockAndCheckConflict(tx, tranlocal, config.spinCount, desiredLockMode)) { throw tx.abortOnReadWriteConflict(this); } } return tranlocal; } final Tranlocal tranlocal = tx.pool.take(this); initTranlocalForRead(config, tranlocal); tx.attach(tranlocal, identityHash); tx.size++; final boolean hasReadsBeforeLoading = tx.hasReads; if (!hasReadsBeforeLoading) { tx.hasReads = true; tx.localConflictCount = config.globalConflictCounter.count(); } if (!load(tx, tranlocal, desiredLockMode, config.spinCount, tx.richmansMansConflictScan)) { throw tx.abortOnReadWriteConflict(this); } //if (hasReadsBeforeLoading && !tx.isReadConsistent(tranlocal)) { if (!tx.isReadConsistent(tranlocal)) { throw tx.abortOnReadWriteConflict(this); } return tranlocal; } // ============================================================================================ // =============================== open for write ============================================= // ============================================================================================ public final Tranlocal openForWrite(final GammaTxn tx, final int lockMode) { if (tx == null) { throw new NullPointerException(); } final int type = tx.transactionType; if (type == TRANSACTIONTYPE_LEAN_MONO) { return openForWrite((LeanMonoGammaTxn) tx, lockMode); } else if (type == TRANSACTIONTYPE_LEAN_FIXED_LENGTH) { return openForWrite((LeanFixedLengthGammaTxn) tx, lockMode); } else if (type == TRANSACTIONTYPE_FAT_MONO) { return openForWrite((FatMonoGammaTxn) tx, lockMode); } else if (type == TRANSACTIONTYPE_FAT_FIXED_LENGTH) { return openForWrite((FatFixedLengthGammaTxn) tx, lockMode); } else { return openForWrite((FatVariableLengthGammaTxn) tx, lockMode); } } public final Tranlocal openForWrite(final LeanMonoGammaTxn tx, int lockMode) { final Tranlocal tranlocal = openForRead(tx, lockMode); if (!tx.hasWrites) { tx.hasWrites = true; } if (tranlocal.mode == TRANLOCAL_READ) { tranlocal.mode = TRANLOCAL_WRITE; } return tranlocal; } public final Tranlocal openForWrite(final LeanFixedLengthGammaTxn tx, int lockMode) { final Tranlocal tranlocal = openForRead(tx, lockMode); if (!tx.hasWrites) { tx.hasWrites = true; } if (tranlocal.mode == TRANLOCAL_READ) { tranlocal.mode = TRANLOCAL_WRITE; } return tranlocal; } public final Tranlocal openForWrite(final FatMonoGammaTxn tx, final int desiredLockMode) { GammaTxnConfig config = tx.config; Tranlocal tranlocal = openForRead(tx, max(desiredLockMode, config.writeLockModeAsInt)); if (config.readonly) { throw tx.abortOpenForWriteOnReadonly(this); } if (!tx.hasWrites) { tx.hasWrites = true; } if (tranlocal.mode == TRANLOCAL_READ) { tranlocal.mode = TRANLOCAL_WRITE; tranlocal.writeSkewCheck = config.isolationLevel == IsolationLevel.Serializable; tranlocal.setDirty(!config.dirtyCheck); } return tranlocal; } public final Tranlocal openForWrite(final FatFixedLengthGammaTxn tx, final int lockMode) { GammaTxnConfig config = tx.config; Tranlocal tranlocal = openForRead(tx, max(lockMode, config.writeLockModeAsInt)); if (config.readonly) { throw tx.abortOpenForWriteOnReadonly(this); } if (!tx.hasWrites) { tx.hasWrites = true; } if (tranlocal.mode == TRANLOCAL_READ) { tranlocal.mode = TRANLOCAL_WRITE; tranlocal.writeSkewCheck = config.isolationLevel == IsolationLevel.Serializable; tranlocal.setDirty(!config.dirtyCheck); } return tranlocal; } public final Tranlocal openForWrite(final FatVariableLengthGammaTxn tx, final int lockMode) { GammaTxnConfig config = tx.config; Tranlocal tranlocal = openForRead(tx, max(lockMode, config.writeLockModeAsInt)); if (config.readonly) { throw tx.abortOpenForWriteOnReadonly(this); } if (!tx.hasWrites) { tx.hasWrites = true; } if (tranlocal.mode == TRANLOCAL_READ) { tranlocal.mode = TRANLOCAL_WRITE; tranlocal.writeSkewCheck = config.isolationLevel == IsolationLevel.Serializable; tranlocal.setDirty(!config.dirtyCheck); } return tranlocal; } // ============================================================================================ // ================================= open for commute ========================================= // ============================================================================================ public final void openForCommute(final GammaTxn tx, final Function function) { if (tx == null) { throw new NullPointerException("txn can't be null"); } final int type = tx.transactionType; if (type == TRANSACTIONTYPE_FAT_MONO) { openForCommute((FatMonoGammaTxn) tx, function); } else if (type == TRANSACTIONTYPE_FAT_FIXED_LENGTH) { openForCommute((FatFixedLengthGammaTxn) tx, function); } else if (type == TRANSACTIONTYPE_FAT_VARIABLE_LENGTH) { openForCommute((FatVariableLengthGammaTxn) tx, function); } else { throw tx.abortCommuteOnCommuteDetected(this); } } private void initTranlocalForCommute(final GammaTxnConfig config, final Tranlocal tranlocal) { tranlocal.owner = this; tranlocal.mode = TRANLOCAL_COMMUTING; tranlocal.isDirty = !config.dirtyCheck; tranlocal.writeSkewCheck = false; } public final void openForCommute(final FatMonoGammaTxn tx, final Function function) { if (tx == null) { throw new NullPointerException(); } if (tx.status != TX_ACTIVE) { throw tx.abortCommuteOnBadStatus(this, function); } if (function == null) { throw tx.abortCommuteOnNullFunction(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForCommuteWhileEvaluatingCommute(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortCommuteOnBadStm(this); } if (config.isReadonly()) { throw tx.abortCommuteOnReadonly(this); } if (config.writeLockModeAsInt > LOCKMODE_NONE) { } final Tranlocal tranlocal = tx.tranlocal; //noinspection ObjectEquality if (tranlocal.owner == this) { if (tranlocal.isCommuting()) { tranlocal.addCommutingFunction(tx.pool, function); return; } if (tranlocal.isRead()) { tranlocal.mode = TRANLOCAL_WRITE; tx.hasWrites = true; } boolean abort = true; try { evaluate(tranlocal, tx, function); abort = false; } finally { if (abort) { tx.abort(); } } return; } if (tranlocal.owner != null) { throw tx.abortOnTransactionTooSmall(2); } tx.hasWrites = true; initTranlocalForCommute(config, tranlocal); tranlocal.addCommutingFunction(tx.pool, function); int writeLockMode = config.writeLockModeAsInt; if (writeLockMode > LOCKMODE_NONE) { flattenCommute(tx, tranlocal, writeLockMode); } } public final void openForCommute(final FatFixedLengthGammaTxn tx, final Function function) { if (tx == null) { throw new NullPointerException(); } if (tx.status != TX_ACTIVE) { throw tx.abortCommuteOnBadStatus(this, function); } if (function == null) { throw tx.abortCommuteOnNullFunction(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForCommuteWhileEvaluatingCommute(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortCommuteOnBadStm(this); } if (config.isReadonly()) { throw tx.abortCommuteOnReadonly(this); } Tranlocal found = null; Tranlocal newNode = null; Tranlocal node = tx.head; if (config.writeLockModeAsInt > LOCKMODE_NONE) { found = openForWrite(tx, config.writeLockModeAsInt); } else { while (true) { if (node == null) { break; } else //noinspection ObjectEquality if (node.owner == this) { found = node; break; } else if (node.owner == null) { newNode = node; break; } else { node = node.next; } } } if (found != null) { if (found.isCommuting()) { found.addCommutingFunction(tx.pool, function); return; } if (found.isRead()) { found.mode = TRANLOCAL_WRITE; tx.hasWrites = true; } boolean abort = true; try { evaluate(found, tx, function); abort = false; } finally { if (abort) { tx.abort(); } } return; } if (newNode == null) { throw tx.abortOnTransactionTooSmall(config.maxFixedLengthTransactionSize + 1); } tx.size++; tx.shiftInFront(newNode); tx.hasWrites = true; initTranlocalForCommute(config, newNode); newNode.addCommutingFunction(tx.pool, function); int writeLockMode = config.writeLockModeAsInt; if (writeLockMode > LOCKMODE_NONE) { flattenCommute(tx, newNode, writeLockMode); } } public final void openForCommute(final FatVariableLengthGammaTxn tx, final Function function) { if (tx == null) { throw new NullPointerException(); } if (tx.status != TX_ACTIVE) { throw tx.abortCommuteOnBadStatus(this, function); } if (function == null) { throw tx.abortCommuteOnNullFunction(this); } if (tx.evaluatingCommute) { throw tx.abortOnOpenForCommuteWhileEvaluatingCommute(this); } final GammaTxnConfig config = tx.config; //noinspection ObjectEquality if (config.stm != stm) { throw tx.abortCommuteOnBadStm(this); } if (config.isReadonly()) { throw tx.abortCommuteOnReadonly(this); } final int identityHash = identityHashCode(); final int indexOf = tx.indexOf(this, identityHash); if (indexOf > -1) { final Tranlocal tranlocal = tx.array[indexOf]; if (tranlocal.isCommuting()) { tranlocal.addCommutingFunction(tx.pool, function); return; } if (tranlocal.isRead()) { tranlocal.mode = TRANLOCAL_WRITE; tx.hasWrites = true; } boolean abort = true; try { evaluate(tranlocal, tx, function); abort = false; } finally { if (abort) { tx.abort(); } } return; } final Tranlocal tranlocal = tx.pool.take(this); initTranlocalForCommute(config, tranlocal); tx.hasWrites = true; tx.attach(tranlocal, identityHash); tx.size++; tranlocal.addCommutingFunction(tx.pool, function); int writeLockMode = config.writeLockModeAsInt; if (writeLockMode > LOCKMODE_NONE) { flattenCommute(tx, tranlocal, writeLockMode); } } public final void ensure() { ensure(getRequiredThreadLocalGammaTxn()); } public final void ensure(final Txn self) { ensure(asGammaTxn(self)); } public final void ensure(final GammaTxn tx) { if (tx == null) { throw new NullPointerException(); } if (tx.status != TX_ACTIVE) { throw tx.abortEnsureOnBadStatus(this); } if (tx.isLean()) { throw tx.abortEnsureOnEnsureDetected(this); } if (tx.config.readonly) { return; } final Tranlocal tranlocal = openForRead(tx, LOCKMODE_NONE); tranlocal.writeSkewCheck = true; } protected final long getLong(final GammaTxn tx, final LockMode lockMode) { assert type != TYPE_REF; if (tx == null) { throw new NullPointerException(); } if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } if (lockMode == null) { throw tx.abortOpenForReadOnNullLockMode(this); } return openForRead(tx, lockMode.asInt()).long_value; } protected final Object getObject(final GammaTxn tx, final LockMode lockMode) { assert type == TYPE_REF; if (tx == null) { throw new NullPointerException(); } if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } if (lockMode == null) { throw tx.abortOpenForReadOnNullLockMode(this); } return openForRead(tx, lockMode.asInt()).ref_value; } protected final long setLong(final GammaTxn tx, final LockMode lockMode, final long newValue, final boolean returnOld) { assert type != TYPE_REF; if (tx == null) { throw new NullPointerException(); } if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } if (lockMode == null) { throw tx.abortOpenForReadOnNullLockMode(this); } final Tranlocal tranlocal = openForWrite(tx, lockMode.asInt()); final long oldValue = tranlocal.long_value; tranlocal.long_value = newValue; return returnOld ? oldValue : newValue; } protected final Object setObject(final GammaTxn tx, final LockMode lockMode, final Object newValue, final boolean returnOld) { assert type == TYPE_REF; if (tx == null) { throw new NullPointerException(); } if (tx.status != TX_ACTIVE) { throw tx.abortOpenForReadOnBadStatus(this); } if (lockMode == null) { throw tx.abortOpenForReadOnNullLockMode(this); } final Tranlocal tranlocal = openForWrite(tx, lockMode.asInt()); final Object oldValue = tranlocal.ref_value; tranlocal.ref_value = newValue; return returnOld ? oldValue : newValue; } public final long atomicGetLong() { assert type != TYPE_REF; int attempt = 1; do { if (!hasExclusiveLock()) { long read = long_value; if (!hasExclusiveLock()) { return read; } } stm.defaultBackoffPolicy.delayUninterruptible(attempt); attempt++; } while (attempt <= stm.spinCount); throw new LockedException(); } public final Object atomicObjectGet() { assert type == TYPE_REF; int attempt = 1; do { if (!hasExclusiveLock()) { Object read = ref_value; if (!hasExclusiveLock()) { return read; } } stm.defaultBackoffPolicy.delayUninterruptible(attempt); attempt++; } while (attempt <= stm.spinCount); throw new LockedException(); } public final long atomicSetLong(final long newValue, boolean returnOld) { assert type != TYPE_REF; final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final long oldValue = long_value; if (oldValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return newValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } long_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { final GammaObjectPool pool = getThreadLocalGammaObjectPool(); listeners.openAll(pool); } return returnOld ? oldValue : newValue; } public final Object atomicSetObject(final Object newValue, boolean returnOld) { assert type == TYPE_REF; final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final Object oldValue = ref_value; if (oldValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return newValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } ref_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { final GammaObjectPool pool = getThreadLocalGammaObjectPool(); listeners.openAll(pool); } return returnOld ? oldValue : newValue; } public final boolean atomicCompareAndSetLong(final long expectedValue, final long newValue) { final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final long currentValue = long_value; if (currentValue != expectedValue) { departAfterFailureAndUnlock(); return false; } if (expectedValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return true; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } long_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return true; } @Override public final void acquire(final LockMode desiredLockMode) { final GammaTxn tx = (GammaTxn) getThreadLocalTxn(); if (tx == null) { throw new TxnMandatoryException(); } acquire(tx, desiredLockMode); } @Override public final void acquire(final Txn tx, final LockMode desiredLockMode) { acquire((GammaTxn) tx, desiredLockMode); } public final void acquire(final GammaTxn tx, final LockMode lockMode) { if (tx == null) { throw new NullPointerException(); } if (lockMode == null) { throw tx.abortAcquireOnNullLockMode(this); } openForRead(tx, lockMode.asInt()); } /** * Tries to acquire a lock on a previous read/written tranlocal and checks for conflict. *

* If the lockMode == LOCKMODE_NONE, this call is ignored. *

* The call to this method can safely made if the current lock level is higher the the desired LockMode. *

* If the can't be acquired, no changes are made on the tranlocal. * * @param tx * @param tranlocal the tranlocal * @param spinCount the maximum number of times to spin * @param desiredLockMode * @return true if the lock was acquired successfully and there was no conflict. */ public final boolean tryLockAndCheckConflict( final GammaTxn tx, final Tranlocal tranlocal, final int spinCount, final int desiredLockMode) { final int currentLockMode = tranlocal.getLockMode(); //if the currentLockMode mode is higher or equal than the desired lockmode, we are done. if (currentLockMode >= desiredLockMode) { return true; } //no lock currently is acquired, lets acquire it. if (currentLockMode == LOCKMODE_NONE) { final long expectedVersion = tranlocal.version; //if the version already is different, there is a conflict, we are done since since the lock doesn't need to be acquired. if (expectedVersion != version) { return false; } if (tranlocal.hasDepartObligation()) { int result = lockAfterArrive(spinCount, desiredLockMode); if (result == FAILURE) { return false; } if ((result & MASK_CONFLICT) != 0) { tx.commitConflict = true; } if (version != expectedVersion) { tranlocal.setDepartObligation(false); departAfterFailureAndUnlock(); return false; } } else { //we need to arrive as well because the the tranlocal was readbiased, and no real arrive was done. final int result = arriveAndLock(spinCount, desiredLockMode); if (result == FAILURE) { return false; } tranlocal.setLockMode(desiredLockMode); if ((result & MASK_UNREGISTERED) == 0) { tranlocal.hasDepartObligation = true; } if ((result & MASK_CONFLICT) != 0) { tx.commitConflict = true; } if (version != expectedVersion) { return false; } } tranlocal.setLockMode(desiredLockMode); return true; } //if a readlock is acquired, we need to upgrade it to a write/exclusive-lock if (currentLockMode == LOCKMODE_READ) { int result = upgradeReadLock(spinCount, desiredLockMode == LOCKMODE_EXCLUSIVE); if (result == FAILURE) { return false; } if ((result & MASK_CONFLICT) != 0) { tx.commitConflict = true; } tranlocal.setLockMode(desiredLockMode); return true; } //so we have the write lock, its needs to be upgraded to a commit lock. if (upgradeWriteLock()) { tx.commitConflict = true; } tranlocal.setLockMode(LOCKMODE_EXCLUSIVE); return true; } public final int registerChangeListener( final RetryLatch latch, final Tranlocal tranlocal, final GammaObjectPool pool, final long listenerEra) { if (tranlocal.isCommuting() || tranlocal.isConstructing()) { return REGISTRATION_NONE; } final long version = tranlocal.version; if (version != this.version) { //if it currently already contains a different version, we are done. latch.open(listenerEra); return REGISTRATION_NOT_NEEDED; } //we are going to register the listener since the current value still matches with is active. //But it could be that the registration completes after the write has happened. Listeners update = pool.takeListeners(); //update.threadName = Thread.currentThread().getName(); update.listener = latch; update.listenerEra = listenerEra; //we need to do this in a loop because other register thread could be contending for the same //listeners field. while (true) { if (version != this.version) { //if it currently already contains a different version, we are done. latch.open(listenerEra); return REGISTRATION_NOT_NEEDED; } //the listeners object is mutable, but as long as it isn't yet registered, this calling //thread has full ownership of it. final Listeners current = listeners; update.next = current; //lets try to register our listeners. final boolean registered = ___unsafe.compareAndSwapObject(this, listenersOffset, current, update); if (!registered) { //so we are contending with another register thread, so lets try it again. Since the compareAndSwap //didn't succeed, we know that the current thread still has exclusive ownership on the Listeners object //so we can try to register it again, but now with the newly found listeners continue; } //the registration was a success. We need to make sure that the ___version hasn't changed. //JMM: the volatile read of ___version can't jump in front of the unsafe.compareAndSwap. if (version == this.version) { //we are lucky, the registration was done successfully and we managed to cas the listener //before the update (since the update we are interested in, hasn't happened yet). This means that //the updating thread is now responsible for notifying the listeners. Retrieval of the most recently //published listener, always happens after the version is updated return REGISTRATION_DONE; } //the version has changed, so an interesting write has happened. No registration is needed. //JMM: the unsafe.compareAndSwap can't jump over the volatile read this.___version. //the update has taken place, we need to check if our listeners still is in place. //if it is, it should be removed and the listeners notified. If the listeners already has changed, //it is the task for the other to do the listener cleanup and notify them while (true) { update = listeners; final boolean removed = ___unsafe.compareAndSwapObject(this, listenersOffset, update, null); if (!removed) { continue; } if (update != null) { //we have complete ownership of the listeners that are removed, so lets open them. update.openAll(pool); } return REGISTRATION_NOT_NEEDED; } } } @SuppressWarnings({"SimplifiableIfStatement"}) public final boolean hasReadConflict(final Tranlocal tranlocal) { if (tranlocal.lockMode != LOCKMODE_NONE) { return false; } if (hasExclusiveLock()) { return true; } return tranlocal.version != version; } protected final int arriveAndExclusiveLockOrBackoff() { final int maxRetries = stm.defaultMaxRetries; final int spinCount = stm.spinCount; for (int k = 0; k <= maxRetries; k++) { final int arriveStatus = arriveAndExclusiveLock(spinCount); if (arriveStatus != FAILURE) { return arriveStatus; } stm.defaultBackoffPolicy.delayUninterruptible(k + 1); } return FAILURE; } } CallableNode.java000066400000000000000000000007111174000617100401720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.functions.Function; public final class CallableNode { public CallableNode next; public Function function; public CallableNode() { } public CallableNode(Function function, CallableNode next) { this.next = next; this.function = function; } public void prepareForPooling() { next = null; function = null; } } GammaObject.java000066400000000000000000000005201174000617100400340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.Lock; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; public interface GammaObject extends GammaConstants { long getVersion(); GammaStm getStm(); Lock getLock(); int identityHashCode(); } GammaTxnBoolean.java000066400000000000000000000253721174000617100407130ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.BooleanFunction; import org.multiverse.api.predicates.BooleanPredicate; import org.multiverse.api.references.TxnBoolean; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.stms.gamma.GammaStmUtils.*; import static org.multiverse.stms.gamma.ThreadLocalGammaObjectPool.getThreadLocalGammaObjectPool; /** * A {@link org.multiverse.api.references.TxnBoolean} for the {@link GammaStm}. * * @author Peter Veentjer. */ public class GammaTxnBoolean extends BaseGammaTxnRef implements TxnBoolean { public GammaTxnBoolean(boolean value){ this((GammaStm) getGlobalStmInstance(),value); } public GammaTxnBoolean(final GammaTxn tx) { this(tx, false); } public GammaTxnBoolean(final GammaTxn tx, final boolean value) { super(tx.getConfig().stm, TYPE_BOOLEAN); arriveAndLock(1, LOCKMODE_EXCLUSIVE); Tranlocal tranlocal = openForConstruction(tx); tranlocal.long_value = booleanAsLong(value); } public GammaTxnBoolean(final GammaStm stm) { this(stm, false); } public GammaTxnBoolean(final GammaStm stm, final boolean b) { super(stm, TYPE_BOOLEAN); this.long_value = booleanAsLong(b); //noinspection PointlessArithmeticExpression this.version = VERSION_UNCOMMITTED + 1; } @Override public final boolean get() { return get(getRequiredThreadLocalGammaTxn()); } @Override public final boolean get(final Txn tx) { return get(asGammaTxn(tx)); } public final boolean get(final GammaTxn tx) { return longAsBoolean(openForRead(tx, LOCKMODE_NONE).long_value); } @Override public final boolean getAndLock(LockMode lockMode) { return getAndLock(getRequiredThreadLocalGammaTxn(), lockMode); } @Override public final boolean getAndLock(Txn tx, LockMode lockMode) { return getAndLock(asGammaTxn(tx), lockMode); } public final boolean getAndLock(GammaTxn tx, LockMode lockMode) { return longAsBoolean(getLong(asGammaTxn(tx), lockMode)); } @Override public final boolean set(final boolean value) { return set(getRequiredThreadLocalGammaTxn(), value); } @Override public final boolean set(final Txn tx, final boolean value) { return set(asGammaTxn(tx), value); } public final boolean set(final GammaTxn tx, final boolean value) { openForWrite(tx, LOCKMODE_NONE).long_value = booleanAsLong(value); return value; } @Override public final boolean setAndLock(boolean value, LockMode lockMode) { return setAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final boolean setAndLock(Txn tx, boolean value, LockMode lockMode) { return setAndLock(asGammaTxn(tx), value, lockMode); } public final boolean setAndLock(GammaTxn tx, boolean value, LockMode lockMode) { return longAsBoolean(setLong(tx, lockMode, booleanAsLong(value), false)); } @Override public final boolean getAndSet(final boolean value) { return getAndSet(getRequiredThreadLocalGammaTxn(), value); } @Override public final boolean getAndSet(final Txn tx, final boolean value) { return getAndSet(asGammaTxn(tx), value); } @Override public final boolean getAndSetAndLock(boolean value, LockMode lockMode) { return getAndSetAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final boolean getAndSetAndLock(Txn tx, boolean value, LockMode lockMode) { return getAndSetAndLock(asGammaTxn(tx), value, lockMode); } public final boolean getAndSetAndLock(GammaTxn tx, boolean value, LockMode lockMode) { return longAsBoolean(setLong(tx, lockMode, booleanAsLong(value), true)); } public final boolean getAndSet(final GammaTxn tx, final boolean value) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); boolean oldValue = longAsBoolean(tranlocal.long_value); tranlocal.long_value = booleanAsLong(value); return oldValue; } @Override public final boolean atomicGet() { return longAsBoolean(atomicGetLong()); } @Override public final boolean atomicWeakGet() { return longAsBoolean(long_value); } @Override public final boolean atomicSet(final boolean newValue) { return longAsBoolean(atomicSetLong(booleanAsLong(newValue), false)); } @Override public final boolean atomicGetAndSet(final boolean newValue) { return longAsBoolean(atomicSetLong(booleanAsLong(newValue), true)); } @Override public final void commute(final BooleanFunction function) { commute(getRequiredThreadLocalGammaTxn(), function); } @Override public final void commute(final Txn tx, final BooleanFunction function) { commute(asGammaTxn(tx), function); } public final void commute(final GammaTxn tx, final BooleanFunction function) { openForCommute(tx, function); } @Override public final boolean getAndAlter(final BooleanFunction function) { return getAndAlter(getRequiredThreadLocalGammaTxn(), function); } @Override public final boolean getAndAlter(final Txn tx, final BooleanFunction function) { return getAndAlter(asGammaTxn(tx), function); } public final boolean getAndAlter(final GammaTxn tx, final BooleanFunction function) { return alter(tx, function, true); } @Override public final boolean alterAndGet(final BooleanFunction function) { return alterAndGet(getRequiredThreadLocalGammaTxn(), function); } @Override public final boolean alterAndGet(final Txn tx, final BooleanFunction function) { return alterAndGet(asGammaTxn(tx), function); } public final boolean alterAndGet(final GammaTxn tx, final BooleanFunction function) { return alter(tx, function, false); } public final boolean alter(final GammaTxn tx, final BooleanFunction function, final boolean returnOld) { if (tx == null) { throw new NullPointerException(); } if (function == null) { tx.abort(); throw new NullPointerException("Function can't be null"); } final Tranlocal write = openForWrite(tx, LOCKMODE_NONE); boolean abort = true; try { boolean oldValue = longAsBoolean(write.long_value); write.long_value = booleanAsLong(function.call(oldValue)); abort = false; return returnOld ? oldValue : longAsBoolean(write.long_value); } finally { if (abort) { tx.abort(); } } } @Override public final boolean atomicAlterAndGet(final BooleanFunction function) { return atomicAlter(function, false); } @Override public final boolean atomicGetAndAlter(final BooleanFunction function) { return atomicAlter(function, true); } private boolean atomicAlter(final BooleanFunction function, final boolean returnOld) { if (function == null) { throw new NullPointerException("Function can't be null"); } final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final boolean oldValue = longAsBoolean(long_value); boolean newValue; boolean abort = true; try { newValue = function.call(oldValue); abort = false; } finally { if (abort) { departAfterFailureAndUnlock(); } } if (oldValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } long_value = booleanAsLong(newValue); //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final boolean atomicCompareAndSet(final boolean expectedValue, final boolean newValue) { return atomicCompareAndSetLong(booleanAsLong(expectedValue), booleanAsLong(newValue)); } @Override public final void await(final boolean value) { await(getRequiredThreadLocalGammaTxn(), value); } @Override public final void await(final Txn tx, final boolean value) { await(asGammaTxn(tx), value); } public final void await(final GammaTxn tx, final boolean value) { if (longAsBoolean(openForRead(tx, LOCKMODE_NONE).long_value) != value) { tx.retry(); } } @Override public final void await(final BooleanPredicate predicate) { await(getRequiredThreadLocalGammaTxn(), predicate); } @Override public final void await(final Txn tx, final BooleanPredicate predicate) { await(asGammaTxn(tx), predicate); } public final void await(final GammaTxn tx, final BooleanPredicate predicate) { final Tranlocal tranlocal = openForRead(tx, LOCKMODE_NONE); boolean abort = true; try { if (!predicate.evaluate(longAsBoolean(tranlocal.long_value))) { tx.retry(); } abort = false; } finally { if (abort) { tx.abort(); } } } @Override public final String toDebugString() { return String.format("GammaTxnBoolean{orec=%s, version=%s, value=%s, hasListeners=%s)", ___toOrecString(), version, longAsBoolean(long_value), listeners != null); } @Override public final String toString() { return toString(getRequiredThreadLocalGammaTxn()); } @Override public final String toString(Txn tx) { return toString(asGammaTxn(tx)); } public final String toString(GammaTxn tx) { return Boolean.toString(get(tx)); } @Override public final String atomicToString() { return Boolean.toString(atomicGet()); } } GammaTxnDouble.java000066400000000000000000000323441174000617100405430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.DoubleFunction; import org.multiverse.api.predicates.DoublePredicate; import org.multiverse.api.references.TxnDouble; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.stms.gamma.GammaStmUtils.*; import static org.multiverse.stms.gamma.ThreadLocalGammaObjectPool.getThreadLocalGammaObjectPool; @SuppressWarnings({"OverlyComplexClass"}) public class GammaTxnDouble extends BaseGammaTxnRef implements TxnDouble { public GammaTxnDouble(double value) { this((GammaStm) getGlobalStmInstance(), value); } public GammaTxnDouble(final GammaTxn tx) { this(tx, 0); } public GammaTxnDouble(final GammaTxn tx, final double value) { super(tx.getConfig().stm, TYPE_DOUBLE); arriveAndLock(1, LOCKMODE_EXCLUSIVE); Tranlocal tranlocal = openForConstruction(tx); tranlocal.long_value = doubleAsLong(value); } public GammaTxnDouble(final GammaStm stm) { this(stm, 0); } public GammaTxnDouble(final GammaStm stm, final double value) { super(stm, TYPE_DOUBLE); this.long_value = doubleAsLong(value); //noinspection PointlessArithmeticExpression this.version = VERSION_UNCOMMITTED + 1; } @Override public final double get() { return get(getRequiredThreadLocalGammaTxn()); } @Override public final double get(final Txn tx) { return get(asGammaTxn(tx)); } public final double get(final GammaTxn tx) { return longAsDouble(openForRead(tx, LOCKMODE_NONE).long_value); } @Override public final double getAndLock(final LockMode lockMode) { return getAndLock(getRequiredThreadLocalGammaTxn(), lockMode); } @Override public final double getAndLock(final Txn tx, final LockMode lockMode) { return getAndLock(asGammaTxn(tx), lockMode); } public final double getAndLock(final GammaTxn tx, final LockMode lockMode) { return longAsDouble(getLong(tx, lockMode)); } @Override public final double set(final double value) { return set(getRequiredThreadLocalGammaTxn(), value); } @Override public final double set(final Txn tx, final double value) { return set(asGammaTxn(tx), value); } public final double set(final GammaTxn tx, final double value) { openForWrite(tx, LOCKMODE_NONE).long_value = doubleAsLong(value); return value; } @Override public final double setAndLock(final double value, final LockMode lockMode) { return setAndLock(getRequiredThreadLocalGammaTxn(), doubleAsLong(value), lockMode); } @Override public final double setAndLock(final Txn tx, final double value, final LockMode lockMode) { return setAndLock(asGammaTxn(tx), value, lockMode); } public final double setAndLock(final GammaTxn tx, final double value, final LockMode lockMode) { return longAsDouble(setLong(tx, lockMode, doubleAsLong(value), false)); } @Override public final double getAndSet(final double value) { return getAndSet(getRequiredThreadLocalGammaTxn(), value); } @Override public final double getAndSet(final Txn tx, final double value) { return getAndSet(asGammaTxn(tx), value); } public final double getAndSet(final GammaTxn tx, final double value) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); double oldValue = longAsDouble(tranlocal.long_value); tranlocal.long_value = doubleAsLong(value); return oldValue; } @Override public final double getAndSetAndLock(final double value, final LockMode lockMode) { return getAndSetAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final double getAndSetAndLock(final Txn tx, final double value, final LockMode lockMode) { return getAndSetAndLock(asGammaTxn(tx), value, lockMode); } public final double getAndSetAndLock(final GammaTxn tx, final double value, final LockMode lockMode) { return longAsDouble(setLong(tx, lockMode, doubleAsLong(value), true)); } @Override public final double atomicGet() { return longAsDouble(atomicGetLong()); } @Override public final double atomicWeakGet() { return longAsDouble(long_value); } @Override public final double atomicSet(final double newValue) { return longAsDouble(atomicSetLong(doubleAsLong(newValue), false)); } @Override public final double atomicGetAndSet(final double newValue) { return longAsDouble(atomicSetLong(doubleAsLong(newValue), true)); } @Override public final void commute(final DoubleFunction function) { commute(getRequiredThreadLocalGammaTxn(), function); } @Override public final void commute(final Txn tx, final DoubleFunction function) { commute(asGammaTxn(tx), function); } public final void commute(final GammaTxn tx, final DoubleFunction function) { openForCommute(tx, function); } @Override public final double atomicAlterAndGet(final DoubleFunction function) { return atomicAlter(function, false); } @Override public final double atomicGetAndAlter(final DoubleFunction function) { return atomicAlter(function, true); } private double atomicAlter(final DoubleFunction function, final boolean returnOld) { if (function == null) { throw new NullPointerException("Function can't be null"); } final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final double oldValue = longAsDouble(long_value); double newValue; boolean abort = true; try { newValue = function.call(oldValue); abort = false; } finally { if (abort) { departAfterFailureAndUnlock(); } } if (oldValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } long_value = doubleAsLong(newValue); //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final double alterAndGet(final DoubleFunction function) { return alterAndGet(getRequiredThreadLocalGammaTxn(), function); } @Override public final double alterAndGet(final Txn tx, final DoubleFunction function) { return alterAndGet(asGammaTxn(tx), function); } public final double alterAndGet(final GammaTxn tx, final DoubleFunction function) { return alter(tx, function, false); } @Override public final double getAndAlter(final DoubleFunction function) { return getAndAlter(getRequiredThreadLocalGammaTxn(), function); } @Override public final double getAndAlter(final Txn tx, final DoubleFunction function) { return getAndAlter(asGammaTxn(tx), function); } public final double getAndAlter(final GammaTxn tx, final DoubleFunction function) { return alter(tx, function, true); } public final double alter(final GammaTxn tx, final DoubleFunction function, boolean returnOld) { if (tx == null) { throw new NullPointerException(); } if (function == null) { tx.abort(); throw new NullPointerException("Function can't be null"); } final Tranlocal write = openForWrite(tx, LOCKMODE_NONE); boolean abort = true; try { double oldValue = longAsDouble(write.long_value); write.long_value = doubleAsLong(function.call(oldValue)); abort = false; return returnOld ? oldValue : longAsDouble(write.long_value); } finally { if (abort) { tx.abort(); } } } @Override public final boolean atomicCompareAndSet(final double expectedValue, final double newValue) { return atomicCompareAndSetLong(doubleAsLong(expectedValue), doubleAsLong(newValue)); } @Override public final double getAndIncrement(final double amount) { return getAndIncrement(getRequiredThreadLocalGammaTxn(), amount); } @Override public final double getAndIncrement(final Txn tx, final double amount) { return getAndIncrement(asGammaTxn(tx), amount); } public final double getAndIncrement(final GammaTxn tx, final double amount) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); double oldValue = longAsDouble(tranlocal.long_value); tranlocal.long_value = doubleAsLong(oldValue + amount); return oldValue; } @Override public final double atomicGetAndIncrement(final double amount) { return atomicIncrement(amount, true); } @Override public final double atomicIncrementAndGet(final double amount) { return atomicIncrement(amount, false); } private double atomicIncrement(final double amount, boolean returnOld) { final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final double oldValue = longAsDouble(long_value); if (amount == 0) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } final double newValue = oldValue + amount; long_value = doubleAsLong(newValue); //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final double incrementAndGet(final double amount) { return incrementAndGet(getRequiredThreadLocalGammaTxn(), amount); } @Override public final double incrementAndGet(final Txn tx, final double amount) { return incrementAndGet(asGammaTxn(tx), amount); } public final double incrementAndGet(final GammaTxn tx, final double amount) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); double result = longAsDouble(tranlocal.long_value) + amount; tranlocal.long_value = doubleAsLong(result); return result; } @Override public final void await(final double value) { await(getRequiredThreadLocalGammaTxn(), value); } @Override public final void await(final Txn tx, final double value) { await(asGammaTxn(tx), value); } public final void await(final GammaTxn tx, final double value) { if (longAsDouble(openForRead(tx, LOCKMODE_NONE).long_value) != value) { tx.retry(); } } @Override public final void await(final DoublePredicate predicate) { await(getRequiredThreadLocalGammaTxn(), predicate); } @Override public final void await(final Txn tx, final DoublePredicate predicate) { await(asGammaTxn(tx), predicate); } public final void await(final GammaTxn tx, final DoublePredicate predicate) { final Tranlocal tranlocal = openForRead(tx, LOCKMODE_NONE); boolean abort = true; try { if (!predicate.evaluate(longAsDouble(tranlocal.long_value))) { tx.retry(); } abort = false; } finally { if (abort) { tx.abort(); } } } @Override public final String toDebugString() { return String.format("GammaTxnDouble{orec=%s, version=%s, value=%s, hasListeners=%s)", ___toOrecString(), version, longAsDouble(long_value), listeners != null); } @Override public final String toString() { return toString(getRequiredThreadLocalGammaTxn()); } @Override public final String toString(Txn tx) { return toString(asGammaTxn(tx)); } public final String toString(GammaTxn tx) { return Double.toString(get(tx)); } @Override public final String atomicToString() { return Double.toString(atomicGet()); } } GammaTxnInteger.java000066400000000000000000000334121174000617100407230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.IntFunction; import org.multiverse.api.predicates.IntPredicate; import org.multiverse.api.references.TxnInteger; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.stms.gamma.GammaStmUtils.*; import static org.multiverse.stms.gamma.ThreadLocalGammaObjectPool.getThreadLocalGammaObjectPool; /** * @author Peter Veentjer. */ @SuppressWarnings({"OverlyComplexClass"}) public class GammaTxnInteger extends BaseGammaTxnRef implements TxnInteger { public GammaTxnInteger(int value) { this((GammaStm) getGlobalStmInstance(), value); } public GammaTxnInteger(final GammaTxn tx) { this(tx, 0); } public GammaTxnInteger(final GammaTxn tx, final int value) { super(tx.getConfig().stm, TYPE_INT); arriveAndLock(1, LOCKMODE_EXCLUSIVE); Tranlocal tranlocal = openForConstruction(tx); tranlocal.long_value = value; } public GammaTxnInteger(final GammaStm stm) { this(stm, 0); } public GammaTxnInteger(final GammaStm stm, final int value) { super(stm, TYPE_INT); this.long_value = value; //noinspection PointlessArithmeticExpression this.version = VERSION_UNCOMMITTED + 1; } @Override public final int get() { return get(getRequiredThreadLocalGammaTxn()); } @Override public final int get(final Txn tx) { return get(asGammaTxn(tx)); } public final int get(final GammaTxn tx) { return (int) openForRead(tx, LOCKMODE_NONE).long_value; } @Override public int getAndLock(final LockMode lockMode) { return getAndLock(getRequiredThreadLocalGammaTxn(), lockMode); } @Override public final int getAndLock(final Txn tx, final LockMode lockMode) { return getAndLock(asGammaTxn(tx), lockMode); } public final int getAndLock(final GammaTxn tx, final LockMode lockMode) { return (int) getLong(tx, lockMode); } @Override public final int set(final int value) { return set(getRequiredThreadLocalGammaTxn(), value); } @Override public final int set(final Txn tx, final int value) { return set(asGammaTxn(tx), value); } public final int set(final GammaTxn tx, final int value) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value = value; return value; } @Override public final int setAndLock(final int value, final LockMode lockMode) { return setAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final int setAndLock(final Txn tx, final int value, final LockMode lockMode) { return setAndLock(asGammaTxn(tx), value, lockMode); } public final int setAndLock(final GammaTxn tx, final int value, final LockMode lockMode) { return (int) longAsDouble(setLong(tx, lockMode, value, false)); } @Override public final int getAndSet(final int value) { return getAndSet(getRequiredThreadLocalGammaTxn(), value); } @Override public final int getAndSet(final Txn tx, final int value) { return getAndSet(asGammaTxn(tx), value); } public final int getAndSet(final GammaTxn tx, final int value) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); int oldValue = (int) tranlocal.long_value; tranlocal.long_value = value; return oldValue; } @Override public final int getAndSetAndLock(final int value, final LockMode lockMode) { return getAndSetLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final int getAndSetAndLock(final Txn tx, final int value, final LockMode lockMode) { return getAndSetLock(asGammaTxn(tx), value, lockMode); } public final int getAndSetLock(final GammaTxn tx, final int value, final LockMode lockMode) { return (int) setLong(tx, lockMode, value, true); } @Override public final int atomicGet() { return (int) atomicGetLong(); } @Override public final int atomicWeakGet() { return (int) long_value; } @Override public final int atomicSet(final int newValue) { return (int) atomicSetLong(newValue, false); } @Override public final int atomicGetAndSet(final int newValue) { return (int) atomicSetLong(newValue, true); } @Override public final void commute(final IntFunction function) { commute(getRequiredThreadLocalGammaTxn(), function); } @Override public final void commute(final Txn tx, final IntFunction function) { commute(asGammaTxn(tx), function); } public final void commute(final GammaTxn tx, final IntFunction function) { openForCommute(tx, function); } @Override public final int atomicAlterAndGet(final IntFunction function) { return atomicAlter(function, false); } @Override public final int atomicGetAndAlter(final IntFunction function) { return atomicAlter(function, true); } private int atomicAlter(final IntFunction function, final boolean returnOld) { if (function == null) { throw new NullPointerException("Function can't be null"); } final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final int oldValue = (int) long_value; int newValue; boolean abort = true; try { newValue = function.call(oldValue); abort = false; } finally { if (abort) { departAfterFailureAndUnlock(); } } if (oldValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } long_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final int alterAndGet(final IntFunction function) { return alterAndGet(getRequiredThreadLocalGammaTxn(), function); } @Override public final int alterAndGet(final Txn tx, final IntFunction function) { return alterAndGet(asGammaTxn(tx), function); } public final int alterAndGet(final GammaTxn tx, final IntFunction function) { return alter(tx, function, false); } @Override public final int getAndAlter(final IntFunction function) { return getAndAlter(getRequiredThreadLocalGammaTxn(), function); } @Override public final int getAndAlter(final Txn tx, final IntFunction function) { return getAndAlter(asGammaTxn(tx), function); } public final int getAndAlter(final GammaTxn tx, final IntFunction function) { return alter(tx, function, true); } private int alter(final GammaTxn tx, final IntFunction function, final boolean returnOld) { if (tx == null) { throw new NullPointerException(); } if (function == null) { tx.abort(); throw new NullPointerException("Function can't be null"); } final Tranlocal write = openForWrite(tx, LOCKMODE_NONE); boolean abort = true; try { int oldValue = (int) write.long_value; write.long_value = function.call(oldValue); abort = false; return returnOld ? oldValue : (int) write.long_value; } finally { if (abort) { tx.abort(); } } } @Override public final boolean atomicCompareAndSet(final int expectedValue, final int newValue) { return atomicCompareAndSetLong(expectedValue, newValue); } @Override public final int atomicGetAndIncrement(final int amount) { return atomicIncrement(amount, true); } @Override public final int atomicIncrementAndGet(final int amount) { return atomicIncrement(amount, false); } private int atomicIncrement(final int amount, boolean returnOld) { final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final int oldValue = (int) long_value; if (amount == 0) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } final int newValue = oldValue + amount; long_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final int getAndIncrement(final int amount) { return getAndIncrement(getRequiredThreadLocalGammaTxn(), amount); } @Override public final int getAndIncrement(final Txn tx, final int amount) { return getAndIncrement(asGammaTxn(tx), amount); } public final int getAndIncrement(final GammaTxn tx, final int amount) { return increment(tx, amount, true); } @Override public final int incrementAndGet(final int amount) { return incrementAndGet(getRequiredThreadLocalGammaTxn(), amount); } @Override public final int incrementAndGet(final Txn tx, final int amount) { return incrementAndGet(asGammaTxn(tx), amount); } public final int incrementAndGet(final GammaTxn tx, final int amount) { return increment(tx, amount, false); } private int increment(final GammaTxn tx, final int amount, final boolean returnOld) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); int oldValue = (int) tranlocal.long_value; tranlocal.long_value += amount; return returnOld ? oldValue : (int) tranlocal.long_value; } @Override public final void increment() { increment(getRequiredThreadLocalGammaTxn(), 1); } @Override public final void increment(final Txn tx) { increment(asGammaTxn(tx), 1); } @Override public final void increment(final int amount) { increment(getRequiredThreadLocalGammaTxn(), amount); } @Override public final void increment(final Txn tx, final int amount) { increment(asGammaTxn(tx), amount); } public final void increment(final GammaTxn tx, final int amount) { commute(tx, Functions.incIntFunction(amount)); } @Override public final void decrement() { increment(getRequiredThreadLocalGammaTxn(), -1); } @Override public final void decrement(Txn tx) { increment(asGammaTxn(tx), -1); } @Override public final void decrement(final int amount) { increment(getRequiredThreadLocalGammaTxn(), -amount); } @Override public final void decrement(final Txn tx, final int amount) { increment(asGammaTxn(tx), -amount); } @Override public final void await(final int value) { await(getRequiredThreadLocalGammaTxn(), value); } @Override public final void await(final Txn tx, final int value) { await(asGammaTxn(tx), value); } public final void await(final GammaTxn tx, final int value) { if (get(tx) != value) { tx.retry(); } } @Override public final void await(final IntPredicate predicate) { await(getRequiredThreadLocalGammaTxn(), predicate); } @Override public final void await(final Txn tx, final IntPredicate predicate) { await(asGammaTxn(tx), predicate); } public final void await(final GammaTxn tx, final IntPredicate predicate) { final Tranlocal tranlocal = openForRead(tx, LOCKMODE_NONE); boolean abort = true; try { if (!predicate.evaluate((int) tranlocal.long_value)) { tx.retry(); } abort = false; } finally { if (abort) { tx.abort(); } } } @Override public final String toDebugString() { return String.format("GammaTxnInteger{orec=%s, version=%s, value=%s, hasListeners=%s)", ___toOrecString(), version, long_value, listeners != null); } @Override public final String toString() { return toString(getRequiredThreadLocalGammaTxn()); } @Override public final String toString(Txn tx) { return toString(asGammaTxn(tx)); } public final String toString(GammaTxn tx) { return Integer.toString(get(tx)); } @Override public final String atomicToString() { return Integer.toString(atomicGet()); } } GammaTxnLong.java000066400000000000000000000335651174000617100402360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.api.predicates.LongPredicate; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.stms.gamma.GammaStmUtils.asGammaTxn; import static org.multiverse.stms.gamma.GammaStmUtils.getRequiredThreadLocalGammaTxn; import static org.multiverse.stms.gamma.ThreadLocalGammaObjectPool.getThreadLocalGammaObjectPool; /** * A {@link org.multiverse.api.references.TxnLong} for the {@link GammaStm}. * * @author Peter Veentjer. */ @SuppressWarnings({"OverlyComplexClass"}) public class GammaTxnLong extends BaseGammaTxnRef implements TxnLong { public GammaTxnLong(long value) { this((GammaStm) getGlobalStmInstance(), value); } public GammaTxnLong(final GammaStm stm) { this(stm, 0); } public GammaTxnLong(final GammaStm stm, long initialValue) { super(stm, TYPE_LONG); this.long_value = initialValue; //noinspection PointlessArithmeticExpression this.version = VERSION_UNCOMMITTED + 1; } public GammaTxnLong(final GammaTxn tx) { this(tx, 0); } public GammaTxnLong(final GammaTxn tx, final long value) { super(tx.getConfig().stm, TYPE_LONG); arriveAndLock(1, LOCKMODE_EXCLUSIVE); Tranlocal tranlocal = openForConstruction(tx); tranlocal.long_value = value; } @Override public final long get() { return get(getRequiredThreadLocalGammaTxn()); } @Override public final long get(final Txn tx) { return get(asGammaTxn(tx)); } public final long get(final GammaTxn tx) { return openForRead(tx, LOCKMODE_NONE).long_value; } @Override public final long getAndLock(final LockMode lockMode) { return getAndLock(getRequiredThreadLocalGammaTxn(), lockMode); } @Override public final long getAndLock(final Txn tx, final LockMode lockMode) { return getAndLock(asGammaTxn(tx), lockMode); } public final long getAndLock(final GammaTxn tx, final LockMode lockMode) { return getLong(tx, lockMode); } @Override public final long set(final long value) { return set(getRequiredThreadLocalGammaTxn(), value); } @Override public final long set(final Txn tx, final long value) { return set(asGammaTxn(tx), value); } public final long set(final GammaTxn tx, final long value) { openForWrite(tx, LOCKMODE_NONE).long_value = value; return value; } @Override public final long setAndLock(final long value, final LockMode lockMode) { return setAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final long setAndLock(final Txn tx, final long value, final LockMode lockMode) { return setAndLock(asGammaTxn(tx), value, lockMode); } public final long setAndLock(final GammaTxn tx, final long value, final LockMode lockMode) { return setLong(tx, lockMode, value, false); } @Override public final long getAndSet(final long value) { return getAndSet(getRequiredThreadLocalGammaTxn(), value); } public final long getAndSet(final Txn tx, final long value) { return getAndSet(asGammaTxn(tx), value); } public final long getAndSet(final GammaTxn tx, final long value) { final Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); final long oldValue = tranlocal.long_value; tranlocal.long_value = value; return oldValue; } @Override public final long getAndSetAndLock(final long value, final LockMode lockMode) { return getAndSetAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final long getAndSetAndLock(final Txn tx, final long value, final LockMode lockMode) { return getAndSetLock(asGammaTxn(tx), value, lockMode); } public final long getAndSetLock(final GammaTxn tx, final long value, final LockMode lockMode) { return setLong(tx, lockMode, value, true); } @Override public final long atomicGet() { return atomicGetLong(); } @Override public final long atomicWeakGet() { return long_value; } @Override public final long atomicSet(final long newValue) { return atomicSetLong(newValue, false); } @Override public final long atomicGetAndSet(final long newValue) { return atomicSetLong(newValue, true); } @Override public final void commute(final LongFunction function) { commute(getRequiredThreadLocalGammaTxn(), function); } @Override public final void commute(Txn tx, LongFunction function) { openForCommute(asGammaTxn(tx), function); } public final void commute(GammaTxn tx, LongFunction function) { openForCommute(tx, function); } @Override public final long atomicAlterAndGet(final LongFunction function) { return atomicAlter(function, false); } private long atomicAlter(final LongFunction function, final boolean returnOld) { if (function == null) { throw new NullPointerException("Function can't be null"); } final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final long oldValue = long_value; long newValue; boolean abort = true; try { newValue = function.call(oldValue); abort = false; } finally { if (abort) { departAfterFailureAndUnlock(); } } if (oldValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } long_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final long alterAndGet(final LongFunction function) { return alterAndGet(getRequiredThreadLocalGammaTxn(), function); } @Override public final long alterAndGet(final Txn tx, final LongFunction function) { return alterAndGet(asGammaTxn(tx), function); } public final long alterAndGet(final GammaTxn tx, final LongFunction function) { return alter(tx, function, false); } @Override public final long atomicGetAndAlter(final LongFunction function) { return atomicAlter(function, true); } @Override public final long getAndAlter(final LongFunction function) { return getAndAlter(getRequiredThreadLocalGammaTxn(), function); } @Override public final long getAndAlter(final Txn tx, final LongFunction function) { return getAndAlter(asGammaTxn(tx), function); } public final long getAndAlter(final GammaTxn tx, final LongFunction function) { return alter(tx, function, true); } private long alter(final GammaTxn tx, final LongFunction function, final boolean returnOld) { if (tx == null) { throw new NullPointerException(); } if (function == null) { tx.abort(); throw new NullPointerException("Function can't be null"); } final Tranlocal write = openForWrite(tx, LOCKMODE_NONE); boolean abort = true; try { long oldValue = write.long_value; write.long_value = function.call(oldValue); abort = false; return returnOld ? oldValue : write.long_value; } finally { if (abort) { tx.abort(); } } } @Override public final boolean atomicCompareAndSet(final long expectedValue, final long newValue) { return atomicCompareAndSetLong(expectedValue, newValue); } @Override public final long atomicGetAndIncrement(final long amount) { final long result = atomicIncrementAndGet(amount); return result - amount; } @Override public final long getAndIncrement(final long amount) { return getAndIncrement(getRequiredThreadLocalGammaTxn(), amount); } @Override public final long getAndIncrement(final Txn tx, final long amount) { return getAndIncrement((GammaTxn) tx, amount); } public final long getAndIncrement(final GammaTxn tx, final long amount) { final Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); final long oldValue = tranlocal.long_value; tranlocal.long_value += amount; return oldValue; } @Override public final long atomicIncrementAndGet(final long amount) { final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final long oldValue = long_value; if (amount == 0) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } final long newValue = oldValue + amount; long_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return newValue; } @Override public final long incrementAndGet(final long amount) { return incrementAndGet(getRequiredThreadLocalGammaTxn(), amount); } @Override public final long incrementAndGet(final Txn tx, final long amount) { return incrementAndGet(asGammaTxn(tx), amount); } public final long incrementAndGet(final GammaTxn tx, final long amount) { final Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value += amount; return tranlocal.long_value; } @Override public final void increment() { increment(getRequiredThreadLocalGammaTxn()); } @Override public final void increment(final Txn tx) { commute(asGammaTxn(tx), Functions.incLongFunction()); } public final void increment(final GammaTxn tx) { commute(tx, Functions.incLongFunction()); } @Override public final void increment(final long amount) { commute(getRequiredThreadLocalGammaTxn(), Functions.incLongFunction(amount)); } @Override public final void increment(final Txn tx, final long amount) { commute(asGammaTxn(tx), Functions.incLongFunction(amount)); } @Override public final void decrement() { commute(getRequiredThreadLocalGammaTxn(), Functions.decLongFunction()); } @Override public final void decrement(final Txn tx) { commute(asGammaTxn(tx), Functions.decLongFunction()); } @Override public final void decrement(final long amount) { commute(getRequiredThreadLocalGammaTxn(), Functions.incLongFunction(-amount)); } @Override public final void decrement(final Txn tx, final long amount) { commute(asGammaTxn(tx), Functions.incLongFunction(-amount)); } @Override public final void await(final long value) { await(getRequiredThreadLocalGammaTxn(), value); } @Override public final void await(final Txn tx, final long value) { await(asGammaTxn(tx), value); } public final void await(final GammaTxn tx, final long value) { if (openForRead(tx, LOCKMODE_NONE).long_value != value) { tx.retry(); } } @Override public final void await(final LongPredicate predicate) { await(getRequiredThreadLocalGammaTxn(), predicate); } @Override public final void await(final Txn tx, final LongPredicate predicate) { await(asGammaTxn(tx), predicate); } public final void await(final GammaTxn tx, final LongPredicate predicate) { final Tranlocal tranlocal = openForRead(tx, LOCKMODE_NONE); boolean abort = true; try { if (!predicate.evaluate(tranlocal.long_value)) { tx.retry(); } abort = false; } finally { if (abort) { tx.abort(); } } } @Override public final String toDebugString() { return String.format("GammaTxnLong{orec=%s, version=%s, value=%s, hasListeners=%s)", ___toOrecString(), version, long_value, listeners != null); } @Override public final String toString() { return toString(getRequiredThreadLocalGammaTxn()); } @Override public final String toString(Txn tx) { return toString(asGammaTxn(tx)); } public final String toString(GammaTxn tx) { return Long.toString(get(tx)); } @Override public final String atomicToString() { return Long.toString(atomicGet()); } } GammaTxnRef.java000066400000000000000000000312131174000617100400370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.Function; import org.multiverse.api.predicates.Predicate; import org.multiverse.api.references.TxnRef; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.getRequiredThreadLocalTxn; import static org.multiverse.stms.gamma.GammaStmUtils.asGammaTxn; import static org.multiverse.stms.gamma.GammaStmUtils.getRequiredThreadLocalGammaTxn; import static org.multiverse.stms.gamma.ThreadLocalGammaObjectPool.getThreadLocalGammaObjectPool; /** * A {@link org.multiverse.api.references.TxnRef} tailored for the {@link GammaStm}. * * @param * @author Peter Veentjer. */ @SuppressWarnings({"OverlyComplexClass"}) public class GammaTxnRef extends BaseGammaTxnRef implements TxnRef { public GammaTxnRef(E value) { this((GammaStm) getGlobalStmInstance(), value); } public GammaTxnRef(final GammaTxn tx) { this(tx, null); } public GammaTxnRef(final GammaTxn tx, final E value) { super(tx.getConfig().stm, TYPE_REF); arriveAndLock(1, LOCKMODE_EXCLUSIVE); Tranlocal tranlocal = openForConstruction(tx); tranlocal.ref_value = value; } public GammaTxnRef(final GammaStm stm) { this(stm, null); } public GammaTxnRef(final GammaStm stm, final E value) { super(stm, TYPE_REF); this.ref_value = value; //noinspection PointlessArithmeticExpression this.version = VERSION_UNCOMMITTED + 1; } @Override public final E get() { return get(getRequiredThreadLocalGammaTxn()); } @Override public final E get(final Txn tx) { return get(asGammaTxn(tx)); } public final E get(final GammaTxn tx) { return (E) openForRead(tx, LOCKMODE_NONE).ref_value; } @Override public final E getAndLock(final LockMode lockMode) { return getAndLock(getRequiredThreadLocalGammaTxn(), lockMode); } @Override public final E getAndLock(final Txn tx, final LockMode lockMode) { return getAndLock(asGammaTxn(tx), lockMode); } public final E getAndLock(final GammaTxn tx, final LockMode lockMode) { return (E) getObject(tx, lockMode); } @Override public final E set(final E value) { return set(getRequiredThreadLocalTxn(), value); } @Override public final E set(final Txn tx, final E value) { return set(asGammaTxn(tx), value); } public final E set(final GammaTxn tx, final E value) { final Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); tranlocal.ref_value = value; return value; } @Override public final E setAndLock(final E value, final LockMode lockMode) { return setAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final E setAndLock(final Txn tx, final E value, final LockMode lockMode) { return setAndLock(asGammaTxn(tx), value, lockMode); } public final E setAndLock(final GammaTxn tx, final E value, final LockMode lockMode) { return (E) setObject(tx, lockMode, value, false); } @Override public final E getAndSet(final E value) { return getAndSet(getRequiredThreadLocalTxn(), value); } @Override public final E getAndSet(final Txn tx, final E value) { return getAndSet(asGammaTxn(tx), value); } public final E getAndSet(final GammaTxn tx, final E value) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); E oldValue = (E) tranlocal.ref_value; tranlocal.ref_value = value; return oldValue; } @Override public final E getAndSetAndLock(final E value, final LockMode lockMode) { return getAndSetAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final E getAndSetAndLock(final Txn tx, final E value, final LockMode lockMode) { return getAndSetAndLock(asGammaTxn(tx), value, lockMode); } public final E getAndSetAndLock(final GammaTxn tx, final E value, final LockMode lockMode) { return (E) setObject(tx, lockMode, value, true); } @Override public final E atomicGet() { return (E) atomicObjectGet(); } @Override public final E atomicWeakGet() { return (E) ref_value; } @Override public final E atomicSet(final E newValue) { return (E) atomicSetObject(newValue, false); } @Override public final E atomicGetAndSet(final E newValue) { return (E) atomicSetObject(newValue, true); } @Override public final void commute(final Function function) { commute(getRequiredThreadLocalTxn(), function); } @Override public final void commute(final Txn tx, final Function function) { commute(asGammaTxn(tx), function); } public final void commute(final GammaTxn tx, final Function function) { openForCommute(tx, function); } @Override public final E atomicAlterAndGet(final Function function) { return atomicAlter(function, false); } @Override public final E atomicGetAndAlter(final Function function) { return atomicAlter(function, true); } private E atomicAlter(final Function function, final boolean returnOld) { if (function == null) { throw new NullPointerException("Function can't be null"); } final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final E oldValue = (E) ref_value; E newValue; boolean abort = true; try { newValue = function.call(oldValue); abort = false; } finally { if (abort) { departAfterFailureAndUnlock(); } } if (oldValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } ref_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final E alterAndGet(final Function function) { return alterAndGet(getRequiredThreadLocalTxn(), function); } @Override public final E alterAndGet(final Txn tx, final Function function) { return alterAndGet(asGammaTxn(tx), function); } public final E alterAndGet(final GammaTxn tx, final Function function) { return alter(tx, function, false); } @Override public final E getAndAlter(final Function function) { return getAndAlter(getRequiredThreadLocalTxn(), function); } @Override public final E getAndAlter(final Txn tx, final Function function) { return getAndAlter(asGammaTxn(tx), function); } public final E getAndAlter(final GammaTxn tx, final Function function) { return alter(tx, function, true); } private E alter(final GammaTxn tx, final Function function, final boolean returnOld) { if (tx == null) { throw new NullPointerException(); } if (function == null) { tx.abort(); throw new NullPointerException("Function can't be null"); } final Tranlocal write = openForWrite(tx, LOCKMODE_NONE); boolean abort = true; try { E oldValue = (E) write.ref_value; write.ref_value = function.call(oldValue); abort = false; return returnOld ? oldValue : (E) write.ref_value; } finally { if (abort) { tx.abort(); } } } @Override public final boolean atomicCompareAndSet(final E expectedValue, final E newValue) { final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final E currentValue = (E) ref_value; if (currentValue != expectedValue) { departAfterFailureAndUnlock(); return false; } if (expectedValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return true; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } ref_value = newValue; //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return true; } @Override public final boolean isNull() { return isNull(getRequiredThreadLocalGammaTxn()); } @Override public final boolean isNull(final Txn tx) { return isNull(asGammaTxn(tx)); } public final boolean isNull(final GammaTxn tx) { return openForRead(tx, LOCKMODE_NONE).ref_value == null; } @Override public final boolean atomicIsNull() { return atomicGet() == null; } @Override public final E awaitNotNullAndGet() { return awaitNotNullAndGet(getRequiredThreadLocalGammaTxn()); } @Override public final E awaitNotNullAndGet(final Txn tx) { return awaitNotNullAndGet(asGammaTxn(tx)); } public final E awaitNotNullAndGet(final GammaTxn tx) { final Tranlocal tranlocal = openForRead(tx, LOCKMODE_NONE); if (tranlocal.ref_value == null) { tx.retry(); } return (E) tranlocal.ref_value; } @Override public final void awaitNull() { await(getRequiredThreadLocalGammaTxn(), (E) null); } @Override public final void awaitNull(final Txn tx) { await(asGammaTxn(tx), (E) null); } public final void awaitNull(final GammaTxn tx) { await(tx, (E) null); } @Override public final void await(final E value) { await(getRequiredThreadLocalTxn(), value); } @Override public final void await(final Txn tx, final E value) { await(asGammaTxn(tx), value); } public final void await(final GammaTxn tx, final E value) { //noinspection ObjectEquality if (openForRead(tx, LOCKMODE_NONE).ref_value != value) { tx.retry(); } } @Override public final void await(final Predicate predicate) { await(getRequiredThreadLocalTxn(), predicate); } @Override public final void await(final Txn tx, final Predicate predicate) { await(asGammaTxn(tx), predicate); } public final void await(final GammaTxn tx, final Predicate predicate) { final Tranlocal tranlocal = openForRead(tx, LOCKMODE_NONE); boolean abort = true; try { if (!predicate.evaluate((E) tranlocal.ref_value)) { tx.retry(); } abort = false; } finally { if (abort) { tx.abort(); } } } @Override public final String toDebugString() { return String.format("GammaTxnRef{orec=%s, version=%s, value=%s, hasListeners=%s)", ___toOrecString(), version, ref_value, listeners != null); } @Override public final String toString() { return toString(getRequiredThreadLocalGammaTxn()); } @Override public final String toString(Txn tx) { return toString(asGammaTxn(tx)); } public final String toString(GammaTxn tx) { final E value = get(tx); return value == null ? "null" : value.toString(); } @Override public final String atomicToString() { final E value = atomicGet(); return value == null ? "null" : value.toString(); } } Tranlocal.java000066400000000000000000000035751174000617100376170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.functions.Function; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaObjectPool; @SuppressWarnings({"ClassWithTooManyFields"}) public final class Tranlocal implements GammaConstants { public E ref_value; public long version; public int lockMode; public BaseGammaTxnRef owner; public int mode; public boolean hasDepartObligation; public boolean isDirty; public Tranlocal next; public Tranlocal previous; public CallableNode headCallable; public boolean writeSkewCheck; public long long_oldValue; public E ref_oldValue; public long long_value; public boolean isDirty() { return isDirty; } public void setDirty(boolean dirty) { isDirty = dirty; } public int getLockMode() { return lockMode; } public void setLockMode(int lockMode) { this.lockMode = lockMode; } public boolean hasDepartObligation() { return hasDepartObligation; } public void setDepartObligation(boolean b) { this.hasDepartObligation = b; } public boolean isCommuting() { return mode == TRANLOCAL_COMMUTING; } public boolean isConstructing() { return mode == TRANLOCAL_CONSTRUCTING; } public boolean isRead() { return mode == TRANLOCAL_READ; } public boolean isWrite() { return mode == TRANLOCAL_WRITE; } public void addCommutingFunction(GammaObjectPool pool, Function function) { final CallableNode newHead = pool.takeCallableNode(); newHead.function = function; newHead.next = headCallable; headCallable = newHead; } public int getMode() { return mode; } public boolean isConflictCheckNeeded() { return writeSkewCheck; } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactions/000077500000000000000000000000001174000617100333765ustar00rootroot00000000000000GammaTxn.java000066400000000000000000000750041174000617100357040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; import org.multiverse.api.Txn; import org.multiverse.api.TxnStatus; import org.multiverse.api.blocking.DefaultRetryLatch; import org.multiverse.api.blocking.RetryLatch; import org.multiverse.api.exceptions.*; import org.multiverse.api.functions.Function; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaObjectPool; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.GammaObject; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import java.util.ArrayList; import static java.lang.String.format; import static org.multiverse.stms.gamma.GammaStmUtils.toDebugString; /** * Abstract GammaTxn to be used by all the concrete GammaTxn implementations. * * @author Peter Veentjer. */ @SuppressWarnings({"OverlyComplexClass", "ClassWithTooManyFields", "OverlyCoupledClass"}) public abstract class GammaTxn implements GammaConstants, Txn { public final GammaObjectPool pool = new GammaObjectPool(); public int status = TX_ACTIVE; public GammaTxnConfig config; public int attempt; public long remainingTimeoutNs; public boolean hasWrites; public final int transactionType; public boolean richmansMansConflictScan; public boolean abortOnly = false; public final RetryLatch retryListener = new DefaultRetryLatch(); public ArrayList listeners; public boolean commitConflict; public boolean evaluatingCommute = false; public GammaTxn(GammaTxnConfig config, int transactionType) { config.init(); init(config); this.transactionType = transactionType; } protected void notifyListeners(TxnEvent event) { if (listeners != null) { boolean abort = true; try { for (int k = 0; k < listeners.size(); k++) { listeners.get(k).notify(this, event); } abort = false; } finally { if (abort) { abortIfAlive(); } } } final ArrayList permanentListeners = config.permanentListeners; if (permanentListeners != null) { boolean abort = true; try { for (int k = 0; k < permanentListeners.size(); k++) { permanentListeners.get(k).notify(this, event); } abort = false; } finally { if (abort) { abortIfAlive(); } } } } protected RetryError newRetryError() { return config.controlFlowErrorsReused ? RetryError.INSTANCE : new RetryError(true); } public final boolean isLean() { return transactionType == TRANSACTIONTYPE_LEAN_MONO || transactionType == TRANSACTIONTYPE_LEAN_FIXED_LENGTH; } public final void abortIfAlive() { if (isAlive()) { abort(); } } public AbortOnlyException abortPrepareOnAbortOnly() { abortIfAlive(); return new AbortOnlyException( format("[%s] Failed to execute transaction.prepare, reason: the transaction was configured as abortOnly", config.familyName)); } public AbortOnlyException abortCommitOnAbortOnly() { abortIfAlive(); return new AbortOnlyException( format("[%s] Failed to execute transaction.commit, reason: the transaction was configured as abortOnly", config.familyName)); } public final ReadWriteConflict abortOnReadWriteConflict(GammaObject object) { abortIfAlive(); if (attempt == config.maxRetries || !config.controlFlowErrorsReused) { return new ReadWriteConflict( format("[%s] Failed transaction, reason: object [%s] contains a read/write-conflict", config.familyName, toDebugString(object))); } else { return ReadWriteConflict.INSTANCE; } } public DeadTxnException failAbortOnAlreadyCommitted() { return new DeadTxnException( format("[%s] Failed to execute transaction.abort, reason: the transaction is already committed", config.familyName)); } // ================= open for read ============================= public SpeculativeConfigurationError abortOpenForReadOrWriteOnExplicitLockingDetected(BaseGammaTxnRef ref) { config.updateSpeculativeConfigurationToUseExplicitLocking(); abortIfAlive(); if (config.controlFlowErrorsReused) { return SpeculativeConfigurationError.INSTANCE; } return new SpeculativeConfigurationError( format("[%s] Failed to execute TxnRef.openForRead/openForWrite '%s', reason: the transaction is lean, " + "but explicit locking is required", config.familyName, toDebugString(ref))); } public SpeculativeConfigurationError abortOpenForReadOnNonRefTypeDetected(BaseGammaTxnRef ref) { config.updateSpeculativeConfigurationToUseNonRefType(); abortIfAlive(); if (config.controlFlowErrorsReused) { return SpeculativeConfigurationError.INSTANCE; } return new SpeculativeConfigurationError( format("[%s] Failed to execute TxnRef.openForRead/openForWrite '%s', reason: the transaction is lean," + " but explicit locking is required", config.familyName, toDebugString(ref))); } public final StmMismatchException abortOpenForReadOnBadStm(GammaObject o) { abortIfAlive(); return new StmMismatchException( format("[%s] Failed to execute TxnRef.openForRead '%s', reason: the stm the ref was created " + "with is a different stm than the stm of the transaction", config.familyName, toDebugString(o))); } public IllegalTxnStateException abortOpenForReadOnNullLockMode(BaseGammaTxnRef object) { switch (status) { case TX_PREPARED: abort(); return new PreparedTxnException( format("[%s] Failed to execute TxnRef.openForRead '%s', reason: the LockMode is null", config.familyName, toDebugString(object))); case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.openForRead '%s', reason: the Lockmode is null", config.familyName, toDebugString(object))); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.openForRead '%s', reason: the LockMode is null", config.familyName, toDebugString(object))); default: throw new IllegalStateException(); } } public final IllegalTxnStateException abortOpenForReadOnBadStatus(GammaObject object) { switch (status) { case TX_PREPARED: abort(); return new PreparedTxnException( format("[%s] Failed to execute TxnRef.openForRead '%s', reason: the transaction is prepared", config.familyName, toDebugString(object))); case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.openForRead '%s', reason: the transaction is aborted", config.familyName, toDebugString(object))); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.openForRead '%s', reason: the transaction is committed", config.familyName, toDebugString(object))); default: throw new IllegalStateException(); } } // ============== open for write ============================ public final ReadonlyException abortOpenForWriteOnReadonly(GammaObject object) { abortIfAlive(); return new ReadonlyException( format("[%s] Failed to TxnRef.openForWrite '%s', reason: the transaction is readonly", config.familyName, toDebugString(object))); } // ============================= retry ============================== public final IllegalTxnStateException abortRetryOnNoRetryPossible() { abortIfAlive(); throw new RetryNotPossibleException( format("[%s] Failed to execute TxnRef.retry, reason: there are no tracked reads", config.familyName)); } public final RetryNotAllowedException abortRetryOnNoBlockingAllowed() { abortIfAlive(); return new RetryNotAllowedException( format("[%s] Failed to execute TxnRef.retry, reason: the transaction doesn't allow blocking", config.familyName)); } public final IllegalTxnStateException abortRetryOnBadStatus() { switch (status) { case TX_PREPARED: abort(); return new PreparedTxnException( format("[%s] Failed to execute Txn.retry, reason: the transaction is prepared", config.familyName)); case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute Txn.retry, reason: the transaction is aborted", config.familyName)); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute Txn.retry, reason: the transaction is committed", config.familyName)); default: throw new IllegalStateException(); } } // ========================== open for construction =========================== public final IllegalArgumentException abortOpenForConstructionOnBadReference( final GammaObject ref) { abortIfAlive(); return new IllegalArgumentException( format("[%s] Failed to execute TxnRef.openForConstruction '%s', reason: the object is not new " + "and has previous commits", config.familyName, toDebugString(ref))); } public final IllegalTxnStateException abortOpenForConstructionOnBadStatus(GammaObject o) { switch (status) { case TX_PREPARED: abort(); return new PreparedTxnException( format("[%s] Failed to execute TxnRef.openForConstruction '%s', reason: the transaction is prepared", config.familyName, toDebugString(o))); case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.openForConstruction '%s', reason: the transaction is aborted", config.familyName, toDebugString(o))); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.openForConstruction '%s', reason: the transaction is committed", config.familyName, toDebugString(o))); default: throw new IllegalStateException(); } } public final StmMismatchException abortOpenForConstructionOnBadStm(GammaObject o) { abortIfAlive(); return new StmMismatchException( format("[%s] Failed to execute TxnRef.openForConstruction '%s', reason: the stm the ref was " + "created with is a different stm than the stm of the transaction", config.familyName, toDebugString(o))); } public ReadonlyException abortOpenForConstructionOnReadonly(GammaObject o) { abortIfAlive(); return new ReadonlyException( format("[%s] Failed to execute TxnRef.openForConstruction '%s', reason: the transaction is readonly", config.familyName, toDebugString(o))); } public SpeculativeConfigurationError abortOpenForConstructionRequired(BaseGammaTxnRef ref) { config.updateSpeculativeConfigurationToUseConstructedObjects(); abortIfAlive(); if (config.controlFlowErrorsReused) { return SpeculativeConfigurationError.INSTANCE; } return new SpeculativeConfigurationError( format("[%s] Failed to execute TxnRef.openForConstruction '%s', reason: the transaction is lean, " + "but explicit attachments of constructed objects is required", config.familyName, toDebugString(ref))); } // ============================== open for commute ====================== public SpeculativeConfigurationError abortCommuteOnCommuteDetected(BaseGammaTxnRef ref) { config.updateSpeculativeConfigurationToUseCommute(); abortIfAlive(); if (config.controlFlowErrorsReused) { return SpeculativeConfigurationError.INSTANCE; } return new SpeculativeConfigurationError( format("[%s] Failed to execute TxnRef.commute '%s', reason: the transaction is lean, but commute is required", config.familyName, toDebugString(ref))); } public IllegalTxnStateException abortCommuteOnBadStatus(final GammaObject object, final Function function) { switch (status) { case TX_PREPARED: abort(); return new PreparedTxnException( format("[%s] Failed to execute TxnRef.commute '%s' with reference '%s', reason: the transaction is prepared", config.familyName, toDebugString(object), function)); case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.commute '%s' with reference '%s', reason: the transaction is aborted", config.familyName, toDebugString(object), function)); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.commute '%s' with reference '%s', reason: the transaction is prepared", config.familyName, toDebugString(object), function)); default: throw new IllegalStateException(); } } public StmMismatchException abortCommuteOnBadStm(GammaObject object) { abortIfAlive(); return new StmMismatchException( format("[%s] Failed to execute TxnRef.commute '%s', reason: the stm the ref was created with is a different" + " stm than the stm of the transaction", config.familyName, toDebugString(object))); } public ReadonlyException abortCommuteOnReadonly(final GammaObject object) { abortIfAlive(); return new ReadonlyException( format("[%s] Failed to execute TxnRef.commute '%s', reason: the transaction is readonly", config.familyName, toDebugString(object))); } public NullPointerException abortCommuteOnNullFunction(final GammaObject object) { abortIfAlive(); return new NullPointerException( format("[%s] Failed to execute TxnRef.commute '%s', reason: the function is null", config.familyName, toDebugString(object))); } // ========================================== public final IllegalTxnStateException abortLocateOnBadStatus(GammaObject object) { switch (status) { case TX_PREPARED: abort(); return new PreparedTxnException( format("[%s] Failed to execute Txn.locate '%s' , reason: the transaction is prepared", toDebugString(object), config.familyName)); case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute Txn.locate, '%s' reason: the transaction is aborted", toDebugString(object), config.familyName)); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute Txn.locate, '%s' reason: the transaction is committed", toDebugString(object), config.familyName)); default: throw new IllegalStateException(); } } public final NullPointerException abortLocateOnNullArgument() { abortIfAlive(); return new NullPointerException( format("[%s] Failed to execute Txn.locate, reason: the reference is null", config.familyName)); } // ====================== register ========================================== private NullPointerException abortRegisterOnNullListener() { abortIfAlive(); return new NullPointerException( format("[%s] Failed to execute Txn.register , reason: the listener is null", config.familyName)); } private IllegalTxnStateException abortRegisterOnBadStatus() { switch (status) { case TX_PREPARED: abort(); return new PreparedTxnException( format("[%s] Failed to execute Txn.register, reason: the transaction is prepared", config.familyName)); case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute Txn.register, reason: the transaction is aborted", config.familyName)); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute Txn.register, reason: the transaction is prepared", config.familyName)); default: throw new IllegalStateException(); } } public SpeculativeConfigurationError abortRegisterOnListenerRequired() { config.updateSpeculativeConfigurationToUseListeners(); abortIfAlive(); if (config.controlFlowErrorsReused) { return SpeculativeConfigurationError.INSTANCE; } return new SpeculativeConfigurationError( format("[%s] Failed to execute Txn.register, reason: the transaction is lean, but listeners are required", config.familyName)); } public final IllegalTxnStateException abortPrepareOnBadStatus() { switch (status) { case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute Txn.prepare, reason: the transaction already is aborted", config.familyName)); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute Txn.prepare, reason: the transaction already is committed", config.familyName)); default: throw new IllegalStateException(); } } public final IllegalTxnStateException abortCommitOnBadStatus() { abortIfAlive(); return new DeadTxnException( format("[%s] Failed to execute Txn.commit, reason: the transaction already is aborted", config.familyName)); } public TxnExecutionException abortOnOpenForConstructionWhileEvaluatingCommute(GammaObject o) { abort(); return new IllegalCommuteException( format("[%s] Failed to execute TxnRef.openForConstruction '%s', " + "reason: the transaction is already evaluating a commuting function", config.familyName, toDebugString(o))); } public TxnExecutionException abortOnOpenForReadWhileEvaluatingCommute(GammaObject o) { abortIfAlive(); return new IllegalCommuteException( format("[%s] Failed to execute TxnRef.openForRead '%s', " + "reason: the transaction is already evaluating a commuting function", config.familyName, toDebugString(o))); } public TxnExecutionException abortOnOpenForCommuteWhileEvaluatingCommute(GammaObject o) { abortIfAlive(); return new IllegalCommuteException( format("[%s] Failed to execute TxnRef.openForCommute '%s', " + "reason: the transaction is already evaluating a commuting function", config.familyName, toDebugString(o))); } public IllegalTxnStateException abortEnsureOnBadStatus(BaseGammaTxnRef o) { switch (status) { case TX_PREPARED: abort(); return new PreparedTxnException( format("[%s] Failed to execute TxnRef.ensure with reference '%s', reason: the transaction is prepared", config.familyName, toDebugString(o))); case TX_ABORTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.ensure with reference '%s', reason: the transaction is aborted", config.familyName, toDebugString(o))); case TX_COMMITTED: return new DeadTxnException( format("[%s] Failed to execute TxnRef.ensure with reference '%s', reason: the transaction is committed", config.familyName, toDebugString(o))); default: throw new IllegalStateException(); } } public final SpeculativeConfigurationError abortOnTransactionTooSmall(int minimalSize) { config.updateSpeculativeConfigurationToUseMinimalTransactionLength(minimalSize); abortIfAlive(); if (config.controlFlowErrorsReused) { return SpeculativeConfigurationError.INSTANCE; } return new SpeculativeConfigurationError( format("[%s] Failed to execute opening a TxnRef, reason: the transaction is too small for this operation", config.familyName)); } public final SpeculativeConfigurationError abortOnRichmanConflictScanDetected() { config.updateSpeculativeConfigurationToUseRichMansConflictScan(); abortIfAlive(); if (config.controlFlowErrorsReused) { return SpeculativeConfigurationError.INSTANCE; } return new SpeculativeConfigurationError( format("[%s] Failed to execute evaluate the Txn read consistency, reason: the transaction is large to be used" + " in combination for a poor mans conflictscan", config.familyName)); } public SpeculativeConfigurationError abortEnsureOnEnsureDetected(GammaObject o) { config.updateSpeculativeConfigurationToUseEnsure(); abortIfAlive(); if (config.controlFlowErrorsReused) { return SpeculativeConfigurationError.INSTANCE; } return new SpeculativeConfigurationError( format("[%s] Failed to execute evaluate the TxnRef.ensure [%s], reason: the transaction lean and a fat one needs to be used", config.familyName, toDebugString(o))); } public final NullPointerException abortAcquireOnNullLockMode(GammaObject o) { switch (status) { case TX_ACTIVE: abort(); return new NullPointerException(); case TX_PREPARED: abort(); return new NullPointerException(); case TX_ABORTED: return new NullPointerException(); case TX_COMMITTED: return new NullPointerException(); default: throw new IllegalStateException(); } } public final boolean hasWrites() { return hasWrites; } public abstract void commit(); public abstract void abort(); public abstract Tranlocal locate(BaseGammaTxnRef o); @Override public final GammaTxnConfig getConfig() { return config; } @Override public final int getAttempt() { return attempt; } @Override public final long getRemainingTimeoutNs() { return remainingTimeoutNs; } @Override public boolean isAbortOnly() { switch (status) { case TX_ACTIVE: return abortOnly; case TX_PREPARED: return abortOnly; case TX_COMMITTED: throw new DeadTxnException( format("[%s] Failed to execute Txn.isAbortOnly, reason: the transaction is committed", config.familyName)); case TX_ABORTED: throw new DeadTxnException( format("[%s] Failed to execute Txn.isAbortOnly, reason: the transaction is aborted", config.familyName)); default: throw new IllegalStateException(); } } @Override public final void setAbortOnly() { switch (status) { case TX_ACTIVE: if (isLean()) { config.updateSpeculativeConfigureToUseAbortOnly(); abort(); if (config.controlFlowErrorsReused) { throw SpeculativeConfigurationError.INSTANCE; } throw new SpeculativeConfigurationError( format("[%s] Failed to execute Txn.setAbortOnly, reason: the transaction is lean, " + "but a fat one is required for dealing with the abortOnly", config.familyName)); } abortOnly = true; break; case TX_PREPARED: abort(); throw new PreparedTxnException( format("[%s] Failed to execute Txn.setAbortOnly, reason: the transaction is prepared", config.familyName)); case TX_COMMITTED: throw new DeadTxnException( format("[%s] Failed to execute Txn.setAbortOnly, reason: the transaction is committed", config.familyName)); case TX_ABORTED: throw new DeadTxnException( format("[%s] Failed to execute Txn.setAbortOnly, reason: the transaction is aborted", config.familyName)); default: throw new IllegalStateException(); } } @Override public void register(TxnListener listener) { if (listener == null) { throw abortRegisterOnNullListener(); } if (status != TX_ACTIVE) { throw abortRegisterOnBadStatus(); } if (transactionType == TRANSACTIONTYPE_LEAN_MONO || transactionType == TRANSACTIONTYPE_LEAN_FIXED_LENGTH) { throw abortRegisterOnListenerRequired(); } if (listeners == null) { listeners = pool.takeArrayList(); } listeners.add(listener); } /** * Does a hard reset of an aborted/committed transaction. This means that it is made ready to be used by another * transaction configuration. */ public abstract void hardReset(); /** * Does a soft reset of an aborted/committed transaction. This method is called when the execution of a transaction * fails, but needs to be retried again. * * @return if another attempt can be made, false otherwise. */ public abstract boolean softReset(); /** * Gets the Tranlocal for a specific AbstractGammaTxnRef. This method doesn't care about the state of a * transaction. * * @param ref the AbstractGammaTxnRef * @return the found Tranlocal or null if not found. */ public abstract Tranlocal getRefTranlocal(BaseGammaTxnRef ref); public final boolean isAlive() { return status == TX_ACTIVE || status == TX_PREPARED; } public final void awaitUpdate() { final long lockEra = retryListener.getEra(); if (config.timeoutNs == Long.MAX_VALUE) { if (config.isInterruptible()) { retryListener.await(lockEra, config.familyName); } else { retryListener.awaitUninterruptible(lockEra); } } else { if (config.isInterruptible()) { remainingTimeoutNs = retryListener.awaitNanos(lockEra, remainingTimeoutNs, config.familyName); } else { remainingTimeoutNs = retryListener.awaitNanosUninterruptible(lockEra, remainingTimeoutNs); } if (remainingTimeoutNs < 0) { throw new RetryTimeoutException( format("[%s] Txn has timed out with a total timeout of %s ns", config.getFamilyName(), config.getTimeoutNs())); } } } public final void copyForSpeculativeFailure(GammaTxn failingTx) { remainingTimeoutNs = failingTx.remainingTimeoutNs; attempt = failingTx.attempt; } public final void init(GammaTxnConfig config) { if (config == null) { throw new NullPointerException(); } this.config = config; hardReset(); } @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) public abstract boolean isReadConsistent(Tranlocal justAdded); public final TxnStatus getStatus() { switch (status) { case TX_ACTIVE: return TxnStatus.Active; case TX_PREPARED: return TxnStatus.Prepared; case TX_COMMITTED: return TxnStatus.Committed; case TX_ABORTED: return TxnStatus.Aborted; default: throw new IllegalStateException(); } } public final boolean skipPrepare() { return config.readLockModeAsInt == LOCKMODE_EXCLUSIVE && !config.dirtyCheck; } /** * Initializes the local conflict counter if the transaction has a need for it. * It should only be initialized if there are no reads. */ public abstract void initLocalConflictCounter(); } GammaTxnConfig.java000066400000000000000000000544251174000617100370360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; import org.multiverse.api.BackoffPolicy; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.api.PropagationLevel; import org.multiverse.api.TraceLevel; import org.multiverse.api.TxnConfig; import org.multiverse.api.exceptions.IllegalTxnFactoryException; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.GlobalConflictCounter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static java.lang.String.format; import static java.util.Collections.EMPTY_LIST; import static java.util.Collections.unmodifiableList; /** * A configuration object that contains the configuration for a GammaTxn. *

* GammaTxnConfig object is considered to be immutable. The only mutable part if the speculative * configuration that can get upgraded if enabled and speculations failed. * * @author Peter Veentjer. */ @SuppressWarnings({"OverlyComplexClass", "ClassWithTooManyFields"}) public final class GammaTxnConfig implements TxnConfig, GammaConstants { public final static AtomicLong idGenerator = new AtomicLong(); public final AtomicReference speculativeConfiguration = new AtomicReference(); public final GammaStm stm; public final GlobalConflictCounter globalConflictCounter; public PropagationLevel propagationLevel; public IsolationLevel isolationLevel; public boolean writeSkewAllowed; public boolean inconsistentReadAllowed; public LockMode readLockMode; public LockMode writeLockMode; public int readLockModeAsInt; public int writeLockModeAsInt; public String familyName; public boolean isAnonymous; public boolean interruptible; public boolean readonly; public int spinCount; public boolean dirtyCheck; public int minimalArrayTreeSize; public boolean trackReads; public boolean blockingAllowed; public int maxRetries; public boolean speculative; public int maxFixedLengthTransactionSize; public BackoffPolicy backoffPolicy; public long timeoutNs; public TraceLevel traceLevel; public boolean controlFlowErrorsReused; public boolean isFat; public int maximumPoorMansConflictScanLength; public ArrayList permanentListeners; public boolean unrepeatableReadAllowed; public GammaTxnConfig(GammaStm stm) { this(stm, new GammaStmConfig()); } public GammaTxnConfig(GammaStm stm, GammaStmConfig config) { this.stm = stm; this.globalConflictCounter = stm.getGlobalConflictCounter(); this.interruptible = config.interruptible; this.readonly = config.readonly; this.spinCount = config.spinCount; this.readLockMode = config.readLockMode; this.readLockModeAsInt = config.readLockMode.asInt(); this.writeLockMode = config.writeLockMode; this.writeLockModeAsInt = config.writeLockMode.asInt(); this.dirtyCheck = config.dirtyCheck; this.minimalArrayTreeSize = config.minimalVariableLengthTransactionSize; this.trackReads = config.trackReads; this.blockingAllowed = config.blockingAllowed; this.maxRetries = config.maxRetries; this.speculative = config.speculativeConfigEnabled; this.maxFixedLengthTransactionSize = config.maxFixedLengthTransactionSize; this.backoffPolicy = config.backoffPolicy; this.timeoutNs = config.timeoutNs; this.traceLevel = config.traceLevel; this.isolationLevel = config.isolationLevel; this.writeSkewAllowed = isolationLevel.doesAllowWriteSkew(); this.inconsistentReadAllowed = isolationLevel.doesAllowInconsistentRead(); this.unrepeatableReadAllowed = isolationLevel.doesAllowUnrepeatableRead(); this.propagationLevel = config.propagationLevel; this.controlFlowErrorsReused = config.controlFlowErrorsReused; this.familyName = "anonymoustransaction-" + idGenerator.incrementAndGet(); this.isAnonymous = true; this.maximumPoorMansConflictScanLength = config.maximumPoorMansConflictScanLength; this.isFat = config.isFat; if (config.permanentListeners.isEmpty()) { this.permanentListeners = null; } else { this.permanentListeners = new ArrayList(config.permanentListeners); } } /** * Makes a clone of the given GammaTxnConfig. * * @param config the GammaTxnConfig to clone. */ private GammaTxnConfig(GammaTxnConfig config) { this.stm = config.stm; this.globalConflictCounter = config.globalConflictCounter; this.propagationLevel = config.propagationLevel; this.isolationLevel = config.isolationLevel; this.writeSkewAllowed = config.writeSkewAllowed; this.inconsistentReadAllowed = config.inconsistentReadAllowed; this.readLockMode = config.readLockMode; this.readLockModeAsInt = config.readLockModeAsInt; this.writeLockMode = config.writeLockMode; this.writeLockModeAsInt = config.writeLockModeAsInt; this.familyName = config.familyName; this.isAnonymous = config.isAnonymous; this.interruptible = config.interruptible; this.readonly = config.readonly; this.spinCount = config.spinCount; this.dirtyCheck = config.dirtyCheck; this.minimalArrayTreeSize = config.minimalArrayTreeSize; this.trackReads = config.trackReads; this.blockingAllowed = config.blockingAllowed; this.maxRetries = config.maxRetries; this.speculative = config.speculative; this.maxFixedLengthTransactionSize = config.maxFixedLengthTransactionSize; this.backoffPolicy = config.backoffPolicy; this.timeoutNs = config.timeoutNs; this.traceLevel = config.traceLevel; this.controlFlowErrorsReused = config.controlFlowErrorsReused; this.isFat = config.isFat; this.maximumPoorMansConflictScanLength = config.maximumPoorMansConflictScanLength; this.permanentListeners = config.permanentListeners; } public GammaTxnConfig(GammaStm stm, int maxFixedLengthTransactionSize) { this(stm); this.maxFixedLengthTransactionSize = maxFixedLengthTransactionSize; } @Override public LockMode getReadLockMode() { return readLockMode; } @Override public LockMode getWriteLockMode() { return writeLockMode; } @Override public IsolationLevel getIsolationLevel() { return isolationLevel; } @Override public boolean isControlFlowErrorsReused() { return controlFlowErrorsReused; } public SpeculativeGammaConfiguration getSpeculativeConfiguration() { return speculativeConfiguration.get(); } @Override public long getTimeoutNs() { return timeoutNs; } @Override public TraceLevel getTraceLevel() { return traceLevel; } @Override public boolean isInterruptible() { return interruptible; } @Override public BackoffPolicy getBackoffPolicy() { return backoffPolicy; } @Override public boolean isSpeculative() { return speculative; } @Override public String getFamilyName() { return familyName; } @Override public boolean isReadonly() { return readonly; } @Override public int getSpinCount() { return spinCount; } @Override public boolean isDirtyCheckEnabled() { return dirtyCheck; } @Override public GammaStm getStm() { return stm; } public GlobalConflictCounter getGlobalConflictCounter() { return globalConflictCounter; } @Override public boolean isReadTrackingEnabled() { return trackReads; } @Override public boolean isBlockingAllowed() { return blockingAllowed; } @Override public int getMaxRetries() { return maxRetries; } @Override public PropagationLevel getPropagationLevel() { return propagationLevel; } @Override public List getPermanentListeners() { if (permanentListeners == null) { return EMPTY_LIST; } return unmodifiableList(permanentListeners); } public void updateSpeculativeConfigurationToUseNonRefType() { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration update = current.newWithNonRefType(); if (speculativeConfiguration.compareAndSet(current, update)) { return; } } } public void updateSpeculativeConfigurationToUseListeners() { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration update = current.newWithListeners(); if (speculativeConfiguration.compareAndSet(current, update)) { return; } } } public void updateSpeculativeConfigureToUseAbortOnly() { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration update = current.newWithAbortOnly(); if (speculativeConfiguration.compareAndSet(current, update)) { return; } } } public void updateSpeculativeConfigurationToUseCommute() { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration update = current.newWithCommute(); if (speculativeConfiguration.compareAndSet(current, update)) { return; } } } public void updateSpeculativeConfigurationToUseExplicitLocking() { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration update = current.newWithLocks(); if (speculativeConfiguration.compareAndSet(current, update)) { return; } } } public void updateSpeculativeConfigurationToUseConstructedObjects() { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration next = current.newWithConstructedObjects(); if (speculativeConfiguration.compareAndSet(current, next)) { return; } } } public void updateSpeculativeConfigurationToUseRichMansConflictScan() { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration next = current.newWithRichMansConflictScan(); if (speculativeConfiguration.compareAndSet(current, next)) { return; } } } public void updateSpeculativeConfigurationToUseMinimalTransactionLength(int newLength) { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration next = current.newWithMinimalLength(newLength); if (speculativeConfiguration.compareAndSet(current, next)) { return; } } } public void updateSpeculativeConfigurationToUseEnsure() { while (true) { SpeculativeGammaConfiguration current = speculativeConfiguration.get(); SpeculativeGammaConfiguration next = current.newWithEnsure(); if (speculativeConfiguration.compareAndSet(current, next)) { return; } } } public GammaTxnConfig init() { if (!writeSkewAllowed && !trackReads && !readonly) { String msg = format("'[%s] If no writeskew is allowed, read tracking should be enabled", familyName); throw new IllegalTxnFactoryException(msg); } if (blockingAllowed && !trackReads) { String msg = format("[%s] If blocking is allowed, read tracking should be enabled", familyName); throw new IllegalTxnFactoryException(msg); } if (readLockModeAsInt > writeLockModeAsInt) { String msg = format("[%s] The used write LockMode [%s] should be equal or higher than the read LockMode [%s]", familyName, readLockMode, writeLockMode); throw new IllegalTxnFactoryException(msg); } if (readLockMode != LockMode.None && !trackReads) { String msg = format("[%s] If readLockMode is [%s] , read tracking should be enabled", familyName, readLockMode); throw new IllegalTxnFactoryException(msg); } if (speculativeConfiguration.get() == null) { SpeculativeGammaConfiguration newSpeculativeConfiguration; if (speculative) { newSpeculativeConfiguration = new SpeculativeGammaConfiguration( isFat(), false, false, false, false, false, false, false, false, false, 1); } else { newSpeculativeConfiguration = new SpeculativeGammaConfiguration( true, true, true, true, true, true, true, true, true, true, Integer.MAX_VALUE); } if (maximumPoorMansConflictScanLength == 0) { newSpeculativeConfiguration = newSpeculativeConfiguration.newWithRichMansConflictScan(); } speculativeConfiguration.compareAndSet(null, newSpeculativeConfiguration); } return this; } private boolean isFat() { if (isFat) { return true; } if (isolationLevel != IsolationLevel.Snapshot) { return true; } if (permanentListeners != null) { return true; } if (readLockMode != LockMode.None) { return true; } if (writeLockMode != LockMode.None) { return true; } if (dirtyCheck) { return true; } if (readonly) { return true; } return false; } public GammaTxnConfig setTimeoutNs(long timeoutNs) { if (timeoutNs < 0) { throw new IllegalArgumentException("timeoutNs can't be smaller than 0"); } GammaTxnConfig config = new GammaTxnConfig(this); config.timeoutNs = timeoutNs; return config; } public GammaTxnConfig setFamilyName(String familyName) { if (familyName == null) { throw new NullPointerException("familyName can't be null"); } GammaTxnConfig config = new GammaTxnConfig(this); config.isAnonymous = false; config.familyName = familyName; return config; } public GammaTxnConfig setMaxRetries(int maxRetries) { if (maxRetries < 0) { throw new IllegalArgumentException("maxRetries can't be smaller than 0"); } GammaTxnConfig config = new GammaTxnConfig(this); config.maxRetries = maxRetries; return config; } public GammaTxnConfig setMaximumPoorMansConflictScanLength(int maximumPoorMansConflictScanLength) { if (maximumPoorMansConflictScanLength < 0) { throw new IllegalStateException(); } GammaTxnConfig config = new GammaTxnConfig(this); config.maximumPoorMansConflictScanLength = maximumPoorMansConflictScanLength; return config; } public GammaTxnConfig setReadTrackingEnabled(boolean trackReads) { GammaTxnConfig config = new GammaTxnConfig(this); config.trackReads = trackReads; return config; } public GammaTxnConfig setSpeculative(boolean speculativeConfigEnabled) { GammaTxnConfig config = new GammaTxnConfig(this); config.speculative = speculativeConfigEnabled; return config; } public GammaTxnConfig setReadonly(boolean readonly) { GammaTxnConfig config = new GammaTxnConfig(this); config.readonly = readonly; return config; } public GammaTxnConfig setDirtyCheckEnabled(boolean dirtyCheck) { GammaTxnConfig config = new GammaTxnConfig(this); config.dirtyCheck = dirtyCheck; return config; } public GammaTxnConfig setBlockingAllowed(boolean blockingAllowed) { GammaTxnConfig config = new GammaTxnConfig(this); config.blockingAllowed = blockingAllowed; return config; } public GammaTxnConfig setInterruptible(boolean interruptible) { GammaTxnConfig config = new GammaTxnConfig(this); config.interruptible = interruptible; return config; } public GammaTxnConfig setControlFlowErrorsReused(boolean controlFlowErrorsReused) { GammaTxnConfig config = new GammaTxnConfig(this); config.controlFlowErrorsReused = controlFlowErrorsReused; return config; } public GammaTxnConfig setSpinCount(int spinCount) { if (spinCount < 0) { throw new IllegalArgumentException("spinCount can't be smaller than 0"); } GammaTxnConfig config = new GammaTxnConfig(this); config.spinCount = spinCount; return config; } public GammaTxnConfig setBackoffPolicy(BackoffPolicy backoffPolicy) { if (backoffPolicy == null) { throw new NullPointerException("backoffPolicy can't be null"); } GammaTxnConfig config = new GammaTxnConfig(this); config.backoffPolicy = backoffPolicy; return config; } public GammaTxnConfig setTraceLevel(TraceLevel traceLevel) { if (traceLevel == null) { throw new NullPointerException("traceLevel can't be null"); } GammaTxnConfig config = new GammaTxnConfig(this); config.traceLevel = traceLevel; return config; } public GammaTxnConfig setPropagationLevel(PropagationLevel propagationLevel) { if (propagationLevel == null) { throw new NullPointerException(); } GammaTxnConfig config = new GammaTxnConfig(this); config.propagationLevel = propagationLevel; return config; } public GammaTxnConfig setIsolationLevel(IsolationLevel isolationLevel) { if (isolationLevel == null) { throw new NullPointerException(); } GammaTxnConfig config = new GammaTxnConfig(this); config.isolationLevel = isolationLevel; config.writeSkewAllowed = isolationLevel.doesAllowWriteSkew(); config.inconsistentReadAllowed = isolationLevel.doesAllowInconsistentRead(); config.unrepeatableReadAllowed = isolationLevel.doesAllowUnrepeatableRead(); return config; } public GammaTxnConfig setWriteLockMode(LockMode writeLockMode) { if (writeLockMode == null) { throw new NullPointerException(); } GammaTxnConfig config = new GammaTxnConfig(this); config.writeLockMode = writeLockMode; config.writeLockModeAsInt = writeLockMode.asInt(); return config; } public GammaTxnConfig setReadLockMode(LockMode readLockMode) { if (readLockMode == null) { throw new NullPointerException(); } GammaTxnConfig config = new GammaTxnConfig(this); config.readLockMode = readLockMode; config.readLockModeAsInt = readLockMode.asInt(); if (config.readLockModeAsInt > config.writeLockModeAsInt) { config.writeLockMode = config.readLockMode; config.writeLockModeAsInt = config.readLockModeAsInt; } return config; } public GammaTxnConfig setFat() { GammaTxnConfig config = new GammaTxnConfig(this); config.isFat = true; return config; } public GammaTxnConfig addPermanentListener(TxnListener listener) { if (listener == null) { throw new NullPointerException(); } //we need to clone the list since the GammaTxnConfig is considered to be immutable ArrayList newPermanentListeners = new ArrayList(); if (permanentListeners != null) { newPermanentListeners.addAll(permanentListeners); } newPermanentListeners.add(listener); GammaTxnConfig config = new GammaTxnConfig(this); config.permanentListeners = newPermanentListeners; return config; } @Override public String toString() { return "GammaTxnConfig{" + "speculativeConfiguration=" + speculativeConfiguration + ", globalConflictCounter=" + globalConflictCounter + ", propagationLevel=" + propagationLevel + ", isolationLevel=" + isolationLevel + ", writeSkewAllowed=" + writeSkewAllowed + ", inconsistentReadAllowed=" + inconsistentReadAllowed + ", readLockMode=" + readLockMode + ", writeLockMode=" + writeLockMode + ", readLockModeAsInt=" + readLockModeAsInt + ", writeLockModeAsInt=" + writeLockModeAsInt + ", familyName='" + familyName + '\'' + ", isAnonymous=" + isAnonymous + ", interruptible=" + interruptible + ", readonly=" + readonly + ", spinCount=" + spinCount + ", dirtyCheck=" + dirtyCheck + ", minimalArrayTreeSize=" + minimalArrayTreeSize + ", trackReads=" + trackReads + ", blockingAllowed=" + blockingAllowed + ", maxRetries=" + maxRetries + ", speculativeConfigEnabled=" + speculative + ", maxFixedLengthTransactionSize=" + maxFixedLengthTransactionSize + ", backoffPolicy=" + backoffPolicy + ", timeoutNs=" + timeoutNs + ", traceLevel=" + traceLevel + ", controlFlowErrorsReused=" + controlFlowErrorsReused + ", isFat=" + isFat + ", maximumPoorMansConflictScanLength=" + maximumPoorMansConflictScanLength + ", permanentListeners=" + permanentListeners + '}'; } } GammaTxnFactory.java000066400000000000000000000007621174000617100372330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; import org.multiverse.api.TxnFactory; /** * A {@link org.multiverse.api.TxnFactory} tailored for the {@link org.multiverse.stms.gamma.GammaStm}. * * @author Peter Veentjer. */ public interface GammaTxnFactory extends TxnFactory { @Override GammaTxnConfig getConfig(); @Override GammaTxn newTxn(); GammaTxn newTransaction(GammaTxnPool pool); GammaTxn upgradeAfterSpeculativeFailure(GammaTxn tx, GammaTxnPool pool); } GammaTxnFactoryBuilder.java000066400000000000000000000041021174000617100405320ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; import org.multiverse.api.*; import org.multiverse.api.TxnFactoryBuilder; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaTxnExecutor; /** * A {@link org.multiverse.api.TxnFactoryBuilder} tailored for the {@link org.multiverse.stms.gamma.GammaStm}. * * @author Peter Veentjer. */ public interface GammaTxnFactoryBuilder extends TxnFactoryBuilder { @Override GammaTxnConfig getConfig(); GammaTxnFactoryBuilder setFat(); @Override GammaTxnFactoryBuilder setControlFlowErrorsReused(boolean reused); @Override GammaTxnFactoryBuilder setReadLockMode(LockMode lockMode); @Override GammaTxnFactoryBuilder setWriteLockMode(LockMode lockMode); @Override GammaTxnFactoryBuilder setFamilyName(String familyName); @Override GammaTxnFactoryBuilder setPropagationLevel(PropagationLevel propagationLevel); @Override GammaTxnFactoryBuilder addPermanentListener(TxnListener listener); @Override GammaTxnFactoryBuilder setTraceLevel(TraceLevel traceLevel); @Override GammaTxnFactoryBuilder setTimeoutNs(long timeoutNs); @Override GammaTxnFactoryBuilder setInterruptible(boolean interruptible); @Override GammaTxnFactoryBuilder setBackoffPolicy(BackoffPolicy backoffPolicy); @Override GammaTxnFactoryBuilder setDirtyCheckEnabled(boolean dirtyCheckEnabled); @Override GammaTxnFactoryBuilder setSpinCount(int spinCount); @Override GammaTxnFactoryBuilder setReadonly(boolean readonly); @Override GammaTxnFactoryBuilder setReadTrackingEnabled(boolean enabled); @Override GammaTxnFactoryBuilder setSpeculative(boolean enabled); @Override GammaTxnFactoryBuilder setMaxRetries(int maxRetries); @Override GammaTxnFactoryBuilder setIsolationLevel(IsolationLevel isolationLevel); @Override GammaTxnFactoryBuilder setBlockingAllowed(boolean blockingAllowed); @Override GammaTxnFactory newTransactionFactory(); @Override GammaTxnExecutor newTxnExecutor(); } GammaTxnPool.java000066400000000000000000000133631174000617100365360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; /** * A pool for pooling GammaTxns. * * @author Peter Veentjer. */ @SuppressWarnings({"ClassWithTooManyFields"}) public final class GammaTxnPool implements GammaConstants { private final static boolean ENABLED = Boolean.parseBoolean( System.getProperty("org.multiverse.stm.gamma.transactions.GammaTxnPool.enabled", "true")); private final boolean enabled; private final FatMonoGammaTxn[] poolFatMono = new FatMonoGammaTxn[10]; private int poolFatMonoIndex = -1; private final FatFixedLengthGammaTxn[] poolFatFixedLength = new FatFixedLengthGammaTxn[10]; private int poolFatFixedLengthIndex = -1; private final LeanMonoGammaTxn[] poolLeanMono = new LeanMonoGammaTxn[10]; private int poolLeanMonoIndex = -1; private final LeanFixedLengthGammaTxn[] poolLeanFixedLength = new LeanFixedLengthGammaTxn[10]; private int poolLeanFixedLengthIndex = -1; private final FatVariableLengthGammaTxn[] poolFatVariableLength = new FatVariableLengthGammaTxn[10]; private int poolFatVariableLengthIndex = -1; public GammaTxnPool() { enabled = ENABLED; } /** * Takes a FatMonoGammaTxn from the pool. * * @return the taken FatMonoGammaTxn or null of none available. */ public FatMonoGammaTxn takeFatMono() { if (!enabled || poolFatMonoIndex == -1) { return null; } FatMonoGammaTxn tx = poolFatMono[poolFatMonoIndex]; poolFatMono[poolFatMonoIndex] = null; poolFatMonoIndex--; return tx; } /** * Takes a FatArrayGammaTxn from the pool. * * @return the taken FatArrayGammaTxn or null of none available. */ public FatFixedLengthGammaTxn takeFatFixedLength() { if (!enabled || poolFatFixedLengthIndex == -1) { return null; } FatFixedLengthGammaTxn tx = poolFatFixedLength[poolFatFixedLengthIndex]; poolFatFixedLength[poolFatFixedLengthIndex] = null; poolFatFixedLengthIndex--; return tx; } /** * Takes a FatMonoGammaTxn from the pool. * * @return the taken FatMonoGammaTxn or null of none available. */ public LeanMonoGammaTxn takeLeanMono() { if (!enabled || poolLeanMonoIndex == -1) { return null; } LeanMonoGammaTxn tx = poolLeanMono[poolLeanMonoIndex]; poolLeanMono[poolLeanMonoIndex] = null; poolLeanMonoIndex--; return tx; } /** * Takes a FatArrayGammaTxn from the pool. * * @return the taken FatArrayGammaTxn or null of none available. */ public LeanFixedLengthGammaTxn takeLeanFixedLength() { if (!enabled || poolLeanFixedLengthIndex == -1) { return null; } LeanFixedLengthGammaTxn tx = poolLeanFixedLength[poolLeanFixedLengthIndex]; poolLeanFixedLength[poolLeanFixedLengthIndex] = null; poolLeanFixedLengthIndex--; return tx; } /** * Takes a FatArrayTreeGammaTxn from the pool. * * @return the taken FatArrayTreeGammaTxn or null of none available. */ public FatVariableLengthGammaTxn takeMap() { if (!enabled || poolFatVariableLengthIndex == -1) { return null; } FatVariableLengthGammaTxn tx = poolFatVariableLength[poolFatVariableLengthIndex]; poolFatVariableLength[poolFatVariableLengthIndex] = null; poolFatVariableLengthIndex--; return tx; } /** * Puts a GammaTxn in the pool. * * @param tx the GammaTxn to put in the pool. * @throws NullPointerException if tx is null. */ public void put(GammaTxn tx) { if (!enabled) { return; } final int type = tx.transactionType; if (type == TRANSACTIONTYPE_FAT_MONO) { if (poolFatMonoIndex == poolFatMono.length - 1) { return; } poolFatMonoIndex++; poolFatMono[poolFatMonoIndex] = (FatMonoGammaTxn) tx; return; } if (type == TRANSACTIONTYPE_FAT_FIXED_LENGTH) { if (poolFatFixedLengthIndex == poolFatFixedLength.length - 1) { return; } poolFatFixedLengthIndex++; poolFatFixedLength[poolFatFixedLengthIndex] = (FatFixedLengthGammaTxn) tx; return; } if (type == TRANSACTIONTYPE_LEAN_MONO) { if (poolLeanMonoIndex == poolLeanMono.length - 1) { return; } poolLeanMonoIndex++; poolLeanMono[poolLeanMonoIndex] = (LeanMonoGammaTxn) tx; return; } if (type == TRANSACTIONTYPE_LEAN_FIXED_LENGTH) { if (poolLeanFixedLengthIndex == poolLeanFixedLength.length - 1) { return; } poolLeanFixedLengthIndex++; poolLeanFixedLength[poolLeanFixedLengthIndex] = (LeanFixedLengthGammaTxn) tx; return; } if (type == TRANSACTIONTYPE_FAT_VARIABLE_LENGTH) { if (poolFatVariableLengthIndex == poolFatVariableLength.length - 1) { return; } poolFatVariableLengthIndex++; poolFatVariableLength[poolFatVariableLengthIndex] = (FatVariableLengthGammaTxn) tx; return; } throw new IllegalArgumentException(); } } SpeculativeGammaConfiguration.java000066400000000000000000000163321174000617100421460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; /** * The GammaStm uses a speculative mechanism (if enabled) to learn from executing transactions. Transactions start * cheap and with a lot of features disabled, but once the speculation failed, the SpeculativeGammaConfguration * is 'updated'. *

* This class is immutable. * * @author Peter Veentjer. */ @SuppressWarnings({"ClassWithTooManyFields"}) public final class SpeculativeGammaConfiguration { public final boolean listenersDetected; public final boolean commuteDetected; public final boolean orelseDetected; public final boolean nonRefTypeDetected; public final boolean fat; public final boolean locksDetected; public final boolean constructedObjectsDetected; public final boolean richMansConflictScanRequired; public final boolean abortOnlyDetected; public final boolean ensureDetected; public final int minimalLength; /** * Creates a full speculative SpeculativeGammaConfiguration. */ public SpeculativeGammaConfiguration() { this(false, false, false, false, false, false, false, false, false, false, 1); } public SpeculativeGammaConfiguration( final boolean isFat, final boolean listenersDetected, final boolean isCommuteDetected, final boolean isNonRefTypeDetected, final boolean isOrelseDetected, final boolean locksDetected, final boolean constructedObjectsDetected, final boolean isRichMansConflictScanRequired, final boolean isAbortOnlyDetected, final boolean ensureDetected, final int minimalLength) { if (minimalLength < 0) { throw new IllegalArgumentException(); } this.fat = isFat; this.constructedObjectsDetected = constructedObjectsDetected; this.listenersDetected = listenersDetected; this.locksDetected = locksDetected; this.commuteDetected = isCommuteDetected; this.richMansConflictScanRequired = isRichMansConflictScanRequired; this.nonRefTypeDetected = isNonRefTypeDetected; this.orelseDetected = isOrelseDetected; this.minimalLength = minimalLength; this.abortOnlyDetected = isAbortOnlyDetected; this.ensureDetected = ensureDetected; } public SpeculativeGammaConfiguration newWithMinimalLength(int newMinimalLength) { if (newMinimalLength < 0) { throw new IllegalArgumentException(); } if (minimalLength >= newMinimalLength) { return this; } return new SpeculativeGammaConfiguration( fat, listenersDetected, commuteDetected, nonRefTypeDetected, orelseDetected, locksDetected, constructedObjectsDetected, richMansConflictScanRequired, abortOnlyDetected, ensureDetected, newMinimalLength); } public SpeculativeGammaConfiguration newWithLocks() { if (locksDetected) { return this; } return new SpeculativeGammaConfiguration( true, listenersDetected, commuteDetected, nonRefTypeDetected, orelseDetected, true, constructedObjectsDetected, richMansConflictScanRequired, abortOnlyDetected, ensureDetected, minimalLength); } public SpeculativeGammaConfiguration newWithAbortOnly() { if (abortOnlyDetected) { return this; } return new SpeculativeGammaConfiguration( true, listenersDetected, commuteDetected, nonRefTypeDetected, orelseDetected, locksDetected, constructedObjectsDetected, richMansConflictScanRequired, true, ensureDetected, minimalLength); } public SpeculativeGammaConfiguration newWithConstructedObjects() { if (constructedObjectsDetected) { return this; } return new SpeculativeGammaConfiguration( true, listenersDetected, commuteDetected, nonRefTypeDetected, orelseDetected, locksDetected, true, richMansConflictScanRequired, abortOnlyDetected, ensureDetected, minimalLength); } public SpeculativeGammaConfiguration newWithListeners() { if (listenersDetected) { return this; } return new SpeculativeGammaConfiguration( true, true, commuteDetected, nonRefTypeDetected, orelseDetected, locksDetected, constructedObjectsDetected, richMansConflictScanRequired, abortOnlyDetected, ensureDetected, minimalLength); } public SpeculativeGammaConfiguration newWithOrElse() { if (orelseDetected) { return this; } return new SpeculativeGammaConfiguration( true, listenersDetected, commuteDetected, nonRefTypeDetected, true, locksDetected, constructedObjectsDetected, richMansConflictScanRequired, abortOnlyDetected, ensureDetected, minimalLength); } public SpeculativeGammaConfiguration newWithNonRefType() { if (nonRefTypeDetected) { return this; } return new SpeculativeGammaConfiguration( true, listenersDetected, commuteDetected, true, orelseDetected, locksDetected, constructedObjectsDetected, richMansConflictScanRequired, abortOnlyDetected, ensureDetected, minimalLength); } public SpeculativeGammaConfiguration newWithCommute() { if (commuteDetected) { return this; } return new SpeculativeGammaConfiguration( true, listenersDetected, true, nonRefTypeDetected, orelseDetected, locksDetected, constructedObjectsDetected, richMansConflictScanRequired, abortOnlyDetected, ensureDetected, minimalLength); } public SpeculativeGammaConfiguration newWithRichMansConflictScan() { if (richMansConflictScanRequired) { return this; } return new SpeculativeGammaConfiguration( true, listenersDetected, commuteDetected, nonRefTypeDetected, orelseDetected, locksDetected, constructedObjectsDetected, true, abortOnlyDetected, ensureDetected, minimalLength); } public SpeculativeGammaConfiguration newWithEnsure() { if (ensureDetected) { return this; } return new SpeculativeGammaConfiguration( true, listenersDetected, commuteDetected, nonRefTypeDetected, orelseDetected, locksDetected, constructedObjectsDetected, true, abortOnlyDetected, true, minimalLength); } @Override public String toString() { return "SpeculativeGammaConfiguration{" + " isFat=" + fat + ", listenersDetected=" + listenersDetected + ", commuteDetected=" + commuteDetected + ", nonRefTypeDetected=" + nonRefTypeDetected + ", locksDetected=" + locksDetected + ", orelseDetected=" + orelseDetected + ", minimalLength=" + minimalLength + ", richMansConflictScanDetected=" + richMansConflictScanRequired + ", constructedObjectsDetected=" + constructedObjectsDetected + ", abortOnlyDetected=" + abortOnlyDetected + ", ensureDetected=" + ensureDetected + '}'; } } ThreadLocalGammaTxnPool.java000066400000000000000000000014201174000617100406300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; /** * A ThreadLocal that stores the {@link GammaTxnPool}. * * @author Peter Veentjer. */ public final class ThreadLocalGammaTxnPool { private final static ThreadLocal threadlocal = new ThreadLocal() { @Override protected GammaTxnPool initialValue() { return new GammaTxnPool(); } }; /** * Returns the GammaTxnalPool stored in the ThreadLocalGammaTxnPool. If no instance exists, * a new instance is created. * * @return the GammaTxnPool. */ public static GammaTxnPool getThreadLocalGammaTxnPool() { return threadlocal.get(); } //we don't want any instances. private ThreadLocalGammaTxnPool() { } } 000077500000000000000000000000001174000617100340715ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactions/fatFatFixedLengthGammaTxn.java000066400000000000000000000251051174000617100412300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.GammaObject; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.multiverse.utils.Bugshaker.shakeBugs; /** * A Fat {@link org.multiverse.stms.gamma.transactions.GammaTxn} (supporting all features) but has a fixed capacity. * * @author Peter Veentjer. */ public final class FatFixedLengthGammaTxn extends GammaTxn { public Tranlocal head; public int size = 0; public boolean hasReads = false; public long localConflictCount; public final Listeners[] listenersArray; public FatFixedLengthGammaTxn(final GammaStm stm) { this(new GammaTxnConfig(stm)); } @SuppressWarnings({"ObjectAllocationInLoop"}) public FatFixedLengthGammaTxn(final GammaTxnConfig config) { super(config, TRANSACTIONTYPE_FAT_FIXED_LENGTH); listenersArray = new Listeners[config.maxFixedLengthTransactionSize]; Tranlocal h = null; for (int k = 0; k < config.maxFixedLengthTransactionSize; k++) { Tranlocal newNode = new Tranlocal(); if (h != null) { h.previous = newNode; newNode.next = h; } h = newNode; } head = h; } @Override public final void commit() { if (status == TX_COMMITTED) { return; } if (status != TX_ACTIVE && status != TX_PREPARED) { throw abortCommitOnBadStatus(); } if (abortOnly) { throw abortCommitOnAbortOnly(); } if (status == TX_ACTIVE) { notifyListeners(TxnEvent.PrePrepare); } if (size > 0) { if (hasWrites) { if (status == TX_ACTIVE) { GammaObject o = prepareChainForCommit(); if (o != null) { throw abortOnReadWriteConflict(o); } } if (commitConflict) { config.globalConflictCounter.signalConflict(); } final Listeners[] listenersArray = commitChain(); if (listenersArray != null) { Listeners.openAll(listenersArray, pool); } } else { releaseChain(true); } } status = TX_COMMITTED; notifyListeners(TxnEvent.PostCommit); } private Listeners[] commitChain() { int listenersIndex = 0; Tranlocal node = head; do { if (SHAKE_BUGS) shakeBugs(); final BaseGammaTxnRef owner = node.owner; //if we are at the end, we can return the listenersArray. if (owner == null) { return listenersArray; } final Listeners listeners = owner.commit(node, pool); if (listeners != null) { listenersArray[listenersIndex] = listeners; listenersIndex++; } node = node.next; } while (node != null); return listenersArray; } @Override public final void prepare() { if (status == TX_PREPARED) { return; } if (status != TX_ACTIVE) { throw abortPrepareOnBadStatus(); } if (abortOnly) { throw abortPrepareOnAbortOnly(); } notifyListeners(TxnEvent.PrePrepare); GammaObject o = prepareChainForCommit(); if (o != null) { throw abortOnReadWriteConflict(o); } status = TX_PREPARED; } @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) private BaseGammaTxnRef prepareChainForCommit() { if (skipPrepare()) { return null; } Tranlocal node = head; do { final BaseGammaTxnRef owner = node.owner; if (owner == null) { return null; } if (SHAKE_BUGS) shakeBugs(); if (!owner.prepare(this, node)) { return owner; } node = node.next; } while (node != null); return null; } @Override public final void abort() { if (status == TX_ABORTED) { return; } if (status == TX_COMMITTED) { throw failAbortOnAlreadyCommitted(); } releaseChain(false); status = TX_ABORTED; notifyListeners(TxnEvent.PostAbort); } private void releaseChain(final boolean success) { Tranlocal node = head; while (node != null) { final BaseGammaTxnRef owner = node.owner; if (owner == null) { return; } if (SHAKE_BUGS) shakeBugs(); if (success) { owner.releaseAfterReading(node, pool); } else { owner.releaseAfterFailure(node, pool); } node = node.next; } } @Override public final Tranlocal getRefTranlocal(final BaseGammaTxnRef ref) { Tranlocal node = head; while (node != null) { //noinspection ObjectEquality if (node.owner == ref) { return node; } if (node.owner == null) { return null; } node = node.next; } return null; } @Override public final void retry() { if (status != TX_ACTIVE) { throw abortRetryOnBadStatus(); } if (!config.isBlockingAllowed()) { throw abortRetryOnNoBlockingAllowed(); } if (size == 0) { throw abortRetryOnNoRetryPossible(); } retryListener.reset(); final long listenerEra = retryListener.getEra(); boolean furtherRegistrationNeeded = true; boolean atLeastOneRegistration = false; Tranlocal tranlocal = head; do { final BaseGammaTxnRef owner = tranlocal.owner; if (furtherRegistrationNeeded) { switch (owner.registerChangeListener(retryListener, tranlocal, pool, listenerEra)) { case REGISTRATION_DONE: atLeastOneRegistration = true; break; case REGISTRATION_NOT_NEEDED: furtherRegistrationNeeded = false; atLeastOneRegistration = true; break; case REGISTRATION_NONE: break; default: throw new IllegalStateException(); } } owner.releaseAfterFailure(tranlocal, pool); tranlocal = tranlocal.next; } while (tranlocal != null && tranlocal.owner != null); status = TX_ABORTED; if (!atLeastOneRegistration) { throw abortRetryOnNoRetryPossible(); } throw newRetryError(); } @Override public final Tranlocal locate(BaseGammaTxnRef o) { if (status != TX_ACTIVE) { throw abortLocateOnBadStatus(o); } if (o == null) { throw abortLocateOnNullArgument(); } return getRefTranlocal(o); } @Override public final void hardReset() { if (listeners != null) { listeners.clear(); pool.putArrayList(listeners); listeners = null; } status = TX_ACTIVE; hasWrites = false; size = 0; remainingTimeoutNs = config.timeoutNs; richmansMansConflictScan = config.speculativeConfiguration.get().richMansConflictScanRequired; attempt = 1; hasReads = false; abortOnly = false; commitConflict = false; evaluatingCommute = false; } @Override public final boolean softReset() { if (attempt >= config.getMaxRetries()) { return false; } if (listeners != null) { listeners.clear(); pool.putArrayList(listeners); listeners = null; } commitConflict = false; status = TX_ACTIVE; hasWrites = false; size = 0; hasReads = false; abortOnly = false; attempt++; evaluatingCommute = false; return true; } public final void shiftInFront(Tranlocal newHead) { //noinspection ObjectEquality if (newHead == head) { return; } head.previous = newHead; if (newHead.next != null) { newHead.next.previous = newHead.previous; } newHead.previous.next = newHead.next; newHead.next = head; newHead.previous = null; head = newHead; } @Override public final boolean isReadConsistent(Tranlocal justAdded) { if (!hasReads) { return true; } if (config.readLockModeAsInt > LOCKMODE_NONE) { return true; } if (config.inconsistentReadAllowed) { return true; } if (richmansMansConflictScan) { if (SHAKE_BUGS) shakeBugs(); final long currentConflictCount = config.globalConflictCounter.count(); if (localConflictCount == currentConflictCount) { return true; } localConflictCount = currentConflictCount; //we are going to fall through to do a full conflict scan } else if (size > config.maximumPoorMansConflictScanLength) { throw abortOnRichmanConflictScanDetected(); } //doing a full conflict scan Tranlocal node = head; while (node != null) { if (SHAKE_BUGS) shakeBugs(); //if we are at the end, we are done. if (node.owner == null) { break; } final boolean skip = !richmansMansConflictScan && node == justAdded; if (!skip && node.owner.hasReadConflict(node)) { return false; } node = node.next; } return true; } @Override public void initLocalConflictCounter() { if (richmansMansConflictScan && !hasReads) { localConflictCount = config.globalConflictCounter.count(); } } } FatMonoGammaTxn.java000066400000000000000000000135551174000617100377450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public final class FatMonoGammaTxn extends GammaTxn { public final Tranlocal tranlocal = new Tranlocal(); public FatMonoGammaTxn(GammaStm stm) { this(new GammaTxnConfig(stm)); } public FatMonoGammaTxn(GammaTxnConfig config) { super(config, TRANSACTIONTYPE_FAT_MONO); richmansMansConflictScan = false; } @Override public final Tranlocal locate(BaseGammaTxnRef o) { if (status != TX_ACTIVE) { throw abortLocateOnBadStatus(o); } if (o == null) { throw abortLocateOnNullArgument(); } return getRefTranlocal(o); } @Override public final void commit() { if (status == TX_COMMITTED) { return; } if (status != TX_ACTIVE && status != TX_PREPARED) { throw abortCommitOnBadStatus(); } if (abortOnly) { throw abortCommitOnAbortOnly(); } if (status == TX_ACTIVE) { notifyListeners(TxnEvent.PrePrepare); } final BaseGammaTxnRef owner = tranlocal.owner; if (owner != null) { if (hasWrites) { if (status == TX_ACTIVE) { if (!skipPrepare()) { if (!owner.prepare(this, tranlocal)) { throw abortOnReadWriteConflict(owner); } } } if (commitConflict) { config.globalConflictCounter.signalConflict(); } Listeners listeners = owner.commit(tranlocal, pool); if (listeners != null) { listeners.openAll(pool); } } else { owner.releaseAfterReading(tranlocal, pool); } } tranlocal.owner = null; status = TX_COMMITTED; notifyListeners(TxnEvent.PostCommit); } @Override public final void abort() { if (status == TX_ABORTED) { return; } if (status == TX_COMMITTED) { throw failAbortOnAlreadyCommitted(); } status = TX_ABORTED; BaseGammaTxnRef owner = tranlocal.owner; if (owner != null) { owner.releaseAfterFailure(tranlocal, pool); } notifyListeners(TxnEvent.PostAbort); } @Override public final void prepare() { if (status == TX_PREPARED) { return; } if (status != TX_ACTIVE) { throw abortPrepareOnBadStatus(); } if (abortOnly) { throw abortPrepareOnAbortOnly(); } notifyListeners(TxnEvent.PrePrepare); final BaseGammaTxnRef owner = tranlocal.owner; if (owner != null) { if (!owner.prepare(this, tranlocal)) { throw abortOnReadWriteConflict(owner); } } status = TX_PREPARED; } @Override public final Tranlocal getRefTranlocal(BaseGammaTxnRef ref) { //noinspection ObjectEquality return tranlocal.owner == ref ? tranlocal : null; } @Override public final void retry() { if (status != TX_ACTIVE) { throw abortRetryOnBadStatus(); } if (!config.isBlockingAllowed()) { throw abortRetryOnNoBlockingAllowed(); } if (tranlocal == null) { throw abortRetryOnNoRetryPossible(); } final BaseGammaTxnRef owner = tranlocal.owner; if (owner == null) { throw abortRetryOnNoRetryPossible(); } retryListener.reset(); final long listenerEra = retryListener.getEra(); boolean atLeastOneRegistration = false; switch (tranlocal.owner.registerChangeListener(retryListener, tranlocal, pool, listenerEra)) { case REGISTRATION_DONE: atLeastOneRegistration = true; break; case REGISTRATION_NOT_NEEDED: atLeastOneRegistration = true; break; case REGISTRATION_NONE: break; default: throw new IllegalStateException(); } owner.releaseAfterFailure(tranlocal, pool); status = TX_ABORTED; if (!atLeastOneRegistration) { throw abortRetryOnNoRetryPossible(); } throw newRetryError(); } @Override public final boolean softReset() { if (attempt >= config.getMaxRetries()) { return false; } if (listeners != null) { listeners.clear(); pool.putArrayList(listeners); listeners = null; } status = TX_ACTIVE; hasWrites = false; attempt++; abortOnly = false; commitConflict = false; evaluatingCommute = false; return true; } @Override public final void hardReset() { if (listeners != null) { listeners.clear(); pool.putArrayList(listeners); listeners = null; } status = TX_ACTIVE; hasWrites = false; remainingTimeoutNs = config.timeoutNs; attempt = 1; abortOnly = false; commitConflict = false; evaluatingCommute = false; } @Override public final boolean isReadConsistent(Tranlocal justAdded) { return true; } @Override public void initLocalConflictCounter() { //ignore } } FatVariableLengthGammaTxn.java000066400000000000000000000305671174000617100417260ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.GammaObject; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.SpeculativeGammaConfiguration; import static org.multiverse.utils.Bugshaker.shakeBugs; @SuppressWarnings({"OverlyComplexClass"}) public final class FatVariableLengthGammaTxn extends GammaTxn { public Tranlocal[] array; public int size = 0; public boolean hasReads = false; public long localConflictCount; public FatVariableLengthGammaTxn(GammaStm stm) { this(new GammaTxnConfig(stm)); } public FatVariableLengthGammaTxn(GammaTxnConfig config) { super(config, TRANSACTIONTYPE_FAT_VARIABLE_LENGTH); this.array = new Tranlocal[config.minimalArrayTreeSize]; } @Override public final void commit() { if (status == TX_COMMITTED) { return; } if (status != TX_ACTIVE && status != TX_PREPARED) { throw abortCommitOnBadStatus(); } if (abortOnly) { throw abortCommitOnAbortOnly(); } if (status == TX_ACTIVE) { notifyListeners(TxnEvent.PrePrepare); } if (size > 0) { if (hasWrites) { if (status == TX_ACTIVE) { GammaObject conflictingObject = doPrepare(); if (conflictingObject != null) { throw abortOnReadWriteConflict(conflictingObject); } } if (commitConflict) { config.globalConflictCounter.signalConflict(); } Listeners[] listenersArray = commitArray(); if (listenersArray != null) { Listeners.openAll(listenersArray, pool); pool.putListenersArray(listenersArray); } } else { releaseArray(true); } } status = TX_COMMITTED; notifyListeners(TxnEvent.PostCommit); } private Listeners[] commitArray() { Listeners[] listenersArray = null; int listenersIndex = 0; int itemCount = 0; //first write everything without releasing for (int k = 0; k < array.length; k++) { if (SHAKE_BUGS) shakeBugs(); final Tranlocal tranlocal = array[k]; if (tranlocal == null) { continue; } final BaseGammaTxnRef owner = tranlocal.owner; final Listeners listeners = owner.commit(tranlocal, pool); if (listeners != null) { if (listenersArray == null) { listenersArray = pool.takeListenersArray(size - itemCount); } listenersArray[listenersIndex] = listeners; listenersIndex++; } pool.put(tranlocal); itemCount++; } return listenersArray; } private void releaseArray(boolean success) { for (int k = 0; k < array.length; k++) { final Tranlocal tranlocal = array[k]; if (tranlocal != null) { if (SHAKE_BUGS) shakeBugs(); array[k] = null; if (success) { tranlocal.owner.releaseAfterReading(tranlocal, pool); } else { tranlocal.owner.releaseAfterFailure(tranlocal, pool); } pool.put(tranlocal); } } } @Override public final void prepare() { if (status == TX_PREPARED) { return; } if (status != TX_ACTIVE) { throw abortPrepareOnBadStatus(); } if (abortOnly) { throw abortPrepareOnAbortOnly(); } notifyListeners(TxnEvent.PrePrepare); if (hasWrites) { final GammaObject conflictingObject = doPrepare(); if (conflictingObject != null) { throw abortOnReadWriteConflict(conflictingObject); } } status = TX_PREPARED; } @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) private GammaObject doPrepare() { if (skipPrepare()) { return null; } for (int k = 0; k < array.length; k++) { if (SHAKE_BUGS) shakeBugs(); final Tranlocal tranlocal = array[k]; if (tranlocal == null) { continue; } final BaseGammaTxnRef owner = tranlocal.owner; if (!owner.prepare(this, tranlocal)) { return owner; } } return null; } @Override public final void abort() { if (status == TX_ABORTED) { return; } if (status == TX_COMMITTED) { throw failAbortOnAlreadyCommitted(); } if (size > 0) { releaseArray(false); } status = TX_ABORTED; notifyListeners(TxnEvent.PostAbort); } @Override public final Tranlocal locate(BaseGammaTxnRef o) { if (status != TX_ACTIVE) { throw abortLocateOnBadStatus(o); } if (o == null) { throw abortLocateOnNullArgument(); } return getRefTranlocal(o); } @Override public final Tranlocal getRefTranlocal(BaseGammaTxnRef ref) { int indexOf = indexOf(ref, ref.identityHashCode()); return indexOf == -1 ? null : array[indexOf]; } @Override public final void retry() { if (status != TX_ACTIVE) { throw abortRetryOnBadStatus(); } if (!config.isBlockingAllowed()) { throw abortRetryOnNoBlockingAllowed(); } if (size == 0) { throw abortRetryOnNoRetryPossible(); } retryListener.reset(); final long listenerEra = retryListener.getEra(); boolean furtherRegistrationNeeded = true; boolean atLeastOneRegistration = false; for (int k = 0; k < array.length; k++) { final Tranlocal tranlocal = array[k]; if (tranlocal == null) { continue; } array[k] = null; final BaseGammaTxnRef owner = tranlocal.owner; if (furtherRegistrationNeeded) { switch (owner.registerChangeListener(retryListener, tranlocal, pool, listenerEra)) { case REGISTRATION_DONE: atLeastOneRegistration = true; break; case REGISTRATION_NOT_NEEDED: furtherRegistrationNeeded = false; atLeastOneRegistration = true; break; case REGISTRATION_NONE: break; default: throw new IllegalStateException(); } } owner.releaseAfterFailure(tranlocal, pool); pool.put(tranlocal); } status = TX_ABORTED; if (!atLeastOneRegistration) { throw abortRetryOnNoRetryPossible(); } throw newRetryError(); } @Override public final boolean softReset() { if (attempt >= config.getMaxRetries()) { return false; } status = TX_ACTIVE; hasReads = false; hasWrites = false; size = 0; abortOnly = false; attempt++; commitConflict = false; evaluatingCommute = false; if (listeners != null) { listeners.clear(); pool.putArrayList(listeners); listeners = null; } return true; } @Override public final void hardReset() { status = TX_ACTIVE; hasReads = false; hasWrites = false; size = 0; abortOnly = false; attempt = 1; remainingTimeoutNs = config.timeoutNs; //todo: only change when the array size is different. if (array != null) { pool.putTranlocalArray(array); } array = pool.takeTranlocalArray(config.minimalArrayTreeSize); final SpeculativeGammaConfiguration speculativeConfig = config.speculativeConfiguration.get(); richmansMansConflictScan = speculativeConfig.richMansConflictScanRequired; commitConflict = false; evaluatingCommute = false; if (listeners != null) { listeners.clear(); pool.putArrayList(listeners); listeners = null; } } @Override public void initLocalConflictCounter() { if (richmansMansConflictScan && !hasReads) { localConflictCount = config.globalConflictCounter.count(); } } @Override public final boolean isReadConsistent(Tranlocal justAdded) { if (!hasReads) { return true; } if (config.readLockModeAsInt > LOCKMODE_NONE) { return true; } if (config.inconsistentReadAllowed) { return true; } if (richmansMansConflictScan) { if (SHAKE_BUGS) shakeBugs(); final long conflictCount = config.globalConflictCounter.count(); if (localConflictCount == conflictCount) { return true; } localConflictCount = conflictCount; //we are going to fall through to do a full conflict scan } else if (size > config.maximumPoorMansConflictScanLength) { throw abortOnRichmanConflictScanDetected(); } //doing a full conflict scan for (int k = 0; k < array.length; k++) { if (SHAKE_BUGS) shakeBugs(); final Tranlocal tranlocal = array[k]; //noinspection ObjectEquality final boolean skip = tranlocal == null || (!richmansMansConflictScan && justAdded == tranlocal); if (!skip && tranlocal.owner.hasReadConflict(tranlocal)) { return false; } } return true; } public final float getUsage() { return (size * 1.0f) / array.length; } public final int size() { return size; } public final int indexOf(final BaseGammaTxnRef ref, final int hash) { int jump = 0; boolean goLeft = true; do { final int offset = goLeft ? -jump : jump; final int index = (hash + offset) % array.length; final Tranlocal current = array[index]; if (current == null || current.owner == null) { return -1; } //noinspection ObjectEquality if (current.owner == ref) { return index; } final int currentHash = current.owner.identityHashCode(); goLeft = currentHash > hash; jump = jump == 0 ? 1 : jump * 2; } while (jump < array.length); return -1; } public final void attach(final Tranlocal tranlocal, final int hash) { int jump = 0; boolean goLeft = true; do { final int offset = goLeft ? -jump : jump; final int index = (hash + offset) % array.length; Tranlocal current = array[index]; if (current == null) { array[index] = tranlocal; return; } final int currentHash = current.owner.identityHashCode(); goLeft = currentHash > hash; jump = jump == 0 ? 1 : jump * 2; } while (jump < array.length); expand(); attach(tranlocal, hash); } private void expand() { Tranlocal[] oldArray = array; int newSize = oldArray.length * 2; array = pool.takeTranlocalArray(newSize); for (int k = 0; k < oldArray.length; k++) { final Tranlocal tranlocal = oldArray[k]; if (tranlocal == null) { continue; } oldArray[k] = null; attach(tranlocal, tranlocal.owner.identityHashCode()); } pool.putTranlocalArray(oldArray); } } 000077500000000000000000000000001174000617100342365ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactions/leanLeanFixedLengthGammaTxn.java000066400000000000000000000226101174000617100415400ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.GammaObject; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.multiverse.utils.Bugshaker.shakeBugs; /** * A Lean GammaTxn that is optimized for a fixed number of GammaTxnRefs. */ public final class LeanFixedLengthGammaTxn extends GammaTxn { public Tranlocal head; public int size = 0; public boolean hasReads = false; public final Listeners[] listenersArray; public LeanFixedLengthGammaTxn(final GammaStm stm) { this(new GammaTxnConfig(stm)); } @SuppressWarnings({"ObjectAllocationInLoop"}) public LeanFixedLengthGammaTxn(final GammaTxnConfig config) { super(config, TRANSACTIONTYPE_LEAN_FIXED_LENGTH); listenersArray = new Listeners[config.maxFixedLengthTransactionSize]; Tranlocal h = null; for (int k = 0; k < config.maxFixedLengthTransactionSize; k++) { Tranlocal newNode = new Tranlocal(); if (h != null) { h.previous = newNode; newNode.next = h; } h = newNode; } head = h; } @Override public final boolean isReadConsistent(Tranlocal justAdded) { throw new UnsupportedOperationException(); } @Override public final void commit() { int s = status; if (s == TX_COMMITTED) { return; } if (s != TX_ACTIVE && s != TX_PREPARED) { throw abortCommitOnBadStatus(); } if (hasWrites) { if (s == TX_ACTIVE) { GammaObject conflictingObject = prepareChainForCommit(); if (conflictingObject != null) { throw abortOnReadWriteConflict(conflictingObject); } } if (commitConflict) { config.globalConflictCounter.signalConflict(); } int listenersIndex = 0; Tranlocal node = head; do { final BaseGammaTxnRef owner = node.owner; if (owner == null) { break; } if (SHAKE_BUGS) shakeBugs(); final Listeners listeners = owner.leanCommit(node); if (listeners != null) { listenersArray[listenersIndex] = listeners; listenersIndex++; } node = node.next; } while (node != null); if (listenersArray != null) { Listeners.openAll(listenersArray, pool); } } else { releaseReadonlyChain(); } status = TX_COMMITTED; } @Override public final void prepare() { if (status == TX_PREPARED) { return; } if (status != TX_ACTIVE) { throw abortPrepareOnBadStatus(); } final GammaObject conflictingObject = prepareChainForCommit(); if (conflictingObject != null) { throw abortOnReadWriteConflict(conflictingObject); } status = TX_PREPARED; } @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) private GammaObject prepareChainForCommit() { Tranlocal node = head; do { final BaseGammaTxnRef owner = node.owner; if (owner == null) { return null; } if (SHAKE_BUGS) shakeBugs(); if (node.mode == TRANLOCAL_READ) { continue; } final long version = node.version; if (owner.version != version) { return owner; } int arriveStatus = owner.arriveAndExclusiveLock(64); if (arriveStatus == FAILURE) { return owner; } if ((arriveStatus & MASK_CONFLICT) != 0) { commitConflict = true; } node.hasDepartObligation = (arriveStatus & MASK_UNREGISTERED) == 0; node.lockMode = LOCKMODE_EXCLUSIVE; if (owner.version != version) { return owner; } node = node.next; } while (node != null); return null; } @Override public final void abort() { if (status == TX_ABORTED) { return; } if (status == TX_COMMITTED) { throw failAbortOnAlreadyCommitted(); } releaseChainForAbort(); status = TX_ABORTED; } private void releaseChainForAbort() { Tranlocal node = head; do { final BaseGammaTxnRef owner = node.owner; if (owner == null) { return; } if (SHAKE_BUGS) shakeBugs(); if (node.isWrite()) { if (node.getLockMode() == LOCKMODE_EXCLUSIVE) { if (node.hasDepartObligation()) { node.setDepartObligation(false); owner.departAfterFailureAndUnlock(); } else { owner.unlockByUnregistered(); } node.setLockMode(LOCKMODE_NONE); } } node.owner = null; node.ref_oldValue = null; node.ref_value = null; node = node.next; } while (node != null); } private void releaseReadonlyChain() { Tranlocal node = head; do { final BaseGammaTxnRef owner = node.owner; if (owner == null) { return; } if (SHAKE_BUGS) shakeBugs(); node.owner = null; node.ref_oldValue = null; node.ref_value = null; node = node.next; } while (node != null); } @Override public final Tranlocal getRefTranlocal(final BaseGammaTxnRef ref) { Tranlocal node = head; do { //noinspection ObjectEquality if (node.owner == ref) { return node; } if (node.owner == null) { return null; } node = node.next; } while (node != null); return null; } @Override public final void retry() { if (status != TX_ACTIVE) { throw abortRetryOnBadStatus(); } if (!config.isBlockingAllowed()) { throw abortRetryOnNoBlockingAllowed(); } if (size == 0) { throw abortRetryOnNoRetryPossible(); } retryListener.reset(); final long listenerEra = retryListener.getEra(); boolean furtherRegistrationNeeded = true; boolean atLeastOneRegistration = false; Tranlocal tranlocal = head; do { final BaseGammaTxnRef owner = tranlocal.owner; if (furtherRegistrationNeeded) { switch (owner.registerChangeListener(retryListener, tranlocal, pool, listenerEra)) { case REGISTRATION_DONE: atLeastOneRegistration = true; break; case REGISTRATION_NOT_NEEDED: furtherRegistrationNeeded = false; atLeastOneRegistration = true; break; case REGISTRATION_NONE: break; default: throw new IllegalStateException(); } } owner.releaseAfterFailure(tranlocal, pool); tranlocal = tranlocal.next; } while (tranlocal != null && tranlocal.owner != null); status = TX_ABORTED; if (!atLeastOneRegistration) { throw abortRetryOnNoRetryPossible(); } throw newRetryError(); } @Override public final Tranlocal locate(BaseGammaTxnRef o) { if (status != TX_ACTIVE) { throw abortLocateOnBadStatus(o); } if (o == null) { throw abortLocateOnNullArgument(); } return getRefTranlocal(o); } @Override public final void hardReset() { status = TX_ACTIVE; hasWrites = false; size = 0; remainingTimeoutNs = config.timeoutNs; attempt = 1; commitConflict = false; hasReads = false; } @Override public final boolean softReset() { if (attempt >= config.getMaxRetries()) { return false; } commitConflict = false; status = TX_ACTIVE; hasWrites = false; size = 0; hasReads = false; attempt++; return true; } public final void shiftInFront(Tranlocal newHead) { //noinspection ObjectEquality if (newHead == head) { return; } head.previous = newHead; if (newHead.next != null) { newHead.next.previous = newHead.previous; } newHead.previous.next = newHead.next; newHead.next = head; newHead.previous = null; head = newHead; } @Override public void initLocalConflictCounter() { //ignore } } LeanMonoGammaTxn.java000066400000000000000000000143101174000617100402450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.multiverse.utils.Bugshaker.shakeBugs; /** * A Lean GammaTxn implementation that is optimized for dealing with only a single * transactional reference. */ public final class LeanMonoGammaTxn extends GammaTxn { public final Tranlocal tranlocal = new Tranlocal(); public LeanMonoGammaTxn(GammaStm stm) { this(new GammaTxnConfig(stm)); } public LeanMonoGammaTxn(GammaTxnConfig config) { super(config, TRANSACTIONTYPE_LEAN_MONO); } @Override public final Tranlocal locate(BaseGammaTxnRef o) { if (status != TX_ACTIVE) { throw abortLocateOnBadStatus(o); } if (o == null) { throw abortLocateOnNullArgument(); } return getRefTranlocal(o); } @Override public final void commit() { if (status == TX_COMMITTED) { return; } if (status != TX_ACTIVE && status != TX_PREPARED) { throw abortCommitOnBadStatus(); } final BaseGammaTxnRef owner = tranlocal.owner; if (owner == null) { status = TX_COMMITTED; return; } if (!hasWrites) { tranlocal.owner = null; tranlocal.ref_value = null; status = TX_COMMITTED; return; } final long version = tranlocal.version; //if the transaction still is active, we need to prepare the transaction. if (status == TX_ACTIVE) { if (owner.version != version) { throw abortOnReadWriteConflict(owner); } final int arriveStatus = owner.arriveAndExclusiveLock(64); if (arriveStatus == FAILURE) { throw abortOnReadWriteConflict(owner); } if (owner.version != version) { if ((arriveStatus & MASK_UNREGISTERED) == 0) { owner.departAfterFailureAndUnlock(); } else { owner.unlockByUnregistered(); } throw abortOnReadWriteConflict(owner); } if((arriveStatus & MASK_CONFLICT)!=0){ commitConflict = true; } } if (commitConflict) { config.globalConflictCounter.signalConflict(); } if(SHAKE_BUGS) shakeBugs(); owner.ref_value = tranlocal.ref_value; owner.version = version + 1; Listeners listeners = owner.listeners; if (listeners != null) { listeners = owner.___removeListenersAfterWrite(); } owner.departAfterUpdateAndUnlock(); tranlocal.owner = null; //we need to set them to null to prevent memory leaks. tranlocal.ref_value = null; tranlocal.ref_oldValue = null; if (listeners != null) { listeners.openAll(pool); } status = TX_COMMITTED; } @Override public final void abort() { if (status == TX_ABORTED) { return; } if (status == TX_COMMITTED) { throw failAbortOnAlreadyCommitted(); } status = TX_ABORTED; BaseGammaTxnRef owner = tranlocal.owner; if (owner != null) { owner.releaseAfterFailure(tranlocal, pool); } } @Override public final void prepare() { if (status == TX_PREPARED) { return; } if (status != TX_ACTIVE) { throw abortPrepareOnBadStatus(); } final BaseGammaTxnRef owner = tranlocal.owner; if (owner != null) { if (!owner.prepare(this, tranlocal)) { throw abortOnReadWriteConflict(owner); } } status = TX_PREPARED; } @Override public final Tranlocal getRefTranlocal(BaseGammaTxnRef ref) { //noinspection ObjectEquality return tranlocal.owner == ref ? tranlocal : null; } @Override public final void retry() { if (status != TX_ACTIVE) { throw abortRetryOnBadStatus(); } if (!config.isBlockingAllowed()) { throw abortRetryOnNoBlockingAllowed(); } if (tranlocal == null) { throw abortRetryOnNoRetryPossible(); } final BaseGammaTxnRef owner = tranlocal.owner; if (owner == null) { throw abortRetryOnNoRetryPossible(); } retryListener.reset(); final long listenerEra = retryListener.getEra(); boolean atLeastOneRegistration = false; switch (tranlocal.owner.registerChangeListener(retryListener, tranlocal, pool, listenerEra)) { case REGISTRATION_DONE: atLeastOneRegistration = true; break; case REGISTRATION_NOT_NEEDED: atLeastOneRegistration = true; break; case REGISTRATION_NONE: break; default: throw new IllegalStateException(); } owner.releaseAfterFailure(tranlocal, pool); status = TX_ABORTED; if (!atLeastOneRegistration) { throw abortRetryOnNoRetryPossible(); } throw newRetryError(); } @Override public final boolean softReset() { if (attempt >= config.getMaxRetries()) { return false; } commitConflict = false; status = TX_ACTIVE; hasWrites = false; attempt++; return true; } @Override public final void hardReset() { commitConflict = false; status = TX_ACTIVE; hasWrites = false; remainingTimeoutNs = config.timeoutNs; attempt = 1; } @Override public final boolean isReadConsistent(Tranlocal justAdded) { return true; } @Override public void initLocalConflictCounter() { //ignore } } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/utils/000077500000000000000000000000001174000617100277565ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/utils/Bugshaker.java000077500000000000000000000033321174000617100325400ustar00rootroot00000000000000package org.multiverse.utils; import org.multiverse.MultiverseConstants; import java.util.concurrent.locks.LockSupport; import static java.lang.Thread.yield; /** * Contains some utility functions for shaking out bugs. It can be used by adding this method is the code like * this: *

 * if(MultiverseConstants.SHAKE_BUGS){shakeBugs();}
 * 
* Since the SHAKE_BUGS field is final, it can be removed by the JIT is the bugshaking is disabled so * there is no overhead. *

* At the moment the inside of the Bugshaker is not configurable (so no control on how much delay and how often * it happens). * * @author Peter Veentjer */ public final class Bugshaker implements MultiverseConstants { /** * Delays a random amount of time. What essentially happens is that a random number is selected and one in the * n cases, a sleep is done and one in the n cases a yield is done. */ @SuppressWarnings({"CallToThreadYield"}) public static void shakeBugs() { int random = ThreadLocalRandom.current().nextInt(100); if (random == 10) { sleepUs(10); } else if (random == 20) { yield(); } } /** * Delays a number of microseconds. Having a delay smaller than a microsecond doesn't provide * value since the minimum delay is a few microseconds. * * If the delay is smaller than 0, the call is ignored. * * @param delayUs the number of microseconds to delay. */ public static void sleepUs(long delayUs) { if (delayUs <= 0) { return; } long nanos = delayUs * 1000; LockSupport.parkNanos(nanos); } //we don't want any instances private Bugshaker() { } } StandardThreadFactory.java000066400000000000000000000200431174000617100347610ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/utilspackage org.multiverse.utils; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * A customizable implementation of the {@link java.util.concurrent.ThreadFactory}. The new * java.util.concurrency library provides a {@link java.util.concurrent.ThreadFactory} interface, which is a great * thing, but strangely enough it doesn't provide an customizable implementation. *

* If the maximum priority of the ThreadGroup is changed after this StandardThreadFactory is * constructed, then this will be ignored by the StandardThreadFactory. So it could be that a * StandardThreadFactory has a higher priority than the ThreadGroup allowed. What will happen at * construction? * * @author Peter Veentjer. */ @SuppressWarnings({"ClassWithTooManyConstructors"}) public final class StandardThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private static String createThreadGroupName() { return Integer.toString(poolNumber.getAndIncrement()); } private final ThreadGroup threadGroup; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; private final boolean daemon; private volatile int priority; /** * Constructs a new StandardThreadFactory with a Thread.NORM_PRIORITY as priority and a newly * created ThreadGroup. The created Threads are not daemons. */ public StandardThreadFactory() { this(Thread.NORM_PRIORITY, createThreadGroupName()); } /** * Constructs a new StandardThreadFactory with a Thread.NORM_PRIORITY as priority and with a * newly created ThreadGroup with the given groupName. The created threads are not daemons. * * @param groupName the name of the ThreadGroup (is allowed to be null). */ public StandardThreadFactory(String groupName) { this(Thread.NORM_PRIORITY, groupName); } /** * Constructs a new StandardThreadFactory with the given priority. The created threads are * not daemons. * * @param priority the priority of th threads. * @throws IllegalArgumentException if the priority is not valid. */ public StandardThreadFactory(int priority) { this(priority, createThreadGroupName()); } /** * Constructs a new StandardThreadFactory with the given priority and with a newly created * ThreadGroup with the given groupName. The created threads are not daemons. * * @param priority the priority of the threads this StandardThreadFactory is going to createReference. * @param groupName the name of the ThreadGroup (is allowed to be null). * @throws IllegalArgumentException if priority is not a valid value. */ public StandardThreadFactory(int priority, String groupName) { this(priority, new ThreadGroup(Thread.currentThread().getThreadGroup(), groupName), false); } /** * Constructs a new StandardThreadFactory with the given priority and are part of the give * ThreadGroup. The created threads are not daemons. * * @param priority the priority of the created threads. * @param threadGroup the ThreadGroup the created Threads are part of. * @throws NullPointerException if threadGroup is null * @throws IllegalArgumentException if the priority is not valid value. */ public StandardThreadFactory(int priority, ThreadGroup threadGroup) { this(priority, threadGroup, false); } /** * Creates a new StandardThreadFactory with the given priority and if the threads are daemons * * @param priority the priority of the thread. * @param daemon if the thread is a daemon. */ public StandardThreadFactory(int priority, boolean daemon) { this(priority, new ThreadGroup( Thread.currentThread().getThreadGroup(), createThreadGroupName()), daemon); } /** * Constructs a new StandardThreadFactory with the given priority and ThreadGroup. * * @param priority the priority of the threads this StandardThreadFactory is going to createReference. * @param threadGroup the ThreadGroup the thread is part of * @param daemon if the thread should be a daemon. * @throws IllegalArgumentException if the priority is not valid. * @throws NullPointerException if threadGroup is null. */ public StandardThreadFactory(int priority, ThreadGroup threadGroup, boolean daemon) { if (threadGroup == null) { throw new NullPointerException(); } this.threadGroup = threadGroup; ensureValidPriority(priority); this.priority = priority; this.daemon = daemon; this.namePrefix = threadGroup.getName() + "-thread#"; } private void ensureValidPriority(int priority) { if (priority < Thread.MIN_PRIORITY) { throw new IllegalArgumentException("priority can`t be smaller than: " + Thread.MIN_PRIORITY + ", priority was: " + priority); } if (priority > Thread.MAX_PRIORITY) { throw new IllegalArgumentException("priority can`t be greater than: " + Thread.MAX_PRIORITY + ", priority was: " + priority); } if (priority > threadGroup.getMaxPriority()) { throw new IllegalArgumentException( "priority can`t be greater than threadGroup.maxPriority: " + threadGroup.getMaxPriority() + ", priority was: " + priority); } } /** * Returns true if this StandardThreadFactory is producing daemon threads, false * otherwise. * * @return true if this StandardThreadFactory is producing daemon threads, false * otherwise. */ public boolean isProducingDaemons() { return daemon; } /** * Returns the ThreadGroup of the created Threads. * * @return the ThreadGroup of the created Threads. */ public ThreadGroup getThreadGroup() { return threadGroup; } /** * Returns the priority of created Threads. This is a value ranging from * Thread.MIN_PRIORITY to Thread.MAX_PRIORITY. * * @return the priority of created Threads. */ public int getPriority() { return priority; } /** * Sets the priority of the threads. This will only effect newly created Threads. A value must * be getAndSet ranging from Thread.MIN_PRIORITY and Thread.MAX_PRIORITY. *

* This call is not completely threadsafe, the following scenario could happen: *

    *
  1. thread1 call setPriority and newTransaction the checking part of this method and the check passes
  2. *
  3. thread2 calls the ThreadGroup directly and lowers the priority
  4. *
  5. thread1 sets the priority on this StandardThreadFactory
  6. *
* The consequence is that the priority of this StandardThreadFactory is higher than the maximum * priority of the ThreadGroup and this means that thread creation could fail because threads are * created with a too high priority. This race problem is very hard to prevent because the check/getAndSet * can't be done atomically because the ThreadGroup is exposed. * * @param priority the new priority. * @throws IllegalArgumentException if priority is smaller than {@link Thread#MIN_PRIORITY} or * larger than {@link Thread#MAX_PRIORITY} or larger than the * maximum priority of the ThreadGroup. */ public void setPriority(int priority) { ensureValidPriority(priority); this.priority = priority; } @Override public Thread newThread(Runnable runnable) { if (runnable == null) throw new NullPointerException(); String threadName = namePrefix + threadNumber.getAndIncrement(); Thread thread = new Thread(threadGroup, runnable, threadName); thread.setDaemon(daemon); thread.setPriority(priority); return thread; } } ThreadLocalRandom.java000077500000000000000000000132771174000617100341020ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/utilspackage org.multiverse.utils; import java.util.Random; @SuppressWarnings({"ClassWithTooManyFields"}) public class ThreadLocalRandom extends Random { // same constants as Random, but must be redeclared because private private final static long multiplier = 0x5DEECE66DL; private final static long addend = 0xBL; private final static long mask = (1L << 48) - 1; /** * The random seed. We can't use super.seed. */ private long rnd; /** * Initialization flag to permit the first and only allowed call * to setSeed (inside Random constructor) to succeed. We can't * allow others since it would cause setting seed in one part of a * program to unintentionally impact other usages by the thread. */ boolean initialized; // Padding to help avoid memory contention among seed updates in // different TLRs in the common case that they are located near // each other. private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; /** * The actual ThreadLocal */ private static final ThreadLocal localRandom = new ThreadLocal() { protected ThreadLocalRandom initialValue() { return new ThreadLocalRandom(); } }; /** * Constructor called only by localRandom.initialValue. * We rely on the fact that the superclass no-arg constructor * invokes setSeed exactly once to initialize. */ public ThreadLocalRandom() { super(); } /** * Returns the current thread's {@code ThreadLocalRandom}. * * @return the current thread's {@code ThreadLocalRandom} */ public static ThreadLocalRandom current() { return localRandom.get(); } /** * Throws {@code UnsupportedOperationException}. Setting seeds in * this generator is not supported. * * @throws UnsupportedOperationException always */ @Override public void setSeed(long seed) { if (initialized) throw new UnsupportedOperationException(); initialized = true; rnd = (seed ^ multiplier) & mask; } protected int next(int bits) { rnd = (rnd * multiplier + addend) & mask; return (int) (rnd >>> (48 - bits)); } /** * Returns a pseudorandom, uniformly distributed value between the * given least value (inclusive) and bound (exclusive). * * @param least the least value returned * @param bound the upper bound (exclusive) * @return the next value * @throws IllegalArgumentException if least greater than or equal * to bound */ public int nextInt(int least, int bound) { if (least >= bound) throw new IllegalArgumentException(); return nextInt(bound - least) + least; } /** * Returns a pseudorandom, uniformly distributed value * between 0 (inclusive) and the specified value (exclusive). * * @param n the bound on the random number to be returned. Must be * positive. * @return the next value * @throws IllegalArgumentException if n is not positive */ public long nextLong(long n) { if (n <= 0) throw new IllegalArgumentException("n must be positive"); // Divide n by two until small enough for nextInt. On each // iteration (at most 31 of them but usually much less), // randomly choose both whether to include high bit in result // (offset) and whether to continue with the lower vs upper // half (which makes a difference only if odd). long offset = 0; while (n >= Integer.MAX_VALUE) { int bits = next(2); long half = n >>> 1; long nextn = ((bits & 2) == 0) ? half : n - half; if ((bits & 1) == 0) offset += n - nextn; n = nextn; } return offset + nextInt((int) n); } /** * Returns a pseudorandom, uniformly distributed value between the * given least value (inclusive) and bound (exclusive). * * @param least the least value returned * @param bound the upper bound (exclusive) * @return the next value * @throws IllegalArgumentException if least greater than or equal * to bound */ public long nextLong(long least, long bound) { if (least >= bound) throw new IllegalArgumentException(); return nextLong(bound - least) + least; } /** * Returns a pseudorandom, uniformly distributed {@code double} value * between 0 (inclusive) and the specified value (exclusive). * * @param n the bound on the random number to be returned. Must be * positive. * @return the next value * @throws IllegalArgumentException if n is not positive */ public double nextDouble(double n) { if (n <= 0) throw new IllegalArgumentException("n must be positive"); return nextDouble() * n; } /** * Returns a pseudorandom, uniformly distributed value between the * given least value (inclusive) and bound (exclusive). * * @param least the least value returned * @param bound the upper bound (exclusive) * @return the next value * @throws IllegalArgumentException if least greater than or equal * to bound */ public double nextDouble(double least, double bound) { if (least >= bound) throw new IllegalArgumentException(); return nextDouble() * (bound - least) + least; } private static final long serialVersionUID = -5851777807851030925L; } Multiverse-multiverse-0.7.0/multiverse-core/src/main/java/org/multiverse/utils/ToolUnsafe.java000077500000000000000000000015471174000617100327120ustar00rootroot00000000000000package org.multiverse.utils; import sun.misc.Unsafe; import java.lang.reflect.Field; /** * A Utility class for accessing the {@link Unsafe}. * * @author Peter Veentjer */ public final class ToolUnsafe { /** * Fetch the Unsafe. Use With Caution. * * @return an Unsafe instance. */ public static Unsafe getUnsafe() { // Not on bootclasspath if (ToolUnsafe.class.getClassLoader() == null) { return Unsafe.getUnsafe(); } try { final Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); return (Unsafe) field.get(ToolUnsafe.class); } catch (Exception e) { throw new RuntimeException("Could not access sun.misc.Unsafe", e); } } //we don't want instances. private ToolUnsafe() { } }Multiverse-multiverse-0.7.0/multiverse-core/src/test/000077500000000000000000000000001174000617100227425ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/000077500000000000000000000000001174000617100236635ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/000077500000000000000000000000001174000617100244525ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/000077500000000000000000000000001174000617100266515ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/SomeError.java000066400000000000000000000001021174000617100314220ustar00rootroot00000000000000package org.multiverse; public class SomeError extends Error { } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/SomeUncheckedException.java000066400000000000000000000001321174000617100341040ustar00rootroot00000000000000package org.multiverse; public class SomeUncheckedException extends RuntimeException { } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/TestThread.java000066400000000000000000000054531174000617100315720ustar00rootroot00000000000000package org.multiverse; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicLong; import static org.junit.Assert.*; /** * A TestThread that tracks if any throwable has been thrown by a thread. * * @author Peter Veentjer. */ public abstract class TestThread extends Thread { private final static AtomicLong idGenerator = new AtomicLong(); private volatile Throwable throwable; private volatile Boolean endedWithInterruptStatus; private volatile boolean startInterrupted; private volatile boolean printStackTrace = true; private long durationMs = -1; private CountDownLatch latch; public TestThread() { this("TestThread-"+idGenerator.incrementAndGet()); } public TestThread(String name) { this(name, false); } public TestThread(String name, boolean startInterrupted) { super(name); this.startInterrupted = startInterrupted; } public void setLatch(CountDownLatch latch) { this.latch = latch; } public void setStartInterrupted(boolean startInterrupted) { this.startInterrupted = startInterrupted; } public void setPrintStackTrace(boolean printStackTrace) { this.printStackTrace = printStackTrace; } public boolean doesStartInterrupted() { return startInterrupted; } public Boolean hasEndedWithInterruptStatus() { return endedWithInterruptStatus; } public long getDurationMs() { return durationMs; } @Override public final void run() { if(latch!=null){ latch.countDown(); } if (startInterrupted) { interrupt(); } long startMs = System.currentTimeMillis(); try { doRun(); } catch (Throwable ex) { if (printStackTrace) { System.out.printf("Thread %s has thrown an exception\n", getName()); ex.printStackTrace(); } this.throwable = ex; } finally { endedWithInterruptStatus = isInterrupted(); durationMs = System.currentTimeMillis() - startMs; } } public abstract void doRun() throws Exception; public Throwable getThrowable() { return throwable; } public void assertInterrupted() { assertFailedWithException(InterruptedException.class); } public void assertEndedWithInterruptStatus(boolean interrupt) { assertEquals(interrupt,endedWithInterruptStatus); } public void assertFailedWithException(Class expected) { assertNotNull(throwable); assertTrue("Found exception: " + throwable.getClass().getName(), throwable.getClass().isAssignableFrom(expected)); } public void assertNothingThrown() { assertNull(throwable); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/TestUtils.java000077500000000000000000000304311174000617100314600ustar00rootroot00000000000000package org.multiverse; import org.multiverse.api.Txn; import org.multiverse.api.TxnStatus; import org.multiverse.api.blocking.RetryLatch; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.utils.Bugshaker; import org.multiverse.utils.ThreadLocalRandom; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import static java.lang.String.format; import static org.junit.Assert.*; /** * @author Peter Veentjer */ public class TestUtils implements MultiverseConstants { public static void assertOrecValue(AbstractGammaObject object, long expected) { assertEquals(expected, object.orec); } public static void assertFailure(int value) { assertEquals(GammaConstants.FAILURE, value); } public static void assertHasMasks(int value, int... masks) { for (int mask : masks) { assertTrue((value & mask) > 0); } } public static void assertNotHasMasks(int value, int... masks) { for (int mask : masks) { assertTrue((value & mask) == 0); } } public static void clearCurrentThreadInterruptedStatus() { Thread.interrupted(); } public static void assertEqualsDouble(String msg, double expected, double found) { assertEquals(msg, Double.doubleToLongBits(expected), Double.doubleToLongBits(found)); } public static void assertEqualsDouble(double expected, double found) { assertEqualsDouble(format("expected %s found %s", expected, found), expected, found); } public static int processorCount() { return Runtime.getRuntime().availableProcessors(); } public static void assertEra(RetryLatch latch, long era) { assertEquals(era, latch.getEra()); } public static void assertOpen(RetryLatch latch) { assertTrue(latch.isOpen()); } public static void assertClosed(RetryLatch latch) { assertFalse(latch.isOpen()); } public static void assertEqualByteArray(byte[] array1, byte[] array2) { if (array1 == array2) { return; } if (array1 == null) { fail(); } int length = array1.length; assertEquals(length, array2.length); for (int k = 0; k < array1.length; k++) { assertEquals(array1[k], array2[k]); } } public static Object getField(Object o, String fieldname) { if (o == null || fieldname == null) { throw new NullPointerException(); } try { Field field = findField(o.getClass(), fieldname); if (field == null) { fail(format("field '%s' is not found on class '%s' or on one of its super classes", fieldname, o.getClass().getName())); } field.setAccessible(true); return field.get(o); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } public static Field findField(Class clazz, String fieldname) { try { return clazz.getDeclaredField(fieldname); } catch (NoSuchFieldException e) { if (clazz.equals(Object.class)) { return null; } return findField(clazz.getSuperclass(), fieldname); } } public static void assertNotEquals(long l1, long l2) { assertFalse(format("both values are %s, but should not be equal", l2), l1 == l2); } public static void assertIsPrepared(Txn... txns) { for (Txn tx : txns) { assertEquals(TxnStatus.Prepared, tx.getStatus()); } } public static void assertIsAborted(Txn... txns) { for (Txn tx : txns) { assertEquals(TxnStatus.Aborted, tx.getStatus()); } } public static void assertIsCommitted(Txn... txns) { for (Txn tx : txns) { assertEquals(TxnStatus.Committed, tx.getStatus()); } } public static void assertIsActive(Txn... txns) { for (Txn tx : txns) { assertEquals(TxnStatus.Active, tx.getStatus()); } } public static int randomInt(int max) { if (max <= 0) { return 0; } return ThreadLocalRandom.current().nextInt(max); } public static void sleepRandomMs(int maxMs) { Bugshaker.sleepUs((long) randomInt((int) TimeUnit.MILLISECONDS.toMicros(maxMs))); } public static void sleepMs(long ms) { long us = TimeUnit.MILLISECONDS.toMicros(ms); Bugshaker.sleepUs(us); } public static boolean randomBoolean() { return randomInt(10) % 2 == 0; } public static boolean randomOneOf(int chance) { return randomInt(Integer.MAX_VALUE) % chance == 0; } public static long getStressTestDurationMs(long defaultDuration) { String value = System.getProperty("org.multiverse.integrationtest.durationMs", String.valueOf(defaultDuration)); return Long.parseLong(value); } public static void assertIsInterrupted(Thread t) { assertTrue(t.isInterrupted()); } public static void assertAlive(Thread... threads) { for (Thread thread : threads) { assertTrue(thread.getName(), thread.isAlive()); } } public static boolean isAlive(Thread... threads) { for (Thread thread : threads) { if (!thread.isAlive()) { return false; } } return true; } public static void assertNothingThrown(TestThread... threads){ for(TestThread t: threads){ Throwable throwable = t.getThrowable(); if(throwable != null){ fail(String.format("TestThread [%s] failed with the following exception\n%s", t.getName(),getStackTrace(throwable))); } } } public static String getStackTrace(Throwable aThrowable) { final Writer result = new StringWriter(); final PrintWriter printWriter = new PrintWriter(result); aThrowable.printStackTrace(printWriter); return result.toString(); } public static void assertNotAlive(Thread... threads) { for (Thread thread : threads) { assertFalse(thread.isAlive()); } } public static void assertEventuallyNotAlive(Thread... threads){ assertEventuallyNotAlive(60 * 1000, threads); } public static void assertEventuallyNotAlive(long timeoutMs, Thread... threads) { for (Thread thread : threads) { if(timeoutMs <=0){ fail("There is no remaining timeout"); } long startMs = System.currentTimeMillis(); try { thread.join(timeoutMs); } catch (InterruptedException e) { fail("Failed to join thread: " + thread.getName()); } long elapsed = System.currentTimeMillis() - startMs; if (thread.isAlive()) { fail(format("Thread [%s] is still alive after a timeout of [%s] ms", thread, timeoutMs)); } assertFalse(thread.isAlive()); timeoutMs -= elapsed; } } public static void startAll(TestThread... threads) { for (Thread thread : threads) { thread.start(); } } public static void assertEventuallyFalse(Callable f) { assertEventually(f, false); } public static void assertEventuallyFalse(Callable f, long timeoutMs) { assertEventually(f, false, timeoutMs); } public static void assertEventually(Callable f, boolean value) { assertEventually(f, value, 60 * 1000); } public static void assertEventuallyTrue(Callable f) { assertEventually(f, true); } public static void assertEventuallyTrue(Callable f, long timeoutMs) { assertEventually(f, true, timeoutMs); } public static void assertEventually(Callable f, boolean value, long timeoutMs) { long endTime = System.currentTimeMillis() + timeoutMs; for (; ; ) { try { if (f.call() == value) { return; } } catch (Exception e) { throw new RuntimeException(e); } sleepMs(100); if (endTime > System.currentTimeMillis()) { fail("Failed to become true in the given timeout"); } } } public static void sleepRandomUs(int maxUs) { Bugshaker.sleepUs((long) randomInt(maxUs)); } public static void assertInstanceof(Class expected, Object o) { assertTrue(o.getClass().getName(), expected.isAssignableFrom(o.getClass())); } /** * Joins all threads. If this can't be done within 5 minutes, an assertion failure is thrown. * * @param threads the threads to join. * @return the total duration of all threads (so the sum of the time each thread has been running. * @see #joinAll(long, TestThread...) for more specifics. */ public static long joinAll(TestThread... threads) { return joinAll(5 * 60, threads); } /** * Joins all threads. If one of the thread throws a throwable, the join will fail as well. * * @param timeoutSec the timeout in seconds. If the join doesn't complete within that time, the * join fails. * @param threads the threads to join. * @return the total duration of all threads (so the sum of the time each thread has been running. */ @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"}) public static long joinAll(long timeoutSec, TestThread... threads) { if (timeoutSec < 0) { throw new IllegalArgumentException(); } List uncompleted = new LinkedList(Arrays.asList(threads)); long maxTimeMs = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(timeoutSec); long durationMs = 0; while (!uncompleted.isEmpty()) { for (Iterator it = uncompleted.iterator(); it.hasNext(); ) { TestThread thread = it.next(); try { if (System.currentTimeMillis() > maxTimeMs) { fail(String.format( "Failed to join all threads in %s seconds, remaining threads %s.\n%s", timeoutSec, uncompleted, getStacks(uncompleted))); } thread.join(100); if (!thread.isAlive()) { it.remove(); durationMs += thread.getDurationMs(); if (thread.getThrowable() == null) { System.out.printf("Multiverse > %s completed successfully\n", thread.getName()); } else { System.out.printf("Multiverse > %s encountered the following error\n", thread.getName()); thread.getThrowable().printStackTrace(); fail(String.format("Multiverse > %s completed with failure", thread.getName())); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(String.format("Joining %s was interrupted", thread), e); } } } return durationMs; } private static String getStacks(List uncompleted) { StringBuffer sb = new StringBuffer(); sb.append("Uncompleted threads:\n"); for (TestThread thread : uncompleted) { sb.append("-------------------------------------------------------------------\n"); sb.append(thread.getName() + "\n"); for (StackTraceElement element : thread.getStackTrace()) { sb.append("\tat " + element + "\n"); } } sb.append("-------------------------------------------------------------------\n"); return sb.toString(); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/000077500000000000000000000000001174000617100274225ustar00rootroot00000000000000SpinningBackoffPolicy.java000066400000000000000000000003751174000617100344340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/apipackage org.multiverse.api; public class SpinningBackoffPolicy implements BackoffPolicy{ @Override public void delay(int attempt) throws InterruptedException { } @Override public void delayUninterruptible(int attempt) { } } StmUtils_executeTest.java000066400000000000000000000072051174000617100343600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/apipackage org.multiverse.api; import org.junit.Before; import org.junit.Test; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.InvisibleCheckedException; import org.multiverse.api.references.TxnInteger; import static org.junit.Assert.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class StmUtils_executeTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test(expected = NullPointerException.class) public void whenNullTxnCallable_thenNullPointerException() { StmUtils.atomic((TxnVoidCallable) null); } @Test public void whenExecuteSuccess() { final TxnInteger ref = newTxnInteger(); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(10); } }); assertEquals(10, ref.atomicGet()); } @Test public void whenExecuteThrowsCheckedException() { final TxnInteger ref = newTxnInteger(); final Exception ex = new Exception(); try { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(10); throw ex; } }); fail(); } catch (InvisibleCheckedException expected) { assertSame(ex, expected.getCause()); } assertEquals(0, ref.atomicGet()); } @Test public void whenExecuteThrowsUncheckedException() { final TxnInteger ref = newTxnInteger(); final RuntimeException ex = new RuntimeException(); try { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(10); throw ex; } }); fail(); } catch (Exception found) { assertSame(ex, found); } assertEquals(0, ref.atomicGet()); } @Test public void whenExecuteCheckedSuccess() throws Exception { final TxnInteger ref = newTxnInteger(); atomicChecked(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(10); } }); assertEquals(10, ref.atomicGet()); } @Test public void whenExecuteCheckedThrowsCheckedException() { final TxnInteger ref = newTxnInteger(); final Exception ex = new Exception(); try { atomicChecked(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(10); throw ex; } }); fail(); } catch (Exception found) { assertSame(ex, found); } assertEquals(0, ref.atomicGet()); } @Test public void whenExecuteCheckedThrowsUncheckedException() { final TxnInteger ref = newTxnInteger(); final RuntimeException ex = new RuntimeException(); try { atomicChecked(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(10); throw ex; } }); fail(); } catch (Exception found) { assertSame(ex, found); } assertEquals(0, ref.atomicGet()); } } StmUtils_newRefsTest.java000066400000000000000000000041551174000617100343300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/apipackage org.multiverse.api; import org.junit.Test; import org.multiverse.api.references.*; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertEqualsDouble; import static org.multiverse.api.StmUtils.*; public class StmUtils_newRefsTest { @Test public void whenNewRefWithDefaultValue() { TxnRef ref = newTxnRef(); assertNotNull(ref); assertNull(ref.atomicGet()); } @Test public void whennewTxnRef() { String value = "foo"; TxnRef ref = newTxnRef(value); assertNotNull(ref); assertSame(value, ref.atomicGet()); } @Test public void whennewTxnIntegerWithDefaultValue() { TxnInteger ref = newTxnInteger(); assertNotNull(ref); assertEquals(0, ref.atomicGet()); } @Test public void whennewTxnInteger() { int value = 10; TxnInteger ref = newTxnInteger(value); assertNotNull(ref); assertEquals(value, ref.atomicGet()); } @Test public void whennewTxnLongWithDefaultValue() { TxnLong ref = newTxnLong(); assertNotNull(ref); assertEquals(0, ref.atomicGet()); } @Test public void whennewTxnLong() { int value = 10; TxnLong ref = newTxnLong(value); assertNotNull(ref); assertEquals(value, ref.atomicGet()); } @Test public void whennewTxnBooleanWithDefaultValue() { TxnBoolean ref = newTxnBoolean(); assertNotNull(ref); assertFalse(ref.atomicGet()); } @Test public void whennewTxnBoolean() { boolean value = true; TxnBoolean ref = newTxnBoolean(value); assertNotNull(ref); assertTrue(ref.atomicGet()); } @Test public void whennewTxnDoubleWithDefaultValue() { TxnDouble ref = newTxnDouble(); assertNotNull(ref); assertEqualsDouble(0, ref.atomicGet()); } @Test public void whennewTxnDouble() { double value = 10; TxnDouble ref = newTxnDouble(value); assertNotNull(ref); assertEqualsDouble(value, ref.atomicGet()); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/blocking/000077500000000000000000000000001174000617100312125ustar00rootroot00000000000000DefaultRetryLatch_awaitTest.java000066400000000000000000000070241174000617100374140ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/blockingpackage org.multiverse.api.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.exceptions.RetryInterruptedException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; public class DefaultRetryLatch_awaitTest { @Before public void setUp(){ clearCurrentThreadInterruptedStatus(); } @Test public void whenAlreadyOpenAndSameEra(){ DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); latch.await(era,"sometransaction"); assertOpen(latch); assertEquals(era, latch.getEra()); } @Test public void whenAlreadyOpenAndDifferentEra(){ DefaultRetryLatch latch = new DefaultRetryLatch(); long oldEra = latch.getEra(); latch.reset(); long era = latch.getEra(); latch.open(era); latch.await(oldEra,"sometransaction"); assertOpen(latch); assertEquals(era, latch.getEra()); } @Test public void whenClosedButDifferentEra(){ DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.reset(); long expectedEra = latch.getEra(); latch.await(era,"sometransaction"); assertEquals(expectedEra, latch.getEra()); assertClosed(latch); } @Test public void whenSomeWaitingIsNeeded() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era); t.start(); sleepMs(500); assertAlive(t); latch.open(era); joinAll(t); assertOpen(latch); } @Test public void whenStartingInterrupted() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); Thread.currentThread().interrupt(); try { latch.await(era,"sometransaction"); fail(); } catch (RetryInterruptedException expected) { } assertEra(latch, era); assertClosed(latch); } @Test public void whenInterruptedWhileWaiting() throws InterruptedException { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era); t.setPrintStackTrace(false); t.start(); sleepMs(500); assertAlive(t); t.interrupt(); t.join(); assertClosed(latch); assertEra(latch, era); t.assertEndedWithInterruptStatus(true); t.assertFailedWithException(RetryInterruptedException.class); } @Test public void whenResetWhileWaiting_thenSleepingThreadsNotified() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era); t.start(); sleepMs(500); assertAlive(t); latch.reset(); joinAll(t); assertClosed(latch); assertEra(latch, era + 1); } class AwaitThread extends TestThread { private final RetryLatch latch; private final long expectedEra; AwaitThread(RetryLatch latch, long expectedEra) { this.latch = latch; this.expectedEra = expectedEra; } @Override public void doRun() throws Exception { latch.await(expectedEra,"sometransaction"); } } } DefaultRetryLatch_awaitUninterruptibleTest.java000066400000000000000000000072261174000617100425340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/blockingpackage org.multiverse.api.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; public class DefaultRetryLatch_awaitUninterruptibleTest { @Before public void setUp(){ clearCurrentThreadInterruptedStatus(); } @Test public void whenAlreadyOpenAndSameEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); latch.awaitUninterruptible(era); assertOpen(latch); assertEquals(era, latch.getEra()); } @Test public void whenAlreadyOpenAndDifferentEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long oldEra = latch.getEra(); latch.reset(); long era = latch.getEra(); latch.open(era); latch.awaitUninterruptible(oldEra); assertOpen(latch); assertEquals(era, latch.getEra()); } @Test public void whenClosedButDifferentEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.reset(); long expectedEra = latch.getEra(); latch.awaitUninterruptible(era); assertEquals(expectedEra, latch.getEra()); assertClosed(latch); } @Test public void whenSomeWaitingIsNeeded() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era); t.start(); sleepMs(500); assertAlive(t); latch.open(era); joinAll(t); assertOpen(latch); } @Test public void whenInterruptedWhileWaiting() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era); t.start(); sleepMs(500); assertAlive(t); t.interrupt(); //do some waiting and see if it still is waiting sleepMs(500); assertAlive(t); //now lets open the latch latch.open(era); joinAll(t); assertOpen(latch); assertEra(latch, era); t.assertEndedWithInterruptStatus(true); } @Test public void whenStartingInterrupted() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era); t.setStartInterrupted(true); t.start(); sleepMs(500); assertAlive(t); //do some waiting and see if it still is waiting sleepMs(500); assertAlive(t); //now lets open the latch latch.open(era); joinAll(t); assertOpen(latch); assertEra(latch, era); t.assertEndedWithInterruptStatus(true); } @Test public void whenResetWhileWaiting_thenSleepingThreadsNotified() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era); t.start(); sleepMs(500); assertAlive(t); latch.reset(); joinAll(t); assertClosed(latch); assertEra(latch, era + 1); } class AwaitThread extends TestThread { private final RetryLatch latch; private final long expectedEra; AwaitThread(RetryLatch latch, long expectedEra) { this.latch = latch; this.expectedEra = expectedEra; } @Override public void doRun() throws Exception { latch.awaitUninterruptible(expectedEra); } } } DefaultRetryLatch_openTest.java000066400000000000000000000025621174000617100372520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/blockingpackage org.multiverse.api.blocking; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; public class DefaultRetryLatch_openTest { @Before public void setUp(){ clearCurrentThreadInterruptedStatus(); } @Test public void whenAlreadyOpenAndDifferentEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); latch.open(era + 1); assertEquals(era, latch.getEra()); assertOpen(latch); } @Test public void whenAlreadyOpenAndSameEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); latch.open(era); assertEquals(era, latch.getEra()); assertOpen(latch); } @Test public void whenClosedAndDifferentEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era + 1); assertEquals(era, latch.getEra()); assertClosed(latch); } @Test public void whenClosedAndSameEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); assertEquals(era, latch.getEra()); assertOpen(latch); } } DefaultRetryLatch_prepareForPoolingTest.java000066400000000000000000000013251174000617100417420ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/blockingpackage org.multiverse.api.blocking; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.assertClosed; public class DefaultRetryLatch_prepareForPoolingTest { @Test public void whenClosed() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.reset(); assertClosed(latch); assertEquals(era + 1, latch.getEra()); } @Test public void whenOpen() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); latch.reset(); assertClosed(latch); assertEquals(era + 1, latch.getEra()); } } DefaultRetryLatch_tryAwaitTest.java000066400000000000000000000137041174000617100401150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/blockingpackage org.multiverse.api.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.exceptions.RetryInterruptedException; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; public class DefaultRetryLatch_tryAwaitTest { @Before public void setUp(){ clearCurrentThreadInterruptedStatus(); } @Test public void whenAlreadyOpenAndSameEra(){ DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); long result = latch.awaitNanos(era, 10,"sometransaction"); assertEquals(10, result); assertOpen(latch); assertEquals(era, latch.getEra()); } @Test public void whenAlreadyOpenAndDifferentEra(){ DefaultRetryLatch latch = new DefaultRetryLatch(); long oldEra = latch.getEra(); latch.reset(); long era = latch.getEra(); latch.open(era); long result = latch.awaitNanos(oldEra, 10,"sometransaction"); assertEquals(10, result); assertOpen(latch); assertEquals(era, latch.getEra()); } @Test public void whenClosedButDifferentEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.reset(); long expectedEra = latch.getEra(); long result = latch.awaitNanos(era, 10,"sometransaction"); assertEquals(10, result); assertEquals(expectedEra, latch.getEra()); assertClosed(latch); } @Test public void whenSomeWaitingIsNeeded() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 10, TimeUnit.SECONDS); t.start(); sleepMs(500); assertAlive(t); latch.open(era); joinAll(t); assertOpen(latch); //assertTrue() } @Test public void testAlreadyOpenAndNulTimeout(){ DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); long remaining = latch.awaitNanos(era, 0,"sometransaction"); assertEquals(0, remaining); assertOpen(latch); assertEra(latch, era); } @Test public void whenStillClosedAndNulTimeout(){ DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); long remaining = latch.awaitNanos(era, 0,"sometransaction"); assertTrue(remaining <= 0); assertClosed(latch); assertEra(latch, era); } @Test public void whenAlreadyOpenAndNegativeTimeout(){ DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); long remaining = latch.awaitNanos(era, -10,"sometransaction"); assertTrue(remaining <= 0); assertOpen(latch); assertEra(latch, era); } @Test public void whenStillClosedAndNegativeTimeout() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); long remaining = latch.awaitNanos(era, -10,"sometransaction"); assertTrue(remaining < 0); assertClosed(latch); assertEra(latch, era); } @Test public void whenTimeout() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 1, TimeUnit.SECONDS); t.start(); joinAll(t); assertClosed(latch); assertEra(latch, era); assertTrue(t.result < 0); } @Test public void whenStartingInterrupted_thenTransactionInterruptedExceptionAndInterruptedStatusRestored() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); Thread.currentThread().interrupt(); try { latch.awaitNanos(era, 10,"sometransaction"); fail(); } catch (RetryInterruptedException expected) { } assertTrue(Thread.currentThread().isInterrupted()); assertEra(latch, era); assertClosed(latch); } @Test public void whenInterruptedWhileWaiting_thenTransactionInterruptedExceptionAndInterruptedStatusRestored() throws InterruptedException { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 10, TimeUnit.SECONDS); t.setPrintStackTrace(false); t.start(); sleepMs(500); assertAlive(t); t.interrupt(); t.join(); assertClosed(latch); assertEra(latch, era); t.assertFailedWithException(RetryInterruptedException.class); t.assertEndedWithInterruptStatus(true); } @Test public void whenResetWhileWaiting_thenSleepingThreadsNotified() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 10, TimeUnit.SECONDS); t.start(); sleepMs(500); assertAlive(t); latch.reset(); joinAll(t); assertClosed(latch); assertEra(latch, era + 1); assertTrue(t.result > 0); assertTrue(t.result < TimeUnit.SECONDS.toNanos(10)); } class AwaitThread extends TestThread { private final RetryLatch latch; private final long expectedEra; private long timeout; private TimeUnit unit; private long result; AwaitThread(RetryLatch latch, long expectedEra, long timeout, TimeUnit unit) { this.latch = latch; this.expectedEra = expectedEra; this.timeout = timeout; this.unit = unit; } @Override public void doRun() throws Exception { result = latch.awaitNanos(expectedEra, unit.toNanos(timeout),"sometransaction"); } } } DefaultRetryLatch_tryAwaitUninterruptibleTest.java000066400000000000000000000141271174000617100432310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/blockingpackage org.multiverse.api.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; public class DefaultRetryLatch_tryAwaitUninterruptibleTest { @Before public void setUp() { clearCurrentThreadInterruptedStatus(); } @Test public void whenAlreadyOpenAndSameEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); long result = latch.awaitNanosUninterruptible(era, 10); assertEquals(10, result); assertOpen(latch); assertEquals(era, latch.getEra()); } @Test public void whenAlreadyOpenAndDifferentEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long oldEra = latch.getEra(); latch.reset(); long era = latch.getEra(); latch.open(era); long result = latch.awaitNanosUninterruptible(oldEra, 10); assertEquals(10, result); assertOpen(latch); assertEquals(era, latch.getEra()); } @Test public void whenClosedButDifferentEra() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.reset(); long expectedEra = latch.getEra(); long result = latch.awaitNanosUninterruptible(era, 10); assertEquals(10, result); assertEquals(expectedEra, latch.getEra()); assertClosed(latch); } @Test public void whenSomeWaitingIsNeeded() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 10, TimeUnit.SECONDS); t.start(); sleepMs(500); assertAlive(t); latch.open(era); joinAll(t); assertOpen(latch); } @Test public void whenTimeout() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 1, TimeUnit.SECONDS); t.start(); joinAll(t); assertClosed(latch); assertEra(latch, era); assertTrue(t.result < 0); } @Test public void testAlreadyOpenAndNulTimeout() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); long remaining = latch.awaitNanosUninterruptible(era, 0); assertEquals(0, remaining); assertOpen(latch); assertEra(latch, era); } @Test public void whenStillClosedAndNulTimeout() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); long remaining = latch.awaitNanosUninterruptible(era, 0); assertTrue(remaining < 0); assertClosed(latch); assertEra(latch, era); } @Test public void whenAlreadyOpenAndNegativeTimeout() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); latch.open(era); long remaining = latch.awaitNanosUninterruptible(era, -10); assertTrue(remaining < 0); assertOpen(latch); assertEra(latch, era); } @Test public void whenStillClosedAndNegativeTimeout() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); long remaining = latch.awaitNanosUninterruptible(era, -10); assertTrue(remaining < 0); assertClosed(latch); assertEra(latch, era); } @Test public void whenStartingInterrupted() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 10, TimeUnit.SECONDS); t.setStartInterrupted(true); t.start(); sleepMs(500); assertAlive(t); //do some waiting and see if it still is waiting sleepMs(500); assertAlive(t); //now lets open the latch latch.open(era); joinAll(t); assertOpen(latch); assertEra(latch, era); t.assertEndedWithInterruptStatus(true); assertTrue(t.result > 0); assertTrue(t.result < TimeUnit.SECONDS.toNanos(10)); } @Test public void whenInterruptedWhileWaiting() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 10, TimeUnit.SECONDS); t.start(); sleepMs(500); assertAlive(t); t.interrupt(); //do some waiting and see if it still is waiting sleepMs(500); assertAlive(t); //now lets open the latch latch.open(era); joinAll(t); assertOpen(latch); assertEra(latch, era); t.assertEndedWithInterruptStatus(true); assertTrue(t.result > 0); assertTrue(t.result < TimeUnit.SECONDS.toNanos(10)); } @Test public void whenResetWhileWaiting_thenSleepingThreadsNotified() { DefaultRetryLatch latch = new DefaultRetryLatch(); long era = latch.getEra(); AwaitThread t = new AwaitThread(latch, era, 10, TimeUnit.SECONDS); t.start(); sleepMs(500); assertAlive(t); latch.reset(); joinAll(t); assertClosed(latch); assertEra(latch, era + 1); assertTrue(t.result > 0); assertTrue(t.result < TimeUnit.SECONDS.toNanos(10)); } class AwaitThread extends TestThread { private final RetryLatch latch; private final long expectedEra; private long timeout; private TimeUnit unit; private long result; AwaitThread(RetryLatch latch, long expectedEra, long timeout, TimeUnit unit) { this.latch = latch; this.expectedEra = expectedEra; this.timeout = timeout; this.unit = unit; } @Override public void doRun() throws Exception { result = latch.awaitNanosUninterruptible(expectedEra, unit.toNanos(timeout)); } } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/functions/000077500000000000000000000000001174000617100314325ustar00rootroot00000000000000FunctionsTest.java000066400000000000000000000014321174000617100350260ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/functionspackage org.multiverse.api.functions; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.multiverse.api.functions.Functions.identityIntFunction; import static org.multiverse.api.functions.Functions.identityLongFunction; public class FunctionsTest { @Test public void testIntIdentityFunction() { IntFunction function = identityIntFunction(); assertEquals(0, function.call(0)); assertEquals(10, function.call(10)); assertEquals(-10, function.call(-10)); } @Test public void testLongIdentityFunction() { LongFunction function = identityLongFunction(); assertEquals(0, function.call(0)); assertEquals(10, function.call(10)); assertEquals(-10, function.call(-10)); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/predicates/000077500000000000000000000000001174000617100315455ustar00rootroot00000000000000PredicatesTest.java000066400000000000000000000016721174000617100352620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/api/predicatespackage org.multiverse.api.predicates; import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.multiverse.api.predicates.Predicates.newIsNotNullPredicate; import static org.multiverse.api.predicates.Predicates.newIsNullPredicate; public class PredicatesTest { @Test public void not_whenNullPredicate_thenNull(){ //Predicates. } @Test public void not_whenSuccess(){ } @Test public void and_(){ } public void or_(){} @Test public void testIsNullPredicate() { Predicate predicate = newIsNullPredicate(); assertTrue(predicate.evaluate(null)); assertFalse(predicate.evaluate("")); } @Test public void testIsNotNullPredicate() { Predicate predicate = newIsNotNullPredicate(); assertFalse(predicate.evaluate(null)); assertTrue(predicate.evaluate("")); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collections/000077500000000000000000000000001174000617100311675ustar00rootroot00000000000000NaiveTxHashMap_clearTest.java000066400000000000000000000036301174000617100366030ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxHashMap_clearTest { private Stm stm; private NaiveTxnHashMap map; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); map = new NaiveTxnHashMap(stm); } @Test public void whenNotEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); map.put("4", "d"); map.clear(); assertEquals(0, map.size()); assertEquals("[]", map.toString()); } }); } @Test public void whenManyItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { for (int k = 0; k < 1000; k++) { map.put("" + k, "" + k); } map.clear(); assertEquals(0, map.size()); assertEquals("[]", map.toString()); } }); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.clear(); assertEquals(0, map.size()); assertEquals("[]", map.toString()); } }); } } NaiveTxnHashMap_containsKeyTest.java000066400000000000000000000051121174000617100401570ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnHashMap_containsKeyTest { private Stm stm; private NaiveTxnHashMap map; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); map = new NaiveTxnHashMap(stm); } @Test public void whenNotFound() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); map.put("4", "d"); boolean result = map.containsKey("banana"); assertFalse(result); //assertEquals(4) //assertEquals("[]",map.toString()); } }); } @Test public void whenFound() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); map.put("4", "d"); boolean result = map.containsKey("3"); assertTrue(result); //assertEquals(4) //assertEquals("[]",map.toString()); } }); } @Test public void whenNullKey_thenReturnFalse() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); map.put("4", "d"); boolean result = map.containsKey(null); assertFalse(result); //assertEquals(4) //assertEquals("[]",map.toString()); } }); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = map.containsKey("1"); assertFalse(result); assertEquals("[]", map.toString()); } }); } } NaiveTxnHashMap_getTest.java000066400000000000000000000051751174000617100364600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnHashMap_getTest { private Stm stm; private NaiveTxnHashMap map; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); map = new NaiveTxnHashMap(stm); } @Test public void whenNotFound() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); map.put("4", "d"); String result = map.get("banana"); assertNull(result); //assertEquals(4) //assertEquals("[]",map.toString()); } }); } @Test public void whenFound() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); map.put("4", "d"); String result = map.get("3"); assertEquals("c", result); //assertEquals(4) //assertEquals("[]",map.toString()); } }); } @Test public void whenNullKey_thenReturnNull(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); map.put("4", "d"); String result = map.get(null); assertNull(result); //assertEquals(4) //assertEquals("[]",map.toString()); } }); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String result = map.get("1"); assertNull(result); assertEquals("[]", map.toString()); } }); } } NaiveTxnHashMap_putAllTest.java000066400000000000000000000063021174000617100371330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.HashMap; import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnHashMap_putAllTest { private Stm stm; private NaiveTxnHashMap map; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); map = new NaiveTxnHashMap(stm); } @Test public void whenNullMap_thenNullPointerException() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { map.putAll(null); fail(); } catch (NullPointerException expected) { } assertEquals(0, map.size()); } }); } @Test public void whenEmptyMapAdded() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.putAll(new HashMap()); assertEquals(0, map.size()); } }); } @Test public void whenOneOfTheItemsIsNull() { } @Test public void whenAllDifferentItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); Map other = new HashMap(); other.put("4", "d"); other.put("5", "e"); other.put("6", "f"); map.putAll(other); assertEquals(6, map.size()); assertEquals("a", map.get("1")); assertEquals("b", map.get("2")); assertEquals("c", map.get("3")); assertEquals("d", map.get("4")); assertEquals("e", map.get("5")); assertEquals("f", map.get("6")); } }); } @Test public void whenSomeItemsReplaced() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); Map other = new HashMap(); other.put("4", "d"); other.put("2", "B"); other.put("3", "C"); map.putAll(other); assertEquals(4, map.size()); assertEquals("a", map.get("1")); assertEquals("B", map.get("2")); assertEquals("C", map.get("3")); assertEquals("d", map.get("4")); } }); } } NaiveTxnHashMap_putTest.java000066400000000000000000000061401174000617100365020ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnHashMap_putTest { private Stm stm; private NaiveTxnHashMap map; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); map = new NaiveTxnHashMap(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String result = map.put("key", "value"); assertNull(result); assertEquals(1, map.size()); //todo: tostring } }); } @Test public void whenReplacingExistingKey() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); String result = map.put("2", "B"); assertEquals("b", result); assertEquals("B", map.get("2")); assertEquals(3, map.size()); //todo: tostring } }); } @Test public void whenNullKey_thenNullPointerException() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { map.put(null, "foo"); fail(); } catch (NullPointerException expected) { } assertEquals(0, map.size()); assertEquals("[]", map.toString()); //todo: tostring } }); } @Test public void whenManyItems() { final int itemCount = 100 * 1000; for (int k = 0; k < itemCount; k++) { final int key = k; StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { map.put("" + key, "" + key); } }); } System.out.println("Finished inserting"); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertEquals(itemCount, map.size()); } }); System.out.println("Doing content check"); for (int k = 0; k < itemCount; k++) { final int key = k; StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertEquals("" + key, map.get("" + key)); } }); } } } NaiveTxnLinkedList_addAllTest.java000066400000000000000000000127471174000617100376060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_addAllTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullCollectionAdded_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.addAll(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); } }); } @Test public void whenOneOfItemsIsNull() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); try { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { List c = Arrays.asList("a", "b", null, "d"); try { list.addAll(c); fail(); } catch (NullPointerException expected) { } assertEquals("[a, b]", list.toString()); throw new NullPointerException(); } }); fail(); } catch (NullPointerException expected) { } StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenNonEmptyListAndEmptyCollection() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.addAll(new LinkedList()); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenBothEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.addAll(new LinkedList()); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmptyListEmptyAndNonEmptyCollection() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { List c = Arrays.asList("1", "2"); list.addAll(c); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenBothNonEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { List c = Arrays.asList("2", "1"); list.add("4"); list.add("3"); list.addAll(c); assertEquals("[4, 3, 2, 1]", list.toString()); assertEquals(4, list.size()); } }); } @Test public void whenCapacityExceeded() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); } }); try { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { List c = Arrays.asList("2", "3"); try { list.addAll(c); fail(); } catch (IllegalStateException expected) { } assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); throw new IllegalStateException(); } }); fail(); } catch (IllegalStateException expected) { } StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertEquals(1, list.size()); assertEquals("[1]", list.toString()); } }); } } NaiveTxnLinkedList_addFirstTest.java000066400000000000000000000051711174000617100401560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_addFirstTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.addFirst(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.addFirst("1"); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.addFirst("2"); assertEquals("[2, 1]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenFull() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); try { list.addFirst("3"); fail(); } catch (IllegalStateException expected) { } assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } } NaiveTxnLinkedList_addLastTest.java000066400000000000000000000052451174000617100377740ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_addLastTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.addLast(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.addLast("1"); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.addLast("2"); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenFull() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); try { list.addLast("3"); fail(); } catch (IllegalStateException expected) { } assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } } NaiveTxnLinkedList_add_Test.java000066400000000000000000000052211174000617100373010ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_add_Test { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.add(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenFull() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); try { list.add("3"); fail(); } catch (IllegalStateException expected) { } assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } } NaiveTxnLinkedList_add_int_Test.java000066400000000000000000000002741174000617100401560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Ignore; import org.junit.Test; public class NaiveTxnLinkedList_add_int_Test { @Test @Ignore public void test(){ } } NaiveTxnLinkedList_clearTest.java000066400000000000000000000034131174000617100375010ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_clearTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.clear(); assertEquals(0, list.size()); assertEquals("[]", list.toString()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.put("foo"); list.clear(); assertEquals(0, list.size()); assertEquals("[]", list.toString()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.put("foo"); list.put("bar"); list.clear(); assertEquals(0, list.size()); assertEquals("[]", list.toString()); } }); } } NaiveTxnLinkedList_containsAllTest.java000066400000000000000000000133761174000617100406730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.Arrays; import java.util.LinkedList; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_containsAllTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullCollection_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.containsAll(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenBothEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = list.containsAll(new LinkedList()); assertTrue(result); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenlistEmpty_andCollectionNonEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = list.containsAll(Arrays.asList("1", "2")); assertFalse(result); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenlistNonEmpty_andCollectionEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); boolean result = list.containsAll(new LinkedList()); assertTrue(result); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenExactMatch() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); boolean result = list.containsAll(Arrays.asList("1", "2")); assertTrue(result); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenOrderDifferentThanStillMatch() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("1"); boolean result = list.containsAll(Arrays.asList("1", "2")); assertTrue(result); assertEquals("[1, 2, 1]", list.toString()); assertEquals(3, list.size()); } }); } @Test public void whenNoneMatch() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); boolean result = list.containsAll(Arrays.asList("a", "b")); assertFalse(result); assertEquals("[1, 2, 3]", list.toString()); assertEquals(3, list.size()); } }); } @Test public void whenSomeMatch() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); boolean result = list.containsAll(Arrays.asList("1", "b")); assertFalse(result); assertEquals("[1, 2, 3]", list.toString()); assertEquals(3, list.size()); } }); } @Test public void whenSomeElementsNull() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); boolean result = list.containsAll(Arrays.asList("1", null)); assertFalse(result); assertEquals("[1, 2, 3]", list.toString()); assertEquals(3, list.size()); } }); } } NaiveTxnLinkedList_containsTest.java000066400000000000000000000047711174000617100402410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_containsTest { private Stm stm; private NaiveTxnLinkedList stack; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); stack = new NaiveTxnLinkedList(stm); } @Test public void whenNullItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); boolean result = stack.contains(null); assertFalse(result); assertEquals("[1, 2]", stack.toString()); } }); } @Test public void whenListStack() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = stack.contains("foo"); assertFalse(result); assertEquals("[]", stack.toString()); } }); } @Test public void whenListDoesntContainItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); stack.add("3"); stack.add("4"); boolean result = stack.contains("b"); assertFalse(result); assertEquals("[1, 2, 3, 4]", stack.toString()); } }); } @Test public void whenContainsItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); stack.add("3"); stack.add("4"); boolean result = stack.contains("3"); assertTrue(result); assertEquals("[1, 2, 3, 4]", stack.toString()); } }); } } NaiveTxnLinkedList_descendingIteratorTest.java000066400000000000000000000003071174000617100422270ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Ignore; import org.junit.Test; public class NaiveTxnLinkedList_descendingIteratorTest { @Test @Ignore public void test(){ } } NaiveTxnLinkedList_elementTest.java000066400000000000000000000041741174000617100400510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.NoSuchElementException; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_elementTest { private NaiveTxnLinkedList list; private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.element(); fail(); } catch (NoSuchElementException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.element(); assertEquals("1", found); assertEquals("[2, 3]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.element(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_getFirstTest.java000066400000000000000000000042011174000617100401760ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.NoSuchElementException; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_getFirstTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.getFirst(); fail(); } catch (NoSuchElementException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.getFirst(); assertEquals("1", found); assertEquals("[2, 3]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.getFirst(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_getLastTest.java000066400000000000000000000041601174000617100400160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.NoSuchElementException; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.atomic; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_getLastTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.getLast(); fail(); } catch (NoSuchElementException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.getLast(); assertEquals("3", found); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.getLast(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_get_int_test.java000066400000000000000000000057521174000617100402530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_get_int_test { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenIndexTooSmall() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); try { list.get(-1); fail(); } catch (IndexOutOfBoundsException expected) { } assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenIndexTooBig() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); try { list.get(2); fail(); } catch (IndexOutOfBoundsException expected) { } assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenListContainsSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); String item = list.get(0); assertEquals("1", item); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); list.add("6"); assertEquals("1", list.get(0)); assertEquals("2", list.get(1)); assertEquals("3", list.get(2)); assertEquals("4", list.get(3)); assertEquals("5", list.get(4)); assertEquals("6", list.get(5)); assertEquals("[1, 2, 3, 4, 5, 6]", list.toString()); assertEquals(6, list.size()); } }); } } NaiveTxnLinkedList_indexOfTest.java000066400000000000000000000056561174000617100400220ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_indexOfTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenNullItem_thenMinusOne() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { int result = list.indexOf(null); assertEquals(result, -1); assertEquals("[]", list.toString()); } }); } @Test public void whenEmptyList() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { int result = list.indexOf("a"); assertEquals(result, -1); assertEquals("[]", list.toString()); } }); } @Test public void whenNotFound_thenMinusOne() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); list.add("4"); int result = list.indexOf("a"); assertEquals(result, -1); assertEquals("[1, 2, 3, 4]", list.toString()); } }); } @Test public void whenOnlyOnceInCollection() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); list.add("4"); int result = list.indexOf("2"); assertEquals(1, result); assertEquals("[1, 2, 3, 4]", list.toString()); } }); } @Test public void whenMultipleTimesInCollection() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("2"); list.add("5"); int result = list.indexOf("2"); assertEquals(1, result); assertEquals("[1, 2, 3, 4, 2, 5]", list.toString()); } }); } } NaiveTxnLinkedList_iteratorTest.java000066400000000000000000000002741174000617100402460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Ignore; import org.junit.Test; public class NaiveTxnLinkedList_iteratorTest { @Test @Ignore public void test(){ } } NaiveTxnLinkedList_lastIndexOfTest.java000066400000000000000000000057341174000617100406430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.atomic; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_lastIndexOfTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenNullItem_thenMinusOne() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { int result = list.lastIndexOf(null); assertEquals(result, -1); assertEquals("[]", list.toString()); } }); } @Test public void whenEmptyList() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { int result = list.lastIndexOf("a"); assertEquals(result, -1); assertEquals("[]", list.toString()); } }); } @Test public void whenNotFound_thenMinusOne() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); list.add("4"); int result = list.lastIndexOf("a"); assertEquals(result, -1); assertEquals("[1, 2, 3, 4]", list.toString()); } }); } @Test public void whenOnlyOnceInCollection() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); list.add("4"); int result = list.lastIndexOf("2"); assertEquals(1, result); assertEquals("[1, 2, 3, 4]", list.toString()); } }); } @Test public void whenMultipleTimesInCollection() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("2"); list.add("5"); int result = list.lastIndexOf("2"); assertEquals(4, result); assertEquals("[1, 2, 3, 4, 2, 5]", list.toString()); } }); } } NaiveTxnLinkedList_offerFirstTest.java000066400000000000000000000043141174000617100405250ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.atomic; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_offerFirstTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.offerFirst(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = list.offerFirst("1"); assertTrue(result); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerFirst("1"); boolean result = list.offerFirst("2"); assertTrue(result); assertEquals("[2, 1]", list.toString()); assertEquals(2, list.size()); } }); } @Test @Ignore public void whenFull() { } } NaiveTxnLinkedList_offerLastTest.java000066400000000000000000000043651174000617100403470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.atomic; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_offerLastTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.offer(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.offerLast(item); assertEquals(1, list.size()); assertEquals("[1]", list.toString()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); assertEquals(3, list.size()); assertEquals("[1, 2, 3]", list.toString()); } }); } @Test @Ignore public void whenFull() { } } NaiveTxnLinkedList_offerTest.java000066400000000000000000000044741174000617100375240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.atomic; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_offerTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.offer(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = list.offer("1"); assertTrue(result); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offer("1"); boolean result = list.offer("2"); assertTrue(result); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test @Ignore public void whenFull() { } } NaiveTxnLinkedList_peekFirstTest.java000066400000000000000000000037711174000617100403560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.atomic; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_peekFirstTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String result = list.peekFirst(); assertNull(result); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.peekFirst(); assertEquals("1", found); assertEquals("[1, 2, 3]", list.toString()); assertEquals(3, list.size()); } }); } @Test public void whenSingleItem() { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.peekFirst(); assertSame(item, found); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } } NaiveTxnLinkedList_peekLastTest.java000066400000000000000000000040141174000617100401610ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_peekLastTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String result = list.peekLast(); assertNull(result); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.peekLast(); assertEquals("3", found); assertEquals("[1, 2, 3]", list.toString()); assertEquals(3, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.peekLast(); assertSame(item, found); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } } NaiveTxnLinkedList_peekTest.java000066400000000000000000000037721174000617100373470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_peekTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String result = list.peek(); assertNull(result); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.peek(); assertEquals("1", found); assertEquals("[1, 2, 3]", list.toString()); assertEquals(3, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.peek(); assertSame(item, found); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } } NaiveTxnLinkedList_pollFirstTest.java000066400000000000000000000041441174000617100403730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_pollFirstTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = list.pollFirst(); assertNull(item); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.pollFirst(); assertEquals("1", found); assertEquals("[2, 3]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.pollFirst(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_pollLastTest.java000066400000000000000000000041431174000617100402060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_pollLastTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = list.pollLast(); assertNull(item); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.pollLast(); assertEquals("3", found); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.pollLast(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_pollTest.java000066400000000000000000000037621174000617100373700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_pollTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = list.poll(); assertNull(item); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.poll(); assertEquals("3", found); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.poll(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_popTest.java000066400000000000000000000041551174000617100372150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.NoSuchElementException; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_popTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.pop(); fail(); } catch (NoSuchElementException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.pop(); assertEquals("1", found); assertEquals("[2, 3]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.pop(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_pushTest.java000066400000000000000000000052231174000617100373730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_pushTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.push(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.push("1"); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.push("2"); assertEquals("[2, 1]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenFull() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); try { list.push("3"); fail(); } catch (IllegalStateException expected) { } assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } } NaiveTxnLinkedList_putFirstTest.java000066400000000000000000000042261174000617100402360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_putFirstTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.putFirst(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.putFirst("1"); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.putFirst("1"); list.putFirst("2"); assertEquals("[2, 1]", list.toString()); assertEquals(2, list.size()); } }); } @Test @Ignore public void whenFull() { } } NaiveTxnLinkedList_putLastTest.java000066400000000000000000000042221174000617100400460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_putLastTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.putLast(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.putLast("1"); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.putLast("1"); list.putLast("2"); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test @Ignore public void whenFull() { } } NaiveTxnLinkedList_putTest.java000066400000000000000000000041731174000617100372270ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_putTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.put(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.put("1"); assertEquals("[1]", list.toString()); assertEquals(1, list.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnLinkedList list = new NaiveTxnLinkedList(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.put("1"); list.put("2"); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test @Ignore public void whenFull() { } } NaiveTxnLinkedList_removeFirstOccurrenceTest.java000066400000000000000000000003111174000617100427230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Ignore; import org.junit.Test; public class NaiveTxnLinkedList_removeFirstOccurrenceTest { @Test @Ignore public void test(){ } } NaiveTxnLinkedList_removeFirstTest.java000066400000000000000000000042141174000617100407200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.NoSuchElementException; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_removeFirstTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.removeFirst(); fail(); } catch (NoSuchElementException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.removeFirst(); assertEquals("1", found); assertEquals("[2, 3]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.removeFirst(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_removeLastOccurrenceTest.java000066400000000000000000000003101174000617100425360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Ignore; import org.junit.Test; public class NaiveTxnLinkedList_removeLastOccurrenceTest { @Test @Ignore public void test(){ } } NaiveTxnLinkedList_removeLastTest.java000066400000000000000000000042141174000617100405340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.NoSuchElementException; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_removeLastTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.removeLast(); fail(); } catch (NoSuchElementException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.removeLast(); assertEquals("3", found); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.removeLast(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_removeTest.java000066400000000000000000000041741174000617100377150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.NoSuchElementException; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_removeTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.remove(); fail(); } catch (NoSuchElementException expected) { } assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.remove(); assertEquals("1", found); assertEquals("[2, 3]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.remove(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_remove_Object_test.java000066400000000000000000000003021174000617100413670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Ignore; import org.junit.Test; public class NaiveTxnLinkedList_remove_Object_test { @Test @Ignore public void test(){ } } NaiveTxnLinkedList_remove_int_test.java000066400000000000000000000002771174000617100407660ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Ignore; import org.junit.Test; public class NaiveTxnLinkedList_remove_int_test { @Test @Ignore public void test(){ } } NaiveTxnLinkedList_set2Test.java000066400000000000000000000045511174000617100372740ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_set2Test { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test public void whenIndexTooSmall() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { list.set(-1, "foo"); fail(); } catch (IndexOutOfBoundsException expected) { } assertEquals(0, list.size()); assertEquals("[]", list.toString()); } }); } @Test public void whenIndexTooBig() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); try { list.set(2, "foo"); fail(); } catch (IndexOutOfBoundsException expected) { } assertEquals(2, list.size()); assertEquals("[1, 2]", list.toString()); } }); } @Test public void whenSuccess() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.add("1"); list.add("2"); list.add("3"); list.add("4"); assertEquals("1", list.set(0, "a")); assertEquals("2", list.set(1, "b")); assertEquals("3", list.set(2, "c")); assertEquals("4", list.set(3, "d")); assertEquals(4, list.size()); assertEquals("[a, b, c, d]", list.toString()); } }); } } NaiveTxnLinkedList_takeFirstTest.java000066400000000000000000000040531174000617100403500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_takeFirstTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test @Ignore public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = list.takeFirst(); assertNull(item); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.takeFirst(); assertEquals("1", found); assertEquals("[2, 3]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.takeFirst(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_takeLastTest.java000066400000000000000000000042111174000617100401600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_takeLastTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test @Ignore public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = list.takeLast(); assertNull(item); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.takeLast(); assertEquals("3", found); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.takeLast(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnLinkedList_takeTest.java000066400000000000000000000040301174000617100373330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnLinkedList_takeTest { private Stm stm; private NaiveTxnLinkedList list; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); list = new NaiveTxnLinkedList(stm); } @Test @Ignore public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = list.take(); assertNull(item); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { list.offerLast("1"); list.offerLast("2"); list.offerLast("3"); String found = list.take(); assertEquals("3", found); assertEquals("[1, 2]", list.toString()); assertEquals(2, list.size()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; list.put(item); String found = list.take(); assertSame(item, found); assertEquals("[]", list.toString()); assertEquals(0, list.size()); } }); } } NaiveTxnSet_containsTest.java000066400000000000000000000001171174000617100367200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; public class NaiveTxnSet_containsTest { } NaiveTxnStack_addAllTest.java000066400000000000000000000131301174000617100365740ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_addAllTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullCollectionAdded_thenNullPointerException() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { stack.addAll(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", stack.toString()); } }); } @Test public void whenOneOfItemsIsNull() { final NaiveTxnStack stack = new NaiveTxnStack(stm); try { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { List list = new LinkedList(); list.add("a"); list.add("b"); list.add(null); list.add("d"); try { stack.addAll(list); fail(); } catch (NullPointerException expected) { } assertEquals("[b, a]", stack.toString()); throw new NullPointerException(); } }); fail(); } catch (NullPointerException expected) { } StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertEquals("[]", stack.toString()); assertEquals(0, stack.size()); } }); } @Test public void whenNonEmptyStackAndEmptyCollection() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); stack.addAll(new LinkedList()); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } @Test public void whenBothEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.addAll(new LinkedList()); assertEquals("[]", stack.toString()); assertEquals(0, stack.size()); } }); } @Test public void whenEmptyStackEmptyAndNonEmptyCollection() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { List list = Arrays.asList("1", "2"); stack.addAll(list); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } @Test public void whenBothNonEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { List list = Arrays.asList("2", "1"); stack.add("4"); stack.add("3"); stack.addAll(list); assertEquals("[1, 2, 3, 4]", stack.toString()); assertEquals(4, stack.size()); } }); } @Test public void whenCapacityExceeded() { final NaiveTxnStack stack = new NaiveTxnStack(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); } }); try { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { List c = Arrays.asList("2", "3"); try { stack.addAll(c); fail(); } catch (IllegalStateException expected) { } assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); throw new IllegalStateException(); } }); fail(); } catch (IllegalStateException expected) { } StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertEquals(1, stack.size()); assertEquals("[1]", stack.toString()); } }); } } NaiveTxnStack_addTest.java000066400000000000000000000052621174000617100361520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_addTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { stack.add(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", stack.toString()); assertEquals(0, stack.size()); } }); } @Test public void whenEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = stack.add("1"); assertTrue(result); assertEquals("[1]", stack.toString()); assertEquals(1, stack.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); boolean result = stack.add("2"); assertTrue(result); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } @Test public void whenFull() { final NaiveTxnStack stack = new NaiveTxnStack(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); try { stack.add("3"); fail(); } catch (IllegalStateException expected) { } assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } } NaiveTxnStack_clearTest.java000066400000000000000000000026761174000617100365160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_clearTest { private Stm stm; private NaiveTxnStack stack; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); stack = new NaiveTxnStack(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.clear(); assertTrue(stack.isEmpty()); assertEquals("[]", stack.toString()); } }); } @Test public void whenNotEmpty(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); stack.clear(); assertTrue(stack.isEmpty()); assertEquals("[]", stack.toString()); } }); } } NaiveTxnStack_containsAllTest.java000066400000000000000000000134071174000617100376710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import java.util.Arrays; import java.util.LinkedList; import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_containsAllTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullCollection_thenNullPointerException() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { stack.containsAll(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", stack.toString()); assertEquals(0, stack.size()); } }); } @Test public void whenBothEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = stack.containsAll(new LinkedList()); assertTrue(result); assertEquals("[]", stack.toString()); assertEquals(0, stack.size()); } }); } @Test public void whenStackEmpty_andCollectionNonEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = stack.containsAll(Arrays.asList("1", "2")); assertFalse(result); assertEquals("[]", stack.toString()); assertEquals(0, stack.size()); } }); } @Test public void whenStackNonEmpty_andCollectionEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); boolean result = stack.containsAll(new LinkedList()); assertTrue(result); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } @Test public void whenExactMatch() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); boolean result = stack.containsAll(Arrays.asList("1", "2")); assertTrue(result); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } @Test public void whenOrderDifferentThanStillMatch() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); stack.add("1"); boolean result = stack.containsAll(Arrays.asList("1", "2")); assertTrue(result); assertEquals("[1, 2, 1]", stack.toString()); assertEquals(3, stack.size()); } }); } @Test public void whenNoneMatch() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); stack.add("3"); boolean result = stack.containsAll(Arrays.asList("a", "b")); assertFalse(result); assertEquals("[3, 2, 1]", stack.toString()); assertEquals(3, stack.size()); } }); } @Test public void whenSomeMatch() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); stack.add("3"); boolean result = stack.containsAll(Arrays.asList("1", "b")); assertFalse(result); assertEquals("[3, 2, 1]", stack.toString()); assertEquals(3, stack.size()); } }); } @Test public void whenSomeElementsNull() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.add("1"); stack.add("2"); stack.add("3"); boolean result = stack.containsAll(Arrays.asList("1", null)); assertFalse(result); assertEquals("[3, 2, 1]", stack.toString()); assertEquals(3, stack.size()); } }); } } NaiveTxnStack_containsTest.java000066400000000000000000000050021174000617100372300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_containsTest { private Stm stm; private NaiveTxnStack stack; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); stack = new NaiveTxnStack(stm); } @Test public void whenNullItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); boolean result = stack.contains(null); assertFalse(result); assertEquals("[2, 1]", stack.toString()); } }); } @Test public void whenEmptyStack() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = stack.contains("foo"); assertFalse(result); assertEquals("[]", stack.toString()); } }); } @Test public void whenStackDoesntContainItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); stack.push("3"); stack.push("4"); boolean result = stack.contains("b"); assertFalse(result); assertEquals("[4, 3, 2, 1]", stack.toString()); } }); } @Test public void whenContainsItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); stack.push("3"); stack.push("4"); boolean result = stack.contains("3"); assertTrue(result); assertEquals("[4, 3, 2, 1]", stack.toString()); } }); } } NaiveTxnStack_iteratorTest.java000066400000000000000000000001211174000617100372400ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; public class NaiveTxnStack_iteratorTest { } NaiveTxnStack_offerTest.java000066400000000000000000000051641174000617100365240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_offerTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { stack.offer(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", stack.toString()); assertEquals(0, stack.size()); } }); } @Test public void whenEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { boolean result = stack.offer("1"); assertTrue(result); assertEquals("[1]", stack.toString()); assertEquals(1, stack.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.offer("1"); boolean result = stack.offer("2"); assertTrue(result); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } @Test public void whenFull() { final NaiveTxnStack stack = new NaiveTxnStack(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.offer("1"); stack.offer("2"); boolean result = stack.offer("3"); assertFalse(result); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } } NaiveTxnStack_peekTest.java000066400000000000000000000025751174000617100363520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_peekTest { private Stm stm; private NaiveTxnStack stack; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); stack = new NaiveTxnStack(stm); } @Test public void whenEmpty(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String s = stack.peek(); assertNull(s); assertEquals("[]", stack.toString()); } }); } @Test public void whenNotEmpty(){ StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); String s = stack.peek(); assertSame("2", s); assertEquals("[2, 1]", stack.toString()); } }); } } NaiveTxnStack_pollTest.java000066400000000000000000000035501174000617100363660ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_pollTest { private Stm stm; private NaiveTxnStack stack; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); stack = new NaiveTxnStack(stm); } @Test public void whenEmpty() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = stack.poll(); assertNull(item); assertEquals("[]", stack.toString()); } }); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); String found = stack.poll(); assertEquals("1", found); assertTrue(stack.isEmpty()); assertEquals("[]", stack.toString()); } }); } @Test public void whenMultipleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); String found = stack.poll(); assertEquals("2", found); assertEquals(1, stack.size()); assertEquals("[1]", stack.toString()); } }); } } NaiveTxnStack_popTest.java000066400000000000000000000041121174000617100362110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.RetryError; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_popTest { private Stm stm; private NaiveTxnStack stack; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); stack = new NaiveTxnStack(stm); } @Test public void whenSingleItem() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item = "1"; stack.push(item); String found = stack.pop(); assertSame(found, item); assertEquals(0, stack.size()); assertEquals("[]", stack.toString()); } }); } @Test public void whenMultipleItems() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { String item1 = "1"; String item2 = "2"; stack.push(item1); stack.push(item2); String found = stack.pop(); assertSame(found, item2); assertEquals(1, stack.size()); assertEquals("[1]", stack.toString()); } }); } @Test @Ignore public void whenEmpty_thenRetryError() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { stack.pop(); fail(); } catch (RetryError retry) { } } }); } } NaiveTxnStack_pushTest.java000066400000000000000000000047611174000617100364040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.Stm; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_pushTest { private Stm stm; @Before public void setUp() { stm = getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNullItem_thenNullPointerException() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { try { stack.push(null); fail(); } catch (NullPointerException expected) { } assertEquals("[]", stack.toString()); assertEquals(0, stack.size()); } }); } @Test public void whenEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); assertEquals("[1]", stack.toString()); assertEquals(1, stack.size()); } }); } @Test public void whenNotEmpty() { final NaiveTxnStack stack = new NaiveTxnStack(stm); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } @Test @Ignore public void whenFull() { final NaiveTxnStack stack = new NaiveTxnStack(stm, 2); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { stack.push("1"); stack.push("2"); stack.push("3"); assertEquals("[2, 1]", stack.toString()); assertEquals(2, stack.size()); } }); } } NaiveTxnStack_removeTest.java000066400000000000000000000012541174000617100367140ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/collectionspackage org.multiverse.collections; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Stm; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NaiveTxnStack_removeTest { private Stm stm; private NaiveTxnStack stack; @Before public void setUp(){ stm = getGlobalStmInstance(); clearThreadLocalTxn(); stack = new NaiveTxnStack(stm); } @Test(expected = UnsupportedOperationException.class) public void whenCalled_thenUnsupportedOperationException(){ stack.remove("foo"); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarriers/000077500000000000000000000000001174000617100316735ustar00rootroot00000000000000CountDownCommitBarrier_IntegrationTest.java000066400000000000000000000046201174000617100422640ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_IntegrationTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void testMultipleWaiters() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(2); AwaitThread t1 = new AwaitThread(barrier); t1.start(); sleepMs(1000); assertTrue(t1.isAlive()); AwaitThread t2 = new AwaitThread(barrier); t2.start(); joinAll(t1, t2); assertEquals(0, barrier.getNumberWaiting()); assertIsCommitted(t2.txn); assertIsCommitted(t1.txn); } @Test public void testSingleWaiter() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); AwaitThread t1 = new AwaitThread(barrier); t1.start(); joinAll(t1); assertEquals(0, barrier.getNumberWaiting()); assertTrue(barrier.isCommitted()); assertIsCommitted(t1.txn); } public class AwaitThread extends TestThread { private Txn txn; private final CountDownCommitBarrier barrier; public AwaitThread(CountDownCommitBarrier barrier) { super("AwaitThread"); this.barrier = barrier; } @Override public void doRun() throws Exception { final TxnLong ref = stm.getDefaultRefFactory().newTxnLong(1); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn txn) throws Exception { AwaitThread.this.txn = txn; ref.set(txn, 10); barrier.joinCommitUninterruptibly(txn); } }); } } } CountDownCommitBarrier_StressTest.java000066400000000000000000000115431174000617100412660ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import java.util.Vector; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicLong; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_StressTest { private AtomicLong totalInc; private AtomicLong commitInc; private int oneOfFails = 4; private int refCount = 50; private int maxPartiesCount = 5; private int spawnCountPerThread = 2 * 1000; private int spawnCount = 5; private GammaTxnInteger[] refs; private ThreadPoolExecutor executor = new ThreadPoolExecutor(50, 50, 0, TimeUnit.SECONDS, new LinkedBlockingQueue()); private ThreadPoolExecutor spawnExecutor = new ThreadPoolExecutor(spawnCount, spawnCount, 0, TimeUnit.SECONDS, new LinkedBlockingQueue()); private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = new GammaStm(); commitInc = new AtomicLong(); totalInc = new AtomicLong(); refs = new GammaTxnInteger[refCount]; for (int k = 0; k < refCount; k++) { refs[k] = stm.getDefaultRefFactory().newTxnInteger(0); } } @Test public void test() throws InterruptedException, TimeoutException { for (int k = 0; k < spawnCount; k++) { spawnExecutor.execute(new SpawnTask("SpawnTask-" + k)); } Runnable shutdownTask = new Runnable() { @Override public void run() { spawnExecutor.shutdown(); } }; spawnExecutor.execute(shutdownTask); if (!spawnExecutor.awaitTermination(5, TimeUnit.MINUTES)) { fail("failed to complete test, it took too long"); } System.out.printf("commitInc %s totalInc %s\n", commitInc.get(), totalInc.get()); assertEquals(commitInc.get(), sum()); } public long sum() { long sum = 0; for (int k = 0; k < refCount; k++) { sum += refs[k].atomicGet(); } return sum; } public class SpawnTask implements Runnable { private String name; public SpawnTask(String name) { this.name = name; } @Override public void run() { for (int k = 0; k < spawnCountPerThread; k++) { runOnce(); if (k % 100 == 0) { System.out.println(name + " is at " + k); } } } public void runOnce() { int partyCount = randomInt(maxPartiesCount) + 1; totalInc.addAndGet(partyCount); CountDownCommitBarrier countDownCommitBarrier = new CountDownCommitBarrier(partyCount); Vector txns = new Vector(); for (int k = 0; k < partyCount; k++) { executor.execute(new WorkerTask(k == 0, countDownCommitBarrier, txns)); } countDownCommitBarrier.awaitOpenUninterruptibly(); if (countDownCommitBarrier.isCommitted()) { commitInc.getAndAdd(partyCount); } } } class WorkerTask implements Runnable { final CountDownCommitBarrier countDownCommitBarrier; final boolean first; private Vector txns; WorkerTask(boolean first, CountDownCommitBarrier countDownCommitBarrier, Vector txns) { this.countDownCommitBarrier = countDownCommitBarrier; this.txns = txns; this.first = first; } @Override public void run() { try { clearThreadLocalTxn(); doRun(); } catch (IllegalStateException ignore) { } } public void doRun() { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { sleepRandomMs(10); refs[randomInt(refs.length)].getAndIncrement(tx, 1); sleepRandomMs(10); txns.add(tx); if (first && randomOneOf(oneOfFails)) { countDownCommitBarrier.abort(); } countDownCommitBarrier.joinCommitUninterruptibly(tx); } }); } } } CountDownCommitBarrier_abortTest.java000066400000000000000000000050631174000617100411120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_abortTest { private CountDownCommitBarrier barrier; private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNoPartiesWaiting() { barrier = new CountDownCommitBarrier(1); barrier.abort(); assertTrue(barrier.isAborted()); } @Test public void whenPartiesWaiting_theyAreAborted() { barrier = new CountDownCommitBarrier(3); CommitThread thread1 = new CommitThread(barrier); CommitThread thread2 = new CommitThread(barrier); startAll(thread1, thread2); sleepMs(500); barrier.abort(); sleepMs(500); assertTrue(barrier.isAborted()); assertIsAborted(thread1.txn); assertIsAborted(thread2.txn); } class CommitThread extends TestThread { final CountDownCommitBarrier barrier; Txn txn; CommitThread(CountDownCommitBarrier barrier) { setPrintStackTrace(false); this.barrier = barrier; } @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn txn) throws Exception { CommitThread.this.txn = txn; barrier.joinCommitUninterruptibly(txn); } }); } } @Test public void whenAborted_thenIgnored() { barrier = new CountDownCommitBarrier(1); barrier.abort(); barrier.abort(); assertTrue(barrier.isAborted()); } @Test public void whenCommitted_thenClosedCommitBarrierException() { barrier = new CountDownCommitBarrier(0); try { barrier.abort(); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); } } CountDownCommitBarrier_atomicIncPartiesTest.java000066400000000000000000000065341174000617100432450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_atomicIncPartiesTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenNegativeNumber_thenIllegalArgumentException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); try { barrier.atomicIncParties(-1); fail(); } catch (IllegalArgumentException expected) { } assertEquals(0, barrier.getNumberWaiting()); assertEquals(10, barrier.getParties()); assertTrue(barrier.isClosed()); } @Test public void whenZeroExtraParties() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(5); barrier.atomicIncParties(0); assertEquals(5, barrier.getParties()); assertEquals(0, barrier.getNumberWaiting()); assertTrue(barrier.isClosed()); } @Test public void whenPositiveNumber() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); barrier.atomicIncParties(5); assertEquals(0, barrier.getNumberWaiting()); assertEquals(15, barrier.getParties()); assertTrue(barrier.isClosed()); } @Test public void whenPartiesAdded_commitTakesLonger() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(2); barrier.atomicIncParties(1); barrier.countDown(); barrier.countDown(); assertTrue(barrier.isClosed()); barrier.countDown(); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenPendingTransactions() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(3); JoinCommitThread t1 = new JoinCommitThread(stm, barrier); JoinCommitThread t2 = new JoinCommitThread(stm, barrier); startAll(t1, t2); sleepMs(500); assertTrue(barrier.isClosed()); barrier.atomicIncParties(1); sleepMs(500); assertAlive(t1, t2); assertTrue(barrier.isClosed()); assertEquals(2, barrier.getNumberWaiting()); assertEquals(4, barrier.getParties()); } @Test public void whenAborted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.abort(); try { barrier.atomicIncParties(10); fail(); } catch (CommitBarrierOpenException expected) { } assertEquals(1, barrier.getParties()); assertEquals(0, barrier.getNumberWaiting()); assertTrue(barrier.isAborted()); } @Test public void whenCommitted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(0); try { barrier.atomicIncParties(); fail(); } catch (CommitBarrierOpenException expected) { } assertEquals(0, barrier.getParties()); assertEquals(0, barrier.getNumberWaiting()); assertTrue(barrier.isCommitted()); } } CountDownCommitBarrier_awaitOpenTest.java000066400000000000000000000055221174000617100417320ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_awaitOpenTest { private CountDownCommitBarrier barrier; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenStartInterrupted_thenInterruptedException() { barrier = new CountDownCommitBarrier(1); Thread.currentThread().interrupt(); try { barrier.awaitOpen(); fail(); } catch (InterruptedException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenInterruptedWhileWaiting_thenInterruptedException() { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { try { barrier.awaitOpen(); fail(); } catch (InterruptedException expected) { } } }; t.start(); sleepMs(500); t.interrupt(); joinAll(t); } @Test public void whenAbortedWhileWaiting() { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpen(); } }; t.start(); sleepMs(500); barrier.abort(); joinAll(t); } @Test public void whenCommittedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpen(); } }; t.start(); sleepMs(500); barrier.countDown(); joinAll(t); assertTrue(barrier.isCommitted()); } @Test public void whenCommitted() throws InterruptedException { barrier = new CountDownCommitBarrier(0); barrier.awaitOpen(); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAborted() throws InterruptedException { barrier = new CountDownCommitBarrier(1); barrier.abort(); barrier.awaitOpen(); assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } } CountDownCommitBarrier_awaitOpenUninterruptiblyTest.java000066400000000000000000000057231174000617100450750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_awaitOpenUninterruptiblyTest { private CountDownCommitBarrier barrier; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenStartInterrupted() { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { Thread.currentThread().interrupt(); barrier.awaitOpenUninterruptibly(); } }; t.start(); sleepMs(500); assertAlive(t); barrier.abort(); joinAll(t); } @Test public void whenInterruptedWhileWaiting() { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpenUninterruptibly(); } }; t.start(); sleepMs(500); t.interrupt(); sleepMs(500); assertAlive(t); barrier.abort(); joinAll(t); } @Test public void whenAbortedWhileWaiting() { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpenUninterruptibly(); } }; t.start(); sleepMs(500); barrier.abort(); joinAll(t); } @Test public void whenCommittedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpenUninterruptibly(); } }; t.start(); sleepMs(500); barrier.countDown(); joinAll(t); assertTrue(barrier.isCommitted()); } @Test public void whenCommitted() throws InterruptedException { barrier = new CountDownCommitBarrier(0); barrier.awaitOpenUninterruptibly(); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAborted() throws InterruptedException { barrier = new CountDownCommitBarrier(1); barrier.abort(); barrier.awaitOpenUninterruptibly(); assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } } CountDownCommitBarrier_constructorTest.java000066400000000000000000000025051174000617100423660ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.multiverse.TestUtils.clearCurrentThreadInterruptedStatus; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_constructorTest { @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test(expected = IllegalArgumentException.class) public void whenNegativeParties_thenIllegalArgumentException() { new CountDownCommitBarrier(-1); } @Test public void whenZeroParties_thenBarrierCommitted() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(0); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getParties()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenPositiveParties() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); assertTrue(barrier.isClosed()); assertEquals(10, barrier.getParties()); assertEquals(0, barrier.getNumberWaiting()); } } CountDownCommitBarrier_countDownTest.java000066400000000000000000000036131174000617100417620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.assertTrue; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_countDownTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenLastOne_thenBarrierOpened() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(3); JoinCommitThread t1 = new JoinCommitThread(stm, barrier); JoinCommitThread t2 = new JoinCommitThread(stm, barrier); startAll(t1, t2); sleepMs(500); assertAlive(t1, t2); assertTrue(barrier.isClosed()); barrier.countDown(); assertTrue(barrier.isCommitted()); joinAll(t1, t2); assertNothingThrown(t1,t2); } @Test public void whenNotLastOne() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(4); JoinCommitThread t1 = new JoinCommitThread(stm, barrier); JoinCommitThread t2 = new JoinCommitThread(stm, barrier); startAll(t1, t2); sleepMs(500); assertAlive(t1, t2); assertTrue(barrier.isClosed()); barrier.countDown(); assertTrue(barrier.isClosed()); sleepMs(500); assertAlive(t1, t2); } @Test public void whenAborted_thenIgnored() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.abort(); barrier.countDown(); assertTrue(barrier.isAborted()); } @Test public void whenCommitted_thenIgnored() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(0); barrier.countDown(); assertTrue(barrier.isCommitted()); } } CountDownCommitBarrier_incPartiesWithTransactionTest.java000066400000000000000000000140331174000617100451430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_incPartiesWithTransactionTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenNegativeNumber_thenIllegalArgumentException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); try { barrier.atomicIncParties(-1); fail(); } catch (IllegalArgumentException expected) { } assertEquals(0, barrier.getNumberWaiting()); assertEquals(10, barrier.getParties()); assertTrue(barrier.isClosed()); } @Test public void whenNullTransaction_thenNullPointerException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); try { barrier.incParties(null, 1); fail(); } catch (NullPointerException expected) { } assertEquals(0, barrier.getNumberWaiting()); assertEquals(10, barrier.getParties()); assertTrue(barrier.isClosed()); } @Test public void whenTransactionPrepared_thenPreparedTransactionFailure() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); Txn tx = stm.newDefaultTxn(); tx.prepare(); try { barrier.incParties(tx, 5); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertEquals(0, barrier.getNumberWaiting()); assertEquals(10, barrier.getParties()); assertTrue(barrier.isClosed()); } @Test public void whenTransactionAborted_thenDeadTxnException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); Txn tx = stm.newDefaultTxn(); tx.abort(); try { barrier.incParties(tx, 1); fail(); } catch (DeadTxnException expected) { } assertEquals(0, barrier.getNumberWaiting()); assertEquals(10, barrier.getParties()); assertTrue(barrier.isClosed()); } @Test public void whenTransactionCommitted_thenDeadTxnException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); Txn tx = stm.newDefaultTxn(); tx.commit(); try { barrier.incParties(tx, 1); fail(); } catch (DeadTxnException expected) { } assertEquals(0, barrier.getNumberWaiting()); assertEquals(10, barrier.getParties()); assertTrue(barrier.isClosed()); } @Test public void whenZeroExtraParties() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(5); Txn tx = stm.newDefaultTxn(); barrier.incParties(tx, 0); assertEquals(5, barrier.getParties()); assertEquals(0, barrier.getNumberWaiting()); assertTrue(barrier.isClosed()); } @Test public void whenPositiveNumber() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(10); Txn tx = stm.newDefaultTxn(); barrier.incParties(tx, 5); assertIsActive(tx); assertEquals(0, barrier.getNumberWaiting()); assertEquals(15, barrier.getParties()); assertTrue(barrier.isClosed()); } @Test public void whenPartiesAdded_thenAdditionalJoinsNeedToBeExecuted() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(2); Txn tx = stm.newDefaultTxn(); barrier.incParties(tx, 1); barrier.countDown(); barrier.countDown(); assertTrue(barrier.isClosed()); barrier.countDown(); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenTransactionAborted_thenPartiesRestored() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(2); Txn tx = stm.newDefaultTxn(); barrier.incParties(tx, 10); tx.abort(); assertIsAborted(tx); assertTrue(barrier.isClosed()); assertEquals(2, barrier.getParties()); } @Test public void whenPendingTransactions() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(3); JoinCommitThread t1 = new JoinCommitThread(stm, barrier); JoinCommitThread t2 = new JoinCommitThread(stm, barrier); startAll(t1, t2); sleepMs(300); barrier.atomicIncParties(2); sleepMs(300); assertAlive(t1, t2); assertEquals(2, barrier.getNumberWaiting()); assertEquals(5, barrier.getParties()); } @Test public void whenAborted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.abort(); Txn tx = stm.newDefaultTxn(); try { barrier.incParties(tx, 10); fail("Should have got CommitBarrierOpenException"); } catch (CommitBarrierOpenException expected) { } assertEquals(1, barrier.getParties()); assertEquals(0, barrier.getNumberWaiting()); assertTrue(barrier.isAborted()); } @Test public void whenCommitted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(0); barrier.countDown(); Txn tx = stm.newDefaultTxn(); try { barrier.incParties(tx, 1); fail("Should have got CommitBarrierOpenException"); } catch (CommitBarrierOpenException expected) { } assertIsActive(tx); assertEquals(0, barrier.getParties()); assertEquals(0, barrier.getNumberWaiting()); assertTrue(barrier.isCommitted()); } } CountDownCommitBarrier_joinCommitTest.java000066400000000000000000000132151174000617100421110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_joinCommitTest { private CountDownCommitBarrier barrier; private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNullTransaction() throws InterruptedException { barrier = new CountDownCommitBarrier(1); try { barrier.joinCommit(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenLastOneEntering() throws InterruptedException { barrier = new CountDownCommitBarrier(1); Txn tx = stm.newTxnFactoryBuilder() .setSpeculative(false) .newTransactionFactory() .newTxn(); barrier.joinCommit(tx); assertIsCommitted(tx); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAbortedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(2); final GammaTxnInteger ref = stm.getDefaultRefFactory().newTxnInteger(0); TestThread t = new TestThread() { @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.set(tx, 10); barrier.joinCommit(tx); } }); } }; t.setPrintStackTrace(false); t.start(); sleepMs(1000); assertAlive(t); assertTrue(barrier.isClosed()); barrier.abort(); t.join(); t.assertFailedWithException(IllegalStateException.class); assertTrue(barrier.isAborted()); assertEquals(0, ref.atomicGet()); } @Test public void whenCommittedWhileWaiting() { barrier = new CountDownCommitBarrier(3); JoinCommitThread t1 = new JoinCommitThread(stm, barrier); JoinCommitThread t2 = new JoinCommitThread(stm, barrier); startAll(t1, t2); sleepMs(500); barrier.countDown(); joinAll(t1, t2); assertTrue(barrier.isCommitted()); } @Test public void whenInterruptedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(2); final GammaTxnInteger ref = stm.getDefaultRefFactory().newTxnInteger(0); TestThread t = new TestThread() { @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().executeChecked(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.set(tx, 10); barrier.joinCommit(tx); } }); } }; t.setPrintStackTrace(false); t.start(); sleepMs(500); t.interrupt(); t.join(); t.assertFailedWithException(InterruptedException.class); assertEquals(0, ref.atomicGet()); assertTrue(barrier.isAborted()); } @Test public void whenTransactionAlreadyCommitted() throws InterruptedException { barrier = new CountDownCommitBarrier(1); Txn tx = stm.newDefaultTxn(); tx.commit(); try { barrier.joinCommit(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertTrue(barrier.isClosed()); } @Test public void whenTransactionAlreadyAborted_thenDeadTxnException() throws InterruptedException { barrier = new CountDownCommitBarrier(1); Txn tx = stm.newDefaultTxn(); tx.abort(); try { barrier.joinCommit(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertTrue(barrier.isClosed()); } @Test public void whenAborted_thenCommitBarrierOpenException() throws InterruptedException { barrier = new CountDownCommitBarrier(1); barrier.abort(); Txn tx = stm.newDefaultTxn(); try { barrier.joinCommit(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenCommitted_thenCommitBarrierOpenException() throws InterruptedException { barrier = new CountDownCommitBarrier(0); Txn tx = stm.newDefaultTxn(); try { barrier.joinCommit(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } } CountDownCommitBarrier_joinCommitUninterruptiblyTest.java000066400000000000000000000114531174000617100452530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_joinCommitUninterruptiblyTest { private CountDownCommitBarrier barrier; private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenOpenAndNullTransaction_thenNullPointerException() { barrier = new CountDownCommitBarrier(1); try { barrier.joinCommitUninterruptibly(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenOpenAndThreadAlreadyInterrupted_thenNotInterruptedButInterruptStatusIsSet() { barrier = new CountDownCommitBarrier(1); Thread.currentThread().interrupt(); Txn tx = stm.newDefaultTxn(); barrier.joinCommitUninterruptibly(tx); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); assertTrue(Thread.currentThread().isInterrupted()); } @Test public void whenOpenAndTransactionActive() { Txn tx = stm.newDefaultTxn(); tx.prepare(); barrier = new CountDownCommitBarrier(1); barrier.joinCommitUninterruptibly(tx); assertIsCommitted(tx); assertTrue(barrier.isCommitted()); } @Test public void whenOpenAndTransactionPrepared() { Txn tx = stm.newDefaultTxn(); tx.prepare(); barrier = new CountDownCommitBarrier(1); barrier.joinCommitUninterruptibly(tx); assertIsCommitted(tx); assertTrue(barrier.isCommitted()); } @Test public void whenOpenAndLastTransaction_thenAllTransactionsCommitted() { barrier = new CountDownCommitBarrier(3); AwaitThread t1 = new AwaitThread(); AwaitThread t2 = new AwaitThread(); startAll(t1, t2); sleepMs(500); assertAlive(t1, t2); assertTrue(barrier.isClosed()); Txn tx = stm.newDefaultTxn(); barrier.joinCommitUninterruptibly(tx); joinAll(t1, t2); assertIsCommitted(tx, t1.txn, t2.txn); } @Test public void whenOpenAndTransactionAborted_thenDeadTxnException() { Txn tx = stm.newDefaultTxn(); tx.abort(); barrier = new CountDownCommitBarrier(1); try { barrier.joinCommitUninterruptibly(tx); fail(); } catch (DeadTxnException ex) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenOpenAndTransactionCommitted_thenDeadTxnException() { Txn tx = stm.newDefaultTxn(); tx.commit(); barrier = new CountDownCommitBarrier(1); try { barrier.joinCommitUninterruptibly(tx); fail(); } catch (DeadTxnException ex) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAborted_thenCommitBarrierOpenException() { barrier = new CountDownCommitBarrier(1); barrier.abort(); Txn tx = stm.newDefaultTxn(); try { barrier.joinCommitUninterruptibly(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); } @Test public void whenCommitted_thenCommitBarrierOpenException() { barrier = new CountDownCommitBarrier(1); barrier.joinCommitUninterruptibly(stm.newDefaultTxn()); Txn tx = stm.newDefaultTxn(); try { barrier.joinCommitUninterruptibly(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertIsAborted(tx); } class AwaitThread extends TestThread { private Txn txn; @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn txn) throws Exception { AwaitThread.this.txn = txn; barrier.joinCommitUninterruptibly(txn); } }); } } } CountDownCommitBarrier_joinCommitUninterruptiblyWithTransactionTest.java000066400000000000000000000157041174000617100503200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnStatus; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.references.TxnInteger; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_joinCommitUninterruptiblyWithTransactionTest { private CountDownCommitBarrier barrier; private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenTransactionNull_thenFailWithNullPointerException() { barrier = new CountDownCommitBarrier(1); try { barrier.joinCommitUninterruptibly(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenTransactionFailsToPrepare() { barrier = new CountDownCommitBarrier(1); Txn tx = mock(Txn.class); when(tx.getStatus()).thenReturn(TxnStatus.Active); doThrow(new RuntimeException()).when(tx).prepare(); try { barrier.joinCommitUninterruptibly(tx); fail("Expecting Runtime Exception thrown on Txn preparation"); } catch (RuntimeException ex) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenTransactionAborted_thenDeadTxnException() { barrier = new CountDownCommitBarrier(1); Txn tx = stm.newDefaultTxn(); tx.abort(); try { barrier.joinCommitUninterruptibly(tx); fail("Should have thrown DeadTxnException"); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenTransactionCommitted_thenDeadTxnException() { barrier = new CountDownCommitBarrier(1); Txn tx = stm.newDefaultTxn(); tx.commit(); try { barrier.joinCommitUninterruptibly(tx); fail("Should have thrown DeadTxnException"); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test @Ignore public void whenStartingInterrupted() throws InterruptedException { } @Test public void whenInterruptedWhileWaiting_thenNoInterruption() throws InterruptedException { barrier = new CountDownCommitBarrier(2); final TxnInteger ref = stm.getDefaultRefFactory().newTxnInteger(10); TestThread t = new TestThread() { @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(tx, 1); barrier.joinCommitUninterruptibly(tx); } }); } }; t.setPrintStackTrace(false); t.start(); sleepMs(500); t.interrupt(); sleepMs(500); assertAlive(t); assertTrue(barrier.isClosed()); //todo //assertTrue(t.isInterrupted()); } @Test public void whenCommittedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(2); final GammaTxnInteger ref = stm.getDefaultRefFactory().newTxnInteger(0); TestThread t = new TestThread() { @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(tx, 1); barrier.joinCommitUninterruptibly(tx); } }); } }; t.setPrintStackTrace(false); t.start(); sleepMs(500); barrier.countDown(); sleepMs(500); t.join(); assertNothingThrown(t); assertTrue(barrier.isCommitted()); assertEquals(1, ref.atomicGet()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAbortedWhileWaiting_() throws InterruptedException { barrier = new CountDownCommitBarrier(2); final GammaTxnInteger ref = stm.getDefaultRefFactory().newTxnInteger(0); TestThread t = new TestThread() { @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getAndIncrement(tx, 1); barrier.joinCommitUninterruptibly(tx); } }); } }; t.setPrintStackTrace(false); t.start(); sleepMs(500); barrier.abort(); sleepMs(500); t.join(); t.assertFailedWithException(IllegalStateException.class); assertTrue(barrier.isAborted()); assertEquals(0, ref.atomicGet()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAborted_thenCommitBarrierOpenException() { barrier = new CountDownCommitBarrier(1); barrier.abort(); Txn tx = stm.newDefaultTxn(); try { barrier.joinCommitUninterruptibly(tx); fail("Expecting CommitBarrierOpenException"); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); assertIsAborted(tx); } @Test public void whenCommitted_thenCommitBarrierOpenException() { barrier = new CountDownCommitBarrier(0); Txn tx = stm.newDefaultTxn(); try { barrier.joinCommitUninterruptibly(tx); fail("Expecting CommitBarrierOpenException"); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); assertIsAborted(tx); } } CountDownCommitBarrier_registerOnAbortTaskTest.java000066400000000000000000000054671174000617100437470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_registerOnAbortTaskTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenNullTask_thenNullPointerException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); try { barrier.registerOnAbortTask(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenAborted_thenTaskExecuted() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); Runnable task = mock(Runnable.class); barrier.registerOnAbortTask(task); barrier.abort(); verify(task, times(1)).run(); } @Test public void whenCommitted_thenTaskNotExecuted() throws InterruptedException { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); Runnable task = mock(Runnable.class); barrier.registerOnAbortTask(task); barrier.countDown(); verify(task, never()).run(); } @Test public void whenTaskThrowsRuntimeException_thenOtherTasksNotExecuted() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); Runnable task1 = mock(Runnable.class); doThrow(new FakeException()).when(task1).run(); Runnable task2 = mock(Runnable.class); barrier.registerOnAbortTask(task1); barrier.registerOnAbortTask(task2); try { barrier.abort(); fail(); } catch (FakeException expected) { } verify(task2, never()).run(); } static class FakeException extends RuntimeException { } @Test public void whenCommitted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(0); Runnable task = mock(Runnable.class); try { barrier.registerOnAbortTask(task); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); verify(task, never()).run(); } @Test public void whenAborted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.abort(); Runnable task = mock(Runnable.class); try { barrier.registerOnAbortTask(task); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); verify(task, never()).run(); } } CountDownCommitBarrier_registerOnCommitTaskTest.java000066400000000000000000000055371174000617100441260ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_registerOnCommitTaskTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenNullTask_thenNullPointerException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); try { barrier.registerOnCommitTask(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenAborted_thenTaskNotExecuted() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); Runnable task = mock(Runnable.class); barrier.registerOnCommitTask(task); barrier.abort(); verify(task, never()).run(); } @Test public void whenCommitted_thenTaskExecuted() throws InterruptedException { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); Runnable task = mock(Runnable.class); barrier.registerOnCommitTask(task); barrier.countDown(); verify(task, times(1)).run(); } @Test public void whenTaskThrowsRuntimeException_thenOtherTasksNotExecuted() throws InterruptedException { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); Runnable task1 = mock(Runnable.class); doThrow(new FakeException()).when(task1).run(); Runnable task2 = mock(Runnable.class); barrier.registerOnCommitTask(task1); barrier.registerOnCommitTask(task2); try { barrier.countDown(); fail(); } catch (FakeException expected) { } verify(task2, never()).run(); } static class FakeException extends RuntimeException { } @Test public void whenCommitted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(0); Runnable task = mock(Runnable.class); try { barrier.registerOnCommitTask(task); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); verify(task, never()).run(); } @Test public void whenAborted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.abort(); Runnable task = mock(Runnable.class); try { barrier.registerOnCommitTask(task); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); verify(task, never()).run(); } } CountDownCommitBarrier_setTimeoutTest.java000066400000000000000000000044661174000617100421530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_setTimeoutTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenNullTimeUnit_thenNullPointerException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); try { barrier.setTimeout(10, null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenTimedOut() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.setTimeout(1000, TimeUnit.MILLISECONDS); sleepMs(3000); assertTrue(barrier.isAborted()); } @Test public void whenCommittedBeforeTimeout() throws InterruptedException { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.setTimeout(1000, TimeUnit.MILLISECONDS); barrier.countDown(); sleepMs(2000); assertTrue(barrier.isCommitted()); } @Test public void whenAbortedBeforeTimeout() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.setTimeout(1000, TimeUnit.MILLISECONDS); barrier.abort(); sleepMs(2000); assertTrue(barrier.isAborted()); } @Test public void whenCommitted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(0); try { barrier.setTimeout(10, TimeUnit.SECONDS); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); } @Test public void whenAborted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.abort(); try { barrier.setTimeout(10, TimeUnit.SECONDS); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); } } CountDownCommitBarrier_tryAwaitOpenTest.java000066400000000000000000000101061174000617100424230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_tryAwaitOpenTest { private CountDownCommitBarrier barrier; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNullTimeUnit_thenNullPointerException() throws InterruptedException { barrier = new CountDownCommitBarrier(1); try { barrier.tryAwaitOpen(10, null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenNegativeTimeoutAndBufferedOpen() throws InterruptedException { barrier = new CountDownCommitBarrier(1); boolean result = barrier.tryAwaitOpen(-1, TimeUnit.DAYS); assertFalse(result); assertTrue(barrier.isClosed()); } @Test public void whenAbortedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(2); TestThread t = new TestThread() { @Override public void doRun() throws Exception { boolean success = barrier.tryAwaitOpen(1, TimeUnit.DAYS); assertTrue(success); } }; t.start(); sleepMs(500); barrier.abort(); assertEventuallyNotAlive(t); assertNothingThrown(t); assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenCommittedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { boolean success = barrier.tryAwaitOpen(1, TimeUnit.DAYS); assertTrue(success); } }; t.start(); sleepMs(500); barrier.countDown(); t.join(); assertNothingThrown(t); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenInterruptedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(2); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.tryAwaitOpen(1, TimeUnit.DAYS); fail(); } }; t.setPrintStackTrace(false); t.start(); sleepMs(500); t.interrupt(); t.join(); t.assertFailedWithException(InterruptedException.class); assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenTimeoutWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(2); TestThread t = new TestThread() { @Override public void doRun() throws Exception { boolean success = barrier.tryAwaitOpen(1, TimeUnit.SECONDS); assertFalse(success); } }; t.start(); t.join(); assertTrue(barrier.isClosed()); } @Test public void whenAborted() throws InterruptedException { barrier = new CountDownCommitBarrier(1); barrier.abort(); boolean result = barrier.tryAwaitOpen(1, TimeUnit.DAYS); assertTrue(result); assertTrue(barrier.isAborted()); } @Test public void whenCommitted() throws InterruptedException { barrier = new CountDownCommitBarrier(0); boolean result = barrier.tryAwaitOpen(1, TimeUnit.DAYS); assertTrue(result); assertTrue(barrier.isCommitted()); } } CountDownCommitBarrier_tryAwaitOpenUninterruptiblyTest.java000066400000000000000000000045311174000617100455700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.TestThread; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_tryAwaitOpenUninterruptiblyTest { private CountDownCommitBarrier barrier; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNullTimeout_thenNullPointerException() { barrier = new CountDownCommitBarrier(1); try { barrier.tryAwaitOpenUninterruptibly(1, null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test @Ignore public void whenInterruptedWhileWaiting() { } @Test public void whenCommittedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(1); TestThread t = new TestThread() { @Override public void doRun() throws Exception { boolean result = barrier.tryAwaitOpenUninterruptibly(1, TimeUnit.DAYS); assertTrue(result); } }; t.start(); sleepMs(500); assertAlive(t); barrier.countDown(); t.join(); assertNothingThrown(t); assertTrue(barrier.isCommitted()); } @Test @Ignore public void whenAbortedWhileWaiting() { } @Test @Ignore public void whenTimeout() { } @Test public void whenCommitted() { barrier = new CountDownCommitBarrier(0); boolean result = barrier.tryAwaitOpenUninterruptibly(1, TimeUnit.DAYS); assertTrue(result); assertTrue(barrier.isCommitted()); } @Test public void whenAborted() { barrier = new CountDownCommitBarrier(1); barrier.abort(); boolean result = barrier.tryAwaitOpenUninterruptibly(1, TimeUnit.DAYS); assertTrue(result); assertTrue(barrier.isAborted()); } } CountDownCommitBarrier_tryJoinCommitTest.java000066400000000000000000000060471174000617100426150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.clearCurrentThreadInterruptedStatus; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_tryJoinCommitTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenOpenAndNullTransaction_thenNullPointerException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); try { barrier.tryJoinCommit(null); fail("Expecting NullPointerException"); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenOpenAndTransactionCommitted_thenDeadTxnException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); Txn tx = stm.newDefaultTxn(); tx.commit(); try { barrier.tryJoinCommit(tx); fail(); } catch (DeadTxnException ex) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenOpenAndTransactionAborted_DeadTxnException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); Txn tx = stm.newDefaultTxn(); tx.abort(); try { barrier.tryJoinCommit(tx); fail(); } catch (DeadTxnException ex) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAborted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(1); barrier.abort(); Txn tx = stm.newDefaultTxn(); try { barrier.tryJoinCommit(tx); fail("Expecting CommitBarrierOpenException"); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); assertIsAborted(tx); } @Test public void whenCommitted_thenCommitBarrierOpenException() { CountDownCommitBarrier barrier = new CountDownCommitBarrier(0); Txn tx = stm.newDefaultTxn(); try { barrier.tryJoinCommit(tx); fail("Expected CommitBarrierOpenException"); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); assertIsAborted(tx); } } CountDownCommitBarrier_tryJoinCommitWithTimeoutTest.java000066400000000000000000000077011174000617100450160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class CountDownCommitBarrier_tryJoinCommitWithTimeoutTest { private CountDownCommitBarrier barrier; private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNullTransaction_thenNullPointerException() throws InterruptedException { barrier = new CountDownCommitBarrier(1); try { barrier.tryJoinCommit(null, 1, TimeUnit.DAYS); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenNullTimeout_thenNullPointerException() throws InterruptedException { barrier = new CountDownCommitBarrier(1); Txn tx = stm.newDefaultTxn(); try { barrier.tryJoinCommit(tx, 1, null); fail(); } catch (NullPointerException expected) { } assertIsActive(tx); assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test @Ignore public void whenNotLastOne() { } @Test @Ignore public void whenInterruptedWhileWaiting() { } @Test @Ignore public void whenTimeout() { } @Test @Ignore public void whenAbortedWhileWaiting() { } @Test public void whenCommittedWhileWaiting() throws InterruptedException { barrier = new CountDownCommitBarrier(2); final GammaTxnInteger ref = stm.getDefaultRefFactory().newTxnInteger(0); TestThread t = new TestThread() { @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getAndIncrement(tx, 1); boolean result = barrier.tryJoinCommit(tx, 1, TimeUnit.DAYS); assertTrue(result); } }); } }; t.start(); sleepMs(500); barrier.countDown(); t.join(); assertNothingThrown(t); assertTrue(barrier.isCommitted()); assertEquals(1, ref.atomicGet()); } @Test public void whenAborted_thenCommitBarrierOpenException() throws InterruptedException { barrier = new CountDownCommitBarrier(1); barrier.abort(); Txn tx = stm.newDefaultTxn(); try { barrier.tryJoinCommit(tx, 1, TimeUnit.DAYS); fail(); } catch (CommitBarrierOpenException expected) { } assertIsActive(tx); assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenCommitted_thenCommitBarrierOpenException() throws InterruptedException { barrier = new CountDownCommitBarrier(0); Txn tx = stm.newDefaultTxn(); try { barrier.tryJoinCommit(tx, 1, TimeUnit.DAYS); fail(); } catch (CommitBarrierOpenException expected) { } assertIsActive(tx); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } } JoinCommitThread.java000066400000000000000000000015441174000617100356630ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.assertNotNull; /** * @author Peter Veentjer */ public class JoinCommitThread extends TestThread { private final CountDownCommitBarrier barrier; private final GammaStm stm; public JoinCommitThread(GammaStm stm, CountDownCommitBarrier barrier) { this.barrier = barrier; this.stm = stm; } @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertNotNull(tx); barrier.joinCommit(tx); } }); } } VetoCommitBarrier_abortTest.java000066400000000000000000000056311174000617100401100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_abortTest { private VetoCommitBarrier barrier; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); stm = new GammaStm(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNoPreparedTransactions() { barrier = new VetoCommitBarrier(); barrier.abort(); assertTrue(barrier.isAborted()); } @Test public void whenPendingTransactions_theyAreAborted() throws InterruptedException { barrier = new VetoCommitBarrier(); GammaTxnInteger ref = new GammaTxnInteger(stm, 0); IncThread thread1 = new IncThread(ref); IncThread thread2 = new IncThread(ref); startAll(thread1, thread2); sleepMs(500); barrier.abort(); thread1.join(); thread2.join(); assertEquals(0, ref.atomicGet()); assertIsAborted(thread1.txn); assertIsAborted(thread2.txn); thread1.assertFailedWithException(CommitBarrierOpenException.class); thread2.assertFailedWithException(CommitBarrierOpenException.class); } @Test public void whenBarrierAborted_thenCallIgnored() { barrier = new VetoCommitBarrier(); barrier.abort(); barrier.abort(); assertTrue(barrier.isAborted()); } @Test public void whenBarrierCommitted_thenCommitBarrierOpenException() { barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); try { barrier.abort(); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); } public class IncThread extends TestThread { private final GammaTxnInteger ref; private Txn txn; public IncThread(GammaTxnInteger ref) { super("IncThread"); setPrintStackTrace(false); this.ref = ref; } @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn txn) throws Exception { IncThread.this.txn = txn; ref.incrementAndGet(txn, 1); barrier.joinCommit(txn); } }); } } } VetoCommitBarrier_awaitOpenTest.java000066400000000000000000000054551174000617100407340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_awaitOpenTest { private VetoCommitBarrier barrier; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenStartInterrupted_thenInterruptedException() { barrier = new VetoCommitBarrier(); Thread.currentThread().interrupt(); try { barrier.awaitOpen(); fail(); } catch (InterruptedException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenInterruptedWhileWaiting_thenInterruptedException() { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { try { barrier.awaitOpen(); fail(); } catch (InterruptedException expected) { } } }; t.start(); sleepMs(500); t.interrupt(); joinAll(t); } @Test public void whenAbortedWhileWaiting() { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpen(); } }; t.start(); sleepMs(500); barrier.abort(); joinAll(t); } @Test public void whenCommittedWhileWaiting() { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpen(); } }; t.start(); sleepMs(500); barrier.atomicVetoCommit(); joinAll(t); } @Test public void whenCommitted() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); barrier.awaitOpen(); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAborted() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.abort(); barrier.awaitOpen(); assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } } VetoCommitBarrier_awaitOpenUninterruptibleTest.java000066400000000000000000000057201174000617100440430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_awaitOpenUninterruptibleTest { private VetoCommitBarrier barrier; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenStartInterrupted_thenInterruptedException() { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { Thread.currentThread().interrupt(); barrier.awaitOpenUninterruptibly(); } }; t.start(); sleepMs(500); assertAlive(t); barrier.atomicVetoCommit(); joinAll(t); } @Test public void whenInterruptedWhileWaiting_thenInterruptedException() { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpenUninterruptibly(); } }; t.start(); sleepMs(500); t.interrupt(); sleepMs(500); assertAlive(t); barrier.atomicVetoCommit(); joinAll(t); } @Test public void whenAbortedWhileWaiting() { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpenUninterruptibly(); } }; t.start(); sleepMs(500); barrier.abort(); joinAll(t); } @Test public void whenCommittedWhileWaiting() { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { barrier.awaitOpenUninterruptibly(); } }; t.start(); sleepMs(500); barrier.atomicVetoCommit(); joinAll(t); } @Test public void whenCommitted() throws InterruptedException { barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); barrier.awaitOpenUninterruptibly(); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenAborted() throws InterruptedException { barrier = new VetoCommitBarrier(); barrier.abort(); barrier.awaitOpenUninterruptibly(); assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } } VetoCommitBarrier_integrationTest.java000066400000000000000000000052101174000617100413150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public class VetoCommitBarrier_integrationTest { private VetoCommitBarrier barrier; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); stm = new GammaStm(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void test() throws InterruptedException { barrier = new VetoCommitBarrier(); GammaTxnInteger ref1 = new GammaTxnInteger(stm); GammaTxnInteger ref2 = new GammaTxnInteger(stm); CommitThread t1 = new CommitThread(1, ref1); CommitThread t2 = new CommitThread(2, ref2); startAll(t1, t2); sleepMs(1000); barrier.atomicVetoCommit(); joinAll(t1, t2); assertEquals(1, ref1.atomicGet()); assertEquals(1, ref2.atomicGet()); } @Test public void testAbort() throws InterruptedException { barrier = new VetoCommitBarrier(); GammaTxnInteger ref1 = new GammaTxnInteger(stm); GammaTxnInteger ref2 = new GammaTxnInteger(stm); CommitThread t1 = new CommitThread(1, ref1); t1.setPrintStackTrace(false); CommitThread t2 = new CommitThread(2, ref2); t2.setPrintStackTrace(false); startAll(t1, t2); sleepMs(500); barrier.abort(); t1.join(); t2.join(); assertEquals(0, ref1.atomicGet()); assertEquals(0, ref2.atomicGet()); } public class CommitThread extends TestThread { private GammaTxnInteger ref; public CommitThread(int id, GammaTxnInteger ref) { super("CommitThread-" + id); this.ref = ref; } @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getAndIncrement(tx, 1); barrier.joinCommit(getThreadLocalTxn()); } }); } } } VetoCommitBarrier_joinCommitTest.java000066400000000000000000000160171174000617100411110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnFactory; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.TooManyRetriesException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_joinCommitTest { private GammaStm stm; private TxnFactory txFactory; @Before public void setUp() { stm = new GammaStm(); txFactory = stm.newTxnFactoryBuilder() .setSpeculative(false) .newTransactionFactory(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenTransactionNull_thenNullPointerException() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); try { barrier.joinCommit(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test @Ignore public void whenTransactionPreparable_thenAdded() { VetoCommitBarrier barrier = new VetoCommitBarrier(); GammaTxnInteger ref = new GammaTxnInteger(stm); IncThread thread = new IncThread(ref, barrier); thread.start(); sleepMs(1000); assertAlive(thread); assertTrue(barrier.isClosed()); assertEquals(1, barrier.getNumberWaiting()); } @Test @Ignore public void whenTransactionPrepared_thenAdded() { VetoCommitBarrier barrier = new VetoCommitBarrier(); GammaTxnInteger ref = new GammaTxnInteger(stm); IncThread thread = new IncThread(ref, barrier, true); thread.start(); sleepMs(1000); assertAlive(thread); assertTrue(barrier.isClosed()); assertEquals(1, barrier.getNumberWaiting()); } @Test @Ignore public void whenPrepareFails() throws InterruptedException { final VetoCommitBarrier group = new VetoCommitBarrier(); final GammaTxnInteger ref = new GammaTxnInteger(stm); FailToPrepareThread thread = new FailToPrepareThread(group, ref); thread.start(); sleepMs(1000); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(tx, 1); } }); thread.join(); thread.assertFailedWithException(TooManyRetriesException.class); assertEquals(0, group.getNumberWaiting()); } class FailToPrepareThread extends TestThread { final VetoCommitBarrier group; final GammaTxnInteger ref; FailToPrepareThread(VetoCommitBarrier group, GammaTxnInteger ref) { super("FailedToPrepareThread"); this.group = group; this.ref = ref; setPrintStackTrace(false); } @Override public void doRun() throws Exception { stm.newTxnFactoryBuilder() .setSpeculative(false) .setMaxRetries(0) .newTxnExecutor() .execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { //we need to load it to cause a conflict ref.get(tx); sleepMs(2000); ref.incrementAndGet(tx, 1); group.joinCommit(tx); } }); } } @Test public void whenTransactionAborted_thenDeadTxnException() throws InterruptedException { Txn tx = txFactory.newTxn(); tx.abort(); VetoCommitBarrier group = new VetoCommitBarrier(); try { group.joinCommit(tx); fail(); } catch (DeadTxnException expected) { } assertTrue(group.isClosed()); assertIsAborted(tx); assertEquals(0, group.getNumberWaiting()); } @Test public void whenTransactionCommitted_thenDeadTxnException() throws InterruptedException { Txn tx = txFactory.newTxn(); tx.commit(); VetoCommitBarrier group = new VetoCommitBarrier(); try { group.joinCommit(tx); fail(); } catch (DeadTxnException expected) { } assertTrue(group.isClosed()); assertIsCommitted(tx); assertEquals(0, group.getNumberWaiting()); } @Test public void whenBarrierAborted_thenCommitBarrierOpenException() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.abort(); Txn tx = txFactory.newTxn(); try { barrier.joinCommit(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertIsActive(tx); assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenCommitted_thenCommitBarrierOpenException() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); System.out.println("barrier.state: " + barrier); Txn tx = txFactory.newTxn(); try { barrier.joinCommit(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertIsActive(tx); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } public class IncThread extends TestThread { private final GammaTxnInteger ref; private final VetoCommitBarrier barrier; private boolean prepare; public IncThread(GammaTxnInteger ref, VetoCommitBarrier barrier) { this(ref, barrier, false); } public IncThread(GammaTxnInteger ref, VetoCommitBarrier barrier, boolean prepare) { super("IncThread"); this.barrier = barrier; this.ref = ref; this.prepare = prepare; } @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(tx, 1); if (prepare) { tx.prepare(); } barrier.joinCommit(tx); } }); } } } VetoCommitBarrier_registerOnAbortTaskTest.java000066400000000000000000000054341174000617100427360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_registerOnAbortTaskTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenNullTask_thenNullPointerException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); try { barrier.registerOnAbortTask(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenAborted_thenTaskExecuted() { VetoCommitBarrier barrier = new VetoCommitBarrier(); Runnable task = mock(Runnable.class); barrier.registerOnAbortTask(task); barrier.abort(); verify(task, times(1)).run(); } @Test public void whenCommitted_thenTaskNotExecuted() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); Runnable task = mock(Runnable.class); barrier.registerOnAbortTask(task); barrier.atomicVetoCommit(); verify(task, never()).run(); } @Test public void whenTaskThrowsRuntimeException_thenOtherTasksNotExecuted() { VetoCommitBarrier barrier = new VetoCommitBarrier(); Runnable task1 = mock(Runnable.class); doThrow(new FakeException()).when(task1).run(); Runnable task2 = mock(Runnable.class); barrier.registerOnAbortTask(task1); barrier.registerOnAbortTask(task2); try { barrier.abort(); fail(); } catch (FakeException expected) { } verify(task2, never()).run(); } static class FakeException extends RuntimeException { } @Test public void whenCommitted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); Runnable task = mock(Runnable.class); try { barrier.registerOnAbortTask(task); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); verify(task, never()).run(); } @Test public void whenAborted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.abort(); Runnable task = mock(Runnable.class); try { barrier.registerOnAbortTask(task); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); verify(task, never()).run(); } } VetoCommitBarrier_registerOnCommitTaskTest.java000066400000000000000000000054661174000617100431240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_registerOnCommitTaskTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenNullTask_thenNullPointerException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); try { barrier.registerOnCommitTask(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenAborted_thenTaskNotExecuted() { VetoCommitBarrier barrier = new VetoCommitBarrier(); Runnable task = mock(Runnable.class); barrier.registerOnCommitTask(task); barrier.abort(); verify(task, never()).run(); } @Test public void whenCommitted_thenTaskExecuted() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); Runnable task = mock(Runnable.class); barrier.registerOnCommitTask(task); barrier.atomicVetoCommit(); verify(task, times(1)).run(); } @Test public void whenTaskThrowsRuntimeException_thenOtherTasksNotExecuted() { VetoCommitBarrier barrier = new VetoCommitBarrier(); Runnable task1 = mock(Runnable.class); doThrow(new FakeException()).when(task1).run(); Runnable task2 = mock(Runnable.class); barrier.registerOnCommitTask(task1); barrier.registerOnCommitTask(task2); try { barrier.atomicVetoCommit(); fail(); } catch (FakeException expected) { } verify(task2, never()).run(); } private static class FakeException extends RuntimeException { } @Test public void whenCommitted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); Runnable task = mock(Runnable.class); try { barrier.registerOnCommitTask(task); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); verify(task, never()).run(); } @Test public void whenAborted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.abort(); Runnable task = mock(Runnable.class); try { barrier.registerOnCommitTask(task); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); verify(task, never()).run(); } } VetoCommitBarrier_setTimeoutTest.java000066400000000000000000000043731174000617100411450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.Before; import org.junit.Test; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_setTimeoutTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenNullTimeUnit_thenNullPointerException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); try { barrier.setTimeout(10, null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenTimedOut() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.setTimeout(500, TimeUnit.MILLISECONDS); sleepMs(1000); assertTrue(barrier.isAborted()); } @Test public void whenCommittedBeforeTimeout() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.setTimeout(500, TimeUnit.MILLISECONDS); barrier.atomicVetoCommit(); sleepMs(1000); assertTrue(barrier.isCommitted()); } @Test public void whenAbortedBeforeTimeout() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.setTimeout(500, TimeUnit.MILLISECONDS); barrier.abort(); sleepMs(1000); assertTrue(barrier.isAborted()); } @Test public void whenCommitted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); try { barrier.setTimeout(10, TimeUnit.SECONDS); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); } @Test public void whenAborted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.abort(); try { barrier.setTimeout(10, TimeUnit.SECONDS); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); } } VetoCommitBarrier_tryAwaitOpenTest.java000066400000000000000000000075101174000617100414250ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_tryAwaitOpenTest { private VetoCommitBarrier barrier; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNullTimeout_thenNullPointerException() throws InterruptedException { barrier = new VetoCommitBarrier(); try { barrier.tryAwaitOpen(1, null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenAlreadyInterrupted() { Thread.currentThread().interrupt(); barrier = new VetoCommitBarrier(); try { barrier.tryAwaitOpen(1, TimeUnit.DAYS); fail(); } catch (InterruptedException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenInterruptedWhileWaiting() throws InterruptedException { barrier = new VetoCommitBarrier(); TestThread thread = new TestThread() { @Override public void doRun() throws Exception { barrier.tryAwaitOpen(1, TimeUnit.DAYS); } }; thread.setPrintStackTrace(false); thread.start(); sleepMs(500); thread.interrupt(); thread.join(); thread.assertFailedWithException(InterruptedException.class); //assertIsOpen() } @Test public void whenCommittedWhileWaiting() { barrier = new VetoCommitBarrier(); TestThread thread = new TestThread() { @Override public void doRun() throws Exception { barrier.tryAwaitOpen(1, TimeUnit.DAYS); } }; thread.setPrintStackTrace(false); thread.start(); sleepMs(500); thread.interrupt(); //thread.join(); //thread.assertFailedWithException(InterruptedException.class); } @Test public void whenAbortedWhileWaiting() throws InterruptedException { barrier = new VetoCommitBarrier(); TestThread thread = new TestThread() { @Override public void doRun() throws Exception { boolean result = barrier.tryAwaitOpen(1, TimeUnit.DAYS); assertTrue(result); } }; thread.setPrintStackTrace(false); thread.start(); sleepMs(500); barrier.abort(); joinAll(thread); } @Test public void whenTimeout() throws InterruptedException { barrier = new VetoCommitBarrier(); TestThread thread = new TestThread() { @Override public void doRun() throws Exception { boolean result = barrier.tryAwaitOpen(1, TimeUnit.SECONDS); assertFalse(result); } }; thread.setPrintStackTrace(false); thread.start(); joinAll(thread); } @Test public void whenAborted() throws InterruptedException { barrier = new VetoCommitBarrier(); barrier.abort(); boolean success = barrier.tryAwaitOpen(1, TimeUnit.DAYS); assertTrue(barrier.isAborted()); assertTrue(success); } @Test public void whenCommitted() throws InterruptedException { barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); barrier.awaitOpen(); assertTrue(barrier.isCommitted()); } } VetoCommitBarrier_tryAwaitOpenUninterruptiblyTest.java000066400000000000000000000073151174000617100445700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_tryAwaitOpenUninterruptiblyTest { private VetoCommitBarrier barrier; @Before public void setUp() { clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNullTimeout_thenNullPointerException() { barrier = new VetoCommitBarrier(); try { barrier.tryAwaitOpenUninterruptibly(1, null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenInterruptedWhileWaiting() throws InterruptedException { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() { boolean result = barrier.tryAwaitOpenUninterruptibly(1500, TimeUnit.MILLISECONDS); assertFalse(result); } }; t.start(); sleepMs(500); assertAlive(t); t.interrupt(); t.join(); assertNothingThrown(t); assertTrue(t.hasEndedWithInterruptStatus()); assertTrue(barrier.isClosed()); } @Test public void whenCommittedWhileWaiting() throws InterruptedException { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { boolean result = barrier.tryAwaitOpenUninterruptibly(1, TimeUnit.DAYS); assertTrue(result); } }; t.start(); sleepMs(500); assertAlive(t); barrier.atomicVetoCommit(); t.join(); assertNothingThrown(t); assertTrue(barrier.isCommitted()); } @Test public void whenAbortedWhileWaiting() throws InterruptedException { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { boolean result = barrier.tryAwaitOpenUninterruptibly(1, TimeUnit.DAYS); assertTrue(result); } }; t.start(); sleepMs(500); assertAlive(t); barrier.abort(); t.join(); assertNothingThrown(t); assertTrue(barrier.isAborted()); } @Test public void whenTimeout() throws InterruptedException { barrier = new VetoCommitBarrier(); TestThread t = new TestThread() { @Override public void doRun() throws Exception { boolean result = barrier.tryAwaitOpenUninterruptibly(1, TimeUnit.SECONDS); assertFalse(result); } }; t.start(); t.join(); assertNothingThrown(t); } @Test public void whenCommitted() { barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); boolean result = barrier.tryAwaitOpenUninterruptibly(1, TimeUnit.DAYS); assertTrue(result); assertTrue(barrier.isCommitted()); } @Test public void whenAborted() { barrier = new VetoCommitBarrier(); barrier.abort(); boolean result = barrier.tryAwaitOpenUninterruptibly(1, TimeUnit.DAYS); assertTrue(result); assertTrue(barrier.isAborted()); } } VetoCommitBarrier_vetoCommitTest.java000066400000000000000000000062641174000617100411320ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_vetoCommitTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNoPendingTransactions() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); assertTrue(barrier.isCommitted()); } @Test public void whenPendingTransactions() { VetoCommitBarrier barrier = new VetoCommitBarrier(); GammaTxnInteger ref1 = new GammaTxnInteger(stm); GammaTxnInteger ref2 = new GammaTxnInteger(stm); GammaTxnInteger ref3 = new GammaTxnInteger(stm); IncThread thread1 = new IncThread(ref1, barrier); IncThread thread2 = new IncThread(ref2, barrier); IncThread thread3 = new IncThread(ref3, barrier); startAll(thread1, thread2, thread3); sleepMs(500); barrier.atomicVetoCommit(); joinAll(thread1, thread2, thread3); assertIsCommitted(thread1.txn); assertIsCommitted(thread2.txn); assertIsCommitted(thread3.txn); assertEquals(1, ref1.atomicGet()); assertEquals(1, ref2.atomicGet()); assertEquals(1, ref3.atomicGet()); } @Test public void whenBarrierCommitted_thenIgnored() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); barrier.atomicVetoCommit(); assertTrue(barrier.isCommitted()); } @Test public void whenBarrierAborted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.abort(); try { barrier.atomicVetoCommit(); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); } public class IncThread extends TestThread { private final GammaTxnInteger ref; private final VetoCommitBarrier barrier; private Txn txn; public IncThread(GammaTxnInteger ref, VetoCommitBarrier barrier) { super("IncThread"); this.barrier = barrier; this.ref = ref; } @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn txn) throws Exception { IncThread.this.txn = txn; ref.getAndIncrement(txn, 1); barrier.joinCommit(txn); } }); } } } VetoCommitBarrier_vetoCommitWithTransactionTest.java000066400000000000000000000114521174000617100441670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/commitbarrierspackage org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_vetoCommitWithTransactionTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenNullTx_thenNullPointerException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); try { barrier.vetoCommit(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); } @Test public void whenNoPendingTransactions() { VetoCommitBarrier barrier = new VetoCommitBarrier(); Txn tx = stm.newDefaultTxn(); barrier.vetoCommit(tx); assertTrue(barrier.isCommitted()); assertIsCommitted(tx); } @Test @Ignore public void whenPendingTransaction() throws InterruptedException { final VetoCommitBarrier barrier = new VetoCommitBarrier(); final GammaTxnInteger ref = new GammaTxnInteger(stm); TestThread t = new TestThread() { @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(tx, 1); barrier.joinCommit(tx); } }); } }; t.start(); sleepMs(500); assertAlive(t); assertTrue(barrier.isClosed()); barrier.atomicVetoCommit(); t.join(); assertNothingThrown(t); assertTrue(barrier.isCommitted()); assertEquals(1, ref.atomicGet()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenTransactionFailedToPrepare_thenBarrierNotAbortedOrCommitted() { final GammaTxnInteger ref = new GammaTxnInteger(stm); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); //conflicting write ref.atomicIncrementAndGet(1); ref.incrementAndGet(tx, 1); VetoCommitBarrier barrier = new VetoCommitBarrier(); try { barrier.vetoCommit(tx); fail(); } catch (ReadWriteConflict expected) { } assertTrue(barrier.isClosed()); } @Test public void whenTransactionAborted_thenDeadTxnException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); Txn tx = stm.newDefaultTxn(); tx.abort(); try { barrier.vetoCommit(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertTrue(barrier.isClosed()); } @Test public void whenTransactionCommitted_thenDeadTxnException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); Txn tx = stm.newDefaultTxn(); tx.commit(); try { barrier.vetoCommit(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertTrue(barrier.isClosed()); } @Test public void whenBarrierCommitted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); Txn tx = stm.newDefaultTxn(); try { barrier.vetoCommit(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isCommitted()); assertIsActive(tx); } @Test public void whenBarrierAborted_thenCommitBarrierOpenException() { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.abort(); Txn tx = stm.newDefaultTxn(); try { barrier.vetoCommit(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertTrue(barrier.isAborted()); assertIsActive(tx); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/000077500000000000000000000000001174000617100276375ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/000077500000000000000000000000001174000617100307215ustar00rootroot00000000000000BenchmarkUtils.java000077500000000000000000000064501174000617100344300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import java.text.NumberFormat; import java.util.*; public class BenchmarkUtils { public static int[] generateProcessorRange() { return generateProcessorRange(Runtime.getRuntime().availableProcessors()); } public static int[] generateProcessorRange(int maxProcessors) { List list = new LinkedList(); for (int k = 1; k <= 16; k++) { if (k <= maxProcessors) { list.add(k); } } list.add(maxProcessors); int k = 16; while (k < maxProcessors) { k = (int) (k * 1.07); if (k <= maxProcessors) { list.add(k); } } //remove all bigger than maxProcessors for (Integer value : list) { if (value > maxProcessors) { list.remove(value); } } //remove all duplicates list = new LinkedList(new HashSet(list)); //sort them Collections.sort(list); Integer[] integerArray = new Integer[list.size()]; integerArray = list.toArray(integerArray); int[] result = new int[integerArray.length]; for (int l = 0; l < integerArray.length; l++) { result[l] = integerArray[l]; } return result; } public static void toGnuplot(Result[] result) { println("---------------------------------------------"); println("------------------ GNUPLOT ------------------"); println("---------------------------------------------"); println("set terminal png"); println("set output \"result.png\""); println("set xlabel \"threads\""); println("set origin 0,0"); println("set ylabel \"transactions/second\""); println("plot '-' using 1:2 with lines"); for (Result aResult : result) { println("%s %s", aResult.processorCount, aResult.performance); } println("e"); println(""); } public static void println(String s, Object... args) { System.out.printf(s + "\n", args); } public static String transactionsPerSecondAsString(long count, long timeMs) { double performance = (1000 * count) / timeMs; return format(performance); } public static String transactionsPerSecondPerThreadAsString(long transactionsPerThread, long totalTimeMs, int threads) { return format(transactionsPerSecondPerThread(transactionsPerThread, totalTimeMs, threads)); } public static double transactionsPerSecondPerThread(long transactionsPerThread, long totalTimeMs, int threads) { long totalTransactions = transactionsPerThread * threads; return (1000d * totalTransactions) / totalTimeMs; } public static double transactionsPerSecond(long transactionsPerThread, long totalTimeMs, int threads) { return threads * transactionsPerSecondPerThread(transactionsPerThread, totalTimeMs, threads); } public static String transactionsPerSecondAsString(long transactionsPerThread, long totalTimeMs, int threads) { return format(transactionsPerSecond(transactionsPerThread, totalTimeMs, threads)); } public static String format(double value) { return NumberFormat.getInstance(Locale.US).format(value); } }FatGammaTxnExecutor_propagationLevelTest.java000066400000000000000000000207311174000617100416310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.PropagationLevel; import org.multiverse.api.callables.TxnIntCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.api.exceptions.TxnNotAllowedException; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import static junit.framework.Assert.assertEquals; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.api.TxnThreadLocal.*; public class FatGammaTxnExecutor_propagationLevelTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenNeverAndTransactionAvailable_thenNoTransactionAllowedException() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Never) .newTxnExecutor(); GammaTxn otherTx = stm.newDefaultTxn(); setThreadLocalTxn(otherTx); TxnVoidCallable callable = mock(TxnVoidCallable.class); try { executor.execute(callable); fail(); } catch (TxnNotAllowedException expected) { } verifyZeroInteractions(callable); assertIsActive(otherTx); assertSame(otherTx, getThreadLocalTxn()); } @Test public void whenNeverAndNoTransactionAvailable() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Never) .newTxnExecutor(); TxnIntCallable callable = new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { assertNull(tx); return 10; } }; int result = executor.execute(callable); assertEquals(10, result); assertNull(getThreadLocalTxn()); } @Test public void whenMandatoryAndNoTransactionAvailable_thenNoTransactionFoundException() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Mandatory) .newTxnExecutor(); TxnVoidCallable callable = mock(TxnVoidCallable.class); try { executor.execute(callable); fail(); } catch (TxnMandatoryException expected) { } verifyZeroInteractions(callable); assertNull(getThreadLocalTxn()); } @Test public void whenMandatoryAndTransactionAvailable_thenExistingTransactionUsed() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Mandatory) .newTxnExecutor(); final GammaTxn otherTx = stm.newDefaultTxn(); setThreadLocalTxn(otherTx); TxnIntCallable callable = new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { assertSame(otherTx, tx); return 10; } }; int result = executor.execute(callable); assertEquals(10, result); assertIsActive(otherTx); assertSame(otherTx, getThreadLocalTxn()); } @Test public void whenRequiresAndNoTransactionAvailable_thenNewTransactionUsed() { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Requires) .newTransactionFactory(); final GammaTxnLong ref = new GammaTxnLong(stm); TxnIntCallable callable = new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { assertNotNull(tx); GammaTxn btx = (GammaTxn) tx; ref.incrementAndGet(1); return 10; } }; int result = new FatGammaTxnExecutor(txFactory).execute(callable); assertEquals(10, result); assertNull(getThreadLocalTxn()); assertEquals(1, ref.atomicGet()); } @Test public void whenRequiresAndTransactionAvailable_thenExistingTransactionUsed() { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Requires) .newTransactionFactory(); final GammaTxn existingTx = stm.newDefaultTxn(); setThreadLocalTxn(existingTx); final GammaTxnLong ref = new GammaTxnLong(stm); TxnIntCallable callable = new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { assertSame(existingTx, tx); GammaTxn btx = (GammaTxn) tx; ref.incrementAndGet(btx, 1); return 10; } }; int result = new FatGammaTxnExecutor(txFactory).execute(callable); assertEquals(10, result); assertSame(existingTx, getThreadLocalTxn()); assertIsActive(existingTx); //since the value hasn't committed yet, it still is zero (the value before the transaction began). assertEquals(0, ref.atomicGet()); } @Test public void whenRequiresNewAndNoTransactionAvailable_thenNewTransactionCreated() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.RequiresNew) .newTxnExecutor(); final GammaTxnLong ref = new GammaTxnLong(stm, 0); TxnIntCallable callable = new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { assertNotNull(tx); GammaTxn btx = (GammaTxn) tx; ref.incrementAndGet(btx, 1); return 10; } }; int result = executor.execute(callable); assertEquals(10, result); assertEquals(1, ref.atomicGet()); assertNull(getThreadLocalTxn()); } @Test public void whenRequiresNewAndTransactionAvailable_thenExistingTransactionSuspended() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.RequiresNew) .newTxnExecutor(); final GammaTxn otherTx = stm.newDefaultTxn(); setThreadLocalTxn(otherTx); final GammaTxnLong ref = new GammaTxnLong(stm, 10); TxnIntCallable callable = new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { assertNotNull(tx); assertNotSame(otherTx, tx); GammaTxn btx = (GammaTxn) tx; ref.incrementAndGet(btx, 1); return 1; } }; int result = executor.execute(callable); assertEquals(1, result); assertEquals(11, ref.atomicGet()); assertSame(otherTx, getThreadLocalTxn()); assertIsActive(otherTx); } @Test public void whenSupportsAndTransactionAvailable() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Supports) .newTxnExecutor(); final GammaTxn otherTx = stm.newDefaultTxn(); setThreadLocalTxn(otherTx); TxnIntCallable callable = new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { assertSame(otherTx, tx); return 10; } }; int result = executor.execute(callable); assertEquals(10, result); assertIsActive(otherTx); assertSame(otherTx, getThreadLocalTxn()); } @Test public void whenSupportsAndNoTransactionAvailable() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Supports) .newTxnExecutor(); TxnIntCallable callable = new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { assertNull(tx); return 10; } }; int result = executor.execute(callable); assertEquals(10, result); assertNull(getThreadLocalTxn()); } } GammaObjectPool_arrayListTest.java000066400000000000000000000022171174000617100374040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import static org.junit.Assert.*; public class GammaObjectPool_arrayListTest { private GammaObjectPool pool; @Before public void setUp() { pool = new GammaObjectPool(); } @Test(expected = NullPointerException.class) public void whenNullArrayList_thenNullPointerException() { pool.putArrayList(null); } @Test public void whenPlacedInPoolThenCleared() { ArrayList list = new ArrayList(); list.add("foo"); list.add("bar"); pool.putArrayList(list); assertTrue(list.isEmpty()); } @Test public void whenSuccess() { ArrayList list1 = new ArrayList(); ArrayList list2 = new ArrayList(); ArrayList list3 = new ArrayList(); pool.putArrayList(list1); pool.putArrayList(list2); pool.putArrayList(list3); assertSame(list3, pool.takeArrayList()); assertSame(list2, pool.takeArrayList()); assertSame(list1, pool.takeArrayList()); assertNotNull(pool.takeArrayList()); } } GammaObjectPool_callableNodeTest.java000066400000000000000000000030131174000617100377720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.functions.Function; import org.multiverse.stms.gamma.transactionalobjects.CallableNode; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; public class GammaObjectPool_callableNodeTest { private GammaObjectPool pool; @Before public void setUp() { pool = new GammaObjectPool(); } @Test(expected = NullPointerException.class) public void whenPutNullNode_thenNullPointerException() { pool.putCallableNode(null); } @Test public void whenPutInPool_thenPreparedForPooling() { Function function = mock(Function.class); CallableNode next = new CallableNode(null, null); CallableNode node = new CallableNode(function, next); pool.putCallableNode(node); assertNull(node.function); assertNull(node.next); } @Test public void whenSuccess() { Function function = mock(Function.class); CallableNode node1 = new CallableNode(function, null); CallableNode node2 = new CallableNode(function, null); CallableNode node3 = new CallableNode(function, null); pool.putCallableNode(node1); pool.putCallableNode(node2); pool.putCallableNode(node3); assertSame(node3, pool.takeCallableNode()); assertSame(node2, pool.takeCallableNode()); assertSame(node1, pool.takeCallableNode()); assertNotNull(pool.takeCallableNode()); } } GammaObjectPool_listenerArrayTest.java000066400000000000000000000006321174000617100402550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; public class GammaObjectPool_listenerArrayTest { private GammaObjectPool pool; @Before public void setUp() { pool = new GammaObjectPool(); } @Test(expected = NullPointerException.class) public void whenNullPutInPool_thenNullPointerException() { pool.putListenersArray(null); } } GammaObjectPool_listenersTest.java000066400000000000000000000030051174000617100374360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.blocking.DefaultRetryLatch; import static org.junit.Assert.*; public class GammaObjectPool_listenersTest { private GammaObjectPool pool; @Before public void setUp() { pool = new GammaObjectPool(); } @Test(expected = NullPointerException.class) public void whenNullPutInPool_thenNullPointerException() { pool.putListeners(null); } @Test public void whenPutInPool_thenPreparedForPooling() { DefaultRetryLatch latch = new DefaultRetryLatch(); latch.reset(); Listeners next = new Listeners(); Listeners listeners = new Listeners(); listeners.listener = latch; listeners.listenerEra = latch.getEra(); listeners.next = next; pool.putListeners(listeners); assertNull(listeners.next); assertNull(listeners.listener); assertEquals(Long.MIN_VALUE, listeners.listenerEra); } @Test public void test() { Listeners listeners1 = new Listeners(); Listeners listeners2 = new Listeners(); Listeners listeners3 = new Listeners(); pool.putListeners(listeners1); pool.putListeners(listeners2); pool.putListeners(listeners3); assertSame(listeners3, pool.takeListeners()); assertSame(listeners2, pool.takeListeners()); assertSame(listeners1, pool.takeListeners()); assertNotNull(pool.takeListeners()); } } GammaObjectPool_tranlocalArrayTest.java000066400000000000000000000034671174000617100404200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; public class GammaObjectPool_tranlocalArrayTest implements GammaConstants { private GammaObjectPool pool; private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); pool = new GammaObjectPool(); } @Test public void whenItemPutInPool_thenPreparedForPooling() { Tranlocal[] array = new Tranlocal[2]; GammaTxn tx = stm.newDefaultTxn(); array[0] = new GammaTxnLong(stm).openForRead(tx, LOCKMODE_NONE); array[1] = new GammaTxnLong(stm).openForRead(tx, LOCKMODE_NONE); pool.putTranlocalArray(array); assertNull(array[0]); assertNull(array[1]); } @Test(expected = NullPointerException.class) public void whenNullArrayAdded_thenNullPointerException() { pool.putTranlocalArray(null); } @Test public void normalScenario_0() { normalScenario(0); } @Test public void normalScenario_1() { normalScenario(1); } @Test public void normalScenario_10() { normalScenario(10); } @Test public void normalScenario_100() { normalScenario(100); } public void normalScenario(int size) { Tranlocal[] array = new Tranlocal[size]; pool.putTranlocalArray(array); Tranlocal[] result = pool.takeTranlocalArray(array.length); assertSame(array, result); Tranlocal[] result2 = pool.takeTranlocalArray(array.length); assertNotNull(result2); assertNotSame(result, result2); } } GammaStmConfigTest.java000066400000000000000000000075101174000617100352040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Test; import org.multiverse.api.LockMode; public class GammaStmConfigTest { @Test(expected = IllegalStateException.class) public void readBiasedThreshold_whenNegative() { GammaStmConfig config = new GammaStmConfig(); config.readBiasedThreshold = -1; config.validate(); } @Test(expected = IllegalStateException.class) public void readBiasedThreshold_whenTooBig() { GammaStmConfig config = new GammaStmConfig(); config.readBiasedThreshold = 1024; config.validate(); } @Test(expected = IllegalStateException.class) public void propagationLevel_whenNull() { GammaStmConfig config = new GammaStmConfig(); config.propagationLevel = null; config.validate(); } @Test(expected = IllegalStateException.class) public void isolationLevel_whenNull() { GammaStmConfig config = new GammaStmConfig(); config.isolationLevel = null; config.validate(); } @Test(expected = IllegalStateException.class) public void readLockMode_whenNull() { GammaStmConfig config = new GammaStmConfig(); config.readLockMode = null; config.validate(); } @Test(expected = IllegalStateException.class) public void writeLockMode_whenNull() { GammaStmConfig config = new GammaStmConfig(); config.writeLockMode = null; config.validate(); } @Test(expected = IllegalStateException.class) public void writeLockMode_whenSmallerThanReadLockMode() { GammaStmConfig config = new GammaStmConfig(); config.writeLockMode = LockMode.None; config.readLockMode = LockMode.Exclusive; config.validate(); } @Test(expected = IllegalStateException.class) public void backoffPolicy_whenNull() { GammaStmConfig config = new GammaStmConfig(); config.backoffPolicy = null; config.validate(); } @Test(expected = IllegalStateException.class) public void traceLevel_whenNull() { GammaStmConfig config = new GammaStmConfig(); config.traceLevel = null; config.validate(); } @Test(expected = IllegalStateException.class) public void maximumPoorMansConflictScanLength_whenNegative() { GammaStmConfig config = new GammaStmConfig(); config.maximumPoorMansConflictScanLength = -1; config.validate(); } @Test(expected = IllegalStateException.class) public void maximumFixedLengthTransactionSize_whenSmallerThan1() { GammaStmConfig config = new GammaStmConfig(); config.maxFixedLengthTransactionSize = 0; config.validate(); } @Test(expected = IllegalStateException.class) public void spinCount_whenSmallerThanZero() { GammaStmConfig config = new GammaStmConfig(); config.spinCount = -1; config.validate(); } @Test(expected = IllegalStateException.class) public void maxRetries_whenSmallerThanZero() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = -1; config.validate(); } @Test(expected = IllegalStateException.class) public void minimalVariableLengthTransactionSize_whenSmallerThan1() { GammaStmConfig config = new GammaStmConfig(); config.minimalVariableLengthTransactionSize = 0; config.validate(); } @Test(expected = IllegalStateException.class) public void blockingAllowed_whenNoReadTracking() { GammaStmConfig config = new GammaStmConfig(); config.blockingAllowed = true; config.trackReads = false; config.validate(); } @Test(expected = IllegalStateException.class) public void timeout_whenSmallerThanZero() { GammaStmConfig config = new GammaStmConfig(); config.timeoutNs = -1; config.validate(); } } GammaStmTxnFactoryBuilder_argumentsTest.java000066400000000000000000000035421174000617100414750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; public class GammaStmTxnFactoryBuilder_argumentsTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test(expected = NullPointerException.class) public void whenNullBackoffPolicy_thenNullPointerException() { stm.newTxnFactoryBuilder().setBackoffPolicy(null); } @Test(expected = NullPointerException.class) public void whenNullFamilyName_thenNullPointerException() { stm.newTxnFactoryBuilder().setFamilyName(null); } @Test(expected = IllegalArgumentException.class) public void whenMaxRetriesNegative_thenIllegalArgumentException() { stm.newTxnFactoryBuilder().setMaxRetries(-1); } @Test(expected = NullPointerException.class) public void whenNullReadLockLevel_thenNullPointerException() { stm.newTxnFactoryBuilder().setReadLockMode(null); } @Test(expected = NullPointerException.class) public void whenNullWriteLockLevel_thenNullPointerException() { stm.newTxnFactoryBuilder().setWriteLockMode(null); } @Test(expected = IllegalArgumentException.class) public void whenNegativeSpinCount_thenIllegalArgumentException() { stm.newTxnFactoryBuilder().setSpinCount(-1); } @Test(expected = NullPointerException.class) public void whenNullTraceLevel_thenIllegalArgumentException() { stm.newTxnFactoryBuilder().setTraceLevel(null); } @Test(expected = IllegalArgumentException.class) public void whenNegativeTimeout_thenIllegalArgumentException() { stm.newTxnFactoryBuilder().setTimeoutNs(-1); } @Test(expected = NullPointerException.class) public void whenAddNullPermanentListener_thenNullPointerException() { stm.newTxnFactoryBuilder().addPermanentListener(null); } } GammaStm_txnExecutorTest.java000066400000000000000000000040441174000617100364650ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.PropagationLevel; import static org.junit.Assert.assertTrue; public class GammaStm_txnExecutorTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenCreateTxnExecutor() { TxnExecutor executor = stm.getDefaultTxnExecutor(); assertTrue(executor instanceof LeanGammaTxnExecutor); } @Test public void testDefault() { TxnExecutor executor = stm.newTxnFactoryBuilder() .newTxnExecutor(); assertTrue(executor instanceof LeanGammaTxnExecutor); } @Test public void whenMandatory() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Mandatory) .newTxnExecutor(); assertTrue(executor instanceof FatGammaTxnExecutor); } @Test public void whenRequires() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Requires) .newTxnExecutor(); assertTrue(executor instanceof LeanGammaTxnExecutor); } @Test public void whenRequiresNew() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.RequiresNew) .newTxnExecutor(); assertTrue(executor instanceof FatGammaTxnExecutor); } @Test public void whenNever() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Never) .newTxnExecutor(); assertTrue(executor instanceof FatGammaTxnExecutor); } @Test public void whenSupports() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setPropagationLevel(PropagationLevel.Supports) .newTxnExecutor(); assertTrue(executor instanceof FatGammaTxnExecutor); } } GammaStm_txnFactoryBuilderTest.java000066400000000000000000000263041174000617100376100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.*; import org.multiverse.api.exceptions.IllegalTxnFactoryException; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.GammaTxnFactoryBuilder; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import java.util.List; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; public class GammaStm_txnFactoryBuilderTest implements GammaConstants{ private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenDefaultTransactionFactory() { GammaTxnConfig config = new GammaTxnConfig(stm); config.init(); assertEquals(IsolationLevel.Snapshot, config.isolationLevel); assertFalse(config.isInterruptible()); assertFalse(config.isReadonly()); assertEquals(LockMode.None, config.readLockMode); assertEquals(LockMode.None, config.writeLockMode); assertTrue(config.dirtyCheck); assertSame(stm, config.getStm()); assertSame(stm.getGlobalConflictCounter(), config.getGlobalConflictCounter()); assertTrue(config.trackReads); assertTrue(config.blockingAllowed); assertEquals(1000, config.maxRetries); assertTrue(config.isSpeculative()); assertTrue(config.isAnonymous); assertSame(DefaultBackoffPolicy.MAX_100_MS, config.getBackoffPolicy()); assertEquals(Long.MAX_VALUE, config.getTimeoutNs()); assertSame(TraceLevel.None, config.getTraceLevel()); assertTrue(config.writeSkewAllowed); assertEquals(PropagationLevel.Requires, config.getPropagationLevel()); assertTrue(config.getPermanentListeners().isEmpty()); } @Test(expected = NullPointerException.class) public void whenNullPermanentListener_thenNullPointerException() { stm.newTxnFactoryBuilder().addPermanentListener(null); } @Test public void whenPermanentListenerAdded() { GammaTxnFactoryBuilder oldBuilder = stm.newTxnFactoryBuilder(); TxnListener listener = mock(TxnListener.class); GammaTxnFactoryBuilder newBuilder = oldBuilder.addPermanentListener(listener); assertEquals(asList(listener), newBuilder.getConfig().getPermanentListeners()); assertTrue(oldBuilder.getConfig().getPermanentListeners().isEmpty()); } @Test public void whenPermanentListenerAdded_thenNoCheckForDuplicates() { GammaTxnFactoryBuilder oldBuilder = stm.newTxnFactoryBuilder(); TxnListener listener = mock(TxnListener.class); GammaTxnFactoryBuilder newBuilder = oldBuilder.addPermanentListener(listener) .addPermanentListener(listener); assertEquals(asList(listener, listener), newBuilder.getConfig().getPermanentListeners()); } @Test public void whenNoPermanentListenersAdded_thenEmptyList() { GammaTxnFactoryBuilder builder = stm.newTxnFactoryBuilder(); assertTrue(builder.getConfig().getPermanentListeners().isEmpty()); } @Test public void whenMultipleListenersAdded_thenTheyAreAddedInOrder() { TxnListener listener1 = mock(TxnListener.class); TxnListener listener2 = mock(TxnListener.class); GammaTxnFactoryBuilder builder = stm.newTxnFactoryBuilder() .addPermanentListener(listener1) .addPermanentListener(listener2); List listeners = builder.getConfig().getPermanentListeners(); assertEquals(asList(listener1, listener2), listeners); } @Test public void whenGetPermanentListenersCalled_immutableListReturned() { GammaTxnFactoryBuilder builder = stm.newTxnFactoryBuilder() .addPermanentListener(mock(TxnListener.class)) .addPermanentListener(mock(TxnListener.class)); List listeners = builder.getConfig().getPermanentListeners(); try { listeners.clear(); fail(); } catch (UnsupportedOperationException e) { } } @Test public void whenReadLockModeOverridesWriteLockMode() { whenReadLockModeOverridesWriteLockMode(LockMode.None, LockMode.None); whenReadLockModeOverridesWriteLockMode(LockMode.None, LockMode.Read); whenReadLockModeOverridesWriteLockMode(LockMode.None, LockMode.Write); whenReadLockModeOverridesWriteLockMode(LockMode.None, LockMode.Exclusive); whenReadLockModeOverridesWriteLockMode(LockMode.Read, LockMode.None); whenReadLockModeOverridesWriteLockMode(LockMode.Read, LockMode.Read); whenReadLockModeOverridesWriteLockMode(LockMode.Read, LockMode.Write); whenReadLockModeOverridesWriteLockMode(LockMode.Read, LockMode.Exclusive); whenReadLockModeOverridesWriteLockMode(LockMode.Write, LockMode.None); whenReadLockModeOverridesWriteLockMode(LockMode.Write, LockMode.Read); whenReadLockModeOverridesWriteLockMode(LockMode.Write, LockMode.Write); whenReadLockModeOverridesWriteLockMode(LockMode.Write, LockMode.Exclusive); whenReadLockModeOverridesWriteLockMode(LockMode.Exclusive, LockMode.None); whenReadLockModeOverridesWriteLockMode(LockMode.Exclusive, LockMode.Read); whenReadLockModeOverridesWriteLockMode(LockMode.Exclusive, LockMode.Write); whenReadLockModeOverridesWriteLockMode(LockMode.Exclusive, LockMode.Exclusive); } public void whenReadLockModeOverridesWriteLockMode(LockMode readLockMode, LockMode writeLockMode) { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setWriteLockMode(writeLockMode) .setReadLockMode(readLockMode) .newTransactionFactory(); assertEquals(readLockMode, txFactory.getConfig().readLockMode); assertEquals(readLockMode.asInt(), txFactory.getConfig().readLockModeAsInt); if (readLockMode.asInt() > writeLockMode.asInt()) { assertEquals(readLockMode, txFactory.getConfig().getWriteLockMode()); assertEquals(readLockMode.asInt(), txFactory.getConfig().writeLockModeAsInt); } else { assertEquals(writeLockMode, txFactory.getConfig().getWriteLockMode()); assertEquals(writeLockMode.asInt(), txFactory.getConfig().writeLockModeAsInt); } } @Test public void whenWriteLockModeOverridesReadLockMode() { whenWriteLockModeOverridesReadLockMode(LockMode.None, LockMode.None, true); whenWriteLockModeOverridesReadLockMode(LockMode.None, LockMode.Read, true); whenWriteLockModeOverridesReadLockMode(LockMode.None, LockMode.Write, true); whenWriteLockModeOverridesReadLockMode(LockMode.None, LockMode.Exclusive, true); whenWriteLockModeOverridesReadLockMode(LockMode.Read, LockMode.None, false); whenWriteLockModeOverridesReadLockMode(LockMode.Read, LockMode.Read, true); whenWriteLockModeOverridesReadLockMode(LockMode.Read, LockMode.Write, true); whenWriteLockModeOverridesReadLockMode(LockMode.Read, LockMode.Exclusive, true); whenWriteLockModeOverridesReadLockMode(LockMode.Write, LockMode.None, false); whenWriteLockModeOverridesReadLockMode(LockMode.Write, LockMode.Read, false); whenWriteLockModeOverridesReadLockMode(LockMode.Write, LockMode.Write, true); whenWriteLockModeOverridesReadLockMode(LockMode.Write, LockMode.Exclusive, true); whenWriteLockModeOverridesReadLockMode(LockMode.Exclusive, LockMode.None, false); whenWriteLockModeOverridesReadLockMode(LockMode.Exclusive, LockMode.Read, false); whenWriteLockModeOverridesReadLockMode(LockMode.Exclusive, LockMode.Write, false); whenWriteLockModeOverridesReadLockMode(LockMode.Exclusive, LockMode.Exclusive, true); } public void whenWriteLockModeOverridesReadLockMode(LockMode readLock, LockMode writeLock, boolean success) { if (success) { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setReadLockMode(readLock) .setWriteLockMode(writeLock) .newTransactionFactory(); assertEquals(readLock, txFactory.getConfig().getReadLockMode()); assertEquals(writeLock, txFactory.getConfig().getWriteLockMode()); } else { try { stm.newTxnFactoryBuilder() .setReadLockMode(readLock) .setWriteLockMode(writeLock) .newTransactionFactory(); fail(); } catch (IllegalTxnFactoryException expected) { } } } @Test public void whenReadtrackingDisabled() { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setReadTrackingEnabled(false) .setBlockingAllowed(false) .newTransactionFactory(); assertFalse(txFactory.getConfig().isReadTrackingEnabled()); } @Test public void whenSpeculativeConfigEnabled() { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .setSpeculative(true) .newTransactionFactory(); GammaTxnConfig configuration = txFactory.getConfig(); assertFalse(configuration.getSpeculativeConfiguration().fat); assertTrue(configuration.isSpeculative()); } @Test public void whenWriteSkewNotAllowed() { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setSpeculative(true) .setIsolationLevel(IsolationLevel.Serializable) .newTransactionFactory(); GammaTxnConfig configuration = txFactory.getConfig(); assertTrue(configuration.getSpeculativeConfiguration().fat); assertTrue(configuration.isSpeculative()); } @Test public void whenSerializedThenFatTransaction() { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .setIsolationLevel(IsolationLevel.Serializable) .newTransactionFactory(); GammaTxn tx = txFactory.newTxn(); assertTrue(tx instanceof FatMonoGammaTxn); } @Test public void whenSnapshotIsolationLevelThenLeanTransaction() { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .setIsolationLevel(IsolationLevel.Snapshot) .newTransactionFactory(); GammaTxn tx = txFactory.newTxn(); assertEquals(TRANSACTIONTYPE_LEAN_MONO, tx.transactionType); } @Test public void whenReadonlyThenFatTransaction() { GammaTxnFactory txFactory = stm.newTxnFactoryBuilder() .setSpeculative(true) .setReadonly(true) .setDirtyCheckEnabled(false) .newTransactionFactory(); GammaTxn tx = txFactory.newTxn(); assertEquals(TRANSACTIONTYPE_FAT_MONO,tx.transactionType); } } GammaStm_txnFactoryValidationTest.java000066400000000000000000000043561174000617100403170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.transactions.GammaTxnFactoryBuilder; import static org.junit.Assert.fail; public class GammaStm_txnFactoryValidationTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenBlockingEnabled_thenAutomaticReadTrackingShouldBeEnabled() { GammaTxnFactoryBuilder builder = stm.newTxnFactoryBuilder() .setReadTrackingEnabled(false) .setBlockingAllowed(true); try { builder.newTransactionFactory(); fail(); } catch (IllegalStateException expected) { } } @Test public void whenWriteSkewAllowed_thenAutomaticReadTrackingShouldBeEnabled() { GammaTxnFactoryBuilder builder = stm.newTxnFactoryBuilder() .setReadonly(false) .setReadTrackingEnabled(false) .setIsolationLevel(IsolationLevel.Serializable); try { builder.newTransactionFactory(); fail(); } catch (IllegalStateException expected) { } } @Test public void whenWriteSkewAllowedAndReadonly_thenThenAutomaticReadTrackingDoesntMatter() { whenWriteSkewAllowedAndReadonly(true); whenWriteSkewAllowedAndReadonly(false); } private void whenWriteSkewAllowedAndReadonly(boolean readTrackingEnabled) { GammaTxnFactoryBuilder builder = stm.newTxnFactoryBuilder() .setBlockingAllowed(false) .setReadonly(true) .setReadTrackingEnabled(readTrackingEnabled) .setIsolationLevel(IsolationLevel.Serializable); builder.newTransactionFactory(); } @Test public void whenLockLevelIsRead_thenAutomaticReadTrackingShouldBeEnabled() { GammaTxnFactoryBuilder builder = stm.newTxnFactoryBuilder() .setReadTrackingEnabled(false) .setReadLockMode(LockMode.Read); try { builder.newTransactionFactory(); fail(); } catch (IllegalStateException expected) { } } } GammaTestUtils.java000066400000000000000000000200711174000617100344100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Assert; import org.multiverse.TestUtils; import org.multiverse.api.LockMode; import org.multiverse.api.blocking.RetryLatch; import org.multiverse.api.functions.Function; import org.multiverse.stms.gamma.transactionalobjects.*; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import java.util.*; import static java.lang.String.format; import static java.util.Arrays.asList; import static junit.framework.Assert.assertEquals; import static org.junit.Assert.*; import static org.multiverse.TestUtils.getField; public class GammaTestUtils implements GammaConstants { public static GammaTxn newArrivingTransaction(GammaStm stm){ GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0) .setSpeculative(false); return new FatVariableLengthGammaTxn(config); } public static void assertGlobalConflictCount(GammaStm stm, long expected){ assertEquals(expected, stm.globalConflictCounter.count()); } public static void causeLotsOfConflicts(GammaStm stm) { for (int k = 0; k < 100; k++) { stm.getGlobalConflictCounter().signalConflict(); } } public static void assertHasCommutingFunctions(Tranlocal tranlocal, Function... expected) { CallableNode current = tranlocal.headCallable; List functions = new LinkedList(); while (current != null) { functions.add(current.function); current = current.next; } Assert.assertEquals(asList(expected), functions); } public static void assertSpeculativeConfigurationNonRefTypeRequired(GammaTxn tx) { assertTrue(tx.config.speculativeConfiguration.get().nonRefTypeDetected); } public static void assertHasListeners(AbstractGammaObject ref, RetryLatch... listeners) { Set expected = new HashSet(Arrays.asList(listeners)); Set found = new HashSet(); Listeners l = (Listeners) getField(ref, "listeners"); while (l != null) { found.add(l.listener); l = l.next; } Assert.assertEquals(expected, found); } public static void assertHasNoListeners(AbstractGammaObject ref) { assertHasListeners(ref); } public static void assertRefHasNoLocks(AbstractGammaObject ref) { assertLockMode(ref, LOCKMODE_NONE); assertReadLockCount(ref, 0); } public static void assertRefHasReadLock(BaseGammaTxnRef ref, GammaTxn tx) { Tranlocal tranlocal = tx.getRefTranlocal(ref); if (tranlocal == null) { fail("A Tranlocal should have been available for a ref that has the read lock"); } Assert.assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertLockMode(ref, LOCKMODE_READ); } public static void assertRefHasNoLocks(BaseGammaTxnRef ref, GammaTxn tx) { Tranlocal tranlocal = tx.getRefTranlocal(ref); if (tranlocal != null) { Assert.assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } assertLockMode(ref, LOCKMODE_NONE); assertReadLockCount(ref, 0); } public static void assertRefHasWriteLock(BaseGammaTxnRef ref, GammaTxn lockOwner) { Tranlocal tranlocal = lockOwner.getRefTranlocal(ref); if (tranlocal == null) { fail("A Tranlocal should have been available for a ref that has the write lock"); } Assert.assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertLockMode(ref, LOCKMODE_WRITE); assertReadLockCount(ref, 0); } public static void assertRefHasExclusiveLock(BaseGammaTxnRef ref, GammaTxn lockOwner) { Tranlocal tranlocal = lockOwner.getRefTranlocal(ref); if (tranlocal == null) { fail("A tranlocal should have been stored in the transaction for the ref"); } Assert.assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertLockMode(ref, LOCKMODE_EXCLUSIVE); assertReadLockCount(ref, 0); } public static void assertRefHasLockMode(BaseGammaTxnRef ref, GammaTxn lockOwner, int lockMode) { switch (lockMode) { case LOCKMODE_NONE: assertRefHasNoLocks(ref, lockOwner); break; case LOCKMODE_READ: assertRefHasReadLock(ref, lockOwner); break; case LOCKMODE_WRITE: assertRefHasWriteLock(ref, lockOwner); break; case LOCKMODE_EXCLUSIVE: assertRefHasExclusiveLock(ref, lockOwner); break; default: throw new IllegalArgumentException(); } } public static void assertVersionAndValue(GammaTxnLong ref, long version, long value) { Assert.assertEquals("version doesn't match", version, ref.getVersion()); Assert.assertEquals("value doesn't match", value, ref.atomicWeakGet()); } public static void assertVersionAndValue(GammaTxnBoolean ref, long version, boolean value) { Assert.assertEquals("version doesn't match", version, ref.getVersion()); Assert.assertEquals("value doesn't match", value, ref.atomicWeakGet()); } public static void assertVersionAndValue(GammaTxnInteger ref, long version, int value) { Assert.assertEquals("version doesn't match", version, ref.getVersion()); Assert.assertEquals("value doesn't match", value, ref.atomicWeakGet()); } public static void assertVersionAndValue(GammaTxnDouble ref, long version, double value) { Assert.assertEquals("version doesn't match", version, ref.getVersion()); TestUtils.assertEqualsDouble(format("value doesn't match, expected %s found %s", value, ref.atomicWeakGet()),value, ref.atomicWeakGet()); } public static void assertVersionAndValue(GammaTxnRef ref, long version, E value) { Assert.assertEquals("version doesn't match", version, ref.getVersion()); Assert.assertSame("value doesn't match", value, ref.atomicWeakGet()); } public static void assertReadLockCount(AbstractGammaObject orec, int readLockCount) { if (readLockCount > 0) { assertEquals(LOCKMODE_READ, orec.atomicGetLockModeAsInt()); } assertEquals(readLockCount, orec.getReadLockCount()); } public static void assertLockMode(GammaObject orec, LockMode lockMode) { assertEquals(lockMode, orec.getLock().atomicGetLockMode()); } public static void assertLockMode(AbstractGammaObject orec, int lockMode) { assertEquals(lockMode, orec.atomicGetLockModeAsInt()); if (lockMode != LOCKMODE_READ) { assertEquals(0, orec.getReadLockCount()); } } public static void assertSurplus(AbstractGammaObject orec, int expectedSurplus) { assertEquals(expectedSurplus, orec.getSurplus()); } public static void assertReadBiased(AbstractGammaObject orec, boolean readBiased) { if (readBiased) { assertReadBiased(orec); } else { assertWriteBiased(orec); } } public static void assertReadBiased(AbstractGammaObject orec) { assertTrue(orec.isReadBiased()); } public static void assertWriteBiased(AbstractGammaObject orec) { assertFalse(orec.isReadBiased()); } public static void assertReadonlyCount(AbstractGammaObject orec, int expectedReadonlyCount) { assertEquals(expectedReadonlyCount, orec.getReadonlyCount()); } public static O makeReadBiased(O orec) { if (orec.isReadBiased()) { return orec; } int x = orec.getReadonlyCount(); for (int k = x; k < orec.getReadBiasedThreshold(); k++) { orec.arrive(1); orec.departAfterReading(); } assertReadBiased(orec); assertLockMode(orec, LOCKMODE_NONE); return orec; } } GammaTxnExecutorTest.java000066400000000000000000000034751174000617100356110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnIntCallable; import org.multiverse.api.callables.TxnLongCallable; import org.multiverse.api.callables.TxnVoidCallable; import static org.junit.Assert.assertEquals; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class GammaTxnExecutorTest { private GammaStm stm; private TxnExecutor executor; @Before public void setUp() { clearThreadLocalTxn(); stm = new GammaStm(); executor = stm.newTxnFactoryBuilder() .newTxnExecutor(); } @Test public void whenTxnIntCallableUsed() { int result = executor.execute(new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { return 10; } }); assertEquals(10, result); } @Test public void whenTxnLongCallableUsed() { long result = executor.execute(new TxnLongCallable() { @Override public long call(Txn tx) throws Exception { return 10; } }); assertEquals(10, result); } @Test public void whenTxnVoidCallableUsed() { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { } }); } @Test public void whenTxnCallableUsed() { String result = executor.execute(new TxnCallable() { @Override public String call(Txn tx) throws Exception { return "foo"; } }); assertEquals("foo", result); } } GammaTxnExecutor_blockingTest.java000066400000000000000000000040451174000617100374530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class GammaTxnExecutor_blockingTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void test() { final GammaTxnLong ref = new GammaTxnLong(stm); WaitThread t = new WaitThread(ref); t.start(); sleepMs(1000); assertAlive(t); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; Tranlocal write = ref.openForWrite(btx, LOCKMODE_NONE); write.long_value = 1; } }); joinAll(t); assertEquals(2, ref.atomicGet()); } class WaitThread extends TestThread { final GammaTxnLong ref; public WaitThread(GammaTxnLong ref) { this.ref = ref; } @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; Tranlocal write = ref.openForWrite(btx, LOCKMODE_NONE); if (write.long_value == 0) { retry(); } write.long_value++; } }); } } } GammaTxnExecutor_exceptionsTest.java000066400000000000000000000122401174000617100400400ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.InvisibleCheckedException; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class GammaTxnExecutor_exceptionsTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void executeChecked_whenCheckedExceptionThrown() { TxnExecutor executor = stm.newTxnFactoryBuilder().newTxnExecutor(); final GammaTxnLong ref = new GammaTxnLong(stm, 10); final Exception ex = new Exception(); try { executor.executeChecked(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value++; throw ex; } }); fail(); } catch (Exception expected) { assertSame(ex, expected); } assertEquals(10, ref.atomicGet()); } @Test public void executeChecked_whenRuntimeExceptionThrown() throws Exception { TxnExecutor executor = stm.newTxnFactoryBuilder().newTxnExecutor(); final GammaTxnLong ref = new GammaTxnLong(stm, 10); final RuntimeException ex = new RuntimeException(); try { executor.executeChecked(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value++; throw ex; } }); fail(); } catch (RuntimeException expected) { assertSame(ex, expected); } assertEquals(10, ref.atomicGet()); } @Test public void executeChecked_whenErrorThrown() throws Exception { TxnExecutor executor = stm.newTxnFactoryBuilder().newTxnExecutor(); final GammaTxnLong ref = new GammaTxnLong(stm, 10); final Error ex = new Error(); try { executor.executeChecked(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value++; throw ex; } }); fail(); } catch (Error expected) { assertSame(ex, expected); } assertEquals(10, ref.atomicGet()); } @Test public void execute_whenCheckedExceptionThrown() { TxnExecutor executor = stm.newTxnFactoryBuilder().newTxnExecutor(); final GammaTxnLong ref = new GammaTxnLong(stm, 10); final Exception ex = new Exception(); try { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value++; throw ex; } }); fail(); } catch (InvisibleCheckedException expected) { assertSame(ex, expected.getCause()); } assertEquals(10, ref.atomicGet()); } @Test public void execute_whenRuntimeExceptionThrown() { TxnExecutor executor = stm.newTxnFactoryBuilder().newTxnExecutor(); final GammaTxnLong ref = new GammaTxnLong(stm, 10); final RuntimeException ex = new RuntimeException(); try { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value++; throw ex; } }); fail(); } catch (RuntimeException expected) { assertSame(ex, expected); } assertEquals(10, ref.atomicGet()); } @Test public void execute_whenErrorThrown() { TxnExecutor executor = stm.newTxnFactoryBuilder().newTxnExecutor(); final GammaTxnLong ref = new GammaTxnLong(stm, 10); final Error ex = new Error(); try { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value++; throw ex; } }); fail(); } catch (Error expected) { assertSame(ex, expected); } assertEquals(10, ref.atomicGet()); } } GammaTxnExecutor_integrationTest.java000066400000000000000000000060421174000617100402050ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnLongCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.TooManyRetriesException; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import static org.junit.Assert.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public class GammaTxnExecutor_integrationTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenRead() { final GammaTxnLong ref = new GammaTxnLong(stm, 10); TxnExecutor executor = stm.newTxnFactoryBuilder().newTxnExecutor(); long result = executor.execute(new TxnLongCallable() { @Override public long call(Txn tx) throws Exception { assertSame(tx, getThreadLocalTxn()); return ref.get(tx); } }); assertNull(getThreadLocalTxn()); assertEquals(10, result); } @Test public void whenUpdate() { final GammaTxnLong ref = new GammaTxnLong(stm, 0); TxnExecutor executor = stm.newTxnFactoryBuilder().newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(tx, 1); } }); assertEquals(1, ref.atomicGet()); } @Test public void whenTooManyRetries() { final GammaTxnLong ref = new GammaTxnLong(stm); FatMonoGammaTxn otherTx = new FatMonoGammaTxn(stm); ref.openForWrite(otherTx, LOCKMODE_EXCLUSIVE); try { TxnExecutor executor = stm.newTxnFactoryBuilder() .setMaxRetries(100) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.get(tx); } }); fail(); } catch (TooManyRetriesException expected) { expected.printStackTrace(); } } @Test public void whenMultipleUpdatesDoneInSingleTransaction() { final GammaTxnLong ref = new GammaTxnLong(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { for (int k = 0; k < 10; k++) { long l = ref.get(); ref.set(l + 1); } } }); assertEquals(10, ref.atomicGet()); } } GammaTxnExecutor_interruptibleTest.java000066400000000000000000000061121174000617100405500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.RetryInterruptedException; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.assertAlive; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class GammaTxnExecutor_interruptibleTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = new GammaStm(); } @Test public void whenNoTimeoutAndInterruptible() throws InterruptedException { final GammaTxnLong ref = new GammaTxnLong(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setInterruptible(true) .newTxnExecutor(); WaitWithoutTimeoutThread t = new WaitWithoutTimeoutThread(ref, executor); t.setPrintStackTrace(false); t.start(); sleepMs(1000); assertAlive(t); t.interrupt(); t.join(); t.assertFailedWithException(RetryInterruptedException.class); assertEquals(0, ref.atomicGet()); } @Test public void whenTimeoutAndInterruptible() throws InterruptedException { final GammaTxnLong ref = new GammaTxnLong(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setTimeoutNs(TimeUnit.SECONDS.toNanos(10)) .setInterruptible(true) .newTxnExecutor(); WaitWithoutTimeoutThread t = new WaitWithoutTimeoutThread(ref, executor); t.setPrintStackTrace(false); t.start(); sleepMs(1000); assertAlive(t); t.interrupt(); t.join(); t.assertFailedWithException(RetryInterruptedException.class); assertEquals(0, ref.atomicGet()); } class WaitWithoutTimeoutThread extends TestThread { final GammaTxnLong ref; private final TxnExecutor executor; public WaitWithoutTimeoutThread(GammaTxnLong ref, TxnExecutor executor) { this.ref = ref; this.executor = executor; } @Override public void doRun() throws Exception { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; Tranlocal write = ref.openForWrite(btx, LOCKMODE_NONE); if (write.long_value == 0) { retry(); } write.long_value = 100; } }); } } } GammaTxnExecutor_speculativeTest.java000066400000000000000000000221241174000617100402050ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.functions.Function; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.multiverse.TestUtils.assertInstanceof; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public class GammaTxnExecutor_speculativeTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenTransactionGrowing() { final GammaTxnRef[] refs = new GammaTxnRef[1000]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnRef(stm, 0L); } final List transactions = new LinkedList(); final AtomicInteger attempt = new AtomicInteger(1); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setControlFlowErrorsReused(false) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { System.out.println(tx.getClass()); assertSame(tx, getThreadLocalTxn()); GammaTxn btx = (GammaTxn) tx; assertEquals(attempt.get(), tx.getAttempt()); attempt.incrementAndGet(); transactions.add(btx); for (GammaTxnRef ref : refs) { ref.set(1L); } } }); for (GammaTxnRef ref : refs) { assertEquals(1L, ref.atomicGet()); } assertEquals(4, transactions.size()); assertInstanceof(LeanMonoGammaTxn.class, transactions.get(0)); assertInstanceof(LeanFixedLengthGammaTxn.class, transactions.get(1)); assertInstanceof(FatVariableLengthGammaTxn.class, transactions.get(2)); assertInstanceof(FatVariableLengthGammaTxn.class, transactions.get(3)); } @Test public void whenCommute() { final List transactions = new LinkedList(); final GammaTxnRef ref = new GammaTxnRef(stm); final Function function = mock(Function.class); TxnExecutor executor = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .setSpeculative(true) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); ref.commute(btx, function); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenEnsure() { final List transactions = new LinkedList(); final GammaTxnRef ref = new GammaTxnRef(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .setSpeculative(true) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); ref.get(btx); ref.ensure(btx); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenConstructing() { final List transactions = new LinkedList(); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); new GammaTxnRef(btx); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenNonRef() { final List transactions = new LinkedList(); final GammaTxnLong ref = new GammaTxnLong(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); ref.get(tx); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenExplicitLocking() { final List transactions = new LinkedList(); final GammaTxnRef ref = new GammaTxnRef(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); ref.getLock().acquire(LockMode.Read); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenNormalListenerAdded() { final List transactions = new LinkedList(); final AtomicBoolean added = new AtomicBoolean(); final TxnListener listener = mock(TxnListener.class); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertSame(tx, getThreadLocalTxn()); GammaTxn btx = (GammaTxn) tx; transactions.add(btx); if (!added.get()) { btx.register(listener); } } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenTimeoutAvailable_thenCopied() { final GammaTxnLong ref1 = new GammaTxnLong(stm); final GammaTxnLong ref2 = new GammaTxnLong(stm); final List transactions = new LinkedList(); TxnExecutor executor = stm.newTxnFactoryBuilder() .setTimeoutNs(1000) .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertSame(tx, getThreadLocalTxn()); GammaTxn btx = (GammaTxn) tx; transactions.add(btx); if (transactions.size() == 1) { btx.remainingTimeoutNs = 500; } else { assertEquals(500, btx.getRemainingTimeoutNs()); } ref1.openForWrite(btx, LOCKMODE_NONE); ref2.openForWrite(btx, LOCKMODE_NONE); } }); } } GammaTxnExecutor_timeoutTest.java000066400000000000000000000070601174000617100373510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.RetryTimeoutException; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class GammaTxnExecutor_timeoutTest { private GammaStm stm; private GammaTxnLong ref; private long timeoutNs; @Before public void setUp() { clearThreadLocalTxn(); stm = new GammaStm(); ref = new GammaTxnLong(stm); timeoutNs = TimeUnit.SECONDS.toNanos(2); } @Test public void whenTimeout() throws InterruptedException { TxnExecutor executor = stm.newTxnFactoryBuilder() .setTimeoutNs(timeoutNs) .newTxnExecutor(); AwaitThread t = new AwaitThread(executor); t.setPrintStackTrace(false); t.start(); t.join(); t.assertFailedWithException(RetryTimeoutException.class); assertEquals(0, ref.atomicGet()); } @Test public void whenSuccess() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setTimeoutNs(timeoutNs) .newTxnExecutor(); AwaitThread t = new AwaitThread(executor); t.setPrintStackTrace(false); t.start(); sleepMs(500); assertAlive(t); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value = 1; } }); joinAll(t); assertNothingThrown(t); assertEquals(2, ref.atomicGet()); } @Test public void whenNoWaitingNeededAndZeroTimeout() { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value = 1; } }); TxnExecutor executor = stm.newTxnFactoryBuilder() .setTimeoutNs(0) .newTxnExecutor(); AwaitThread t = new AwaitThread(executor); t.setPrintStackTrace(false); t.start(); joinAll(t); assertNothingThrown(t); assertEquals(2, ref.atomicGet()); } class AwaitThread extends TestThread { private final TxnExecutor executor; public AwaitThread(TxnExecutor executor) { this.executor = executor; } @Override public void doRun() throws Exception { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; Tranlocal write = ref.openForWrite(btx, LOCKMODE_NONE); if (write.long_value == 0) { retry(); } write.long_value = 2; } }); } } } LeanGammaTxnExecutor_integrationTest.java000066400000000000000000000024421174000617100410050ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public class LeanGammaTxnExecutor_integrationTest { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = new GammaStm(); } @Test public void whenExecutedThenTxnThreadLocalSet() { GammaTxnFactory transactionFactory = stm.newTxnFactoryBuilder().newTransactionFactory(); TxnExecutor executor = new LeanGammaTxnExecutor(transactionFactory); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertNotNull(tx); assertIsActive((GammaTxn) tx); assertSame(tx, getThreadLocalTxn()); } }); assertNull(getThreadLocalTxn()); } } Listeners_openAllTest.java000066400000000000000000000015351174000617100357730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.blocking.RetryLatch; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; public class Listeners_openAllTest { private GammaObjectPool pool; @Before public void setUp() { pool = new GammaObjectPool(); } @Test public void test() { RetryLatch latch1 = mock(RetryLatch.class); RetryLatch latch2 = mock(RetryLatch.class); Listeners listeners = new Listeners(); listeners.listener = latch1; listeners.listenerEra = 1; listeners.next = new Listeners(); listeners.next.listener = latch2; listeners.next.listenerEra = 2; listeners.openAll(pool); verify(latch1).open(1); verify(latch2).open(2); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/Result.java000077500000000000000000000005011174000617100330410ustar00rootroot00000000000000package org.multiverse.stms.gamma; /** * @author Peter Veentjer */ public class Result { public final int processorCount; public final double performance; public Result(int processorCount, double performance) { this.processorCount = processorCount; this.performance = performance; } } StmUtilsTest.java000066400000000000000000000117321174000617100341350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gammapackage org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.TxnMandatoryException; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class StmUtilsTest { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = new GammaStm(); } @Test public void whenScheduleDeferredTaskAndNoTransactionAvailable() { Runnable task = mock(Runnable.class); try { scheduleDeferredTask(task); fail(); } catch (TxnMandatoryException expected) { } verifyZeroInteractions(task); } @Test(expected = NullPointerException.class) public void whenScheduleDeferredNullTask_thenNullPointerException() { scheduleDeferredTask(null); } @Test public void whenScheduleDeferredTaskAndCommit_thenCalled() { final Runnable task = mock(Runnable.class); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleDeferredTask(task); } }); verify(task).run(); } @Test public void whenScheduleDeferredTaskAndAborted_thenNotCalled() { final Runnable task = mock(Runnable.class); try { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleDeferredTask(task); throw new NonsenseException(); } }); fail(); } catch (NonsenseException expected) { } verifyZeroInteractions(task); } class NonsenseException extends RuntimeException { } @Test public void whenScheduleCompensatingTaskAndNoTransactionAvailable_thenNoTransactionFoundException() { Runnable task = mock(Runnable.class); try { scheduleCompensatingTask(task); fail(); } catch (TxnMandatoryException expected) { } verifyZeroInteractions(task); } @Test(expected = NullPointerException.class) public void whenScheduleCompensatingNullTask_thenNullPointerException() { scheduleCompensatingTask(null); } @Test public void whenScheduleCompensatingTaskAndCommit_thenCalled() { final Runnable task = mock(Runnable.class); try { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleCompensatingTask(task); throw new NonsenseException(); } }); fail(); } catch (NonsenseException expected) { } verify(task).run(); } @Test public void whenScheduleCompensatingTaskAndAborted_thenNotCalled() { final Runnable task = mock(Runnable.class); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleCompensatingTask(task); } }); verifyZeroInteractions(task); } @Test public void whenScheduleCompensatingOrDeferredTaskAndNoTransactionAvailable_thenNoTransactionFoundException() { Runnable task = mock(Runnable.class); try { scheduleCompensatingOrDeferredTask(task); fail(); } catch (TxnMandatoryException expected) { } verifyZeroInteractions(task); } @Test(expected = NullPointerException.class) public void whenScheduleCompensatingOrDeferredNullTask_thenNullPointerException() { scheduleCompensatingOrDeferredTask(null); } @Test public void whenScheduleCompensatingOrDeferredTaskAndCommit_thenCalled() { final Runnable task = mock(Runnable.class); try { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleCompensatingOrDeferredTask(task); throw new NonsenseException(); } }); fail(); } catch (NonsenseException expected) { } verify(task).run(); } @Test public void whenScheduleCompensatingOrDeferredTaskAndAborted_thenCalled() { final Runnable task = mock(Runnable.class); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleCompensatingOrDeferredTask(task); } }); verify(task).run(); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/000077500000000000000000000000001174000617100332445ustar00rootroot00000000000000AtomicReadBiasedWithPeriodicUpdateTest.java000066400000000000000000000022641174000617100434720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integrationpackage org.multiverse.stms.gamma.integration; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.assertEquals; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class AtomicReadBiasedWithPeriodicUpdateTest { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } @Test public void test() { GammaTxnLong ref = new GammaTxnLong(stm); for (int l = 0; l < 100; l++) { long value = ref.atomicGet() + 1; ref.atomicGetAndSet(value); for (int k = 0; k < 1000; k++) { long result = ref.atomicGet(); assertEquals(value, result); } } assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); System.out.println("orec: " + ref.___toOrecString()); } } ReadBiasedTest.java000077500000000000000000000024141174000617100366570ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integrationpackage org.multiverse.stms.gamma.integration; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class ReadBiasedTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } @Test public void test() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); for (int k = 0; k < 10000; k++) { GammaTxn tx = stm.newDefaultTxn(); tx.richmansMansConflictScan = true; ref.openForRead(tx, LOCKMODE_NONE); tx.commit(); } assertSurplus(ref, 1); assertReadBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, version, 100); System.out.println("orec: " + ref.___toOrecString()); } } ReadBiasedWithPeriodicUpdateTest.java000077500000000000000000000030541174000617100423360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integrationpackage org.multiverse.stms.gamma.integration; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class ReadBiasedWithPeriodicUpdateTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } @Test public void test() { GammaTxnLong ref = new GammaTxnLong(stm); for (int l = 0; l < 100; l++) { GammaTxn tx = new FatMonoGammaTxn(stm); tx.richmansMansConflictScan = true; ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); for (int k = 0; k < 1000; k++) { GammaTxn readonlyTx = new FatMonoGammaTxn(stm); readonlyTx.richmansMansConflictScan = true; ref.openForRead(readonlyTx, LOCKMODE_NONE); readonlyTx.commit(); } } assertSurplus(ref, 1); assertReadBiased(ref); assertRefHasNoLocks(ref); System.out.println("orec: " + ref.___toOrecString()); } } 000077500000000000000000000000001174000617100347555ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingBlockingTest.java000066400000000000000000000024411174000617100402110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.txnlong.TxnLongAwaitThread; import static org.multiverse.TestUtils.assertAlive; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class BlockingTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenDesiredValueNotAvailable_thenThreadBlocks() { GammaTxnLong ref = new GammaTxnLong(stm, 0); TxnLongAwaitThread t = new TxnLongAwaitThread(ref, 1); t.start(); sleepMs(1000); assertAlive(t); } @Test public void whenDesiredValueStillNotAvailable_thenThreadBlocks() { GammaTxnLong ref = new GammaTxnLong(stm, 0); TxnLongAwaitThread t = new TxnLongAwaitThread(ref, 2); t.start(); sleepMs(2000); ref.atomicSet(1); sleepMs(1000); assertAlive(t); } } ConnectionPool_AbstractTest.java000066400000000000000000000133561174000617100432440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnIntCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * A StressTest that simulates a database connection pool. The code is quite ugly, but that is because * no instrumentation is used here. * * @author Peter Veentjer. */ public abstract class ConnectionPool_AbstractTest implements GammaConstants { private int poolsize = processorCount(); private int threadCount = processorCount() * 2; private volatile boolean stop; private ConnectionPool pool; protected GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; } protected abstract TxnExecutor newReturnBlock(); protected abstract TxnExecutor newTakeBlock(); @Test public void sanityTest() { ConnectionPool pool = new ConnectionPool(2); Connection c1 = pool.takeConnection(); assertEquals(1, pool.size()); Connection c2 = pool.takeConnection(); assertEquals(0, pool.size()); pool.returnConnection(c1); assertEquals(1, pool.size()); pool.returnConnection(c2); assertEquals(2, pool.size()); } public void run() { pool = new ConnectionPool(poolsize); WorkerThread[] threads = createThreads(); startAll(threads); sleepMs(30 * 1000); stop = true; joinAll(threads); assertEquals(poolsize, pool.size()); } class ConnectionPool { final TxnExecutor takeConnectionBlock = newTakeBlock(); final TxnExecutor returnConnectionBlock = newReturnBlock(); final TxnExecutor sizeBlock = stm.newTxnFactoryBuilder().newTxnExecutor(); final GammaTxnInteger size = new GammaTxnInteger(stm); final GammaTxnRef> head = new GammaTxnRef>(stm); ConnectionPool(final int poolsize) { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) { size.set(poolsize); Node h = null; for (int k = 0; k < poolsize; k++) { h = new Node(h, new Connection()); } head.set(h); } }); } Connection takeConnection() { return takeConnectionBlock.execute(new TxnCallable() { @Override public Connection call(Txn tx) { if (size.get() == 0) { tx.retry(); } size.decrement(); Node current = head.get(); head.set(current.next); return current.item; } }); } void returnConnection(final Connection c) { returnConnectionBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { size.incrementAndGet(1); Node oldHead = head.get(); head.set(new Node(oldHead, c)); } }); } int size() { return sizeBlock.execute(new TxnIntCallable() { @Override public int call(Txn tx) throws Exception { return size.get(); } }); } } static class Node { final Node next; final E item; Node(Node next, E item) { this.next = next; this.item = item; } } static class Connection { AtomicInteger users = new AtomicInteger(); void startUsing() { if (!users.compareAndSet(0, 1)) { fail(); } } void stopUsing() { if (!users.compareAndSet(1, 0)) { fail(); } } } private WorkerThread[] createThreads() { WorkerThread[] threads = new WorkerThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new WorkerThread(k); } return threads; } class WorkerThread extends TestThread { public WorkerThread(int id) { super("WorkerThread-" + id); } @Override public void doRun() throws Exception { int k = 0; while (!stop) { if (k % 100 == 0) { System.out.printf("%s is at %s\n", getName(), k); } Connection c = pool.takeConnection(); assertNotNull(c); c.startUsing(); try { sleepRandomMs(50); } finally { c.stopUsing(); pool.returnConnection(c); } k++; } } } } ConnectionPool_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000026001174000617100473230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class ConnectionPool_FatFixedLengthGammaTxn_StressTest extends ConnectionPool_AbstractTest { private LockMode lockMode = LockMode.None; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newTakeBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newReturnBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } ConnectionPool_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000026151174000617100500170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class ConnectionPool_FatVariableLengthGammaTxn_StressTest extends ConnectionPool_AbstractTest { private LockMode lockMode = LockMode.None; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newTakeBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newReturnBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } ManyListenersStressTest.java000066400000000000000000000051371174000617100424670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.TestUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnLong; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class ManyListenersStressTest { private int refCount = 10; private int threadCount = 5; private volatile boolean stop; private TxnLong[] refs; private StressThread[] threads; @Before public void setUp() { clearThreadLocalTxn(); stop = false; threads = new StressThread[threadCount]; for (int k = 0; k < threadCount; k++) { threads[k] = new StressThread(k + 1, k == threadCount - 1 ? 1 : k + 2); } refs = new TxnLong[refCount]; for (int k = 0; k < refCount; k++) { refs[k] = newTxnLong(0); } } @Test public void test() { refs[0].atomicSet(1); startAll(threads); TestUtils.sleepMs(30000); stop = true; refs[0].atomicSet(-1); joinAll(threads); } class StressThread extends TestThread { private int wakeup; long count; private int signal; public StressThread(int wakeup, int signal) { super("StressThread-" + wakeup); this.wakeup = wakeup; this.signal = signal; } @Override public void doRun() throws Exception { while (!stop) { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { for (TxnLong ref : refs) { final long value = ref.get(); if (value == -1) { return; } if (value == wakeup) { ref.set(0); refs[TestUtils.randomInt(refs.length)].set(signal); return; } } retry(); } }); count++; if (count % 10000 == 0) { System.out.printf("%s is at %s\n", getName(), count); } } } } } MultipleReadsRetryStressTest.java000066400000000000000000000122421174000617100434650ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.TestUtils; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class MultipleReadsRetryStressTest implements GammaConstants { private GammaStm stm; private GammaTxnLong[] refs; private GammaTxnLong stopRef; private volatile boolean stop; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; stopRef = new GammaTxnLong(stm, 0); } @Test public void withMapTransactionAnd2Threads() throws InterruptedException { FatVariableLengthGammaTxnFactory txFactory = new FatVariableLengthGammaTxnFactory(stm); test(new LeanGammaTxnExecutor(txFactory), 10, 2); } @Test public void withArrayTransactionAnd2Threads() throws InterruptedException { int refCount = 10; GammaTxnConfig config = new GammaTxnConfig(stm, refCount + 1); FatFixedLengthGammaTxnFactory txFactory = new FatFixedLengthGammaTxnFactory(config); test(new LeanGammaTxnExecutor(txFactory), refCount, 2); } @Test public void withMapTransactionAnd5Threads() throws InterruptedException { FatVariableLengthGammaTxnFactory txFactory = new FatVariableLengthGammaTxnFactory(stm); test(new LeanGammaTxnExecutor(txFactory), 10, 5); } @Test public void withArrayTransactionAnd5Threads() throws InterruptedException { int refCount = 10; GammaTxnConfig config = new GammaTxnConfig(stm, refCount + 1); FatFixedLengthGammaTxnFactory txFactory = new FatFixedLengthGammaTxnFactory(config); test(new LeanGammaTxnExecutor(txFactory), refCount, 5); } public void test(TxnExecutor txnExecutor, int refCount, int threadCount) throws InterruptedException { refs = new GammaTxnLong[refCount]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnLong(stm); } UpdateThread[] threads = new UpdateThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k, txnExecutor, threadCount); } startAll(threads); sleepMs(30 * 1000); stop = true; stopRef.atomicSet(-1); System.out.println("Waiting for joining threads"); joinAll(threads); assertEquals(sumCount(threads), sumRefs()); } private long sumRefs() { long result = 0; for (GammaTxnLong ref : refs) { result += ref.atomicGet(); } return result; } private long sumCount(UpdateThread[] threads) { long result = 0; for (UpdateThread thread : threads) { result += thread.count; } return result; } private class UpdateThread extends TestThread { private final TxnExecutor txnExecutor; private final int id; private final int threadCount; private long count; public UpdateThread(int id, TxnExecutor txnExecutor, int threadCount) { super("UpdateThread-" + id); this.txnExecutor = txnExecutor; this.id = id; this.threadCount = threadCount; } @Override public void doRun() { TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) { if (stopRef.get() < 0) { throw new StopException(); } long sum = 0; for (GammaTxnLong ref : refs) { sum += ref.get(); } if (sum % threadCount != id) { retry(); } GammaTxnLong ref = refs[TestUtils.randomInt(refs.length)]; ref.incrementAndGet(1); } }; while (!stop) { if (count % (10000) == 0) { System.out.println(getName() + " " + count); } try { txnExecutor.execute(callable); } catch (StopException e) { break; } count++; } } } class StopException extends RuntimeException { } } NoBlockingTest.java000066400000000000000000000056531174000617100405160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.RetryNotAllowedException; import org.multiverse.api.exceptions.RetryNotPossibleException; import org.multiverse.api.functions.Functions; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class NoBlockingTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenNothingRead_thenNoRetryPossibleException() { try { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { retry(); } }); fail(); } catch (RetryNotPossibleException expected) { } } @Test public void whenContainsCommute_thenNoRetryPossibleException() { final TxnLong ref = newTxnLong(); try { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.commute(Functions.incLongFunction()); retry(); } }); fail(); } catch (RetryNotPossibleException expected) { } } @Test public void whenContainsConstructing_thenNoRetryPossibleException() { try { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; GammaTxnLong ref = new GammaTxnLong(btx); retry(); } }); fail(); } catch (RetryNotPossibleException expected) { } } @Test public void whenBlockingNotAllowed_thenNoBlockingRetryAllowedException() { final TxnLong ref = newTxnLong(); TxnExecutor executor = getGlobalStmInstance() .newTxnFactoryBuilder() .setBlockingAllowed(false) .newTxnExecutor(); try { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.set(1); retry(); } }); fail(); } catch (RetryNotAllowedException expected) { } assertEquals(0, ref.atomicGet()); } } OrElseTest.java000066400000000000000000000041761174000617100376610ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnLongCallable; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.api.references.TxnLong; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.multiverse.api.StmUtils.newTxnLong; import static org.multiverse.api.StmUtils.retry; /** * @author Peter Veentjer */ public class OrElseTest { @Test(expected = TxnMandatoryException.class) public void whenCalledWithoutTransaction_thenTxnMandatoryException() { TxnCallable callable = mock(TxnCallable.class); StmUtils.atomic(callable, callable); } @Test public void whenEitherBranchIsSuccess() { final TxnLong ref1 = newTxnLong(1); final TxnLong ref2 = newTxnLong(0); long value = StmUtils.atomic(new TxnLongCallable() { @Override public long call(Txn tx) throws Exception { return StmUtils.atomic(new GetCallable(ref1), new GetCallable(ref2)); } }); assertEquals(1, value); } class GetCallable implements TxnLongCallable { private final TxnLong ref; GetCallable(TxnLong ref) { this.ref = ref; } @Override public long call(Txn tx) throws Exception { if (ref.get() == 0) { retry(); } return ref.get(); } } @Test @Ignore public void whenOrElseBranchIsSuccess() { final TxnLong ref1 = newTxnLong(0); final TxnLong ref2 = newTxnLong(2); long value = StmUtils.atomic(new TxnLongCallable() { @Override public long call(Txn tx) throws Exception { return StmUtils.atomic(new GetCallable(ref1), new GetCallable(ref2)); } }); assertEquals(2, value); } @Test @Ignore public void whenBothBranchedBlock() { } } PingPongStressTest.java000077500000000000000000000115051174000617100414120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnBooleanCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import static java.lang.Math.abs; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class PingPongStressTest { private volatile boolean stop = false; private GammaTxnLong ref; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); ref = new GammaTxnLong(stm); stop = false; } @Test public void withMonoTransactionAnd2Threads() throws InterruptedException { test(new FatMonoGammaTxnFactory(stm), 2); } @Test public void withArrayTransactionAnd2Threads() throws InterruptedException { test(new FatFixedLengthGammaTxnFactory(stm), 2); } @Test public void withMapTransactionAnd2Threads() throws InterruptedException { test(new FatVariableLengthGammaTxnFactory(stm), 2); } @Test public void withMonoTransactionAnd10Threads() throws InterruptedException { test(new FatMonoGammaTxnFactory(stm), 10); } @Test public void withArrayTransactionAnd10Threads() throws InterruptedException { test(new FatFixedLengthGammaTxnFactory(stm), 10); } @Test public void withMapTransactionAnd10Threads() throws InterruptedException { test(new FatVariableLengthGammaTxnFactory(stm), 10); } public void test(GammaTxnFactory transactionFactory, int threadCount) throws InterruptedException { TxnExecutor executor = new LeanGammaTxnExecutor(transactionFactory); PingPongThread[] threads = createThreads(executor, threadCount); startAll(threads); sleepMs(30 * 1000); stop = true; stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.set(-abs(ref.get())); } }); System.out.println("Waiting for joining threads"); joinAll(threads); assertEquals(sum(threads), -ref.atomicGet()); System.out.println(stm.getGlobalConflictCounter().count()); } private PingPongThread[] createThreads(TxnExecutor executor, int threadCount) { PingPongThread[] threads = new PingPongThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new PingPongThread(k, executor, threadCount); } return threads; } private long sum(PingPongThread[] threads) { long result = 0; for (PingPongThread t : threads) { result += t.count; } return result; } private class PingPongThread extends TestThread { private final TxnExecutor executor; private final int threadCount; private final int id; private long count; public PingPongThread(int id, TxnExecutor executor, int threadCount) { super("PingPongThread-" + id); this.id = id; this.executor = executor; this.threadCount = threadCount; } @Override public void doRun() { TxnBooleanCallable callable = new TxnBooleanCallable() { @Override public boolean call(Txn tx) throws Exception { if (ref.get() < 0) { return false; } if (ref.get() % threadCount != id) { retry(); } ref.increment(); return true; } }; while (!stop) { if (count % (20000) == 0) { System.out.println(getName() + " " + count); } if (!executor.execute(callable)) { break; } count++; } System.out.printf("%s finished\n", getName()); } } } QueueWithCapacity_AbstractTest.java000066400000000000000000000124061174000617100437040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.LinkedList; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public abstract class QueueWithCapacity_AbstractTest implements GammaConstants { protected GammaStm stm; private Queue queue; private int itemCount = 2 * 1000 * 1000; private int maxCapacity = 1000; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } protected abstract TxnExecutor newPopBlock(); protected abstract TxnExecutor newPushBlock(); public void run() { queue = new Queue(); ProduceThread produceThread = new ProduceThread(); ConsumeThread consumeThread = new ConsumeThread(); startAll(produceThread, consumeThread); joinAll(produceThread, consumeThread); assertEquals(itemCount, produceThread.producedItems.size()); assertEquals(produceThread.producedItems, consumeThread.consumedItems); } class ConsumeThread extends TestThread { private final LinkedList consumedItems = new LinkedList(); public ConsumeThread() { super("ConsumeThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { int item = queue.pop(); consumedItems.add(item); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class ProduceThread extends TestThread { private final LinkedList producedItems = new LinkedList(); public ProduceThread() { super("ProduceThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { queue.push(k); producedItems.add(k); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class Queue { final Stack pushedStack = new Stack(); final Stack readyToPopStack = new Stack(); final TxnExecutor pushBlock = newPushBlock(); final TxnExecutor popBlock = newPopBlock(); final GammaTxnInteger size = new GammaTxnInteger(stm); public void push(final E item) { pushBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (size.get() >= maxCapacity) { retry(); } GammaTxn btx = (GammaTxn) tx; size.incrementAndGet(1); pushedStack.push(btx, item); } }); } public E pop() { return popBlock.execute(new TxnCallable() { @Override public E call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; if (!readyToPopStack.isEmpty(btx)) { size.decrement(); return readyToPopStack.pop(btx); } while (!pushedStack.isEmpty(btx)) { E item = pushedStack.pop(btx); readyToPopStack.push(btx, item); } if (!readyToPopStack.isEmpty(btx)) { size.decrement(); return readyToPopStack.pop(btx); } retry(); return null; } }); } } class Stack { final GammaTxnRef> head = new GammaTxnRef>(stm); void push(GammaTxn tx, E item) { head.set(tx, new Node(item, head.get(tx))); } boolean isEmpty(GammaTxn tx) { return head.isNull(tx); } E pop(GammaTxn tx) { Node node = head.get(); if (node == null) { tx.retry(); } if (node == null) { retry(); } head.set(tx, node.next); return node.item; } } class Node { final E item; Node next; Node(E item, Node next) { this.item = item; this.next = next; } } } QueueWithCapacity_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000025631174000617100500000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class QueueWithCapacity_FatFixedLengthGammaTxn_StressTest extends QueueWithCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPushBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } QueueWithCapacity_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000025771174000617100504730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class QueueWithCapacity_FatVariableLengthGammaTxn_StressTest extends QueueWithCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPushBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } QueueWithoutCapacity_AbstractTest.java000066400000000000000000000112321174000617100444300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.LinkedList; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public abstract class QueueWithoutCapacity_AbstractTest implements GammaConstants { protected GammaStm stm; private Queue queue; private int itemCount = 10 * 1000 * 1000; protected abstract TxnExecutor newPopBlock(); protected abstract TxnExecutor newPushBlock(); @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } public void run() { queue = new Queue(); ProduceThread produceThread = new ProduceThread(); ConsumeThread consumeThread = new ConsumeThread(); startAll(produceThread, consumeThread); joinAll(produceThread, consumeThread); assertEquals(itemCount, produceThread.producedItems.size()); assertEquals(produceThread.producedItems, consumeThread.consumedItems); } class ConsumeThread extends TestThread { private final LinkedList consumedItems = new LinkedList(); public ConsumeThread() { super("ConsumeThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { int item = queue.pop(); consumedItems.add(item); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class ProduceThread extends TestThread { private final LinkedList producedItems = new LinkedList(); public ProduceThread() { super("ProduceThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { queue.push(k); producedItems.add(k); if (k % 100000 == 0) { sleepMs(100); System.out.printf("%s is at %s\n", getName(), k); } } } } class Queue { final Stack pushedStack = new Stack(); final Stack readyToPopStack = new Stack(); final TxnExecutor pushBlock = newPushBlock(); final TxnExecutor popBlock = newPopBlock(); public void push(final E item) { pushBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; pushedStack.push(btx, item); } }); } public E pop() { return popBlock.execute(new TxnCallable() { @Override public E call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; if (!readyToPopStack.isEmpty(btx)) { return readyToPopStack.pop(btx); } while (!pushedStack.isEmpty(btx)) { E item = pushedStack.pop(btx); readyToPopStack.push(btx, item); } return readyToPopStack.pop(btx); } }); } } class Stack { final GammaTxnRef> head = new GammaTxnRef>(stm); void push(GammaTxn tx, E item) { Node newHead = new Node(item, head.get()); head.set(newHead); } boolean isEmpty(GammaTxn tx) { return head.isNull(); } E pop(GammaTxn tx) { Node node = head.get(); if (node == null) { retry(); } head.set(node.next); return node.item; } } class Node { final E item; Node next; Node(E item, Node next) { this.item = item; this.next = next; } } } QueueWithoutCapacity_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000025711174000617100505270ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class QueueWithoutCapacity_FatFixedLengthGammaTxn_StressTest extends QueueWithoutCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPushBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } QueueWithoutCapacity_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000026051174000617100512130ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class QueueWithoutCapacity_FatVariableLengthGammaTxn_StressTest extends QueueWithoutCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPushBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } QueueWithoutCapacity_LeanFixedLengthGammaTxn_StressTest.java000066400000000000000000000013211174000617100506640ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxnFactory; public class QueueWithoutCapacity_LeanFixedLengthGammaTxn_StressTest extends QueueWithoutCapacity_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newPopBlock() { return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(stm)); } @Override protected TxnExecutor newPushBlock() { return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(stm)); } } RetryInterruptibleTest.java000066400000000000000000000042521174000617100423410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.RetryInterruptedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertTrue; import static org.multiverse.TestUtils.assertAlive; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class RetryInterruptibleTest { private GammaTxnLong ref; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); ref = new GammaTxnLong(stm); } @Test public void test() throws InterruptedException { ref = new GammaTxnLong(stm, 0); AwaitThread t = new AwaitThread(); t.start(); sleepMs(200); assertAlive(t); t.interrupt(); t.join(); assertTrue(t.wasInterrupted); } class AwaitThread extends TestThread { private boolean wasInterrupted; public void doRun() throws Exception { try { await(); } catch (RetryInterruptedException e) { wasInterrupted = true; } } public void await() throws Exception { TxnExecutor executor = stm.newTxnFactoryBuilder() .setInterruptible(true) .newTxnExecutor(); executor.executeChecked(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; if (ref.get(btx) != 1) { retry(); } } }); } } } StackWithCapacity_AbstractTest.java000066400000000000000000000110521174000617100436610ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import java.util.HashSet; import java.util.LinkedList; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * The test is not very efficient since a lot of temporary objects like the transaction template are created. * But that is alright for this test since it isn't a benchmark. * * @author Peter Veentjer. */ public abstract class StackWithCapacity_AbstractTest implements GammaConstants { protected GammaStm stm; private int itemCount = 2 * 1000 * 1000; private Stack stack; private int maxCapacity = 1000; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } protected abstract TxnExecutor newPopBlock(); protected abstract TxnExecutor newPushBlock(); public void run() { stack = new Stack(); ProduceThread produceThread = new ProduceThread(); ConsumeThread consumeThread = new ConsumeThread(); startAll(produceThread, consumeThread); joinAll(produceThread, consumeThread); System.out.println("finished executing"); assertEquals(itemCount, produceThread.producedItems.size()); assertEquals( new HashSet(produceThread.producedItems), new HashSet(consumeThread.consumedItems)); } class ConsumeThread extends TestThread { private final LinkedList consumedItems = new LinkedList(); public ConsumeThread() { super("ConsumeThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { int item = stack.pop(); consumedItems.add(item); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class ProduceThread extends TestThread { private final LinkedList producedItems = new LinkedList(); public ProduceThread() { super("ProduceThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { stack.push(k); producedItems.add(k); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class Stack { private final GammaTxnRef> head = new GammaTxnRef>(stm); private final GammaTxnInteger size = new GammaTxnInteger(stm); private final TxnExecutor pushBlock = newPushBlock(); private final TxnExecutor popBlock = newPopBlock(); public void push(final E item) { pushBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (size.get() >= maxCapacity) { retry(); } size.increment(); head.set(new Node(item, head.get())); } }); } public E pop() { return popBlock.execute(new TxnCallable() { @Override public E call(Txn tx) throws Exception { if (head.isNull()) { retry(); } size.decrement(); Node node = head.get(); head.set(node.next); return node.item; } }); } } class Node { final E item; Node next; Node(E item, Node next) { this.item = item; this.next = next; } } } StackWithCapacity_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000025641174000617100477620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class StackWithCapacity_FatFixedLengthGammaTxn_StressTest extends StackWithCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPushBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } StackWithCapacity_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000025771174000617100504540ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class StackWithCapacity_FatVariableLengthGammaTxn_StressTest extends StackWithCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPushBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } StackWithoutCapacity_AbstractTest.java000066400000000000000000000104371174000617100444170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.After; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import java.util.HashSet; import java.util.LinkedList; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * The test is not very efficient since a lot of temporary objects like the transaction template are created. * But that is alright for this test since it isn't a benchmark. * * @author Peter Veentjer. */ public abstract class StackWithoutCapacity_AbstractTest implements GammaConstants { public GammaStm stm; private int itemCount = 5 * 1000 * 1000; private Stack stack; @Before public void setUp() { clearThreadLocalTxn(); stm = new GammaStm(); } @After public void tearDown() { if (stack != null) { System.out.println(stack.head.toDebugString()); } } public void run() { stack = new Stack(); ProduceThread produceThread = new ProduceThread(); ConsumeThread consumeThread = new ConsumeThread(); startAll(produceThread, consumeThread); joinAll(produceThread, consumeThread); System.out.println("finished executing, checking if content is correct (can take some time)"); assertEquals(itemCount, produceThread.producedItems.size()); assertEquals( new HashSet(produceThread.producedItems), new HashSet(consumeThread.consumedItems)); System.out.println("Finished comparing content"); } class ConsumeThread extends TestThread { private final LinkedList consumedItems = new LinkedList(); public ConsumeThread() { super("ConsumeThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { int item = stack.pop(); consumedItems.add(item); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class ProduceThread extends TestThread { private final LinkedList producedItems = new LinkedList(); public ProduceThread() { super("ProduceThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { stack.push(k); producedItems.add(k); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class Stack { private final GammaTxnRef> head = new GammaTxnRef>(stm); private final TxnExecutor pushExecutor = newPushTxnExecutor(); private final TxnExecutor popExecutor = newPopTxnExecutor(); public void push(final E item) { pushExecutor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { head.set(new Node(item, head.get())); } }); } public E pop() { return popExecutor.execute(new TxnCallable() { @Override public E call(Txn tx) throws Exception { Node node = head.awaitNotNullAndGet(); head.set(node.next); return node.item; } }); } } protected abstract TxnExecutor newPopTxnExecutor(); protected abstract TxnExecutor newPushTxnExecutor(); class Node { final E item; Node next; Node(E item, Node next) { this.item = item; this.next = next; } } } StackWithoutCapacity_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000026051174000617100505060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class StackWithoutCapacity_FatFixedLengthGammaTxn_StressTest extends StackWithoutCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopTxnExecutor() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPushTxnExecutor() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } StackWithoutCapacity_FatMonoGammaTxn_StressTest.java000066400000000000000000000025511174000617100472150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; public class StackWithoutCapacity_FatMonoGammaTxn_StressTest extends StackWithoutCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopTxnExecutor() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } @Override protected TxnExecutor newPushTxnExecutor() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } } StackWithoutCapacity_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000026211174000617100511720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class StackWithoutCapacity_FatVariableLengthGammaTxn_StressTest extends StackWithoutCapacity_AbstractTest { private LockMode lockMode; @Test public void testNoLock() { lockMode = LockMode.None; run(); } @Test public void testReadLock() { lockMode = LockMode.Read; run(); } @Test public void testWriteLock() { lockMode = LockMode.Write; run(); } @Test public void testExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPopTxnExecutor() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPushTxnExecutor() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } StackWithoutCapacity_LeanFixedLengthGammaTxn_StressTest.java000066400000000000000000000013351174000617100506520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxnFactory; public class StackWithoutCapacity_LeanFixedLengthGammaTxn_StressTest extends StackWithoutCapacity_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newPopTxnExecutor() { return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(stm)); } @Override protected TxnExecutor newPushTxnExecutor() { return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(stm)); } } StackWithoutCapacity_LeanMonoGammaTxn_StressTest.java000066400000000000000000000013011174000617100473520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxnFactory; public class StackWithoutCapacity_LeanMonoGammaTxn_StressTest extends StackWithoutCapacity_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newPopTxnExecutor() { return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(stm)); } @Override protected TxnExecutor newPushTxnExecutor() { return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(stm)); } } TimeoutTestLongTest.java000066400000000000000000000047541174000617100416000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/blockingpackage org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.RetryTimeoutException; import org.multiverse.api.references.TxnInteger; import java.util.concurrent.TimeUnit; import static org.multiverse.TestUtils.assertNothingThrown; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.newTxnInteger; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class TimeoutTestLongTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenNoRetryNeeded() throws InterruptedException { TxnInteger ref = newTxnInteger(1); WaitAndTimeoutThread thread = new WaitAndTimeoutThread(ref); thread.start(); thread.join(); assertNothingThrown(thread); } @Test public void whenTimeout() throws InterruptedException { TxnInteger ref = newTxnInteger(); WaitAndTimeoutThread thread = new WaitAndTimeoutThread(ref); thread.setPrintStackTrace(false); thread.start(); sleepMs(1000); thread.join(); thread.assertFailedWithException(RetryTimeoutException.class); } @Test public void whenValueUpdatedInTime() throws InterruptedException { TxnInteger ref = newTxnInteger(); WaitAndTimeoutThread thread = new WaitAndTimeoutThread(ref); thread.start(); sleepMs(1000); ref.atomicSet(1); thread.join(); thread.assertNothingThrown(); } class WaitAndTimeoutThread extends TestThread { private final TxnInteger ref; WaitAndTimeoutThread(TxnInteger ref) { super("WaitAndTimeoutThread"); this.ref = ref; } @Override public void doRun() throws Exception { TxnExecutor executor = getGlobalStmInstance() .newTxnFactoryBuilder() .setTimeoutNs(TimeUnit.SECONDS.toNanos(5)) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.await(1); } }); } } } 000077500000000000000000000000001174000617100346065ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicCigaretteSmokersProblem_AbstractTest.java000066400000000000000000000146121174000617100447340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.TestUtils; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnBooleanCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnBoolean; import org.multiverse.api.references.TxnRef; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * http://en.wikipedia.org/wiki/Cigarette_smokers_problem */ public abstract class CigaretteSmokersProblem_AbstractTest { private static final int SMOKE_TIME_SECONDS = 10; private TxnBoolean tobaccoAvailable; private TxnBoolean paperAvailable; private TxnBoolean matchesAvailable; private TxnRef notifier; private ArbiterThread arbiterThread; private SmokerThread paperProvider; private SmokerThread matchProvider; private SmokerThread tobaccoProvider; private volatile boolean stop; private TxnExecutor executor; protected GammaStm stm; protected abstract TxnExecutor newBlock(); @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); tobaccoAvailable = newTxnBoolean(); paperAvailable = newTxnBoolean(); matchesAvailable = newTxnBoolean(); notifier = newTxnRef(); arbiterThread = new ArbiterThread(); paperProvider = new SmokerThread("PaperProviderThread", tobaccoAvailable, matchesAvailable); matchProvider = new SmokerThread("MatchProvidedThread", tobaccoAvailable, paperAvailable); tobaccoProvider = new SmokerThread("TobaccoProviderThread", paperAvailable, matchesAvailable); stop = false; } public void run() { executor = newBlock(); startAll(arbiterThread, paperProvider, matchProvider, tobaccoProvider); sleepMs(60000); System.out.println("Stopping threads"); stop = true; joinAll(arbiterThread, paperProvider, matchProvider, tobaccoProvider); System.out.println("MatchesAvailable: " + matchesAvailable.atomicGet()); System.out.println("PaperAvailable: " + paperAvailable.atomicGet()); System.out.println("TobaccoAvailable: " + tobaccoAvailable.atomicGet()); assertEquals(arbiterThread.count, paperProvider.count + matchProvider.count + tobaccoProvider.count); } class ArbiterThread extends TestThread { private int count; public ArbiterThread() { super("Arbiter"); } @Override public void doRun() throws Exception { while (!stop) { count++; switch (TestUtils.randomInt(3)) { case 0: executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) { if (notifier.get() != null) { retry(); } tobaccoAvailable.set(true); paperAvailable.set(true); notifier.set(matchProvider); } }); break; case 1: executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) { if (notifier.get() != null) { retry(); } tobaccoAvailable.set(true); matchesAvailable.set(true); notifier.set(paperProvider); } }); break; case 2: executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) { if (notifier.get() != null) { retry(); } matchesAvailable.set(true); paperAvailable.set(true); notifier.set(tobaccoProvider); } }); break; default: throw new RuntimeException(); } } executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { notifier.awaitNull(); notifier.set(arbiterThread); } }); } } class SmokerThread extends TestThread { private int count; private TxnBoolean item1; private TxnBoolean item2; public SmokerThread(String name, TxnBoolean item1, TxnBoolean item2) { super(name); this.item1 = item1; this.item2 = item2; } @Override public void doRun() throws Exception { while (makeCigarette()) { sleepRandomMs(SMOKE_TIME_SECONDS); count++; if (count % 100 == 0) { System.out.printf("%s is at %s\n", getName(), count); } } } private boolean makeCigarette() { return executor.execute(new TxnBooleanCallable() { @Override public boolean call(Txn tx) throws Exception { if (notifier.get() != SmokerThread.this) { if (notifier.get() == arbiterThread) { return false; } retry(); } item1.set(false); item2.set(false); notifier.set(null); return true; } }); } } } CigaretteSmokersProblem_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000022031174000617100510160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class CigaretteSmokersProblem_FatFixedLengthGammaTxn_StressTest extends CigaretteSmokersProblem_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } CigaretteSmokersProblem_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000022141174000617100515060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class CigaretteSmokersProblem_FatVariableLengthGammaTxn_StressTest extends CigaretteSmokersProblem_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } DiningPhilosophers_AbstractTest.java000066400000000000000000000107551174000617100437540ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnBoolean; import org.multiverse.api.references.TxnRefFactory; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import static org.junit.Assert.assertFalse; import static org.multiverse.TestUtils.*; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * http://en.wikipedia.org/wiki/Dining_philosophers_problem */ public abstract class DiningPhilosophers_AbstractTest implements GammaConstants { private int philosopherCount = 10; private volatile boolean stop; private TxnBoolean[] forks; protected GammaStm stm; private TxnRefFactory refFactory; @Before public void setUp() { clearThreadLocalTxn(); GammaStmConfig config = new GammaStmConfig(); //config.backoffPolicy = new SpinningBackoffPolicy(); stm = new GammaStm(config); refFactory = stm.getTxRefFactoryBuilder().build(); stop = false; } protected abstract TxnExecutor newTakeForksBlock(); protected abstract TxnExecutor newReleaseForksBlock(); public void run() { createForks(); PhilosopherThread[] philosopherThreads = createPhilosopherThreads(); startAll(philosopherThreads); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(philosopherThreads); assertAllForksHaveReturned(); for (PhilosopherThread philosopherThread : philosopherThreads) { System.out.printf("%s ate %s times\n", philosopherThread.getName(), philosopherThread.eatCount); } } public void assertAllForksHaveReturned() { for (TxnBoolean fork : forks) { assertFalse(fork.atomicGet()); } } public PhilosopherThread[] createPhilosopherThreads() { PhilosopherThread[] threads = new PhilosopherThread[philosopherCount]; for (int k = 0; k < philosopherCount; k++) { TxnBoolean leftFork = forks[k]; TxnBoolean rightFork = k == philosopherCount - 1 ? forks[0] : forks[k + 1]; threads[k] = new PhilosopherThread(k, leftFork, rightFork); } return threads; } public void createForks() { forks = new TxnBoolean[philosopherCount]; for (int k = 0; k < forks.length; k++) { forks[k] = refFactory.newTxnBoolean(false); } } class PhilosopherThread extends TestThread { private int eatCount = 0; private final TxnBoolean leftFork; private final TxnBoolean rightFork; private final TxnExecutor releaseForksBlock = newReleaseForksBlock(); private final TxnExecutor takeForksBlock = newTakeForksBlock(); PhilosopherThread(int id, TxnBoolean leftFork, TxnBoolean rightFork) { super("PhilosopherThread-" + id); this.leftFork = leftFork; this.rightFork = rightFork; } @Override public void doRun() { while (!stop) { eatCount++; if (eatCount % 100 == 0) { System.out.printf("%s at %s\n", getName(), eatCount); } eat(); // sleepMs(5); } } public void eat() { takeForks(); stuffHole(); releaseForks(); } private void stuffHole() { //simulate the eating sleepRandomMs(50); } public void releaseForks() { releaseForksBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { leftFork.set(false); rightFork.set(false); } }); } public void takeForks() { takeForksBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (leftFork.get() || rightFork.get()) { retry(); } leftFork.set(true); rightFork.set(true); } }); } } } DiningPhilosophers_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000027161174000617100500430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class DiningPhilosophers_FatFixedLengthGammaTxn_StressTest extends DiningPhilosophers_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newTakeForksBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newReleaseForksBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } DiningPhilosophers_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000027331174000617100505300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class DiningPhilosophers_FatVariableLengthGammaTxn_StressTest extends DiningPhilosophers_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newTakeForksBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newReleaseForksBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } ProducerConsumer_AbstractTest.java000066400000000000000000000076531174000617100434460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnInteger; import org.multiverse.stms.gamma.GammaStm; import static junit.framework.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.newTxnInteger; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * http://en.wikipedia.org/wiki/Producer-consumer_problem */ public abstract class ProducerConsumer_AbstractTest { private Buffer buffer; private volatile boolean stop; private static final int MAX_CAPACITY = 100; protected GammaStm stm; protected abstract TxnExecutor newPutBlock(); protected abstract TxnExecutor newTakeBlock(); @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; } public void run() { buffer = new Buffer(); ProducerThread producerThread = new ProducerThread(); ConsumerThread consumerThread = new ConsumerThread(); startAll(producerThread, consumerThread); sleepMs(30 * 1000); stop = true; joinAll(producerThread, consumerThread); assertEquals(producerThread.produced, buffer.size.atomicGet() + consumerThread.consumed); } public class ProducerThread extends TestThread { private int produced; public ProducerThread() { super("ProducerThread"); } @Override public void doRun() { produced = 0; while (!stop) { buffer.put(produced); produced++; if (produced % 1000000 == 0) { System.out.printf("%s is at %d\n", getName(), produced); } } buffer.put(-1); produced++; } } public class ConsumerThread extends TestThread { public int consumed; public ConsumerThread() { super("ConsumerThread"); } @Override public void doRun() { int item; do { item = buffer.take(); consumed++; if (consumed % 1000000 == 0) { System.out.printf("%s is at %d\n", getName(), consumed); } } while (item != -1); } } class Buffer { private final TxnInteger size = newTxnInteger(); private final TxnInteger[] items; private final TxnExecutor takeBlock = newTakeBlock(); private final TxnExecutor putBlock = newPutBlock(); Buffer() { this.items = new TxnInteger[MAX_CAPACITY]; for (int k = 0; k < items.length; k++) { items[k] = newTxnInteger(); } } int take() { return takeBlock.execute(new TxnCallable() { @Override public Integer call(Txn tx) throws Exception { if (size.get() == 0) { retry(); } size.decrement(); return items[size.get()].get(); } }); } void put(final int item) { putBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (size.get() >= MAX_CAPACITY) { retry(); } items[size.get()].set(item); size.increment(); } }); } } } ProducerConsumer_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000026741174000617100475350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class ProducerConsumer_FatFixedLengthGammaTxn_StressTest extends ProducerConsumer_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPutBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newTakeBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } ProducerConsumer_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000027101174000617100502120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class ProducerConsumer_FatVariableLengthGammaTxn_StressTest extends ProducerConsumer_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPutBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newTakeBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } ReadersWritersProblem_AbstractTest.java000066400000000000000000000132171174000617100444260ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.GammaStm; import java.util.concurrent.atomic.AtomicLong; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.newTxnLong; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * http://en.wikipedia.org/wiki/Readers-writers_problem */ public abstract class ReadersWritersProblem_AbstractTest { private long count = 3000; private int readerThreadCount = 10; private int writerThreadCount = 5; private ReadersWritersLock readWriteLock; private AtomicLong currentReaderCount = new AtomicLong(); private AtomicLong currentWriterCount = new AtomicLong(); protected GammaStm stm; protected abstract TxnExecutor newAcquiredBlock(); protected abstract TxnExecutor newAcquireBlock(); @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } public void run() { readWriteLock = new ReadersWritersLock(); ReaderThread[] readers = createReaderThreads(); WriterThread[] writers = createWriterThreads(); startAll(writers); startAll(readers); joinAll(1000, writers); joinAll(1000, readers); assertEquals(0, currentReaderCount.get()); assertEquals(0, currentWriterCount.get()); } private ReaderThread[] createReaderThreads() { ReaderThread[] readers = new ReaderThread[readerThreadCount]; for (int k = 0; k < readerThreadCount; k++) { readers[k] = new ReaderThread(k); } return readers; } private WriterThread[] createWriterThreads() { WriterThread[] writers = new WriterThread[writerThreadCount]; for (int k = 0; k < writerThreadCount; k++) { writers[k] = new WriterThread(k); } return writers; } public class ReaderThread extends TestThread { public ReaderThread(int id) { super("ReaderThread-" + id); } @Override public void doRun() throws Exception { for (int k = 0; k < count; k++) { readWriteLock.acquireReadLock(); try { assertNoWriters(); currentReaderCount.incrementAndGet(); sleepRandomMs(2); currentReaderCount.decrementAndGet(); assertNoWriters(); if (k % 100 == 0) { System.out.printf("%s is at count %s\n", getName(), k); } } finally { readWriteLock.releaseReadLock(); } sleepRandomMs(5); } } } private void assertNoWriters() { if (currentWriterCount.get() > 0) { fail(); } } private void assertNoReaders() { if (currentReaderCount.get() > 0) { fail(); } } public class WriterThread extends TestThread { public WriterThread(int id) { super("WriterThread-" + id); } @Override public void doRun() throws Exception { for (int k = 0; k < count; k++) { readWriteLock.acquireWriteLock(); try { assertNoReaders(); assertNoWriters(); currentWriterCount.incrementAndGet(); sleepRandomMs(20); currentWriterCount.decrementAndGet(); assertNoWriters(); assertNoReaders(); if (k % 100 == 0) { System.out.printf("%s is at count %s\n", getName(), k); } } finally { readWriteLock.releaseWriteLock(); } } } } class ReadersWritersLock { //-1 is write lock, 0 = free, positive number is readLock count. private final TxnLong readerCount = newTxnLong(); private TxnExecutor acquireReadLockBlock; private TxnExecutor acquireWriteLockBlock; public ReadersWritersLock() { acquireReadLockBlock = newAcquireBlock(); acquireWriteLockBlock = newAcquiredBlock(); } public void acquireReadLock() { acquireReadLockBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (readerCount.get() == -1) { retry(); } readerCount.increment(); } }); } public void acquireWriteLock() { acquireWriteLockBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (readerCount.get() != 0) { retry(); } readerCount.decrement(); } }); } public void releaseWriteLock() { readerCount.atomicSet(0); } public void releaseReadLock() { readerCount.atomicIncrementAndGet(-1); } } } ReadersWriters_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000027071174000617100472000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class ReadersWriters_FatFixedLengthGammaTxn_StressTest extends ReadersWritersProblem_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newAcquiredBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newAcquireBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } ReadersWriters_FatMonoGammaTxn_StressTest.java000066400000000000000000000026531174000617100457070ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; public class ReadersWriters_FatMonoGammaTxn_StressTest extends ReadersWritersProblem_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newAcquiredBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } @Override protected TxnExecutor newAcquireBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } } ReadersWriters_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000027231174000617100476640ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class ReadersWriters_FatVariableLengthGammaTxn_StressTest extends ReadersWritersProblem_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newAcquiredBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newAcquireBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } SleepingBarberStressTest.java000066400000000000000000000056541174000617100424130ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/classicpackage org.multiverse.stms.gamma.integration.classic; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnBoolean; import org.multiverse.api.references.TxnInteger; import static org.multiverse.TestUtils.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * http://en.wikipedia.org/wiki/Sleeping_barber_problem */ public class SleepingBarberStressTest { private BarberShop barberShop; private volatile boolean stop; @Before public void setUp() { clearThreadLocalTxn(); barberShop = new BarberShop(); stop = false; } @Test public void test() { BarberThread thread = new BarberThread(); CustomerSpawnThread spawnThread = new CustomerSpawnThread(); startAll(thread, spawnThread); sleepMs(30 * 1000); stop = true; joinAll(thread, spawnThread); } @SuppressWarnings({"ObjectAllocationInLoop"}) class CustomerSpawnThread extends TestThread { public CustomerSpawnThread() { super("CustomerSpawnThread"); } @Override public void doRun() throws Exception { int customerId = 1; while (!stop) { CustomerThread customerThread = new CustomerThread(customerId); customerThread.start(); customerId++; sleepRandomMs(100); } } } class BarberThread extends TestThread { public BarberThread() { super("BarberThread"); } @Override public void doRun() { TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { //todo } }; while (!stop) { atomic(callable); } barberShop.atomicClose(); } } class CustomerThread extends TestThread { public CustomerThread(int id) { super("CustomerThread-" + id); } @Override public void doRun() throws Exception { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (barberShop.closed.get()) { return; } if (barberShop.freeSeats.get() == 0) { return; } //todo } }); } } static class BarberShop { private TxnBoolean closed = newTxnBoolean(false); private TxnInteger freeSeats = newTxnInteger(5); void atomicClose() { closed.atomicSet(false); } } } 000077500000000000000000000000001174000617100346365ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/commuteCommute_AbstractTest.java000066400000000000000000000071061174000617100416010ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/commutepackage org.multiverse.stms.gamma.integration.commute; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnLongCallable; import org.multiverse.api.functions.Functions; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public abstract class Commute_AbstractTest { protected GammaStm stm; private volatile boolean stop; private GammaTxnLong[] refs; private int refCount = 10; private int workerCount = 2; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; } protected abstract TxnExecutor newBlock(); @Test public void test() { refs = new GammaTxnLong[refCount]; for (int k = 0; k < refCount; k++) { refs[k] = new GammaTxnLong(stm); } WorkerThread[] workers = new WorkerThread[workerCount]; for (int k = 0; k < workers.length; k++) { workers[k] = new WorkerThread(k); } startAll(workers); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(workers); assertEquals(count(workers), count(refs)); } public long count(GammaTxnLong[] refs) { long result = 0; for (GammaTxnLong ref : refs) { result += ref.atomicGet(); } return result; } public long count(WorkerThread[] threads) { long result = 0; for (WorkerThread thread : threads) { result += thread.count; } return result; } public class WorkerThread extends TestThread { private long count; public WorkerThread(int id) { super("CommuteThread-" + id); } @Override public void doRun() throws Exception { TxnExecutor executor = newBlock(); TxnLongCallable commutingCallable = new TxnLongCallable() { @Override public long call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; for (int k = 0; k < refs.length; k++) { refs[k].commute(btx, Functions.incLongFunction(1)); } return refs.length; } }; TxnLongCallable nonCommutingCallable = new TxnLongCallable() { @Override public long call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; for (int k = 0; k < refs.length; k++) { refs[k].openForWrite(btx, LOCKMODE_NONE).long_value++; } return refs.length; } }; int k = 0; while (!stop) { TxnLongCallable callable = randomOneOf(10) ? nonCommutingCallable : commutingCallable; count += executor.execute(callable); k++; if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } System.out.printf("%s completed %s\n", getName(), k); } } } Commute_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000011551174000617100456700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/commutepackage org.multiverse.stms.gamma.integration.commute; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class Commute_FatFixedLengthGammaTxn_StressTest extends Commute_AbstractTest { @Override protected TxnExecutor newBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } Commute_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000011661174000617100463600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/commutepackage org.multiverse.stms.gamma.integration.commute; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class Commute_FatVariableLengthGammaTxn_StressTest extends Commute_AbstractTest { @Override protected TxnExecutor newBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } UncontendedCommutePerformanceTest.java000066400000000000000000000066451174000617100443360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/commutepackage org.multiverse.stms.gamma.integration.commute; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.functions.Functions; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.BenchmarkUtils.transactionsPerSecondAsString; public class UncontendedCommutePerformanceTest { private volatile boolean stop; private GammaStm stm; private GammaTxnLong ref; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); ref = new GammaTxnLong(stm); } @Test public void withNormalIncrement() { NormalIncThread thread = new NormalIncThread(); startAll(thread); long durationMs = getStressTestDurationMs(30 * 1000); sleepMs(durationMs); stop = true; joinAll(thread); long transactionCount = ref.atomicGet(); String performance = transactionsPerSecondAsString(transactionCount, durationMs); System.out.println(performance + " Transactions/second"); } @Test public void withCommuteIncrement() { CommuteIncThread thread = new CommuteIncThread(); startAll(thread); long durationMs = getStressTestDurationMs(30 * 1000); sleepMs(durationMs); stop = true; joinAll(thread); long transactionCount = ref.atomicGet(); String performance = transactionsPerSecondAsString(transactionCount, durationMs); System.out.println(performance + " Transactions/second"); } public class NormalIncThread extends TestThread { public NormalIncThread() { super("NormalIncThread"); } @Override public void doRun() throws Exception { TxnExecutor executor = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.openForWrite(btx, LOCKMODE_NONE).long_value++; } }; while (!stop) { executor.execute(callable); } } } public class CommuteIncThread extends TestThread { public CommuteIncThread() { super("CommuteIncThread"); } @Override public void doRun() throws Exception { TxnExecutor executor = stm.newTxnFactoryBuilder() .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.commute(btx, Functions.incLongFunction(1)); } }; while (!stop) { executor.execute(callable); } } } } 000077500000000000000000000000001174000617100360435ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/composabilityComposabilityAndBlockingTest.java000066400000000000000000000005321174000617100444600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/composabilitypackage org.multiverse.stms.gamma.integration.composability; import org.junit.Before; import org.junit.Test; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class ComposabilityAndBlockingTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void test() { } } ComposabilityAndLockingTest.java000066400000000000000000000103051174000617100443150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/composabilitypackage org.multiverse.stms.gamma.integration.composability; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.assertEquals; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class ComposabilityAndLockingTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenEnsuredInOuter_thenCanSafelyBeEnsuredInInner() { final int initialValue = 10; final TxnLong ref = new GammaTxnLong(stm, initialValue); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getLock().acquire(LockMode.Write); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getLock().acquire(LockMode.Write); assertEquals(LockMode.Write, ref.getLock().getLockMode()); } }); } }); assertEquals(LockMode.None, ref.getLock().atomicGetLockMode()); assertEquals(initialValue, ref.atomicGet()); } @Test public void whenEnsuredInOuter_thenCanSafelyBePrivatizedInInner() { final int initialValue = 10; final TxnLong ref = new GammaTxnLong(stm, initialValue); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getLock().acquire(LockMode.Write); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getLock().acquire(LockMode.Exclusive); assertEquals(LockMode.Exclusive, ref.getLock().getLockMode()); } }); } }); assertEquals(LockMode.None, ref.getLock().atomicGetLockMode()); assertEquals(initialValue, ref.atomicGet()); } @Test public void whenPrivatizedInOuter_thenCanSafelyBeEnsuredInInner() { final int initialValue = 10; final TxnLong ref = new GammaTxnLong(stm, initialValue); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getLock().acquire(LockMode.Exclusive); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getLock().acquire(LockMode.Write); assertEquals(LockMode.Exclusive, ref.getLock().getLockMode()); } }); } }); assertEquals(LockMode.None, ref.getLock().atomicGetLockMode()); assertEquals(initialValue, ref.atomicGet()); } @Test public void whenPrivatizedInOuter_thenCanSafelyBePrivatizedInInner() { final int initialValue = 10; final TxnLong ref = new GammaTxnLong(stm, initialValue); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getLock().acquire(LockMode.Exclusive); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.getLock().acquire(LockMode.Exclusive); assertEquals(LockMode.Exclusive, ref.getLock().getLockMode()); } }); } }); assertEquals(LockMode.None, ref.getLock().atomicGetLockMode()); assertEquals(initialValue, ref.atomicGet()); } } ComposabilityAndReadConsistencyTest.java000066400000000000000000000003321174000617100460230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/composabilitypackage org.multiverse.stms.gamma.integration.composability; import org.junit.Ignore; import org.junit.Test; public class ComposabilityAndReadConsistencyTest { @Test @Ignore public void test() { } } ComposabilityTest.java000066400000000000000000000170061174000617100423700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/composabilitypackage org.multiverse.stms.gamma.integration.composability; import org.junit.Before; import org.junit.Test; import org.multiverse.SomeUncheckedException; import org.multiverse.api.StmUtils; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnInteger; import static org.junit.Assert.*; import static org.multiverse.api.StmUtils.newTxnInteger; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class ComposabilityTest { @Before public void setUp() { clearThreadLocalTxn(); } @Test public void whenChangeMadeInOneSibling_thenItWillBeVisibleInNextSubling() { final int initialValue = 10; final TxnInteger ref = newTxnInteger(initialValue); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); } }); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertEquals(initialValue + 1, ref.get()); ref.increment(); } }); assertEquals(initialValue + 2, ref.get()); } }); assertEquals(initialValue + 2, ref.atomicGet()); } @Test public void whenMultipleSiblings_thenSameTransaction() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(final Txn outerTx) throws Exception { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn innerTx) throws Exception { assertSame(innerTx, outerTx); } }); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn innerTx) throws Exception { assertSame(innerTx, outerTx); } }); } }); } @Test public void whenComposingTransaction_thenInnerAndOuterTransactionAreTheSame() { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(final Txn outerTx) throws Exception { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn innerTx) throws Exception { assertSame(innerTx, outerTx); } }); } }); } @Test public void whenSurroundingTransactionFails_thenChangesInInnerTransactionWillRollback() { int initialValue = 10; final TxnInteger ref = newTxnInteger(initialValue); try { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); } }); throw new SomeUncheckedException(); } }); fail(); } catch (SomeUncheckedException expected) { } assertEquals(initialValue, ref.atomicGet()); } @Test public void whenInnerTransactionFails_thenOuterTransactionWillRollback() { int initialValue = 10; final TxnInteger ref = newTxnInteger(initialValue); try { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { throw new SomeUncheckedException(); } }); } }); fail(); } catch (SomeUncheckedException expected) { } assertEquals(initialValue, ref.atomicGet()); } @Test public void whenSiblingFails_thenAllRollback() { int initialValue = 10; final TxnInteger ref = newTxnInteger(initialValue); try { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); } }); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { throw new SomeUncheckedException(); } }); } }); fail(); } catch (SomeUncheckedException expected) { } assertEquals(initialValue, ref.atomicGet()); } @Test public void whenOuterTransactionMakesChange_thenItWillBeVisibleInInnerTransaction() { final int initialValue = 10; final TxnInteger ref = newTxnInteger(initialValue); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertEquals(initialValue + 1, ref.get()); } }); } }); assertEquals(initialValue + 1, ref.atomicGet()); } @Test public void whenInnerTransactionMakesChange_thenItWillBeVisibleInOuterTransaction() { final int initialValue = 10; final TxnInteger ref = newTxnInteger(initialValue); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); } }); assertEquals(initialValue + 1, ref.get()); } }); assertEquals(initialValue + 1, ref.atomicGet()); } @Test public void whenInnerAndOuterChanges_thenWillCommitAsOne() { final int initialValue = 10; final TxnInteger ref = newTxnInteger(initialValue); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); StmUtils.atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.increment(); } }); ref.increment(); } }); assertEquals(initialValue + 3, ref.atomicGet()); } } 000077500000000000000000000000001174000617100365375ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/failureatomicityFailureAtomicityStressTest.java000066400000000000000000000066731174000617100447340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/failureatomicitypackage org.multiverse.stms.gamma.integration.failureatomicity; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class FailureAtomicityStressTest { private int modifyThreadCount = 10; private boolean stop; private GammaTxnLong ref; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); ref = new GammaTxnLong(stm); stop = false; } @Test public void test() { ModifyThread[] modifyThreads = new ModifyThread[modifyThreadCount]; for (int k = 0; k < modifyThreadCount; k++) { modifyThreads[k] = new ModifyThread(k); } startAll(modifyThreads); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(modifyThreads); //since half of the transactions are going to be aborted we need to divide it by 2 assertEquals(sum(modifyThreads), ref.atomicGet()); } public long sum(ModifyThread[] threads) { long result = 0; for (ModifyThread thread : threads) { result += thread.writeCount; } return result; } public class ModifyThread extends TestThread { long writeCount; final TxnExecutor txnExecutor = stm.newTxnFactoryBuilder() .newTxnExecutor(); public ModifyThread(int id) { super("ModifyThread-" + id); } @Override public void doRun() throws Exception { while (!stop) { if (writeCount % 500000 == 0) { System.out.printf("%s is at %s\n", getName(), writeCount); } boolean abort = randomOneOf(10); if (abort) { try { modifyButAbort(); fail(); } catch (DeadTxnException ignore) { } } else { writeCount++; modify(); } } } private void modify() { txnExecutor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; long value = ref.get(btx); ref.getAndSet(btx, value + 1); } }); } private void modifyButAbort() { txnExecutor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; long value = ref.get(btx); ref.getAndSet(btx, value + 1); btx.abort(); } }); } } } TimeoutRollbackTest.java000066400000000000000000000035171174000617100433500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/failureatomicitypackage org.multiverse.stms.gamma.integration.failureatomicity; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.RetryTimeoutException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class TimeoutRollbackTest { private GammaTxnLong modifyRef; private GammaTxnLong awaitRef; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); modifyRef = new GammaTxnLong(stm); awaitRef = new GammaTxnLong(stm); } @Test public void test() { try { setAndTimeout(); fail(); } catch (RetryTimeoutException expected) { } assertEquals(0, modifyRef.atomicGet()); } public void setAndTimeout() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setTimeoutNs(TimeUnit.SECONDS.toNanos(1)) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; modifyRef.getAndSet(btx, 1); if (awaitRef.get(btx) != 1000) { retry(); } } }); } } TooManyRetriesRollbackTest.java000066400000000000000000000054751174000617100446530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/failureatomicitypackage org.multiverse.stms.gamma.integration.failureatomicity; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.TooManyRetriesException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class TooManyRetriesRollbackTest { private GammaTxnLong modifyRef; private GammaTxnLong retryRef; private volatile boolean finished; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); modifyRef = new GammaTxnLong(stm); retryRef = new GammaTxnLong(stm); finished = false; } @Test public void test() { NotifyThread notifyThread = new NotifyThread(); notifyThread.start(); try { setAndAwaitUneven(1); fail(); } catch (TooManyRetriesException expected) { } finished = true; assertEquals(0, modifyRef.atomicGet()); joinAll(notifyThread); } public void setAndAwaitUneven(final int value) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setMaxRetries(10) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; modifyRef.getAndSet(btx, value); if (retryRef.get(btx) % 2 == 0) { retry(); } } }); } class NotifyThread extends TestThread { public NotifyThread() { super("NotifyThread"); } @Override public void doRun() throws Exception { TxnExecutor executor = stm.newTxnFactoryBuilder() .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; long value = retryRef.get(btx); retryRef.getAndSet(btx, value + 2); } }; while (!finished) { executor.execute(callable); } } } } 000077500000000000000000000000001174000617100351665ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationAbaTest.java000066400000000000000000000020631174000617100373550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class AbaTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void test() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); ref.atomicIncrementAndGet(1); ref.atomicIncrementAndGet(-1); ref.incrementAndGet(tx, 1); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } } } AtomicIncrementIsolationStressTest.java000066400000000000000000000057531174000617100450520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static java.lang.System.currentTimeMillis; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.BenchmarkUtils.transactionsPerSecondAsString; import static org.multiverse.stms.gamma.BenchmarkUtils.transactionsPerSecondPerThreadAsString; public class AtomicIncrementIsolationStressTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void test() { int threadCount = 2; UpdateThread[] threads = new UpdateThread[threadCount]; GammaTxnLong ref = new GammaTxnLong(stm, 0); long transactionsPerThread = 200 * 1000 * 1000; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k, ref, transactionsPerThread); } for (UpdateThread thread : threads) { thread.start(); } joinAll(10 * 60, threads); long totalDurationMs = 0; for (UpdateThread thread : threads) { totalDurationMs += thread.durationMs; } System.out.println("--------------------------------------------------------"); System.out.printf("Threadcount: %s\n", threadCount); System.out.printf("Performance: %s transactions/second/thread\n", transactionsPerSecondPerThreadAsString(transactionsPerThread, totalDurationMs, threadCount)); System.out.printf("Performance: %s transactions/second\n", transactionsPerSecondAsString(transactionsPerThread, totalDurationMs, threadCount)); assertEquals(threadCount * transactionsPerThread, ref.atomicGet()); System.out.println("ref.orec: " + ref.___toOrecString()); } class UpdateThread extends TestThread { private final GammaTxnLong ref; private final long count; private long durationMs; public UpdateThread(int id, GammaTxnLong ref, long count) { super("UpdateThread-" + id); this.ref = ref; this.count = count; } @Override public void doRun() { long startMs = currentTimeMillis(); for (long k = 0; k < count; k++) { ref.atomicIncrementAndGet(1); if (k % 10000000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } durationMs = currentTimeMillis() - startMs; System.out.printf("finished %s after %s ms\n", getName(), durationMs); } } } DirtyCheckTest.java000066400000000000000000000057611174000617100407330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class DirtyCheckTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenNoDirtyCheckAndNonDirtyWrite() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .newTransactionFactory() .newTxn(); ref.set(tx, initialValue); tx.commit(); assertEquals(initialValue, ref.atomicGet()); assertVersionAndValue(ref, initialVersion + 1, initialValue); } @Test public void whenNoDirtyCheckAndDirtyWrite() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .newTransactionFactory() .newTxn(); String newValue = "bar"; ref.set(tx, newValue); tx.commit(); assertEquals(newValue, ref.atomicGet()); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenDirtyCheckAndNonDirtyWrite() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(true) .newTransactionFactory() .newTxn(); ref.set(tx, initialValue); tx.commit(); assertEquals(initialValue, ref.atomicGet()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenDirtyCheckAndDirtyWrite() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(true) .newTransactionFactory() .newTxn(); String newValue = "bar"; ref.set(tx, newValue); tx.commit(); assertEquals(newValue, ref.atomicGet()); assertVersionAndValue(ref, initialVersion + 1, newValue); } } Isolation_AbstractTest.java000077500000000000000000000150351174000617100424640ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static java.lang.System.currentTimeMillis; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.BenchmarkUtils.transactionsPerSecondAsString; import static org.multiverse.stms.gamma.BenchmarkUtils.transactionsPerSecondPerThreadAsString; /** * A StressTest that checks if the system is able to deal with concurrent increments on a TxnLong * So there is a lot of contention. * * @author Peter Veentjer */ public abstract class Isolation_AbstractTest implements GammaConstants { public long transactionsPerThread = 50 * 1000 * 1000; public final int threadCount = 2; protected GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } protected abstract TxnExecutor newBlock(LockMode lockMode, boolean dirtyCheckEnabled); @Test public void withNoLockingDirtyCheck() { test(LockMode.None, true); } @Test public void withNoLockAndNoDirtyCheck() { test(LockMode.None, false); } @Test public void withReadLockAndDirtyCheck() { test(LockMode.Read, true); } @Test public void withReadLockAndNoDirtyCheck() { test(LockMode.Read, false); } @Test public void withWriteLockingAndDirtyCheck() { test(LockMode.Write, true); } @Test public void withWriteLockAndNoDirtyCheck() { test(LockMode.Write, false); } @Test public void withExclusiveLockAndDirtyCheck() { test(LockMode.Exclusive, true); } @Test public void withExclusiveLockNoDirtyCheck() { test(LockMode.Exclusive, false); } @Test public void withMixedSettings() { transactionsPerThread = 10000000; GammaTxnLong ref = new GammaTxnLong(stm); UpdateThread[] threads = new UpdateThread[8]; threads[0] = new UpdateThread(0, ref, LockMode.None, true); threads[1] = new UpdateThread(1, ref, LockMode.None, false); threads[2] = new UpdateThread(0, ref, LockMode.Read, true); threads[3] = new UpdateThread(1, ref, LockMode.Read, false); threads[4] = new UpdateThread(2, ref, LockMode.Write, true); threads[5] = new UpdateThread(3, ref, LockMode.Write, false); threads[6] = new UpdateThread(4, ref, LockMode.Exclusive, true); threads[7] = new UpdateThread(5, ref, LockMode.Exclusive, false); startAll(threads); joinAll(threads); long totalDurationMs = 0; for (UpdateThread thread : threads) { totalDurationMs += thread.durationMs; } System.out.println("--------------------------------------------------------"); System.out.printf("Threadcount: %s\n", threads.length); System.out.printf("Performance: %s transactions/second/thread\n", transactionsPerSecondPerThreadAsString(transactionsPerThread, totalDurationMs, threads.length)); System.out.printf("Performance: %s transactions/second\n", transactionsPerSecondAsString(transactionsPerThread, totalDurationMs, threads.length)); assertEquals(threads.length * transactionsPerThread, ref.atomicGet()); System.out.println("ref.orec: " + ref.___toOrecString()); } public void test(LockMode lockMode, boolean dirtyCheckEnabled) { UpdateThread[] threads = new UpdateThread[threadCount]; GammaTxnLong ref = new GammaTxnLong(stm); for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k, ref, lockMode, dirtyCheckEnabled); } startAll(threads); joinAll(threads); long totalDurationMs = 0; for (UpdateThread thread : threads) { totalDurationMs += thread.durationMs; } System.out.println("--------------------------------------------------------"); System.out.printf("Threadcount: %s\n", threadCount); System.out.printf("Performance: %s transactions/second/thread\n", transactionsPerSecondPerThreadAsString(transactionsPerThread, totalDurationMs, threadCount)); System.out.printf("Performance: %s transactions/second\n", transactionsPerSecondAsString(transactionsPerThread, totalDurationMs, threadCount)); System.out.println("ref.orec: " + ref.___toOrecString()); assertEquals(threadCount * transactionsPerThread, ref.atomicGet()); } class UpdateThread extends TestThread { private final boolean dirtyCheckEnabled; private final GammaTxnLong ref; private final LockMode lockMode; private long durationMs; public UpdateThread(int id, GammaTxnLong ref, LockMode lockMode, boolean dirtyCheckEnabled) { super("UpdateThread-" + id); this.ref = ref; this.lockMode = lockMode; this.dirtyCheckEnabled = dirtyCheckEnabled; } @Override public void doRun() { TxnExecutor executor = newBlock(lockMode, dirtyCheckEnabled); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; btx.richmansMansConflictScan = false; ref.openForWrite(btx, LOCKMODE_NONE).long_value++; } }; long startMs = currentTimeMillis(); for (long k = 0; k < transactionsPerThread; k++) { executor.execute(callable); if (k % 500000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } durationMs = currentTimeMillis() - startMs; System.out.printf("finished %s after %s ms\n", getName(), durationMs); } } } Isolation_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000014471174000617100465540ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class Isolation_FatFixedLengthGammaTxn_StressTest extends Isolation_AbstractTest { @Override protected TxnExecutor newBlock(LockMode lockMode, boolean dirtyCheckEnabled) { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode) .setDirtyCheckEnabled(dirtyCheckEnabled); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } Isolation_FatMonoGammaTxn_StressTest.java000066400000000000000000000014211174000617100452530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; public class Isolation_FatMonoGammaTxn_StressTest extends Isolation_AbstractTest { @Override protected TxnExecutor newBlock(LockMode lockMode, boolean dirtyCheckEnabled) { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode) .setDirtyCheckEnabled(dirtyCheckEnabled); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } } Isolation_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000014601174000617100472350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class Isolation_FatVariableLengthGammaTxn_StressTest extends Isolation_AbstractTest { @Override protected TxnExecutor newBlock(LockMode lockMode, boolean dirtyCheckEnabled) { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode) .setDirtyCheckEnabled(dirtyCheckEnabled); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } LongRefReadConsistency_AbstractTest.java000066400000000000000000000123361174000617100450730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.After; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.Assert.assertFalse; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * Question: could the problem be in the quick release mechanism? *

* Problem? * if a writing transaction has done n updates (and has released the updates) and has m to go. * If a reading transaction reads the n updates, there is no reason for the updating transaction to cause * a conflict since they are no conflicting arrives on the part if has already completes. If the reading transactions * hits the n+1 update, it is allowed to see a different value than it already has read... * problem.. the n updates it has read, already contains the new values, so reading another new value is no problem. */ public abstract class LongRefReadConsistency_AbstractTest { private GammaTxnLong[] refs; private int readerCount = 10; private int writerCount = 2; private long durationMs = 1 * 60 * 1000; private volatile boolean stop; protected GammaStm stm; protected final AtomicBoolean inconsistencyDetected = new AtomicBoolean(); @Before public void setUp() { clearThreadLocalTxn(); stop = false; stm = new GammaStm(); inconsistencyDetected.set(false); } @After public void tearDown() { System.out.println("Stm.GlobalConflictCount: " + stm.getGlobalConflictCounter().count()); for (GammaTxnLong ref : refs) { System.out.println(ref.toDebugString()); } } protected abstract TxnExecutor createReadBlock(); protected abstract TxnExecutor createWriteBlock(); public void run(int refCount) { refs = new GammaTxnLong[refCount]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnLong(stm); } ReadThread[] readerThreads = new ReadThread[readerCount]; for (int k = 0; k < readerThreads.length; k++) { readerThreads[k] = new ReadThread(k); } WriterThread[] writerThreads = new WriterThread[writerCount]; for (int k = 0; k < writerThreads.length; k++) { writerThreads[k] = new WriterThread(k); } startAll(readerThreads); startAll(writerThreads); System.out.printf("Running for %s milliseconds\n", durationMs); sleepMs(getStressTestDurationMs(durationMs)); stop = true; joinAll(readerThreads); joinAll(writerThreads); assertFalse(inconsistencyDetected.get()); } public class WriterThread extends TestThread { private int id; public WriterThread(int id) { super("WriterThread-" + id); this.id = id; } @Override public void doRun() throws Exception { TxnExecutor executor = createWriteBlock(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; for (int k = 0; k < refs.length; k++) { refs[k].set(btx, id); } } }; int mod = 1; int k = 0; while (!stop) { executor.execute(callable); sleepRandomUs(100); k++; if (k % mod == 0) { mod = mod * 2; System.out.printf("%s is at %s\n", getName(), k); } } } } public class ReadThread extends TestThread { public ReadThread(int id) { super("ReadThread-" + id); } @Override public void doRun() throws Exception { TxnExecutor executor = createReadBlock(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; long initial = refs[0].get(btx); for (int k = 1; k < refs.length; k++) { long s = refs[k].get(btx); if(initial!=s){ inconsistencyDetected.set(true); stop = true; System.out.printf("Inconsistency detected at index %s!!\n",k); } } } }; int mod = 1; int k = 0; while (!stop) { executor.execute(callable); k++; if (k % mod == 0) { mod = mod * 2; System.out.printf("%s is at %s\n", getName(), k); } } } } } LongRefReadConsistency_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000062141174000617100511620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class LongRefReadConsistency_FatFixedLengthGammaTxn_StressTest extends LongRefReadConsistency_AbstractTest { private int refCount; private boolean poorMansReadConsistency; @Test public void poormansReadConsistency_with2Refs() { refCount = 2; poorMansReadConsistency = true; run(refCount); } @Test public void poormansReadConsistency_with4Refs() { refCount = 4; poorMansReadConsistency = true; run(refCount); } @Test public void poormansReadConsistency_with8Refs() { poorMansReadConsistency = true; refCount = 8; run(refCount); } @Test public void poormansReadConsistency_with16Refs() { poorMansReadConsistency = true; refCount = 16; run(refCount); } @Test public void poormansReadConsistency_with32Refs() { poorMansReadConsistency = true; refCount = 32; run(refCount); } @Test public void poormansReadConsistency_with64Refs() { poorMansReadConsistency = true; refCount = 64; run(refCount); } @Test public void richmansReadConsistency_with2Refs() { refCount = 2; poorMansReadConsistency = false; run(refCount); } @Test public void richmansReadConsistency_with4Refs() { refCount = 4; poorMansReadConsistency = false; run(refCount); } @Test public void richmansReadConsistency_with8Refs() { poorMansReadConsistency = false; refCount = 8; run(refCount); } @Test public void richmansReadConsistency_with16Refs() { poorMansReadConsistency = false; refCount = 16; run(refCount); } @Test public void richmansReadConsistency_with32Refs() { poorMansReadConsistency = false; refCount = 32; run(refCount); } @Test public void richmansReadConsistency_with64Refs() { poorMansReadConsistency = false; refCount = 64; run(refCount); } @Override protected TxnExecutor createReadBlock() { GammaTxnConfig config = new GammaTxnConfig(stm, refCount) .setSpeculative(false) .setDirtyCheckEnabled(false) .setMaximumPoorMansConflictScanLength(poorMansReadConsistency ? Integer.MAX_VALUE : 0); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor createWriteBlock() { GammaTxnConfig config = new GammaTxnConfig(stm, refCount) .setDirtyCheckEnabled(false) .setSpeculative(false) .setMaximumPoorMansConflictScanLength(poorMansReadConsistency ? Integer.MAX_VALUE : 0); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } LongRefReadConsistency_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000073001174000617100516450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class LongRefReadConsistency_FatVariableLengthGammaTxn_StressTest extends LongRefReadConsistency_AbstractTest { private int refCount; private boolean poorMansReadConsistency; @Test public void poorMansConflictScan_testWith2Refs() { refCount = 2; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith4Refs() { refCount = 4; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith8Refs() { refCount = 8; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith16Refs() { refCount = 16; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith32Refs() { refCount = 32; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith128Refs() { refCount = 128; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith512Refs() { refCount = 512; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith2048Refs() { poorMansReadConsistency = true; refCount = 2048; run(refCount); } @Test public void richMansConflictScan_testWith2Refs() { refCount = 2; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith4Refs() { refCount = 4; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith8Refs() { refCount = 8; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith16Refs() { refCount = 16; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith32Refs() { refCount = 32; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith128Refs() { refCount = 128; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith512Refs() { refCount = 512; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith2048Refs() { poorMansReadConsistency = false; refCount = 2048; run(refCount); } @Override protected TxnExecutor createReadBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setMaximumPoorMansConflictScanLength(poorMansReadConsistency ? Integer.MAX_VALUE : 0); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor createWriteBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setMaximumPoorMansConflictScanLength(poorMansReadConsistency ? Integer.MAX_VALUE : 0); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } MoneyTransfer_AbstractTest.java000077500000000000000000000076171174000617100433260ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.After; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; //todo: testing of different lock modes //todo: testing if multiple transfers are done public abstract class MoneyTransfer_AbstractTest { private volatile boolean stop; private GammaTxnLong[] accounts; protected GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stop = false; stm = (GammaStm) getGlobalStmInstance(); } @After public void tearDown() { System.out.println("Stm.GlobalConflictCount: " + stm.getGlobalConflictCounter().count()); for (GammaTxnLong ref : accounts) { System.out.println(ref.toDebugString()); } } protected abstract TxnExecutor newTxnExecutor(); public void run(int accountCount, int threadCount) { accounts = new GammaTxnLong[accountCount]; long initialAmount = 0; for (int k = 0; k < accountCount; k++) { long amount = randomInt(1000); initialAmount += amount; accounts[k] = new GammaTxnLong(stm, amount); } TransferThread[] threads = createThreads(threadCount); startAll(threads); sleepMs(30 * 1000); stop = true; joinAll(threads); assertEquals(initialAmount, getTotal()); } private long getTotal() { long sum = 0; for (GammaTxnLong account : accounts) { sum += account.atomicGet(); } return sum; } private TransferThread[] createThreads(int threadCount) { TransferThread[] threads = new TransferThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new TransferThread(k); } return threads; } private class TransferThread extends TestThread { public TransferThread(int id) { super("TransferThread-" + id); } public void doRun() { TxnExecutor executor = newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; GammaTxnLong from = accounts[randomInt(accounts.length)]; GammaTxnLong to = accounts[randomInt(accounts.length)]; int amount = randomInt(100); to.openForWrite(btx, LOCKMODE_NONE).long_value += amount; sleepRandomMs(10); Tranlocal toTranlocal = from.openForWrite(btx, LOCKMODE_NONE); if (toTranlocal.long_value < 0) { throw new NotEnoughMoneyException(); } toTranlocal.long_value -= amount; } }; int k = 0; while (!stop) { try { executor.execute(callable); if ((k % 500) == 0) { System.out.printf("%s is at iteration %s\n", getName(), k); } k++; } catch (NotEnoughMoneyException ignore) { } } } } private static class NotEnoughMoneyException extends RuntimeException { } } MoneyTransfer_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000031451174000617100474040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class MoneyTransfer_FatFixedLengthGammaTxn_StressTest extends MoneyTransfer_AbstractTest { private LockMode lockMode; private int accountCount; @Test public void when10AccountsAnd2ThreadsAndOptimistic() { lockMode = LockMode.None; accountCount = 10; run(accountCount, 2); } @Test public void when10AccountsAnd2ThreadsAndPessimistic() { lockMode = LockMode.Exclusive; accountCount = 10; run(accountCount, 2); } @Test public void when100AccountAnd10ThreadsAndOptimistic() { lockMode = LockMode.None; accountCount = 100; run(accountCount, 10); } @Test public void when100AccountAnd10ThreadsAndPessimistic() { lockMode = LockMode.Exclusive; accountCount = 100; run(accountCount, 10); } @Test public void when30AccountsAnd30ThreadsAndOptimistic() { lockMode = LockMode.None; accountCount = 30; run(accountCount, 30); } @Override protected TxnExecutor newTxnExecutor() { GammaTxnConfig config = new GammaTxnConfig(stm, accountCount) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } MoneyTransfer_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000034501174000617100500710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class MoneyTransfer_FatVariableLengthGammaTxn_StressTest extends MoneyTransfer_AbstractTest { private LockMode lockMode; @Test public void when10AccountsAnd2ThreadsAndOptimistic() { lockMode = LockMode.None; run(10, 2); } @Test public void when10AccountsAnd2ThreadsAndPessimistic() { lockMode = LockMode.Exclusive; run(10, 2); } @Test public void when100AccountAnd10ThreadsAndOptimistic() { lockMode = LockMode.None; run(100, 10); } @Test public void when100AccountAnd10ThreadsAndPessimistic() { lockMode = LockMode.Exclusive; run(100, 10); } @Test public void when1000AccountsAnd10ThreadsAndOptimistic() { lockMode = LockMode.None; run(1000, 10); } @Test public void when1000AccountsAnd10ThreadsAndPessimistic() { lockMode = LockMode.Exclusive; run(1000, 10); } @Test public void when30AccountsAnd30ThreadsAndOptimistic() { lockMode = LockMode.None; run(30, 30); } @Test public void when30AccountsAnd30ThreadsAndPessimistic() { lockMode = LockMode.Exclusive; run(30, 30); } @Override protected TxnExecutor newTxnExecutor() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } Orec_LongRef_ReadConsistencyStressTest.java000066400000000000000000000373201174000617100455630ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.*; import org.multiverse.stms.gamma.GammaTxnExecutor; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.multiverse.TestUtils.*; /** * Conclusion so far: * with refs it fails * with longs it succeeds. */ public class Orec_LongRef_ReadConsistencyStressTest implements GammaConstants { private GammaStm stm; private GammaTxnLong[] refs; private volatile boolean stop; private final AtomicBoolean inconstencyDetected = new AtomicBoolean(); private int readingThreadCount; private int writingThreadCount; private int refCount; private int durationMs; @Before public void setUp() { stm = new GammaStm(); stop = false; refCount = 128; readingThreadCount = 10; writingThreadCount = 2; durationMs = 300 * 1000; refs = new GammaTxnLong[refCount]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnLong(stm, 0); } inconstencyDetected.set(false); } @After public void after() { for (GammaTxnLong ref : refs) { System.out.println(ref.toDebugString()); } } @Test public void test() { FatVariableLengthTransactionWithBlockThread[] readingThreads = new FatVariableLengthTransactionWithBlockThread[readingThreadCount]; for (int k = 0; k < readingThreads.length; k++) { readingThreads[k] = new FatVariableLengthTransactionWithBlockThread(k); } UpdatingThread[] threads = new UpdatingThread[writingThreadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdatingThread(k); } startAll(readingThreads); startAll(threads); sleepMs(durationMs); stop = true; joinAll(readingThreads); joinAll(threads); assertFalse(inconstencyDetected.get()); } class UpdatingThread extends TestThread { private int id; public UpdatingThread(int id) { super("UpdatingThread-" + id); this.id = id; } @Override public void doRun() throws Exception { GammaTxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(false) .setMaxRetries(100000) .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { for (GammaTxnLong ref : refs) { ref.incrementAndGet(1); } } }; int iteration = 0; while (!stop) { executor.execute(callable); sleepRandomUs(100); iteration++; if (iteration % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } } class ReadingThread extends TestThread { private Tranlocal[] tranlocals; private long lastConflictCount = stm.getGlobalConflictCounter().count(); private GammaObjectPool pool = new GammaObjectPool(); private GammaTxn dummyTx = stm.newDefaultTxn(); public ReadingThread(int id) { super("ReadingThread-" + id); tranlocals = new Tranlocal[refs.length]; for (int k = 0; k < tranlocals.length; k++) { Tranlocal tranlocal = new Tranlocal(); tranlocal.owner = refs[k]; tranlocals[k] = tranlocal; } } @Override public void doRun() throws Exception { long iteration = 0; while (!stop) { singleRun(System.nanoTime() % 10 == 0 && false); iteration++; if (iteration % 10000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun(boolean write) { boolean success = false; while (!success) { assertCorrectlyCleared(); fullRead(); assertReadConsistent(); success = !write || fullWrite(); } releaseChainAfterSuccess(write); } private boolean fullWrite() { for (int k = 0; k < refs.length; k++) { GammaTxnLong ref = refs[k]; Tranlocal tranlocal = tranlocals[k]; //if (!ref.tryLockAfterNormalArrive(64, LOCKMODE_EXCLUSIVE)) { // releaseChainAfterFailure(); // return false; //} tranlocal.lockMode = LOCKMODE_EXCLUSIVE; if (tranlocal.version != ref.version) { releaseChainAfterFailure(); return false; } } for (int k = 0; k < refs.length; k++) { refs[k].version++; refs[k].departAfterUpdateAndUnlock(); tranlocals[k].lockMode = LOCKMODE_NONE; tranlocals[k].hasDepartObligation = false; } return true; } private void fullRead() { for (; ;) { lastConflictCount = stm.getGlobalConflictCounter().count(); for (int k = 0; k < refs.length; k++) { GammaTxnLong ref = refs[k]; Tranlocal tranlocal = tranlocals[k]; if (!ref.load(dummyTx,tranlocal, LOCKMODE_NONE, 64, true)) { releaseChainAfterFailure(); break; } if (!isReadConsistent()) { releaseChainAfterFailure(); break; } if (k == refs.length - 1) { return; } } } } private void assertReadConsistent() { long version = tranlocals[0].version; for (int k = 1; k < tranlocals.length; k++) { if (version != tranlocals[k].version) { System.out.println("Inconsistency detected"); inconstencyDetected.compareAndSet(false, true); stop = true; break; } } } private boolean isReadConsistent() { long globalConflictCount = stm.getGlobalConflictCounter().count(); if (lastConflictCount == globalConflictCount) { return true; } lastConflictCount = globalConflictCount; for (Tranlocal tranlocal : tranlocals) { BaseGammaTxnRef owner = tranlocal.owner; if (!tranlocal.hasDepartObligation) { continue; } if (owner.hasExclusiveLock()) { return false; } if (tranlocal.version != owner.version) { return false; } } return true; } private void assertCorrectlyCleared() { for (Tranlocal tranlocal : tranlocals) { assertFalse(tranlocal.hasDepartObligation); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); } } private void releaseChainAfterFailure() { for (Tranlocal tranlocal : tranlocals) { BaseGammaTxnRef owner = tranlocal.owner; tranlocal.owner.releaseAfterFailure(tranlocal, pool); tranlocal.owner = owner; //if (tranlocal.hasDepartObligation) { // tranlocal.hasDepartObligation = false; // if (tranlocal.lockMode == LOCKMODE_NONE) { // tranlocal.owner.departAfterFailure(); // } else { // tranlocal.lockMode = LOCKMODE_NONE; // tranlocal.owner.departAfterFailureAndUnlock(); // } //} } } private void releaseChainAfterSuccess(boolean write) { for (Tranlocal tranlocal : tranlocals) { BaseGammaTxnRef owner = tranlocal.owner; if (write) { owner.releaseAfterUpdate(tranlocal, pool); } else { owner.releaseAfterReading(tranlocal, pool); } tranlocal.owner = owner; } } } class FixedReadingThread extends TestThread { private FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn( new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(0) .setDirtyCheckEnabled(false) ); public FixedReadingThread(int id) { super("ReadingThread-" + id); } @Override public void doRun() throws Exception { long iteration = 0; while (!stop) { singleRun(System.nanoTime() % 10 == 0 && false); iteration++; if (iteration % 1000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun(boolean write) { tx.hardReset(); boolean success = false; while (!success) { fullRead(write); assertReadConsistent(tx); try { tx.commit(); success = true; } catch (ReadWriteConflict expected) { success = false; tx.attempt = 1; tx.softReset(); } } tx.commit(); } private void fullRead(boolean write) { for (; ;) { try { for (int k = 0; k < refs.length; k++) { if (write) { refs[k].openForWrite(tx, LOCKMODE_NONE); } else { Tranlocal tranlocal = refs[k].openForRead(tx, LOCKMODE_NONE); tranlocal.long_value = tranlocal.version + 1; } if (k == refs.length - 1) { return; } } } catch (ReadWriteConflict expected) { tx.attempt = 1; tx.softReset(); } } } } class VariableReadingThread extends TestThread { private FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn( new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(0) .setDirtyCheckEnabled(false) ); public VariableReadingThread(int id) { super("ReadingThread-" + id); } @Override public void doRun() throws Exception { long iteration = 0; while (!stop) { singleRun(System.nanoTime() % 10 == 0 && false); iteration++; if (iteration % 1000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun(boolean write) { tx.hardReset(); boolean success = false; while (!success) { fullRead(write); assertReadConsistent(tx); try { tx.commit(); success = true; } catch (ReadWriteConflict expected) { success = false; tx.attempt = 1; tx.softReset(); } } tx.commit(); } private void fullRead(boolean write) { for (; ;) { try { for (int k = 0; k < refs.length; k++) { if (write) { Tranlocal tranlocal = refs[k].openForWrite(tx, LOCKMODE_NONE); tranlocal.ref_value = getName(); } else { refs[k].openForRead(tx, LOCKMODE_NONE); } if (k == refs.length - 1) { return; } } } catch (ReadWriteConflict expected) { tx.attempt = 1; tx.softReset(); } } } } class FatVariableLengthTransactionWithBlockThread extends TestThread { private LeanGammaTxnExecutor executor; public FatVariableLengthTransactionWithBlockThread(int id) { super("VariableReadingWithBlockThread-" + id); } @Override public void doRun() throws Exception { GammaTxnConfig config = new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(0) .setMaxRetries(100000) .setSpeculative(false) .setDirtyCheckEnabled(false); executor = new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); long iteration = 0; while (!stop) { singleRun(); iteration++; if (iteration % 1000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun() { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { fullRead((GammaTxn) tx); assertReadConsistent((GammaTxn) tx); } }); } private void fullRead(GammaTxn tx) { long value = refs[0].get(tx); for (int k = 0; k < refs.length; k++) { assertEquals(value, refs[k].openForWrite(tx, LOCKMODE_NONE).long_value); } } } private void assertReadConsistent(GammaTxn tx) { long version = tx.getRefTranlocal(refs[0]).version; long value = refs[0].get(tx); for (int k = 1; k < refs.length; k++) { boolean b = version == tx.getRefTranlocal(refs[k]).version && value == refs[k].get(tx); if (!b) { System.out.println("Inconsistency detected"); inconstencyDetected.compareAndSet(false, true); stop = true; break; } } } } Orec_Ref_ReadConsistencyStressTest.java000066400000000000000000000515451174000617100447500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.*; import org.multiverse.stms.gamma.GammaTxnExecutor; import org.multiverse.stms.gamma.transactionalobjects.BaseGammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.*; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; public class Orec_Ref_ReadConsistencyStressTest implements GammaConstants { private GammaStm stm; private GammaTxnRef[] refs; private volatile boolean stop; private final AtomicBoolean inconsistencyDetected = new AtomicBoolean(); private final long durationMs = 360 * 1000; private int refCount = 256; private int writingThreadCount; private int readingThreadCount; @Before public void setUp() { stm = new GammaStm(); stop = false; inconsistencyDetected.set(false); readingThreadCount = 10; writingThreadCount = 2; refs = new GammaTxnRef[refCount]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnRef(stm, 0); } } @After public void after() { for (GammaTxnRef ref : refs) { System.out.println(ref.toDebugString()); } } class UpdatingThread extends TestThread { public UpdatingThread(int id) { super("UpdatingThread-" + id); } @Override public void doRun() throws Exception { GammaTxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(false) .setMaxRetries(100000) // .setReadLockMode(LockMode.Exclusive) .newTxnExecutor(); final String name = getName(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { for (GammaTxnRef ref : refs) { ref.set(tx, name); } } }; int iteration = 0; while (!stop) { executor.execute(callable); sleepRandomUs(100); iteration++; if (iteration % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } } @Test public void basicTest() { BasicReadThread[] readingThreads = new BasicReadThread[readingThreadCount]; for (int k = 0; k < readingThreads.length; k++) { readingThreads[k] = new BasicReadThread(k); } UpdatingThread[] updatingThreads = new UpdatingThread[writingThreadCount]; for (int k = 0; k < updatingThreads.length; k++) { updatingThreads[k] = new UpdatingThread(k); } startAll(readingThreads); startAll(updatingThreads); sleepMs(durationMs); stop = true; sleepMs(1000); joinAll(readingThreads); joinAll(updatingThreads); assertFalse(inconsistencyDetected.get()); } class BasicReadThread extends TestThread { private Tranlocal[] tranlocals; private long lastConflictCount = stm.getGlobalConflictCounter().count(); private GammaObjectPool pool = new GammaObjectPool(); private Tranlocal firstTranlocal; private GammaTxn dummyTransaction = stm.newDefaultTxn(); public BasicReadThread(int id) { super("ReadingThread-" + id); tranlocals = new Tranlocal[refs.length]; for (int k = 0; k < tranlocals.length; k++) { Tranlocal tranlocal = new Tranlocal(); tranlocal.owner = refs[k]; tranlocals[k] = tranlocal; } } @Override public void doRun() throws Exception { long iteration = 0; while (!stop) { singleRun(); iteration++; if (iteration % 10000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun() { assertCorrectlyCleared(); fullRead(); assertReadConsistent(); releaseChainAfterSuccess(); } private void fullRead() { for (; ;) { lastConflictCount = stm.getGlobalConflictCounter().count(); Object v = null; for (int k = 0; k < refs.length; k++) { GammaTxnRef ref = refs[k]; Tranlocal tranlocal = tranlocals[k]; if (!ref.load(dummyTransaction, tranlocal, LOCKMODE_NONE, 64, true)) { releaseChainAfterFailure(); break; } if (!isReadConsistent()) { releaseChainAfterFailure(); break; } if (k == 0) { v = tranlocal.ref_value; } else { if (v != tranlocal.ref_value) { System.out.println("Inconsistency detected"); stop = true; fail(); } } if (k == refs.length - 1) { return; } } } } private void assertReadConsistent() { firstTranlocal = tranlocals[0]; for (int k = 1; k < tranlocals.length; k++) { boolean badValue = tranlocals[k].ref_value != firstTranlocal.ref_value; boolean badVersion = tranlocals[k].version != firstTranlocal.version; if (badValue || badVersion) { if (badValue) { System.out.printf("Inconsistency detected on bad value %s %s\n", tranlocals[k].ref_value, firstTranlocal.ref_value); } else { System.out.printf("Inconsistency detected on bad version %s %s\n", tranlocals[k].version, firstTranlocal.version); } inconsistencyDetected.compareAndSet(false, true); stop = true; break; } } } private boolean isReadConsistent() { long globalConflictCount = stm.getGlobalConflictCounter().count(); if (lastConflictCount == globalConflictCount) { return true; } lastConflictCount = globalConflictCount; for (Tranlocal tranlocal : tranlocals) { BaseGammaTxnRef owner = tranlocal.owner; if (!tranlocal.hasDepartObligation) { continue; } if (owner.hasReadConflict(tranlocal)) { return false; } //if (owner.hasExclusiveLock()) { // return false; //} //if (tranlocal.version != owner.version) { // return false; //} } return true; } private void assertCorrectlyCleared() { for (Tranlocal tranlocal : tranlocals) { assertFalse(tranlocal.hasDepartObligation); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); } } private void releaseChainAfterFailure() { for (Tranlocal tranlocal : tranlocals) { BaseGammaTxnRef owner = tranlocal.owner; tranlocal.owner.releaseAfterFailure(tranlocal, pool); tranlocal.owner = owner; //if (tranlocal.hasDepartObligation) { // tranlocal.hasDepartObligation = false; // if (tranlocal.lockMode == LOCKMODE_NONE) { // tranlocal.owner.departAfterFailure(); // } else { // tranlocal.lockMode = LOCKMODE_NONE; // tranlocal.owner.departAfterFailureAndUnlock(); // } //} } } private void releaseChainAfterSuccess() { for (Tranlocal tranlocal : tranlocals) { BaseGammaTxnRef owner = tranlocal.owner; owner.releaseAfterReading(tranlocal, pool); tranlocal.owner = owner; //if (tranlocal.hasDepartObligation) { // tranlocal.hasDepartObligation = false; // if (tranlocal.lockMode == LOCKMODE_NONE) { // tranlocal.owner.departAfterReading(); // } else { // tranlocal.lockMode = LOCKMODE_NONE; // tranlocal.owner.departAfterUpdateAndUnlock(); // } //} } } } @Test public void testFixedLengthTransactionUsingReadThread() { FixedLengthTransactionUsingReadThread[] readingThreads = new FixedLengthTransactionUsingReadThread[readingThreadCount]; for (int k = 0; k < readingThreads.length; k++) { readingThreads[k] = new FixedLengthTransactionUsingReadThread(k); } UpdatingThread[] updatingThreads = new UpdatingThread[writingThreadCount]; for (int k = 0; k < updatingThreads.length; k++) { updatingThreads[k] = new UpdatingThread(k); } startAll(readingThreads); startAll(updatingThreads); sleepMs(durationMs); stop = true; sleepMs(1000); for (GammaTxnRef ref : refs) { System.out.println(ref.toDebugString()); } joinAll(readingThreads); joinAll(updatingThreads); assertFalse(inconsistencyDetected.get()); } class FixedLengthTransactionUsingReadThread extends TestThread { public final FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn( new GammaTxnConfig(stm, refs.length + 1) .setMaxRetries(10000000) .setMaximumPoorMansConflictScanLength(0) .setDirtyCheckEnabled(false) .setSpeculative(false) ); public FixedLengthTransactionUsingReadThread(int id) { super("ReadingThread-" + id); } @Override public void doRun() throws Exception { long iteration = 0; while (!stop) { singleRun(); iteration++; if (iteration % 10000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun() { tx.hardReset(); while (true) { try { fullRead(); assertReadConsistent(tx); tx.commit(); return; } catch (ReadWriteConflict expected) { tx.hardReset(); } } } private void fullRead() { for (int k = 0; k < refs.length; k++) { GammaTxnRef ref = refs[k]; Tranlocal tranlocal = tx.head; while (tranlocal.owner != null) { tranlocal = tranlocal.next; } tx.size++; if (!tx.hasReads) { tx.localConflictCount = stm.globalConflictCounter.count(); tx.hasReads = true; } if (!ref.load(tx, tranlocal, LOCKMODE_NONE, 64, true)) { throw tx.abortOnReadWriteConflict(ref); } if (!tx.isReadConsistent(tranlocal)) { throw tx.abortOnReadWriteConflict(ref); } //ref.openForRead(tx, LOCKMODE_NONE); if (k == refs.length - 1) { return; } } } } class FixedLengthTransactionReadingThread extends TestThread { private FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn( new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(0) .setDirtyCheckEnabled(false) ); public FixedLengthTransactionReadingThread(int id) { super("ReadingThread-" + id); } @Override public void doRun() throws Exception { long iteration = 0; while (!stop) { singleRun(System.nanoTime() % 10 == 0 && false); iteration++; if (iteration % 1000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun(boolean write) { tx.hardReset(); boolean success = false; while (!success) { fullRead(write); assertReadConsistent(tx); try { tx.commit(); success = true; } catch (ReadWriteConflict expected) { success = false; tx.attempt = 1; tx.softReset(); } } tx.commit(); } private void fullRead(boolean write) { for (; ;) { try { for (int k = 0; k < refs.length; k++) { if (write) { Tranlocal tranlocal = refs[k].openForWrite(tx, LOCKMODE_NONE); tranlocal.ref_value = getName(); } else { refs[k].openForRead(tx, LOCKMODE_NONE); } if (k == refs.length - 1) { return; } } } catch (ReadWriteConflict expected) { tx.attempt = 1; tx.softReset(); } } } } class VariableLengthReadingThread extends TestThread { private FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn( new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(0) .setDirtyCheckEnabled(false) ); public VariableLengthReadingThread(int id) { super("ReadingThread-" + id); } @Override public void doRun() throws Exception { long iteration = 0; while (!stop) { singleRun(System.nanoTime() % 10 == 0 && false); iteration++; if (iteration % 1000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun(boolean write) { tx.hardReset(); boolean success = false; while (!success) { fullRead(write); assertReadConsistent(tx); try { tx.commit(); success = true; } catch (ReadWriteConflict expected) { success = false; tx.attempt = 1; tx.softReset(); } } tx.commit(); } private void fullRead(boolean write) { for (; ;) { try { for (int k = 0; k < refs.length; k++) { if (write) { Tranlocal tranlocal = refs[k].openForWrite(tx, LOCKMODE_NONE); tranlocal.ref_value = getName(); } else { refs[k].openForRead(tx, LOCKMODE_NONE); } if (k == refs.length - 1) { return; } } } catch (ReadWriteConflict expected) { tx.attempt = 1; tx.softReset(); } } } } class VariableReadingWithBlockThread extends TestThread { private LeanGammaTxnExecutor executor; public VariableReadingWithBlockThread(int id) { super("VariableReadingWithBlockThread-" + id); } @Override public void doRun() throws Exception { GammaTxnConfig config = new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(0) .setMaxRetries(100000) .setSpeculative(false) .setDirtyCheckEnabled(false); executor = new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); long iteration = 0; while (!stop) { singleRun(); iteration++; if (iteration % 10000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun() { executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { fullRead((GammaTxn) tx); assertReadConsistent((GammaTxn) tx); } }); } private void fullRead(GammaTxn tx) { Object value = refs[0].get(tx); for (int k = 0; k < refs.length; k++) { assertSame(value, refs[k].openForRead(tx, LOCKMODE_NONE).ref_value); } } } class FixedReadingWithBlockThread extends TestThread { private LeanGammaTxnExecutor executor; private GammaTxnConfig config; public FixedReadingWithBlockThread(int id) { super("VariableReadingWithBlockThread-" + id); } @Override public void doRun() throws Exception { config = new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(0) .setDirtyCheckEnabled(false); executor = new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); long iteration = 0; while (!stop) { singleRun(); iteration++; if (iteration % 10000 == 0) { System.out.printf("%s is at %s\n", getName(), iteration); } } } private void singleRun() { TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { fullRead((GammaTxn) tx); assertReadConsistent((GammaTxn) tx); } }; FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); while (true) { try { callable.call(tx); tx.commit(); return; } catch (ReadWriteConflict expected) { tx.hardReset(); } catch (Exception ex) { throw new RuntimeException(ex); } } //executor.atomicChecked(callable); } private void fullRead(GammaTxn tx) { for (int k = 0; k < refs.length; k++) { refs[k].openForRead(tx, LOCKMODE_NONE); } } } private void assertReadConsistent(GammaTxn tx) { long version = tx.getRefTranlocal(refs[0]).version; Object value = tx.getRefTranlocal(refs[0]).ref_value; for (int k = 1; k < refs.length; k++) { boolean badVersion = version != tx.getRefTranlocal(refs[k]).version; boolean badValue = value != tx.getRefTranlocal(refs[k]).ref_value; if (badValue || badVersion) { System.out.printf("Inconsistency detected badValue=%s badVersion=%s\n", badValue, badVersion); inconsistencyDetected.compareAndSet(false, true); stop = true; break; } } } } PhantomReadTest.java000066400000000000000000000007101174000617100410710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; public class PhantomReadTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); } @Test @Ignore public void test() { } } ReadBiasedIsolationStressTest.java000066400000000000000000000125651174000617100437530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnBooleanCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static java.lang.System.currentTimeMillis; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.randomOneOf; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.BenchmarkUtils.transactionsPerSecondAsString; import static org.multiverse.stms.gamma.BenchmarkUtils.transactionsPerSecondPerThreadAsString; /** * A Stress test that checks if the system is able to deal with mostly reading transactions and doesn't cause * any isolation problems. * * @author Peter Veentjer. */ public class ReadBiasedIsolationStressTest { private GammaStm stm = (GammaStm) getGlobalStmInstance(); private int chanceOfUpdate = new GammaTxnLong(stm).getReadBiasedThreshold() * 5; private int threadCount = 4; @Before public void setUp() { clearThreadLocalTxn(); } //todo: testing with and without arriveenabled functionality @Test public void none_and_dirtyCheckEnabled() { test(LockMode.None, true); } @Test public void none_read_and_dirtyCheckDisabled() { test(LockMode.None, false); } @Test public void read_and_dirtyCheckEnabled() { test(LockMode.Read, true); } @Test public void read_and_dirtyCheckDisabled() { test(LockMode.Read, false); } @Test public void write_and_dirtyCheckEnabled() { test(LockMode.Write, true); } @Test public void write_and_dirtyCheckDisabled() { test(LockMode.Write, false); } @Test public void commit_and_dirtyCheckEnabled() { test(LockMode.Exclusive, true); } @Test public void commit_and_dirtyCheckDisabled() { test(LockMode.Exclusive, false); } public void test(LockMode lockMode, boolean dirtyCheckEnabled) { StressThread[] threads = new StressThread[threadCount]; GammaTxnLong ref = new GammaTxnLong(stm); long transactionsPerThread = 100 * 1000 * 1000; for (int k = 0; k < threads.length; k++) { threads[k] = new StressThread(k, ref, transactionsPerThread, lockMode, dirtyCheckEnabled); } for (StressThread thread : threads) { thread.start(); } joinAll(threads); long totalDurationMs = 0; long sum = 0; for (StressThread thread : threads) { totalDurationMs += thread.durationMs; sum += thread.incrementCount; } System.out.println("--------------------------------------------------------"); System.out.printf("Threadcount: %s\n", threadCount); System.out.printf("Performance: %s transactions/second/thread\n", transactionsPerSecondPerThreadAsString(transactionsPerThread, totalDurationMs, threadCount)); System.out.printf("Performance: %s transactions/second\n", transactionsPerSecondAsString(transactionsPerThread, totalDurationMs, threadCount)); assertEquals(sum, ref.atomicGet()); System.out.println("ref.orec: " + ref.___toOrecString()); } class StressThread extends TestThread { private final boolean dirtyCheckEnabled; private final GammaTxnLong ref; private final long count; private long durationMs; private LockMode lockMode; private long incrementCount = 0; public StressThread(int id, GammaTxnLong ref, long count, LockMode lockMode, boolean dirtyCheckEnabled) { super("StressThread-" + id); this.ref = ref; this.count = count; this.lockMode = lockMode; this.dirtyCheckEnabled = dirtyCheckEnabled; } @Override public void doRun() { TxnExecutor executor = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(dirtyCheckEnabled) .newTxnExecutor(); TxnBooleanCallable callable = new TxnBooleanCallable() { @Override public boolean call(Txn tx) throws Exception { ref.getLock().acquire(tx, lockMode); if (randomOneOf(chanceOfUpdate)) { ref.incrementAndGet(tx, 1); return true; } else { ref.get(tx); return false; } } }; long startMs = currentTimeMillis(); for (long k = 0; k < count; k++) { if (executor.execute(callable)) { incrementCount++; } if (k % 10000000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } durationMs = currentTimeMillis() - startMs; System.out.printf("finished %s after %s ms\n", getName(), durationMs); } } } ReadCommittedStressTest.java000066400000000000000000000102221174000617100426130ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * A Stresstest that check if the it is possible that a dirty read is done (this is not allowed). * * @author Peter Veentjer. */ public class ReadCommittedStressTest { private GammaTxnLong ref; private int readThreadCount = 10; private int modifyThreadCount = 2; private volatile boolean stop; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); ref = new GammaTxnLong(stm); stop = false; } @Test public void test() { FailingModifyThread[] modifyThreads = new FailingModifyThread[modifyThreadCount]; for (int k = 0; k < modifyThreadCount; k++) { modifyThreads[k] = new FailingModifyThread(k); } ReadThread[] readerThread = new ReadThread[readThreadCount]; for (int k = 0; k < readThreadCount; k++) { readerThread[k] = new ReadThread(k); } startAll(modifyThreads); startAll(readerThread); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(modifyThreads); joinAll(readerThread); } class FailingModifyThread extends TestThread { public FailingModifyThread(int threadId) { super("FailingModifyThread-" + threadId); } @Override public void doRun() { TxnExecutor executor = stm.getDefaultTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.getAndSet(btx, ref.get(btx)); btx.abort(); } }; while (!stop) { try { executor.execute(callable); fail(); } catch (DeadTxnException ignore) { } sleepRandomMs(10); } } } class ReadThread extends TestThread { public ReadThread(int threadId) { super("ReadThread-" + threadId); } @Override public void doRun() { TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; if (ref.get(btx) % 2 != 0) { fail(); } } }; TxnExecutor readonlyReadtrackingBlock = stm.newTxnFactoryBuilder() .setReadonly(true) .setReadTrackingEnabled(true) .newTxnExecutor(); TxnExecutor updateReadtrackingBlock = stm.newTxnFactoryBuilder() .setReadonly(false) .setReadTrackingEnabled(true) .newTxnExecutor(); int k = 0; while (!stop) { switch (k % 2) { case 0: readonlyReadtrackingBlock.execute(callable); break; case 1: case 3: updateReadtrackingBlock.execute(callable); break; default: throw new IllegalStateException(); } k++; sleepRandomMs(5); } } } } ReadConflictTest.java000066400000000000000000000032651174000617100412340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class ReadConflictTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenAlreadyReadThenNoConflict() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); ref.atomicIncrementAndGet(1); long result = ref.get(tx); assertEquals(5, result); tx.commit(); assertIsCommitted(tx); } @Test public void testCausalConsistency() { GammaTxnLong ref1 = new GammaTxnLong(stm, 0); GammaTxnLong ref2 = new GammaTxnLong(stm, 0); GammaTxn tx = stm.newDefaultTxn(); ref1.get(tx); GammaTxn otherTx = stm.newDefaultTxn(); ref1.set(otherTx, 1); ref2.set(otherTx, 1); otherTx.commit(); try { ref2.get(tx); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); } } ReadonlyRepeatableReadStressTest.java000066400000000000000000000075231174000617100444420ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.TestUtils; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class ReadonlyRepeatableReadStressTest { private volatile boolean stop; private GammaTxnLong ref; private int readThreadCount = 5; private int modifyThreadCount = 2; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); ref = new GammaTxnLong(stm); stop = false; } @Test public void test() { ModifyThread[] modifyThreads = new ModifyThread[modifyThreadCount]; for (int k = 0; k < modifyThreadCount; k++) { modifyThreads[k] = new ModifyThread(k); } ReadThread[] readerThread = new ReadThread[readThreadCount]; for (int k = 0; k < readThreadCount; k++) { readerThread[k] = new ReadThread(k); } startAll(modifyThreads); startAll(readerThread); sleepMs(TestUtils.getStressTestDurationMs(30 * 1000)); stop = true; joinAll(modifyThreads); joinAll(readerThread); } class ModifyThread extends TestThread { public ModifyThread(int id) { super("ModifyThread-" + id); } @Override public void doRun() { TxnExecutor executor = stm.newTxnFactoryBuilder() .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.getAndSet(btx, ref.get(btx)); } }; while (!stop) { executor.execute(callable); sleepRandomMs(5); } } } class ReadThread extends TestThread { private final TxnExecutor readTrackingReadonlyBlock = stm.newTxnFactoryBuilder() .setReadonly(true) .setReadTrackingEnabled(true) .newTxnExecutor(); private final TxnExecutor readTrackingUpdateBlock = stm.newTxnFactoryBuilder() .setReadonly(false) .setReadTrackingEnabled(true) .newTxnExecutor(); private final TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; long firstTime = ref.get(btx); sleepRandomMs(2); long secondTime = ref.get(btx); assertEquals(firstTime, secondTime); } }; public ReadThread(int id) { super("ReadThread-" + id); } @Override public void doRun() { int k = 0; while (!stop) { switch (k % 2) { case 0: readTrackingReadonlyBlock.execute(callable); break; case 1: readTrackingUpdateBlock.execute(callable); break; default: throw new IllegalStateException(); } k++; } } } } RefReadConsistency_AbstractTest.java000066400000000000000000000132271174000617100442530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.After; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.Assert.assertFalse; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * Question: could the problem be in the quick release mechanism? *

* Problem? * if a writing transaction has done n updates (and has released the updates) and has m to go. * If a reading transaction reads the n updates, there is no reason for the updating transaction to cause * a conflict since they are no conflicting arrives on the part if has already completes. If the reading transactions * hits the n+1 update, it is allowed to see a different value than it already has read... * problem.. the n updates it has read, already contains the new values, so reading another new value is no problem. */ public abstract class RefReadConsistency_AbstractTest { private GammaTxnRef[] refs; private final AtomicBoolean inconsistencyDetected = new AtomicBoolean(); private int readerCount = 10; private int writerCount = 2; private int durationMs = 1 * 60 * 1000; private volatile boolean stop; protected GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stop = false; stm = (GammaStm) getGlobalStmInstance(); inconsistencyDetected.set(false); } @After public void tearDown() { System.out.println("Stm.GlobalConflictCount: " + stm.getGlobalConflictCounter().count()); for (GammaTxnRef ref : refs) { System.out.println(ref.toDebugString()); } } protected abstract TxnExecutor createReadBlock(); protected abstract TxnExecutor createWriteBlock(); public void run(int refCount) { refs = new GammaTxnRef[refCount]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnRef(stm); } ReadThread[] readerThreads = new ReadThread[readerCount]; for (int k = 0; k < readerThreads.length; k++) { readerThreads[k] = new ReadThread(k); } WriterThread[] writerThreads = new WriterThread[writerCount]; for (int k = 0; k < writerThreads.length; k++) { writerThreads[k] = new WriterThread(k); } startAll(readerThreads); startAll(writerThreads); System.out.printf("Running for %s milliseconds\n", durationMs); sleepMs(getStressTestDurationMs(durationMs)); stop = true; joinAll(readerThreads); joinAll(writerThreads); assertFalse("Inconsistency detected", inconsistencyDetected.get()); } public class WriterThread extends TestThread { public WriterThread(int id) { super("WriterThread-" + id); } @Override public void doRun() throws Exception { final String value = getName(); TxnExecutor executor = createWriteBlock(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; //String initial = refs[0].get(btx); for (int k = 0; k < refs.length; k++) { refs[k].openForWrite(btx, LOCKMODE_NONE).ref_value = value; //String s = refs[k].getAndSet(tx, value); //assertSame("failed at " + k, initial, s); } } }; int mod = 1; int k = 0; while (!stop) { executor.execute(callable); sleepRandomUs(100); k++; if (k % mod == 0) { mod = mod * 2; System.out.printf("%s is at %s\n", getName(), k); } } } } public class ReadThread extends TestThread { public ReadThread(int id) { super("ReadThread-" + id); } @Override public void doRun() throws Exception { TxnExecutor executor = createReadBlock(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; String initial = (String) refs[0].openForRead(btx, LOCKMODE_NONE).ref_value; for (int k = 1; k < refs.length; k++) { String s = (String) refs[k].openForRead(btx, LOCKMODE_NONE).ref_value; if (s != initial) { System.out.printf("Inconsistency detected at index %s!!!\n",k); inconsistencyDetected.set(true); stop = true; } } } }; int mod = 1; int k = 0; while (!stop) { executor.execute(callable); k++; if (k % mod == 0) { mod = mod * 2; System.out.printf("%s is at %s\n", getName(), k); } } } } } RefReadConsistency_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000060661174000617100503470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class RefReadConsistency_FatFixedLengthGammaTxn_StressTest extends RefReadConsistency_AbstractTest { private int refCount; private boolean poorMansReadConsistency; @Test public void poormansReadConsistency_with2Refs() { refCount = 2; poorMansReadConsistency = true; run(refCount); } @Test public void poormansReadConsistency_with4Refs() { refCount = 4; poorMansReadConsistency = true; run(refCount); } @Test public void poormansReadConsistency_with8Refs() { poorMansReadConsistency = true; refCount = 8; run(refCount); } @Test public void poormansReadConsistency_with16Refs() { poorMansReadConsistency = true; refCount = 16; run(refCount); } @Test public void poormansReadConsistency_with32Refs() { poorMansReadConsistency = true; refCount = 32; run(refCount); } @Test public void poormansReadConsistency_with64Refs() { poorMansReadConsistency = true; refCount = 64; run(refCount); } @Test public void richmansReadConsistency_with2Refs() { refCount = 2; poorMansReadConsistency = false; run(refCount); } @Test public void richmansReadConsistency_with4Refs() { refCount = 4; poorMansReadConsistency = false; run(refCount); } @Test public void richmansReadConsistency_with8Refs() { poorMansReadConsistency = false; refCount = 8; run(refCount); } @Test public void richmansReadConsistency_with16Refs() { poorMansReadConsistency = false; refCount = 16; run(refCount); } @Test public void richmansReadConsistency_with32Refs() { poorMansReadConsistency = false; refCount = 32; run(refCount); } @Test public void richmansReadConsistency_with64Refs() { poorMansReadConsistency = false; refCount = 64; run(refCount); } @Override protected TxnExecutor createReadBlock() { GammaTxnConfig config = new GammaTxnConfig(stm, refCount) .setDirtyCheckEnabled(false) .setMaximumPoorMansConflictScanLength(poorMansReadConsistency ? Integer.MAX_VALUE : 0); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor createWriteBlock() { GammaTxnConfig config = new GammaTxnConfig(stm, refCount) .setDirtyCheckEnabled(false) .setMaximumPoorMansConflictScanLength(poorMansReadConsistency ? Integer.MAX_VALUE : 0); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } RefReadConsistency_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000072701174000617100510330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class RefReadConsistency_FatVariableLengthGammaTxn_StressTest extends RefReadConsistency_AbstractTest { private int refCount; private boolean poorMansReadConsistency; @Test public void poorMansConflictScan_testWith2Refs() { refCount = 2; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith4Refs() { refCount = 4; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith8Refs() { refCount = 8; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith16Refs() { refCount = 16; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith32Refs() { refCount = 32; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith128Refs() { refCount = 128; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith512Refs() { refCount = 512; poorMansReadConsistency = true; run(refCount); } @Test public void poorMansConflictScan_testWith2048Refs() { poorMansReadConsistency = true; refCount = 2048; run(refCount); } @Test public void richMansConflictScan_testWith2Refs() { refCount = 2; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith4Refs() { refCount = 4; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith8Refs() { refCount = 8; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith16Refs() { refCount = 16; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith32Refs() { refCount = 32; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith128Refs() { refCount = 128; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith512Refs() { refCount = 512; poorMansReadConsistency = false; run(refCount); } @Test public void richMansConflictScan_testWith2048Refs() { poorMansReadConsistency = false; refCount = 2048; run(refCount); } @Override protected TxnExecutor createReadBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setMaximumPoorMansConflictScanLength(poorMansReadConsistency ? Integer.MAX_VALUE : 0); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor createWriteBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setMaximumPoorMansConflictScanLength(poorMansReadConsistency ? Integer.MAX_VALUE : 0); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } RefReadConsistency_LeanFixedLengthGammaTxn_StressTest.java000066400000000000000000000041471174000617100505120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxnFactory; /** * The refCount in some cases is set to an unrealistic high value because * normally you want to have a 10/20 refs inside max since a full conflict * scan needs to be done. But it is a nice way to check if it still is able * to deal with read consistency. */ public class RefReadConsistency_LeanFixedLengthGammaTxn_StressTest extends RefReadConsistency_AbstractTest { private int refCount; @Test public void testWith2Refs() { refCount = 2; run(refCount); } @Test public void testWith4Refs() { refCount = 4; run(refCount); } @Test public void testWith8Refs() { refCount = 8; run(refCount); } @Test public void testWith16Refs() { refCount = 16; run(refCount); } @Test public void testWith32Refs() { refCount = 32; run(refCount); } @Test public void testWith64Refs() { refCount = 64; run(refCount); } @Test public void testWith128Refs() { refCount = 128; run(refCount); } @Test public void testWith512Refs() { refCount = 512; run(refCount); } @Override protected TxnExecutor createReadBlock() { GammaTxnConfig config = new GammaTxnConfig(stm, refCount) .setMaximumPoorMansConflictScanLength(refCount) .setMaxRetries(10000); return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor createWriteBlock() { GammaTxnConfig config = new GammaTxnConfig(stm, refCount) .setMaximumPoorMansConflictScanLength(refCount) .setMaxRetries(10000); return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(config)); } } WriteConflictTest.java000066400000000000000000000073171174000617100414550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolationpackage org.multiverse.stms.gamma.integration.isolation; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class WriteConflictTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } @After public void tearDown() { clearThreadLocalTxn(); } @Test public void whenDirtyCheckAndChange_ThenWriteConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setSpeculative(false) .setDirtyCheckEnabled(true) .newTransactionFactory() .newTxn(); Tranlocal write = ref.openForWrite(tx, LOCKMODE_NONE); write.long_value++; ref.atomicIncrementAndGet(1); long version = ref.getVersion(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 1); } @Test public void whenDirtyCheckAndNoChange_ThenNoWriteConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setSpeculative(false) .setDirtyCheckEnabled(true) .newTransactionFactory() .newTxn(); ref.openForWrite(tx, LOCKMODE_NONE); ref.atomicIncrementAndGet(1); long version = ref.getVersion(); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, version, 1); } @Test public void whenNoDirtyCheckAndChange_ThenWriteConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setSpeculative(false) .setDirtyCheckEnabled(false) .newTransactionFactory() .newTxn(); Tranlocal write = ref.openForWrite(tx, LOCKMODE_NONE); write.long_value++; ref.atomicIncrementAndGet(1); long version = ref.getVersion(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 1); } @Test public void whenNoDirtyCheckAndNoChange_ThenWriteConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setSpeculative(false) .setDirtyCheckEnabled(false) .newTransactionFactory() .newTxn(); Tranlocal write = ref.openForWrite(tx, LOCKMODE_NONE); write.long_value++; ref.atomicIncrementAndGet(1); long version = ref.getVersion(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 1); } } 000077500000000000000000000000001174000617100364605ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolation/levelsIsolationLevelSerializableTest.java000066400000000000000000000072661174000617100454560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolation/levelspackage org.multiverse.stms.gamma.integration.isolation.levels; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.IsolationLevel; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.makeReadBiased; public class IsolationLevelSerializableTest { private GammaStm stm; private GammaTxnFactory transactionFactory; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); transactionFactory = stm.newTxnFactoryBuilder() .setSpeculative(false) .setIsolationLevel(IsolationLevel.Serializable) .newTransactionFactory(); } @Test public void repeatableRead_whenTracked_thenNoInconsistentRead() { final GammaTxnLong ref = new GammaTxnLong(stm); transactionFactory = stm.newTxnFactoryBuilder() .setSpeculative(false) .setReadTrackingEnabled(true) .setIsolationLevel(IsolationLevel.Serializable) .newTransactionFactory(); GammaTxn tx = transactionFactory.newTxn(); ref.get(tx); ref.atomicIncrementAndGet(1); long read2 = ref.get(tx); assertEquals(0, read2); } @Test @Ignore public void repeatableRead_whenNotTrackedAndConflictingUpdate_thenReadConflict() { final GammaTxnLong ref = makeReadBiased(new GammaTxnLong(stm)); transactionFactory = stm.newTxnFactoryBuilder() .setSpeculative(false) .setReadTrackingEnabled(false) .setBlockingAllowed(false) .setIsolationLevel(IsolationLevel.Serializable) .newTransactionFactory(); GammaTxn tx = transactionFactory.newTxn(); ref.get(tx); ref.atomicIncrementAndGet(1); try { ref.get(tx); fail(); } catch (ReadWriteConflict expected) { } } @Test public void causalConsistency_whenConflictingWrite_thenReadWriteConflict() { final GammaTxnLong ref1 = new GammaTxnLong(stm); final GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); ref1.get(tx); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref1.incrementAndGet(1); ref2.incrementAndGet(1); } }); try { ref2.get(tx); fail(); } catch (ReadWriteConflict expected) { } } @Test public void writeSkewNotPossible() { final GammaTxnLong ref1 = new GammaTxnLong(stm); final GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); ref1.get(tx); ref2.incrementAndGet(tx, 1); ref1.atomicIncrementAndGet(1); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertEquals(1, ref1.atomicGet()); assertEquals(0, ref2.atomicGet()); } } IsolationLevelSnapshotTest.java000066400000000000000000000044571174000617100446460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolation/levelspackage org.multiverse.stms.gamma.integration.isolation.levels; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.IsolationLevel; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class IsolationLevelSnapshotTest { private GammaStm stm; private GammaTxnFactory transactionFactory; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); transactionFactory = stm.newTxnFactoryBuilder() .setSpeculative(false) .setIsolationLevel(IsolationLevel.Snapshot) .newTransactionFactory(); } @Test @Ignore public void unrepeatableRead() { } @Test public void causalConsistencyViolationNotPossible() { final GammaTxnLong ref1 = new GammaTxnLong(stm); final GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); ref1.get(tx); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref1.incrementAndGet(1); ref2.incrementAndGet(1); } }); try { ref2.get(tx); fail(); } catch (ReadWriteConflict expected) { } } @Test public void writeSkewPossible() { final GammaTxnLong ref1 = new GammaTxnLong(stm); final GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); ref1.get(tx); ref2.incrementAndGet(tx, 1); ref1.atomicIncrementAndGet(1); tx.commit(); assertEquals(1, ref1.atomicGet()); assertEquals(1, ref2.atomicGet()); } } 000077500000000000000000000000001174000617100372125ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolation/writeskewWriteSkewStressTest.java000066400000000000000000000321441174000617100440510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolation/writeskewpackage org.multiverse.stms.gamma.integration.isolation.writeskew; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.TxnExecutor; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.concurrent.atomic.AtomicBoolean; import static java.lang.String.format; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * A Test that checks if the writeskew problem is happening. When * pessimisticRead/LockLevel.Read/writeskew=false is used, no writeskew is possible. Otherwise * it can happen. * * @author Peter Veentjer. */ public class WriteSkewStressTest { private volatile boolean stop; private Customer customer1; private Customer customer2; enum Mode { snapshot, pessimisticReadLevel, pessimisticWriteLevel, pessimisticReads, pessimisticWrites, serialized } private Mode mode; private TransferThread[] threads; private AtomicBoolean writeSkewEncountered = new AtomicBoolean(); private GammaStm stm; private int threadCount = 8; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); customer1 = new Customer(); customer2 = new Customer(); stop = false; writeSkewEncountered.set(false); threads = new TransferThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new TransferThread(k); } GammaTxnLong account = customer1.getRandomAccount(); GammaTxn tx = stm.newDefaultTxn(); account.openForWrite(tx, LOCKMODE_NONE).long_value = 1000; tx.commit(); } @Test public void whenPessimisticRead_thenNoWriteSkewPossible() { mode = Mode.pessimisticReads; startAll(threads); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(threads); System.out.println("User1: " + customer1); System.out.println("User2: " + customer2); assertFalse("writeskew detected", writeSkewEncountered.get()); } /** * If this test fails, the anomaly we are looking for, hasn't occurred yet. Try increasing the * running time. */ @Test public void whenPessimisticWrite_thenWriteSkewPossible() { mode = Mode.pessimisticWrites; startAll(threads); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(threads); System.out.println("User1: " + customer1); System.out.println("User2: " + customer2); assertTrue("no writeskew detected", writeSkewEncountered.get()); } @Test public void whenPessimisticWriteSanityTest() { Customer customer1 = new Customer(); Customer customer2 = new Customer(); GammaTxn tx1 = stm.newDefaultTxn(); GammaTxn tx2 = stm.newDefaultTxn(); customer1.account1.get(tx1); customer1.account2.get(tx1); customer1.account2.get(tx1); customer2.account2.get(tx1); customer1.account1.get(tx2); customer1.account2.get(tx2); customer2.account1.get(tx2); customer2.account2.get(tx2); customer1.account1.openForWrite(tx1, LOCKMODE_READ).long_value++; customer2.account1.openForWrite(tx1, LOCKMODE_READ).long_value++; customer1.account2.openForWrite(tx2, LOCKMODE_READ).long_value++; customer2.account2.openForWrite(tx2, LOCKMODE_READ).long_value++; tx1.commit(); tx2.commit(); } @Test public void whenPessimisticWriteLevel_thenWriteSkewPossible() { mode = Mode.pessimisticWriteLevel; startAll(threads); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(threads); System.out.println("User1: " + customer1); System.out.println("User2: " + customer2); assertTrue("no writeskew detected", writeSkewEncountered.get()); } @Test public void whenPessimisticWriteLevelSanityTest() { Customer customer1 = new Customer(); Customer customer2 = new Customer(); GammaTxn tx1 = stm.newTxnFactoryBuilder() .setSpeculative(false) .setWriteLockMode(LockMode.Read) .newTransactionFactory() .newTxn(); GammaTxn tx2 = stm.newTxnFactoryBuilder() .setSpeculative(false) .setWriteLockMode(LockMode.Read) .newTransactionFactory() .newTxn(); customer1.account1.get(tx1); customer1.account2.get(tx1); customer1.account2.get(tx1); customer2.account2.get(tx1); customer1.account1.get(tx2); customer1.account2.get(tx2); customer2.account1.get(tx2); customer2.account2.get(tx2); customer1.account1.openForWrite(tx1, LOCKMODE_NONE).long_value++; customer2.account1.openForWrite(tx1, LOCKMODE_NONE).long_value++; customer1.account2.openForWrite(tx2, LOCKMODE_NONE).long_value++; customer2.account2.openForWrite(tx2, LOCKMODE_NONE).long_value++; tx1.commit(); tx2.commit(); } @Test public void whenPessimisticReadLevel_thenNoWriteSkewPossible() { mode = Mode.pessimisticReadLevel; startAll(threads); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(threads); System.out.println("User1: " + customer1); System.out.println("User2: " + customer2); assertFalse("writeskew detected", writeSkewEncountered.get()); } @Test public void whenSnapshotIsolation_thenWriteSkewPossible() { mode = Mode.snapshot; startAll(threads); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(threads); System.out.println("User1: " + customer1); System.out.println("User2: " + customer2); System.out.println("User1.account1: " + customer1.account1.toDebugString()); System.out.println("User1.account2: " + customer1.account2.toDebugString()); System.out.println("User2.account1: " + customer2.account1.toDebugString()); System.out.println("User2.account2: " + customer2.account2.toDebugString()); assertTrue(writeSkewEncountered.get()); } @Test public void whenSerializedIsolationLevel_thenWriteSkewNotPossible() { mode = Mode.serialized; startAll(threads); sleepMs(getStressTestDurationMs(30 * 1000)); stop = true; joinAll(threads); System.out.println("User1: " + customer1); System.out.println("User2: " + customer2); assertFalse("writeskew detected", writeSkewEncountered.get()); } public class TransferThread extends TestThread { private final TxnExecutor snapshotBlock = stm.newTxnFactoryBuilder() .setSpeculative(false) .setMaxRetries(10000) .newTxnExecutor(); private final TxnExecutor serializedBlock = stm.newTxnFactoryBuilder() .setSpeculative(false) .setIsolationLevel(IsolationLevel.Serializable) .setMaxRetries(10000) .newTxnExecutor(); private final TxnExecutor pessimisticReadsBlock = stm.newTxnFactoryBuilder() .setSpeculative(false) .setReadLockMode(LockMode.Read) .setMaxRetries(10000) .newTxnExecutor(); private final TxnExecutor pessimisticWritesBlock = stm.newTxnFactoryBuilder() .setSpeculative(false) .setWriteLockMode(LockMode.Read) .setMaxRetries(10000) .newTxnExecutor(); public TransferThread(int id) { super("TransferThread-" + id); } @Override public void doRun() throws Exception { int k = 0; while (!stop) { if (k % 100 == 0) { System.out.printf("%s is at %s\n", getName(), k); } switch (mode) { case snapshot: runWithSnapshotIsolation(); break; case serialized: runWithSerializedIsolation(); break; case pessimisticReadLevel: runWithPessimisticReadLevel(); break; case pessimisticWriteLevel: runWithPessimisticWriteLevel(); break; case pessimisticReads: runWithPessimisticReads(); break; case pessimisticWrites: runWithPessimisticWrites(); break; default: throw new IllegalStateException(); } k++; } } private void runWithPessimisticReadLevel() { pessimisticReadsBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; run(btx, LockMode.None, LockMode.None); } }); } private void runWithPessimisticWriteLevel() { pessimisticWritesBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; run(btx, LockMode.None, LockMode.None); } }); } private void runWithSerializedIsolation() { serializedBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; run(btx, LockMode.None, LockMode.None); } }); } private void runWithSnapshotIsolation() { snapshotBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; run(btx, LockMode.None, LockMode.None); } }); } private void runWithPessimisticReads() { snapshotBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; run(btx, LockMode.Read, LockMode.None); } }); } private void runWithPessimisticWrites() { snapshotBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; run(btx, LockMode.None, LockMode.Read); } }); } public void run(GammaTxn tx, LockMode readLockMode, LockMode writeLockMode) { int amount = randomInt(100); Customer from = random(customer1, customer2); Customer to = random(customer1, customer2); long sum = from.account1.openForRead(tx, readLockMode.asInt()).long_value + from.account2.openForRead(tx, readLockMode.asInt()).long_value; if (sum < 0) { if (writeSkewEncountered.compareAndSet(false, true)) { System.out.println("writeskew detected"); } } sleepRandomMs(5); if (sum >= amount) { GammaTxnLong fromAccount = from.getRandomAccount(); fromAccount.openForWrite(tx, writeLockMode.asInt()).long_value -= amount; GammaTxnLong toAccount = to.getRandomAccount(); toAccount.openForWrite(tx, writeLockMode.asInt()).long_value += amount; } sleepRandomMs(5); } } public Customer random(Customer customer1, Customer customer2) { return randomBoolean() ? customer1 : customer2; } public class Customer { private GammaTxnLong account1 = new GammaTxnLong(stm); private GammaTxnLong account2 = new GammaTxnLong(stm); public GammaTxnLong getRandomAccount() { return randomBoolean() ? account1 : account2; } public String toString() { return format("User(account1 = %s, account2 = %s, sum=%s)", account1.atomicToString(), account2.atomicToString(), account1.atomicGet() + account2.atomicGet()); } } } WriteSkew_AbstractTest.java000066400000000000000000000133601174000617100444670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolation/writeskewpackage org.multiverse.stms.gamma.integration.isolation.writeskew; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public abstract class WriteSkew_AbstractTest { protected GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } public abstract T newTransaction(GammaTxnConfig config); @After public void tearDown() { clearThreadLocalTxn(); } @Test public void whenWriteSkewAllowed_thenNotDetected() { GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setSpeculative(false) .setIsolationLevel(IsolationLevel.Snapshot); GammaTxn tx = newTransaction(config); ref1.incrementAndGet(tx, 1); ref2.get(tx); ref2.atomicIncrementAndGet(1); tx.commit(); assertEquals(1, ref1.atomicGet()); } @Test public void whenWritesLocked_thenWriteSkewNotDetected() { whenWritesLocked_thenWriteSkewNotDetected(LockMode.None); whenWritesLocked_thenWriteSkewNotDetected(LockMode.Read); whenWritesLocked_thenWriteSkewNotDetected(LockMode.Write); whenWritesLocked_thenWriteSkewNotDetected(LockMode.Exclusive); } public void whenWritesLocked_thenWriteSkewNotDetected(LockMode writeLockMode) { GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setSpeculative(false) .setIsolationLevel(IsolationLevel.Snapshot) .setWriteLockMode(writeLockMode); GammaTxn tx = newTransaction(config); ref1.incrementAndGet(tx, 1); ref2.get(tx); ref2.atomicIncrementAndGet(1); tx.commit(); assertEquals(1, ref1.atomicGet()); } @Test public void whenReadsLocked_thenWriteSkewNotPossible() { whenReadsLocked_thenWriteSkewNotPossible(LockMode.Read); whenReadsLocked_thenWriteSkewNotPossible(LockMode.Write); whenReadsLocked_thenWriteSkewNotPossible(LockMode.Exclusive); } public void whenReadsLocked_thenWriteSkewNotPossible(LockMode readLockMode) { GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setSpeculative(false) .setIsolationLevel(IsolationLevel.Snapshot) .setControlFlowErrorsReused(false); GammaTxn tx = newTransaction(config); ref1.incrementAndGet(tx, 1); ref2.get(tx); GammaTxn otherTx = stm.newDefaultTxn(); ref2.incrementAndGet(otherTx, 1); ref2.getLock().acquire(tx, readLockMode); try { otherTx.commit(); fail(); } catch (ReadWriteConflict ignored) { } tx.commit(); } @Test public void whenLocked_thenWriteSkewNotPossible() { whenLocked_thenWriteSkewNotPossible(LockMode.Read); whenLocked_thenWriteSkewNotPossible(LockMode.Write); whenLocked_thenWriteSkewNotPossible(LockMode.Exclusive); } public void whenLocked_thenWriteSkewNotPossible(LockMode lockMode) { GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setSpeculative(false) .setIsolationLevel(IsolationLevel.Snapshot); GammaTxn tx = newTransaction(config); ref1.incrementAndGet(tx, 1); GammaTxn otherTx = stm.newDefaultTxn(); ref2.incrementAndGet(otherTx, 1); ref2.getLock().acquire(tx, lockMode); ref2.get(tx); try { otherTx.commit(); fail(); } catch (ReadWriteConflict expected) { } tx.commit(); } @Test public void whenEnsured_thenWriteSkewNotPossible() { GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setSpeculative(false) .setIsolationLevel(IsolationLevel.Snapshot); GammaTxn tx = newTransaction(config); ref1.incrementAndGet(tx, 1); ref2.ensure(tx); ref2.atomicIncrementAndGet(1); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } } @Test public void whenSerializedIsolationLevel_thenWriteSkewNotPossible() { GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setSpeculative(false) .setIsolationLevel(IsolationLevel.Serializable); GammaTxn tx = newTransaction(config); ref1.incrementAndGet(tx, 1); ref2.get(tx); ref2.atomicIncrementAndGet(1); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } } } WriteSkew_FatFixedLengthGammaTxn_Test.java000066400000000000000000000007151174000617100473540ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolation/writeskewpackage org.multiverse.stms.gamma.integration.isolation.writeskew; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; public class WriteSkew_FatFixedLengthGammaTxn_Test extends WriteSkew_AbstractTest { @Override public FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } } WriteSkew_FatVariableLengthGammaTxn_Test.java000066400000000000000000000007341174000617100500430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/isolation/writeskewpackage org.multiverse.stms.gamma.integration.isolation.writeskew; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; public class WriteSkew_FatVariableLengthGammaTxn_Test extends WriteSkew_AbstractTest { @Override public FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } } 000077500000000000000000000000001174000617100351245ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lifecycleLifecycleTest.java000066400000000000000000000066231174000617100405350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lifecyclepackage org.multiverse.stms.gamma.integration.lifecycle; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.stms.gamma.GammaStm; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class LifecycleTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenTransactionCommit_thenCompensatingOrDeferredTaskExecuted() { final Runnable task = mock(Runnable.class); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleCompensatingOrDeferredTask(task); tx.commit(); } }); verify(task).run(); } @Test public void whenTransactionAborts_thenCompensatingOrDeferredTaskExecuted() { final Runnable task = mock(Runnable.class); try { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleCompensatingOrDeferredTask(task); tx.abort(); } }); fail(); } catch (DeadTxnException expected) { } verify(task).run(); } @Test public void whenTransactionCommit_thenDeferredOperationCalled() { final Runnable task = mock(Runnable.class); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleDeferredTask(task); tx.commit(); } }); verify(task).run(); } @Test public void whenTransactionCommit_thenCompensatingOperationNotCalled() { final Runnable task = mock(Runnable.class); atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleCompensatingTask(task); tx.commit(); } }); verifyZeroInteractions(task); } @Test public void whenTransactionAborts_thenDeferredOperationNotCalled() { final Runnable task = mock(Runnable.class); try { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleDeferredTask(task); tx.abort(); } }); fail(); } catch (DeadTxnException e) { } verifyZeroInteractions(task); } @Test public void whenTransactionAborts_thenCompensatingOperationCalled() { final Runnable task = mock(Runnable.class); try { atomic(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { scheduleCompensatingTask(task); tx.abort(); } }); fail(); } catch (DeadTxnException e) { } verify(task).run(); } } 000077500000000000000000000000001174000617100350155ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/livenessDeadLockStressTest.java000066400000000000000000000121141174000617100413710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/livenesspackage org.multiverse.stms.gamma.integration.liveness; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class DeadLockStressTest { enum Mode { Normal, Mix, PrivatizeReadLevelMode, PrivatizeWriteLevelMode } private volatile boolean stop; private int refCount = 100; private int threadCount = 10; private GammaTxnLong[] refs; private ChangeThread[] threads; private GammaStm stm; private Mode mode; @Before public void setUp() { clearThreadLocalTxn(); stop = false; stm = (GammaStm) getGlobalStmInstance(); } @Test public void whenNormal() { test(Mode.Normal); } @Test public void whenMix() { test(Mode.Mix); } @Test public void whenPessimisticReadLevel() { test(Mode.PrivatizeReadLevelMode); } @Test public void whenPessimisticWriteLevel() { test(Mode.PrivatizeWriteLevelMode); } public void test(Mode mode) { this.mode = mode; refs = new GammaTxnLong[refCount]; for (int k = 0; k < refCount; k++) { refs[k] = new GammaTxnLong(stm); } threads = new ChangeThread[threadCount]; for (int k = 0; k < threadCount; k++) { threads[k] = new ChangeThread(k); } startAll(threads); sleepMs(getStressTestDurationMs(60 * 1000)); stop = true; joinAll(threads); } public class ChangeThread extends TestThread { private final TxnExecutor normalBlock = stm.newTxnFactoryBuilder() .newTxnExecutor(); private final TxnExecutor pessimisticReadLevelBlock = stm.newTxnFactoryBuilder() .setReadLockMode(LockMode.Exclusive) .newTxnExecutor(); private final TxnExecutor pessimisticWriteLevelBlock = stm.newTxnFactoryBuilder() .setWriteLockMode(LockMode.Exclusive) .newTxnExecutor(); public ChangeThread(int id) { super("ChangeThread-" + id); } @Override public void doRun() throws Exception { int k = 0; while (!stop) { if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } switch (mode) { case PrivatizeReadLevelMode: privatizeReadLevel(); break; case PrivatizeWriteLevelMode: privatizeWriteLevel(); break; case Normal: normal(); break; case Mix: switch (randomInt(3)) { case 0: privatizeReadLevel(); break; case 1: privatizeWriteLevel(); break; case 2: normal(); break; default: throw new IllegalStateException(); } break; default: throw new IllegalStateException(); } k++; } } public void normal() { normalBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { doIt((GammaTxn) tx); } }); } public void privatizeReadLevel() { pessimisticReadLevelBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { doIt((GammaTxn) tx); } }); } public void privatizeWriteLevel() { pessimisticWriteLevelBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { doIt((GammaTxn) tx); } }); } public void doIt(GammaTxn tx) { for (int k = 0; k < refs.length; k++) { if (!randomOneOf(10)) { continue; } int index = randomInt(refs.length); GammaTxnLong ref = refs[index]; ref.getAndSet(tx, ref.get(tx) + 1); } } } } DeadLockTest.java000066400000000000000000000030601174000617100401650ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/livenesspackage org.multiverse.stms.gamma.integration.liveness; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class DeadLockTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } @Test public void test() { GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxn tx1 = stm.newDefaultTxn(); GammaTxn tx2 = stm.newDefaultTxn(); ref1.openForWrite(tx1, LOCKMODE_EXCLUSIVE).long_value++; ref2.openForWrite(tx2, LOCKMODE_EXCLUSIVE).long_value++; try { ref2.openForWrite(tx1, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx1); ref1.openForWrite(tx2, LOCKMODE_EXCLUSIVE).long_value++; tx2.commit(); assertEquals(1, ref1.atomicGet()); assertEquals(1, ref2.atomicGet()); } } EnsureDeadLockStressTest.java000066400000000000000000000054721174000617100425640ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/livenesspackage org.multiverse.stms.gamma.integration.liveness; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class EnsureDeadLockStressTest { private int threadCount = 4; private int refCount = 5; private volatile boolean stop; private GammaStm stm; private GammaTxnLong[] refs; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; refs = new GammaTxnLong[refCount]; for (int k = 0; k < refCount; k++) { refs[k] = new GammaTxnLong(stm); } } @Test public void test() { StressThread[] threads = new StressThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new StressThread(k); } startAll(threads); sleepMs(getStressTestDurationMs(60 * 1000)); stop = true; joinAll(threads); } class StressThread extends TestThread { private boolean leftToRight; public StressThread(int id) { super("StressThread-" + id); this.leftToRight = id % 2 == 0; } @Override public void doRun() throws Exception { TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpinCount(1000) .setMaxRetries(10000) .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (leftToRight) { for (int k = 0; k < refCount; k++) { refs[k].getLock().acquire(tx, LockMode.Write); sleepMs(5); } } else { for (int k = refCount - 1; k >= 0; k--) { refs[k].getLock().acquire(tx, LockMode.Write); sleepMs(5); } } } }; int k = 0; while (!stop) { executor.execute(callable); sleepMs(10); k++; if (k % 10 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } } PrivatizationDeadLockStressTest.java000066400000000000000000000055111174000617100441600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/livenesspackage org.multiverse.stms.gamma.integration.liveness; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class PrivatizationDeadLockStressTest { private int threadCount = 4; private int refCount = 5; private volatile boolean stop; private GammaStm stm; private GammaTxnLong[] refs; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; refs = new GammaTxnLong[refCount]; for (int k = 0; k < refCount; k++) { refs[k] = new GammaTxnLong(stm); } } @Test public void test() { StressThread[] threads = new StressThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new StressThread(k); } startAll(threads); sleepMs(getStressTestDurationMs(60 * 1000)); stop = true; joinAll(threads); } class StressThread extends TestThread { private boolean leftToRight; public StressThread(int id) { super("StressThread-" + id); this.leftToRight = id % 2 == 0; } @Override public void doRun() throws Exception { TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpinCount(1000) .setMaxRetries(10000) .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (leftToRight) { for (int k = 0; k < refCount; k++) { refs[k].getLock().acquire(tx, LockMode.Exclusive); sleepMs(5); } } else { for (int k = refCount - 1; k >= 0; k--) { refs[k].getLock().acquire(tx, LockMode.Exclusive); sleepMs(5); } } } }; int k = 0; while (!stop) { executor.execute(callable); sleepMs(10); k++; if (k % 10 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } } 000077500000000000000000000000001174000617100346135ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lockingEnsureTest.java000066400000000000000000000046421174000617100375650ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lockingpackage org.multiverse.stms.gamma.integration.locking; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; public class EnsureTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenOnlyReadsThenIgnored() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); ref.ensure(tx); ref.atomicIncrementAndGet(1); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); } @Test public void whenUpdateTransactionButNoConflictOnRead_thenSuccess() { long initialValue = 10; GammaTxnLong ref1 = new GammaTxnLong(stm, initialValue); GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue); GammaTxn tx = stm.newDefaultTxn(); ref1.get(tx); ref1.ensure(tx); ref2.increment(tx); tx.commit(); assertIsCommitted(tx); assertEquals(initialValue, ref1.atomicGet()); assertEquals(initialValue + 1, ref2.atomicGet()); } @Test public void whenUpdateTransactionAndConflictOnRead_thenReadWriteConflict() { long initialValue = 10; GammaTxnLong ref1 = new GammaTxnLong(stm, initialValue); GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue); GammaTxn tx = stm.newDefaultTxn(); ref1.get(tx); ref1.ensure(tx); ref2.increment(tx); ref1.atomicIncrementAndGet(1); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertEquals(initialValue + 1, ref1.atomicGet()); assertEquals(initialValue, ref2.atomicGet()); } } LockLevelTest.java000066400000000000000000000001271174000617100401760ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lockingpackage org.multiverse.stms.gamma.integration.locking; public class LockLevelTest { } PessimisticTest.java000066400000000000000000000016431174000617100406160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lockingpackage org.multiverse.stms.gamma.integration.locking; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasExclusiveLock; public class PessimisticTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void constructedObjectAutomaticallyIsLocked() { GammaTxn tx = stm.newDefaultTxn(); GammaTxnLong ref = new GammaTxnLong(tx); ref.openForConstruction(tx); assertRefHasExclusiveLock(ref, tx); } } 000077500000000000000000000000001174000617100343005ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/locksExclusiveLockTest.java000066400000000000000000000170721174000617100405720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lockspackage org.multiverse.stms.gamma.integration.locks; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class ExclusiveLockTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenUnlocked() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); } @Test public void whenReadLockAlreadyAcquiredByOther_thenExclusiveLockNotPossible() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasReadLock(ref, otherTx); } @Test public void whenExclusiveLockAlreadyAcquiredByOther_thenExclusiveLockNotPossible() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenWriteLockAlreadyAcquiredByOther_thenExclusiveLockNotPossible() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasWriteLock(ref, otherTx); } @Test public void whenExclusiveLockAcquiredByOther_thenReadNotPossible() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); GammaTxn otherTx = stm.newDefaultTxn(); try { ref.get(otherTx); fail(); } catch (ReadWriteConflict expected) { } } @Test public void whenPreviouslyReadByOtherThread_thenNoProblems() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn otherTx = stm.newDefaultTxn(); ref.get(otherTx); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); long result = ref.get(otherTx); assertEquals(10, result); } @Test public void whenPreviouslyReadByOtherThread_thenWriteSuccessButExclusiveFails() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); ref.set(tx, 100); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenExclusiveLockAcquiredByOther_thenWriteNotAllowed() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.set(tx, 100); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); } @Test public void writeLockIsUpgradableToExclusiveLock() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); ref.getLock().acquire(tx, LockMode.Exclusive); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); } @Test public void whenReadLockAcquired_thenUpgradableToExclusiveLock() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); ref.getLock().acquire(tx, LockMode.Exclusive); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); } @Test public void whenReadLockAlsoAcquiredByOther_thenNotUpgradableToExclusiveLock() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenTransactionCommits_thenExclusiveLockReleased() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); } @Test public void whenTransactionIsPrepared_thenExclusiveLockRemains() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); tx.prepare(); assertIsPrepared(tx); assertRefHasExclusiveLock(ref, tx); } @Test public void whenTransactionAborts_thenExclusiveLockIsReleased() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); tx.abort(); assertIsAborted(tx); assertRefHasNoLocks(ref); } @Test public void whenExclusiveLockAlreadyIsAcquired_thenReentrantExclusiveLockIsSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); ref.getLock().acquire(tx, LockMode.Exclusive); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); } @Test public void whenReadConflict_thenExclusiveLockFails() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); ref.atomicIncrementAndGet(1); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); } } ReadLockTest.java000066400000000000000000000173261174000617100375000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lockspackage org.multiverse.stms.gamma.integration.locks; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class ReadLockTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenUnlocked() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); assertIsActive(tx); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); } @Test public void whenReadLockAlreadyAcquiredByOther_thenReadLockSuccess() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); assertIsActive(tx); assertRefHasReadLock(ref, otherTx); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 2); } @Test public void whenWriteLockAlreadyAcquiredByOther_thenReadLockNotPossible() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasWriteLock(ref, otherTx); } @Test public void whenExclusiveLockAlreadyAcquiredByOther_thenReadLockNotPossible() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenReadLockAcquiredByOther_thenReadPossible() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); long result = ref.get(tx); assertIsActive(tx); assertEquals(initialValue, result); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenReadLockAcquiredByOther_thenWritePossible() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); ref.set(tx, initialValue + 1); assertEquals(initialValue + 1, ref.get(tx)); assertIsActive(tx); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenReadLockAcquiredByOtherAndDirtyTransaction_thenReadFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); ref.set(tx, initialValue + 1); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenReadLockAcquiredByOtherAndDirtyTransaction_thenPrepareFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); ref.set(tx, initialValue + 1); try { tx.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenPreviouslyReadByOtherThread_thenNoProblems() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn otherTx = stm.newDefaultTxn(); ref.get(otherTx); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); long result = ref.get(otherTx); assertEquals(10, result); } @Test public void whenReadLockAcquiredAcquired_thenAcquireReadLockSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); ref.getLock().acquire(tx, LockMode.Read); assertIsActive(tx); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); } @Test public void whenWriteLockAcquired_thenUpgradableToReadLockIgnored() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); ref.getLock().acquire(tx, LockMode.Read); assertIsActive(tx); assertRefHasWriteLock(ref, tx); } @Test public void whenExclusiveLockAcquired_thenUpgradableToReadLockIgnored() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); ref.getLock().acquire(tx, LockMode.Read); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); } @Test public void whenTransactionCommits_thenReadLockReleased() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); } @Test public void whenTransactionIsPrepared_thenReadLockRemains() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); tx.prepare(); assertIsPrepared(tx); assertRefHasReadLock(ref, tx); } @Test public void whenTransactionAborts_thenReadLockIsReleased() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); tx.abort(); assertIsAborted(tx); assertRefHasNoLocks(ref); } @Test public void whenReadWriteConflictAfterInitialRead_thenReadWriteLockFails() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); ref.atomicIncrementAndGet(1); try { ref.getLock().acquire(tx, LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); } } WriteLockStressTest.java000066400000000000000000000010071174000617100411100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lockspackage org.multiverse.stms.gamma.integration.locks; import org.junit.Ignore; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class WriteLockStressTest { private GammaStm stm; public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } @Test @Ignore public void test() { } } WriteLockTest.java000066400000000000000000000171201174000617100377070ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/lockspackage org.multiverse.stms.gamma.integration.locks; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class WriteLockTest { private GammaStm stm; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } @Test public void whenUnlocked() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); assertIsActive(tx); assertRefHasWriteLock(ref, tx); } @Test public void whenReadLockAlreadyAcquiredByOther_thenWriteLockFails() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenWriteLockAlreadyAcquiredOther_thenWriteLockFails() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasWriteLock(ref, otherTx); } @Test public void whenExclusiveLockAlreadyAcquiredByOther_thenWriteLockFails() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenWriteLockAcquiredByOther_thenReadStillAllowed() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); long result = ref.get(tx); assertEquals(5, result); assertIsActive(tx); assertRefHasWriteLock(ref, otherTx); } @Test public void whenPreviouslyReadByOtherThread_thenNoProblems() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); long result = ref.get(tx); assertEquals(10, result); assertIsActive(tx); assertRefHasWriteLock(ref, otherTx); } @Test public void whenPreviouslyReadByOtherTransaction_thenWriteSuccessButCommitFails() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); ref.set(tx, 100); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasWriteLock(ref, otherTx); } @Test public void whenWriteLockAcquired_thenWriteAllowedButCommitFails() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); ref.set(tx, 100); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasWriteLock(ref, otherTx); } @Test public void whenReadLockAlreadyAcquiredBySelf_thenWriteLockAcquired() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); ref.getLock().acquire(tx, LockMode.Write); assertIsActive(tx); assertRefHasWriteLock(ref, tx); } @Test public void whenReadLockAlsoAcquiredByOther_thenWriteLockFails() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); try { ref.getLock().acquire(tx, LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenWriteLockAlreadyAcquiredBySelf_thenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); ref.getLock().acquire(tx, LockMode.Write); assertIsActive(tx); assertRefHasWriteLock(ref, tx); } @Test public void whenExclusiveLockAlreadyAcquiredBySelf_thenExclusiveLockRemains() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); ref.getLock().acquire(tx, LockMode.Write); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); } @Test public void whenTransactionCommits_thenWriteLockIsReleased() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); } @Test public void whenTransactionIsPrepared_thenWriteLockRemains() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); tx.prepare(); assertIsPrepared(tx); assertRefHasWriteLock(ref, tx); } @Test public void whenTransactionAborts_thenWriteLockReleased() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); tx.abort(); assertIsAborted(tx); assertRefHasNoLocks(ref); } @Test public void whenReadConflict_thenAcquireWriteLockFails() { GammaTxnLong ref = new GammaTxnLong(stm, 5); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); ref.atomicIncrementAndGet(1); try { ref.getLock().acquire(tx, LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); } } 000077500000000000000000000000001174000617100350025ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/readonlyReadonlyTest.java000066400000000000000000000160511174000617100402650ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/readonlypackage org.multiverse.stms.gamma.integration.readonly; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnLongCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.ReadonlyException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class ReadonlyTest { private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); } @Test public void whenReadonly_thenUpdateFails() { GammaTxnLong ref = new GammaTxnLong(stm); try { updateInReadonlyMethod(ref, 10); fail(); } catch (ReadonlyException expected) { } assertEquals(0, ref.atomicGet()); } public void updateInReadonlyMethod(final GammaTxnLong ref, final int newValue) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadonly(true) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.getAndSet(btx, newValue); } }); } @Test public void whenReadonly_thenCreationOfNewTxnObjectNotFails() { try { readonly_createNewTransactionObject(10); fail(); } catch (ReadonlyException expected) { } } public void readonly_createNewTransactionObject(final long value) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadonly(true) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; GammaTxnLong ref = new GammaTxnLong(btx); ref.openForConstruction(btx).long_value = value; } }); } @Test public void whenReadonly_thenCreationOfNonTxnObjectSucceeds() { Integer ref = readonly_createNormalObject(100); assertNotNull(ref); assertEquals(100, ref.intValue()); } public Integer readonly_createNormalObject(final int value) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadonly(true) .newTxnExecutor(); return executor.execute(new TxnCallable() { @Override public Integer call(Txn tx) throws Exception { return new Integer(value); } }); } @Test public void whenReadonly_thenReadAllowed() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long result = readInReadonlyMethod(ref); assertEquals(10, result); assertEquals(10, ref.atomicGet()); } public long readInReadonlyMethod(final GammaTxnLong ref) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadonly(true) .newTxnExecutor(); return executor.execute(new TxnLongCallable() { @Override public long call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; return ref.get(btx); } }); } @Test public void whenUpdate_thenCreationOfNewTxnObjectsSucceeds() { GammaTxnLong ref = update_createNewTransactionObject(100); assertNotNull(ref); assertEquals(100, ref.atomicGet()); } public GammaTxnLong update_createNewTransactionObject(final int value) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadonly(false) .newTxnExecutor(); return executor.execute(new TxnCallable() { @Override public GammaTxnLong call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; GammaTxnLong ref = new GammaTxnLong(btx); ref.openForConstruction(btx).long_value = value; return ref; } }); } @Test public void whenUpdate_thenCreationOfNonTxnObjectSucceeds() { Integer ref = update_createNormalObject(100); assertNotNull(ref); assertEquals(100, ref.intValue()); } public Integer update_createNormalObject(final int value) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadonly(false) .newTxnExecutor(); return executor.execute(new TxnCallable() { @Override public Integer call(Txn tx) throws Exception { return new Integer(value); } }); } @Test public void whenUpdate_thenReadSucceeds() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long result = readInUpdateMethod(ref); assertEquals(10, result); assertEquals(10, ref.atomicGet()); } public long readInUpdateMethod(final GammaTxnLong ref) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadonly(false) .newTxnExecutor(); return executor.execute(new TxnLongCallable() { @Override public long call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; return ref.get(btx); } }); } @Test public void whenUpdate_thenUpdateSucceeds() { GammaTxnLong ref = new GammaTxnLong(stm); updateInUpdateMethod(ref, 10); assertEquals(10, ref.atomicGet()); } public void updateInUpdateMethod(final GammaTxnLong ref, final int newValue) { TxnExecutor executor = stm.newTxnFactoryBuilder() .setReadonly(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertFalse(tx.getConfig().isReadonly()); GammaTxn btx = (GammaTxn) tx; ref.getAndSet(btx, newValue); } }); } @Test public void whenDefault_thenUpdateSuccess() { GammaTxnLong ref = new GammaTxnLong(stm); defaultTransactionalMethod(ref); assertEquals(1, ref.atomicGet()); } public void defaultTransactionalMethod(final GammaTxnLong ref) { stm.newTxnFactoryBuilder().newTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertFalse(tx.getConfig().isReadonly()); GammaTxn btx = (GammaTxn) tx; ref.getAndSet(btx, ref.get(btx) + 1); } }); } } 000077500000000000000000000000001174000617100406615ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationConditionVariable_AbstractTest.java000066400000000000000000000103261174000617100476050ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnBoolean; import org.multiverse.api.references.TxnInteger; import org.multiverse.api.references.TxnRef; import org.multiverse.stms.gamma.GammaStm; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.startAll; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public abstract class ConditionVariable_AbstractTest { protected GammaStm stm; private Stack stack; private int itemCount = 10000000; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); } protected abstract TxnExecutor newPopBlock(); protected abstract TxnExecutor newPushBlock(); public void run() { stack = new Stack(100); PushThread pushThread = new PushThread(); PopThread popThread = new PopThread(); startAll(pushThread, popThread); joinAll(pushThread, popThread); } public class PushThread extends TestThread { public PushThread() { super("PushThread"); } @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { stack.push("foo"); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } public class PopThread extends TestThread { @Override public void doRun() throws Exception { for (int k = 0; k < itemCount; k++) { stack.pop(); if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class Stack { ConditionVariable isNotFull = new ConditionVariable(true); ConditionVariable isNotEmpty = new ConditionVariable(false); TxnRef head = newTxnRef(); TxnInteger size = newTxnInteger(); final int capacity; final TxnExecutor pushBlock = newPushBlock(); final TxnExecutor popBlock = newPopBlock(); Stack(int capacity) { this.capacity = capacity; } void push(final String item) { pushBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { isNotFull.awaitTrue(); head.set(new Node(item, head.get())); size.increment(); if (size.get() == capacity) { isNotFull.set(false); } isNotEmpty.set(true); } }); } String pop() { return popBlock.execute(new TxnCallable() { @Override public String call(Txn tx) throws Exception { isNotEmpty.awaitTrue(); Node node = head.get(); head.set(node.next); size.decrement(); if (size.get() == 0) { isNotEmpty.set(false); } isNotFull.set(true); return node.value; } }); } } class Node { final String value; final Node next; Node(String value, Node next) { this.value = value; this.next = next; } } class ConditionVariable { final TxnBoolean ref; ConditionVariable(boolean value) { this.ref = newTxnBoolean(value); } void awaitTrue() { ref.await(true); } void awaitFalse() { ref.await(false); } void set(boolean value) { ref.set(value); } } } ConditionVariable_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000026461174000617100537040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; /** * @author Peter Veentjer */ public class ConditionVariable_FatFixedLengthGammaTxn_StressTest extends ConditionVariable_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPushBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPopBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } ConditionVariable_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000026621174000617100543700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; /** * @author Peter Veentjer */ public class ConditionVariable_FatVariableLengthGammaTxn_StressTest extends ConditionVariable_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newPushBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newPopBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } NonReentrantMutex_AbstractTest.java000066400000000000000000000101001174000617100476370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.TestUtils; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * A stresstest that checks if the NonReentrantMutex; a traditional synchronization structure, can be build * using stm. It isn't meant as a replacement for Mutex, but just to see if the system behaves like it should. * * @author Peter Veentjer. */ public abstract class NonReentrantMutex_AbstractTest { private volatile boolean stop; private int accountCount = 50; private int threadCount = processorCount() * 4; private ProtectedIntValue[] intValues; protected GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; } protected abstract TxnExecutor newUnlockBlock(); protected abstract TxnExecutor newLockBlock(); public void run() { intValues = new ProtectedIntValue[accountCount]; for (int k = 0; k < accountCount; k++) { intValues[k] = new ProtectedIntValue(); } IncThread[] threads = new IncThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new IncThread(k); } startAll(threads); sleepMs(TestUtils.getStressTestDurationMs(60 * 1000)); stop = true; joinAll(threads); assertEquals(sum(threads), sum(intValues)); System.out.println("total increments: " + sum(threads)); } int sum(IncThread[] threads) { int result = 0; for (IncThread thread : threads) { result += thread.count; } return result; } int sum(ProtectedIntValue[] intValues) { int result = 0; for (ProtectedIntValue intValue : intValues) { result += intValue.balance; } return result; } class IncThread extends TestThread { private int count; public IncThread(int id) { super("IncThread-" + id); } @Override public void doRun() throws Exception { while (!stop) { ProtectedIntValue intValue = intValues[TestUtils.randomInt(accountCount)]; intValue.inc(); if (count % 500000 == 0) { System.out.printf("%s is at %s\n", getName(), count); } count++; } } } class ProtectedIntValue { final NonReentrantMutex mutex = new NonReentrantMutex(); int balance; public void inc() { mutex.lock(); balance++; mutex.unlock(); } } class NonReentrantMutex { final GammaTxnRef locked = new GammaTxnRef(stm, null); final TxnExecutor lockBlock = newLockBlock(); final TxnExecutor unlockBlock = newUnlockBlock(); final TxnVoidCallable lockCallable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { locked.awaitNull(tx); locked.set(tx, this); } }; final TxnVoidCallable unlockCallable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (locked.isNull(tx)) { throw new IllegalStateException(); } locked.set(tx, null); } }; public void lock() { lockBlock.execute(lockCallable); } public void unlock() { unlockBlock.execute(unlockCallable); } } } NonReentrantMutex_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000027241174000617100537450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class NonReentrantMutex_FatFixedLengthGammaTxn_StressTest extends NonReentrantMutex_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newUnlockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } NonReentrantMutex_FatMonoGammaTxn_StressTest.java000066400000000000000000000027221174000617100524520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxnFactory; public class NonReentrantMutex_FatMonoGammaTxn_StressTest extends NonReentrantMutex_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newUnlockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(config)); } } NonReentrantMutex_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000027401174000617100544310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class NonReentrantMutex_FatVariableLengthGammaTxn_StressTest extends NonReentrantMutex_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newUnlockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } NonReentrantMutex_LeanFixedLengthGammaTxn_StressTest.java000066400000000000000000000017421174000617100541110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxnFactory; public class NonReentrantMutex_LeanFixedLengthGammaTxn_StressTest extends NonReentrantMutex_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000); return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newUnlockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000); return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(config)); } } NonReentrantMutex_LeanMonoGammaTxn_StressTest.java000066400000000000000000000017061174000617100526200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxnFactory; public class NonReentrantMutex_LeanMonoGammaTxn_StressTest extends NonReentrantMutex_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000); return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(config)); } @Override protected TxnExecutor newUnlockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000); return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(config)); } } NonReentrantReadWriteLock_AbstractTest.java000066400000000000000000000116251174000617100512510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import java.util.concurrent.atomic.AtomicLong; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * A Stresstest that sees if the stm can be used to create a readwritelock that is not reentrant. * * @author Peter Veentjer. */ public abstract class NonReentrantReadWriteLock_AbstractTest { protected GammaStm stm; private int threadCount = 10; private ReadWriteLock readWriteLock; private volatile boolean stop; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); stop = false; } protected abstract TxnExecutor newReleaseWriteLockBlock(); protected abstract TxnExecutor newAcquireWriteLockBlock(); protected abstract TxnExecutor newReleaseReadLockBlock(); protected abstract TxnExecutor newAcquireReadLockBlock(); public void run() { readWriteLock = new ReadWriteLock(); StressThread[] threads = new StressThread[threadCount]; for (int k = 0; k < threadCount; k++) { threads[k] = new StressThread(k); } startAll(threads); sleepMs(30000); stop = true; joinAll(threads); } class StressThread extends TestThread { public StressThread(int id) { super("StressThread-" + id); } @Override public void doRun() throws Exception { long count = 0; while (!stop) { if (randomOneOf(5)) { readWriteLock.acquireWriteLock(); sleepMs(100); readWriteLock.releaseWriteLock(); } else { readWriteLock.acquireReadLock(); sleepMs(100); readWriteLock.releaseReadLock(); } count++; if (count % 10 == 0) { System.out.printf("%s is at %s\n", getName(), count); } } } } class ReadWriteLock { final GammaTxnRef lock = new GammaTxnRef(stm, 0L); final AtomicLong readers = new AtomicLong(); final AtomicLong writers = new AtomicLong(); final TxnExecutor acquireReadLockBlock = newAcquireReadLockBlock(); final TxnExecutor releaseReadLockBlock = newReleaseReadLockBlock(); final TxnExecutor acquireWriteLockBlock = newAcquireWriteLockBlock(); final TxnExecutor releaseWriteLockBlock = newReleaseWriteLockBlock(); public void acquireReadLock() { acquireReadLockBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (lock.get() < 0) { retry(); } lock.set(lock.get() + 1); } }); readers.incrementAndGet(); assertEquals(0, writers.get()); } public void releaseReadLock() { readers.decrementAndGet(); assertEquals(0, writers.get()); releaseReadLockBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (lock.get() <= 0) { throw new IllegalMonitorStateException(); } lock.set(lock.get() - 1); } }); } public void acquireWriteLock() { acquireWriteLockBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (lock.get() != 0) { retry(); } lock.set(-1L); } }); writers.incrementAndGet(); assertEquals(0, readers.get()); } public void releaseWriteLock() { writers.decrementAndGet(); assertEquals(0, readers.get()); releaseWriteLockBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (lock.get() != -1) { throw new IllegalMonitorStateException(); } lock.set(0L); } }); } } } NonReentrantReadWriteLock_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000040301174000617100553320ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; public class NonReentrantReadWriteLock_FatFixedLengthGammaTxn_StressTest extends NonReentrantReadWriteLock_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } protected TxnExecutor newReleaseWriteLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } protected TxnExecutor newAcquireWriteLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } protected TxnExecutor newReleaseReadLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } protected TxnExecutor newAcquireReadLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } NonReentrantReadWriteLock_FatMonoGammaTxn_StressTest.java000066400000000000000000000037561174000617100540570ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; public class NonReentrantReadWriteLock_FatMonoGammaTxn_StressTest extends NonReentrantReadWriteLock_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } protected TxnExecutor newReleaseWriteLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } protected TxnExecutor newAcquireWriteLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } protected TxnExecutor newReleaseReadLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } protected TxnExecutor newAcquireReadLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } } NonReentrantReadWriteLock_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000040521174000617100560240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; public class NonReentrantReadWriteLock_FatVariableLengthGammaTxn_StressTest extends NonReentrantReadWriteLock_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } protected TxnExecutor newReleaseWriteLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } protected TxnExecutor newAcquireWriteLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } protected TxnExecutor newReleaseReadLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } protected TxnExecutor newAcquireReadLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } NonReentrantReadWriteLock_LeanFixedLengthGammaTxn_StressTest.java000066400000000000000000000021001174000617100554730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxnFactory; public class NonReentrantReadWriteLock_LeanFixedLengthGammaTxn_StressTest extends NonReentrantReadWriteLock_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newReleaseWriteLockBlock() { return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(stm)); } @Override protected TxnExecutor newAcquireWriteLockBlock() { return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(stm)); } @Override protected TxnExecutor newReleaseReadLockBlock() { return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(stm)); } @Override protected TxnExecutor newAcquireReadLockBlock() { return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(stm)); } } NonReentrantReadWriteLock_LeanMonoGammaTxn_StressTest.java000066400000000000000000000020261174000617100542110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxnFactory; public class NonReentrantReadWriteLock_LeanMonoGammaTxn_StressTest extends NonReentrantReadWriteLock_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newReleaseWriteLockBlock() { return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(stm)); } @Override protected TxnExecutor newAcquireWriteLockBlock() { return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(stm)); } @Override protected TxnExecutor newReleaseReadLockBlock() { return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(stm)); } @Override protected TxnExecutor newAcquireReadLockBlock() { return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(stm)); } } ReentrantMutex_AbstractTest.java000066400000000000000000000070271174000617100472020ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnInteger; import org.multiverse.api.references.TxnRef; import org.multiverse.stms.gamma.GammaTxnExecutor; import org.multiverse.stms.gamma.GammaStm; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public abstract class ReentrantMutex_AbstractTest { protected GammaStm stm; private int threadCount = 10; private ReentrantMutex mutex; private volatile boolean stop; @Before public void setUp() { stm = (GammaStm) getGlobalStmInstance(); clearThreadLocalTxn(); stop = false; } protected abstract GammaTxnExecutor newUnlockBlock(); protected abstract GammaTxnExecutor newLockBlock(); public void run() { mutex = new ReentrantMutex(); StressThread[] threads = new StressThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new StressThread(k); } startAll(threads); sleepMs(30000); stop = true; joinAll(threads); } class StressThread extends TestThread { public StressThread(int id) { super("StressThread-" + id); } @Override public void doRun() throws Exception { long count = 0; while (!stop) { mutex.lock(this); boolean nested = randomOneOf(3); if (nested) { mutex.lock(this); } sleepRandomMs(100); mutex.unlock(this); if (nested) { mutex.unlock(this); } count++; if (count % 10 == 0) { System.out.printf("%s is at %s\n", getName(), count); } } } } class ReentrantMutex { private final TxnRef owner = newTxnRef(); private final TxnInteger count = newTxnInteger(); private final GammaTxnExecutor lockBlock = newLockBlock(); private final GammaTxnExecutor unlockBlock = newUnlockBlock(); public void lock(final Thread thread) { lockBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (owner.get() == null) { owner.set(thread); count.increment(); return; } if (owner.get() == thread) { count.increment(); return; } retry(); } }); } public void unlock(final Thread thread) { unlockBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (owner.get() != thread) { throw new IllegalMonitorStateException(); } count.decrement(); if (count.get() == 0) { owner.set(null); } } }); } } } ReentrantMutex_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000027531174000617100532740ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaTxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; /** * @author Peter Veentjer */ public class ReentrantMutex_FatFixedLengthGammaTxn_StressTest extends ReentrantMutex_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } protected GammaTxnExecutor newLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } protected GammaTxnExecutor newUnlockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } ReentrantMutex_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000027671174000617100537670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaTxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; /** * @author Peter Veentjer */ public class ReentrantMutex_FatVariableLengthGammaTxn_StressTest extends ReentrantMutex_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } protected GammaTxnExecutor newLockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } protected GammaTxnExecutor newUnlockBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaxRetries(10000) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } Semaphore_AbstractTest.java000066400000000000000000000065341174000617100461420ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.TestUtils; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import java.util.concurrent.atomic.AtomicLong; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * A StressTest that checks if a the Semaphore; a traditional synchronization structure can be build * using an STM. */ public abstract class Semaphore_AbstractTest { protected GammaStm stm; private volatile boolean stop; private int threadCount = 10; private int resourceCount = 5; private Semaphore semaphore; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; } protected abstract TxnExecutor newDownBlock(); protected abstract TxnExecutor newUpBlock(); public void run() { semaphore = new Semaphore(resourceCount); WorkerThread[] workers = new WorkerThread[threadCount]; for (int k = 0; k < threadCount; k++) { workers[k] = new WorkerThread(k); } startAll(workers); sleepMs(TestUtils.getStressTestDurationMs(30 * 1000)); System.out.println("Terminating"); stop = true; System.out.println(semaphore.ref.toDebugString()); joinAll(workers); } class WorkerThread extends TestThread { long count; public WorkerThread(int id) { super("Producer-" + id); } @Override public void doRun() throws Exception { while (!stop) { semaphore.down(); semaphore.up(); count++; if (count % 1000000 == 0) { System.out.printf("%s is at %s\n", getName(), count); } } } } class Semaphore { private GammaTxnRef ref; private AtomicLong users = new AtomicLong(); private TxnExecutor upBlock = newUpBlock(); private TxnExecutor downBlock = newDownBlock(); public Semaphore(int initial) { ref = new GammaTxnRef(stm, new Long(initial)); } public void up() { upBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.set(ref.get() + 1); } }); users.incrementAndGet(); if (users.get() > resourceCount) { fail(); } } public void down() { users.decrementAndGet(); downBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (ref.get() == 0) { retry(); } ref.set(ref.get() - 1); } }); } } } Semaphore_FatFixedLengthGammaTxn_StressTest.java000066400000000000000000000026261174000617100522310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; /** * @author Peter Veentjer */ public class Semaphore_FatFixedLengthGammaTxn_StressTest extends Semaphore_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newDownBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newUpBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatFixedLengthGammaTxnFactory(config)); } } Semaphore_FatMonoGammaTxn_StressTest.java000066400000000000000000000025731174000617100507410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; /** * @author Peter Veentjer */ public class Semaphore_FatMonoGammaTxn_StressTest extends Semaphore_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newDownBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } @Override protected TxnExecutor newUpBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatMonoGammaTxnFactory(config)); } } Semaphore_FatVariableLengthGammaTxn_StressTest.java000066400000000000000000000026421174000617100527150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; /** * @author Peter Veentjer */ public class Semaphore_FatVariableLengthGammaTxn_StressTest extends Semaphore_AbstractTest { private LockMode lockMode; @Test public void whenNoLock() { lockMode = LockMode.None; run(); } @Test public void whenReadLock() { lockMode = LockMode.Read; run(); } @Test public void whenWriteLock() { lockMode = LockMode.Write; run(); } @Test public void whenExclusiveLock() { lockMode = LockMode.Exclusive; run(); } @Override protected TxnExecutor newDownBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newUpBlock() { GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(lockMode); return new LeanGammaTxnExecutor(new FatVariableLengthGammaTxnFactory(config)); } } Semaphore_LeanFixedLengthGammaTxn_StressTest.java000066400000000000000000000016461174000617100523770ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxnFactory; /** * @author Peter Veentjer */ public class Semaphore_LeanFixedLengthGammaTxn_StressTest extends Semaphore_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newDownBlock() { GammaTxnConfig config = new GammaTxnConfig(stm); return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(config)); } @Override protected TxnExecutor newUpBlock() { GammaTxnConfig config = new GammaTxnConfig(stm); return new LeanGammaTxnExecutor(new LeanFixedLengthGammaTxnFactory(config)); } } Semaphore_LeanMonoGammaTxn_StressTest.java000066400000000000000000000016131174000617100511000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/integration/traditionalsynchronizationpackage org.multiverse.stms.gamma.integration.traditionalsynchronization; import org.junit.Test; import org.multiverse.api.TxnExecutor; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxnFactory; /** * @author Peter Veentjer */ public class Semaphore_LeanMonoGammaTxn_StressTest extends Semaphore_AbstractTest { @Test public void test() { run(); } @Override protected TxnExecutor newDownBlock() { GammaTxnConfig config = new GammaTxnConfig(stm); return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(config)); } @Override protected TxnExecutor newUpBlock() { GammaTxnConfig config = new GammaTxnConfig(stm); return new LeanGammaTxnExecutor(new LeanMonoGammaTxnFactory(config)); } } 000077500000000000000000000000001174000617100350565ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjectsAddCommutingFunctionTest.java000066400000000000000000000036541174000617100426520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjectspackage org.multiverse.stms.gamma.transactionalobjects; import org.junit.Before; import org.junit.Test; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaObjectPool; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.multiverse.stms.gamma.GammaTestUtils.assertHasCommutingFunctions; public class AddCommutingFunctionTest implements GammaConstants { private GammaObjectPool pool; private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); pool = new GammaObjectPool(); } @Test public void whenFirstAddition() { Tranlocal tranlocal = new Tranlocal(); tranlocal.mode = TRANLOCAL_COMMUTING; tranlocal.addCommutingFunction(pool, Functions.incLongFunction(1)); assertFalse(tranlocal.isRead()); assertTrue(tranlocal.isCommuting()); assertEquals(0, tranlocal.long_value); assertHasCommutingFunctions(tranlocal, Functions.incLongFunction(1)); } @Test public void whenMultipleAdditions() { Tranlocal tranlocal = new Tranlocal(); tranlocal.mode = TRANLOCAL_COMMUTING; LongFunction function1 = mock(LongFunction.class); LongFunction function2 = mock(LongFunction.class); LongFunction function3 = mock(LongFunction.class); tranlocal.addCommutingFunction(pool, function1); tranlocal.addCommutingFunction(pool, function2); tranlocal.addCommutingFunction(pool, function3); assertFalse(tranlocal.isRead()); assertTrue(tranlocal.isCommuting()); assertEquals(0, tranlocal.long_value); assertHasCommutingFunctions(tranlocal, function3, function2, function1); } } 000077500000000000000000000000001174000617100360065ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/lockLock_acquire0Test.java000066400000000000000000000475161174000617100422070ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/lockpackage org.multiverse.stms.gamma.transactionalobjects.lock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.*; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class Lock_acquire0Test { private GammaStm stm; private boolean readBiased; public Lock_acquire0Test(boolean readBiased) { this.readBiased = readBiased; } @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList(new Boolean[]{true}, new Boolean[]{false}); } public GammaTxnLong newTxnLong(long initialValue) { if (readBiased) { return makeReadBiased(new GammaTxnLong(stm, initialValue)); } else { return new GammaTxnLong(stm, initialValue); } } //todo: conflict detection. @Test public void whenNullLock() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullTransaction() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (TxnMandatoryException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.None); assertIsActive(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); assertIsActive(tx); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); assertIsActive(tx); assertRefHasWriteLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); ref.getLock().acquire(LockMode.None); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); ref.getLock().acquire(LockMode.Write); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); ref.getLock().acquire(LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); ref.getLock().acquire(LockMode.None); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); ref.getLock().acquire(LockMode.Read); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); ref.getLock().acquire(LockMode.Write); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); ref.getLock().acquire(LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); ref.getLock().acquire(LockMode.None); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); ref.getLock().acquire(LockMode.Read); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); ref.getLock().acquire(LockMode.Write); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); ref.getLock().acquire(LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } //todo: other locks. // =========================== locked by other ========================== @Test public void otherLocked_whenOtherHasReadLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.None); //todo: check state of tx with regard to lock assertRefHasReadLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); assertRefHasReadLock(ref, tx); assertRefHasReadLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasReadLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasReadLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.None); //todo: check state of tx and locking assertRefHasWriteLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.None); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } // ========================== states ==================================== @Test public void whenTransactionPrepared_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.prepare(); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAborted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.abort(); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionCommitted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.commit(); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } } Lock_acquire1Test.java000066400000000000000000000456461174000617100422120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/lockpackage org.multiverse.stms.gamma.transactionalobjects.lock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class Lock_acquire1Test { private GammaStm stm; private boolean readBiased; public Lock_acquire1Test(boolean readBiased) { this.readBiased = readBiased; } @Before public void setUp() { stm = new GammaStm(); } @Parameterized.Parameters public static Collection configs() { return asList(new Boolean[]{true}, new Boolean[]{false}); } public GammaTxnLong newTxnLong(long initialValue) { if (readBiased) { return makeReadBiased(new GammaTxnLong(stm, initialValue)); } else { return new GammaTxnLong(stm, initialValue); } } //todo: conflict detection. @Test public void whenNullLock() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullTransaction() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); try { ref.getLock().acquire(null, LockMode.Read); fail(); } catch (NullPointerException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.None); assertIsActive(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); assertIsActive(tx); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); assertIsActive(tx); assertRefHasWriteLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); ref.getLock().acquire(tx, LockMode.None); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); ref.getLock().acquire(tx, LockMode.Write); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); ref.getLock().acquire(tx, LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); ref.getLock().acquire(tx, LockMode.None); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); ref.getLock().acquire(tx, LockMode.Read); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); ref.getLock().acquire(tx, LockMode.Write); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); ref.getLock().acquire(tx, LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); ref.getLock().acquire(tx, LockMode.None); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); ref.getLock().acquire(tx, LockMode.Read); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); ref.getLock().acquire(tx, LockMode.Write); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); ref.getLock().acquire(tx, LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } //todo: other locks. // =========================== locked by other ========================== @Test public void otherLocked_whenOtherHasReadLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.None); //todo: check state of tx with regard to lock assertRefHasReadLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); assertRefHasReadLock(ref, tx); assertRefHasReadLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasReadLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasReadLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.None); //todo: check state of tx and locking assertRefHasWriteLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.None); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.getLock().acquire(tx, LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } // ========================== states ==================================== @Test public void whenTransactionPrepared_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); try { ref.getLock().acquire(tx, LockMode.Read); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAborted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.getLock().acquire(tx, LockMode.Read); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionCommitted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); try { ref.getLock().acquire(tx, LockMode.Read); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } } Lock_atomicGetLockModeTest.java000066400000000000000000000016651174000617100440230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/lockpackage org.multiverse.stms.gamma.transactionalobjects.lock; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; public class Lock_atomicGetLockModeTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void test() { test(LockMode.None); test(LockMode.Read); test(LockMode.Write); test(LockMode.Exclusive); } public void test(LockMode lockMode){ GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, lockMode); LockMode result = ref.atomicGetLockMode(); assertEquals(lockMode, result); } } Lock_getLockMode0Test.java000066400000000000000000000111001174000617100427270ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/lockpackage org.multiverse.stms.gamma.transactionalobjects.lock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasLockMode; @RunWith(Parameterized.class) public class Lock_getLockMode0Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public Lock_getLockMode0Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test(expected = NullPointerException.class) public void whenNullTransaction() { GammaTxnLong ref = new GammaTxnLong(stm); ref.getLock().getLockMode(null); } @Test public void other_whenLockedForWriteByOther() { whenLockedByOther(LockMode.Read); whenLockedByOther(LockMode.Write); whenLockedByOther(LockMode.Exclusive); } public void whenLockedByOther(LockMode lockMode) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, lockMode); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); LockMode result = ref.getLock().getLockMode(); assertEquals(LockMode.None, result); assertRefHasLockMode(ref,otherTx, lockMode.asInt()); } @Test public void whenLockedBySelf(){ self_whenLocked(LockMode.None); self_whenLocked(LockMode.Read); self_whenLocked(LockMode.Write); self_whenLocked(LockMode.Exclusive); } public void self_whenLocked(LockMode lockMode){ GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); ref.getLock().acquire(tx, lockMode); setThreadLocalTxn(tx); LockMode result = ref.getLock().getLockMode(); assertEquals(lockMode, result); assertIsActive(tx); } // ====================== states ================================== @Test public void whenTransactionPrepared_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.getLock().getLockMode(tx); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); } @Test public void whenTransactionAborted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.getLock().getLockMode(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } @Test public void whenTransactionCommitted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.getLock().getLockMode(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); } } Lock_getLockMode1Test.java000066400000000000000000000105141174000617100427400ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/lockpackage org.multiverse.stms.gamma.transactionalobjects.lock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasLockMode; @RunWith(Parameterized.class) public class Lock_getLockMode1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public Lock_getLockMode1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test(expected = NullPointerException.class) public void whenNullTransaction() { GammaTxnLong ref = new GammaTxnLong(stm); ref.getLock().getLockMode(null); } @Test public void other_whenLockedForWriteByOther() { whenLockedByOther(LockMode.Read); whenLockedByOther(LockMode.Write); whenLockedByOther(LockMode.Exclusive); } public void whenLockedByOther(LockMode lockMode) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, lockMode); GammaTxn tx = transactionFactory.newTxn(); LockMode result = ref.getLock().getLockMode(tx); assertEquals(LockMode.None, result); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); } @Test public void whenLockedBySelf(){ self_whenLocked(LockMode.None); self_whenLocked(LockMode.Read); self_whenLocked(LockMode.Write); self_whenLocked(LockMode.Exclusive); } public void self_whenLocked(LockMode lockMode){ GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); ref.getLock().acquire(tx, lockMode); LockMode result = ref.getLock().getLockMode(tx); assertEquals(lockMode, result); assertIsActive(tx); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.getLock().getLockMode(tx); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); } @Test public void whenTransactionAborted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.getLock().getLockMode(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } @Test public void whenTransactionCommitted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.getLock().getLockMode(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); } } 000077500000000000000000000000001174000617100360065ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecOrec_arriveAndExclusiveLockTest.java000066400000000000000000000107761174000617100451100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_arriveAndExclusiveLockTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } // ==================== write biased =============================== @Test public void writeBiased_whenNoLockAcquired() { GammaTxnLong orec = new GammaTxnLong(stm); int result = orec.arriveAndExclusiveLock(1); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertWriteBiased(orec); assertSurplus(orec, 1); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void writeBiased_whenSurplusOfReaders() { GammaTxnLong orec = new GammaTxnLong(stm); orec.arrive(1); int result = orec.arriveAndExclusiveLock(1); assertHasMasks(result, MASK_SUCCESS, MASK_CONFLICT); assertNotHasMasks(result, MASK_UNREGISTERED); assertWriteBiased(orec); assertSurplus(orec, 2); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void writeBiased_whenReadLockAcquiredByOther() { GammaTxnLong orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.arriveAndExclusiveLock(1); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenWriteLockAcquiredByOther() { GammaTxnLong orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arriveAndExclusiveLock(1); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenExclusiveLockAcquiredByOther() { GammaTxnLong orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arriveAndExclusiveLock(1); assertFailure(result); assertOrecValue(orec, orecValue); } // ==================== read biased =============================== @Test public void readBiased_whenNoLockAcquired() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); int result = orec.arriveAndExclusiveLock(1); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertReadBiased(orec); assertSurplus(orec, 1); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void readBiased_whenSurplusOfReaders() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); orec.arrive(1); int result = orec.arriveAndExclusiveLock(1); assertHasMasks(result, MASK_SUCCESS, MASK_CONFLICT, MASK_UNREGISTERED); assertReadBiased(orec); assertSurplus(orec, 1); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void readBiased_whenReadLockAcquiredByOther() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.arriveAndExclusiveLock(1); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void readBiased_whenWriteLockAcquiredByOther() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arriveAndExclusiveLock(1); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void readBiased_whenExclusiveLockAcquiredByOther() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arriveAndExclusiveLock(1); assertFailure(result); assertOrecValue(orec, orecValue); } } Orec_arriveAndLockTest.java000066400000000000000000000332151174000617100432110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_arriveAndLockTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } // ================ write biased and acquire read lock ======================== @Test public void writeBiased_acquireReadLock_whenUnlocked() { AbstractGammaObject orec = new GammaTxnLong(stm); int result = orec.arriveAndLock(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 1); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 1); } @Test public void writeBiased_acquireReadLock_whenUnlockedAndConflictingReaders() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); int result = orec.arriveAndLock(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 1); } @Test public void writeBiased_acquireReadLock_whenWriteLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_READ); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireReadLock_whenExclusiveLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_READ); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireReadLock_whenReadLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.arriveAndLock(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 2); } // ================ write biased and acquire write lock ======================== @Test public void writeBiased_acquireWriteLock_whenUnlocked() { AbstractGammaObject orec = new GammaTxnLong(stm); int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_UNREGISTERED, MASK_CONFLICT); assertSurplus(orec, 1); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_WRITE); } @Test public void writeBiased_acquireWriteLock_whenUnlockedAndConflictingReaders() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_UNREGISTERED, MASK_CONFLICT); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_WRITE); } @Test public void writeBiased_acquireWriteLock_whenWriteLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireWriteLock_whenExclusiveLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireWriteLock_whenReadLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } // ================ write biased and acquire exclusive lock ======================== @Test public void writeBiased_acquireExclusiveLock_whenUnlocked() { AbstractGammaObject orec = new GammaTxnLong(stm); int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 1); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void writeBiased_acquireExclusiveLock_whenUnlockedAndConflictingReaders() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertHasMasks(result, MASK_SUCCESS, MASK_CONFLICT); assertNotHasMasks(result, MASK_UNREGISTERED); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void writeBiased_acquireExclusiveLock_whenWriteLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireExclusiveLock_whenExclusiveLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireExclusiveLock_whenReadLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertFailure(result); assertOrecValue(orec, orecValue); } // ==================================================================== @Test public void readBiased_acquireExclusiveLock_whenUnlockedAndNoSurplus() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertSurplus(orec, 1); assertReadBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void readBiased_acquireExclusiveLock_whenUnlockedAndSurplus() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arrive(1); int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED, MASK_CONFLICT); assertSurplus(orec, 1); assertReadBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void readBiased_acquireExclusiveLock_whenReadLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertEquals(FAILURE, result); assertOrecValue(orec, orecValue); } @Test public void readBiased_acquireExclusiveLock_whenWriteLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void readBiased_acquireExclusiveLock_whenExclusiveLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); assertFailure(result); assertOrecValue(orec, orecValue); } // ======================================================================= @Test public void readBiased_acquireWriteLock_whenUnlocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertSurplus(orec, 1); assertReadBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_WRITE); } @Test public void readBiased_acquireWriteLock_whenUnlockedAndSurplus() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertSurplus(orec, 1); assertReadBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_WRITE); } @Test public void readBiased_acquireWriteLock_whenWriteLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void readBiased_acquireWriteLock_whenExclusiveLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void readBiased_acquireWriteLock_whenReadLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } // ======================================================================= @Test public void readBiased_acquireReadLock_whenUnlocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); int result = orec.arriveAndLock(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertSurplus(orec, 1); assertReadBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 1); } @Test public void readBiased_acquireReadLock_whenSurplusAndUnlocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arrive(1); int result = orec.arriveAndLock(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertSurplus(orec, 1); assertReadBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 1); } @Test public void readBiased_acquireReadLock_whenWriteLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_READ); assertEquals(FAILURE, result); assertOrecValue(orec, orecValue); } @Test public void readBiased_acquireReadLock_whenExclusiveLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arriveAndLock(1, LOCKMODE_READ); assertEquals(FAILURE, result); assertOrecValue(orec, orecValue); } @Test public void readBiased_acquireReadLock_whenReadLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.arriveAndLock(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertSurplus(orec, 1); assertReadBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 2); } } Orec_arriveTest.java000066400000000000000000000110241174000617100417470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static junit.framework.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_arriveTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } // ======================= write biased ============================== @Test public void writeBiased_whenNotLockedAndNoSurplus_thenNormalArrive() { AbstractGammaObject orec = new GammaTxnLong(stm, 0); int result = orec.arrive(1); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 1); assertReadonlyCount(orec, 0); assertWriteBiased(orec); assertLockMode(orec, LOCKMODE_NONE); } @Test public void writeBiased_whenNotLockedAndSurplus_thenNormalArrive() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); int result = orec.arrive(1); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertWriteBiased(orec); assertSurplus(orec, 3); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_NONE); } @Test public void writeBiased_whenExclusiveLock_thenLockNotFree() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arrive(1); assertEquals(FAILURE, result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenWriteLock_thenArriveSuccess() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); int result = orec.arrive(1); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_CONFLICT); assertSurplus(orec, 2); assertReadonlyCount(orec, 0); assertWriteBiased(orec); assertLockMode(orec, LOCKMODE_WRITE); } // ======================= read biased ============================== @Test public void readBiased_whenNoSurplus() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); int result = orec.arrive(1); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 1); assertReadBiased(orec); assertReadonlyCount(orec, 0); } @Test public void readBiased_whenSurplus_thenCallIgnored() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arrive(1); long orecValue = orec.orec; int result = orec.arrive(1); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertOrecValue(orec, orecValue); } @Test public void readBiased_whenReadLockAcquired() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.arrive(1); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertOrecValue(orec, orecValue); } @Test public void readBiased_whenWriteLockAcquired() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.arrive(1); assertHasMasks(result, MASK_SUCCESS, MASK_UNREGISTERED); assertNotHasMasks(result, MASK_CONFLICT); assertOrecValue(orec, orecValue); } @Test public void readBiased_whenExclusiveLockAquired() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.arrive(1); assertFailure(result); assertOrecValue(orec, orecValue); } } Orec_departAfterFailureAndUnlockTest.java000066400000000000000000000077461174000617100460470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_departAfterFailureAndUnlockTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenUpdateBiasedNotLocked_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.departAfterFailureAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenReadBiasedAndNotLocked_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); long orecValue = orec.orec; try { orec.departAfterFailureAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenUpdateBiasedAndHasMultipleReadLocks() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); orec.departAfterFailureAndUnlock(); assertLockMode(orec, LOCKMODE_READ); assertReadLockCount(orec, 1); assertSurplus(orec, 1); assertReadonlyCount(orec, 0); assertWriteBiased(orec); } @Test public void whenUpdateBiasedAndHasSingleReadLock() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); orec.departAfterFailureAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 0); assertReadonlyCount(orec, 0); assertWriteBiased(orec); assertReadLockCount(orec, 0); } @Test public void whenUpdateBiasedAndHasWriteLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); orec.departAfterFailureAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 0); assertReadonlyCount(orec, 0); assertWriteBiased(orec); assertReadLockCount(orec, 0); } @Test public void whenUpdateBiasedAndHasWriteLockedAndSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_WRITE); orec.departAfterFailureAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 2); assertReadonlyCount(orec, 0); assertWriteBiased(orec); assertReadLockCount(orec, 0); } @Test public void whenUpdateBiasedAndHasExclusiveLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); orec.departAfterFailureAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 0); assertReadonlyCount(orec, 0); assertWriteBiased(orec); assertReadLockCount(orec, 0); } @Test public void whenUpdateBiasedAndHasExclusiveLockedAndSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(2); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); orec.departAfterFailureAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 2); assertReadonlyCount(orec, 0); assertWriteBiased(orec); assertReadLockCount(orec, 0); } } Orec_departAfterFailureTest.java000066400000000000000000000056261174000617100442430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_departAfterFailureTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenUpdateBiasedAndNoSurplusAndNotLocked_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.departAfterFailure(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenUpdateBiasedAndSurplusAndNotLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.departAfterFailure(); assertSurplus(orec, 0); assertWriteBiased(orec); assertLockMode(orec, LOCKMODE_NONE); assertReadonlyCount(orec, 0); } @Test public void whenUpdateBiasedAndSurplusAndLockedForCommit() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); orec.departAfterFailure(); assertSurplus(orec, 1); assertWriteBiased(orec); assertLockMode(orec, LOCKMODE_EXCLUSIVE); assertReadonlyCount(orec, 0); } @Test public void whenUpdateBiasedAndSurplusAndLockedForUpdate() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); orec.lockAfterArrive(1, LOCKMODE_WRITE); orec.departAfterFailure(); assertSurplus(orec, 1); assertWriteBiased(orec); assertLockMode(orec, LOCKMODE_WRITE); assertReadonlyCount(orec, 0); } @Test public void whenReadBiasedAndLockedForCommit_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; try { orec.departAfterFailure(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenReadBiasedAndNotLocked_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); long orecValue = orec.orec; try { orec.departAfterFailure(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } } Orec_departAfterReadingAndUnlockTest.java000066400000000000000000000102001174000617100460040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_departAfterReadingAndUnlockTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void writeBiased_whenSingleReadLock() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); orec.departAfterReadingAndUnlock(); assertSurplus(orec, 0); assertReadLockCount(orec, 0); assertLockMode(orec, LOCKMODE_NONE); } @Test public void writeBiased_whenMultipleReadLocks() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); orec.departAfterReadingAndUnlock(); assertSurplus(orec, 2); assertReadLockCount(orec, 2); assertLockMode(orec, LOCKMODE_READ); } @Test public void writeBiased_whenWriteLock() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); orec.departAfterReadingAndUnlock(); assertSurplus(orec, 0); assertReadLockCount(orec, 0); assertLockMode(orec, LOCKMODE_NONE); } @Test public void writeBiased_whenExclusiveLock() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); orec.departAfterReadingAndUnlock(); assertSurplus(orec, 0); assertReadLockCount(orec, 0); assertLockMode(orec, LOCKMODE_NONE); } @Test public void writeBiased_whenMultipleArrivesAndLockedForCommit() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(2); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); orec.departAfterReadingAndUnlock(); assertSurplus(orec, 2); assertLockMode(orec, LOCKMODE_NONE); assertWriteBiased(orec); assertReadonlyCount(orec, 1); } @Test public void writeBiased_whenMultipleArrivesAndLockedForWrite() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(2); orec.arriveAndLock(1, LOCKMODE_WRITE); orec.departAfterReadingAndUnlock(); assertSurplus(orec, 2); assertLockMode(orec, LOCKMODE_NONE); assertWriteBiased(orec); assertReadonlyCount(orec, 1); } @Test public void writeBiased_whenNotLockedAndNoSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.departAfterReadingAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } // ======================= read biased ========================= @Test public void readBiased_whenLocked() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; try { orec.departAfterReadingAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenNotLockedAndSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); long orecValue = orec.orec; try { orec.departAfterReadingAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } } Orec_departAfterReadingTest.java000066400000000000000000000105271174000617100442210ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_departAfterReadingTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenNoSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.departAfterReading(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenMuchSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); orec.departAfterReading(); assertSurplus(orec, 1); assertReadonlyCount(orec, 1); assertWriteBiased(orec); assertLockMode(orec, LOCKMODE_NONE); } @Test public void whenReadLockAndSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); orec.lockAfterArrive(1, LOCKMODE_READ); orec.departAfterReading(); assertSurplus(orec, 1); assertWriteBiased(orec); assertReadonlyCount(orec, 1); assertLockMode(orec, LOCKMODE_READ); } @Test public void whenReadLockAndNoAdditionalSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; try { orec.departAfterReading(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenWriteLockAndSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_WRITE); orec.departAfterReading(); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 1); assertLockMode(orec, LOCKMODE_WRITE); } @Test public void whenWriteLockAndNoAdditionalSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; try { orec.departAfterReading(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenExclusiveLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); orec.departAfterReading(); assertSurplus(orec, 1); assertWriteBiased(orec); assertReadonlyCount(orec, 1); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void whenExclusiveLockAndNoAdditionalSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; try { orec.departAfterReading(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenReadBiasedAndLockedForCommit_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; try { orec.departAfterReading(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenReadBiasedAndUnlocked_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); long orecValue = orec.orec; try { orec.departAfterReading(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } } Orec_departAfterUpdateAndUnlockTest.java000066400000000000000000000127461174000617100456760ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_departAfterUpdateAndUnlockTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } // ================ write biased =============================== @Test public void writeBiased_whenNotLockedAndNoSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.departAfterUpdateAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenNotLockedAndSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); long orecValue = orec.orec; try { orec.departAfterUpdateAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenLockedAndNoAdditionalSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); orec.departAfterUpdateAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 0); assertWriteBiased(orec); assertReadonlyCount(orec, 0); } @Test public void writeBiased_whenLockedAndAdditionalSurplus() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); orec.arrive(1); orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); orec.departAfterUpdateAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); } @Test public void writeBiased_whenWriteLock_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; try { orec.departAfterUpdateAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenReadLockAcquired_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; try { orec.departAfterUpdateAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } // ================ read biased =============================== @Test public void readBiased_whenNotLockedAndNoSurplus_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); long orecValue = orec.orec; try { orec.departAfterUpdateAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenNotLockedAndSurplus_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arrive(1); long orecValue = orec.orec; try { orec.departAfterUpdateAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenLockedAndNoAdditionalSurplus() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); orec.departAfterUpdateAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 0); assertWriteBiased(orec); assertReadonlyCount(orec, 0); } @Test public void readBiased_whenLockedAndAdditionalSurplus() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); orec.departAfterUpdateAndUnlock(); assertLockMode(orec, LOCKMODE_NONE); assertSurplus(orec, 0); assertWriteBiased(orec); assertReadonlyCount(orec, 0); } @Test public void readBiased_whenWriteLock_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; try { orec.departAfterUpdateAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenReadLockAcquired_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; try { orec.departAfterUpdateAndUnlock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } } Orec_lockAfterArriveTest.java000066400000000000000000000246551174000617100435600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_lockAfterArriveTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } // ===================== write biased and acquire readlock ========================= @Test public void writeBiased_acquireReadLock_whenNoSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.lockAfterArrive(1, LOCKMODE_READ); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireReadLock_whenUnlocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); int result = orec.lockAfterArrive(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 1); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 1); } @Test public void writeBiased_acquireReadLock_whenUnlockedAndConflictingReaders() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); int result = orec.lockAfterArrive(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 1); } @Test public void writeBiased_acquireReadLock_whenWriteLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.lockAfterArrive(1, LOCKMODE_READ); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireReadLock_whenExclusiveLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.lockAfterArrive(1, LOCKMODE_READ); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireReadLock_whenReadLockAcquiredOnceByOther() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.lockAfterArrive(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 2); } @Test public void writeBiased_acquireReadLock_whenReadLockAcquiredMoreThanOnceByOthers() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.lockAfterArrive(1, LOCKMODE_READ); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 3); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertReadLockCount(orec, 3); } // ===================== write biased and acquire writelock ========================= @Test public void writeBiased_acquireWriteLock_whenUnlocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); int result = orec.lockAfterArrive(1, LOCKMODE_WRITE); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 1); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_WRITE); } @Test public void writeBiased_acquireWriteLock_whenUnlockedButConflictingReaders() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); int result = orec.lockAfterArrive(1, LOCKMODE_WRITE); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_WRITE); } @Test public void writeBiased_acquireWriteLock_whenNoSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.lockAfterArrive(1, LOCKMODE_WRITE); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireWriteLock_whenWriteLocked_thenFailure() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; int result = orec.lockAfterArrive(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireWriteLock_whenExclusiveLocked_thenFailure() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.lockAfterArrive(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireWriteLock_whenReadLocken_thenFailure() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.lockAfterArrive(1, LOCKMODE_WRITE); assertFailure(result); assertOrecValue(orec, orecValue); } // ===================== write biased and acquire exclusivelock ========================= @Test public void writeBiased_acquireExclusiveLock_whenUnlocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); int result = orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT, MASK_UNREGISTERED); assertSurplus(orec, 1); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void writeBiased_acquireExclusiveLock_whenUnlockedAndConflictingReaders() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arrive(1); int result = orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); assertHasMasks(result, MASK_SUCCESS, MASK_CONFLICT); assertNotHasMasks(result, MASK_UNREGISTERED); assertSurplus(orec, 2); assertWriteBiased(orec); assertReadonlyCount(orec, 0); assertLockMode(orec, LOCKMODE_EXCLUSIVE); } @Test public void writeeBiased_acquireExclusiveLock_whenNoSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireExclusiveLock_whenReadLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireExclusiveLock_whenWriteLocked_thenFailure() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); orec.arrive(1); long orecValue = orec.orec; int result = orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_acquireExclusiveLock_whenExclusiveLocked() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; int result = orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); assertFailure(result); assertOrecValue(orec, orecValue); } // ==================================================================== @Test public void readBiased_acquireExclusiveLock_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); long orecValue = orec.orec; try { orec.lockAfterArrive(1, LOCKMODE_EXCLUSIVE); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_acquireWriteLock_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); long orecValue = orec.orec; try { orec.lockAfterArrive(1, LOCKMODE_WRITE); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_acquireReadLock_thenPanicError() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); long orecValue = orec.orec; try { orec.lockAfterArrive(1, LOCKMODE_READ); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } } Orec_unlockByUnregisteredTest.java000066400000000000000000000053651174000617100446410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_unlockByUnregisteredTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenUpdateBiasedAndNoSurplus_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.unlockByUnregistered(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void whenUpdateBiasedAndNotLocked_thenPanicError() { AbstractGammaObject orec = new GammaTxnLong(stm); orec.arrive(1); long orecValue = orec.orec; try { orec.unlockByUnregistered(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenReadLockedAcquiredOnce() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); orec.unlockByUnregistered(); assertLockMode(orec, LockMode.None); assertSurplus(orec, 1); } @Test public void readBiased_whenReadLockAcquiredMultipleTimes() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); orec.unlockByUnregistered(); assertLockMode(orec, LockMode.Read); assertReadLockCount(orec, 2); assertSurplus(orec, 1); } @Test public void readBiased_whenWriteLockAcquired() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_WRITE); orec.unlockByUnregistered(); assertLockMode(orec, LockMode.None); assertSurplus(orec, 1); } @Test public void readBiased_whenExclusiveLockAcquired() { AbstractGammaObject orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); orec.unlockByUnregistered(); assertLockMode(orec, LOCKMODE_NONE); assertReadBiased(orec); assertSurplus(orec, 1); } } Orec_upgradeReadLockTest.java000066400000000000000000000223771174000617100435300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_upgradeReadLockTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } // ================================ write biased =================================== @Test public void writeBiased_whenNoLockAcquiredAndUpgradeToWriteLock_thenPanicError() { GammaTxnLong orec = new GammaTxnLong(stm, 0); long orecValue = orec.orec; try { orec.upgradeReadLock(1, false); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenNoLockAcquiredAndUpgradeToExclusiveLock_thenPanicError() { GammaTxnLong orec = new GammaTxnLong(stm, 0); long orecValue = orec.orec; try { orec.upgradeReadLock(1, true); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenWriteLockAcquired_thenPanicError() { GammaTxnLong orec = new GammaTxnLong(stm, 0); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; try { orec.upgradeReadLock(1, true); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenExclusiveLockAcquired_thenPanicError() { GammaTxnLong orec = new GammaTxnLong(stm, 0); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; try { orec.upgradeReadLock(1, true); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenSingleReadLockAcquiredAndUpgradeToWriteLockAndNoSurplus_thenSuccess() { GammaTxnLong orec = new GammaTxnLong(stm, 0); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.upgradeReadLock(1, false); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT); assertTrue(orec.hasWriteLock()); assertReadLockCount(orec, 0); assertSurplus(orec, 1); assertWriteBiased(orec); } @Test public void writeBiased_whenSingleReadLockAcquiredAndUpgradeToWriteLockAndSurplus_thenSuccess() { GammaTxnLong orec = new GammaTxnLong(stm, 0); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.upgradeReadLock(1, false); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT); assertTrue(orec.hasWriteLock()); assertReadLockCount(orec, 0); assertSurplus(orec, 2); assertWriteBiased(orec); } @Test public void writeBiased_whenSingleReadLockAcquiredAndUpgradeToExclusiveLockAndNoSurplus_thenSuccess() { GammaTxnLong orec = new GammaTxnLong(stm, 0); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.upgradeReadLock(1, true); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT); assertTrue(orec.hasExclusiveLock()); assertReadLockCount(orec, 0); assertSurplus(orec, 1); assertReadonlyCount(orec, 0); assertWriteBiased(orec); } @Test public void writeBiased_whenSingleReadLockAcquiredAndUpgradeToExclusiveAndSurplus_thenConflict() { GammaTxnLong orec = new GammaTxnLong(stm, 0); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.upgradeReadLock(1, true); assertHasMasks(result, MASK_SUCCESS, MASK_CONFLICT); assertTrue(orec.hasExclusiveLock()); assertReadLockCount(orec, 0); assertSurplus(orec, 2); assertReadonlyCount(orec, 0); assertWriteBiased(orec); } @Test public void writeeBiased_whenMultipleReadLocksAcquired_thenUpgradeToWriteLockFailure() { GammaTxnLong orec = new GammaTxnLong(stm, 0); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.upgradeReadLock(1, false); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenMultipleReadLocksAcquired_thenUpgradeToExclusiveLockFailure() { GammaTxnLong orec = new GammaTxnLong(stm, 0); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.upgradeReadLock(1, true); assertFailure(result); assertOrecValue(orec, orecValue); } // ================================ read biased =================================== @Test public void readBiased_whenNoLockAcquiredAndUpgradeToWriteLock_thenPanicError() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); long orecValue = orec.orec; try { orec.upgradeReadLock(1, false); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenNoLockAcquiredAndUpgradeToExclusiveLock_thenPanicError() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); long orecValue = orec.orec; try { orec.upgradeReadLock(1, true); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenWriteLockAcquired_thenPanicError() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); orec.arriveAndLock(1, LOCKMODE_WRITE); long orecValue = orec.orec; try { orec.upgradeReadLock(1, true); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenExclusiveLockAcquired_thenPanicError() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); long orecValue = orec.orec; try { orec.upgradeReadLock(1, true); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenSingleReadLockAcquiredAndUpgradeToWriteLockAndNoSurplus_thenSuccess() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.upgradeReadLock(1, false); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT); assertTrue(orec.hasWriteLock()); assertReadLockCount(orec, 0); assertSurplus(orec, 1); assertReadBiased(orec); } @Test public void readBiased_whenSingleReadLockAcquiredAndUpgradeToWriteLockAndSurplus_thenSuccess() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.upgradeReadLock(1, false); assertHasMasks(result, MASK_SUCCESS); assertNotHasMasks(result, MASK_CONFLICT); assertTrue(orec.hasWriteLock()); assertReadLockCount(orec, 0); assertSurplus(orec, 1); assertReadBiased(orec); } @Test public void readBiased_whenSingleReadLockAcquiredAndUpgradeToExclusiveLockAndNoSurplus_thenSuccess() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); orec.arriveAndLock(1, LOCKMODE_READ); int result = orec.upgradeReadLock(1, true); assertHasMasks(result, MASK_SUCCESS, MASK_CONFLICT); assertTrue(orec.hasExclusiveLock()); assertReadLockCount(orec, 0); assertSurplus(orec, 1); assertReadonlyCount(orec, 0); assertReadBiased(orec); } @Test public void readBiased_whenMultipleReadLocksAcquired_thenUpgradeToWriteLockFailure() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.upgradeReadLock(1, false); assertFailure(result); assertOrecValue(orec, orecValue); } @Test public void readBiased_whenMultipleReadLocksAcquired_thenUpgradeToExclusiveLockFailure() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm, 0)); orec.arriveAndLock(1, LOCKMODE_READ); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; int result = orec.upgradeReadLock(1, true); assertFailure(result); assertOrecValue(orec, orecValue); } } Orec_upgradeWriteLockTest.java000066400000000000000000000112541174000617100437370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/orecpackage org.multiverse.stms.gamma.transactionalobjects.orec; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.PanicError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class Orec_upgradeWriteLockTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } // ==================== write biased ================================ @Test public void writeBiased_whenNotLocked_thenPanicError() { GammaTxnLong orec = new GammaTxnLong(stm); long orecValue = orec.orec; try { orec.upgradeWriteLock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenReadLocked_thenPanicError() { GammaTxnLong orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; try { orec.upgradeWriteLock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void writeBiased_whenWriteLockedAndNoSurplus() { GammaTxnLong orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_WRITE); boolean result = orec.upgradeWriteLock(); assertFalse(result); assertSurplus(orec, 1); assertLockMode(orec, LOCKMODE_EXCLUSIVE); assertWriteBiased(orec); assertReadonlyCount(orec, 0); } @Test public void writeBiased_whenWriteLockedAndSurplusOfReaders() { GammaTxnLong orec = new GammaTxnLong(stm); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_WRITE); boolean result = orec.upgradeWriteLock(); assertTrue(result); assertSurplus(orec, 2); assertLockMode(orec, LOCKMODE_EXCLUSIVE); assertWriteBiased(orec); assertReadonlyCount(orec, 0); } @Test public void writeBiased_whenExclusiveLocked() { GammaTxnLong orec = new GammaTxnLong(stm); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); boolean result = orec.upgradeWriteLock(); assertFalse(result); assertSurplus(orec, 1); assertLockMode(orec, LOCKMODE_EXCLUSIVE); assertWriteBiased(orec); assertReadonlyCount(orec, 0); } // ==================== read biased ================================ @Test public void readBiased_whenNotLocked_thenPanicError() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); long orecValue = orec.orec; try { orec.upgradeWriteLock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenReadLocked_thenPanicError() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_READ); long orecValue = orec.orec; try { orec.upgradeWriteLock(); fail(); } catch (PanicError expected) { } assertOrecValue(orec, orecValue); } @Test public void readBiased_whenWriteLockedAndNoSurplus() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_WRITE); boolean result = orec.upgradeWriteLock(); assertTrue(result); assertSurplus(orec, 1); assertLockMode(orec, LOCKMODE_EXCLUSIVE); assertReadBiased(orec); assertReadonlyCount(orec, 0); } @Test public void readBiased_whenWriteLockedAndSurplusOfReaders() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); orec.arrive(1); orec.arriveAndLock(1, LOCKMODE_WRITE); boolean result = orec.upgradeWriteLock(); assertTrue(result); assertSurplus(orec, 1); assertLockMode(orec, LOCKMODE_EXCLUSIVE); assertReadBiased(orec); assertReadonlyCount(orec, 0); } @Test public void readBiased_whenExclusiveLocked() { GammaTxnLong orec = makeReadBiased(new GammaTxnLong(stm)); orec.arriveAndLock(1, LOCKMODE_EXCLUSIVE); boolean result = orec.upgradeWriteLock(); assertFalse(result); assertSurplus(orec, 1); assertLockMode(orec, LOCKMODE_EXCLUSIVE); assertReadBiased(orec); assertReadonlyCount(orec, 0); } } 000077500000000000000000000000001174000617100360155ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refsCommitTest.java000066400000000000000000000402311174000617100407500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.*; import org.multiverse.stms.gamma.transactionalobjects.*; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.stms.gamma.GammaStmUtils.doubleAsLong; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class CommitTest implements GammaConstants { private GammaStm stm; private GammaObjectPool pool; @Before public void setUp() { stm = new GammaStm(); pool = new GammaObjectPool(); } @Test public void intRef_whenDirty() { int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); int newValue = 20; tranlocal.long_value = newValue; tranlocal.setDirty(true); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void intRef_whenNotDirty() { int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void intRef_whenDirtyAndListener() { int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); int newValue = 20; tranlocal.long_value = newValue; tranlocal.setDirty(true); Listeners result = ref.commit(tranlocal, pool); assertSame(result, listeners); assertNull(ref.listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void intRef_whenNotDirtyAndListener() { int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners result = ref.commit(tranlocal, pool); assertNull(result); assertSame(listeners, ref.listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void booleanRef_whenDirty() { boolean initialValue = true; GammaTxnBoolean ref = new GammaTxnBoolean(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); boolean newValue = false; tranlocal.long_value = GammaStmUtils.booleanAsLong(newValue); tranlocal.setDirty(true); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion + 1, false); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void booleanRef_whenNotDirty() { boolean initialValue = false; GammaTxnBoolean ref = new GammaTxnBoolean(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void booleanRef_whenDirtyAndListener() { boolean initialValue = true; GammaTxnBoolean ref = new GammaTxnBoolean(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); boolean newValue = false; tranlocal.long_value = GammaStmUtils.booleanAsLong(newValue); tranlocal.setDirty(true); Listeners result = ref.commit(tranlocal, pool); assertSame(result, listeners); assertNull(ref.listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void booleanRef_whenNotDirtyAndListener() { boolean initialValue = true; GammaTxnBoolean ref = new GammaTxnBoolean(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners result = ref.commit(tranlocal, pool); assertNull(result); assertSame(listeners, ref.listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void TxnDouble_whenDirty() { double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); double newValue = 20; tranlocal.long_value = doubleAsLong(newValue); tranlocal.setDirty(true); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void TxnDouble_whenNotDirty() { double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void TxnDouble_whenDirtyAndListener() { double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); double newValue = 20; tranlocal.long_value = doubleAsLong(newValue); tranlocal.setDirty(true); Listeners result = ref.commit(tranlocal, pool); assertSame(result, listeners); assertNull(ref.listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void TxnDouble_whenNotDirtyAndListener() { double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners result = ref.commit(tranlocal, pool); assertNull(result); assertSame(listeners, ref.listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void longRef_whenDirty() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); long newValue = 20; tranlocal.long_value = newValue; tranlocal.setDirty(true); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void longRef_whenNotDirty() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void longRef_whenDirtyAndListener() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); long newValue = 20; tranlocal.long_value = newValue; tranlocal.setDirty(true); Listeners result = ref.commit(tranlocal, pool); assertSame(result, listeners); assertNull(ref.listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void longRef_whenNotDirtyAndListener() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners result = ref.commit(tranlocal, pool); assertNull(result); assertSame(listeners, ref.listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); } @Test public void ref_whenDirty() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); String newValue = "bar"; tranlocal.ref_value = newValue; tranlocal.setDirty(true); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); } @Test public void ref_whenNotDirty() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.version; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners listeners = ref.commit(tranlocal, pool); assertNull(listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); } @Test public void ref_whenDirtyAndListener() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); String newValue = "bar"; tranlocal.ref_value = newValue; tranlocal.setDirty(true); Listeners result = ref.commit(tranlocal, pool); assertSame(result, listeners); assertNull(ref.listeners); assertVersionAndValue(ref, initialVersion + 1, newValue); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); } @Test public void ref_whenNotDirtyAndListener() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.version; Listeners listeners = new Listeners(); ref.listeners = listeners; Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, false); tranlocal.setDirty(false); Listeners result = ref.commit(tranlocal, pool); assertNull(result); assertSame(listeners, ref.listeners); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); } } Ensure0Test.java000066400000000000000000000240251174000617100410440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.*; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class Ensure0Test implements GammaConstants { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public Ensure0Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenReadonlyAndConflictingWrite_thenCommitSucceeds() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.get(); ref.ensure(); ref.atomicIncrementAndGet(1); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void whenReadLockAcquiredBySelf() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.set(initialValue + 1); ref.getLock().acquire(LockMode.Read); ref.ensure(); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertRefHasReadLock(ref, tx); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); tx.commit(); assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void whenWriteLockAcquiredBySelf() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.set(initialValue + 1); ref.getLock().acquire(LockMode.Write); ref.ensure(); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertRefHasWriteLock(ref, tx); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); tx.commit(); assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void whenExclusiveLockAcquiredBySelf() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.set(initialValue + 1); ref.getLock().acquire(LockMode.Exclusive); ref.ensure(); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertRefHasExclusiveLock(ref, tx); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); tx.commit(); assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void whenEnsuredByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.set(initialValue + 1); ref.ensure(); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertRefHasWriteLock(ref, otherTx); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPrivatizedByOther_thenDeferredEnsureFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.ensure(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCalled_thenNoLockingDuringTransaction() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.ensure(); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertTrue(tranlocal.isConflictCheckNeeded()); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void state_whenNullTransaction_thenNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.ensure(null); fail(); } catch (NullPointerException expected) { } assertSame(null, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void state_whenAlreadyPrepared_thenPreparedTxnException() { GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.prepare(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.ensure(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void state_whenAlreadyAborted_thenDeadTxnException() { GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.ensure(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void state_whenAlreadyCommitted_thenDeadTxnException() { GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.ensure(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void whenPossibleWriteSkew_thenCanBeDetectedWithEnsure() { assumeTrue(!(transactionFactory.newTxn() instanceof FatMonoGammaTxn)); GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxn tx1 = transactionFactory.newTxn(); ref1.get(tx1); ref2.incrementAndGet(tx1, 1); GammaTxn tx2 = transactionFactory.newTxn(); ref1.incrementAndGet(tx2, 1); ref2.get(tx2); ref2.ensure(tx2); tx1.prepare(); try { tx2.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx2); } } Ensure1Test.java000066400000000000000000000241501174000617100410440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.*; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.multiverse.TestUtils.LOCKMODE_EXCLUSIVE; import static org.multiverse.TestUtils.LOCKMODE_NONE; import static org.multiverse.TestUtils.LOCKMODE_READ; import static org.multiverse.TestUtils.LOCKMODE_WRITE; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class Ensure1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public Ensure1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenReadonlyAndConflictingWrite_thenCommitSucceeds() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.get(tx); ref.ensure(tx); ref.atomicIncrementAndGet(1); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void whenReadLockAcquiredBySelf() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.set(tx, initialValue + 1); ref.getLock().acquire(tx, LockMode.Read); ref.ensure(tx); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void whenWriteLockAcquiredBySelf() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.set(tx, initialValue + 1); ref.getLock().acquire(tx, LockMode.Write); ref.ensure(tx); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void whenExclusiveLockAcquiredBySelf() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.set(tx, initialValue + 1); ref.getLock().acquire(tx, LockMode.Exclusive); ref.ensure(tx); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertRefHasExclusiveLock(ref, tx); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); tx.commit(); assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void whenReadLockAcquiredByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = transactionFactory.newTxn(); ref.set(tx, initialValue + 1); ref.ensure(tx); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertRefHasReadLock(ref, otherTx); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenWriteLockAcquiredByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); ref.set(tx, initialValue + 1); ref.ensure(tx); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertIsActive(tx); assertTrue(tranlocal.isConflictCheckNeeded()); assertRefHasWriteLock(ref, otherTx); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPrivatizedByOther_thenDeferredEnsureFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); try { ref.ensure(tx); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void state_whenNullTransaction_thenNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.ensure(null); fail(); } catch (NullPointerException expected) { } assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void state_whenAlreadyPrepared_thenPreparedTxnException() { GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.ensure(tx); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void state_whenAlreadyAborted_thenDeadTxnException() { GammaTxn tx = transactionFactory.newTxn(); tx.abort(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.ensure(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void state_whenAlreadyCommitted_thenDeadTxnException() { GammaTxn tx = transactionFactory.newTxn(); tx.commit(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.ensure(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void whenPossibleWriteSkew_thenCanBeDetectedWithDeferredEnsure() { assumeTrue(!(transactionFactory.newTxn() instanceof FatMonoGammaTxn)); GammaTxnLong ref1 = new GammaTxnLong(stm); GammaTxnLong ref2 = new GammaTxnLong(stm); GammaTxn tx1 = transactionFactory.newTxn(); ref1.get(tx1); ref2.incrementAndGet(tx1, 1); GammaTxn tx2 = transactionFactory.newTxn(); ref1.incrementAndGet(tx2, 1); ref2.get(tx2); ref2.ensure(tx2); tx1.prepare(); try { tx2.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx2); } } EnsureLeanTransactionTest.java000066400000000000000000000030711174000617100437700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.SpeculativeConfigurationError; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; public class EnsureLeanTransactionTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenLeanMonoGammaTxnUsed() { GammaTxnRef ref = new GammaTxnRef(stm, null); LeanMonoGammaTxn tx = new LeanMonoGammaTxn(stm); try { ref.ensure(tx); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.config.speculativeConfiguration.get().ensureDetected); } @Test public void whenLeanFixedLengthGammaTxnUsed() { GammaTxnRef ref = new GammaTxnRef(stm, null); LeanFixedLengthGammaTxn tx = new LeanFixedLengthGammaTxn(stm); try { ref.ensure(tx); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.config.speculativeConfiguration.get().ensureDetected); } } HasReadConflictTest.java000066400000000000000000000134601174000617100425150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class HasReadConflictTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenReadAndNoConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); boolean hasReadConflict = ref.hasReadConflict(read); assertFalse(hasReadConflict); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenWriteAndNoConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal write = ref.openForWrite(tx, LOCKMODE_NONE); boolean hasReadConflict = ref.hasReadConflict(write); assertFalse(hasReadConflict); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenPrivatizedBySelf_thenNoConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_EXCLUSIVE); boolean hasConflict = ref.hasReadConflict(read); assertFalse(hasConflict); assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, tx); } @Test public void whenEnsuredBySelf_thenNoConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_WRITE); boolean hasConflict = ref.hasReadConflict(read); assertFalse(hasConflict); assertSurplus(ref, 1); assertRefHasWriteLock(ref, tx); } @Test public void whenUpdatedByOther_thenConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); //conflicting update ref.atomicIncrementAndGet(1); boolean hasConflict = ref.hasReadConflict(read); assertTrue(hasConflict); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenFresh() { GammaTxn tx = stm.newDefaultTxn(); GammaTxnLong ref = new GammaTxnLong(tx); Tranlocal tranlocal = tx.locate(ref); long orecValue = ref.orec; boolean conflict = ref.hasReadConflict(tranlocal); assertFalse(conflict); assertOrecValue(ref, orecValue); } @Test public void whenValueChangedByOtherAndLockedForCommitByOther() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); //do the conflicting update ref.atomicIncrementAndGet(1); //privatize it GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); boolean hasConflict = ref.hasReadConflict(read); assertTrue(hasConflict); assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenValueChangedByOtherAndEnsuredAgain() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); //do the conflicting update ref.atomicIncrementAndGet(1); //ensure it. GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); boolean hasConflict = ref.hasReadConflict(read); assertTrue(hasConflict); assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); } @Test public void whenUpdateInProgressBecauseLockedByOther() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.openForRead(otherTx, LOCKMODE_EXCLUSIVE); boolean hasReadConflict = ref.hasReadConflict(tranlocal); assertTrue(hasReadConflict); } @Test public void whenAlsoReadByOther_thenNoConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); ref.get(tx); GammaTxn otherTx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(otherTx, LOCKMODE_NONE); boolean hasConflict = ref.hasReadConflict(read); assertFalse(hasConflict); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenPendingUpdateByOther_thenNoConflict() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); ref.set(tx, 200); GammaTxn otherTx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(otherTx, LOCKMODE_NONE); boolean hasConflict = ref.hasReadConflict(read); assertFalse(hasConflict); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test @Ignore public void whenReadBiased() { } } LoadTest.java000066400000000000000000000070621174000617100404040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.stms.gamma.GammaTestUtils.assertLockMode; import static org.multiverse.stms.gamma.GammaTestUtils.assertSurplus; public class LoadTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenLongRef() { whenLongRef(LockMode.None, true); whenLongRef(LockMode.None, false); whenLongRef(LockMode.Read, true); whenLongRef(LockMode.Read, false); whenLongRef(LockMode.Write, true); whenLongRef(LockMode.Write, false); whenLongRef(LockMode.Exclusive, true); whenLongRef(LockMode.Exclusive, false); } public void whenLongRef(LockMode lockMode, boolean arriveNeeded) { long initialValue = 100; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); GammaTxn tx = stm.newDefaultTxn(); long initialVersion = ref.getVersion(); Tranlocal tranlocal = new Tranlocal(); boolean result = ref.load(tx,tranlocal, lockMode.asInt(), 1, arriveNeeded); assertTrue(result); assertSame(ref, tranlocal.owner); assertEquals(lockMode.asInt(), tranlocal.lockMode); assertEquals(initialVersion, tranlocal.version); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); if (arriveNeeded || lockMode.asInt() > LOCKMODE_NONE) { assertSurplus(ref, 1); assertTrue(tranlocal.hasDepartObligation); } else { assertSurplus(ref, 0); assertFalse(tranlocal.hasDepartObligation); } assertLockMode(ref, lockMode); } @Test public void whenRef() { whenRef(LockMode.None, true); whenRef(LockMode.None, false); whenRef(LockMode.Read, true); whenRef(LockMode.Read, false); whenRef(LockMode.Write, true); whenRef(LockMode.Write, false); whenRef(LockMode.Exclusive, true); whenRef(LockMode.Exclusive, false); } public void whenRef(LockMode lockMode, boolean arriveNeeded) { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = new Tranlocal(); boolean result = ref.load(tx,tranlocal, lockMode.asInt(), 1, arriveNeeded); assertTrue(result); assertSame(ref, tranlocal.owner); assertEquals(lockMode.asInt(), tranlocal.lockMode); assertEquals(initialVersion, tranlocal.version); assertSame(initialValue, tranlocal.ref_value); assertSame(initialValue, tranlocal.ref_oldValue); if (arriveNeeded || lockMode.asInt() > LOCKMODE_NONE) { assertSurplus(ref, 1); assertTrue(tranlocal.hasDepartObligation); } else { assertSurplus(ref, 0); assertFalse(tranlocal.hasDepartObligation); } assertLockMode(ref, lockMode); } } PrepareTest.java000066400000000000000000000122141174000617100411160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; public class PrepareTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test @Ignore public void whenNormalReadButLockedByOther() { } @Test public void whenNormalRead() { whenNormalRead(LockMode.None); whenNormalRead(LockMode.Read); whenNormalRead(LockMode.Write); whenNormalRead(LockMode.Exclusive); } public void whenNormalRead(LockMode lockMode) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .newTransactionFactory() .newTxn(); Tranlocal tranlocal = ref.openForRead(tx, lockMode.asInt()); boolean success = ref.prepare(tx, tranlocal); assertTrue(success); assertSame(ref, tranlocal.owner); assertEquals(lockMode.asInt(), tranlocal.getLockMode()); assertEquals(TRANLOCAL_READ, tranlocal.mode); assertFalse(tranlocal.isDirty); assertFalse(tranlocal.writeSkewCheck); assertNull(tranlocal.headCallable); } @Test public void whenNonDirtyWriteAndDirtyCheckEnabled() { whenNonDirtyWriteAndDirtyCheckEnabled(LockMode.None); whenNonDirtyWriteAndDirtyCheckEnabled(LockMode.Read); whenNonDirtyWriteAndDirtyCheckEnabled(LockMode.Write); whenNonDirtyWriteAndDirtyCheckEnabled(LockMode.Exclusive); } public void whenNonDirtyWriteAndDirtyCheckEnabled(LockMode lockMode) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .setDirtyCheckEnabled(true) .newTransactionFactory() .newTxn(); Tranlocal tranlocal = ref.openForWrite(tx, lockMode.asInt()); boolean success = ref.prepare(tx, tranlocal); assertTrue(success); assertSame(ref, tranlocal.owner); assertEquals(lockMode.asInt(), tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.mode); assertFalse(tranlocal.isDirty); assertFalse(tranlocal.writeSkewCheck); assertNull(tranlocal.headCallable); } @Test public void whenNormalDirtyWriteAndDirtyCheckEnabled() { whenNormalDirtyWrite(LockMode.None, true); whenNormalDirtyWrite(LockMode.Read, true); whenNormalDirtyWrite(LockMode.Write, true); whenNormalDirtyWrite(LockMode.Exclusive, true); } @Test public void whenNormalDirtyWriteAndDirtyCheckDisabled() { whenNormalDirtyWrite(LockMode.None, false); whenNormalDirtyWrite(LockMode.Read, false); whenNormalDirtyWrite(LockMode.Write, false); whenNormalDirtyWrite(LockMode.Exclusive, false); } public void whenNormalDirtyWrite(LockMode lockMode, boolean dirtyCheck) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .setDirtyCheckEnabled(dirtyCheck) .newTransactionFactory() .newTxn(); Tranlocal tranlocal = ref.openForWrite(tx, lockMode.asInt()); tranlocal.long_value++; boolean success = ref.prepare(tx, tranlocal); assertTrue(success); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.mode); assertTrue(tranlocal.isDirty); assertFalse(tranlocal.writeSkewCheck); assertNull(tranlocal.headCallable); } @Test public void whenNonDirtyWriteAndDirtyCheckDisabled() { whenNonDirtyWrite(LockMode.None); whenNonDirtyWrite(LockMode.Read); whenNonDirtyWrite(LockMode.Write); whenNonDirtyWrite(LockMode.Exclusive); } public void whenNonDirtyWrite(LockMode lockMode) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .setDirtyCheckEnabled(false) .newTransactionFactory() .newTxn(); Tranlocal tranlocal = ref.openForWrite(tx, lockMode.asInt()); boolean success = ref.prepare(tx, tranlocal); assertTrue(success); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.mode); assertTrue(tranlocal.isDirty); assertFalse(tranlocal.writeSkewCheck); assertNull(tranlocal.headCallable); } @Test @Ignore public void whenConstructed() { } @Test @Ignore public void whenCommuting() { } } RegisterChangeListenerTest.java000066400000000000000000000204751174000617100441300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.blocking.DefaultRetryLatch; import org.multiverse.api.blocking.RetryLatch; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaObjectPool; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.multiverse.TestUtils.getField; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class RegisterChangeListenerTest implements GammaConstants { private GammaStm stm; private GammaObjectPool pool; @Before public void setUp() { stm = new GammaStm(); pool = new GammaObjectPool(); clearThreadLocalTxn(); } @Test public void whenCommuting() { GammaTxnLong ref = new GammaTxnLong(stm, 0); LongFunction function = mock(LongFunction.class); GammaTxn tx = stm.newDefaultTxn(); ref.commute(tx, function); RetryLatch latch = new DefaultRetryLatch(); long listenerEra = latch.getEra(); Tranlocal tranlocal = tx.getRefTranlocal(ref); int result = ref.registerChangeListener(latch, tranlocal, pool, listenerEra); assertEquals(REGISTRATION_NONE, result); assertNull(getField(ref, "listeners")); assertFalse(latch.isOpen()); verifyZeroInteractions(function); } @Test public void whenInterestingWriteAlreadyHappened_thenLatchOpenedAndNoRegistration() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); Tranlocal write = ref.openForWrite(otherTx, LOCKMODE_NONE); write.long_value++; otherTx.commit(); RetryLatch latch = new DefaultRetryLatch(); long listenerEra = latch.getEra(); int result = ref.registerChangeListener(latch, read, pool, listenerEra); assertEquals(REGISTRATION_NOT_NEEDED, result); assertNull(getField(ref, "listeners")); assertTrue(latch.isOpen()); } @Test public void whenExclusiveLockAndNoConflict_thenRegistered() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); RetryLatch latch = new DefaultRetryLatch(); long listenerEra = latch.getEra(); int result = ref.registerChangeListener(latch, read, pool, listenerEra); assertEquals(REGISTRATION_DONE, result); assertSurplus(ref, 1); assertHasListeners(ref, latch); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, version, 10); assertFalse(latch.isOpen()); } @Test public void whenWriteLockAndNoConflict_thenRegistered() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); RetryLatch latch = new DefaultRetryLatch(); long listenerEra = latch.getEra(); int result = ref.registerChangeListener(latch, read, pool, listenerEra); assertEquals(REGISTRATION_DONE, result); assertSurplus(ref, 1); assertHasListeners(ref, latch); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, version, 10); assertFalse(latch.isOpen()); } @Test public void whenExclusiveLockAndInterestingChangeAlreadyHappened() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); ref.atomicIncrementAndGet(1); long version = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); RetryLatch latch = new DefaultRetryLatch(); long listenerEra = latch.getEra(); int result = ref.registerChangeListener(latch, read, pool, listenerEra); assertEquals(REGISTRATION_NOT_NEEDED, result); assertNull(getField(ref, "listeners")); assertTrue(latch.isOpen()); assertSurplus(ref, 1); assertHasNoListeners(ref); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, version, 1); } @Test public void wheWriteLockAndInterestingChangeAlreadyHappened() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); ref.atomicIncrementAndGet(1); long version = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); RetryLatch latch = new DefaultRetryLatch(); long listenerEra = latch.getEra(); int result = ref.registerChangeListener(latch, read, pool, listenerEra); assertEquals(REGISTRATION_NOT_NEEDED, result); assertNull(getField(ref, "listeners")); assertTrue(latch.isOpen()); assertSurplus(ref, 1); assertHasNoListeners(ref); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, version, 1); } @Test public void whenConstructed_thenNoRegistration() { GammaTxn tx = stm.newDefaultTxn(); GammaTxnLong ref = new GammaTxnLong(tx); Tranlocal read = tx.locate(ref); RetryLatch latch = new DefaultRetryLatch(); long listenerEra = latch.getEra(); int result = ref.registerChangeListener(latch, read, pool, listenerEra); assertEquals(REGISTRATION_NONE, result); assertHasNoListeners(ref); assertFalse(latch.isOpen()); } @Test public void whenFirstOne_thenRegistrationSuccessful() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); RetryLatch latch = new DefaultRetryLatch(); long listenerEra = latch.getEra(); int result = ref.registerChangeListener(latch, read, pool, listenerEra); assertEquals(REGISTRATION_DONE, result); Listeners listeners = (Listeners) getField(ref, "listeners"); assertNotNull(listeners); assertSame(latch, listeners.listener); assertNull(listeners.next); assertEquals(listenerEra, listeners.listenerEra); assertFalse(latch.isOpen()); } @Test public void whenSecondOne_thenListenerAddedToChain() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx1 = stm.newDefaultTxn(); Tranlocal read1 = ref.openForRead(tx1, LOCKMODE_NONE); RetryLatch latch1 = new DefaultRetryLatch(); long listenerEra1 = latch1.getEra(); ref.registerChangeListener(latch1, read1, pool, listenerEra1); GammaTxn tx2 = stm.newDefaultTxn(); Tranlocal read2 = ref.openForRead(tx2, LOCKMODE_NONE); RetryLatch latch2 = new DefaultRetryLatch(); long listenerEra2 = latch2.getEra(); int result = ref.registerChangeListener(latch2, read2, pool, listenerEra2); assertEquals(REGISTRATION_DONE, result); Listeners listeners = (Listeners) getField(ref, "listeners"); assertNotNull(listeners); assertSame(latch2, listeners.listener); assertEquals(listenerEra2, listeners.listenerEra); assertNotNull(listeners.next); assertSame(latch1, listeners.next.listener); assertEquals(listenerEra1, listeners.next.listenerEra); assertFalse(latch1.isOpen()); } } ReleaseAfterFailureTest.java000066400000000000000000000155141174000617100434000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.baseGammaTxnRef; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class ReleaseAfterFailureTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } // ================================ misc ========================== @Test public void writeBiased_whenCommuting() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); LongFunction function = mock(LongFunction.class); ref.commute(tx, function); Tranlocal tranlocal = tx.getRefTranlocal(ref); ref.releaseAfterFailure(tranlocal, tx.pool); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.headCallable); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void writeBiased_whenRead() { writeBiased_whenRead(LockMode.None); writeBiased_whenRead(LockMode.Read); writeBiased_whenRead(LockMode.Write); writeBiased_whenRead(LockMode.Exclusive); } public void writeBiased_whenRead(LockMode lockMode) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, lockMode.asInt()); ref.releaseAfterFailure(tranlocal, tx.pool); assertNull(tranlocal.owner); assertFalse(tranlocal.hasDepartObligation); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertSurplus(ref, 0); assertLockMode(ref, LockMode.None); assertWriteBiased(ref); assertReadonlyCount(ref, 0); } @Test public void writeBiased_whenWrite() { writeBiased_whenWrite(LockMode.None); writeBiased_whenWrite(LockMode.Read); writeBiased_whenWrite(LockMode.Write); writeBiased_whenWrite(LockMode.Exclusive); } public void writeBiased_whenWrite(LockMode lockMode) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForWrite(tx, lockMode.asInt()); tranlocal.isDirty = true; ref.releaseAfterFailure(tranlocal, tx.pool); assertNull(tranlocal.owner); assertFalse(tranlocal.hasDepartObligation); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertSurplus(ref, 0); assertLockMode(ref, LockMode.None); assertWriteBiased(ref); assertReadonlyCount(ref, 0); } // ========================= read biased ================================ @Test public void readBiased_whenCommuting() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); LongFunction function = mock(LongFunction.class); ref.commute(tx, function); Tranlocal tranlocal = tx.getRefTranlocal(ref); ref.releaseAfterFailure(tranlocal, tx.pool); assertRefHasNoLocks(ref); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.headCallable); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void readBiased_whenRead() { readBiased_whenRead(true,LockMode.None); readBiased_whenRead(true,LockMode.Read); readBiased_whenRead(true,LockMode.Write); readBiased_whenRead(true,LockMode.Exclusive); readBiased_whenRead(false,LockMode.None); readBiased_whenRead(false,LockMode.Read); readBiased_whenRead(false,LockMode.Write); readBiased_whenRead(false,LockMode.Exclusive); } public void readBiased_whenRead(boolean additionalSurplus, LockMode lockMode) { GammaTxnLong ref = makeReadBiased(new GammaTxnLong(stm)); if(additionalSurplus){ ref.arrive(1); } GammaTxn tx = newArrivingTransaction(stm); Tranlocal tranlocal = ref.openForRead(tx, lockMode.asInt()); ref.releaseAfterFailure(tranlocal, tx.pool); assertNull(tranlocal.owner); assertFalse(tranlocal.hasDepartObligation); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertSurplus(ref, 1); assertLockMode(ref, LockMode.None); assertReadBiased(ref); assertReadonlyCount(ref, 0); } @Test public void readBiased_whenWrite() { readBiased_whenWrite(false,LockMode.None); readBiased_whenWrite(false,LockMode.Read); readBiased_whenWrite(false,LockMode.Write); readBiased_whenWrite(false,LockMode.Exclusive); readBiased_whenWrite(true,LockMode.None); readBiased_whenWrite(true,LockMode.Read); readBiased_whenWrite(true,LockMode.Write); readBiased_whenWrite(true,LockMode.Exclusive); } public void readBiased_whenWrite(boolean additionalSurplus, LockMode lockMode) { GammaTxnLong ref = makeReadBiased(new GammaTxnLong(stm)); if(additionalSurplus){ ref.arrive(1); } GammaTxn tx = newArrivingTransaction(stm); Tranlocal tranlocal = ref.openForWrite(tx, lockMode.asInt()); tranlocal.isDirty = true; ref.releaseAfterFailure(tranlocal, tx.pool); assertNull(tranlocal.owner); assertFalse(tranlocal.hasDepartObligation); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertSurplus(ref, 1); assertLockMode(ref, LockMode.None); assertReadBiased(ref); assertReadonlyCount(ref, 0); } // ================================ misc ========================== @Test public void whenConstructing() { GammaTxn tx = stm.newDefaultTxn(); GammaTxnLong ref = new GammaTxnLong(tx, 0); Tranlocal tranlocal = tx.locate(ref); ref.releaseAfterFailure(tranlocal, tx.pool); assertNull(tranlocal.owner); assertFalse(tranlocal.hasDepartObligation); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertSurplus(ref, 1); assertLockMode(ref, LockMode.Exclusive); assertWriteBiased(ref); assertReadonlyCount(ref, 0); } } ReleaseAfterReadingTest.java000066400000000000000000000001471174000617100433560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; public class ReleaseAfterReadingTest { } ReleaseAfterUpdateTest.java000066400000000000000000000063261174000617100432340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; import static org.multiverse.stms.gamma.GammaTestUtils.makeReadBiased; import static org.multiverse.stms.gamma.GammaTestUtils.newArrivingTransaction; public class ReleaseAfterUpdateTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void writeBiased_whenNormalRef() { String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); GammaTxn tx = newArrivingTransaction(stm); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_EXCLUSIVE); tranlocal.isDirty = true; ref.releaseAfterUpdate(tranlocal, tx.pool); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertFalse(tranlocal.hasDepartObligation()); assertRefHasNoLocks(ref); } @Test public void writeBiased_whenLongRef() { GammaTxnLong ref = new GammaTxnLong(stm, 0); GammaTxn tx = newArrivingTransaction(stm); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_EXCLUSIVE); tranlocal.isDirty = true; ref.releaseAfterUpdate(tranlocal, tx.pool); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertFalse(tranlocal.hasDepartObligation()); assertRefHasNoLocks(ref); } @Test public void readBiased_whenNormalRef() { String initialValue = "initialValue"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); GammaTxn tx = newArrivingTransaction(stm); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_EXCLUSIVE); tranlocal.isDirty = true; ref.releaseAfterUpdate(tranlocal, tx.pool); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertFalse(tranlocal.hasDepartObligation()); assertRefHasNoLocks(ref); } @Test public void readBiased_whenLongRef() { GammaTxnLong ref = makeReadBiased(new GammaTxnLong(stm, 0)); GammaTxn tx = newArrivingTransaction(stm); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_EXCLUSIVE); tranlocal.isDirty = true; ref.releaseAfterUpdate(tranlocal, tx.pool); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertFalse(tranlocal.hasDepartObligation()); assertRefHasNoLocks(ref); } } TryLockAndCheckConflictTest.java000066400000000000000000001045171174000617100441620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/refspackage org.multiverse.stms.gamma.transactionalobjects.refs; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class TryLockAndCheckConflictTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } //conflicts @Test public void writeBiased_whenOtherHasLocked() { writeBiased_whenOtherHasLocked(LockMode.Read, LockMode.None, true); writeBiased_whenOtherHasLocked(LockMode.Read, LockMode.Read, true); writeBiased_whenOtherHasLocked(LockMode.Read, LockMode.Write, false); writeBiased_whenOtherHasLocked(LockMode.Read, LockMode.Exclusive, false); writeBiased_whenOtherHasLocked(LockMode.Write, LockMode.None, true); writeBiased_whenOtherHasLocked(LockMode.Write, LockMode.Read, false); writeBiased_whenOtherHasLocked(LockMode.Write, LockMode.Write, false); writeBiased_whenOtherHasLocked(LockMode.Write, LockMode.Exclusive, false); //write_whenOtherHasLocked(LockMode.Exclusive, LockMode.None, false); writeBiased_whenOtherHasLocked(LockMode.Exclusive, LockMode.Read, false); writeBiased_whenOtherHasLocked(LockMode.Exclusive, LockMode.Write, false); writeBiased_whenOtherHasLocked(LockMode.Exclusive, LockMode.Exclusive, false); } public void writeBiased_whenOtherHasLocked(LockMode otherLockMode, LockMode thisLockMode, boolean success) { GammaTxnLong ref = new GammaTxnLong(stm); //tx.arriveEnabled = arriveNeeded; Tranlocal tranlocal = ref.openForRead(stm.newDefaultTxn(), LOCKMODE_NONE); ref.openForRead(stm.newDefaultTxn(), otherLockMode.asInt()); //todo: null transaction boolean result = ref.tryLockAndCheckConflict(null, tranlocal, 1, thisLockMode.asInt()); assertEquals(success, result); //assertEquals(expectedLockMode.asInt(), tranlocal.getLockMode()); //assertLockMode(ref, expectedLockMode); //assertSurplus(ref, expectedSurplus); } @Test public void writeBiased_whenLockFreeAndArriveNeeded() { writeBiased(true, LockMode.None, LockMode.None, LockMode.None, 1); writeBiased(true, LockMode.None, LockMode.Read, LockMode.Read, 1); writeBiased(true, LockMode.None, LockMode.Write, LockMode.Write, 1); writeBiased(true, LockMode.None, LockMode.Exclusive, LockMode.Exclusive, 1); writeBiased(true, LockMode.Read, LockMode.None, LockMode.Read, 1); writeBiased(true, LockMode.Read, LockMode.Read, LockMode.Read, 1); writeBiased(true, LockMode.Read, LockMode.Write, LockMode.Write, 1); writeBiased(true, LockMode.Read, LockMode.Exclusive, LockMode.Exclusive, 1); writeBiased(true, LockMode.Write, LockMode.None, LockMode.Write, 1); writeBiased(true, LockMode.Write, LockMode.Read, LockMode.Write, 1); writeBiased(true, LockMode.Write, LockMode.Write, LockMode.Write, 1); writeBiased(true, LockMode.Write, LockMode.Exclusive, LockMode.Exclusive, 1); writeBiased(true, LockMode.Exclusive, LockMode.None, LockMode.Exclusive, 1); writeBiased(true, LockMode.Exclusive, LockMode.Read, LockMode.Exclusive, 1); writeBiased(true, LockMode.Exclusive, LockMode.Write, LockMode.Exclusive, 1); writeBiased(true, LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive, 1); } @Test public void writeBiased_whenLockFreeAndNoArriveNeeded() { writeBiased(false, LockMode.None, LockMode.None, LockMode.None, 0); writeBiased(false, LockMode.None, LockMode.Read, LockMode.Read, 1); writeBiased(false, LockMode.None, LockMode.Write, LockMode.Write, 1); writeBiased(false, LockMode.None, LockMode.Exclusive, LockMode.Exclusive, 1); writeBiased(false, LockMode.Read, LockMode.None, LockMode.Read, 1); writeBiased(false, LockMode.Read, LockMode.Read, LockMode.Read, 1); writeBiased(false, LockMode.Read, LockMode.Write, LockMode.Write, 1); writeBiased(false, LockMode.Read, LockMode.Exclusive, LockMode.Exclusive, 1); writeBiased(false, LockMode.Write, LockMode.None, LockMode.Write, 1); writeBiased(false, LockMode.Write, LockMode.Read, LockMode.Write, 1); writeBiased(false, LockMode.Write, LockMode.Write, LockMode.Write, 1); writeBiased(false, LockMode.Write, LockMode.Exclusive, LockMode.Exclusive, 1); writeBiased(false, LockMode.Exclusive, LockMode.None, LockMode.Exclusive, 1); writeBiased(false, LockMode.Exclusive, LockMode.Read, LockMode.Exclusive, 1); writeBiased(false, LockMode.Exclusive, LockMode.Write, LockMode.Exclusive, 1); writeBiased(false, LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive, 1); } public void writeBiased(boolean arriveNeeded, LockMode firstLockMode, LockMode secondLockMode, LockMode expectedLockMode, int expectedSurplus) { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); tx.richmansMansConflictScan = arriveNeeded; Tranlocal tranlocal = ref.openForRead(tx, firstLockMode.asInt()); boolean result = ref.tryLockAndCheckConflict(tx, tranlocal, 1, secondLockMode.asInt()); assertTrue(result); assertEquals(expectedLockMode.asInt(), tranlocal.getLockMode()); assertLockMode(ref, expectedLockMode); assertSurplus(ref, expectedSurplus); } @Test public void readBiased_whenLockFree() { readBiased(LockMode.None, LockMode.None, LockMode.None); readBiased(LockMode.None, LockMode.Read, LockMode.Read); readBiased(LockMode.None, LockMode.Write, LockMode.Write); readBiased(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); readBiased(LockMode.Read, LockMode.None, LockMode.Read); readBiased(LockMode.Read, LockMode.Read, LockMode.Read); readBiased(LockMode.Read, LockMode.Write, LockMode.Write); readBiased(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); readBiased(LockMode.Write, LockMode.None, LockMode.Write); readBiased(LockMode.Write, LockMode.Read, LockMode.Write); readBiased(LockMode.Write, LockMode.Write, LockMode.Write); readBiased(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); readBiased(LockMode.Exclusive, LockMode.None, LockMode.Exclusive); readBiased(LockMode.Exclusive, LockMode.Read, LockMode.Exclusive); readBiased(LockMode.Exclusive, LockMode.Write, LockMode.Exclusive); readBiased(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void readBiased(LockMode firstLockMode, LockMode secondLockMode, LockMode expectedLockMode) { GammaTxnLong ref = makeReadBiased(new GammaTxnLong(stm)); GammaTxn tx = stm.newDefaultTxn(); tx.richmansMansConflictScan = true; Tranlocal tranlocal = ref.openForRead(tx, firstLockMode.asInt()); boolean result = ref.tryLockAndCheckConflict(tx, tranlocal, 1, secondLockMode.asInt()); assertTrue(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(expectedLockMode.asInt(), tranlocal.getLockMode()); assertLockMode(ref, expectedLockMode); assertSurplus(ref, 1); } @Test @Ignore public void lockNotFree() { } // ===================== lock free ================================== @Test public void lockFree_tryNoneLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_NONE); assertTrue(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 0); } @Test public void lockFree_tryReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockFree_tryWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockFree_tryExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } // ==================== lock upgrade ======================== @Test public void lockUpgrade_readLockAcquired_tryNoLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_NONE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockUpgrade_readLockAcquired_tryReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockUpgrade_readLockAcquired_otherTransactionAlreadyAcquiredReadLock_tryReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 2); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 2); } @Test public void lockUpgrade_readLockAcquired_tryWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockUpgrade_readLockAcquired_otherTransactionAlsoAcquiredReadLock_tryWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertFalse(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 2); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 2); } @Test public void lockUpgrade_readLockAcquired_tryExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockUpgrade_readLockAcquired_otherTransactionAlsoAcquiredReadLock_tryExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertFalse(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 2); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 2); } @Test public void lockUpgrade_writeLockAcquired_tryNoLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_WRITE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_NONE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockUpgrade_writeLockAcquired_tryReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_WRITE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockAcquired_writeLockAcquired_tryWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_WRITE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockAcquired_writeLockAcquired_tryExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_WRITE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockUpgrade_exclusiveLockAcquired_tryNoLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_EXCLUSIVE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_NONE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockUpgrade_exclusiveLockAcquired_tryReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_EXCLUSIVE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockAcquired_exclusiveLockAcquired_tryWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_EXCLUSIVE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockAcquired_exclusiveLockAcquired_tryExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_EXCLUSIVE); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } // ===================== lock free ================================== @Test public void lockFreeButConflictingUpdate_tryNoneLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); ref.atomicIncrementAndGet(1); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_NONE); assertTrue(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void lockFreeButConflictingUpdate__tryReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); ref.atomicIncrementAndGet(1); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void lockFreeButConflictingUpdate__tryWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); ref.atomicIncrementAndGet(1); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } @Test public void lockFreeButConflictingUpdate__tryExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); ref.atomicIncrementAndGet(1); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); } // ===================== lock not free ================================== @Test public void lockNotFree_readLockAcquired_acquireNone() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_NONE); assertTrue(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_readLockAcquired_acquireReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertTrue(result); assertTrue(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 2); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 2); } @Test public void lockNotFree_readLockAcquired_acquireWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_readLockAcquired_acquireExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_writeLockAcquired_acquireNoLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_NONE); assertTrue(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_writeLockAcquired_acquireReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_writeLockAcquired_acquireWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_writeLockAcquired_acquireExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_exclusiveLockAcquired_acquireNoLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_NONE); assertTrue(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_exclusiveLockAcquired_acquireReadLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_READ); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_exclusiveLockAcquired_acquireWriteLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_WRITE); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } @Test public void lockNotFree_exclusiveLockAcquired_acquireExclusiveLock() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); boolean result = ref.tryLockAndCheckConflict(tx,tranlocal, 1, LOCKMODE_EXCLUSIVE); assertFalse(result); assertFalse(tranlocal.hasDepartObligation()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 1); } } 000077500000000000000000000000001174000617100365475ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongGammaTxnLong_alterAndGet1Test.java000066400000000000000000000173131174000617100451460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.api.functions.Functions.identityLongFunction; import static org.multiverse.api.functions.Functions.incLongFunction; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_alterAndGet1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_alterAndGet1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenActiveTransactionAvailableAndNullFunction_thenNullPointerException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.alterAndGet(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); } @Test public void whenFunctionCausesException() { GammaTxnLong ref = new GammaTxnLong(stm); LongFunction function = mock(LongFunction.class); RuntimeException ex = new RuntimeException(); when(function.call(anyLong())).thenThrow(ex); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.alterAndGet(function); fail(); } catch (RuntimeException found) { assertSame(ex, found); } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); } @Test public void whenActiveTransactionAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); LongFunction function = Functions.incLongFunction(); ref.alterAndGet(function); assertEquals(initialValue + 1, ref.get()); assertVersionAndValue(ref, initialVersion, initialValue); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenActiveTransactionAvailableButNoChange_thenNoWrite() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); LongFunction function = identityLongFunction(); ref.alterAndGet(function); assertEquals(initialValue, ref.get()); assertVersionAndValue(ref, initialVersion, initialValue); tx.commit(); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); setThreadLocalTxn(tx); try { ref.alterAndGet(function); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransactionAvailable_thenNoTransactionFoundException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); try { ref.alterAndGet(function); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); try { ref.alterAndGet(function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = incLongFunction(1); try { ref.alterAndGet(function); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable_thenTheyAreNotified() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.alterAndGet(Functions.incLongFunction()); tx.commit(); joinAll(thread); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnLong_alterAndGet2Test.java000066400000000000000000000204461174000617100451500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_alterAndGet2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_alterAndGet2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenNullTransaction_thenNullPointerException() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(null, function); fail(); } catch (NullPointerException expected) { } verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullFunction_thenNullPointerException() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); try { ref.alterAndGet(tx, null); fail(); } catch (NullPointerException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCommittedTransaction_thenDeadTxnException() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(tx, function); fail(); } catch (PreparedTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransaction() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(tx, function); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenFunctionCausesException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); RuntimeException ex = new RuntimeException(); when(function.call(anyLong())).thenThrow(ex); GammaTxn tx = transactionFactory.newTxn(); try { ref.alterAndGet(tx, function); fail(); } catch (RuntimeException found) { assertSame(ex, found); } assertRefHasNoLocks(ref); assertIsAborted(tx); assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPrivatizedByOther() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long version = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(tx, function); fail(); } catch (ReadWriteConflict expected) { } assertSurplus(ref, 1); assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, version, initialValue); } @Test public void whenEnsuredByOther_thenOperationSucceedsButCommitFails() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); LongFunction function = Functions.incLongFunction(1); ref.alterAndGet(tx, function); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertIsActive(otherTx); assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenListenersAvailable_thenTheyAreNotified() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); ref.alterAndGet(tx, Functions.incLongFunction()); tx.commit(); joinAll(thread); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenSuccess() { LongFunction function = new LongFunction() { @Override public long call(long current) { return current + 1; } }; GammaTxnLong ref = new GammaTxnLong(stm, 100); GammaTxn tx = transactionFactory.newTxn(); long result = ref.alterAndGet(tx, function); tx.commit(); assertEquals(101, ref.atomicGet()); assertEquals(101, result); } } GammaTxnLong_atomicAlterAndGetTest.java000066400000000000000000000136521174000617100462240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.api.functions.Functions.identityLongFunction; import static org.multiverse.api.functions.Functions.incLongFunction; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_atomicAlterAndGetTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenFunctionCausesException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); RuntimeException ex = new RuntimeException(); when(function.call(anyLong())).thenThrow(ex); try { ref.atomicAlterAndGet(function); fail(); } catch (RuntimeException found) { assertSame(ex, found); } assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertNull(getThreadLocalTxn()); } @Test public void whenNullFunction_thenNullPointerException() { int initialValue = 5; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.atomicAlterAndGet(null); fail(); } catch (NullPointerException expected) { } assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenSuccess() { int initialValue = 5; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); long result = ref.atomicAlterAndGet(function); assertEquals(initialValue + 1, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenNoChange() { int initialValue = 5; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long version = ref.getVersion(); LongFunction function = identityLongFunction(); long result = ref.atomicAlterAndGet(function); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, version, initialValue); } @Test public void whenActiveTransactionAvailable_thenIgnored() { long initialValue = 5; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(tx, 100); LongFunction function = incLongFunction(1); long result = ref.atomicAlterAndGet(function); assertEquals(initialValue + 1, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); } @Test public void whenEnsuredByOther_thenLockedException() { int initialValue = 5; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); LongFunction function = mock(LongFunction.class); try { ref.atomicAlterAndGet(function); fail(); } catch (LockedException expected) { } verifyZeroInteractions(function); assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPrivatizedByOther() { int initialValue = 5; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); LongFunction function = mock(LongFunction.class); try { ref.atomicAlterAndGet(function); fail(); } catch (LockedException expected) { } verifyZeroInteractions(function); assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, otherTx); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); ref.atomicAlterAndGet(Functions.incLongFunction()); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnLong_atomicCompareAndSetTest.java000066400000000000000000000113421174000617100465510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_atomicCompareAndSetTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenPrivatizedByOther_thenLockedException() { long initialValue = 1; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); long newValue = 2; try { ref.atomicCompareAndSet(initialValue, newValue); fail(); } catch (LockedException expected) { } assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOther_thenLockedException() { long initialValue = 1; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); long newValue = 2; try { ref.atomicCompareAndSet(initialValue, newValue); fail(); } catch (LockedException expected) { } assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenActiveTransactionAvailable_thenIgnored() { int initialValue = 1; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(initialValue + 100); long newValue = 2; boolean result = ref.atomicCompareAndSet(initialValue, newValue); assertTrue(result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenExpectedValueFoundAndUpdateIsSame() { long initialValue = 1; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); boolean result = ref.atomicCompareAndSet(initialValue, initialValue); assertTrue(result); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertSurplus(ref, 0); } @Test public void whenExpectedValueFound() { long initialValue = 1; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long newValue = initialValue + 1; boolean result = ref.atomicCompareAndSet(initialValue, newValue); assertTrue(result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenExpectedValueNotFound() { int initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); boolean result = ref.atomicCompareAndSet(1, 3); assertFalse(result); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertSurplus(ref, 0); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long newValue = initialValue + 1; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, newValue); thread.start(); sleepMs(500); ref.atomicCompareAndSet(initialValue, newValue); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } } GammaTxnLong_atomicGetAndAlterTest.java000066400000000000000000000132701174000617100462200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.api.functions.Functions.identityLongFunction; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_atomicGetAndAlterTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenSuccess() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(); long result = ref.atomicGetAndAlter(function); assertEquals(2, result); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenNullFunction_thenNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.atomicGetAndAlter(null); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertWriteBiased(ref); } @Test public void whenActiveTransactionAvailable_thenIgnored() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(10); LongFunction function = Functions.incLongFunction(); long result = ref.atomicGetAndAlter(function); tx.abort(); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenPrivatizedByOther_thenLockedException() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); LongFunction function = mock(LongFunction.class); try { ref.atomicGetAndAlter(function); fail(); } catch (LockedException expected) { } verifyZeroInteractions(function); assertRefHasExclusiveLock(ref, otherTx); assertWriteBiased(ref); assertSurplus(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOtherAndNothingDirty_thenLockedException() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); try { ref.atomicGetAndAlter(identityLongFunction()); fail(); } catch (LockedException expected) { } assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOther_thenLockedException() { int initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); LongFunction function = mock(LongFunction.class); try { ref.atomicGetAndAlter(function); fail(); } catch (LockedException expected) { } verifyZeroInteractions(function); assertRefHasWriteLock(ref, otherTx); assertWriteBiased(ref); assertSurplus(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); long result = ref.atomicGetAndAlter(Functions.incLongFunction()); assertEquals(result, initialValue); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnLong_atomicGetAndIncrementTest.java000066400000000000000000000102061174000617100470710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_atomicGetAndIncrementTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenSuccess() { int initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long result = ref.atomicGetAndIncrement(1); assertEquals(initialValue, result); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertNull(getThreadLocalTxn()); } @Test public void whenNoChange() { int initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long result = ref.atomicGetAndIncrement(0); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenActiveTransactionAvailable_thenIgnored() { int initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(10); long result = ref.atomicGetAndIncrement(1); assertEquals(initialValue, result); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertSurplus(ref, 0); assertSame(tx, getThreadLocalTxn()); assertIsActive(tx); } @Test public void whenPrivatizedByOther_thenLockedException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.atomicCompareAndSet(0, 1); fail(); } catch (LockedException expected) { } assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOther_thenLockedException() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); try { ref.atomicCompareAndSet(initialValue, 20); fail(); } catch (LockedException expected) { } assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, 10); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); int amount = 1; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + amount); thread.start(); sleepMs(500); long result = ref.atomicGetAndIncrement(amount); assertEquals(result, initialValue); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); } } GammaTxnLong_atomicGetAndSetTest.java000066400000000000000000000102661174000617100457060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_atomicGetAndSetTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenSuccess() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); int newValue = 10; long result = ref.atomicGetAndSet(newValue); assertEquals(initialValue, result); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenActiveTransactionAvailable_thenIgnored() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); long newValue = 10; long result = ref.atomicGetAndSet(newValue); assertIsActive(tx); assert (tx.getRefTranlocal(ref) == null); assertEquals(initialValue, result); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenLockedByOther_thenLockedException() { whenLockedByOther_thenLockedException(LockMode.Read); whenLockedByOther_thenLockedException(LockMode.Write); whenLockedByOther_thenLockedException(LockMode.Exclusive); } public void whenLockedByOther_thenLockedException(LockMode lockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, lockMode); long orecValue = ref.orec; try { ref.atomicGetAndSet(1); fail(); } catch (LockedException expected) { } assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoChange_thenNoCommit() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long result = ref.atomicGetAndSet(initialValue); assertEquals(initialValue, result); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long newValue = initialValue + 1; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, newValue); thread.start(); sleepMs(500); long result = ref.atomicGetAndSet(newValue); assertEquals(initialValue, result); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } } GammaTxnLong_atomicGetTest.java000066400000000000000000000076201174000617100446070ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_atomicGetTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test(expected = LockedException.class) public void whenUnconstructed() { GammaTxn tx = stm.newDefaultTxn(); GammaTxnLong ref = new GammaTxnLong(tx); ref.atomicGet(); } @Test public void whenActiveTransactionAvailable_thenIgnored() { GammaTxnLong ref = new GammaTxnLong(stm, 100); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(10); assertEquals(100, ref.atomicGet()); assertSame(tx, getThreadLocalTxn()); } @Test public void whenUpdatedBiasedOnUnlocked() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long result = ref.atomicGet(); assertEquals(100, result); //assertUpdateBiased(ref); } @Test public void whenUpdateBiasedAndPrivatizedByOther_thenLockedException() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.atomicGet(); fail(); } catch (LockedException ex) { } assertSurplus(ref, 1); assertWriteBiased(ref); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, version, 100); } @Test public void whenUpdateBiasedAndEnsuredByOther() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); long result = ref.atomicGet(); assertEquals(100, result); assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertWriteBiased(ref); assertVersionAndValue(ref, version, 100); } @Test public void whenReadBiasedAndUnlocked() { GammaTxnLong ref = makeReadBiased(new GammaTxnLong(stm, 100)); long result = ref.atomicGet(); assertEquals(100, result); assertReadBiased(ref); } @Test public void whenReadBiasedAndPrivatizedByOther_thenLockedException() { GammaTxnLong ref = makeReadBiased(new GammaTxnLong(stm, 100)); long version = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); long orecValue = ref.orec; try { ref.atomicGet(); fail(); } catch (LockedException ex) { } assertOrecValue(ref, orecValue); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, version, 100); } @Test public void whenReadBiasedAndEnsuredByOther_thenLockedException() { GammaTxnLong ref = makeReadBiased(new GammaTxnLong(stm, 100)); long version = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); long orecValue = ref.orec; try { ref.atomicGet(); fail(); } catch (LockedException expected) { } assertOrecValue(ref,orecValue); assertVersionAndValue(ref, version, 100); } } GammaTxnLong_atomicIncrementAndGetTest.java000066400000000000000000000103041174000617100470700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_atomicIncrementAndGetTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenSuccess() { int initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); int amount = 10; long result = ref.atomicIncrementAndGet(amount); assertEquals(initialValue + amount, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); assertNull(getThreadLocalTxn()); } @Test public void whenActiveTransactionAvailable_thenIgnored() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(tx, 1000); long amount = 1; long result = ref.atomicIncrementAndGet(amount); assertEquals(initialValue + amount, result); assertRefHasNoLocks(ref); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); } @Test public void whenNoChange() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long result = ref.atomicIncrementAndGet(0); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPrivatizedByOther_thenLockedException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.atomicIncrementAndGet(1); fail(); } catch (LockedException expected) { } assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOtherAndChange_thenLockedException() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); try { ref.atomicIncrementAndGet(1); fail(); } catch (LockedException expected) { } assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long newValue = initialValue + 1; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, newValue); thread.start(); sleepMs(500); ref.atomicIncrementAndGet(1); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } } GammaTxnLong_atomicSetTest.java000066400000000000000000000104251174000617100446200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_atomicSetTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenSuccess() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); int newValue = 10; long result = ref.atomicSet(newValue); assertEquals(newValue, result); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenActiveTransactionAvailable_thenIgnored() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); long newValue = 10; long result = ref.atomicSet(newValue); assertIsActive(tx); assert (tx.getRefTranlocal(ref) == null); assertEquals(newValue, result); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenPrivatizedByOther_thenLockedException() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.atomicSet(1); fail(); } catch (LockedException expected) { } assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOtherAndChange_thenLockedException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); try { ref.atomicSet(1); fail(); } catch (LockedException expected) { } assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoChange_thenNoCommit() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long result = ref.atomicSet(initialValue); assertEquals(initialValue, result); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long newValue = initialValue + 1; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, newValue); thread.start(); sleepMs(500); long result = ref.atomicSet(newValue); assertEquals(newValue, result); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } } GammaTxnLong_await1WithPredicateTest.java000066400000000000000000000157431174000617100465430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.SomeUncheckedException; import org.multiverse.api.exceptions.*; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.predicates.LongPredicate; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.api.predicates.LongPredicate.newEqualsPredicate; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnLong_await1WithPredicateTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenPredicateEvaluatesToFalse() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); try { ref.await(newEqualsPredicate(initialValue + 1)); fail(); } catch (RetryError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPredicateReturnsTrue() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); ref.await(newEqualsPredicate(initialValue)); assertIsActive(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPredicateThrowsException_thenTransactionAborted() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongPredicate predicate = mock(LongPredicate.class); when(predicate.evaluate(initialValue)).thenThrow(new SomeUncheckedException()); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.await(predicate); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullPredicate_thenTransactionAbortedAndNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.await(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(predicate); fail(); } catch (TxnMandatoryException expected) { } verifyZeroInteractions(predicate); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.prepare(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(predicate); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(predicate); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAborted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.abort(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(predicate); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); verifyZeroInteractions(predicate); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionCommitted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.commit(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(predicate); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); verifyZeroInteractions(predicate); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenSomeWaitingNeeded() { int initialValue = 0; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread1 = new TxnLongAwaitThread(ref, 10); TxnLongAwaitThread thread2 = new TxnLongAwaitThread(ref, 20); thread1.start(); thread2.start(); sleepMs(1000); assertAlive(thread1, thread2); ref.atomicSet(10); assertEventuallyNotAlive(thread1); assertNothingThrown(thread1); assertAlive(thread2); ref.atomicSet(20); assertEventuallyNotAlive(thread2); assertNothingThrown(thread2); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 2, 20); } } GammaTxnLong_await2WithPredicateTest.java000066400000000000000000000162771174000617100465470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.SomeUncheckedException; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.RetryError; import org.multiverse.api.predicates.LongPredicate; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.predicates.LongPredicate.newEqualsPredicate; import static org.multiverse.api.predicates.LongPredicate.newLargerThanOrEqualsPredicate; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnLong_await2WithPredicateTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenPredicateEvaluatesToFalse() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .newTransactionFactory() .newTxn(); try { ref.await(tx, newEqualsPredicate(initialValue + 1)); fail(); } catch (RetryError expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPredicateReturnsTrue() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.await(tx, newEqualsPredicate(initialValue)); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPredicateThrowsException_thenTransactionAborted() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongPredicate predicate = mock(LongPredicate.class); when(predicate.evaluate(initialValue)).thenThrow(new SomeUncheckedException()); GammaTxn tx = stm.newDefaultTxn(); try { ref.await(tx, predicate); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullPredicate_thenTransactionAbortedAndNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); try { ref.await(tx, null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullTransaction_thenNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(null, predicate); fail(); } catch (NullPointerException expected) { } verifyZeroInteractions(predicate); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(tx, predicate); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(predicate); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAborted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(tx, predicate); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(predicate); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionCommitted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(tx, predicate); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); verifyZeroInteractions(predicate); assertVersionAndValue(ref, initialVersion, initialValue); } @Test @Ignore public void whenSomeWaitingNeeded() { int initialValue = 0; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); AwaitThread thread1 = new AwaitThread(0, 10, ref); AwaitThread thread2 = new AwaitThread(1, 20, ref); thread1.start(); thread2.start(); sleepMs(1000); assertAlive(thread1, thread2); ref.atomicSet(10); assertEventuallyNotAlive(thread1); assertNothingThrown(thread1); assertAlive(thread2); ref.atomicSet(20); assertEventuallyNotAlive(thread2); assertNothingThrown(thread2); assertVersionAndValue(ref, initialVersion + 2, 20); } public class AwaitThread extends TestThread { private long minimumValue; private TxnLong ref; public AwaitThread(int id, long minimumValue, TxnLong ref) { super("AwaitThread-" + id); this.minimumValue = minimumValue; this.ref = ref; } @Override public void doRun() throws Exception { ref.getStm().getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.await(tx, newLargerThanOrEqualsPredicate(minimumValue)); } }); } } } GammaTxnLong_await2WithValueTest.java000066400000000000000000000052251174000617100457120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.RetryNotAllowedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class GammaTxnLong_await2WithValueTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test @Ignore public void whenSomeWaitingNeeded() { } @Test public void whenNullTransaction_thenNullPointerException() { GammaTxnLong ref = new GammaTxnLong(stm); try { ref.await(null, 10); fail(); } catch (NullPointerException expected) { } } @Test public void whenPreparedTransaction_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); try { ref.await(tx, 10); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); } @Test public void whenAbortedTransaction_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.await(tx, 10); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } @Test public void whenCommittedTransaction_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.await(tx, 10); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } @Test public void whenBlockingNotAllowed_thenRetryNotAllowedException() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = stm.newTxnFactoryBuilder() .setBlockingAllowed(false) .setSpeculative(false) .newTransactionFactory() .newTxn(); try { ref.await(tx, 10); fail(); } catch (RetryNotAllowedException expected) { } assertIsAborted(tx); } } GammaTxnLong_commute1Test.java000066400000000000000000000263621174000617100444310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_commute1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_commute1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenActiveTransactionAvailable() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); LongFunction function = Functions.incLongFunction(1); ref.commute(function); Tranlocal commuting = tx.getRefTranlocal(ref); assertNotNull(commuting); assertTrue(commuting.isCommuting()); assertFalse(commuting.isRead()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertEquals(0, commuting.long_value); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); tx.commit(); assertEquals(1, ref.atomicGet()); assertIsCommitted(tx); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); } @Test public void whenActiveTransactionAvailableAndNoChange() { GammaTxnLong ref = new GammaTxnLong(stm); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); LongFunction function = Functions.identityLongFunction(); ref.commute(function); Tranlocal commuting = tx.getRefTranlocal(ref); assertNotNull(commuting); assertTrue(commuting.isCommuting()); assertFalse(commuting.isRead()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertEquals(0, commuting.long_value); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); tx.commit(); assertEquals(0, ref.atomicGet()); assertVersionAndValue(ref, version, 0); assertIsCommitted(tx); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); } @Test public void whenActiveTransactionAvailableAndNullFunction_thenNullPointerException() { GammaTxnLong ref = new GammaTxnLong(stm); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.commute(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, version, 0); } @Test public void whenNoTransactionAvailable_thenNoTransactionFoundException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); try { ref.commute(function); fail(); } catch (TxnMandatoryException expected) { } assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); LongFunction function = Functions.incLongFunction(1); try { ref.commute(function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); LongFunction function = Functions.incLongFunction(1); try { ref.commute(function); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 2); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.prepare(); LongFunction function = Functions.incLongFunction(1); try { ref.commute(function); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, version, 2); assertEquals(2, ref.atomicGet()); } @Test public void whenAlreadyEnsuredBySelf_thenNoCommute() { GammaTxnLong ref = new GammaTxnLong(stm, 2); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); LongFunction function = Functions.incLongFunction(1); ref.commute(function); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertFalse(tranlocal.isCommuting()); assertEquals(3, tranlocal.long_value); assertIsActive(tx); assertRefHasWriteLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); tx.commit(); assertSurplus(ref, 0); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertSame(tx, getThreadLocalTxn()); assertEquals(3, ref.atomicGet()); } @Test public void whenAlreadyPrivatizedBySelf_thenNoCommute() { GammaTxnLong ref = new GammaTxnLong(stm, 2); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); LongFunction function = Functions.incLongFunction(1); ref.commute(function); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertFalse(tranlocal.isCommuting()); assertEquals(3, tranlocal.long_value); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertSame(tx, getThreadLocalTxn()); assertEquals(3, ref.atomicGet()); assertSurplus(ref, 0); } @Test @Ignore public void whenReadLockAcquiredByOther() { } @Test public void whenWriteLockAcquiredByOther_thenCommuteSucceedsButCommitFails() { GammaTxnLong ref = new GammaTxnLong(stm, 2); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); LongFunction function = Functions.incLongFunction(1); ref.commute(function); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertTrue(tranlocal.isCommuting()); assertHasCommutingFunctions(tranlocal, function); assertIsActive(tx); assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, version, 2); assertSurplus(ref, 1); } @Test public void whenExclusiveLockByOther_thenCommuteSucceedsButCommitFails() { GammaTxnLong ref = new GammaTxnLong(stm, 2); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); LongFunction function = Functions.incLongFunction(1); ref.commute(function); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertTrue(tranlocal.isCommuting()); assertHasCommutingFunctions(tranlocal, function); assertIsActive(tx); assertRefHasExclusiveLock(ref, otherTx); assertSurplus(ref, 1); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, version, 2); assertSurplus(ref, 1); } } GammaTxnLong_commute2Test.java000066400000000000000000000323671174000617100444340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.LOCKMODE_NONE; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_commute2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_commute2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenCommuteFunctionCausesProblems_thenNoProblemsSinceCommuteFunctionNotEvaluatedImmediately() { GammaTxnLong ref = new GammaTxnLong(stm); LongFunction function = mock(LongFunction.class); RuntimeException ex = new RuntimeException(); when(function.call(anyLong())).thenThrow(ex); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, function); assertHasCommutingFunctions(tx.getRefTranlocal(ref), function); assertIsActive(tx); assertEquals(0, ref.atomicGet()); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertNull(getThreadLocalTxn()); } @Test public void whenExclusiveLockAcquiredByOther_thenCommuteSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, Functions.incLongFunction()); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertSurplus(ref, 1); assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenWriteLockAcquiredByOther_thenCommuteSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, Functions.incLongFunction()); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenReadLockAcquiredByOther_thenCommuteSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, Functions.incLongFunction()); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertSurplus(ref, 1); assertRefHasReadLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertTrue(commute.isCommuting()); assertEquals(0, commute.long_value); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenNoChange() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.identityLongFunction(); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertTrue(commute.isCommuting()); assertEquals(0, commute.long_value); tx.commit(); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNormalTransactionUsed() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); Txn tx = transactionFactory.newTxn(); ref.commute(tx, function); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenAlreadyOpenedForRead() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); GammaTxn tx = transactionFactory.newTxn(); ref.get(tx); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertFalse(commute.isCommuting()); assertEquals(11, commute.long_value); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenAlreadyOpenedForConstruction() { LongFunction function = Functions.incLongFunction(1); GammaTxn tx = transactionFactory.newTxn(); GammaTxnLong ref = new GammaTxnLong(tx); ref.openForConstruction(tx); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertFalse(commute.isCommuting()); assertEquals(1, commute.long_value); tx.commit(); assertEquals(1, ref.atomicGet()); } @Test public void whenAlreadyOpenedForWrite() { GammaTxnLong ref = new GammaTxnLong(stm, 10); LongFunction function = Functions.incLongFunction(); GammaTxn tx = transactionFactory.newTxn(); ref.set(tx, 11); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertFalse(commute.isCommuting()); assertEquals(12, commute.long_value); tx.commit(); assertEquals(12, ref.atomicGet()); } @Test public void whenAlreadyCommuting() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function1 = Functions.incLongFunction(); LongFunction function2 = Functions.incLongFunction(); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, function1); ref.commute(tx, function2); Tranlocal commute = tx.getRefTranlocal(ref); assertTrue(commute.isCommuting()); assertEquals(0, commute.long_value); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 2); } @Test public void whenNullFunction_thenNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); try { ref.commute(tx, null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullTransaction_thenNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); try { ref.commute((Txn) null, function); fail(); } catch (NullPointerException expected) { } verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAborted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.commute(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionCommitted_thenDeadTxnException() { long initialValue = 20; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.commute(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.commute(tx, function); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void fullExample() { assumeTrue(!(transactionFactory.newTxn() instanceof FatMonoGammaTxn)); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); GammaTxnLong ref2 = new GammaTxnLong(stm, 10); GammaTxn tx1 = transactionFactory.newTxn(); ref1.openForWrite(tx1, LOCKMODE_NONE).long_value++; ref2.commute(tx1, Functions.incLongFunction(1)); GammaTxn tx2 = transactionFactory.newTxn(); ref2.openForWrite(tx2, LOCKMODE_NONE).long_value++; tx2.commit(); tx1.commit(); assertIsCommitted(tx1); assertEquals(11, ref1.atomicGet()); assertEquals(12, ref2.atomicGet()); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, Functions.incLongFunction()); tx.commit(); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnLong_consistentLoadStressTest.java000066400000000000000000000066561174000617100471000ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.concurrent.atomic.AtomicLong; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; public class GammaTxnLong_consistentLoadStressTest implements GammaConstants { private GammaStm stm; private volatile boolean stop; private GammaTxnLong ref; private final AtomicLong inconsistencyCount = new AtomicLong(); @Before public void setUp() { stm = new GammaStm(); stop = false; ref = new GammaTxnLong(stm, VERSION_UNCOMMITTED + 1); } @Test public void test() { int readThreadCount = 10; ReadThread[] readThreads = new ReadThread[readThreadCount]; for (int k = 0; k < readThreads.length; k++) { readThreads[k] = new ReadThread(k); } int writerCount = 2; UpdateThread[] updateThreads = new UpdateThread[writerCount]; for (int k = 0; k < updateThreads.length; k++) { updateThreads[k] = new UpdateThread(k); } startAll(readThreads); startAll(updateThreads); sleepMs(30 * 1000); stop = true; joinAll(readThreads); joinAll(writerCount); assertEquals(0, inconsistencyCount.get()); } class ReadThread extends TestThread { private final GammaTxn tx = stm.newDefaultTxn(); public ReadThread(int id) { super("ReadThread-" + id); } @Override public void doRun() throws Exception { Tranlocal tranlocal = new Tranlocal(); int k = 0; while (!stop) { boolean success = ref.load(tx, tranlocal, LOCKMODE_NONE, 100, true); if (success) { if (tranlocal.version != tranlocal.long_value) { inconsistencyCount.incrementAndGet(); System.out.printf("Inconsistency detected, version %s and value %s\n", tranlocal.version, tranlocal.long_value); } if (tranlocal.hasDepartObligation) { ref.departAfterReading(); } } k++; if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class UpdateThread extends TestThread { public UpdateThread(int id) { super("UpdateThread-" + id); } @Override public void doRun() throws Exception { int k = 0; while (!stop) { int arriveStatus = ref.arriveAndLock(1, LOCKMODE_EXCLUSIVE); if (arriveStatus == FAILURE) { continue; } ref.long_value = ref.version + 1; ref.version = ref.version + 1; ref.departAfterUpdateAndUnlock(); k++; if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } } GammaTxnLong_constructionTest.java000066400000000000000000000056201174000617100454230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.SpeculativeConfigurationError; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasExclusiveLock; public class GammaTxnLong_constructionTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void withTransaction_whenFatMonoGammaTxnUsed() { FatMonoGammaTxn tx = new FatMonoGammaTxn(stm); GammaTxnLong ref = new GammaTxnLong(tx, 10); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tx.hasWrites); assertFalse(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } @Test public void withTransaction_whenFatFixedLengthGammaTxnUsed() { FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(stm); GammaTxnLong ref = new GammaTxnLong(tx, 10); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tx.hasWrites); assertFalse(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } @Test public void withTransaction_whenFatVariableLengthGammaTxnUsed() { FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(stm); GammaTxnLong ref = new GammaTxnLong(tx, 10); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tx.hasWrites); assertFalse(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } @Test public void withTransaction_whenLeanFixedLengthGammaTxnUsed() { LeanFixedLengthGammaTxn tx = new LeanFixedLengthGammaTxn(stm); try { new GammaTxnLong(tx, 10); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } @Test public void withTransaction_whenLeanMonoGammaTxnUsed() { LeanMonoGammaTxn tx = new LeanMonoGammaTxn(stm); try { new GammaTxnLong(tx, 10); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } } GammaTxnLong_decrement0Test.java000066400000000000000000000162361174000617100447240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.*; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_decrement0Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_decrement0Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.decrement(); tx.commit(); assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue - 1); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setReadonly(true) .setSpeculative(false) .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); try { ref.decrement(); fail(); } catch (ReadonlyException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.decrement(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenPrivatizedByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.decrement(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenCommittedTransactionFound() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); try { ref.decrement(); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionFound_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); try { ref.decrement(); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionFound_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.prepare(); try { ref.decrement(); fail(); } catch (PreparedTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.decrement(); fail(); } catch (TxnMandatoryException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue - 1); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.decrement(); tx.commit(); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue - 1); } } GammaTxnLong_decrement1Test.java000066400000000000000000000173741174000617100447310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.ReadonlyException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_decrement1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_decrement1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.decrement(tx); tx.commit(); assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue - 1); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setReadonly(true) .setSpeculative(false) .newTransactionFactory() .newTxn(); try { ref.decrement(tx); fail(); } catch (ReadonlyException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenReadLockAcquiredByOther_thenDecrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = transactionFactory.newTxn(); ref.decrement(tx); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); } @Test public void whenWriteLockAcquiredByOther_thenDecrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); ref.decrement(tx); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenExclusiveLockAcquiredByOther_thenDecrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); ref.decrement(tx); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenCommittedTransactionFound() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.decrement(tx); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionFound_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.decrement(tx); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionFound_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.decrement(tx); fail(); } catch (PreparedTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.decrement(null); fail(); } catch (NullPointerException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue - 1); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); ref.decrement(tx); tx.commit(); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue - 1); } } GammaTxnLong_decrement1WithAmountTest.java000066400000000000000000000166121174000617100467430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.*; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_decrement1WithAmountTest { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_decrement1WithAmountTest(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.decrement(5); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue - 5); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setReadonly(true) .setSpeculative(false) .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); try { ref.decrement(5); fail(); } catch (ReadonlyException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenReadLockAcquiredByOther_thenDecrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.decrement(5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); } @Test public void whenWriteLockAcquiredByOther_thenDecrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.decrement(5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenPrivatizedByOther_thenDecrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.decrement(5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenCommittedTransactionFound() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); try { ref.decrement(5); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionFound_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); try { ref.decrement(5); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionFound_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.prepare(); try { ref.decrement(5); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.decrement(5); fail(); } catch (TxnMandatoryException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } } GammaTxnLong_decrement2Test.java000066400000000000000000000126731174000617100447270ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.ReadonlyException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnLong_decrement2Test { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.decrement(tx, 5); tx.commit(); assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue - 5); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setReadonly(true) .setSpeculative(false) .newTransactionFactory() .newTxn(); try { ref.decrement(tx, 5); fail(); } catch (ReadonlyException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOther_thenDecrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); ref.decrement(tx, 5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenPrivatizedByOther_thenDecrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); ref.decrement(tx, 5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenCommittedTransactionFound() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); try { ref.decrement(tx, 5); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionFound_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.decrement(tx, 5); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionFound_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); try { ref.decrement(tx, 5); fail(); } catch (PreparedTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.decrement(null, 5); fail(); } catch (NullPointerException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } } GammaTxnLong_get0Test.java000066400000000000000000000157301174000617100435330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_get0Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_get0Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { TxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); setThreadLocalTxn(tx); try { ref.get(); fail(); } catch (PreparedTxnException expected) { } } @Test public void whenPrivatizedBySelf_thenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); long value = ref.get(); assertEquals(100, value); assertRefHasExclusiveLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertEquals(version, ref.getVersion()); assertEquals(100, ref.long_value); } @Test public void whenEnsuredBySelf() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); long value = ref.get(); assertEquals(100, value); assertRefHasWriteLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 100); } @Test public void whenPrivatizedByOther_thenReadConflict() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.get(); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(otherTx); assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 100); } @Test public void whenEnsuredByother_thenReadStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); long value = ref.get(); assertEquals(100, value); assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(otherTx); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 100); } @Test public void whenActiveTransactionAvailable_thenPreparedTxnException() { TxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long value = ref.get(); assertEquals(10, value); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); } @Test public void whenNoTransactionAvailable_thenNoTransactionFoundException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.get(); fail(); } catch (TxnMandatoryException expected) { } assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); setThreadLocalTxn(tx); try { ref.get(); fail(); } catch (DeadTxnException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); setThreadLocalTxn(tx); try { ref.get(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); } } GammaTxnLong_get1Test.java000066400000000000000000000157151174000617100435370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_get1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_get1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { TxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.get(tx); fail(); } catch (PreparedTxnException expected) { } } @Test public void whenLockedForCommitBySelf_thenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); long value = ref.get(tx); assertEquals(100, value); assertRefHasExclusiveLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(tx); assertEquals(version, ref.getVersion()); assertEquals(100, ref.long_value); } @Test public void whenLockedForWriteBySelf() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.getLock().acquire(tx, LockMode.Write); long value = ref.get(tx); assertEquals(100, value); assertRefHasWriteLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(tx); assertVersionAndValue(ref, version, 100); } @Test public void whenLockedForReadBySelf() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.getLock().acquire(tx, LockMode.Read); long value = ref.get(tx); assertEquals(100, value); assertRefHasReadLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(tx); assertVersionAndValue(ref, version, 100); } @Test public void whenCommtLockAcquiredByOther_thenReadConflict() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.get(tx); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(otherTx); assertIsAborted(tx); assertVersionAndValue(ref, version, 100); } @Test public void whenEnsuredByother_thenReadStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); long value = ref.get(tx); assertEquals(100, value); assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(otherTx); assertIsActive(tx); assertVersionAndValue(ref, version, 100); } @Test public void whenActiveTransactionAvailable_thenPreparedTxnException() { TxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = transactionFactory.newTxn(); long value = ref.get(tx); assertEquals(10, value); assertIsActive(tx); } @Test public void whenNullTransactionAvailable_thenNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.get((Txn)null); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.get(tx); fail(); } catch (DeadTxnException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertIsCommitted(tx); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.get(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } } GammaTxnLong_getAndAlter2Test.java000066400000000000000000000146031174000617100451460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.SomeUncheckedException; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; @RunWith(Parameterized.class) public class GammaTxnLong_getAndAlter2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_getAndAlter2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenNullTransaction_thenNullPointerException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); LongFunction function = mock(LongFunction.class); try { ref.getAndAlter(null, function); fail(); } catch (NullPointerException expected) { } verifyZeroInteractions(function); assertVersionAndValue(ref, version, 10); } @Test public void whenNullFunction_thenNullPointerException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); try { ref.getAndAlter(tx, null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenCommittedTransaction_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); LongFunction function = mock(LongFunction.class); try { ref.getAndAlter(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); LongFunction function = mock(LongFunction.class); try { ref.getAndAlter(tx, function); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenAbortedTransaction() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); LongFunction function = mock(LongFunction.class); try { ref.getAndAlter(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenAlterFunctionCausesProblems_thenTransactionAborted() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); when(function.call(initialValue)).thenThrow(new SomeUncheckedException()); GammaTxn tx = transactionFactory.newTxn(); try { ref.getAndAlter(tx, function); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); long result = ref.getAndAlter(tx, Functions.incLongFunction()); tx.commit(); joinAll(thread); assertEquals(result, initialValue); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenSuccess() { LongFunction function = new LongFunction() { @Override public long call(long current) { return current + 1; } }; GammaTxnLong ref = new GammaTxnLong(stm, 100); GammaTxn tx = transactionFactory.newTxn(); long result = ref.getAndAlter(tx, function); tx.commit(); assertEquals(101, ref.atomicGet()); assertEquals(100, result); } } GammaTxnLong_getAndIncrement1Test.java000066400000000000000000000152271174000617100460250ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.*; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.references.TxnLong; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_getAndIncrement1Test implements GammaConstants { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_getAndIncrement1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); setThreadLocalTxn(tx); try { ref.getAndIncrement(30); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenActiveTransactionAvailable() { TxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long value = ref.getAndIncrement(20); tx.commit(); assertEquals(10, value); assertIsCommitted(tx); assertEquals(30, ref.atomicGet()); assertSame(tx, getThreadLocalTxn()); } @Test public void whenNoChange() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long value = ref.getAndIncrement(0); tx.commit(); assertEquals(10, value); assertIsCommitted(tx); assertEquals(10, ref.atomicGet()); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 10); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long amount = 2; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + amount); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long result = ref.getAndIncrement(amount); tx.commit(); joinAll(thread); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); } @Test public void whenLocked_thenReadWriteConflict() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long version = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.getAndIncrement(1); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, initialValue); assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenNoTransactionAvailable_thenNoTransactionFoundException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.getAndIncrement(1); fail(); } catch (TxnMandatoryException expected) { } assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(getThreadLocalTxn()); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); try { ref.getAndIncrement(2); fail(); } catch (DeadTxnException expected) { } assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSame(tx, getThreadLocalTxn()); assertIsCommitted(tx); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); try { ref.getAndIncrement(1); fail(); } catch (DeadTxnException expected) { } assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSame(tx, getThreadLocalTxn()); assertIsAborted(tx); } } GammaTxnLong_getAndIncrement2Test.java000066400000000000000000000107221174000617100460210ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; @RunWith(Parameterized.class) public class GammaTxnLong_getAndIncrement2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_getAndIncrement2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenTransactionNull_thenNullPointerException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); try { ref.getAndIncrement(null, 10); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, version, 10); } @Test public void whenTransactionCommitted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.getAndIncrement(tx, 10); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenTransactionAborted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.getAndIncrement(tx, 10); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.getAndIncrement(tx, 10); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenNoChange() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); long result = ref.getAndIncrement(tx, 0); tx.commit(); assertEquals(10, result); assertIsCommitted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); long result = ref.getAndIncrement(tx, 20); tx.commit(); assertIsCommitted(tx); assertEquals(10, result); assertVersionAndValue(ref, version + 1, 30); } } GammaTxnLong_getAndLock2Test.java000066400000000000000000000025161174000617100447670ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertSame; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasLockMode; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnLong_getAndLock2Test { private GammaStm stm; @Before public void setUp(){ stm = new GammaStm(); } @Test public void whenLockFree(){ whenLockFree(LockMode.None); whenLockFree(LockMode.Read); whenLockFree(LockMode.Write); whenLockFree(LockMode.Exclusive); } public void whenLockFree(LockMode lockMode){ String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); String result = ref.getAndLock(tx, lockMode); assertSame(initialValue, result); assertVersionAndValue(ref,initialVersion, initialValue); assertRefHasLockMode(ref, tx, lockMode.asInt()); } } GammaTxnLong_getAndSet1Test.java000066400000000000000000000213661174000617100446350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_getAndSet1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_getAndSet1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenActiveTransactionAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long value = ref.getAndSet(initialValue + 2); tx.commit(); assertEquals(initialValue, value); assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion + 1, initialValue + 2); } @Test public void whenNoChange() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long value = ref.getAndSet(initialValue); tx.commit(); assertEquals(initialValue, value); assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredBySelf() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); long result = ref.getAndSet(20); assertEquals(10, result); assertIsActive(tx); assertRefHasWriteLock(ref, tx); assertSurplus(ref, 1); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 10); } @Test public void whenPrivatizedBySelf() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); long result = ref.getAndSet(20); assertEquals(10, result); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertSurplus(ref, 1); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 10); } @Test public void whenEnsuredByOther_thenGetAndSetSucceedsButCommitFails() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); long result = ref.getAndSet(20); assertEquals(10, result); assertIsActive(tx); assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertIsActive(otherTx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 10); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertIsActive(otherTx); assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 10); } @Test public void whenPrivatizedByOther_thenReadConflict() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.getAndSet(20); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertSurplus(ref, 1); assertIsActive(otherTx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 10); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long newValue = 20; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, newValue); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long result = ref.getAndSet(newValue); tx.commit(); joinAll(thread); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenNoTransactionAvailable_thenNoTransactionFoundException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, 10); long initialVersion = ref.getVersion(); long newValue = 20; try { ref.getAndSet(newValue); fail(); } catch (TxnMandatoryException expected) { } assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); setThreadLocalTxn(tx); try { ref.getAndSet(30); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); setThreadLocalTxn(tx); try { ref.getAndSet(initialValue + 1); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); setThreadLocalTxn(tx); try { ref.getAndSet(initialValue + 1); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } } GammaTxnLong_getAndSet2Test.java000066400000000000000000000126361174000617100446360ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_getAndSet2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_getAndSet2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenNullTransaction() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); try { ref.getAndSet(null, 11); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, version, 10); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.getAndSet(tx, 11); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenAbortedTransaction_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.getAndSet(tx, 11); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenCommittedTransaction_thenCommittedTransactionException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.getAndSet(tx, 11); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); long result = ref.getAndSet(tx, 20); tx.commit(); assertEquals(10, result); assertVersionAndValue(ref, version + 1, 20); } @Test public void whenNormalTransactionUsed() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); long result = ref.getAndSet(tx, 20); tx.commit(); assertEquals(10, result); assertVersionAndValue(ref, version + 1, 20); } @Test public void whenNoChange() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); long value = ref.getAndSet(tx, 10); tx.commit(); assertEquals(10, value); assertIsCommitted(tx); assertEquals(10, ref.atomicGet()); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertVersionAndValue(ref, version, 10); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long newValue = 20; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, newValue); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); long result = ref.getAndSet(tx, newValue); tx.commit(); joinAll(thread); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } } GammaTxnLong_getAndSetAndLock3Test.java000066400000000000000000000030161174000617100460630ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasLockMode; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnLong_getAndSetAndLock3Test { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenLockFree() { whenLockFree(LockMode.None); whenLockFree(LockMode.Read); whenLockFree(LockMode.Write); whenLockFree(LockMode.Exclusive); } public void whenLockFree(LockMode lockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); long newValue = 20; long result = ref.getAndSetAndLock(tx, newValue, lockMode); Tranlocal tranlocal = tx.locate(ref); assertEquals(initialValue, result); assertEquals(newValue,tranlocal.long_value); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, lockMode.asInt()); } } GammaTxnLong_increment0Test.java000066400000000000000000000172761174000617100447470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.*; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_increment0Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_increment0Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setReadonly(true) .setSpeculative(false) .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); try { ref.increment(); fail(); } catch (ReadonlyException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenReadLockAcquiredByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenWriteLockAcquiredByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenExclusiveLockAcquiredByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenCommittedTransactionFound() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); try { ref.increment(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionFound_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); try { ref.increment(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionFound_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.prepare(); try { ref.increment(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.increment(); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(); tx.commit(); joinAll(thread); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnLong_increment1WithAmountTest.java000066400000000000000000000174041174000617100467610ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.*; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_increment1WithAmountTest { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_increment1WithAmountTest(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(5); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 5); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setReadonly(true) .setSpeculative(false) .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); try { ref.increment(5); fail(); } catch (ReadonlyException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenReadLockAcquiredByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenWriteLockAcquiredByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenExclusiveLockAcquiredByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenCommittedTransactionFound() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); try { ref.increment(5); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionFound_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); try { ref.increment(5); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionFound_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.prepare(); try { ref.increment(5); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.increment(5); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long amount = 4; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + amount); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.increment(amount); tx.commit(); joinAll(thread); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); } } GammaTxnLong_increment1WithTransactionTest.java000066400000000000000000000155411174000617100500030ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.ReadonlyException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_increment1WithTransactionTest { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_increment1WithTransactionTest(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setReadonly(true) .setSpeculative(false) .newTransactionFactory() .newTxn(); try { ref.increment(tx); fail(); } catch (ReadonlyException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenPrivatizedByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenCommittedTransactionFound() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.increment(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionFound_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.increment(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionFound_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.increment(tx); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.increment(null); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx); tx.commit(); joinAll(thread); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnLong_increment2Test.java000066400000000000000000000170451174000617100447430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.*; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_increment2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_increment2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx, 5); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 5); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setReadonly(true) .setSpeculative(false) .newTransactionFactory() .newTxn(); try { ref.increment(tx, 5); fail(); } catch (ReadonlyException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenLockedForReadByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx, 5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void whenLockedForWriteByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx, 5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenLockedForCommitByOther_thenIncrementSucceedsButCommitFails() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx, 5); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenCommittedTransactionFound() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.increment(tx, 5); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionFound_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.increment(tx, 5); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionFound_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.increment(tx, 5); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.increment(null, 5); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long amount = 4; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + amount); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); ref.increment(tx, amount); tx.commit(); joinAll(thread); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); } } GammaTxnLong_incrementAndGet1Test.java000066400000000000000000000224121174000617100460170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_incrementAndGet1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_incrementAndGet1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); setThreadLocalTxn(tx); long amount = 30; try { ref.incrementAndGet(amount); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void whenActiveTransactionAvailable() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long amount = 20; long value = ref.incrementAndGet(amount); tx.commit(); assertEquals(initialValue + amount, value); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); assertRefHasNoLocks(ref); assertSame(tx, getThreadLocalTxn()); } @Test public void whenNoTransactionAvailable_thenNoTransactionFoundException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.incrementAndGet(1); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenCommittedTransactionAvailable_thenExecutedAtomically() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); try { ref.incrementAndGet(20); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); try { ref.incrementAndGet(20); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenReadLockAlreadyAcquiredBySelf_thenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); int amount = 1; long result = ref.incrementAndGet(amount); assertEquals(initialValue + amount, result); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 1); assertRefHasReadLock(ref, tx); } @Test public void whenWriteLockAlreadyAcquiredBySelf_thenSuccess() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); int amount = 1; long result = ref.incrementAndGet(amount); assertEquals(initialValue + amount, result); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 1); assertRefHasWriteLock(ref, tx); } @Test public void whenExclusiveLockAlreadyAcquiredBySelf_thenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); long result = ref.incrementAndGet(1); assertEquals(11, result); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, tx); } @Test public void whenExclusiveLockAcquiredByOther_thenReadConflict() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.incrementAndGet(1); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 1); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, version, 10); } @Test public void whenWriteLockAcquiredByOther_thenIncrementSucceedsButCommitFails() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); long result = ref.incrementAndGet(1); assertEquals(11, result); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertSame(version, ref.getVersion()); assertEquals(10, ref.atomicWeakGet()); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 1); assertRefHasWriteLock(ref, otherTx); assertSame(version, ref.getVersion()); assertEquals(10, ref.atomicWeakGet()); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long amount = 4; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + amount); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long result = ref.incrementAndGet(amount); tx.commit(); joinAll(thread); assertEquals(initialValue + amount, result); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); } } GammaTxnLong_incrementAndGet2Test.java000066400000000000000000000122151174000617100460200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; @RunWith(Parameterized.class) public class GammaTxnLong_incrementAndGet2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_incrementAndGet2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenTransactionNull_thenNullPointerException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); try { ref.incrementAndGet(null, 10); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, version, 10); } @Test public void whenTransactionCommitted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.incrementAndGet(tx, 10); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenTransactionAborted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.incrementAndGet(tx, 10); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.incrementAndGet(tx, 10); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenNoChange() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); long result = ref.incrementAndGet(tx, 0); tx.commit(); assertEquals(10, result); assertIsCommitted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); long result = ref.incrementAndGet(tx, 20); tx.commit(); assertIsCommitted(tx); assertEquals(30, result); assertVersionAndValue(ref, version + 1, 30); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long amount = 4; TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + amount); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); long result = ref.incrementAndGet(tx, amount); tx.commit(); joinAll(thread); assertEquals(initialValue + amount, result); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + amount); } } GammaTxnLong_loadTest.java000066400000000000000000000413521174000617100436120ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaTestUtils; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_loadTest implements GammaConstants { private GammaStm stm; private boolean readBiased; private boolean arriveNeeded; public GammaTxnLong_loadTest(boolean readBiased, boolean arriveNeeded) { this.readBiased = readBiased; this.arriveNeeded = arriveNeeded; } @Before public void setUp() { stm = new GammaStm(); } @Parameterized.Parameters public static Collection configs() { return asList( new Boolean[]{false, false}, new Boolean[]{false, true}, new Boolean[]{true, false}, new Boolean[]{true, true} ); } public GammaTxnLong newTxnLong(long initialValue) { GammaTxnLong ref = new GammaTxnLong(stm, initialValue); if (readBiased) { ref = GammaTestUtils.makeReadBiased(ref); } return ref; } // ====================== locking ========================== @Test public void locking_whenNotLockedByOtherAndNoLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.None); GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = new Tranlocal(); boolean result = ref.load(tx,tranlocal, LOCKMODE_NONE, 1, arriveNeeded); assertTrue(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertSame(ref, tranlocal.owner); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(initialVersion, tranlocal.version); assertEquals(arriveNeeded && !readBiased, tranlocal.hasDepartObligation()); assertLockMode(ref, LockMode.None); assertSurplus(ref, arriveNeeded ? 1 : 0); assertReadonlyCount(ref, 0); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenNotLockedByOtherAndReadLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.None); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_READ, 1, arriveNeeded); assertTrue(result); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertSame(ref, tranlocal.owner); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(initialVersion, tranlocal.version); assertEquals(!readBiased, tranlocal.hasDepartObligation()); assertLockMode(ref, LockMode.Read); assertReadLockCount(ref, 1); assertSurplus(ref, 1); assertReadonlyCount(ref, 0); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenNotLockedByOtherAndWriteLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.None); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_WRITE, 1, arriveNeeded); assertTrue(result); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertSame(ref, tranlocal.owner); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(initialVersion, tranlocal.version); assertEquals(!readBiased, tranlocal.hasDepartObligation()); assertLockMode(ref, LockMode.Write); assertSurplus(ref, 1); assertReadonlyCount(ref, 0); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenNotLockedByOtherAndExclusiveLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.None); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, arriveNeeded); assertTrue(result); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertSame(ref, tranlocal.owner); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(initialVersion, tranlocal.version); assertEquals(!readBiased, tranlocal.hasDepartObligation()); assertLockMode(ref, LockMode.Exclusive); assertSurplus(ref, 1); assertReadonlyCount(ref, 0); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenReadLockedByOtherAndNoLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_NONE, 1, arriveNeeded); assertTrue(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertSame(ref, tranlocal.owner); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(initialVersion, tranlocal.version); assertEquals(!readBiased && arriveNeeded, tranlocal.hasDepartObligation()); assertLockMode(ref, LockMode.Read); assertSurplus(ref, !readBiased && arriveNeeded ? 2 : 1); assertReadLockCount(ref, 1); assertReadonlyCount(ref, 0); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenReadLockedByOtherAndReadLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_READ, 1, arriveNeeded); assertTrue(result); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertSame(ref, tranlocal.owner); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(initialVersion, tranlocal.version); assertEquals(!readBiased, tranlocal.hasDepartObligation()); assertLockMode(ref, LockMode.Read); assertSurplus(ref, readBiased ? 1 : 2); assertReadLockCount(ref, 2); assertReadonlyCount(ref, 0); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenReadLockedByOtherAndWriteLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_WRITE, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Read); assertSurplus(ref, 1); assertReadLockCount(ref, 1); assertReadonlyCount(ref, 0); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenReadLockedByOtherAndExclusiveLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Read); assertSurplus(ref, 1); assertReadLockCount(ref, 1); assertReadonlyCount(ref, 0); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenWriteLockedByOtherAndNoLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_NONE, 1, arriveNeeded); assertTrue(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertSame(ref, tranlocal.owner); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(initialVersion, tranlocal.version); assertEquals(arriveNeeded && !readBiased, tranlocal.hasDepartObligation()); assertLockMode(ref, LockMode.Write); assertSurplus(ref, arriveNeeded && !readBiased ? 2 : 1); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenWritetLockedByOtherAndReadLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_READ, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Write); assertSurplus(ref, 1); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenWriteLockedByOtherAndWriteLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_WRITE, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Write); assertSurplus(ref, 1); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenWriteLockedByOtherAndExclusiveLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Write); assertSurplus(ref, 1); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenExclusiveLockedByOtherAndNoLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx, tranlocal, LOCKMODE_NONE, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Exclusive); assertSurplus(ref, 1); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenExclusiveLockedByOtherAndReadLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_READ, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Exclusive); assertSurplus(ref, 1); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenExclusiveLockedByOtherAndWriteLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_WRITE, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Exclusive); assertSurplus(ref, 1); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void locking_whenExclusiveLockedByOtherAndExclusiveLockNeeded() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); Tranlocal tranlocal = new Tranlocal(); GammaTxn tx = stm.newDefaultTxn(); boolean result = ref.load(tx,tranlocal, LOCKMODE_EXCLUSIVE, 1, arriveNeeded); assertFalse(result); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Exclusive); assertSurplus(ref, 1); assertReadBiased(ref, readBiased); assertVersionAndValue(ref, initialVersion, initialValue); } } GammaTxnLong_set1Test.java000066400000000000000000000227741174000617100435560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnLong_set1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_set1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); setThreadLocalTxn(tx); try { ref.set(30); fail(); } catch (PreparedTxnException expected) { } assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertIsAborted(tx); assertEquals(10, ref.atomicGet()); assertVersionAndValue(ref, version, 10); } @Test public void whenActiveTransactionAvailable_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long value = ref.set(20); assertIsActive(tx); assertEquals(20, value); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertWriteBiased(ref); assertVersionAndValue(ref, version, 10); tx.commit(); assertIsCommitted(tx); assertEquals(20, ref.atomicGet()); assertSame(tx, getThreadLocalTxn()); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertWriteBiased(ref); } @Test public void whenLocked_thenReadWriteConflict() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.set(20); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); otherTx.abort(); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertSame(tx, getThreadLocalTxn()); } @Test public void whenNoChange() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); long result = ref.set(initialValue); tx.commit(); assertIsCommitted(tx); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransactionFound_thenNoTransactionFoundException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.set(20); fail(); } catch (TxnMandatoryException expected) { } assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPrivatizedBySelf_thenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); long value = ref.set(200); assertEquals(200, value); assertRefHasExclusiveLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 100); } @Test public void whenEnsuredBySelf_thenSuccess() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); long value = ref.set(200); assertEquals(200, value); assertRefHasWriteLock(ref, tx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 100); } @Test public void whenPrivatizedByOtherAndFirstTimeRead_thenReadConflict() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try { ref.set(200); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(otherTx); assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 100); } @Test public void whenEnsuredByOther_thenSetPossibleButCommitFails() { GammaTxnLong ref = new GammaTxnLong(stm, 100); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); long value = ref.set(200); assertEquals(200, value); assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(otherTx); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 100); try { tx.commit(); fail(); } catch (ReadWriteConflict e) { } assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertIsActive(otherTx); assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, version, 100); } @Test public void whenCommittedTransactionAvailable_thenExecutedAtomically() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, 10); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); setThreadLocalTxn(tx); try { ref.set(initialValue + 1); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); setThreadLocalTxn(tx); try { ref.set(20); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertSame(tx, getThreadLocalTxn()); } } GammaTxnLong_set2Test.java000066400000000000000000000075221174000617100435510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; @RunWith(Parameterized.class) public class GammaTxnLong_set2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnLong_set2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenNullTransaction_thenNullPointerException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); try { ref.set(null, 20); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, version, 10); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); try { ref.set(tx, 20); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenAborted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); try { ref.set(tx, 20); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, version, 10); } @Test public void whenCommitted_thenDeadTxnException() { GammaTxnLong ref = new GammaTxnLong(stm, 10); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); try { ref.set(tx, 20); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, version, 10); } @Test public void test() { GammaTxnLong ref = new GammaTxnLong(stm, 10); GammaTxn tx = transactionFactory.newTxn(); long value = ref.get(tx); assertEquals(10, value); } } GammaTxnLong_setAndLock3Test.java000066400000000000000000000025311174000617100450010ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasLockMode; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnLong_setAndLock3Test { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenLockFree() { whenLockFree(LockMode.None); whenLockFree(LockMode.Read); whenLockFree(LockMode.Write); whenLockFree(LockMode.Exclusive); } public void whenLockFree(LockMode lockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); long newValue = 20; long result = ref.setAndLock(tx, newValue, lockMode); assertEquals(newValue, result); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, lockMode.asInt()); } } GammaTxnLong_toDebugStringTest.java000066400000000000000000000014031174000617100454440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import static org.junit.Assert.assertEquals; public class GammaTxnLong_toDebugStringTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void test() { GammaTxnLong ref = new GammaTxnLong(stm); String s = ref.toDebugString(); assertEquals("GammaTxnLong{orec=Orec(hasExclusiveLock=false, hasWriteLock=false, readLocks=0, surplus=0, " + "isReadBiased=false, readonlyCount=0), version=1, value=0, hasListeners=false)", s); } } TxnLongAwaitThread.java000066400000000000000000000024271174000617100431260ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnlongpackage org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.predicates.LongPredicate; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; public class TxnLongAwaitThread extends TestThread { private final GammaTxnLong ref; private final LongPredicate predicate; public TxnLongAwaitThread(GammaTxnLong ref, final long awaitValue) { this(ref, new LongPredicate() { @Override public boolean evaluate(long current) { return current == awaitValue; } }); } public TxnLongAwaitThread(GammaTxnLong ref, LongPredicate predicate) { this.ref = ref; this.predicate = predicate; } @Override public void doRun() throws Exception { ref.getStm().getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { System.out.println("Starting wait and ref.value found: " + ref.get()); ref.await(predicate); System.out.println("Finished wait and ref.value found: " + ref.get()); } }); } } 000077500000000000000000000000001174000617100363645ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefGammaTxnRef_alterAndGet1Test.java000066400000000000000000000177041174000617100446040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.gammaref; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.mockito.Matchers; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.api.functions.Function; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.txnref.TxnRefAwaitThread; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.api.functions.Functions.identityLongFunction; import static org.multiverse.api.functions.Functions.incLongFunction; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnRef_alterAndGet1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnRef_alterAndGet1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenActiveTransactionAvailableAndNullFunction_thenNullPointerException() { GammaTxnRef ref = new GammaTxnRef(stm); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.alterAndGet(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); } @Test public void whenFunctionCausesException() { GammaTxnRef ref = new GammaTxnRef(stm); Function function = mock(Function.class); RuntimeException ex = new RuntimeException(); when(function.call(Matchers.anyObject())).thenThrow(ex); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.alterAndGet(function); fail(); } catch (RuntimeException found) { assertSame(ex, found); } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); } @Test public void whenActiveTransactionAvailable() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); Function function = Functions.incLongFunction(); ref.alterAndGet(function); assertEquals(new Long(initialValue + 1L), ref.get()); assertVersionAndValue(ref, initialVersion, initialValue); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenActiveTransactionAvailableButNoChange_thenNoWrite() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); Function function = identityLongFunction(); ref.alterAndGet(function); assertEquals(initialValue, ref.get()); assertVersionAndValue(ref, initialVersion, initialValue); tx.commit(); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); Function function = mock(LongFunction.class); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); setThreadLocalTxn(tx); try { ref.alterAndGet(function); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransactionAvailable_thenNoTransactionFoundException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); Function function = Functions.incLongFunction(1); try { ref.alterAndGet(function); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); long initialValue = 10; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); Function function = Functions.incLongFunction(1); try { ref.alterAndGet(function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); Function function = incLongFunction(1); try { ref.alterAndGet(function); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable_thenTheyAreNotified() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); TxnRefAwaitThread thread = new TxnRefAwaitThread(ref, initialValue + 1L); thread.start(); sleepMs(500); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.alterAndGet(Functions.incLongFunction()); tx.commit(); joinAll(thread); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnRef_alterAndGet2Test.java000066400000000000000000000213051174000617100445750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.functions.Function; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnRef_alterAndGet2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnRef_alterAndGet2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenNullTransaction_thenNullPointerException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(null, function); fail(); } catch (NullPointerException expected) { } verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullFunction_thenNullPointerException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); try { ref.alterAndGet(tx, null); fail(); } catch (NullPointerException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCommittedTransaction_thenDeadTxnException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(tx, function); fail(); } catch (PreparedTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransaction() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(tx, function); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenFunctionCausesException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); RuntimeException ex = new RuntimeException(); when(function.call(anyLong())).thenThrow(ex); GammaTxn tx = transactionFactory.newTxn(); try { ref.alterAndGet(tx, function); fail(); } catch (RuntimeException found) { assertSame(ex, found); } assertRefHasNoLocks(ref); assertIsAborted(tx); assertNull(getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPrivatizedByOther() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long version = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = transactionFactory.newTxn(); LongFunction function = mock(LongFunction.class); try { ref.alterAndGet(tx, function); fail(); } catch (ReadWriteConflict expected) { } assertSurplus(ref, 1); assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, version, initialValue); } @Test public void whenWriteLockedByOther_thenOperationSucceedsButCommitFails() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long version = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = transactionFactory.newTxn(); LongFunction function = Functions.incLongFunction(1); ref.alterAndGet(tx, function); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertIsActive(otherTx); assertIsAborted(tx); assertVersionAndValue(ref, version, initialValue); } @Test public void whenListenersAvailable_thenTheyAreNotified() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); final Long newValue = 11L; TxnRefAwaitThread thread = new TxnRefAwaitThread(ref, newValue); thread.start(); sleepMs(500); Function function = new Function(){ @Override public Long call(Long value) { return newValue; } }; GammaTxn tx = transactionFactory.newTxn(); ref.alterAndGet(tx, function); tx.commit(); joinAll(thread); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenSuccess() { LongFunction function = new LongFunction() { @Override public long call(long current) { return current + 1; } }; GammaTxnRef ref = new GammaTxnRef(stm, 100L); GammaTxn tx = transactionFactory.newTxn(); long result = ref.alterAndGet(tx, function); tx.commit(); assertEquals(new Long(101), ref.atomicGet()); assertEquals(101L, result); } } GammaTxnRef_atomicAlterAndGetTest.java000066400000000000000000000127641174000617100456610ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.api.functions.Functions.identityLongFunction; import static org.multiverse.api.functions.Functions.incLongFunction; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnRef_atomicAlterAndGetTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenFunctionCausesException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); RuntimeException ex = new RuntimeException(); when(function.call(anyLong())).thenThrow(ex); long orecValue = ref.orec; try { ref.atomicAlterAndGet(function); fail(); } catch (RuntimeException found) { assertSame(ex, found); } assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertNull(getThreadLocalTxn()); } @Test public void whenNullFunction_thenNullPointerException() { Long initialValue = 5L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.atomicAlterAndGet(null); fail(); } catch (NullPointerException expected) { } assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenSuccess() { Long initialValue = 5L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); long result = ref.atomicAlterAndGet(function); assertEquals(initialValue + 1, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenNoChange() { Long initialValue = 5L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long version = ref.getVersion(); LongFunction function = identityLongFunction(); Long result = ref.atomicAlterAndGet(function); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, version, initialValue); } @Test public void whenActiveTransactionAvailable_thenIgnored() { Long initialValue = 5L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(tx, 100L); LongFunction function = incLongFunction(1); long result = ref.atomicAlterAndGet(function); assertEquals(initialValue + 1, result); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); } @Test public void whenLockedByOther(){ whenLockedByOther(LockMode.Read); whenLockedByOther(LockMode.Write); whenLockedByOther(LockMode.Exclusive); } public void whenLockedByOther(LockMode lockMode) { Long initialValue = 5L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, lockMode); long orecValue = ref.orec; LongFunction function = mock(LongFunction.class); try { ref.atomicAlterAndGet(function); fail(); } catch (LockedException expected) { } assertOrecValue(ref, orecValue); verifyZeroInteractions(function); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); TxnRefAwaitThread thread = new TxnRefAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); ref.atomicAlterAndGet(Functions.incLongFunction()); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnRef_atomicGetAndAlterTest.java000066400000000000000000000134101174000617100456460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.txnlong.TxnLongAwaitThread; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.multiverse.TestUtils.joinAll; import static org.multiverse.TestUtils.sleepMs; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.api.functions.Functions.identityLongFunction; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnRef_atomicGetAndAlterTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenSuccess() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(); long result = ref.atomicGetAndAlter(function); assertEquals(2, result); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenNullFunction_thenNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.atomicGetAndAlter(null); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertWriteBiased(ref); } @Test public void whenActiveTransactionAvailable_thenIgnored() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(10); LongFunction function = Functions.incLongFunction(); long result = ref.atomicGetAndAlter(function); tx.abort(); assertEquals(initialValue, result); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertSurplus(ref, 0); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenPrivatizedByOther_thenLockedException() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); LongFunction function = mock(LongFunction.class); try { ref.atomicGetAndAlter(function); fail(); } catch (LockedException expected) { } verifyZeroInteractions(function); assertRefHasExclusiveLock(ref, otherTx); assertWriteBiased(ref); assertSurplus(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOtherAndNothingDirty_thenLockedException() { long initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); try { ref.atomicGetAndAlter(identityLongFunction()); fail(); } catch (LockedException expected) { } assertRefHasWriteLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenEnsuredByOther_thenLockedException() { int initialValue = 2; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); LongFunction function = mock(LongFunction.class); try { ref.atomicGetAndAlter(function); fail(); } catch (LockedException expected) { } verifyZeroInteractions(function); assertRefHasWriteLock(ref, otherTx); assertWriteBiased(ref); assertSurplus(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenListenersAvailable() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); long result = ref.atomicGetAndAlter(Functions.incLongFunction()); assertEquals(result, initialValue); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnRef_atomicGetAndSetTest.java000066400000000000000000000102361174000617100453350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnRef_atomicGetAndSetTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 10; stm = new GammaStm(config); clearThreadLocalTxn(); } @Test public void whenSuccess() { String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); String newValue = "newValue"; String result = ref.atomicGetAndSet(newValue); assertEquals(initialValue, result); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenActiveTransactionAvailable_thenIgnored() { String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); String newValue = "newValue"; String result = ref.atomicGetAndSet(newValue); assertIsActive(tx); assert (tx.getRefTranlocal(ref) == null); assertEquals(initialValue, result); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenLockedByOther_thenLockedException() { whenLockedByOther_thenLockedException(LockMode.Read); whenLockedByOther_thenLockedException(LockMode.Write); whenLockedByOther_thenLockedException(LockMode.Exclusive); } public void whenLockedByOther_thenLockedException(LockMode lockMode) { String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, lockMode); long orecValue = ref.orec; try { ref.atomicGetAndSet("newValue"); fail(); } catch (LockedException expected) { } assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoChange_thenNoCommit() { String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); String result = ref.atomicGetAndSet(initialValue); assertEquals(initialValue, result); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(getThreadLocalTxn()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); } @Test public void whenListenersAvailable() { String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); String newValue = "newValue"; TxnRefAwaitThread thread = new TxnRefAwaitThread(ref, newValue); thread.start(); sleepMs(500); String result = ref.atomicGetAndSet(newValue); assertEquals(initialValue, result); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); } } GammaTxnRef_atomicGetTest.java000066400000000000000000000165121174000617100442410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertGlobalConflictCount; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; import static org.multiverse.stms.gamma.GammaTestUtils.makeReadBiased; public class GammaTxnRef_atomicGetTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } // ==================== write biased ==================== @Test public void writeBiased_whenReadLocked() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); String result = ref.atomicGet(); assertSame(result, initialValue); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenWriteLocked() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); String result = ref.atomicGet(); assertSame(result, initialValue); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenExclusiveLocked_thenLockedException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); try { ref.atomicGet(); fail(); } catch (LockedException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenNull() { GammaTxnRef ref = new GammaTxnRef(stm, null); long initialVersion = ref.getVersion(); long conflictCount = stm.globalConflictCounter.count(); long orecValue = ref.orec; String result = ref.atomicGet(); assertNull(result); assertVersionAndValue(ref, initialVersion, null); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenNotNull() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); long conflictCount = stm.globalConflictCounter.count(); long orecValue = ref.orec; String result = ref.atomicGet(); assertSame(initialValue, result); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } // ==================== read biased ==================== @Test public void readBiased_whenReadLocked() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); String result = ref.atomicGet(); assertSame(result, initialValue); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenWriteLocked() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); String result = ref.atomicGet(); assertSame(result, initialValue); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenExclusiveLocked_thenLockedException() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); try { ref.atomicGet(); fail(); } catch (LockedException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenNull() { GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, null)); long initialVersion = ref.getVersion(); long conflictCount = stm.globalConflictCounter.count(); long orecValue = ref.orec; String result = ref.atomicGet(); assertNull(result); assertVersionAndValue(ref, initialVersion, null); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenNotNull() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); long conflictCount = stm.globalConflictCounter.count(); long orecValue = ref.orec; String result = ref.atomicGet(); assertSame(initialValue, result); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, conflictCount); } } GammaTxnRef_atomicIsNullTest.java000066400000000000000000000212731174000617100447300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertGlobalConflictCount; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; import static org.multiverse.stms.gamma.GammaTestUtils.makeReadBiased; public class GammaTxnRef_atomicIsNullTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } // ==================== write biased ======================================== @Test public void writeBiased_whenReadLocked_thenSuccess() { String initialValue = null; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertTrue(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenWriteLocked_thenSuccess() { String initialValue = null; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertTrue(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenExclusiveLocked_thenLockedException() { GammaTxnRef ref = new GammaTxnRef(stm, null); long initialVersion = ref.version; GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); try { ref.atomicIsNull(); fail(); } catch (LockedException expected) { } assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, null); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenNull() { GammaTxnRef ref = new GammaTxnRef(stm, null); long initialVersion = ref.getVersion(); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertTrue(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, null); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenActiveTransactionAvailable_thenIgnored() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(tx, null); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertFalse(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void writeBiased_whenNotNull() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertFalse(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, conflictCount); } // ==================== read biased ======================================== @Test public void readBiased_whenReadLocked_thenSuccess() { String initialValue = null; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Read); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertTrue(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenWriteLocked_thenSuccess() { String initialValue = null; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Write); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertTrue(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenExclusiveLocked_thenLockedException() { String initialValue = null; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.version; GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, LockMode.Exclusive); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); try { ref.atomicIsNull(); fail(); } catch (LockedException expected) { } assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, null); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenNull() { String initialValue = null; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertTrue(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, null); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenActiveTransactionAvailable_thenIgnored() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.set(tx, null); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertFalse(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, conflictCount); } @Test public void readBiased_whenNotNull() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.getVersion(); long orecValue = ref.orec; long conflictCount = stm.globalConflictCounter.count(); boolean result = ref.atomicIsNull(); assertFalse(result); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, conflictCount); } } GammaTxnRef_atomicSetTest.java000066400000000000000000000172441174000617100442600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.LockedException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertOrecValue; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; import static org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject.setReadonlyCount; import static org.multiverse.stms.gamma.transactionalobjects.AbstractGammaObject.setSurplus; public class GammaTxnRef_atomicSetTest { private GammaStm stm; @Before public void setUp() { GammaStmConfig config = new GammaStmConfig(); config.maxRetries = 0; stm = new GammaStm(config); clearThreadLocalTxn(); } // =================== write biased ============================== @Test public void writeBiased_whenReadLocked_thenLockedException() { writeBiased_whenLocked_thenLockedException(LockMode.Read); } @Test public void writeBiased_whenWriteLocked_thenLockedException() { writeBiased_whenLocked_thenLockedException(LockMode.Write); } @Test public void writeBiased_whenExclusiveLocked_thenLockedException() { writeBiased_whenLocked_thenLockedException(LockMode.Exclusive); } public void writeBiased_whenLocked_thenLockedException(LockMode lockMode) { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.version; GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, lockMode); long orecValue = ref.orec; long globalConflictCount = stm.globalConflictCounter.count(); try { ref.atomicSet("bar"); fail(); } catch (LockedException expected) { } assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void writeBiased_whenNoChange() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.version; long orecValue = ref.orec; long globalConflictCount = stm.globalConflictCounter.count(); String result = ref.atomicSet(initialValue); assertSame(initialValue, result); assertOrecValue(ref, setReadonlyCount(orecValue, 1)); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void writeBiased_whenNoSurplusOfReaders() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.version; long orecValue = ref.orec; long globalConflictCount = stm.globalConflictCounter.count(); String newValue = "bar"; String result = ref.atomicSet(newValue); assertSame(newValue, result); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion+1, newValue); } @Test public void writeBiased_whenSurplusOfReaders_thenGlobalConflictCounterIncreased() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.version; ref.arrive(1); long orecValue = ref.orec; long globalConflictCount = stm.globalConflictCounter.count(); String newValue = "bar"; String result = ref.atomicSet(newValue); assertSame(newValue, result); assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, globalConflictCount+1); assertVersionAndValue(ref, initialVersion+1, newValue); } // =================== read biased ============================== @Test public void readBiased_whenReadLocked_thenLockedException() { readBiased_whenLocked_thenLockedException(LockMode.Read); } @Test public void readBiased_whenWriteLocked_thenLockedException() { readBiased_whenLocked_thenLockedException(LockMode.Write); } @Test public void readBiased_whenExclusiveLocked_thenLockedException() { readBiased_whenLocked_thenLockedException(LockMode.Exclusive); } public void readBiased_whenLocked_thenLockedException(LockMode lockMode) { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.version; GammaTxn tx = stm.newDefaultTxn(); ref.getLock().acquire(tx, lockMode); long orecValue = ref.orec; long globalConflictCount = stm.globalConflictCounter.count(); try { ref.atomicSet("bar"); fail(); } catch (LockedException expected) { } assertOrecValue(ref, orecValue); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void readBiased_whenNoChange() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.version; long orecValue = ref.orec; long globalConflictCount = stm.globalConflictCounter.count(); String result = ref.atomicSet(initialValue); System.out.println(ref.toDebugString()); assertSame(initialValue, result); assertOrecValue(ref, setSurplus(orecValue, 1)); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void readBiased_whenNoSurplusOfReaders() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.version; long globalConflictCount = stm.globalConflictCounter.count(); String newValue = "bar"; String result = ref.atomicSet(newValue); System.out.println(ref.toDebugString()); assertSame(newValue, result); assertWriteBiased(ref); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertLockMode(ref, LockMode.None); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion+1, newValue); } @Test public void readBiased_whenSurplusOfReaders_thenGlobalConflictCounterIncreased() { String initialValue = "foo"; GammaTxnRef ref = makeReadBiased(new GammaTxnRef(stm, initialValue)); long initialVersion = ref.version; ref.arrive(1); long globalConflictCount = stm.globalConflictCounter.count(); String newValue = "bar"; String result = ref.atomicSet(newValue); System.out.println(ref.toDebugString()); assertSame(newValue, result); assertWriteBiased(ref); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertLockMode(ref, LockMode.None); assertGlobalConflictCount(stm, globalConflictCount+1); assertVersionAndValue(ref, initialVersion+1, newValue); } } GammaTxnRef_awaitNotNullAndGet0Test.java000066400000000000000000000132351174000617100461100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.*; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnRef_awaitNotNullAndGet0Test implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenNull_thenReturnImmediately() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); String result = ref.awaitNotNullAndGet(); assertSame(initialValue, result); Tranlocal tranlocal = tx.locate(ref); assertTrue(tranlocal.isRead()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void whenPrivatizedByOtherBeforeReading_thenReadWriteConflict() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.awaitNotNullAndGet(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenEnsuredByOtherBeforeReading_thenSuccess() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); String result = ref.awaitNotNullAndGet(); assertSame(initialValue, result); Tranlocal tranlocal = tx.locate(ref); assertTrue(tranlocal.isRead()); assertEquals(LockMode.LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, otherTx); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenNull_thenWait() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); try { ref.awaitNotNullAndGet(); fail(); } catch (RetryError expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasNoLocks(ref); } @Test public void whenNoTransactionAvailable_thenTxnMandatoryException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); try { ref.awaitNotNullAndGet(); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, null); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); setThreadLocalTxn(tx); try { ref.awaitNotNullAndGet(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); } @Test public void whenAbortedTransaction_thenDeadTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); setThreadLocalTxn(tx); try { ref.awaitNotNullAndGet(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); } @Test public void whenCommittedTransaction_thenDeadTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); setThreadLocalTxn(tx); try { ref.awaitNotNullAndGet(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, null); } } GammaTxnRef_awaitNotNullAndGet1Test.java000066400000000000000000000130331174000617100461050ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.RetryError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnRef_awaitNotNullAndGet1Test implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenNotNull_thenReturnImmediately() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); String result = ref.awaitNotNullAndGet(tx); assertSame(initialValue, result); Tranlocal tranlocal = tx.locate(ref); assertTrue(tranlocal.isRead()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void whenPrivatizedByOther_thenReadWriteConflict() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.awaitNotNullAndGet(tx); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenEnsuredByOther_thenSuccess() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); String result = ref.awaitNotNullAndGet(tx); assertSame(initialValue, result); Tranlocal tranlocal = tx.locate(ref); assertTrue(tranlocal.isRead()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, otherTx); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void whenNull_thenWait() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .newTransactionFactory() .newTxn(); try { ref.awaitNotNullAndGet(tx); fail(); } catch (RetryError expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasNoLocks(ref); } @Test public void whenNullTransaction_thenNullPointerException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); try { ref.awaitNotNullAndGet(null); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, initialVersion, null); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); try { ref.awaitNotNullAndGet(tx); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); } @Test public void whenAbortedTransaction_thenDeadTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.awaitNotNullAndGet(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); } @Test public void whenCommittedTransaction_thenDeadTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); try { ref.awaitNotNullAndGet(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, null); } } GammaTxnRef_awaitNull0Test.java000066400000000000000000000124621174000617100443450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.*; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnRef_awaitNull0Test { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenNull_thenReturnImmediately() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.awaitNull(); Tranlocal tranlocal = tx.locate(ref); assertTrue(tranlocal.isRead()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasNoLocks(ref); } @Test public void whenPrivatizedByOther_thenReadWriteConflict() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.awaitNull(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenEnsuredByOther_thenSuccess() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.awaitNull(); Tranlocal tranlocal = tx.locate(ref); assertTrue(tranlocal.isRead()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, otherTx); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasWriteLock(ref, otherTx); } @Test public void whenNotNull_thenWait() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); try { ref.awaitNull(); fail(); } catch (RetryError expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void whenNoTransactionAvailable_thenTxnMandatoryException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); try { ref.awaitNull(); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, null); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); setThreadLocalTxn(tx); try { ref.awaitNull(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); } @Test public void whenAbortedTransaction_thenDeadTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); setThreadLocalTxn(tx); try { ref.awaitNull(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); } @Test public void whenCommittedTransaction_thenDeadTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); setThreadLocalTxn(tx); try { ref.awaitNull(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, null); } } GammaTxnRef_awaitNull1Test.java000066400000000000000000000124331174000617100443440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.RetryError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnRef_awaitNull1Test implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenNull_thenReturnImmediately() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.awaitNull(tx); Tranlocal tranlocal = tx.locate(ref); assertTrue(tranlocal.isRead()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasNoLocks(ref); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasNoLocks(ref); } @Test public void whenPrivatizedByOther_thenReadWriteConflict() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); try { ref.awaitNull(tx); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasExclusiveLock(ref, otherTx); } @Test public void whenEnsuredByOther_thenSuccess() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); ref.awaitNull(tx); Tranlocal tranlocal = tx.locate(ref); assertTrue(tranlocal.isRead()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertRefHasWriteLock(ref, otherTx); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, null); assertRefHasWriteLock(ref, otherTx); } @Test public void whenNotNull_thenWait() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .newTransactionFactory() .newTxn(); try { ref.awaitNull(tx); fail(); } catch (RetryError expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void whenNullTransaction_thenNullPointerException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); try { ref.awaitNull(null); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, initialVersion, null); } @Test public void whenPreparedTransaction_thenPreparedTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); try { ref.awaitNull(tx); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); } @Test public void whenAbortedTransaction_thenDeadTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.awaitNull(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, null); } @Test public void whenCommittedTransaction_thenDeadTxnException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); try { ref.awaitNull(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, null); } } GammaTxnRef_commute1Test.java000066400000000000000000000245431174000617100440620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.api.functions.Function; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnRef_commute1Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnRef_commute1Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenActiveTransactionAvailable() { Long initialValue = 1L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); LongFunction function = Functions.incLongFunction(1); ref.commute(function); Tranlocal commuting = tx.getRefTranlocal(ref); assertNotNull(commuting); assertTrue(commuting.isCommuting()); assertFalse(commuting.isRead()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertEquals(0, commuting.long_value); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); tx.commit(); assertEquals(new Long(2), ref.atomicGet()); assertIsCommitted(tx); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); } @Test public void whenActiveTransactionAvailableAndNoChange() { Long initialValue = 1L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); Function function = Functions.identityFunction(); ref.commute(function); Tranlocal commuting = tx.getRefTranlocal(ref); assertNotNull(commuting); assertTrue(commuting.isCommuting()); assertFalse(commuting.isRead()); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertNull(commuting.ref_value); assertIsActive(tx); assertSame(tx, getThreadLocalTxn()); tx.commit(); assertEquals(initialValue, ref.atomicGet()); assertVersionAndValue(ref, version, initialValue); assertIsCommitted(tx); assertSurplus(ref, 0); assertRefHasNoLocks(ref); assertWriteBiased(ref); } @Test public void whenActiveTransactionAvailableAndNullFunction_thenNullPointerException() { Long initalValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initalValue); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); try { ref.commute(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, version, initalValue); } @Test public void whenNoTransactionAvailable_thenNoTransactionFoundException() { long initialValue = 10; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); try { ref.commute(function); fail(); } catch (TxnMandatoryException expected) { } assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.commit(); LongFunction function = Functions.incLongFunction(1); try { ref.commute(function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.abort(); LongFunction function = Functions.incLongFunction(1); try { ref.commute(function); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { Long initialValue = 2L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); tx.prepare(); LongFunction function = Functions.incLongFunction(1); try { ref.commute(function); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertSurplus(ref, 0); assertWriteBiased(ref); assertRefHasNoLocks(ref); assertVersionAndValue(ref, version, initialValue); assertEquals(initialValue, ref.atomicGet()); } @Test public void whenAlreadyLockedBySelf_thenNoCommute() { whenAlreadyLockedBySelf_thenNoCommute(LockMode.Read); whenAlreadyLockedBySelf_thenNoCommute(LockMode.Write); whenAlreadyLockedBySelf_thenNoCommute(LockMode.Exclusive); } public void whenAlreadyLockedBySelf_thenNoCommute(LockMode lockMode) { Long initialValue = 2L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(lockMode); LongFunction function = Functions.incLongFunction(1); ref.commute(function); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertFalse(tranlocal.isCommuting()); assertEquals(new Long(3), tranlocal.ref_value); assertIsActive(tx); assertRefHasLockMode(ref, tx, lockMode.asInt()); assertSurplus(ref, 1); assertWriteBiased(ref); tx.commit(); assertSurplus(ref, 0); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertSame(tx, getThreadLocalTxn()); assertEquals(new Long(3), ref.atomicGet()); } @Test public void whenLockedAcquiredByOther_thenCommuteSucceedsButCommitFails() { whenNonExclusiveLockAcquiredByOther_thenCommuteSucceedsButCommitFails(LockMode.Read); whenNonExclusiveLockAcquiredByOther_thenCommuteSucceedsButCommitFails(LockMode.Write); whenNonExclusiveLockAcquiredByOther_thenCommuteSucceedsButCommitFails(LockMode.Exclusive); } public void whenNonExclusiveLockAcquiredByOther_thenCommuteSucceedsButCommitFails(LockMode lockMode) { Long initialValue = 2L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long version = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); setThreadLocalTxn(tx); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, lockMode); LongFunction function = Functions.incLongFunction(1); ref.commute(function); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertTrue(tranlocal.isCommuting()); assertHasCommutingFunctions(tranlocal, function); assertIsActive(tx); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertSurplus(ref, 1); long orecValue = ref.orec; try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertOrecValue(ref, orecValue); assertVersionAndValue(ref, version, initialValue); } } GammaTxnRef_commute2Test.java000066400000000000000000000313341174000617100440570ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.TxnFactory; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.LOCKMODE_NONE; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class GammaTxnRef_commute2Test { private final GammaTxnFactory transactionFactory; private final GammaStm stm; public GammaTxnRef_commute2Test(GammaTxnFactory transactionFactory) { this.transactionFactory = transactionFactory; this.stm = transactionFactory.getConfig().getStm(); } @Before public void setUp() { clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection configs() { return asList( new TxnFactory[]{new FatVariableLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatFixedLengthGammaTxnFactory(new GammaStm())}, new TxnFactory[]{new FatMonoGammaTxnFactory(new GammaStm())} ); } @Test public void whenCommuteFunctionCausesProblems_thenNoProblemsSinceCommuteFunctionNotEvaluatedImmediately() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); LongFunction function = mock(LongFunction.class); RuntimeException ex = new RuntimeException(); when(function.call(anyLong())).thenThrow(ex); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, function); assertHasCommutingFunctions(tx.getRefTranlocal(ref), function); assertIsActive(tx); assertEquals(initialValue, ref.atomicGet()); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertNull(getThreadLocalTxn()); } @Test public void whenLockedByOther(){ whenLockedByOther(LockMode.Read); whenLockedByOther(LockMode.Write); whenLockedByOther(LockMode.Exclusive); } public void whenLockedByOther(LockMode lockMode) { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = transactionFactory.newTxn(); ref.getLock().acquire(otherTx, lockMode); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, Functions.incLongFunction()); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertSurplus(ref, 1); assertIsAborted(tx); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenSuccess() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertTrue(commute.isCommuting()); assertEquals(0, commute.long_value); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenNoChange() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.identityLongFunction(); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertTrue(commute.isCommuting()); assertEquals(0, commute.long_value); tx.commit(); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNormalTransactionUsed() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); Txn tx = transactionFactory.newTxn(); ref.commute(tx, function); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenAlreadyOpenedForRead() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = Functions.incLongFunction(1); GammaTxn tx = transactionFactory.newTxn(); ref.get(tx); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertFalse(commute.isCommuting()); assertEquals(new Long(11), commute.ref_value); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } @Test public void whenAlreadyOpenedForConstruction() { GammaTxn tx = transactionFactory.newTxn(); Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(tx, initialValue); ref.openForConstruction(tx); ref.commute(tx, Functions.incLongFunction()); Tranlocal commute = tx.getRefTranlocal(ref); assertFalse(commute.isCommuting()); assertEquals(new Long(11), commute.ref_value); tx.commit(); assertEquals(new Long(11), ref.atomicGet()); } @Test public void whenAlreadyOpenedForWrite() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); LongFunction function = Functions.incLongFunction(); GammaTxn tx = transactionFactory.newTxn(); ref.set(tx, new Long(11)); ref.commute(tx, function); Tranlocal commute = tx.getRefTranlocal(ref); assertFalse(commute.isCommuting()); assertEquals(new Long(12), commute.ref_value); tx.commit(); assertEquals(new Long(12), ref.atomicGet()); } @Test public void whenAlreadyCommuting() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function1 = Functions.incLongFunction(); LongFunction function2 = Functions.incLongFunction(); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, function1); ref.commute(tx, function2); Tranlocal commute = tx.getRefTranlocal(ref); assertTrue(commute.isCommuting()); assertEquals(0, commute.long_value); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 2); } @Test public void whenNullFunction_thenNullPointerException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = transactionFactory.newTxn(); long orecValue = ref.orec; try { ref.commute(tx, null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); } @Test public void whenNullTransaction_thenNullPointerException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); long orecValue = ref.orec; try { ref.commute((Txn) null, function); fail(); } catch (NullPointerException expected) { } verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); } @Test public void whenTransactionAborted_thenDeadTxnException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); GammaTxn tx = transactionFactory.newTxn(); tx.abort(); long orecValue = ref.orec; try { ref.commute(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref,orecValue); } @Test public void whenTransactionCommitted_thenDeadTxnException() { Long initialValue = 20L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); GammaTxn tx = transactionFactory.newTxn(); tx.commit(); long orecValue = ref.orec; try { ref.commute(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); GammaTxn tx = transactionFactory.newTxn(); tx.prepare(); long orecValue = ref.orec; try { ref.commute(tx, function); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(function); assertVersionAndValue(ref, initialVersion, initialValue); assertOrecValue(ref, orecValue); } @Test public void fullExample() { assumeTrue(!(transactionFactory.newTxn() instanceof FatMonoGammaTxn)); Long initialValue = 10L; GammaTxnRef ref1 = new GammaTxnRef(stm, initialValue); GammaTxnRef ref2 = new GammaTxnRef(stm, initialValue); GammaTxn tx1 = transactionFactory.newTxn(); ref1.openForWrite(tx1, LOCKMODE_NONE).ref_value = new Long(11); ref2.commute(tx1, Functions.incLongFunction(1)); GammaTxn tx2 = transactionFactory.newTxn(); ref2.openForWrite(tx2, LOCKMODE_NONE).ref_value = new Long(11); tx2.commit(); tx1.commit(); assertIsCommitted(tx1); assertEquals(new Long(11), ref1.atomicGet()); assertEquals(new Long(12), ref2.atomicGet()); } @Test public void whenListenersAvailable() { Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); TxnRefAwaitThread thread = new TxnRefAwaitThread(ref, initialValue + 1); thread.start(); sleepMs(500); GammaTxn tx = transactionFactory.newTxn(); ref.commute(tx, Functions.incLongFunction()); tx.commit(); joinAll(thread); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); } } GammaTxnRef_consistentLoadStressTest.java000066400000000000000000000066611174000617100465260ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.concurrent.atomic.AtomicLong; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; public class GammaTxnRef_consistentLoadStressTest implements GammaConstants { private GammaStm stm; private volatile boolean stop; private GammaTxnRef ref; private final AtomicLong inconsistencyCount = new AtomicLong(); @Before public void setUp() { stm = new GammaStm(); stop = false; ref = new GammaTxnRef(stm, new Long(VERSION_UNCOMMITTED + 1)); } @Test public void test() { int readThreadCount = 10; ReadThread[] readThreads = new ReadThread[readThreadCount]; for (int k = 0; k < readThreads.length; k++) { readThreads[k] = new ReadThread(k); } int writerCount = 2; UpdateThread[] updateThreads = new UpdateThread[writerCount]; for (int k = 0; k < updateThreads.length; k++) { updateThreads[k] = new UpdateThread(k); } startAll(readThreads); startAll(updateThreads); sleepMs(60 * 1000); stop = true; joinAll(readThreads); joinAll(writerCount); assertEquals(0, inconsistencyCount.get()); } class ReadThread extends TestThread { public ReadThread(int id) { super("ReadThread-" + id); } @Override public void doRun() throws Exception { int k = 0; GammaTxn tx = stm.newDefaultTxn(); Tranlocal tranlocal = new Tranlocal(); while (!stop) { boolean success = ref.load(tx, tranlocal, LOCKMODE_NONE, 100, true); if (success) { Long v = (Long) tranlocal.ref_value; if (tranlocal.version != v.longValue()) { inconsistencyCount.incrementAndGet(); System.out.println("Inconsistency detected"); } if (tranlocal.hasDepartObligation) { ref.departAfterReading(); } } k++; if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } class UpdateThread extends TestThread { public UpdateThread(int id) { super("UpdateThread-" + id); } @Override public void doRun() throws Exception { int k = 0; while (!stop) { int arriveStatus = ref.arriveAndLock(1, LOCKMODE_EXCLUSIVE); if (arriveStatus == FAILURE) { continue; } Long value = ref.version + 1; ref.ref_value = value; ref.version = value; ref.departAfterUpdateAndUnlock(); k++; if (k % 100000 == 0) { System.out.printf("%s is at %s\n", getName(), k); } } } } } GammaTxnRef_constructionTest.java000066400000000000000000000071771174000617100450660ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.SpeculativeConfigurationError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaTestUtils; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class GammaTxnRef_constructionTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenInitialValueUsed() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); GammaTestUtils.assertVersionAndValue(ref, GammaConstants.VERSION_UNCOMMITTED + 1, initialValue); assertRefHasNoLocks(ref); assertReadonlyCount(ref, 0); assertSurplus(ref, 0); } @Test public void whenDefaultValueUsed() { GammaTxnRef ref = new GammaTxnRef(stm); assertVersionAndValue(ref, GammaConstants.VERSION_UNCOMMITTED + 1, null); assertRefHasNoLocks(ref); assertReadonlyCount(ref, 0); assertSurplus(ref, 0); } @Test public void withTransaction_whenFatMonoGammaTxnUsed() { FatMonoGammaTxn tx = new FatMonoGammaTxn(stm); GammaTxnRef ref = new GammaTxnRef(tx, 10); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tx.hasWrites); assertFalse(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } @Test public void withTransaction_whenFatFixedLengthGammaTxnUsed() { FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(stm); GammaTxnRef ref = new GammaTxnRef(tx, 10); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tx.hasWrites); assertFalse(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } @Test public void withTransaction_whenFatVariableLengthGammaTxnUsed() { FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(stm); GammaTxnRef ref = new GammaTxnRef(tx, 10); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tx.hasWrites); assertFalse(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } @Test public void withTransaction_whenLeanFixedLengthGammaTxnUsed() { LeanFixedLengthGammaTxn tx = new LeanFixedLengthGammaTxn(stm); try { new GammaTxnRef(tx, 10); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } @Test public void withTransaction_whenLeanMonoGammaTxnUsed() { LeanMonoGammaTxn tx = new LeanMonoGammaTxn(stm); try { new GammaTxnRef(tx, 10); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.config.speculativeConfiguration.get().constructedObjectsDetected); } } GammaTxnRef_getAndAlterTest.java000066400000000000000000000003151174000617100445110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Ignore; import org.junit.Test; public class GammaTxnRef_getAndAlterTest { @Test @Ignore public void test(){} } GammaTxnRef_getAndLock2Test.java000066400000000000000000000024621174000617100444210ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertEquals; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasLockMode; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnRef_getAndLock2Test { private GammaStm stm; @Before public void setUp(){ stm = new GammaStm(); } @Test public void whenLockFree(){ whenLockFree(LockMode.None); whenLockFree(LockMode.Read); whenLockFree(LockMode.Write); whenLockFree(LockMode.Exclusive); } public void whenLockFree(LockMode lockMode){ long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); long result = ref.getAndLock(tx, lockMode); assertEquals(initialValue,result); assertVersionAndValue(ref,initialVersion, initialValue); assertRefHasLockMode(ref, tx, lockMode.asInt()); } } GammaTxnRef_getAndSetAndLock3Test.java000066400000000000000000000030551174000617100455200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertSame; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasLockMode; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnRef_getAndSetAndLock3Test { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenLockFree() { whenLockFree(LockMode.None); whenLockFree(LockMode.Read); whenLockFree(LockMode.Write); whenLockFree(LockMode.Exclusive); } public void whenLockFree(LockMode lockMode) { String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); String newValue = "newValue"; String result = ref.getAndSetAndLock(tx, newValue, lockMode); Tranlocal tranlocal = tx.locate(ref); assertSame(initialValue, result); assertSame(newValue, tranlocal.ref_value); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, lockMode.asInt()); } } GammaTxnRef_getTest.java000066400000000000000000000055531174000617100431070ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnRef_getTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test @Ignore public void locked() { } @Test @Ignore public void locked_writeLockAcquired() { } @Test @Ignore public void locked_readLockAcquired() { } @Test @Ignore public void locked_exclusiveLockAcquired() { } @Test public void whenTransactionPrepared_thenPreparedTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); try { ref.get(tx); fail(); } catch (PreparedTxnException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertIsAborted(tx); } @Test public void whenTransactionCommitted_thenDeadTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); try { ref.get(tx); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertIsCommitted(tx); } @Test public void whenTransactionAborted_thenDeadTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.get(tx); fail(); } catch (DeadTxnException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertIsAborted(tx); } } GammaTxnRef_isNullTest.java000066400000000000000000000077571174000617100436060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.TxnMandatoryException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.*; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnRef_isNullTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenNoTransactionAvailableAndNullValue_thenNoTransactionFoundException() { GammaTxnRef ref = new GammaTxnRef(stm); long initialVersion = ref.getVersion(); try { ref.isNull(); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, null); } @Test public void whenNoTransactionAvailableAndValue_thenNoTransactionFoundException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.isNull(); fail(); } catch (TxnMandatoryException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenActiveTransactionAvailable() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); assertFalse(ref.isNull()); ref.set(tx, null); assertTrue(ref.isNull()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPreparedTransactionAvailable_thenPreparedTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.prepare(); try { ref.isNull(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertEquals(initialVersion, ref.getVersion()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenCommittedTransactionAvailable_thenDeadTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.commit(); setThreadLocalTxn(tx); try { ref.isNull(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAbortedTransactionAvailable_thenDeadTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); tx.abort(); setThreadLocalTxn(tx); try { ref.isNull(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertSame(tx, getThreadLocalTxn()); assertVersionAndValue(ref, initialVersion, initialValue); } } GammaTxnRef_setAndLock3Test.java000066400000000000000000000025661174000617100444430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertSame; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasLockMode; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnRef_setAndLock3Test { private GammaStm stm; @Before public void setUp(){ stm = new GammaStm(); } @Test public void whenLockFree(){ whenLockFree(LockMode.None); whenLockFree(LockMode.Read); whenLockFree(LockMode.Write); whenLockFree(LockMode.Exclusive); } public void whenLockFree(LockMode lockMode){ String initialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); String newValue = "newValue"; String result = ref.setAndLock(tx, newValue,lockMode); assertSame(newValue, result); assertVersionAndValue(ref,initialVersion, initialValue); assertRefHasLockMode(ref, tx, lockMode.asInt()); } } GammaTxnRef_setTest.java000066400000000000000000000062441174000617100431210ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnRef_setTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void test() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); long initialOrec = ref.orec; GammaTxn tx = stm.newDefaultTxn(); String newValue = "bar"; String result = ref.set(tx, newValue); assertSame(newValue, result); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); long initialOrec = ref.orec; GammaTxn tx = stm.newDefaultTxn(); tx.prepare(); try { ref.set(tx, "bar"); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertEquals(initialOrec, ref.orec); } @Test public void whenTransactionAborted_thenDeadTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); long initialOrec = ref.orec; GammaTxn tx = stm.newDefaultTxn(); tx.abort(); try { ref.set(tx, "bar"); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertEquals(initialOrec, ref.orec); } @Test public void whenTransactionCommitted_thenDeadTxnException() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); long initialOrec = ref.orec; GammaTxn tx = stm.newDefaultTxn(); tx.commit(); try { ref.set(tx, "bar"); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertEquals(initialOrec, ref.orec); } } GammaTxnRef_toDebugStringTest.java000066400000000000000000000022301174000617100450750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import static org.junit.Assert.assertEquals; public class GammaTxnRef_toDebugStringTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void testNullValue() { GammaTxnRef ref = new GammaTxnRef(stm); String s = ref.toDebugString(); assertEquals("GammaTxnRef{orec=Orec(hasExclusiveLock=false, hasWriteLock=false, readLocks=0, surplus=0, " + "isReadBiased=false, readonlyCount=0), version=1, value=null, hasListeners=false)", s); } @Test public void testNonNullValue() { GammaTxnRef ref = new GammaTxnRef(stm,"foo"); String s = ref.toDebugString(); assertEquals("GammaTxnRef{orec=Orec(hasExclusiveLock=false, hasWriteLock=false, readLocks=0, surplus=0, " + "isReadBiased=false, readonlyCount=0), version=1, value=foo, hasListeners=false)", s); } } TxnRefAwaitThread.java000066400000000000000000000024131174000617100425530ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionalobjects/txnrefpackage org.multiverse.stms.gamma.transactionalobjects.txnref; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.predicates.Predicate; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; public class TxnRefAwaitThread extends TestThread { private final GammaTxnRef ref; private final Predicate predicate; public TxnRefAwaitThread(GammaTxnRef ref, final T awaitValue) { this(ref, new Predicate() { @Override public boolean evaluate(T current) { return current == awaitValue; } }); } public TxnRefAwaitThread(GammaTxnRef ref, Predicate predicate) { this.ref = ref; this.predicate = predicate; } @Override public void doRun() throws Exception { ref.getStm().getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { System.out.println("Starting wait and ref.value found: " + ref.get()); ref.await(predicate); System.out.println("Finished wait and ref.value found: " + ref.get()); } }); } } Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/000077500000000000000000000000001174000617100334315ustar00rootroot00000000000000GammaTxnConfigTest.java000066400000000000000000000025021174000617100377160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaStmConfig; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * @author Peter Veentjer */ public class GammaTxnConfigTest { @Test public void testIsRichMansConflictScanRequired() { GammaStmConfig stmConfig = new GammaStmConfig(); stmConfig.maximumPoorMansConflictScanLength = 0; stmConfig.speculativeConfigEnabled = true; GammaStm stm = new GammaStm(stmConfig); GammaTxnConfig txConfig = new GammaTxnConfig(stm, stmConfig); txConfig.init(); assertTrue(txConfig.speculativeConfiguration.get().richMansConflictScanRequired); } @Test public void testIsRichMansConflictScanRequiredIfMaximumPoorMansConflictScanLengthIsZero() { GammaStmConfig stmConfig = new GammaStmConfig(); stmConfig.maximumPoorMansConflictScanLength = 10; stmConfig.speculativeConfigEnabled = true; stmConfig.dirtyCheck = false; GammaStm stm = new GammaStm(stmConfig); GammaTxnConfig txConfig = new GammaTxnConfig(stm, stmConfig); txConfig.init(); assertFalse(txConfig.speculativeConfiguration.get().richMansConflictScanRequired); } } SpeculativeGammaConfigurationTest.java000066400000000000000000000143761174000617100430470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactionspackage org.multiverse.stms.gamma.transactions; import org.junit.Test; import static org.junit.Assert.*; public class SpeculativeGammaConfigurationTest { @Test public void whenLean() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration(); assertFalse(config.fat); assertFalse(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertFalse(config.orelseDetected); assertFalse(config.listenersDetected); assertFalse(config.locksDetected); assertFalse(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } @Test public void newWithNonRefType() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithNonRefType(); assertTrue(config.fat); assertTrue(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertFalse(config.orelseDetected); assertFalse(config.listenersDetected); assertFalse(config.locksDetected); assertFalse(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } @Test public void newWithEnsure() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithEnsure(); assertTrue(config.fat); assertFalse(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertFalse(config.orelseDetected); assertFalse(config.listenersDetected); assertFalse(config.locksDetected); assertFalse(config.abortOnlyDetected); assertTrue(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } @Test public void newWithAbortOnly() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithAbortOnly(); assertTrue(config.fat); assertFalse(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertFalse(config.orelseDetected); assertFalse(config.listenersDetected); assertFalse(config.locksDetected); assertTrue(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } @Test public void newWithCommute() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithCommute(); assertTrue(config.fat); assertFalse(config.nonRefTypeDetected); assertTrue(config.commuteDetected); assertFalse(config.orelseDetected); assertFalse(config.listenersDetected); assertFalse(config.locksDetected); assertFalse(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } @Test public void newListListeners() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithListeners(); assertTrue(config.fat); assertFalse(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertFalse(config.orelseDetected); assertTrue(config.listenersDetected); assertFalse(config.locksDetected); assertFalse(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } @Test public void newWithOrElse() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithOrElse(); assertTrue(config.fat); assertFalse(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertTrue(config.orelseDetected); assertFalse(config.listenersDetected); assertFalse(config.locksDetected); assertFalse(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } @Test public void newWithMinimalLength() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithMinimalLength(10); assertFalse(config.fat); assertFalse(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertFalse(config.orelseDetected); assertFalse(config.listenersDetected); assertFalse(config.locksDetected); assertFalse(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(10, config.minimalLength); } @Test public void newWithLocks() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithLocks(); assertTrue(config.fat); assertFalse(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertFalse(config.orelseDetected); assertFalse(config.listenersDetected); assertTrue(config.locksDetected); assertFalse(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertFalse(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } @Test public void newWithConstructedObjects() { SpeculativeGammaConfiguration config = new SpeculativeGammaConfiguration() .newWithConstructedObjects(); assertTrue(config.fat); assertFalse(config.nonRefTypeDetected); assertFalse(config.commuteDetected); assertFalse(config.orelseDetected); assertFalse(config.listenersDetected); assertFalse(config.locksDetected); assertFalse(config.abortOnlyDetected); assertFalse(config.ensureDetected); assertTrue(config.constructedObjectsDetected); assertEquals(1, config.minimalLength); } } 000077500000000000000000000000001174000617100341245ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatFatFixedLengthGammaTxnFactory.java000066400000000000000000000031431174000617100426110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.api.TxnFactoryBuilder; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.GammaTxnPool; import static org.multiverse.stms.gamma.transactions.ThreadLocalGammaTxnPool.getThreadLocalGammaTxnPool; public class FatFixedLengthGammaTxnFactory implements GammaTxnFactory { private final GammaTxnConfig config; public FatFixedLengthGammaTxnFactory(GammaStm stm) { this(new GammaTxnConfig(stm)); } public FatFixedLengthGammaTxnFactory(GammaTxnConfig config) { this.config = config.init(); } @Override public GammaTxnConfig getConfig() { return config; } @Override public GammaTxn upgradeAfterSpeculativeFailure(GammaTxn failingTransaction, GammaTxnPool pool) { throw new UnsupportedOperationException(); } @Override public TxnFactoryBuilder getTxnFactoryBuilder() { throw new UnsupportedOperationException(); } @Override public FatFixedLengthGammaTxn newTxn() { return newTransaction(getThreadLocalGammaTxnPool()); } @Override public FatFixedLengthGammaTxn newTransaction(GammaTxnPool pool) { FatFixedLengthGammaTxn tx = pool.takeFatFixedLength(); if (tx == null) { tx = new FatFixedLengthGammaTxn(config); } else { tx.init(config); } return tx; } }FatFixedLengthGammaTxn_abortTest.java000066400000000000000000000014731174000617100433140ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.assertNull; public class FatFixedLengthGammaTxn_abortTest extends FatGammaTxn_abortTest { @Override protected void assertCleaned(FatFixedLengthGammaTxn tx) { Tranlocal node = tx.head; while (node != null) { assertNull(node.owner); node = node.next; } } @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Override protected FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } } FatFixedLengthGammaTxn_commitTest.java000066400000000000000000000033351174000617100434740ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Test; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.assertNull; import static org.multiverse.stms.gamma.GammaTestUtils.assertSurplus; public class FatFixedLengthGammaTxn_commitTest extends FatGammaTxn_commitTest { @Override protected void assertCleaned(FatFixedLengthGammaTxn tx) { Tranlocal node = tx.head; while (node != null) { assertNull(node.owner); node = node.next; } } @Override protected FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Test public void richmansConflict_multipleReadsOnSameRef() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatVariableLengthGammaTxn tx1 = new FatVariableLengthGammaTxn(config); FatVariableLengthGammaTxn tx2 = new FatVariableLengthGammaTxn(config); FatVariableLengthGammaTxn tx3 = new FatVariableLengthGammaTxn(config); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); ref.openForRead(tx1, LOCKMODE_NONE); ref.openForRead(tx2, LOCKMODE_NONE); ref.openForRead(tx3, LOCKMODE_NONE); ref.set(tx, 1); tx.commit(); assertSurplus(ref, 3); } } FatFixedLengthGammaTxn_commuteTest.java000066400000000000000000000011621174000617100436510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatFixedLengthGammaTxn_commuteTest extends FatGammaTxn_commuteTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Override protected FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } @Override protected int getMaxCapacity() { return new GammaTxnConfig(stm).maxFixedLengthTransactionSize; } } FatFixedLengthGammaTxn_hardResetTest.java000066400000000000000000000004771174000617100441310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxn; public class FatFixedLengthGammaTxn_hardResetTest extends FatGammaTxn_hardResetTest { @Override protected GammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } } FatFixedLengthGammaTxn_initTest.java000066400000000000000000000004271174000617100431460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatFixedLengthGammaTxn_initTest extends FatGammaTxn_initTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } } FatFixedLengthGammaTxn_isAbortOnlyTest.java000066400000000000000000000004461174000617100444510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatFixedLengthGammaTxn_isAbortOnlyTest extends FatGammaTxn_isAbortOnlyTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } } FatFixedLengthGammaTxn_locateTest.java000066400000000000000000000004341174000617100434500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatFixedLengthGammaTxn_locateTest extends FatGammaTxn_locateTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } } FatFixedLengthGammaTxn_openForConstructionTest.java000066400000000000000000000010221174000617100462160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatFixedLengthGammaTxn_openForConstructionTest extends FatGammaTxn_openForConstructionTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Override protected FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } } FatFixedLengthGammaTxn_openForReadTest.java000066400000000000000000000121161174000617100444050ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class FatFixedLengthGammaTxn_openForReadTest extends FatGammaTxn_openForReadTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Override protected FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } @Override protected int getMaxCapacity() { return new GammaTxnConfig(stm).maxFixedLengthTransactionSize; } @Test public void richmansConflict_multipleReadsOnSameRef() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatFixedLengthGammaTxn tx1 = new FatFixedLengthGammaTxn(config); FatFixedLengthGammaTxn tx2 = new FatFixedLengthGammaTxn(config); FatFixedLengthGammaTxn tx3 = new FatFixedLengthGammaTxn(config); ref.openForRead(tx1, LOCKMODE_NONE); ref.openForRead(tx2, LOCKMODE_NONE); ref.openForRead(tx3, LOCKMODE_NONE); assertSurplus(ref, 3); } @Test public void richmansConflictScan_whenFirstRead() { causeLotsOfConflicts(stm); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertTrue(tranlocal.hasDepartObligation); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_READ, tranlocal.mode); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertIsActive(tx); assertTrue(tx.hasReads); assertEquals(stm.getGlobalConflictCounter().count(), tx.localConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void richmansConflictScan_whenUnrealConflict() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); long initialValue2 = 10; GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue2); long initialVersion2 = ref2.getVersion(); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); ref1.openForRead(tx, LOCKMODE_NONE); causeLotsOfConflicts(stm); long newConflictCount = stm.getGlobalConflictCounter().count(); Tranlocal tranlocal2 = ref2.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal2); assertTrue(tranlocal2.hasDepartObligation); assertEquals(initialValue2, tranlocal2.long_value); assertEquals(initialValue2, tranlocal2.long_oldValue); assertEquals(LOCKMODE_NONE, tranlocal2.lockMode); assertEquals(TRANLOCAL_READ, tranlocal2.mode); assertSurplus(ref2, 1); assertWriteBiased(ref2); assertReadonlyCount(ref2, 0); assertIsActive(tx); assertTrue(tx.hasReads); assertEquals(newConflictCount, tx.localConflictCount); assertVersionAndValue(ref2, initialVersion2, initialValue2); assertRefHasNoLocks(ref2); } @Test public void richmansConflictScan_whenConflict() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); long initialValue2 = 10; GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue2); long initialVersion2 = ref2.getVersion(); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); ref1.openForRead(tx, LOCKMODE_NONE); ref1.atomicIncrementAndGet(1); try { ref2.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertSurplus(ref2, 0); assertWriteBiased(ref2); assertReadonlyCount(ref2, 0); assertIsAborted(tx); assertVersionAndValue(ref2, initialVersion2, initialValue2); assertRefHasNoLocks(ref2); } } FatFixedLengthGammaTxn_openForWriteTest.java000066400000000000000000000122001174000617100446160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class FatFixedLengthGammaTxn_openForWriteTest extends FatGammaTxn_openForWriteTest { @Override protected GammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } @Override protected GammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Override protected int getMaxCapacity() { return new GammaTxnConfig(stm).maxFixedLengthTransactionSize; } @Test public void richmansConflict_multipleReadsOnSameRef() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatFixedLengthGammaTxn tx1 = new FatFixedLengthGammaTxn(config); FatFixedLengthGammaTxn tx2 = new FatFixedLengthGammaTxn(config); FatFixedLengthGammaTxn tx3 = new FatFixedLengthGammaTxn(config); ref.openForWrite(tx1, LOCKMODE_NONE); ref.openForWrite(tx2, LOCKMODE_NONE); ref.openForWrite(tx3, LOCKMODE_NONE); assertSurplus(ref, 3); } @Test public void richmansConflictScan_whenFirstRead() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertTrue(tranlocal.hasDepartObligation); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_WRITE, tranlocal.mode); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertIsActive(tx); assertTrue(tx.hasReads); assertEquals(stm.getGlobalConflictCounter().count(), tx.localConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void richmansConflictScan_whenUnrealConflict() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); long initialValue2 = 10; GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue2); long initialVersion2 = ref2.getVersion(); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); ref1.openForRead(tx, LOCKMODE_NONE); causeLotsOfConflicts(stm); long newConflictCount = stm.getGlobalConflictCounter().count(); Tranlocal tranlocal2 = ref2.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal2); assertTrue(tranlocal2.hasDepartObligation); assertEquals(initialValue2, tranlocal2.long_value); assertEquals(initialValue2, tranlocal2.long_oldValue); assertEquals(LOCKMODE_NONE, tranlocal2.lockMode); assertEquals(TRANLOCAL_WRITE, tranlocal2.mode); assertSurplus(ref2, 1); assertWriteBiased(ref2); assertReadonlyCount(ref2, 0); assertIsActive(tx); assertTrue(tx.hasReads); assertEquals(newConflictCount, tx.localConflictCount); assertVersionAndValue(ref2, initialVersion2, initialValue2); assertRefHasNoLocks(ref2); } @Test public void richmansConflictScan_whenConflict() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); long initialValue2 = 10; GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue2); long initialVersion2 = ref2.getVersion(); FatFixedLengthGammaTxn tx = new FatFixedLengthGammaTxn(config); ref1.openForWrite(tx, LOCKMODE_NONE); ref1.atomicIncrementAndGet(1); try { ref2.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertSurplus(ref2, 0); assertWriteBiased(ref2); assertReadonlyCount(ref2, 0); assertIsAborted(tx); assertVersionAndValue(ref2, initialVersion2, initialValue2); assertRefHasNoLocks(ref2); } } FatFixedLengthGammaTxn_prepareTest.java000066400000000000000000000007621174000617100436430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatFixedLengthGammaTxn_prepareTest extends FatGammaTxn_prepareTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Override protected FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } } FatFixedLengthGammaTxn_registerTest.java000066400000000000000000000004401174000617100440220ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatFixedLengthGammaTxn_registerTest extends FatGammaTxn_registerTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } } FatFixedLengthGammaTxn_retryTest.java000066400000000000000000000007561174000617100433550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatFixedLengthGammaTxn_retryTest extends FatGammaTxn_retryTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Override protected FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } } FatFixedLengthGammaTxn_setAbortOnlyTest.java000066400000000000000000000007741174000617100446350ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatFixedLengthGammaTxn_setAbortOnlyTest extends FatGammaTxn_setAbortOnlyTest { @Override protected FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } @Override protected FatFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatFixedLengthGammaTxn(config); } } FatFixedLengthGammaTxn_softResetTest.java000066400000000000000000000004361174000617100441610ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatFixedLengthGammaTxn_softResetTest extends FatGammaTxn_softResetTest { @Override public FatFixedLengthGammaTxn newTransaction() { return new FatFixedLengthGammaTxn(stm); } } FatFixedLengthGammaTxn_stressTest.java000066400000000000000000000054611174000617100435310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import java.util.Random; import static org.junit.Assert.assertEquals; public class FatFixedLengthGammaTxn_stressTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void newTransaction_whenMultipleUpdatesAndDirtyCheckEnabled() { integrationTest_whenMultipleUpdatesAndDirtyCheck(true, false); } @Test public void newTransaction_whenMultipleUpdatesAndDirtyCheckDisabled() { integrationTest_whenMultipleUpdatesAndDirtyCheck(false, false); } @Test public void reuseTransaction_whenMultipleUpdatesAndDirtyCheckEnabled() { integrationTest_whenMultipleUpdatesAndDirtyCheck(true, true); } @Test public void reuseTransaction_whenMultipleUpdatesAndDirtyCheckDisabled() { integrationTest_whenMultipleUpdatesAndDirtyCheck(false, true); } public void integrationTest_whenMultipleUpdatesAndDirtyCheck(final boolean dirtyCheck, final boolean transactionReuse) { GammaTxnLong[] refs = new GammaTxnLong[30]; long created = 0; //create the references for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnLong(stm, 0); } Random random = new Random(); int transactionCount = 100000; GammaTxnConfig config = new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(refs.length); config.dirtyCheck = dirtyCheck; FatFixedLengthGammaTxn tx = null; for (int transaction = 0; transaction < transactionCount; transaction++) { if (transactionReuse) { if (tx == null) { tx = new FatFixedLengthGammaTxn(config); } } else { tx = new FatFixedLengthGammaTxn(config); } for (int k = 0; k < refs.length; k++) { if (random.nextInt(3) == 1) { refs[k].openForWrite(tx, LOCKMODE_NONE).long_value++; created++; } else { refs[k].openForWrite(tx, LOCKMODE_NONE); } } tx.commit(); tx.hardReset(); if (transaction % 1000 == 0) { System.out.println("at " + transaction); } } long sum = 0; for (int k = 0; k < refs.length; k++) { sum += refs[k].atomicGet(); } assertEquals(created, sum); } } FatGammaTxn_abortTest.java000066400000000000000000000126251174000617100411730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.functions.LongFunction; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_abortTest implements GammaConstants { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); protected abstract void assertCleaned(T tx); @Test public void listener_whenNormalListenerAvailable() { T tx = newTransaction(); TxnListener listener = mock(TxnListener.class); tx.register(listener); tx.abort(); assertIsAborted(tx); //verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PostAbort); } @Test public void listener_whenPermanentListenerAvailable() { TxnListener listener = mock(TxnListener.class); GammaTxnConfig config = new GammaTxnConfig(stm) .addPermanentListener(listener); T tx = newTransaction(config); tx.abort(); assertIsAborted(tx); //verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PostAbort); } @Test public void whenUnused() { T tx = newTransaction(); tx.abort(); assertEquals(TxnStatus.Aborted, tx.getStatus()); } @Test public void locking_whenHasConstructed_thenRemainLocked() { GammaTxn tx = newTransaction(); GammaTxnLong ref = new GammaTxnLong(tx); Tranlocal write = tx.getRefTranlocal(ref); tx.abort(); assertIsAborted(tx); assertLockMode(ref, LOCKMODE_EXCLUSIVE); assertSurplus(ref, 1); assertWriteBiased(ref); assertVersionAndValue(ref, 0, 0); assertFalse(write.hasDepartObligation()); assertTrue(write.isConstructing()); } @Test public void whenContainsCommutes() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); LongFunction function = mock(LongFunction.class); ref.commute(tx, function); Tranlocal tranlocal = tx.getRefTranlocal(ref); tx.abort(); assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.headCallable); } @Test public void whenHasRead() { whenHasRead(LockMode.None); whenHasRead(LockMode.Read); whenHasRead(LockMode.Write); whenHasRead(LockMode.Exclusive); } public void whenHasRead(LockMode readLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, readLockMode.asInt()); tx.abort(); assertIsAborted(tx); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertNull(tranlocal.owner); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.getVersion()); assertCleaned(tx); } @Test public void whenHasWrite() { whenHasWrite(LockMode.None); whenHasWrite(LockMode.Read); whenHasWrite(LockMode.Write); whenHasWrite(LockMode.Exclusive); } public void whenHasWrite(LockMode writeLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, writeLockMode.asInt()); tx.abort(); assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertNull(tranlocal.owner); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.getVersion()); assertCleaned(tx); } @Test public void whenAborted() { T tx = newTransaction(); tx.abort(); tx.abort(); assertEquals(TxnStatus.Aborted, tx.getStatus()); assertCleaned(tx); } @Test public void whenCommitted_thenDeadTxnException() { T tx = newTransaction(); tx.commit(); try { tx.abort(); fail(); } catch (DeadTxnException expected) { } assertEquals(TxnStatus.Committed, tx.getStatus()); assertCleaned(tx); } } FatGammaTxn_commitTest.java000066400000000000000000000720371174000617100413570ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.SomeError; import org.multiverse.SomeUncheckedException; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.AbortOnlyException; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.RetryError; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.*; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_commitTest implements GammaConstants { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); protected abstract void assertCleaned(T transaction); @Test public void listener_whenNormalListenerAvailable() { T tx = newTransaction(); TxnListener listener = mock(TxnListener.class); tx.register(listener); tx.commit(); assertIsCommitted(tx); verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PostCommit); } @Test public void listener_whenPermanentListenerAvailable() { TxnListener listener = mock(TxnListener.class); GammaTxnConfig config = new GammaTxnConfig(stm) .addPermanentListener(listener); T tx = newTransaction(config); tx.commit(); assertIsCommitted(tx); verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PostCommit); } @Test public void retryListeners_whenDirtyWrite_thenListenersNotified() { retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.None, LockMode.None); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.None, LockMode.Read); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.None, LockMode.Write); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.None, LockMode.Exclusive); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Read, LockMode.Read); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Read, LockMode.Write); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Read, LockMode.Exclusive); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Write, LockMode.Write); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Write, LockMode.Exclusive); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Exclusive, LockMode.Exclusive); } public void retryListeners_whenDirtyWrite_thenListenersNotified(LockMode readLockMode, LockMode writeLockMode) { String oldValue = "oldvalue"; GammaTxnRef ref = new GammaTxnRef(stm, oldValue); long initialVersion = ref.getVersion(); GammaTxn waitingTx = newTransaction(); ref.get(waitingTx); try { waitingTx.retry(); fail(); } catch (RetryError expected) { } GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(readLockMode) .setWriteLockMode(writeLockMode); GammaTxn tx = newTransaction(config); String newValue = "newvalue"; ref.set(tx, newValue); tx.commit(); assertTrue(waitingTx.retryListener.isOpen()); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void conflict_whenArriveByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); long newValue = 1; ref.set(tx, newValue); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatVariableLengthGammaTxn otherTx = new FatVariableLengthGammaTxn(config); ref.get(otherTx); long globalConflictCount = stm.globalConflictCounter.count(); tx.commit(); assertGlobalConflictCount(stm, globalConflictCount + 1); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenContainsConstructedIntRef() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsConstructedBooleanRef() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); boolean initialValue = true; GammaTxnBoolean ref = new GammaTxnBoolean(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsConstructedTxnDouble() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsConstructedRef() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsConstructedLongRef() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenCommuteThrowsRuntimeException() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); LongFunction function = mock(LongFunction.class); when(function.call(initialValue)).thenThrow(new SomeUncheckedException()); ref.commute(tx, function); try { tx.commit(); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenCommuteThrowsError() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); LongFunction function = mock(LongFunction.class); when(function.call(initialValue)).thenThrow(new SomeError()); ref.commute(tx, function); try { tx.commit(); fail(); } catch (SomeError expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsCommute() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); ref.commute(tx, Functions.incLongFunction()); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void abortOnly_whenUnused() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.setAbortOnly(); try { tx.commit(); fail(); } catch (AbortOnlyException expected) { } assertIsAborted(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void abortOnly_whenDirty() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.setAbortOnly(); try { ref.set(tx, initialValue + 1); tx.commit(); fail(); } catch (AbortOnlyException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenBooleanRef() { long globalConflictCount = stm.globalConflictCounter.count(); boolean initialValue = false; GammaTxnBoolean ref = new GammaTxnBoolean(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.set(tx, true); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, true); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenIntRef() { long globalConflictCount = stm.globalConflictCounter.count(); int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.set(tx, initialValue + 1); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenLongRef() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.set(tx, initialValue + 1); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenTxnDouble() { long globalConflictCount = stm.globalConflictCounter.count(); double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.set(tx, initialValue + 1); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenRef() { long globalConflictCount = stm.globalConflictCounter.count(); String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); String newValue = "bar"; ref.set(tx, newValue); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, "bar"); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsListener() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn listeningTx = newTransaction(); ref.openForRead(listeningTx, LOCKMODE_NONE); try { listeningTx.retry(); fail(); } catch (RetryError retry) { } GammaTxn tx = newTransaction(); ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); assertTrue(listeningTx.retryListener.isOpen()); assertNull(getField(ref, "listeners")); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenUnused() { long globalConflictCount = stm.globalConflictCounter.count(); GammaTxn tx = newTransaction(); tx.commit(); assertEquals(TxnStatus.Committed, tx.getStatus()); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenConflict() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; //a conflicting write. T otherTx = newTransaction(); ref.openForWrite(otherTx, LOCKMODE_NONE).long_value++; otherTx.commit(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } //todo: dirty checking //todo: lock releasing @Test public void whenContainsDirtyWrite() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; tx.commit(); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenMultipleCommitsUsingNewTransaction() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); int txCount = 10; for (int k = 0; k < txCount; k++) { T tx = newTransaction(); ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); } assertEquals(initialValue + txCount, ref.long_value); assertEquals(initialVersion + txCount, ref.version); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenMultipleCommitsUsingSame() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); int txCount = 10; T tx = newTransaction(); for (int k = 0; k < txCount; k++) { ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); tx.hardReset(); } assertEquals(initialValue + txCount, ref.long_value); assertEquals(initialVersion + txCount, ref.version); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenPreparedAndContainsRead() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); tx.prepare(); tx.commit(); assertNull(tranlocal.owner); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenPreparedAndContainsWrite() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; tx.prepare(); tx.commit(); assertNull(tranlocal.owner); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } // ================================ dirty check ================================ @Test public void whenContainsRead() { whenContainsRead(true, LockMode.None); whenContainsRead(true, LockMode.Read); whenContainsRead(true, LockMode.Write); whenContainsRead(true, LockMode.Exclusive); whenContainsRead(false, LockMode.None); whenContainsRead(false, LockMode.Read); whenContainsRead(false, LockMode.Write); whenContainsRead(false, LockMode.Exclusive); } public void whenContainsRead(boolean prepareFirst, LockMode readLockMode) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, readLockMode.asInt()); if (prepareFirst) { tx.prepare(); } tx.commit(); assertIsCommitted(tx); assertLockMode(ref, LockMode.None); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertVersionAndValue(ref, initialVersion, initialValue); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } // ================================ dirty check ================================ @Test public void dirty_whenNoDirtyCheckAndNoDirtyWrite() { dirty_whenNoDirtyCheckAndNoDirtyWrite(true); dirty_whenNoDirtyCheckAndNoDirtyWrite(false); } public void dirty_whenNoDirtyCheckAndNoDirtyWrite(boolean prepareFirst) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.dirtyCheck = false; T tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); if (prepareFirst) { tx.prepare(); } tx.commit(); assertNull(tranlocal.owner); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirty_whenNoDirtyCheckAndDirtyWrite() { dirty_whenNoDirtyCheckAndDirtyWrite(true); dirty_whenNoDirtyCheckAndDirtyWrite(false); } public void dirty_whenNoDirtyCheckAndDirtyWrite(boolean prepareFirst) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.dirtyCheck = false; T tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; if (prepareFirst) { tx.prepare(); } tx.commit(); assertNull(tranlocal.owner); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertCleaned(tx); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirty_whenDirtyCheckAndNoDirtyWrite() { dirty_whenDirtyCheckAndNoDirtyWrite(true); dirty_whenDirtyCheckAndNoDirtyWrite(false); } public void dirty_whenDirtyCheckAndNoDirtyWrite(boolean prepareFirst) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.dirtyCheck = true; T tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); if (prepareFirst) { tx.prepare(); } tx.commit(); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); assertCleaned(tx); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirty_whenDirtyCheckAndDirtyWrite() { dirty_whenDirtyCheckAndDirtyWrite(true); dirty_whenDirtyCheckAndDirtyWrite(false); } public void dirty_whenDirtyCheckAndDirtyWrite(boolean prepareFirst) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.dirtyCheck = true; T tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; if (prepareFirst) { tx.prepare(); } tx.commit(); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } // =============================== locked by other ============================= @Test public void conflict_dirty_whenReadLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_READ); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void conflict_dirty_whenWriteLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_WRITE); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void conflict_dirty_whenExclusiveLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_EXCLUSIVE); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); assertGlobalConflictCount(stm, globalConflictCount); } // ========================= states ================================== @Test public void whenPreparedAndUnused() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.prepare(); tx.commit(); assertIsCommitted(tx); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAborted_thenDeadTxnException() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.abort(); try { tx.commit(); fail(); } catch (DeadTxnException expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenCommitted_thenIgnored() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.commit(); tx.commit(); assertEquals(TxnStatus.Committed, tx.getStatus()); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } } FatGammaTxn_commuteTest.java000066400000000000000000000377131174000617100415420ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.SomeUncheckedException; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.*; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.GammaTestUtils; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.LOCKMODE_NONE; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_commuteTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); protected abstract int getMaxCapacity(); @Test public void whenTransactionAbortOnly_thenWriteStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 0); GammaTxn tx = stm.newDefaultTxn(); tx.setAbortOnly(); ref.commute(tx, Functions.incLongFunction()); Tranlocal tranlocal = tx.locate(ref); assertNotNull(tranlocal); assertEquals(TRANLOCAL_COMMUTING, tranlocal.getMode()); assertTrue(tx.isAbortOnly()); assertIsActive(tx); } @Test public void whenMultipleCommutesOnSingleRef() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.commute(tx, Functions.incLongFunction()); ref.commute(tx, Functions.incLongFunction()); ref.commute(tx, Functions.incLongFunction()); tx.commit(); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 3); } @Test public void whenAlreadyOpenedForRead() { whenAlreadyOpenedForRead(LockMode.None); whenAlreadyOpenedForRead(LockMode.Read); whenAlreadyOpenedForRead(LockMode.Write); whenAlreadyOpenedForRead(LockMode.Exclusive); } public void whenAlreadyOpenedForRead(LockMode lockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.version; GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, lockMode.asInt()); LongFunction incFunction = Functions.incLongFunction(); ref.commute(tx, incFunction); assertEquals(initialValue + 1, tranlocal.long_value); assertTrue(tx.hasWrites); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, lockMode); assertTrue(tranlocal.isWrite()); assertNull(tranlocal.headCallable); } @Test public void whenAlreadyOpenedForReadAndFunctionCausesProblem() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initalVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); LongFunction function = mock(LongFunction.class); when(function.call(anyLong())).thenThrow(new SomeUncheckedException()); try { ref.commute(tx, function); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertNull(tranlocal.owner); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initalVersion, initialValue); } @Test public void whenAlreadyOpenedForWrite() { whenAlreadyOpenedForWrite(LockMode.None); whenAlreadyOpenedForWrite(LockMode.Read); whenAlreadyOpenedForWrite(LockMode.Write); whenAlreadyOpenedForWrite(LockMode.Exclusive); } public void whenAlreadyOpenedForWrite(LockMode lockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.version; GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, lockMode.asInt()); LongFunction incFunction = Functions.incLongFunction(); ref.commute(tx, incFunction); assertEquals(initialValue + 1, tranlocal.long_value); assertTrue(tx.hasWrites); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, lockMode); assertTrue(tranlocal.isWrite()); assertNull(tranlocal.headCallable); } @Test public void whenAlreadyOpenedForWriteAndFunctionCausesProblem() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initalVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); LongFunction function = mock(LongFunction.class); when(function.call(anyLong())).thenThrow(new SomeUncheckedException()); try { ref.commute(tx, function); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertNull(tranlocal.owner); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initalVersion, initialValue); } @Test public void whenNotOpenedBefore() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); LongFunction function = mock(LongFunction.class); ref.commute(tx, function); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertTrue(tranlocal.isCommuting()); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsActive(tx); GammaTestUtils.assertHasCommutingFunctions(tranlocal, function); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForCommute() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); LongFunction function1 = mock(LongFunction.class); LongFunction function2 = mock(LongFunction.class); ref.commute(tx, function1); ref.commute(tx, function2); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertTrue(tranlocal.isCommuting()); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsActive(tx); GammaTestUtils.assertHasCommutingFunctions(tranlocal, function2, function1); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void lockedByOther() { lockedByOther(LockMode.None); lockedByOther(LockMode.Read); lockedByOther(LockMode.Write); lockedByOther(LockMode.Exclusive); } public void lockedByOther(LockMode otherLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, otherLockMode); GammaTxn tx = stm.newDefaultTxn(); LongFunction function1 = mock(LongFunction.class); LongFunction function2 = mock(LongFunction.class); ref.commute(tx, function1); ref.commute(tx, function2); Tranlocal tranlocal = tx.getRefTranlocal(ref); assertNotNull(tranlocal); assertTrue(tranlocal.isCommuting()); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsActive(tx); GammaTestUtils.assertHasCommutingFunctions(tranlocal, function2, function1); assertRefHasLockMode(ref, otherTx, otherLockMode.asInt()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForConstruction() { GammaTxn tx = newTransaction(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(tx, initialValue); Tranlocal tranlocal = tx.locate(ref); LongFunction incFunction = Functions.incLongFunction(); ref.commute(tx, incFunction); assertEquals(initialValue + 1, tranlocal.long_value); assertTrue(tx.hasWrites); assertIsActive(tx); assertVersionAndValue(ref, GammaConstants.VERSION_UNCOMMITTED, 0); assertLockMode(ref, LockMode.Exclusive); assertTrue(tranlocal.isConstructing()); assertNull(tranlocal.headCallable); } @Test public void whenAlreadyOpenedForConstructionAndFunctionCausesProblem() { GammaTxn tx = newTransaction(); LongFunction function = mock(LongFunction.class); when(function.call(anyLong())).thenThrow(new SomeUncheckedException()); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(tx, initialValue); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); try { ref.commute(tx, function); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertNull(tranlocal.owner); assertLockMode(ref, LockMode.Exclusive); assertVersionAndValue(ref, GammaConstants.VERSION_UNCOMMITTED, 0); } @Test public void whenOverflowing() { int maxCapacity = getMaxCapacity(); assumeTrue(maxCapacity < Integer.MAX_VALUE); GammaTxn tx = newTransaction(); for (int k = 0; k < maxCapacity; k++) { GammaTxnLong ref = new GammaTxnLong(stm, 0); ref.openForRead(tx, LOCKMODE_NONE); } GammaTxnLong ref = new GammaTxnLong(stm, 0); try { ref.commute(tx, Functions.incLongFunction()); fail(); } catch (SpeculativeConfigurationError expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); } @Test public void whenNullTransaction() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongFunction function = mock(LongFunction.class); try { ref.commute((FatFixedLengthGammaTxn) null, function); fail(); } catch (NullPointerException expected) { } assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, LOCKMODE_NONE); verifyZeroInteractions(function); } @Test public void whenNullFunction() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setReadonly(true); GammaTxn tx = newTransaction(config); try { ref.commute(tx, null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, LOCKMODE_NONE); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setReadonly(true); GammaTxn tx = newTransaction(config); LongFunction function = mock(LongFunction.class); try { ref.commute(tx, function); fail(); } catch (ReadonlyException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, LOCKMODE_NONE); verifyZeroInteractions(function); } @Test public void whenStmMismatch() { GammaStm otherStm = new GammaStm(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(otherStm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); LongFunction function = mock(LongFunction.class); try { ref.commute(tx, function); fail(); } catch (StmMismatchException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); verifyZeroInteractions(function); } // =========================== commuting ========================= @Test public void commuting_whenCommuting_thenFailure() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.evaluatingCommute = true; LongFunction function = mock(LongFunction.class); try { ref.commute(tx, function); fail(); } catch (IllegalCommuteException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); verifyZeroInteractions(function); } // ========================== state ============================== @Test public void whenTransactionPrepared_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); LongFunction function = mock(LongFunction.class); tx.prepare(); try { ref.commute(tx, function); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, LOCKMODE_NONE); verifyZeroInteractions(function); } @Test public void whenTransactionAborted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); LongFunction function = mock(LongFunction.class); tx.abort(); try { ref.commute(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, LOCKMODE_NONE); verifyZeroInteractions(function); } @Test public void whenTransactionCommitted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); LongFunction function = mock(LongFunction.class); tx.commit(); try { ref.commute(tx, function); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, LOCKMODE_NONE); verifyZeroInteractions(function); } } FatGammaTxn_hardResetTest.java000066400000000000000000000006161174000617100420020ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; public abstract class FatGammaTxn_hardResetTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); } FatGammaTxn_initTest.java000066400000000000000000000016401174000617100410220ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.assertSame; public abstract class FatGammaTxn_initTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); @Test(expected = NullPointerException.class) public void whenNullConfig_thenNullPointerException() { T tx = newTransaction(); tx.init(null); } @Test public void whenSuccess() { T tx = newTransaction(); GammaTxnConfig config = new GammaTxnConfig(stm); config.init(); tx.init(config); assertSame(config, tx.getConfig()); } } FatGammaTxn_isAbortOnlyTest.java000066400000000000000000000041071174000617100423250ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; public abstract class FatGammaTxn_isAbortOnlyTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); @Test public void whenActiveAndNotSetAbortOnly() { T tx = newTransaction(); boolean result = tx.isAbortOnly(); assertFalse(result); assertIsActive(tx); } @Test public void whenActiveAndSetAbortOnly() { T tx = newTransaction(); tx.setAbortOnly(); boolean result = tx.isAbortOnly(); assertTrue(result); assertIsActive(tx); } @Test public void whenPreparedAndNotSetAbortOnly() { T tx = newTransaction(); tx.prepare(); boolean result = tx.isAbortOnly(); assertFalse(result); assertIsPrepared(tx); } @Test public void whenPreparedAndSetAbortOnly_thenPreparedTxnException() { T tx = newTransaction(); tx.prepare(); try { tx.setAbortOnly(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); } @Test public void whenAborted_thenDeadTxnException() { T tx = newTransaction(); tx.abort(); try { tx.isAbortOnly(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } @Test public void whenCommitted_thenDeadTxnException() { T tx = newTransaction(); tx.commit(); try { tx.isAbortOnly(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); } } FatGammaTxn_locateTest.java000066400000000000000000000051001174000617100413210ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; public abstract class FatGammaTxn_locateTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); @Test public void whenNull_thenNullPointerException() { GammaTxn tx = newTransaction(); try { tx.locate(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); } @Test public void whenNotFound() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnLong otherRef = new GammaTxnLong(stm); GammaTxn tx = newTransaction(); ref.openForRead(tx, LOCKMODE_NONE); Tranlocal found = tx.locate(otherRef); assertNull(found); assertIsActive(tx); } @Test public void whenFound() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); Tranlocal found = tx.locate(ref); assertSame(tranlocal, found); assertIsActive(tx); } @Test public void whenAlreadyPrepared() { GammaTxn tx = newTransaction(); tx.prepare(); GammaTxnLong ref = new GammaTxnLong(stm); try { tx.locate(ref); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); } @Test public void whenAlreadyCommitted() { GammaTxn tx = newTransaction(); tx.commit(); GammaTxnLong ref = new GammaTxnLong(stm); try { tx.locate(ref); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); } @Test public void whenAlreadyAborted() { GammaTxn tx = newTransaction(); tx.abort(); GammaTxnLong ref = new GammaTxnLong(stm); try { tx.locate(ref); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } } FatGammaTxn_openForConstructionTest.java000066400000000000000000000103331174000617100441010ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.*; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_openForConstructionTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); @Test public void whenReadonlyTransaction() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setReadonly(true); GammaTxn tx = newTransaction(config); try { ref.openForConstruction(tx); fail(); } catch (ReadonlyException expected) { } assertIsAborted(tx); } @Test public void whenSuccess() { T tx = newTransaction(); long initialVersion = 10; GammaTxnLong ref = new GammaTxnLong(tx, initialVersion); Tranlocal tranlocal = tx.locate(ref); assertNotNull(tranlocal); assertRefHasExclusiveLock(ref, tx); assertTrue(tx.hasWrites); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_CONSTRUCTING, tranlocal.getMode()); assertTrue(tranlocal.isDirty); assertRefHasExclusiveLock(ref, tx); } @Test public void whenAlreadyOpenedForConstruction() { T tx = newTransaction(); long initialVersion = 10; GammaTxnLong ref = new GammaTxnLong(tx, initialVersion); Tranlocal tranlocal = ref.openForConstruction(tx); assertNotNull(tranlocal); assertRefHasExclusiveLock(ref, tx); assertTrue(tx.hasWrites); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_CONSTRUCTING, tranlocal.getMode()); assertTrue(tranlocal.isDirty); assertRefHasExclusiveLock(ref, tx); } @Test public void whenStmMismatch() { GammaStm otherStm = new GammaStm(); GammaTxnLong ref = new GammaTxnLong(otherStm); GammaTxn tx = newTransaction(); try { ref.openForConstruction(tx); fail(); } catch (StmMismatchException expected) { } assertIsAborted(tx); } // ========================================== @Test public void commuting_whenCommuting_thenFailure() { long initialValue = 10; T tx = newTransaction(); tx.evaluatingCommute = true; try{ new GammaTxnLong(tx, initialValue); fail(); }catch(IllegalCommuteException expected){ } assertIsAborted(tx); } @Test public void whenTransactionAlreadyPrepared() { GammaTxn tx = newTransaction(); tx.prepare(); try { new GammaTxnLong(tx); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); } @Test public void whenTransactionAlreadyAborted() { GammaTxn tx = newTransaction(); tx.abort(); GammaTxnLong ref = new GammaTxnLong(stm); try { ref.openForConstruction(tx); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } @Test public void whenTransactionAlreadyCommitted() { GammaTxn tx = newTransaction(); tx.commit(); GammaTxnLong ref = new GammaTxnLong(stm); try { ref.openForConstruction(tx); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); } } FatGammaTxn_openForReadTest.java000066400000000000000000000733601174000617100422730ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.*; import org.multiverse.api.functions.Functions; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_openForReadTest implements GammaConstants { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract int getMaxCapacity(); protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); @Test public void whenArrive() { //the mono transaction doesn't support (or need) the richmans conflict assumeTrue(getMaxCapacity() > 1); GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); T tx = newTransaction(config); ref.openForRead(tx, LOCKMODE_NONE); assertSurplus(ref, 1); } @Test public void whenStmMismatch() { GammaStm otherStm = new GammaStm(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(otherStm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (StmMismatchException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAbortOnly_thenReadStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 0); GammaTxn tx = stm.newDefaultTxn(); tx.setAbortOnly(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertTrue(tx.isAbortOnly()); assertIsActive(tx); } @Test public void whenTransactionAbortOnly_thenRereadStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 0); GammaTxn tx = newTransaction(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); tx.setAbortOnly(); Tranlocal reread = ref.openForRead(tx, LOCKMODE_NONE); assertSame(read, reread); assertTrue(tx.isAbortOnly()); assertIsActive(tx); } @Test public void whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem() { whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode.None); whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode.Read); whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode.Write); whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode.Exclusive); } public void whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode lockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = newTransaction(); ref.getLock().acquire(otherTx, lockMode); Tranlocal read2 = ref.openForRead(tx, LOCKMODE_NONE); assertIsActive(tx); assertSame(read, read2); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForConstruction() { T tx = newTransaction(); GammaTxnLong ref = new GammaTxnLong(tx, 0); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_CONSTRUCTING, tranlocal.getMode()); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); } @Test public void whenAlreadyOpenedForCommute() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); ref.commute(tx, Functions.incLongFunction()); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); assertIsActive(tx); assertEquals(11, tranlocal.long_value); assertEquals(10, tranlocal.long_oldValue); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForCommuteAndLockingConflicts() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); ref.commute(tx, Functions.incLongFunction()); Tranlocal tranlocal = tx.locate(ref); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try{ ref.openForRead(tx, LOCKMODE_NONE); fail(); }catch(ReadWriteConflict expected){ } assertNotNull(tranlocal); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenOverflowing() { int maxCapacity = getMaxCapacity(); assumeTrue(maxCapacity < Integer.MAX_VALUE); GammaTxn tx = newTransaction(); for (int k = 0; k < maxCapacity; k++) { GammaTxnLong ref = new GammaTxnLong(stm, 0); ref.openForRead(tx, LOCKMODE_NONE); } GammaTxnLong ref = new GammaTxnLong(stm, 0); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(maxCapacity + 1, tx.getConfig().getSpeculativeConfiguration().minimalLength); } @Test public void whenReadonly() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.readonly = true; GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(initialVersion, tranlocal.version); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertTrue(tranlocal.isRead()); assertFalse(tx.hasWrites()); } @Test public void whenNotOpenedBefore() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(initialVersion, tranlocal.version); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertTrue(tranlocal.isRead()); assertFalse(tx.hasWrites()); } @Test public void whenRefAlreadyOpenedForRead() { whenRefAlreadyOpenedForRead(LockMode.None, LockMode.None, LockMode.None); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.None, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.None, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Read, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.None, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Read, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Write, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void whenRefAlreadyOpenedForRead(LockMode firstReadLockMode, LockMode secondReadLockMode, LockMode expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal first = ref.openForWrite(tx, firstReadLockMode.asInt()); Tranlocal second = ref.openForRead(tx, secondReadLockMode.asInt()); assertSame(first, second); assertNotNull(second); assertSame(ref, second.owner); assertEquals(initialVersion, second.version); assertEquals(initialValue, second.long_value); assertEquals(initialValue, second.long_oldValue); assertLockMode(ref, expectedLockMode); assertTrue(second.isWrite()); assertTrue(tx.hasWrites()); } @Test public void whenRefAlreadyOpenedForWrite() { whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.None, LockMode.None); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.None, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.None, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Read, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.None, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Read, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Write, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void whenRefAlreadyOpenedForWrite(LockMode writeLockMode, LockMode readLockMode, LockMode expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal first = ref.openForWrite(tx, writeLockMode.asInt()); Tranlocal second = ref.openForRead(tx, readLockMode.asInt()); assertSame(first, second); assertSame(ref, second.owner); assertEquals(initialVersion, second.version); assertEquals(initialValue, second.long_value); assertEquals(initialValue, second.long_oldValue); assertLockMode(ref, expectedLockMode); assertTrue(second.isWrite()); assertTrue(tx.hasWrites()); } @Test public void readConsistency_whenNotConsistent() { assumeTrue(getMaxCapacity() > 1); GammaTxnLong ref1 = new GammaTxnLong(stm, 0); GammaTxnLong ref2 = new GammaTxnLong(stm, 0); GammaTxn tx = newTransaction(); ref1.openForRead(tx, LOCKMODE_NONE); ref1.atomicIncrementAndGet(1); try { ref2.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); } // ====================== lock level ======================================== @Test public void lockLevel() { lockLevel(LockMode.None, LockMode.None, LockMode.None); lockLevel(LockMode.None, LockMode.Read, LockMode.Read); lockLevel(LockMode.None, LockMode.Write, LockMode.Write); lockLevel(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); lockLevel(LockMode.Read, LockMode.Read, LockMode.Read); lockLevel(LockMode.Read, LockMode.Write, LockMode.Write); lockLevel(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); lockLevel(LockMode.Write, LockMode.Write, LockMode.Write); lockLevel(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); lockLevel(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void lockLevel(LockMode transactionReadLockMode, LockMode readLockMode, LockMode expectedReadLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(transactionReadLockMode) .setWriteLockMode(transactionReadLockMode); GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForRead(tx, readLockMode.asInt()); assertEquals(expectedReadLockMode.asInt(), tranlocal.getLockMode()); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, expectedReadLockMode.asInt()); } // ===================== lock upgrade ====================================== @Test public void lockUpgrade() { lockUpgrade(LOCKMODE_NONE, LOCKMODE_NONE, LOCKMODE_NONE); lockUpgrade(LOCKMODE_NONE, LOCKMODE_READ, LOCKMODE_READ); lockUpgrade(LOCKMODE_NONE, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_NONE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_READ, LOCKMODE_NONE, LOCKMODE_READ); lockUpgrade(LOCKMODE_READ, LOCKMODE_READ, LOCKMODE_READ); lockUpgrade(LOCKMODE_READ, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_READ, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_NONE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_READ, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_NONE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_READ, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_WRITE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); } public void lockUpgrade(int firstMode, int secondLockMode, int expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.openForRead(tx, firstMode); Tranlocal tranlocal = ref.openForRead(tx, secondLockMode); assertEquals(expectedLockMode, tranlocal.getLockMode()); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, expectedLockMode); } // ===================== locking ============================================ @Test public void locking_noLockRequired_whenLockedForReadByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_noLockRequired_whenLockedForWriteByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, otherTx); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_noLockReqyired_whenLockedForCommitByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_readLockRequired_whenFree() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_readLockRequired_whenLockedForReadByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, otherTx); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 2); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_readLockRequired_whenLockedForWriteByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_READ); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_readLockReqyired_whenLockedForCommitByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_READ); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_writeLockRequired_whenFree() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_WRITE); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, tx); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_writeLockRequired_whenLockedForReadByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, otherTx); } @Test public void locking_writeLockRequired_whenLockedForWriteByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_writeLockReqyired_whenLockedForCommitByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_exclusiveLockRequired_whenFree() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_EXCLUSIVE); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, tx); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_exclusiveLockRequired_whenLockedForReadByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void locking_exclusiveLockRequired_whenLockedForWriteByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_exclusiveLockReqyired_whenLockedForCommitByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, otherTx); } // =================== while commuting ============================ @Test public void commuting_whenCommuting_thenFailure() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.evaluatingCommute = true; try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (IllegalCommuteException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } // ================================================================ @Test public void whenRepeatableReadIsolationLevel(){ assumeTrue(getMaxCapacity()>1); long initialValue = 1; GammaTxnLong ref1 = new GammaTxnLong(stm, initialValue); GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue); GammaTxnConfig config = new GammaTxnConfig(stm) .setIsolationLevel(IsolationLevel.RepeatableRead); T tx = newTransaction(config); ref1.get(tx); ref1.atomicIncrementAndGet(1); long value = ref2.get(tx); assertIsActive(tx); assertEquals(1, value); } // ================================================================ @Test public void whenTransactionPrepared_thenPreparedTxnException() { GammaTxn tx = newTransaction(); tx.prepare(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } @Test public void state_whenTransactionAlreadyAborted_thenDeadTxnException() { GammaTxn tx = newTransaction(); tx.abort(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } @Test public void state_whenTransactionAlreadyCommitted_thenDeadTxnException() { GammaTxn tx = newTransaction(); tx.commit(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } } FatGammaTxn_openForWriteTest.java000066400000000000000000000740161174000617100425110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.*; import org.multiverse.api.functions.Functions; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_openForWriteTest implements GammaConstants { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(GammaTxnConfig config); protected abstract T newTransaction(); protected abstract int getMaxCapacity(); @Test public void whenArrive() { //the mono transaction doesn't support (or need) the richmans conflict assumeTrue(getMaxCapacity() > 1); GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); T tx = newTransaction(config); ref.openForWrite(tx, LOCKMODE_NONE); assertSurplus(ref, 1); } @Test public void whenStmMismatch() { GammaStm otherStm = new GammaStm(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(otherStm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (StmMismatchException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForConstruction() { T tx = newTransaction(); GammaTxnLong ref = new GammaTxnLong(tx, 0); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_CONSTRUCTING, tranlocal.getMode()); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); } @Test public void whenAlreadyOpenedForCommute() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); ref.commute(tx, Functions.incLongFunction()); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); assertIsActive(tx); assertEquals(11, tranlocal.long_value); assertEquals(10, tranlocal.long_oldValue); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForCommuteAndLockingConflicts() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); ref.commute(tx, Functions.incLongFunction()); Tranlocal tranlocal = tx.locate(ref); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try{ ref.openForWrite(tx, LOCKMODE_NONE); fail(); }catch(ReadWriteConflict expected){ } assertNotNull(tranlocal); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAbortOnly_thenWriteStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 0); GammaTxn tx = stm.newDefaultTxn(); tx.setAbortOnly(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertTrue(tx.isAbortOnly()); assertIsActive(tx); } @Test public void whenTransactionAbortOnly_thenRereadStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 0); GammaTxn tx = stm.newDefaultTxn(); Tranlocal read = ref.openForWrite(tx, LOCKMODE_NONE); tx.setAbortOnly(); Tranlocal reread = ref.openForWrite(tx, LOCKMODE_NONE); assertSame(read, reread); assertTrue(tx.isAbortOnly()); assertIsActive(tx); } @Test public void whenWriteFirstAndExclusivelyLockedByOtherAndThenReWrite_thenNoProblem() { whenWriteFirstAndExclusivelyLockedByOtherAndThenReWrite_thenNoProblem(LockMode.None); whenWriteFirstAndExclusivelyLockedByOtherAndThenReWrite_thenNoProblem(LockMode.Read); whenWriteFirstAndExclusivelyLockedByOtherAndThenReWrite_thenNoProblem(LockMode.Write); whenWriteFirstAndExclusivelyLockedByOtherAndThenReWrite_thenNoProblem(LockMode.Exclusive); } public void whenWriteFirstAndExclusivelyLockedByOtherAndThenReWrite_thenNoProblem(LockMode lockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = newTransaction(); ref.getLock().acquire(otherTx, lockMode); Tranlocal read2 = ref.openForWrite(tx, LOCKMODE_NONE); assertIsActive(tx); assertSame(read, read2); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenOverflowing() { int maxCapacity = getMaxCapacity(); assumeTrue(maxCapacity < Integer.MAX_VALUE); T tx = newTransaction(); System.out.println(tx.getConfig().getSpeculativeConfiguration().minimalLength); for (int k = 0; k < maxCapacity; k++) { GammaTxnLong ref = new GammaTxnLong(stm, 0); ref.openForWrite(tx, LOCKMODE_NONE); } GammaTxnLong ref = new GammaTxnLong(stm, 0); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(maxCapacity + 1, tx.getConfig().getSpeculativeConfiguration().minimalLength); } @Test public void whenReadonlyTransaction_thenReadonlyException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.readonly = true; T tx = newTransaction(config); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (ReadonlyException expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } @Test public void whenNotOpenedBefore() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(initialVersion, tranlocal.version); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertTrue(tranlocal.isWrite()); assertTrue(tx.hasWrites()); } @Test public void whenRefAlreadyOpenedForRead() { whenRefAlreadyOpenedForRead(LockMode.None, LockMode.None, LockMode.None); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.None, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.None, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Read, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.None, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Read, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Write, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void whenRefAlreadyOpenedForRead(LockMode readLockMode, LockMode writeLockMode, LockMode expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal first = ref.openForRead(tx, readLockMode.asInt()); Tranlocal second = ref.openForWrite(tx, writeLockMode.asInt()); assertSame(first, second); assertNotNull(second); assertSame(ref, second.owner); assertEquals(initialVersion, second.version); assertEquals(initialValue, second.long_value); assertEquals(initialValue, second.long_oldValue); assertLockMode(ref, expectedLockMode); assertTrue(second.isWrite()); assertTrue(tx.hasWrites()); } @Test public void whenRefAlreadyOpenedForWrite() { whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.None, LockMode.None); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.None, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.None, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Read, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.None, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Read, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Write, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void whenRefAlreadyOpenedForWrite(LockMode firstWriteLockMode, LockMode secondWriteLockMode, LockMode expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal first = ref.openForWrite(tx, firstWriteLockMode.asInt()); Tranlocal second = ref.openForWrite(tx, secondWriteLockMode.asInt()); assertSame(first, second); assertSame(ref, second.owner); assertEquals(initialVersion, second.version); assertEquals(initialValue, second.long_value); assertEquals(initialValue, second.long_oldValue); assertLockMode(ref, expectedLockMode); assertTrue(second.isWrite()); assertTrue(tx.hasWrites()); } @Test public void readConsistency_whenNotConsistent() { assumeTrue(getMaxCapacity() > 1); GammaTxnLong ref1 = new GammaTxnLong(stm, 0); GammaTxnLong ref2 = new GammaTxnLong(stm, 0); GammaTxn tx = newTransaction(); ref1.openForWrite(tx, LOCKMODE_NONE); ref1.atomicIncrementAndGet(1); try { ref2.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); } // ====================== lock level ======================================== @Test public void lockLevel() { lockLevel(LOCKMODE_NONE, LOCKMODE_NONE, LOCKMODE_NONE); lockLevel(LOCKMODE_NONE, LOCKMODE_READ, LOCKMODE_READ); lockLevel(LOCKMODE_NONE, LOCKMODE_WRITE, LOCKMODE_WRITE); lockLevel(LOCKMODE_NONE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockLevel(LOCKMODE_READ, LOCKMODE_NONE, LOCKMODE_READ); lockLevel(LOCKMODE_READ, LOCKMODE_READ, LOCKMODE_READ); lockLevel(LOCKMODE_READ, LOCKMODE_WRITE, LOCKMODE_WRITE); lockLevel(LOCKMODE_READ, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockLevel(LOCKMODE_WRITE, LOCKMODE_NONE, LOCKMODE_WRITE); lockLevel(LOCKMODE_WRITE, LOCKMODE_READ, LOCKMODE_WRITE); lockLevel(LOCKMODE_WRITE, LOCKMODE_WRITE, LOCKMODE_WRITE); lockLevel(LOCKMODE_WRITE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockLevel(LOCKMODE_EXCLUSIVE, LOCKMODE_NONE, LOCKMODE_EXCLUSIVE); lockLevel(LOCKMODE_EXCLUSIVE, LOCKMODE_READ, LOCKMODE_EXCLUSIVE); lockLevel(LOCKMODE_EXCLUSIVE, LOCKMODE_WRITE, LOCKMODE_EXCLUSIVE); lockLevel(LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); } public void lockLevel(int transactionWriteLockMode, int writeLockMode, int expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.writeLockModeAsInt = transactionWriteLockMode; GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, writeLockMode); assertEquals(expectedLockMode, tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, expectedLockMode); } // ======================= lock upgrade =================================== @Test public void lockUpgrade() { lockUpgrade(LOCKMODE_NONE, LOCKMODE_NONE, LOCKMODE_NONE); lockUpgrade(LOCKMODE_NONE, LOCKMODE_READ, LOCKMODE_READ); lockUpgrade(LOCKMODE_NONE, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_NONE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_READ, LOCKMODE_NONE, LOCKMODE_READ); lockUpgrade(LOCKMODE_READ, LOCKMODE_READ, LOCKMODE_READ); lockUpgrade(LOCKMODE_READ, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_READ, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_NONE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_READ, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_NONE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_READ, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_WRITE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); } public void lockUpgrade(int firstMode, int secondLockMode, int expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.openForWrite(tx, firstMode); Tranlocal tranlocal = ref.openForWrite(tx, secondLockMode); assertEquals(expectedLockMode, tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, expectedLockMode); } // ===================== locking ============================================ @Test public void locking_noLockRequired_whenLockedForReadByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); } @Test public void locking_noLockRequired_whenLockedForWriteByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); assertEquals(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); } @Test public void locking_noLockReqyired_whenLockedForCommitByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_readLockRequired_whenFree() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_READ); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); } @Test public void locking_readLockRequired_whenLockedForReadByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_READ); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 2); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); } @Test public void locking_readLockRequired_whenLockedForWriteByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_READ); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_readLockReqyired_whenLockedForCommitByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_READ); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_writeLockRequired_whenFree() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_WRITE); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, tx); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); } @Test public void locking_writeLockRequired_whenLockedForReadByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void locking_writeLockRequired_whenLockedForWriteByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_writeLockRequired_whenLockedForCommitByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_exclusiveLockRequired_whenFree() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_EXCLUSIVE); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, tx); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); } @Test public void locking_exclusiveLockRequired_whenLockedForReadByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void locking_exclusiveLockRequired_whenLockedForWriteByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_exclusiveLockReqyired_whenLockedForCommitByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); } //==================================================== @Test public void whenRepeatableReadIsolationLevel(){ assumeTrue(getMaxCapacity()>1); long initialValue = 1; GammaTxnLong ref1 = new GammaTxnLong(stm, initialValue); GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue); GammaTxnConfig config = new GammaTxnConfig(stm) .setIsolationLevel(IsolationLevel.RepeatableRead); T tx = newTransaction(config); ref1.openForWrite(tx, LOCKMODE_NONE); ref1.atomicIncrementAndGet(1); ref2.openForWrite(tx, LOCKMODE_NONE); assertIsActive(tx); } // ========================================== @Test public void commuting_whenCommuting_thenFailure() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.evaluatingCommute = true; try{ ref.openForWrite(tx, LOCKMODE_NONE); fail(); }catch(IllegalCommuteException expected){ } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } // ================================================================ @Test public void whenTransactionPrepared_thenPreparedTxnException() { GammaTxn tx = newTransaction(); tx.prepare(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } @Test public void whenTransactionAlreadyAborted_thenDeadTxnException() { GammaTxn tx = newTransaction(); tx.abort(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } @Test public void whenTransactionAlreadyCommitted_thenDeadTxnException() { GammaTxn tx = newTransaction(); tx.commit(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } } FatGammaTxn_prepareTest.java000066400000000000000000000442611174000617100415230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.SomeUncheckedException; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.AbortOnlyException; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_prepareTest implements GammaConstants { public GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); @Test public void listener_whenNormalListenerAvailable() { T tx = newTransaction(); TxnListener listener = mock(TxnListener.class); tx.register(listener); tx.prepare(); assertIsPrepared(tx); //verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PrePrepare); } @Test public void listener_whenPermanentListenerAvailable() { TxnListener listener = mock(TxnListener.class); GammaTxnConfig config = new GammaTxnConfig(stm) .addPermanentListener(listener); T tx = newTransaction(config); tx.prepare(); assertIsPrepared(tx); //verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PrePrepare); } @Test public void conflict_whenArriveByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); long newValue = 1; ref.set(tx, newValue); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatVariableLengthGammaTxn otherTx = new FatVariableLengthGammaTxn(config); ref.get(otherTx); long globalConflictCount = stm.globalConflictCounter.count(); tx.prepare(); assertIsPrepared(tx); assertTrue(tx.commitConflict); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, LOCKMODE_EXCLUSIVE); assertSurplus(ref, 2); } @Test public void whenAbortOnly() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.setAbortOnly(); try { tx.prepare(); fail(); } catch (AbortOnlyException expected) { } assertIsAborted(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsRead() { whenContainsRead(LockMode.None); whenContainsRead(LockMode.Read); whenContainsRead(LockMode.Write); whenContainsRead(LockMode.Exclusive); } public void whenContainsRead(LockMode readLockMode) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.openForRead(tx, readLockMode.asInt()); tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertLockMode(ref, readLockMode); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } @Test @Ignore public void writeSkew() { } @Test public void whenContainsCommute() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long globalConflictCount = stm.globalConflictCounter.count(); LongFunction function = Functions.incLongFunction(); GammaTxn tx = newTransaction(); ref.commute(tx, function); Tranlocal tranlocal = tx.locate(ref); tx.prepare(); assertIsPrepared(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tranlocal.isDirty); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.lockMode); assertEquals(initialValue + 1, tranlocal.long_value); assertTrue(tranlocal.hasDepartObligation); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenContainsMultipleCommutes() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long globalConflictCount = stm.globalConflictCounter.count(); LongFunction function1 = Functions.incLongFunction(); LongFunction function2 = Functions.incLongFunction(); LongFunction function3 = Functions.incLongFunction(); GammaTxn tx = newTransaction(); ref.commute(tx, function1); ref.commute(tx, function2); ref.commute(tx, function3); Tranlocal tranlocal = tx.locate(ref); tx.prepare(); assertIsPrepared(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tranlocal.isDirty); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.lockMode); assertEquals(initialValue + 3, tranlocal.long_value); assertTrue(tranlocal.hasDepartObligation); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenContainsCommuteThatCausesProblems() { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long globalConflictCount = stm.globalConflictCounter.count(); LongFunction function = mock(LongFunction.class); when(function.call(anyLong())).thenThrow(new SomeUncheckedException()); GammaTxn tx = newTransaction(); ref.commute(tx, function); Tranlocal tranlocal = tx.locate(ref); try { tx.prepare(); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenContainsCommuteThatIsLocked() { whenContainsCommuteThatIsLocked(LockMode.Read); whenContainsCommuteThatIsLocked(LockMode.Write); whenContainsCommuteThatIsLocked(LockMode.Exclusive); } public void whenContainsCommuteThatIsLocked(LockMode lockMode) { int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); long globalConflictCount = stm.globalConflictCounter.count(); LongFunction function = mock(LongFunction.class); when(function.call(anyLong())).thenThrow(new SomeUncheckedException()); GammaTxn tx = newTransaction(); ref.commute(tx, function); Tranlocal tranlocal = tx.locate(ref); GammaTxn otherTx = newTransaction(); ref.getLock().acquire(otherTx, lockMode); try { tx.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenContainsConstructed() { long globalConflictCount = stm.globalConflictCounter.count(); GammaTxn tx = newTransaction(); int initialValue = 10; GammaTxnLong ref = new GammaTxnLong(tx, initialValue); Tranlocal tranlocal = tx.locate(ref); tx.prepare(); assertIsPrepared(tx); assertRefHasExclusiveLock(ref, tx); assertTrue(tranlocal.isDirty); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.lockMode); assertTrue(tranlocal.hasDepartObligation); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, GammaConstants.VERSION_UNCOMMITTED, 0); } // =============================== dirty check ================================= @Test public void dirtyCheckDisabled_whenNotDirty_thenLockedForCommit() { dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode.None); dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode.Read); dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode.Write); dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode.None); } public void dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode writeLockMode) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setDirtyCheckEnabled(false); GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, writeLockMode.asInt()); tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertTrue(tranlocal.isDirty()); assertEquals(LockMode.Exclusive.asInt(), tranlocal.getLockMode()); assertLockMode(ref, LockMode.Exclusive); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirtyCheckDisabled_whenDirty_thenLockedForCommit() { dirtyCheckDisabled_whenDirty_thenLockedForCommit(LockMode.None); dirtyCheckDisabled_whenDirty_thenLockedForCommit(LockMode.Read); dirtyCheckDisabled_whenDirty_thenLockedForCommit(LockMode.Write); dirtyCheckDisabled_whenDirty_thenLockedForCommit(LockMode.None); } public void dirtyCheckDisabled_whenDirty_thenLockedForCommit(LockMode writeLockMode) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setDirtyCheckEnabled(false); GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, writeLockMode.asInt()); tranlocal.long_value++; tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertTrue(tranlocal.isDirty()); assertEquals(LockMode.Exclusive.asInt(), tranlocal.getLockMode()); assertLockMode(ref, LockMode.Exclusive); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirtyCheckEnabled_whenNotDirty_thenNothingHappens() { dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode.None); dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode.Read); dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode.Write); dirtyCheckDisabled_whenNotDirty_thenLockedForCommit(LockMode.Exclusive); } public void dirtyCheckEnabled_whenNotDirty_nothingHappens(LockMode writeLockMode) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setDirtyCheckEnabled(true); GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, writeLockMode.asInt()); tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertFalse(tranlocal.isDirty()); assertEquals(writeLockMode.asInt(), tranlocal.getLockMode()); assertLockMode(ref, writeLockMode); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirtyCheckEnabled_whenDirty_thenLockedForCommit() { dirtyCheckEnabled_whenDirty_thenLockedForCommit(LockMode.None); dirtyCheckEnabled_whenDirty_thenLockedForCommit(LockMode.Read); dirtyCheckEnabled_whenDirty_thenLockedForCommit(LockMode.Write); dirtyCheckEnabled_whenDirty_thenLockedForCommit(LockMode.Exclusive); } public void dirtyCheckEnabled_whenDirty_thenLockedForCommit(LockMode writeLockMode) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setDirtyCheckEnabled(true); GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, writeLockMode.asInt()); tranlocal.long_value++; tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertTrue(tranlocal.isDirty()); assertEquals(LockMode.Exclusive.asInt(), tranlocal.getLockMode()); assertLockMode(ref, LockMode.Exclusive); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } // =============================== locked by other ============================= @Test public void conflict_dirty_whenReadLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_READ); try { tx.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void conflict_dirty_whenWriteLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_WRITE); try { tx.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void conflict_dirty_whenExclusiveLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_EXCLUSIVE); try { tx.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); assertGlobalConflictCount(stm, globalConflictCount); } // ================================ states ===================================== @Test public void whenPreparedAndUnused() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.prepare(); tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAlreadyAborted_thenDeadTxnException() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.abort(); try { tx.prepare(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAlreadyCommitted_thenDeadTxnException() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.commit(); try { tx.prepare(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertGlobalConflictCount(stm, globalConflictCount); } } FatGammaTxn_registerTest.java000066400000000000000000000067131174000617100417110ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.Arrays; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.multiverse.TestUtils.*; public abstract class FatGammaTxn_registerTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); @Test public void whenNullListener_thenNullPointerException() { T tx = newTransaction(); try { tx.register(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); } @Test public void whenSuccess() { T tx = newTransaction(); TxnListener listener = mock(TxnListener.class); tx.register(listener); assertIsActive(tx); assertNotNull(tx.listeners); assertEquals(Arrays.asList(listener), tx.listeners); verifyZeroInteractions(listener); } @Test public void whenMultpleListeners() { T tx = newTransaction(); TxnListener listener1 = mock(TxnListener.class); TxnListener listener2 = mock(TxnListener.class); TxnListener listener3 = mock(TxnListener.class); tx.register(listener1); tx.register(listener2); tx.register(listener3); assertIsActive(tx); assertNotNull(tx.listeners); assertEquals(Arrays.asList(listener1, listener2, listener3), tx.listeners); verifyZeroInteractions(listener1); verifyZeroInteractions(listener2); verifyZeroInteractions(listener3); } @Test public void whenSameListenerAddedMultipleTimes() { T tx = newTransaction(); TxnListener listener = mock(TxnListener.class); tx.register(listener); tx.register(listener); assertIsActive(tx); assertNotNull(tx.listeners); assertEquals(Arrays.asList(listener, listener), tx.listeners); verifyZeroInteractions(listener); } @Test public void whenAlreadyPrepared() { T tx = newTransaction(); tx.prepare(); TxnListener listener = mock(TxnListener.class); try { tx.register(listener); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(listener); } @Test public void whenAlreadyAborted() { T tx = newTransaction(); tx.abort(); TxnListener listener = mock(TxnListener.class); try { tx.register(listener); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(listener); } @Test public void whenAlreadyCommitted() { T tx = newTransaction(); tx.commit(); TxnListener listener = mock(TxnListener.class); try { tx.register(listener); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); verifyZeroInteractions(listener); } } FatGammaTxn_retryTest.java000066400000000000000000000071521174000617100412300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.*; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.functions.Function; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.stms.gamma.GammaTestUtils.assertLockMode; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; public abstract class FatGammaTxn_retryTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(GammaTxnConfig config); protected abstract T newTransaction(); @Test @Ignore public void whenContainsRead() { } @Test @Ignore public void whenContainsWrite() { } @Test public void whenOnlyContainsConstructed() { GammaTxn tx = newTransaction(); GammaTxnRef ref = new GammaTxnRef(tx, "foo"); try { tx.retry(); fail(); } catch (RetryNotPossibleException expected) { } assertIsAborted(tx); assertLockMode(ref, LockMode.Exclusive); } @Test public void whenOnlyContainsCommute() { String intialValue = "initialValue"; GammaTxnRef ref = new GammaTxnRef(stm, intialValue); GammaTxn tx = newTransaction(); Function function = mock(Function.class); ref.commute(tx, function); try { tx.retry(); fail(); } catch (RetryNotPossibleException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); verifyZeroInteractions(function); } @Test public void whenUnused() { GammaTxn tx = newTransaction(); try { tx.retry(); fail(); } catch (RetryNotPossibleException expected) { } assertIsAborted(tx); } @Test public void whenNoRetryAllowed() { GammaTxnConfig config = new GammaTxnConfig(stm); config.blockingAllowed = false; T tx = newTransaction(config); try { tx.retry(); fail(); } catch (RetryNotAllowedException expected) { } assertIsAborted(tx); } @Test public void whenAlreadyPrepared() { T tx = newTransaction(); tx.prepare(); try { tx.retry(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); } @Test public void whenAlreadyAborted() { T tx = newTransaction(); tx.abort(); try { tx.retry(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } @Test public void whenAlreadyCommitted() { T tx = newTransaction(); tx.commit(); try { tx.retry(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); } } FatGammaTxn_setAbortOnlyTest.java000066400000000000000000000036751174000617100425160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; public abstract class FatGammaTxn_setAbortOnlyTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } abstract protected T newTransaction(); abstract protected T newTransaction(GammaTxnConfig config); @Test public void whenActive() { GammaTxn tx = newTransaction(); tx.setAbortOnly(); assertIsActive(tx); assertTrue((Boolean) getField(tx, "abortOnly")); } @Test public void whenPrepared_thenPreparedTxnException() { GammaTxn tx = newTransaction(); tx.prepare(); try { tx.setAbortOnly(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertFalse((Boolean) getField(tx, "abortOnly")); } @Test public void whenAborted_thenDeadTxnException() { GammaTxn tx = newTransaction(); tx.abort(); try { tx.setAbortOnly(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertFalse((Boolean) getField(tx, "abortOnly")); } @Test public void whenCommitted_thenDeadTxnException() { GammaTxn tx = newTransaction(); tx.commit(); try { tx.setAbortOnly(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertFalse((Boolean) getField(tx, "abortOnly")); } } FatGammaTxn_softResetTest.java000066400000000000000000000006131174000617100420340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; public abstract class FatGammaTxn_softResetTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); } FatMonoGammaTxnFactory.java000066400000000000000000000031511174000617100413170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.api.TxnFactoryBuilder; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.GammaTxnPool; import static org.multiverse.stms.gamma.transactions.ThreadLocalGammaTxnPool.getThreadLocalGammaTxnPool; public class FatMonoGammaTxnFactory implements GammaTxnFactory { private final GammaTxnConfig config; public FatMonoGammaTxnFactory(GammaStm stm) { this(new GammaTxnConfig(stm).setControlFlowErrorsReused(false)); } public FatMonoGammaTxnFactory(GammaTxnConfig config) { this.config = config.setControlFlowErrorsReused(false).init(); } @Override public TxnFactoryBuilder getTxnFactoryBuilder() { throw new UnsupportedOperationException(); } @Override public GammaTxnConfig getConfig() { return config; } @Override public GammaTxn upgradeAfterSpeculativeFailure(GammaTxn failingTransaction, GammaTxnPool pool) { throw new UnsupportedOperationException(); } @Override public GammaTxn newTxn() { return newTransaction(getThreadLocalGammaTxnPool()); } @Override public FatMonoGammaTxn newTransaction(GammaTxnPool pool) { FatMonoGammaTxn tx = pool.takeFatMono(); if (tx == null) { tx = new FatMonoGammaTxn(config); } else { tx.init(config); } return tx; } } FatMonoGammaTxn_abortTest.java000066400000000000000000000011521174000617100420150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.assertNull; public class FatMonoGammaTxn_abortTest extends FatGammaTxn_abortTest { @Override protected void assertCleaned(FatMonoGammaTxn tx) { assertNull(tx.tranlocal.owner); } protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(new GammaTxnConfig(stm)); } @Override protected FatMonoGammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } } FatMonoGammaTxn_commitTest.java000066400000000000000000000011761174000617100422040ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.assertNull; public class FatMonoGammaTxn_commitTest extends FatGammaTxn_commitTest { @Override protected void assertCleaned(FatMonoGammaTxn transaction) { assertNull(transaction.tranlocal.owner); } @Override protected FatMonoGammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(new GammaTxnConfig(stm)); } } FatMonoGammaTxn_commuteTest.java000066400000000000000000000010241174000617100423550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatMonoGammaTxn_commuteTest extends FatGammaTxn_commuteTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } @Override protected FatMonoGammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } @Override protected int getMaxCapacity() { return 1; } } FatMonoGammaTxn_hardResetTest.java000066400000000000000000000004061174000617100426300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatMonoGammaTxn_hardResetTest extends FatGammaTxn_hardResetTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } } FatMonoGammaTxn_initTest.java000066400000000000000000000003741174000617100416560ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatMonoGammaTxn_initTest extends FatGammaTxn_initTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } } FatMonoGammaTxn_isAbortOnlyTest.java000066400000000000000000000004121174000617100431510ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatMonoGammaTxn_isAbortOnlyTest extends FatGammaTxn_isAbortOnlyTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } } FatMonoGammaTxn_locateTest.java000066400000000000000000000004001174000617100421500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatMonoGammaTxn_locateTest extends FatGammaTxn_locateTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } } FatMonoGammaTxn_openForConstructionTest.java000066400000000000000000000007501174000617100447340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatMonoGammaTxn_openForConstructionTest extends FatGammaTxn_openForConstructionTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } @Override protected FatMonoGammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } } FatMonoGammaTxn_openForReadTest.java000066400000000000000000000010421174000617100431100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatMonoGammaTxn_openForReadTest extends FatGammaTxn_openForReadTest { @Override protected FatMonoGammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(new GammaTxnConfig(stm)); } @Override protected int getMaxCapacity() { return 1; } } FatMonoGammaTxn_openForWriteTest.java000066400000000000000000000010771174000617100433370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatMonoGammaTxn_openForWriteTest extends FatGammaTxn_openForWriteTest { @Override protected GammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } protected GammaTxn newTransaction() { return new FatMonoGammaTxn(new GammaTxnConfig(stm)); } @Override protected int getMaxCapacity() { return 1; } } FatMonoGammaTxn_prepareTest.java000066400000000000000000000007101174000617100423430ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatMonoGammaTxn_prepareTest extends FatGammaTxn_prepareTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } @Override protected FatMonoGammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } } FatMonoGammaTxn_registerTest.java000066400000000000000000000004031174000617100425300ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatMonoGammaTxn_registerTest extends FatGammaTxn_registerTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } } FatMonoGammaTxn_retryTest.java000066400000000000000000000007041174000617100420550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatMonoGammaTxn_retryTest extends FatGammaTxn_retryTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } @Override protected FatMonoGammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } } FatMonoGammaTxn_setAbortOnlyTest.java000066400000000000000000000007211174000617100433340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatMonoGammaTxn_setAbortOnlyTest extends FatGammaTxn_setAbortOnlyTest { @Override protected FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } @Override protected FatMonoGammaTxn newTransaction(GammaTxnConfig config) { return new FatMonoGammaTxn(config); } } FatMonoGammaTxn_softResetTest.java000066400000000000000000000004031174000617100426620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatMonoGammaTxn_softResetTest extends FatGammaTxn_softResetTest { @Override public FatMonoGammaTxn newTransaction() { return new FatMonoGammaTxn(stm); } } FatVariableLengthGammaTxnFactory.java000066400000000000000000000032041174000617100432750ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.api.TxnFactoryBuilder; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.GammaTxnPool; import static org.multiverse.stms.gamma.transactions.ThreadLocalGammaTxnPool.getThreadLocalGammaTxnPool; public final class FatVariableLengthGammaTxnFactory implements GammaTxnFactory { private final GammaTxnConfig config; public FatVariableLengthGammaTxnFactory(GammaStm stm) { this(new GammaTxnConfig(stm)); } public FatVariableLengthGammaTxnFactory(GammaTxnConfig config) { this.config = config.init(); } @Override public TxnFactoryBuilder getTxnFactoryBuilder() { throw new UnsupportedOperationException(); } @Override public GammaTxnConfig getConfig() { return config; } @Override public FatVariableLengthGammaTxn upgradeAfterSpeculativeFailure(GammaTxn failingTransaction, GammaTxnPool pool) { throw new UnsupportedOperationException(); } @Override public FatVariableLengthGammaTxn newTxn() { return newTransaction(getThreadLocalGammaTxnPool()); } @Override public FatVariableLengthGammaTxn newTransaction(GammaTxnPool pool) { FatVariableLengthGammaTxn tx = pool.takeMap(); if (tx == null) { tx = new FatVariableLengthGammaTxn(config); } else { tx.init(config); } return tx; } } FatVariableLengthGammaTxn_abortTest.java000066400000000000000000000012121174000617100437710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatVariableLengthGammaTxn_abortTest extends FatGammaTxn_abortTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } @Override protected void assertCleaned(FatVariableLengthGammaTxn tx) { //throw new TodoException(); //todo } } FatVariableLengthGammaTxn_commitTest.java000066400000000000000000000031041174000617100441540ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Test; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.multiverse.stms.gamma.GammaTestUtils.assertSurplus; public class FatVariableLengthGammaTxn_commitTest extends FatGammaTxn_commitTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } @Override protected void assertCleaned(FatVariableLengthGammaTxn transaction) { //throw new TodoException(); } @Test public void richmansConflict_multipleReadsOnSameRef() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatVariableLengthGammaTxn tx1 = new FatVariableLengthGammaTxn(config); FatVariableLengthGammaTxn tx2 = new FatVariableLengthGammaTxn(config); FatVariableLengthGammaTxn tx3 = new FatVariableLengthGammaTxn(config); FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(config); ref.openForRead(tx1, LOCKMODE_NONE); ref.openForRead(tx2, LOCKMODE_NONE); ref.openForRead(tx3, LOCKMODE_NONE); ref.set(tx, 1); tx.commit(); assertSurplus(ref, 3); } } FatVariableLengthGammaTxn_commuteTest.java000066400000000000000000000011401174000617100443330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatVariableLengthGammaTxn_commuteTest extends FatGammaTxn_commuteTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } @Override protected int getMaxCapacity() { return Integer.MAX_VALUE; } } FatVariableLengthGammaTxn_hardResetTest.java000066400000000000000000000013411174000617100446060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Test; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import static org.junit.Assert.assertEquals; public class FatVariableLengthGammaTxn_hardResetTest extends FatGammaTxn_hardResetTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Test public void testDownsizing(){ FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(stm); for(int k=0;k<10000;k++){ new GammaTxnRef(tx); } tx.hardReset(); assertEquals(tx.config.minimalArrayTreeSize, tx.array.length); } } FatVariableLengthGammaTxn_initTest.java000066400000000000000000000004441174000617100436330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatVariableLengthGammaTxn_initTest extends FatGammaTxn_initTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } } FatVariableLengthGammaTxn_isAbortOnlyTest.java000066400000000000000000000004641174000617100451370ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatVariableLengthGammaTxn_isAbortOnlyTest extends FatGammaTxn_isAbortOnlyTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } } FatVariableLengthGammaTxn_locateTest.java000066400000000000000000000004501174000617100441340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatVariableLengthGammaTxn_locateTest extends FatGammaTxn_locateTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } } FatVariableLengthGammaTxn_openForConstructionTest.java000066400000000000000000000010441174000617100467100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatVariableLengthGammaTxn_openForConstructionTest extends FatGammaTxn_openForConstructionTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } } FatVariableLengthGammaTxn_openForReadTest.java000066400000000000000000000121321174000617100450710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class FatVariableLengthGammaTxn_openForReadTest extends FatGammaTxn_openForReadTest { @Override protected int getMaxCapacity() { return Integer.MAX_VALUE; } @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } @Test public void richmansConflict_multipleReadsOnSameRef() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatFixedLengthGammaTxn tx1 = new FatFixedLengthGammaTxn(config); FatVariableLengthGammaTxn tx2 = new FatVariableLengthGammaTxn(config); FatVariableLengthGammaTxn tx3 = new FatVariableLengthGammaTxn(config); ref.openForRead(tx1, LOCKMODE_NONE); ref.openForRead(tx2, LOCKMODE_NONE); ref.openForRead(tx3, LOCKMODE_NONE); assertSurplus(ref, 3); } @Test public void richmansConflictScan_whenFirstRead() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(config); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertTrue(tranlocal.hasDepartObligation); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_READ, tranlocal.mode); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertIsActive(tx); assertTrue(tx.hasReads); assertEquals(stm.getGlobalConflictCounter().count(), tx.localConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void richmansConflictScan_whenUnrealConflict() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); long initialValue2 = 10; GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue2); long initialVersion2 = ref2.getVersion(); FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(config); ref1.openForRead(tx, LOCKMODE_NONE); causeLotsOfConflicts(stm); long newConflictCount = stm.getGlobalConflictCounter().count(); Tranlocal tranlocal2 = ref2.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal2); assertTrue(tranlocal2.hasDepartObligation); assertEquals(initialValue2, tranlocal2.long_value); assertEquals(initialValue2, tranlocal2.long_oldValue); assertEquals(LOCKMODE_NONE, tranlocal2.lockMode); assertEquals(TRANLOCAL_READ, tranlocal2.mode); assertSurplus(ref2, 1); assertWriteBiased(ref2); assertReadonlyCount(ref2, 0); assertIsActive(tx); assertTrue(tx.hasReads); assertEquals(newConflictCount, tx.localConflictCount); assertVersionAndValue(ref2, initialVersion2, initialValue2); assertRefHasNoLocks(ref2); } @Test public void richmansConflictScan_whenConflict() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); long initialValue2 = 10; GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue2); long initialVersion2 = ref2.getVersion(); FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(config); ref1.openForRead(tx, LOCKMODE_NONE); ref1.atomicIncrementAndGet(1); try { ref2.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertSurplus(ref2, 0); assertWriteBiased(ref2); assertReadonlyCount(ref2, 0); assertIsAborted(tx); assertVersionAndValue(ref2, initialVersion2, initialValue2); assertRefHasNoLocks(ref2); } } FatVariableLengthGammaTxn_openForWriteTest.java000066400000000000000000000122461174000617100453160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Test; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.*; public class FatVariableLengthGammaTxn_openForWriteTest extends FatGammaTxn_openForWriteTest { @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected int getMaxCapacity() { return Integer.MAX_VALUE; } @Test public void richmansConflict_multipleReadsOnSameRef() { GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatFixedLengthGammaTxn tx1 = new FatFixedLengthGammaTxn(config); FatVariableLengthGammaTxn tx2 = new FatVariableLengthGammaTxn(config); FatVariableLengthGammaTxn tx3 = new FatVariableLengthGammaTxn(config); ref.openForWrite(tx1, LOCKMODE_NONE); ref.openForWrite(tx2, LOCKMODE_NONE); ref.openForWrite(tx3, LOCKMODE_NONE); assertSurplus(ref, 3); } @Test public void richmansConflictScan_whenFirstRead() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertTrue(tranlocal.hasDepartObligation); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_WRITE, tranlocal.mode); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertIsActive(tx); assertTrue(tx.hasReads); assertEquals(stm.getGlobalConflictCounter().count(), tx.localConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } @Test public void richmansConflictScan_whenUnrealConflict() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); long initialValue2 = 10; GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue2); long initialVersion2 = ref2.getVersion(); FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(config); ref1.openForRead(tx, LOCKMODE_NONE); causeLotsOfConflicts(stm); long newConflictCount = stm.getGlobalConflictCounter().count(); Tranlocal tranlocal2 = ref2.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal2); assertTrue(tranlocal2.hasDepartObligation); assertEquals(initialValue2, tranlocal2.long_value); assertEquals(initialValue2, tranlocal2.long_oldValue); assertEquals(LOCKMODE_NONE, tranlocal2.lockMode); assertEquals(TRANLOCAL_WRITE, tranlocal2.mode); assertSurplus(ref2, 1); assertWriteBiased(ref2); assertReadonlyCount(ref2, 0); assertIsActive(tx); assertTrue(tx.hasReads); assertEquals(newConflictCount, tx.localConflictCount); assertVersionAndValue(ref2, initialVersion2, initialValue2); assertRefHasNoLocks(ref2); } @Test public void richmansConflictScan_whenConflict() { GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); causeLotsOfConflicts(stm); GammaTxnLong ref1 = new GammaTxnLong(stm, 10); long initialValue2 = 10; GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue2); long initialVersion2 = ref2.getVersion(); FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(config); ref1.openForWrite(tx, LOCKMODE_NONE); ref1.atomicIncrementAndGet(1); try { ref2.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertSurplus(ref2, 0); assertWriteBiased(ref2); assertReadonlyCount(ref2, 0); assertIsAborted(tx); assertVersionAndValue(ref2, initialVersion2, initialValue2); assertRefHasNoLocks(ref2); } } FatVariableLengthGammaTxn_openingManyItemsTest.java000066400000000000000000000041451174000617100461600ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static junit.framework.Assert.assertSame; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.multiverse.TestUtils.assertIsActive; public class FatVariableLengthGammaTxn_openingManyItemsTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void whenReadonly() { whenManyItems(true); } @Test public void whenUpdate() { whenManyItems(false); } public void whenManyItems(boolean reading) { int refCount = 10000; GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(refCount); FatVariableLengthGammaTxn tx = new FatVariableLengthGammaTxn(config); GammaTxnLong[] refs = new GammaTxnLong[refCount]; Tranlocal[] tranlocals = new Tranlocal[refCount]; for (int k = 0; k < refCount; k++) { GammaTxnLong ref = new GammaTxnLong(stm); refs[k] = ref; tranlocals[k] = reading ? ref.openForRead(tx, LOCKMODE_NONE) : ref.openForWrite(tx, LOCKMODE_NONE); } assertEquals(refCount, tx.size()); System.out.println("everything inserted"); System.out.println("usage percentage: " + (100 * tx.getUsage())); for (int k = 0; k < refCount; k++) { GammaTxnLong ref = refs[k]; Tranlocal found = reading ? ref.openForRead(tx, LOCKMODE_NONE) : ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(found); assertSame(ref, found.owner); assertSame("tranlocal is incorrect at " + k, tranlocals[k], found); } assertIsActive(tx); } } FatVariableLengthGammaTxn_prepareTest.java000066400000000000000000000010041174000617100443170ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatVariableLengthGammaTxn_prepareTest extends FatGammaTxn_prepareTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } } FatVariableLengthGammaTxn_registerTest.java000066400000000000000000000004541174000617100445150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatVariableLengthGammaTxn_registerTest extends FatGammaTxn_registerTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } } FatVariableLengthGammaTxn_retryTest.java000066400000000000000000000010001174000617100440220ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatVariableLengthGammaTxn_retryTest extends FatGammaTxn_retryTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } } FatVariableLengthGammaTxn_setAbortOnlyTest.java000066400000000000000000000010151174000617100453100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class FatVariableLengthGammaTxn_setAbortOnlyTest extends FatGammaTxn_setAbortOnlyTest { @Override protected FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } @Override protected FatVariableLengthGammaTxn newTransaction(GammaTxnConfig config) { return new FatVariableLengthGammaTxn(config); } } FatVariableLengthGammaTxn_softResetTest.java000066400000000000000000000004521174000617100446450ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; public class FatVariableLengthGammaTxn_softResetTest extends FatGammaTxn_softResetTest { @Override public FatVariableLengthGammaTxn newTransaction() { return new FatVariableLengthGammaTxn(stm); } } FatVariableLengthGammaTxn_stressTest.java000066400000000000000000000054741174000617100442230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/fatpackage org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import java.util.Random; import static org.junit.Assert.assertEquals; public class FatVariableLengthGammaTxn_stressTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } @Test public void newTransaction_whenMultipleUpdatesAndDirtyCheckEnabled() { integrationTest_whenMultipleUpdatesAndDirtyCheck(true, false); } @Test public void newTransaction_whenMultipleUpdatesAndDirtyCheckDisabled() { integrationTest_whenMultipleUpdatesAndDirtyCheck(false, false); } @Test public void reuseTransaction_whenMultipleUpdatesAndDirtyCheckEnabled() { integrationTest_whenMultipleUpdatesAndDirtyCheck(true, true); } @Test public void reuseTransaction_whenMultipleUpdatesAndDirtyCheckDisabled() { integrationTest_whenMultipleUpdatesAndDirtyCheck(false, true); } public void integrationTest_whenMultipleUpdatesAndDirtyCheck(final boolean dirtyCheck, final boolean transactionReuse) { GammaTxnLong[] refs = new GammaTxnLong[30]; long created = 0; //create the references for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnLong(stm, 0); } Random random = new Random(); int transactionCount = 100000; GammaTxnConfig config = new GammaTxnConfig(stm, refs.length) .setMaximumPoorMansConflictScanLength(refs.length); config.dirtyCheck = dirtyCheck; FatVariableLengthGammaTxn tx = null; for (int transaction = 0; transaction < transactionCount; transaction++) { if (transactionReuse) { if (tx == null) { tx = new FatVariableLengthGammaTxn(config); } } else { tx = new FatVariableLengthGammaTxn(config); } for (int k = 0; k < refs.length; k++) { if (random.nextInt(3) == 1) { refs[k].openForWrite(tx, LOCKMODE_NONE).long_value++; created++; } else { refs[k].openForWrite(tx, LOCKMODE_NONE); } } tx.commit(); tx.hardReset(); if (transaction % 1000 == 0) { System.out.println("at " + transaction); } } long sum = 0; for (int k = 0; k < refs.length; k++) { sum += refs[k].atomicGet(); } assertEquals(created, sum); } } 000077500000000000000000000000001174000617100342715ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanLeanFixedLengthGammaTxnFactory.java000066400000000000000000000033721174000617100431270ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.api.TxnFactoryBuilder; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.GammaTxnPool; import static org.multiverse.stms.gamma.transactions.ThreadLocalGammaTxnPool.getThreadLocalGammaTxnPool; public class LeanFixedLengthGammaTxnFactory implements GammaTxnFactory { private final GammaTxnConfig config; public LeanFixedLengthGammaTxnFactory(GammaStm stm) { this(new GammaTxnConfig(stm)); } public LeanFixedLengthGammaTxnFactory(GammaStm stm, int fixedLengthSize) { this(new GammaTxnConfig(stm, fixedLengthSize)); } public LeanFixedLengthGammaTxnFactory(GammaTxnConfig config) { this.config = config.init(); } @Override public TxnFactoryBuilder getTxnFactoryBuilder() { throw new UnsupportedOperationException(); } @Override public GammaTxnConfig getConfig() { return config; } @Override public GammaTxn upgradeAfterSpeculativeFailure(GammaTxn failingTransaction, GammaTxnPool pool) { throw new UnsupportedOperationException(); } @Override public LeanFixedLengthGammaTxn newTxn() { return newTransaction(getThreadLocalGammaTxnPool()); } @Override public LeanFixedLengthGammaTxn newTransaction(GammaTxnPool pool) { LeanFixedLengthGammaTxn tx = pool.takeLeanFixedLength(); if (tx == null) { tx = new LeanFixedLengthGammaTxn(config); } else { tx.init(config); } return tx; } }LeanFixedLengthGammaTxn_abortTest.java000066400000000000000000000004341174000617100436220ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanFixedLengthGammaTxn_abortTest extends LeanGammaTxn_abortTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } } LeanFixedLengthGammaTxn_commitTest.java000066400000000000000000000014141174000617100440020ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class LeanFixedLengthGammaTxn_commitTest extends LeanGammaTxn_commitTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } @Override public void assertClearedAfterCommit() { //To change body of implemented methods use File | Settings | File Templates. } @Override public void assertClearedAfterAbort() { //To change body of implemented methods use File | Settings | File Templates. } @Override public int getMaximumLength() { return new GammaTxnConfig(stm).maxFixedLengthTransactionSize; } } LeanFixedLengthGammaTxn_commuteTest.java000066400000000000000000000004411174000617100441620ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanFixedLengthGammaTxn_commuteTest extends LeanGammaTxn_commuteTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } } LeanFixedLengthGammaTxn_openForConstructionTest.java000066400000000000000000000005011174000617100465310ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanFixedLengthGammaTxn_openForConstructionTest extends LeanGammaTxn_openForConstructionTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } } LeanFixedLengthGammaTxn_openForReadTest.java000066400000000000000000000007501174000617100447200ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class LeanFixedLengthGammaTxn_openForReadTest extends LeanGammaTxn_openForReadTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } @Override public int getMaximumLength() { return new GammaTxnConfig(stm).maxFixedLengthTransactionSize; } } LeanFixedLengthGammaTxn_openForWriteTest.java000066400000000000000000000007521174000617100451410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class LeanFixedLengthGammaTxn_openForWriteTest extends LeanGammaTxn_openForWriteTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } @Override public int getMaximumLength() { return new GammaTxnConfig(stm).maxFixedLengthTransactionSize; } } LeanFixedLengthGammaTxn_prepareTest.java000066400000000000000000000004401174000617100441460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanFixedLengthGammaTxn_prepareTest extends LeanGammaTxn_prepareTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } } LeanFixedLengthGammaTxn_registerTest.java000066400000000000000000000004531174000617100443400ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanFixedLengthGammaTxn_registerTest extends LeanGammaTxn_registerTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } } LeanFixedLengthGammaTxn_retryTest.java000066400000000000000000000007571174000617100436700ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class LeanFixedLengthGammaTxn_retryTest extends LeanGammaTxn_retryTest{ @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } @Override public LeanFixedLengthGammaTxn newTransaction(GammaTxnConfig config) { return new LeanFixedLengthGammaTxn(config); } } LeanFixedLengthGammaTxn_setAbortOnlyTest.java000066400000000000000000000004531174000617100451410ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanFixedLengthGammaTxn_setAbortOnlyTest extends LeanGammaTxn_setAbortOnlyTest { @Override public LeanFixedLengthGammaTxn newTransaction() { return new LeanFixedLengthGammaTxn(stm); } } LeanGammaTxn_abortTest.java000066400000000000000000000055701174000617100415060ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class LeanGammaTxn_abortTest { public GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); @Test public void whenUnused() { T tx = newTransaction(); tx.abort(); assertIsAborted(tx); } @Test public void whenContainsRead() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); tx.abort(); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 0); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertRefHasNoLocks(ref); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertNull(tranlocal.owner); } @Test public void whenContainsWrite() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tx.abort(); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertSurplus(ref, 0); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertRefHasNoLocks(ref); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertNull(tranlocal.owner); } @Test public void whenUnusedAndPrepared() { T tx = newTransaction(); tx.prepare(); tx.abort(); assertIsAborted(tx); } @Test public void whenAborted() { T tx = newTransaction(); tx.abort(); tx.abort(); assertIsAborted(tx); } @Test public void whenCommitted() { T tx = newTransaction(); tx.commit(); try { tx.abort(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); } } LeanGammaTxn_commitTest.java000066400000000000000000000245001174000617100416610ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class LeanGammaTxn_commitTest { public GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); public abstract int getMaximumLength(); public abstract void assertClearedAfterCommit(); public abstract void assertClearedAfterAbort(); @Test public void conflict_whenReadByOther(){ String initialValue = null; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); String newValue = "bar"; ref.set(tx, newValue); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatVariableLengthGammaTxn otherTx = new FatVariableLengthGammaTxn(config); ref.get(otherTx); long globalConflictCount = stm.globalConflictCounter.count(); tx.commit(); assertGlobalConflictCount(stm, globalConflictCount+1); assertVersionAndValue(ref, initialVersion+1, newValue); } @Test public void whenUnused() { T tx = newTransaction(); long globalConflictCount = stm.globalConflictCounter.count(); tx.commit(); assertIsCommitted(); assertClearedAfterCommit(); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenMultipleDirtyWrites() { assumeTrue(getMaximumLength() > 1); long globalConflictCount = stm.globalConflictCounter.count(); String initialValue1 = "foo1"; String updateValue1 = "bar1"; GammaTxnRef ref1 = new GammaTxnRef(stm, initialValue1); long initialVersion1 = ref1.getVersion(); String initialValue2 = "foo2"; String updateValue2 = "bar1"; GammaTxnRef ref2 = new GammaTxnRef(stm, initialValue2); long initialVersion2 = ref2.getVersion(); T tx = newTransaction(); Tranlocal tranlocal1 = ref1.openForWrite(tx, LOCKMODE_NONE); tranlocal1.ref_value = updateValue1; Tranlocal tranlocal2 = ref2.openForWrite(tx, LOCKMODE_NONE); tranlocal2.ref_value = updateValue2; tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref1); assertSurplus(ref1, 0); assertVersionAndValue(ref1, initialVersion1 + 1, updateValue1); assertWriteBiased(ref1); assertNull(tranlocal1.owner); assertNull(tranlocal1.ref_value); assertFalse(tranlocal1.hasDepartObligation); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); assertVersionAndValue(ref2, initialVersion2 + 1, updateValue2); assertWriteBiased(ref2); assertNull(tranlocal2.owner); assertNull(tranlocal2.ref_value); assertFalse(tranlocal2.hasDepartObligation); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenMultipleNonDirtyWrites() { assumeTrue(getMaximumLength() > 1); long globalConflictCount = stm.globalConflictCounter.count(); String initialValue1 = "foo1"; GammaTxnRef ref1 = new GammaTxnRef(stm, initialValue1); long initialVersion1 = ref1.getVersion(); String initialValue2 = "foo2"; GammaTxnRef ref2 = new GammaTxnRef(stm, initialValue2); long initialVersion2 = ref2.getVersion(); T tx = newTransaction(); Tranlocal tranlocal1 = ref1.openForWrite(tx, LOCKMODE_NONE); Tranlocal tranlocal2 = ref2.openForWrite(tx, LOCKMODE_NONE); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref1); assertSurplus(ref1, 0); assertVersionAndValue(ref1, initialVersion1 + 1, initialValue1); assertWriteBiased(ref1); assertNull(tranlocal1.owner); assertNull(tranlocal1.ref_value); assertFalse(tranlocal1.hasDepartObligation); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); assertVersionAndValue(ref2, initialVersion2 + 1, initialValue2); assertWriteBiased(ref2); assertNull(tranlocal2.owner); assertNull(tranlocal2.ref_value); assertFalse(tranlocal2.hasDepartObligation); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenNonDirtyUpdate() { long globalConflictCount = stm.globalConflictCounter.count(); String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.ref_value = initialValue; tx.commit(); assertNull(tranlocal.owner); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertIsCommitted(tx); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue); assertIsCommitted(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenDirtyUpdate() { long globalConflictCount = stm.globalConflictCounter.count(); String initialValue = "foo"; String newValue = "bar"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.ref_value = newValue; tx.commit(); assertNull(tranlocal.owner); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertIsCommitted(tx); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, newValue); assertIsCommitted(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenLockedByOtherAndWrite() { whenLockedByOtherAndWrite(LockMode.Read); whenLockedByOtherAndWrite(LockMode.Write); whenLockedByOtherAndWrite(LockMode.Exclusive); } protected void whenLockedByOtherAndWrite(LockMode lockMode) { long globalConflictCount = stm.globalConflictCounter.count(); String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, lockMode); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertSurplus(ref, 1); assertNull(tranlocal.owner); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenNormalRead() { long globalConflictCount = stm.globalConflictCounter.count(); String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); tx.commit(); assertIsCommitted(tx); assertNull(tranlocal.owner); assertNull(tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAlreadyPreparedAndUnused() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.prepare(); tx.commit(); assertIsCommitted(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAlreadyCommitted() { long globalConflictCount = stm.globalConflictCounter.count(); String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.commit(); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAlreadyAborted() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.abort(); try { tx.commit(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertGlobalConflictCount(stm, globalConflictCount); } } LeanGammaTxn_commuteTest.java000066400000000000000000000032771174000617100420520ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.SpeculativeConfigurationError; import org.multiverse.api.functions.Function; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class LeanGammaTxn_commuteTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); @Test public void whenCommute_thenSpeculativeConfigurationError() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Function function = mock(Function.class); try { ref.commute(tx, function); fail(); } catch (SpeculativeConfigurationError expected) { } verifyZeroInteractions(function); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertTrue(tx.getConfig().speculativeConfiguration.get().commuteDetected); } } LeanGammaTxn_openForConstructionTest.java000066400000000000000000000021041174000617100444100ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.SpeculativeConfigurationError; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; public abstract class LeanGammaTxn_openForConstructionTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); @Test public void whenOpenedForConstruction_thenSpeculativeConfigurationError() { T tx = newTransaction(); try { new GammaTxnRef(tx); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.getConfig().speculativeConfiguration.get().constructedObjectsDetected); } } LeanGammaTxn_openForReadTest.java000066400000000000000000000342261174000617100426030ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.SpeculativeConfigurationError; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.*; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class LeanGammaTxn_openForReadTest implements GammaConstants { protected GammaStm stm; public abstract T newTransaction(); public abstract int getMaximumLength(); @Before public void setUp() { stm = new GammaStm(); } @Test public void whenMultipleWrites() { assumeTrue(getMaximumLength() > 1); String initialValue1 = "foo1"; GammaTxnRef ref1 = new GammaTxnRef(stm, initialValue1); String initialValue2 = "foo2"; GammaTxnRef ref2 = new GammaTxnRef(stm, initialValue2); GammaTxn tx = newTransaction(); Tranlocal tranlocal1 = ref1.openForRead(tx, LOCKMODE_NONE); Tranlocal tranlocal2 = ref2.openForRead(tx, LOCKMODE_NONE); assertIsActive(tx); assertRefHasNoLocks(ref1); assertSurplus(ref1, 0); assertSame(ref1, tranlocal1.owner); assertEquals(TRANLOCAL_READ, tranlocal1.mode); assertSame(initialValue1, tranlocal1.ref_value); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); assertSame(ref2, tranlocal2.owner); assertEquals(TRANLOCAL_READ, tranlocal2.mode); assertSame(initialValue2, tranlocal2.ref_value); } @Test public void whenExplicitLocking_thenSpeculativeConfigurationFailure() { whenExplicitLocking(LockMode.Read); whenExplicitLocking(LockMode.Write); whenExplicitLocking(LockMode.Exclusive); } public void whenExplicitLocking(LockMode lockMode) { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForRead(tx, lockMode.asInt()); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertTrue(tx.config.speculativeConfiguration.get().locksDetected); } @Test public void whenIntRef_thenSpeculativeConfigurationError() { int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSpeculativeConfigurationNonRefTypeRequired(tx); } @Test public void whenBooleanRef_thenSpeculativeConfigurationError() { boolean initialValue = true; GammaTxnBoolean ref = new GammaTxnBoolean(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSpeculativeConfigurationNonRefTypeRequired(tx); } @Test public void whenTxnDouble_thenSpeculativeConfigurationError() { double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSpeculativeConfigurationNonRefTypeRequired(tx); } @Test public void whenLongRef_thenSpeculativeConfigurationError() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSpeculativeConfigurationNonRefTypeRequired(tx); } @Test public void whenExclusiveLockObtainedByOthers() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNonExclusiveLockAcquiredByOthers() { whenNonExclusiveLockAcquiredByOthers(LockMode.Read); whenNonExclusiveLockAcquiredByOthers(LockMode.Write); } public void whenNonExclusiveLockAcquiredByOthers(LockMode lockMode) { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, lockMode); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertIsActive(tx); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertSame(initialValue, tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_READ, tranlocal.mode); assertFalse(tranlocal.hasDepartObligation); assertEquals(initialVersion, tranlocal.version); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNotOpenedBefore() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_READ, tranlocal.mode); assertSame(initialValue, tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertEquals(initialVersion, tranlocal.version); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForRead() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal first = ref.openForRead(tx, LOCKMODE_NONE); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertSame(first, tranlocal); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_READ, tranlocal.mode); assertSame(initialValue, tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertEquals(initialVersion, tranlocal.version); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenMultipleReadsAndConsistent() { assumeTrue(getMaximumLength() > 1); GammaTxnRef ref1 = new GammaTxnRef(stm); GammaTxnRef ref2 = new GammaTxnRef(stm); GammaTxn tx = newTransaction(); ref1.openForRead(tx, LOCKMODE_NONE); ref2.openForRead(tx, LOCKMODE_NONE); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref1); assertSurplus(ref1, 0); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); } @Test public void whenMultipleReadsAndInconsistent() { assumeTrue(getMaximumLength() > 1); GammaTxnRef ref1 = new GammaTxnRef(stm); GammaTxnRef ref2 = new GammaTxnRef(stm); GammaTxn tx = newTransaction(); ref1.openForRead(tx, LOCKMODE_NONE); ref1.atomicSet("foo"); try { ref2.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref1); assertSurplus(ref1, 0); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); } @Test public void whenMultipleReadsAndPreviousReadLockedExclusively() { assumeTrue(getMaximumLength() > 1); GammaTxnRef ref1 = new GammaTxnRef(stm); GammaTxnRef ref2 = new GammaTxnRef(stm); GammaTxn tx = newTransaction(); ref1.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref1.getLock().acquire(otherTx, LockMode.Exclusive); try { ref2.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref1, otherTx); assertSurplus(ref1, 1); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); } @Test public void whenAlreadyOpenedForWrite() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal first = ref.openForWrite(tx, LOCKMODE_NONE); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertSame(first, tranlocal); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_WRITE, tranlocal.mode); assertSame(initialValue, tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertEquals(initialVersion, tranlocal.version); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyPreparedAndunused() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.prepare(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyCommitted() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.commit(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyAborted() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.abort(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenOverflowing() { int maxCapacity = getMaximumLength(); assumeTrue(maxCapacity < Integer.MAX_VALUE); GammaTxn tx = newTransaction(); for (int k = 0; k < maxCapacity; k++) { GammaTxnRef ref = new GammaTxnRef(stm, 0); ref.openForRead(tx, LOCKMODE_NONE); } GammaTxnRef ref = new GammaTxnRef(stm, 0); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(maxCapacity + 1, tx.getConfig().getSpeculativeConfiguration().minimalLength); } } LeanGammaTxn_openForWriteTest.java000066400000000000000000000341051174000617100430160ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.*; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.*; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class LeanGammaTxn_openForWriteTest implements GammaConstants { public GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); public abstract int getMaximumLength(); @Test public void whenMultipleReadsAndInconsistent() { assumeTrue(getMaximumLength() > 1); GammaTxnRef ref1 = new GammaTxnRef(stm); GammaTxnRef ref2 = new GammaTxnRef(stm); GammaTxn tx = newTransaction(); ref1.openForWrite(tx, LOCKMODE_NONE); ref1.atomicSet("foo"); try { ref2.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref1); assertSurplus(ref1, 0); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); } @Test public void whenMultipleReadsAndPreviousReadLockedExclusively() { assumeTrue(getMaximumLength() > 1); GammaTxnRef ref1 = new GammaTxnRef(stm); GammaTxnRef ref2 = new GammaTxnRef(stm); GammaTxn tx = newTransaction(); ref1.openForWrite(tx, LOCKMODE_NONE); GammaTxn otherTx = stm.newDefaultTxn(); ref1.getLock().acquire(otherTx, LockMode.Exclusive); try { ref2.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref1, otherTx); assertSurplus(ref1, 1); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); } @Test public void whenMultipleWrites() { assumeTrue(getMaximumLength() > 1); String initialValue1 = "foo1"; GammaTxnRef ref1 = new GammaTxnRef(stm, initialValue1); String initialValue2 = "foo2"; GammaTxnRef ref2 = new GammaTxnRef(stm, initialValue2); GammaTxn tx = newTransaction(); Tranlocal tranlocal1 = ref1.openForWrite(tx, LOCKMODE_NONE); Tranlocal tranlocal2 = ref2.openForWrite(tx, LOCKMODE_NONE); assertIsActive(tx); assertRefHasNoLocks(ref1); assertSurplus(ref1, 0); assertSame(ref1, tranlocal1.owner); assertEquals(TRANLOCAL_WRITE, tranlocal1.mode); assertSame(initialValue1, tranlocal1.ref_value); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); assertSame(ref2, tranlocal2.owner); assertEquals(TRANLOCAL_WRITE, tranlocal2.mode); assertSame(initialValue2, tranlocal2.ref_value); } @Test public void whenMultipleReadsAndConsistent() { assumeTrue(getMaximumLength() > 1); GammaTxnRef ref1 = new GammaTxnRef(stm); GammaTxnRef ref2 = new GammaTxnRef(stm); GammaTxn tx = newTransaction(); ref1.openForWrite(tx, LOCKMODE_NONE); ref2.openForWrite(tx, LOCKMODE_NONE); assertIsActive(tx); assertRefHasNoLocks(ref1); assertSurplus(ref1, 0); assertRefHasNoLocks(ref2); assertSurplus(ref2, 0); } @Test public void whenExplicitLocking_thenSpeculativeConfigurationFailure() { whenExplicitLocking(LockMode.Read); whenExplicitLocking(LockMode.Write); whenExplicitLocking(LockMode.Exclusive); } public void whenExplicitLocking(LockMode lockMode) { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForWrite(tx, lockMode.asInt()); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertTrue(tx.config.speculativeConfiguration.get().locksDetected); } @Test public void whenIntRef_thenSpeculativeConfigurationError() { int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSpeculativeConfigurationNonRefTypeRequired(tx); } @Test public void whenBooleanRef_thenSpeculativeConfigurationError() { boolean initialValue = true; GammaTxnBoolean ref = new GammaTxnBoolean(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSpeculativeConfigurationNonRefTypeRequired(tx); } @Test public void whenTxnDouble_thenSpeculativeConfigurationError() { double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSpeculativeConfigurationNonRefTypeRequired(tx); } @Test public void whenLongRef_thenSpeculativeConfigurationError() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertSpeculativeConfigurationNonRefTypeRequired(tx); } @Test public void whenExclusiveLockObtainedByOthers() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNonExclusiveLockAcquiredByOthers() { whenNonExclusiveLockAcquiredByOthers(LockMode.Read); whenNonExclusiveLockAcquiredByOthers(LockMode.Write); } public void whenNonExclusiveLockAcquiredByOthers(LockMode lockMode) { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, lockMode); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertIsActive(tx); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertSame(initialValue, tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TRANLOCAL_WRITE, tranlocal.mode); assertFalse(tranlocal.hasDepartObligation); assertEquals(initialVersion, tranlocal.version); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertSurplus(ref, 1); assertWriteBiased(ref); assertReadonlyCount(ref, 0); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenOverflowing() { int maxCapacity = getMaximumLength(); assumeTrue(maxCapacity < Integer.MAX_VALUE); T tx = newTransaction(); for (int k = 0; k < maxCapacity; k++) { GammaTxnRef ref = new GammaTxnRef(stm, 0); ref.openForWrite(tx, LOCKMODE_NONE); } GammaTxnRef ref = new GammaTxnRef(stm, 0); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(maxCapacity + 1, tx.getConfig().getSpeculativeConfiguration().minimalLength); } @Test public void whenNotOpenedBefore() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertSame(initialValue, tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertEquals(initialVersion, tranlocal.version); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForRead() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(read, tranlocal); assertSame(ref, tranlocal.owner); assertSame(initialValue, tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertEquals(initialVersion, tranlocal.version); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForWrite() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal first = ref.openForWrite(tx, LOCKMODE_NONE); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(first, tranlocal); assertSame(ref, tranlocal.owner); assertSame(initialValue, tranlocal.ref_value); assertNull(tranlocal.ref_oldValue); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertEquals(initialVersion, tranlocal.version); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyPreparedAndunused() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.prepare(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyCommitted() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.commit(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyAborted() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.abort(); try { ref.openForWrite(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } } LeanGammaTxn_prepareTest.java000066400000000000000000000204721174000617100420330ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.LOCKMODE_EXCLUSIVE; import static org.multiverse.stms.gamma.GammaTestUtils.LOCKMODE_NONE; import static org.multiverse.stms.gamma.GammaTestUtils.LOCKMODE_READ; import static org.multiverse.stms.gamma.GammaTestUtils.LOCKMODE_WRITE; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class LeanGammaTxn_prepareTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); @Test public void conflict_whenArriveByOther() { String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); String newValue = "bar"; ref.set(tx, newValue); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatVariableLengthGammaTxn otherTx = new FatVariableLengthGammaTxn(config); ref.get(otherTx); long globalConflictCount = stm.globalConflictCounter.count(); tx.prepare(); assertIsPrepared(tx); assertTrue(tx.commitConflict); assertGlobalConflictCount(stm, globalConflictCount); assertVersionAndValue(ref, initialVersion, initialValue); assertLockMode(ref, LOCKMODE_EXCLUSIVE); assertSurplus(ref, 2); } @Test public void whenContainsRead() { long globalConflictCount = stm.getGlobalConflictCounter().count(); String initialValue = "foo"; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); ref.openForRead(tx, LOCKMODE_NONE); tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertLockMode(ref, LOCKMODE_NONE); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } public void whenNonDirtyDirty_thenLockedForCommit() { long globalConflictCount = stm.getGlobalConflictCounter().count(); Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tx.prepare(); assertIsPrepared(tx); assertTrue(tranlocal.isDirty()); assertFalse(tx.commitConflict); assertEquals(LockMode.Exclusive.asInt(), tranlocal.getLockMode()); assertLockMode(ref, LockMode.Exclusive); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } public void whenDirtyDirty_thenLockedForCommit() { long globalConflictCount = stm.getGlobalConflictCounter().count(); Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertTrue(tranlocal.isDirty()); assertEquals(LockMode.Exclusive.asInt(), tranlocal.getLockMode()); assertLockMode(ref, LockMode.Exclusive); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } // =============================== locked by other ============================= @Test public void conflict_dirty_whenReadLockedByOther() { long globalConflictCount = stm.getGlobalConflictCounter().count(); Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; FatMonoGammaTxn otherTx = new FatMonoGammaTxn(stm); ref.openForRead(otherTx, LOCKMODE_READ); try { tx.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void conflict_dirty_whenWriteLockedByOther() { long globalConflictCount = stm.getGlobalConflictCounter().count(); Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; FatMonoGammaTxn otherTx = new FatMonoGammaTxn(stm); ref.openForRead(otherTx, LOCKMODE_WRITE); try { tx.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void conflict_dirty_whenExclusiveLockedByOther() { long globalConflictCount = stm.getGlobalConflictCounter().count(); Long initialValue = 10L; GammaTxnRef ref = new GammaTxnRef(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; FatMonoGammaTxn otherTx = new FatMonoGammaTxn(stm); ref.openForRead(otherTx, LOCKMODE_EXCLUSIVE); try { tx.prepare(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); assertGlobalConflictCount(stm, globalConflictCount); } // ================================ states ===================================== @Test public void whenPreparedAndUnused() { long globalConflictCount = stm.getGlobalConflictCounter().count(); T tx = newTransaction(); tx.prepare(); tx.prepare(); assertIsPrepared(tx); assertFalse(tx.commitConflict); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAlreadyAborted_thenDeadTxnException() { long globalConflictCount = stm.getGlobalConflictCounter().count(); T tx = newTransaction(); tx.abort(); try { tx.prepare(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAlreadyCommitted_thenDeadTxnException() { long globalConflictCount = stm.getGlobalConflictCounter().count(); T tx = newTransaction(); tx.commit(); try { tx.prepare(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertGlobalConflictCount(stm, globalConflictCount); } } LeanGammaTxn_registerTest.java000066400000000000000000000057771174000617100422340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.SpeculativeConfigurationError; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; public abstract class LeanGammaTxn_registerTest { public GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); @Test public void whenNullListener_thenNullPointerException() { T tx = newTransaction(); try { tx.register(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertFalse(tx.getConfig().getSpeculativeConfiguration().listenersDetected); } @Test public void whenSuccess() { T tx = newTransaction(); TxnListener listener = mock(TxnListener.class); try { tx.register(listener); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.getConfig().getSpeculativeConfiguration().listenersDetected); assertNull(tx.listeners); verifyZeroInteractions(listener); } @Test public void whenAlreadyPrepared() { T tx = newTransaction(); tx.prepare(); TxnListener listener = mock(TxnListener.class); try { tx.register(listener); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(listener); assertFalse(tx.getConfig().getSpeculativeConfiguration().listenersDetected); } @Test public void whenAlreadyAborted() { T tx = newTransaction(); tx.abort(); TxnListener listener = mock(TxnListener.class); try { tx.register(listener); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(listener); assertFalse(tx.getConfig().getSpeculativeConfiguration().listenersDetected); } @Test public void whenAlreadyCommitted() { T tx = newTransaction(); tx.commit(); TxnListener listener = mock(TxnListener.class); try { tx.register(listener); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); verifyZeroInteractions(listener); assertFalse(tx.getConfig().getSpeculativeConfiguration().listenersDetected); } } LeanGammaTxn_retryTest.java000066400000000000000000000043711174000617100415420ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.exceptions.RetryNotAllowedException; import org.multiverse.api.exceptions.RetryNotPossibleException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsCommitted; public abstract class LeanGammaTxn_retryTest { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } public abstract T newTransaction(); public abstract T newTransaction(GammaTxnConfig config); @Test public void whenUnused() { GammaTxn tx = newTransaction(); try { tx.retry(); fail(); } catch (RetryNotPossibleException expected) { } assertIsAborted(tx); } @Test public void whenNoRetryAllowed() { GammaTxnConfig config = new GammaTxnConfig(stm); config.blockingAllowed = false; T tx = newTransaction(config); try { tx.retry(); fail(); } catch (RetryNotAllowedException expected) { } assertIsAborted(tx); } @Test public void whenAlreadyPrepared() { T tx = newTransaction(); tx.prepare(); try { tx.retry(); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); } @Test public void whenAlreadyAborted() { T tx = newTransaction(); tx.abort(); try { tx.retry(); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); } @Test public void whenAlreadyCommitted() { T tx = newTransaction(); tx.commit(); try { tx.retry(); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); } } LeanGammaTxn_setAbortOnlyTest.java000066400000000000000000000017451174000617100430240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.junit.Before; import org.junit.Test; import org.multiverse.api.exceptions.SpeculativeConfigurationError; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.assertIsAborted; public abstract class LeanGammaTxn_setAbortOnlyTest { public GammaStm stm; public abstract T newTransaction(); @Before public void setUp() { stm = new GammaStm(); } @Test public void whenSetAbortOnlyCalled_thenSpeculativeConfigurationError() { T tx = newTransaction(); try { tx.setAbortOnly(); fail(); } catch (SpeculativeConfigurationError expected) { } assertIsAborted(tx); assertTrue(tx.config.speculativeConfiguration.get().abortOnlyDetected); } } LeanMonoGammaTxnFactory.java000066400000000000000000000031721174000617100416340ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.api.TxnFactoryBuilder; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.GammaTxnFactory; import org.multiverse.stms.gamma.transactions.GammaTxnPool; import static org.multiverse.stms.gamma.transactions.ThreadLocalGammaTxnPool.getThreadLocalGammaTxnPool; public class LeanMonoGammaTxnFactory implements GammaTxnFactory { private final GammaTxnConfig config; public LeanMonoGammaTxnFactory(GammaStm stm) { this(new GammaTxnConfig(stm).setControlFlowErrorsReused(false)); } public LeanMonoGammaTxnFactory(GammaTxnConfig config) { this.config = config.setControlFlowErrorsReused(false).init(); } @Override public GammaTxnConfig getConfig() { return config; } @Override public GammaTxn upgradeAfterSpeculativeFailure(GammaTxn failingTransaction, GammaTxnPool pool) { throw new UnsupportedOperationException(); } @Override public TxnFactoryBuilder getTxnFactoryBuilder() { throw new UnsupportedOperationException(); } @Override public LeanMonoGammaTxn newTxn() { return newTransaction(getThreadLocalGammaTxnPool()); } @Override public LeanMonoGammaTxn newTransaction(GammaTxnPool pool) { LeanMonoGammaTxn tx = pool.takeLeanMono(); if (tx == null) { tx = new LeanMonoGammaTxn(config); } else { tx.init(config); } return tx; } } LeanMonoGammaTxn_abortTest.java000066400000000000000000000004011174000617100423230ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_abortTest extends LeanGammaTxn_abortTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } } LeanMonoGammaTxn_commitTest.java000066400000000000000000000011751174000617100425150ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_commitTest extends LeanGammaTxn_commitTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } @Override public void assertClearedAfterCommit() { //To change body of implemented methods use File | Settings | File Templates. } @Override public void assertClearedAfterAbort() { //To change body of implemented methods use File | Settings | File Templates. } @Override public int getMaximumLength() { return 1; } } LeanMonoGammaTxn_commuteTest.java000066400000000000000000000004151174000617100426720ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_commuteTest extends LeanGammaTxn_commuteTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } } LeanMonoGammaTxn_openForConstructionTest.java000066400000000000000000000004451174000617100452470ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_openForConstructionTest extends LeanGammaTxn_openForConstructionTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } } LeanMonoGammaTxn_openForReadTest.java000066400000000000000000000005401174000617100434240ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_openForReadTest extends LeanGammaTxn_openForReadTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } @Override public int getMaximumLength() { return 1; } } LeanMonoGammaTxn_openForWriteTest.java000066400000000000000000000005321174000617100436440ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_openForWriteTest extends LeanGammaTxn_openForWriteTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } @Override public int getMaximumLength() { return 1; } } LeanMonoGammaTxn_prepareTest.java000066400000000000000000000004041174000617100426550ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_prepareTest extends LeanGammaTxn_prepareTest{ @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } } LeanMonoGammaTxn_registerTest.java000066400000000000000000000004071174000617100430460ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_registerTest extends LeanGammaTxn_registerTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } } LeanMonoGammaTxn_retryTest.java000066400000000000000000000007061174000617100423710ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; public class LeanMonoGammaTxn_retryTest extends LeanGammaTxn_retryTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } @Override public LeanMonoGammaTxn newTransaction(GammaTxnConfig config) { return new LeanMonoGammaTxn(config); } } LeanMonoGammaTxn_setAbortOnlyTest.java000066400000000000000000000004171174000617100436500ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-core/src/test/java/org/multiverse/stms/gamma/transactions/leanpackage org.multiverse.stms.gamma.transactions.lean; public class LeanMonoGammaTxn_setAbortOnlyTest extends LeanGammaTxn_setAbortOnlyTest { @Override public LeanMonoGammaTxn newTransaction() { return new LeanMonoGammaTxn(stm); } } Multiverse-multiverse-0.7.0/multiverse-core/todo.txt000077500000000000000000000127761174000617100227220ustar00rootroot00000000000000ideas: - fast 'write' on orec.depart when exclusive lock and no surplus - fast readset validation on committing transaction if the conflict counter has not changed needs more research. - stripe of conflict counters. - optimize the tx-pool logic (instead of using an array, use a single linked list).. transactions can also act as node (no need to introduce additional datastructures). - Collections - 'size' structure to help with an approximate size for collections - instead of going through the transaction to deal with tranlocals, one you have a reference to one, all operations like openForWrite/checkConflict/ensure etc. - ensure on the transaction? To make all changes 'committable'. - selective notifies in transaction, instead of always waking up.. one could provide a function that only wakes up under certain conditions. - actor atomic block, doesn't look at an existing transaction. Automatically exposes the onAbort/onCommit - on read/ on write function - stuff like encryption and security could be added through this general purpose mechanism - reset the speculative stuff once and a while. - some spinning is allowed for the read conflict scan: is this desirable? If it is locked, chances are high that and update already is done or is going to be done. - cheap writeskew detection; first lock all writes.. if conflict counter hasn't changed, you know that there are no read conflicts.. - write validation: can it be optimized? If the conflict counter has not changed, you know that no other transaction has caused any conflicting writes. So you know that there is no write conflict. - when a transaction needs to wait for a lock, can it help another transaction? - contention management. - the class index makes it easy to create some kind of arrays that store all kind of information on the transactional class level. The question is how to to do it for transactions. You don't want to publish it every time. - is it possible to combine pessimistic locking with blocking? What if a transaction wants to wait for a lock to become free... so can when a lock release is done, see if there are listeners before releasing the lock? If done before, the transaction knows it can remove the current listeners with the a cas, and add them to the set of listeners that to be notified. If a transaction wants to block ... when a normal transaction... when a lock is acquired, a retry error should also be thrown. - durability: only when committing, a dirty transactional object needs to be checked if it is durable. If it isn't no unitofwrite needs to be used. If it is, a unit of write needs to be used. So the commit needs to - create an orec that never become readbiased (useful for performance comparison). - transactional treemap - transactional treeset - a reference that always causes a privatization. - transactional array - use a retry policy for re-acquiring lock. atm only spinning is used. - cram all logic of the tranlocal in a long - tryEnsure - tryPrivatize - tryEnsureWhen - tryPrivatizeWhen - reading and backoff? Atm only spinning is used. - acquire commit lock. atm only some spinning is used - clojure: add watch. Basic functionality already is there, but atm it is done to all reads and not specific ones. - commute: commuting functions are executed in reverse order. - blocking and speculative readtracking? - lean mono should not upgrade to array when untracked read is done, but should just attach it to the transaction. - rollbackfor/rollnotbackfor exception configuration - profiler - full transactional objects - logic for full transactional objects needs to be fixed. - pooling for generic transactional object tranlocals. - jmm issue with commit and listeners, it could happen that a write is done after a check is done if a listeners is available. This could lead to a deadlock since the listener that is set after the write - adding read committed isolation level -------------------------------------------------------------------- to do -------------------------------------------------------------------- - CountDownCommitBarrier: RestorePartiesCompensatingTask - iterators and transactional collections - transactional collections and check on isolation level of transaction - pre/post start listeners and fat gamma block - NaiveTransactionalHashMap & todo's - NaiveTransactionalhashSet & todo's - NaiveTransactionalLinkedList & todo's - CommitBarrier & todo's - testing: prepare of transactions and excusive lock isolation level - testing: listeners & exceptions - testing: commute and locking - testing: atomic change operations and globalconflictcounter increment - testing: local conflict counter should be set if needed when the flatten commute is called. - testing: GammaTxnRef_getAndAlterTest - testing: PhantomReadTest - Javadoc: TransactionalCollection - Javadoc: TransactionalCollectionFactory - Javadoc: TransactionalDeque - Javadoc: TransactionalIterable - Javadoc: TransactionalList - Javadoc: TransactionalMap - Javadoc: TransactionalQueue - Javadoc: TransactionalSet - Javadoc: TransactionalStack - Javadoc: BinaryFunction - Javadoc: Isolation Level - cleanup codehaus uploads - automatic publication of SNAPSHOT javadoc on codehaus - automatic publication of javadoc on codehaus - automatic publication of site on codehaus - publication of benchy ---------------------------------------------------------------------- done ---------------------------------------------------------------------- Multiverse-multiverse-0.7.0/multiverse-site/000077500000000000000000000000001174000617100212105ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-site/license.css000066400000000000000000000013331174000617100233440ustar00rootroot00000000000000body { font-family:Arial,Helvetica,sans-serif; font-size:11pt; color:#000000; background-color:#ffffff; text-align:left; } .bodywidth { width:750px; } h1, h2, h3, .contentbar { padding:3px; } h1, h2, h3 { font-weight:bold; } h1 { font-size:24pt; text-align:center; } h2, h3, .contentbar { color:#000000; background-color:#ccccff; border:none; } h2 { font-size:14pt; } h3 { font-size:10pt; } img { border:0; } ul { list-style-type:square; } pre { color:#000000; background-color:#cccccc; font-family:monospace; font-size:8pt; padding:3px; } Multiverse-multiverse-0.7.0/multiverse-site/license.html000066400000000000000000000031071174000617100235210ustar00rootroot00000000000000 XXX License

XXX License (MIT License)

Copyright (c) 2012 Peter Veentjer.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Multiverse-multiverse-0.7.0/multiverse-site/menu.groovy000066400000000000000000000065301174000617100234270ustar00rootroot00000000000000import groovy.text.GStringTemplateEngine class Menu { String name MenuItem[] items } class MenuItem { String url, title, pageid SubMenuItem[] items boolean containsSubMenuItem(String pageid) { for (def item in items) { if (item.pageid == pageid) { return true; } } false } } class SubMenuItem { String url, title, pageid } class Page { String pageid, dir } //======================================================= def lastupdate = String.format("%te %60 Second guide to Multiverse Multiverse is a Software Transansactional Memory (STM) implementation and meant as an alternative to traditional lock based concurrency control. If you have worked with databases before, STM should feel familiar because both share one very important concept: transactions. Mutuable state that needs be accessed transactionally should be stored in transactional references (comparible to the atomic references from java.util.concurrent.atomic package).

Underneath you can see a small example of an Account with 2 mutable fields: balance and lastUpdate. These 2 fields will be updated atomically in the incBalance method using a transaction.

    import org.multiverse.api.references.*;
    import static org.multiverse.api.StmUtils.*;

    public class Account{

        private final TxnRef<Date> lastUpdate;
        private final TxnInteger balance = newTxnInteger();

        public Account(int balance){
            this.lastUpdate = newTxnRef<Date>(new Date());
            this.balance = newTxnInteger(balance);
        }

        public void incBalance(final int amount, final Date date){
            atomic(new Runnable(){
                public void run(){
                    balance.inc(amount);
                    lastUpdate.set(date);

                    if(balance.get()<<0){
                        throw new IllegalStateException("Not enough money");
                    }
                }
            });
        }
    }
The transactional behavior of the incBalance method gives us:
  1. failure atomicity: all writes will commit or none will commit. In this case it could happen that money is withdrawn and the balance becomes negative. At the end this will be detected, but the changes are already made. The STM will make sure that these changes will never be committed.
  2. isolation: all reads and writes are thread-safe and are isolated from other transaction. A txn automatically gets a Oracle version of the SERIALIZABLE isolation level. You don't need to deal with lower isolation levels like READ_UNCOMMITTED, READ_COMMITTED or REPEATABLE_READ.
  3. no deadlocks between transactions because deadlocks are prevented by Multiverse.

Composing transactional methods

Transactional methods can also be composed in new transactional methods, e.g.
    public static void transfer(final Account from, final Account to, final int amount){
        atomic(new Runnable(){
            public void run(){
                Date date = new Date();

                from.incBalance(-amount, date);
                to.incBalance(amount, date);
             }
        });
    }
With lock based concurrency control this is dangerous to do since you can quickly run into a deadlock (e.g. when 2 threads are transferring money from 2 accounts in the opposite direction). But with STM, deadlocks will be prevented and transactions retried automatically.

This example only scratches the surface of Multiverse, but just having transactional methods can be a very big step forward in a lot of cases. For more advanced features and in-depth documention, the manual or documentation overview are the best places to get started. Multiverse-multiverse-0.7.0/multiverse-site/site/development.html000066400000000000000000000020621174000617100253640ustar00rootroot00000000000000

Development

On this page you can find all information related to developing Multiverse. For more information about how to set up your project that depends on Multiverse, check the following page.

Links

Underneath you can find the most important links:

Building the project

You need to install Gradle 1.0 Milestone 9 (download). If you go to the root directory and type 'gradle -i' (the -i adds progress information) the project will automatically be compiled and the artifacts will also be stored in your local maven repository. Other important commands:
    //builds the jar from scratch (unit tests are not executed)
    gradle -i clean install

    //runs the tests
    gradle -i test

    //runs the integration tests (this can some time).
    gradle -i integrationtest
Multiverse-multiverse-0.7.0/multiverse-site/site/documentationoverview.html000066400000000000000000000111371174000617100275050ustar00rootroot00000000000000

Documentation overview

Introductions

Multiverse 0.7 Reference and API

For a more thorough explanation of Multiverse and how to configure it, check out one of the following manuals. And don't be scared to check out the Javadoc and source code. Understanding the source also helps to understand how to use Multiverse more effectivly or how to extend it. Or check the download page to download Multiverse artifacts.

Recommended Papers

A lot of research has been done on transactional memory by many very smart people. Multiverse relies on a lot of the concepts and techniques discovered and invented by them. This is a listing of the most influencal papers for Multiverse.

Recommended Books

Multiverse-multiverse-0.7.0/multiverse-site/site/download.html000066400000000000000000000004261174000617100246530ustar00rootroot00000000000000

Download

Multiverse 0.7.0 is the most recent final release and can be found here:
  1. releases
  2. snapshots
Multiverse-multiverse-0.7.0/multiverse-site/site/faq.html000066400000000000000000000270111174000617100236120ustar00rootroot00000000000000

Frequent asked questions

  1. Does Multiverse rely on instrumentation?
  2. Can Multiverse be used with different languages?
  3. Can I use arbitrary threads?
  4. Can multiple STM instances be used within the same JVM?
  5. Do I need a special JVM?
  6. Can the changes be persisted?
  7. Can Multiverse be distributed?
  8. Which License is used?
  9. Does Multiverse support blocking transactions?
  10. Does Multiverse scale linearly?
  11. Does Multiverse prevent deadlocking?
  12. Does Multiverse prevent livelocking?
  13. Does Multiverse prevent starvation?
  14. Can Multiverse transactions participate in a distributed transaction?
  15. Does Multiverse suffer from Zombie threads?
  16. Can non transactional objects be used in transactions?
  17. Can IO be done in transactions?
  18. Does Multiverse provide support for pessimistic locking?
  19. Does Multiverse support nesting of transactions?
  20. Does Multiverse allow non transactional access?
  21. Does Multiverse support early or late conflict detection?
  22. Does Multiverse support direct or deferred updates?
  23. Can Multiverse be combined with traditional lock based technology?
  24. Are Multiverse Transactions thread-safe?
  25. Is lock based concurrency control bad?
  26. Multiverse and the Java Memory Model
  27. Does Multiverse have object or field granularity?
  28. Can Multiverse be combined with Spring/Guice/...?

Does Multiverse rely on instrumentation

No; it doesn't. Although instrumentation makes a cleaner integration in Java possible, it is a hassle to integrate in real projects. So instrumentation has been dropped.

Can Multiverse be used with different languages?

Multiverse can be used with different Java based languages like Groovy or Scala. For Groovy integration see the GPars project.

Can I use arbitrary threads?

Yes you can. Multiverse doesn't require any special threads or any special settings on threads.

Can multiple STM instances be used within the same JVM?

Yes you can. But each transactional object only belongs to a single STM instance. If you combine different STM's you will get exceptions.

Do I need a special JVM?

No you don't. You can use an ordinary Java 1.6+ JVM like the JVM from Sun/Oracle or IBM.

Can the changes be persisted?

No, for the moment this isn't possible. But hooking some kind of persistance mechanism up to the stm shouldn't be impossible and is planned for the future.

Can Multiverse be distributed

No, for the moment.

Which License is used

Multiverse is released under the Apache 2 License.

Does Multiverse support blocking transactions?

Yes. For more information about blocking operations, check the 5 Minute guide to blocking transactions.

Does Multiverse scale linearly?

It depends. With the introduction of Multiverse 0.7, there is no shared clock. So independant parts of the system can scale independantly.

Does Multiverse prevent deadlocking?

Yes. As long as transactional resources of Multiverse are used, transactions won't deadlock. There are 2 requirements for a deadlock:
  1. uncontrolled order of locking
  2. uncontrolled waiting
Acquiring locks in Multiverse is done with a maximum waiting time, so the second condition for a deadlock is not present. The lock behavior can be customized by providing a custom CommitLockPolicy implementation.

Does Multiverse prevent livelocking?

Multiverse is very optimistic, so it could be that while reading/writing to transactional object a failure is encountered or when the transaction commits. The TxnExecutor automatically retries the transaction in the hope that it will succeed next time. Uncontrolled retrying could lead to livelocking because resources are consumed (memory and cpu cycles) but no progress is made because transaction keep aborting. By default a bound number of retries will be used and the livelocking transaction will eventually fail with a TooManyRetriesException.

Does Multiverse prevent starvation?

No. Multiverse doesn't provide any guarantee that transaction that content over resources are going to commit. Meaning that a transaction eventually fails with a TooManyRetriesException. A practical example of starving transactions are long running transactions, the keep conflicting on very short running transactions. In the future a contention manager is going to be added, but for the time being there is no support available.

Does Multiverse suffer from Zombie threads?

It depends. By default no zombie threads are possible, but if lower than SERIALIZED isolation level is selected, zombie threads are possible and there currently is no protection agains them. So using a lowe level isolation level should be used with care.

Can non transactional objects be used in transactions?

Yes you can. Normal objects can be used in transactions, for example a normal Person POJO be exchanged over a transactional BlockingQueue for example. But changes made on these objects won't be protected by the transaction, so you need to know what you are doing.

Can IO be used in transactions?

It is possible to do IO in a transaction, but it could be that the transaction is aborted and restarted many times (for example because a read conflict or write conflict is encountered). It is possible to register tasks to be executed when a Transaction aborts or commits, giving the option to 'undo' what is done. Support for transacional IO is planned, but doesn't have a high priority at the moment.

Does Multiverse provide support for pessimistic locking?

Yes. See the Lock and LockMode.

Does Multiverse provide support for nesting transactions?

Yes. Transactions can be nested and atm they will always be flattened (so only the outer transaction counts). An abort or commit will always be executed on the while transaction and not subtransactions.

Does Multiverse allow non transactional access?

It depends. It isn't possible to see changes made by transactions in progress (so no dirty reads).

Does Multiverse support early or late conflict detection?

It depends.

Does Multiverse support direct or deferred updates?

Multiverse only supports deferred updates, so the changes are made visible to other transaction when the transaction commits. That is why dirty reads are not possible.

Can Multiverse be combined with traditional lock based technology?

Yes, it can. But this is not without risk; changes made in non transactional resources are not protected by the STM. And blocking operations on non transactional resouces, doesnt benefit from deadlock detection, listening to multiple blocking resources, etc. So if you know what you are doing, traditional lock based technology can be combined with Multiverse.

Are Multiverse Transactions thread-safe?

No, a transaction is not thread-safe to use and therefor can't be used by multiple threads concurrently. It is possible however to hand over a transaction from one thread to another because the transation itself doesn't rely on any thread/threadlocal information. But it could be that the systems in front of the STM does rely on this. So threads can safely be handed over from one thread to another, if you really know what you are doing.

The org.multiverse.api.Txn can be compared to the Hibernate Session, that also isn't threadsafe to use.

Is lock based concurrency control bad?

I certainly don't think that lock based concurrency control is bad. Multiverse even couldn't exist with low level synchronization structures like locks or cas instructions (AtomicLongs for example). But I do think that lock based concurrency control is very complex; it is very easy to get in all sorts of traditional problems (race problems, deadlocks etc) even for the more experienced developer. And next these well known issues, it also is quite easy to introduce reordening or visibility problems if you don't understand the Java Memory Model well.

That is why I think that STM's are a very valuable tool in the toolbox of developers, that could boost productivity if used correctly. You could compare it with Hibernate and raw SQL; Hibernate makes live easy because you don't need to deal with all the SQL issues all the time. But from time to time, you need to get dirty and use SQL directly to get the things done.

Multiverse and the Java Memory Model

The Java Memory Model is defined in happens before rules, for example the volatile variable rule that states that all changes made before a volatile write, will be visible when a volatile read is done. Using this mechanism it is possible to hand over an object graph from one thread to another without worrying about visibility or reordering issues. Multiverse also provides a happens before rule: all changes made before a transaction commits, will be visible to all starting transactions. So you don't need to worry about reordering or visibility problems.

On a lower level this behavior is realized using CAS instructions (for example an AtomicReference) that provides the same happens before semantics as volatile variables.

Does Multiverse have object or field granularity?

Multiverse doesn't support instrumentation (anymore), so evertything will be field level granularity.

Does Multiverse have provides support for contention management?

No. Currently Multiverse doesn't provide any support for contention management. Contention management if very usefull to provide certain fairness guarantees and to prevent livelocking and will be added in the future. The big problem I currently see is that it could cause a lot of overhead and adding it all over could impact performance all over. I believe that you only should pay for something when you are using it.

Can Multiverse be combined with Spring/Guice/...?

Yes it can. But atm there is no spring TransactionManager, so you have to make use of the instrumentation or you have to make use of a more explicit approach (TransactionlReference/TransactionTemplate). Multiverse-multiverse-0.7.0/multiverse-site/site/features.html000066400000000000000000000000351174000617100246560ustar00rootroot00000000000000

Features

Multiverse-multiverse-0.7.0/multiverse-site/site/index.html000066400000000000000000000001451174000617100241510ustar00rootroot00000000000000 Multiverse-multiverse-0.7.0/multiverse-site/site/license.html000066400000000000000000000013601174000617100244640ustar00rootroot00000000000000

License

This software is licensed under the Apache 2 license, quoted below.

Copyright 2009-2012 Peter Veentjer.

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. Multiverse-multiverse-0.7.0/multiverse-site/site/missionstatement.html000066400000000000000000000030371174000617100264530ustar00rootroot00000000000000

Mission statement

  1. Reduce complexity of concurrency control where applicable by raising the abstraction level. The goal is not to replace traditional concurrency control completely, but to provide an alternative programming model. Multiverse can be seen as filling the gap between traditional databases and traditional lock based concurrency control.
  2. Seamless integration in the Java projects. Multiverse doesn't rely on instrumentation, so can seamlessly be integrated in complexer builds. Multiverse also tries to stay out of the design of projects that use it as much as possible.
  3. To be integrated in other JVM based languages like Scala, Groovy or JRuby. Although Multiverse has been written with Java in mind, it can also be integrated in other languages. Multiverse is uses under water in the Groovy Parallel Systems Library: GPars and in the past has been used as the STM implementation in Scala based Actor framework Akka.
  4. Production environment quality. Multiverse is not an academic experiment. The goal is to create a library that can be used in the most demanding production environments.
  5. Provide a framework for STM experiments. It should be easy to swap/tune the STM implementation without causing a big impact.
Multiverse-multiverse-0.7.0/multiverse-site/site/overview.html000066400000000000000000000023041174000617100247070ustar00rootroot00000000000000

Overview

Multiverse is a Java based Software Transactional Memory (STM) implementation that wants to realize the following goals:
  1. Language independent: so it can be used without relying on instrumentation and therefore can easily be used with other languages that can run on the JVM like like Scala, Groovy or JRuby.
  2. Framework: for different STM implementation. This makes it easy to experiment with new features or build a customized STM implementation.
For a more complete list check the mission statement.

News

  • 1 May 2012: release of Multiverse 0.7. A complete redesign where the central clock is removed to improve scalability, a lot of performance improvements, support for commute, ensure/privatize, atomic operations on references, isolation levels and pessimistic lock mode levels.
  • 1 February 2012: Moved to github
Multiverse-multiverse-0.7.0/multiverse-site/site/pagetemplate.html000066400000000000000000000054061174000617100255170ustar00rootroot00000000000000 Multiverse : Software Transactional Memory for Java & the JVM

Software Transactional Memory for Java & the JVM


<% for(menu in menus){%>
<%}%>
${pagecontent}
Multiverse-multiverse-0.7.0/multiverse-site/site/settings.xml000066400000000000000000000020311174000617100245320ustar00rootroot00000000000000 multiverse-releases username password multiverse-snapshots username password multiverse-snapshots username password multiverse-site username password default /home/alarmnummer/.m2/clover.license default Multiverse-multiverse-0.7.0/multiverse-site/site/sponsors.html000066400000000000000000000006631174000617100247350ustar00rootroot00000000000000

Sponsors

ej-technologies

ej-technologies is responsible for providing a great profiler called JProfiler.

Jetbrains

Jetbrains is responsible for providing the best ide ever: IntelliJ IDEA. Multiverse-multiverse-0.7.0/multiverse-site/site/style.css000066400000000000000000000156501174000617100240350ustar00rootroot00000000000000body, td, th, input { /* redundant rules for bad browsers */ font-family: verdana, sans-serif; font-size: x-small; voice-family: "\"}\""; voice-family: inherit; font-size: small; } h1, h2, h3, h4, h5, h6 { margin: 1em 0 0.2em 0; font-family: arial, verdana, sans-serif; } h1, h2, h3 { border-bottom: 1px solid #ccc; } li h1, li h2, li h3, li h4, li h5, li h6 { border: none; } li { padding: 2px 3px; } h1 { font-size: 160%; font-weight: normal; margin-top: 30px; margin-bottom: 30px; } h2 { font-size: 150%; font-weight: normal; margin-top: 20px; margin-bottom: 20px; width: 85%; } h3 { font-size: 120%; width: 70%; min-width: 250px; } h4 { font-size: 100%; } h5 { font-size: 90%; } h6 { font-size: 90%; border: 0; } pre { font-size: 110%; padding: 5px; border-style: solid; border-width: 1px; border-color: #CCCCCC; background-color: #f3f5e9; } :link { color: #039; } :visited { color: #039; } :link:hover, :visited:hover { color: #333; } :link:active, :link:active { color: #000; } body { margin: 0 0 1em 0; padding: 0; /* need for Opera */ color: #333; min-width: 610px; background: #efefef; } form { margin: 0; } img { margin-top: 20px; margin-bottom: 20px; } #side { float: left; width: 23%; margin-bottom: 1em; margin-top: 1em; } #mainContent { float: right; width: 74%; margin-bottom: 3em; } #footer { } .hide { display: none; } #header, #content, #main-header { padding: 0 50px; } #header, #main-header { max-width: 900px; } #footer { padding: 0 20px; margin: 0 50px; } #main-header, #header, #content, #footer { max-width: 900px; margin: 0 auto; } #content { border: none; /*margin: 0px 0px 0px 7px; padding: 4px 0px 0 0;*/ } h1.main-header-left { float: left; } h1.main-header-right { float: right; } /* ========================================= header =========================================*/ #header { background: #4070A0; color: #fff; padding-top: 5px; padding-bottom: 5px; /*border-bottom: 1px solid #A1A6B1;*/ border-left: 1px solid #333333; border-right: 1px solid #333333; z-index: 1; } #header-title { /*background:url("unity-codehaus-logo-only.png") no-repeat right;*/ } #header-logo { float: right; background-color: red; color: chartreuse; } #header h1 { border: 0; font-size: 250%; padding: 0; margin-top: 2px; margin-bottom: 2px; } #header a:link, #header a:visited { color: #FFFFFF; } /* ========================================= main-header =========================================*/ #main-header { background: #ccc; padding-top: 5px; padding-bottom: 8px; border-left: 1px solid #333333; border-right: 1px solid #333333; height: 30px; } #main-header h1 { border: 0; } #main-header h1 { padding: 0; margin-top: 2px; margin-bottom: 2px; } #content { background-color: #ffffff; border-left: 1px solid #333333; border-right: 1px solid #333333; border-bottom: 1px solid #333333; } .submenu { } .submenu ul { list-style-image: none; list-style-position: outside; list-style-type: none; margin: 0; padding: 0; } .submenu ul li { font-size: 95%; margin: 0; padding: 0; } .submenu ul li a { display: block; border-bottom-color: #DDDDDD; border-bottom-style: solid; border-bottom-width: 1px; border-top-color: #FFFFFF; border-top-style: solid; border-top-width: 1px; padding-bottom: 5px; padding-left: 36px; padding-right: 7px; padding-top: 5px; border-left-color: #DDDDDD; border-left-style: solid; border-left-width: 1px; background: #FEFEFE; } /* ======================================== Sidebar =========================================*/ .nav-title { background: #ccc; border: 1px solid #AAA; padding: 3px 0px 3px 0px; width: auto !important; } .nav-title div { width: 100%; } .nav-title div div { background: none; padding: 0; } .nav-title div h3 { font-size: 100%; font-weight: bold; /*color: #eef;*/ text-decoration: none; border: none; margin: 0 0 0 7px; padding: 4px 0px 0 0; } .nav-footer { border-top: 1px solid #fff; height: 10px; margin-bottom: 3em; } .nav-footer div { width: 100%; height: 10px; } .nav-footer div div { background: none; padding: 0; height: 10px; } .nav { border-right: 1px solid #ddd; } .nav, .nav ul { margin: 0; padding: 0; list-style: none; } .nav li { display: inline; padding: 0; margin: 0; font-size: 95%; } .nav li span { /* used for un-linked menu items */ display: block; padding: 6px 10px; font-weight: bold; color: #666; } .nav li span#configParent, #nav li span #configuration { display: inline; font-weight: normal; padding: 0; } .nav li a { display: block; text-decoration: none; background: #F0F0F0; border-bottom: 1px solid #ddd; border-top: 1px solid #fff; color: #225; padding: 5px 7px; } /* ========================================= News =========================================*/ .news { border-right: 1px solid #AAA; border-left: 1px solid #AAA; padding: 0; margin: 0; background: #f0f0f0; font-size: 100%; } .news-title { background: #ccc; border: 1px solid #AAA; padding: 3px 0px 3px 0px; width: auto !important; } .news-title h3 { padding: 0 0 0 7px; border: 0; margin: 0; } .news-footer { border-top: 1px solid #AAA; } .news dt { padding: 3px 7px 0px 7px; font-weight: bold; border-top: 1px solid #fff; } .news dd { padding: 0px 7px 10px 7px; margin: 0; border-bottom: 1px solid #ddd; } .nav li a.selected { background: #FFE8A0; } .nav li a:hover { background: #E4E4E4; /*#FFF0C0;*/ } .nav li a.selected:hover { background: #F4DE99; /*#FFF0C0;*/ } .nav li li span { /* used for un-linked menu items */ padding: 4px 8px 4px 20px; } .nav li li a { padding: 6px 8px 6px 20px; } #oN { background-color: #E0E9E9; } #oN:hover { background-color: #C6DCDC; } /* ========================================= Footer =========================================*/ #footer { clear: both; margin-top: 3em; margin-bottom: 1em; color: #888; padding: 25px 50px; text-align: center; } #footer-contents { padding: 0; border-top: 1px solid #C9D0E0; } #footer ul#footer-menu { position: relative; top: -0.8em; margin: 0 1em 0 1em; padding: 0; list-style-type: none; } #footer ul#footer-menu li { display: inline; background: #fff; margin: 0 1em; } #footer ul#footer-menu li a { margin: 0 1em; white-space: nowrap; } #footer p { margin: 0.3em; } #footer .site-tools { display: none; } Multiverse-multiverse-0.7.0/multiverse-site/src/000077500000000000000000000000001174000617100217775ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/000077500000000000000000000000001174000617100234175ustar00rootroot00000000000000Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-2pc.xml000066400000000000000000000015671174000617100262620ustar00rootroot00000000000000 2 Phase Commit (in progress) Introduction CommitBarrier CountDownCommitBarrier The CountDownCommitBarrier is a CommitBarrier implementation comparable to the java.util.concurrent.CountDownLatch where all pending txns can continue when the configured number of parties have arrived. VetoCommitBarrier The VetoCommitBarrier is a CommitBarrier implementation where all pending txns can continue when one of the Transactions veto's the VetoCommitBarrier to open. Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-blocking-transactions.xml000066400000000000000000000172061174000617100320710ustar00rootroot00000000000000 Blocking Transactions (in progress) Introduction With traditional concurrency control, one can write blocking structures (so structures where a thread waits until some condition changes) based on primitive synchronization structures like the waitset/java.util.concurrent.locks.Condition. Or using some higher blocking primitives like the java.util.concurrent.CountDownLatch or java.util.concurrent.Future. With Stm it also is possible to write blocking datastructures using the retry primitive. The following example shows a Counter, where a thread can block until the counter has reached some value. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; public class Counter{ private final IntRef value = newTxnInteger(0); public void increment(){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ value.increment(1); } }); } public void await(final int expected){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ if(value.get()<expected){ retry(); } } }); } ... } In this example, when a txn executed the await and finds that the value has not reached the expected value, the txn will block until the value become equal or larger to the expected value. For explanation purposes, the code is more elaborate than strictly needed. The IntRef has different methods for waiting on certain values and the Counter.increment could be simplified by calling an IntRef.atomicIncrement(). RetryError The blocking functionality works like this: when a retry is called, the txn will register a listener on all reads it has executed, aborts the txn and throws a org.multiverse.api.exceptions.RetryError (an instance of the org.multiverse.api.exceptions.ControlFlowError). This Error should only be caught by the AtomicBlock and till it is caught, it unwinds the callstack. When it is caught by the AtomicBlock, the RetryLatch.await that was registered on all reads references, will be called and the txn is going to block. So do not catch this Error unless you really know what you are doing. Composition Orelse Blocking on multiple resources With traditional concurrency contol, it is hard to make it possible on multiple datastructures. If yuo have 2 BlockingQueues for example, it is hard for a thread to wait for an element to be placed on either one of them. Luckily this problem is solved when STM is used. Example: public class Foo{ private final Counter counter1 = new Counter(); private final Counter counter2 = new Counter(); public void awaitBoth(final int value){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ if(counter1.get()>=value && counter2.get()>value){ return; } retry(); } }); } ... } This example show hows to wait until both counters have reached some value. A txn will automatically block on all references it has read. Prevent blocking The default setting for a txn, is that it is allowed to block. If you don't want a txn to be able to block, the TransactionFactoryBuilder.setBlockingAllowed can be called. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; public class Counter{ private final static AtomicBlock awaitBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .setBlockingAllowed(false) .newAtomicBlock(); private final IntRef value = newTxnInteger(0); public void await(final int a){ awaitBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ if(value.get()<a){ retry(); } } }); } ... } When the await method is called, and the amount is not sufficient, a retry is executed. But instead of blocking, a org.multiverse.api.exceptions.RetryNotAllowedException is thrown. Timeout The default is that unbound waiting is used. But in some cases you want to configure how long a txn is allowed to block before throwing a org.multiverse.api.exceptions.RetryTimeoutException. This can be done through the TransactionFactoryBuilder.setTimeoutNs method. Atm no support is provided to configure this on a lower level. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; public class Counter{ private final static AtomicBlock awaitBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .setTimeoutNs(TimeUnit.SECONDS.toNanos(10)) .newAtomicBlock(); private final IntRef value = newTxnInteger(0); public void await(final int a){ awaitBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ if(value.get()<a){ retry(); } } }); } ... } Interruptibility The default is that a txn is not interruptible. But in some cases you want a txn to be interruptible. This can be done using the setInterruptible method on the org.multiverse.api.TxnFactoryBuilder. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; public class Counter{ private final static AtomicBlock awaitBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .setInterruptible(true) .newAtomicBlock(); private final IntRef value = newTxnInteger(0); public void await(final int a){ awaitBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ if(value.get()<a){ retry(); } } }); } ... } If a thread blocks on the retry, it can be interrupted by a nother thread. Instead of the java.lang.InterruptedException is thrown, the org.multiverse.api.exceptions.RetryInterruptedException is thrown which is unchecked. Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-controlflow-errors.xml000066400000000000000000000112501174000617100314460ustar00rootroot00000000000000 org.multiverse.api.exceptions.ControlFlowError Introduction STM in most cases is very optimistic, this means that a txn can fail at the end and needs to be retried because the next time it is more likely to succeed. The problem with normal Java code is that control flow only is limited to normal returns in methods or through exceptions (throwables). Multiverse lifts on the latter to regulate control flow. E.g. if a read conflict is detected, a special multiverse error: org.multiverse.api.exceptions.ControlFlowError is thrown. This Error is caught by the AtomicBlock and then it decides what to do next. There currently are 3 different subclasses of the ControlFlowError in Multiverse: org.multiverse.api.exceptions.ReadWriteConflict org.multiverse.api.exceptions.RetryError org.multiverse.api.exceptions.SpeculativeConfigurationError These exceptions normally should not be caught. Therefor it is best to make sure that all resources used inside a txn are used in a try/finally clause to make sure that they are cleaned up. org.multiverse.api.exceptions.ReadWriteConflict If the Transaction detects a read or write conflict, a org.multiverse.api.exceptions.ReadWriteConflict is thrown. This Error is caught by the AtomicBlock and it automatically retries the txn. To prevent contention, there also is a org.multiverse.api.BackoffPolicy available, that control if the txn should wait a little (so should back off), or should retry immediately. The maximum number of retries can be configured through the maxRetries property on the org.multiverse.api.TxnFactoryBuilder. org.multiverse.api.exceptions.RetryError If a blocking operation should be executed, a RetryError is thrown. This ControlFlowError is caught by the AtomicBlock and it registers a latch to all refs read and the calling thread blocks on the latch. If a read on one of those refs happens, the latch is opened and the blocked thread continues. org.multiverse.api.exceptions.SpeculativeConfigurationError Multiverse uses a speculative mechanism to figure out the best config for a txn. E.g. there a different txn implementations optimized for a different number of refs. The speculative config mechanism starts with a settings, but as soon as it figures out that the settings are too cheap, it throws a org.multiverse.api.exceptions.SpeculativeConfigurationError. This error is caught by the org.multiverse.api.TxnExecutor and upgrades the txn/settings. Once the AtomicBlock has learned, it will not make the same mistakes again. So in the beginning there can be some unexpected failure, but after a few tries, they won't appear again. This mechanism can be disabled by setting the 'setSpeculative' to true on the org.multiverse.api.TxnFactoryBuilder. Caching of org.multiverse.api.exceptions.ControlFlowError Normally caching an Exception would be considered an very big no-no. The problem with using new exceptions for control flow, is that is can seriously limit scalability since exceptions are very expensive to create (especially the stacktrace). That is why the default is that instances of the org.multiverse.api.exceptions.ControlFlowError are created in the beginning and reused. If you need to have a closer look in the exception to see what is happening (or where it is happening), the 'setControlFlowErrorsReused' on the org.multiverse.api.TxnFactoryBuilder can be called (else you will see an empty stacktrace). You need to make sure that you don't gobble up this Error, but propagate it since the AtomicBlock is the one that is going to deal with it. Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-deferredandcompensatingtasks.xml000066400000000000000000000122651174000617100335140ustar00rootroot00000000000000 Deferred and compensating tasks (in progress) Introduction When a Multiverse txn is used, all changes made to transactional references during that txns are either committed or aborted. So it won't happen that changes of an uncommitted txn ever become visible in another txn. But in some cases you need to execute logic that is not managed by a txn, e.g. cleaning up resources. This can be done using: Deferred tasks: executed after txn commit Compensating tasks: executed after txn abort In Multiverse there are 2 different tastes of deferred and compensating actions: normal tasks: these tasks are registered during the execution of the txn, and are automatically cleared on txn commit/abort. This type of task is useful, if it depends on logic executed during the execution of the txn. permanent tasks: these tasks are registered when the org.multiverse.api.TxnExecutor is created. The advantage of permanent tasks is that they don't need to be registered every time the txn runs, so there is a lot less overhead (especially gc). Permanent listeners are also useful if Multiverse needs to be integrated in other systems/languages so that integration logic can be executed. Normal compensating task When a txn commits, using the normal compensating tasks, additional logic can be executed after the commit of the txn. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Foo{ public void foo(){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ ... logic scheduleDeferredTask(new Runnable()){ public void run(){ System.out.println("Transaction committed"); } }); ... more logic } }); } ... } The StmUtils.scheduleDeferredTask forwards to the Transaction.register(TxnListener) method and uses the Transaction stored on the ThreadLocalTransaction. Normal compensating tasks are always executed in the order they were registered. Normal deferred task When a txn aborts, using the normal compensating tasks, additional logic can be executed after the abort of the txn. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Foo{ public void foo(){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ ... logic scheduleCompensatingTask(new Runnable()){ public void run(){ System.out.println("Transaction aborted"); } }); ... more logic } }); } ... } The StmUtils.scheduleCompensatingTask forwards to the Transaction.register(TxnListener) method and uses the Transaction stored on the ThreadLocalTransaction. Normal compensating tasks are always executed in the order they are registered. Permanent deferred task In some cases you want logic to be executed after a Transaction commits. This can be done using a compensating task. Permanent compensating task In some cases you want logic to be executed after a Transaction fails. This can be done using a deferred task. org.multiverse.api.lifecycle.TxnListener Execution order Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-designguidelines.xml000066400000000000000000000051451174000617100311140ustar00rootroot00000000000000 Design guidelines Introduction This chapter contains information contains information about design guidelines for setting up a system that uses STM. Another set of design guidelines can be found in the 'performance tuning' chapter. Customize the AtomicBlock In Multiverse some convenience methods are added to make using the STM very easy. But if you want to get most out of performance of want to tune behavior of an org.multiverse.api.TxnExecutor, the AtomicBlock needs to be customized. E.g.: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Account{ private final static AtomicBlock transferBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final IntRef amount = newTxnInteger(0); public void foo(){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ ... register(new Runna } }); } ... } AtomicBlock per atomic method It is best, if there are more than 1 method that needs to have its own txn, that each of these methods gets it own AtomicBlock. It is useful for debugging purposes because you can see which txn is causing problems. It also is more useful for the speculative mechanism, so that the system is able to learn from each AtomicBlock independently, and is able to infer the optimal config for each individual method. AtomicBlock at service level It is best to prevent making every method txn (so have it own AtomicBlock). In most cases it is best to have one high level methods that should be have an AtomicBlock, and the internals can lift on the txn provided. This is comparable to using database txns; you create your transactional services, but underneath no txn management is needed. Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-gammastm.xml000066400000000000000000000152061174000617100273770ustar00rootroot00000000000000 GammaStm Introduction The new GammaStm (the default instance of the Stm interface, and stored in the GlobalStm) is a complete rewrite of the AlphaStm. The AlphaStm was based on the TL2 design of David Dice with some optimizations. But having a central clock (an AtomicLong) as a hidden contention point that makes is harder to writer scalable transactional datastructures. The new GammaStm make use of a conflict counter (comparable to that used in the SkySTM) which only is increased on conflict. This means that this conflict counter only needs to be increased if there are conflict, and not just on every write. Which means that the total pressure on the conflict counter will always be equal or smaller than that of the TL2 design. Not only the fundamental design of the STM has been improved, also a very large effort was made in preventing unjustifiably overhead. E.g. virtual method calls (prevent inlining), switch case statements (causes problems with branch predication) etc. So a lot of stuff has been optimized and the code is not always as pretty. Orec Each transactional reference has a ownership record (just an long). Using bit-tweaking a lot of information can be stored here: surplus: so the number of current readers readonly count: so the number of txn that have only read and not updated the transactional reference. read/update biased: if the orec is read or update biased. lock information: readlock (so the number of txn that acquired the read-lock), write-lock and exclusive-lock. So a lot of operations like doing an arrive/depart or acquiring a lock, can all be done by a single cas. No Garbage One of the causes of a not scalable STM is that a lot of garbage is created. The new GammaStm is able to reuse a lot of objects (so it pools internally) for almost all txns. The only object that needs to be created is the AtomicClosure. If you can even pool that, then there will be zero waste. One of techniques used to deal with the primitive types and the reference type, is that code is generated using Velocity. So the logic only needs to be written once, and the Java code that is optimized for a certain type is generated. There is no runtime dependency on Velocity. Read consistency The new GammaStm uses 1 basic mechanism for providing read consistency. The basic mechanism is based is on semi visible reads (so it is visible that other txns have read the data, but not which ones). When a txn reads a ref, it increments the surplus, and when the txn is done with it (so aborts or commits), automatically a depart is done. When a txn commits, and finds that there are reading threads, it increments the global conflict counter (which in the future probably will be striped). When a reading txn sees that the global conflict counter has changed, it does a full conflict scan. Transactions used by the GammaStm always use readtracking. 2 Very important optimizations have been added to this design. Read biased references: if references are only read, they can become read biased. Once they have become read biased, no arrives/departs are required. So if you have a tree for example, the roots of the tree will no change very often, but without read biased references, they still require an arrive/depart, which in turn limits scalability. If they have become readbiased, and an update is done, the global conflict counter will always be increased and all txns are forced to do a full conflict scan. Once a ref is written, it automatically become update biased until a certain number of reads have been done. Always do a full conflict scan: short txns (so ranging to 20 refs.. this value is configurable) always do a full conflict scan. It should expensive, but in most cases it will only cause some volatile reads. The advantage of using this approach is that a short txn never needs to do an arrive/depart and never cause the global conflict counter to increment. If only short txns are used, independant datastructure will scale independently. Other features Pessimistic txns Propagation level Isolation level Commute ... Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-introduction.xml000066400000000000000000000071251174000617100303130ustar00rootroot00000000000000 Introduction Traditional Concurrency Control (in progress) Traditional concurrency control is complex because you need to worry about a lot of problems. First of all you need to make sure that the program does no bad things (so no race problems), and you also need to worry about that good things happen eventually ( so no deadlocks, livelocks or starvation). Lock based concurrency control is well known but also dreaded because even simple code can very quickly become too complex to reason about. The idea behind Software Transactional Memory (STM), is that a database like programming model can be provided on in memory datastructures. The STM is going to worry about read/write inconsistencies, deadlocks etc and makes sure that all changes make it or none make it. To give you an example: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; public class Account{ private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(a); } }); } public int getAmount(){ execute(new AtomicIntClosure()){ public int execute(Transaction tx){ return amount.get(); } }); } } As you can see, the Account class has a single field 'amount' which is of class IntRef; a transactional reference. All reads/writes on this ref are coordinated and perhaps tracked by the txn. The logic of both methods is captured in an AtomicClosure. There are different types of Closures for the different return types. There are also primitive versions that prevent unwanted autoboxing. An AtomicClosure is executed by an AtomicBlock (in our case this AtomicBlock is stored in the StmUtils and exposed through the execute methods. In the previous example, only a single field was updated, but there are no restructions in the number of fields. If you want you could add more: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; public class Account{ final private IntRef amount = newTxnInteger(0); final private Ref date = newTxnRef(new Date()); public void transfer(final int a){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(a); lastModifiedDate.set(new Date()); } }); } public Date getLastModifiedDate(){ execute(new AtomicClosure()){ public Date execute(Transaction tx){ return lastModifiedDate.get(); } }); } public int getAmount(){ execute(new AtomicIntClosure()){ public int execute(Transaction tx){ return amount.get(); } }); } } Composition Transactions can be composed Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-isolationlevel.xml000066400000000000000000000051301174000617100306150ustar00rootroot00000000000000 Isolation Level (in progress) Introduction Isolation Level The Lock has 3 different isolation levels atm: IsolationLevel.RepeatableRead IsolationLevel.Snapshot. This provides the Oracle version of the Serializable isolation level, but still alows the writeskew to happen. This is the default isolation level. IsolationLevel.Serializable The IsolationLevel can be set using the TransactionFactoryBuilder, e.g.: public class Counter{ private final static AtomicBlock awaitBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .setIsolationLevel(IsolationLevel.Serializable) .newAtomicBlock(); private final IntRef value = newTxnInteger(0); public void await(final int a){ awaitBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ if(value.get()<a){ retry(); } } }); } ... } Readonly txn Transactions that are readonly, can't suffer from the writeskew problem. So if they are configured using the Snapshot IsolationLevel, they have the same isolation guarantees as when the IsolationLevel.Serializable is configured. Dirty read A dirty read happens when a txns reads information written by another txn, but the txn fails in the end. The problem is that values can be seen, that never made it in the system. Multiverse doesn't support (or have the need to) for dealing with dirty reads. So they can't happen. Non repeatable read Writeskew Ensure DeferredEnsure Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-jmm.xml000066400000000000000000000065021174000617100263530ustar00rootroot00000000000000 STM and the Java Memory Model Introduction Prior to Java 5, the Java Memory Model (JMM) was broken. It was possible to get all kinds of strange results like unpredictable merged writes made by concurrent executing threads, unexpected reordering of instructions, and even final fields were not guaranteed to be final. With Java 5 and JSR-133, the Java Memory Model is clearly specified. This specification makes it possible to write code that performs, but doesn't cause concurrency problems. Happens before rules The Java Memory Model is specified in happens before rules, e.g.: monitor lock rule: all writes executed before some lock is released, are visible when the same lock is acquired. volatile variable rule: all writes executed before some volatile variable is written, are visible when the same volatile variable is read. The happens before rules clearly specify which visibility guarantees are provided on memory content and which reordering are allowed. Without these rules it would not be possible to write concurrent code in Java. For a more detailed explanation, please check ... or "Java Concurrency in Practice by Brian Goetz. Transaction rule Multiverse also provides a happens before rule called the txn rule. It guarantees that a write on a transactional object is visible after the txn commits and before another txn reads the same transactional object. On a lower level this is realized by lifting on the volatile variable or lock rule. Check out at the following code fragment for an example: public class Foo{ private final IntRef value = newTxnInteger(); public void write(final int newValue){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ value.set(newValue); } }); } public int read(){ return execute(new AtomicIntClosure()){ public void execute(Transaction tx){ return value.get(); } }); } } In this example there is a happens before relation between the commit of the write txn and the start of the read txn. For developers this means that you don't need to worry about the JMM when txns are used and you don't need to define variable as volatile or synchronized blocks to introduce the needed memory fences; this is all done for you. Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-performance-tuning.xml000066400000000000000000000244131174000617100313740ustar00rootroot00000000000000 Performance tuning Introduction This chapter contains various tips for improving performance of transactional datastructures. Primitive refs Multiverse provides support for various primitives refs: IntRef, LongRef, BooleanRef and TxnDouble. Using a primitive instead of a normal ref in combination with wrapper types, has the advantage that no autoboxing is needed. Doing millions of wrapper creations per second, can seriously limit performance and scalability. Don't throw away the AtomicBlock It is best to create an AtomicBlock once and stored it in a final static field. For more information see 'Customize the AtomicBlock'. Customize the AtomicBlock Use a customized AtomicBlock, so instead of using this: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; public class Account{ private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(a); } }); } ... } Use the following: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Account{ private final static AtomicBlock transferBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ transferBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(a); } }); } ... } The transferBlock can be placed in a static field and can safely be shared between threads (it is completely threadsafe and designed to be used in this way). The advantage of this approach, is that the Stm is able to learn based on previous txn executions and select the best performing settings. It relies on a speculative config mechanism where the system starts with the cheapest settings, but upgrades to more expensive one if the bet failed. If the AtomicBlock is discarded after usage, the STM will never be able to learn. Another problem is that it also causes a lot of GC overhead. So reuse your AtomicBlocks! Short txns Transactions should be kept as short as possible. If the executes over a longer period, chances increase that it runs into a read/write conflict. When this happens, a lot of work is lost and needs to be redone. It also could lead to livelock problems. Small txns Transactions should be as small as possible, so the less it needs to track, the faster it will be. Also when small txns are used, Multiverse is able to use special optimized txns that cause less overhead than longer txns. Another advantage of using small txns, is that the mechanism for providing a read consistent view gets a lot cheaper (if the GammaStm is used). This reduces the pressure on the shared conflict counter. Use atomic methods If only a single ref needs to be read or written, consider using one the atomic methods that the refs support. They all support atomicGet, atomicWeakGet, atomicSet and atomicGetAndSet. Atomic method provide the same guarantees and functionality you normally have with txns, but the overhead of txns is considerably lower. Explicit txn passing Normally a Transaction doesn't need to be passed explicitly, because it is placed in the org.multiverse.api.TxnThreadLocal. Every time the txn is needed, it needs to be read from this ThreadLocal. By passing the Transaction explicitly, this overhead is removed. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Account{ private final static AtomicBlock transferBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ transferBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(tx, a); } }); } ... } As you can see, the increment method now has an explicit txn. Almost all methods of the ref are overloaded with a version that also accepts a Transaction. If your methods call other transactional methods, the txn can be passed manually, e.g. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Foo{ private final static AtomicBlock someBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final IntRef ref = newTxnInteger(0); public void internalMethod(Transaction tx){ ref.set(tx, 2); } public void externalMethod(){ someBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ internalMethod(tx); } }); } } Unfortunately this boilerplate code is required as long as the instrumentation is not available in Multiverse. Instrumentation can transform this code mechanically. In other JVM based languages like Groovy, Scala, JRuby, this ugliness can be tucked away behind some syntactic sugar. Nested transactional methods It can happen that nested transactional methods are required, e.g.: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Foo{ private final static AtomicBlock method1Block = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final static AtomicBlock method2Block = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final IntRef ref = newTxnInteger(0); public void method1(){ method1Block.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ ref.set(2); } }); } public void method2(){ method2Block.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ method1(); } }); } } The problem with this approach is that 2 AtomicClosures are created when method2 is called. This problem can be prevented by creating 2 version of the method; 1 with a txn and one without. E.g.: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Foo{ private final static AtomicBlock method1Block = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final static AtomicBlock method2Block = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final IntRef ref = newTxnInteger(0); public void method1(){ method1Block.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ method1(tx); } }); } public void method1(Transaction tx){ ref.set(tx, 2); } public void method2(){ method2Block.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ internalMethod(tx); } }); } public void method2(Transaction tx){ method1(tx); } } Ref access Accessing the ref for a read or write costs time (at least if you want to make sure of the methods that participate in txns). So some care should be applied about the number of times a ref is accessed. So if you have the chance to store it in a local variable, instead of doing a read/write every time, this will give you better performance. Primitive AtomicClosure Multiverse provides various forms of AtomicClosures for void, reference and primitive types. The primitive AtomicClosures like the AtomicIntClosure, AtomicBooleanClosure, AtomicLongClosure and AtomicDoubleClosure prevent any form of boxing. So if you need to return a int, boolean, long or Double, make sure you are using a primitive AtomicClosure. Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-pessimistic-locking.xml000066400000000000000000000053231174000617100315500ustar00rootroot00000000000000 Pessimistic Locking (in progress) Introduction Normally STM's are very optimistic, so this means that a txn can fail when it commits because anothertransaction has updated data it has read. When this happens, a org.multiverse.api.exceptions.ControlFlowError is thrown (in this case a org.multiverse.api.exceptions.ReadWriteConflict), which is caught by the org.multiverse.api.TxnExecutor and the txn is retried. In some cases the optimistic nature can be problematic and something more pessimistic is needed. Multiverse provides support for pessimistic behavior on the Ref level using the Ref.getLock or on the Transaction level by setting the readLockMode or writeLockMode. Lock modes The Lock has 4 different Lock modes: LockMode.None: no pessimistic lock is acquired LockMode.Read: a readlock is acquired that prevents other txns from acquiring a writelock or exclusive lock, but it still always others to read. LockMode.Write: a writelock is acquired that prevents other txns from acquiring the readlock/writelock or exclusive lock. But it is important to realize that others still are allowed to read it. LockMode.Exclusive: an exclusive lock is acquired that prevents other txns from acquiring any form of lock or do any reads/wites. Lock upgrade Pessimistic locking on ref level Pessimistic locking on txn level Pessimistic locking can be done on all reads made by a txn by configuring the Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-propagation.xml000066400000000000000000000072011174000617100301100ustar00rootroot00000000000000 Propagation Introduction It can happen that AtomicBlocks are called within the execution of other AtomicBlock and this leads to txn nesting. In a lot of cases you want to allow this, but in some cases you want to control it. This can be done by config the txn propagation. PropagationLevel Multiverse supports propagation by setting the correct PropagationLevel on the TransactionFactoryBuilder (defaults to PropagationLevel.Requires). The following propagation levels are supported: PropagationLevel.RequiresNew: Indicates that a new txn always is started, even when there is an active txn. The active txn is postponed and used again after the nested txn commits. It could be that the outer txn conflicts made on changes by the inner txn. PropagationLevel.Requires: Indicates that a new txn will be used if none exists. If one exists, the logic will lift on that txn. This is the default propagation level PropagationLevel.Supports: Indicates that it the logic can either be run with or without txn. PropagationLevel.Never: Indicates that no active txn should be available. If a txn is found, a org.multiverse.api.exceptions.TxnNotAllowedException is thrown. PropagationLevel.Mandatory: Indicates that a txn should always be available. If not, a org.multiverse.api.exceptions.TxnMandatoryException is thrown. An example of configuring the propagation level: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Account{ private final static AtomicBlock transferBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .setPropagationLevel(PropagationLevel.Requires) .newAtomicBlock(); private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ transferBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.incrementAndGet(tx, a); } }); } ... } In this example the transfer method will lift on an already running txn, but if none is found, it will use it own. Warning Atm there are no checks if outer AtomicBlock violates the inner AtomicBlock. If the inner AtomicBlock is configured as readonly and the outer as an update txn, an outer txn is able to make updates. Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-transaction.xml000066400000000000000000000166141174000617100301220ustar00rootroot00000000000000 Transaction (in progress) Introduction This chapter contains many of the txn config options. Customizing a txn Transactions can be configured by creating a custom AtomicBlock, e.g. import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Account{ private final static AtomicBlock transferBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .newAtomicBlock(); private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ transferBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(tx, a); } }); } ... } By configuring the TransactionFactoryBuilder, you can control the behavior of the Transaction. AtomicBlocks are designed to be threadsafe and not form a contention point. It is easiest to store them in a final static field so that they can be shared over multiple threads and objects. It is important to realize that a TransactionFactoryBuilder is immutable, so if a config method is called, a new instance is returned. This instance should be used to do the following config step or by used for creating the AtomicBlock. Familyname For debugging purposes, the txn family name can be set. It is best to choose a name that makes it easy to find the code that is executed by the AtomicBlock, e.g.: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Account{ private final static AtomicBlock transferBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .setFamilyName("Account.transfer") .newAtomicBlock(); private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ transferBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(tx, a); } }); } ... } If no value is set, some generated value (which most likely is not very usable) is used. Readonly By default a txn is configured as an update txn; so it is allowed to make changes to transactional references. This behavior can be changed by setting the readonly property of the Transaction, e.g.: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Account{ private final static AtomicBlock transferBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .setReadonly(true) .newAtomicBlock(); private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ transferBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(tx, a); } }); } ... } In this case a org.multiverse.api.exceptions.ReadonlyException is thrown when the amount.increment is called. In case of the GammaStm it doesn't make much of a performance impact if a txn is configured as readonly. Maximum retries An AtomicBlock automatically is going to be retried until one of the following things happens: It completes. An exception (a Throwable) is thrown during the execution of the atomic block. The txn has executed too many times and a org.multiverse.api.exceptions.TooManyRetriesException is thrown. The txn is going to block (see the retry functionality for more information how this works). The default for the maximum retries is 1000 and can be configured through the TransactionFactoryBuilder: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; import static org.multiverse.api.GlobalStmInstance.* public class Account{ private final static AtomicBlock transferBlock = getGlobalStmInstance() .newTransactionFactoryBuilder() .setMaximumRetries(200) .newAtomicBlock(); private final IntRef amount = newTxnInteger(0); public void transfer(final int a){ transferBlock.execute(new AtomicVoidClosure()){ public void execute(Transaction tx){ amount.increment(tx, a); } }); } ... } In this example the maximum number of retries is configured to be 200. Setting the value very low, could lead to txns not being able to complete. If the speculative config mechanism is enabled for an AtomicBlock (defaults to true), it can happen that the first few times an AtomicBlock is used, some ControlFlowErrors (org.multiverse.api.exceptions.SpeculativeConfigurationError) are thrown even though there is no contention. If the value is set to a very high value, the system could suffer more from livelock problems. The consequence of a livelock is that the system is doing work (so consuming cpu and memory), but isn't making any progress. Don't rely on Transaction instance To prevent causing a lot of unwanted gc overhead, txn instances are reused. This means that the same txn instance could be used for different executions of the same AtomicBlock, but it also could be reused to execute a completely different AtomicBlock. That is why it is important to realize that Transaction instances should not be stored. Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/chapter-transactional-references.xml000066400000000000000000000065651174000617100325620ustar00rootroot00000000000000 Transactional References (in progress) Introduction In Multiverse all coordinated state changes need to be done through transactional references. These references can be compared to the java.util.concurrent.atomic references, except that they can participate in txns. So if you have worked with these references before, it shouldn't be too hard to grasp. Check out the following code fragment: import org.multiverse.api.*; import org.multiverse.api.refs.*; import static org.multiverse.api.StmUtils.*; public class Account{ private final IntRef amount = newTxnInteger(0); private final Ref<Date> lastModified = newTxnRef(new Date()); ... } Changes made on the amount and lastModified ref are coordinated through a txn where all changes happen isolated and are consistent. It is best to make these fields final, since they should not be changed after creation. Types There aren't different types of transactional refs. Some are optimized for primitive types, while the 'Ref' is optimized for object references: IntRef: a transactional ref for primitive int. BooleanRef: a transactional refs for the primitive boolean. LongRef: a transactional ref for the primitive long. TxnDouble: a transactional ref for the primitive double. Ref: a transactional ref for storing a object reference. The advantage of the primitive types is that they not only have methods only useful for their specific type (like increment) but also that they prevent unwanted autoboxing. Generating millions of objects per second, just kills performance and scalability. Atomic methods The different ref implementation also expose atomic methods like atomicGet/atomicSet (and many more). These methods automatically run under their own 'txn' and ignoring the current txn if one is available. Atomic methods are very fast since a lot of overhead of the txn is removed. Commute It is important to realize that although certain operations commute, e.g. the add or multiply, but they don't have to commute with each other. So be careful when combining different commuting operations. Alter Blocking methods Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/manual.xml000066400000000000000000000057131174000617100254240ustar00rootroot00000000000000 ]> Manual Multiverse 0.7 Peter Veentjer
alarmnummer@gmail.com
2011 Peter Veentjer The Manual for Multiverse 0.7.
Preface After almost a year of hard and backbreaking work, Multiverse 0.7 was finally released. It is a complete rewrite from the previous releases where a lot of effort was made on removing some fundamental problems with the 0.6 design (the need for a shared clock was reduced considerably), so it should scale a lot better. Also the performance was increased considerably, and last but not least a whole new set of new features are added like commuting operations, pessimistic locking, isolation and propagation levels etc. Also the instrumentation was removed and the focus for this release is completely on transactional references. The instrumentation will be added in the future. &chapter-introduction; &chapter-transactional-references; &chapter-txn;; &chapter-propagation; &chapter-blockingtransactions; &chapter-controlflow-errors; &chapter-pessimistic-locking; &chapter-deferredandcompensatingtasks; &chapter-isolationlevel; &chapter-gammastm; &chapter-performance-tuning; &chapter-jmm; &chapter-designguidelines; &chapter-2pc;
Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/style.css000066400000000000000000000023361174000617100252750ustar00rootroot00000000000000body, td, th, input { /* redundant rules for bad browsers */ font-family: verdana, sans-serif; font-size: x-small; voice-family: "\"}\""; voice-family: inherit; font-size: small; } h1, h2, h3, h4, h5, h6 { font-family: arial, verdana, sans-serif; } h1, h2, h3 { border-bottom: 1px solid #ccc; } h1 { font-size: 160%; font-weight: normal; margin-top: 30px; margin-bottom: 30px; } h2 { font-size: 150%; font-weight: normal; margin-top: 20px; margin-bottom: 20px; width: 85%; } h3 { font-size: 120%; width: 70%; min-width: 250px; } h4 { font-size: 100%; } h5 { font-size: 90%; } h6 { font-size: 90%; border: 0; } pre { font-size: 110%; padding: 5px; border-style: solid; border-width: 1px; border-color: #CCCCCC; background-color: #f3f5e9; } :link { color: #039; } :visited { color: #039; } :link:hover, :visited:hover { color: #333; } :link:active, :link:active { color: #000; } body { padding: 10; color: #333; min-width: 610px; max-width: 900px; background: #efefef; } form { margin: 0; } img { margin-top: 20px; margin-bottom: 20px; } .hide { display: none; }Multiverse-multiverse-0.7.0/multiverse-site/src/docbook/todo.txt000066400000000000000000000001511174000617100251220ustar00rootroot00000000000000todo - links to javadoc done - chapter content on 1 page - css - summaries - sub-chapter numbering Multiverse-multiverse-0.7.0/multiverse-site/todo.txt000066400000000000000000000000121174000617100227070ustar00rootroot00000000000000todo doneMultiverse-multiverse-0.7.0/pom.xml000066400000000000000000000043341174000617100173700ustar00rootroot00000000000000 4.0.0 pom org.multiverse multiverse 0.7.0 Multiverse Parent Project A Software Transactional Memory implementation for the JVM. scm:git:git://github.com/pveentjer/Multiverse.git scm:git:git@github.com:pveentjer/Multiverse.git http://github.com/pveentjer/Multiverse maven-deploy-plugin 2.5 org.apache.maven.wagon wagon-webdav-jackrabbit 1.0-beta-7 multiverse-releases Multiverse Central Repository dav:https://dav.codehaus.org/repository/multiverse/ multiverse-snapshots Multiverse Central Development Repository dav:https://dav.codehaus.org/snapshots.repository/multiverse/ http://dist.codehaus.org/multiverse/ multiverse-core Multiverse-multiverse-0.7.0/settings.gradle000066400000000000000000000000541174000617100210660ustar00rootroot00000000000000include 'multiverse-core','multiverse-site' Multiverse-multiverse-0.7.0/site.sh000077500000000000000000000012341174000617100173520ustar00rootroot00000000000000#!/bin/sh rm -dfr multiverse-site/build xsltproc \ --stringparam chunk.section.depth 0 \ --stringparam section.autolabel 1 \ --stringparam section.label.includes.component.label 1 \ --stringparam html.stylesheet style.css \ -o multiverse-site/build/site/manual/ /usr/share/xml/docbook/stylesheet/nwalsh/xhtml/chunk.xsl multiverse-site/src/docbook/manual.xml cp multiverse-site/src/docbook/*.css multiverse-site/build/site/manual groovy multiverse-site/menu.groovy mkdir multiverse-site/build/site/charts cp charts/*.* multiverse-site/build/site/charts gradle multiverse-gamma:javadoc cp -r multiverse-gamma/build/docs/javadoc/ multiverse-site/build/site/