BoolNet/0000755000176200001440000000000014506551754011630 5ustar liggesusersBoolNet/NAMESPACE0000644000176200001440000000270013301233422013023 0ustar liggesusersuseDynLib(BoolNet, .registration = TRUE) import("igraph", "XML") importFrom("graphics", "abline", "arrows", "axis", "hist", "legend", "lines", "par", "plot", "rect", "text") importFrom("grDevices", "adjustcolor") importFrom("grDevices", "dev.interactive") importFrom("stats", "dist", "kmeans", "quantile", "rnorm", "rpois", "runif") importFrom("utils", "installed.packages", "tail") S3method(print, AttractorInfo) S3method(print, SymbolicSimulation) S3method(print, BooleanNetwork) S3method(print, SymbolicBooleanNetwork) S3method(print, BooleanNetworkCollection) S3method(print, ProbabilisticBooleanNetwork) S3method(print, BooleanStateInfo) S3method(print, TransitionTable) S3method(print, MarkovSimulation) export( loadNetwork, loadBioTapestry, loadSBML, saveNetwork, getAttractors, plotAttractors, plotSequence, plotStateGraph, plotNetworkWiring, plotPBNTransitions, attractorsToLaTeX, sequenceToLaTeX, stateTransition, getAttractorSequence, getTransitionTable, getStateSummary, getBasinOfAttraction, getPathToAttractor, getTransitionProbabilities, toPajek, toSBML, generateRandomNKNetwork, generateCanalyzing, generateNestedCanalyzing, generateState, generateTimeSeries, perturbNetwork, perturbTrajectories, simplifyNetwork, simulateSymbolicModel, reconstructNetwork, chooseNetwork, fixGenes, binarizeTimeSeries, markovSimulation, testNetworkProperties, testAttractorRobustness, testTransitionRobustness, testIndegree, truthTableToSymbolic, symbolicToTruthTable) BoolNet/data/0000755000176200001440000000000013277247010012530 5ustar liggesusersBoolNet/data/examplePBN.rda0000644000176200001440000000060713277247010015216 0ustar liggesusersŔN0KD3ٍ7ˁ^/z,^agYKEL"2>wK|`ZJбœo}Uj7 =:^ O 13kiS![IcDEnmav3¡\UDBq$pLo~Ð0*}?`g@<=/ VE! ߱='b$! eD%"A HEdR5/MZ01`bЂ2h=DYf?9" +2 ƭAƾn_`=`Ӵ\?4^Т9%3HSPДp%悒0TT-H-;.43 al$ M.yсBoolNet/data/cellcycle.rda0000644000176200001440000000106413277247010015160 0ustar liggesusersWN@Ki|4ƴ `ʨ<+$&l0(B1j¿K~zE%`$ܶ3ǴUoW2q3i2Q"&Ap@ 0jZ0>ĸ7\h7H$sf?>U9BpD?jaXL!9^Q0~at\;RK9VUms59RU8nܔ=!BٛhN0}, the result list contains an additional matrix \code{perturbations} specifying the artificial perturbations applied to the different time series. This matrix has \code{numSeries} columns and one row for each gene in the network. A matrix entry is 0 for a knock-out of the corresponding gene in the corresponding time series, 1 for overexpression, and NA for no perturbation. The result format is compatible with the input parameters of \code{\link{binarizeTimeSeries}} \if{latex}{\cr} and \code{\link{reconstructNetwork}}. } \seealso{ \code{\link{stateTransition}}, \code{\link{binarizeTimeSeries}}, \code{\link{reconstructNetwork}} } \examples{ \dontrun{ # generate noisy time series from the cell cycle network data(cellcycle) ts <- generateTimeSeries(cellcycle, numSeries=50, numMeasurements=10, noiseLevel=0.1) # binarize the noisy time series bin <- binarizeTimeSeries(ts, method="kmeans")$binarizedMeasurements # reconstruct the network print(reconstructNetwork(bin, method="bestfit")) } } BoolNet/man/yeastTimeSeries.Rd0000644000176200001440000000224214302073351015773 0ustar liggesusers\name{yeastTimeSeries} \alias{yeastTimeSeries} \docType{data} \title{ Yeast cell cycle time series data } \description{ Preprocessed time series measurements of four genes from the yeast cell cycle data by Spellman et al. } \usage{data(yeastTimeSeries)} \format{ A matrix with 14 measurements for the genes Fhk2, Swi5, Sic1, and Clb1. Each gene is a row of the matrix, and each column is a measurement. } \details{ The data were obtained from the web site of the yeast cell cycle analysis project. The time series synchronized with the elutriation method were extracted for the genes Fhk2, Swi5, SIC1, and Clb1. In a preprocessing step, missing values were imputed by taking the means of the measurements of the same genes at neighbouring time points. } \source{ P. T. Spellman, G. Sherlock, M. Q. Zhang, V. R. Iyer, K. Anders, M. B. Eisen, P. O. Brown, D. Botstein, B. Futcher (1998), Comprehensive Identification of Cell Cycle-regulated Genes of the Yeast Saccharomyces cerevisiae by Microarray Hybridization. Molecular Biology of the Cell 9(12):3273--3297. } \examples{ data(yeastTimeSeries) # the data set is stored in a variable called 'yeastTimeSeries' print(yeastTimeSeries) }BoolNet/man/simplifyNetwork.Rd0000644000176200001440000000535314302073254016072 0ustar liggesusers\name{simplifyNetwork} \Rdversion{1.1} \alias{simplifyNetwork} \title{ Simplify the functions of a synchronous, asynchronous, or probabilistic Boolean network } \description{ Eliminates irrelevant variables from the inputs of the gene transition functions. This can be useful if the network was generated randomly via \code{\link{generateRandomNKNetwork}} or if it was perturbed via \code{\link{perturbNetwork}}. } \usage{ simplifyNetwork(network, readableFunctions = FALSE) } \arguments{ \item{network}{ A network structure of class \code{BooleanNetwork}, \code{ProbabilisticBooleanNetwork} or \code{BooleanNetworkCollection}. These networks can be read from files by \code{\link{loadNetwork}}, generated by \if{latex}{\cr}\code{\link{generateRandomNKNetwork}}, or reconstructed by \code{\link{reconstructNetwork}}. } \item{readableFunctions}{ This parameter specifies if readable DNF representations of the transition function truth tables are generated and displayed when the network is printed. If set to FALSE, the truth table result column is displayed. If set to "canonical", a canonical Disjunctive Normal Form is generated from each truth table. If set to "short", the canonical DNF is minimized by joining terms (which can be time-consuming for functions with many inputs). If set to TRUE, a short DNF is generated for functions with up to 12 inputs, and a canonical DNF is generated for functions with more than 12 inputs. } } \details{ The function checks whether the output of a gene transition function is independent from the states of any of the input variables. If this is the case, these input variables are dropped, and the transition function is shortened accordingly. In non-probabilistic Boolean networks (class \code{BooleanNetwork}), constant genes are automatically fixed (e.g. knocked-out or over-expressed). This means that they are always set to the constant value, and states with the complementary value are not considered in transition tables etc. If you would like to change this behaviour, use \code{\link{fixGenes}} to reset the fixing. } \value{ The simplified network of class \code{BooleanNetwork}, \code{ProbabilisticBooleanNetwork} or \code{BooleanNetworkCollection}. These classes are described in more detail in \code{\link{loadNetwork}} and \code{\link{reconstructNetwork}}. } \seealso{ \code{\link{loadNetwork}},\code{\link{generateRandomNKNetwork}}, \code{\link{perturbNetwork}}, \code{\link{reconstructNetwork}}, \code{\link{fixGenes}} } \examples{ \dontrun{ # load example data data(cellcycle) # perturb the network perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="shuffle") print(perturbedNet$interactions) # simplify the network perturbedNet <- simplifyNetwork(perturbedNet) print(perturbedNet$interactions) } }BoolNet/man/getPathToAttractor.Rd0000644000176200001440000000602014302073003016427 0ustar liggesusers\name{getPathToAttractor} \alias{getPathToAttractor} \title{ Get state transitions between a state and its attractor } \description{ Lists the states in the path from a specified state to the corresponding synchronous attractor. } \usage{ getPathToAttractor(network, state, includeAttractorStates = c("all","first","none")) } \arguments{ \item{network}{Either a network structure of class \code{BooleanNetwork} or \code{SymbolicBooleanNetwork} , or an attractor search result of class \code{AttractorInfo}. In the former case, a synchronous attractor search starting from \code{state} is conducted. In the latter case, \code{network} must be the result of a call to \code{\link{getAttractors}} with \code{returnTable=TRUE}, and its transition table must include \code{state}. } \item{state}{ A binary vector with exactly one entry per gene in the network. If \code{network} is of class \code{SymbolicBooleanNetwork} and makes use of more than one predecessor state, this can also be a matrix with the genes in the columns and multiple predecessor states in the rows. } \item{includeAttractorStates}{ Specifies whether the actual attractor states are included in the resulting table or not. If \code{includeAttractorStates = "all"} (which is the default behaviour), the sequence ends when the attractor was traversed once. If \code{includeAttractorStates = "first"}, only the first state of attractor is added to the sequence. This corresponds to the behaviour prior to \pkg{BoolNet} version 1.5. If {includeAttractorStates = "none"}, the sequence ends with the last non-attractor state. In this case, the sequence can be empty if the start state is an attractor state. } } \value{ Returns a data frame with the genes in the columns. The rows are the successive states from \code{state} to the the corresponding attractor. Depending on \code{includeAttractorStates}, attractor states are included or not. The data frame has an attribute \code{attractor} specifying the indices of the states that belong to the attractor. If \code{includeAttractorStates} is \code{"first"} or \code{"none"}, these indices may correspond to states that are not included in the sequence itself. This attribute is used by \code{\link{plotSequence}} to highlight the attractor states. } \seealso{ \code{\link{getAttractors}}, \code{\link{simulateSymbolicModel}}, \code{\link{getTransitionTable}}, \code{\link{getBasinOfAttraction}}, \code{\link{plotSequence}}, \code{\link{attributes}} } \examples{ \dontrun{ # load example network data(cellcycle) # get path from a state to its attractor # include all attractor states path <- getPathToAttractor(cellcycle, rep(1,10), includeAttractorStates="all") print(path) # include only the first attractor state path <- getPathToAttractor(cellcycle, rep(1,10), includeAttractorStates="first") print(path) # exclude attractor states path <- getPathToAttractor(cellcycle, rep(1,10), includeAttractorStates="none") print(path) } } BoolNet/man/testNetworkProperties.Rd0000644000176200001440000003241614302073327017273 0ustar liggesusers\name{testNetworkProperties} \alias{testNetworkProperties} \alias{testIndegree} \alias{testAttractorRobustness} \alias{testTransitionRobustness} \title{ Test properties of networks by comparing them to random networks } \description{ This is a general function designed to determine unique properties of biological networks by comparing them to a set of randomly generated networks with similar structure. } \usage{ testNetworkProperties(network, numRandomNets = 100, testFunction = "testIndegree", testFunctionParams = list(), accumulation = c("characteristic", "kullback_leibler"), alternative=c("greater","less"), sign.level = 0.05, drawSignificanceLevel = TRUE, klBins, klMinVal = 1e-05, linkage = c("uniform", "lattice"), functionGeneration = c("uniform", "biased"), validationFunction, failureIterations=10000, simplify = FALSE, noIrrelevantGenes = TRUE, d_lattice = 1, zeroBias = 0.5, title = "", xlab, xlim, breaks = 30, ...) } \arguments{ \item{network}{ A network structure of class \code{BooleanNetwork} or \code{SymbolicBooleanNetwork} } \item{numRandomNets}{ The number of random networks to generate for comparison } \item{testFunction}{ The name of a function that calculates characteristic values that describe properties of the network. There are two built-in functions: "testIndegree" calculates the in-degrees of states in the network, and "testAttractorRobustness" counts the occurrences of attractors in perturbed copies. It is possible to supply user-defined functions here. See Details. } \item{testFunctionParams}{ A list of parameters to \code{testFunction}. The elements of the list depend on the chosen function. } \item{accumulation}{ If "characteristic" is chosen, the test function is required to return a single value that describes the network. In this case, a histogram of these values in random networks is plotted, and the value of the original network is inserted as a vertical line. If "kullback_leibler" is chosen, the test function can return a vector of values which is regarded as a sample from a probability distribution. In this case, the Kullback-Leibler distances of the distributions from the original network and each of the random networks are calculated and plotted in a histogram. The Kullback-Leibler distance measures the difference between two probability distributions. In this case, the resulting histogram shows the distribution of differences between the original network and randomly generated networks. } \item{alternative}{ If \code{accumulation="characteristic"}, this specifies whether the characteristic value is expected to be greater or less than the random results under the alternative hypothesis. } \item{sign.level}{ If \code{accumulation="characteristic"}, this specifies a significance level for a computer-intensive test. If \code{alternative="greater"}, the test is significant if the characteristic value is greater than at least \code{(1-sign.level)*100}\% of the characteristic values of the random networks. If \code{alternative="less"}, the test is significant if the characteristic value is less than at most \code{sign.level*100}\% of the characteristic values of the random networks. } \item{drawSignificanceLevel}{ If \code{accumulation="characteristic"} and this is true, a vertical line is plotted for the significance level in the histogram. } \item{linkage, functionGeneration, validationFunction, failureIterations, simplify, noIrrelevantGenes, d_lattice, zeroBias}{ The corresponding parameters of \code{\link{generateRandomNKNetwork}} used to generate the random networks. This allows for customization of the network generation process. The three remaining parameters of \code{\link{generateRandomNKNetwork}} are set to values that ensure structural similarity to the original network: The parameters \code{n} and \code{k} are set to the corresponding values of the original network, and \code{topology="fixed"}. } \item{klBins}{ If \code{accumulation="kullback_leibler"}, the number of bins used to discretize the samples for the Kullback-Leibler distance calculations. By default, each unique value in the samples has its own bin, i.e. no further discretization is performed. The influence of discretization on the resulting histogram may be high. } \item{klMinVal}{ If \code{accumulation="kullback_leibler"}, this defines the minimum probability for the calculation of the Kullback-Leibler distance to ensure stability of the results. } \item{title}{ The title of the plots. This is empty by default. } \item{xlab}{ Customizes label of the x axis of the histogram. For the built-in test functions, the x axis label is set automatically. } \item{xlim}{ Customizes the limits of the x axis of the histogram. For the built-in test functions, suitable values are chosen automatically. } \item{breaks}{ Customizes the number of breaks in the } \item{\dots}{ Further graphical parameters for \code{\link{hist}} } } \details{ This function generically compares properties of biological networks to a set of random networks. It can be extended by supplying custom functions to the parameter \code{testFunction}. Such a function must have the signature \code{function(network, accumulate=TRUE, params)} \describe{ \item{network}{This is the network to test. In the process of the comparison, both the original network and the random networks are passed to the function} \item{accumulate}{If \code{accumulate=TRUE}, the function must return a single value quantifying the examined property of the network. If \code{accumulate=FALSE}, the function can return a vector of values (e.g., one value for each gene/state etc.)} \item{params}{A list of further parameters for the function supplied by the user in \code{testFunctionParams} (see above). This can contain any type of information your test function needs.} } Three built-in functions for synchronous Boolean networks already exist: \describe{ \item{testIndegree}{This function is based on the observation that, often, in biological networks, many state transitions lead to the same states. In other words, there is a small number of "hub" states. In the state graph, this means that the in-degree of some states (i.e., the number of transitions leading to it) is high, while the in-degree of many other states is 0. We observed that random networks do not show this behaviour, thus it may be a distinct property of biological networks. For this function, the parameter \code{alternative} of \code{testNetworkProperties} should be set to "greater". The function does not require any parameter entries in \code{params}. If \code{accumulate=FALSE}, it returns the in-degrees of all synchronous states in the network. If \code{accumulate=TRUE}, the Gini index of the in-degrees is returned as a characteristic value of the network. The Gini index is a measure of inequality. If all states have an in-degree of 1, the Gini index is 0. If all state transitions lead to one single state, the Gini index is 1. This function requires the \pkg{igraph} package for the analysis of the in-degrees. } \item{testAttractorRobustness}{This function tests the robustness of attractors in a network to noise. We expect attractors in a real network to be less susceptible to noise than attractors in randomly generated networks, as biological processes can be assumed to be comparatively stable. There are modes of generating noise: Either the functions of the network can be perturbed, or the state trajectories can be perturbed in a simulation of the network. If \code{perturb="functions"} or \code{perturb="transitions"}, the function generates a number of perturbed copies of the network using \code{\link{perturbNetwork}} and checks whether the original attractors can still be found in the network. If \code{perturb="trajectories"}, the network itself is not perturbed. Instead, a set of random initial states is generated, and a set of perturbed states is generated from these initial states by flipping one or more bits. Then, the function tests whether the attractors are the same for the initial states and the corresponding perturbed states. This corresponds to calling \code{\link{perturbTrajectories}} with \code{measure="attractor"}. \code{params} can hold a number of parameters: \describe{ \item{numSamples}{If \code{perturb="trajectories"}, the number of randomly generated state pairs to generate. Otherwise the number of perturbed networks that are generated.} \item{perturb}{Specifies the type of perturbation to be applied (possible values: \code{"functions"}, \code{"transitions"} and \code{"trajectories"} -- see above).} \item{method, simplify, readableFunctions, excludeFixed, maxNumBits, numStates}{ If \code{perturb="functions"} or \code{perturb="transitions"}, these are the corresponding parameters of \code{\link{perturbNetwork}} that influence the way the network is perturbed.} \item{flipBits}{ If \code{perturb="trajectories"}, the are the corresponding parameters of \code{\link{perturbTrajectories}} that defines how many bits are flipped.} } If {perturb="functions"} or \code{perturb="transitions"} and \code{accumulate=FALSE}, the function returns a vector of percentages of original attractors found in each of the perturbed copies of the original network. If \code{accumulate=TRUE}, the function returns the overall percentage of original attractors found in all perturbed copies. If \code{perturb="trajectories"} and \code{accumulate=FALSE}, the function returns a logical vector of length \code{numSamples} specifying whether the attractor was the same for each initial state and the corresponding perturbed state. If \code{accumulate=TRUE}, the function returns the percentage of pairs of initial states and perturbed states for which the attractors were the same. For this function, the parameter \code{alternative} of \code{testNetworkProperties} should be set to "greater". } \item{testTransitionRobustness}{This function calls \code{perturbTrajectories} with \code{measure="hamming"} to measure the average Hamming distance between successor states of randomly generated initial states and perturbed copies of these states. code{params} can hold parameters \code{numSamples, flipBits} corresponding to the parameters of \code{\link{perturbTrajectories}} that define how many initial states are drawn and how many bits are flipped. If \code{accumulate=FALSE}, the function returns a numeric vector of length \code{numSamples} with the normalized Hamming distances of all pairs of initial states and perturbed copies. If \code{accumulate=TRUE}, the mean normalized Hamming distance over all pairs is returned. For this function, the parameter \code{alternative} of \code{testNetworkProperties} should be set to "less". } } } \value{ The function returns a list with the following elements \item{hist}{The histogram that was plotted. The type of histogram depends on the parameter \code{accumulation}.} \item{pval}{If \code{accumulation="characteristic"}, a p-value for the alternative hypothesis that the test statistic value of the supplied network is greater than the value of a randomly generated network is supplied.} \item{significant}{If \code{accumulation="characteristic"}, this is true for \code{pval < sign.level}.} } \seealso{ \code{\link{generateRandomNKNetwork}}, \code{\link{perturbNetwork}}, \code{\link{perturbTrajectories}}, \code{\link{plotStateGraph}}, \code{\link{getAttractors}} } \examples{ \dontrun{ # load mammalian cell cycle network data(cellcycle) if (interactive()) # do not run these examples in the package check, as they take some time { # compare the in-degrees of the states in the # cell cycle network to random networks testNetworkProperties(cellcycle, testFunction="testIndegree", alternative="greater") # compare the in-degrees of the states in the # cell cycle network to random networks, # and plot the Kullback-Leibler distances of the 100 experiments testNetworkProperties(cellcycle, testFunction="testIndegree", accumulation = "kullback_leibler") # compare the robustness of attractors in the cell cycle network # to random networks by perturbing the networks testNetworkProperties(cellcycle, testFunction="testAttractorRobustness", testFunctionParams=list(perturb="functions", numSamples=10), alternative="greater") # compare the robustness of attractors in the cell cycle network # to random networks by perturbing the state trajectories testNetworkProperties(cellcycle, testFunction="testAttractorRobustness", testFunctionParams=list(perturb="trajectories", numSamples=10), alternative="greater") # compare the robustness of single state transitions in the cell cycle network testNetworkProperties(cellcycle, testFunction="testTransitionRobustness", testFunctionParams=list(numSamples=10), alternative="less") } } }BoolNet/man/markovSimulation.Rd0000644000176200001440000000701614302073115016222 0ustar liggesusers\name{markovSimulation} \alias{markovSimulation} %- Also NEED an '\alias' for EACH other topic documented here. \title{ Identify important states in probabilistic Boolean networks } \description{ Identifies important states in probabilistic Boolean networks (PBN) using a Markov chain simulation } \usage{ markovSimulation(network, numIterations = 1000, startStates = list(), cutoff = 0.001, returnTable = TRUE) } \arguments{ \item{network}{ An object of class \code{ProbabilisticBooleanNetwork} or \code{BooleanNetwork} whose transitions are simulated } \item{numIterations}{ The number of iterations for the matrix multiplication, which corresponds to the number of state transitions to simulate } \item{startStates}{ An optional list of start states. Each entry of the list must be a vector with a 0/1 value for each gene. If specified, the simulation is restricted to the states reachable from the supplied start states. Otherwise, all states are considered. } \item{cutoff}{ The cutoff value used to determine if a probability is 0. All output probabilities less than or equal to this value are set to 0. } \item{returnTable}{ If set to true, a transition table annotated with the probabilities for the transitions is included in the results. This is required by \code{\link{plotPBNTransitions}} and \code{\link{getTransitionProbabilities}}. } } \details{ The algorithm identifies important states by performing the following steps: First, a Markov matrix is calculated from the set of transition functions, where each entry of the matrix specifies the probability of a state transition from the state belonging to the corresponding row to the state belonging to the corresponding column. A vector is initialized with uniform probability for all states (or -- if specified -- uniform probability for all start states) and repeatedly multiplied with the Markov matrix. The method returns all states with non-zero probability in this vector. See the references for more details. } \value{ An object of class \code{MarkovSimulation} with the following components: \item{reachedStates}{A data frame with one state in each row. The first columns specify the gene values of the state, and the last column holds the probability that the corresponding state is reached after \code{numIterations} transitions. Only states with a probability greater than \code{cutoff} are included in this table.} \item{genes}{A vector of gene names of the input network} \item{table}{If \code{returnTable=TRUE}, this structure holds a table of transitions with the corresponding probabilities that transitions are chosen. This is a list with the following components: \describe{ \item{initialStates}{A matrix of encoded start states of the transitions} \item{nextStates}{The encoded successor states of the transitions} \item{probabilities}{The probabilities that the transitions are chosen in a single step} }} } \references{ I. Shmulevich, E. R. Dougherty, S. Kim, W. Zhang (2002), Probabilistic Boolean networks: a rule-based uncertainty model for gene regulatory networks. Bioinformatics 18(2):261--274. } \seealso{ \code{\link{reconstructNetwork}}, \code{\link{plotPBNTransitions}}, \code{\link{getTransitionProbabilities}} } \examples{ \dontrun{ # load example network data(examplePBN) # perform a Markov chain simulation sim <- markovSimulation(examplePBN) # print the relevant states and transition probabilities print(sim) # plot the transitions and their probabilities plotPBNTransitions(sim) } }BoolNet/man/getAttractors.Rd0000644000176200001440000003524114272167337015525 0ustar liggesusers\name{getAttractors} \Rdversion{1.1} \alias{getAttractors} %- Also NEED an '\alias' for EACH other topic documented here. \title{Identify attractors in a Boolean network} \description{Identifies attractors (cycles) in a supplied Boolean network using synchronous or asynchronous state transitions} \usage{ getAttractors(network, type = c("synchronous","asynchronous"), method = c("exhaustive", "sat.exhaustive", "sat.restricted", "random", "chosen"), startStates = list(), genesON = c(), genesOFF = c(), canonical = TRUE, randomChainLength = 10000, avoidSelfLoops = TRUE, geneProbabilities = NULL, maxAttractorLength = Inf, returnTable = TRUE) } \arguments{ \item{network}{ A network structure of class \code{BooleanNetwork} or \code{SymbolicBooleanNetwork}. These networks can be read from files by \code{\link{loadNetwork}}, generated by \code{\link{generateRandomNKNetwork}}, or reconstructed by \code{\link{reconstructNetwork}}. } \item{type}{ If \code{type="synchronous"}, synchronous state transitions are used, i.e. all genes are updated at the same time. Synchronous attractor search can be performed in an exhaustive manner or using a heuristic that starts from predefined states. For symbolic networks, only synchronous updates are possible. If \code{type="asynchronous"}, asynchronous state transitions are performed, i.e. one (randomly chosen) gene is updated in each transition. Steady-state attractors are the same in asynchronous and synchronous networks, but the asynchronous search is also able to identify complex/loose attractors. Asynchronous search relies on a heuristic algorithm that starts from predefined states. See Details for more information on the algorithms. } \item{method}{ The search method to be used. If "exhaustive", attractors are identified by exhaustive state space search, i.e. by calculating the sucessors of all 2^n states (where n is the number of genes that are not set to a fixed value). This kind of search is only available for synchronous attractor search, and the maximum number of genes allowed for exhaustive search is 29. Apart from the attractors, this method generates the full state transition graph. If \code{method} is "sat.exhaustive" or "sat.restricted", attractors are identified using algorithms based on the satisfiability problem. This search type is also restricted to synchronous networks. It can be used to identify attractors in much larger networks than with \code{method="exhaustive"}, but does not return the state transition graph. For \code{method="sat.exhaustive"}, an exhaustive attractor search is performed, while \code{method="sat.restricted"} only searches for attractors of a specified maximum length \code{maxAttractorLength}. If \code{method} is "random", \code{startStates} is interpreted as an integer value specifying the number of states to be generated randomly. The algorithm is then initialized with these random states and identifies the attractors to which these states lead. If \code{method} is "chosen", \code{startStates} is interpreted as a list of binary vectors, each specifying one input state. Each vector must have \code{length(network$genes)} elements with 0 or 1 values. The algorithm identifies the attractors to which the supplied states lead. If \code{network} is of class \code{SymbolicBooleanNetwork} and makes use of more than one predecessor state, this can also be a list of matrices with the genes in the columns and multiple predecessor states in the rows. If \code{method} is not supplied, the desired method is inferred from the type of \code{startStates}. By default, if neither \code{method} nor \code{startStates} are provided, an exhaustive search is performed. } \item{startStates}{ The value of \code{startStates} depends on the chosen method. See \code{method} for more details. } \item{genesON}{ A vector of genes whose values are fixed to 1, which reduces the complexity of the search. This is equivalent to a preceding call of \code{\link{fixGenes}}. } \item{genesOFF}{ A vector of genes whose values are fixed to 0, which reduces the complexity of the search. This is equivalent to a preceding call of \code{\link{fixGenes}}. } \item{canonical}{ If set to true, the states in the attractors are rearranged such that the state whose binary encoding makes up the smallest number is the first element of the vector. This ensures that attractors found by different heuristic runs of \code{getAttractors} are comparable, as the cycles may have been entered at different states in different runs of the algorithm. } \item{randomChainLength}{ If \code{type="asynchronous"}, this parameter specifies the number of random transitions performed by the search to enter a potential attractor (see Details). Defaults to 10000. } \item{avoidSelfLoops}{ If \code{type="asynchronous"} and \code{avoidSelfLoops=TRUE}, the asynchronous attractor search only enters self loops (i.e. transitions that result in the same state) if none of the possible transitions can leave the state. This results in attractors with fewer edges. Otherwise, self loops are included in the attractors. By default, self loops are avoided. } \item{geneProbabilities}{ If \code{type="asynchronous"}, this allows to specify probabilities for the genes. By default, each gene has the same probability to be chosen for the next state transition. You can supply a vector of probabilities for each of the genes which sums up to one. } \item{maxAttractorLength}{If \code{method="sat.restricted"}, this required parameter specifies the maximum size of attractors (i.e. the number of states in the loop) to be searched. For \code{method="sat.exhaustive"}, this parameter is optional and specifies the maximum attractor length for the initial length-restricted search phase that is performed to speed up the subsequent exhaustive search. In this case, changing this value might bring performance benefits, but does not change the results.} \item{returnTable}{ Specifies whether a transition table is included in the returned \code{AttractorInfo} structure. If \code{type="asynchronous"} or \code{method="sat"}, this parameter is ignored, as the corresponding algorithms never return a transition table. } } \details{ Depending on the type of network and the chosen parameters, different search algorithms are started. For \code{BooleanNetwork} networks, there are three different modes of attractor search: \describe{ \item{Exhaustive synchronous state space search}{ In this mode, synchronous state transitions are carried out from each of the possible states until an attractor is reached. This identifies all synchronous attractors. } \item{Heuristic synchronous state space search}{ In contrast to exhaustive synchronous search, only a subset of the possible states is used. From these states, synchronous transitions are carried out until an attractor is reached. This subset is specified in \code{startStates}. } \item{Exhaustive synchronous SAT-based search}{ Here, the attractor search problem is formulated as a satisfiability problem and solved using Armin Biere's PicoSAT solver. The algorithm is a variant of the method by Dubrova and Teslenko which searches for a satisfying assignment of a chain constructed by unfolding the transition relation. Depending on \code{maxAttractorLength}, it additionally applies an initial size-restricted SAT-based search (see below) to increase overall search speed. This method is suitable for larger networks of up to several hundreds of genes and exhaustively identifies all attractors in these networks. In contrast to the state space search, it does not construct and return a state transition table. } \item{Size-restricted synchronous SAT-based search}{ Here, the SAT solver directly looks for satisfying assignments for loops of a specific size. This may be more efficient for large networks and is guaranteed to find all attractors that comprise up to \code{maxAttractorLength} states (e.g. all steady states for \code{maxAttractorLength=1}) , but does not find any larger attractors. As for the exhaustive SAT-based method, no transition table is returned. } \item{Heuristic asynchronous search}{ This algorithm uses asynchronous state transitions and is able to identify steady-state and complex/loose attractors (see Harvey and Bossomaier, Garg et al.). These attractors are sets of states from which all possible asynchronous transitions lead into a state that is member of the set as well. The heuristic algorithm does the following for each of the input state specified by \code{startStates}: \enumerate{ \item Perform \code{randomChainLength} random asynchronous transitions. After these transitions, the network state is expected to be located in an attractor with a high probability. \item Calculate the forward reachable set of the current state. Then, compare this set to the forward reachable set of all states in the set. If all sets are equal, a complex attractor is found. } } For \code{SymbolicBooleanNetwork} networks, \code{getAttractors} is simply a wrapper for \code{\link{simulateSymbolicModel}} with preset parameters. } Printing the return value of \code{getAttractors} using \code{\link{print}} visualizes the identified attractors.} \value{ For \code{BooleanNetwork} networks, this returns a list of class \code{AttractorInfo} with components \item{attractors}{A list of attractors. Each element is a 2-element list with the following components: \describe{ \item{involvedStates}{A matrix containing the states that make up the attractor. Each column represents one state. The entries are decimal numbers that internally represent the states of the genes. The number of rows depends on the number of genes in the network: The first 32 genes are encoded in the first row, genes 33-64 are encoded in the second row, etc.} \item{initialStates}{This element is only available if an asynchronous search was carried out and this is a complex attractor. In this case, it holds the encoded start states of the transitions in the complex attractor} \item{nextStates}{This element is only available if an asynchronous search was carried out and this is a complex attractor. In this case, it holds the encoded successor states of the transitions in the complex attractor} \item{basinSize}{The number of states in the basin of attraction. Details on the states in the basin can be retrieved via \code{\link{getBasinOfAttraction}}.} }} \item{stateInfo}{A summary structure of class \code{BooleanStateInfo} containing information on the transition table. It has the following components: \describe{ \item{initialStates}{This element is only available if \code{type="synchronous"}, \code{method} is "random" or "chosen", and \code{returnTable=TRUE}. This is a matrix describing the initial states that lead to the states in \code{table} after a state transition. If \code{method} is "exhaustive", this component is \code{NULL}. In this case, the initial states can be inferred, as all states are used. The format of the matrix is described in \code{involvedStates}.} \item{table}{This element is only available if \code{type="synchronous"} and \if{latex}{\cr}\code{returnTable=TRUE}. It holds result vector of the transition table as a matrix with one column for each state. These are encoded bit vectors in decimal numbers as described above.} \item{attractorAssignment}{This element is only available if \code{type="synchronous"} and \code{returnTable=TRUE}. It contains a vector that corresponds to the entries in \code{table} and describes the attractor index in \code{attractors} to which successive transitions from the described state finally lead.} \item{stepsToAttractor}{This element is only available if \code{type="synchronous"} and \code{returnTable=TRUE}. Referring to \code{attractorAssignment}, this is the number of transitions needed to reach the attractor.} \item{genes}{A list of names of the genes in \code{network}.} \item{fixedGenes}{Specifies the fixed genes as in the \code{fixed} component of \code{network}.} } The structure supports pretty printing using the \code{\link{print}} method.} For \code{SymbolicBooleanNetwork} networks, \code{getAttractors} redirects the call to \code{\link{simulateSymbolicModel}} and returns an object of class \code{SymbolicSimulation} containing the attractors and (if \code{returnTable=TRUE}) the transition graph. } \references{ S. A. Kauffman (1969), Metabolic stability and epigenesis in randomly constructed nets. J. Theor. Biol. 22:437--467. S. A. Kauffman (1993), The Origins of Order. Oxford University Press. I. Harvey, T. Bossomaier (1997), Time out of joint: Attractors in asynchronous random Boolean networks. Proc. of the Fourth European Conference on Artificial Life, 67--75. A. Garg, A. Di Cara, I. Xenarios, L. Mendoza, G. De Micheli (2008), Synchronous versus asynchronous modeling of gene regulatory networks. Bioinformatics 24(17):1917--1925. E. Dubrova, M. Teslenko (2011), A SAT-based algorithm for finding attractors in synchronous Boolean networks. IEEE/ACM Transactions on Computational Biology and Bioinformatics 8(5):1393--1399. A. Biere (2008), PicoSAT Essentials. Journal on Satisfiability, Boolean Modeling and Computation 4:75-97. } \seealso{ \code{\link{loadNetwork}}, \code{\link{generateRandomNKNetwork}}, \code{\link{simulateSymbolicModel}}, \code{\link{plotAttractors}}, \code{\link{attractorsToLaTeX}}, \code{\link{getTransitionTable}}, \code{\link{getBasinOfAttraction}}, \code{\link{getAttractorSequence}}, \code{\link{getStateSummary}}, \code{\link{getPathToAttractor}}, \code{\link{fixGenes}}, \code{\link{generateState}} } \examples{ \dontrun{ # load example data data(cellcycle) # get all synchronous attractors by exhaustive search attractors <- getAttractors(cellcycle) # plot attractors side by side par(mfrow=c(2, length(attractors$attractors))) plotAttractors(attractors) # finds the synchronous attractor with 7 states attractors <- getAttractors(cellcycle, method="chosen", startStates=list(rep(1, length(cellcycle$genes)))) plotAttractors(attractors) # finds the attractor with 1 state attractors <- getAttractors(cellcycle, method="chosen", startStates=list(rep(0, length(cellcycle$genes)))) plotAttractors(attractors) # also finds the attractor with 1 state by restricting the attractor length attractors <- getAttractors(cellcycle, method="sat.restricted", maxAttractorLength=1) plotAttractors(attractors) # identifies asynchronous attractors attractors <- getAttractors(cellcycle, type="asynchronous", startStates=100) plotAttractors(attractors, mode="graph") } } BoolNet/man/toSBML.Rd0000644000176200001440000000472514272164572014000 0ustar liggesusers\name{toSBML} \alias{toSBML} \title{ Export a network to SBML } \description{ Exports a synchronous or asynchronous Boolean network to SBML with the \code{sbml-qual} extension package. } \usage{ toSBML(network, file, generateDNFs = FALSE, saveFixed = TRUE) } \arguments{ \item{network}{ An object of class \code{BooleanNetwork} or \code{SymbolicBooleanNetwork} to be exported } \item{file}{ The name of the SBML file to be created } \item{generateDNFs}{ If \code{network} is a \code{BooleanNetwork} object, this parameter specifies whether formulae in Disjunctive Normal Form are exported instead of the expressions that describe the transition functions. If set to FALSE, the original expressions are exported. If set to "canonical", a canonical Disjunctive Normal Form is generated from each truth table. If set to "short", the canonical DNF is minimized by joining terms (which can be time-consuming for functions with many inputs). If set to TRUE, a short DNF is generated for functions with up to 12 inputs, and a canonical DNF is generated for functions with more than 12 inputs. For objects of class \code{SymbolicBooleanNetwork}, this parameter is ignored. } \item{saveFixed}{ If set to TRUE, knock-outs and overexpression of genes override their transition functions. That is, if a gene in the network is fixed to 0 or 1, this value is exported, regardless of the transition function. If set to FALSE, the transition function is exported. Defaults to TRUE. } } \details{ The export creates an SBML file describing a general logical model that corresponds to the Boolean network. Importing tools must support the \code{sbml-qual} extension package version 1.0. The export translates the expressions that describe the network transition functions to a MathML description. If these expressions cannot be parsed or \code{generateDNFs} is true, a DNF representation of the transition functions is generated and exported. For symbolic networks, temporal operators and delays of more than one time step are not allowed, as they are not compatible with SBML. } \references{ \url{http://sbml.org/Documents/Specifications/SBML_Level_3/Packages/Qualitative_Models_(qual)} } \seealso{ \code{\link{loadSBML}}, \code{\link{loadNetwork}}, \code{\link{saveNetwork}}, \code{\link{toPajek}} } \examples{ \dontrun{ # load the cell cycle network data(cellcycle) # export the network to SBML toSBML(cellcycle, file="cellcycle.sbml") # reimport the model print(loadSBML("cellcycle.sbml")) } }BoolNet/man/loadNetwork.Rd0000644000176200001440000003346614302073063015161 0ustar liggesusers\name{loadNetwork} \Rdversion{1.1} \alias{loadNetwork} %- Also NEED an '\alias' for EACH other topic documented here. \title{ Load a Boolean network from a file } \description{ Loads a Boolean network or probabilistic Boolean network from a file and converts it to an internal transition table representation. } \usage{ loadNetwork(file, bodySeparator = ",", lowercaseGenes = FALSE, symbolic = FALSE) } \arguments{ \item{file}{ The name of the file to be read } \item{bodySeparator}{ An optional separation character to divide the target factors and the formulas. Default is ",". } \item{lowercaseGenes}{ If set to \code{TRUE}, all gene names are converted to lower case, i.e. the gene names are case-insensitive. This corresponds to the behaviour of \pkg{BoolNet} versions prior to 1.5. Defaults to \code{FALSE}. } \item{symbolic}{ If set to \code{TRUE}, a symbolic representation of class \code{SymbolicBooleanNetwork} is returned. This is not available for asynchronous or probabilistic Boolean networks, but is required for the simulation of networks with extended temporal predicates and time delays (see \code{\link{simulateSymbolicModel}}). If such predicates are detected, the switch is activated by default. } } \details{ Depending on whether the network is loaded in truth table representation or not, the supported network file formats differ slightly. For the truth table representation (\code{symbolic=FALSE}), the language basically consists of expressions based on the Boolean operators AND (&), or (|), and NOT (!). In addition, some convenience operators are included (see EBNF and operator description below). The first line contains a header. In case of a Boolean network with only one function per gene, the header is "targets, functions"; in a probabilistic network, there is an optional third column "probabilities". All subsequent lines contain Boolean rules or comment lines that are omitted by the parser. A rule consists of a target gene, a separator, a Boolean expression to calculate a transition step for the target gene, and an optional probability for the rule (for probabilistic Boolean networks only -- see below). The EBNF description of the network file format is as follows: \preformatted{ Network = Header Newline {Rule Newline | Comment Newline}; Header = "targets" Separator "factors"; Rule = GeneName Separator BooleanExpression [Separator Probability]; Comment = "#" String; BooleanExpression = GeneName | "!" BooleanExpression | "(" BooleanExpression ")" | BooleanExpression " & " BooleanExpression | BooleanExpression " | " BooleanExpression; | "all(" BooleanExpression {"," BooleanExpression} ")" | "any(" BooleanExpression {"," BooleanExpression} ")" | "maj(" BooleanExpression {"," BooleanExpression} ")" | "sumgt(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "sumlt(" BooleanExpression {"," BooleanExpression} "," Integer ")"; GeneName = ? A gene name from the list of involved genes ?; Separator = ","; Integer = ? An integer value?; Probability = ? A floating-point number ?; String = ? Any sequence of characters (except a line break) ?; Newline = ? A line break character ?; } The extended format for Boolean networks with temporal elements that can be loaded if \code{symbolic=TRUE} additionally allows for a specification of time steps. Furthermore, the operators can be extended with iterators that evaluate their arguments over multiple time steps. \preformatted{ Network = Header Newline {Function Newline | Comment Newline}; Header = "targets" Separator "factors"; Function = GeneName Separator BooleanExpression; Comment = "#" String; BooleanExpression = GeneName | GeneName TemporalSpecification | BooleanOperator | TemporalOperator BooleanOperator = BooleanExpression | "!" BooleanExpression | "(" BooleanExpression ")" | BooleanExpression " & " BooleanExpression | BooleanExpression " | " BooleanExpression; TemporalOperator = "all" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "any" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "maj" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "sumgt" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "sumlt" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "timeis" "(" Integer ")" | "timegt" "(" Integer ")" | "timelt" "(" Integer ")"; TemporalIteratorDef = "[" TemporalIterator "=" Integer ".." Integer "]"; TemporalSpecification = "[" TemporalOperand {"+" TemporalOperand | "-" TemporalOperand} "]"; TemporalOperand = TemporalIterator | Integer TemporalIterator = ? An alphanumeric string ?; GeneName = ? A gene name from the list of involved genes ?; Separator = ","; Integer = ? An integer value?; String = ? Any sequence of characters (except a line break) ?; Newline = ? A line break character ?; } The meaning of the operators is as follows: \describe{ \item{\code{all}}{Equivalent to a conjunction of all arguments. For symbolic networks, the operator can have a time range, in which case the arguments are evaluated for each time point specified in the iterator.} \item{\code{any}}{Equivalent to a disjunction of all arguments. For symbolic networks, the operator can have a time range, in which case the arguments are evaluated for each time point specified in the iterator.} \item{\code{maj}}{Evaluates to true if the majority of the arguments evaluate to true. For symbolic networks, the operator can have a time range, in which case the arguments are evaluated for each time point specified in the iterator.} \item{\code{sumgt}}{Evaluates to true if the number of arguments (except the last) that evaluate to true is greater than the number specified in the last argument. For symbolic networks, the operator can have a time range, in which case the arguments are evaluated for each time point specified in the iterator.} \item{\code{sumlt}}{Evaluates to true if the number of arguments (except the last) that evaluate to true is less than the number specified in the last argument. For symbolic networks, the operator can have a time range, in which case the arguments are evaluated for each time point specified in the iterator.} \item{\code{timeis}}{Evaluates to true if the current absolute time step (i.e. number of state transitions performed from the current start state) is the same as the argument.} \item{\code{timelt}}{Evaluates to true if the current absolute time step (i.e. number of state transitions performed from the current start state) is the less than the argument.} \item{\code{timegt}}{Evaluates to true if the current absolute time step (i.e. number of state transitions performed from the current start state) is greater than the argument.} } If \code{symbolic=FALSE} and there is exactly one rule for each gene, a Boolean network of class \code{BooleanNetwork} is created. In these networks, constant genes are automatically fixed (e.g. knocked-out or over-expressed). This means that they are always set to the constant value, and states with the complementary value are not considered in transition tables etc. If you would like to change this behaviour, use \code{\link{fixGenes}} to reset the fixing. If \code{symbolic=FALSE} and two or more rules exist for the same gene, the function returns a probabilistic network of class \code{ProbabilisticBooleanNetwork}. In this case, alternative rules may be annotated with probabilities, which must sum up to 1 for all rules that belong to the same gene. If no probabilities are supplied, uniform distribution is assumed. If \code{symbolic=TRUE}, a symbolic representation of a (possibly temporal) Boolean network of class \code{SymbolicBooleanNetwork} is created. } \value{ If \code{symbolic=FALSE} and only one function per gene is specified, a structure of class \code{BooleanNetwork} representing the network is returned. It has the following components: \item{genes}{A vector of gene names involved in the network. This list determines the indices of genes in inputs of functions or in state bit vectors.} \item{interactions}{A list with \code{length(genes)} elements, where the i-th element describes the transition function for the i-th gene. Each element has the following sub-components: \describe{ \item{input}{A vector of indices of the genes that serve as the input of the Boolean transition function. If the function has no input (i.e. the gene is constant), the vector consists of a zero element.} \item{func}{The transition function in truth table representation. This vector has \if{latex}{\cr}\code{2^length(input)} entries, one for each combination of input variables. If the gene is constant, the function is 1 or 0.} \item{expression}{A string representation of the Boolean expression from which the truth table was generated} }} \item{fixed}{A vector specifying which genes are knocked-out or over-expressed. For each gene, there is one element which is set to 0 if the gene is knocked-out, to 1 if the gene is over-expressed, and to -1 if the gene is not fixed at all, i. e. can change its value according to the supplied transition function. Constant genes are automatically set to fixed values.} If \code{symbolic=FALSE} and there is at least one gene with two or more alternative transition functions, a structure of class \code{ProbabilisticBooleanNetwork} is returned. This structure is similar to \code{BooleanNetwork}, but allows for storing more than one function in an interaction. It consists of the following components: \item{genes}{A vector of gene names involved in the network. This list determines the indices of genes in inputs of functions or in state bit vectors.} \item{interactions}{A list with \code{length(genes)} elements, where the i-th element describes the alternative transition functions for the i-th gene. Each element is a list of transition functions. In this second-level list, each element has the the following sub-components: \describe{ \item{input}{A vector of indices of the genes that serve as the input of the Boolean transition function. If the function has no input (i.e. the gene is constant), the vector consists of a zero element.} \item{func}{The transition function in truth table representation. This vector has \if{latex}{\cr}\code{2^length(input)} entries, one for each combination of input variables. If the gene is constant, the function is -1.} \item{expression}{A string representation of the underlying Boolean expression} \item{probability}{The probability that the corresponding transition function is chosen} }} \item{fixed}{A vector specifying which genes are knocked-out or over-expressed. For each gene, there is one element which is set to 0 if the gene is knocked-out, to 1 if the gene is over-expressed, and to -1 if the gene is not fixed at all, i. e. can change its value according to the supplied transition function. You can knock-out and over-express genes using \code{\link{fixGenes}}.} If \code{symbolic=TRUE}, a structure of class \code{SymbolicBooleanNetwork} that represents the network as expression trees is returned. It has the following components: \item{genes}{A vector of gene names involved in the network. This list determines the indices of genes in inputs of functions or in state bit vectors.} \item{interactions}{A list with \code{length(genes)} elements, where the i-th element describes the transition function for the i-th gene in a symbolic representation. Each such element is a list that represents a recursive expression tree, possibly consisting of sub-elements (operands) that are expression trees themselves. Each element in an expression tree can be a Boolean/temporal operator, a literal ("atom") or a numeric constant.} \item{internalStructs}{A pointer referencing an internal representation of the expression trees as raw C objects. This is used for simulations and must be set to NULL if \code{interactions} are changed to force a refreshment. } \item{timeDelays}{An integer vector storing the temporal memory sizes required for each of the genes in the network. That is, the vector stores the minimum number of predecessor states of each gene that need to be saved to determine the successor state of the network.} \item{fixed}{A vector specifying which genes are knocked-out or over-expressed. For each gene, there is one element which is set to 0 if the gene is knocked-out, to 1 if the gene is over-expressed, and to -1 if the gene is not fixed at all, i. e. can change its value according to the supplied transition function. Constant genes are automatically set to fixed values.} } \seealso{ \code{\link{getAttractors}}, \code{\link{simulateSymbolicModel}}, \code{\link{markovSimulation}}, \code{\link{stateTransition}}, \code{\link{fixGenes}}, \code{\link{loadSBML}}, \code{\link{loadBioTapestry}} } \examples{ \dontrun{ # write example network to file fil <- tempfile(pattern = "testNet") sink(fil) cat("targets, factors\n") cat("Gene1, !Gene2 | !Gene3\n") cat("Gene2, Gene3 & Gene4\n") cat("Gene3, Gene2 & !Gene1\n") cat("Gene4, 1\n") sink() # read file net <- loadNetwork(fil) print(net) } }BoolNet/man/plotSequence.Rd0000644000176200001440000001664314302073207015335 0ustar liggesusers\name{plotSequence} \alias{plotSequence} \title{ Plot a sequence of states } \description{ Visualizes sequences of states in synchronous Boolean networks, either by drawing a table of the involved states in two colors, or by drawing a graph of transitions between the successive states. } \usage{ plotSequence(network, startState, includeAttractorStates = c("all","first","none"), sequence, title = "", mode=c("table","graph"), plotFixed = TRUE, grouping = list(), onColor="#4daf4a", offColor = "#e41a1c", layout, drawLabels=TRUE, drawLegend=TRUE, highlightAttractor=TRUE, reverse = FALSE, borderColor = "black", eps=0.1, attractor.sep.lwd = 2, attractor.sep.col = "blue", ...) } \arguments{ \item{network}{ An object of class \code{BooleanNetwork} or \code{SymbolicBooleanNetwork} for which a sequence of state transitions is calculated } \item{startState}{ The start state of the sequence } \item{includeAttractorStates}{ Specifies whether the actual attractor states are included in the plot or not (see also \code{\link{getPathToAttractor}}). If \code{includeAttractorStates = "all"} (which is the default behaviour), the sequence ends when the attractor was traversed once. If \code{includeAttractorStates = "first"}, only the first state of attractor is added to the sequence. If {includeAttractorStates = "none"}, the sequence ends with the last non-attractor state. } \item{sequence}{ The alternative call to \code{plotSequence} requires the specification of the sequence itself instead of the network and the start state. The sequence must be provided as a data frame with the genes in the columns and the successive states in the rows. For example, sequences can be obtained using \code{\link{getPathToAttractor}} or \code{\link{getAttractorSequence}} (however, the specialized plot \code{\link{plotAttractors}} exists for attractors).} \item{title}{ An optional title for the plot } \item{mode}{Switches between two kinds of attractor plots. See Details for more information. Default is "table".} \item{plotFixed}{This optional parameter is only used if \code{mode="table"}. If this is true, genes with fixed values are included in the plot. Otherwise, these genes are not drawn. } \item{grouping}{This optional parameter is only used if \code{mode="table"} and specifies a structure to form groups of genes in the plot. This is a list with the following elements: \describe{ \item{class}{A vector of names for the groups. These names will be printed in the region belonging to the group in the plot.} \item{index}{A list with the same length as \code{class}. Each element is a vector of gene names or gene indices belonging to the group.}} } \item{onColor}{This optional parameter is only used if \code{mode="table"} and specifies the color value for the 1/ON values in the table. Defaults to green. } \item{offColor}{This optional parameter is only used if \code{mode="table"} and specifies the color value for the 0/OFF values in the table. Defaults to red. } \item{layout}{If \code{mode="graph"}, this parameter specifies a layouting function that determines the placement of the nodes in the graph. Please refer to the \code{\link[igraph]{layout}} manual entry in the \pkg{igraph} package for further details. By default, the nodes are placed in a horizontal line. } \item{drawLabels}{This parameter is only relevant if \code{mode="graph"}. It determines whether the nodes of the graph are annotated with the corresponding values of the genes in the attractor states. } \item{drawLegend}{Specifies whether a color key for the ON/OFF states is drawn if \code{mode="table"}. Defaults to \code{TRUE}. } \item{highlightAttractor}{ If set to true, the attractor states are highlighted in the plot. If \code{mode="table"}, a line is drawn at the begin of the attractor, and the states are labeled correspondingly. If \code{mode="graph"}, the attractor transitions are drawn as bold lines. Information on the attractor must be supplied in the attribute \code{attractor} of the sequence, which is a vector of indices of the states that belong to the attractor. This attribute is usually present if the sequence was obtained using \code{\link{getPathToAttractor}}. } \item{reverse}{ Specifies the order of the genes in the plot. By default, the first gene is placed in the first row of the plot. If \code{reverse=TRUE} (which was the default until \pkg{BoolNet} version 2.0.2), the first gene in the network is placed in the bottom row of the plot. } \item{borderColor}{ Specifies the border or seprating color of states in an attractor. Defaults to \code{"black"}. } \item{eps}{ Specifies plotting margin for the sequence of states. Defaults to \code{0.1}. } \item{attractor.sep.lwd}{ Specifies the line width of the attractor separator. Defaults to \code{2}. } \item{attractor.sep.col}{ Specifies the line color of the attractor separator. Defaults to \code{"blue"}. } \item{\dots}{ Further graphical parameters to be passed to \code{\link[igraph:plot.graph]{plot.igraph}} if \code{mode="graph"}. } } \details{ This function comprises two different types of plots: The "table" mode visualizes the gene values of the states in the sequence. The figure is a table with the genes in the rows and the successive states of the sequence in the columns. Cells of the table are (by default) red for 0/OFF values and green for 1/ON values. If \code{grouping} is set, the genes are rearranged according to the indices in the group, horizontal separation lines are plotted between the groups, and the group names are printed. The "graph" mode visualizes the transitions between different states. It creates a graph in which the vertices are the states in the sequence and the edges are state transitions among these states. The function can be called with different types of inputs: The user can specify the parameters \code{network}, \code{startState} and \code{includeAttractorStates}), in which case \code{\link{getPathToAttractor}} is called to obtain the sequence. Alternatively, the sequence can be supplied directly as a data frame in the \code{sequence} parameter. } \value{ If \code{mode="table"}, a matrix corresponding to the table is returned. The matrix has the genes in the rows and the states of the attractors in the columns. If \code{sequence} was supplied, this corresponds to the transposed input whose rows may be rearranged if \code{grouping} was set. If \code{mode="graph"}, an object of class \code{igraph} describing the graph for the sequence is returned. } \seealso{ \code{\link{sequenceToLaTeX}}, \code{\link{plotAttractors}}, \code{\link{attractorsToLaTeX}}, \code{\link{getPathToAttractor}}, \code{\link{getAttractorSequence}}, \code{\link{simulateSymbolicModel}} } \examples{ \dontrun{ # load example data data(cellcycle) # alternative 1: supply network and start state # and plot sequence as a table plotSequence(network=cellcycle, startState=rep(1,10), includeAttractorStates="all") # alternative 2: calculate sequence in advance sequence <- getPathToAttractor(cellcycle, state=rep(1,10), includeAttractorStates="all") # plot sequence as a graph plotSequence(sequence=sequence, mode="graph") } }BoolNet/man/plotAttractors.Rd0000644000176200001440000001561314302073154015710 0ustar liggesusers\name{plotAttractors} \Rdversion{1.1} \alias{plotAttractors} \title{ Plot state tables or transition graphs of attractors } \description{ Visualizes attractors, either by drawing a table of the involved states in two colors, or by drawing a graph of transitions between the states of the attractor. } \usage{ plotAttractors(attractorInfo, subset, title = "", mode = c("table","graph"), grouping = list(), plotFixed = TRUE, onColor = "#4daf4a", offColor = "#e41a1c", layout = layout.circle, drawLabels = TRUE, drawLegend = TRUE, ask = TRUE, reverse = FALSE, borderColor = "black", eps = 0.1, allInOnePlot = FALSE, ...) } \arguments{ \item{attractorInfo}{ An object of class \code{AttractorInfo}, as returned by \code{\link{getAttractors}}, or an object of class \code{SymbolicSimulation}, as returned by \code{\link{simulateSymbolicModel}}. } \item{subset}{An subset of attractors to be plotted. This is a vector of attractor indices in \code{attractorInfo}.} \item{title}{ An optional title for the plot } \item{mode}{Switches between two kinds of attractor plots. See Details for more information. Default is "table".} \item{grouping}{This optional parameter is only used if \code{mode="table"} and specifies a structure to form groups of genes in the plot. This is a list with the following elements: \describe{ \item{class}{A vector of names for the groups. These names will be printed in the region belonging to the group in the plot.} \item{index}{A list with the same length as \code{class}. Each element is a vector of gene names or gene indices belonging to the group.}} } \item{plotFixed}{This optional parameter is only used if \code{mode="table"}. If this is true, genes with fixed values are included in the plot. Otherwise, these genes are not drawn. } \item{onColor}{This optional parameter is only used if \code{mode="table"} and specifies the color value for the 1/ON values in the table. Defaults to green. } \item{offColor}{This optional parameter is only used if \code{mode="table"} and specifies the color value for the 0/OFF values in the table. Defaults to red. } \item{layout}{If \code{mode="graph"}, this parameter specifies a layouting function that determines the placement of the nodes in the graph. Please refer to the \code{\link[igraph]{layout}} manual entry in the \pkg{igraph} package for further details. By default, the circle layout is used. } \item{drawLabels}{This parameter is only relevant if \code{mode="graph"}. It determines whether the nodes of the graph are annotated with the corresponding values of the genes in the attractor states. } \item{drawLegend}{Specifies whether a color key for the ON/OFF states is drawn if \code{mode="table"}. Defaults to \code{TRUE}. } \item{ask}{ If set to true, the plot function will prompt for a user input for each new plot that is shown on an interactive device (see \code{link{par("ask")}}). } \item{reverse}{ Specifies the order of the genes in the plot. By default, the first gene is placed in the first row of the plot. If \code{reverse=TRUE} (which was the default until \pkg{BoolNet} version 2.0.2), the first gene in the network is placed in the bottom row of the plot. } \item{borderColor}{ Specifies the border or seprating color of states in an attractor. Defaults to \code{"black"}. } \item{eps}{ Specifies plotting margin for the sequence of states. Defaults to \code{0.1}. } \item{allInOnePlot}{ If this is \code{TRUE} then all attractors, with \code{mode = "table"}, are plotted in one plot as specified internally by \code{par$mfrow} parameter. Previous value of the \code{par$mfrow} parameter is preserved. Defaults to \code{FALSE}, meaning the plots for more than one attractor will be switched interactively or all plotted in an non-interactive graphical device. } \item{\dots}{ Further graphical parameters to be passed to \code{\link[igraph:plot.graph]{plot.igraph}} if \code{mode="graph"}. } } \details{ This function comprises two different types of plots: The "table" mode visualizes the gene values of the states in the attractor and is only suited for synchronous or steady-state attractors. Complex asynchronous attractors are omitted in this mode. Attractors in \code{attractorInfo} are first grouped by length. Then, a figure is plotted to the currently selected device for each attractor length (i.e. one plot with all attractors consisting of 1 state, one plot with all attractors consisting of 2 states, etc.). If \code{ask=TRUE} and the standard X11 output device is used, the user must confirm that the next plot for the next attractor size should be shown. The figure is a table with the genes in the rows and the states of the attractors in the columns. Cells of the table are (by default) red for 0/OFF values and green for 1/ON values. If \code{grouping} is set, the genes are rearranged according to the indices in the group, horizontal separation lines are plotted between the groups, and the group names are printed. The "graph" mode visualizes the transitions between different states. It creates a graph in which the vertices are the states in the attractor and the edges are state transitions among these states. This mode can visualize all kinds of attractors, including complex/loose attractors. One plot is drawn for each attractor. As before, this means that on the standard output device, only the last plot is displayed unless you set \code{par(mfrow=c(...))} accordingly. } \value{ If \code{mode="table"}, a list of matrices corresponding to the tables is returned. Each of these matrices has the genes in the rows and the states of the attractors in the columns. If \code{mode="graph"}, a list of objects of class \code{igraph} is returned. Each of these objects describes the graph for one attractor. } \seealso{ \code{\link{getAttractors}}, \code{\link{simulateSymbolicModel}}, \code{\link{attractorsToLaTeX}}, \code{\link{plotSequence}}, \code{\link{sequenceToLaTeX}} } \examples{ \dontrun{ # load example data data(cellcycle) # get attractors attractors <- getAttractors(cellcycle) # calculate number of different attractor lengths, # and plot attractors side by side in "table" mode par(mfrow=c(1, length(table(sapply(attractors$attractors, function(attractor) { length(attractor$involvedStates) }))))) plotAttractors(attractors) # plot attractors in "graph" mode par(mfrow=c(1, length(attractors$attractors))) plotAttractors(attractors, mode="graph") # identify asynchronous attractors attractors <- getAttractors(cellcycle, type="asynchronous") # plot attractors in "graph" mode par(mfrow=c(1, length(attractors$attractors))) plotAttractors(attractors, mode="graph") } }BoolNet/man/fixGenes.Rd0000644000176200001440000000263414302072646014437 0ustar liggesusers\name{fixGenes} \alias{fixGenes} \title{ Simulate knocked-out or over-expressed genes } \description{ Simulates knocked-out or over-expressed genes by fixing the values of genes to 0 or 1, or turn off knock-out or over-expression of genes. } \usage{ fixGenes(network, fixIndices, values) } \arguments{ \item{network}{ The original network of class \code{BooleanNetwork}, \if{latex}{\cr} \code{SymbolicBooleanNetwork} or \code{ProbabilisticBooleanNetwork} containing the genes to be fixed } \item{fixIndices}{ A vector of names or indices of the genes to be fixed } \item{values}{ Either one single value, or a vector with the same length as \code{fixIndices}. For each gene, a value of 1 means that the gene is always turned on (over-expressed), a value of 0 means that the gene is always turned off (knocked-out), and a value of -1 means that the gene is not fixed. } } \value{ Depending on the input, an object of class \code{BooleanNetwork}, \code{SymbolicBooleanNetwork} or \code{ProbabilisticBooleanNetwork} containing the fixed genes is returned. These classes are described in more detail in \code{\link{loadNetwork}}. } \seealso{ \code{\link{loadNetwork}}} \examples{ \dontrun{ # load example data data(cellcycle) # knock out gene CycD (index 1) net <- fixGenes(cellcycle, 1, 0) # or net <- fixGenes(cellcycle, "CycD", 0) # get attractors by exhaustive search attractors <- getAttractors(net) print(attractors) } }BoolNet/man/generateRandomNKNetwork.Rd0000644000176200001440000002110114302072665017414 0ustar liggesusers\name{generateRandomNKNetwork} \Rdversion{1.1} \alias{generateRandomNKNetwork} \title{ Generate a random N-K Boolean network } \description{ Generates a random N-K Boolean network (see Kauffman, 1969) using different configurations for the topology, the linkage, and the functions. } \usage{ generateRandomNKNetwork(n, k, topology = c("fixed", "homogeneous", "scale_free"), linkage = c("uniform", "lattice"), functionGeneration = c("uniform", "biased"), validationFunction, failureIterations=10000, simplify = FALSE, noIrrelevantGenes=TRUE, readableFunctions = FALSE, d_lattice = 1, zeroBias = 0.5, gamma = 2.5, approx_cutoff = 100) } \arguments{ \item{n}{ The total number of genes in the network } \item{k}{ If this is a single number, this is either the maximum number of genes in the input of a transition function (for \code{topology="fixed"} and \code{topology="scale_free"}) or the mean number of genes in the input of a function (for \code{topology="homogeneous"}). If \code{topology="fixed"}, this can also be a vector with \code{n} elements specifying the number of input genes for each gene separately. } \item{topology}{ If set to "fixed", all transition functions of the network depend on exactly \code{k} input genes (unless there are irrelevant input genes to be removed if \code{simplify=TRUE} and \code{noIrrelevantGenes=FALSE}). If set to "homogeneous", the number of input genes is drawn independently at random from a Poisson distribution with lambda = k. If set to "scale_free", the number of input genes of each function is drawn from a Zeta distribution with parameter \code{gamma}. } \item{linkage}{ If this parameter is "uniform", the actual input genes are drawn uniformly at random from the total \code{k} genes. If set to "lattice", only genes from the neighbourhood \if{latex}{\cr}\code{(i - d_lattice * k_i):(i + d_lattice * k_i)} are taken, which means that all genes are dependent from other genes in the direct neighbourhood. } \item{functionGeneration}{ This parameter specifies how the truth tables of the transition functions are generated. If set to "uniform", the truth table result column of the function is filled uniformly at random with 0 and 1. If set to "biased", a bias is introduced, where the probability of drawing a 0 is determined by the parameter \code{zeroBias}. As a third option, \code{functionGeneration} can be set to a user-defined function that generates the truth tables. This function must have a single parameter \code{input} that is supplied with a vector of input gene indices. It must return a binary vector of size \code{2^length(input)} corresponding to the result column of the truth table. For the generation of canalyzing and nested canalyzing functions that are often assumed to be biologically plausible, the generation functions \code{\link{generateCanalyzing}} and \code{\link{generateNestedCanalyzing}} are included in \pkg{BoolNet}. } \item{validationFunction}{ An optional function that restricts the generated Boolean functions to certain classes. This can be used if no explicit generation function can be specified in \code{functionGeneration}, but it is nevertheless possible to check whether a generated function belongs to that class or not. The function should have two input parameter \code{input} and \code{func} that receive a candidate function. \code{input} is a matrix of 0/1 integer values specifying the input part of the truth table of the candidate function, with the input genes in the columns. Each of the 2^k rows of \code{input} (where k is the number of input genes) corresponds to one entry of \code{func}, which is an integer vector of 0/1 values corresponding to the output of the candidate function. The validation function should return \code{TRUE} if the candidate function is accepted or \code{FALSE} if it is rejected. } \item{failureIterations}{ The maximum number of iterations the generator tries to generate a function that is accepted by \code{validationFunction} before it gives up and throws an error. Defaults to 10000. } \item{simplify}{ If this is true, \code{\link{simplifyNetwork}} is called to simplify the gene transition functions after the perturbation. This removes irrelevant input genes. Should not be used together with \code{noIrrelevantGenes=TRUE}, as this automatically generates a network that cannot be simplified any further. Defaults to FALSE. } \item{noIrrelevantGenes}{ If set to true, gene transition functions are not allowed to contain irrelevant genes, i.e. the functions have exactly the number of input genes determined by the \code{topology} method. This means that the network cannot be simplified any further, and \code{simplify} should be turned off. The default value is TRUE. } \item{readableFunctions}{ This parameter specifies if readable DNF representations of the transition function truth tables are generated and displayed when the network is printed. If set to FALSE, the truth table result column is displayed. If set to "canonical", a canonical Disjunctive Normal Form is generated from each truth table. If set to "short", the canonical DNF is minimized by joining terms (which can be time-consuming for functions with many inputs). If set to TRUE, a short DNF is generated for functions with up to 12 inputs, and a canonical DNF is generated for functions with more than 12 inputs. } \item{d_lattice}{ The dimension parameter for the lattice if \code{linkage="lattice"}. Defaults to 1. } \item{zeroBias}{ The bias parameter for biased functions for \code{functionGeneration="biased"}. Defaults to 0.5 (no bias). } \item{gamma}{ The Gamma parameter of the Zeta distribution for \code{topology="scale_free"}. Default is 2.5. } \item{approx_cutoff}{ This parameter is only used with \code{topology="scale_free"}. It sets the number of iterations in the sum used to approximate the Riemann Zeta function. Defaults to 100. } } \details{ The function supports a high number of different configurations to generate random networks. Several of the parameters are only needed for special configurations. The generated networks have different structural properties. Refer to the literature for more details. Constant genes are automatically fixed (e.g. knocked-out or over-expressed). This means that they are always set to the constant value, and states with the complementary value are not considered in transition tables etc. If you would like to change this behaviour, use \code{\link{fixGenes}} to reset the fixing. } \value{ An object of class \code{BooleanNetwork} containing the generated random network. The class \if{latex}{\cr}\code{BooleanNetwork} is described in more detail in \code{\link{loadNetwork}}. } \references{ S. A. Kauffman (1969), Metabolic stability and epigenesis in randomly constructed nets. J. Theor. Biol. 22:437--467. S. A. Kauffman (1993), The Origins of Order. Oxford University Press. M. Aldana (2003), Boolean dynamics of networks with scale-free topology. Physica D 185: 45--66. M. Aldana and S. Coppersmith and L. P. Kadanoff (2003), Boolean dynamics with random coupling. In E. Kaplan, J. E. Marsden and K. R. Sreenivasan (editors): Perspectives and Problems in Nonlinear Science, Springer. } \seealso{ \code{\link{perturbNetwork}},\code{\link{loadNetwork}}, \code{\link{simplifyNetwork}}, \code{\link{fixGenes}} } \examples{ \dontrun{ # generate different random networks net1 <- generateRandomNKNetwork(n=10, k=10, topology="scale_free", linkage="uniform", functionGeneration="uniform", noIrrelevantGenes=FALSE, simplify=TRUE) net2 <- generateRandomNKNetwork(n=10, k=3, topology="homogeneous", linkage="lattice", functionGeneration="uniform", d_lattice=1.5, simplify=TRUE) net3 <- generateRandomNKNetwork(n=10, k=2, topology="fixed", linkage="uniform", functionGeneration="biased", noIrrelevantGenes=FALSE, zeroBias=0.6) # get attractors print(getAttractors(net1)) print(getAttractors(net2)) print(getAttractors(net3)) } }BoolNet/man/getStateSummary.Rd0000644000176200001440000000405514302073020016007 0ustar liggesusers\name{getStateSummary} \Rdversion{1.1} \alias{getStateSummary} %- Also NEED an '\alias' for EACH other topic documented here. \title{ Retrieve summary information on a state } \description{ Returns information on the supplied state, i.e. the successive state after a transition, the (synchronous) attractor to which the state leads, and the distance to this attractor. } \usage{ getStateSummary(attractorInfo, state) } \arguments{ \item{attractorInfo}{ An object of class \code{AttractorInfo}, as returned by \code{\link{getAttractors}}, or of class \code{SymbolicSimulation}, as returned by \code{\link{simulateSymbolicModel}}. As the transition table information in this structure is required, \code{getAttractors} must be called in synchronous mode and with \code{returnTable} set to TRUE. Similarly, \code{simulateSymbolicModel} must be called with \code{returnGraph=TRUE}. } \item{state}{ A 0-1 vector with n elements (where n is the number of genes in the underlying networks) describing the state. } } \value{ Returns a generic dataframe of the class \code{TransitionTable}. For n genes, the first n columns code for the original state (in this case, the \code{state} parameter), i.e. each column represents the value of one gene. The next n columns code for the successive state after a transition. The column \code{attractorAssignment} indicates the attractor to the state is assigned. If this information is available, the column \code{stepsToAttractor} indicates how many transitions are needed from the original state to the attractor. In this case, the table has only one row describing the supplied state. The \code{TransitionTable} class supports pretty printing using the \code{\link{print}} method. } \seealso{ \code{\link{getBasinOfAttraction}}, \code{\link{getTransitionTable}}, \code{\link{getAttractors}}, \code{\link{simulateSymbolicModel}} } \examples{ \dontrun{ # load example data data(cellcycle) # get attractors attractors <- getAttractors(cellcycle) # print information for an arbitrary state print(getStateSummary(attractors, c(1,1,1,1,1,1,1,1,1,1))) } }BoolNet/man/binarizeTimeSeries.Rd0000644000176200001440000001322514272163616016466 0ustar liggesusers\name{binarizeTimeSeries} \alias{binarizeTimeSeries} \title{ Binarize a set of real-valued time series } \description{ Binarizes a set of real-valued time series using k-means clustering, edge detection, or scan statistics. } \usage{ binarizeTimeSeries(measurements, method = c("kmeans","edgeDetector","scanStatistic"), nstart = 100, iter.max = 1000, edge = c("firstEdge","maxEdge"), scaling = 1, windowSize = 0.25, sign.level = 0.1, dropInsignificant = FALSE) } \arguments{ \item{measurements}{ A list of matrices, each corresponding to one time series. Each row of these matrices contains real-valued measurements for one gene on a time line, i. e. column \code{i+1} contains the successor states of column \code{i+1}. The genes must be the same for all matrices in the list. } \item{method}{The employed binarization technique. "kmeans" uses k-means clustering for binarization. "edgeDetector" searches for a large gradient in the sorted measurements. "scanStatistic" searches for accumulations in the measurements. See Details for descriptions of the techniques.} \item{nstart}{ If \code{method="kmeans"}, this is the number of restarts for k-means. See \code{\link{kmeans}} for details. } \item{iter.max}{ If \code{method="kmeans"}, the maximum number of iterations for k-means. See \code{\link{kmeans}} for details. } \item{edge}{If \code{method="edgeDetector"}, this decides which of the edges is used as a threshold for binarization. If set to "firstEdge",the binarization threshold is the first combination of two successive sorted values whose difference exceeds a predefined value (average gradient * \code{scaling}). The parameter \code{scaling} can be used to adjust this value. If set to "maxEdge", the binarization threshold is the position of the edge with the overall highest gradient.} \item{scaling}{If \code{method="edgeDetector"} and \code{edge="firstEdge"}, this holds the scaling factor used for adjustment of the average gradient.} \item{windowSize}{If \code{method="scanStatistic"}, this specifies the size of the scanning window (see Details). The size is given as a fraction of the whole range of input values for a gene. Default is 0.25.} \item{sign.level}{If \code{method="scanStatistic"}, the significance level used for the scan statistic (see Details). } \item{dropInsignificant}{ If this is set to true, genes whose binarizations are insignificant in the scan statistic (see Details) are removed from the binarized time series. Otherwise, a warning is printed if such genes exist. } } \details{ This method supports three binarization techniques: \describe{ \item{k-means clustering}{For each gene, k-means clusterings are performed to determine a good separation of groups. The values belonging to the cluster with the smaller centroid are set to 0, and the values belonging to the greater centroid are set to 1.} \item{Edge detector}{This approach first sorts the measurements for each gene. In the sorted measurements, the algorithm searches for differences of two successive values that satisfy a predefined condition: If the "firstEdge" method was chosen, the pair of values whose difference exceeds the scaled average gradient of all values is chosen and used as maximum and minimum value of the two groups. If the "maxEdge" method was chosen, the largest difference between two successive values is taken. For details, see Shmulevich et al.} \item{Scan statistic}{The scan statistic assumes that the measurements for each gene are uniformly and independently distributed independently over a certain range. The scan statistic shifts a scanning window across the data and decides for each window position whether there is an unusual accumulation of data points based on an approximated test statistic (see Glaz et al.). The window with the smallest p-value is remembered. The boundaries of this window form two thresholds, from which the value that results in more balanced groups is taken for binarization. Depending on the supplied significance level, gene binarizations are rated according to the p-value of the chosen window.} } } \value{ Returns a list with the following elements: \item{binarizedMeasurements}{A list of matrices with the same structure as \code{measurements} containing the binarized time series measurements} \item{reject}{If \code{method="scanStatistic"}, a Boolean vector indicating for each gene whether the scan statistic algorithm was able to find a significant binarization window (FALSE) or not (TRUE). Rejected genes should probably be excluded from the data.} \item{thresholds}{The thresholds used for binarization} } \references{ I. Shmulevich and W. Zhang (2002), Binary analysis and optimization-based normalization of gene expression data. Bioinformatics 18(4):555--565. J. Glaz, J. Naus, S. Wallenstein (2001), Scan Statistics. New York: Springer. } \seealso{ \code{\link{reconstructNetwork}} } \examples{ # load test data data(yeastTimeSeries) # perform binarization with k-means bin <- binarizeTimeSeries(yeastTimeSeries) print(bin) # perform binarization with scan statistic # - will find and remove 2 insignificant genes! bin <- binarizeTimeSeries(yeastTimeSeries, method="scanStatistic", dropInsignificant=TRUE, sign.level=0.2) print(bin) # perform binarization with edge detector bin <- binarizeTimeSeries(yeastTimeSeries, method="edgeDetector") print(bin) # reconstruct a network from the data reconstructed <- reconstructNetwork(bin$binarizedMeasurements, method="bestfit", maxK=4) print(reconstructed) } BoolNet/man/print.MarkovSimulation.Rd0000644000176200001440000000226214272164061017322 0ustar liggesusers\name{print.MarkovSimulation} \alias{print.MarkovSimulation} \title{ Print the results of a Markov chain simulation } \description{ A specialized method to print an object of class \code{MarkovSimulation}. This prints all states that have a non-zero probability to be reached after the number of iterations in the Markov simulation. If the simulation was run with \code{returnTable=TRUE}, it also prints a table of state transitions and their probabilities to be chosen in a single step. } \usage{ \method{print}{MarkovSimulation}(x, activeOnly = FALSE, ...) } %- maybe also 'usage' for other objects documented here. \arguments{ \item{x}{ An object of class \code{MarkovSimulation} to be printed } \item{activeOnly}{ If set to true, a state is represented by a list of active genes (i.e., genes which are set to 1). If set to false, a state is represented by a binary vector with one entry for each gene, specifying whether the gene is active or not. Defaults to \code{FALSE}. } \item{\dots}{ Further parameters for the \code{\link{print}} method. Currently not used. } } \value{ Invisibly returns the printed object } \seealso{ \code{\link{print}}, \code{\link{markovSimulation}} } BoolNet/man/examplePBN.Rd0000644000176200001440000000156314272163643014666 0ustar liggesusers\name{examplePBN} \alias{examplePBN} \docType{data} \title{ An artificial probabilistic Boolean network } \description{ An artificial probabilistic Boolean network example introduced by Shmulevich et al. } \usage{data(examplePBN)} \details{ This artificial network is introduced by Shmulevich et al. for a step-by-step description of their Markov chain algorithm. It is included as a general example for a probabilistic Boolean network. The network consists of 3 genes, where gene 1 and gene 3 have two alternative transition functions, and gene 1 has a unique transition function. } \source{ I. Shmulevich, E. R. Dougherty, S. Kim, W. Zhang (2002), Probabilistic Boolean networks: a rule-based uncertainty model for gene regulatory networks. Bioinformatics 18(2):261--274. } \examples{ data(examplePBN) # the network is stored in a variable called 'examplePBN' print(examplePBN) }BoolNet/man/print.AttractorInfo.Rd0000644000176200001440000000225114272164052016573 0ustar liggesusers\name{print.AttractorInfo} \Rdversion{1.1} \alias{print.AttractorInfo} \title{ Print attractor cycles } \description{ Specialized print method to print the attractor cycles stored in an \code{AttractorInfo} object. For simple or steady-state attractors, the states of the attractors are printed in binary encoding in the order they are reached. For asynchronous complex/loose attractors, the possible transitions of the states in the attractor are printed. The method can print either the full states, or only the active genes of the states. } \usage{ \method{print}{AttractorInfo}(x, activeOnly = FALSE, ...) } \arguments{ \item{x}{ An object of class \code{AttractorInfo} to be printed } \item{activeOnly}{ If set to true, a state is represented by a list of active genes (i.e., genes which are set to 1). If set to false, a state is represented by a binary vector with one entry for each gene, specifying whether the gene is active or not. Defaults to \code{FALSE}. } \item{\dots}{ Further parameters for the \code{\link{print}} method. Currently not used. } } \value{ Invisibly returns the printed object } \seealso{ \code{\link{print}}, \code{\link{getAttractors}} }BoolNet/man/loadSBML.Rd0000644000176200001440000000342714302073075014262 0ustar liggesusers\name{loadSBML} \alias{loadSBML} \title{ Load an SBML document } \description{ Loads an SBML document that specifies a qualitative model using the \code{sbml-qual} extension package. } \usage{ loadSBML(file, symbolic=FALSE) } \arguments{ \item{file}{ The SBML document to be imported } \item{symbolic}{ If set to \code{TRUE}, the function returns an object of class \code{SymbolicBooleanNetwork} with an expression tree representation. Otherwise, it returns an object of class \code{BooleanNetwork} with a truth table representation. } } \details{ The import assumes an SBML level 3 version 1 document with the \code{sbml-qual} extension package version 1.0. \pkg{BoolNet} only supports a subset of the \code{sbml-qual} standard. The function tries to import those documents that describe a logical model with two possible values per species. It does not support general logical models with more than two values per species or Petri nets. Further details on the import: \itemize{ \item{The import supports multiple function terms with the same output for a transition and interprets them as a disjunction, as proposed in the specification.} \item{Comparison operators are converted to the corresponding Boolean expressions.} \item{Compartments are ignored.} } For the import, the \pkg{XML} package is required. } \value{ Returns a structure of class \code{BooleanNetwork} or \code{SymbolicBooleanNetwork}, as described in \code{\link{loadNetwork}}. } \references{ \url{http://sbml.org/Documents/Specifications/SBML_Level_3/Packages/Qualitative_Models_(qual)} } \seealso{ \code{\link{toSBML}}, \code{\link{loadNetwork}} } \examples{ \dontrun{ # load the cell cycle network data(cellcycle) fil <- tempfile() # export the network to SBML toSBML(cellcycle, fil) # reimport the model print(loadSBML(fil)) } }BoolNet/man/getAttractorSequence.Rd0000644000176200001440000000300414302072755017014 0ustar liggesusers\name{getAttractorSequence} \alias{getAttractorSequence} \title{ Decode the state sequence of a synchronous attractor } \description{ Obtains the sequence of states belonging to a single synchronous attractor from the encoded data in an \code{AttractorInfo} structure or in a \code{SymbolicSimulation} structure. } \usage{ getAttractorSequence(attractorInfo, attractorNo) } \arguments{ \item{attractorInfo}{ An object of class \code{AttractorInfo}, as returned by \code{\link{getAttractors}}, or of class \code{SymbolicSimulation}, as returned by \code{\link{simulateSymbolicModel}}. As the transition table information in this structure is required, \code{getAttractors} must be called in synchronous mode and with \code{returnTable} set to TRUE. Similarly, \code{simulateSymbolicModel} must be called with \code{returnGraph=TRUE}. } \item{attractorNo}{ The index of the attractor in \code{attractorInfo} whose state sequence should be obtained } } \value{ Returns a data frame with the genes in the columns. The rows are the successive states of the attractor. The successor state of the last state (i.e. the last row) is the first state (i.e. the first row). } \seealso{ \code{\link{getAttractors}}, \code{\link{simulateSymbolicModel}}, \code{\link{getPathToAttractor}}, \code{\link{plotSequence}}, \code{\link{sequenceToLaTeX}} } \examples{ \dontrun{ # load example data data(cellcycle) # get attractors attractors <- getAttractors(cellcycle) # print basin of 7-state attractor print(getAttractorSequence(attractors, 2)) } } BoolNet/man/truthTableToSymbolic.Rd0000644000176200001440000000305014302073344016777 0ustar liggesusers\name{truthTableToSymbolic} \alias{truthTableToSymbolic} \title{ Convert a network in truth table representation into a symbolic representation } \description{ Converts an object of class \code{BooleanNetwork} into an object of class \code{SymbolicBooleanNetwork} by generating symbolic expression trees. } \usage{ truthTableToSymbolic(network, generateDNFs = FALSE) } %- maybe also 'usage' for other objects documented here. \arguments{ \item{network}{ An object of class \code{BooleanNetwork} to be converted. } \item{generateDNFs}{ This parameter specifies whether formulae in Disjunctive Normal Form are generated instead of the parsing the string expressions that describe the transition functions. If set to FALSE, the original expressions are parsed. If set to "canonical", a canonical Disjunctive Normal Form is generated from each truth table. If set to "short", the canonical DNF is minimized by joining terms (which can be time-consuming for functions with many inputs). If set to TRUE, a short DNF is generated for functions with up to 12 inputs, and a canonical DNF is generated for functions with more than 12 inputs. } } \value{ Returns an object of class \code{SymbolicBooleanNetwork}, as described in \code{\link{loadNetwork}}. } \seealso{ \code{\link{truthTableToSymbolic}}, \code{\link{loadNetwork}} } \examples{ \dontrun{ # Convert a truth table representation into a # symbolic representation and back data(cellcycle) symbolicNet <- truthTableToSymbolic(cellcycle) print(symbolicNet) ttNet <- symbolicToTruthTable(symbolicNet) print(cellcycle) } }BoolNet/man/plotNetworkWiring.Rd0000644000176200001440000000375414274223004016375 0ustar liggesusers\name{plotNetworkWiring} \alias{plotNetworkWiring} \title{ Plot the wiring of a Boolean network } \description{ Plots the wiring of genes (i.e. the gene dependencies) of a synchronous or probabilistic Boolean network. The nodes of the graph are the genes, and the directed edges show the dependencies of the genes. This requires the \pkg{igraph} package. } \usage{ plotNetworkWiring(network, layout = layout.fruchterman.reingold, plotIt = TRUE, ...) } \arguments{ \item{network}{ A network structure of class \code{BooleanNetwork}, \code{SymbolicBooleanNetwork} or \code{ProbabilisticBooleanNetwork}. These networks can be read from files by \code{\link{loadNetwork}}, generated by \if{latex}{\cr}\code{\link{generateRandomNKNetwork}}, or reconstructed by \code{\link{reconstructNetwork}}. } \item{layout}{ A layouting function that determines the placement of the nodes in the graph. Please refer to the \code{\link[igraph]{layout}} manual entry in the \pkg{igraph} package for further details. By default, the Fruchterman-Reingold algorithm is used. } \item{plotIt}{ If this is true, a plot is generated. Otherwise, only an object of class \code{igraph} is returned, but no plot is drawn. } \item{\dots}{ Further graphical parameters to be passed to \code{\link[igraph:plot.graph]{plot.igraph}}. } } \details{ This function uses the \code{\link[igraph:plot.graph]{plot.igraph}} function from the \pkg{igraph} package. The plots are customizeable using the \code{\dots} argument. For details on possible parameters, please refer to \code{\link[igraph:plot.common]{igraph.plotting}}. } \value{ Returns an invisible object of class \code{igraph} containing the wiring graph. } \seealso{ \code{\link{loadNetwork}}, \code{\link{generateRandomNKNetwork}}, \code{\link{reconstructNetwork}}, \code{\link{plotStateGraph}}, \code{\link[igraph:plot.graph]{igraph.plotting}} } \examples{ \dontrun{ # load example data data(cellcycle) # plot wiring graph plotNetworkWiring(cellcycle) } }BoolNet/man/igf.Rd0000644000176200001440000000153314272163763013440 0ustar liggesusers\name{igf} \alias{igf} \docType{data} \title{ Boolean model of the IGF pathway } \description{ A small Boolean model of major components of the IGF (Insuline-like growth receptor) pathway. Through IRS, IGF activates the well-known PI3K-Akt-mTOR signalling cascade. This cascade is finally inactivated by a feedback inhibion of IRS. The model simplifies several complex formations and cascades by representing them as single nodes and specifying time delays instead. It therefore demonstrates the usage of temporal Boolean networks in \pkg{BoolNet}. } \usage{data(igf)} \format{ This data set consists of a variable \code{igf} of class \code{SymbolicBooleanNetwork} with 5 genes. The class \code{SymbolicBooleanNetwork} is described in more detail in \code{\link{loadNetwork}}. } \examples{ data(igf) sim <- simulateSymbolicModel(igf) plotAttractors(sim) }BoolNet/man/toPajek.Rd0000644000176200001440000000342414377064112014263 0ustar liggesusers\name{toPajek} \Rdversion{1.1} \alias{toPajek} \title{ Export a network to the Pajek file format } \description{ Exports a network to the Pajek file format to visualize transition trajectories. For more information on Pajek, please refer to \url{http://mrvar.fdv.uni-lj.si/pajek/} } \usage{ toPajek(stateGraph, file = "boolean.net", includeLabels=FALSE, ...) } \arguments{ \item{stateGraph}{ An object of class \code{AttractorInfo} or \code{SymbolicSimulation}, as returned by \code{\link{getAttractors}} and \code{\link{simulateSymbolicModel}} respectively. As the transition table information in this structure is required, \code{getAttractors} must be called in synchronous mode and with \code{returnTable} set to TRUE. Similarly, \code{simulateSymbolicModel} must be called with \code{returnGraph=TRUE}. Alternatively, \code{stateGraph} can be an object of class \code{TransitionTable}, which can be extracted using the functions \code{\link{getTransitionTable}}, \code{\link{getBasinOfAttraction}}, or \code{\link{getStateSummary}} . } \item{file}{ The name of the output file for Pajek. Defaults to "boolean.net". } \item{includeLabels}{ If set to true, the vertices of the graph in the output file are labeled with the binary encodings of the states. Defaults to FALSE. } \item{\dots}{ This is only for compatibility with previous versions and should not be used. } } \value{ This function has no return value. } \seealso{ \code{\link{getAttractors}}, \code{\link{simulateSymbolicModel}}, \code{\link{getTransitionTable}}, \code{\link{getBasinOfAttraction}}, \code{\link{getStateSummary}}, \code{\link{toSBML}} } \examples{ \dontrun{ # load example data data(cellcycle) # get attractors attractors <- getAttractors(cellcycle) # export to Pajek toPajek(attractors, file="pajek_export.net") } }BoolNet/man/loadBioTapestry.Rd0000644000176200001440000000374114506502316015772 0ustar liggesusers\name{loadBioTapestry} \alias{loadBioTapestry} \title{ Import a network from BioTapestry } \description{ Imports a Boolean network from a BioTapestry file (*.btp). BioTapestry is an interactive tool for building, visualizing, and simulating gene-regulatory networks, and can be accessed at \url{https://biotapestry.systemsbiology.net}. } \usage{ loadBioTapestry(file, symbolic = FALSE) } \arguments{ \item{file}{ The name of the file to import. This must be a BioTapestry XML file (*.btp). } \item{symbolic}{ If set to \code{TRUE}, the function returns an object of class \code{SymbolicBooleanNetwork} with an expression tree representation. Otherwise, it returns an object of class \code{BooleanNetwork} with a truth table representation. } } \details{ The function builds up a Boolean network by importing the nodes, the links between these nodes, and the simulation parameters of the top-level plot of a BioTapestry file. The BioTapestry network should have the following properties: \itemize{ \item All links should be either enhancers or repressors. Unspecified ("neutral") links are ignored. \item In the simulation parameters, each node should specify the correct logical function (AND, OR, XOR) for its inputs. \item Constant genes can be generated by modeling a gene without any input link and setting the simulation parameter \code{initVal} to 0 or 1. } } \value{ A network of class \code{BooleanNetwork} or \code{SymbolicBooleanNetwork}, as described in \code{\link{loadNetwork}}. } \references{ W. J. R. Longabaugh, E. H. Davidson, H. Bolour (2005), Computational representation of developmental genetic regulatory networks. Developmental Biology 283(1):1--16. } \seealso{ \code{\link{loadNetwork}}, \code{\link{loadSBML}} } \examples{ # import the example BioTapestry file # included in the package vignette exampleFile <- system.file("doc/example.btp", package="BoolNet") net <- loadBioTapestry(exampleFile) # print the imported network print(net) }BoolNet/man/stateTransition.Rd0000644000176200001440000000715614302073276016066 0ustar liggesusers\name{stateTransition} \Rdversion{1.1} \alias{stateTransition} \title{ Perform a transition to the next state } \description{ Calculates the next state in a supplied network for a given current state } \usage{ stateTransition(network, state, type = c("synchronous","asynchronous","probabilistic"), geneProbabilities, chosenGene, chosenFunctions, timeStep = 0) } \arguments{ \item{network}{ A network structure of class \code{BooleanNetwork}, \code{SymbolicBooleanNetwork} or \code{ProbabilisticBooleanNetwork}. These networks can be read from files by \code{\link{loadNetwork}}, generated by \if{latex}{\cr}\code{\link{generateRandomNKNetwork}}, or reconstructed by \code{\link{reconstructNetwork}}. } \item{state}{ The current state of the network, encoded as a vector with one 0-1 element for each gene. If \code{network} is of class \code{SymbolicBooleanNetwork} and makes use of more than one predecessor state, this can also be a matrix with the genes in the columns and multiple predecessor states in the rows. } \item{type}{The type of transition to be performed. If set to "synchronous", all genes are updated using the corresponding transition functions. If set to "asynchronous", only one gene is updated. This gene is either chosen randomly or supplied in parameter \code{chosenGene}. If set to "probabilistic", one transition function is chosen for each gene, and the genes are updated synchronously. The functions are either chosen randomly depending on their probabilities, or they are supplied in parameter \code{chosenFunctions}. Default is "synchronous" for objects of class \code{BooleanNetwork} and \code{SymbolicBooleanNetwork}, and "probabilistic" for objects of class \code{ProbabilisticBooleanNetwork}.} \item{geneProbabilities}{An optional vector of probabilities for the genes if \code{type="asynchronous"}. By default, each gene has the same probability to be chosen for the next state transition. These probabilities can be modified by supplying a vector of probabilities for the genes which sums up to one.} \item{chosenGene}{If \code{type="asynchronous"} and this parameter is supplied, no random update is performed. Instead, the gene with the supplied name or index is chosen for the next transition.} \item{chosenFunctions}{If \code{type="probabilistic"}, this parameter can contain a set of function indices for each gene. In this case, transition functions are not chosen randomly, but the provided functions are used in the state transition.} \item{timeStep}{An optional parameter that specifies the current time step associated with \code{state}. This is only relevant for networks of class \code{SymbolicBooleanNetwork} that make use of time-dependent predicates (\code{timelt, timeis, timegt}). Otherwise, this parameter is ignored. } } \value{ The subsequent state of the network, encoded as a vector with one 0-1 element for each gene.} \seealso{ \code{\link{loadNetwork}}, \code{\link{generateRandomNKNetwork}}, \code{\link{generateState}} } \examples{ \dontrun{ # load example network data(cellcycle) # calculate a synchronous state transition print(stateTransition(cellcycle, c(1,1,1,1,1,1,1,1,1,1))) # calculate an asynchronous state transition of gene CycA print(stateTransition(cellcycle, c(1,1,1,1,1,1,1,1,1,1), type="asynchronous", chosenGene="CycA")) # load probabilistic network data(examplePBN) # perform a probabilistic state transition print(stateTransition(examplePBN, c(0,1,1), type="probabilistic")) } }BoolNet/man/perturbNetwork.Rd0000644000176200001440000000766714302074160015730 0ustar liggesusers\name{perturbNetwork} \Rdversion{1.1} \alias{perturbNetwork} %- Also NEED an '\alias' for EACH other topic documented here. \title{ Perturb a Boolean network randomly } \description{ Modifies a synchronous, asynchronous, or probabilistic Boolean network by randomly perturbing either the functions for single genes or the state transitions. Random perturbations can be employed to assess the stability of the network. } \usage{ perturbNetwork(network, perturb = c("functions","transitions"), method = c("bitflip","shuffle"), simplify = (perturb[1]!="functions"), readableFunctions = FALSE, excludeFixed = TRUE, maxNumBits = 1, numStates = max(1,2^length(network$genes)/100)) } \arguments{ \item{network}{ A network structure of class \code{BooleanNetwork} or \code{ProbabilisticBooleanNetwork}. These networks can be read from files by \code{\link{loadNetwork}}, generated by \if{latex}{\cr}\code{\link{generateRandomNKNetwork}}, or reconstructed by \code{\link{reconstructNetwork}}. } \item{perturb}{ If set to "functions", a transition function of a single gene is chosen at random and perturbed directly. This is the default mode. If set to "transitions", the transition table is generated, one or several state transitions are perturbed randomly, and the gene transition functions are rebuilt from the modified transition table. \code{perturb="transitions"} is only allowed for non-probabilistic networks of class \code{BooleanNetworks}. } \item{method}{ The perturbation method to be applied to the functions or transitions. "bitflip" randomly inverts one or several bits (depending on the value of \code{maxNumBits}). "shuffle" generates a random permutation of the positions in the function or state and rearranges the bits according to this permutation. } \item{simplify}{ If this is true, \code{\link{simplifyNetwork}} is called to simplify the gene transition functions after the perturbation. This removes irrelevant input genes. Defaults to TRUE if \code{perturb} is "transitions", and to FALSE otherwise. } \item{readableFunctions}{ If this is true, readable DNF representations of the truth tables of the functions are generated. These DNF are displayed when the network is printed. The DNF representations are not minimized and can thus be very long. If set to FALSE, the truth table result column is displayed. } \item{excludeFixed}{ Determines whether fixed variables can also be perturbed (if set to FALSE) or if they are excluded from the perturbation (if set to TRUE). Default is TRUE. } \item{maxNumBits}{ The maximum number of bits to be perturbed in one function or state. Defaults to 1. } \item{numStates}{ The number of state transitions to be perturbed if \code{perturb} is "transitions". Defaults to 1% of all states. } } \value{ Depending on the input, an object of class \code{BooleanNetwork} or \code{ProbabilisticBooleanNetwork} containing the perturbed copy of the original network is returned. The classes \code{BooleanNetwork} and \code{ProbabilisticBooleanNetwork} are described in more detail in \code{\link{loadNetwork}}. } \seealso{ \code{\link{loadNetwork}}, \code{\link{generateRandomNKNetwork}}, \code{\link{reconstructNetwork}}, \code{\link{simplifyNetwork}}} \examples{ \dontrun{ # load example data data(cellcycle) # perturb the network perturbedNet1 <- perturbNetwork(cellcycle, perturb="functions", method="shuffle") perturbedNet2 <- perturbNetwork(cellcycle, perturb="transitions", method="bitflip") # get attractors print(getAttractors(perturbedNet1)) print(getAttractors(perturbedNet2)) } } \references{ Y. Xiao and E. R. Dougherty (2007), The impact of function perturbations in Boolean networks. Bioinformatics 23(10):1265--1273. I. Shmulevich, E. R. Dougherty, W. Zhang (2002), Control of stationary behavior in probabilistic Boolean networks by means of structural intervention. Journal of Biological Systems 10(4):431--445. } BoolNet/man/getTransitionTable.Rd0000644000176200001440000000414614302073043016461 0ustar liggesusers\name{getTransitionTable} \Rdversion{1.1} \alias{getTransitionTable} \title{ Retrieve the transition table of a network } \description{ Retrieves the transition table and additional attractor information of a network. } \usage{ getTransitionTable(attractorInfo) } \arguments{ \item{attractorInfo}{ An object of class \code{AttractorInfo}, as returned by \code{\link{getAttractors}}, or of class \code{SymbolicSimulation}, as returned by \code{\link{simulateSymbolicModel}}. As the transition table information in this structure is required, \code{getAttractors} must be called in synchronous mode and with \code{returnTable} set to TRUE. Similarly, \code{simulateSymbolicModel} must be called with \code{returnGraph=TRUE}. } } \details{ Depending on the configuration of the call to \code{getAttractors} or \code{simulateSymbolicModel} that returned \code{attractorInfo}, this function either returns the complete transition table (for exhaustive synchronous search) or the part of the transition table calculated in a heuristic synchronous search. Asynchronous search is not supported, as no transition table is calculated. } \value{ Returns a generic dataframe of the class \code{TransitionTable}. For n genes, the first n columns code for the original state (in this case, the \code{state} parameter), i.e. each column represents the value of one gene. The next n columns code for the successive state after a transition. The column \code{attractorAssignment} indicates the attractor to the state is assigned. If this information is available, the column \code{stepsToAttractor} indicates how many transitions are needed from the original state to the attractor. The table has a row for each possible input state. The \code{TransitionTable} class supports pretty printing using the \code{\link{print}} method. } \seealso{ \code{\link{getStateSummary}}, \code{\link{getBasinOfAttraction}}, \code{\link{getAttractors}}, \code{\link{simulateSymbolicModel}} } \examples{ \dontrun{ # load example data data(cellcycle) # get attractors attractors <- getAttractors(cellcycle) # print the transition table print(getTransitionTable(attractors)) } }BoolNet/DESCRIPTION0000644000176200001440000000244514506551754013343 0ustar liggesusersPackage: BoolNet Type: Package Title: Construction, Simulation and Analysis of Boolean Networks Version: 2.1.9 Date: 2023-10-02 Authors@R: c(person("Christoph", "Müssel", role = "aut"), person("Martin", "Hopfensitz", role = "aut"), person("Dao", "Zhou", role = "aut"), person(c("Hans", "A."), "Kestler", email = "hans.kestler@uni-ulm.de", role = c("aut", "cre")), person("Armin", "Biere", role = "ctb", comment="contributed PicoSAT code"), person(c("Troy", "D."), "Hanson", role = "ctb", comment="contributed uthash macros")) Imports: igraph (>= 0.6), XML Description: Functions to reconstruct, generate, and simulate synchronous, asynchronous, probabilistic, and temporal Boolean networks. Provides also functions to analyze and visualize attractors in Boolean networks . License: Artistic-2.0 LazyLoad: yes ByteCompile: TRUE Encoding: UTF-8 NeedsCompilation: yes Packaged: 2023-10-02 08:56:07 UTC; julian_schwab Author: Christoph Müssel [aut], Martin Hopfensitz [aut], Dao Zhou [aut], Hans A. Kestler [aut, cre], Armin Biere [ctb] (contributed PicoSAT code), Troy D. Hanson [ctb] (contributed uthash macros) Maintainer: Hans A. Kestler Repository: CRAN Date/Publication: 2023-10-02 14:30:04 UTC BoolNet/build/0000755000176200001440000000000014506502645012722 5ustar liggesusersBoolNet/build/vignette.rds0000644000176200001440000000037514506502645015266 0ustar liggesusersQMK1f!`Yz)Tʰ-id]˭+mTp`>ޛC"]ao $02wk> +շZWv'vf/[&OvDtw;?9F%> 3̨d ~aCP,2Y;$64\u --4Щ \ zL BoolNet/src/0000755000176200001440000000000014506502647012414 5ustar liggesusersBoolNet/src/picosat.c0000644000176200001440000050064214377113670014231 0ustar liggesusers/**************************************************************************** Copyright (c) 2006 - 2015, Armin Biere, Johannes Kepler University. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include #include #include #include #include #include #include #include #include "picosat.h" /* By default code for 'all different constraints' is disabled, since 'NADC' * is defined. */ #define NADC /* By default we enable failed literals, since 'NFL' is undefined. * #define NFL */ /* By default we 'detach satisfied (large) clauses', e.g. NDSC undefined. * #define NDSC */ /* Do not use luby restart schedule instead of inner/outer. * #define NLUBY */ /* Enabling this define, will use gnuplot to visualize how the scores evolve. * #define VISCORES */ #ifdef VISCORES // #define WRITEGIF /* ... to generate a video */ #endif #ifdef VISCORES #ifndef WRITEGIF #include /* for 'usleep' */ #endif #endif #ifndef NRCODE #include #endif #define MINRESTART 100 /* minimum restart interval */ #define MAXRESTART 1000000 /* maximum restart interval */ #define RDECIDE 1000 /* interval of random decisions */ #define FRESTART 110 /* restart increase factor in percent */ #define FREDUCE 110 /* reduce increase factor in percent */ #define FREDADJ 121 /* reduce increase adjustment factor */ #define MAXCILS 10 /* maximal number of unrecycled internals */ #define FFLIPPED 10000 /* flipped reduce factor */ #define FFLIPPEDPREC 10000000/* flipped reduce factor precision */ #define INTERRUPTLIM 1024 /* check interrupt after that many decisions */ #ifndef TRACE #define NO_BINARY_CLAUSES /* store binary clauses more compactly */ #endif /* For debugging purposes you may want to define 'LOGGING', which actually * can be enforced by using the '--log' option for the configure script. */ #ifdef LOGGING #define LOG(code) do { code; } while (0) #else #define LOG(code) do { } while (0) #endif #define NOLOG(code) do { } while (0) /* log exception */ #define ONLYLOG(code) do { code; } while (0) /* force logging */ #define FALSE ((Val)-1) #define UNDEF ((Val)0) #define TRUE ((Val)1) #define COMPACT_TRACECHECK_TRACE_FMT 0 #define EXTENDED_TRACECHECK_TRACE_FMT 1 #define RUP_TRACE_FMT 2 #define NEWN(p,n) do { (p) = new (ps, sizeof (*(p)) * (n)); } while (0) #define CLRN(p,n) do { memset ((p), 0, sizeof (*(p)) * (n)); } while (0) #define CLR(p) CLRN(p,1) #define DELETEN(p,n) \ do { delete (ps, p, sizeof (*(p)) * (n)); (p) = 0; } while (0) #define RESIZEN(p,old_num,new_num) \ do { \ size_t old_size = sizeof (*(p)) * (old_num); \ size_t new_size = sizeof (*(p)) * (new_num); \ (p) = resize (ps, (p), old_size, new_size) ; \ } while (0) #define ENLARGE(start,head,end) \ do { \ unsigned old_num = (ptrdiff_t)((end) - (start)); \ size_t new_num = old_num ? (2 * old_num) : 1; \ unsigned count = (head) - (start); \ assert ((start) <= (end)); \ RESIZEN((start),old_num,new_num); \ (head) = (start) + count; \ (end) = (start) + new_num; \ } while (0) #define NOTLIT(l) (ps->lits + (1 ^ ((l) - ps->lits))) #define LIT2IDX(l) ((ptrdiff_t)((l) - ps->lits) / 2) #define LIT2IMPLS(l) (ps->impls + (ptrdiff_t)((l) - ps->lits)) #define LIT2INT(l) ((int)(LIT2SGN(l) * LIT2IDX(l))) #define LIT2SGN(l) (((ptrdiff_t)((l) - ps->lits) & 1) ? -1 : 1) #define LIT2VAR(l) (ps->vars + LIT2IDX(l)) #define LIT2HTPS(l) (ps->htps + (ptrdiff_t)((l) - ps->lits)) #define LIT2JWH(l) (ps->jwh + ((l) - ps->lits)) #ifndef NDSC #define LIT2DHTPS(l) (ps->dhtps + (ptrdiff_t)((l) - ps->lits)) #endif #ifdef NO_BINARY_CLAUSES typedef uintptr_t Wrd; #define ISLITREASON(C) (1&(Wrd)C) #define LIT2REASON(L) \ (assert (L->val==TRUE), ((Cls*)(1 + (2*(L - ps->lits))))) #define REASON2LIT(C) ((Lit*)(ps->lits + ((Wrd)C)/2)) #endif #define ENDOFCLS(c) ((void*)((Lit**)(c)->lits + (c)->size)) #define SOC ((ps->oclauses == ps->ohead) ? ps->lclauses : ps->oclauses) #define EOC (ps->lhead) #define NXC(p) (((p) + 1 == ps->ohead) ? ps->lclauses : (p) + 1) #define OIDX2IDX(idx) (2 * ((idx) + 1)) #define LIDX2IDX(idx) (2 * (idx) + 1) #define ISLIDX(idx) ((idx)&1) #define IDX2OIDX(idx) (assert(!ISLIDX(idx)), (idx)/2 - 1) #define IDX2LIDX(idx) (assert(ISLIDX(idx)), (idx)/2) #define EXPORTIDX(idx) \ ((ISLIDX(idx) ? (IDX2LIDX (idx) + (ps->ohead - ps->oclauses)) : IDX2OIDX(idx)) + 1) #define IDX2CLS(i) \ (assert(i), (ISLIDX(i) ? ps->lclauses : ps->oclauses)[(i)/2 - !ISLIDX(i)]) #define IDX2ZHN(i) (assert(i), (ISLIDX(i) ? ps->zhains[(i)/2] : 0)) #define CLS2TRD(c) (((Trd*)(c)) - 1) #define CLS2IDX(c) ((((Trd*)(c)) - 1)->idx) #define CLS2ACT(c) \ ((Act*)((assert((c)->learned)),assert((c)->size>2),ENDOFCLS(c))) #define VAR2LIT(v) (ps->lits + 2 * ((v) - ps->vars)) #define VAR2RNK(v) (ps->rnks + ((v) - ps->vars)) #define RNK2LIT(r) (ps->lits + 2 * ((r) - ps->rnks)) #define RNK2VAR(r) (ps->vars + ((r) - ps->rnks)) #define BLK_FILL_BYTES 8 #define SIZE_OF_BLK (sizeof (Blk) - BLK_FILL_BYTES) #define PTR2BLK(void_ptr) \ ((void_ptr) ? (Blk*)(((char*)(void_ptr)) - SIZE_OF_BLK) : 0) #define AVERAGE(a,b) ((b) ? (((double)a) / (double)(b)) : 0.0) #define PERCENT(a,b) (100.0 * AVERAGE(a,b)) #ifndef NRCODE #define ABORT(msg) \ do { \ Rf_error(msg); \ } while (0) #else #define ABORT(msg) \ do { \ fputs ("*** picosat: " msg "\n", stderr); \ abort (); \ } while (0) #endif #define ABORTIF(cond,msg) \ do { \ if (!(cond)) break; \ ABORT (msg); \ } while (0) #define ZEROFLT (0x00000000u) #define EPSFLT (0x00000001u) #define INFFLT (0xffffffffu) #define FLTCARRY (1u << 25) #define FLTMSB (1u << 24) #define FLTMAXMANTISSA (FLTMSB - 1) #define FLTMANTISSA(d) ((d) & FLTMAXMANTISSA) #define FLTEXPONENT(d) ((int)((d) >> 24) - 128) #define FLTMINEXPONENT (-128) #define FLTMAXEXPONENT (127) #define CMPSWAPFLT(a,b) \ do { \ Flt tmp; \ if (((a) < (b))) \ { \ tmp = (a); \ (a) = (b); \ (b) = tmp; \ } \ } while (0) #define UNPACKFLT(u,m,e) \ do { \ (m) = FLTMANTISSA(u); \ (e) = FLTEXPONENT(u); \ (m) |= FLTMSB; \ } while (0) #define INSERTION_SORT_LIMIT 10 #define SORTING_SWAP(T,p,q) \ do { \ T tmp = *(q); \ *(q) = *(p); \ *(p) = tmp; \ } while (0) #define SORTING_CMP_SWAP(T,cmp,p,q) \ do { \ if ((cmp) (ps, *(p), *(q)) > 0) \ SORTING_SWAP (T, p, q); \ } while(0) #define QUICKSORT_PARTITION(T,cmp,a,l,r) \ do { \ T pivot; \ int j; \ i = (l) - 1; /* result in 'i' */ \ j = (r); \ pivot = (a)[j]; \ for (;;) \ { \ while ((cmp) (ps, (a)[++i], pivot) < 0) \ ; \ while ((cmp) (ps, pivot, (a)[--j]) < 0) \ if (j == (l)) \ break; \ if (i >= j) \ break; \ SORTING_SWAP (T, (a) + i, (a) + j); \ } \ SORTING_SWAP (T, (a) + i, (a) + (r)); \ } while(0) #define QUICKSORT(T,cmp,a,n) \ do { \ int l = 0, r = (n) - 1, m, ll, rr, i; \ assert (ps->ihead == ps->indices); \ if (r - l <= INSERTION_SORT_LIMIT) \ break; \ for (;;) \ { \ m = (l + r) / 2; \ SORTING_SWAP (T, (a) + m, (a) + r - 1); \ SORTING_CMP_SWAP (T, cmp, (a) + l, (a) + r - 1); \ SORTING_CMP_SWAP (T, cmp, (a) + l, (a) + r); \ SORTING_CMP_SWAP (T, cmp, (a) + r - 1, (a) + r); \ QUICKSORT_PARTITION (T, cmp, (a), l + 1, r - 1); \ if (i - l < r - i) \ { \ ll = i + 1; \ rr = r; \ r = i - 1; \ } \ else \ { \ ll = l; \ rr = i - 1; \ l = i + 1; \ } \ if (r - l > INSERTION_SORT_LIMIT) \ { \ assert (rr - ll > INSERTION_SORT_LIMIT); \ if (ps->ihead == ps->eoi) \ ENLARGE (ps->indices, ps->ihead, ps->eoi); \ *ps->ihead++ = ll; \ if (ps->ihead == ps->eoi) \ ENLARGE (ps->indices, ps->ihead, ps->eoi); \ *ps->ihead++ = rr; \ } \ else if (rr - ll > INSERTION_SORT_LIMIT) \ { \ l = ll; \ r = rr; \ } \ else if (ps->ihead > ps->indices) \ { \ r = *--ps->ihead; \ l = *--ps->ihead; \ } \ else \ break; \ } \ } while (0) #define INSERTION_SORT(T,cmp,a,n) \ do { \ T pivot; \ int l = 0, r = (n) - 1, i, j; \ for (i = r; i > l; i--) \ SORTING_CMP_SWAP (T, cmp, (a) + i - 1, (a) + i); \ for (i = l + 2; i <= r; i++) \ { \ j = i; \ pivot = (a)[i]; \ while ((cmp) (ps, pivot, (a)[j - 1]) < 0) \ { \ (a)[j] = (a)[j - 1]; \ j--; \ } \ (a)[j] = pivot; \ } \ } while (0) #ifdef NDEBUG #define CHECK_SORTED(cmp,a,n) do { } while(0) #else #define CHECK_SORTED(cmp,a,n) \ do { \ int i; \ for (i = 0; i < (n) - 1; i++) \ assert ((cmp) (ps, (a)[i], (a)[i + 1]) <= 0); \ } while(0) #endif #define SORT(T,cmp,a,n) \ do { \ T * aa = (a); \ int nn = (n); \ QUICKSORT (T, cmp, aa, nn); \ INSERTION_SORT (T, cmp, aa, nn); \ assert (ps->ihead == ps->indices); \ CHECK_SORTED (cmp, aa, nn); \ } while (0) #define WRDSZ (sizeof (long) * 8) #ifndef NRCODE #define picosat_fprintf(...) do { } while (0) #define picosat_vfprintf(...) do { } while (0) #define picosat_fputs(...) do { } while (0) #define picosat_fputc(...) do { } while (0) #else #define picosat_fprintf(file, fmt, ...) do { fprintf(file, fmt, ##__VA_ARGS__); } while (0) #define picosat_vfprintf(file, fmt, va_list) do { vfprintf(file, fmt, va_list); } while (0) #define picosat_fputs(str, file) do { fputs(str, file); } while (0) #define picosat_fputc(c, file) do { fputc(c, file); } while (0) #endif typedef unsigned Flt; /* 32 bit deterministic soft float */ typedef Flt Act; /* clause and variable activity */ typedef struct Blk Blk; /* allocated memory block */ typedef struct Cls Cls; /* clause */ typedef struct Lit Lit; /* literal */ typedef struct Rnk Rnk; /* variable to score mapping */ typedef signed char Val; /* TRUE, UNDEF, FALSE */ typedef struct Var Var; /* variable */ #ifdef TRACE typedef struct Trd Trd; /* trace data for clauses */ typedef struct Zhn Zhn; /* compressed chain (=zain) data */ typedef unsigned char Znt; /* compressed antecedent data */ #endif #ifdef NO_BINARY_CLAUSES typedef struct Ltk Ltk; struct Ltk { Lit ** start; unsigned count : WRDSZ == 32 ? 27 : 32; unsigned ldsize : WRDSZ == 32 ? 5 : 32; }; #endif struct Lit { Val val; }; struct Var { unsigned mark : 1; /*bit 1*/ unsigned resolved : 1; /*bit 2*/ unsigned phase : 1; /*bit 3*/ unsigned assigned : 1; /*bit 4*/ unsigned used : 1; /*bit 5*/ unsigned failed : 1; /*bit 6*/ unsigned internal : 1; /*bit 7*/ unsigned usedefphase : 1; /*bit 8*/ unsigned defphase : 1; /*bit 9*/ unsigned msspos : 1; /*bit 10*/ unsigned mssneg : 1; /*bit 11*/ unsigned humuspos : 1; /*bit 12*/ unsigned humusneg : 1; /*bit 13*/ unsigned partial : 1; /*bit 14*/ #ifdef TRACE unsigned core : 1; /*bit 15*/ #endif unsigned level; Cls *reason; #ifndef NADC Lit ** inado; Lit ** ado; Lit *** adotabpos; #endif }; struct Rnk { Act score; unsigned pos : 30; /* 0 iff not on heap */ unsigned moreimportant : 1; unsigned lessimportant : 1; }; struct Cls { unsigned size; unsigned collect:1; /* bit 1 */ unsigned learned:1; /* bit 2 */ unsigned locked:1; /* bit 3 */ unsigned used:1; /* bit 4 */ #ifndef NDEBUG unsigned connected:1; /* bit 5 */ #endif #ifdef TRACE unsigned collected:1; /* bit 6 */ unsigned core:1; /* bit 7 */ #endif #define LDMAXGLUE 25 /* 32 - 7 */ #define MAXGLUE ((1<= FLTCARRY) { if (e >= FLTMAXEXPONENT) return INFFLT; e++; m >>= 1; } } m &= ~FLTMSB; return packflt (m, e); } static Flt addflt (Flt a, Flt b) { unsigned ma, mb, delta; int ea, eb; CMPSWAPFLT (a, b); if (!b) return a; UNPACKFLT (a, ma, ea); UNPACKFLT (b, mb, eb); assert (ea >= eb); delta = ea - eb; if (delta < 32) mb >>= delta; else mb = 0; if (!mb) return a; ma += mb; if (ma & FLTCARRY) { if (ea == FLTMAXEXPONENT) return INFFLT; ea++; ma >>= 1; } assert (ma < FLTCARRY); ma &= FLTMAXMANTISSA; return packflt (ma, ea); } static Flt mulflt (Flt a, Flt b) { unsigned ma, mb; unsigned long long accu; int ea, eb; CMPSWAPFLT (a, b); if (!b) return ZEROFLT; UNPACKFLT (a, ma, ea); UNPACKFLT (b, mb, eb); ea += eb; ea += 24; if (ea > FLTMAXEXPONENT) return INFFLT; if (ea < FLTMINEXPONENT) return EPSFLT; accu = ma; accu *= mb; accu >>= 24; if (accu >= FLTCARRY) { if (ea == FLTMAXEXPONENT) return INFFLT; ea++; accu >>= 1; if (accu >= FLTCARRY) return INFFLT; } assert (accu < FLTCARRY); assert (accu & FLTMSB); ma = accu; ma &= ~FLTMSB; return packflt (ma, ea); } static Flt ascii2flt (const char *str) { Flt ten = base2flt (10, 0); Flt onetenth = base2flt (26843546, -28); Flt res = ZEROFLT, tmp, base; const char *p = str; char ch; ch = *p++; if (ch != '.') { if (!isdigit (ch)) return INFFLT; /* better abort ? */ res = base2flt (ch - '0', 0); while ((ch = *p++)) { if (ch == '.') break; if (!isdigit (ch)) return INFFLT; /* better abort? */ res = mulflt (res, ten); tmp = base2flt (ch - '0', 0); res = addflt (res, tmp); } } if (ch == '.') { ch = *p++; if (!isdigit (ch)) return INFFLT; /* better abort ? */ base = onetenth; tmp = mulflt (base2flt (ch - '0', 0), base); res = addflt (res, tmp); while ((ch = *p++)) { if (!isdigit (ch)) return INFFLT; /* better abort? */ base = mulflt (base, onetenth); tmp = mulflt (base2flt (ch - '0', 0), base); res = addflt (res, tmp); } } return res; } #if defined(VISCORES) static double flt2double (Flt f) { double res; unsigned m; int e, i; UNPACKFLT (f, m, e); res = m; if (e < 0) { for (i = e; i < 0; i++) res *= 0.5; } else { for (i = 0; i < e; i++) res *= 2.0; } return res; } #endif static int log2flt (Flt a) { return FLTEXPONENT (a) + 24; } static int cmpflt (Flt a, Flt b) { if (a < b) return -1; if (a > b) return 1; return 0; } static void * new (PS * ps, size_t size) { size_t bytes; Blk *b; if (!size) return 0; bytes = size + SIZE_OF_BLK; if (ps->enew) b = ps->enew (ps->emgr, bytes); else b = malloc (bytes); ABORTIF (!b, "out of memory in 'new'"); #ifndef NDEBUG b->header.size = size; #endif ps->current_bytes += size; if (ps->current_bytes > ps->max_bytes) ps->max_bytes = ps->current_bytes; return b->data; } static void delete (PS * ps, void *void_ptr, size_t size) { size_t bytes; Blk *b; if (!void_ptr) { assert (!size); return; } assert (size); b = PTR2BLK (void_ptr); assert (size <= ps->current_bytes); ps->current_bytes -= size; assert (b->header.size == size); bytes = size + SIZE_OF_BLK; if (ps->edelete) ps->edelete (ps->emgr, b, bytes); else free (b); } static void * resize (PS * ps, void *void_ptr, size_t old_size, size_t new_size) { size_t old_bytes, new_bytes; Blk *b; b = PTR2BLK (void_ptr); assert (old_size <= ps->current_bytes); ps->current_bytes -= old_size; if ((old_bytes = old_size)) { assert (old_size && b && b->header.size == old_size); old_bytes += SIZE_OF_BLK; } else assert (!b); if ((new_bytes = new_size)) new_bytes += SIZE_OF_BLK; if (ps->eresize) b = ps->eresize (ps->emgr, b, old_bytes, new_bytes); else b = realloc (b, new_bytes); if (!new_size) { assert (!b); return 0; } ABORTIF (!b, "out of memory in 'resize'"); #ifndef NDEBUG b->header.size = new_size; #endif ps->current_bytes += new_size; if (ps->current_bytes > ps->max_bytes) ps->max_bytes = ps->current_bytes; return b->data; } static unsigned int2unsigned (int l) { return (l < 0) ? 1 + 2 * -l : 2 * l; } static Lit * int2lit (PS * ps, int l) { return ps->lits + int2unsigned (l); } static Lit ** end_of_lits (Cls * c) { return (Lit**)c->lits + c->size; } #if !defined(NDEBUG) || defined(LOGGING) static void dumplits (PS * ps, Lit ** l, Lit ** end) { int first; Lit ** p; if (l == end) { /* empty clause */ } else if (l + 1 == end) { picosat_fprintf (ps->out, "%d ", LIT2INT (l[0])); } else { assert (l + 2 <= end); first = (abs (LIT2INT (l[0])) > abs (LIT2INT (l[1]))); picosat_fprintf (ps->out, "%d ", LIT2INT (l[first])); picosat_fprintf (ps->out, "%d ", LIT2INT (l[!first])); for (p = l + 2; p < end; p++) picosat_fprintf (ps->out, "%d ", LIT2INT (*p)); } picosat_fputc ('0', ps->out); } static void dumpcls (PS * ps, Cls * c) { Lit **end; if (c) { end = end_of_lits (c); dumplits (ps, c->lits, end); #ifdef TRACE if (ps->trace) picosat_fprintf (ps->out, " clause(%u)", CLS2IDX (c)); #endif } else picosat_fputs ("DECISION", ps->out); } static void dumpclsnl (PS * ps, Cls * c) { dumpcls (ps, c); picosat_fputc ('\n', ps->out); } void dumpcnf (PS * ps) { Cls **p, *c; for (p = SOC; p != EOC; p = NXC (p)) { c = *p; if (!c) continue; #ifdef TRACE if (c->collected) continue; #endif dumpclsnl (ps, *p); } } #endif static void delete_prefix (PS * ps) { if (!ps->prefix) return; delete (ps, ps->prefix, strlen (ps->prefix) + 1); ps->prefix = 0; } static void new_prefix (PS * ps, const char * str) { delete_prefix (ps); assert (str); ps->prefix = new (ps, strlen (str) + 1); strcpy (ps->prefix, str); } static PS * init (void * pmgr, picosat_malloc pnew, picosat_realloc presize, picosat_free pdelete) { PS * ps; #if 0 int count = 3 - !pnew - !presize - !pdelete; ABORTIF (count && !pnew, "API usage: missing 'picosat_set_new'"); ABORTIF (count && !presize, "API usage: missing 'picosat_set_resize'"); ABORTIF (count && !pdelete, "API usage: missing 'picosat_set_delete'"); #endif ps = pnew ? pnew (pmgr, sizeof *ps) : malloc (sizeof *ps); ABORTIF (!ps, "failed to allocate memory for PicoSAT manager"); memset (ps, 0, sizeof *ps); ps->emgr = pmgr; ps->enew = pnew; ps->eresize = presize; ps->edelete = pdelete; ps->size_vars = 1; ps->state = RESET; ps->defaultphase = JWLPHASE; #ifdef TRACE ps->ocore = -1; #endif ps->lastrheader = -2; #ifndef NADC ps->adoconflictlimit = UINT_MAX; #endif ps->min_flipped = UINT_MAX; NEWN (ps->lits, 2 * ps->size_vars); NEWN (ps->jwh, 2 * ps->size_vars); NEWN (ps->htps, 2 * ps->size_vars); #ifndef NDSC NEWN (ps->dhtps, 2 * ps->size_vars); #endif NEWN (ps->impls, 2 * ps->size_vars); NEWN (ps->vars, ps->size_vars); NEWN (ps->rnks, ps->size_vars); /* because '0' pos denotes not on heap */ ENLARGE (ps->heap, ps->hhead, ps->eoh); ps->hhead = ps->heap + 1; ps->vinc = base2flt (1, 0); /* initial var activity */ ps->ifvinc = ascii2flt ("1.05"); /* var score rescore factor */ #ifdef VISCORES ps->fvinc = ascii2flt ("0.9523809"); /* 1/f = 1/1.05 */ ps->nvinc = ascii2flt ("0.0476191"); /* 1 - 1/f = 1 - 1/1.05 */ #endif ps->lscore = base2flt (1, 90); /* var activity rescore limit */ ps->ilvinc = base2flt (1, -90); /* inverse of 'lscore' */ ps->cinc = base2flt (1, 0); /* initial clause activity */ ps->fcinc = ascii2flt ("1.001"); /* cls activity rescore factor */ ps->lcinc = base2flt (1, 90); /* cls activity rescore limit */ ps->ilcinc = base2flt (1, -90); /* inverse of 'ilcinc' */ ps->lreduceadjustcnt = ps->lreduceadjustinc = 100; ps->lpropagations = ~0ull; #ifdef NRCODE ps->out = stdout; #else ps->out = NULL; #endif new_prefix (ps, "c "); ps->verbosity = 0; ps->plain = 0; #ifdef NO_BINARY_CLAUSES memset (&ps->impl, 0, sizeof (ps->impl)); ps->impl.size = 2; memset (&ps->cimpl, 0, sizeof (ps->impl)); ps->cimpl.size = 2; #endif #ifdef VISCORES ps->fviscores = popen ( "/usr/bin/gnuplot -background black" " -xrm 'gnuplot*textColor:white'" " -xrm 'gnuplot*borderColor:white'" " -xrm 'gnuplot*axisColor:white'" , "w"); picosat_fprintf (ps->fviscores, "unset key\n"); // fprintf (ps->fviscores, "set log y\n"); fflush (ps->fviscores); system ("rm -rf /tmp/picosat-viscores"); system ("mkdir /tmp/picosat-viscores"); system ("mkdir /tmp/picosat-viscores/data"); #ifdef WRITEGIF system ("mkdir /tmp/picosat-viscores/gif"); picosat_fprintf (ps->fviscores, "set terminal gif giant animate opt size 1024,768 x000000 xffffff" "\n"); picosat_fprintf (ps->fviscores, "set output \"/tmp/picosat-viscores/gif/animated.gif\"\n"); #endif #endif ps->defaultphase = JWLPHASE; ps->state = READY; ps->last_sat_call_result = 0; return ps; } static size_t bytes_clause (PS * ps, unsigned size, unsigned learned) { size_t res; res = sizeof (Cls); res += size * sizeof (Lit *); res -= 2 * sizeof (Lit *); if (learned && size > 2) res += sizeof (Act); /* add activity */ #ifdef TRACE if (ps->trace) res += sizeof (Trd); /* add trace data */ #else (void) ps; #endif return res; } static Cls * new_clause (PS * ps, unsigned size, unsigned learned) { size_t bytes; void * tmp; #ifdef TRACE Trd *trd; #endif Cls *res; bytes = bytes_clause (ps, size, learned); tmp = new (ps, bytes); #ifdef TRACE if (ps->trace) { trd = tmp; if (learned) trd->idx = LIDX2IDX (ps->lhead - ps->lclauses); else trd->idx = OIDX2IDX (ps->ohead - ps->oclauses); res = trd->cls; } else #endif res = tmp; res->size = size; res->learned = learned; res->collect = 0; #ifndef NDEBUG res->connected = 0; #endif res->locked = 0; res->used = 0; #ifdef TRACE res->core = 0; res->collected = 0; #endif if (learned && size > 2) { Act * p = CLS2ACT (res); *p = ps->cinc; } return res; } static void delete_clause (PS * ps, Cls * c) { size_t bytes; #ifdef TRACE Trd *trd; #endif bytes = bytes_clause (ps, c->size, c->learned); #ifdef TRACE if (ps->trace) { trd = CLS2TRD (c); delete (ps, trd, bytes); } else #endif delete (ps, c, bytes); } static void delete_clauses (PS * ps) { Cls **p; for (p = SOC; p != EOC; p = NXC (p)) if (*p) delete_clause (ps, *p); DELETEN (ps->oclauses, ps->eoo - ps->oclauses); DELETEN (ps->lclauses, ps->EOL - ps->lclauses); ps->ohead = ps->eoo = ps->lhead = ps->EOL = 0; } #ifdef TRACE static void delete_zhain (PS * ps, Zhn * zhain) { const Znt *p, *znt; assert (zhain); znt = zhain->znt; for (p = znt; *p; p++) ; delete (ps, zhain, sizeof (Zhn) + (p - znt) + 1); } static void delete_zhains (PS * ps) { Zhn **p, *z; for (p = ps->zhains; p < ps->zhead; p++) if ((z = *p)) delete_zhain (ps, z); DELETEN (ps->zhains, ps->eoz - ps->zhains); ps->eoz = ps->zhead = 0; } #endif #ifdef NO_BINARY_CLAUSES static void lrelease (PS * ps, Ltk * stk) { if (stk->start) DELETEN (stk->start, (1 << (stk->ldsize))); memset (stk, 0, sizeof (*stk)); } #endif #ifndef NADC static unsigned llength (Lit ** a) { Lit ** p; for (p = a; *p; p++) ; return p - a; } static void resetadoconflict (PS * ps) { assert (ps->adoconflict); delete_clause (ps->adoconflict); ps->adoconflict = 0; } static void reset_ados (PS * ps) { Lit *** p; for (p = ps->ados; p < ps->hados; p++) DELETEN (*p, llength (*p) + 1); DELETEN (ps->ados, ps->eados - ps->ados); ps->hados = ps->eados = 0; DELETEN (ps->adotab, ps->szadotab); ps->szadotab = ps->nadotab = 0; if (ps->adoconflict) resetadoconflict (ps); ps->adoconflicts = 0; ps->adoconflictlimit = UINT_MAX; ps->adodisabled = 0; } #endif static void reset (PS * ps) { ABORTIF (!ps || ps->state == RESET, "API usage: reset without initialization"); delete_clauses (ps); #ifdef TRACE delete_zhains (ps); #endif #ifdef NO_BINARY_CLAUSES { unsigned i; for (i = 2; i <= 2 * ps->max_var + 1; i++) lrelease (ps, ps->impls + i); } #endif #ifndef NADC reset_ados (ps); #endif #ifndef NFL DELETEN (ps->saved, ps->saved_size); #endif DELETEN (ps->htps, 2 * ps->size_vars); #ifndef NDSC DELETEN (ps->dhtps, 2 * ps->size_vars); #endif DELETEN (ps->impls, 2 * ps->size_vars); DELETEN (ps->lits, 2 * ps->size_vars); DELETEN (ps->jwh, 2 * ps->size_vars); DELETEN (ps->vars, ps->size_vars); DELETEN (ps->rnks, ps->size_vars); DELETEN (ps->trail, ps->eot - ps->trail); DELETEN (ps->heap, ps->eoh - ps->heap); DELETEN (ps->als, ps->eoals - ps->als); DELETEN (ps->CLS, ps->eocls - ps->CLS); DELETEN (ps->rils, ps->eorils - ps->rils); DELETEN (ps->cils, ps->eocils - ps->cils); DELETEN (ps->fals, ps->eofals - ps->fals); DELETEN (ps->mass, ps->szmass); DELETEN (ps->mssass, ps->szmssass); DELETEN (ps->mcsass, ps->szmcsass); DELETEN (ps->humus, ps->szhumus); DELETEN (ps->added, ps->eoa - ps->added); DELETEN (ps->marked, ps->eom - ps->marked); DELETEN (ps->dfs, ps->eod - ps->dfs); DELETEN (ps->resolved, ps->eor - ps->resolved); DELETEN (ps->levels, ps->eolevels - ps->levels); DELETEN (ps->dused, ps->eodused - ps->dused); DELETEN (ps->buffer, ps->eob - ps->buffer); DELETEN (ps->indices, ps->eoi - ps->indices); DELETEN (ps->soclauses, ps->eoso - ps->soclauses); delete_prefix (ps); delete (ps, ps->rline[0], ps->szrline); delete (ps, ps->rline[1], ps->szrline); assert (getenv ("LEAK") || !ps->current_bytes); /* found leak if failing */ #ifdef VISCORES pclose (ps->fviscores); #endif if (ps->edelete) ps->edelete (ps->emgr, ps, sizeof *ps); else free (ps); } inline static void tpush (PS * ps, Lit * lit) { assert (ps->lits < lit && lit <= ps->lits + 2* ps->max_var + 1); if (ps->thead == ps->eot) { unsigned ttail2count = ps->ttail2 - ps->trail; unsigned ttailcount = ps->ttail - ps->trail; #ifndef NADC unsigned ttailadocount = ps->ttailado - ps->trail; #endif ENLARGE (ps->trail, ps->thead, ps->eot); ps->ttail = ps->trail + ttailcount; ps->ttail2 = ps->trail + ttail2count; #ifndef NADC ps->ttailado = ps->trail + ttailadocount; #endif } *ps->thead++ = lit; } static void assign_reason (PS * ps, Var * v, Cls * reason) { #if defined(NO_BINARY_CLAUSES) && !defined(NDEBUG) assert (reason != &ps->impl); #else (void) ps; #endif v->reason = reason; } static void assign_phase (PS * ps, Lit * lit) { unsigned new_phase, idx; Var * v = LIT2VAR (lit); #ifndef NFL /* In 'simplifying' mode we only need to keep 'min_flipped' up to date if * we force assignments on the top level. The other assignments will be * undone and thus we can keep the old saved value of the phase. */ if (!ps->LEVEL || !ps->simplifying) #endif { new_phase = (LIT2SGN (lit) > 0); if (v->assigned) { ps->sdflips -= ps->sdflips/FFLIPPED; if (new_phase != v->phase) { assert (FFLIPPEDPREC >= FFLIPPED); ps->sdflips += FFLIPPEDPREC / FFLIPPED; ps->flips++; idx = LIT2IDX (lit); if (idx < ps->min_flipped) ps->min_flipped = idx; NOLOG (picosat_fprintf (ps->out, "%sflipped %d\n", ps->prefix, LIT2INT (lit))); } } v->phase = new_phase; v->assigned = 1; } lit->val = TRUE; NOTLIT (lit)->val = FALSE; } inline static void assign (PS * ps, Lit * lit, Cls * reason) { Var * v = LIT2VAR (lit); assert (lit->val == UNDEF); #ifdef STATS ps->assignments++; #endif v->level = ps->LEVEL; assign_phase (ps, lit); assign_reason (ps, v, reason); tpush (ps, lit); } inline static int cmp_added (PS * ps, Lit * k, Lit * l) { Val a = k->val, b = l->val; Var *u, *v; int res; if (a == UNDEF && b != UNDEF) return -1; if (a != UNDEF && b == UNDEF) return 1; u = LIT2VAR (k); v = LIT2VAR (l); if (a != UNDEF) { assert (b != UNDEF); res = v->level - u->level; if (res) return res; /* larger level first */ } res = cmpflt (VAR2RNK (u)->score, VAR2RNK (v)->score); if (res) return res; /* smaller activity first */ return u - v; /* smaller index first */ } static void sorttwolits (Lit ** v) { Lit * a = v[0], * b = v[1]; assert (a != b); if (a < b) return; v[0] = b; v[1] = a; } inline static void sortlits (PS * ps, Lit ** v, unsigned size) { if (size == 2) sorttwolits (v); /* same order with and with out 'NO_BINARY_CLAUSES' */ else SORT (Lit *, cmp_added, v, size); } #ifdef NO_BINARY_CLAUSES static Cls * setimpl (PS * ps, Lit * a, Lit * b) { assert (!ps->implvalid); assert (ps->impl.size == 2); ps->impl.lits[0] = a; ps->impl.lits[1] = b; sorttwolits (ps->impl.lits); ps->implvalid = 1; return &ps->impl; } static void resetimpl (PS * ps) { ps->implvalid = 0; } static Cls * setcimpl (PS * ps, Lit * a, Lit * b) { assert (!ps->cimplvalid); assert (ps->cimpl.size == 2); ps->cimpl.lits[0] = a; ps->cimpl.lits[1] = b; sorttwolits (ps->cimpl.lits); ps->cimplvalid = 1; return &ps->cimpl; } static void resetcimpl (PS * ps) { assert (ps->cimplvalid); ps->cimplvalid = 0; } #endif static int cmp_ptr (PS * ps, void *l, void *k) { (void) ps; return ((char*)l) - (char*)k; /* arbitrarily already reverse */ } static int cmp_rnk (Rnk * r, Rnk * s) { if (!r->moreimportant && s->moreimportant) return -1; if (r->moreimportant && !s->moreimportant) return 1; if (!r->lessimportant && s->lessimportant) return 1; if (r->lessimportant && !s->lessimportant) return -1; if (r->score < s->score) return -1; if (r->score > s->score) return 1; return -cmp_ptr (0, r, s); } static void hup (PS * ps, Rnk * v) { int upos, vpos; Rnk *u; #ifndef NFL assert (!ps->simplifying); #endif vpos = v->pos; assert (0 < vpos); assert (vpos < ps->hhead - ps->heap); assert (ps->heap[vpos] == v); while (vpos > 1) { upos = vpos / 2; u = ps->heap[upos]; if (cmp_rnk (u, v) > 0) break; ps->heap[vpos] = u; u->pos = vpos; vpos = upos; } ps->heap[vpos] = v; v->pos = vpos; } static Cls *add_simplified_clause (PS *, int); inline static void add_antecedent (PS * ps, Cls * c) { assert (c); #ifdef NO_BINARY_CLAUSES if (ISLITREASON (c)) return; if (c == &ps->impl) return; #elif defined(STATS) && defined(TRACE) ps->antecedents++; #endif if (ps->rhead == ps->eor) ENLARGE (ps->resolved, ps->rhead, ps->eor); assert (ps->rhead < ps->eor); *ps->rhead++ = c; } #ifdef TRACE #ifdef NO_BINARY_CLAUSES #error "can not combine TRACE and NO_BINARY_CLAUSES" #endif #endif /* TRACE */ static void add_lit (PS * ps, Lit * lit) { assert (lit); if (ps->ahead == ps->eoa) ENLARGE (ps->added, ps->ahead, ps->eoa); *ps->ahead++ = lit; } static void push_var_as_marked (PS * ps, Var * v) { if (ps->mhead == ps->eom) ENLARGE (ps->marked, ps->mhead, ps->eom); *ps->mhead++ = v; } static void mark_var (PS * ps, Var * v) { assert (!v->mark); v->mark = 1; push_var_as_marked (ps, v); } #ifdef NO_BINARY_CLAUSES static Cls * impl2reason (PS * ps, Lit * lit) { Lit * other; Cls * res; other = ps->impl.lits[0]; if (lit == other) other = ps->impl.lits[1]; assert (other->val == FALSE); res = LIT2REASON (NOTLIT (other)); resetimpl (ps); return res; } #endif /* Whenever we have a top level derived unit we really should derive a unit * clause otherwise the resolutions in 'add_simplified_clause' become * incorrect. */ static Cls * resolve_top_level_unit (PS * ps, Lit * lit, Cls * reason) { unsigned count_resolved; Lit **p, **eol, *other; Var *u, *v; assert (ps->rhead == ps->resolved); assert (ps->ahead == ps->added); add_lit (ps, lit); add_antecedent (ps, reason); count_resolved = 1; v = LIT2VAR (lit); eol = end_of_lits (reason); for (p = reason->lits; p < eol; p++) { other = *p; u = LIT2VAR (other); if (u == v) continue; add_antecedent (ps, u->reason); count_resolved++; } /* Some of the literals could be assumptions. If at least one * variable is not an assumption, we should resolve. */ if (count_resolved >= 2) { #ifdef NO_BINARY_CLAUSES if (reason == &ps->impl) resetimpl (ps); #endif reason = add_simplified_clause (ps, 1); #ifdef NO_BINARY_CLAUSES if (reason->size == 2) { assert (reason == &ps->impl); reason = impl2reason (ps, lit); } #endif assign_reason (ps, v, reason); } else { ps->ahead = ps->added; ps->rhead = ps->resolved; } return reason; } static void fixvar (PS * ps, Var * v) { Rnk * r; assert (VAR2LIT (v) != UNDEF); assert (!v->level); ps->fixed++; r = VAR2RNK (v); r->score = INFFLT; #ifndef NFL if (ps->simplifying) return; #endif if (!r->pos) return; hup (ps, r); } static void use_var (PS * ps, Var * v) { if (v->used) return; v->used = 1; ps->vused++; } static void assign_forced (PS * ps, Lit * lit, Cls * reason) { Var *v; assert (reason); assert (lit->val == UNDEF); #ifdef STATS ps->FORCED++; #endif assign (ps, lit, reason); #ifdef NO_BINARY_CLAUSES assert (reason != &ps->impl); if (ISLITREASON (reason)) { reason = setimpl (ps, lit, NOTLIT (REASON2LIT (reason))); assert (reason); } #endif LOG ( picosat_fprintf (ps->out, "%sassign %d at level %d by ", ps->prefix, LIT2INT (lit), ps->LEVEL); dumpclsnl (ps, reason)); v = LIT2VAR (lit); if (!ps->LEVEL) use_var (ps, v); if (!ps->LEVEL && reason->size > 1) { reason = resolve_top_level_unit (ps, lit, reason); assert (reason); } #ifdef NO_BINARY_CLAUSES if (ISLITREASON (reason) || reason == &ps->impl) { /* DO NOTHING */ } else #endif { assert (!reason->locked); reason->locked = 1; if (reason->learned && reason->size > 2) ps->llocked++; } #ifdef NO_BINARY_CLAUSES if (reason == &ps->impl) resetimpl (ps); #endif if (!ps->LEVEL) fixvar (ps, v); } #ifdef NO_BINARY_CLAUSES static void lpush (PS * ps, Lit * lit, Cls * c) { int pos = (c->lits[0] == lit); Ltk * s = LIT2IMPLS (lit); unsigned oldsize, newsize; assert (c->size == 2); if (!s->start) { assert (!s->count); assert (!s->ldsize); NEWN (s->start, 1); } else { oldsize = (1 << (s->ldsize)); assert (s->count <= oldsize); if (s->count == oldsize) { newsize = 2 * oldsize; RESIZEN (s->start, oldsize, newsize); s->ldsize++; } } s->start[s->count++] = c->lits[pos]; } #endif static void connect_head_tail (PS * ps, Lit * lit, Cls * c) { Cls ** s; assert (c->size >= 1); if (c->size == 2) { #ifdef NO_BINARY_CLAUSES lpush (ps, lit, c); return; #else s = LIT2IMPLS (lit); #endif } else s = LIT2HTPS (lit); if (c->lits[0] != lit) { assert (c->size >= 2); assert (c->lits[1] == lit); c->next[1] = *s; } else c->next[0] = *s; *s = c; } #ifdef TRACE static void zpush (PS * ps, Zhn * zhain) { assert (ps->trace); if (ps->zhead == ps->eoz) ENLARGE (ps->zhains, ps->zhead, ps->eoz); *ps->zhead++ = zhain; } static int cmp_resolved (PS * ps, Cls * c, Cls * d) { #ifndef NDEBUG assert (ps->trace); #else (void) ps; #endif return CLS2IDX (c) - CLS2IDX (d); } static void bpushc (PS * ps, unsigned char ch) { if (ps->bhead == ps->eob) ENLARGE (ps->buffer, ps->bhead, ps->eob); *ps->bhead++ = ch; } static void bpushu (PS * ps, unsigned u) { while (u & ~0x7f) { bpushc (ps, u | 0x80); u >>= 7; } bpushc (ps, u); } static void bpushd (PS * ps, unsigned prev, unsigned this) { unsigned delta; assert (prev < this); delta = this - prev; bpushu (ps, delta); } static void add_zhain (PS * ps) { unsigned prev, this, count, rcount; Cls **p, *c; Zhn *res; assert (ps->trace); assert (ps->bhead == ps->buffer); assert (ps->rhead > ps->resolved); rcount = ps->rhead - ps->resolved; SORT (Cls *, cmp_resolved, ps->resolved, rcount); prev = 0; for (p = ps->resolved; p < ps->rhead; p++) { c = *p; this = CLS2TRD (c)->idx; bpushd (ps, prev, this); prev = this; } bpushc (ps, 0); count = ps->bhead - ps->buffer; res = new (ps, sizeof (Zhn) + count); res->core = 0; res->ref = 0; memcpy (res->znt, ps->buffer, count); ps->bhead = ps->buffer; #ifdef STATS ps->znts += count - 1; #endif zpush (ps, res); } #endif static void add_resolved (PS * ps, int learned) { #if defined(STATS) || defined(TRACE) Cls **p, *c; for (p = ps->resolved; p < ps->rhead; p++) { c = *p; if (c->used) continue; c->used = 1; if (c->size <= 2) continue; #ifdef STATS if (c->learned) ps->llused++; else ps->loused++; #endif } #endif #ifdef TRACE if (learned && ps->trace) add_zhain (ps); #else (void) learned; #endif ps->rhead = ps->resolved; } static void incjwh (PS * ps, Cls * c) { Lit **p, *lit, ** eol; Flt * f, inc, sum; unsigned size = 0; Var * v; Val val; eol = end_of_lits (c); for (p = c->lits; p < eol; p++) { lit = *p; val = lit->val; if (val && ps->LEVEL > 0) { v = LIT2VAR (lit); if (v->level > 0) val = UNDEF; } if (val == TRUE) return; if (val != FALSE) size++; } inc = base2flt (1, -size); for (p = c->lits; p < eol; p++) { lit = *p; f = LIT2JWH (lit); sum = addflt (*f, inc); *f = sum; } } static void write_rup_header (PS * ps, FILE * file) { char line[80]; int i; //sprintf (line, "%%RUPD32 %u %u", ps->rupvariables, ps->rupclauses); picosat_fputs (line, file); for (i = 255 - strlen (line); i >= 0; i--) picosat_fputc (' ', file); picosat_fputc ('\n', file); fflush (file); } static Cls * add_simplified_clause (PS * ps, int learned) { unsigned num_true, num_undef, num_false, size, count_resolved; Lit **p, **q, *lit, ** end; unsigned litlevel, glue; Cls *res, * reason; int reentered; Val val; Var *v; #if !defined(NDEBUG) && defined(TRACE) unsigned idx; #endif reentered = 0; REENTER: size = ps->ahead - ps->added; add_resolved (ps, learned); if (learned) { ps->ladded++; ps->llitsadded += size; if (size > 2) { ps->lladded++; ps->nlclauses++; ps->llits += size; } } else { ps->oadded++; if (size > 2) { ps->loadded++; ps->noclauses++; ps->olits += size; } } ps->addedclauses++; assert (ps->addedclauses == ps->ladded + ps->oadded); #ifdef NO_BINARY_CLAUSES if (size == 2) res = setimpl (ps, ps->added[0], ps->added[1]); else #endif { sortlits (ps, ps->added, size); if (learned) { if (ps->lhead == ps->EOL) { ENLARGE (ps->lclauses, ps->lhead, ps->EOL); /* A very difficult to find bug, which only occurs if the * learned clauses stack is immediately allocated before the * original clauses stack without padding. In this case, we * have 'SOC == EOC', which terminates all loops using the * idiom 'for (p = SOC; p != EOC; p = NXC(p))' immediately. * Unfortunately this occurred in 'fix_clause_lits' after * using a recent version of the memory allocator of 'Google' * perftools in the context of one large benchmark for * our SMT solver 'Boolector'. */ if (ps->EOL == ps->oclauses) ENLARGE (ps->lclauses, ps->lhead, ps->EOL); } #if !defined(NDEBUG) && defined(TRACE) idx = LIDX2IDX (ps->lhead - ps->lclauses); #endif } else { if (ps->ohead == ps->eoo) { ENLARGE (ps->oclauses, ps->ohead, ps->eoo); if (ps->EOL == ps->oclauses) ENLARGE (ps->oclauses, ps->ohead, ps->eoo); /* ditto */ } #if !defined(NDEBUG) && defined(TRACE) idx = OIDX2IDX (ps->ohead - ps->oclauses); #endif } assert (ps->EOL != ps->oclauses); /* ditto */ res = new_clause (ps, size, learned); glue = 0; if (learned) { assert (ps->dusedhead == ps->dused); for (p = ps->added; p < ps->ahead; p++) { lit = *p; if (lit->val) { litlevel = LIT2VAR (lit)->level; assert (litlevel <= ps->LEVEL); while (ps->levels + litlevel >= ps->levelshead) { if (ps->levelshead >= ps->eolevels) ENLARGE (ps->levels, ps->levelshead, ps->eolevels); assert (ps->levelshead < ps->eolevels); *ps->levelshead++ = 0; } if (!ps->levels[litlevel]) { if (ps->dusedhead >= ps->eodused) ENLARGE (ps->dused, ps->dusedhead, ps->eodused); assert (ps->dusedhead < ps->eodused); *ps->dusedhead++ = litlevel; ps->levels[litlevel] = 1; glue++; } } else glue++; } while (ps->dusedhead > ps->dused) { litlevel = *--ps->dusedhead; assert (ps->levels + litlevel < ps->levelshead); assert (ps->levels[litlevel]); ps->levels[litlevel] = 0; } } assert (glue <= MAXGLUE); res->glue = glue; #if !defined(NDEBUG) && defined(TRACE) if (ps->trace) assert (CLS2IDX (res) == idx); #endif if (learned) *ps->lhead++ = res; else *ps->ohead++ = res; #if !defined(NDEBUG) && defined(TRACE) if (ps->trace && learned) assert (ps->zhead - ps->zhains == ps->lhead - ps->lclauses); #endif assert (ps->lhead != ps->oclauses); /* ditto */ } if (learned && ps->rup) { if (!ps->rupstarted) { write_rup_header (ps, ps->rup); ps->rupstarted = 1; } } num_true = num_undef = num_false = 0; q = res->lits; for (p = ps->added; p < ps->ahead; p++) { lit = *p; *q++ = lit; if (learned && ps->rup) picosat_fprintf (ps->rup, "%d ", LIT2INT (lit)); val = lit->val; num_true += (val == TRUE); num_undef += (val == UNDEF); num_false += (val == FALSE); } assert (num_false + num_true + num_undef == size); if (learned && ps->rup) picosat_fputs ("0\n", ps->rup); ps->ahead = ps->added; /* reset */ if (!reentered) // TODO merge if (size > 0) { assert (size <= 2 || !reentered); // TODO remove connect_head_tail (ps, res->lits[0], res); if (size > 1) connect_head_tail (ps, res->lits[1], res); } if (size == 0) { if (!ps->mtcls) ps->mtcls = res; } #ifdef NO_BINARY_CLAUSES if (size != 2) #endif #ifndef NDEBUG res->connected = 1; #endif LOG ( picosat_fprintf (ps->out, "%s%s ", ps->prefix, learned ? "learned" : "original"); dumpclsnl (ps, res)); /* Shrink clause by resolving it against top level assignments. */ if (!ps->LEVEL && num_false > 0) { assert (ps->ahead == ps->added); assert (ps->rhead == ps->resolved); count_resolved = 1; add_antecedent (ps, res); end = end_of_lits (res); for (p = res->lits; p < end; p++) { lit = *p; v = LIT2VAR (lit); use_var (ps, v); if (lit->val == FALSE) { add_antecedent (ps, v->reason); count_resolved++; } else add_lit (ps, lit); } assert (count_resolved >= 2); learned = 1; #ifdef NO_BINARY_CLAUSES if (res == &ps->impl) resetimpl (ps); #endif reentered = 1; goto REENTER; /* and return simplified clause */ } if (!num_true && num_undef == 1) /* unit clause */ { lit = 0; for (p = res->lits; p < res->lits + size; p++) { if ((*p)->val == UNDEF) lit = *p; v = LIT2VAR (*p); use_var (ps, v); } assert (lit); reason = res; #ifdef NO_BINARY_CLAUSES if (size == 2) { Lit * other = res->lits[0]; if (other == lit) other = res->lits[1]; assert (other->val == FALSE); reason = LIT2REASON (NOTLIT (other)); } #endif assign_forced (ps, lit, reason); num_true++; } if (num_false == size && !ps->conflict) { #ifdef NO_BINARY_CLAUSES if (res == &ps->impl) ps->conflict = setcimpl (ps, res->lits[0], res->lits[1]); else #endif ps->conflict = res; } if (!learned && !num_true && num_undef) incjwh (ps, res); #ifdef NO_BINARY_CLAUSES if (res == &ps->impl) resetimpl (ps); #endif return res; } static int trivial_clause (PS * ps) { Lit **p, **q, *prev; Var *v; SORT (Lit *, cmp_ptr, ps->added, ps->ahead - ps->added); prev = 0; q = ps->added; for (p = q; p < ps->ahead; p++) { Lit *this = *p; v = LIT2VAR (this); if (prev == this) /* skip repeated literals */ continue; /* Top level satisfied ? */ if (this->val == TRUE && !v->level) return 1; if (prev == NOTLIT (this))/* found pair of dual literals */ return 1; *q++ = prev = this; } ps->ahead = q; /* shrink */ return 0; } static void simplify_and_add_original_clause (PS * ps) { #ifdef NO_BINARY_CLAUSES Cls * c; #endif if (trivial_clause (ps)) { ps->ahead = ps->added; if (ps->ohead == ps->eoo) ENLARGE (ps->oclauses, ps->ohead, ps->eoo); *ps->ohead++ = 0; ps->addedclauses++; ps->oadded++; } else { if (ps->CLS != ps->clshead) add_lit (ps, NOTLIT (ps->clshead[-1])); #ifdef NO_BINARY_CLAUSES c = #endif add_simplified_clause (ps, 0); #ifdef NO_BINARY_CLAUSES if (c == &ps->impl) assert (!ps->implvalid); #endif } } #ifndef NADC static void add_ado (PS * ps) { unsigned len = ps->ahead - ps->added; Lit ** ado, ** p, ** q, *lit; Var * v, * u; #ifdef TRACE assert (!ps->trace); #endif ABORTIF (ps->ados < ps->hados && llength (ps->ados[0]) != len, "internal: non matching all different constraint object lengths"); if (ps->hados == ps->eados) ENLARGE (ps->ados, ps->hados, ps->eados); NEWN (ado, len + 1); *hados++ = ado; p = ps->added; q = ado; u = 0; while (p < ps->ahead) { lit = *p++; v = LIT2VAR (lit); ABORTIF (v->inado, "internal: variable in multiple all different objects"); v->inado = ado; if (!u && !lit->val) u = v; *q++ = lit; } assert (q == ado + len); *q++ = 0; /* TODO simply do a conflict test as in propado */ ABORTIF (!u, "internal: " "adding fully instantiated all different object not implemented yet"); assert (u); assert (u->inado == ado); assert (!u->ado); u->ado = ado; ps->ahead = ps->added; } #endif static void hdown (PS * ps, Rnk * r) { unsigned end, rpos, cpos, opos; Rnk *child, *other; assert (r->pos > 0); assert (ps->heap[r->pos] == r); end = ps->hhead - ps->heap; rpos = r->pos; for (;;) { cpos = 2 * rpos; if (cpos >= end) break; opos = cpos + 1; child = ps->heap[cpos]; if (cmp_rnk (r, child) < 0) { if (opos < end) { other = ps->heap[opos]; if (cmp_rnk (child, other) < 0) { child = other; cpos = opos; } } } else if (opos < end) { child = ps->heap[opos]; if (cmp_rnk (r, child) >= 0) break; cpos = opos; } else break; ps->heap[rpos] = child; child->pos = rpos; rpos = cpos; } r->pos = rpos; ps->heap[rpos] = r; } static Rnk * htop (PS * ps) { assert (ps->hhead > ps->heap + 1); return ps->heap[1]; } static Rnk * hpop (PS * ps) { Rnk *res, *last; unsigned end; assert (ps->hhead > ps->heap + 1); res = ps->heap[1]; res->pos = 0; end = --ps->hhead - ps->heap; if (end == 1) return res; last = ps->heap[end]; ps->heap[last->pos = 1] = last; hdown (ps, last); return res; } inline static void hpush (PS * ps, Rnk * r) { assert (!r->pos); if (ps->hhead == ps->eoh) ENLARGE (ps->heap, ps->hhead, ps->eoh); r->pos = ps->hhead++ - ps->heap; ps->heap[r->pos] = r; hup (ps, r); } static void fix_trail_lits (PS * ps, long delta) { Lit **p; for (p = ps->trail; p < ps->thead; p++) *p += delta; } #ifdef NO_BINARY_CLAUSES static void fix_impl_lits (PS * ps, long delta) { Ltk * s; Lit ** p; for (s = ps->impls + 2; s <= ps->impls + 2 * ps->max_var + 1; s++) for (p = s->start; p < s->start + s->count; p++) *p += delta; } #endif static void fix_clause_lits (PS * ps, long delta) { Cls **p, *clause; Lit **q, *lit, **eol; for (p = SOC; p != EOC; p = NXC (p)) { clause = *p; if (!clause) continue; q = clause->lits; eol = end_of_lits (clause); while (q < eol) { assert (q - clause->lits <= (int) clause->size); lit = *q; lit += delta; *q++ = lit; } } } static void fix_added_lits (PS * ps, long delta) { Lit **p; for (p = ps->added; p < ps->ahead; p++) *p += delta; } static void fix_assumed_lits (PS * ps, long delta) { Lit **p; for (p = ps->als; p < ps->alshead; p++) *p += delta; } static void fix_cls_lits (PS * ps, long delta) { Lit **p; for (p = ps->CLS; p < ps->clshead; p++) *p += delta; } static void fix_heap_rnks (PS * ps, long delta) { Rnk **p; for (p = ps->heap + 1; p < ps->hhead; p++) *p += delta; } #ifndef NADC static void fix_ado (long delta, Lit ** ado) { Lit ** p; for (p = ado; *p; p++) *p += delta; } static void fix_ados (PS * ps, long delta) { Lit *** p; for (p = ps->ados; p < ps->hados; p++) fix_ado (delta, *p); } #endif static void enlarge (PS * ps, unsigned new_size_vars) { long rnks_delta, lits_delta; Lit *old_lits = ps->lits; Rnk *old_rnks = ps->rnks; RESIZEN (ps->lits, 2 * ps->size_vars, 2 * new_size_vars); RESIZEN (ps->jwh, 2 * ps->size_vars, 2 * new_size_vars); RESIZEN (ps->htps, 2 * ps->size_vars, 2 * new_size_vars); #ifndef NDSC RESIZEN (ps->dhtps, 2 * ps->size_vars, 2 * new_size_vars); #endif RESIZEN (ps->impls, 2 * ps->size_vars, 2 * new_size_vars); RESIZEN (ps->vars, ps->size_vars, new_size_vars); RESIZEN (ps->rnks, ps->size_vars, new_size_vars); if ((lits_delta = ps->lits - old_lits)) { fix_trail_lits (ps, lits_delta); fix_clause_lits (ps, lits_delta); fix_added_lits (ps, lits_delta); fix_assumed_lits (ps, lits_delta); fix_cls_lits (ps, lits_delta); #ifdef NO_BINARY_CLAUSES fix_impl_lits (ps, lits_delta); #endif #ifndef NADC fix_ados (ps, lits_delta); #endif } if ((rnks_delta = ps->rnks - old_rnks)) { fix_heap_rnks (ps, rnks_delta); } assert (ps->mhead == ps->marked); ps->size_vars = new_size_vars; } static void unassign (PS * ps, Lit * lit) { Cls *reason; Var *v; Rnk *r; assert (lit->val == TRUE); LOG ( picosat_fprintf (ps->out, "%sunassign %d\n", ps->prefix, LIT2INT (lit))); v = LIT2VAR (lit); reason = v->reason; #ifdef NO_BINARY_CLAUSES assert (reason != &ps->impl); if (ISLITREASON (reason)) { /* DO NOTHING */ } else #endif if (reason) { assert (reason->locked); reason->locked = 0; if (reason->learned && reason->size > 2) { assert (ps->llocked > 0); ps->llocked--; } } lit->val = UNDEF; NOTLIT (lit)->val = UNDEF; r = VAR2RNK (v); if (!r->pos) hpush (ps, r); #ifndef NDSC { Cls * p, * next, ** q; q = LIT2DHTPS (lit); p = *q; *q = 0; while (p) { Lit * other = p->lits[0]; if (other == lit) { other = p->lits[1]; q = p->next + 1; } else { assert (p->lits[1] == lit); q = p->next; } next = *q; *q = *LIT2HTPS (other); *LIT2HTPS (other) = p; p = next; } } #endif #ifndef NADC if (v->adotabpos) { assert (ps->nadotab); assert (*v->adotabpos == v->ado); *v->adotabpos = 0; v->adotabpos = 0; ps->nadotab--; } #endif } static Cls * var2reason (PS * ps, Var * var) { Cls * res = var->reason; #ifdef NO_BINARY_CLAUSES Lit * this, * other; if (ISLITREASON (res)) { this = VAR2LIT (var); if (this->val == FALSE) this = NOTLIT (this); other = REASON2LIT (res); assert (other->val == TRUE); assert (this->val == TRUE); res = setimpl (ps, NOTLIT (other), this); } #else (void) ps; #endif return res; } static void mark_clause_to_be_collected (Cls * c) { assert (!c->collect); c->collect = 1; } static void undo (PS * ps, unsigned new_level) { Lit *lit; Var *v; while (ps->thead > ps->trail) { lit = *--ps->thead; v = LIT2VAR (lit); if (v->level == new_level) { ps->thead++; /* fix pre decrement */ break; } unassign (ps, lit); } ps->LEVEL = new_level; ps->ttail = ps->thead; ps->ttail2 = ps->thead; #ifndef NADC ps->ttailado = ps->thead; #endif #ifdef NO_BINARY_CLAUSES if (ps->conflict == &ps->cimpl) resetcimpl (ps); #endif #ifndef NADC if (ps->conflict && ps->conflict == ps->adoconflict) resetadoconflict (ps); #endif ps->conflict = ps->mtcls; if (ps->LEVEL < ps->adecidelevel) { assert (ps->als < ps->alshead); ps->adecidelevel = 0; ps->alstail = ps->als; } LOG ( picosat_fprintf (ps->out, "%sback to level %u\n", ps->prefix, ps->LEVEL)); } #ifndef NDEBUG static int clause_satisfied (Cls * c) { Lit **p, **eol, *lit; eol = end_of_lits (c); for (p = c->lits; p < eol; p++) { lit = *p; if (lit->val == TRUE) return 1; } return 0; } static void original_clauses_satisfied (PS * ps) { Cls **p, *c; for (p = ps->oclauses; p < ps->ohead; p++) { c = *p; if (!c) continue; if (c->learned) continue; assert (clause_satisfied (c)); } } static void assumptions_satisfied (PS * ps) { Lit *lit, ** p; for (p = ps->als; p < ps->alshead; p++) { lit = *p; assert (lit->val == TRUE); } } #endif static void sflush (PS * ps) { double now = picosat_time_stamp (); double delta = now - ps->entered; delta = (delta < 0) ? 0 : delta; ps->seconds += delta; ps->entered = now; } static double mb (PS * ps) { return ps->current_bytes / (double) (1 << 20); } static double avglevel (PS * ps) { return ps->decisions ? ps->levelsum / ps->decisions : 0.0; } static void rheader (PS * ps) { assert (ps->lastrheader <= ps->reports); if (ps->lastrheader == ps->reports) return; ps->lastrheader = ps->reports; picosat_fprintf (ps->out, "%s\n", ps->prefix); picosat_fprintf (ps->out, "%s %s\n", ps->prefix, ps->rline[0]); picosat_fprintf (ps->out, "%s %s\n", ps->prefix, ps->rline[1]); picosat_fprintf (ps->out, "%s\n", ps->prefix); } static unsigned dynamic_flips_per_assignment_per_mille (PS * ps) { assert (FFLIPPEDPREC >= 1000); return ps->sdflips / (FFLIPPEDPREC / 1000); } #ifdef NLUBY static int high_agility (PS * ps) { return dynamic_flips_per_assignment_per_mille (ps) >= 200; } static int very_high_agility (PS * ps) { return dynamic_flips_per_assignment_per_mille (ps) >= 250; } #else static int medium_agility (PS * ps) { return dynamic_flips_per_assignment_per_mille (ps) >= 230; } #endif static void relemdata (PS * ps) { char *p; int x; if (ps->reports < 0) { /* strip trailing white space */ for (x = 0; x <= 1; x++) { p = ps->rline[x] + strlen (ps->rline[x]); while (p-- > ps->rline[x]) { if (*p != ' ') break; *p = 0; } } rheader (ps); } else picosat_fputc ('\n', ps->out); ps->RCOUNT = 0; } static void relemhead (PS * ps, const char * name, int fp, double val) { int x, y, len, size; const char *fmt; unsigned tmp, e; if (ps->reports < 0) { x = ps->RCOUNT & 1; y = (ps->RCOUNT / 2) * 12 + x * 6; // if (ps->RCOUNT == 1) // sprintf (ps->rline[1], "%6s", ""); len = strlen (name); while (ps->szrline <= len + y + 1) { size = ps->szrline ? 2 * ps->szrline : 128; ps->rline[0] = resize (ps, ps->rline[0], ps->szrline, size); ps->rline[1] = resize (ps, ps->rline[1], ps->szrline, size); ps->szrline = size; } fmt = (len <= 6) ? "%6s%10s" : "%-10s%4s"; // sprintf (ps->rline[x] + y, fmt, name, ""); } else if (val < 0) { assert (fp); if (val > -100 && (tmp = val * 10.0 - 0.5) > -1000.0) { picosat_fprintf (ps->out, "-%4.1f ", -tmp / 10.0); } else { tmp = -val / 10.0 + 0.5; e = 1; while (tmp >= 100) { tmp /= 10; e++; } picosat_fprintf (ps->out, "-%2ue%u ", tmp, e); } } else { if (fp && val < 1000 && (tmp = val * 10.0 + 0.5) < 10000) { picosat_fprintf (ps->out, "%5.1f ", tmp / 10.0); } else if (!fp && (tmp = val) < 100000) { picosat_fprintf (ps->out, "%5u ", tmp); } else { tmp = val / 10.0 + 0.5; e = 1; while (tmp >= 1000) { tmp /= 10; e++; } picosat_fprintf (ps->out, "%3ue%u ", tmp, e); } } ps->RCOUNT++; } inline static void relem (PS * ps, const char *name, int fp, double val) { if (name) relemhead (ps, name, fp, val); else relemdata (ps); } static unsigned reduce_limit_on_lclauses (PS * ps) { unsigned res = ps->lreduce; res += ps->llocked; return res; } static void report (PS * ps, int replevel, char type) { int rounds; if (ps->verbosity < replevel) return; sflush (ps); if (!ps->reports) ps->reports = -1; for (rounds = (ps->reports < 0) ? 2 : 1; rounds; rounds--) { if (ps->reports >= 0) picosat_fprintf (ps->out, "%s%c ", ps->prefix, type); relem (ps, "seconds", 1, ps->seconds); relem (ps, "level", 1, avglevel (ps)); assert (ps->fixed <= ps->max_var); relem (ps, "variables", 0, ps->max_var - ps->fixed); relem (ps, "used", 1, PERCENT (ps->vused, ps->max_var)); relem (ps, "original", 0, ps->noclauses); relem (ps, "conflicts", 0, ps->conflicts); // relem (ps, "decisions", 0, ps->decisions); // relem (ps, "conf/dec", 1, PERCENT(ps->conflicts,ps->decisions)); // relem (ps, "limit", 0, reduce_limit_on_lclauses (ps)); relem (ps, "learned", 0, ps->nlclauses); // relem (ps, "limit", 1, PERCENT (ps->nlclauses, reduce_limit_on_lclauses (ps))); relem (ps, "limit", 0, ps->lreduce); #ifdef STATS relem (ps, "learning", 1, PERCENT (ps->llused, ps->lladded)); #endif relem (ps, "agility", 1, dynamic_flips_per_assignment_per_mille (ps) / 10.0); // relem (ps, "original", 0, ps->noclauses); relem (ps, "MB", 1, mb (ps)); // relem (ps, "lladded", 0, ps->lladded); // relem (ps, "llused", 0, ps->llused); relem (ps, 0, 0, 0); ps->reports++; } /* Adapt this to the number of rows in your terminal. */ #define ROWS 25 if (ps->reports % (ROWS - 3) == (ROWS - 4)) rheader (ps); fflush (ps->out); } static int bcp_queue_is_empty (PS * ps) { if (ps->ttail != ps->thead) return 0; if (ps->ttail2 != ps->thead) return 0; #ifndef NADC if (ps->ttailado != ps->thead) return 0; #endif return 1; } static int satisfied (PS * ps) { assert (!ps->mtcls); assert (!ps->failed_assumption); if (ps->alstail < ps->alshead) return 0; assert (!ps->conflict); assert (bcp_queue_is_empty (ps)); return ps->thead == ps->trail + ps->max_var; /* all assigned */ } static void vrescore (PS * ps) { Rnk *p, *eor = ps->rnks + ps->max_var; for (p = ps->rnks + 1; p <= eor; p++) if (p->score != INFFLT) p->score = mulflt (p->score, ps->ilvinc); ps->vinc = mulflt (ps->vinc, ps->ilvinc);; #ifdef VISCORES ps->nvinc = mulflt (ps->nvinc, ps->lscore);; #endif } static void inc_score (PS * ps, Var * v) { Flt score; Rnk *r; #ifndef NFL if (ps->simplifying) return; #endif if (!v->level) return; if (v->internal) return; r = VAR2RNK (v); score = r->score; assert (score != INFFLT); score = addflt (score, ps->vinc); assert (score < INFFLT); r->score = score; if (r->pos > 0) hup (ps, r); if (score > ps->lscore) vrescore (ps); } static void inc_activity (PS * ps, Cls * c) { Act *p; if (!c->learned) return; if (c->size <= 2) return; p = CLS2ACT (c); *p = addflt (*p, ps->cinc); } static unsigned hashlevel (unsigned l) { return 1u << (l & 31); } static void push (PS * ps, Var * v) { if (ps->dhead == ps->eod) ENLARGE (ps->dfs, ps->dhead, ps->eod); *ps->dhead++ = v; } static Var * pop (PS * ps) { assert (ps->dfs < ps->dhead); return *--ps->dhead; } static void analyze (PS * ps) { unsigned open, minlevel, siglevels, l, old, i, orig; Lit *this, *other, **p, **q, **eol; Var *v, *u, **m, *start, *uip; Cls *c; assert (ps->conflict); assert (ps->ahead == ps->added); assert (ps->mhead == ps->marked); assert (ps->rhead == ps->resolved); /* First, search for First UIP variable and mark all resolved variables. * At the same time determine the minimum decision level involved. * Increase activities of resolved variables. */ q = ps->thead; open = 0; minlevel = ps->LEVEL; siglevels = 0; uip = 0; c = ps->conflict; for (;;) { add_antecedent (ps, c); inc_activity (ps, c); eol = end_of_lits (c); for (p = c->lits; p < eol; p++) { other = *p; if (other->val == TRUE) continue; assert (other->val == FALSE); u = LIT2VAR (other); if (u->mark) continue; u->mark = 1; inc_score (ps, u); use_var (ps, u); if (u->level == ps->LEVEL) { open++; } else { push_var_as_marked (ps, u); if (u->level) { /* The statistics counter 'nonminimizedllits' sums up the * number of literals that would be added if only the * 'first UIP' scheme for learned clauses would be used * and no clause minimization. */ ps->nonminimizedllits++; if (u->level < minlevel) minlevel = u->level; siglevels |= hashlevel (u->level); } else { assert (!u->level); assert (u->reason); } } } do { if (q == ps->trail) { uip = 0; goto DONE_FIRST_UIP; } this = *--q; uip = LIT2VAR (this); } while (!uip->mark); uip->mark = 0; c = var2reason (ps, uip); #ifdef NO_BINARY_CLAUSES if (c == &ps->impl) resetimpl (ps); #endif open--; if ((!open && ps->LEVEL) || !c) break; assert (c); } DONE_FIRST_UIP: if (uip) { assert (ps->LEVEL); this = VAR2LIT (uip); this += (this->val == TRUE); ps->nonminimizedllits++; ps->minimizedllits++; add_lit (ps, this); #ifdef STATS if (uip->reason) ps->uips++; #endif } else assert (!ps->LEVEL); /* Second, try to mark more intermediate variables, with the goal to * minimize the conflict clause. This is a DFS from already marked * variables backward through the implication graph. It tries to reach * other marked variables. If the search reaches an unmarked decision * variable or a variable assigned below the minimum level of variables in * the first uip learned clause or a level on which no variable has been * marked, then the variable from which the DFS is started is not * redundant. Otherwise the start variable is redundant and will * eventually be removed from the learned clause in step 4. We initially * implemented BFS, but then profiling revelead that this step is a bottle * neck for certain incremental applications. After switching to DFS this * hot spot went away. */ orig = ps->mhead - ps->marked; for (i = 0; i < orig; i++) { start = ps->marked[i]; assert (start->mark); assert (start != uip); assert (start->level < ps->LEVEL); if (!start->reason) continue; old = ps->mhead - ps->marked; assert (ps->dhead == ps->dfs); push (ps, start); while (ps->dhead > ps->dfs) { u = pop (ps); assert (u->mark); c = var2reason (ps, u); #ifdef NO_BINARY_CLAUSES if (c == &ps->impl) resetimpl (ps); #endif if (!c || ((l = u->level) && (l < minlevel || ((hashlevel (l) & ~siglevels))))) { while (ps->mhead > ps->marked + old) /* reset all marked */ (*--ps->mhead)->mark = 0; ps->dhead = ps->dfs; /* and DFS stack */ break; } eol = end_of_lits (c); for (p = c->lits; p < eol; p++) { v = LIT2VAR (*p); if (v->mark) continue; mark_var (ps, v); push (ps, v); } } } for (m = ps->marked; m < ps->mhead; m++) { v = *m; assert (v->mark); assert (!v->resolved); use_var (ps, v); c = var2reason (ps, v); if (!c) continue; #ifdef NO_BINARY_CLAUSES if (c == &ps->impl) resetimpl (ps); #endif eol = end_of_lits (c); for (p = c->lits; p < eol; p++) { other = *p; u = LIT2VAR (other); if (!u->level) continue; if (!u->mark) /* 'MARKTEST' */ break; } if (p != eol) continue; add_antecedent (ps, c); v->resolved = 1; } for (m = ps->marked; m < ps->mhead; m++) { v = *m; assert (v->mark); v->mark = 0; if (v->resolved) { v->resolved = 0; continue; } this = VAR2LIT (v); if (this->val == TRUE) this++; /* actually NOTLIT */ add_lit (ps, this); ps->minimizedllits++; } assert (ps->ahead <= ps->eoa); assert (ps->rhead <= ps->eor); ps->mhead = ps->marked; } static void fanalyze (PS * ps) { Lit ** eol, ** p, * lit; Cls * c, * reason; Var * v, * u; int next; double start = picosat_time_stamp (); assert (ps->failed_assumption); assert (ps->failed_assumption->val == FALSE); v = LIT2VAR (ps->failed_assumption); reason = var2reason (ps, v); if (!reason) return; #ifdef NO_BINARY_CLAUSES if (reason == &ps->impl) resetimpl (ps); #endif eol = end_of_lits (reason); for (p = reason->lits; p != eol; p++) { lit = *p; u = LIT2VAR (lit); if (u == v) continue; if (u->reason) break; } if (p == eol) return; assert (ps->ahead == ps->added); assert (ps->mhead == ps->marked); assert (ps->rhead == ps->resolved); next = 0; mark_var (ps, v); add_lit (ps, NOTLIT (ps->failed_assumption)); do { v = ps->marked[next++]; use_var (ps, v); if (v->reason) { reason = var2reason (ps, v); #ifdef NO_BINARY_CLAUSES if (reason == &ps->impl) resetimpl (ps); #endif add_antecedent (ps, reason); eol = end_of_lits (reason); for (p = reason->lits; p != eol; p++) { lit = *p; u = LIT2VAR (lit); if (u == v) continue; if (u->mark) continue; mark_var (ps, u); } } else { lit = VAR2LIT (v); if (lit->val == TRUE) lit = NOTLIT (lit); add_lit (ps, lit); } } while (ps->marked + next < ps->mhead); c = add_simplified_clause (ps, 1); v = LIT2VAR (ps->failed_assumption); reason = v->reason; #ifdef NO_BINARY_CLAUSES if (!ISLITREASON (reason)) #endif { assert (reason->locked); reason->locked = 0; if (reason->learned && reason->size > 2) { assert (ps->llocked > 0); ps->llocked--; } } #ifdef NO_BINARY_CLAUSES if (c == &ps->impl) { c = impl2reason (ps, NOTLIT (ps->failed_assumption)); } else #endif { assert (c->learned); assert (!c->locked); c->locked = 1; if (c->size > 2) { ps->llocked++; assert (ps->llocked > 0); } } v->reason = c; while (ps->mhead > ps->marked) (*--ps->mhead)->mark = 0; if (ps->verbosity) picosat_fprintf (ps->out, "%sfanalyze took %.1f seconds\n", ps->prefix, picosat_time_stamp () - start); } /* Propagate assignment of 'this' to 'FALSE' by visiting all binary clauses in * which 'this' occurs. */ inline static void prop2 (PS * ps, Lit * this) { #ifdef NO_BINARY_CLAUSES Lit ** l, ** start; Ltk * lstk; #else Cls * c, ** p; Cls * next; #endif Lit * other; Val tmp; assert (this->val == FALSE); #ifdef NO_BINARY_CLAUSES lstk = LIT2IMPLS (this); start = lstk->start; l = start + lstk->count; while (l != start) { /* The counter 'visits' is the number of clauses that are * visited during propagations of assignments. */ ps->visits++; #ifdef STATS ps->bvisits++; #endif other = *--l; tmp = other->val; if (tmp == TRUE) { #ifdef STATS ps->othertrue++; ps->othertrue2++; if (LIT2VAR (other)->level < ps->LEVEL) ps->othertrue2u++; #endif continue; } if (tmp != FALSE) { assign_forced (ps, other, LIT2REASON (NOTLIT(this))); continue; } if (ps->conflict == &ps->cimpl) resetcimpl (ps); ps->conflict = setcimpl (ps, this, other); } #else /* Traverse all binary clauses with 'this'. Head/Tail pointers for binary * clauses do not have to be modified here. */ p = LIT2IMPLS (this); for (c = *p; c; c = next) { ps->visits++; #ifdef STATS ps->bvisits++; #endif assert (!c->collect); #ifdef TRACE assert (!c->collected); #endif assert (c->size == 2); other = c->lits[0]; if (other == this) { next = c->next[0]; other = c->lits[1]; } else next = c->next[1]; tmp = other->val; if (tmp == TRUE) { #ifdef STATS ps->othertrue++; ps->othertrue2++; if (LIT2VAR (other)->level < ps->LEVEL) ps->othertrue2u++; #endif continue; } if (tmp == FALSE) ps->conflict = c; else assign_forced (ps, other, c); /* unit clause */ } #endif /* !defined(NO_BINARY_CLAUSES) */ } #ifndef NDSC static int should_disconnect_head_tail (PS * ps, Lit * lit) { unsigned litlevel; Var * v; assert (lit->val == TRUE); v = LIT2VAR (lit); litlevel = v->level; if (!litlevel) return 1; #ifndef NFL if (ps->simplifying) return 0; #endif return litlevel < ps->LEVEL; } #endif inline static void propl (PS * ps, Lit * this) { Lit **l, *other, *prev, *new_lit, **eol; Cls *next, **htp_ptr, **new_htp_ptr; Cls *c; #ifdef STATS unsigned size; #endif htp_ptr = LIT2HTPS (this); assert (this->val == FALSE); /* Traverse all non binary clauses with 'this'. Head/Tail pointers are * updated as well. */ for (c = *htp_ptr; c; c = next) { ps->visits++; #ifdef STATS size = c->size; assert (size >= 3); ps->traversals++; /* other is dereferenced at least */ if (size == 3) ps->tvisits++; else if (size >= 4) { ps->lvisits++; ps->ltraversals++; } #endif #ifdef TRACE assert (!c->collected); #endif assert (c->size > 0); other = c->lits[0]; if (other != this) { assert (c->size != 1); c->lits[0] = this; c->lits[1] = other; next = c->next[1]; c->next[1] = c->next[0]; c->next[0] = next; } else if (c->size == 1) /* With assumptions we need to * traverse unit clauses as well. */ { assert (!ps->conflict); ps->conflict = c; break; } else { assert (other == this && c->size > 1); other = c->lits[1]; next = c->next[0]; } assert (other == c->lits[1]); assert (this == c->lits[0]); assert (next == c->next[0]); assert (!c->collect); if (other->val == TRUE) { #ifdef STATS ps->othertrue++; ps->othertruel++; #endif #ifndef NDSC if (should_disconnect_head_tail (ps, other)) { new_htp_ptr = LIT2DHTPS (other); c->next[0] = *new_htp_ptr; *new_htp_ptr = c; #ifdef STATS ps->othertruelu++; #endif *htp_ptr = next; continue; } #endif htp_ptr = c->next; continue; } l = c->lits + 1; eol = (Lit**) c->lits + c->size; prev = this; while (++l != eol) { #ifdef STATS if (size >= 3) { ps->traversals++; if (size > 3) ps->ltraversals++; } #endif new_lit = *l; *l = prev; prev = new_lit; if (new_lit->val != FALSE) break; } if (l == eol) { while (l > c->lits + 2) { new_lit = *--l; *l = prev; prev = new_lit; } assert (c->lits[0] == this); assert (other == c->lits[1]); if (other->val == FALSE) /* found conflict */ { assert (!ps->conflict); ps->conflict = c; return; } assign_forced (ps, other, c); /* unit clause */ htp_ptr = c->next; } else { assert (new_lit->val == TRUE || new_lit->val == UNDEF); c->lits[0] = new_lit; // *l = this; new_htp_ptr = LIT2HTPS (new_lit); c->next[0] = *new_htp_ptr; *new_htp_ptr = c; *htp_ptr = next; } } } #ifndef NADC static unsigned primes[] = { 996293, 330643, 753947, 500873 }; #define PRIMES ((sizeof primes)/sizeof *primes) static unsigned hash_ado (Lit ** ado, unsigned salt) { unsigned i, res, tmp; Lit ** p, * lit; assert (salt < PRIMES); i = salt; res = 0; for (p = ado; (lit = *p); p++) { assert (lit->val); tmp = res >> 31; res <<= 1; if (lit->val > 0) res |= 1; assert (i < PRIMES); res *= primes[i++]; if (i == PRIMES) i = 0; res += tmp; } return res & (ps->szadotab - 1); } static unsigned cmp_ado (Lit ** a, Lit ** b) { Lit ** p, ** q, * l, * k; int res; for (p = a, q = b; (l = *p); p++, q++) { k = *q; assert (k); if ((res = (l->val - k->val))) return res; } assert (!*q); return 0; } static Lit *** find_ado (Lit ** ado) { Lit *** res, ** other; unsigned pos, delta; pos = hash_ado (ado, 0); assert (pos < ps->szadotab); res = ps->adotab + pos; other = *res; if (!other || !cmp_ado (other, ado)) return res; delta = hash_ado (ado, 1); if (!(delta & 1)) delta++; assert (delta & 1); assert (delta < ps->szadotab); for (;;) { pos += delta; if (pos >= ps->szadotab) pos -= ps->szadotab; assert (pos < ps->szadotab); res = ps->adotab + pos; other = *res; if (!other || !cmp_ado (other, ado)) return res; } } static void enlarge_adotab (PS * ps) { /* TODO make this generic */ ABORTIF (ps->szadotab, "internal: all different objects table needs larger initial size"); assert (!ps->nadotab); ps->szadotab = 10000; NEWN (ps->adotab, ps->szadotab); CLRN (ps->adotab, ps->szadotab); } static int propado (Var * v) { Lit ** p, ** q, *** adotabpos, **ado, * lit; Var * u; if (ps->level && ps->adodisabled) return 1; assert (!ps->conflict); assert (!ps->adoconflict); assert (VAR2LIT (v)->val != UNDEF); assert (!v->adotabpos); if (!v->ado) return 1; assert (v->inado); for (p = v->ado; (lit = *p); p++) if (lit->val == UNDEF) { u = LIT2VAR (lit); assert (!u->ado); u->ado = v->ado; v->ado = 0; return 1; } if (4 * ps->nadotab >= 3 * ps->szadotab) /* at least 75% filled */ enlarge_adotab (ps); adotabpos = find_ado (v->ado); ado = *adotabpos; if (!ado) { ps->nadotab++; v->adotabpos = adotabpos; *adotabpos = v->ado; return 1; } assert (ado != v->ado); ps->adoconflict = new_clause (2 * llength (ado), 1); q = ps->adoconflict->lits; for (p = ado; (lit = *p); p++) *q++ = lit->val == FALSE ? lit : NOTLIT (lit); for (p = v->ado; (lit = *p); p++) *q++ = lit->val == FALSE ? lit : NOTLIT (lit); assert (q == ENDOFCLS (ps->adoconflict)); ps->conflict = ps->adoconflict; ps->adoconflicts++; return 0; } #endif static void bcp (PS * ps) { int props = 0; assert (!ps->conflict); if (ps->mtcls) return; for (;;) { if (ps->ttail2 < ps->thead) /* prioritize implications */ { props++; prop2 (ps, NOTLIT (*ps->ttail2++)); } else if (ps->ttail < ps->thead) /* unit clauses or clauses with length > 2 */ { if (ps->conflict) break; propl (ps, NOTLIT (*ps->ttail++)); if (ps->conflict) break; } #ifndef NADC else if (ps->ttailado < ps->thead) { if (ps->conflict) break; propado (ps, LIT2VAR (*ps->ttailado++)); if (ps->conflict) break; } #endif else break; /* all assignments propagated, so break */ } ps->propagations += props; } static unsigned drive (PS * ps) { unsigned res, vlevel; Lit **p; Var *v; res = 0; for (p = ps->added; p < ps->ahead; p++) { v = LIT2VAR (*p); vlevel = v->level; assert (vlevel <= ps->LEVEL); if (vlevel < ps->LEVEL && vlevel > res) res = vlevel; } return res; } #ifdef VISCORES static void viscores (PS * ps) { Rnk *p, *eor = ps->rnks + ps->max_var; char name[100], cmd[200]; FILE * data; Flt s; int i; for (p = ps->rnks + 1; p <= ps->eor; p++) { s = p->score; if (s == INFFLT) continue; s = mulflt (s, ps->nvinc); assert (flt2double (s) <= 1.0); } //sprintf (name, "/tmp/picosat-viscores/data/%08u", ps->conflicts); //sprintf (cmd, "sort -n|nl>%s", name); data = popen (cmd, "w"); for (p = ps->rnks + 1; p <= ps->eor; p++) { s = p->score; if (s == INFFLT) continue; s = mulflt (s, ps->nvinc); picosat_fprintf (data, "%lf %d\n", 100.0 * flt2double (s), (int)(p - ps->rnks)); } fflush (data); pclose (data); for (i = 0; i < 8; i++) { // sprintf (cmd, "awk '$3%%8==%d' %s>%s.%d", i, name, name, i); system (cmd); } picosat_fprintf (ps->fviscores, "set title \"%u\"\n", ps->conflicts); picosat_fprintf (ps->fviscores, "plot [0:%u] 0, 100 * (1 - 1/1.1), 100", ps->max_var); for (i = 0; i < 8; i++) picosat_fprintf (ps->fviscores, ", \"%s.%d\" using 1:2:3 with labels tc lt %d", name, i, i + 1); picosat_fputc ('\n', ps->fviscores); fflush (ps->fviscores); #ifndef WRITEGIF usleep (50000); /* refresh rate of 20 Hz */ #endif } #endif static void crescore (PS * ps) { Cls **p, *c; Act *a; Flt factor; int l = log2flt (ps->cinc); assert (l > 0); factor = base2flt (1, -l); for (p = ps->lclauses; p != ps->lhead; p++) { c = *p; if (!c) continue; #ifdef TRACE if (c->collected) continue; #endif assert (c->learned); if (c->size <= 2) continue; a = CLS2ACT (c); *a = mulflt (*a, factor); } ps->cinc = mulflt (ps->cinc, factor); } static void inc_vinc (PS * ps) { #ifdef VISCORES ps->nvinc = mulflt (ps->nvinc, ps->fvinc); #endif ps->vinc = mulflt (ps->vinc, ps->ifvinc); } inline static void inc_max_var (PS * ps) { Lit *lit; Rnk *r; Var *v; assert (ps->max_var < ps->size_vars); if (ps->max_var + 1 == ps->size_vars) enlarge (ps, ps->size_vars + 2*(ps->size_vars + 3) / 4); /* +25% */ ps->max_var++; /* new index of variable */ assert (ps->max_var); /* no unsigned overflow */ assert (ps->max_var < ps->size_vars); lit = ps->lits + 2 * ps->max_var; lit[0].val = lit[1].val = UNDEF; memset (ps->htps + 2 * ps->max_var, 0, 2 * sizeof *ps->htps); #ifndef NDSC memset (ps->dhtps + 2 * ps->max_var, 0, 2 * sizeof *ps->dhtps); #endif memset (ps->impls + 2 * ps->max_var, 0, 2 * sizeof *ps->impls); memset (ps->jwh + 2 * ps->max_var, 0, 2 * sizeof *ps->jwh); v = ps->vars + ps->max_var; /* initialize variable components */ CLR (v); r = ps->rnks + ps->max_var; /* initialize rank */ CLR (r); hpush (ps, r); } static void force (PS * ps, Cls * c) { Lit ** p, ** eol, * lit, * forced; Cls * reason; forced = 0; reason = c; eol = end_of_lits (c); for (p = c->lits; p < eol; p++) { lit = *p; if (lit->val == UNDEF) { assert (!forced); forced = lit; #ifdef NO_BINARY_CLAUSES if (c == &ps->impl) reason = LIT2REASON (NOTLIT (p[p == c->lits ? 1 : -1])); #endif } else assert (lit->val == FALSE); } #ifdef NO_BINARY_CLAUSES if (c == &ps->impl) resetimpl (ps); #endif if (!forced) return; assign_forced (ps, forced, reason); } static void inc_lreduce (PS * ps) { #ifdef STATS ps->inclreduces++; #endif ps->lreduce *= FREDUCE; ps->lreduce /= 100; report (ps, 1, '+'); } static void backtrack (PS * ps) { unsigned new_level; Cls * c; ps->conflicts++; LOG ( picosat_fprintf (ps->out, "%sconflict ", ps->prefix); dumpclsnl (ps, ps->conflict)); analyze (ps); new_level = drive (ps); // TODO: why not? assert (new_level != 1 || (ps->ahead - ps->added) == 2); c = add_simplified_clause (ps, 1); undo (ps, new_level); force (ps, c); if ( #ifndef NFL !ps->simplifying && #endif !--ps->lreduceadjustcnt) { /* With FREDUCE==110 and FREDADJ=121 we stir 'lreduce' to be * proportional to 'sqrt(conflicts)'. In earlier version we actually * used 'FREDADJ=150', which results in 'lreduce' to approximate * 'conflicts^(log(1.1)/log(1.5))' which is close to the fourth root * of 'conflicts', since log(1.1)/log(1.5)=0.235 (as observed by * Donald Knuth). The square root is the same we get by a Glucose * style increase, which simply adds a constant at every reduction. * This would be way simpler to implement but for now we keep the more * complicated code using the adjust increments and counters. */ ps->lreduceadjustinc *= FREDADJ; ps->lreduceadjustinc /= 100; ps->lreduceadjustcnt = ps->lreduceadjustinc; inc_lreduce (ps); } if (ps->verbosity >= 4 && !(ps->conflicts % 1000)) report (ps, 4, 'C'); } static void inc_cinc (PS * ps) { ps->cinc = mulflt (ps->cinc, ps->fcinc); if (ps->lcinc < ps->cinc) crescore (ps); } static void incincs (PS * ps) { inc_vinc (ps); inc_cinc (ps); #ifdef VISCORES viscores (ps); #endif } static void disconnect_clause (PS * ps, Cls * c) { assert (c->connected); if (c->size > 2) { if (c->learned) { assert (ps->nlclauses > 0); ps->nlclauses--; assert (ps->llits >= c->size); ps->llits -= c->size; } else { assert (ps->noclauses > 0); ps->noclauses--; assert (ps->olits >= c->size); ps->olits -= c->size; } } #ifndef NDEBUG c->connected = 0; #endif } static int clause_is_toplevel_satisfied (PS * ps, Cls * c) { Lit *lit, **p, **eol = end_of_lits (c); Var *v; for (p = c->lits; p < eol; p++) { lit = *p; if (lit->val == TRUE) { v = LIT2VAR (lit); if (!v->level) return 1; } } return 0; } static int collect_clause (PS * ps, Cls * c) { assert (c->collect); c->collect = 0; #ifdef TRACE assert (!c->collected); c->collected = 1; #endif disconnect_clause (ps, c); #ifdef TRACE if (ps->trace && (!c->learned || c->used)) return 0; #endif delete_clause (ps, c); return 1; } static size_t collect_clauses (PS * ps) { Cls *c, **p, **q, * next; Lit * lit, * eol; size_t res; int i; res = ps->current_bytes; eol = ps->lits + 2 * ps->max_var + 1; for (lit = ps->lits + 2; lit <= eol; lit++) { for (i = 0; i <= 1; i++) { if (i) { #ifdef NO_BINARY_CLAUSES Ltk * lstk = LIT2IMPLS (lit); Lit ** r, ** s; r = lstk->start; if (lit->val != TRUE || LIT2VAR (lit)->level) for (s = r; s < lstk->start + lstk->count; s++) { Lit * other = *s; Var *v = LIT2VAR (other); if (v->level || other->val != TRUE) *r++ = other; } lstk->count = r - lstk->start; continue; #else p = LIT2IMPLS (lit); #endif } else p = LIT2HTPS (lit); for (c = *p; c; c = next) { q = c->next; if (c->lits[0] != lit) q++; next = *q; if (c->collect) *p = next; else p = q; } } } #ifndef NDSC for (lit = ps->lits + 2; lit <= eol; lit++) { p = LIT2DHTPS (lit); while ((c = *p)) { Lit * other = c->lits[0]; if (other == lit) { q = c->next + 1; } else { assert (c->lits[1] == lit); q = c->next; } if (c->collect) *p = *q; else p = q; } } #endif for (p = SOC; p != EOC; p = NXC (p)) { c = *p; if (!c) continue; if (!c->collect) continue; if (collect_clause (ps, c)) *p = 0; } #ifdef TRACE if (!ps->trace) #endif { q = ps->oclauses; for (p = q; p < ps->ohead; p++) if ((c = *p)) *q++ = c; ps->ohead = q; q = ps->lclauses; for (p = q; p < ps->lhead; p++) if ((c = *p)) *q++ = c; ps->lhead = q; } assert (ps->current_bytes <= res); res -= ps->current_bytes; ps->recycled += res; LOG ( picosat_fprintf (ps->out, "%scollected %ld bytes\n", ps->prefix, (long)res)); return res; } static int need_to_reduce (PS * ps) { return ps->nlclauses >= reduce_limit_on_lclauses (ps); } #ifdef NLUBY static void inc_drestart (PS * ps) { ps->drestart *= FRESTART; ps->drestart /= 100; if (ps->drestart >= MAXRESTART) ps->drestart = MAXRESTART; } static void inc_ddrestart (PS * ps) { ps->ddrestart *= FRESTART; ps->ddrestart /= 100; if (ps->ddrestart >= MAXRESTART) ps->ddrestart = MAXRESTART; } #else static unsigned luby (unsigned i) { unsigned k; for (k = 1; k < 32; k++) if (i == (1u << k) - 1) return 1u << (k - 1); for (k = 1;; k++) if ((1u << (k - 1)) <= i && i < (1u << k) - 1) return luby (i - (1u << (k-1)) + 1); } #endif #ifndef NLUBY static void inc_lrestart (PS * ps, int skip) { unsigned delta; delta = 100 * luby (++ps->lubycnt); ps->lrestart = ps->conflicts + delta; if (ps->waslubymaxdelta) report (ps, 1, skip ? 'N' : 'R'); else report (ps, 2, skip ? 'n' : 'r'); if (delta > ps->lubymaxdelta) { ps->lubymaxdelta = delta; ps->waslubymaxdelta = 1; } else ps->waslubymaxdelta = 0; } #endif static void init_restart (PS * ps) { #ifdef NLUBY /* TODO: why is it better in incremental usage to have smaller initial * outer restart interval? */ ps->ddrestart = ps->calls > 1 ? MINRESTART : 1000; ps->drestart = MINRESTART; ps->lrestart = ps->conflicts + ps->drestart; #else ps->lubycnt = 0; ps->lubymaxdelta = 0; ps->waslubymaxdelta = 0; inc_lrestart (ps, 0); #endif } static void restart (PS * ps) { int skip; #ifdef NLUBY char kind; int outer; inc_drestart (ps); outer = (ps->drestart >= ps->ddrestart); if (outer) skip = very_high_agility (ps); else skip = high_agility (ps); #else skip = medium_agility (ps); #endif #ifdef STATS if (skip) ps->skippedrestarts++; #endif assert (ps->conflicts >= ps->lrestart); if (!skip) { ps->restarts++; assert (ps->LEVEL > 1); LOG ( picosat_fprintf (ps->out, "%srestart %u\n", ps->prefix, ps->restarts)); undo (ps, 0); } #ifdef NLUBY if (outer) { kind = skip ? 'N' : 'R'; inc_ddrestart (ps); ps->drestart = MINRESTART; } else if (skip) { kind = 'n'; } else { kind = 'r'; } assert (ps->drestart <= MAXRESTART); ps->lrestart = ps->conflicts + ps->drestart; assert (ps->lrestart > ps->conflicts); report (outer ? 1 : 2, kind); #else inc_lrestart (ps, skip); #endif } inline static void assign_decision (PS * ps, Lit * lit) { assert (!ps->conflict); ps->LEVEL++; LOG ( picosat_fprintf (ps->out, "%snew level %u\n", ps->prefix, ps->LEVEL)); LOG ( picosat_fprintf (ps->out, "%sassign %d at level %d <= DECISION\n", ps->prefix, LIT2INT (lit), ps->LEVEL)); assign (ps, lit, 0); } #ifndef NFL static int lit_has_binary_clauses (PS * ps, Lit * lit) { #ifdef NO_BINARY_CLAUSES Ltk* lstk = LIT2IMPLS (lit); return lstk->count != 0; #else return *LIT2IMPLS (lit) != 0; #endif } static void flbcp (PS * ps) { #ifdef STATS unsigned long long propagaions_before_bcp = ps->propagations; #endif bcp (ps); #ifdef STATS ps->flprops += ps->propagations - propagaions_before_bcp; #endif } inline static int cmp_inverse_rnk (PS * ps, Rnk * a, Rnk * b) { (void) ps; return -cmp_rnk (a, b); } inline static Flt rnk2jwh (PS * ps, Rnk * r) { Flt res, sum, pjwh, njwh; Lit * plit, * nlit; plit = RNK2LIT (r); nlit = plit + 1; pjwh = *LIT2JWH (plit); njwh = *LIT2JWH (nlit); res = mulflt (pjwh, njwh); sum = addflt (pjwh, njwh); sum = mulflt (sum, base2flt (1, -10)); res = addflt (res, sum); return res; } static int cmp_inverse_jwh_rnk (PS * ps, Rnk * r, Rnk * s) { Flt a = rnk2jwh (ps, r); Flt b = rnk2jwh (ps, s); int res = cmpflt (a, b); if (res) return -res; return cmp_inverse_rnk (ps, r, s); } static void faillits (PS * ps) { unsigned i, j, old_trail_count, common, saved_count; unsigned new_saved_size, oldladded = ps->ladded; unsigned long long limit, delta; Lit * lit, * other, * pivot; Rnk * r, ** p, ** q; int new_trail_count; double started; if (ps->plain) return; if (ps->heap + 1 >= ps->hhead) return; if (ps->propagations < ps->fllimit) return; sflush (ps); started = ps->seconds; ps->flcalls++; #ifdef STATSA ps->flrounds++; #endif delta = ps->propagations/10; if (delta >= 100*1000*1000) delta = 100*1000*1000; else if (delta <= 100*1000) delta = 100*1000; limit = ps->propagations + delta; ps->fllimit = ps->propagations; assert (!ps->LEVEL); assert (ps->simplifying); if (ps->flcalls <= 1) SORT (Rnk *, cmp_inverse_jwh_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1)); else SORT (Rnk *, cmp_inverse_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1)); i = 1; /* NOTE: heap starts at position '1' */ while (ps->propagations < limit) { if (ps->heap + i == ps->hhead) { if (ps->ladded == oldladded) break; i = 1; #ifdef STATS ps->flrounds++; #endif oldladded = ps->ladded; } assert (ps->heap + i < ps->hhead); r = ps->heap[i++]; lit = RNK2LIT (r); if (lit->val) continue; if (!lit_has_binary_clauses (ps, NOTLIT (lit))) { #ifdef STATS ps->flskipped++; #endif continue; } #ifdef STATS ps->fltried++; #endif LOG ( picosat_fprintf (ps->out, "%strying %d as failed literal\n", ps->prefix, LIT2INT (lit))); assign_decision (ps, lit); old_trail_count = ps->thead - ps->trail; flbcp (ps); if (ps->conflict) { EXPLICITLY_FAILED_LITERAL: LOG ( picosat_fprintf (ps->out, "%sfound explicitly failed literal %d\n", ps->prefix, LIT2INT (lit))); ps->failedlits++; ps->efailedlits++; backtrack (ps); flbcp (ps); if (!ps->conflict) continue; CONTRADICTION: assert (!ps->LEVEL); backtrack (ps); assert (ps->mtcls); goto RETURN; } if (ps->propagations >= limit) { undo (ps, 0); break; } lit = NOTLIT (lit); if (!lit_has_binary_clauses (ps, NOTLIT (lit))) { #ifdef STATS ps->flskipped++; #endif undo (ps, 0); continue; } #ifdef STATS ps->fltried++; #endif LOG ( picosat_fprintf (ps->out, "%strying %d as failed literals\n", ps->prefix, LIT2INT (lit))); new_trail_count = ps->thead - ps->trail; saved_count = new_trail_count - old_trail_count; if (saved_count > ps->saved_size) { new_saved_size = ps->saved_size ? 2 * ps->saved_size : 1; while (saved_count > new_saved_size) new_saved_size *= 2; RESIZEN (ps->saved, ps->saved_size, new_saved_size); ps->saved_size = new_saved_size; } for (j = 0; j < saved_count; j++) ps->saved[j] = ps->trail[old_trail_count + j]; undo (ps, 0); assign_decision (ps, lit); flbcp (ps); if (ps->conflict) goto EXPLICITLY_FAILED_LITERAL; pivot = (ps->thead - ps->trail <= new_trail_count) ? lit : NOTLIT (lit); common = 0; for (j = 0; j < saved_count; j++) if ((other = ps->saved[j])->val == TRUE) ps->saved[common++] = other; undo (ps, 0); LOG (if (common) picosat_fprintf (ps->out, "%sfound %d literals implied by %d and %d\n", ps->prefix, common, LIT2INT (NOTLIT (lit)), LIT2INT (lit))); #if 1 // set to zero to disable 'lifting' for (j = 0; j < common /* TODO: For some Velev benchmarks, extracting the common implicit * failed literals took quite some time. This needs to be fixed by * a dedicated analyzer. Up to then we bound the number of * propagations in this loop as well. */ && ps->propagations < limit + delta ; j++) { other = ps->saved[j]; if (other->val == TRUE) continue; assert (!other->val); LOG ( picosat_fprintf (ps->out, "%sforcing %d as forced implicitly failed literal\n", ps->prefix, LIT2INT (other))); assert (pivot != NOTLIT (other)); assert (pivot != other); assign_decision (ps, NOTLIT (other)); flbcp (ps); assert (ps->LEVEL == 1); if (ps->conflict) { backtrack (ps); assert (!ps->LEVEL); } else { assign_decision (ps, pivot); flbcp (ps); backtrack (ps); if (ps->LEVEL) { assert (ps->LEVEL == 1); flbcp (ps); if (ps->conflict) { backtrack (ps); assert (!ps->LEVEL); } else { assign_decision (ps, NOTLIT (pivot)); flbcp (ps); backtrack (ps); if (ps->LEVEL) { assert (ps->LEVEL == 1); flbcp (ps); if (!ps->conflict) { #ifdef STATS ps->floopsed++; #endif undo (ps, 0); continue; } backtrack (ps); } assert (!ps->LEVEL); } assert (!ps->LEVEL); } } assert (!ps->LEVEL); flbcp (ps); ps->failedlits++; ps->ifailedlits++; if (ps->conflict) goto CONTRADICTION; } #endif } ps->fllimit += 9 * (ps->propagations - ps->fllimit); /* 10% for failed literals */ RETURN: /* First flush top level assigned literals. Those are prohibited from * being pushed up the heap during 'faillits' since 'simplifying' is set. */ assert (ps->heap < ps->hhead); for (p = q = ps->heap + 1; p < ps->hhead; p++) { r = *p; lit = RNK2LIT (r); if (lit->val) r->pos = 0; else *q++ = r; } /* Then resort with respect to EVSIDS score and fix positions. */ SORT (Rnk *, cmp_inverse_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1)); for (p = ps->heap + 1; p < ps->hhead; p++) (*p)->pos = p - ps->heap; sflush (ps); ps->flseconds += ps->seconds - started; } #endif static void simplify (PS * ps, int forced) { Lit * lit, * notlit, ** t; unsigned collect, delta; #ifdef STATS size_t bytes_collected; #endif int * q, ilit; Cls **p, *c; Var * v; #ifndef NDEDBUG (void) forced; #endif assert (!ps->mtcls); assert (!satisfied (ps)); assert (forced || ps->lsimplify <= ps->propagations); assert (forced || ps->fsimplify <= ps->fixed); if (ps->LEVEL) undo (ps, 0); #ifndef NFL ps->simplifying = 1; faillits (ps); ps->simplifying = 0; if (ps->mtcls) return; #endif if (ps->cils != ps->cilshead) { assert (ps->ttail == ps->thead); assert (ps->ttail2 == ps->thead); ps->ttail = ps->trail; for (t = ps->trail; t < ps->thead; t++) { lit = *t; v = LIT2VAR (lit); if (v->internal) { assert (LIT2INT (lit) < 0); assert (lit->val == TRUE); unassign (ps, lit); } else *ps->ttail++ = lit; } ps->ttail2 = ps->thead = ps->ttail; for (q = ps->cils; q != ps->cilshead; q++) { ilit = *q; assert (0 < ilit && ilit <= (int) ps->max_var); v = ps->vars + ilit; assert (v->internal); v->level = 0; v->reason = 0; lit = int2lit (ps, -ilit); assert (lit->val == UNDEF); lit->val = TRUE; notlit = NOTLIT (lit); assert (notlit->val == UNDEF); notlit->val = FALSE; } } collect = 0; for (p = SOC; p != EOC; p = NXC (p)) { c = *p; if (!c) continue; #ifdef TRACE if (c->collected) continue; #endif if (c->locked) continue; assert (!c->collect); if (clause_is_toplevel_satisfied (ps, c)) { mark_clause_to_be_collected (c); collect++; } } LOG ( picosat_fprintf (ps->out, "%scollecting %d clauses\n", ps->prefix, collect)); #ifdef STATS bytes_collected = #endif collect_clauses (ps); #ifdef STATS ps->srecycled += bytes_collected; #endif if (ps->cils != ps->cilshead) { for (q = ps->cils; q != ps->cilshead; q++) { ilit = *q; assert (0 < ilit && ilit <= (int) ps->max_var); assert (ps->vars[ilit].internal); if (ps->rilshead == ps->eorils) ENLARGE (ps->rils, ps->rilshead, ps->eorils); *ps->rilshead++ = ilit; lit = int2lit (ps, -ilit); assert (lit->val == TRUE); lit->val = UNDEF; notlit = NOTLIT (lit); assert (notlit->val == FALSE); notlit->val = UNDEF; } ps->cilshead = ps->cils; } delta = 10 * (ps->olits + ps->llits) + 100000; if (delta > 2000000) delta = 2000000; ps->lsimplify = ps->propagations + delta; ps->fsimplify = ps->fixed; ps->simps++; report (ps, 1, 's'); } static void iteration (PS * ps) { assert (!ps->LEVEL); assert (bcp_queue_is_empty (ps)); assert (ps->isimplify < ps->fixed); ps->iterations++; report (ps, 2, 'i'); #ifdef NLUBY ps->drestart = MINRESTART; ps->lrestart = ps->conflicts + ps->drestart; #else init_restart (ps); #endif ps->isimplify = ps->fixed; } static int cmp_glue_activity_size (PS * ps, Cls * c, Cls * d) { Act a, b, * p, * q; (void) ps; assert (c->learned); assert (d->learned); if (c->glue < d->glue) // smaller glue preferred return 1; if (c->glue > d->glue) return -1; p = CLS2ACT (c); q = CLS2ACT (d); a = *p; b = *q; if (a < b) // then higher activity return -1; if (b < a) return 1; if (c->size < d->size) // then smaller size return 1; if (c->size > d->size) return -1; return 0; } static void reduce (PS * ps, unsigned percentage) { unsigned redcount, lcollect, collect, target; #ifdef STATS size_t bytes_collected; #endif Cls **p, *c; assert (ps->rhead == ps->resolved); ps->lastreduceconflicts = ps->conflicts; assert (percentage <= 100); LOG ( picosat_fprintf (ps->out, "%sreducing %u%% learned clauses\n", ps->prefix, percentage)); while (ps->nlclauses - ps->llocked > (unsigned)(ps->eor - ps->resolved)) ENLARGE (ps->resolved, ps->rhead, ps->eor); collect = 0; lcollect = 0; for (p = ((ps->fsimplify < ps->fixed) ? SOC : ps->lclauses); p != EOC; p = NXC (p)) { c = *p; if (!c) continue; #ifdef TRACE if (c->collected) continue; #endif if (c->locked) continue; assert (!c->collect); if (ps->fsimplify < ps->fixed && clause_is_toplevel_satisfied (ps, c)) { mark_clause_to_be_collected (c); collect++; if (c->learned && c->size > 2) lcollect++; continue; } if (!c->learned) continue; if (c->size <= 2) continue; assert (ps->rhead < ps->eor); *ps->rhead++ = c; } assert (ps->rhead <= ps->eor); ps->fsimplify = ps->fixed; redcount = ps->rhead - ps->resolved; SORT (Cls *, cmp_glue_activity_size, ps->resolved, redcount); assert (ps->nlclauses >= lcollect); target = ps->nlclauses - lcollect + 1; target = (percentage * target + 99) / 100; if (target >= redcount) target = redcount; ps->rhead = ps->resolved + target; while (ps->rhead > ps->resolved) { c = *--ps->rhead; mark_clause_to_be_collected (c); collect++; if (c->learned && c->size > 2) /* just for consistency */ lcollect++; } if (collect) { ps->reductions++; #ifdef STATS bytes_collected = #endif collect_clauses (ps); #ifdef STATS ps->rrecycled += bytes_collected; #endif report (ps, 2, '-'); } if (!lcollect) inc_lreduce (ps); /* avoid dead lock */ assert (ps->rhead == ps->resolved); } static void init_reduce (PS * ps) { // lreduce = loadded / 2; ps->lreduce = 1000; if (ps->lreduce < 100) ps->lreduce = 100; if (ps->verbosity) picosat_fprintf (ps->out, "%s\n%sinitial reduction limit %u clauses\n%s\n", ps->prefix, ps->prefix, ps->lreduce, ps->prefix); } static unsigned rng (PS * ps) { unsigned res = ps->srng; ps->srng *= 1664525u; ps->srng += 1013904223u; NOLOG ( picosat_fprintf (ps->out, "%srng () = %u\n", ps->prefix, res)); return res; } static unsigned rrng (PS * ps, unsigned low, unsigned high) { unsigned long long tmp; unsigned res, elements; assert (low <= high); elements = high - low + 1; tmp = rng (ps); tmp *= elements; tmp >>= 32; tmp += low; res = tmp; NOLOG ( picosat_fprintf (ps->out, "%srrng (ps, %u, %u) = %u\n", ps->prefix, low, high, res)); assert (low <= res); assert (res <= high); return res; } static Lit * decide_phase (PS * ps, Lit * lit) { Lit * not_lit = NOTLIT (lit); Var *v = LIT2VAR (lit); assert (LIT2SGN (lit) > 0); if (v->usedefphase) { if (v->defphase) { /* assign to TRUE */ } else { /* assign to FALSE */ lit = not_lit; } } else if (!v->assigned) { #ifdef STATS ps->staticphasedecisions++; #endif if (ps->defaultphase == POSPHASE) { /* assign to TRUE */ } else if (ps->defaultphase == NEGPHASE) { /* assign to FALSE */ lit = not_lit; } else if (ps->defaultphase == RNDPHASE) { /* randomly assign default phase */ if (rrng (ps, 1, 2) != 2) lit = not_lit; } else if (*LIT2JWH(lit) <= *LIT2JWH (not_lit)) { /* assign to FALSE (Jeroslow-Wang says there are more short * clauses with negative occurence of this variable, so satisfy * those, to minimize BCP) */ lit = not_lit; } else { /* assign to TRUE (... but strictly more positive occurrences) */ } } else { /* repeat last phase: phase saving heuristic */ if (v->phase) { /* assign to TRUE (last phase was TRUE as well) */ } else { /* assign to FALSE (last phase was FALSE as well) */ lit = not_lit; } } return lit; } static unsigned gcd (unsigned a, unsigned b) { unsigned tmp; assert (a); assert (b); if (a < b) { tmp = a; a = b; b = tmp; } while (b) { assert (a >= b); tmp = b; b = a % b; a = tmp; } return a; } static Lit * rdecide (PS * ps) { unsigned idx, delta, spread; Lit * res; spread = RDECIDE; if (rrng (ps, 1, spread) != 2) return 0; assert (1 <= ps->max_var); idx = rrng (ps, 1, ps->max_var); res = int2lit (ps, idx); if (res->val != UNDEF) { delta = rrng (ps, 1, ps->max_var); while (gcd (delta, ps->max_var) != 1) delta--; assert (1 <= delta); assert (delta <= ps->max_var); do { idx += delta; if (idx > ps->max_var) idx -= ps->max_var; res = int2lit (ps, idx); } while (res->val != UNDEF); } #ifdef STATS ps->rdecisions++; #endif res = decide_phase (ps, res); LOG ( picosat_fprintf (ps->out, "%srdecide %d\n", ps->prefix, LIT2INT (res))); return res; } static Lit * sdecide (PS * ps) { Lit *res; Rnk *r; for (;;) { r = htop (ps); res = RNK2LIT (r); if (res->val == UNDEF) break; (void) hpop (ps); NOLOG ( picosat_fprintf (ps->out, "%shpop %u %u %u\n", ps->prefix, r - ps->rnks, FLTMANTISSA(r->score), FLTEXPONENT(r->score))); } #ifdef STATS ps->sdecisions++; #endif res = decide_phase (ps, res); LOG ( picosat_fprintf (ps->out, "%ssdecide %d\n", ps->prefix, LIT2INT (res))); return res; } static Lit * adecide (PS * ps) { Lit *lit; Var * v; assert (ps->als < ps->alshead); assert (!ps->failed_assumption); while (ps->alstail < ps->alshead) { lit = *ps->alstail++; if (lit->val == FALSE) { ps->failed_assumption = lit; v = LIT2VAR (lit); use_var (ps, v); LOG ( picosat_fprintf (ps->out, "%sfirst failed assumption %d\n", ps->prefix, LIT2INT (ps->failed_assumption))); fanalyze (ps); return 0; } if (lit->val == TRUE) { v = LIT2VAR (lit); if (v->level > ps->adecidelevel) ps->adecidelevel = v->level; continue; } #ifdef STATS ps->assumptions++; #endif LOG ( picosat_fprintf (ps->out, "%sadecide %d\n", ps->prefix, LIT2INT (lit))); ps->adecidelevel = ps->LEVEL + 1; return lit; } return 0; } static void decide (PS * ps) { Lit * lit; assert (!satisfied (ps)); assert (!ps->conflict); if (ps->alstail < ps->alshead && (lit = adecide (ps))) ; else if (ps->failed_assumption) return; else if (satisfied (ps)) return; else if (!(lit = rdecide (ps))) lit = sdecide (ps); assert (lit); assign_decision (ps, lit); ps->levelsum += ps->LEVEL; ps->decisions++; } static int sat (PS * ps, int l) { int count = 0, backtracked; if (!ps->conflict) bcp (ps); if (ps->conflict) backtrack (ps); if (ps->mtcls) return PICOSAT_UNSATISFIABLE; if (satisfied (ps)) goto SATISFIED; if (ps->lsimplify <= ps->propagations) simplify (ps, 0); if (ps->mtcls) return PICOSAT_UNSATISFIABLE; if (satisfied (ps)) goto SATISFIED; init_restart (ps); if (!ps->lreduce) init_reduce (ps); ps->isimplify = ps->fixed; backtracked = 0; for (;;) { if (!ps->conflict) bcp (ps); if (ps->conflict) { incincs (ps); backtrack (ps); if (ps->mtcls) return PICOSAT_UNSATISFIABLE; backtracked = 1; continue; } if (satisfied (ps)) { SATISFIED: #ifndef NDEBUG original_clauses_satisfied (ps); assumptions_satisfied (ps); #endif return PICOSAT_SATISFIABLE; } if (backtracked) { backtracked = 0; if (!ps->LEVEL && ps->isimplify < ps->fixed) iteration (ps); } if (l >= 0 && count >= l) /* decision limit reached ? */ return PICOSAT_UNKNOWN; if (ps->interrupt.function && /* external interrupt */ count > 0 && !(count % INTERRUPTLIM) && ps->interrupt.function (ps->interrupt.state)) return PICOSAT_UNKNOWN; if (ps->propagations >= ps->lpropagations)/* propagation limit reached ? */ return PICOSAT_UNKNOWN; #ifndef NADC if (!ps->adodisabled && ps->adoconflicts >= ps->adoconflictlimit) { assert (bcp_queue_is_empty (ps)); return PICOSAT_UNKNOWN; } #endif if (ps->fsimplify < ps->fixed && ps->lsimplify <= ps->propagations) { simplify (ps, 0); if (!bcp_queue_is_empty (ps)) continue; #ifndef NFL if (ps->mtcls) return PICOSAT_UNSATISFIABLE; if (satisfied (ps)) return PICOSAT_SATISFIABLE; assert (!ps->LEVEL); #endif } if (need_to_reduce (ps)) reduce (ps, 50); if (ps->conflicts >= ps->lrestart && ps->LEVEL > 2) restart (ps); decide (ps); if (ps->failed_assumption) return PICOSAT_UNSATISFIABLE; count++; } } static void rebias (PS * ps) { Cls ** p, * c; Var * v; for (v = ps->vars + 1; v <= ps->vars + ps->max_var; v++) v->assigned = 0; memset (ps->jwh, 0, 2 * (ps->max_var + 1) * sizeof *ps->jwh); for (p = ps->oclauses; p < ps->ohead; p++) { c = *p; if (!c) continue; if (c->learned) continue; incjwh (ps, c); } } #ifdef TRACE static unsigned core (PS * ps) { unsigned idx, prev, this, delta, i, lcore, vcore; unsigned *stack, *shead, *eos; Lit **q, **eol, *lit; Cls *c, *reason; Znt *p, byte; Zhn *zhain; Var *v; assert (ps->trace); assert (ps->mtcls || ps->failed_assumption); if (ps->ocore >= 0) return ps->ocore; lcore = ps->ocore = vcore = 0; stack = shead = eos = 0; ENLARGE (stack, shead, eos); if (ps->mtcls) { idx = CLS2IDX (ps->mtcls); *shead++ = idx; } else { assert (ps->failed_assumption); v = LIT2VAR (ps->failed_assumption); reason = v->reason; assert (reason); idx = CLS2IDX (reason); *shead++ = idx; } while (shead > stack) { idx = *--shead; zhain = IDX2ZHN (idx); if (zhain) { if (zhain->core) continue; zhain->core = 1; lcore++; c = IDX2CLS (idx); if (c) { assert (!c->core); c->core = 1; } i = 0; delta = 0; prev = 0; for (p = zhain->znt; (byte = *p); p++, i += 7) { delta |= (byte & 0x7f) << i; if (byte & 0x80) continue; this = prev + delta; assert (prev < this); /* no overflow */ if (shead == eos) ENLARGE (stack, shead, eos); *shead++ = this; prev = this; delta = 0; i = -7; } } else { c = IDX2CLS (idx); assert (c); assert (!c->learned); if (c->core) continue; c->core = 1; ps->ocore++; eol = end_of_lits (c); for (q = c->lits; q < eol; q++) { lit = *q; v = LIT2VAR (lit); if (v->core) continue; v->core = 1; vcore++; if (!ps->failed_assumption) continue; if (lit != ps->failed_assumption) continue; reason = v->reason; if (!reason) continue; if (reason->core) continue; idx = CLS2IDX (reason); if (shead == eos) ENLARGE (stack, shead, eos); *shead++ = idx; } } } DELETEN (stack, eos - stack); if (ps->verbosity) picosat_fprintf (ps->out, "%s%u core variables out of %u (%.1f%%)\n" "%s%u core original clauses out of %u (%.1f%%)\n" "%s%u core learned clauses out of %u (%.1f%%)\n", ps->prefix, vcore, ps->max_var, PERCENT (vcore, ps->max_var), ps->prefix, ps->ocore, ps->oadded, PERCENT (ps->ocore, ps->oadded), ps->prefix, lcore, ps->ladded, PERCENT (lcore, ps->ladded)); return ps->ocore; } static void trace_lits (PS * ps, Cls * c, FILE * file) { Lit **p, **eol = end_of_lits (c); assert (c); assert (c->core); for (p = c->lits; p < eol; p++) picosat_fprintf (file, "%d ", LIT2INT (*p)); picosat_fputc ('0', file); } static void write_idx (PS * ps, unsigned idx, FILE * file) { picosat_fprintf (file, "%ld", EXPORTIDX (idx)); } static void trace_clause (PS * ps, unsigned idx, Cls * c, FILE * file, int fmt) { assert (c); assert (c->core); assert (fmt == RUP_TRACE_FMT || !c->learned); assert (CLS2IDX (c) == idx); if (fmt != RUP_TRACE_FMT) { write_idx (ps, idx, file); picosat_fputc (' ', file); } trace_lits (ps, c, file); if (fmt != RUP_TRACE_FMT) picosat_fputs (" 0", file); picosat_fputc ('\n', file); } static void trace_zhain (PS * ps, unsigned idx, Zhn * zhain, FILE * file, int fmt) { unsigned prev, this, delta, i; Znt *p, byte; Cls * c; assert (zhain); assert (zhain->core); write_idx (ps, idx, file); picosat_fputc (' ', file); if (fmt == EXTENDED_TRACECHECK_TRACE_FMT) { c = IDX2CLS (idx); assert (c); trace_lits (ps, c, file); } else { assert (fmt == COMPACT_TRACECHECK_TRACE_FMT); putc ('*', file); } i = 0; delta = 0; prev = 0; for (p = zhain->znt; (byte = *p); p++, i += 7) { delta |= (byte & 0x7f) << i; if (byte & 0x80) continue; this = prev + delta; putc (' ', file); write_idx (ps, this, file); prev = this; delta = 0; i = -7; } picosat_fputs (" 0\n", file); } static void write_core (PS * ps, FILE * file) { Lit **q, **eol; Cls **p, *c; picosat_fprintf (file, "p cnf %u %u\n", ps->max_var, core (ps)); for (p = SOC; p != EOC; p = NXC (p)) { c = *p; if (!c || c->learned || !c->core) continue; eol = end_of_lits (c); for (q = c->lits; q < eol; q++) picosat_fprintf (file, "%d ", LIT2INT (*q)); picosat_fputs ("0\n", file); } } #endif static void write_trace (PS * ps, FILE * file, int fmt) { #ifdef TRACE Cls *c, ** p; Zhn *zhain; unsigned i; core (ps); if (fmt == RUP_TRACE_FMT) { ps->rupvariables = picosat_variables (ps), ps->rupclauses = picosat_added_original_clauses (ps); write_rup_header (ps, file); } for (p = SOC; p != EOC; p = NXC (p)) { c = *p; if (ps->oclauses <= p && p < ps->eoo) { i = OIDX2IDX (p - ps->oclauses); assert (!c || CLS2IDX (c) == i); } else { assert (ps->lclauses <= p && p < ps->EOL); i = LIDX2IDX (p - ps->lclauses); } zhain = IDX2ZHN (i); if (zhain) { if (zhain->core) { if (fmt == RUP_TRACE_FMT) trace_clause (ps,i, c, file, fmt); else trace_zhain (ps, i, zhain, file, fmt); } } else if (c) { if (fmt != RUP_TRACE_FMT && c) { if (c->core) trace_clause (ps, i, c, file, fmt); } } } #else (void) file; (void) fmt; (void) ps; #endif } static void write_core_wrapper (PS * ps, FILE * file, int fmt) { (void) fmt; #ifdef TRACE write_core (ps, file); #else (void) ps; (void) file; #endif } static Lit * import_lit (PS * ps, int lit, int nointernal) { Lit * res; Var * v; ABORTIF (lit == INT_MIN, "API usage: INT_MIN literal"); ABORTIF (abs (lit) > (int) ps->max_var && ps->CLS != ps->clshead, "API usage: new variable index after 'picosat_push'"); if (abs (lit) <= (int) ps->max_var) { res = int2lit (ps, lit); v = LIT2VAR (res); if (nointernal && v->internal) ABORT ("API usage: trying to import invalid literal"); else if (!nointernal && !v->internal) ABORT ("API usage: trying to import invalid context"); } else { while (abs (lit) > (int) ps->max_var) inc_max_var (ps); res = int2lit (ps, lit); } return res; } #ifdef TRACE static void reset_core (PS * ps) { Cls ** p, * c; Zhn ** q, * z; unsigned i; for (i = 1; i <= ps->max_var; i++) ps->vars[i].core = 0; for (p = SOC; p != EOC; p = NXC (p)) if ((c = *p)) c->core = 0; for (q = ps->zhains; q != ps->zhead; q++) if ((z = *q)) z->core = 0; ps->ocore = -1; } #endif static void reset_assumptions (PS * ps) { Lit ** p; ps->failed_assumption = 0; if (ps->extracted_all_failed_assumptions) { for (p = ps->als; p < ps->alshead; p++) LIT2VAR (*p)->failed = 0; ps->extracted_all_failed_assumptions = 0; } ps->alstail = ps->alshead = ps->als; ps->adecidelevel = 0; } static void check_ready (PS * ps) { ABORTIF (!ps || ps->state == RESET, "API usage: uninitialized"); } static void check_sat_state (PS * ps) { ABORTIF (ps->state != SAT, "API usage: expected to be in SAT state"); } static void check_unsat_state (PS * ps) { ABORTIF (ps->state != UNSAT, "API usage: expected to be in UNSAT state"); } static void check_sat_or_unsat_or_unknown_state (PS * ps) { ABORTIF (ps->state != SAT && ps->state != UNSAT && ps->state != UNKNOWN, "API usage: expected to be in SAT, UNSAT, or UNKNOWN state"); } static void reset_partial (PS * ps) { unsigned idx; if (!ps->partial) return; for (idx = 1; idx <= ps->max_var; idx++) ps->vars[idx].partial = 0; ps->partial = 0; } static void reset_incremental_usage (PS * ps) { unsigned num_non_false; Lit * lit, ** q; check_sat_or_unsat_or_unknown_state (ps); LOG ( picosat_fprintf (ps->out, "%sRESET incremental usage\n", ps->prefix)); if (ps->LEVEL) undo (ps, 0); reset_assumptions (ps); if (ps->conflict) { num_non_false = 0; for (q = ps->conflict->lits; q < end_of_lits (ps->conflict); q++) { lit = *q; if (lit->val != FALSE) num_non_false++; } // assert (num_non_false >= 2); // TODO: why this assertion? #ifdef NO_BINARY_CLAUSES if (ps->conflict == &ps->cimpl) resetcimpl (ps); #endif #ifndef NADC if (ps->conflict == ps->adoconflict) resetadoconflict (ps); #endif ps->conflict = 0; } #ifdef TRACE reset_core (ps); #endif reset_partial (ps); ps->saved_flips = ps->flips; ps->min_flipped = UINT_MAX; ps->saved_max_var = ps->max_var; ps->state = READY; } static void enter (PS * ps) { if (ps->nentered++) return; check_ready (ps); ps->entered = picosat_time_stamp (); } static void leave (PS * ps) { assert (ps->nentered); if (--ps->nentered) return; sflush (ps); } static void check_trace_support_and_execute (PS * ps, FILE * file, void (*f)(PS*,FILE*,int), int fmt) { check_ready (ps); check_unsat_state (ps); #ifdef TRACE ABORTIF (!ps->trace, "API usage: tracing disabled"); enter (ps); f (ps, file, fmt); leave (ps); #else (void) file; (void) fmt; (void) f; ABORT ("compiled without trace support"); #endif } static void extract_all_failed_assumptions (PS * ps) { Lit ** p, ** eol; Var * v, * u; int pos; Cls * c; assert (!ps->extracted_all_failed_assumptions); assert (ps->failed_assumption); assert (ps->mhead == ps->marked); if (ps->marked == ps->eom) ENLARGE (ps->marked, ps->mhead, ps->eom); v = LIT2VAR (ps->failed_assumption); mark_var (ps, v); pos = 0; while (pos < ps->mhead - ps->marked) { v = ps->marked[pos++]; assert (v->mark); c = var2reason (ps, v); if (!c) continue; eol = end_of_lits (c); for (p = c->lits; p < eol; p++) { u = LIT2VAR (*p); if (!u->mark) mark_var (ps, u); } #ifdef NO_BINARY_CLAUSES if (c == &ps->impl) resetimpl (ps); #endif } for (p = ps->als; p < ps->alshead; p++) { u = LIT2VAR (*p); if (!u->mark) continue; u->failed = 1; LOG ( picosat_fprintf (ps->out, "%sfailed assumption %d\n", ps->prefix, LIT2INT (*p))); } while (ps->mhead > ps->marked) (*--ps->mhead)->mark = 0; ps->extracted_all_failed_assumptions = 1; } const char * picosat_copyright (void) { return "Copyright (c) 2006 - 2014 Armin Biere JKU Linz"; } PicoSAT * picosat_init (void) { return init (0, 0, 0, 0); } PicoSAT * picosat_minit (void * pmgr, picosat_malloc pnew, picosat_realloc presize, picosat_free pfree) { ABORTIF (!pnew, "API usage: zero 'picosat_malloc' argument"); ABORTIF (!presize, "API usage: zero 'picosat_realloc' argument"); ABORTIF (!pfree, "API usage: zero 'picosat_free' argument"); return init (pmgr, pnew, presize, pfree); } void picosat_adjust (PS * ps, int new_max_var) { unsigned new_size_vars; ABORTIF (abs (new_max_var) > (int) ps->max_var && ps->CLS != ps->clshead, "API usage: adjusting variable index after 'picosat_push'"); enter (ps); new_max_var = abs (new_max_var); new_size_vars = new_max_var + 1; if (ps->size_vars < new_size_vars) enlarge (ps, new_size_vars); while (ps->max_var < (unsigned) new_max_var) inc_max_var (ps); leave (ps); } int picosat_inc_max_var (PS * ps) { if (ps->measurealltimeinlib) enter (ps); else check_ready (ps); inc_max_var (ps); if (ps->measurealltimeinlib) leave (ps); return ps->max_var; } int picosat_context (PS * ps) { return ps->clshead == ps->CLS ? 0 : LIT2INT (ps->clshead[-1]); } int picosat_push (PS * ps) { int res; Lit *lit; Var * v; if (ps->measurealltimeinlib) enter (ps); else check_ready (ps); if (ps->state != READY) reset_incremental_usage (ps); if (ps->rils != ps->rilshead) { res = *--ps->rilshead; assert (ps->vars[res].internal); } else { inc_max_var (ps); res = ps->max_var; v = ps->vars + res; assert (!v->internal); v->internal = 1; ps->internals++; LOG ( picosat_fprintf (ps->out, "%snew internal variable index %d\n", ps->prefix, res)); } lit = int2lit (ps, res); if (ps->clshead == ps->eocls) ENLARGE (ps->CLS, ps->clshead, ps->eocls); *ps->clshead++ = lit; ps->contexts++; LOG ( picosat_fprintf (ps->out, "%snew context %d at depth %ld after push\n", ps->prefix, res, (long)(ps->clshead - ps->CLS))); if (ps->measurealltimeinlib) leave (ps); return res; } int picosat_pop (PS * ps) { Lit * lit; int res; ABORTIF (ps->CLS == ps->clshead, "API usage: too many 'picosat_pop'"); ABORTIF (ps->added != ps->ahead, "API usage: incomplete clause"); if (ps->measurealltimeinlib) enter (ps); else check_ready (ps); if (ps->state != READY) reset_incremental_usage (ps); assert (ps->CLS < ps->clshead); lit = *--ps->clshead; LOG ( picosat_fprintf (ps->out, "%sclosing context %d at depth %ld after pop\n", ps->prefix, LIT2INT (lit), (long)(ps->clshead - ps->CLS) + 1)); if (ps->cilshead == ps->eocils) ENLARGE (ps->cils, ps->cilshead, ps->eocils); *ps->cilshead++ = LIT2INT (lit); if (ps->cilshead - ps->cils > MAXCILS) { LOG ( picosat_fprintf (ps->out, "%srecycling %ld interals with forced simplification\n", ps->prefix, (long)(ps->cilshead - ps->cils))); simplify (ps, 1); } res = picosat_context (ps); if (res) LOG ( picosat_fprintf (ps->out, "%snew context %d at depth %ld after pop\n", ps->prefix, res, (long)(ps->clshead - ps->CLS))); else LOG ( picosat_fprintf (ps->out, "%souter most context reached after pop\n", ps->prefix)); if (ps->measurealltimeinlib) leave (ps); return res; } void picosat_set_verbosity (PS * ps, int new_verbosity_level) { check_ready (ps); ps->verbosity = new_verbosity_level; } void picosat_set_plain (PS * ps, int new_plain_value) { check_ready (ps); ps->plain = new_plain_value; } int picosat_enable_trace_generation (PS * ps) { int res = 0; check_ready (ps); #ifdef TRACE ABORTIF (ps->addedclauses, "API usage: trace generation enabled after adding clauses"); res = ps->trace = 1; #endif return res; } void picosat_set_incremental_rup_file (PS * ps, FILE * rup_file, int m, int n) { check_ready (ps); assert (!ps->rupstarted); ps->rup = rup_file; ps->rupvariables = m; ps->rupclauses = n; } void picosat_set_output (PS * ps, FILE * output_file) { check_ready (ps); ps->out = output_file; } void picosat_measure_all_calls (PS * ps) { check_ready (ps); ps->measurealltimeinlib = 1; } void picosat_set_prefix (PS * ps, const char * str) { check_ready (ps); new_prefix (ps, str); } void picosat_set_seed (PS * ps, unsigned s) { check_ready (ps); ps->srng = s; } void picosat_reset (PS * ps) { check_ready (ps); reset (ps); } int picosat_add (PS * ps, int int_lit) { int res = ps->oadded; Lit *lit; if (ps->measurealltimeinlib) enter (ps); else check_ready (ps); ABORTIF (ps->rup && ps->rupstarted && ps->oadded >= (unsigned)ps->rupclauses, "API usage: adding too many clauses after RUP header written"); #ifndef NADC ABORTIF (ps->addingtoado, "API usage: 'picosat_add' and 'picosat_add_ado_lit' mixed"); #endif if (ps->state != READY) reset_incremental_usage (ps); if (ps->saveorig) { if (ps->sohead == ps->eoso) ENLARGE (ps->soclauses, ps->sohead, ps->eoso); *ps->sohead++ = int_lit; } if (int_lit) { lit = import_lit (ps, int_lit, 1); add_lit (ps, lit); } else simplify_and_add_original_clause (ps); if (ps->measurealltimeinlib) leave (ps); return res; } int picosat_add_arg (PS * ps, ...) { int lit; va_list ap; va_start (ap, ps); while ((lit = va_arg (ap, int))) (void) picosat_add (ps, lit); va_end (ap); return picosat_add (ps, 0); } int picosat_add_lits (PS * ps, int * lits) { const int * p; int lit; for (p = lits; (lit = *p); p++) (void) picosat_add (ps, lit); return picosat_add (ps, 0); } void picosat_add_ado_lit (PS * ps, int external_lit) { #ifndef NADC Lit * internal_lit; if (ps->measurealltimeinlib) enter (ps); else check_ready (ps); if (ps->state != READY) reset_incremental_usage (ps); ABORTIF (!ps->addingtoado && ps->ahead > ps->added, "API usage: 'picosat_add' and 'picosat_add_ado_lit' mixed"); if (external_lit) { ps->addingtoado = 1; internal_lit = import_lit (external_lit, 1); add_lit (internal_lit); } else { ps->addingtoado = 0; add_ado (ps); } if (ps->measurealltimeinlib) leave (ps); #else (void) ps; (void) external_lit; ABORT ("compiled without all different constraint support"); #endif } static void assume (PS * ps, Lit * lit) { if (ps->alshead == ps->eoals) { assert (ps->alstail == ps->als); ENLARGE (ps->als, ps->alshead, ps->eoals); ps->alstail = ps->als; } *ps->alshead++ = lit; LOG ( picosat_fprintf (ps->out, "%sassumption %d\n", ps->prefix, LIT2INT (lit))); } static void assume_contexts (PS * ps) { Lit ** p; if (ps->als != ps->alshead) return; for (p = ps->CLS; p != ps->clshead; p++) assume (ps, *p); } static const char * enumstr (int i) { int last = i % 10; if (last == 1) return "st"; if (last == 2) return "nd"; if (last == 3) return "rd"; return "th"; } static int tderef (PS * ps, int int_lit) { Lit * lit; Var * v; assert (abs (int_lit) <= (int) ps->max_var); lit = int2lit (ps, int_lit); v = LIT2VAR (lit); if (v->level > 0) return 0; if (lit->val == TRUE) return 1; if (lit->val == FALSE) return -1; return 0; } static int pderef (PS * ps, int int_lit) { Lit * lit; Var * v; assert (abs (int_lit) <= (int) ps->max_var); v = ps->vars + abs (int_lit); if (!v->partial) return 0; lit = int2lit (ps, int_lit); if (lit->val == TRUE) return 1; if (lit->val == FALSE) return -1; return 0; } static void minautarky (PS * ps) { unsigned * occs, maxoccs, tmpoccs, npartial; int * p, * c, lit, best, val; #ifdef LOGGING int tl; #endif assert (!ps->partial); npartial = 0; NEWN (occs, 2*ps->max_var + 1); CLRN (occs, 2*ps->max_var + 1); occs += ps->max_var; for (p = ps->soclauses; p < ps->sohead; p++) occs[*p]++; assert (occs[0] == ps->oadded); for (c = ps->soclauses; c < ps->sohead; c = p + 1) { #ifdef LOGGING tl = 0; #endif best = 0; maxoccs = 0; for (p = c; (lit = *p); p++) { val = tderef (ps, lit); if (val < 0) continue; if (val > 0) { #ifdef LOGGING tl = 1; #endif best = lit; maxoccs = occs[lit]; } val = pderef (ps, lit); if (val > 0) break; if (val < 0) continue; val = int2lit (ps, lit)->val; assert (val); if (val < 0) continue; tmpoccs = occs[lit]; if (best && tmpoccs <= maxoccs) continue; best = lit; maxoccs = tmpoccs; } if (!lit) { assert (best); LOG ( picosat_fprintf (ps->out, "%sautark %d with %d occs%s\n", ps->prefix, best, maxoccs, tl ? " (top)" : "")); ps->vars[abs (best)].partial = 1; npartial++; } for (p = c; (lit = *p); p++) { assert (occs[lit] > 0); occs[lit]--; } } occs -= ps->max_var; DELETEN (occs, 2*ps->max_var + 1); ps->partial = 1; if (ps->verbosity) picosat_fprintf (ps->out, "%sautarky of size %u out of %u satisfying all clauses (%.1f%%)\n", ps->prefix, npartial, ps->max_var, PERCENT (npartial, ps->max_var)); } void picosat_assume (PS * ps, int int_lit) { Lit *lit; if (ps->measurealltimeinlib) enter (ps); else check_ready (ps); if (ps->state != READY) reset_incremental_usage (ps); assume_contexts (ps); lit = import_lit (ps, int_lit, 1); assume (ps, lit); if (ps->measurealltimeinlib) leave (ps); } int picosat_sat (PS * ps, int l) { int res; char ch; enter (ps); ps->calls++; LOG ( picosat_fprintf (ps->out, "%sSTART call %u\n", ps->prefix, ps->calls)); if (ps->added < ps->ahead) { #ifndef NADC if (ps->addingtoado) ABORT ("API usage: incomplete all different constraint"); else #endif ABORT ("API usage: incomplete clause"); } if (ps->state != READY) reset_incremental_usage (ps); assume_contexts (ps); res = sat (ps, l); assert (ps->state == READY); switch (res) { case PICOSAT_UNSATISFIABLE: ch = '0'; ps->state = UNSAT; break; case PICOSAT_SATISFIABLE: ch = '1'; ps->state = SAT; break; default: ch = '?'; ps->state = UNKNOWN; break; } if (ps->verbosity) { report (ps, 1, ch); rheader (ps); } leave (ps); LOG ( picosat_fprintf (ps->out, "%sEND call %u result %d\n", ps->prefix, ps->calls, res)); ps->last_sat_call_result = res; return res; } int picosat_res (PS * ps) { return ps->last_sat_call_result; } int picosat_deref (PS * ps, int int_lit) { Lit *lit; check_ready (ps); check_sat_state (ps); ABORTIF (!int_lit, "API usage: can not deref zero literal"); ABORTIF (ps->mtcls, "API usage: deref after empty clause generated"); #ifdef STATS ps->derefs++; #endif if (abs (int_lit) > (int) ps->max_var) return 0; lit = int2lit (ps, int_lit); if (lit->val == TRUE) return 1; if (lit->val == FALSE) return -1; return 0; } int picosat_deref_toplevel (PS * ps, int int_lit) { check_ready (ps); ABORTIF (!int_lit, "API usage: can not deref zero literal"); #ifdef STATS ps->derefs++; #endif if (abs (int_lit) > (int) ps->max_var) return 0; return tderef (ps, int_lit); } int picosat_inconsistent (PS * ps) { check_ready (ps); return ps->mtcls != 0; } int picosat_corelit (PS * ps, int int_lit) { check_ready (ps); check_unsat_state (ps); ABORTIF (!int_lit, "API usage: zero literal can not be in core"); assert (ps->mtcls || ps->failed_assumption); #ifdef TRACE { int res = 0; ABORTIF (!ps->trace, "tracing disabled"); if (ps->measurealltimeinlib) enter (ps); core (ps); if (abs (int_lit) <= (int) ps->max_var) res = ps->vars[abs (int_lit)].core; assert (!res || ps->failed_assumption || ps->vars[abs (int_lit)].used); if (ps->measurealltimeinlib) leave (ps); return res; } #else ABORT ("compiled without trace support"); return 0; #endif } int picosat_coreclause (PS * ps, int ocls) { check_ready (ps); check_unsat_state (ps); ABORTIF (ocls < 0, "API usage: negative original clause index"); ABORTIF (ocls >= (int)ps->oadded, "API usage: original clause index exceeded"); assert (ps->mtcls || ps->failed_assumption); #ifdef TRACE { Cls ** clsptr, * c; int res = 0; ABORTIF (!ps->trace, "tracing disabled"); if (ps->measurealltimeinlib) enter (ps); core (ps); clsptr = ps->oclauses + ocls; assert (clsptr < ps->ohead); c = *clsptr; if (c) res = c->core; if (ps->measurealltimeinlib) leave (ps); return res; } #else ABORT ("compiled without trace support"); return 0; #endif } int picosat_failed_assumption (PS * ps, int int_lit) { Lit * lit; Var * v; ABORTIF (!int_lit, "API usage: zero literal as assumption"); check_ready (ps); check_unsat_state (ps); if (ps->mtcls) return 0; assert (ps->failed_assumption); if (abs (int_lit) > (int) ps->max_var) return 0; if (!ps->extracted_all_failed_assumptions) extract_all_failed_assumptions (ps); lit = import_lit (ps, int_lit, 1); v = LIT2VAR (lit); return v->failed; } int picosat_failed_context (PS * ps, int int_lit) { Lit * lit; Var * v; ABORTIF (!int_lit, "API usage: zero literal as context"); ABORTIF (abs (int_lit) > (int) ps->max_var, "API usage: invalid context"); check_ready (ps); check_unsat_state (ps); assert (ps->failed_assumption); if (!ps->extracted_all_failed_assumptions) extract_all_failed_assumptions (ps); lit = import_lit (ps, int_lit, 0); v = LIT2VAR (lit); return v->failed; } const int * picosat_failed_assumptions (PS * ps) { Lit ** p, * lit; Var * v; int ilit; ps->falshead = ps->fals; check_ready (ps); check_unsat_state (ps); if (!ps->mtcls) { assert (ps->failed_assumption); if (!ps->extracted_all_failed_assumptions) extract_all_failed_assumptions (ps); for (p = ps->als; p < ps->alshead; p++) { lit = *p; v = LIT2VAR (*p); if (!v->failed) continue; ilit = LIT2INT (lit); if (ps->falshead == ps->eofals) ENLARGE (ps->fals, ps->falshead, ps->eofals); *ps->falshead++ = ilit; } } if (ps->falshead == ps->eofals) ENLARGE (ps->fals, ps->falshead, ps->eofals); *ps->falshead++ = 0; return ps->fals; } const int * picosat_mus_assumptions (PS * ps, void * s, void (*cb)(void*,const int*), int fix) { int i, j, ilit, len, norig = ps->alshead - ps->als, nwork, * work, res; signed char * redundant; Lit ** p, * lit; int failed; Var * v; #ifndef NDEBUG int oldlen; #endif check_ready (ps); check_unsat_state (ps); len = 0; if (!ps->mtcls) { assert (ps->failed_assumption); if (!ps->extracted_all_failed_assumptions) extract_all_failed_assumptions (ps); for (p = ps->als; p < ps->alshead; p++) if (LIT2VAR (*p)->failed) len++; } if (ps->mass) DELETEN (ps->mass, ps->szmass); ps->szmass = len + 1; NEWN (ps->mass, ps->szmass); i = 0; for (p = ps->als; p < ps->alshead; p++) { lit = *p; v = LIT2VAR (lit); if (!v->failed) continue; ilit = LIT2INT (lit); assert (i < len); ps->mass[i++] = ilit; } assert (i == len); ps->mass[i] = 0; if (ps->verbosity) picosat_fprintf (ps->out, "%sinitial set of failed assumptions of size %d out of %d (%.0f%%)\n", ps->prefix, len, norig, PERCENT (len, norig)); if (cb) cb (s, ps->mass); nwork = len; NEWN (work, nwork); for (i = 0; i < len; i++) work[i] = ps->mass[i]; NEWN (redundant, nwork); CLRN (redundant, nwork); for (i = 0; i < nwork; i++) { if (redundant[i]) continue; if (ps->verbosity > 1) picosat_fprintf (ps->out, "%strying to drop %d%s assumption %d\n", ps->prefix, i, enumstr (i), work[i]); for (j = 0; j < nwork; j++) { if (i == j) continue; if (j < i && fix) continue; if (redundant[j]) continue; picosat_assume (ps, work[j]); } res = picosat_sat (ps, -1); if (res == 10) { if (ps->verbosity > 1) picosat_fprintf (ps->out, "%sfailed to drop %d%s assumption %d\n", ps->prefix, i, enumstr (i), work[i]); if (fix) { picosat_add (ps, work[i]); picosat_add (ps, 0); } } else { assert (res == 20); if (ps->verbosity > 1) picosat_fprintf (ps->out, "%ssuceeded to drop %d%s assumption %d\n", ps->prefix, i, enumstr (i), work[i]); redundant[i] = 1; for (j = 0; j < nwork; j++) { failed = picosat_failed_assumption (ps, work[j]); if (j <= i) { assert ((j < i && fix) || redundant[j] == !failed); continue; } if (!failed) { redundant[j] = -1; if (ps->verbosity > 1) picosat_fprintf (ps->out, "%salso suceeded to drop %d%s assumption %d\n", ps->prefix, j, enumstr (j), work[j]); } } #ifndef NDEBUG oldlen = len; #endif len = 0; for (j = 0; j < nwork; j++) if (!redundant[j]) ps->mass[len++] = work[j]; ps->mass[len] = 0; assert (len < oldlen); if (fix) { picosat_add (ps, -work[i]); picosat_add (ps, 0); } #ifndef NDEBUG for (j = 0; j <= i; j++) assert (redundant[j] >= 0); #endif for (j = i + 1; j < nwork; j++) { if (redundant[j] >= 0) continue; if (fix) { picosat_add (ps, -work[j]); picosat_add (ps, 0); } redundant[j] = 1; } if (ps->verbosity) picosat_fprintf (ps->out, "%sreduced set of failed assumptions of size %d out of %d (%.0f%%)\n", ps->prefix, len, norig, PERCENT (len, norig)); if (cb) cb (s, ps->mass); } } DELETEN (work, nwork); DELETEN (redundant, nwork); if (ps->verbosity) { picosat_fprintf (ps->out, "%sreinitializing unsat state\n", ps->prefix); fflush (ps->out); } for (i = 0; i < len; i++) picosat_assume (ps, ps->mass[i]); #ifndef NDEBUG res = #endif picosat_sat (ps, -1); assert (res == 20); if (!ps->mtcls) { assert (!ps->extracted_all_failed_assumptions); extract_all_failed_assumptions (ps); } return ps->mass; } static const int * mss (PS * ps, int * a, int size) { int i, j, k, res; assert (!ps->mtcls); if (ps->szmssass) DELETEN (ps->mssass, ps->szmssass); ps->szmssass = 0; ps->mssass = 0; ps->szmssass = size + 1; NEWN (ps->mssass, ps->szmssass); LOG ( picosat_fprintf (ps->out, "%ssearch MSS over %d assumptions\n", ps->prefix, size)); k = 0; for (i = k; i < size; i++) { for (j = 0; j < k; j++) picosat_assume (ps, ps->mssass[j]); LOG ( picosat_fprintf (ps->out, "%strying to add assumption %d to MSS : %d\n", ps->prefix, i, a[i])); picosat_assume (ps, a[i]); res = picosat_sat (ps, -1); if (res == 10) { LOG ( picosat_fprintf (ps->out, "%sadding assumption %d to MSS : %d\n", ps->prefix, i, a[i])); ps->mssass[k++] = a[i]; for (j = i + 1; j < size; j++) { if (picosat_deref (ps, a[j]) <= 0) continue; LOG ( picosat_fprintf (ps->out, "%salso adding assumption %d to MSS : %d\n", ps->prefix, j, a[j])); ps->mssass[k++] = a[j]; if (++i != j) { int tmp = a[i]; a[i] = a[j]; a[j] = tmp; } } } else { assert (res == 20); LOG ( picosat_fprintf (ps->out, "%signoring assumption %d in MSS : %d\n", ps->prefix, i, a[i])); } } ps->mssass[k] = 0; LOG ( picosat_fprintf (ps->out, "%sfound MSS of size %d\n", ps->prefix, k)); return ps->mssass; } static void reassume (PS * ps, const int * a, int size) { int i; LOG ( picosat_fprintf (ps->out, "%sreassuming all assumptions\n", ps->prefix)); for (i = 0; i < size; i++) picosat_assume (ps, a[i]); } const int * picosat_maximal_satisfiable_subset_of_assumptions (PS * ps) { const int * res; int i, *a, size; ABORTIF (ps->mtcls, "API usage: CNF inconsistent (use 'picosat_inconsistent')"); enter (ps); size = ps->alshead - ps->als; NEWN (a, size); for (i = 0; i < size; i++) a[i] = LIT2INT (ps->als[i]); res = mss (ps, a, size); reassume (ps, a, size); DELETEN (a, size); leave (ps); return res; } static void check_mss_flags_clean (PS * ps) { #ifndef NDEBUG unsigned i; for (i = 1; i <= ps->max_var; i++) { assert (!ps->vars[i].msspos); assert (!ps->vars[i].mssneg); } #else (void) ps; #endif } static void push_mcsass (PS * ps, int lit) { if (ps->nmcsass == ps->szmcsass) { ps->szmcsass = ps->szmcsass ? 2*ps->szmcsass : 1; RESIZEN (ps->mcsass, ps->nmcsass, ps->szmcsass); } ps->mcsass[ps->nmcsass++] = lit; } static const int * next_mss (PS * ps, int mcs) { int i, *a, size, mssize, mcsize, lit, inmss; const int * res, * p; Var * v; if (ps->mtcls) return 0; check_mss_flags_clean (ps); if (mcs && ps->mcsass) { DELETEN (ps->mcsass, ps->szmcsass); ps->nmcsass = ps->szmcsass = 0; ps->mcsass = 0; } size = ps->alshead - ps->als; NEWN (a, size); for (i = 0; i < size; i++) a[i] = LIT2INT (ps->als[i]); (void) picosat_sat (ps, -1); //TODO short cut for 'picosat_res () == 10'? if (ps->mtcls) { assert (picosat_res (ps) == 20); res = 0; goto DONE; } res = mss (ps, a, size); if (ps->mtcls) { res = 0; goto DONE; } for (p = res; (lit = *p); p++) { v = ps->vars + abs (lit); if (lit < 0) { assert (!v->msspos); v->mssneg = 1; } else { assert (!v->mssneg); v->msspos = 1; } } mssize = p - res; mcsize = INT_MIN; for (i = 0; i < size; i++) { lit = a[i]; v = ps->vars + abs (lit); if (lit > 0 && v->msspos) inmss = 1; else if (lit < 0 && v->mssneg) inmss = 1; else inmss = 0; if (mssize < mcsize) { if (inmss) picosat_add (ps, -lit); } else { if (!inmss) picosat_add (ps, lit); } if (!inmss && mcs) push_mcsass (ps, lit); } picosat_add (ps, 0); if (mcs) push_mcsass (ps, 0); for (i = 0; i < size; i++) { lit = a[i]; v = ps->vars + abs (lit); v->msspos = 0; v->mssneg = 0; } DONE: reassume (ps, a, size); DELETEN (a, size); return res; } const int * picosat_next_maximal_satisfiable_subset_of_assumptions (PS * ps) { const int * res; enter (ps); res = next_mss (ps, 0); leave (ps); return res; } const int * picosat_next_minimal_correcting_subset_of_assumptions (PS * ps) { const int * res, * tmp; enter (ps); tmp = next_mss (ps, 1); res = tmp ? ps->mcsass : 0; leave (ps); return res; } const int * picosat_humus (PS * ps, void (*callback)(void*state,int nmcs,int nhumus), void * state) { int lit, nmcs, j, nhumus; const int * mcs, * p; unsigned i; Var * v; enter (ps); #ifndef NDEBUG for (i = 1; i <= ps->max_var; i++) { v = ps->vars + i; assert (!v->humuspos); assert (!v->humusneg); } #endif nhumus = nmcs = 0; while ((mcs = picosat_next_minimal_correcting_subset_of_assumptions (ps))) { for (p = mcs; (lit = *p); p++) { v = ps->vars + abs (lit); if (lit < 0) { if (!v->humusneg) { v->humusneg = 1; nhumus++; } } else { if (!v->humuspos) { v->humuspos = 1; nhumus++; } } } nmcs++; LOG ( picosat_fprintf (ps->out, "%smcs %d of size %d humus %d\n", ps->prefix, nmcs, (int)(p - mcs), nhumus)); if (callback) callback (state, nmcs, nhumus); } assert (!ps->szhumus); ps->szhumus = 1; for (i = 1; i <= ps->max_var; i++) { v = ps->vars + i; if (v->humuspos) ps->szhumus++; if (v->humusneg) ps->szhumus++; } assert (nhumus + 1 == ps->szhumus); NEWN (ps->humus, ps->szhumus); j = 0; for (i = 1; i <= ps->max_var; i++) { v = ps->vars + i; if (v->humuspos) { assert (j < nhumus); ps->humus[j++] = (int) i; } if (v->humusneg) { assert (j < nhumus); assert (i < INT_MAX); ps->humus[j++] = - (int) i; } } assert (j == nhumus); assert (j < ps->szhumus); ps->humus[j] = 0; leave (ps); return ps->humus; } int picosat_usedlit (PS * ps, int int_lit) { int res; check_ready (ps); check_sat_or_unsat_or_unknown_state (ps); ABORTIF (!int_lit, "API usage: zero literal can not be used"); int_lit = abs (int_lit); res = (int_lit <= (int) ps->max_var) ? ps->vars[int_lit].used : 0; return res; } void picosat_write_clausal_core (PS * ps, FILE * file) { check_trace_support_and_execute (ps, file, write_core_wrapper, 0); } void picosat_write_compact_trace (PS * ps, FILE * file) { check_trace_support_and_execute (ps, file, write_trace, COMPACT_TRACECHECK_TRACE_FMT); } void picosat_write_extended_trace (PS * ps, FILE * file) { check_trace_support_and_execute (ps, file, write_trace, EXTENDED_TRACECHECK_TRACE_FMT); } void picosat_write_rup_trace (PS * ps, FILE * file) { check_trace_support_and_execute (ps, file, write_trace, RUP_TRACE_FMT); } size_t picosat_max_bytes_allocated (PS * ps) { check_ready (ps); return ps->max_bytes; } void picosat_set_propagation_limit (PS * ps, unsigned long long l) { ps->lpropagations = l; } unsigned long long picosat_propagations (PS * ps) { return ps->propagations; } unsigned long long picosat_visits (PS * ps) { return ps->visits; } unsigned long long picosat_decisions (PS * ps) { return ps->decisions; } int picosat_variables (PS * ps) { check_ready (ps); return (int) ps->max_var; } int picosat_added_original_clauses (PS * ps) { check_ready (ps); return (int) ps->oadded; } void picosat_stats (PS * ps) { unsigned redlits; #ifdef STATS check_ready (ps); assert (ps->sdecisions + ps->rdecisions + ps->assumptions == ps->decisions); #endif if (ps->calls > 1) picosat_fprintf (ps->out, "%s%u calls\n", ps->prefix, ps->calls); if (ps->contexts) { picosat_fprintf (ps->out, "%s%u contexts", ps->prefix, ps->contexts); #ifdef STATS picosat_fprintf (ps->out, " %u internal variables", ps->internals); #endif picosat_fprintf (ps->out, "\n"); } picosat_fprintf (ps->out, "%s%u iterations\n", ps->prefix, ps->iterations); picosat_fprintf (ps->out, "%s%u restarts", ps->prefix, ps->restarts); #ifdef STATS picosat_fprintf (ps->out, " (%u skipped)", ps->skippedrestarts); #endif picosat_fputc ('\n', ps->out); #ifndef NFL picosat_fprintf (ps->out, "%s%u failed literals", ps->prefix, ps->failedlits); #ifdef STATS picosat_fprintf (ps->out, ", %u calls, %u rounds, %llu propagations", ps->flcalls, ps->flrounds, ps->flprops); #endif picosat_fputc ('\n', ps->out); #ifdef STATS picosat_fprintf (ps->out, "%sfl: %u = %.1f%% implicit, %llu oopsed, %llu tried, %llu skipped\n", ps->prefix, ps->ifailedlits, PERCENT (ps->ifailedlits, ps->failedlits), ps->floopsed, ps->fltried, ps->flskipped); #endif #endif picosat_fprintf (ps->out, "%s%u conflicts", ps->prefix, ps->conflicts); #ifdef STATS picosat_fprintf (ps->out, " (%u uips = %.1f%%)\n", ps->uips, PERCENT(ps->uips,ps->conflicts)); #else picosat_fputc ('\n', ps->out); #endif #ifndef NADC picosat_fprintf (ps->out, "%s%u adc conflicts\n", ps->prefix, ps->adoconflicts); #endif #ifdef STATS picosat_fprintf (ps->out, "%s%llu dereferenced literals\n", ps->prefix, ps->derefs); #endif picosat_fprintf (ps->out, "%s%u decisions", ps->prefix, ps->decisions); #ifdef STATS picosat_fprintf (ps->out, " (%u random = %.2f%%", ps->rdecisions, PERCENT (ps->rdecisions, ps->decisions)); picosat_fprintf (ps->out, ", %u assumptions", ps->assumptions); picosat_fputc (')', ps->out); #endif picosat_fputc ('\n', ps->out); #ifdef STATS picosat_fprintf (ps->out, "%s%u static phase decisions (%.1f%% of all variables)\n", ps->prefix, ps->staticphasedecisions, PERCENT (ps->staticphasedecisions, ps->max_var)); #endif picosat_fprintf (ps->out, "%s%u fixed variables\n", ps->prefix, ps->fixed); assert (ps->nonminimizedllits >= ps->minimizedllits); redlits = ps->nonminimizedllits - ps->minimizedllits; picosat_fprintf (ps->out, "%s%u learned literals\n", ps->prefix, ps->llitsadded); picosat_fprintf (ps->out, "%s%.1f%% deleted literals\n", ps->prefix, PERCENT (redlits, ps->nonminimizedllits)); #ifdef STATS #ifdef TRACE picosat_fprintf (ps->out, "%s%llu antecedents (%.1f antecedents per clause", ps->prefix, ps->antecedents, AVERAGE (ps->antecedents, ps->conflicts)); if (ps->trace) picosat_fprintf (ps->out, ", %.1f bytes/antecedent)", AVERAGE (ps->znts, ps->antecedents)); picosat_fputs (")\n", ps->out); #endif picosat_fprintf (ps->out, "%s%llu propagations (%.1f propagations per decision)\n", ps->prefix, ps->propagations, AVERAGE (ps->propagations, ps->decisions)); picosat_fprintf (ps->out, "%s%llu visits (%.1f per propagation)\n", ps->prefix, ps->visits, AVERAGE (ps->visits, ps->propagations)); picosat_fprintf (ps->out, "%s%llu binary clauses visited (%.1f%% %.1f per propagation)\n", ps->prefix, ps->bvisits, PERCENT (ps->bvisits, ps->visits), AVERAGE (ps->bvisits, ps->propagations)); picosat_fprintf (ps->out, "%s%llu ternary clauses visited (%.1f%% %.1f per propagation)\n", ps->prefix, ps->tvisits, PERCENT (ps->tvisits, ps->visits), AVERAGE (ps->tvisits, ps->propagations)); picosat_fprintf (ps->out, "%s%llu large clauses visited (%.1f%% %.1f per propagation)\n", ps->prefix, ps->lvisits, PERCENT (ps->lvisits, ps->visits), AVERAGE (ps->lvisits, ps->propagations)); picosat_fprintf (ps->out, "%s%llu other true (%.1f%% of visited clauses)\n", ps->prefix, ps->othertrue, PERCENT (ps->othertrue, ps->visits)); picosat_fprintf (ps->out, "%s%llu other true in binary clauses (%.1f%%)" ", %llu upper (%.1f%%)\n", ps->prefix, ps->othertrue2, PERCENT (ps->othertrue2, ps->othertrue), ps->othertrue2u, PERCENT (ps->othertrue2u, ps->othertrue2)); picosat_fprintf (ps->out, "%s%llu other true in large clauses (%.1f%%)" ", %llu upper (%.1f%%)\n", ps->prefix, ps->othertruel, PERCENT (ps->othertruel, ps->othertrue), ps->othertruelu, PERCENT (ps->othertruelu, ps->othertruel)); picosat_fprintf (ps->out, "%s%llu ternary and large traversals (%.1f per visit)\n", ps->prefix, ps->traversals, AVERAGE (ps->traversals, ps->visits)); picosat_fprintf (ps->out, "%s%llu large traversals (%.1f per large visit)\n", ps->prefix, ps->ltraversals, AVERAGE (ps->ltraversals, ps->lvisits)); picosat_fprintf (ps->out, "%s%llu assignments\n", ps->prefix, ps->assignments); #else picosat_fprintf (ps->out, "%s%llu propagations\n", ps->prefix, picosat_propagations (ps)); picosat_fprintf (ps->out, "%s%llu visits\n", ps->prefix, picosat_visits (ps)); #endif picosat_fprintf (ps->out, "%s%.1f%% variables used\n", ps->prefix, PERCENT (ps->vused, ps->max_var)); sflush (ps); picosat_fprintf (ps->out, "%s%.1f seconds in library\n", ps->prefix, ps->seconds); picosat_fprintf (ps->out, "%s%.1f megaprops/second\n", ps->prefix, AVERAGE (ps->propagations / 1e6f, ps->seconds)); picosat_fprintf (ps->out, "%s%.1f megavisits/second\n", ps->prefix, AVERAGE (ps->visits / 1e6f, ps->seconds)); picosat_fprintf (ps->out, "%sprobing %.1f seconds %.0f%%\n", ps->prefix, ps->flseconds, PERCENT (ps->flseconds, ps->seconds)); #ifdef STATS picosat_fprintf (ps->out, "%srecycled %.1f MB in %u reductions\n", ps->prefix, ps->rrecycled / (double) (1 << 20), ps->reductions); picosat_fprintf (ps->out, "%srecycled %.1f MB in %u simplifications\n", ps->prefix, ps->srecycled / (double) (1 << 20), ps->simps); #else picosat_fprintf (ps->out, "%s%u simplifications\n", ps->prefix, ps->simps); picosat_fprintf (ps->out, "%s%u reductions\n", ps->prefix, ps->reductions); picosat_fprintf (ps->out, "%s%.1f MB recycled\n", ps->prefix, ps->recycled / (double) (1 << 20)); #endif picosat_fprintf (ps->out, "%s%.1f MB maximally allocated\n", ps->prefix, picosat_max_bytes_allocated (ps) / (double) (1 << 20)); } #ifndef NGETRUSAGE #include #include #include #endif double picosat_time_stamp (void) { double res = -1; #ifndef NGETRUSAGE struct rusage u; res = 0; if (!getrusage (RUSAGE_SELF, &u)) { res += u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec; res += u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec; } #endif return res; } double picosat_seconds (PS * ps) { check_ready (ps); return ps->seconds; } void picosat_print (PS * ps, FILE * file) { #ifdef NO_BINARY_CLAUSES Lit * lit, *other, * last; Ltk * stack; #endif Lit **q, **eol; Cls **p, *c; unsigned n; if (ps->measurealltimeinlib) enter (ps); else check_ready (ps); n = 0; n += ps->alshead - ps->als; for (p = SOC; p != EOC; p = NXC (p)) { c = *p; if (!c) continue; #ifdef TRACE if (c->collected) continue; #endif n++; } #ifdef NO_BINARY_CLAUSES last = int2lit (ps, -ps->max_var); for (lit = int2lit (ps, 1); lit <= last; lit++) { stack = LIT2IMPLS (lit); eol = stack->start + stack->count; for (q = stack->start; q < eol; q++) if (*q >= lit) n++; } #endif picosat_fprintf (file, "p cnf %d %u\n", ps->max_var, n); for (p = SOC; p != EOC; p = NXC (p)) { c = *p; if (!c) continue; #ifdef TRACE if (c->collected) continue; #endif eol = end_of_lits (c); for (q = c->lits; q < eol; q++) picosat_fprintf (file, "%d ", LIT2INT (*q)); picosat_fputs ("0\n", file); } #ifdef NO_BINARY_CLAUSES last = int2lit (ps, -ps->max_var); for (lit = int2lit (ps, 1); lit <= last; lit++) { stack = LIT2IMPLS (lit); eol = stack->start + stack->count; for (q = stack->start; q < eol; q++) if ((other = *q) >= lit) picosat_fprintf (file, "%d %d 0\n", LIT2INT (lit), LIT2INT (other)); } #endif { Lit **r; for (r = ps->als; r < ps->alshead; r++) picosat_fprintf (file, "%d 0\n", LIT2INT (*r)); } fflush (file); if (ps->measurealltimeinlib) leave (ps); } void picosat_enter (PS * ps) { enter (ps); } void picosat_leave (PS * ps) { leave (ps); } void picosat_message (PS * ps, int vlevel, const char * fmt, ...) { va_list ap; if (vlevel > ps->verbosity) return; picosat_fputs (ps->prefix, ps->out); va_start (ap, fmt); picosat_vfprintf (ps->out, fmt, ap); va_end (ap); picosat_fputc ('\n', ps->out); } int picosat_changed (PS * ps) { int res; check_ready (ps); check_sat_state (ps); res = (ps->min_flipped <= ps->saved_max_var); assert (!res || ps->saved_flips != ps->flips); return res; } void picosat_reset_phases (PS * ps) { rebias (ps); } void picosat_reset_scores (PS * ps) { Rnk * r; ps->hhead = ps->heap + 1; for (r = ps->rnks + 1; r <= ps->rnks + ps->max_var; r++) { CLR (r); hpush (ps, r); } } void picosat_remove_learned (PS * ps, unsigned percentage) { enter (ps); reset_incremental_usage (ps); reduce (ps, percentage); leave (ps); } void picosat_set_global_default_phase (PS * ps, int phase) { check_ready (ps); ABORTIF (phase < 0, "API usage: 'picosat_set_global_default_phase' " "with negative argument"); ABORTIF (phase > 3, "API usage: 'picosat_set_global_default_phase' " "with argument > 3"); ps->defaultphase = phase; } void picosat_set_default_phase_lit (PS * ps, int int_lit, int phase) { unsigned newphase; Lit * lit; Var * v; check_ready (ps); lit = import_lit (ps, int_lit, 1); v = LIT2VAR (lit); if (phase) { newphase = (int_lit < 0) == (phase < 0); v->defphase = v->phase = newphase; v->usedefphase = v->assigned = 1; } else { v->usedefphase = v->assigned = 0; } } void picosat_set_more_important_lit (PS * ps, int int_lit) { Lit * lit; Var * v; Rnk * r; check_ready (ps); lit = import_lit (ps, int_lit, 1); v = LIT2VAR (lit); r = VAR2RNK (v); ABORTIF (r->lessimportant, "can not mark variable more and less important"); if (r->moreimportant) return; r->moreimportant = 1; if (r->pos) hup (ps, r); } void picosat_set_less_important_lit (PS * ps, int int_lit) { Lit * lit; Var * v; Rnk * r; check_ready (ps); lit = import_lit (ps, int_lit, 1); v = LIT2VAR (lit); r = VAR2RNK (v); ABORTIF (r->moreimportant, "can not mark variable more and less important"); if (r->lessimportant) return; r->lessimportant = 1; if (r->pos) hdown (ps, r); } #ifndef NADC unsigned picosat_ado_conflicts (PS * ps) { check_ready (ps); return ps->adoconflicts; } void picosat_disable_ado (PS * ps) { check_ready (ps); assert (!ps->adodisabled); ps->adodisabled = 1; } void picosat_enable_ado (PS * ps) { check_ready (ps); assert (ps->adodisabled); ps->adodisabled = 0; } void picosat_set_ado_conflict_limit (unsigned newadoconflictlimit) { check_ready (ps); ps->adoconflictlimit = newadoconflictlimit; } #endif void picosat_simplify (PS * ps) { enter (ps); reset_incremental_usage (ps); simplify (ps, 1); leave (ps); } int picosat_haveados (void) { #ifndef NADC return 1; #else return 0; #endif } void picosat_save_original_clauses (PS * ps) { if (ps->saveorig) return; ABORTIF (ps->oadded, "API usage: 'picosat_save_original_clauses' too late"); ps->saveorig = 1; } void picosat_set_interrupt (PicoSAT * ps, void * external_state, int (*interrupted)(void * external_state)) { ps->interrupt.state = external_state; ps->interrupt.function = interrupted; } int picosat_deref_partial (PS * ps, int int_lit) { check_ready (ps); check_sat_state (ps); ABORTIF (!int_lit, "API usage: can not partial deref zero literal"); ABORTIF (ps->mtcls, "API usage: deref partial after empty clause generated"); ABORTIF (!ps->saveorig, "API usage: 'picosat_save_original_clauses' missing"); #ifdef STATS ps->derefs++; #endif if (!ps->partial) minautarky (ps); return pderef (ps, int_lit); } BoolNet/src/attractor_search_interface.c0000644000176200001440000002766113451410121020123 0ustar liggesusers#include #include #include "statespace_search.h" #include "sat_search.h" #include "common.h" /** * Identification of attractors */ #define SYNC_MODE_STATE_SPACE 0 #define ASYNC_MODE_RANDOM 1 #define SYNC_MODE_SAT_EXHAUSTIVE 2 #define SYNC_MODE_SAT_RESTRICTED 3 /** * The R wrapper function for getAttractors. * Arguments: * inputGenes An integer vector containing the concatenated input gene lists * of *all* transition functions * inputGenePositions A vector of positions to split up for each transition function * transitionFunctions The concatenated truth table result columns of the transition functions of all genes. * transitionFunctionPositions A vector of positions to split up for each transition function. * fixedGenes A vector that contains -1 for all genes that can be both ON and OFF, 1 for genes that are always ON, * and 0 for genes that are always OFF. * specialInitializations A matrix of special initializations supplied by the user. The first row contains the genes, * the second row contains the corresponding initialization values. * startStates An optional array of encoded states used to initialize the heuristics * (not needed for exhaustive search) * simType An integer that determines whether a synchronous, asynchronous or SAT-based search is performed * geneProbabilities For asynchronous search, the probabilities of each gene to be chosen for update * randomSteps For asynchronous search, the number of random transitions performed to reach a potential attractor * avoidSelfLoops If set to true, self loops are only allowed if no other transitions are possible, which reduces the * number of edges in the attractors * returnTable If set to true and networkType is synchronous, the transition table is included in the return value. * maxAttractorSize The maximum attractor length for SAT-based search */ SEXP getAttractors_R(SEXP inputGenes, SEXP inputGenePositions, SEXP transitionFunctions, SEXP transitionFunctionPositions, SEXP fixedGenes, SEXP startStates, SEXP simType, SEXP geneProbabilities, SEXP randomSteps, SEXP avoidSelfLoops, SEXP returnTable, SEXP maxAttractorSize) { GetRNGstate(); // decode information in SEXP for use in C TruthTableBooleanNetwork network; network.type = TRUTHTABLE_BOOLEAN_NETWORK; network.numGenes = length(fixedGenes); network.inputGenes = INTEGER(inputGenes); network.inputGenePositions = INTEGER(inputGenePositions); network.transitionFunctions = INTEGER(transitionFunctions); network.transitionFunctionPositions = INTEGER(transitionFunctionPositions); network.fixedGenes = INTEGER(fixedGenes); network.nonFixedGeneBits = CALLOC(network.numGenes, sizeof(unsigned int)); int _networkType = *INTEGER(simType); int _randomSteps = *INTEGER(randomSteps); bool _returnTable = (bool) (*INTEGER(returnTable)); bool _avoidSelfLoops = (bool) (*INTEGER(avoidSelfLoops)); double * _probabilities = NULL; if (!isNull(geneProbabilities) && length(geneProbabilities) > 0) _probabilities = REAL(geneProbabilities); // count fixed genes, and create an index array for non-fixed genes: // contains the bit positions in a state // at which the -th gene is stored - this is different from // as fixed genes are not stored unsigned int numNonFixed = 0, i; for (i = 0; i < network.numGenes; i++) { if (network.fixedGenes[i] == -1) { network.nonFixedGeneBits[i] = numNonFixed++; } } pAttractorInfo res; if (_networkType == SYNC_MODE_STATE_SPACE && (isNull(startStates) || length(startStates) == 0)) // no start states supplied => perform exhaustive search { // calculate transition table unsigned long long * table = getTransitionTable(&network); if (table == 0) { PutRNGstate(); return R_NilValue; } unsigned long long numStates = (unsigned long long) 1 << numNonFixed;//pow(2,numNonFixed); // find attractors res = getAttractors(table, numStates, network.numGenes); } else // start states supplied or SAT search { unsigned int numElts; if (network.numGenes % BITS_PER_BLOCK_32 == 0) numElts = network.numGenes / BITS_PER_BLOCK_32; else numElts = network.numGenes / BITS_PER_BLOCK_32 + 1; unsigned int* _startStates = (unsigned int*) INTEGER(startStates); if (_networkType == SYNC_MODE_STATE_SPACE) { for (unsigned int i = 0; i < length(startStates) / numElts; ++i) { removeFixedGenes(&_startStates[i * numElts], network.fixedGenes, network.numGenes); } res = getAttractorsForStates(_startStates, length(startStates) / numElts, &network); } else if (_networkType == SYNC_MODE_SAT_EXHAUSTIVE) { int _maxAttractorSize; if (isNull(maxAttractorSize)) { _maxAttractorSize = 1; } else _maxAttractorSize = *INTEGER(maxAttractorSize); res = getAttractors_SAT_exhaustive( (BooleanNetwork *) &network, _maxAttractorSize, EXTENSION_MIXED); } else if (_networkType == SYNC_MODE_SAT_RESTRICTED) { res = getAttractors_SAT_maxLength((BooleanNetwork *) &network, *INTEGER(maxAttractorSize)); } else { res = getLooseAttractors(_startStates, length(startStates) / numElts, &network, _randomSteps, _avoidSelfLoops, _probabilities); } } // pack results in SEXP structure for return value SEXP stateInfoSXP; if (res->tableSize != 0 && _returnTable) stateInfoSXP = allocList(4); else stateInfoSXP = R_NilValue; PROTECT(stateInfoSXP); //1 int* array; if (res->tableSize != 0 && _returnTable) { // create a 3-element list for the transition table //PROTECT(stateInfoSXP = allocList(4)); SET_TAG(stateInfoSXP, install("table")); SET_TAG(CDR(stateInfoSXP), install("attractorAssignment")); SET_TAG(CDR(CDR(stateInfoSXP)), install("stepsToAttractor")); SET_TAG(CDR(CDR(CDR(stateInfoSXP))), install("initialStates")); // write transition table result column SEXP tableSXP; PROTECT( tableSXP = allocVector(INTSXP,res->tableSize * res->numElementsPerEntry)); //2 array = INTEGER(tableSXP); for (i = 0; i < res->tableSize; ++i) { // the transition table results do not contain fixed genes => insert them insertFixedGenes(&res->table[i * res->numElementsPerEntry], network.fixedGenes, network.numGenes); memcpy(&array[i * res->numElementsPerEntry], &res->table[i * res->numElementsPerEntry], res->numElementsPerEntry * sizeof(unsigned int)); } SETCAR(stateInfoSXP, tableSXP); UNPROTECT(1); //tableSXP 1 // write attractor assignment vector for states in transition table SEXP assignmentSXP; PROTECT(assignmentSXP = allocVector(INTSXP,res->tableSize)); //2 array = INTEGER(assignmentSXP); memcpy(array, res->attractorAssignment, res->tableSize * sizeof(int)); SETCADR(stateInfoSXP, assignmentSXP); UNPROTECT(1); //assignmentSXP 1 // write a vector with number of transitions from a state to an attractor SEXP stepSXP; PROTECT(stepSXP = allocVector(INTSXP,res->tableSize)); //2 array = INTEGER(stepSXP); memcpy(array, res->stepsToAttractor, res->tableSize * sizeof(int)); SETCADDR(stateInfoSXP, stepSXP); UNPROTECT(1); //stepSXP 1 // if available, write the original states SEXP initialStateSXP; if (res->initialStates == 0) PROTECT(initialStateSXP = R_NilValue); //2 else // if start states are specified, the initial states for each transition have to be saved as well, // as they cannot be inferred by enumeration { PROTECT( initialStateSXP = allocVector(INTSXP,res->tableSize * res->numElementsPerEntry)); //2 array = INTEGER(initialStateSXP); for (i = 0; i < res->tableSize; ++i) { // the transition table results do not contain fixed genes => insert them insertFixedGenes( &res->initialStates[i * res->numElementsPerEntry], network.fixedGenes, network.numGenes); memcpy(&array[i * res->numElementsPerEntry], &res->initialStates[i * res->numElementsPerEntry], res->numElementsPerEntry * sizeof(unsigned int)); } } SETCADDDR(stateInfoSXP, initialStateSXP); UNPROTECT(1); //initialStateSXP 1 } // count attractors unsigned int numAttractors = 0; pAttractor el; for (el = res->attractorList; el->next != NULL; el = el->next) ++numAttractors; // write attractors SEXP attractorsSXP; PROTECT(attractorsSXP = allocList(numAttractors)); //2 SEXP listPos = attractorsSXP; for (el = res->attractorList, i = 0; el->next != NULL; el = el->next, ++i) { SEXP attractorSXP; // each attractor is a 2-element list with a list of states included // in the attractor and the size of the basin if (el->transitionTableSize == 0) attractorSXP = allocList(2); else attractorSXP = allocList(4); PROTECT(attractorSXP); //3 SET_TAG(attractorSXP, install("involvedStates")); SET_TAG(CDR(attractorSXP), install("basinSize")); if (el->transitionTableSize != 0) { SET_TAG(CDR(CDR(attractorSXP)), install("initialStates")); SET_TAG(CDR(CDR(CDR(attractorSXP))), install("nextStates")); } SEXP stateSXP; PROTECT(stateSXP = allocVector(INTSXP,el->length * el->numElementsPerEntry)); //4 array = INTEGER(stateSXP); for (i = 0; i < el->length; ++i) { if (_networkType == SYNC_MODE_STATE_SPACE) // insert fixed gene values, as they are missing in the calculated results insertFixedGenes( &el->involvedStates[i * el->numElementsPerEntry], network.fixedGenes, network.numGenes); memcpy(&array[i * el->numElementsPerEntry], &el->involvedStates[i * el->numElementsPerEntry], el->numElementsPerEntry * sizeof(unsigned int)); } SETCAR(attractorSXP, stateSXP); // write basin size SEXP basinSXP; PROTECT(basinSXP = allocVector(INTSXP,1)); //5 array = INTEGER(basinSXP); array[0] = el->basinSize; SETCADR(attractorSXP, basinSXP); SETCAR(listPos, attractorSXP); if (el->next != NULL) listPos = CDR(listPos); if (el->transitionTableSize != 0) { SEXP attrInitialStateSXP; SEXP attrNextStateSXP; PROTECT(attrInitialStateSXP = allocVector(INTSXP,el->numElementsPerEntry * el->transitionTableSize)); //6 PROTECT(attrNextStateSXP = allocVector(INTSXP,el->numElementsPerEntry * el->transitionTableSize)); //7 unsigned int * initial = (unsigned int*) INTEGER( attrInitialStateSXP); unsigned int * next = (unsigned int*) INTEGER(attrNextStateSXP); TransitionTableEntry * currentState = el->table; for (i = 0; i < el->transitionTableSize; ++i) { memcpy(&initial[i * el->numElementsPerEntry], currentState->initialState, sizeof(unsigned int) * el->numElementsPerEntry); memcpy(&next[i * el->numElementsPerEntry], currentState->nextState, sizeof(unsigned int) * el->numElementsPerEntry); currentState = currentState->next; } SETCADDR(attractorSXP, attrInitialStateSXP); SETCADDDR(attractorSXP, attrNextStateSXP); UNPROTECT(2); //attrInitialStateSXP,attrNextStateSXP 5 } UNPROTECT(3); //basinSXP,stateSXP,attractorSXP //2 } SEXP resSXP; // create a result list with two elements (attractors and transition table) PROTECT(resSXP = allocList(2)); //3 SET_TAG(resSXP, install("stateInfo")); SET_TAG(CDR(resSXP), install("attractors")); SETCADR(resSXP, attractorsSXP); SETCAR(resSXP, stateInfoSXP); PutRNGstate(); UNPROTECT(3); // free resources freeAttractorInfo(res); FREE(network.nonFixedGeneBits); return (resSXP); } BoolNet/src/attractor_info.c0000644000176200001440000000254313277247010015574 0ustar liggesusers#include "attractor_info.h" #include "common.h" /** * Allocate a new AttractorInfo structure for states */ pAttractorInfo allocAttractorInfo(unsigned long long tableSize, unsigned int numGenes) { pAttractorInfo res = (pAttractorInfo)CALLOC(1,sizeof(AttractorInfo)); if ((numGenes % BITS_PER_BLOCK_32) == 0) res->numElementsPerEntry = numGenes/BITS_PER_BLOCK_32; else res->numElementsPerEntry = numGenes/BITS_PER_BLOCK_32 + 1; res->numAttractors = 0; res->table = NULL; res->tableSize = tableSize; res->initialStates = NULL; res->table = (unsigned int*) CALLOC(tableSize * res->numElementsPerEntry,sizeof(unsigned int)); res->attractorAssignment = (unsigned int*) CALLOC(tableSize,sizeof(unsigned int)); res->stepsToAttractor = (unsigned int*) CALLOC(tableSize,sizeof(unsigned int)); return res; } /** * Free a list of attractor structures */ void freeAttractorList(pAttractor p) { do { pAttractor next = p->next; if (p->involvedStates != NULL) FREE(p->involvedStates); FREE(p); p = next; } while(p != NULL); } /** * Free an AttractorInfo structure including * all sub-elements and the attractor list */ void freeAttractorInfo(pAttractorInfo p) { if (p->initialStates != 0) FREE(p->initialStates); FREE(p->table); FREE(p->attractorAssignment); FREE(p->stepsToAttractor); freeAttractorList(p->attractorList); FREE(p); } BoolNet/src/symbolic_simulator.c0000644000176200001440000011176414377062452016513 0ustar liggesusers#include #include #include #include #include #include #include #include #include #include "symbolic_network.h" #include "uthash.h" #include "common.h" #include "random.h" #include "sat_search.h" #define STATEHASH_ARRAY_SIZE 1024 /** * A list element containing the states of one attractor */ typedef struct ASLE { TemporalState ** states; unsigned int numStates; struct ASLE * next; unsigned int index; } TemporalAttractorStateListElement; /** * A list comprising attractors */ typedef struct { TemporalAttractorStateListElement * head; TemporalAttractorStateListElement * tail; unsigned int size; } TemporalAttractorStateList; /** * A hash structure for state sets */ typedef struct SH { UT_hash_handle hh; struct SH * nextState; unsigned int sequenceIndex; TemporalState * initialState; } TemporalStateHash; /** * A structure for mapping states to attractors */ typedef struct { UT_hash_handle hh; TemporalAttractorStateListElement * attractor; TemporalState * state; } TemporalAttractorHash; /** * A wrapper structure for a state set */ typedef struct { ArrayListElement * hashStructs; ArrayListElement * stateStructs; TemporalStateHash * table; unsigned int stateSize; unsigned int internalStateSize; unsigned int hashSize; unsigned int currentEntryHash; unsigned int poolArraySize; } TemporalStateHashTable; /** * A wrapper structure for a map * mapping states to attractors */ typedef struct { ArrayListElement * hashStructs; ArrayListElement * stateStructs; TemporalAttractorHash * table; unsigned int stateSize; unsigned int internalStateSize; unsigned int currentEntryHash; unsigned int poolArraySize; } AttractorHashTable; /** * Functions to handle hash tables for states and attractors */ TemporalStateHashTable * allocStateHashTable(unsigned int stateSize) { TemporalStateHashTable * res = CALLOC(1, sizeof(TemporalStateHashTable)); res->hashStructs = NULL; res->stateStructs = NULL; res->stateSize = stateSize; // ensure proper alignment of states in array if (stateSize % sizeof(unsigned long long) == 0) res->internalStateSize = stateSize; else res->internalStateSize = ((stateSize / sizeof(unsigned long long)) * sizeof(unsigned long long) + sizeof(unsigned long long)); res->hashSize = offsetof(TemporalState, state) + stateSize * sizeof(unsigned char); res->table = NULL; res->currentEntryHash = 0; res->poolArraySize = STATEHASH_ARRAY_SIZE; return res; } AttractorHashTable * allocAttractorHashTable(unsigned int stateSize) { AttractorHashTable * res = CALLOC(1, sizeof(AttractorHashTable)); res->hashStructs = NULL; res->stateStructs = NULL; res->stateSize = stateSize; // ensure proper alignment of states in array if (stateSize % sizeof(unsigned long long) == 0) res->internalStateSize = stateSize; else res->internalStateSize = ((stateSize / sizeof(unsigned long long)) * sizeof(unsigned long long) + sizeof(unsigned long long)); res->table = NULL; res->currentEntryHash = 0; res->poolArraySize = STATEHASH_ARRAY_SIZE; return res; } void freeStateHashTable(TemporalStateHashTable * hash) { TemporalStateHash * entry, *tmp; HASH_ITER(hh, hash->table, entry, tmp) { HASH_DEL(hash->table, entry); } freeArrayList(hash->hashStructs); freeArrayList(hash->stateStructs); FREE(hash); } void freeAttractorHashTable(AttractorHashTable * hash) { TemporalAttractorHash * entry, *tmp; HASH_ITER(hh, hash->table, entry, tmp) { HASH_DEL(hash->table, entry); } freeArrayList(hash->hashStructs); freeArrayList(hash->stateStructs); FREE(hash); } /** * Decode a sequence of states as a state-memory representation and * returns it in . * is the network to which the state belongs. * is the number of entries in the state vector. */ inline static void decodeState(SymbolicBooleanNetwork * network, int * state, unsigned int stateLength, TemporalState * result) { unsigned int numStates = stateLength / network->numGenes; unsigned int i, j; memset(result, 0, sizeof(TemporalState) + network->totalStateSize * sizeof(unsigned char)); for (i = 0; i < network->numGenes; ++i) { for (j = 0; j < network->stateSizes[i]; ++j) { if (j < numStates) result->state[network->stateOffsets[i] + j] = state[i * numStates + j]; else result->state[network->stateOffsets[i] + j] = state[(i + 1) * numStates - 1]; } } } /** * Check whether a stat transition pair has already been traversed, and store it in the hash * table otherwise. * is the hash table for the lookup. * is the next state after the state transition. * receives the initial state of the transition if it was found. * If is true, the absolute time point is not stored in the table. * is the index of the sequence to which the transition belongs. * Returns true if the state was found, and false otherwise. */ bool findOrStore(TemporalStateHashTable * hash, TemporalStateHash ** initialState, TemporalState * nextState, bool dropTimeInfo, unsigned int sequenceIndex) { //TemporalState * search = CALLOC(1, sizeof(StateHash) + sizeof(unsigned char) * hash->stateSize); //memcpy(search, nextState, sizeof(TemporalState) + sizeof(unsigned char) * hash->stateSize); //if (dropTimeInfo) //{ // search->timeStep = HASH_UNSET; // search->startState = HASH_UNSET; //} TemporalStateHash * res = NULL; if (dropTimeInfo) { HASH_FIND(hh, hash->table, nextState->state, hash->stateSize, res); } else { HASH_FIND(hh, hash->table, nextState, hash->hashSize, res); } if (res != NULL) { if (*initialState != NULL) (*initialState)->nextState = res; *initialState = res; return true; } if (hash->currentEntryHash % hash->poolArraySize == 0) { allocNewArray(&hash->hashStructs, hash->poolArraySize, sizeof(TemporalStateHash)); allocNewArray(&hash->stateStructs, hash->poolArraySize, sizeof(TemporalState) + sizeof(unsigned char) * hash->internalStateSize); } res = (TemporalStateHash *) (((unsigned char *) hash->hashStructs->array) + sizeof(TemporalStateHash) * (hash->currentEntryHash % hash->poolArraySize)); res->initialState = (TemporalState *) (((unsigned char *) hash->stateStructs->array) + (sizeof(TemporalState) + sizeof(unsigned char) * hash->internalStateSize) * (hash->currentEntryHash % hash->poolArraySize)); memcpy(res->initialState, nextState, sizeof(TemporalState) + sizeof(unsigned char) * hash->stateSize); res->sequenceIndex = sequenceIndex; ++hash->currentEntryHash; if (*initialState != NULL) { (*initialState)->nextState = res; } //unsigned int i; //for (i = 0; i < hash->hashSize; ++i) // Rprintf("%x",((unsigned char *)&res->initialState)[i]); if (dropTimeInfo) { HASH_ADD(hh, hash->table, initialState->state, hash->stateSize, res); } else { HASH_ADD_KEYPTR(hh, hash->table, res->initialState, hash->hashSize, res); } *initialState = res; return false; } TemporalAttractorHash * addAttractorHashEntry(AttractorHashTable * hash, TemporalState * state, TemporalAttractorStateListElement * listElement) { if (hash->currentEntryHash % hash->poolArraySize == 0) { allocNewArray(&hash->hashStructs, hash->poolArraySize, sizeof(TemporalAttractorHash)); allocNewArray(&hash->stateStructs, hash->poolArraySize, sizeof(TemporalState) + sizeof(unsigned char) * hash->internalStateSize); } TemporalAttractorHash * res = (TemporalAttractorHash *) (((unsigned char *) hash->hashStructs->array) + sizeof(TemporalAttractorHash) * (hash->currentEntryHash % hash->poolArraySize)); res->state = (TemporalState *) (((unsigned char *) hash->stateStructs->array) + (sizeof(TemporalState) + sizeof(unsigned char) * hash->internalStateSize) * (hash->currentEntryHash % hash->poolArraySize)); memcpy(res->state, state, sizeof(TemporalState) + sizeof(unsigned char) * hash->stateSize); res->attractor = listElement; ++hash->currentEntryHash; HASH_ADD(hh, hash->table, state->state, hash->stateSize, res); return res; } /** * Find the attractor belonging to state in the hash table * and return it if it exists. */ TemporalAttractorStateListElement * getAttractorForState( AttractorHashTable * hash, TemporalState * state) { TemporalAttractorHash * res = NULL; HASH_FIND(hh, hash->table, state->state, hash->stateSize, res); if (res == NULL) { return NULL; } else { return res->attractor; } } /** * Allocate a list structure that stores attractors */ TemporalAttractorStateList * allocAttractorStateList(void) { TemporalAttractorStateList * res = CALLOC(1, sizeof(TemporalAttractorStateList)); res->size = 0; res->head = res->tail = NULL; return res; } /** * Add an empty attractor entry to the attractor list . * is the number of states of the attractor. * Returns the empty entry. */ TemporalAttractorStateListElement * addAttractor( TemporalAttractorStateList * list, unsigned int numStates) { TemporalAttractorStateListElement * res = CALLOC(1, sizeof(TemporalAttractorStateListElement)); res->numStates = numStates; res->states = CALLOC(numStates, sizeof(TemporalState *)); if (list->head == NULL) { list->head = res; res->index = 0; } else { list->tail->next = res; res->index = list->tail->index + 1; } ++list->size; list->tail = res; return res; } /** * Free all entries of the attractor list */ void freeAttractorStateList(TemporalAttractorStateList * list) { TemporalAttractorStateListElement * current = list->head, *tmp; while (true) { if (current == NULL) break; tmp = current; current = current->next; FREE(tmp->states); FREE(tmp); } FREE(list); } /** * Perform a state transition of the network from state * at the absolute time point . * Assigns the successor state to . */ void symbolicStateTransition(SymbolicBooleanNetwork * network, TemporalState * currentState, TemporalState * nextState, unsigned int * timeStep) { unsigned int i; for (i = 0; i < network->numGenes; ++i) { if (network->stateSizes[i] > 1) memcpy(&nextState->state[network->stateOffsets[i] + 1], ¤tState->state[network->stateOffsets[i]], (network->stateSizes[i] - 1) * sizeof(unsigned char)); if (network->fixedGenes[i] != -1) nextState->state[network->stateOffsets[i]] = network->fixedGenes[i]; else nextState->state[network->stateOffsets[i]] = evaluate( network->interactions[i], currentState, network->stateOffsets, network->numGenes); } nextState->timeStep = *timeStep; nextState->startState = currentState->startState; ++*timeStep; } /** * Finalizer that ensures that the internal C structures * of the R network object are freed when the * garbage collector frees . */ static void finalizeSymbolicNetwork(SEXP network) { if (NULL == R_ExternalPtrAddr(network)) return; //Rprintf("finalizing\n"); SymbolicBooleanNetwork * _network = R_ExternalPtrAddr(network); freeSymbolicNetwork(_network); R_ClearExternalPtr(network); } /** * Parse an R list specifying an expression tree and convert it to the * internal representation. * is a vector specifying the size of the history for each gene. * is the time step at which the last predicate that * depends on the absolute time point has obtained its final value. * is a Boolean vector that is set to true if the gene occurs in the formula * and to false otherwise. * Returns an internal tree representation of . */ BooleanFormula * parseRTree(SEXP formula, unsigned int * memorySizes, unsigned int * attractorSearchStartTime, bool * geneOccurs) { if (strcmp(CHAR(STRING_ELT(getListElement(formula, "type"), 0)), "atom") == 0) { BooleanAtom * res = allocAtom( *INTEGER(getListElement(formula, "index")) - 1, -*INTEGER(getListElement(formula, "time")) - 1, *LOGICAL(getListElement(formula, "negated"))); if (res->literal >= 0) { if (geneOccurs != NULL) geneOccurs[res->literal] = true; if (memorySizes[res->literal] < res->time + 1) { memorySizes[res->literal] = res->time + 1; } } return (BooleanFormula *) res; } else if (strcmp(CHAR(STRING_ELT(getListElement(formula, "type"), 0)), "constant") == 0) { Constant * res = allocConstant( *INTEGER(getListElement(formula, "value")), *LOGICAL(getListElement(formula, "negated"))); return (BooleanFormula *) res; } else { const char * operator = CHAR( STRING_ELT(getListElement(formula, "operator"), 0)); unsigned int op; if (strcmp(operator, "|") == 0) op = OPERATOR_OR; else if (strcmp(operator, "&") == 0) op = OPERATOR_AND; else if (strcmp(operator, "maj") == 0) op = OPERATOR_MAJ; else if (strcmp(operator, "sumis") == 0) op = OPERATOR_SUMIS; else if (strcmp(operator, "sumgt") == 0) op = OPERATOR_SUMGT; else if (strcmp(operator, "sumlt") == 0) op = OPERATOR_SUMLT; else if (strcmp(operator, "timeis") == 0) op = OPERATOR_TIMEIS; else if (strcmp(operator, "timegt") == 0) op = OPERATOR_TIMEGT; else if (strcmp(operator, "timelt") == 0) op = OPERATOR_TIMELT; else error("Unknown operator!"); SEXP operands = getListElement(formula, "operands"); BooleanOperator * res = allocOperator(op, *LOGICAL(getListElement(formula, "negated")), length(operands), NULL); unsigned int i; for (i = 0; i < length(operands); ++i) { res->operands[i] = parseRTree(VECTOR_ELT(operands, i), memorySizes, attractorSearchStartTime, geneOccurs); } if (res->operator == OPERATOR_TIMEIS || res->operator == OPERATOR_TIMEGT || res->operator == OPERATOR_TIMELT) { if (res->numOperands < 1|| res->operands[0]->type != FORMULA_CONSTANT) error("Time operator has an invalid specification!"); Constant * constant = ((Constant*) res->operands[0]); unsigned int value = constant->value; if (res->operator == OPERATOR_TIMELT) --value; if (value >= *attractorSearchStartTime) *attractorSearchStartTime = value; } return (BooleanFormula *) res; } } /** * R interface function to perform a state transition of * the network from state * at the absolute time point . * Returns the successor state. */ SEXP symbolicStateTransition_R(SEXP network, SEXP previousState, SEXP timeStep) { SymbolicBooleanNetwork * _network = R_ExternalPtrAddr(network); if (_network == NULL) error("Internal network structures not supplied to C handler!"); unsigned int _timeStep = *INTEGER(timeStep), k; TemporalState * current = CALLOC(1, sizeof(TemporalState) + _network->totalStateSize * sizeof(unsigned char)); TemporalState * next = CALLOC(1, sizeof(TemporalState) + _network->totalStateSize * sizeof(unsigned char)); decodeState(_network, INTEGER(previousState), length(previousState), current); current->timeStep = _timeStep; symbolicStateTransition(_network, current, next, &_timeStep); SEXP retSXP; PROTECT(retSXP = allocVector(INTSXP, _network->numGenes)); int * resultState = INTEGER(retSXP); for (k = 0; k < _network->numGenes; ++k) { resultState[k] = next->state[_network->stateOffsets[k]]; } UNPROTECT(1); FREE(next); FREE(current); return retSXP; } /** * Convert a Boolean expression tree to a * truth table representation. * is the total number of genes in the network. * Returns a binary vector representing the truth table result column. */ SEXP getTruthTable_R(SEXP tree, SEXP numGenes) { int _numGenes = *INTEGER(numGenes); unsigned int attractorSearchStartTime = 0; unsigned int * stateSizes = CALLOC(_numGenes, sizeof(unsigned int)); unsigned int * stateOffsets = CALLOC(_numGenes, sizeof(unsigned int)); bool * geneOccurs = CALLOC(_numGenes, sizeof(bool)); unsigned int i, j; for (i = 0; i < _numGenes; ++i) { stateSizes[i] = 1; } BooleanFormula * _tree = parseRTree(tree, stateSizes, &attractorSearchStartTime, geneOccurs); if (attractorSearchStartTime > 0) { freeFormula(_tree); FREE(stateSizes); FREE(stateOffsets); FREE(geneOccurs); Rf_error( "Temporal operators are not allowed in the truth table representation!"); } unsigned int geneCount = 0; for (i = 0; i < _numGenes; ++i) { if (stateSizes[i] > 1) { freeFormula(_tree); FREE(stateSizes); FREE(stateOffsets); FREE(geneOccurs); Rf_error( "Temporal operators are not allowed in the truth table representation!"); } stateOffsets[i] = geneCount; if (geneOccurs[i]) ++geneCount; } SEXP res = PROTECT(allocList(2)); SEXP table = PROTECT(allocVector(INTSXP, 1 << geneCount)); SEXP genes = PROTECT(allocVector(INTSXP, (geneCount == 0? 1 : geneCount))); if (geneCount == 0) *INTEGER(genes) = 0; else { j = 0; for (i = 0; i < _numGenes; ++i) { if (geneOccurs[i]) { INTEGER(genes)[j++] = i + 1; } } } TemporalState * current = CALLOC(1, sizeof(TemporalState) + geneCount * sizeof(unsigned char)); memset(current, 0, sizeof(TemporalState) + geneCount * sizeof(unsigned char)); int * tableEntry = INTEGER(table); do { current->timeStep = 0; *tableEntry = evaluate(_tree, current, stateOffsets, geneCount); ++tableEntry; } while (getNextState(current->state, NULL, geneCount)); SETCAR(res, genes); SETCADR(res, table); freeFormula(_tree); FREE(stateSizes); FREE(stateOffsets); FREE(geneOccurs); UNPROTECT(3); return res; } /** * Construct the internal expression tree representation * of a symbolic network specified by the R object */ SEXP constructNetworkTrees_R(SEXP object) { SymbolicBooleanNetwork * network = calloc(1, sizeof(SymbolicBooleanNetwork)); SEXP interactions = getListElement(object, "interactions"); SEXP fixed = getListElement(object, "fixed"); network->type = SYMBOLIC_BOOLEAN_NETWORK; network->numGenes = length(interactions); network->attractorSearchStartTime = 0; network->stateSizes = calloc(network->numGenes, sizeof(unsigned int)); network->stateOffsets = calloc(network->numGenes + 1, sizeof(unsigned int)); network->fixedGenes = calloc(network->numGenes, sizeof(int)); network->interactions = calloc(network->numGenes, sizeof(BooleanFormula *)); unsigned int i, j; for (i = 0; i < network->numGenes; ++i) { network->fixedGenes[i] = INTEGER(fixed)[i]; network->stateSizes[i] = 1; } for (i = 0; i < network->numGenes; ++i) { network->interactions[i] = parseRTree(VECTOR_ELT(interactions, i), network->stateSizes, &network->attractorSearchStartTime, NULL); //printFormula(network->interactions[i]); //Rprintf("\n"); } network->totalStateSize = 0; for (i = 0; i < network->numGenes; ++i) { network->stateOffsets[i] = network->totalStateSize; network->totalStateSize += network->stateSizes[i]; } network->stateOffsets[network->numGenes] = network->totalStateSize; network->stateFixed = calloc(network->totalStateSize, sizeof(int)); for (i = 0; i < network->numGenes; ++i) { for (j = 0; j < network->stateSizes[i]; ++j) { network->stateFixed[network->stateOffsets[i] + j] = network->fixedGenes[i]; } } SEXP res = PROTECT( R_MakeExternalPtr(network, install("CStructures"), R_NilValue)); R_RegisterCFinalizerEx(res, finalizeSymbolicNetwork, true); UNPROTECT(1); return res; } BooleanFormula * getSATFormula(unsigned int targetIndex, BooleanFormula * formula, unsigned int time) { // create a formula of the form target <=> factors, i.e. // (target & factors) | (!target & !factors) // outer and BooleanOperator * extendedInteraction = allocOperator(OPERATOR_OR, false, 2, NULL); // target literal BooleanAtom * target = allocAtom(targetIndex, 0, false); // inner conjunctions BooleanOperator * firstConjunction = allocOperator(OPERATOR_AND, false, 2, NULL); BooleanOperator * secondConjunction = allocOperator(OPERATOR_AND, false, 2, NULL); // first conjunction: positive operands firstConjunction->operands[0] = (BooleanFormula *) target; // factors are considered one time step earlier than the target firstConjunction->operands[1] = copyFormula(formula, false, 1); // second conjunction: negated operands secondConjunction->operands[0] = copyFormula((BooleanFormula *) target, false, 0); secondConjunction->operands[0]->negated = !secondConjunction->operands[0]->negated; secondConjunction->operands[1] = copyFormula(formula, false, 1); secondConjunction->operands[1]->negated = !secondConjunction->operands[1]->negated; // assemble top-level DNF from conjunctions extendedInteraction->operands[0] = (BooleanFormula *) firstConjunction; extendedInteraction->operands[1] = (BooleanFormula *) secondConjunction; // convert whole top-level DNF to CNF, and store it in the network object BooleanFormula * res = convertToCNF((BooleanFormula *) extendedInteraction, false, time); // free temporary DNF freeFormula((BooleanFormula *) extendedInteraction); return res; } /** * Start an attractor search based on a SAT formulation of the * symbolic network . * is an optional parameter specifying the maximum attractor size. * If is true, a search for attractors of up to * is started. Otherwise, attractors are identified based on the approach by Dubrova and Teslenko. * Returns a list with four elements as simulateStates_R, where only the third element is non-null * and comprises the identified attractors */ SEXP symbolicSATSearch_R(SEXP network, SEXP maxAttractorSize, SEXP restrictedSearch) { SymbolicBooleanNetwork * _network = R_ExternalPtrAddr(network); bool _restrictedSearch = *LOGICAL(restrictedSearch); if (_network == NULL) error("Internal network structures not supplied to C handler!"); GetRNGstate(); unsigned int i, j, k; if (_network->cnfInteractions == NULL) // create a CNF representation of the formulae, including the // equivalence relations to the targets { _network->cnfInteractions = calloc(_network->numGenes, sizeof(BooleanFormula **)); for (i = 0; i < _network->numGenes; ++i) { _network->cnfInteractions[i] = calloc( _network->attractorSearchStartTime + 1, sizeof(BooleanFormula *)); for (j = 0; j <= _network->attractorSearchStartTime; ++j) { _network->cnfInteractions[i][j] = getSATFormula(i, _network->interactions[i], _network->attractorSearchStartTime - j); } } } pAttractorInfo res; if (!_restrictedSearch) // start exhaustive SAT search as described by Dubrova and Teslenko { int _maxAttractorSize; if (isNull(maxAttractorSize)) { _maxAttractorSize = 1; } else _maxAttractorSize = *INTEGER(maxAttractorSize); res = getAttractors_SAT_exhaustive((BooleanNetwork *) _network, _maxAttractorSize, EXTENSION_MIXED); } else // only search for cycles of a specified maximum length { res = getAttractors_SAT_maxLength((BooleanNetwork *) _network, *INTEGER(maxAttractorSize)); } SEXP retSXP, attractorListSXP, iterSXP; // create list with 3 empty elements to have same return value structure // as simulateStates_R PROTECT(retSXP = allocList(4)); PROTECT(iterSXP = attractorListSXP = allocList(res->numAttractors)); pAttractor el = res->attractorList; for (i = 0; i < res->numAttractors; ++i) { SEXP attractorSXP; PROTECT( attractorSXP = allocVector(INTSXP, el->length * _network->numGenes)); int * attractorStates = INTEGER(attractorSXP); for (j = 0; j < el->length; ++j) { for (k = 0; k < _network->numGenes; ++k) // decode bit vector in Attractor structure { attractorStates[j * _network->numGenes + k] = GET_BIT_ARRAY( el->involvedStates[j * el->numElementsPerEntry], k); } } SETCAR(iterSXP, attractorSXP); UNPROTECT(1); iterSXP = CDR(iterSXP); el = el->next; } SETCADDR(retSXP, attractorListSXP); PutRNGstate(); UNPROTECT(2); return (retSXP); } /** * Symbolic simulator that identifies attractors and generates sequences of states * and attractor graphs. * is a pointer to the C structures of a symbolic network. * is either a list of start states, an integer specifying the number of * random start states, or NULL for an exhaustive search. * is the maximum number of state transitions performed to find an attractor. * , and specify whether the return * value comprises the state sequences, the transition graph, and the attractors respectively. */ SEXP simulateStates_R(SEXP network, SEXP states, SEXP maxTransitions, SEXP returnSequences, SEXP returnGraph, SEXP returnAttractors) { SymbolicBooleanNetwork * _network = R_ExternalPtrAddr(network); if (_network == NULL) error("Internal network structures not supplied to C handler!"); unsigned int _maxTransitions = *INTEGER(maxTransitions); unsigned long long _numStates = length(states); unsigned long long i, j, k; unsigned int mode; unsigned char * randomStartStates = NULL; if (!Rf_isNull(states)) { if (IS_INTEGER(states)) // a number of start states to generate randomly is supplied { _numStates = *INTEGER(states); mode = MODE_RANDOM; GetRNGstate(); randomStartStates = CALLOC(_numStates, sizeof(unsigned char) * _network->totalStateSize); } else // the start states themselves are supplied { _numStates = length(states); mode = MODE_SUPPLIED; } } else // exhaustive search { unsigned int numNonFixed = 0; for (j = 0; j < _network->numGenes; ++j) { if (_network->fixedGenes[j] == -1) numNonFixed += _network->stateSizes[j]; } _numStates = (unsigned int) 1 << numNonFixed; mode = MODE_EXHAUSTIVE; } // allocate required structures bool _returnSequences = *LOGICAL(returnSequences); bool _returnGraph = *LOGICAL(returnGraph); bool _returnAttractors = *LOGICAL(returnAttractors); TemporalStateHashTable * hash = allocStateHashTable( _network->totalStateSize); TemporalStateHashTable * usedStates = NULL; AttractorHashTable * attractorHash = allocAttractorHashTable( _network->totalStateSize); TemporalState * current = CALLOC(1, sizeof(TemporalState) + _network->totalStateSize * sizeof(unsigned char)); TemporalState * currentStart = CALLOC(1, sizeof(TemporalState) + _network->totalStateSize * sizeof(unsigned char)); TemporalState * next = CALLOC(1, sizeof(TemporalState) + _network->totalStateSize * sizeof(unsigned char)); TemporalAttractorStateList * attractors = allocAttractorStateList(); unsigned long long stateCount = 0; unsigned long long * sequenceSizes = CALLOC(_numStates, sizeof(unsigned long long)); int * attractorIndices = CALLOC(_numStates, sizeof(int)); if (mode == MODE_EXHAUSTIVE) // generate first initial state for exhaustive search (all non-fixed genes set to 0) { for (j = 0; j < _network->totalStateSize; ++j) { if (_network->stateFixed[j] == -1) currentStart->state[j] = 0; else currentStart->state[j] = _network->stateFixed[j]; } } else if (mode == MODE_RANDOM) { usedStates = allocStateHashTable(_network->totalStateSize); } for (i = 0; i < _numStates; ++i) // iterate over start states { R_CheckUserInterrupt(); sequenceSizes[i] = 1; attractorIndices[i] = ~0; SEXP state; switch (mode) { case MODE_SUPPLIED: // take next start state from the input list state = VECTOR_ELT(states, i); decodeState(_network, INTEGER(state), length(state), currentStart); break; case MODE_RANDOM: // generate a random start state while (true) { TemporalStateHash * dummy = NULL; for (j = 0; j < _network->totalStateSize; ++j) { if (_network->stateFixed[j] == -1) currentStart->state[j] = randomStartStates[i * _network->totalStateSize + j] = intrand(2); else currentStart->state[j] = randomStartStates[i * _network->totalStateSize + j] = _network->stateFixed[j]; } // check whether the state has already been choosen as a start state if (!findOrStore(usedStates, &dummy, currentStart, true, 0)) break; } break; } currentStart->startState = i; currentStart->timeStep = 0; memcpy(current, currentStart, sizeof(TemporalState) + _network->totalStateSize * sizeof(unsigned char)); unsigned int timeStep = 1; TemporalStateHash * previous = NULL; if (!findOrStore(hash, &previous, current, _network->attractorSearchStartTime == 0, i)) ++stateCount; for (j = 0; j < _maxTransitions || _maxTransitions == 0; ++j) // calculate successor states { symbolicStateTransition(_network, current, next, &timeStep); if (findOrStore(hash, &previous, next, _network->attractorSearchStartTime < timeStep, i)) // a previously found state has been reached { if (next->startState == previous->initialState->startState) // a new attractor has been found { unsigned int attractorSize = timeStep - previous->initialState->timeStep - 1; TemporalAttractorStateListElement * el = addAttractor( attractors, attractorSize); attractorIndices[i] = el->index; for (k = 0; k < attractorSize; ++k) // enumerate attractor states { addAttractorHashEntry(attractorHash, previous->initialState, el); el->states[k] = previous->initialState; previous = previous->nextState; } if (attractorSize + 1 == timeStep) // If the whole sequence is an attractor, add the initial state at the end ++sequenceSizes[i]; } else // we have reached a sequence we traversed before // => determine sequence size etc. from previous run if (_returnSequences) { while (sequenceSizes[i] < _maxTransitions || _maxTransitions == 0) { if (previous == NULL) // not enough transitions) break; TemporalAttractorStateListElement * entry = getAttractorForState(attractorHash, previous->initialState); if (entry != NULL) { sequenceSizes[i] += entry->numStates; attractorIndices[i] = entry->index; break; } ++sequenceSizes[i]; previous = previous->nextState; } } break; } ++sequenceSizes[i]; ++stateCount; memcpy(current, next, sizeof(TemporalState) + _network->totalStateSize * sizeof(unsigned char)); } if (i < _numStates - 1 && mode == MODE_EXHAUSTIVE) // generate next state for exhaustive search { getNextState(currentStart->state, _network->stateFixed, _network->totalStateSize); } } SEXP retSXP, attractorListSXP, initialStatesSXP, nextStatesSXP, attractorAssignmentSXP, transitionSXP, iterSXP, graphSXP; PROTECT(retSXP = allocList(4)); if (_returnAttractors) // store attractor sequences in results { PROTECT(iterSXP = attractorListSXP = allocList(attractors->size)); TemporalAttractorStateListElement * el = attractors->head; for (i = 0; i < attractors->size; ++i) { SEXP attractorSXP; PROTECT( attractorSXP = allocVector(INTSXP, el->numStates * _network->numGenes)); int * attractorStates = INTEGER(attractorSXP); for (j = 0; j < el->numStates; ++j) { for (k = 0; k < _network->numGenes; ++k) { attractorStates[j * _network->numGenes + k] = el->states[j]->state[_network->stateOffsets[k]]; } } SETCAR(iterSXP, attractorSXP); UNPROTECT(1); iterSXP = CDR(iterSXP); el = el->next; } SETCADDR(retSXP, attractorListSXP); if (_returnSequences) // also store indices of attractors for the sequences { SEXP attractorIndexSXP; PROTECT(attractorIndexSXP = allocVector(INTSXP, _numStates)); memcpy(INTEGER(attractorIndexSXP), attractorIndices, sizeof(int) * _numStates); SETCADDDR(retSXP, attractorIndexSXP); UNPROTECT(1); } UNPROTECT(1); } if (_returnSequences) { // calculate maximum delay in the network unsigned int maxTimeDiff = 1; for (k = 0; k < _network->numGenes; ++k) { if (_network->stateSizes[k] > maxTimeDiff) maxTimeDiff = _network->stateSizes[k]; } PROTECT(iterSXP = transitionSXP = allocList(_numStates)); if (mode == MODE_EXHAUSTIVE) // again, regenerate first start state for exhaustive search { for (j = 0; j < _network->totalStateSize; ++j) { if (_network->stateFixed[j] == -1) currentStart->state[j] = 0; else currentStart->state[j] = _network->stateFixed[j]; } } for (i = 0; i < _numStates; ++i) // iterate over states { R_CheckUserInterrupt(); SEXP transitionStatesSXP; PROTECT( transitionStatesSXP = allocVector(INTSXP, ((maxTimeDiff - 1) + sequenceSizes[i]) * _network->numGenes)); int * transitionStates = INTEGER(transitionStatesSXP); SEXP state; switch (mode) { case MODE_SUPPLIED: state = VECTOR_ELT(states, i); decodeState(_network, INTEGER(state), length(state), currentStart); break; case MODE_RANDOM: memcpy(currentStart->state, &randomStartStates[i * _network->totalStateSize], sizeof(unsigned char) * _network->totalStateSize); break; } currentStart->startState = i; currentStart->timeStep = 0; unsigned int currentState = 0; for (j = 0; j < maxTimeDiff; ++j) { bool nextState = false; for (k = 0; k < _network->numGenes; ++k) { if (mode == MODE_SUPPLIED) // store supplied initial states in results { SEXP state = VECTOR_ELT(states, i); int * _state = INTEGER(state); unsigned int numStates = length(state) / _network->numGenes; if ((maxTimeDiff - j) <= numStates) { transitionStates[j * _network->numGenes + k] = _state[k * numStates + (numStates - currentState - 1)]; nextState = true; } else transitionStates[j * _network->numGenes + k] = _state[(k + 1) * numStates - 1]; } else // construct list of initial states from internal vector representation if (_network->stateSizes[k] >= maxTimeDiff - j) transitionStates[j * _network->numGenes + k] = currentStart->state[_network->stateOffsets[k] + (maxTimeDiff - j - 1)]; else transitionStates[j * _network->numGenes + k] = currentStart->state[_network->stateOffsets[k] + _network->stateSizes[k] - 1]; } if (nextState) { ++currentState; nextState = false; } } memcpy(current, currentStart, sizeof(TemporalState) + _network->totalStateSize * sizeof(unsigned char)); // get successor states from hash table TemporalStateHash * res; if (_network->attractorSearchStartTime == 0) HASH_FIND(hh, hash->table, current->state, hash->stateSize, res); else HASH_FIND(hh, hash->table, current, hash->hashSize, res); for (j = 0; j < sequenceSizes[i]; ++j) { if (res != NULL) // encode successor state for results { for (k = 0; k < _network->numGenes; ++k) { transitionStates[(maxTimeDiff + j - 1) * _network->numGenes + k] = res->initialState->state[_network->stateOffsets[k]]; } res = res->nextState; } else error("Did not find a required successor state!"); } SETCAR(iterSXP, transitionStatesSXP); iterSXP = CDR(iterSXP); UNPROTECT(1); if (mode == MODE_EXHAUSTIVE) // generate next start state for exhaustive search { getNextState(currentStart->state, _network->stateFixed, _network->totalStateSize); } } SETCAR(retSXP, transitionSXP); UNPROTECT(1); } if (mode == MODE_RANDOM) { FREE(randomStartStates); PutRNGstate(); } TemporalStateHash * entry, *tmp; if (_returnGraph) // generate the graph representation { PROTECT(graphSXP = allocList(3)); PROTECT( initialStatesSXP = allocVector(INTSXP,stateCount * _network->numGenes)); PROTECT( nextStatesSXP = allocVector(INTSXP,stateCount * _network->numGenes)); PROTECT(attractorAssignmentSXP = allocVector(INTSXP,stateCount)); int * initialStates = INTEGER(initialStatesSXP); int * nextStates = INTEGER(nextStatesSXP); int * attractorAssignment = INTEGER(attractorAssignmentSXP); // add all state pairs in the hash table to the graph i = 0; HASH_ITER(hh, hash->table, entry, tmp) { R_CheckUserInterrupt(); for (k = 0; k < _network->numGenes; ++k) { initialStates[i * _network->numGenes + k] = entry->initialState->state[_network->stateOffsets[k]]; if (entry->nextState != NULL) nextStates[i * _network->numGenes + k] = entry->nextState->initialState->state[_network->stateOffsets[k]]; else nextStates[i * _network->numGenes + k] = entry->initialState->state[_network->stateOffsets[k]]; } attractorAssignment[i] = attractorIndices[entry->sequenceIndex]; ++i; } SETCAR(graphSXP, initialStatesSXP); SETCADR(graphSXP, nextStatesSXP); SETCADDR(graphSXP, attractorAssignmentSXP); SETCADR(retSXP, graphSXP); UNPROTECT(4); } UNPROTECT(1); if (mode == MODE_RANDOM) freeStateHashTable(usedStates); freeStateHashTable(hash); freeAttractorHashTable(attractorHash); FREE(sequenceSizes); FREE(next); FREE(current); FREE(currentStart); FREE(attractorIndices); freeAttractorStateList(attractors); return retSXP; } /** * Check whether is a null pointer. */ SEXP checkNullPointerC(SEXP ptr) { void * p = R_ExternalPtrAddr(ptr); SEXP ret; PROTECT(ret = allocVector(LGLSXP,1)); *LOGICAL(ret) = (p == NULL); UNPROTECT(1); return (ret); } BoolNet/src/uthash.h0000644000176200001440000016264113277247010014065 0ustar liggesusers/* Copyright (c) 2003-2011, Troy D. Hanson http://uthash.sourceforge.net All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTHASH_H #define UTHASH_H #include /* memcmp,strlen */ #include /* ptrdiff_t */ #include /* exit() */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #ifdef _MSC_VER /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #define DECLTYPE(x) #endif #else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #ifdef NO_DECLTYPE #define DECLTYPE_ASSIGN(dst,src) \ do { \ char **_da_dst = (char**)(&(dst)); \ *_da_dst = (char*)(src); \ } while(0) #else #define DECLTYPE_ASSIGN(dst,src) \ do { \ (dst) = DECLTYPE(dst)(src); \ } while(0) #endif /* a number of the hash function use uint32_t which isn't defined on win32 */ #ifdef _MSC_VER typedef unsigned int uint32_t; typedef unsigned char uint8_t; #else #include /* uint32_t */ #endif #define UTHASH_VERSION 1.9.4 //Modified by C. Muessel for use in R #define uthash_fatal(msg) error(msg) /* fatal error (out of memory,etc) */ #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #define uthash_free(ptr,sz) free(ptr) /* free fcn */ #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #define uthash_expand_fyi(tbl) /* can be defined to log expands */ /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ #define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhe */ #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) #define HASH_FIND(hh,head,keyptr,keylen,out) \ do { \ unsigned _hf_bkt,_hf_hashv; \ out=NULL; \ if (head) { \ HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ keyptr,keylen,out); \ } \ } \ } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) #define HASH_BLOOM_MAKE(tbl) \ do { \ (tbl)->bloom_nbits = HASH_BLOOM; \ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ } while (0); #define HASH_BLOOM_FREE(tbl) \ do { \ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ } while (0); #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) #define HASH_BLOOM_ADD(tbl,hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) #define HASH_BLOOM_TEST(tbl,hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) #else #define HASH_BLOOM_MAKE(tbl) #define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_TEST(tbl,hashv) (1) #endif #define HASH_MAKE_TABLE(hh,head) \ do { \ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ sizeof(UT_hash_table)); \ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ (head)->hh.tbl->tail = &((head)->hh); \ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl->buckets, 0, \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_MAKE((head)->hh.tbl); \ (head)->hh.tbl->signature = HASH_SIGNATURE; \ } while(0) #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ do { \ unsigned _ha_bkt; \ (add)->hh.next = NULL; \ (add)->hh.key = (char*)keyptr; \ (add)->hh.keylen = keylen_in; \ if (!(head)) { \ head = (add); \ (head)->hh.prev = NULL; \ HASH_MAKE_TABLE(hh,head); \ } else { \ (head)->hh.tbl->tail->next = (add); \ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ (head)->hh.tbl->tail = &((add)->hh); \ } \ (head)->hh.tbl->num_items++; \ (add)->hh.tbl = (head)->hh.tbl; \ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ (add)->hh.hashv, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ HASH_FSCK(hh,head); \ } while(0) #define HASH_TO_BKT( hashv, num_bkts, bkt ) \ do { \ bkt = ((hashv) & ((num_bkts) - 1)); \ } while(0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. * The use of _hd_hh_del below deserves special explanation. * These used to be expressed using (delptr) but that led to a bug * if someone used the same symbol for the head and deletee, like * HASH_DELETE(hh,users,users); * We want that to work, but by changing the head (users) below * we were forfeiting our ability to further refer to the deletee (users) * in the patch-up process. Solution: use scratch space to * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ #define HASH_DELETE(hh,head,delptr) \ do { \ unsigned _hd_bkt; \ struct UT_hash_handle *_hd_hh_del; \ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ head = NULL; \ } else { \ _hd_hh_del = &((delptr)->hh); \ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ (head)->hh.tbl->tail = \ (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ (head)->hh.tbl->hho); \ } \ if ((delptr)->hh.prev) { \ ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ } else { \ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ } \ if (_hd_hh_del->next) { \ ((UT_hash_handle*)((char*)_hd_hh_del->next + \ (head)->hh.tbl->hho))->prev = \ _hd_hh_del->prev; \ } \ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ (head)->hh.tbl->num_items--; \ } \ HASH_FSCK(hh,head); \ } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ #define HASH_FIND_STR(head,findstr,out) \ HASH_FIND(hh,head,findstr,strlen(findstr),out) #define HASH_ADD_STR(head,strfield,add) \ HASH_ADD(hh,head,strfield,strlen(add->strfield),add) #define HASH_FIND_INT(head,findint,out) \ HASH_FIND(hh,head,findint,sizeof(int),out) #define HASH_ADD_INT(head,intfield,add) \ HASH_ADD(hh,head,intfield,sizeof(int),add) #define HASH_FIND_PTR(head,findptr,out) \ HASH_FIND(hh,head,findptr,sizeof(void *),out) #define HASH_ADD_PTR(head,ptrfield,add) \ HASH_ADD(hh,head,ptrfield,sizeof(void *),add) #define HASH_DEL(head,delptr) \ HASH_DELETE(hh,head,delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) #define HASH_FSCK(hh,head) \ do { \ unsigned _bkt_i; \ unsigned _count, _bkt_count; \ char *_prev; \ struct UT_hash_handle *_thh; \ if (head) { \ _count = 0; \ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ _bkt_count = 0; \ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ _prev = NULL; \ while (_thh) { \ if (_prev != (char*)(_thh->hh_prev)) { \ HASH_OOPS("invalid hh_prev %p, actual %p\n", \ _thh->hh_prev, _prev ); \ } \ _bkt_count++; \ _prev = (char*)(_thh); \ _thh = _thh->hh_next; \ } \ _count += _bkt_count; \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ HASH_OOPS("invalid bucket count %d, actual %d\n", \ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid hh item count %d, actual %d\n", \ (head)->hh.tbl->num_items, _count ); \ } \ /* traverse hh in app order; check next/prev integrity, count */ \ _count = 0; \ _prev = NULL; \ _thh = &(head)->hh; \ while (_thh) { \ _count++; \ if (_prev !=(char*)(_thh->prev)) { \ HASH_OOPS("invalid prev %p, actual %p\n", \ _thh->prev, _prev ); \ } \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ (head)->hh.tbl->hho) : NULL ); \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid app item count %d, actual %d\n", \ (head)->hh.tbl->num_items, _count ); \ } \ } \ } while (0) #else #define HASH_FSCK(hh,head) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ do { \ unsigned _klen = fieldlen; \ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ write(HASH_EMIT_KEYS, keyptr, fieldlen); \ } while (0) #else #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ #ifdef HASH_FUNCTION #define HASH_FCN HASH_FUNCTION #else #define HASH_FCN HASH_JEN #endif /* The Bernstein hash function, used in Perl prior to v5.6 */ #define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _hb_keylen=keylen; \ char *_hb_key=(char*)(key); \ (hashv) = 0; \ while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ bkt = (hashv) & (num_bkts-1); \ } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _sx_i; \ char *_hs_key=(char*)(key); \ hashv = 0; \ for(_sx_i=0; _sx_i < keylen; _sx_i++) \ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ bkt = hashv & (num_bkts-1); \ } while (0) #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _fn_i; \ char *_hf_key=(char*)(key); \ hashv = 2166136261UL; \ for(_fn_i=0; _fn_i < keylen; _fn_i++) \ hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ bkt = hashv & (num_bkts-1); \ } while(0); #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _ho_i; \ char *_ho_key=(char*)(key); \ hashv = 0; \ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ hashv += _ho_key[_ho_i]; \ hashv += (hashv << 10); \ hashv ^= (hashv >> 6); \ } \ hashv += (hashv << 3); \ hashv ^= (hashv >> 11); \ hashv += (hashv << 15); \ bkt = hashv & (num_bkts-1); \ } while(0) #define HASH_JEN_MIX(a,b,c) \ do { \ a -= b; a -= c; a ^= ( c >> 13 ); \ b -= c; b -= a; b ^= ( a << 8 ); \ c -= a; c -= b; c ^= ( b >> 13 ); \ a -= b; a -= c; a ^= ( c >> 12 ); \ b -= c; b -= a; b ^= ( a << 16 ); \ c -= a; c -= b; c ^= ( b >> 5 ); \ a -= b; a -= c; a ^= ( c >> 3 ); \ b -= c; b -= a; b ^= ( a << 10 ); \ c -= a; c -= b; c ^= ( b >> 15 ); \ } while (0) #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _hj_i,_hj_j,_hj_k; \ char *_hj_key=(char*)(key); \ hashv = 0xfeedbeef; \ _hj_i = _hj_j = 0x9e3779b9; \ _hj_k = keylen; \ while (_hj_k >= 12) { \ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + ( (unsigned)_hj_key[2] << 16 ) \ + ( (unsigned)_hj_key[3] << 24 ) ); \ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + ( (unsigned)_hj_key[6] << 16 ) \ + ( (unsigned)_hj_key[7] << 24 ) ); \ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + ( (unsigned)_hj_key[10] << 16 ) \ + ( (unsigned)_hj_key[11] << 24 ) ); \ \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ \ _hj_key += 12; \ _hj_k -= 12; \ } \ hashv += keylen; \ switch ( _hj_k ) { \ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ case 5: _hj_j += _hj_key[4]; \ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ case 1: _hj_i += _hj_key[0]; \ } \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ bkt = hashv & (num_bkts-1); \ } while(0) /* The Paul Hsieh hash function */ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) #define get16bits(d) (*((const uint16_t *) (d))) #endif #if !defined (get16bits) #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ +(uint32_t)(((const uint8_t *)(d))[0]) ) #endif #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ do { \ char *_sfh_key=(char*)(key); \ uint32_t _sfh_tmp, _sfh_len = keylen; \ \ int _sfh_rem = _sfh_len & 3; \ _sfh_len >>= 2; \ hashv = 0xcafebabe; \ \ /* Main loop */ \ for (;_sfh_len > 0; _sfh_len--) { \ hashv += get16bits (_sfh_key); \ _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ hashv = (hashv << 16) ^ _sfh_tmp; \ _sfh_key += 2*sizeof (uint16_t); \ hashv += hashv >> 11; \ } \ \ /* Handle end cases */ \ switch (_sfh_rem) { \ case 3: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 16; \ hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ hashv += hashv >> 11; \ break; \ case 2: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 11; \ hashv += hashv >> 17; \ break; \ case 1: hashv += *_sfh_key; \ hashv ^= hashv << 10; \ hashv += hashv >> 1; \ } \ \ /* Force "avalanching" of final 127 bits */ \ hashv ^= hashv << 3; \ hashv += hashv >> 5; \ hashv ^= hashv << 4; \ hashv += hashv >> 17; \ hashv ^= hashv << 25; \ hashv += hashv >> 6; \ bkt = hashv & (num_bkts-1); \ } while(0); #ifdef HASH_USING_NO_STRICT_ALIASING /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. * MurmurHash uses the faster approach only on CPU's where we know it's safe. * * Note the preprocessor built-in defines can be emitted using: * * gcc -m64 -dM -E - < /dev/null (on gcc) * cc -## a.c (where a.c is a simple test file) (Sun Studio) */ #if (defined(__i386__) || defined(__x86_64__)) #define MUR_GETBLOCK(p,i) p[i] #else /* non intel */ #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) #else /* assume little endian non-intel */ #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) #endif #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ MUR_ONE_THREE(p)))) #endif #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) #define MUR_FMIX(_h) \ do { \ _h ^= _h >> 16; \ _h *= 0x85ebca6b; \ _h ^= _h >> 13; \ _h *= 0xc2b2ae35l; \ _h ^= _h >> 16; \ } while(0) #define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ do { \ const uint8_t *_mur_data = (const uint8_t*)(key); \ const int _mur_nblocks = (keylen) / 4; \ uint32_t _mur_h1 = 0xf88D5353; \ uint32_t _mur_c1 = 0xcc9e2d51; \ uint32_t _mur_c2 = 0x1b873593; \ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ int _mur_i; \ for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ uint32_t _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ \ _mur_h1 ^= _mur_k1; \ _mur_h1 = MUR_ROTL32(_mur_h1,13); \ _mur_h1 = _mur_h1*5+0xe6546b64; \ } \ const uint8_t *_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ uint32_t _mur_k1=0; \ switch((keylen) & 3) { \ case 3: _mur_k1 ^= _mur_tail[2] << 16; \ case 2: _mur_k1 ^= _mur_tail[1] << 8; \ case 1: _mur_k1 ^= _mur_tail[0]; \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ _mur_h1 ^= _mur_k1; \ } \ _mur_h1 ^= (keylen); \ MUR_FMIX(_mur_h1); \ hashv = _mur_h1; \ bkt = hashv & (num_bkts-1); \ } while(0) #endif /* HASH_USING_NO_STRICT_ALIASING */ /* key comparison function; return 0 if keys equal */ #define HASH_KEYCMP(a,b,len) memcmp(a,b,len) /* iterate over items in a known bucket to find desired item */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ do { \ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ else out=NULL; \ while (out) { \ if (out->hh.keylen == keylen_in) { \ if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ } \ if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ else out = NULL; \ } \ } while(0) /* add an item to a bucket */ #define HASH_ADD_TO_BKT(head,addhh) \ do { \ head.count++; \ (addhh)->hh_next = head.hh_head; \ (addhh)->hh_prev = NULL; \ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ (head).hh_head=addhh; \ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ && (addhh)->tbl->noexpand != 1) { \ HASH_EXPAND_BUCKETS((addhh)->tbl); \ } \ } while(0) /* remove an item from a given bucket */ #define HASH_DEL_IN_BKT(hh,head,hh_del) \ (head).count--; \ if ((head).hh_head == hh_del) { \ (head).hh_head = hh_del->hh_next; \ } \ if (hh_del->hh_prev) { \ hh_del->hh_prev->hh_next = hh_del->hh_next; \ } \ if (hh_del->hh_next) { \ hh_del->hh_next->hh_prev = hh_del->hh_prev; \ } /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the * items will distribute more or less evenly into the new buckets * (the extent to which this is true is a measure of the quality of * the hash function as it applies to the key domain). * * With the items distributed into more buckets, the chain length * (item count) in each bucket is reduced. Thus by expanding buckets * the hash keeps a bound on the chain length. This bounded chain * length is the essence of how a hash provides constant time lookup. * * The calculation of tbl->ideal_chain_maxlen below deserves some * explanation. First, keep in mind that we're calculating the ideal * maximum chain length based on the *new* (doubled) bucket count. * In fractions this is just n/b (n=number of items,b=new num buckets). * Since the ideal chain length is an integer, we want to calculate * ceil(n/b). We don't depend on floating point arithmetic in this * hash, so to calculate ceil(n/b) with integers we could write * * ceil(n/b) = (n/b) + ((n%b)?1:0) * * and in fact a previous version of this hash did just that. * But now we have improved things a bit by recognizing that b is * always a power of two. We keep its base 2 log handy (call it lb), * so now we can write this with a bit shift and logical AND: * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ #define HASH_EXPAND_BUCKETS(tbl) \ do { \ unsigned _he_bkt; \ unsigned _he_bkt_i; \ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ memset(_he_new_buckets, 0, \ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ tbl->ideal_chain_maxlen = \ (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ tbl->nonideal_items = 0; \ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ { \ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ while (_he_thh) { \ _he_hh_nxt = _he_thh->hh_next; \ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ tbl->nonideal_items++; \ _he_newbkt->expand_mult = _he_newbkt->count / \ tbl->ideal_chain_maxlen; \ } \ _he_thh->hh_prev = NULL; \ _he_thh->hh_next = _he_newbkt->hh_head; \ if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ _he_thh; \ _he_newbkt->hh_head = _he_thh; \ _he_thh = _he_hh_nxt; \ } \ } \ uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ tbl->num_buckets *= 2; \ tbl->log2_num_buckets++; \ tbl->buckets = _he_new_buckets; \ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ (tbl->ineff_expands+1) : 0; \ if (tbl->ineff_expands > 1) { \ tbl->noexpand=1; \ uthash_noexpand_fyi(tbl); \ } \ uthash_expand_fyi(tbl); \ } while(0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ do { \ unsigned _hs_i; \ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ if (head) { \ _hs_insize = 1; \ _hs_looping = 1; \ _hs_list = &((head)->hh); \ while (_hs_looping) { \ _hs_p = _hs_list; \ _hs_list = NULL; \ _hs_tail = NULL; \ _hs_nmerges = 0; \ while (_hs_p) { \ _hs_nmerges++; \ _hs_q = _hs_p; \ _hs_psize = 0; \ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ _hs_psize++; \ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ if (! (_hs_q) ) break; \ } \ _hs_qsize = _hs_insize; \ while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ if (_hs_psize == 0) { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ _hs_e = _hs_p; \ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_psize--; \ } else if (( \ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ ) <= 0) { \ _hs_e = _hs_p; \ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_psize--; \ } else { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } \ if ( _hs_tail ) { \ _hs_tail->next = ((_hs_e) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ } else { \ _hs_list = _hs_e; \ } \ _hs_e->prev = ((_hs_tail) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ _hs_tail = _hs_e; \ } \ _hs_p = _hs_q; \ } \ _hs_tail->next = NULL; \ if ( _hs_nmerges <= 1 ) { \ _hs_looping=0; \ (head)->hh.tbl->tail = _hs_tail; \ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ } \ _hs_insize *= 2; \ } \ HASH_FSCK(hh,head); \ } \ } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ unsigned _src_bkt, _dst_bkt; \ void *_last_elt=NULL, *_elt; \ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ if (src) { \ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ _src_hh; \ _src_hh = _src_hh->hh_next) { \ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ if (cond(_elt)) { \ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ _dst_hh->key = _src_hh->key; \ _dst_hh->keylen = _src_hh->keylen; \ _dst_hh->hashv = _src_hh->hashv; \ _dst_hh->prev = _last_elt; \ _dst_hh->next = NULL; \ if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ if (!dst) { \ DECLTYPE_ASSIGN(dst,_elt); \ HASH_MAKE_TABLE(hh_dst,dst); \ } else { \ _dst_hh->tbl = (dst)->hh_dst.tbl; \ } \ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ (dst)->hh_dst.tbl->num_items++; \ _last_elt = _elt; \ _last_elt_hh = _dst_hh; \ } \ } \ } \ } \ HASH_FSCK(hh_dst,dst); \ } while (0) #define HASH_CLEAR(hh,head) \ do { \ if (head) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head)=NULL; \ } \ } while(0) #ifdef NO_DECLTYPE #define HASH_ITER(hh,head,el,tmp) \ for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) #else #define HASH_ITER(hh,head,el,tmp) \ for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) #endif /* obtain a count of items in the hash */ #define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; /* expand_mult is normally set to 0. In this situation, the max chain length * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If * the bucket's chain exceeds this length, bucket expansion is triggered). * However, setting expand_mult to a non-zero value delays bucket expansion * (that would be triggered by additions to this particular bucket) * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. * (The multiplier is simply expand_mult+1). The whole idea of this * multiplier is to reduce bucket expansions, since they are expensive, in * situations where we know that a particular bucket tends to be overused. * It is better to let its chain length grow to a longer yet-still-bounded * value, than to do an O(n) bucket expansion too often. */ unsigned expand_mult; } UT_hash_bucket; /* random signature used only to find hash tables in external analysis */ #define HASH_SIGNATURE 0xa0111fe1 #define HASH_BLOOM_SIGNATURE 0xb12220f2 typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ /* in an ideal situation (all buckets used equally), no bucket would have * more than ceil(#items/#buckets) items. that's the ideal chain length. */ unsigned ideal_chain_maxlen; /* nonideal_items is the number of items in the hash whose chain position * exceeds the ideal chain maxlen. these items pay the penalty for an uneven * hash distribution; reaching them in a chain traversal takes >ideal steps */ unsigned nonideal_items; /* ineffective expands occur when a bucket doubling was performed, but * afterward, more than half the items in the hash had nonideal chain * positions. If this happens on two consecutive expansions we inhibit any * further expansion, as it's not helping; this happens when the hash * function isn't a good fit for the key domain. When expansion is inhibited * the hash will still work, albeit no longer in constant time. */ unsigned ineff_expands, noexpand; uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ uint8_t *bloom_bv; char bloom_nbits; #endif } UT_hash_table; typedef struct UT_hash_handle { struct UT_hash_table *tbl; void *prev; /* prev element in app order */ void *next; /* next element in app order */ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ struct UT_hash_handle *hh_next; /* next hh in bucket order */ void *key; /* ptr to enclosing struct's key */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ BoolNet/src/init.c0000644000176200001440000000367214377062333013532 0ustar liggesusers#include #include #include // for NULL #include /* .C calls */ extern void bin2decC(void *, void *, void *); extern void dec2binC(void *, void *, void *); extern void freeAllMemory(void); /* .Call calls */ extern SEXP checkNullPointerC(SEXP); extern SEXP constructNetworkTrees_R(SEXP); extern SEXP getAttractors_R(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP getTruthTable_R(SEXP, SEXP); extern SEXP markovSimulation_R(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP reconstructNetwork_R(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP simulateStates_R(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP symbolicSATSearch_R(SEXP, SEXP, SEXP); extern SEXP symbolicStateTransition_R(SEXP, SEXP, SEXP); static const R_CMethodDef CEntries[] = { {"bin2decC", (DL_FUNC) &bin2decC, 3}, {"dec2binC", (DL_FUNC) &dec2binC, 3}, {"freeAllMemory", (DL_FUNC) &freeAllMemory, 0}, {NULL, NULL, 0} }; static const R_CallMethodDef CallEntries[] = { {"checkNullPointerC", (DL_FUNC) &checkNullPointerC, 1}, {"constructNetworkTrees_R", (DL_FUNC) &constructNetworkTrees_R, 1}, {"getAttractors_R", (DL_FUNC) &getAttractors_R, 12}, {"getTruthTable_R", (DL_FUNC) &getTruthTable_R, 2}, {"markovSimulation_R", (DL_FUNC) &markovSimulation_R, 11}, {"reconstructNetwork_R", (DL_FUNC) &reconstructNetwork_R, 10}, {"simulateStates_R", (DL_FUNC) &simulateStates_R, 6}, {"symbolicSATSearch_R", (DL_FUNC) &symbolicSATSearch_R, 3}, {"symbolicStateTransition_R", (DL_FUNC) &symbolicStateTransition_R, 3}, {NULL, NULL, 0} }; void R_init_BoolNet(DllInfo *dll) { R_registerRoutines(dll, CEntries, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } BoolNet/src/probabilistic_boolean_network.c0000644000176200001440000004371413277247010020661 0ustar liggesusers/** * C code for Markov simulations of Probabilistic Boolean Networks * * This is part of the BoolNet R package. * * Copyright 2009/2010 by Christoph Müssel * * Contact christoph.muessel@uni-ulm.de * */ #include "uthash.h" #include "common.h" #include "boolean_network.h" #include #include #include #include #include #include #include #define MATRIX_POOL_SIZE 1024 /** * An entry in the state probability matrix */ typedef struct { // the initial state // (next state is the index of the matrix array) unsigned int state; // the probability for this state transition double probability; // used by the hash table UT_hash_handle hh; } MatrixEntry; /* * Structure that maintains a sparse matrix */ typedef struct { MatrixEntry ** matrix; ArrayListElement * entryPool; unsigned int poolArraySize; unsigned int currentEntry; unsigned int numCols; } SparseMatrix; /* * Initialize a matrix with columns * maintaining an entry pool with arrays of size * */ static inline SparseMatrix * allocSparseMatrix(unsigned int numCols, unsigned int poolArraySize) { SparseMatrix * res = CALLOC(1, sizeof(SparseMatrix)); res->matrix = CALLOC(numCols, sizeof(MatrixEntry *)); memset(res->matrix,0,sizeof(MatrixEntry *) * numCols); res->poolArraySize = poolArraySize; res->currentEntry = 0; res->entryPool = NULL; res->numCols = numCols; return res; } /** * Calculate a transition table with one entry for each state. Each entry consists of * one bit per (non-fixed) function in . * receives the number of elements in the table. * receives the number of array elements occupied by one state. * Returns an array of states. */ unsigned int * probabilisticTransitionTable(ProbabilisticBooleanNetwork * net, unsigned int * tableSize, unsigned int * numElements) { // determine number of fixed genes unsigned int totalFunctionCount = 0; unsigned int i, j, k, numNonFixed = 0; for (i = 0; i < net->numGenes; ++i) { if (net->fixedGenes[i] == -1) { totalFunctionCount += net->numFunctionsPerGene[i]; ++numNonFixed; } } if (totalFunctionCount % BITS_PER_BLOCK_32 == 0) *numElements = totalFunctionCount / BITS_PER_BLOCK_32; else *numElements = totalFunctionCount / BITS_PER_BLOCK_32 + 1; // allocate truth table with 2^(non-fixed genes) elements *tableSize = ((unsigned int)1 << numNonFixed); unsigned int * table = CALLOC(*tableSize * *numElements,sizeof(unsigned int)); if (table == 0) { Rf_error("Too few memory available!"); } unsigned int initialState = 0; // calculate state transitions for(initialState = 0; initialState < *tableSize; ++initialState) { R_CheckUserInterrupt(); //state is simply the binary encoding of the counter //calculate transitions for (i = 0; i < net->numGenes; ++i) { if (net->fixedGenes[i] == -1) { for (j = 0; j < net->numFunctionsPerGene[i]; ++j) { PBNFunction * current = &net->transitionFunctions[i][j]; unsigned int inputdec = 0; for (k = 0; k < current->numGenes; ++k) { if (current->inputGenes[k]) // if the input of the function is not 0 (constant gene), take input bit { unsigned int gene = current->inputGenes[k] - 1; unsigned int bit; if (net->fixedGenes[gene] == -1) bit = (GET_BIT(initialState, net->nonFixedGeneBits[gene])); else // fixed genes are not encoded in the states // => take them from fixedGenes vector bit = net->fixedGenes[gene]; inputdec |= bit << (current->numGenes - k - 1); } } int transition = current->transitionFunction[inputdec]; if(transition != -1) // apply transition function table[initialState * *numElements + current->functionIndex / BITS_PER_BLOCK_32] |= (transition << (current->functionIndex % BITS_PER_BLOCK_32)); else // this is a dummy function for a constant gene // => value does not change table[initialState * *numElements + current->functionIndex / BITS_PER_BLOCK_32] |= (GET_BIT(initialState, net->nonFixedGeneBits[i]) << (current->functionIndex % BITS_PER_BLOCK_32)); } } } } return table; } /** * Calculate combinations of function indices. * is an array containing the numbers of functions for each gene. * is the previous function combination from which the next * combination is calculated. * is the number of functions. * Returns false if there are no more combinations, and true otherwise. */ static inline bool nextFunctionCombination(unsigned int * maxVals, unsigned int * combination, unsigned int size) { unsigned int i; while(true) { for (i = 0; i < size; ++i) { ++combination[i]; if (combination[i] < maxVals[i]) return true; else { if (i == size - 1) return false; else combination[i] = 0; } } } } /** * Add to the element of whose start state is , * or add the corresponding element to the hash table */ static inline void addToMatrixEntry(SparseMatrix * matrix, unsigned int column, unsigned int state, double value) { MatrixEntry * entry; HASH_FIND_INT(matrix->matrix[column], &state, entry); if (entry == NULL) // add a new hash table entry { if (matrix->currentEntry % matrix->poolArraySize == 0) allocNewArray(&matrix->entryPool, matrix->poolArraySize, sizeof(MatrixEntry)); entry = &(((MatrixEntry *)matrix->entryPool->array)[matrix->currentEntry % matrix->poolArraySize]); ++matrix->currentEntry; entry->probability = 0.0; entry->state = state; HASH_ADD_INT(matrix->matrix[column],state,entry); } // increment probability entry->probability += value; } /** * Extract a state from the combined transition table of all functions * depending on the function combination . * is the number of array elements occupied by one state. * is the state for which the successor state is looked up. * holds the network information. * Returns the extracted state as an integer. */ static inline unsigned int extractState(unsigned int * table, unsigned int numElements, unsigned int initialState, unsigned int * combination, ProbabilisticBooleanNetwork * net) { unsigned int i, j, res = 0; for (i = 0, j = 0; i < net->numGenes; ++i) { if (net->fixedGenes[i] == -1) // exclude fixed genes { unsigned int functionIndex = net->transitionFunctions[i][combination[j]].functionIndex; // insert the th bit at the next position res |= (GET_BIT(table[initialState * numElements + functionIndex / BITS_PER_BLOCK_32], functionIndex % BITS_PER_BLOCK_32)) << net->nonFixedGeneBits[i]; ++j; } } return res; } /** * Free all hash tables in the matrix array * and the array itself. * is the number of columns of the matrix. */ void freeMatrix(SparseMatrix * matrix) { unsigned int i; for (i = 0; i < matrix->numCols; ++i) { // free hash table HASH_CLEAR(hh,matrix->matrix[i]); } // FREE(matrix->matrix); freeArrayList(matrix->entryPool); // free array FREE(matrix); } /** * Start a Markov chain simulation on network by performing matrix multiplications. * receives the number of elements in the returned probability vector. * is the matrix of state transition probabilities with columns. * is an optional vector with encoded start states. */ double * markovSimulation(ProbabilisticBooleanNetwork * net, unsigned int numIterations, unsigned int * outcomeSize, SparseMatrix ** stateProbabilities, unsigned int * startStates, unsigned int numStartStates) { unsigned int tableSize = 0, numElements = 0, i, k; // calculate combined transition table unsigned int * table = probabilisticTransitionTable(net,&tableSize,&numElements); SparseMatrix * matrix = allocSparseMatrix(tableSize, MATRIX_POOL_SIZE); *stateProbabilities = matrix; unsigned int combination[net->numNonFixedGenes]; memset(combination,0,sizeof(unsigned int) * net->numNonFixedGenes); unsigned int maxCombination[net->numNonFixedGenes]; unsigned int geneIndices[net->numNonFixedGenes]; // write array with numbers of functions for (i = 0; i < net->numGenes; ++i) { if (net->fixedGenes[i] == -1) { maxCombination[net->nonFixedGeneBits[i]] = net->numFunctionsPerGene[i]; geneIndices[net->nonFixedGeneBits[i]] = i; } } // set up transition probability matrix do // iterate over all possible function combinations { double probability = net->transitionFunctions[geneIndices[0]][combination[0]].probability; for (i = 1; i < net->numNonFixedGenes; ++i) probability *= net->transitionFunctions[geneIndices[i]][combination[i]].probability; for (i = 0; i < tableSize; ++i) // add probabilities for all reached states in the transition table { R_CheckUserInterrupt(); unsigned int state = extractState(table,numElements,i,combination,net); addToMatrixEntry(matrix,state,i,probability); } } while (nextFunctionCombination(maxCombination,combination,net->numNonFixedGenes)); FREE(table); double * outcome = CALLOC(tableSize,sizeof(double)); double * oldOutcome = CALLOC(tableSize,sizeof(double)); *outcomeSize = tableSize; if (numStartStates == 0) // no start states => equal probability for all states { for (i = 0; i < tableSize; ++i) { outcome[i] = 1.0/tableSize; } } else // start states supplied => equal probability for all supplied states { for (i = 0; i < numStartStates; ++i) { outcome[startStates[i]] = 1.0/numStartStates; } } for (k = 0; k < numIterations; ++k) // perform matrix multiplications { R_CheckUserInterrupt(); memcpy(oldOutcome,outcome,sizeof(double) * tableSize); for (i = 0; i < tableSize; ++i) { MatrixEntry * entry; outcome[i] = 0.0; for(entry = matrix->matrix[i]; entry != NULL; entry=entry->hh.next) { outcome[i] += oldOutcome[entry->state] * entry->probability; } } } FREE(oldOutcome); return outcome; } /** * R wrapper for the Markov simulation. * is a concatenated integer vector of the input genes for all functions. * is used to split up into the single function inputs. * contains the truth table result columns of all functions and is * split up according to . * specifies whether genes are fixed (0,1) or not (-1). * is a vector specifying which function belongs to which gene. * is a vector of probabilities for the functions. * is the number of matrix multiplications to be performed. * is an optional vector of start states (otherwise all states are considered). * is the value below which values are considered to be 0. * specifies whether the result should contain a transition table * Returns a list containing a data frame of important states and their probabilities * and, optionally, the transition table. */ SEXP markovSimulation_R(SEXP inputGenes, SEXP inputGenePositions, SEXP transitionFunctions, SEXP transitionFunctionPositions, SEXP fixedGenes, SEXP functionAssignment, SEXP probabilities, SEXP numSteps, SEXP startStates, SEXP cutoff, SEXP returnTable) { ProbabilisticBooleanNetwork network; network.type = PROBABILISTIC_BOOLEAN_NETWORK; int * _inputGenes = INTEGER(inputGenes); int * _inputGenePositions = INTEGER(inputGenePositions); int * _transitionFunctions = INTEGER(transitionFunctions); int * _transitionFunctionPositions = INTEGER(transitionFunctionPositions); int * _functionAssignment = INTEGER(functionAssignment); double * _probabilities = REAL(probabilities); int _numSteps = *INTEGER(numSteps); int * _startStates = NULL; if (!isNull(startStates)) _startStates = INTEGER(startStates); double _cutoff = *REAL(cutoff); bool _returnTable = (bool)(*INTEGER(returnTable)); unsigned int i, j; network.numGenes = length(fixedGenes); network.fixedGenes = CALLOC(network.numGenes,sizeof(int)); memcpy(network.fixedGenes,INTEGER(fixedGenes),sizeof(unsigned int) * network.numGenes); network.nonFixedGeneBits = CALLOC(network.numGenes,sizeof(unsigned int)); // determine which genes are not fixed network.numNonFixedGenes = 0; for(i = 0; i < network.numGenes; i++) { if(network.fixedGenes[i] == -1) { network.nonFixedGeneBits[i] = network.numNonFixedGenes++; } } network.numFunctionsPerGene = CALLOC(network.numGenes,sizeof(unsigned int)); network.transitionFunctions = CALLOC(network.numGenes,sizeof(PBNFunction *)); // count number of functions per gene for (i = 0; i < length(functionAssignment); ++i) { ++network.numFunctionsPerGene[_functionAssignment[i]]; } // allocate function vectors for (i = 0; i < network.numGenes; ++i) { network.transitionFunctions[i] = CALLOC(network.numFunctionsPerGene[i],sizeof(PBNFunction)); } unsigned int functionCounter[network.numGenes]; memset(functionCounter,0,sizeof(unsigned int) * network.numGenes); unsigned int functionIndex = 0; for (i = 0; i < length(functionAssignment); ++i) // decode functions { PBNFunction * current = &network.transitionFunctions[_functionAssignment[i]] [functionCounter[_functionAssignment[i]]++]; unsigned int numInputs = _inputGenePositions[i+1] - _inputGenePositions[i]; current->inputGenes = CALLOC(numInputs,sizeof(int)); memcpy(current->inputGenes,&_inputGenes[_inputGenePositions[i]],numInputs*sizeof(int)); current->numGenes = numInputs; current->transitionFunction = CALLOC((unsigned int)1 << numInputs,sizeof(int)); memcpy(current->transitionFunction,&_transitionFunctions[_transitionFunctionPositions[i]], ((unsigned int)1 << numInputs)*sizeof(int)); current->probability = _probabilities[i]; if (network.fixedGenes[_functionAssignment[i]] == -1) { current->functionIndex = functionIndex++; } else { current->functionIndex = ~0; } } unsigned int startStateElements; if (network.numGenes % (sizeof(unsigned int) * 8) == 0) { startStateElements = network.numGenes / BITS_PER_BLOCK_32; } else { startStateElements = network.numGenes / BITS_PER_BLOCK_32 + 1; } // decode start states (remove fixed genes) unsigned int numStartStates; unsigned int * decodedStartStates = NULL; if (isNull(startStates)) numStartStates = 0; else { numStartStates = length(startStates)/startStateElements; decodedStartStates = (unsigned int*)CALLOC(numStartStates, sizeof(unsigned int)); } for (i = 0; i < numStartStates; ++i) { decodedStartStates[i] = 0; for (j = 0; j < network.numGenes; ++j) { if (network.fixedGenes[j] == -1) { decodedStartStates[i] |= GET_BIT(_startStates[i * startStateElements + j / BITS_PER_BLOCK_32], j % BITS_PER_BLOCK_32) << network.nonFixedGeneBits[j]; } } } unsigned int outcomeSize = 0; SparseMatrix * matrix; // perform simulation double * outcome = markovSimulation(&network,_numSteps,&outcomeSize,&matrix, decodedStartStates,numStartStates); // determine number of non-zero results unsigned int nonZero = 0; for (i = 0; i < outcomeSize; ++i) { if (outcome[i] > _cutoff) ++nonZero; } // encode results SEXP resSXP, stateSXP, probSXP; if (_returnTable) PROTECT(resSXP = allocList(5)); else PROTECT(resSXP = allocList(2)); PROTECT(stateSXP = allocVector(INTSXP,nonZero*startStateElements)); PROTECT(probSXP = allocVector(REALSXP,nonZero)); int * states = INTEGER(stateSXP); double * prob = REAL(probSXP); //return R_NilValue; for (i = 0, j = 0; i < outcomeSize; ++i) // encode states with non-zero probability { if (outcome[i] > _cutoff) { prob[j] = outcome[i]; states[j*startStateElements] = i; // re-encode fixed genes insertFixedGenes((unsigned int *)&states[j*startStateElements],network.fixedGenes,network.numGenes); ++j; } } SET_TAG(resSXP, install("states")); SET_TAG(CDR(resSXP), install("probabilities")); SETCAR(resSXP,stateSXP); SETCADR(resSXP,probSXP); if (_returnTable) // encode the transition table { SET_TAG(CDR(CDR(resSXP)), install("initialStates")); SET_TAG(CDR(CDR(CDR(resSXP))), install("nextStates")); SET_TAG(CDR(CDR(CDR(CDR(resSXP)))), install("transitionProbabilities")); //calculate size of transition table unsigned int tableSize = 0; for (i = 0; i < outcomeSize; ++i) { MatrixEntry * entry; for(entry = matrix->matrix[i]; entry != NULL; entry=entry->hh.next) { ++tableSize; } } SEXP initialStateSXP, nextStateSXP, transitionProbSXP; PROTECT(initialStateSXP = allocVector(INTSXP,tableSize * startStateElements)); PROTECT(nextStateSXP = allocVector(INTSXP,tableSize * startStateElements)); PROTECT(transitionProbSXP = allocVector(REALSXP,tableSize)); unsigned int * initialStates = (unsigned int *)INTEGER(initialStateSXP); unsigned int * nextStates = (unsigned int *)INTEGER(nextStateSXP); double * transitionProbs = (double *)REAL(transitionProbSXP); // encode non-zero states in transition matrix j = 0; for (i = 0; i < outcomeSize; ++i) { MatrixEntry * entry; for(entry = matrix->matrix[i]; entry != NULL; entry=entry->hh.next) { initialStates[j * startStateElements] = entry->state; insertFixedGenes(&initialStates[j*startStateElements],network.fixedGenes,network.numGenes); nextStates[j * startStateElements] = i; insertFixedGenes(&nextStates[j*startStateElements],network.fixedGenes,network.numGenes); transitionProbs[j] = entry->probability; ++j; } } SETCADDR(resSXP,initialStateSXP); SETCADDDR(resSXP,nextStateSXP); SETCADDDR(CDR(resSXP),transitionProbSXP); UNPROTECT(3); } UNPROTECT(3); freeMatrix(matrix); FREE(outcome); if (decodedStartStates != NULL) FREE(decodedStartStates); return resSXP; } BoolNet/src/boolean_network.h0000644000176200001440000000557213277247010015760 0ustar liggesusers#ifndef BOOLEAN_NETWORK_H #define BOOLEAN_NETWORK_H #define TRUTHTABLE_BOOLEAN_NETWORK 0 #define PROBABILISTIC_BOOLEAN_NETWORK 1 #define SYMBOLIC_BOOLEAN_NETWORK 2 /** * Basic structure for different types of * Boolean network (extended by derived structures * TruthTableBooleanNetwork, ProbabilisticBooleanNetwork and SymbolicBooleanNetwork) */ typedef struct { // the network type unsigned char type; // the number of genes in the network unsigned int numGenes; // a vector specifying whether the genes are fixed: // -1 means the gene is not fixed, 1 and 0 means the // genes are fixed to the corresponding values int * fixedGenes; } BooleanNetwork; /** * Internal structure describing a Boolean network * with a truth table representation */ typedef struct { // here: type = TRUTHTABLE_BOOLEAN_NETWORK unsigned char type; // the number of genes in the network unsigned int numGenes; // a vector specifying whether the genes are fixed: // -1 means the gene is not fixed, 1 and 0 means the // genes are fixed to the corresponding values int * fixedGenes; // an index array with the -th entry // specifying the bit position of the -th gene // in a state array - this is not always equal to , // as fixed genes are not stored unsigned int * nonFixedGeneBits; // a vector encoding the input genes for all transition functions. int * inputGenes; // a vector of indices to split up for the single // gene transition functions. int * inputGenePositions; // a vector encoding the return values of all transition functions int * transitionFunctions; // a vector of indices to split up for the single // genes. int * transitionFunctionPositions; } TruthTableBooleanNetwork; typedef struct { int * inputGenes; int * transitionFunction; unsigned int numGenes; double probability; unsigned int functionIndex; } PBNFunction; /** * Internal structure describing a Probabilistic Boolean network */ typedef struct { // here: type = PROBABILISTIC_BOOLEAN_NETWORK unsigned char type; // the number of genes in the network unsigned int numGenes; // a vector specifying whether the genes are fixed: // -1 means the gene is not fixed, 1 and 0 means the // genes are fixed to the corresponding values int * fixedGenes; // the number of non-fixed genes in the network unsigned int numNonFixedGenes; // an index array with the -th entry // specifying the bit position of the -th gene // in a state array - this is not always equal to , // as fixed genes are not stored unsigned int * nonFixedGeneBits; // an array containing an array of transition functions for each gene PBNFunction ** transitionFunctions; // the lengths of the arrays in unsigned int * numFunctionsPerGene; } ProbabilisticBooleanNetwork; // see also symbolic_boolean_network.h for the definition of symbolic networks #endif BoolNet/src/symbolic_network.c0000644000176200001440000003411513277247010016150 0ustar liggesusers/** * C code for a generic symbolic simulator for Boolean networks * * This is part of the BoolNet R package. * * Copyright 2013 by Christoph Muessel * * Contact christoph.muessel@uni-ulm.de * */ #include "random.h" #include "common.h" #include "symbolic_network.h" /** * Free the expression tree */ void freeFormula(BooleanFormula * formula) { if (formula->type == FORMULA_ATOM || formula->type == FORMULA_CONSTANT) { free(formula); } else { BooleanOperator* operator = (BooleanOperator*) formula; unsigned int i; for (i = 0; i < operator->numOperands; ++i) { freeFormula(operator->operands[i]); } free(operator->operands); free(operator); } } /** * Free the internal network structure */ void freeSymbolicNetwork(SymbolicBooleanNetwork * network) { free(network->stateSizes); free(network->stateOffsets); free(network->fixedGenes); free(network->stateFixed); unsigned int i, j; for (i = 0; i < network->numGenes; ++i) { freeFormula(network->interactions[i]); if (network->cnfInteractions != NULL) { for (j = 0; j <= network->attractorSearchStartTime; ++j) freeFormula(network->cnfInteractions[i][j]); free(network->cnfInteractions[i]); } } free(network->interactions); if (network->cnfInteractions != NULL) free(network->cnfInteractions); free(network); } /** * Evaluate an expression tree on the previous state . * is an array describing where the history of the i-th gene starts. * is the total number of genes in the network. * Returns a logical value resulting from the evaluation. */ unsigned char evaluate(BooleanFormula * formula, TemporalState * state, unsigned int * stateOffsets, const unsigned int numGenes) { if (formula->type == FORMULA_CONSTANT) // return the constant value { Constant* constant = (Constant*) formula; char value = constant->value; if (constant->negated) return !value; else return value; } else if (formula->type == FORMULA_ATOM) // return the value of the atom in the current state { unsigned char res; BooleanAtom* atom = (BooleanAtom*) formula; res = state->state[stateOffsets[atom->literal] + atom->time]; if (atom->negated) return !res; else return res; } else // recursively evaluate operands and summarize them using the operators { BooleanOperator* operator = (BooleanOperator*) formula; unsigned int i, threshold, sum, comparisonTimeStep; switch (operator->operator) { case OPERATOR_OR: for (i = 0; i < operator->numOperands; ++i) { if (evaluate(operator->operands[i], state, stateOffsets, numGenes)) { return !operator->negated; } } return operator->negated; case OPERATOR_AND: for (i = 0; i < operator->numOperands; ++i) { if (!evaluate(operator->operands[i], state, stateOffsets, numGenes)) { return operator->negated; } } return !operator->negated; case OPERATOR_MAJ: threshold = floor(operator->numOperands / 2.0); sum = 0; for (i = 0; i < operator->numOperands; ++i) { if (evaluate(operator->operands[i], state, stateOffsets, numGenes)) { ++sum; if (sum > threshold) return !operator->negated; } } return operator->negated; case OPERATOR_SUMIS: threshold = ((Constant *) operator->operands[operator->numOperands - 1])->value; sum = 0; for (i = 0; i < operator->numOperands - 1; ++i) { if (evaluate(operator->operands[i], state, stateOffsets, numGenes)) { ++sum; } } if (sum == threshold) return !operator->negated; else return operator->negated; case OPERATOR_SUMGT: threshold = ((Constant *) operator->operands[operator->numOperands - 1])->value; sum = 0; for (i = 0; i < operator->numOperands - 1; ++i) { if (evaluate(operator->operands[i], state, stateOffsets, numGenes)) { ++sum; if (sum > threshold) return !operator->negated; } } return operator->negated; case OPERATOR_SUMLT: threshold = ((Constant *) operator->operands[operator->numOperands - 1])->value; sum = 0; for (i = 0; i < operator->numOperands - 1; ++i) { if (evaluate(operator->operands[i], state, stateOffsets, numGenes)) { ++sum; if (sum >= threshold) return operator->negated; } } return !operator->negated; case OPERATOR_TIMEIS: comparisonTimeStep = ((Constant *) operator->operands[0])->value; if (operator->negated) return (state->timeStep != comparisonTimeStep - 1); else return (state->timeStep == comparisonTimeStep - 1); case OPERATOR_TIMEGT: comparisonTimeStep = ((Constant *) operator->operands[0])->value; if (operator->negated) return (state->timeStep <= comparisonTimeStep - 1); else return (state->timeStep > comparisonTimeStep - 1); case OPERATOR_TIMELT: comparisonTimeStep = ((Constant *) operator->operands[0])->value; if (operator->negated) return (state->timeStep >= comparisonTimeStep - 1); else return (state->timeStep < comparisonTimeStep - 1); default: Rf_error("Unknown operator!"); } } } /** * Print a Boolean expression tree (for debugging purposes only) */ void printFormula(BooleanFormula * formula) { if (formula->type == FORMULA_ATOM) { BooleanAtom* atom = (BooleanAtom*) formula; if (atom->negated) Rprintf("!"); Rprintf("var%d", atom->literal); if (atom->time != 0) Rprintf("[%d]", -atom->time - 1); } else if (formula->type == FORMULA_CONSTANT) { Constant* constant = (Constant*) formula; if (constant->negated) Rprintf("!"); Rprintf("%d", constant->value); } else { BooleanOperator* operator = (BooleanOperator*) formula; if (operator->negated) Rprintf("!"); if (operator->operator == OPERATOR_MAJ) Rprintf("maj"); else if (operator->operator == OPERATOR_SUMGT) Rprintf("sumgt"); else if (operator->operator == OPERATOR_TIMEIS) Rprintf("timeis"); else if (operator->operator == OPERATOR_TIMEGT) Rprintf("timegt"); else if (operator->operator == OPERATOR_TIMELT) Rprintf("timelt"); Rprintf("("); unsigned int i; for (i = 0; i < operator->numOperands; ++i) { printFormula(operator->operands[i]); if (i < operator->numOperands - 1) { if (operator->operator == OPERATOR_OR) Rprintf(" | "); else if (operator->operator == OPERATOR_AND) Rprintf(" & "); else Rprintf(", "); } } Rprintf(")"); } } BooleanFormula * copyFormula(BooleanFormula * formula, bool negate, unsigned int timeOffset) { if (formula->type == FORMULA_ATOM) { BooleanAtom * res = calloc(1, sizeof(BooleanAtom)); memcpy(res, formula, sizeof(BooleanAtom)); if (negate) res->negated = !res->negated; res->time += timeOffset; return (BooleanFormula *) res; } if (formula->type == FORMULA_CONSTANT) { Constant * res = calloc(1, sizeof(Constant)); memcpy(res, formula, sizeof(Constant)); if (negate) res->negated = !res->negated; return (BooleanFormula *) res; } unsigned int i; BooleanOperator * operator = (BooleanOperator*) formula; bool negated = (negate && !operator->negated) || (!negate && operator->negated); BooleanOperator * res = allocOperator(operator->operator, negated, operator->numOperands, NULL); for (i = 0; i < res->numOperands; ++i) { res->operands[i] = copyFormula(operator->operands[i], false, timeOffset); } return (BooleanFormula *) res; } BooleanFormula * convertToCNF(BooleanFormula * formula, bool negate, unsigned int time) { bool innerNegate = (!negate && formula->negated) || (negate && !formula->negated); if (formula->type == FORMULA_ATOM || formula->type == FORMULA_CONSTANT) { return copyFormula(formula, negate, 0); } BooleanOperator* operator = (BooleanOperator*) formula; if (operator->operator == OPERATOR_TIMEIS || operator->operator == OPERATOR_TIMELT || operator->operator == OPERATOR_TIMEGT) // temporal operators => compare to time { int value; int comparisonTimeStep = ((Constant *) operator->operands[0])->value - 1; switch (operator->operator) { case OPERATOR_TIMEGT: value = (time > comparisonTimeStep); break; case OPERATOR_TIMELT: value = (time < comparisonTimeStep); break; default: value = (time == comparisonTimeStep); break; } if (innerNegate) value = !value; Constant * res = allocConstant(value, false); return (BooleanFormula *) res; } unsigned int operandBufferSize, numOperands, i, j; BooleanFormula ** operands; ALLOC_BUFFER(operands, BooleanFormula *, operandBufferSize, numOperands); if (operator->operator == OPERATOR_SUMGT || operator->operator == OPERATOR_SUMLT || operator->operator == OPERATOR_SUMIS || operator->operator == OPERATOR_MAJ) // counting operators => transform to canonical CNF { unsigned int stateSize, threshold; if (operator->operator != OPERATOR_MAJ) { stateSize = operator->numOperands - 1; threshold = ((Constant*) operator->operands[stateSize])->value; } else { stateSize = operator->numOperands; threshold = floor(stateSize / 2.0); } unsigned char * state = calloc(stateSize, sizeof(unsigned char)); do { bool includeTerm = false; unsigned int count = 0; for (i = 0; i < stateSize; ++i) { if (state[i]) ++count; } switch (operator->operator) { case OPERATOR_SUMGT: case OPERATOR_MAJ: includeTerm = (count <= threshold); break; case OPERATOR_SUMLT: includeTerm = (count >= threshold); break; case OPERATOR_SUMIS: includeTerm = (count != threshold); break; } if (innerNegate) includeTerm = !includeTerm; if (includeTerm) { BooleanFormula ** subOperands = calloc(stateSize, sizeof(BooleanFormula *)); for (i = 0; i < stateSize; ++i) { subOperands[i] = copyFormula(operator->operands[i], state[i], 0); } BooleanOperator * subOp = allocOperator(OPERATOR_OR, false, stateSize, subOperands); PUT_BUFFER(operands, BooleanFormula *, operandBufferSize, numOperands, subOp); } } while (getNextState(state, NULL, stateSize)); free(state); BooleanOperator * res = allocOperator(OPERATOR_AND, false, numOperands, operands); BooleanFormula * res2 = convertToCNF((BooleanFormula *) res, false, time); freeFormula((BooleanFormula *) res); return res2; } // AND or OR unsigned int innerAnds = 0, op; if (innerNegate) { if (operator->operator == OPERATOR_AND) op = OPERATOR_OR; else op = OPERATOR_AND; } else op = operator->operator; Constant * overrideResult = NULL; for (i = 0; i < operator->numOperands; ++i) { BooleanFormula * operand = convertToCNF(operator->operands[i], innerNegate, time); if (operand->type == FORMULA_OPERATOR) { BooleanOperator * subOp = (BooleanOperator *) operand; if (subOp->operator == op || subOp->numOperands == 1) { for (j = 0; j < subOp->numOperands; ++j) { PUT_BUFFER(operands, BooleanFormula *, operandBufferSize, numOperands, subOp->operands[j]); } free(subOp->operands); free(subOp); } else { if (subOp->operator == OPERATOR_AND) ++innerAnds; PUT_BUFFER(operands, BooleanFormula *, operandBufferSize, numOperands, subOp); } } else { if (operand->type == FORMULA_CONSTANT) { Constant * c = (Constant * )operand; if ((op == OPERATOR_OR && ((c->value == 1) ^ c->negated)) || (op == OPERATOR_AND && ((c->value == 0) ^ c->negated))) overrideResult = (Constant *)copyFormula((BooleanFormula *)c, false, 0); else freeFormula(operand); } else PUT_BUFFER(operands, BooleanFormula *, operandBufferSize, numOperands, operand); } } if (overrideResult != NULL) { for (i = 0; i < numOperands; ++i) { freeFormula(operands[i]); } free(operands); return (BooleanFormula *)overrideResult; } if (op == OPERATOR_OR && innerAnds > 0) { unsigned int transformedOperandBufferSize, numTransformedOperands; BooleanFormula ** transformedOperands; ALLOC_BUFFER(transformedOperands, BooleanFormula *, transformedOperandBufferSize, numTransformedOperands); unsigned int * comb = calloc(numOperands, sizeof(unsigned int)); unsigned int * counts = calloc(numOperands, sizeof(unsigned int)); for (i = 0; i < numOperands; ++i) { if (operands[i]->type == FORMULA_OPERATOR) counts[i] = ((BooleanOperator *) operands[i])->numOperands; else counts[i] = 1; } unsigned int pos = 0; while (true) { BooleanOperator * newOp = allocOperator(OPERATOR_OR, false, numOperands, NULL); for (i = 0; i < numOperands; ++i) { if (operands[i]->type == FORMULA_OPERATOR) newOp->operands[i] = copyFormula( ((BooleanOperator *) operands[i])->operands[comb[i]], false, 0); else newOp->operands[i] = copyFormula(operands[i], false, 0); } PUT_BUFFER(transformedOperands, BooleanFormula *, transformedOperandBufferSize, numTransformedOperands, newOp); if (comb[pos] < counts[pos] - 1) ++comb[pos]; else { if (pos == numOperands - 1) break; while (pos < numOperands && comb[pos] == counts[pos] - 1) ++pos; if (pos == numOperands) break; for (i = 0; i < pos; ++i) { comb[i] = 0; } ++comb[pos]; pos = 0; } } free(comb); free(counts); for (i = 0; i < numOperands; ++i) freeFormula(operands[i]); free(operands); BooleanOperator * res = allocOperator(OPERATOR_AND, false, numTransformedOperands, transformedOperands); BooleanFormula * res2 = convertToCNF((BooleanFormula *) res, false, time); freeFormula((BooleanFormula *) res); return res2; } else { BooleanOperator * res = allocOperator(op, false, numOperands, operands); return (BooleanFormula *) res; } } SEXP convertToCNF_R(SEXP network) { SymbolicBooleanNetwork * _network = R_ExternalPtrAddr(network); if (_network == NULL) error("Internal network structures not supplied to C handler!"); unsigned int k; for (k = 0; k < _network->numGenes; ++k) { Rprintf("var%d = ", k); BooleanFormula * converted = convertToCNF(_network->interactions[k], false, 0); printFormula(converted); freeFormula(converted); Rprintf("\n"); } return R_NilValue; } BoolNet/src/statespace_search.h0000644000176200001440000000430413277247010016241 0ustar liggesusers#ifndef STATESPACE_SEARCH_H #define STATESPACE_SEARCH_H #include "boolean_network.h" #include "attractor_info.h" #include /** * Retrieves attractors only for a given set of input states supplied in . * Here, numGenes / 32)> consecutive array entries describe one state, thus * the array size is numGenes / 32) * numberOfStates> * describes the network structure. */ extern pAttractorInfo getAttractorsForStates(unsigned int * selectedStates, unsigned int numberOfStates, TruthTableBooleanNetwork * net); /** * Retrieves attractors from a given transition table
with entries. * * Returns a list of attractors - the last element of this list is empty! */ extern pAttractorInfo getAttractors(unsigned long long * table, unsigned long long numberOfStates, unsigned int numberOfGenes); /** * Calculate complex/loose attractors by performing random transitions from * the states supplied in . * If is true, self loops are only considered if there are no other possible transitions. * If is not NULL, this vector holds the probabilities for each gene to be chosen * for a transition. */ pAttractorInfo getLooseAttractors(unsigned int * selectedStates, unsigned int numberOfStates, TruthTableBooleanNetwork * net, unsigned int randomSteps, bool avoidSelfLoops, double * probabilities); /** * Retrieves the result column of the state transition table. * specifies the total number of genes. * is an array of values specifying whether gene is fixed (0 or 1) or not (-1). * provides the input genes for all transition functions and can be split up * for a single function according to . * provides the truth tables for all transition functions and can be split up * for a single function according to . */ unsigned long long * getTransitionTable(TruthTableBooleanNetwork * net); #endif BoolNet/src/symbolic_network.h0000644000176200001440000001162613277247010016157 0ustar liggesusers#ifndef SYMBOLIC_SIMULATOR_H #define SYMBOLIC_SIMULATOR_H #include #include #include "boolean_network.h" #define FORMULA_ATOM 0 #define FORMULA_OPERATOR 1 #define FORMULA_CONSTANT 2 #define OPERATOR_AND 0 #define OPERATOR_OR 1 #define OPERATOR_MAJ 2 #define OPERATOR_SUMIS 3 #define OPERATOR_SUMGT 4 #define OPERATOR_SUMLT 5 #define OPERATOR_TIMEIS 6 #define OPERATOR_TIMEGT 7 #define OPERATOR_TIMELT 8 #define MODE_EXHAUSTIVE 0 #define MODE_SUPPLIED 1 #define MODE_RANDOM 2 #define HASH_UNSET ~0 /** * "Base class" for Boolean Formulae */ typedef struct { // The formula type which allows // for casting to the corresponding "derived" type unsigned char type; // Is the formula negated or not? bool negated; } BooleanFormula; /** * "Derived class" for operators */ typedef struct { // here: type = FORMULA_OPERATOR unsigned char type; bool negated; // The operator type unsigned char operator; // The number of operands unsigned int numOperands; // The operands BooleanFormula ** operands; } BooleanOperator; /** * "Derived class" for literals */ typedef struct { // here: type = FORMULA_ATOM unsigned char type; bool negated; // The index of the variable that this object represents int literal; // The temporal difference unsigned int time; } BooleanAtom; /** * "Derived class" for constants */ typedef struct { // here: type = FORMULA_CONSTANT unsigned char type; bool negated; // The value of the constant int value; } Constant; /** * A structure holding a symbolic network * with all its network trees */ typedef struct { // here: type = SYMBOLIC_BOOLEAN_NETWORK unsigned char type; // The number of genes in the network unsigned int numGenes; // A vector specifying whether genes are fixed (0/1) or not (-1) int * fixedGenes; // The formulae representing the transition functions BooleanFormula ** interactions; // The formulae representing the transition functions in CNF // (for SAT-based attractor search) // Usually, this is a single formula per gene. // In the presence of time-dependent predicates, there are // + 1 formulae per gene. BooleanFormula *** cnfInteractions; // A vector specifying the maximum delay for each gene unsigned int * stateSizes; // The sum of all elements in stateSizes unsigned int totalStateSize; // The point of time at which attractor search can start, // as temporal predicates do not change any more unsigned int attractorSearchStartTime; // A vector specifying the indices in the state vector // at which the histories for each of the genes start unsigned int * stateOffsets; // A vector marking each entry in the state vector as fixed or not, // corresponding to the genes it belongs to int * stateFixed; } SymbolicBooleanNetwork; /** * A structure holding a state for temporal network simulation */ typedef struct { // The index of the start state to which this state belongs unsigned long long startState; // The current time step unsigned int timeStep; // The state vector (also containing previous states for certain genes if required) unsigned char state[]; } TemporalState; extern void freeSymbolicNetwork(SymbolicBooleanNetwork * network); static inline BooleanOperator * allocOperator(unsigned int operator, bool negated, unsigned int numOperands, BooleanFormula ** operands) { BooleanOperator * res = calloc(1, sizeof(BooleanOperator)); res->negated = negated; res->type = FORMULA_OPERATOR; res->operator = operator; res->numOperands = numOperands; if (operands == NULL) res->operands = calloc(numOperands, sizeof(BooleanFormula *)); else res->operands = operands; return res; } static inline BooleanAtom * allocAtom(int literal, unsigned int time, bool negated) { BooleanAtom * res = calloc(1, sizeof(BooleanAtom)); res->type = FORMULA_ATOM; res->negated = negated; res->literal = literal; res->time = time; return res; } static inline Constant * allocConstant(int value, bool negated) { Constant * res = calloc(1, sizeof(Constant)); res->type = FORMULA_CONSTANT; res->negated = negated; res->value = value; return res; } /** * Free the expression tree */ extern void freeFormula(BooleanFormula * formula); /** * Free the internal network structure */ extern void freeSymbolicNetwork(SymbolicBooleanNetwork * network); extern BooleanFormula * copyFormula(BooleanFormula * formula, bool negate, unsigned int timeOffset); /** * Evaluate an expression tree on the previous state . * is an array describing where the history of the i-th gene starts. * is the total number of genes in the network. * Returns a logical value resulting from the evaluation. */ extern unsigned char evaluate(BooleanFormula * formula, TemporalState * state, unsigned int * stateOffsets, const unsigned int numGenes); extern BooleanFormula * convertToCNF(BooleanFormula * formula, bool negate, unsigned int time); #endif BoolNet/src/sat_search.c0000644000176200001440000006257314362447345014714 0ustar liggesusers#include "sat_search.h" #include #include #include #include "attractor_info.h" #include "common.h" #include "random.h" // Activate this switch to use the Lingeling solver instead of PicoSAT // - requires lglib.c and lglib.h to be present in the package. // Make sure to respect Lingeling's license terms! //#define USE_LINGELING #ifdef USE_LINGELING #include "lglib.h" #define sat_add_literal(solver, lit) lgladd(solver, lit) #define sat_deref(solver, lit) lglderef(solver, lit) #define sat_solve(solver) lglsat(solver) #define sat_free(solver) lglrelease(solver) #define SATISFIABLE LGL_SATISFIABLE /** * Custom interrupt function to be used with Lingeling. * The function calls R's user interrupt check. */ void SATInterrupt(void * external_state) { R_CheckUserInterrupt(); } typedef LGL Solver; #else #include "picosat.h" #define sat_add_literal(solver, lit) picosat_add(solver, lit) #define sat_deref(solver, lit) picosat_deref(solver, lit) #define sat_solve(solver) picosat_sat(solver, -1) #define sat_free(solver) picosat_reset(solver) #define SATISFIABLE PICOSAT_SATISFIABLE typedef PicoSAT Solver; /** * Custom interrupt function to be used with PicoSAT. * The function calls R's user interrupt check. */ int SATInterrupt(void * external_state) { R_CheckUserInterrupt(); return 0; } #endif #include "symbolic_network.h" /** * Custom memory allocator to be used with PicoSAT. * The allocator uses the internal memory map of BoolNet */ void * SATAlloc(void* mem, size_t sz) { return CALLOC(sz, 1); } /** * Custom memory deallocator to be used with PicoSAT/Lingeling. * The deallocator uses the internal memory map of BoolNet */ void SATDealloc(void* mem, void * ptr, size_t sz) { FREE(ptr); } /** * Custom memory resize function to be used with PicoSAT/Lingeling. * The function uses the internal memory map of BoolNet */ void * SATRealloc(void* mem, void * ptr, size_t old, size_t new) { return REALLOC(ptr, new); } #ifdef USE_LINGELING /** * Initialize the Lingeling SAT solver using appropriate memory handlers * and interrupt handlers. */ Solver * initSATSolver() { Solver * sat = lglminit(NULL, &SATAlloc, &SATRealloc, &SATDealloc); lglonabort(sat, NULL, &SATInterrupt); lglsetopt(sat, "elmfull", 1); lglsetopt(sat, "elmschedprod", 1); lglsetopt(sat, "seed", intrand(~0))); return sat; } #else /** * Initialize the PicoSAT SAT solver using appropriate memory handlers * and interrupt handlers. */ Solver * initSATSolver(void) { Solver * sat = picosat_minit(NULL, &SATAlloc, &SATRealloc, &SATDealloc); picosat_set_interrupt(sat, NULL, &SATInterrupt); picosat_set_seed(sat, intrand(~0)); return sat; } #endif /** * Recursively encode a symbolic formula for the SAT solver. This function expects that * is already in CNF, being either a constant, an atom, or a conjunction * comprising only constants, atoms or flat disjunctions. * is the network to which the formula belongs. * is the index of the gene that is currently encoded. * is the index of the state for which the formula should be encoded. * is the SAT solver. */ void encodeFormula(SymbolicBooleanNetwork * network, BooleanFormula * formula, int geneIndex, int stateIndex, Solver * sat) { assert(formula->type != FORMULA_CONSTANT); // if (formula->type == FORMULA_CONSTANT) // { // Constant * constant = (Constant *) formula; // if ((constant->value == 1 && !constant->negated) // || (constant->value == 0 && constant->negated)) // { // // add tautology // picosat_add(sat, -(network->numGenes * stateIndex + geneIndex + 1)); // picosat_add(sat, network->numGenes * stateIndex + geneIndex + 1); //// picosat_assume(sat, network->numGenes * stateIndex + geneIndex + 1); // } // else // { //// picosat_assume(sat, -(network->numGenes * stateIndex + geneIndex + 1)); // } // } // else if (formula->type == FORMULA_ATOM) { BooleanAtom * atom = (BooleanAtom *) formula; // add the atom directly if (atom->negated) { sat_add_literal(sat, -(network->numGenes * (stateIndex + atom->time) + atom->literal + 1)); } else { sat_add_literal(sat, network->numGenes * (stateIndex + atom->time) + atom->literal + 1); } } else if (formula->type == FORMULA_OPERATOR) { BooleanOperator * operator = (BooleanOperator *) formula; int i; for (i = 0; i < operator->numOperands; ++i) { // recursively encode operands encodeFormula(network, operator->operands[i], geneIndex, stateIndex, sat); if (operator->operator == OPERATOR_AND) // if this is the outer conjunction, each inner element must be a clause // and thus be terminated by a 0 { sat_add_literal(sat, 0); } } } } /** * Add CNF clauses that represent the th-last state of the network * in the chain to the SAT solver . * specifies which of the formulae available for each gene should * be utilized for the state (usually the first, but there may be more than one * formula if the network comprises time-dependent predicates). */ static inline void addState_SAT(BooleanNetwork * network, Solver * sat, int stateIndex, unsigned int formulaIndex) { unsigned int i, j, k; for (i = 0; i < network->numGenes; ++i) { if (network->fixedGenes[i] != -1) // fixed gene => add a clause with a constant 1 or 0 for that gene { if (network->fixedGenes[i] == 0) sat_add_literal(sat, -(network->numGenes * stateIndex + i + 1)); else sat_add_literal(sat, network->numGenes * stateIndex + i + 1); sat_add_literal(sat, 0); } else // non-fixed gene { if (network->type == TRUTHTABLE_BOOLEAN_NETWORK) // network in truth table representation => construct CNF from truth table { TruthTableBooleanNetwork * ttNetwork = (TruthTableBooleanNetwork *) network; unsigned int numInputs = ttNetwork->inputGenePositions[i + 1] - ttNetwork->inputGenePositions[i]; unsigned int funcSize = ttNetwork->transitionFunctionPositions[i + 1] - ttNetwork->transitionFunctionPositions[i]; // construct clauses for equivalence relations by "doubling" the truth table of // the transition function (corresponding to inactive and active output) for (j = 0; j < funcSize; ++j) { // in the first half, the target gene is inactive (truth table result is negated) // input genes must be negated for CNF if (ttNetwork->transitionFunctions[ttNetwork->transitionFunctionPositions[i] + j]) { sat_add_literal(sat, network->numGenes * stateIndex + i + 1); for (k = 0; k < numInputs; ++k) { int varIndex = network->numGenes * (stateIndex + 1) + ttNetwork->inputGenes[ttNetwork->inputGenePositions[i] + k]; if (((j >> (numInputs - k - 1)) & 1) != 0) sat_add_literal(sat, -varIndex); else sat_add_literal(sat, varIndex); } sat_add_literal(sat, 0); } else { // in the second half, the target gene is active (unchanged truth table result) // input genes must be negated for CNF sat_add_literal(sat, -(network->numGenes * stateIndex + i + 1)); for (k = 0; k < numInputs; ++k) { int varIndex = network->numGenes * (stateIndex + 1) + ttNetwork->inputGenes[ttNetwork->inputGenePositions[i] + k]; if (((j >> (numInputs - k - 1)) & 1) != 0) sat_add_literal(sat, -varIndex); else sat_add_literal(sat, varIndex); } sat_add_literal(sat, 0); } } } else if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // network in symbolic representation => use CNF representation of the formulae // to generate the corresponding SAT solver clauses { SymbolicBooleanNetwork * symNetwork = (SymbolicBooleanNetwork *) network; // recursively encode the formula encodeFormula(symNetwork, symNetwork->cnfInteractions[i][formulaIndex], i, stateIndex, sat); if (symNetwork->cnfInteractions[i][formulaIndex]->type != FORMULA_OPERATOR || ((BooleanOperator *) symNetwork->cnfInteractions[i][formulaIndex])->operator != OPERATOR_AND) // if the top-level formula is not an AND operator, // the result is a single clause that needs to be terminated here { sat_add_literal(sat, 0); } } } } } /** * Add clauses to the SAT solver to specify that the -th last state and * the -th last state of the chain should be equal. * is the Boolean network from which the transition functions come. */ static inline void addEqualityCondition_SAT(Solver * sat, BooleanNetwork * network, unsigned int state1, unsigned int state2) { unsigned int i, j; for (i = 0; i < network->numGenes; ++i) // iterate over genes { unsigned int historySize = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // determine history size historySize = ((SymbolicBooleanNetwork *) network)->stateSizes[i]; // for temporal networks, the history must also be equal for the two states for (j = 0; j < historySize; ++j) { int gene1 = network->numGenes * (state1 + j) + i + 1; int gene2 = network->numGenes * (state2 + j) + i + 1; // equivalence consists of two clauses: (!A | B) & (A | !B) sat_add_literal(sat, gene1); sat_add_literal(sat, -gene2); sat_add_literal(sat, 0); sat_add_literal(sat, -gene1); sat_add_literal(sat, gene2); sat_add_literal(sat, 0); } } } /** * Exclude an identified attractor from the SAT search by adding its complement to the formula. * is a pointer to the SAT solver. * is the employed Boolean network. * is a structure holding the attractor to be excluded. */ static inline void excludeAttractor_SAT(Solver * sat, BooleanNetwork * network, pAttractor attractor) { unsigned int l, i, j; for (l = 0; l < attractor->length; ++l) // iterate over attractor states { // add the complement of the current state as a clause // (for temporal networks, this must also include the state history) for (i = 0; i < network->numGenes; ++i) // iterate over genes { unsigned int historySize = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // determine history size of the current gene historySize = ((SymbolicBooleanNetwork *) network)->stateSizes[i]; for (j = 0; j < historySize; ++j) { // decode value of the gene bool val = GET_BIT_ARRAY( attractor->involvedStates[((attractor->length + l - j) % attractor->length) * attractor->numElementsPerEntry], i); // add its complement to the clause (at the last state of the chain) if (val) sat_add_literal(sat, -(j * network->numGenes + i + 1)); else sat_add_literal(sat, j * network->numGenes + i + 1); } } // finish clause for the state sat_add_literal(sat, 0); } } /** * If a temporal network contains time-dependent predicates, this function adds a sequence of states * traversing the instable phase of the network to the beginning of the chain in . This is required * to ensure that only reachable start states are used for the attractor search. * is index of the current beginning of the chain. */ static inline void addBurnInPhase(SymbolicBooleanNetwork * network, Solver * sat, int startStateIndex) { if (network->attractorSearchStartTime > 0) // only do this if there is a time-dependent predicate { unsigned int j; for (j = 1; j <= network->attractorSearchStartTime; ++j) // iterate over the number of steps required for the burn-in and add states // utilizing the formulae that describe the behaviour at the corresponding time step addState_SAT((BooleanNetwork *) network, sat, startStateIndex + j, j); } } /** * Determine whether the SAT solver found an attractor. If yes, the attractor is * encoded in a Attractor structure and returned, and its states are excluded from future * SAT searches. * is the employed Boolean network. * is the length of the attractor if already known, or -1 if the length * should be determined by the function. * is the total length of the state chain (which may be more than the attractor size). * Returns a pointer to an Attractor structure holding the attractor, or NULL if no attractor * was found in the state chain. */ static inline pAttractor getNextAttractor_SAT(Solver * sat, BooleanNetwork * network, int attractorLength, unsigned int maxLength) { int i, j; if (attractorLength <= 0) // determine length if not already known { bool identical = true; for (attractorLength = 1; attractorLength <= maxLength; ++attractorLength) // traverse the states from the next-to-first to the last to find a duplicate of the // first state (chain is reversed => first state is a potential attractor state) { identical = true; for (i = 0; i < network->numGenes; ++i) // compare the values of each gene in the current state and the first state { unsigned int historySize = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // determine history size of current gene historySize = ((SymbolicBooleanNetwork *) network)->stateSizes[i]; for (j = 0; j < historySize; ++j) // in temporal networks, do not only compare the current state, // but also its history to make sure this is really an attractor { if (sat_deref(sat, (attractorLength + j) * network->numGenes + i + 1) != sat_deref(sat, j * network->numGenes + i + 1)) { identical = false; break; } } if (!identical) break; } if (identical) break; } if (!identical) // none of the states was identical to the last one => no attractor in the chain return NULL; } // An attractor was found => build Attractor structure pAttractor res = CALLOC(1, sizeof(Attractor)); if ((network->numGenes % BITS_PER_BLOCK_32) == 0) res->numElementsPerEntry = network->numGenes / BITS_PER_BLOCK_32; else res->numElementsPerEntry = network->numGenes / BITS_PER_BLOCK_32 + 1; res->length = attractorLength; res->involvedStates = (unsigned int *) CALLOC( res->length * res->numElementsPerEntry, sizeof(unsigned int)); for (attractorLength = 0; attractorLength < res->length; ++attractorLength) // iterate over attractor states { for (i = 0; i < network->numGenes; ++i) // iterate over genes { // determine gene value and set the corresponding entry in the state array if (sat_deref(sat, (res->length - attractorLength - 1) * network->numGenes + i + 1) == 1) SET_BIT_ARRAY( res->involvedStates[attractorLength * res->numElementsPerEntry], i); } } // exclude the found attractor from future SAT searches excludeAttractor_SAT(sat, network, res); return res; } /** * Determine all attractors having at most states in the network , * and return them in an AttractorInfo structure. */ pAttractorInfo getAttractors_SAT_maxLength(BooleanNetwork * network, unsigned int maxLength) { if (network->type == SYMBOLIC_BOOLEAN_NETWORK && ((SymbolicBooleanNetwork *) network)->attractorSearchStartTime > 0) { Rf_error( "SAT-based attractor search in networks with time-dependent predicates is only possible without attractor length restrictions!"); } pAttractorInfo res = allocAttractorInfo(0, network->numGenes); // add dummy terminator node res->attractorList = (pAttractor) CALLOC(1, sizeof(Attractor)); unsigned int i, j, length; unsigned int maxDelay = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // determine maximum time delay in the network { for (j = 0; j < network->numGenes; ++j) { unsigned int stateSize = ((SymbolicBooleanNetwork *) network)->stateSizes[j]; if (stateSize > maxDelay) { maxDelay = stateSize; } } } for (length = 1; length <= maxLength; ++length) // iterate over possible attractor lengths { // initialize SAT solver Solver * sat = initSATSolver(); pAttractor attractor = res->attractorList; while (attractor->next != NULL) // exclude all previously identified attractors from the search { excludeAttractor_SAT(sat, network, attractor); attractor = attractor->next; } // create a chain of +1 states for (i = 0; i <= length + maxDelay; ++i) { addState_SAT(network, sat, i, 0); } #ifdef USE_LINGELING for (i = 0; i < network->numGenes; ++i) // freeze the first state(s) of the chain: // the variables of the first state are used // to exclude identified attractors from future searches // (multiple states for temporal Boolean networks with delays >1) { unsigned int stateSize = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // determine history size for current gene stateSize = ((SymbolicBooleanNetwork *) network)->stateSizes[i]; for (j = 0; j < stateSize; ++j) { lglfreeze(sat, j * network->numGenes + i + 1); } } #endif // specify that the first and the last state of the chain // should be identical addEqualityCondition_SAT(sat, network, 0, length); //lglprint(lgl, stdout); // call the SAT solver int satisfiable = sat_solve(sat); while (satisfiable == SATISFIABLE) // as long as the formula is satisfiable, there are more attractors // of the specified length { // encode the attractor in an Attractor structure, // prepend it to the result list, and exclude it from the search pAttractor attr = getNextAttractor_SAT(sat, network, length, 0); ++res->numAttractors; attr->next = res->attractorList; res->attractorList = attr; // try to find further solutions satisfiable = sat_solve(sat); } // free SAT solver sat_free(sat); } return res; } /** * Identify all attractors using a SAT-based algorithm adapted from Dubrova et al., 2011. * Here, is the network whose attractors are identified. * If > 0, the first step of the algorithm is to identify and exclude * all attractors of length 1 to . * specifies the way the chain is extended: * EXTENSION_EXPONENTIAL corresponds to the exponential scheme by Dubrova et al. * EXTENSION_LINEAR corresponds to linearly increasing the length * EXTENSION_LINEAR_ADAPT corresponds to a linear increase whose step width is * increased over the iterations * EXTENSION_MIXED corresponds to a mixture of linear and exponential increase, * where the chain length is doubled after 5 linear increases. * Returns an AttractorInfo structure comprising all attractors of the network. */ pAttractorInfo getAttractors_SAT_exhaustive(BooleanNetwork * network, unsigned int initialCycleSearchLength, unsigned int extensionMode) { // initialize SAT solver Solver * sat = initSATSolver(); int i, j, maxDelay = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // determine maximum time delay in the network { for (j = 0; j < network->numGenes; ++j) { unsigned int stateSize = ((SymbolicBooleanNetwork *) network)->stateSizes[j]; if (stateSize > maxDelay) { maxDelay = stateSize; } } } // check if the network comprises time-dependent predicates -- // for such networks, the chain cannot be extended and must be rebuilt // each time a longer chain is needed bool isTimeDependent = (network->type == SYMBOLIC_BOOLEAN_NETWORK && ((SymbolicBooleanNetwork *) network)->attractorSearchStartTime > 0); if (isTimeDependent) // for time-dependent predicates, length-based attractor search is not supported { initialCycleSearchLength = 0; } pAttractorInfo res; if (initialCycleSearchLength != 0) // first determine attractors by explicitly searching for cycles // if a cycle length is specified { //unsigned int maxAttractorLength = 2000/network->numGenes; //if (maxAttractorLength == 0) // maxAttractorLength = 1; //else //if (maxAttractorLength > 10) // maxAttractorLength = 10; res = getAttractors_SAT_maxLength(network, initialCycleSearchLength); } else // initialize empty attractor list { res = allocAttractorInfo(0, network->numGenes); // add dummy terminator node res->attractorList = (pAttractor) CALLOC(1, sizeof(Attractor)); } // construct initial chain of maximum length 100 int numStates = network->numGenes > 100 ? 100 : network->numGenes; for (i = 0; i < numStates; ++i) { addState_SAT(network, sat, i, 0); } //picosat_print(sat, stdout); if (initialCycleSearchLength != 0) // if attractors have been identified by the cycle search, // exclude them from the search { pAttractor attractor = res->attractorList; while (attractor->next != NULL) { excludeAttractor_SAT(sat, network, attractor); attractor = attractor->next; } } #ifdef USE_LINGELING for (i = 0; i < network->numGenes; ++i) // freeze the first and the last state(s) of the chain: // the variables of the first state are used // to exclude identified attractors from future searches, // whereas the variables of the last state(s) are required for // an extension of the chain // (multiple states for temporal Boolean networks with delays >1) { unsigned int stateSize = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // determine history size of current gene stateSize = ((SymbolicBooleanNetwork *) network)->stateSizes[i]; for (j = 0; j < stateSize; ++j) { lglfreeze(sat, j * network->numGenes + i + 1); if (!isTimeDependent) lglfreeze(sat, (numStates + j) * network->numGenes + i + 1); } } #endif if (isTimeDependent) // add additional states in case of time-dependent predicates addBurnInPhase((SymbolicBooleanNetwork *) network, sat, numStates - 1); //picosat_print(sat, stdout); int satisfiable = sat_solve(sat); unsigned int numIncrements = 0; while (satisfiable == SATISFIABLE) // as long as the formula is satisfiable, there may be more attractors { // check whether the identified chain comprises an attractor, // and decode it if yes pAttractor attr = getNextAttractor_SAT(sat, network, -1, numStates - maxDelay + 1); if (attr == NULL) // no attractor found => chain is too short and must be prolonged { if (isTimeDependent) // if additional burn-in states were added, the chain must be rebuilt "from scratch", // i.e. the previous result cannot be recycled. { // free old solver sat_free(sat); // create new solver sat = initSATSolver(); // exclude already identified attractors pAttractor attractor = res->attractorList; while (attractor->next != NULL) { excludeAttractor_SAT(sat, network, attractor); attractor = attractor->next; } // start chain at time point 0 i = 0; } else { #ifdef USE_LINGELING if (!isTimeDependent) { // melt the variables of the last state(s), as // the chain will be extended for (i = 0; i < network->numGenes; ++i) { unsigned int stateSize = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) stateSize = ((SymbolicBooleanNetwork *) network)->stateSizes[i]; for (j = 0; j < stateSize; ++j) lglmelt(sat, (numStates + j) * network->numGenes + i + 1); } // extend chain at previous time point i = numStates; } #endif } switch (extensionMode) // determine the new chain length depending on the extension mode { case EXTENSION_EXPONENTIAL: // double the chain length numStates *= 2; break; case EXTENSION_LINEAR: // add the initial chain length numStates += network->numGenes > 100 ? 100 : network->numGenes; break; case EXTENSION_LINEAR_ADAPT: // add a multiple of the initial chain length depending // on the number of increments already performed numStates += (numIncrements++ / 5 + 1) * (network->numGenes > 100 ? 100 : network->numGenes); break; case EXTENSION_MIXED: // perform an exponential increase every five increments and a // linear increase otherwise if (++numIncrements % 5 == 0) numStates *= 2; else numStates += network->numGenes > 100 ? 100 : network->numGenes; break; } // add new states to the chain for (; i < numStates; ++i) { addState_SAT(network, sat, i, 0); } if (!isTimeDependent) { #ifdef USE_LINGELING // freeze the new end of the chain // (possibly multiple states in temporal Boolean networks) for (i = 0; i < network->numGenes; ++i) { unsigned int stateSize = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) // determine history size of current gene stateSize = ((SymbolicBooleanNetwork *) network)->stateSizes[i]; for (j = 0; j < stateSize; ++j) lglfreeze(sat, (numStates + j) * network->numGenes + i + 1); } #endif } else // network has time-dependent predicates { // add additional states in case of time-dependent predicates addBurnInPhase((SymbolicBooleanNetwork *) network, sat, numStates - 1); #ifdef USE_LINGELING // as a new chain has been constructed from scratch, we must // again freeze the start state(s) for (i = 0; i < network->numGenes; ++i) { unsigned int stateSize = 1; if (network->type == SYMBOLIC_BOOLEAN_NETWORK) stateSize = ((SymbolicBooleanNetwork *) network)->stateSizes[i]; for (j = 0; j < stateSize; ++j) { lglfreeze(sat, j * network->numGenes + i + 1); } } #endif } } else // an attractor has been found => add it { ++res->numAttractors; attr->next = res->attractorList; res->attractorList = attr; } // look for more potential solutions satisfiable = sat_solve(sat); } // free the SAT solver sat_free(sat); return res; } BoolNet/src/common.c0000644000176200001440000000765714362446442014067 0ustar liggesusers#include "common.h" #include #include AllocatedMemory * memoryMap = NULL; /** * Common utilities for the BoolNet package * * Copyright 2009/2010 by Christoph Müssel and Zhou Dao * * Contact christoph.muessel@uni-ulm.de */ void freeAllMemory(void) { AllocatedMemory * m, * tmp; HASH_ITER(hh, memoryMap, m, tmp) { HASH_DEL(memoryMap, m); free(m->ptr); free(m); } //Rprintf("Freed all memory\n"); } /** * Encode a vector of binary values in an integer. * The rightmost element in is the leftmost bit in * is an array of elements, and points * to an integer to which the result is written. */ void bin2decC(int *dec, int *bin, int *numBits) { // clear output first unsigned int numElts; if (*numBits % BITS_PER_BLOCK_32 == 0) numElts = *numBits / BITS_PER_BLOCK_32; else numElts = *numBits / BITS_PER_BLOCK_32 + 1; memset(dec,0,numElts*sizeof(int)); // decode input and write binary integers unsigned int * unsigned_dec = (unsigned int *) dec; unsigned int i; for(i = 0; i < *numBits; ++i) { unsigned_dec[i / BITS_PER_BLOCK_32] |= ((unsigned int)bin[i] << (i % BITS_PER_BLOCK_32)); } } /** * Decode an integer to a vector of binary values. * The rightmost element in is the leftmost bit in * points to the result vector, is a number * to be decoded, and is the number of bits/elements in bin */ void dec2binC(int *bin, int *dec, int *numBits) { unsigned int i; unsigned int * unsigned_dec = (unsigned int *) dec; for(i = 0; i < *numBits; ++i) if( (unsigned_dec[i / BITS_PER_BLOCK_32] & ((unsigned int)1 << (i % BITS_PER_BLOCK_32))) != 0) bin[i] = 1; else bin[i] = 0; } /** * Inserts values of fixed genes into states - this is required as * fixed genes are not encoded in the internal state representations. * is a pointer to a state to be corrected. * is an array specifying which genes are fixed, as contained in * the BooleanNetwork structure. * is the length of . * The function changes the state pointed to by and has no return value. */ void insertFixedGenes(unsigned int * value, int* fixedGenes, unsigned int numGenes) { unsigned int tmp[numGenes]; unsigned int i, j = 0; // build an array of Boolean values for the genes for (i = 0; i < numGenes; ++i) { if (fixedGenes[i] != -1) // this gene is fixed { tmp[i] = fixedGenes[i]; } else // not a fixed gene => take value from original state { tmp[i] = ((value[j / BITS_PER_BLOCK_32] & ((unsigned int)1 << (j % BITS_PER_BLOCK_32))) != 0) ? 1 : 0; ++j; } } // re-encode Boolean array to integer value bin2decC((int *)value,(int*)tmp,(int*)&numGenes); } /** * Removes values of fixed genes from states - this is required as * fixed genes are not encoded in the internal state representations. * is a pointer to a state to be corrected. * is an array specifying which genes are fixed, as contained in * the BooleanNetwork structure. * is the length of . * The function changes the state pointed to by and has no return value. */ void removeFixedGenes(unsigned int * value, int* fixedGenes, unsigned int numGenes) { unsigned int tmp[numGenes]; memset(tmp,0,sizeof(unsigned int) * numGenes); unsigned int i, j = 0; // build an array of Boolean values for the genes for (i = 0; i < numGenes; ++i) { if (fixedGenes[i] == -1) { tmp[j] = ((value[i / BITS_PER_BLOCK_32] & ((unsigned int)1 << (i % BITS_PER_BLOCK_32))) != 0) ? 1 : 0; ++j; } } // re-encode Boolean array to integer value bin2decC((int *)value,(int*)tmp,(int*)&numGenes); } SEXP getListElement(SEXP list, char *str) { SEXP names = getAttrib(list, R_NamesSymbol); unsigned int i; for (i = 0; i < length(list); ++i) { if (strcmp(CHAR(STRING_ELT(names, i)), str) == 0 ) { return VECTOR_ELT(list, i); } } return R_NilValue; } BoolNet/src/Makevars.win0000644000176200001440000000005014506502626014674 0ustar liggesusersPKG_CFLAGS = -DNGETRUSAGE -DNALLSIGNALS BoolNet/src/picosat.h0000644000176200001440000006775413277247010014244 0ustar liggesusers/**************************************************************************** Copyright (c) 2006 - 2015, Armin Biere, Johannes Kepler University. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #ifndef picosat_h_INCLUDED #define picosat_h_INCLUDED /*------------------------------------------------------------------------*/ #include #include /*------------------------------------------------------------------------*/ /* The following macros allows for users to distiguish between different * versions of the API. The first 'PICOSAT_REENTRANT_API' is defined for * the new reentrant API which allows to generate multiple instances of * PicoSAT in one process. The second 'PICOSAT_API_VERSION' defines the * (smallest) version of PicoSAT to which this API conforms. */ #define PICOSAT_REENTRANT_API #define PICOSAT_API_VERSION 953 /* API version */ /*------------------------------------------------------------------------*/ /* These are the return values for 'picosat_sat' as for instance * standardized by the output format of the SAT competition. */ #define PICOSAT_UNKNOWN 0 #define PICOSAT_SATISFIABLE 10 #define PICOSAT_UNSATISFIABLE 20 /*------------------------------------------------------------------------*/ typedef struct PicoSAT PicoSAT; /*------------------------------------------------------------------------*/ const char *picosat_version (void); const char *picosat_config (void); const char *picosat_copyright (void); /*------------------------------------------------------------------------*/ /* You can make PicoSAT use an external memory manager instead of the one * provided by LIBC. But then you need to call these three function before * 'picosat_init'. The memory manager functions here all have an additional * first argument which is a pointer to the memory manager, but otherwise * are supposed to work as their LIBC counter parts 'malloc', 'realloc' and * 'free'. As exception the 'resize' and 'delete' function have as third * argument the number of bytes of the block given as second argument. */ typedef void * (*picosat_malloc)(void *, size_t); typedef void * (*picosat_realloc)(void*, void *, size_t, size_t); typedef void (*picosat_free)(void*, void*, size_t); /*------------------------------------------------------------------------*/ PicoSAT * picosat_init (void); /* constructor */ PicoSAT * picosat_minit (void * state, picosat_malloc, picosat_realloc, picosat_free); void picosat_reset (PicoSAT *); /* destructor */ /*------------------------------------------------------------------------*/ /* The following five functions are essentially parameters to 'init', and * thus should be called right after 'picosat_init' before doing anything * else. You should not call any of them after adding a literal. */ /* Set output file, default is 'stdout'. */ void picosat_set_output (PicoSAT *, FILE *); /* Measure all time spent in all calls in the solver. By default only the * time spent in 'picosat_sat' is measured. Enabling this function might * for instance triple the time needed to add large CNFs, since every call * to 'picosat_add' will trigger a call to 'getrusage'. */ void picosat_measure_all_calls (PicoSAT *); /* Set the prefix used for printing verbose messages and statistics. * Default is "c ". */ void picosat_set_prefix (PicoSAT *, const char *); /* Set verbosity level. A verbosity level of 1 and above prints more and * more detailed progress reports on the output file, set by * 'picosat_set_output'. Verbose messages are prefixed with the string set * by 'picosat_set_prefix'. */ void picosat_set_verbosity (PicoSAT *, int new_verbosity_level); /* Disable/Enable all pre-processing, currently only failed literal probing. * * new_plain_value != 0 only 'plain' solving, so no preprocessing * new_plain_value == 0 allow preprocessing */ void picosat_set_plain (PicoSAT *, int new_plain_value); /* Set default initial phase: * * 0 = false * 1 = true * 2 = Jeroslow-Wang (default) * 3 = random initial phase * * After a variable has been assigned the first time, it will always * be assigned the previous value if it is picked as decision variable. * The initial assignment can be chosen with this function. */ void picosat_set_global_default_phase (PicoSAT *, int); /* Set next/initial phase of a particular variable if picked as decision * variable. Second argument 'phase' has the following meaning: * * negative = next value if picked as decision variable is false * * positive = next value if picked as decision variable is true * * 0 = use global default phase as next value and * assume 'lit' was never assigned * * Again if 'lit' is assigned afterwards through a forced assignment, * then this forced assignment is the next phase if this variable is * used as decision variable. */ void picosat_set_default_phase_lit (PicoSAT *, int lit, int phase); /* You can reset all phases by the following function. */ void picosat_reset_phases (PicoSAT *); /* Scores can be erased as well. Note, however, that even after erasing * scores and phases, learned clauses are kept. In addition head tail * pointers for literals are not moved either. So expect a difference * between calling the solver in incremental mode or with a fresh copy of * the CNF. */ void picosat_reset_scores (PicoSAT *); /* Reset assignment if in SAT state and then remove the given percentage of * less active (large) learned clauses. If you specify 100% all large * learned clauses are removed. */ void picosat_remove_learned (PicoSAT *, unsigned percentage); /* Set some variables to be more important than others. These variables are * always used as decisions before other variables are used. Dually there * is a set of variables that is used last. The default is * to mark all variables as being indifferent only. */ void picosat_set_more_important_lit (PicoSAT *, int lit); void picosat_set_less_important_lit (PicoSAT *, int lit); /* Allows to print to internal 'out' file from client. */ void picosat_message (PicoSAT *, int verbosity_level, const char * fmt, ...); /* Set a seed for the random number generator. The random number generator * is currently just used for generating random decisions. In our * experiments having random decisions did not really help on industrial * examples, but was rather helpful to randomize the solver in order to * do proper benchmarking of different internal parameter sets. */ void picosat_set_seed (PicoSAT *, unsigned random_number_generator_seed); /* If you ever want to extract cores or proof traces with the current * instance of PicoSAT initialized with 'picosat_init', then make sure to * call 'picosat_enable_trace_generation' right after 'picosat_init'. This * is not necessary if you only use 'picosat_set_incremental_rup_file'. * * NOTE, trace generation code is not necessarily included, e.g. if you * configure PicoSAT with full optimzation as './configure -O' or with * you do not get any results by trying to generate traces. * * The return value is non-zero if code for generating traces is included * and it is zero if traces can not be generated. */ int picosat_enable_trace_generation (PicoSAT *); /* You can dump proof traces in RUP format incrementally even without * keeping the proof trace in memory. The advantage is a reduction of * memory usage, but the dumped clauses do not necessarily belong to the * clausal core. Beside the file the additional parameters denotes the * maximal number of variables and the number of original clauses. */ void picosat_set_incremental_rup_file (PicoSAT *, FILE * file, int m, int n); /* Save original clauses for 'picosat_deref_partial'. See comments to that * function further down. */ void picosat_save_original_clauses (PicoSAT *); /* Add a call back which is checked regularly to notify the SAT solver * to terminate earlier. This is useful for setting external time limits * or terminate early in say a portfolio style parallel SAT solver. */ void picosat_set_interrupt (PicoSAT *, void * external_state, int (*interrupted)(void * external_state)); /*------------------------------------------------------------------------*/ /* This function returns the next available unused variable index and * allocates a variable for it even though this variable does not occur as * assumption, nor in a clause or any other constraints. In future calls to * 'picosat_sat', 'picosat_deref' and particularly for 'picosat_changed', * this variable is treated as if it had been used. */ int picosat_inc_max_var (PicoSAT *); /*------------------------------------------------------------------------*/ /* Push and pop semantics for PicoSAT. 'picosat_push' opens up a new * context. All clauses added in this context are attached to it and * discarded when the context is closed with 'picosat_pop'. It is also * possible to nest contexts. * * The current implementation uses a new internal variable for each context. * However, the indices for these internal variables are shared with * ordinary external variables. This means that after any call to * 'picosat_push', new variable indices should be obtained with * 'picosat_inc_max_var' and not just by incrementing the largest variable * index used so far. * * The return value is the index of the literal that assumes this context. * This literal can only be used for 'picosat_failed_context' otherwise * it will lead to an API usage error. */ int picosat_push (PicoSAT *); /* This is as 'picosat_failed_assumption', but only for internal variables * generated by 'picosat_push'. */ int picosat_failed_context (PicoSAT *, int lit); /* Returns the literal that assumes the current context or zero if the * outer context has been reached. */ int picosat_context (PicoSAT *); /* Closes the current context and recycles the literal generated for * assuming this context. The return value is the literal for the new * outer context or zero if the outer most context has been reached. */ int picosat_pop (PicoSAT *); /* Force immmediate removal of all satisfied clauses and clauses that are * added or generated in closed contexts. This function is called * internally if enough units are learned or after a certain number of * contexts have been closed. This number is fixed at compile time * and defined as MAXCILS in 'picosat.c'. * * Note that learned clauses which only involve outer contexts are kept. */ void picosat_simplify (PicoSAT *); /*------------------------------------------------------------------------*/ /* If you know a good estimate on how many variables you are going to use * then calling this function before adding literals will result in less * resizing of the variable table. But this is just a minor optimization. * Beside exactly allocating enough variables it has the same effect as * calling 'picosat_inc_max_var'. */ void picosat_adjust (PicoSAT *, int max_idx); /*------------------------------------------------------------------------*/ /* Statistics. */ int picosat_variables (PicoSAT *); /* p cnf n */ int picosat_added_original_clauses (PicoSAT *); /* p cnf m */ size_t picosat_max_bytes_allocated (PicoSAT *); double picosat_time_stamp (void); /* ... in process */ void picosat_stats (PicoSAT *); /* > output file */ unsigned long long picosat_propagations (PicoSAT *); /* #propagations */ unsigned long long picosat_decisions (PicoSAT *); /* #decisions */ unsigned long long picosat_visits (PicoSAT *); /* #visits */ /* The time spent in calls to the library or in 'picosat_sat' respectively. * The former is returned if, right after initialization * 'picosat_measure_all_calls' is called. */ double picosat_seconds (PicoSAT *); /*------------------------------------------------------------------------*/ /* Add a literal of the next clause. A zero terminates the clause. The * solver is incremental. Adding a new literal will reset the previous * assignment. The return value is the original clause index to which * this literal respectively the trailing zero belong starting at 0. */ int picosat_add (PicoSAT *, int lit); /* As the previous function, but allows to add a full clause at once with an * at compiled time known size. The list of argument literals has to be * terminated with a zero literal. Literals beyond the first zero literal * are discarded. */ int picosat_add_arg (PicoSAT *, ...); /* As the previous function but with an at compile time unknown size. */ int picosat_add_lits (PicoSAT *, int * lits); /* Print the CNF to the given file in DIMACS format. */ void picosat_print (PicoSAT *, FILE *); /* You can add arbitrary many assumptions before the next 'picosat_sat' * call. This is similar to the using assumptions in MiniSAT, except that * for PicoSAT you do not have to collect all your assumptions in a vector * yourself. In PicoSAT you can add one after the other, to be used in the * next call to 'picosat_sat'. * * These assumptions can be interpreted as adding unit clauses with those * assumptions as literals. However these assumption clauses are only valid * for exactly the next call to 'picosat_sat', and will be removed * afterwards, e.g. in following future calls to 'picosat_sat' after the * next 'picosat_sat' call, unless they are assumed again trough * 'picosat_assume'. * * More precisely, assumptions actually remain valid even after the next * call to 'picosat_sat' has returned. Valid means they remain 'assumed' * internally until a call to 'picosat_add', 'picosat_assume', or a second * 'picosat_sat', following the first 'picosat_sat'. The reason for keeping * them valid is to allow 'picosat_failed_assumption' to return correct * values. * * Example: * * picosat_assume (1); // assume unit clause '1 0' * picosat_assume (-2); // additionally assume clause '-2 0' * res = picosat_sat (1000); // assumes 1 and -2 to hold * // 1000 decisions max. * * if (res == PICOSAT_UNSATISFIABLE) * { * if (picosat_failed_assumption (1)) * // unit clause '1 0' was necessary to derive UNSAT * * if (picosat_failed_assumption (-2)) * // unit clause '-2 0' was necessary to derive UNSAT * * // at least one but also both could be necessary * * picosat_assume (17); // previous assumptions are removed * // now assume unit clause '17 0' for * // the next call to 'picosat_sat' * * // adding a new clause, actually the first literal of * // a clause would also make the assumptions used in the previous * // call to 'picosat_sat' invalid. * * // The first two assumptions above are not assumed anymore. Only * // the assumptions, since the last call to 'picosat_sat' returned * // are assumed, e.g. the unit clause '17 0'. * * res = picosat_sat (-1); * } * else if (res == PICOSAT_SATISFIABLE) * { * // now the assignment is valid and we can call 'picosat_deref' * * assert (picosat_deref (1) == 1)); * assert (picosat_deref (-2) == 1)); * * val = picosat_deref (15); * * // previous two assumptions are still valid * * // would become invalid if 'picosat_add' or 'picosat_assume' is * // called here, but we immediately call 'picosat_sat'. Now when * // entering 'picosat_sat' the solver knows that the previous call * // returned SAT and it can safely reset the previous assumptions * * res = picosat_sat (-1); * } * else * { * assert (res == PICOSAT_UNKNOWN); * * // assumptions valid, but assignment invalid * // except for top level assigned literals which * // necessarily need to have this value if the formula is SAT * * // as above the solver nows that the previous call returned UNKWOWN * // and will before doing anything else reset assumptions * * picosat_sat (-1); * } */ void picosat_assume (PicoSAT *, int lit); /*------------------------------------------------------------------------*/ /* This is an experimental feature for handling 'all different constraints' * (ADC). Currently only one global ADC can be handled. The bit-width of * all the bit-vectors entered in this ADC (stored in 'all different * objects' or ADOs) has to be identical. * * TODO: also handle top level assigned literals here. */ void picosat_add_ado_lit (PicoSAT *, int); /*------------------------------------------------------------------------*/ /* Call the main SAT routine. A negative decision limit sets no limit on * the number of decisions. The return values are as above, e.g. * 'PICOSAT_UNSATISFIABLE', 'PICOSAT_SATISFIABLE', or 'PICOSAT_UNKNOWN'. */ int picosat_sat (PicoSAT *, int decision_limit); /* As alternative to a decision limit you can use the number of propagations * as limit. This is more linearly related to execution time. This has to * be called after 'picosat_init' and before 'picosat_sat'. */ void picosat_set_propagation_limit (PicoSAT *, unsigned long long limit); /* Return last result of calling 'picosat_sat' or '0' if not called. */ int picosat_res (PicoSAT *); /* After 'picosat_sat' was called and returned 'PICOSAT_SATISFIABLE', then * the satisfying assignment can be obtained by 'dereferencing' literals. * The value of the literal is return as '1' for 'true', '-1' for 'false' * and '0' for an unknown value. */ int picosat_deref (PicoSAT *, int lit); /* Same as before but just returns true resp. false if the literals is * forced to this assignment at the top level. This function does not * require that 'picosat_sat' was called and also does not internally reset * incremental usage. */ int picosat_deref_toplevel (PicoSAT *, int lit); /* After 'picosat_sat' was called and returned 'PICOSAT_SATISFIABLE' a * partial satisfying assignment can be obtained as well. It satisfies all * original clauses. The value of the literal is return as '1' for 'true', * '-1' for 'false' and '0' for an unknown value. In order to make this * work all original clauses have to be saved internally, which has to be * enabled by 'picosat_save_original_clauses' right after initialization. */ int picosat_deref_partial (PicoSAT *, int lit); /* Returns non zero if the CNF is unsatisfiable because an empty clause was * added or derived. */ int picosat_inconsistent (PicoSAT *); /* Returns non zero if the literal is a failed assumption, which is defined * as an assumption used to derive unsatisfiability. This is as accurate as * generating core literals, but still of course is an overapproximation of * the set of assumptions really necessary. The technique does not need * clausal core generation nor tracing to be enabled and thus can be much * more effective. The function can only be called as long the current * assumptions are valid. See 'picosat_assume' for more details. */ int picosat_failed_assumption (PicoSAT *, int lit); /* Returns a zero terminated list of failed assumption in the last call to * 'picosat_sat'. The pointer is valid until the next call to * 'picosat_sat' or 'picosat_failed_assumptions'. It only makes sense if the * last call to 'picosat_sat' returned 'PICOSAT_UNSATISFIABLE'. */ const int * picosat_failed_assumptions (PicoSAT *); /* Returns a zero terminated minimized list of failed assumption for the last * call to 'picosat_sat'. The pointer is valid until the next call to this * function or 'picosat_sat' or 'picosat_mus_assumptions'. It only makes sense * if the last call to 'picosat_sat' returned 'PICOSAT_UNSATISFIABLE'. * * The call back function is called for all successful simplification * attempts. The first argument of the call back function is the state * given as first argument to 'picosat_mus_assumptions'. The second * argument to the call back function is the new reduced list of failed * assumptions. * * This function will call 'picosat_assume' and 'picosat_sat' internally but * before returning reestablish a proper UNSAT state, e.g. * 'picosat_failed_assumption' will work afterwards as expected. * * The last argument if non zero fixes assumptions. In particular, if an * assumption can not be removed it is permanently assigned true, otherwise * if it turns out to be redundant it is permanently assumed to be false. */ const int * picosat_mus_assumptions (PicoSAT *, void *, void(*)(void*,const int*),int); /* Compute one maximal subset of satisfiable assumptions. You need to set * the assumptions, call 'picosat_sat' and check for 'picosat_inconsistent', * before calling this function. The result is a zero terminated array of * assumptions that consistently can be asserted at the same time. Before * returing the library 'reassumes' all assumptions. * * It could be beneficial to set the default phase of assumptions * to true (positive). This can speed up the computation. */ const int * picosat_maximal_satisfiable_subset_of_assumptions (PicoSAT *); /* This function assumes that you have set up all assumptions with * 'picosat_assume'. Then it calls 'picosat_sat' internally unless the * formula is already inconsistent without assumptions, i.e. it contains * the empty clause. After that it extracts a maximal satisfiable subset of * assumptions. * * The result is a zero terminated maximal subset of consistent assumptions * or a zero pointer if the formula contains the empty clause and thus no * more maximal consistent subsets of assumptions can be extracted. In the * first case, before returning, a blocking clause is added, that rules out * the result for the next call. * * NOTE: adding the blocking clause changes the CNF. * * So the following idiom * * const int * mss; * picosat_assume (a1); * picosat_assume (a2); * picosat_assume (a3); * picosat_assume (a4); * while ((mss = picosat_next_maximal_satisfiable_subset_of_assumptions ())) * process_mss (mss); * * can be used to iterate over all maximal consistent subsets of * the set of assumptions {a1,a2,a3,a4}. * * It could be beneficial to set the default phase of assumptions * to true (positive). This might speed up the computation. */ const int * picosat_next_maximal_satisfiable_subset_of_assumptions (PicoSAT *); /* Similarly we can iterate over all minimal correcting assumption sets. * See the CAMUS literature [M. Liffiton, K. Sakallah JAR 2008]. * * The result contains each assumed literal only once, even if it * was assumed multiple times (in contrast to the maximal consistent * subset functions above). * * It could be beneficial to set the default phase of assumptions * to true (positive). This might speed up the computation. */ const int * picosat_next_minimal_correcting_subset_of_assumptions (PicoSAT *); /* Compute the union of all minmal correcting sets, which is called * the 'high level union of all minimal unsatisfiable subset sets' * or 'HUMUS' in our papers. * * It uses 'picosat_next_minimal_correcting_subset_of_assumptions' and * the same notes and advices apply. In particular, this implies that * after calling the function once, the current CNF becomes inconsistent, * and PicoSAT has to be reset. So even this function internally uses * PicoSAT incrementally, it can not be used incrementally itself at this * point. * * The 'callback' can be used for progress logging and is called after * each extracted minimal correcting set if non zero. The 'nhumus' * parameter of 'callback' denotes the number of assumptions found to be * part of the HUMUS sofar. */ const int * picosat_humus (PicoSAT *, void (*callback)(void * state, int nmcs, int nhumus), void * state); /*------------------------------------------------------------------------*/ /* Assume that a previous call to 'picosat_sat' in incremental usage, * returned 'SATISFIABLE'. Then a couple of clauses and optionally new * variables were added (a new variable is a variable that has an index * larger then the maximum variable added so far). The next call to * 'picosat_sat' also returns 'SATISFIABLE'. If this function * 'picosat_changed' returns '0', then the assignment to the old variables * is guaranteed to not have changed. Otherwise it might have changed. * * The return value to this function is only valid until new clauses are * added through 'picosat_add', an assumption is made through * 'picosat_assume', or again 'picosat_sat' is called. This is the same * assumption as for 'picosat_deref'. * * TODO currently this function might also return a non zero value even if * the old assignment did not change, because it only checks whether the * assignment of at least one old variable was flipped at least once during * the search. In principle it should be possible to be exact in the other * direction as well by using a counter of variables that have an odd number * of flips. But this is not implemented yet. */ int picosat_changed (PicoSAT *); /*------------------------------------------------------------------------*/ /* The following six functions internally extract the variable and clausal * core and thus require trace generation to be enabled with * 'picosat_enable_trace_generation' right after calling 'picosat_init'. * * TODO: using these functions in incremental mode with failed assumptions * has only been tested for 'picosat_corelit' thoroughly. The others * probably only work in non-incremental mode or without using * 'picosat_assume'. */ /* This function determines whether the i'th added original clause is in the * core. The 'i' is the return value of 'picosat_add', which starts at zero * and is incremented by one after a original clause is added (that is after * 'picosat_add (0)'). For the index 'i' the following has to hold: * * 0 <= i < picosat_added_original_clauses () */ int picosat_coreclause (PicoSAT *, int i); /* This function gives access to the variable core, which is made up of the * variables that were resolved in deriving the empty clause. */ int picosat_corelit (PicoSAT *, int lit); /* Write the clauses that were used in deriving the empty clause to a file * in DIMACS format. */ void picosat_write_clausal_core (PicoSAT *, FILE * core_file); /* Write a proof trace in TraceCheck format to a file. */ void picosat_write_compact_trace (PicoSAT *, FILE * trace_file); void picosat_write_extended_trace (PicoSAT *, FILE * trace_file); /* Write a RUP trace to a file. This trace file contains only the learned * core clauses while this is not necessarily the case for the RUP file * obtained with 'picosat_set_incremental_rup_file'. */ void picosat_write_rup_trace (PicoSAT *, FILE * trace_file); /*------------------------------------------------------------------------*/ /* Keeping the proof trace around is not necessary if an over-approximation * of the core is enough. A literal is 'used' if it was involved in a * resolution to derive a learned clause. The core literals are necessarily * a subset of the 'used' literals. */ int picosat_usedlit (PicoSAT *, int lit); /*------------------------------------------------------------------------*/ #endif BoolNet/src/attractor_info.h0000644000176200001440000000457313277247010015606 0ustar liggesusers#ifndef ATTRACTOR_INFO_H #define ATTRACTOR_INFO_H typedef struct TTE { unsigned int * initialState; unsigned int * nextState; struct TTE * next; } TransitionTableEntry; /** * Structure that internally describes an attractor */ typedef struct Attractor { // an array of states the attractor consists of unsigned int *involvedStates; // if this is a complex attractor, // the transitions of the attractor are stored here TransitionTableEntry * table; // the number of elements in
unsigned int transitionTableSize; // the number of array elements for one entry of // - i.e. for more than 32 genes, successive // array elements form one entry. unsigned int numElementsPerEntry; // the number of states in int length; // the number of states in the basin of attraction unsigned int basinSize; // list pointer to the next element struct Attractor *next; } Attractor, *pAttractor; /** * A structure holding all information * retrieved by the algorithms in this file */ typedef struct { // the number of elements in the following three arrays unsigned long long tableSize; // the states before the transition - can be NULL unsigned int *initialStates; // the resulting states of the transition table unsigned int *table; // the number of array elements for one entry of the table // - i.e. for more than 32 genes, successive // array elements in
and form one table entry. unsigned int numElementsPerEntry; // the attractors the corresponding states belong to unsigned int *attractorAssignment; // the number of transitions needed to go from the original state // (before transition, not stored here as it is defined by the order) // to the attractor unsigned int *stepsToAttractor; // the list of attractors pAttractor attractorList; // the number of list elements in attractorList unsigned int numAttractors; } AttractorInfo, *pAttractorInfo; /** * Allocate a new AttractorInfo structure for states */ extern pAttractorInfo allocAttractorInfo(unsigned long long tableSize, unsigned int numGenes); /** * Free a list of attractor structures */ extern void freeAttractorList(pAttractor p); /** * Free an AttractorInfo structure including * all sub-elements and the attractor list */ extern void freeAttractorInfo(pAttractorInfo p); #endif BoolNet/src/statespace_search.c0000644000176200001440000012004313277247010016233 0ustar liggesusers/** * C code to identify attractors in Boolean networks * * This is part of the BoolNet R package. * * Copyright 2009/2010 by Christoph Müssel and Zhou Dao * * Contact christoph.muessel@uni-ulm.de * */ #include #include #include #include #include #include "random.h" #include "common.h" #include "boolean_network.h" #include "statespace_search.h" #include #define NODE_ARRAY_SIZE 1024 /** * A structure saving search trees for states. * State trees are employed if a non-exhaustive search is * conducted to provide an efficient method to lookup * states that have already been visited. */ typedef struct STN { // The left child node (containing "smaller" states) struct STN * leftChild; // The right child node (containing "larger" states) struct STN * rightChild; union { // In case of synchronous networks: struct { // The node holding the next state after a transition has // been applied to the current state struct STN * successor; // The basin of attraction to which the state belongs unsigned int attractorAssignment; // The number of transitions required to enter the attractor unsigned int stepsToAttractor; } sync; // In case of asynchronous networks: struct { // An array of all successor nodes struct STN ** successors; // The number of successor states unsigned int numSuccessors; // Dummy variable unsigned int unused; } async; } type; // The state itself - a set of binary-encoded integers with // elements unsigned int * data; } StateTreeNode; typedef struct { StateTreeNode * root; unsigned int arraySize; unsigned int nodeCount; unsigned int numElements; unsigned int successorPos; ArrayListElement * nodeArrays; ArrayListElement * dataArrays; ArrayListElement * successorArrays; } StateTree; void stateTransition(unsigned int * currentState, unsigned int * nextState, TruthTableBooleanNetwork * net); /** * Insert a new transition from to into
. * is the number of array elements occupied by a state. */ TransitionTableEntry * insertNewTransition(TransitionTableEntry ** table, unsigned int * initialState, unsigned int * nextState, unsigned int numElements) { TransitionTableEntry * entry = (TransitionTableEntry *)CALLOC(1,sizeof(TransitionTableEntry)); entry->initialState = CALLOC(numElements,sizeof(unsigned int)); entry->nextState = CALLOC(numElements,sizeof(unsigned int)); memcpy(entry->initialState,initialState,numElements*sizeof(unsigned int)); memcpy(entry->nextState,nextState,numElements*sizeof(unsigned int)); entry->next = *table; *table = entry; return entry; } /** * Free a list-type transition table as used in complex attractors */ void freeTransitionTableEntry(TransitionTableEntry * t) { do { TransitionTableEntry * next = t->next; FREE(t->initialState); FREE(t->nextState); FREE(t); t = next; } while (t != NULL); } static inline StateTree * allocStateTree(unsigned int numElements, unsigned int arraySize) { StateTree * tree = CALLOC(1, sizeof(StateTree)); tree->root = NULL; tree->arraySize = arraySize; tree->successorPos = 0; tree->nodeCount = 0; tree->nodeArrays = NULL; tree->dataArrays = NULL; tree->successorArrays = NULL; tree->numElements = numElements; return(tree); } static inline void newNodeArray(StateTree * tree) { allocNewArray(&tree->nodeArrays, tree->arraySize, sizeof(StateTreeNode)); allocNewArray(&tree->dataArrays, tree->arraySize * tree->numElements, sizeof(unsigned int)); } static inline void newSuccessorArray(StateTree * tree) { allocNewArray(&tree->successorArrays, tree->arraySize, sizeof(StateTreeNode *)); tree->successorPos = 0; } static inline void freeStateTree(StateTree * tree) { freeArrayList(tree->nodeArrays); freeArrayList(tree->dataArrays); freeArrayList(tree->successorArrays); FREE(tree); } /** * Allocate a new node of a state tree. * and are pointers to the * left and right subtrees. * is the state reached after a state transition. * is an array of binary-encoded integers of length * describing the state. * is the basin of attraction the state belongs to, * and is the number of transitions required to enter * the attractor. * * Returns a state tree node with the supplied values. */ static inline StateTreeNode * allocTreeNode(StateTree * tree, StateTreeNode * leftChild, StateTreeNode * rightChild, StateTreeNode * successor, unsigned int * data, unsigned int numElements, unsigned int attractorAssignment, unsigned int stepsToAttractor) { if (tree->nodeCount % tree->arraySize == 0) newNodeArray(tree); StateTreeNode * res = &(((StateTreeNode *)tree->nodeArrays->array)[tree->nodeCount % tree->arraySize]); res->leftChild = leftChild; res->rightChild = rightChild; res->type.sync.successor = successor; res->data = &(((unsigned int *)tree->dataArrays->array) [(tree->nodeCount % tree->arraySize) * tree->numElements]); memcpy(res->data,data,numElements*sizeof(unsigned int)); res->type.sync.attractorAssignment = attractorAssignment; res->type.sync.stepsToAttractor = stepsToAttractor; ++tree->nodeCount; return res; } static inline StateTreeNode ** reserveSuccessorArray(StateTree * tree, unsigned int numSuccessors) { if (tree->successorArrays == NULL || tree->successorPos + numSuccessors >= tree->arraySize) newSuccessorArray(tree); StateTreeNode ** res = &(((StateTreeNode **)tree->successorArrays->array)[tree->successorPos]); tree->successorPos += numSuccessors; return res; } /** * Recursive helper function for findNode() */ StateTreeNode * findNodeRec(StateTree * tree, StateTreeNode * parent, unsigned int * data, unsigned int numElements, bool * found) { unsigned int direction = 0; int i; for (i = numElements - 1; i >= 0; --i) { if (data[i] > parent->data[i]) { direction = 1; break; } if (data[i] < parent->data[i]) { direction = 2; break; } } switch(direction) { case 0: *found = true; return parent; case 1: if (parent->rightChild == 0) { parent->rightChild = allocTreeNode(tree, 0,0,0,data,numElements,0,0); *found = false; return parent->rightChild; } else return findNodeRec(tree, parent->rightChild,data,numElements,found); case 2: if (parent->leftChild == 0) { parent->leftChild = allocTreeNode(tree, 0,0,0,data,numElements,0,0); *found = false; return parent->leftChild; } else return findNodeRec(tree, parent->leftChild,data,numElements,found); } // should never be reached return 0; } /** * Recursively find the node corresponding to state in the state tree , * or insert the node if it does not exist. * is the size of the state vector . * The return value of indicates whether the element previously existed in the tree * * Returns the (possibly newly created) node belonging to . If the tree is empty, * is set to this node. */ StateTreeNode * findNode(StateTree * tree, unsigned int * data, unsigned int numElements, bool * found) { if (tree->root == 0) { tree->root = allocTreeNode(tree, 0,0,0,data,numElements,0,0); *found = false; return tree->root; } return findNodeRec(tree, tree->root,data,numElements, found); } /** * Returns the successor of the supplied state node . * If the state transition has not yet been calculated, * a new node is inserted into the tree . * is the number of array elements required to store one state. * describes the network for which a state transition is performed. * is a counter to be increased when a new state is identified */ StateTreeNode * findSuccessor(StateTree * tree, StateTreeNode * current, unsigned int numElementsPerEntry, TruthTableBooleanNetwork * net, unsigned int * basinCounter) { bool found; if (current->type.sync.successor == 0) // the state does not exist => calculate state transition and insert it { unsigned int nextState[numElementsPerEntry]; stateTransition(current->data,nextState,net); current->type.sync.successor = findNode(tree,nextState,numElementsPerEntry, &found); ++ *basinCounter; } return current->type.sync.successor; } /** * Traverse the tree supplied by in-order, and write the values * of the tree nodes to the corresponding arrays , *
, , and . * is the number of array elements allocated by one state. * is the current value of the node counter used for the array indices * and increased during recursion. This should be initially set to 0. */ void inOrderSerializeTree(StateTreeNode * root, unsigned int * initialStates, unsigned int * table, unsigned int * attractorAssignment, unsigned int * stepsToAttractor, unsigned int numElements, unsigned int * nodeNo) { R_CheckUserInterrupt(); if (root->leftChild != 0) // recursive descent of left subtree inOrderSerializeTree(root->leftChild,initialStates,table,attractorAssignment, stepsToAttractor,numElements,nodeNo); // write the state itself memcpy(&initialStates[numElements* (*nodeNo)],root->data,numElements*sizeof(unsigned int)); memcpy(&table[numElements* (*nodeNo)],root->type.sync.successor->data,numElements*sizeof(unsigned int)); attractorAssignment[*nodeNo] = root->type.sync.attractorAssignment; stepsToAttractor[*nodeNo] = root->type.sync.stepsToAttractor; *nodeNo = *nodeNo + 1; if (root->rightChild != 0) // recursive descent of right subtree inOrderSerializeTree(root->rightChild,initialStates,table,attractorAssignment, stepsToAttractor,numElements,nodeNo); } /** * Free a state tree supplied by recursively. * If , is assumed to be an array and freed */ /* void freeTreeNode(StateTreeNode * node, bool freeSuccessorArray) { if (node->leftChild != 0) freeTreeNode(node->leftChild, freeSuccessorArray); if (node->rightChild != 0) freeTreeNode(node->rightChild, freeSuccessorArray); if (freeSuccessorArray) FREE(node->type.async.successors); FREE(node->data); FREE(node); --nodeCount; } */ /** * Make a transition from to the next state. * States are encoded as arrays of ints and can thus contain an arbitrary number of genes. * is a binary-coded integer with used bits. * is an array of values specifying whether gene is fixed (0 or 1) or not (-1). * provides the input genes for all transition functions and can be split up * for a single function according to . * provides the truth tables for all transition functions and can be split up * for a single function according to . * * The return value is the next state, encoded in a single integer. */ void stateTransition(unsigned int * currentState, unsigned int * nextState, TruthTableBooleanNetwork * net) { unsigned int i = 0, k = 0, idx = 0; unsigned int elementsPerEntry; if (net->numGenes % BITS_PER_BLOCK_32 == 0) { elementsPerEntry = net->numGenes / BITS_PER_BLOCK_32; } else { elementsPerEntry = net->numGenes / BITS_PER_BLOCK_32 + 1; } for (i = 0; i < elementsPerEntry; ++i) nextState[i] = 0; for (i = 1; i <= net->numGenes; ++i) { if (net->fixedGenes[i-1] == -1) // the gene is not fixed { unsigned long long inputdec = 0; for (k = net->inputGenePositions[i-1]; k < net->inputGenePositions[i]; k++) { if (net->inputGenes[k]) // if the input of the function is not 0 (constant gene), take input bit { unsigned int gene = net->inputGenes[k] - 1; unsigned int bit; if (net->fixedGenes[gene] == -1) bit = (GET_BIT(currentState[net->nonFixedGeneBits[gene] / BITS_PER_BLOCK_32], net->nonFixedGeneBits[gene] % BITS_PER_BLOCK_32)); else // fixed genes are not encoded in the states // => take them from fixedGenes vector bit = net->fixedGenes[gene]; inputdec |= bit << (net->inputGenePositions[i] - k - 1); } } // determine transition function int transition = net->transitionFunctions[net->transitionFunctionPositions[i-1] + inputdec]; if(transition != -1) // apply transition function nextState[idx / BITS_PER_BLOCK_32] |= ((unsigned int)transition << (idx % BITS_PER_BLOCK_32)); else // this is a dummy function for a constant gene // => value does not change nextState[idx / BITS_PER_BLOCK_32] |= (GET_BIT(currentState[idx / BITS_PER_BLOCK_32], idx % BITS_PER_BLOCK_32) << (idx % BITS_PER_BLOCK_32)); //(GET_BIT(currentState[(i-1) / BITS_PER_BLOCK_32], // (i-1) % BITS_PER_BLOCK_32) << (idx % BITS_PER_BLOCK_32)); ++idx; } } } /** * Make a transition from to the next state for a bit vector encoded * as a single integer (max. 64 genes). * is a binary-coded integer with used bits. * is an array of values specifying whether gene is fixed (0 or 1) or not (-1). * provides the input genes for all transition functions and can be split up * for a single function according to . * provides the truth tables for all transition functions and can be split up * for a single function according to . * * The return value is the next state, encoded in a single integer. */ unsigned long long stateTransition_singleInt(unsigned long long currentState, TruthTableBooleanNetwork * net) { unsigned int i = 0, k = 0, idx = 0; unsigned long long nextState = 0; for (i = 1; i <= net->numGenes; ++i) { if (net->fixedGenes[i-1] == -1) // the gene is not fixed { unsigned long long inputdec = 0; for (k = net->inputGenePositions[i-1]; k < net->inputGenePositions[i]; k++) { if (net->inputGenes[k]) // if the input of the function is not 0 (constant gene), take input bit { unsigned int gene = net->inputGenes[k] - 1; unsigned int bit; if (net->fixedGenes[gene] == -1) bit = (GET_BIT(currentState, net->nonFixedGeneBits[gene])); else // fixed genes are not encoded in the states // => take them from fixedGenes vector bit = net->fixedGenes[gene]; inputdec |= bit << (net->inputGenePositions[i] - k - 1); } } // determine transition function int transition = net->transitionFunctions[net->transitionFunctionPositions[i-1] + inputdec]; if(transition != -1) // apply transition function nextState |= (transition << idx); else // this is a dummy function for a constant gene // => value does not change nextState |= (GET_BIT(currentState, idx) << idx); ++idx; } } return nextState; } /** * Retrieves the result column of the state transition table. * specifies the total number of genes. * is an array of values specifying whether gene is fixed (0 or 1) or not (-1). * provides the input genes for all transition functions and can be split up * for a single function according to . * provides the truth tables for all transition functions and can be split up * for a single function according to . */ unsigned long long * getTransitionTable(TruthTableBooleanNetwork * net) { unsigned long long i = 0; // determine number of fixed genes int numFixed = 0; for( i = 0; i < net->numGenes; i++) if(net->fixedGenes[i] != -1) ++numFixed; int numNonFixed = net->numGenes - numFixed; // allocate truth table with 2^(non-fixed genes) elements unsigned long long numberOfElements = (unsigned long long)1 << numNonFixed;//pow(2,numNonFixed); unsigned long long * table = CALLOC(numberOfElements,sizeof(unsigned long long)); if (table == 0) { Rf_error("Too few memory available!"); } unsigned long long initialState = 0; // calculate state transitions for(initialState = 0; initialState < numberOfElements; ++initialState) { R_CheckUserInterrupt(); //state is simply the binary encoding of the counter //calculate transition table[initialState] = stateTransition_singleInt(initialState, net); } return table; } /** * Retrieves attractors from a given transition table
with entries. * * Returns a list of attractors - the last element of this list is empty! */ pAttractorInfo getAttractors(unsigned long long * table, unsigned long long numberOfStates, unsigned int numberOfGenes) { unsigned long long i; unsigned int current_attractor = 0, elementsPerEntry; if (numberOfGenes <= 32) { elementsPerEntry = 1; } else { elementsPerEntry = 2; } pAttractorInfo result = allocAttractorInfo(numberOfStates,numberOfGenes); for (i = 0; i < numberOfStates; ++i) { //memcpy(&result->table[i],&table[i],sizeof(unsigned int) * elementsPerEntry); result->table[i*elementsPerEntry] = table[i] & 0xFFFFFFFF; if (elementsPerEntry == 2) result->table[i*elementsPerEntry + 1] = (table[i] & 0xFFFFFFFF00000000) >> 32; } pAttractor attractorHead, attractorList,tmpList; attractorHead = attractorList = (pAttractor) CALLOC(1,sizeof(Attractor)); attractorList->next = NULL; for(i = 0; i < numberOfStates; i++) { R_CheckUserInterrupt(); if(!result->attractorAssignment[i]) // the current state has not yet been visited { // first attractor has number 1 current_attractor++; unsigned long long begin = i; unsigned int steps = 0; while(!result->attractorAssignment[begin]) // iterate while no attractor has been assigned { ++steps; // first simply count steps until attractor is reached // - to get the distance to the attractor, this number is // later subtracted from the maximum distance result->stepsToAttractor[begin] = steps; result->attractorAssignment[begin] = current_attractor; // perform a state transition begin = table[begin]; } if(current_attractor == result->attractorAssignment[begin]) //calculate length and basin size of new attractor { attractorList->basinSize = steps; // fix the number of steps to the attractor by calculating // the maximum distance and subtracting the current value from it int maxstep = result->stepsToAttractor[begin]; int rec = 0; unsigned long long tmp = i; while(tmp != begin) { rec++; result->stepsToAttractor[tmp] = maxstep - result->stepsToAttractor[tmp]; tmp = table[tmp]; } attractorList->length = steps - rec; attractorList->involvedStates = (unsigned int *) CALLOC(attractorList->length * elementsPerEntry,sizeof(unsigned int)); attractorList->numElementsPerEntry = elementsPerEntry; int a=0; do { result->stepsToAttractor[tmp] = 0; //attractorList->involvedStates[a++] = tmp; //memcpy(&attractorList->involvedStates[a],&tmp,elementsPerEntry*sizeof(unsigned int)); // get low-order and high-order longs in a platform-independent manner attractorList->involvedStates[a] = tmp & 0xFFFFFFFF; if (elementsPerEntry == 2) attractorList->involvedStates[a+1] = (tmp & 0xFFFFFFFF00000000) >> 32; tmp = table[tmp]; a += elementsPerEntry; } while(tmp != begin); /* set steps of attractors to 0; add attractor stub information */ //generate a next attractor space attractorList->next = (pAttractor)CALLOC(1,sizeof(Attractor)); attractorList = attractorList->next; attractorList->next = NULL; } else //update existing attractor { // reset attractor number current_attractor--; // assign states to attractor basin, and // correct the numbers of steps to the attractor unsigned long long tmp = i; int maxstp = result->stepsToAttractor[begin] + steps; while(tmp != begin) { result->attractorAssignment[tmp] = result->attractorAssignment[begin]; result->stepsToAttractor[tmp] = maxstp - result->stepsToAttractor[tmp] + 1; tmp = table[tmp]; } // update basin size in attractor record tmpList = attractorHead; for (tmp = 1; tmp < result->attractorAssignment[begin]; tmp++) tmpList = tmpList->next; tmpList->basinSize = tmpList->basinSize + steps; } } } result->attractorList = attractorHead; result->numAttractors = current_attractor - 1; FREE(table); return result; } /** * Retrieves attractors only for a given set of input states supplied in . * Here, numGenes / 32)> consecutive array entries describe one state, thus * the array size is numGenes / 32) * numberOfStates> * describes the network structure. */ pAttractorInfo getAttractorsForStates(unsigned int * selectedStates, unsigned int numberOfStates, TruthTableBooleanNetwork * net) { unsigned long long i; unsigned int current_attractor = 0, elementsPerEntry; bool found; // calculate the number of array elements required for one state // (depending on the number of genes) if (net->numGenes % (sizeof(unsigned int) * 8) == 0) { elementsPerEntry = net->numGenes / BITS_PER_BLOCK_32; } else { elementsPerEntry = net->numGenes / BITS_PER_BLOCK_32 + 1; } // all states are stored in a tree for fast search StateTree * stateTree = allocStateTree(elementsPerEntry, NODE_ARRAY_SIZE); pAttractor attractorHead, attractorList,tmpList; attractorHead = attractorList = (pAttractor) CALLOC(1,sizeof(Attractor)); attractorList->next = NULL; for(i = 0; i < numberOfStates; i++) { // check whether the current state is already in the state tree, otherwise insert it StateTreeNode * currentState = findNode(stateTree,&selectedStates[i*elementsPerEntry],elementsPerEntry,&found); if(!currentState->type.sync.attractorAssignment) // the current state has not yet been visited { // first attractor has number 1 current_attractor++; unsigned int steps = 0; unsigned int basinSize = 0; while(!currentState->type.sync.attractorAssignment) // iterate while no attractor has been assigned { R_CheckUserInterrupt(); ++steps; // first simply count steps until attractor is reached // - to get the distance to the attractor, this number is // later subtracted from the maximum distance currentState->type.sync.stepsToAttractor = steps; currentState->type.sync.attractorAssignment = current_attractor; // perform a state transition currentState = findSuccessor(stateTree,currentState,elementsPerEntry,net,&basinSize); } if(current_attractor == currentState->type.sync.attractorAssignment) //calculate length and basin size of new attractor { attractorList->basinSize = steps; // fix the number of steps to the attractor by calculating // the maximum distance and subtracting the current value from it int maxstep = currentState->type.sync.stepsToAttractor; int rec = 0; StateTreeNode * tmp = findNode(stateTree,&selectedStates[i*elementsPerEntry],elementsPerEntry,&found); while(memcmp(tmp->data,currentState->data,elementsPerEntry*sizeof(unsigned int))) { R_CheckUserInterrupt(); rec++; tmp->type.sync.stepsToAttractor = maxstep - tmp->type.sync.stepsToAttractor; // perform a state transition tmp = findSuccessor(stateTree,tmp,elementsPerEntry,net,&basinSize); } attractorList->length = steps - rec; attractorList->involvedStates = (unsigned int *) CALLOC(attractorList->length * elementsPerEntry,sizeof(unsigned int)); attractorList->numElementsPerEntry = elementsPerEntry; int a=0; do { R_CheckUserInterrupt(); tmp->type.sync.stepsToAttractor = 0; memcpy(&attractorList->involvedStates[a],tmp->data,elementsPerEntry*sizeof(unsigned int)); tmp = findSuccessor(stateTree,tmp,elementsPerEntry,net,&basinSize); a += elementsPerEntry; } while(memcmp(tmp->data,currentState->data,elementsPerEntry*sizeof(unsigned int))); //generate a next attractor space attractorList->next = (pAttractor)CALLOC(1,sizeof(Attractor)); attractorList = attractorList->next; attractorList->next = NULL; } else //update existing attractor { // reset attractor number current_attractor--; // assign states to attractor basin, and // correct the numbers of steps to the attractor StateTreeNode * tmp = findNode(stateTree,&selectedStates[i*elementsPerEntry],elementsPerEntry,&found); int maxstp = currentState->type.sync.stepsToAttractor + steps; while(memcmp(tmp->data,currentState->data,elementsPerEntry*sizeof(unsigned int))) { R_CheckUserInterrupt(); tmp->type.sync.attractorAssignment = currentState->type.sync.attractorAssignment; tmp->type.sync.stepsToAttractor = maxstp - tmp->type.sync.stepsToAttractor + 1; //perform a state transition tmp = findSuccessor(stateTree,tmp,elementsPerEntry,net,&basinSize); } // update basin size in attractor record tmpList = attractorHead; unsigned int i; for (i = 1; i < currentState->type.sync.attractorAssignment; ++i) tmpList = tmpList->next; tmpList->basinSize = tmpList->basinSize + basinSize; } } } pAttractorInfo result = allocAttractorInfo(stateTree->nodeCount,net->numGenes); result->attractorList = attractorHead; result->initialStates = CALLOC(result->tableSize * elementsPerEntry,sizeof(unsigned int)); result->numAttractors = current_attractor - 1; unsigned int nodeNo = 0; // build a series of arrays by in-order traversing the tree inOrderSerializeTree(stateTree->root, result->initialStates, result->table, result->attractorAssignment, result->stepsToAttractor, elementsPerEntry, &nodeNo); freeStateTree(stateTree); return result; } /** * Identification of attractors in asynchronous networks */ typedef struct SSE { unsigned int * state; struct SSE * next; } StateStackElement; /** * Push a new element on top of the stack . * is the state to push onto the stack and has elements. * Returns the new stack element. */ static inline StateStackElement * pushStateStackElement(StateStackElement ** stack, unsigned int * state, unsigned int numElements) { StateStackElement * el = CALLOC(1,sizeof(StateStackElement)); el->state = CALLOC(numElements,sizeof(unsigned int)); memcpy(el->state,state,sizeof(unsigned int) * numElements); el->next = *stack; *stack = el; return el; } /** * Remove the top-level element from . */ static inline void deleteStateStackElement(StateStackElement ** stack) { StateStackElement * el = *stack; *stack = (*stack)->next; FREE(el->state); FREE(el); } /** * Applies the transition function belonging to gene to state . * holds the network information. * The result is returned in . */ static inline void applySingleFunction(unsigned int * currentState, unsigned int geneIdx, TruthTableBooleanNetwork * net) { unsigned int k = 0; if (net->fixedGenes[geneIdx] == -1) // the gene is not fixed { unsigned long long inputdec = 0; for (k = net->inputGenePositions[geneIdx]; k < net->inputGenePositions[geneIdx+1]; k++) { if (net->inputGenes[k]) // if the input of the function is not 0 (constant gene), take input bit { unsigned int gene = net->inputGenes[k] - 1; unsigned int bit; if (net->fixedGenes[gene] == -1) bit = (GET_BIT(currentState[gene / BITS_PER_BLOCK_32], gene % BITS_PER_BLOCK_32)); else // fixed genes are not encoded in the states // => take them from fixedGenes vector bit = net->fixedGenes[gene]; inputdec |= bit << (net->inputGenePositions[geneIdx+1] - k - 1); } } // determine transition function int transition = net->transitionFunctions[net->transitionFunctionPositions[geneIdx] + inputdec]; currentState[geneIdx / BITS_PER_BLOCK_32] = CLEAR_BIT(currentState[geneIdx / BITS_PER_BLOCK_32], geneIdx % BITS_PER_BLOCK_32); if(transition != -1) // apply transition function currentState[geneIdx / BITS_PER_BLOCK_32] |= (transition << (geneIdx % BITS_PER_BLOCK_32)); else // this is a dummy function for a constant gene // => value does not change currentState[geneIdx / BITS_PER_BLOCK_32] |= (GET_BIT(currentState[geneIdx / BITS_PER_BLOCK_32], geneIdx % BITS_PER_BLOCK_32) << (geneIdx % BITS_PER_BLOCK_32)); } } /** * Calculate a random asynchronous state transition for . * If is not NULL, this is a vector specifying * the cumulative distribution function of the probabilities of genes * to be chosen for a transition. Otherwise, each gene has equal probability. */ static inline void asynchronousStateTransition(unsigned int * currentState, double * probabilities, TruthTableBooleanNetwork * net) { unsigned int i; if (probabilities == NULL) // uniform gene selection { unsigned int r; // ensure that no fixed gene is chosen do { r = intrand(net->numGenes); } while (net->fixedGenes[r] != -1); // make a transition with the chosen gene applySingleFunction(currentState,r,net); } else { double r = doublerand_1(); // find the last index in the cumulative distribution that // is less than for (i = 0; i < net->numGenes; ++i) { if (probabilities[i] < r && probabilities[i+1] >= r) break; } // make a transition with the chosen gene applySingleFunction(currentState,i,net); } } /** * Calculate the forward reachable set of . * is the number of array elements used to represent one state. * If is true, self loops are only considered if there are no other possible transitions. * holds the network information. * Returns the resulting state tree (set).. */ StateTree * buildAsynchronousStateSet(unsigned int * startState, unsigned int numElements, bool avoidSelfLoops, TruthTableBooleanNetwork * net) { StateTree * res = allocStateTree(numElements, NODE_ARRAY_SIZE); StateStackElement * stack = NULL; unsigned int i; bool found=false, newNodes=false; // push the start state onto the stack pushStateStackElement(&stack,startState,numElements); do // iterate while stack is not empty (depth-first search) { R_CheckUserInterrupt(); unsigned int origstate[numElements]; memcpy(origstate,stack->state,sizeof(unsigned int) * numElements); // remove the top-level stack element deleteStateStackElement(&stack); StateTreeNode * current = findNode(res,origstate,numElements,&found); StateTreeNode ** successors; unsigned int numSuccessors; if (avoidSelfLoops) // try to find successor states that do not lead to the initial state { unsigned int successorStates[net->numGenes*numElements]; for (i = 0; i < net->numGenes; ++i) // first, calculate all successors { memcpy(&successorStates[i*numElements],origstate,sizeof(unsigned int) * numElements); applySingleFunction(&successorStates[i*numElements],i,net); } unsigned int numNonSelfLoops = 0; bool noSelfLoop[net->numGenes]; for (i = 0; i < net->numGenes; ++i) // now, check which of the successor states are the same as the initial state { if (memcmp(&successorStates[i*numElements],origstate,sizeof(unsigned int) * numElements) != 0) { ++numNonSelfLoops; noSelfLoop[i] = true; } else noSelfLoop[i] = false; } if (numNonSelfLoops == 0) // all transitions are self loops // => accept self loop { successors = reserveSuccessorArray(res,1); numSuccessors = 1; successors[0] = findNode(res,successorStates,numElements,&found); if (!found) pushStateStackElement(&stack,successorStates,numElements); } else // there is at least one transition that is no self loop // => do not accept self loops { successors = reserveSuccessorArray(res, numNonSelfLoops); numSuccessors = numNonSelfLoops; unsigned int j; for (i = 0, j = 0; i < net->numGenes; ++i) { if (noSelfLoop[i]) // create successor in tree { successors[j++] = findNode(res,&successorStates[i*numElements],numElements,&found); newNodes = newNodes | !found; if (!found) pushStateStackElement(&stack,&successorStates[i*numElements],numElements); } } } } else // self loops are allowed { unsigned int state[numElements]; successors = reserveSuccessorArray(res,net->numGenes); numSuccessors = net->numGenes; for (i = 0; i < net->numGenes; ++i) // calculate all successors { memcpy(state,origstate,sizeof(unsigned int) * numElements); applySingleFunction(state,i,net); successors[i] = findNode(res,state,numElements,&found); newNodes = newNodes | !found; if (!found) pushStateStackElement(&stack,state,numElements); } } current->type.async.successors = successors; current->type.async.numSuccessors = numSuccessors; } while (stack != NULL); // return the number of elements in the state set return res; } /** * Recursively retrieve an array of states from a tree * and store it to is the number of array elements used to represent one state. * is the current array entry to be written and should be initialized to 0. */ void getStateSet(StateTreeNode * root, unsigned int * states, unsigned int numElements, unsigned int * nodeNo) { if (root->leftChild != 0) // recursive descent of left subtree getStateSet(root->leftChild,states,numElements,nodeNo); // write the state itself memcpy(&states[numElements* (*nodeNo)],root->data,numElements*sizeof(unsigned int)); *nodeNo = *nodeNo + 1; if (root->rightChild != 0) // recursive descent of right subtree getStateSet(root->rightChild,states,numElements,nodeNo); } /** * Recursively extract the transition table from a state set * and store it to a list of transitions
. * is the number of array elements used to represent one state. * receives the size of the resulting table. */ void getLooseAttractorTransitionTable(StateTreeNode * root, TransitionTableEntry ** table, unsigned int numElements, unsigned int * size) { if (root->leftChild != 0) // recursive descent of left subtree getLooseAttractorTransitionTable(root->leftChild,table,numElements,size); bool duplicate[root->type.async.numSuccessors]; memset(duplicate,0,sizeof(bool)*root->type.async.numSuccessors); unsigned int i, j; // check for duplicate transitions for (i = 0; i < root->type.async.numSuccessors; ++i) { for (j = i + 1; j < root->type.async.numSuccessors; ++j) { if (memcmp(&root->type.async.successors[i * numElements], &root->type.async.successors[j * numElements], sizeof(unsigned int) * numElements) == 0) duplicate[j] = true; } } // copy the unique transitions to the table for (i = 0; i < root->type.async.numSuccessors; ++i) { if (!duplicate[i]) { insertNewTransition(table,root->data,root->type.async.successors[i]->data,numElements); ++ *size; } } if (root->rightChild != 0) // recursive descent of right subtree getLooseAttractorTransitionTable(root->rightChild,table,numElements, size); } /** * Validate whether a set with states is a true attractor. * If is true, self loops are only considered if there are no other possible transitions. * holds the network information. */ bool validateAttractor(unsigned int * attractor, unsigned int attractorLength, bool avoidSelfLoops,TruthTableBooleanNetwork * net) { unsigned int numElts, i; if (net->numGenes % BITS_PER_BLOCK_32 == 0) numElts = net->numGenes / BITS_PER_BLOCK_32; else numElts = net->numGenes / BITS_PER_BLOCK_32 + 1; for (i = 0; i < attractorLength; ++i) // iterate over states { StateTree * set = buildAsynchronousStateSet(&attractor[i*numElts],numElts,avoidSelfLoops,net); if (set->nodeCount != attractorLength) { freeStateTree(set); return false; } unsigned int size_set = set->nodeCount; unsigned int states_set[numElts * size_set]; unsigned int nodeNo = 0; getStateSet(set->root,states_set,numElts,&nodeNo); freeStateTree(set); // compare forward reachable set to original set if (memcmp(states_set,attractor,sizeof(unsigned int) * numElts * size_set) != 0) // no attractor return false; } return true; } /** * Calculate complex/loose attractors by performing random transitions from * the states supplied in . * If is true, self loops are only considered if there are no other possible transitions. * If is not NULL, this vector holds the probabilities for each gene to be chosen * for a transition. */ pAttractorInfo getLooseAttractors(unsigned int * selectedStates, unsigned int numberOfStates, TruthTableBooleanNetwork * net, unsigned int randomSteps, bool avoidSelfLoops, double * probabilities) { // attractor list has empty dummy element at the end pAttractor attractorList = CALLOC(1,sizeof(Attractor)); unsigned int numElts, i, j; if (net->numGenes % BITS_PER_BLOCK_32 == 0) numElts = net->numGenes / BITS_PER_BLOCK_32; else numElts = net->numGenes / BITS_PER_BLOCK_32 + 1; // if probabilities for the genes are supplied, exclude fixed genes (if any) // and recalculate probabilities double * pProbabilities = NULL; double convertedProbabilities[net->numGenes + 1]; if (probabilities != NULL) { convertedProbabilities[0] = 0.0; double probabilitySum = 0.0; for (i = 0; i < net->numGenes; ++i) { if (net->fixedGenes[i] == -1) probabilitySum += probabilities[i]; } for (i = 0; i < net->numGenes; ++i) { if (net->fixedGenes[i] == -1) convertedProbabilities[i+1] = convertedProbabilities[i] + probabilities[i]/probabilitySum; else convertedProbabilities[i+1] = convertedProbabilities[i]; } pProbabilities = convertedProbabilities; } unsigned int attractorCount = 0; for (i = 0; i < numberOfStates; ++i) // iterate over supplied start states { unsigned int currentState[numElts]; memcpy(currentState,&selectedStates[i*numElts],sizeof(unsigned int) * numElts); unsigned int t = 0; for (j = randomSteps; j > 0; --j) // perform random state transitions // to reach a potential attractor { asynchronousStateTransition(currentState,pProbabilities,net); ++t; } // calculate forward reachable set of end state StateTree * set = buildAsynchronousStateSet(currentState,numElts,avoidSelfLoops,net); unsigned int states_set[numElts * set->nodeCount]; unsigned int nodeNo = 0; getStateSet(set->root,states_set,numElts,&nodeNo); // search for the current potential attractor in the attractor list bool found = false; pAttractor current = attractorList; while (current != NULL && !found) { found = ((set->nodeCount == current->length) && (memcmp(states_set,current->involvedStates,sizeof(unsigned int) * numElts * set->nodeCount) == 0)); current = current->next; } if (!found) // the potential attractor does not yet exist in the result list { if (validateAttractor(states_set,set->nodeCount,avoidSelfLoops,net)) // check whether this is a true attractor { pAttractor attractor = CALLOC(1,sizeof(Attractor)); attractor->numElementsPerEntry = numElts; attractor->length = set->nodeCount; attractor->involvedStates = CALLOC(numElts * set->nodeCount,sizeof(unsigned int)); memcpy(attractor->involvedStates,states_set,sizeof(unsigned int) * numElts * set->nodeCount); attractor->transitionTableSize = 0; if (set->nodeCount != 1) // if this is a steady-state attractor, no need to store transition table! getLooseAttractorTransitionTable(set->root,&attractor->table,numElts,&(attractor->transitionTableSize)); ++attractorCount; attractor->next = attractorList; attractorList = attractor; } } freeStateTree(set); } pAttractorInfo res = allocAttractorInfo(0,net->numGenes); res->numAttractors = attractorCount; res->attractorList = attractorList; return res; } BoolNet/src/sat_search.h0000644000176200001440000000314713277247010014700 0ustar liggesusers#ifndef SAT_SEARCH_H #define SAT_SEARCH_H #include "boolean_network.h" #include "attractor_info.h" #define EXTENSION_EXPONENTIAL 0 #define EXTENSION_LINEAR 1 #define EXTENSION_LINEAR_ADAPT 2 #define EXTENSION_MIXED 3 /** * Determine all attractors having at most states in the network , * and return them in an AttractorInfo structure. */ extern pAttractorInfo getAttractors_SAT_exhaustive(BooleanNetwork * network, unsigned int initialCycleSearchLength, unsigned int extensionMode); /** * Identify all attractors using a SAT-based algorithm adapted from Dubrova et al., 2011. * Here, is the network whose attractors are identified. * If > 0, the first step of the algorithm is to identify and exclude * all attractors of length 1 to . * specifies the way the chain is extended: * EXTENSION_EXPONENTIAL corresponds to the exponential scheme by Dubrova et al. * EXTENSION_LINEAR corresponds to linearly increasing the length * EXTENSION_LINEAR_ADAPT corresponds to a linear increase whose step width is * increased over the iterations * EXTENSION_MIXED corresponds to a mixture of linear and exponential increase, * where the chain length is doubled after 5 linear increases. * Returns an AttractorInfo structure comprising all attractors of the network. */ extern pAttractorInfo getAttractors_SAT_maxLength(BooleanNetwork * network, unsigned int maxLength); #endif BoolNet/src/common.h0000644000176200001440000001506513301250404014043 0ustar liggesusers#ifndef COMMON_H #define COMMON_H #include #include #include #include "uthash.h" /** * Common structures and definitions */ /** * Macros for bit manipulation */ // the number of bits that can be stored in one component of a 32-bit state array #define BITS_PER_BLOCK_32 (sizeof(unsigned int) * 8) // Retrieve the -th bit in #define GET_BIT(x,i) (((x) & ((unsigned long long)1 << (i))) != 0) // Set the -th bit in to 1 #define SET_BIT(x,i) ((x) | ((unsigned long long)1 << (i))) // Set the -th bit in to 0 #define CLEAR_BIT(x,i) ((x) & (~((unsigned long long)1 << (i)))) // Set the -th bit in to #define SET_BIT_TO_VAL(x,i,v) (((x) & (~((unsigned long long)1 << (i)))) | ((v) << (i))) // Retrieve the -th bit in an array of 32-bit integers #define GET_BIT_ARRAY(x,i) (((*(&(x) + i / BITS_PER_BLOCK_32)) & ((unsigned int)1 << (i % BITS_PER_BLOCK_32))) != 0) // Set the -th bit in an array of 32-bit integers to 1 #define SET_BIT_ARRAY(x,i) (*(&(x) + i / BITS_PER_BLOCK_32) |= ((unsigned int)1 << (i % BITS_PER_BLOCK_32))) // Set the -th bit in an array of 32-bit integers to 0 #define CLEAR_BIT_ARRAY(x,i) (*(&(x) + i / BITS_PER_BLOCK_32) &= (~((unsigned int)1 << (i % BITS_PER_BLOCK_32)))) /** * Macros for the management of vector-like buffers with automatic resizing */ // Allocate a buffer of type [] and set the capacity counter and the number of elements #define ALLOC_BUFFER(buf, type, sz, count) do{sz = 4; count = 0; buf = calloc(sz, sizeof(type)); } while(0); // Add a new element of type to the buffer , and update the capacity counter and the number of elements #define PUT_BUFFER(buf, type, sz, count, el) do{if (sz == count) {sz *= 2; buf = realloc(buf, sz * sizeof(type));} buf[count++] = (type) el; } while(0); // Set the capacity of the buffer of type [] to the current number of elements #define FINALIZE_BUFFER(buf, type, sz, count) do{sz = count; buf = realloc(buf, sz * sizeof(type)); } while(0); /** * A hash structure for the allocated memory map */ typedef struct { // a pointer to the allocated memory void * ptr; // used by the hash table UT_hash_handle hh; } AllocatedMemory; // map that stores all allocated memory pointers // to free them on interrupt extern AllocatedMemory * memoryMap; /** * Custom function to allocate memory that stores * the pointers in the global map. */ static inline void* CALLOC(size_t n, size_t sz) { void * ptr = calloc(n, sz); if (ptr == NULL) error("Out of memory!"); AllocatedMemory * m = calloc(1, sizeof(AllocatedMemory)); m->ptr = ptr; HASH_ADD_PTR(memoryMap, ptr, m); return ptr; } static inline void* REALLOC(void* ptr, size_t new_sz) { if (ptr == NULL) return CALLOC(new_sz, 1); void * newptr = realloc(ptr, new_sz); if (newptr == NULL) error("Out of memory!"); if (newptr != ptr) { AllocatedMemory * m; HASH_FIND_PTR(memoryMap, &ptr, m); HASH_DEL(memoryMap, m); m->ptr = newptr; HASH_ADD_PTR(memoryMap, ptr, m); } return newptr; } /** * Custom function to free memory that was * allocated using CALLOC(). */ static inline void FREE(void * ptr) { AllocatedMemory * m; HASH_FIND_PTR(memoryMap, &ptr, m); HASH_DEL(memoryMap, m); free(m); free(ptr); } /** * Add one to a binary number represented by an array of characters * with 0/1 elements. * is a vector of fixed positions that are not touched or NULL. * Return true if there is a next state, or false in case of an overflow. */ static inline bool getNextState(unsigned char * state, int * fixed, unsigned int numBits) { if (numBits == 0) return false; int i = numBits - 1; while(true) { while (fixed != NULL && fixed[i] != -1) { --i; } if (i < 0) return false; if (state[i] == 0) { state[i] = 1; return true; } else { if (i == 0) return false; state[i] = 0; --i; } } } /** * Free all remaining memory blocks stored in * the global map. * moved to init.c */ //extern void freeAllMemory(); /** * A structure that provides flexible * large array blocks as a list of arrays */ typedef struct ALE { void * array; struct ALE * next; } ArrayListElement; static inline void allocNewArray(ArrayListElement ** head, unsigned int numElements, unsigned int elementSize) { ArrayListElement * el = CALLOC(1, sizeof(ArrayListElement)); el->array = CALLOC(numElements, elementSize); el->next = *head; *head = el; } /* * Free an array list . */ static inline void freeArrayList(ArrayListElement * head) { ArrayListElement * current = head; while (current != NULL) { ArrayListElement * next = current->next; FREE(current->array); FREE(current); current = next; } } /** * Encode a vector of binary values in an integer. * The rightmost element in is the leftmost bit in * is an array of elements, and points * to an integer to which the result is written. * Moved to init.c */ extern void bin2decC(int *dec, int *bin, int *numBits); /** * Decode an integer to a vector of binary values. * The rightmost element in is the leftmost bit in * points to the result vector, is a number * to be decoded, and is the number of bits/elements in bin * moved to init.c */ extern void dec2binC(int *bin, int *dec, int *numBits); /** * Inserts values of fixed genes into states - this is required as * fixed genes are not encoded in the internal state representations. * is a pointer to a state to be corrected. * is an array specifying which genes are fixed, as contained in * the BooleanNetwork structure. * is the length of . * The function changes the state pointed to by and has no return value. */ extern void insertFixedGenes(unsigned int * value, int* fixedGenes, unsigned int numGenes); /** * Removes values of fixed genes from states - this is required as * fixed genes are not encoded in the internal state representations. * is a pointer to a state to be corrected. * is an array specifying which genes are fixed, as contained in * the BooleanNetwork structure. * is the length of . * The function changes the state pointed to by and has no return value. */ extern void removeFixedGenes(unsigned int * value, int* fixedGenes, unsigned int numGenes); extern SEXP getListElement(SEXP list, char *str); #endif BoolNet/src/random.h0000644000176200001440000000065314362447270014051 0ustar liggesusers#ifndef RANDOM_H_ #define RANDOM_H_ #include /** * This header contains wrapper methods to generate random numbers. */ /** * Returns a random double in [0,1) */ static inline double doublerand_1(void) { return unif_rand(); } /** * Returns a random integer value in [0,maxVal-1] */ static inline unsigned int intrand(unsigned int maxVal) { return (unsigned int)(unif_rand() * maxVal); } #endif /*RANDOM_H_*/ BoolNet/src/reconstruct_network.c0000644000176200001440000010537513301250640016700 0ustar liggesusers/** * C code for the reconstruction of Boolean networks * * This is part of the BoolNet R package. * * Copyright 2009/2010 by Christoph Müssel * * Contact christoph.muessel@uni-ulm.de * */ #include #include #include #include #include #include #include #include "common.h" /** * Structure for lists of * transition functions for * the return value of reconstruction functions */ typedef struct FLE { // the number of input genes unsigned int k; // the indices of the input genes int * inputGenes; // The transition function. // ATTENTION: // If all functions are built (returnPBN = true), this // is a bit vector containing the transition function // If "don't care" values are allowed (returnPBN = false), // each integer element encodes one bit unsigned int * transitionFunction; // the next element in the list struct FLE * next; } FunctionListElement; /** * Structure to build an internal stack * of functions. This is used to determine * all equally-rated functions recursively */ typedef struct FSE { // the bit position to be processed next unsigned int pos; // the (incomplete) transition function unsigned int * transitionFunction; // the next element on the stack struct FSE * next; } FunctionStackElement; typedef struct { unsigned int pos; unsigned int numFixed; unsigned int numAvailable; unsigned int k; unsigned int n; unsigned int * indexMapping; int * comb; int * intComb; } InputCombination; /** * Add a new element to the function list specified by . * Set the corresponding values , and * by copying the supplied values. * is the number of elements needed for the transition function vector. * Returns the new list element. */ static inline FunctionListElement * addFunctionListElement(FunctionListElement ** root, unsigned int k, unsigned int transitionFunctionSize, int * inputGenes, unsigned int * transitionFunction) { FunctionListElement * el = CALLOC(1,sizeof(FunctionListElement)); el->k = k; el->inputGenes = CALLOC(k,sizeof(unsigned int)); memcpy(el->inputGenes,inputGenes,sizeof(unsigned int) * k); el->transitionFunction = CALLOC(transitionFunctionSize,sizeof(unsigned int)); memcpy(el->transitionFunction,transitionFunction,sizeof(unsigned int) * transitionFunctionSize); el->next = *root; *root = el; return el; } /** * Free all elements of the list */ void freeFunctionList(FunctionListElement ** root) { if (*root == NULL) return; FunctionListElement * current = *root; do { FunctionListElement * next = current->next; FREE(current->inputGenes); FREE(current->transitionFunction); FREE(current); current = next; } while(current != NULL); *root = NULL; } /** * Push a new element on top of the stack . * and describe the data to be pushed. * These elements are copied. * is the number of elements of . * Returns the new stack element. */ static inline FunctionStackElement * pushFunctionStackElement(FunctionStackElement ** stack, unsigned int * transitionFunction, unsigned int transitionFunctionSize, unsigned int pos) { FunctionStackElement * el = CALLOC(1,sizeof(FunctionStackElement)); el->pos = pos; el->transitionFunction = CALLOC(transitionFunctionSize,sizeof(unsigned int)); memcpy(el->transitionFunction,transitionFunction,sizeof(unsigned int) * transitionFunctionSize); el->next = *stack; *stack = el; return el; } /** * Remove the top-level element from . */ static inline void deleteFunctionStackElement(FunctionStackElement ** stack) { FunctionStackElement * el = *stack; *stack = (*stack)->next; FREE(el->transitionFunction); FREE(el); } /** * A function that iteratively returns all choose combinations of input genes * if called multiple times. * The function receives an input array containing the previous combination. * Before the first call, this combination must be initialized to {k-1, k-2, ... , 0}, * and must be set to 0. * After each call, contains the next combination. If all combinations have been * listed, the function returns false, otherwise true. */ static inline bool nextCombination(InputCombination * comb) { bool posChanged = false; // find the first position that has not been set // to its maximum number while(comb->pos < comb->k - comb->numFixed && comb->intComb[comb->pos] == comb->numAvailable - comb->pos - 1) { ++ (comb->pos); posChanged = true; } if (comb->pos == comb->k - comb->numFixed) { // all elements have been listed return false; } if (posChanged) // reset lower-order positions, and increase // the position found previously { unsigned int i; ++comb->intComb[comb->pos]; for (i = comb->pos; i > 0; --i) comb->intComb[i-1] = comb->intComb[i] + 1; comb->pos = 0; } else // the current position has not been set to its maximum value // => increase it ++comb->intComb[comb->pos]; unsigned int j; for (j = 0; j < comb->k - comb->numFixed; ++j) { comb->comb[comb->numFixed + j] = comb->indexMapping[comb->intComb[j]]; } //for (j = 0; j < comb->k; ++j) // Rprintf("%d ",comb->comb[j]); //Rprintf("\n"); return true; } static inline InputCombination * initCombination(int * requiredDependencies, int * excludedDependencies, unsigned int k, unsigned int n) { InputCombination * res = CALLOC(1,sizeof(InputCombination)); res->comb = CALLOC(k,sizeof(int)); res->indexMapping = CALLOC(n,sizeof(int)); res->k = k; res->n = n; res->numFixed = 0; res->numAvailable = 0; unsigned int j; for (j = 0; j < n; ++j) { if (requiredDependencies != NULL && requiredDependencies[j] != 0) { res->comb[res->numFixed] = j; ++(res->numFixed); } else if (excludedDependencies == NULL || excludedDependencies[j] == 0) { res->indexMapping[res->numAvailable] = j; ++(res->numAvailable); } } res->intComb = CALLOC(res->numAvailable,sizeof(unsigned int)); for (j = 0; j < res->k - res->numFixed; ++j) { res->intComb[j] = k - res->numFixed - j - 1; res->comb[res->numFixed + j] = res->indexMapping[res->intComb[j]]; } return res; } static inline void freeInputCombination(InputCombination * comb) { FREE(comb->comb); FREE(comb->intComb); FREE(comb->indexMapping); FREE(comb); } /** * Lähdesmäki's best-fit extension algorithm to infer Boolean networks * from time series. * and represent state transitions. * Here, consecutive array entries describe one state, * thus the array size is . * is an array of the same length as specifying * whether inputs were normally regulated (-1), overexpressed (1), or knocked out (0). * is the number of genes in the time series. * is the maximum number of inputs a function can have. * is a flattened Boolean matrix specifying dependencies * that *must* occur in the reconstructed networks. * Similarly, specifies dependencies * that *must not* occur in the reconstructed networks. * receives one list of possible functions for each gene, and * stores the error of these functions on the time series. * specifies whether the algorithm stops as soon as a perfect solution * is found (false) or not (true). * specifies whether incomplete functions (with "don't care" values) * are expanded recursively (true) or returned as-is (false). */ void bestFitExtension(unsigned int * inputStates, unsigned int * outputStates, unsigned int * perturbations, unsigned int numStates, unsigned int numGenes, int * requiredDependencies, int * excludedDependencies, unsigned int maxK, FunctionListElement ** result, unsigned int * errors, bool allSolutions, bool returnPBN) { unsigned int i, j; unsigned int numElts; // calculate block size in time series array if (numGenes % BITS_PER_BLOCK_32 == 0) numElts = numGenes / BITS_PER_BLOCK_32; else numElts = numGenes / BITS_PER_BLOCK_32 + 1; // store the lengths of the current best solutions for // each gene - initialized with maximum value. unsigned int bestLength[numGenes]; memset(bestLength,0xFF,sizeof(unsigned int) * numGenes); for (i = 0; i < numGenes; ++i) // iterate over genes { unsigned int currentMaxK = maxK, minK = 0, excludedCount = 0; if (requiredDependencies != NULL) for (j = 0; j < numGenes; ++j) if (requiredDependencies[i*numGenes + j] != 0) ++minK; if (excludedDependencies != NULL) for (j = 0; j < numGenes; ++j) if (excludedDependencies[i*numGenes + j] != 0) ++excludedCount; if (currentMaxK < minK) currentMaxK = minK; if (currentMaxK > numGenes - excludedCount) currentMaxK = numGenes - excludedCount; // set error to maximum errors[i] = ~0; unsigned int k, s; if (minK == 0) { // check for constant genes unsigned int geneVal = GET_BIT(outputStates[i/BITS_PER_BLOCK_32],i % BITS_PER_BLOCK_32); bool isConst = true; unsigned int const0Err = (geneVal > 0), const1Err = (geneVal == 0); for (s = 1; s < numStates; ++s) { if (perturbations != NULL && perturbations[s * numGenes + i] != -1) // ignore this state if the current gene is perturbed continue; unsigned int nextBit = GET_BIT(outputStates[s*numElts + i/BITS_PER_BLOCK_32],i % BITS_PER_BLOCK_32); if (nextBit != geneVal) { isConst = false; } if (nextBit) ++const0Err; else ++const1Err; } if (isConst) // gene is constant => simplest function already found! { int inputGenes = -1; addFunctionListElement(&result[i],1,1,&inputGenes,&geneVal); errors[i] = 0; bestLength[i] = 0; } else { if (const0Err <= const1Err) { int inputGenes = -1; unsigned int val = 0; addFunctionListElement(&result[i],1,1,&inputGenes,&val); errors[i] = const0Err; bestLength[i] = 0; } if (const1Err <= const0Err) { int inputGenes = -1; unsigned int val = 1; addFunctionListElement(&result[i],1,1,&inputGenes,&val); errors[i] = const1Err; bestLength[i] = 0; } } } for (k = (minK > 1? minK : 1); k <= currentMaxK; ++k) // iterate over possible numbers of inputs { if (errors[i] == 0 && !allSolutions) break; // initialize gene combination vector InputCombination * comb = initCombination((requiredDependencies == NULL? NULL : &requiredDependencies[i*numGenes]), (excludedDependencies == NULL? NULL : &excludedDependencies[i*numGenes]), k, numGenes); // calculate the number of array elements needed // to represent the output of a function unsigned int array_sz = (unsigned int)1 << k; unsigned int numEltsFunc; if (array_sz % BITS_PER_BLOCK_32 == 0) numEltsFunc = array_sz / BITS_PER_BLOCK_32; else numEltsFunc = array_sz / BITS_PER_BLOCK_32 + 1; unsigned int c_0[array_sz]; unsigned int c_1[array_sz]; do { R_CheckUserInterrupt(); memset(c_0,0,sizeof(unsigned int) * array_sz); memset(c_1,0,sizeof(unsigned int) * array_sz); for (s = 0; s < numStates; ++s) // iterate over states and count errors { if (perturbations != NULL && perturbations[s * numGenes + i] != -1) // the current gene is perturbed in this state // => ignore the state for inference of this gene continue; unsigned int input = 0, bit; for (bit = 0; bit < k; ++bit) // build input by transferring the bits of the input genes // in the current state into a condensed input value { input |= (GET_BIT(inputStates[s * numElts + comb->comb[bit]/BITS_PER_BLOCK_32], comb->comb[bit] % BITS_PER_BLOCK_32)) << bit; } // determine the response value after a state transition unsigned int response = GET_BIT(outputStates[s * numElts + i/BITS_PER_BLOCK_32],i % BITS_PER_BLOCK_32); if (response == 0) ++c_1[input]; else ++c_0[input]; } unsigned int f[numEltsFunc]; memset(f,0,sizeof(unsigned int) * numEltsFunc); unsigned int error = 0, c; for (c = 0; c < array_sz; ++c) { if (c_0[c] > c_1[c]) error += c_1[c]; else error += c_0[c]; } if (error < errors[i]) // the new solution is better than all previously found solutions // => reset the solution list and the best error { errors[i] = error; bestLength[i] = k; freeFunctionList(&result[i]); } if (error <= errors[i] && (bestLength[i] >= k || allSolutions)) { if (!returnPBN) // encode a function with "don't care" value // note: in contrast to the code below, // each entry of f corresponds to a single bit here { unsigned int f[array_sz]; memset(f,0,sizeof(unsigned int) * array_sz); for (unsigned int l = 0; l < array_sz; ++l) { if (c_1[l] < c_0[l]) { f[l] = 1; } else if (c_1[l] > c_0[l]) { f[l] = 0; } else { f[l] = -1; } } addFunctionListElement(&result[i],k,array_sz,comb->comb,f); } else { // recursively determine all functions by filling "don't care" values. // note: here, the elements of f are used as bit vectors // to save memory // start with an element initialized to zero, // and first examine the 0-th position unsigned int f[numEltsFunc]; memset(f,0,sizeof(unsigned int) * numEltsFunc); FunctionStackElement * stack = NULL; pushFunctionStackElement(&stack,f,numEltsFunc,0); do { R_CheckUserInterrupt(); // get top-level stack element FunctionStackElement * el = stack; if (el->pos == array_sz) // the top-level element on the stack is a complete function // => clean it up { // create a new element in the result function list containing the // completed function on the stack addFunctionListElement(&result[i],k,numEltsFunc, comb->comb,el->transitionFunction); // remove the completed function from the stack deleteFunctionStackElement(&stack); } else if (c_1[el->pos] == c_0[el->pos]) // the 0-error and the 1-error are equal // => create two solution branches, one with the -th bit set to 1 // and one with the -th bit set to 0 { // create a new element on the stack with the -th bit set to 1 FunctionStackElement * new = pushFunctionStackElement(&stack,el->transitionFunction, numEltsFunc,el->pos+1); new->transitionFunction[el->pos / BITS_PER_BLOCK_32] |= (unsigned int)1 << (el->pos % BITS_PER_BLOCK_32); // increment the position of the old element, which remains on the stack // with the -th bit set to 0 (due to initialization) ++el->pos; } else if (c_1[el->pos] < c_0[el->pos]) // the error is lower if the -th bit is set to 1 { // set the -th bit of the top-level stack element to 1, // and increment the position to be examined el->transitionFunction[el->pos / BITS_PER_BLOCK_32] |= (unsigned int)1 << (el->pos % BITS_PER_BLOCK_32); ++el->pos; } else // the error is lower if the -th bit is set to 0 { // due to initialization, the -th bit is already set to 0 // => increment the position to be examined ++el->pos; } } // terminate if all stack elements have been completed while (stack != NULL); } } } // get next input gene combination vector while(nextCombination(comb)); freeInputCombination(comb); } } } /** * Calculate the entropy of a set of genes (gene_1,...,gene_n) * specified by . * All values less than specify genes in the input states, and values greater or * equal to specify genes in the output states. * and contain states, each consisting * of array elements. * is an array of the same length as specifying * whether inputs were normally regulated (-1), overexpressed (1), or knocked out (0). * The table counting the occurrences of gene value combinations is returned in
, which * must be initialized to a size of 2^. * The return value is the entropy H(gene1,...,gene_n). */ static inline double entropy( unsigned int * inputStates, unsigned int * outputStates, unsigned int * perturbations, unsigned int currentGene, unsigned int numStates, unsigned int elementsPerEntry, unsigned int numGenes, int * chosenIndices, unsigned int numChosenIndices, unsigned int * table) { unsigned int numEntries = (unsigned int)1 << numChosenIndices; // reset table to 0 memset(table,0,sizeof(unsigned int) * numEntries); unsigned int state, validStates = 0; for (state = 0; state < numStates; ++state) { if (perturbations != NULL && perturbations[state * numGenes + currentGene] != -1) // the current gene is perturbed in this state // => ignore the state in the entropy calculation continue; ++validStates; unsigned int tableIndex = 0, geneIndex; for (geneIndex = 0; geneIndex < numChosenIndices; ++geneIndex) // count the number of occurrences of gene value combinations { // encode the index of the table element to be increased if (chosenIndices[geneIndex] < numGenes) // this is a gene in the input states { unsigned int chosenIndex = chosenIndices[geneIndex]; tableIndex |= (GET_BIT(inputStates[state * elementsPerEntry + chosenIndex/BITS_PER_BLOCK_32],chosenIndex % BITS_PER_BLOCK_32)) << geneIndex; } else // this is a gene in the output states { unsigned int chosenIndex = chosenIndices[geneIndex] - numGenes; tableIndex |= (GET_BIT(outputStates[state * elementsPerEntry + chosenIndex/BITS_PER_BLOCK_32],chosenIndex % BITS_PER_BLOCK_32)) << geneIndex; } } // increase the corresponding table entry ++table[tableIndex]; } // calculate entropy double result = 0.0; unsigned int tableIndex; for (tableIndex = 0; tableIndex < numEntries; ++tableIndex) { if (table[tableIndex] != 0) result += ((double)table[tableIndex])/validStates*log2(((double)table[tableIndex])/validStates); } return -result; } /** * Liang's REVEAL algorithm for reconstruction of Boolean networks. * This version is enhanced for dealing with inconsistent samples by * taking the solutions that produce the minimum error. * and represent state transitions. * Here, consecutive array entries describe one state, * thus the array size is . * is an array of the same length as specifying * whether inputs were normally regulated (-1), overexpressed (1), or knocked out (0). * is the number of genes in the time series. * is the maximum number of inputs a function can have. * is a flattened Boolean matrix specifying dependencies * that *must* occur in the reconstructed networks. * Similarly, specifies dependencies * that *must not* occur in the reconstructed networks. * receives one list of possible functions for each gene, and * stores the error of these functions on the time series. * specifies whether the algorithm stops as soon as a perfect solution * is found (false) or not (true). * specifies whether incomplete functions (with "don't care" values) * are expanded recursively (true) or returned as-is (false). */ void reveal(unsigned int * inputStates, unsigned int * outputStates, unsigned int * perturbations, unsigned int numStates, unsigned int numGenes, int * requiredDependencies, int * excludedDependencies, unsigned int maxK, FunctionListElement ** result, unsigned int * errors, bool allSolutions, bool returnPBN) { unsigned int i, j; unsigned int numElts; // calculate block size in time series array if (numGenes % BITS_PER_BLOCK_32 == 0) numElts = numGenes / BITS_PER_BLOCK_32; else numElts = numGenes / BITS_PER_BLOCK_32 + 1; for (i = 0; i < numGenes; ++i) // iterate over genes { unsigned int currentMaxK = maxK, minK = 0, excludedCount = 0; if (requiredDependencies != NULL) for (j = 0; j < numGenes; ++j) if (requiredDependencies[i*numGenes + j] != 0) ++minK; if (excludedDependencies != NULL) for (j = 0; j < numGenes; ++j) if (excludedDependencies[i*numGenes + j] != 0) ++excludedCount; if (currentMaxK < minK) currentMaxK = minK; if (currentMaxK > numGenes - excludedCount) currentMaxK = numGenes - excludedCount; // set error to maximum // Note: in REVEAL, is only used as an indicator // whether a solution has been found, i.e. it is 0 if // a solution was found, and anything else otherwise. errors[i] = ~0; unsigned int k, s; // check for constant genes unsigned int geneVal = GET_BIT(outputStates[i/BITS_PER_BLOCK_32],i % BITS_PER_BLOCK_32); bool isConst = true; for (s = 1; s < numStates; ++s) { if ((perturbations == NULL || perturbations[s * numGenes + i] == -1) && GET_BIT(outputStates[s*numElts + i/BITS_PER_BLOCK_32],i % BITS_PER_BLOCK_32) != geneVal) // ignore this state if the current gene is perturbed { isConst = false; break; } } if (isConst) // gene is constant => simplest function already found! { int inputGenes = -1; addFunctionListElement(&result[i],1,1,&inputGenes,&geneVal); errors[i] = 0; } for (k = (minK > 1? minK : 1); k <= currentMaxK; ++k) // iterate over possible numbers of inputs { if (errors[i] == 0 && !allSolutions) break; // initialize gene combination vector InputCombination * comb = initCombination((requiredDependencies == NULL? NULL : &requiredDependencies[i*numGenes]), (excludedDependencies == NULL? NULL : &excludedDependencies[i*numGenes]), k, numGenes); // calculate the number of array elements needed // to represent the output of a function unsigned int array_sz = (unsigned int)1 << k; unsigned int numEltsFunc; if (array_sz % BITS_PER_BLOCK_32 == 0) numEltsFunc = array_sz / BITS_PER_BLOCK_32; else numEltsFunc = array_sz / BITS_PER_BLOCK_32 + 1; do { R_CheckUserInterrupt(); // calculate entropy of input genes unsigned int table_input[array_sz]; double entropy_input = entropy(inputStates, outputStates, perturbations, i, numStates, numElts, numGenes, comb->comb, k, table_input); // calculate entropy of the combination of input genes and output value int comb_output[k+1]; memcpy(comb_output,comb->comb,sizeof(unsigned int) * k); comb_output[k] = numGenes + i; unsigned int table_output[(unsigned int)1 << (k+1)]; double entropy_all = entropy(inputStates, outputStates, perturbations, i, numStates, numElts, numGenes, comb_output, k+1, table_output); if (fabs(entropy_input - entropy_all) < 1E-6) // the two entropies are the same => output is fully explained by input { // a solution has been found => set errors to 0 so that // the algorithm does not search for higher k's errors[i] = 0; if (!returnPBN) // encode a function with "don't care" value // note: in contrast to the code below, // each entry of f corresponds to a single bit here { unsigned int f[array_sz]; memset(f,0,sizeof(unsigned int) * array_sz); for (unsigned int l = 0; l < array_sz; ++l) { if (table_input[l] == 0 || table_output[l | ((unsigned int)1 << k)] == table_output[l]) { f[l] = -1; } else if (table_output[l | ((unsigned int)1 << k)] > table_output[l]) { f[l] = 1; } else { f[l] = 0; } } addFunctionListElement(&result[i],k,array_sz,comb->comb,f); } else { // recursively determine all functions by filling "don't care" values. // note: here, the elements of f are used as bit vectors // to save memory // start with an element initialized to zero, // and first examine the 0-th position unsigned int f[numEltsFunc]; memset(f,0,sizeof(unsigned int) * numEltsFunc); FunctionStackElement * stack = NULL; pushFunctionStackElement(&stack,f,numEltsFunc,0); do { R_CheckUserInterrupt(); // get top-level stack element FunctionStackElement * el = stack; if (el->pos == array_sz) // the top-level element on the stack is a complete function // => clean it up { // create a new element in the result function list containing the // completed function on the stack addFunctionListElement(&result[i],k,numEltsFunc, comb->comb,el->transitionFunction); // remove the completed function from the stack deleteFunctionStackElement(&stack); } else if (table_input[el->pos] == 0 || table_output[el->pos | ((unsigned int)1 << k)] == table_output[el->pos]) // no information is available if the -th bit must be set to one or zero // => create two solution branches, one with the -th bit set to 1 // and one with the -th bit set to 0 { // create a new element on the stack with the -th bit set to 1 FunctionStackElement * new = pushFunctionStackElement(&stack,el->transitionFunction, numEltsFunc,el->pos+1); new->transitionFunction[el->pos / BITS_PER_BLOCK_32] |= (unsigned int)1 << (el->pos % BITS_PER_BLOCK_32); // increment the position of the old element, which remains on the stack // with the -th bit set to 0 (due to initialization) ++el->pos; } else if (table_output[el->pos | ((unsigned int)1 << k)] > table_output[el->pos]) // the -th bit must be set to 1 { // set the -th bit of the top-level stack element to 1, // and increment the position to be examined el->transitionFunction[el->pos / BITS_PER_BLOCK_32] |= (unsigned int)1 << (el->pos % BITS_PER_BLOCK_32); ++el->pos; } else // the -th bit must be set to 0 { // due to initialization, the -th bit is already set to 0 // => increment the position to be examined ++el->pos; } } while (stack != NULL); } } } // get next input gene combination vector while(nextCombination(comb)); freeInputCombination(comb); } } } /** * R Wrapper for bestFitExtension() and reveal() * contains an array of * binary * values, where consecutive values form one state. * specifies the number of states in the array. * is the highest number of input genes for a function. * If is 0, bestFitExtension is called. If is 1, reveal() is called. * Returns a list of lists. The outer list has elements, and the inner * list has one element for each equally-rated function for the current gene. Each of these * elements consists of a vector of input genes, the function as a binary vector, and * the error this function makes on the input time series. */ SEXP reconstructNetwork_R(SEXP inputStates, SEXP outputStates, SEXP perturbations, SEXP numberOfStates, SEXP requiredDependencies, SEXP excludedDependencies, SEXP maxK, SEXP method, SEXP allSolutions, SEXP returnPBN) { int * _inputStates = INTEGER(inputStates); int * _outputStates = INTEGER(outputStates); unsigned int * _perturbations = (Rf_isNull(perturbations)? NULL : (unsigned int *)INTEGER(perturbations)); int * _requiredDependencies = (Rf_isNull(requiredDependencies)? NULL : INTEGER(requiredDependencies)); int * _excludedDependencies = (Rf_isNull(excludedDependencies)? NULL : INTEGER(excludedDependencies)); int _numberOfStates = *INTEGER(numberOfStates); int _maxK = *INTEGER(maxK); int _method = *INTEGER(method); int _allSolutions = *INTEGER(allSolutions); int _returnPBN = *INTEGER(returnPBN); unsigned int numGenes = length(inputStates) / _numberOfStates; unsigned int numElts; if (numGenes % BITS_PER_BLOCK_32 == 0) numElts = numGenes / BITS_PER_BLOCK_32; else numElts = numGenes / BITS_PER_BLOCK_32 + 1; unsigned int encodedInputStates[numElts * _numberOfStates]; memset(encodedInputStates,0,numElts * _numberOfStates * sizeof(unsigned int)); unsigned int encodedOutputStates[numElts * _numberOfStates]; memset(encodedOutputStates,0,numElts * _numberOfStates * sizeof(unsigned int)); unsigned int state,gene; for (state = 0; state < _numberOfStates; ++state) // binary encoding of input states { for (gene = 0; gene < numGenes; ++gene) encodedInputStates[(numElts * state) + gene / BITS_PER_BLOCK_32] |= (_inputStates[state*numGenes + gene] << (gene % BITS_PER_BLOCK_32)); } for (state = 0; state < _numberOfStates; ++state) // binary encoding of output states { for (gene = 0; gene < numGenes; ++gene) encodedOutputStates[(numElts * state) + gene / BITS_PER_BLOCK_32] |= (_outputStates[state*numGenes + gene] << (gene % BITS_PER_BLOCK_32)); } FunctionListElement ** res = CALLOC(numGenes,sizeof(FunctionListElement *)); unsigned int * errors = CALLOC(numGenes,sizeof(unsigned int)); if (_method == 0) // perform Lähdesmäki's best-fit extension bestFitExtension(encodedInputStates,encodedOutputStates,_perturbations, _numberOfStates,numGenes, _requiredDependencies,_excludedDependencies, _maxK,res,errors,_allSolutions,_returnPBN); else // start REVEAL algorithm reveal(encodedInputStates,encodedOutputStates,_perturbations, _numberOfStates,numGenes, _requiredDependencies,_excludedDependencies, _maxK,res,errors,_allSolutions,_returnPBN); // for (gene = 0; gene < numGenes; ++gene) // { // printf("Gene %d\n",gene+1); // FunctionListElement * cur = res[gene]; // while (cur != NULL) // { // printf("Input: "); // unsigned int k; // for (k = 0; k < cur->k; ++k) // printf("%d ",cur->inputGenes[k] + 1); // printf("\nFunction: "); // for (k = 0; k < (1 << cur->k); ++k) // printf("%d",GET_BIT(cur->transitionFunction[k / BITS_PER_BLOCK_32],k%BITS_PER_BLOCK_32)); // printf("\nError: %d\n\n",errors[gene]); // cur = cur->next; // } // } // pack R objects SEXP resSXP; PROTECT(resSXP = allocList(numGenes)); SEXP listPos1 = resSXP; for(gene = 0; gene < numGenes; ++gene) { SEXP geneSXP; unsigned int listLength = 0; FunctionListElement * cur = res[gene]; while (cur != NULL) { ++listLength; cur = cur->next; } PROTECT(geneSXP = allocList(listLength)); cur = res[gene]; unsigned int i; SEXP listPos2 = geneSXP; for (i = 0; i < listLength; ++i) { SEXP entrySXP,inputSXP,funcSXP,errorSXP; PROTECT(entrySXP = allocList(3)); SET_TAG(entrySXP, install("input")); SET_TAG(CDR(entrySXP), install("func")); SET_TAG(CDR(CDR(entrySXP)), install("error")); PROTECT(inputSXP = allocVector(INTSXP,cur->k)); int * array = INTEGER(inputSXP); unsigned int j; unsigned int numBits; if (cur->k == 1 && cur->inputGenes[0] == -1) { numBits = 1; array[0] = 0; } else { numBits = (unsigned int)1 << cur->k; for (j = 0; j < cur->k; j++) array[j] = cur->inputGenes[cur->k - j - 1] + 1; } SETCAR(entrySXP,inputSXP); UNPROTECT(1); PROTECT(funcSXP = allocVector(INTSXP,numBits)); array = INTEGER(funcSXP); if (_returnPBN) // for PBN, functions are internally represented as bit vectors to save memory dec2binC(array,(int*)cur->transitionFunction,(int*)&numBits); else // for incomplete truth tables, we need a third "don't care" value // hence, each bit is an integer in this case (but far fewer entries => less memory) memcpy(array,(int*)cur->transitionFunction,numBits*sizeof(int)); SETCADR(entrySXP,funcSXP); UNPROTECT(1); PROTECT(errorSXP = allocVector(INTSXP,1)); array = INTEGER(errorSXP); *array = errors[gene]; SETCADDR(entrySXP,errorSXP); UNPROTECT(1); SETCAR(listPos2,entrySXP); UNPROTECT(1); listPos2 = CDR(listPos2); cur = cur->next; } UNPROTECT(1); SETCAR(listPos1,geneSXP); listPos1 = CDR(listPos1); } UNPROTECT(1); // free resources for (gene = 0; gene < numGenes; ++gene) freeFunctionList(&res[gene]); FREE(errors); FREE(res); return resSXP; } BoolNet/vignettes/0000755000176200001440000000000014506502647013635 5ustar liggesusersBoolNet/vignettes/basinsize.pdf0000644000176200001440000001103214272155061016306 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802100256) /ModDate (D:20220802100256) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 696 /Filter /FlateDecode >> stream xMO0sA=tgyTPJ-+8lZAUN@hq؈w}3Sp 9ZU͗Gi*B(ͦO(~u0Z:9Xŏ%a 2-4A_|[7iZ6]i~-^|SDJ!:;8y?nͯ%fS<>HSjY_Ji\W D hF-(68{{)PEN"?^f =e: Uy/>ZP^_Ųˈ%n$D_r^p{[q Րq RqPC[l嶌†GG]џn3TCNQ̣̼= <ɂ{22sV <̕P,xLw9h\% Lgik;/JRmg֠iWg Yd:i=?6n uJs?gY6t,8vB]N Gg7^3"]8& n>>GGzk"MzuMhnzq%a aL8i/F/xLCgK0^ %d'KOZ*n(H9Uxv8c#N]nqX^$6> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001059 00000 n 0000001142 00000 n 0000001254 00000 n 0000001287 00000 n 0000000212 00000 n 0000000292 00000 n 0000003982 00000 n 0000004239 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 4336 %%EOF BoolNet/vignettes/attractor1.pdf0000644000176200001440000001165514272152322016413 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094002) /ModDate (D:20220802094002) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 830 /Filter /FlateDecode >> stream xMO0s{3v,VHD٪ EJc{Le6'x[ovן-`R^w_~e :H$8)`:D`DloyXm~?Qs'D}z9HS)l&f{'/'DwF8;9 assup"'ݥӓ]&u0IDwܜ"ۦ4~Q1!1ZayەҪtr^; L_ݨN.eJ7 opiX S hcQAR&ACN+řp{ՑiM}l\{FP"[`$8;%<\CG=P̘b+ąa$8 TW> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj 11 0 obj << /Type /Font /Subtype /Type1 /Name /F3 /BaseFont /Helvetica-Bold /Encoding 9 0 R >> endobj 12 0 obj << /Type /Font /Subtype /Type1 /Name /F4 /BaseFont /Helvetica-Oblique /Encoding 9 0 R >> endobj xref 0 13 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001193 00000 n 0000001276 00000 n 0000001410 00000 n 0000001443 00000 n 0000000212 00000 n 0000000292 00000 n 0000004138 00000 n 0000004395 00000 n 0000004492 00000 n 0000004594 00000 n trailer << /Size 13 /Info 1 0 R /Root 2 0 R >> startxref 4699 %%EOF BoolNet/vignettes/BoolNet_package_vignette.bib0000644000176200001440000001213013277247010021224 0ustar liggesusers@article{laehdesmaeki03, Address = {Hingham, MA, USA}, Author = {H. L\"{a}hdesm\"{a}ki and I. Shmulevich and O. Yli-Harja}, Journal = {Machine Learning}, Number = {1-2}, Pages = {147--167}, Publisher = {Kluwer Academic Publishers}, Title = {{On Learning Gene Regulatory Networks Under the Boolean Network Model}}, Volume = {52}, Year = {2003}} @article{akutsu00, Author = {Akutsu, T. and Miyano, S. and Kuhara, S.}, Journal = {Bioinformatics}, Number = {8}, Pages = {727--734}, Title = {{I}nferring qualitative relations in genetic networks and metabolic pathways}, Volume = {16}, Year = {2000}} @article{li04, Author = {F. Li and T. Long and Q. Ouyang and C. Tang}, Journal = {PNAS}, Pages = {4781-4786}, Title = {{The yeast cell-cycle network is robustly designed}}, Volume = 101, Year = 2004} @article{xiao07, Author = {Y. Xiao and E. R. Dougherty}, Journal = {Bioinformatics}, Number = {10}, Pages = {1265--1273}, Title = {{The impact of function perturbations in Boolean networks}}, Volume = {23}, Year = {2007}} @article{faure06, Author = {A. Faur{\'e} and A. Naldi and C. Chaouiya and D. Thieffry}, Journal = {Bioinformatics}, Number = {14}, Pages = {e124--e131}, Title = {{Dynamical analysis of a generic Boolean model for the control of the mammalian cell cycle}}, Volume = {22}, Year = {2006}} @book{kauffman93, Author = {S. A. Kauffman}, Publisher = {Oxford University Press}, Title = {{The Origins of Order: Self-Organization and Selection in Evolution}}, Year = {1993}} @article{kauffman69, Author = {S. A. Kauffman}, Journal = {Journal of Theoretical Biology}, Number = 3, Pages = {437--467}, Title = {{Metabolic Stability and Epigensis in Randomly Constructed Genetic Nets}}, Volume = 22, Year = 1969} @article{aldana03, Author = {M. Aldana}, Journal = {Physica D}, Number = {1}, Pages = {45--66}, Title = {{Boolean dynamics of networks with scale-free topology}}, Volume = {185}, Year = {2003}} @article{liang98, Author = {S. Liang and S. Fuhrman and R. Somogyi}, Journal = {Pacific Symposium on Biocomputing}, Pages = {18--29}, Title = {{REVEAL, a general reverse engineering algorithm for inference of genetic network architectures}}, Volume = 3, Year = {1998}} @inproceedings{aldana03_2, Author = {M. Aldana and S. Coppersmith and L. P. Kadanoff}, Booktitle = {{Perspectives and Problems in Nonlinear Science}}, Editor = {E. Kaplan and J. E. Marsden and K. R. Sreenivasan}, Publisher = {Springer}, Title = {{Boolean dynamics with random coupling}}, Year = 2003} @article{spellman98, Author = {P. T. Spellman and G. Sherlock and M. Q. Zhang and V. R. Iyer and K. Anders and M. B. Eisen and P. O. Brown and D. Botstein and B. Futcher}, Title = {{Comprehensive Identification of Cell Cycle-regulated Genes of the Yeast Saccharomyces cerevisiae by Microarray Hybridization}}, Journal = {Molecular Biology of the Cell}, Volume = 9, Number = 12, Pages = {3273--3297}, Year = 1998 } @article{kim07, Author = {S. Kim and J. Kim and K.-H. Cho}, Title = {{Inferring gene regulatory networks from temporal expression profiles under time-delay and noise}}, Journal = {Computational Biology and Chemistry}, Volume = 31, Pages = {239--245}, Year = 2007 } @article{shmulevich02, Author = {I. Shmulevich and E. R. Dougherty and S. Kim and W. Zhang}, Title = {{Probabilistic Boolean networks: a rule-based uncertainty model for gene-regulatory networks}}, Journal = {Bioinformatics}, Volume = 18, Number = 2, Pages = {261--274}, Year = 2002 } @article{longabaugh05, Author = {W. J. R. Longabaugh and E. H. Davidson and H. Bolouri}, Title = {{Computational representation of developmental genetic regulatory networks}}, Journal = {Developmental Biology}, Volume = 283, Number = 1, Pages = {1--16}, Year = 2005 } @article{batagelij98, Author = {V. Batagelij and A. Mrvar}, Journal = {Connections}, Number = 2, Pages = {47--57}, Title = {{Pajek -- Program for Large Network Analysis}}, Volume = 21, Year = 1998 } @book{cover91, Author = {T. M. Cover and J. A. Thomas}, Title = {Information Theory}, Publisher = {Wiley}, Address = {New York}, Year = {1991} } @article{kauffman04, Author = {S. Kauffman and C. Peterson and B. Samuelsson and C. Troein}, Title = {Genetic networks with canalyzing {B}oolean rules are always stable}, Journal = {PNAS}, Volume = {101}, Number = {49}, Pages = {17102–-17107}, Year = {2004} } @article{maucher11, author = {M. Maucher and B. Kracher and M. K\"uhl and H. A. Kestler}, title = {Inferring {B}oolean network structure via correlation}, journal = {Bioinformatics}, volume = {27}, number = {11}, pages = {1529--1536}, year = {2011} } @article{dubrova11, author = {E. Dubrova and M. Teslenko}, title = {A {SAT}-based algorithm for finding attractors in synchronous Boolean networks}, journal = {IEEE/ACM Transactions on Computational Biology and Bioinformatics}, volume = {8}, number = {5}, pages = {1393--1399}, year = {2011} } @article{biere08, author = {A. Biere}, title = {{PicoSAT Essentials}}, journal = {Journal on Satisfiability, Boolean Modeling and Computation}, volume = 4, pages = {75--97}, year = 2008} } BoolNet/vignettes/wiring2.pdf0000644000176200001440000001276014272151464015714 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802093307) /ModDate (D:20220802093307) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 1675 /Filter /FlateDecode >> stream xWM5_#\k" +q@\v9SUyo6 ag_n&>yy!X~bcxyo_Ww{p~޽oG /?RS ]fa8Vx yYce8s= 4K,-W"걮0WRl% QʱSŽV6rʱe5#AX +[̂0HaR#~;(8&Kc[I+M;Ņ[ʌ 8+]Ͼ:h3"UM6^7= x†q W34v3ctj$`vsa j([gd&:n`)oIt䱥yGd/0&,~G_[ߎ)S9N}I\N|'>P_9zS<v3||G|դ?tg8@!9dGMy lιxaP5Vitgຶrb<\ͱbwU}Ƭ4Z$Stu?0 iZeR\uu^]b&jjZIZwT>t{=7^ D'W75޵[Mwf_r00Aԫےi۩1uIhlc8K鶤F? 3uC c5+eCkB$WѢͣߡ[bQޤMM{F EU$ W@cBf@Iu_ &. 8cdy FŬ1jXIC(՞jmwF*~slqNXhq)8:bDDldnAUQ^- CT ;;rڏ`*# OyX̍ AT$܉bҿOᵦD^ u3}ĺ3Zm'~;O~g`[ r]Wc|y>P=Yߔ'6}dI`.wOU)6=;cisZ%{:/5n~ŝKooް(0^!m[l#Mo-̄$塛 '>n~ p(n2&0(7{>t^v$콾{M_5q.k ]Ĭqk?^{:ܿ|s/wߵ᫸Q}1ݚNL3.:wp75IMendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /BaseFont /Times-Roman /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000002039 00000 n 0000002122 00000 n 0000002234 00000 n 0000002267 00000 n 0000000212 00000 n 0000000292 00000 n 0000004962 00000 n 0000005219 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 5318 %%EOF BoolNet/vignettes/biotap_logic.png0000644000176200001440000010732713277247010017002 0ustar liggesusersPNG  IHDR[DiCCPICC ProfilexZgTM0 9Ðs F$A2"DEE0&"(b%b~gw_:uޚ;\$NxQ0 ,<:DBƽ|z66(#6Rel=77 ԪtR0#@6%7޿qMFtOU!X:bkۘƌoWd}WH±>}.d XpߠpDE ZF  @%5+\@x!w@e_4-/dl4sK6ohzM@wha",`; ~8 > *Oq#ohQ(2J GYQ~(***AU.QwQOPoPPh4͇Fk:A@A_Aw/5 ÅǨaL0?L4S c1X+Ua8l6 ۀ}p81灣ppgq7pp<ύ$| :~DCQ1񤉡ɡJffH+HAkMG@[D{9KP&|ńBa0O$Db81XMN&~ґ4(ttYt5t7}'ҋӻ_31h280D23401%A$>ɉK*&5i};7xv02313dɬ\|yyEeA;,Xqa-Xظش<پ3;'װ`PpH̩y< "/W0WW+n, 7;<7O(O -j9y_a\5G;7$dWr&2T ~e!!;B^ 5 \eC)',.)*~X7 A {Lv9I~I[t6OR|RRRץH J;HHwH/Hxɬ*ɞ}*Gӓ'(V[V>[K~YA^!@R"bbw%I%JϔMSo*/ȫVWRW-P}UWKRkW~^F+MvMfc-:-sl{;; wֆwj'kwho$M vLyGgׯOԷ/6`3p2(7xc(`gxpH(ڨhxqq IS! K?wi:Yٔ^6 `ajQ`’lhlbog̚:z»wۢmml)%QX(_EY7,ʜf՝3D2j ݏPxGzOҞAOAh{^^^L~>DO+x_7f?%tK@S 6-%&hOе``!!!!=ܡQ„žˆgODhFG|P{6E"#x⢆sgb bbbccG(N*.;nfx83߁c ;V]o$q'%$%k'JLL>(t0LԆ44j!C={22r3fR2۲xf϶naIș5mc;7u|wG,\--H/RPQ$^TXR[m|f\EKWïܾ~823~AmOKyia5n V.~}|cl3o,7 cXs ={.\ G=t0@@o( BH!x#<(EC X!=(¢p|łڇDۡ0v)~;M#C@K&ӛ3(ȌLh +]Cӂ+;2(?!*X-4#$(/!',&k*W(RQ@GVeR[٥5-c{x}aQ S.35Vw iP,=ӝJ/rtt$y|t|-\WFG(Q2GD6WcVc7x\ BIdL4t桕̙79r==<\\8(t,RZȩZwTJi3qg ybYcf)W]ޮvM[;;C»z-uUCGCO;6=)|~EWQcQO|369617yn*xZazw'Ψ}|x0QO?3|r=?[֌77#<$  Y"P `+^GF6O?GLBƈ-tA $EFN&:S~Z%8i+DHP#1T++KNKLO>ȖJJ#§73V3rsym..J)>K<'wT8!+!JJi]z. yѷP3ErЕW[qmF퇮DҾ}Z\`N˽}JBH{8w0{(Ipgԑ/"_ƽJx&fϚ~d3gY Ǘ/_~s^xآҕ_U2@hxaPY1PY;DE@AYщ; m hDhn:.*QC HXC̦,t,#lknpuSg' \Vmw$I.H=n9!O"@0إt\9LEOEZzVھ: *=aQn]s?8jioi5f]c[c;lWC7rpsp*vpvp6~#eלwOozsAuC,BC*PEFDMF|w0.`u <$dTF_iˇd,gqf[/vħphűbeWU(r^K㵸:gC7jȿQ-Ɨ^%\noߍ$[m {ݵ gx>``:{E;vx$>,LKQRno7Ϛ~-GB"yvycEvuǚ:n}`{-@Wd@o`8 C)Qf"&="p/y3ii}iG;D]m:;BHtQq)\b2ZĦÕs;G!x_MN-#,-',FKJydddf8MTTԞj`45Bwit+bbj\e2K,|R*]g),Yd.K[ X Z 9&~*rzt[Ҿrd/&˥J5NkO2,3K&sdsSs *^+v,?tҙryUkkO;+~ABkҥf$Nx67hocz=J_C?x@yxn`ɡOOs<{(X7'&Zb9h)i/_c^nN?--)/Z6^~KׅUՉ5ĵ+kם 776667)7{wh "B#"練$k0!51z#wڠn!:_"V`Hc[#}!j@?5چ<)> DD^eNUDjG0;bH~HqGg9 3Eł 0 V !1x$R#9aS"mQ Gp#`?z&1H~YȈ?6/Ƚ[m[/4mFA~V~ϘТhE ZAk2 dhuZicg[ZcODtDZVభߟm \ܟ 9ȓXdN"y~Iu%/n+WDPGFI?ipYi`8P233%--M|>I~2$^SS#˖- Vö-((1cH^^SuYwU[Ryi3dgr[%3-G&o/O8Dwk\@@x9JbtEYŭ7؆A|}|q|ϕJaVukēN{!θH~rW\^ yi:-)Ý:RNyVϷ.IA2hd)[W*uU rԓe1{uYψ;cx,"+XjsMq[GQX|YV' {M-CoP* ]0d6]\~@;;R|"`KyL>|Zנ]k@FX&Yf^Z, AP,WVnR)-)qֱޡC: z)ereƄäF٣7/er;whh}>3Ҿ@_ }̻ryyi~\v>A"]'r|<'r {(o;o]FϾ@fʉ~.h\HneiΔY S9Du[Oܻ,z탻ϕL?pU O_7R򶠦7W{oZqȡ,gO"<|ջe^1?Z:ion_ްe/EviՒRI{M R~}4YM(YKiR f!N-[~)YYκ6΋4m(Gϗa92`lJEZY#ihr/̐IՑ&d>1'/{S:r]sOs[.MÚa!; ۮʮ~LݗS@rw7ݸL_ >k}D&5KZ!Oy1s&a\t?[U˲ޕ=~$EB_e[:~)mW#/?"W9dcKw[?%GL,+_G㯤~}CnV@'NMaMk_zU밄kEK~Zu:7󥒹T2&R愙-//;nmiKC}յ)++Y6c/eIH;JN^dDVȇ5M:ԡEK%0M,Rlc`3!zdjFl;YrR7OMf4g]!Ww9p?󝗝)?DNn kmiMhoW:ԧ}~i7_?H _U5dm֖̉r%XN*~cI}Ԛ m[re)2L;lݜϗtZk'05v;ֱumwyU ȰRԿH{$=/uR^R_ ('!m,u|DXȆj(_'lpz|aev_ڶȼG_7Rk`۠/|~˟A|h~:w徳`eYimBq+1pܴOEm^Σ: /5_+?V7G^X.^ӦSnNY"c?xI_S"zHJ)+Y#%5R#nw\~yU6tǵ}w?RDJ7Hm]TY-eZdqF+,׀lCU`m "Uvt\^X|}Gsֵյ!NnS(E3S%Cs}4rZZ3Yj 7e6K6)nCA F)ןw|/?;:U{yRMrʰn@1`em H``kI&u6i2@-~#k &^ݦ)^^3I9n/_"gBJF\kk*Vaclm9nb9ڶ+S%[Mٚ>V~9xF~(I2M~}*e6:N?L4j{MsYs2L?`te /nY&tnT8\vH-Jm}KM&Zruw}ڡ2﷟e{/ tʛl)d0k_EEz7#k=|U5ҥTOIqv~݆mfܵ˗׽ ^f61$3߼ K|W*H-iuZf3>h$%c[oT{*`7KzNa]*~4-u{۷M^sH4hO?d=beǀC _/y}#=yij߼, ?yLddiS_:+nalPݷ?@SS:w~d8kk﬎a-,~qv#zYMommհ ^LR^|Mqt"-ăAxcԶ]K NL\M;mag9C]Bf~'#m4W^#5e!rGGH٧E?3d}t<֡rF%8eןzZ@yR$us?(=jMz/*YnuY~3Oэ)Sw_J?|ݣ gntciWucFJ)+#($E!*Nizz`Fޏﷃ,{Wʿs%×!;'8Cet*[V.92p \}XSNc(闱^uS L=iTV%dRn4R%GsĒ%/#tHo2uV߾֟Iv˃B`}7.Hζi"_6L#lۣtWڅT+O< @ &;#-`ǺZoY`m!5zq~Dg=k3u]&Zuŭ떹5= @Rf!9i^MY  ̜9(6 ݙ,ں%:䡬lM2,Z@uoR'֣k&7ܺ-ϖqg֪ggd ?wL+-# OnnuÝ]}ޝ{w>tpB{nu=y @Ok+$8ܷ'  @tN=m  ė#?(//__  t_`3zc~@@Hd_1!  7Lȇ! Kŀ   uH#L@@:B@@H :$a  _^  I!@ML#@@    /7%!  *P^  I!P84@@@Ԁonㅀ[EEWKiiŹׇ*Q< IDAT3lV$FraBkc쵑/'N}W222<("@M||@,gd΃W,HFWORn7KdAގ綋X ykk?o!f""<F A7˒[25ִ^=lPdhe1mvY!gj{;QvSD3g}ˋ/(wx#@7{_ 4M7)>fZ ?3c /phX rw̆ @:t)lúT<ԵkϧhCB=}V7f )6kioj,Jv|voBIOOw`XO0 Ch/RH8>IuܱƳOHQ`nelEpz?ҿx<]>rivk xƝ `mp|I=TO/SLQGE\+'o2p`{YfB<`G!Pt >T]jQ&[;LsZ ]ړ<2a49i'gtzG*ݍ%5HccL0A{=Yb{rGDUNݒWZt6baՓ:kggg3O@`冔2dMUhN[gP9GU;S5M!+{>km˱YQN6f.s6;#;}{k{_U鼍 kYYY[u)</&tV)*41V5Uj[NotUNZ]VfL|irʾ_/:CW]#s6Sf9\^r W?دku<[_ L9rnvN]淴fCo[/pʹ[cQG%oV{~tM2g5jTVTHWr vMO,Y"J ;SL>].\^ڵk夓Nrʞ6ms5kPKN."O>M]G?yd]1ӞMM߭HJz|hzA@giZ,z93;G)UoS.kݾj +2a3t@_ۿO^/8O9^S䰹Jteq3//p+,+g)h7R24;?qz 5U+gdwn}>-o{ڶYc4z1q˗/|P^:-kNP7nwyr 77s='gye}38C.'D;;mҶ<+=x)y[1^]],#jQBo^[Mդ`ncpjªeM,2y\K,Pv}6t{7Zy#Gt_J'qۮַCem\  r-j,:C{r/,:Ă O ''GFu9j^V@ ,J榧H |5jc8T{ zu-٢mavOWﴇ P2\{}3)g[/}Kي/4=Nsjy]ŏ.cLmRfm~M8c+]{n~z硝f]ݛh!+k'X_봰iǭNq6]݇oѢEb'NͶ69moz|-qVH=`W -E4`Ҋ=ď33' ۫3Go6!Ն9XՐktN"_lw6/^*_Irc~2nU'Yκ'^z<_ɛ"v!|<}e|mP;J!ܦYW'hy7Cr\/x큍rVj빡pquc=C[䢋.rlwqS[g۶vs޻vmrn9=555r]w9Aծ0k,]wo =QXXׯL4)ݷ-wkc m$^TVV:C mqZyy߼ ]x 6Lj@ *[S#fKEb+?w6_6 br ̩S Bu$w<ɢn!uM '_[&MمC y*fE]?R9Z۠AY6满t~m,LdA_޾nk֬qN7L \իW;bB@s333o۱w^/e KaJAVf|`m zs$?o@s񛯖r9y'zT׀6\vL׿rsծdSwƵF[v{fp6O.lFk|^Dc>+`?vopli𵳆P)`vxN(r.*`\uvi_'ւ=v&[ i5"K=+ ~EstwtDzpDp'S7ywlCk+xOWoE5!VJ~(;-j&Ch4sd5m_+;pyScJAx ѣĨ w/Eo {s{GIz,=-1 [oM6:՞3mb|'/ذK{@@?yZ>]kok_2'/g}fy6כ{N}cf׏cB zIY .`?OĹ,dB ^v@ <R =Db'Y7bYc7=. @NpÌ{M @tv5   /@MCL@@L@@ )Iqi$    @Rl:dee% D@^B@@bQG:! x.@@@bQG:! x.m@ R` 4RV)kVmH?qݖd@v INIFE q/u4|QWX/5BoeC { [{1t,Ƃޡy29x_BF@:[z|m*%խQ_VVHņjVF|O:.Jog7([G1R՘&O2M چ [7^:zKJNk̘6^Kxֲܹ"}iq }x7Ujŷʻ%u", ><d  vGu<^ӻJf3vr$7#U{57Vȁi")uS44ZՎ[gay&o -R!Y9Ke2 kK@D$:YpNd^2M-4K~iֳlX;TBۙ*nVHQ m "V묏e"YE;ev) t)@품_zCŖ, r$ç!9xݔ;~-xz&߰D.rHѠa|`X33ܡ'-z~ERa帩 D/@ެ}I}&.Y֨iÛ0HV1 nyno?{9yԩrGKzzz{E|I)-+uSG-{ddd/wX ٱzUt,mP7sURf׹27:kWYm5Zo 527cB@b6?Aɮ}駟!CȔ)SXe /0ֆR ^!g!szWm^7 && M#D':SN9EV\)_W{aÆ>7o444Ȅ ߖ y衇dwwG*kk٣ЩZgڒv +"}ޫ;-zQˎ{Ug-|F{ŝ^Cc@@kwN^veUf|W^1}v_3jjj DfeO;w|K/IAA֙g)w .󟖠x~;g3fm&ӦMsG*Ywg IhT'c/?Ly/_J:uFr]ؗ @H fuw: ˼+%Y;vl_7ܾn[va5jG|\nClLӉ'(>`{QSgw?Yvi'97w:/_~Yϟ/ӧOz)2\;3jVHC<6t> NoKSmr}ݴW?w>{rkӧ~*X ֭<(/1r"o˼X~+rU~r_ےEԛmIe2}TU67z[Rx~1 l@\38C֮]+=<裲j*SOjyg>eٲebg秝vb/[o}СC+>s|7/΃uɻܬ'ҝVX!UUUS'ۘUw6Y},?ξm;EV x .lV^h2j{S3,-Uunmӵi!o퍐㴳ҡ ɹ_q3ׯ[ҤZ&K/CC@` S =6}Ϝ6,vlAYYYUl'rY/vzmx{Z+3tBW]mk˻2N^cniiiao`ݛ]׎o~yze|sI3]\\h[.;gC`;!{̄ [&`P\ֆ1=%,8ׯ]o]ᡳɮ`cymaa)"''z׭VTg[lW֦HSw #mߓkd)h=GȾJ~Ns<C{^c}og=>h0~)xqC]di{^{ll_bQ3xy+adaY2uHl7 > = @ |>wk$4),E9b6YǸ&dBOȋMv3MQ:ɘTGoo4 @GoGZfH`NT/]{t^9 ,+/Ov =, qv@g! u-ix%6;/ 3J ꩀeC@,1!  ߄?4@@@@BF" |y  $7)3D@ @@H oRf  @5  @ h4@@` x-=bשG}r" $;]e˰u2N"@@Tۧ@@%~@@Tۧ@@%~@@Tۧ@@%~@@Tۧ@@%~@@Tۧ@@%~@@Tۧ@@%~@@Tۧ@@%~@@Tۧ@@< @~@@\li| O@@zKli-  @hX@@ .qyب4  @hX@@ .qyب4  @hX@@ .qyب4  @hX@@ .qyب4  @hX@@ .qyب4  @hX@@ .qyب4  @hX@@ .qyب4  @hX@@ .< @ .4  @ x-= >/Ĩ  @\ x-= q)J@@BF" |y  $7)3D@ @@H oRf  @5  ߤ84@@k@@ )Iqi$    @R|0H@@/@@ &a  _^  I!@ML#@@< @Q@@<:[z|}>'@@Ζ_  *@#C@@< zIa  *@#C@@< zIa  *@#C@@< zIa  *@#C@@< zIa  *@#C@@< zIa  *@#C@@< zIa  *@#C@@< zIa  *@#C@@<4O+Ga  +u4|=2@@SӖR   |=Ĥ(@@ f   |=Ĥ(@@ f   |=Ĥ(@@ f   |=Ĥ(@@ f   |=Ĥ(@@ f   |=Ĥ(@@ f   |=Ĥ(@@ f   |=Ĥ(@@4m)5C@+&E@]7v٨  @ |@@@$ &Ɂ  @ |@@@$ &Ɂ  @ |@@@$ &Ɂ  @ |@@@$ &Ɂ  @ |@@@$ &Ɂ  @ |@@@$ &Ɂ  @ |@@@$ &Ɂ  @ |@@@$4$a  [[li|[  $^gKOo  8 `  #@g  >>@@w^@@X# w   @ |{@@ 3{A@cov  ;qf/  },@@@zG;@@< @@@Eli|L;@@Xlicv  @DoD  $7&mA@(@H@@D &Ѥ-  iX  HD:@@ 7" @@IHG  D Fa  @" |h@@߈4,@@H$o"Mڂ  Q  $@MI[@@" |#Ұ@@ < @ lh   @ x-= >i5  @" x-= M[@@KXǓ  D Fa6  @b |x@@0F@H,obOZ  A  %@MIk@@"|#0@@ u !  !@ e  >?T@@7>@@\燀  7  @ |P@@4ި3@@H%!  !u4@@@'ߞ   @ |Qa@@|{6  q'@CF@@z"@  ĝ7F@'jl  w߸;dT@@'ߞ   @ |Qa@@|{6  q'@CF@@z"@  ĝ7F@'jl  w@ wT@@ 6Ζ_j @@ Ζ߸Ӥ  I#@MCMC@@ &  @|PP@@ }i=  4ߤ94@HnorZ $7i5 E@[ǟ# I#@MCMC@@ &  @|PP@@ }i=  4ߤ94@HnorZ $7i5 E@[[# x&u4|>JA  -u4&  ,@C@@< zFIA  ,@C@@< zFIA  ,@C@@< zFIA  ,@C@@< zFIA  ,@C@@< zFIA  ,@C@@< zFIA  ,@C@@< zFIA  ,@C@@<4*FA  -u4|>:@@3׳VR   |=8@@ qV   |=8@@ qV   |=8@@ qV   |=8@@ qV   |=8@@ qV   |=8@@ qV   |=8@@ qV   |=8@@4l%B@;(F@M76ɨ  "_^  I!@ML#@@@@BF" |y  $7)3D@ @@H oRf  @5  ߤ84@@k@@ )Iqi$    @R|0H@@/@@4@  [_li|[_=  $GF" ĥ7.F@V# ĥ7.F@V# ĥ7.F@V# ĥ7.F@V# ĥ7.F@V# ĥ7.F@V# ĥ7.F@V# ĥ7.F@V?#  Vli|a+L@@:[z|m #  [ޒf?  }*@S~v  [ޒf?  }*@S~v  [ޒf?  }*@S~v  [ޒf?  }*@S~v  [ޒf?  }*@S~v  [ޒf?  }*@S~v  [ޒf?  }*@S~v  [ޒf?  }*i }v  8^gKOKiZ  Ч^gKOoʰs@@: v"@@ &α%  |;a  @|X@@N@@ qs,i   @'NpX  89@@o'8,B@HoKZ  Љ! $7q%-A@D @@G8ǒ  t"@E  #i #CK@@Tli|}@@GliMfZ  hD;@@ 7, 3@@MhG   ea&  @ |@@߰,D@H4oQڃ  V  &@M#J{@@ |ò0@@ vDi  @XoXf" $7ю(A@+@ L@@D &=  a< @ N  @^gKO狶=  @X7l  @ |c P@@/@@@ 1p   n}c  8T@@` |1{@@ۻ)]DADy^E_ hH@ぉ$*`y|^cTOxx[J(**jE@(UcTL&Sn @@ 0cT,).  @ VPcSU@@|+;  PAT@dJn} To56UE@*Y[# $@[AMU@@J ֧  @ VPcSU@@|+;  PAT@dJn} To56UE@*Y-+_WWז\  Q  Pܺ @@ 'zfsg@@|SvVZOȃ  @N@1b4S7uݖ.]jUUUV__oL&Ͳr,@@2PO˗b4So׮]ږ-[4 ʱ@@*Cƺuf;wN©* v!S1C@HTV F@B7f   *H~@@ |h&   PoG@B7f   *H~@@ |h&   PoG@B7f   *H~@@ |h&   PoG@B7f   *H~@@ |h&   PoG@B7f   *H~@@ |h&   PoG@B7f   *H~@@ j(%D@ eUVlsε?ܖ.]jWv?U6uLƯ2."Zhg3֡ujkkk/i߷P1m5Wi]a? ޼?#9su d[hʕ+?p{饗~c=>h 3ſbʸGc|ߞ@Dm֬Y{%\b{^DYP1|zkmÇ[uuuAnmrsƴ-~maL@ 0 z5/-ªW_V 7G6@B?`zdž 꼡i/;gLӸ,?F+m߁?3@Tj,#Fئn^TNA4V& ah\S.]O{̶v[g}˭sܒm%s2&mU؆ P˗/ `[MlM}5)WTk@Ϟ=sX:tzvWp nkؽqlvuo/.np;`;vaȤކZ=[55a@JL@'|bom+VaԤ`aZsAԩSmرvwzUB瞮񁭯ϧ] *PooU͟?߭Jks}vWoo7|kn})Sֹ_ӆM4zuQn_e۵^kAS&ikOcz|}K3G(K>S(`XӛPpݤ al|}}4{w/u%(=BK`h\զR hy:Vc馶;vmg ,p9dM:Etn\OjҤIsm=M=sM=]vw}5 o{\[{צ2G l…'}hlO |%מ?7g}Ә׷s@?3z5Uϴ*8ԛp*Ǩ;Dao4o?s\`[cÇ sfdr=j}c^{\ڄ#tnknziWZi\n^zG/b E?]O\[!zU|2(6[n_좤ْ%Klڴivgz,||:lyͳvɵϊpvywa=ә]6. @-mp+9|ӦېÇΩzTW7ӗ3ʫ:DjY !@&I+QI=Zc=\A9_}U7uz;qo\kkOcu#9cƌc/@t=nP_h+vG؏?h>~ӘW-MB([iWpe?@tA]weW]uU yqSjRu˥㏷3fӧO#G>^WU5ϯ\ڑf/}}޽{Ӽ__GydKOPo?Ve<*(UouU۷o.qnv~ɓݵ%'}tmw~HSme_< PzCQ=jKO5'-+Pn8Sǁ;.rS+kmqL]cZuǥ8qux:-kM|JgevJٗIE7yo#4|C6S_g&7>LeGy=.VuUoM2j6e G?62@f}J7~ߣ:7oOc_ @,'7hiS=M)=XPϖ瓾sPJoi(0֤M郄m8 }^m;C)89 ГDSDS- |j!n֦1 H7hMzR0UOz㯫{Dci3+Xֶnݺlٮ4iԨQ.z}Cs*z{e!S͕IzCv\m}5)`?3-~xh jK Ї7=Yק~ZO\מ:ˍ5`Ӣ'k ѷ6C׶Yk_Gvm'gXw;PR*ڿJv@Ph7qWNwϯ\_n('C3gt?qOKճ8)hUے$CuI?oذa >pn ~O=TLZկw4WmOzV<)0Q|[MjݥK}]oxf;(i!=O> x`'b[e@ЛP~??WЫ+b77W' oO*PLNm鬠=2 @@/G Z^-'GS|_W_mXM>sZs~>\ɯ7lm_2  >>*i7>W/jgN֯z)o|>h7   Pmqgssşzx]X";P+IENDB`BoolNet/vignettes/wiring_biotap.pdf0000644000176200001440000001315414272153727017172 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802095255) /ModDate (D:20220802095255) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 1799 /Filter /FlateDecode >> stream xXˎ]5߯8K8m"RX 4!,"&ד Lv]8Iǫ#?.H%~^Cه_>?^]bh͎݋ǟxrI+b*g~Gm?KÞYCKòs(EM,,0\RkhcB\{NlvOa]_dnZ)jn6lo|OJߓ|oDG=$o>GB~x x%rÜ2m 7u/pwᮐN.R\ZOeqWXO?\{/), d>A8 :#P-2,nEPcFR$$!Ō/ )HT(#R|_i;*OS|wahx#"X Gǝt*JLGtyF)jҨ,܅)߫8Sz}VW!vPfb"ސ\cyfa*PR[Sq+$đ!@$!`Ecrc9!gf,SyUQ`n,`64IE }?vFs,sizW׽2kj/je5 y%?3Q34a"LVf)+ndmQ'0 82&p!cqO#Eˌ)Rj( s & -1g yU :T # >X* 鰺*\YXUtPg@yIעv5څbȡѳ (8!/8JhkL9$CbŚ€SEjah~)Bhѡ̬98Qʒ?ɅLݙg>(!г7yBP< r4QILh)&+puYi7㬏TGk4Ź7, 8Ta& θm-Vu4!%9:u{Ou%W5\?ߜXV֡t f 53.m_)xh׳ nI`gIzݽ]\Cwex]kв97StA9"ɧ׊xuj^2>1~4mp` #"+j/˦_]}}%Vjy֌ZnG^we:nysey-ֈu> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /BaseFont /Times-Roman /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000002163 00000 n 0000002246 00000 n 0000002358 00000 n 0000002391 00000 n 0000000212 00000 n 0000000292 00000 n 0000005086 00000 n 0000005343 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 5442 %%EOF BoolNet/vignettes/attractor_robustness.pdf0000644000176200001440000001101514272153052020610 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094538) /ModDate (D:20220802094538) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 683 /Filter /FlateDecode >> stream xVMo0 WR =ECm@ ` MI&)ɖ[!'>=.s>r_)TJ_n:~#Ś9~0v=/kXS ۟2o2wK4H64{T^|uzz^mOaP/Ro!鿸u# o@mEp?5 WơU H[ZU +.QDG {vo߆=P6VnO(+t@uƿzKz933LSX)#==7:[O-6yശG74&ڭ7lT#=rqOr}Rqw@Ncg8 \x%@YZd?l 2q2,z4Lrio'Ki 01dwL&ɛ /e{BlUk,>C'c9zpny}}CyttC72))&/xz^zu,c@endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001046 00000 n 0000001129 00000 n 0000001241 00000 n 0000001274 00000 n 0000000212 00000 n 0000000292 00000 n 0000003969 00000 n 0000004226 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 4323 %%EOF BoolNet/vignettes/stategraph2.pdf0000644000176200001440000007403314272152674016564 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094356) /ModDate (D:20220802094356) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 26478 /Filter /FlateDecode >> stream xɮ&;r&8˪E8˒P-@@5z!hqkpR o7DH^`;F-Gw{?_ӷ?|KSJ;?u~J}s÷ >˷Z~?>z񽎏߿Zvw?yO[ 4̧}/u|{!f|^2=eu<fOxygJxW\ςl-46?G>05j|y=w#ֻǰ xE\59%퇾Wm~h,~ͧs[a^ZZ4?w_q`Gu_y_}`!/|>73:7>~_ïyἜm?ā-}>G?+GOjFWGqĞ\t,EhOO50'P=-Z7?MQvV8=E=7q'[Zԑ[̈A$-3OGIJ>\B@}W@b$[;$Vn=rg b_LDggtߓ//W"Gx$"Q!<[o>pZ衢^s/ܡ CZqFjĠ&x쟥ks KZ|s:Ӎ3_+-FpBC{qb7cv)$9Hoiq>WX+XbL4V~74yRLٲ_"žOgntkzzzD1:̯<}`!+/|N=lg]x&-D=so4=0`~z~>q׷QUl{Ł*GT5>;?p!ɇN80  g2F_W`Цb`%{w!waY^p|B4kGę5^D4߸k=2zgzzg#Dگh?> gsy? L#>ir?g@X_{.PϏW1^8t!hEZ:d[Y ` Xm/""7<2&H~{\#2Ӕ[U<˜9W,3Ѹgn|$7,k6M캟4ls~y,6qiqa|Be~85{ ;T ȇ0 1p1O4%$< &:֓&?`ςq D/,Io4vYIxlcl3*!Qz_iMMǁ99{3x!K/|>UƷ3޽_xWz\/%|/WA=yؠϏޏ8O593C=$ ܱ 1B3aqoUCwu!JYJr!6NJ+yZ8v0 !~!cP<-P^x.<40|qBV+`3P%C$ 6>#!d{igLMF,`p-X!*(0HL=I ݱ^'8$̵ ?TU{ q oxh>~_ß_ tYß_) P~GUz~G`|_nI.A|80(~OtS ʔCX0q|Y/Ű< L8/a/:_OfCs0$Bst=b'0'*1Ȁ'X~p!`p`.k9& ln`S )łzf[>R1CWS)  @ w8Wϥ}P'!KS>1]9x]Q# ~\Kʝaްf#$>FaH`"lƟsLqtԉ_<2D~US˅Zv}(iFaodL!L0~tt>j]rTqSz!- z6>6:*2Ul"^HxQ(5 e/ ^s:׷CwQ8,= ZohM\ p} z |a{OraXo!fkCDPt2T?UIG8D'CpX9PmSx TqPyQ'L1`(By \$g>crW3412duP0~n~Ͷ4xZHx)ߡ^ԻqPil9fl~( cxQsIwH.jz+t8}R.*~?H)pwV5lޮlT֟pgU޷«%ADhg-̷pv74Fg_\H},׷yY3} ΡzC5lwzh?]Y:P-6nQJyQuLBzZn֩Yf+dY7u!/K^ju'XO0!6h5ў^dUNsS!+8ˉkƎ;?ozL#׈qALttCB8Y'H DB;`vAbh;x`J0v1ZtMW&$ LP̏v </سa <"vLG=ֻ ?bC WI: 1OkYF'|G.W3K z_̉mׄ/{§8o|w1ˤf|͒M~\|O-_ï/]ÑrTx50'1f;dh{ oT]BC_ %͢x~S$sAY-cJppKI;5.49AV~+\k.|#;(z\P;MG<=g:X 5309a=7mb1kMe!uZ#8qX.yA^HFžܝ2"L4G0>^I\߹5 qdr#2؇͋wVcz_gH4ir.ur|P=]Tg!vA1X<|r}q6Z u ;$[8 [e]yp0$zMfas`[5#!8J 穀]ô T>Xb@.W]a;oZS  I 41 P}t-a&UXBU6e  Ţ4p.M"܃A䁣 ZL2EHJpʺF#X l(v.R(ni .ZTmIs~&µUH(6DiÔFlpQ.*)83/fؘe4ؔp `E!_cH̄?gLt&]F }uҠD; 6&i\q|'`҃.¼]Nj8LMt/A&9D>=ܯ`(Q^pA[Jfk-R:P4? =b4 ۄЦbZ=.z9*bH@ވ> jOF2k`H=JFV'P fL|0[ᆚkc|qn#,0SsCǵ^u8%v{g \15d5`F3>,i&h%C[1C׃j7H-g / wM@?לّ9i,_qU_ w!EE#BK2qԍK+ʢKѾΈcBq$^$qXR҄oI徘WV,1bAp@?7 xس̋komp@{1B7Wlv `y,^88}f#<>Q({kv{뱴ba3w?5SqTJgqG8#-mpϥ>♨~aAs0C0IlZ䋠LjtLol8j>(&/P 6.NXwgɵ؍5\b(<.0SkIW/sG*^A @|>tPˍ3p2cN@6aCF7a׸HifeG#uђ½Y"4.avY?uJ#.qo;7H J0 ż0C!OPA>N{$vЁQ v׉ {qPAlDxinB1K(3J.=c#R .R'zB"mХ@cSiѣ'۸h35| />܁@ǠnD=]ASaOPGKCvJ%zG)}Bӣ}6i8  Y(4a= .:h6Fk[P\Ylnf~B@n*@%{Au@S!V!`K+!fB F1M%D1 O3郢B˧ oPZS  yx=0#P@?. e|Rp8%B,mhDt7<7q&}- iJ"fP.r3*`Oѹ⁑AoҶHv m=Hgнr=yB>Ec6-ikyXb\u0C\ߘӒ".|صRƵ&4GK۲䳔` agpd }ZF셞[,\o8+E0MWlQ_y`6(0?y"ǥa [FᔓA(> +4q`$ 5s獾iANqu" X iIV*kjZW򥉴z,<#tAjQ>Q 440dBi0h +!UoX,ּB+B-dx#Ĺ@rYS;o/S?xcr~Vvq.P\t$JFL܂둞qlckΝ:vdaP݀"Ad vn­]H_3QY7&gKl`cʘL^o*vƹɠИj.~v'hD=SP {Qa#''v_qk: e ZJٜ &o;҆9Iih2nA#NL2!H^Q^ѰIԋqb99;^mL% /8c; Zt&OHD"4DòcWbIPָy _6WafbGVI.M2煂Xa +E &(شU%Z!^ H:v'bc*%8sXy+Půtn(.4fM;OcҸբPu1utok`"CT^dQZ$JKWI QxdrqYTPKٱ v'&kƽ8)s1`iLr;r#[i{:yEak㊁6lSep֓4ZEodzo>Ov5FEX@XJg|!&Jse/ǫ=A]t.hP""a%Ǖ +5F>Kd2|{km,ٟhޝ]d&#oF;EfzF^i6;,).߄UoW8{uSUyPU'5'߃0ѧ Pl7Il;s{%aNbz7z*+,2o o˘,zI>ԋ[b^%&GnY.` Pc4cZ 0#>' .xNaMQ[N+^r ' UHӈեsA?{[;4 SS z]K~#,͆L3rd"S(tVg}F>K}qw23F}VVY;9BBR3#'aZIi XSco)21dZ K9v?4|= NLYR#0]ph04߇T|I\93dsf ]T59eJ7^VEKE*$=݋y< ٨LrU5 W)K#}3&RP6辺v r`)JĤ@LK'ϝc\ٍ3 y oΊ֠Ȃ4U4 ұ5bM uiUȃ[b^2x $mc˧ H#Kі a|9w+.lZh1JrEĜJɳ*])\N?n0y OeŎ M1.rRUXҀYRUFÄ!;OnpI:S+-3ph)wI|bUAkqN\5Wjơ9o:Q:ͬM jwP$\#6~ DAèP0b4s,=*gcsıF'Ҁ gi]<W\+ LK$x=plL|Wm>^pײ(8 |0O 0:cNոx tb{] 8~>Wk]i+i4xM&Atͯ'Rg[,l o=CZp4ɺy0g,5_W"5QG_wc' +Yy昕 <6o}Hz?8{•{U.3T LW23|c y``d6/ىh/T:=PkPYc>iM׀Qr-QZ$`a 6q 3ao"S]9I̔[Sk˭noLJL2`n2f`n<6Pͻq/NX cgRvkN:UFdMΔ0֍5 m\Oe!i}e%(~2x>lH뛤}c=-T]Ea`D=eȓ`rN\gN`g)13&rE@wo*o${aOyICz9פR͉3 Ν4*s#grQSN%.P(]'*3C)d uoZ~aB[ ,n1"*]yOf*qmmeQ K գ8Oym(҄발!+Ϡd|6w0!yB, W+2`r\kkkɪC71i] Th8]EfHxddyqP9 *HK/^^bz<9@xUӓJ*4߭[WҨYi}&PhgBm[zXWt_2"E7WI4RݷxWq0kXL3;טz .`ٙx$[?6fɂ, Ge‰" gR8C#cޑ^7g`.L7e &-f*-c;Т:K ^`1{PDU?PqZÚ$ҩ?\?5|>s?f',O_ FqU9UH.h3Rֺ59TxL#Ò88MCQ'1ܵUNL'u5!HS}ivzLQ{cMJGuO0V\P)=1e;)ͯ닃-dС,; s0bB!8vm.\ƤW3F&*]I~Sª'SDBZӔ~ [@н5@ʩ qU:-]ƖXwU`j'H‹$ =BXS˻?vDaVQFcQ P\1or$Cyl1DȲ4y~I'fz<?yy8"T<-;Ӂ2!9U(YHalTx1׮ǚ֡/ݛ[,:ן(ҶTu8qɣ) =AۤinzS"oۙN_SnYɑȯ$(Pg9 s gc6z,v 53wZQlD4dH`x.,FG2-:̧P eWvpY,*ch\Smz:3]A .=ꆂ~jes6܆U7^/oeJ?A6^8 @vyV}Jqrs/zQh(SL[l|ٴ^vۆ'Md;u9AXa;n8y]mB)5;@DA;R5Ntl'Ocqہ8ʶrhF͕vdRRU23 D5@j\ 3aPؽ8#pb Y!iF LdEbYK86d^\"33=B؎>so~*7} 0Z +\މ` Kk/Z($ɼتzȲd~ݚ2s S93S77:%7fVzD2u ,y.&*}*ոQQ.âz'nCc, XNf (m` 7>"6t'ȥ$W,9t=t¥la-.gѴc opDgI!;!4N+4Q7 X >XaЗf3Mτ۽+cB> G"bI֥>뱘/0@ sbo,DGq2J5rNd+.G@eD&S3#. ˃J`\Zy$KOnK^D˦B77o"= (۔,n2!jUTK\[#ŜwZȢllBtb[7uts0Ց\ xK(2jDE+Ff‥a Qo,*I[َ 33J'еLi`3d p- nq*8`MCRKY~pNu#"ȖMgy~3Nʂ. ŧ#t˽z ȯdJ6t.6ǔ ƓtaE( ,A!LkAօk]ԚLy5S?{5e1zغ&5F'}o+O؂wrY5$<.ІyT~ʐmAQH$LLwVA8 zD#3cC0>:tA)_f1D2l$.wDXbSob p2j'2Ialr^_I9 6b?F 3,oyK,u `Va.uiBa] O'VedX9"_UzPr/$\kXUd27eFV_E $\ aldItЎ3EFm\̐0t1RNy֠FhJ?p(UlJ'\ L,R .oæY_ߓ%*a^^r ̝x^̐k+ f__ly3P(7.'=>M>ZL,=0M7<%ankDƠ4}^J2 0(bytgT~tYD%k\N2+0Q6+8ȿEL{f@ \\>/#SNY:4\b#{>҇ 6/,ȳR0&sԑc Է мL0XaPk!qa`aɩ*ӎg~~ph7RFoq 8ew&>?Xc-߉ͬ 8)[K m}+⸷0k2iY!/L>wuN]Ţu,TVGĝdv9Jd}E|YB:yAW訂koy ,o Nj"ʧpeaj%Uxr.;e"YBb!A`U䮬]ޭй rwl ܔn!Y <FHR#%z*EN_}4wyۼw"/8rem[raOI҃&?UW6w<;( &C*+' 0Uڒ@aM~tY? x"La顱ٛQrN6"-e5YDybEX4 y!N`{GОX2CL"]5CR8-,ʙ 1>\GUCyq}HsXup),0L|0S (#n0`B>j9(5IA4,)O瓺)2QB!1D%Wqݬ¹nJU yh '']%+A`hXo7<>" ]eƁ:KY@XHfʌiKi!M>[% IÀz` ĸ|d g'Aɐ2覀9nx (:5{bX[f4K 5Jz,ӪH*hXRF]Ig/UsEEе=h@2^&G뱩 #ʆd͞1 h((3DԦ+m4~|RN*q-z hSnM}J+ݲdQƑ,IU 0cR\t\CkPYz P=#\WYe&^\UVci+ ዉ%y=Becb<[ ؘX5PAsQW7&a1K}+kٳ-}i3S(Q!*a MK0i$"ҭ݅@ U 2(W Dݕ?8I`YU\jDkUWg/JPO{؍?ʲ^^M$Gu7Su~B!yN*˨sd7"sڮۛS%\$xÀo6gNJ␇~nFv\C1hU35YV׈Y XCU.U?-n:8x+-jʛY4y9hvR#d3=4Q!NZQ85p 9u#bW !트 :$:Heߥăzxfjߝ,[gqCF::{Tzp-T`g-[Tt +3T:YJ(xܓ0aE*խ&) CvZ>1>Dq-lgsP(^q^l,.͝R|?hlj?Q.f.• ɂdm֏ رA31Gƒk=a!l1ɴ.["^r .fE=],^!1?YuowI zflQJ(q33@2,3qZf[ף漢ё7Y:h)b¯O^Q{-.Y&w* X|=uֿt7rrLdYV~5t%k 0KJCN= |e䡀X+x,u&4FޅLRY~ lŦɠb\NZAhՖR\KIXAYQS"+x8Fi.(\+]Մ*$J^T& l˹", iuPQ}{ӨfNT 71ƛ"Mh|) `p:p7 .<2cM9W MЦ㗢aABׇ?M4Uw!&$iŔP=KS( -ʉ [MȺpK:=8ո~N7lHuw&2N;foC-rTA3A7? *"BEhr;o]jvQ7/efVAXvA]d.lֈE=سAlr ] =c-R4&vXGH*j 7 e x!aSqؖCDS {`߿)Ixi7#@Y(+ d[*ks*tbȾ xJg9yq愭݉Rv.JRc5(b놥YH}`!%J]-%qbu!53T`n D:jixAũ pkH5gKMk\-|4\*-LMZyIIS+jq N45ڋ-w@aLmw{q6 f EI䋴fN:n*SLB6K%`"Y܀2pKVeoDc)5zl6iw] pUGfZuTɴ^QU4,YUtaj8r;Ak]uB%Hufpy )Q|(̠ES<say/@/z#R\ =!ZtȭvsD(k N@ )+ |VZ[4Q,3o 8 ft$j߶^B}bj)2m|>R {AN 3ȄJ}u2cgu~:™JVbTw 76F4S!o)e L\ -(tfRq#+'htA0xsȽ"uېIMjo esKM(ݔ496&7?IwH!?$:|^V9^/Y酰"֜٣"쬘>vn^~nў9f54HxN5ĹdQouÞWTl1|y?J  W'q'm7/uveBd<ݲ\ȀU5ŴiosL ŧ$㜖g~,/⹳"k/"(5LBvPeS0; 15fv#@9I|ғ])V ?"u+#|.ۣ0>A jKsz5f%V׳gm), ~IQr.8 ?ߛԴra϶bx qCxNcdC O;]̘wĄ;?b__B6Q1p'K ˇC Ta#n`-a=Ň2o M2']*upk~ K>P aT;Hmlf Nip-VF[^@'g;a0(OP?LxL酰`i^д,$2.SJ.#qGm+}muOmY}k\j Z^?BP؂"rg=gy~I b[7!oƥqs.6Cd-jyQ [Av[CoVQ4}k\leڗ̮ml*_&6xL T[֮ϡm o_+?-B7!oFqk. a5?߿*@*ϙam o_`m57 oŶ_͹@ڨ}/4V]Y| qm狕5vf*z[T{ne[ַ\R/m:?߿Rh}1/7rM m +\b/6_oKtL4fA1 ӱzDY m:_Mm &:_5.}[8f>߿0&XFu`B~4Le/4VmRL}k\j@P_Y6sC2x>8!]eF?g>?5~a}W})b/هU(/!<Ч(!sx޶з>~iNַ\R5Je0IG*ɯ4rMz7 oƥqk.tJeO C3Ȥʟ~΂ln+}mB3yķm=׸=nzIs/Lb~YeD<@0ﶆ)>n$7o@^zqU=nͥArnM_Zg@A^G&zz5a_A J7!oŶ_-:.߿u:|Lnk}m2s1&ěsKm[|rqM?! p+SrFz"j'`za?ɽoeY:V_OF~/R(B!)ױ@oxw/-fs ;mgU/)\R}ܩd^/׈J~D9UMK&SDBm}[5.}l zt=Ue3S4 >Wt~2}6{\7fHKE?LmZg@K36{4Ď~a&Yge}x8;ƈ_m /Fx;B +Phc-Q*m>˸9u,~~@5up[WS[A?L(Վ^7TQ'l͡V a*ާL}5ȋw /*%m}[5.}Z O 9Ln4] y  vtͻoFvj+XbJ \":= ahϙZmo_ VLȾ m~5.}sY.B?!yz%d[Y75UN*@mLKȳ^ U~SO5<{UDG SJJnVQ J؞duNzūU:r[WxSFcGcJHx&~S@b1ލFC1Tkk?^ɧUXMSzi eto˾Qn[hzW߀ʯھ͹4cZuG.[Ey!N@7q;^7Gv_ƪr_`4l"WeǢF~gir[Co؊o[}k\leܺx>īü"ɂ̲e)=Th$r?߿ Rzܰ 4 7z?G VPeqMo~q{ڗ0dj[oeel떠 ӌ|.j'U ^X7oڽj{ 5e/Lcr!,X"cVeO/붉Ɋk YoyrV}[s6CgmpVTE&n0|m zٴ`qB57aX}*nKp'E /4ĥ_"LPwfT߄x* <0[bbZ׮pe^8(!n s-dWCmmoBx b/-WJ-~4gX:@>9Jz߶7/sیNMoDxq{ܚKG$ſ%5,kiERqr@^{}VۛWy"lfsKmbTNZ_z ~L"dKm)UTd-`,}=.2nKMd1MSAdbҦvþϙm5/`ho[nŦm=O/f}^:/^adjkAi2~Nۤ B|$mB&ķm?=nM)9`Њ4և "ܒMxj /HYpVRL]usmsQP/H^2x;!4+<|4 ?enMo~q{UOZȺ0Rzbf ](3!ryIj!m;[ȺΖEǼm1ܝ/,۲-!Hy^3}ޘH]mNաűŶ_m2/y‚wog |/=3 JW_HmbDMozqq6!Ap.ܫY#22 s+"^º *"d].H3.}[4)JS/֮ πq4emr߄sKmQ{]Â~`Q\M^R4%PX0i[@ G>ڽk3ȣZsHdC4[5 4a![ v7Qk6*Bn뗒l6݌ n3Oa'ՒIVP~j'koB4/z*=n ̔4}~a`7Ĥ$~1 ,rnWD+sTm .B(),;< S=]bôz%N\C~SO9쒬wVu:Z3^?$.gd ?f5~nG [ XJTʖૃ: /A{9f"P_#qa8?  jGz>gr4j:|!ky??!g"\uLSfQ;Wmȣv㚮o)Gvnd__~o}s÷O[mxĔG ??[߾ƱqFdDAFuB QD|_"h^}'zoe~_)(?}?2w?˿<~??ͷG|*HѿU]Bendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << /GS1 11 0 R /GS2 12 0 R /GS257 13 0 R /GS258 14 0 R >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj 11 0 obj << /Type /ExtGState /CA 0.302 >> endobj 12 0 obj << /Type /ExtGState /CA 1.000 >> endobj 13 0 obj << /Type /ExtGState /ca 0.302 >> endobj 14 0 obj << /Type /ExtGState /ca 1.000 >> endobj xref 0 15 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000026843 00000 n 0000026926 00000 n 0000027090 00000 n 0000027123 00000 n 0000000212 00000 n 0000000292 00000 n 0000029818 00000 n 0000030075 00000 n 0000030172 00000 n 0000030221 00000 n 0000030270 00000 n 0000030319 00000 n trailer << /Size 15 /Info 1 0 R /Root 2 0 R >> startxref 30368 %%EOF BoolNet/vignettes/pajek.png0000644000176200001440000020540513277247010015435 0ustar liggesusersPNG  IHDRPsRGBgAMA a pHYsodIDATx^}U~.?P _hӈ4#$ॏ-JJsKD!"nQ!! 5!\B(Y>w昗\k?ڕw9c>YsO^ƷC @{=\6?O.>#>۾~g@ ?<|{" xǗ @~jCoiE@?!<@ x o'!r Ǘ@ @7o.Fi7@ @7o-_1пۿx @ #E?io @~'_mo @9_?@ 1_zv/WGGOk{v:@ <|7x_[cK}'W#bs%vݠ_׾o"{ʀ'@ ~ѷ}=\,/|},6) ^CHE7|K_ryc'ˋ~<ў@ 0/wo~bs}|?'<+ГJeIEP?o1l_y'#G~ÀٟD_Oh֝Gğ*Nj#5?% yG"gVW>Pˊ,<}'-Wq<^]_?e/ۘ׿|/= ],%/yrB˷|2fUFK# <_k׿|۾k?}+W<&8YK4 gz%yyM N\-BM+>s:Oms/Vl.GE{TEa] .`y>,/QОc۴Ģt 3__O*x3||XgiηЋh^r#4ñ?U=W+UR>}?XKxjwYx;EϝA35yzX ^ JϬѳu]s>Df-Qu RȅYMmF@` ;oe׾$Yyyכ\,~K,򄬙/<#dv]ny%\,{h3 MSkE+/7l %x'bN?_{'?Ya+ࢧNٿy#7;|9znW\zWG>sZTߑzx1>:eU,O} -Z^W\^L܍jhOcOZ 7򇸊}Os>C^}Ҙe<3 /Y$g?8%˚w~o><|?-Gϭ̊U:+.~>y|H2OX(5Fh?]x< 8x~ 4]ɫ*sY-:@3|W~Ǣ2[&.6˫7wW|kC=啿'8_E<_޵&ޙZl.=̏0 Ogǝb~K~cyrݓB^W/Oj?X _p'|oz^//~K}j޺{~sBOP\<[s^zwί.h?Uqŧ/(=@!B{0/~^܅~Y Ry=xɲT^Ve}.[Ȳ..V6^@ x/XwK,Jm_eoO# /9=xW@Sws:wX4=0O5WLzsԫ~{-#_g>,FӘe/x:y|7f{Ċb*?`( %Uѣᏻ;_/USX~mY?3O2]!9q+~٧=? g'OE]GAٛtx o_z~]obso}w{x,??_Bby^y:~'|ϟjgXs9"W-d4B/zq"׬b=_,WUoyKy1< G.t(n N?o WVjv%?W̠ǟ],68w?]i>w󝀦9WM^^? C0>ok_;7~9gy喫Fy;@ }{bs7//o~ݓ|wo}ꛟ>_^?h=Yl.cof~;Gw =;x$kb-C8X wbsj_ucŲ|>MLC  @Ak͟_?Xl.W wX+^~rf<\,{Q?ľSx @ #C<@ od~@ @ F#V [8^<@ -#Ew?oE? @ p,zZC?x @D`~ @ p,zZC_{ @&_wO>ɇկO~7$}|I?2!˛-p#;LZV~_ׇv7$Mu+ʆ=q{ OZ0|tU܅ˇ?k-Q H;mDc.@ ,zZC7~[ԓGj{>̱Oxic^!O7d.#O>1LCưʤ`PIz__J~'r=y>E!FO`=_+}gO_=?sH4d-BMfO%D;'>>q^1qc`t1X@nпoo-^=roxO|}p?-F^0]nj}/7Ww^3(ZۥA>EcYa s~gpWP(<5>OK&H*wvh`Qr}>ӝ^5tz]JIՊŲyT{U7"qwxa/)#WZ5>u7`mU,K[;Hq&ev&gU4#.@ P@_~ۯ7|חWzŋ<։_'ɯk>Zy`\s>_ܯ/>݅Nޭk=yN|ËK O^Lg㵏_Ekַ1/zoۖ'}?}naU02E-xlY~lY,W) E1go1hw^Fy9{ 끿6_K;VţpL=Ly?3jN.Y-.HޏYd]ZM-pG8^~OwJޱg'Eʤt/KnfH30 Xp_{7~“ױ_wn|s/~{g٘_' 7Eϕ}ÇW5O|3k($pUL(؋Q]3{_vEpo^s^O&37~b 癑:68OC~坆~@,e޾{n7o+) ]hy4VLe5Jx㨍fmt&[i>X@j=\o7-^^_zs^e19/e"Gg {WY~g:X7|^ƫv,7¬~y/~c?04MP[8{PȍO[P$SSpr)x;pY1gMݪ;gԟ'UûONN;`"Xs&Y{q>S}ꊊsx(Ln~M9SSLv:@ п?f=/}s?|'?Wɓ|oqS-4_O_{'??>pC;g֞:Y崟w>^m)#&J(<}3T 0'S@IyɯȺ{wÞ/@ F`QB'?:~[~?QC@ @^C?ɏ4k//<4 ? @#bi_hhTI M2m @`U,tп]? =CCA8F  pkx@N~Տ*@C7@)h%z` ` s!FCXTɏ4_hCE [2Dԁ@`~Ϗis~p!8E }lFwL@Cgp Bwm8gA'~?p}Х@xSp^9S!<)~h=/M}SgYXTɏΡ'~?ϒ39tP2Xzq1@̉@-!AmD`ë!bi}4R{:W3SȮ/f(^p:0"hD8keN"48vF`QB'?m;vD4t|rorvH}N(OFLi'e o E ,4={@CTqlH]qH @}ZL1@,kG:uF#"ihoVq~d` J3ё)7ƀ(U,t# ? = ۴߄W{p OS{bD @mi:ĝZg:iH !bix44*Qn>d30Vnb %&YEDɳK⌠,XGo 46^bFf48A v*d8}şigZ#8*: r :^[E0zAs)ȐK='a7Uov;U,t24vhߐeڣ"^NPE1!ihtFC{c9$^WE?p}:Wp_VYd[h*a) .@ہf Bp]!XTɏΡӿ;{QkL7:c.3s"v1E^1x&D`QB'?ow4)ʥ!Q C詊 "`f#H,soF,XG-?n%MkZCg%2ί>DCC@H A`QB'??4tSCӣ-FO7UwhnIjh2C[.KľwN~;л% 5tL?0,$-7ML=A~ NI7E"# ($x[EBC'a@p\MXhHH. ,XGG; 1'aQشt'EoS nO.ȓI蒷jhSy7n9":yUxc g "ё4E)7$lxN>h@NC?ɏ4{bLmz]׻#A @@eb(zǟ1,]py PN~Y?57obupQdU{~oe0Yw880nEN^ ?gh)MlmZ4 ЛƁ `^syo.٤ F aN~io;='I(3+g p:8}ACq,z,N$34f exbwJ4>e4%etiŇ4 8 @@@Fg(#OCACQ#X~{(WiZ8:S.Z3[,WN'q4pDhs"bCUzUh9x=3n$xciW0 G@h72oiˁ /EU,t# ?gh"0 3UiQ>A`[|0>o &rL!!bO#q}@x@`lkvC3ܫ'B4B@R XHQS#tYwQM @`EMl.Ge8WZnA sD ʦ865tO{3^P7( 'sLƏl[T l 0`<fN!G#@:5) f;M# }?Qng'J1\! 4ɻ;ZxɵAQӵK`<C#쁀)F"^Q@`b< c7 >70nhHen҈?LfUww쩡=3ts%`"4($ag'L; S>@愶 }WFٽjl'k\@>!t拆l ^yS'l) Љ4t'~ ☙ysX-)M54_3/.8x+@CJps78^W<#LsnXFxt 苧n]Oɛ3l3b mEun \D .."u[NpC~%DL@`Aepzpr" $j]CwwUX:@C_'7 Un64 1FFFﯡR\p UL74 &R!R  'W2DtFAvr}HWD6FQ㻢Ż=$~/![3Cb p Ǜb7#7@^FG%g%LR8, 7}2{87g$@Γ2( Wp/G VQ A &/mwN@m:5= =P@~8;.  pac &5`&M @CsQ ]?36H:8(w0{a/ܛ mx*E\:/k}t?\h˧N&Y[$c:e%54sB\h;o#$9hM,;kf޶1|Ijn[XL=kVV-k@g]2z"2VKT@@C4qp @m^q\Q\2J \6Ц5@h0`<5\ Q @ZѱgΛ AC44j|Mt+C`1|t{Sna4PSFiݭ|,L?C 'm@j` u&FA/`,cHIVh!ف 28mz=1gNpq*?g^>4h@]<mvy>oy|$qRj}hS#ЦWg2`E ,8;gYmû^BYuϴ鹅Kic#ЬTCV8Ed &%q\PO-&N\'qjxvG@_VЦGPl RI520k,c,Χe4L^e~kmd ݇fO-aSn-L!z׷ްt!tӁ! b8Ή[\CuX(0s>g)CUHiTWm֎s#WƟhS'3ЦT>̑n j,)C.Mv(pm h赐i8XF%@ LLQE = TR6{X$e4oA0]'!SLs?m#6k:Ҕ^.*m~2X\ؓ;OѬ ]f̋WKc@C*A`&;'EчxtSӻ~B)) #P[I}oΌd6Et‰Eփ)(X:?#^1f)V8 .LWwٱ:;͏ZF=ƕ3zĴ }\@ Qh;My;)#4uxPUtBӱθ0T|'E1NgҙU29&Ђ{6ׂͼuRrZhW42&B9x=_!uS!1Šd,K@Cϐ@@C6D`aIIh茼<4~(+pF8꿼 ad*?_!̈́ZbD (^9֐sƹ>Wfs:qY6kѷ%>7LFWy[&Z^?Ju5O, JE^:Eb0?)‡" =aRNfU,zOsN4[&$6^5z}ޯj{:v҇D  l$?:Vd$9+^4_rI! *"6w>v`͍CV:(2k3\'Dz #24uźJFĥ0)Όrj{H5TihQ  P57gG /ŞŸ@L"_TI*B 8c ],stj慌Xb S=LK|I T!؃֍N b9;p:>"tֆ ̘arşyL*2[ܴV:P D 5Y%X+rOCS{[E36 mQCk72ylsxL-D\= L\{=Z tmåV 7оUh!8Sw󦪢! =2uLByATu2W=JTK-52m1є-5O%s K,ԔN9qRp#@?\&6g@:d#éO8(@ jũRc\zR+Mq 44ͦ:MUpЖ6*6fv XzpuiZ&߈c!@Cf*" ]jؔoG$miVE+Fr Ϛ{\?^!ZonEL,GlU`\Q`] _4CxMp4gpX:sɑ174tYCJBgqZF %jjU R{ѽ\;; 4@OD;840oq;U2AeU0/k=ڨmuyJ=Ot,KE'oVdSrވE0[N5tH[~aB B.޵='$&`KӾy]ohh[Cp7 .0˥a?|`)U3'VUŨ)NC iHf̦Ozo=/혷y 0M fSNj {59loP'J\~R-"ˤM }+jhN>3b }#E^Y 0m (cU:xE pB.`5jdogin̔B:}B+d4Dхdf ivZV \0YEd6̽U5 $h$aİhh S@Ux%IZКՃq8CoNabؘkaN7rz~cP 5u[T>W |*.y o6$Z`U1XevXE 88/p*<|%y[vMiIht"pNg0@CW%;TZxAG ($/{K+f."k>Vi͕t5 :>W+>`d$;Ԧ6ۣ<nZ@woY4t$4Tή78s.v33=L6uTw{T6tܛ9ۡ7@fWz{]xZ sA,T^kG]jhW#oo$LhDsaO˰as 4mߩ p[+ҿ?Ojhf 0% c 3;^dy%hk;*9}XM&s#|G4ٚkYrd0rs:ӏL@UB9?8 к߈(t7s%h?%`f-S!P,~R6O[7"o ߄Vz9PAJ[696~'a@Cץ)ٿ/4yeh#z+gtFCke- 3CHq.6fυ@9s H"[BDMg2"cws7:(Ijh8n[hj4Wm4k3@-EcS@q n;#a #PBd~)G\MC'96!4tu NIM>:d:vC AHR@D\ h; nX25'S(Xk5`B!Cނjxhg6RfLsϡ# y.o].ycX{ 5!%MIdy#u 2p~7)#1-h\1Q]\9c5`-S`[f!FRrg]Ti-A%|]?O Uf.Jj>_? 5֠C B`֗ D}m:w Ex^d,m4tKydvԄ%̙ pSu~+f Y- }K@@YМ _;q_ ~CH54XKc- hƬw>_#f[ Gq/lyyA[- @`KڶIw%\Ϙ|e?L,ʓ33z[l4t#MnӴZ& ĔΤE"}c r7[Zjnm5 gRCpş_D-$l\o,74tc3,nӴ44JuBF'5AS]`8mBш-Qy:xYn4zئ'c`n̲79qmLs p:>bڬhzmc>I)M1 ,v.jhKۤE0ۊ5F̌4tcvrT'ZGܞz؍zOƥ1^֦fC\rmC&ѧ QQ+ww81zm1nOwQFi}m̴ pkӟi=噷" X=w ͬMJ6 Ѐ@6Z_XOs5VƚvU9+Ɛ PrIZ\k`f S /ޖs4(KTA{ЫhR=O9 -fGZ>LMkNƶl6/3wussbP.BE E/ez^Ф)9opOWB-6\ۊ,9->o1sУDjQFLlxrf>Bꁫt ClBCF&A #2 #5Җ+gϚх".K@L2EwORpc#nWCWh_¥ag=mƋ#ōhv8$E@Ї2d6f~L 4qb0+4tٸu^p`nQCzL&JޡJεD-XZ=^@mrw,0!3(a)4'Zb)@z"I0^7B_8kܦxS+ih~ќ"E5PKV4>(NfL~O'b@ a khhNyТIu|mBzvw:W: |!}1@9R7FsGo5kUJ>YsǨ=k D\mEK[S5u)@$EYQ,MKhhS 5tzy,sݗ1C5߻(jhz$Bk2"Z%^SMZ8E$0 03\;({vB"sKoU-'bw͔i?/_^_%צ(/[۬Y 87W-kn*Is[?QVi干'@zQ[#CHX8#d'l!M!8Bы;4D?|-stS 7F]DA>MpLjf0QtaIfx+}wp^x8;`%.Y\hn$ZF i+tpVuZ3[:Qh_7jwLS4  mihږq#WE):fs3c3u27Y<ݿT]($ZY4M3)zϧMi9l K.-jh n 3z:uS=Ůn@Ohkf&mB SD@(XXq-OSri+h8Ѽ-n-Sz+&չq"  q%b@C?MPb=HhBLh<3b m>IfUKc7`m!߳Zqf f'ZimSa#DkCvd>rImra@'Y M@k1s7Q7tVӅ\[em:[DΑ_:9Rd$9 À*DUWfF,)r){0hB'ݭaVH#_0~ bZLCy1[wX>={\KL>u声tW6wr52?_\h!{"}|$PKbUq" ݮy:i;",s 9缆sMf.O4tB0x$3jNZFoA)ԤmMP**)5› &Ƶy -.b\ |Yz|;\Z)5Aij4Q+i͏"ԞD?9FxLYSXM!vFe>նZmbM6s_!WB8!Ѓ5&.J @CǛG]~3f>j{9ⅆ Un? \wjS#2o}fEu6/trPD6A 8jh}j޴فmZ`C_@$ 6 >qYԛg #pU'A ==6Mm˘|jIƗ NU:`~Mj8v.Rdͦ+^Ԕm{G/;|+!1 gvj='|*m`u!=l2aCPCC*PF8u{Hsp :S5Vާydp3;$fs PsyDZ8uM9rW'4o77{`$jhs{:&)4UJ<2{8)36 gSF 9ujJz@rӠwjx0xRei+z@üY+8 뼘77Ӱ3o!{bl)$ށVucTߒCZZ7" 6!لk#p} ]{ۃ{jz{kы4\fn9Αݘ+56*o1ͨaES+M<nrk&1OeH1\YC]m7k*J*hs+lϢHz5<$\< (yBeO'= `m"7Gg@FQ(;:_ #/\ +tUm\P{f bOSy9vJ_KdwItJwa FYtݨctXAC } W tg@Ԫgɼּ/9L$_b[qeYgxZ3[޺ÓZg?dwK|1L )QȐM:Hp>hퟴ@C9Jҁɉ\% 푩#>ȼJԂEqл$7Ԧ!Bt_ٹπ,5r┢|U|'ߤ8jz FNe5tLSYlگ|$5)5\ 0ͦ)[8g1yL__܉{v@d`zUנ=%`'bӃ51:]9s&5SGU6#k/MnoJC{C\кak L?_;7 ƏB@l(چfWGyu;;K&7kCt;o(ūYn@kkF="'UMLq,;IsU~3L zj! \]W= sot.9׌cѳ 4H4 ƓN2Vnj]FPŰO ݦm:Fou'^<-ܕ[R=scőQqhU]ZK߬r9>S&- d4l3b(Q:~+"2pUH iUDۡjc4YgnFC7eQ*gbo"{JP)&kDSs6i=UI07)Msl>ԵyԖAݕ'_(‹\SCkɑlBQ|&sFO4;l%f%D wݮX6NaFj_:8\徍SY6m65lj`-g3eef#MLHx[o[.w~l(=d8B͹T.8aby"pZD@:E1O[mE3RO'׻t*j}DcmnYYsxȱV0:+z}nB0rkr2KK&W˃D 9-r~6A14UĞd %>&6ЋŧWJ%z=Mפ-kRD|Og";{i{k8(ԌmEu&Ŷ%0+]&W`UD&;U?q`^ (2MP+B3FM\G%ɷX yV25@@ .QOaSqŷCqWn65x` H'(80yUnkbo}]pj \JC)sl@3%}3%i>kڣibUOCDDgݢis .O\:R6p#E Y斧C2Zol@n \%jүJλ!\PC'/1r&(@Q1b]ʟ*+i}мPO-Eh ?d;Hϋ"Z(0|]lK怶0O]pZPoyrbe4kLGG[#;%hKD, pM k^Fg44 5-_]A ]%49zmUHYKVF[7YjSR HG}Z[ݧ[ 0Tt!,W+4\1*i"Z|oMV[њ9m-ܺ-L:&ujm1u1 tV(f7܈ ] p&E+LyִNYc@f}Tq: \ uaV(?Eg:"7.cYQl=1/3`pDçmpFf =ϟtt~ O+wiW3GfӥH1/gXyNyŢE ΔА sW0rF֒6OFzݶC$ͼ&&+(A.)C=7b<^lK%fhG5hm*t>f}u&b3֔/݆͆T.w)nQfK#DPCMdD#lxϱlm. Csw#V~34'CEj8MLmF[h1؛[4藙<"CFb }CzHI.?\X|p/ZQ[y iqrIu=e½1Sy?: \rEhh;uPf"Tmjhًt_AG0LàܥS} \z-k ~ 1ĭ|{ȘJu5%{ͱ͋@/K2V3@Ci2岦L3.mmd<|@IsqΦHS "nCC,̻)Ÿ{^1.񷆀95Vpa89\Gz%Lfc^0ŋ[ۏ h7N 5wLЬ.ݘyEe:z|ݍ晍d0V̓8y2X Of+̵ WHm^m:0,P+N\+l^h9qzqu[m9q86?#VZ{R70S1~:h! cR-Fia' `>U8#HCK|`={ fPi͆4t6#dy$Py韌Kn{_2P?Y=7 S@@! i9](\-E1I+dOWz[ k|  \`W > (vgჅ ]oEN噉Lzkz>[!%XswZ Cb\0g.2)<'K74t2DE:NZ]\a&ӄJoRozЂoW1UXD@Cey"$W2z%,a:ݢ3<Ȍ RwV >oZ]-5'vX]WGo5ĻNZA;"^N/0h<iY.sM1z+ShShhAt<h(zki$D'ףi.xO&IӟIfYۻG9"\[g=Vg#BA@o3)oLqMK,!t T}T4 K"2&ˉL{A:u: 5.V0xQŅq9Fq-]!gA Z{xj?P䎆ZjnЂLļho z4x\\lhټxJ%<.돷x1ʤm`cB qL̓jŷ7oJ:|BmY_rm߁,ݰ_l U4 &N )--Řu\AC{Eۉee+z:löEs%-s>|h<%e%8R/|ΟEF4K4,NmTzK9bDA5f6O,/:{ :/kh1敷Ђ ;N?I0!.;m4ǢIrƘ:?_ {ڬ׹ws M\6eH(h`5ۘҐJ6A ͇&\ACELX@K*$^̌1hfcj6;Ek^$[c'jM0"DezҿFѝbǙW(l?G ^/.i"l<dX"p ͷw( ͢PɈôq&5|ٹ0Y yA7_@(\FM\ Ρ>15wr/A#c*.fD`Q Ђ2H/WNAȏE*}ޱ#=.4/h`;&WtX` n|/Ǝ7@Ђ tDbߙdnJ3g-SEoh p) ]XTVqS)iPMB)n*b]f3Qi#. && pf#y254bA&1y!J:4 ̒o-5 (Va4AZ 酵fv 5I[˴qlSXwE6?J4dLŗ@4`H`pnQC'WqtI&wJ<#աfN;'2Qt&-)q-[ǘΌƋc- Qzpen|5{7JF92}M6•l%L aH p8 ,%I7yQy^ !9Rw0 h{@߆Xlb@[E 4Ȼ@Ik *q^|yάL.7MaCwџ5 ]rk ȮSk`SaE4tLEMnrZ1āb6?Npѫ }Ǥ:f̮2nB!4Gu.lgYXTQ}}N1ewLW&5[gͣ)B激qP'@y96 3&0 0-ePLKO)hSrMi& jƧ'vN➝$m\Dze,•vy)[qn4w)9MV&us4t ,б6 dxX΅MhX@hMFYynD[oR7C<*M NOF a $'kΤ^mz$гqj2-BŮo[PjKC=kf:c{E15tn>WܚCE-p0ʢ x(U}sOz=̺z7ҙTg$uO(-UzcD5yN"j>r2Z?QД5( M Љ5t,wLAYAIҶtgnM q#2C)+ݺj͑mt4M mKĎNGASRI2Q=uB 4t[WҢ9<)A!)C:/K[$˥G~GP歙cFD{at+)Nlsn!.V͗eƂ9&315 ť7h&YYR2jex <,g`1kޒy0 PE4``3{o%i MsZHG*^i{ <ھFXU>?3@0r~ iM/_E끑ȧVCױ}EDj6!="pz 92Ev>6U Wx]V;ڢ+|-d4oio 6^zDF&$uk؃Z.AM;U7'Pn:w#fϗ3D*yH 5WЙ:O}1V&tY׊'egB(X@`ͫ5tR>rʥ-/=yK֭̋LZD2 "pn 0Kpu|kS_d9xH Ab`rpqC D?(.s=ej_=Ż]Sf5ց_MÄ 'Ё+=f:3+ 0U7[1E?=)5np\GvĮॆ`md2qM\[1sZ \ $loD 0 skABaԦ5ۨ vDr[@\:k0I<(32V(i=1, pI*$cg Ǻ[0$N 58wM40uDy^5NAQc+hhR3|sz_BVQ@5OxSW-@"á5X!j*cPQ&F-&mch@F*;kӚ{  \aDhU~) <%zb]|EL7Jn;ȩ8nSyhːVmv,S%vESS Nn:3k(\q 4FZ 5zdiEڑ: 2.HUiQSCwMniRC A Pޢ{@[" ˴+Ny{k.-&赺6@-ū;R hҝI2\ߚ _ N]>FX0O}A_ϓ cSj#H&3z nSe6;-^[x[`S4 "*4̭'' Mjh2Hjo{'H3cs k@` 'Фf` -50Ԟd:Qaܢ yO6N11{#55_]JO"xX;EkhܴLC:0Y5t^wn!FppLT=~p iދm8Ԧrv! ȇ+-Pj> J7>a5ٞOkYZhVGZX$M 0 sk" 3}tG4.M*/c3~O"9du, Y@et\&Y$[2܆p%I1 8Dg\YCϩEТ1VҼ@·|*giMRbqjY h$#&R]4kuzwIr֙L 0e5Ί ̘ᥰ.ʥs|wBa?96;gɝgrpjY:\ {hZ1lSSx7{̵v&9À\SC))rR$KzB8˯#Y{fg-`҃Qvh~PEb]ShX|g 'D"\4@(.w ZㄣRNt7K8S%9zFe4v}\t! ^]y{u e(dMaS v^ ~&%@Cw%Ehߴ2=bh%5Wɮ3"$nlf}`R<6XܦYM:h^37h;@7/!,fCjzg (A{&U@@ .1v#ZT `Cbb]Of]&iY_?y>ՈU@-B 绵>^;I(AWy|ij,hw`x,C`hUǯ+{u_"5Kpl<ʲ#̿'}5NY5!;5̩TF@tLcH@d\LXO)]cQKҪu0W9,k ]e  Dz9$S4sm=ϹW@&1r7LUꙣh8;HG*M1_xc;Zg&8AFe{?Ń#U>qwNlIqL Ff4?"řȄ(@`#ہN0SǼ]K@CCCOB@HIϳzn2N!ʃo m .y)}U3ORhc SjM2([:.9S:P8˜= (@58u[R+`:L{E_Հ:X\XC+pB(O6Z/'hAChE7}Y3RD`B ݶM>wC4%2뀟v<ߙeLF_O6 *֎i'{U2}xv:+W:A)E/) 75 d9}vb4\N m'>tvykm:}>]8p52/cf'#@CovoPDF'+ABC؍3P)ZKnPNpeq˿M(s2%)M=կ-m! ݛoL=f„lPC ڥy888Tm 6ϛ9śY\]>1>3Mx(nOgքQ֦6aI!"&_kWH14t{ [m?3B7s{A3'([y"}6o_/Xh4(8 H'9u6Wul9hF`mcFi&?bs/Ϡq8'srƑ9&'Y<FjE_{,d E׆@@C7(+ Dq'w`%ټ9Fؼ&8>te й/j1uz}RעYڃ*A=yd*{_ .ɿW.-8>9{"\IU|Yj<܍Qīqs z9 C{u?m K58B=&yFu]NEqL7»=Nlz%@--ѻ@D_^vkodZu) qfaShvvYe pv{3ȻBc);PB '9L79U<8#im0hJ&1 dLg̃ zѓΫ3A-Y OX .yc@ŕw]7S|k*؂Lox45wqzlNGjpL21@ @p7HhM}f\ {*\R-$c,'c65%ambGr-@Ld>F ~'OmaEEVI7rW{Z@tTa@ F26 7NBzy99J".DKN@d"Ԙ:ZCo-NTQ/*Pmv|S3X}820l_C-=hH-~n}P^pB@Ch tWmsY@#%-Hr~~l~Ǯ^ţz\]LXaq5bH q^7B&FG!0~@5iױN5Gu39zjKpE#fDSRocӴft(N*h;L ]aJyGcB1 à>uI7`3eS|z\ EQiʠ`DM6%˺P60] 44ճh*'4 ڻ5.NQNO=ݺͻ;n;SLy1 pjKF2ڣlt3N}UUDsyMjы R,j5X- x_[1-pRi bq)B,1R;cx({ 7% }d}j5MMmeNQ&&L5Фl X7et1*N4xrjFғk%ĿaWDwz$ң*PELxasJKnk9=bj%>V; WN\L=Dtwk eiJkh}ܡ3KWśE??= YW1SXҤwP. ]]ri*Ί) DA-:_k$^7 Ǔ$wOG3{ūs^Qt%dw0tOgPsye._ܭ3`7gH<̿} yPk( bE!iы]@7t_jYo쏇OU9g|&x[,"x=7n_c@5oФ8-TNN5B ]Sy_$.n(@1h1-SYSgUZqטZ_#+SXtI 5V6* ]!:U!T8kj居JLR` 5S3ȱcszd$XZ2ΓhuV$R6 ~Hv=b~=+h~ۭ2Y|ِw&F^,@s:)_.rSwHr0ګt)w dhʺ9$a#p.$+߫YjetC#ъSH?LMgb-XB ӀՐk,|$Poo<`s{OwpTqԜUNJB,e ]]6+{qS}Exz-%Is<]殒 )3ERPeś8Njd[fN$i~/lj@Sm ցBD5 XHmj%F}SZ2u1@m|}X 4^hÛnU%t>q,&fJJӽ9D_nut3yF~8 +'Ihޒ( Aڼ{Rec&*"zZIGzDV nq{>D{'#3z.LiK+*} ;v[:^πt{)(-L:Fh'ͤ6UA()"bFx.wGѫI:sQҚ~U,ْ %+"&VڦöOQmst -wDgϽ'/TY3_fo^BPvaZW=߂b Q0 ՠ'1cx3˓w.7HC=eYiF . i4/6 QY]6M(=o,2YZӈ58O.g= `k!ss736ȸIRiH.ZS%,$E ~"{0҆@PEh[4t#bN. WuOZе=oœuG7E$WލtgB4Dff%'SHEDQuvu1! >bMMUc;hw6f1e'9!OurcǒcׂTyEu#kh齲[ h -3TpG^:*CN\MrNl=sOr J뱱dRNIKz,zc,_Y@UQZ@/CCWL&[؜h BȚD\+XbdM'Ir?c祯NvP̦)4ti 5#i8 J>*^ɝuԑE;M\{\C 鐉j17olphz+1YF@%]o͏s( =bw^4=p4Ρ+ Sz"Skޭp:*"uQp'F1EhU-\G$tE*N&e[c߫uľkIO&_\K`񲁘6?+OR^Ykw>*,MZ4Z=w iS(.AAyZ]^=Go[ʝnPg5nA!h֖Mւ@zDEa]( n`"( fɱKb #A~Xn;NHD?+S+t`eSsxzmeZ;kbֻlkyrbwBCW'musdqP.()[к2Z["#BYT^ֵ\7OY5H_=x.ng]gxkyJtl}eWw`G0FU ԛk mנ\q4”;/:6]ThXk"VBoXh)qrǢBt;EeRߺhu6!kY<}HOk3RgS'}ӛMɾvhƄ2iJKW>4t# _@ka5xuDo9nBhC缀&IM?bC6S$&L2VC2!^n|$ w#(ۆWڞS7h&hE}7 Fl1^4]l$!IBC)L9]7zxlS'5g!Ş1À8$3}ȢI] &%G̕DZSkWT#竆:)E>\[%p쉸^⓸,lJ]BCWYbrI kxmyltqO6酩Q{ZgOA#]& kxD`_zb4d}G {E[gGGeʗc54u(S@wI&1im7$ ݋Yo-DOUJf f~~z͸L,vqflv\ z<,-ܣznL%%ʑw Lo1q)% c`pjjh][2FO ^ B 4tou󵂻c.82?OQY;c"b4B2ÐU6r(z>īNWs**j4(ԕ*y F͞E[US>}3`%X)E\lnp6$9JVif4t%wLPɭ.+9+ﴦ`nn~4^p_Bgjˇ$I,R%Mx"-\UԉOiX3od\|i$('S}PY´ ]qр`g"#}SKF|K ?vB0!EM@C44CO4S5AzH#OfÄ^ikW*{aih.Toq EEեWE@(y("8zs{ӳ|o=(n!./Xxnh+ F!MWu71tϘi 1'Rҷ،Qѥ+q1Q߱@7-=/j';lIfX?=!ŏz8,Zd*Sн&,B5?K.=5f$nIƦ9x;"1ns4X;R!ԽXc5OdX%gBb&q^caםHV~=uY<ƞmFx2;mb A/gAt0o9Rl.Kt݌ <5kfHRmLACW ߿F%ahRnPu fΘ|6w6NjN it>f+i 'Z4Yo;n~|Eť P'mqI >֠E.)9 Z,K(b,c- s`Nk4}{COAmXkǣ5qN<ŀ& #MzAgn18nc{k7I}*w>#^ZI,n _l-μ6ϝ*59s ]Lycpܟk̾)vPWz8rsMϫ/f/.<`oM5?CMjܹ#4H:0HS^-wp#X4|e>xp]kxZ W(pIqusE=*:9]~I'{5Ĺi ;_i|FжY4SQI&Z)VJת4'QQ^gz-hq)*ŏ9f7G`~;qkĞd>{iY;Lny$v[,!ajiGW1S jv|g=4-& ɨ_SLNXΫs/:ӎFKEMx5&MϗPf=SF6NO,s;LM@usH5dfK1RBL) 3o w U54oüMz-x!'z"3嶜?Nj_J%%SIaˤQ#˂6RYL f #|xNsܚoFWȄ45|(F` 4tB]qi77|ɠֵbv[%0l9ncN̎j[8\eSC8?T Uu iU\K&fDzH+!tP.ֺ i)fG'̷L$?3hq (gp}-ӃVm>03;, =;JC-4QO|jɐZX#;RpjWDr#Ǩqˁ.X|l ‡Qk{x4ț‰p6 ث!IEjJPKb`rm7*v!)??߽~ yoǎOi7xs:L-ͼq,yh/?4]@%ʩ{E6xn@+Nӝk;=Is1Lv5? d4AqNj̀/xһjxoI]EшI&cy&wc,' =,|cjچylP8'n/I~\}. 񬧳Y-}8-A׽0@;V؁VoWE%":{lUqS8r='>q &v[=T&A5O@{t ; 6msygK; õ LarYnd,naC3o]3GSe͈RÆh>Z>*' ]Dm~_V1OdhU}\D (f> i$=qAU-^+ҦH3LlIר}0]% ʈ(i^QŎ 'ŭ/H&^a-d 4mw~ AC"mu+j]o"z|dZq zb(MxClo~Mf*G?M*m?\ӫYBq&"9"vӱ ?Ps9-$N1}ԵbrV!xQ{oi0끨-Xnvybƫ@C @l%3EGD6yc2OS꺜"Z<!5*J_/]<t#t 503 dwU#ʘE(=.zoUh?/]#j^ >ifx3m=˧$5|ڲ)z<Dn\L!%xb}{^B_&jbYWn^"U\o[RfU+bp'kRLe22"CR-A]ɗ֌* "-U`kdn 5;afW;'BCwx7=&5Gר3J'ɇ"5Ys\8qm l=3W79ıϽ9jOG9aWQh~n9wF(#'s#h^ ʛfߞ-P ^s֞k5Y = IJ(&q~Zg@bz)nք7Ztf6T.8t*RZm1u@]y7$]HԶyJqA9Ó$paUC}=8duyc|d[k>Eh&4t[mƛYC{D\=a^">_>VB&n4t)&A~N6cy'ح@;h'F0`gs (覢;r%%AoTm~C@|QSkB.ѬÆI%7C`}%51 .A(QI,0+CCgZHr#(:E>QK5s4{-n|QTJECJ$MŖ(z0=|7ؕns*N eElKch!a^w sN  1{&*^tpmئmOu ~ٮskQhÓm7`G>?M3a[U 34 ܥ]~7[``hNM?c5{ԜEkM$5s yd}E"sT6lj*Cгzkəܭs{j\6jAɬZ;Tx8 e|/}rb^ӊm9gn.k3Lϥ Zf?킂퉺I78"t-J85xwbaj"7J~fG352 :3&;ίiC޿X1MI 3'u<7)1wo} C"$hYȫgZT0^/!q#&xՌUxEN|Eb) 13tt8f*?U/922[tгed?zshpl@ZBWnKt`v<2-3p!+t4 GIZި,]j6F;}64hc?ĀZ$(Rr󊜏;]}xxsy?\h;<Uyt dגVйOv%=^/ސwkh"SOƳE:$MDO(5EL֭ b eX,x%]!y˩;JNC D<.2WӃaP7t0}kX7 ) .=a*E0Up[WbF)l#؛3n#cMW7+L\U("I_<+S+=.d\\略4Ii 0\qR =k-@CӏWk,OɈE:QVg#o)|$b_ -8YoVT L^VLڟLw M(1iTEŴEy5Ĥf>! ݆[kz=Ih8 MoeZun {y*ʇixhGdiCaԪITM!ts> 8x.VM ![ _-{?Zyz|e!R[K"5 / ؍~sDh]TE 2SGdu n:D`?Ն5g:kR2i(0hd>H)Xk+sSYڔZzq$P[%Zo+5\z\տz)ƔdghhOx'xm;o+>DL_ws1T1yoZ6͸Fr-/Tλ QmgOh⓼gx46 ZUMaݸ]MDXL7ڂBR1g3f˴}l ` D;4,:L_KpX ?,I ~lu'Qy^ (;Ӄ.@C]A{K;-bkɡY#;,QAF0Zg fmZSw'5|C ϻ7 3I|ŝB̟ W2)8 !dh5Cb!gLQtD #dthSyg"`6̓s69`>^h^Z(l,9#}2w#O<9UTT*D2!=?dô89 ԣ< -dIr=!sSZ`fʘŘ6p6K-Yo_Cb\MydSop)V3.ϔYb/n$60.(mGze6}fE ͍&仆p*huFm;56)=scM7b`|Zzqh6 lg9;\Nڽ׷y.LUlE@ hSFwHR:_$2ғ,xNҦֺN=8^qr5?6oaϑI~ӥ] zsIB%BS^ufqBߥxEޞAf,u^`B?0қ2hh}D & j.%k 44m@z:R@@Ky#dt|L4ѰF\,4I=k&549`ZS~Zu>Wx^:-N;Q~Ȁ; / }V hB44?.5LENOoJb:x30k*φV\z%^VB:L($l@ Xq3Yo}n|77锶ԥ4 }?pW^ paof'l[fbo9?kL>: eA17GjigF@T;ɟr:x@;ylXkt RY@(FWkm񓻷' } ]K%DJ, xWl+ZQ7txrUםM\Q/ubvAYJ愰\r.t梖pm=kes]͓NŅy䃠>.s<4Sc #5sjO_4箊-t3@I{ڜ.XvQ5{Y\3zKl㌔/in'3vN.62XtlkAC"8~k%]2l ǂIy]~cTN;ʥOE|Е (Z԰'{C :ӂ`vCPnD,F<[#7G(.3zT|Q7(O2wܴ2&}Eoug|BK@@BҦX;`[Dw%.#]{~ϻ# GqE>}IKN\=2@CQ!zlqk*j8 ^œN({GF[^. ώےmӓ@I'^yB+ ^-SSd>w -<'<7)46JmIܿQ};eY_N5Zo]؏EsQS|2ՓtN zT3x# uL3Ԋ{Ȝ޹}^fخ8 菖)[,.4N de/oָ͕̔e;~K#QjY4 7UjՂ鰸 -&oF'hӷЦ;oͱcbhӥbe$|p.cQn\yq=0 eYF;1Sk@{yiPk!Q413I'YO1_8 ހob@!v:DK6;HN:)@H)+C_TLBm9ğ"nvcU&죌\ #1T\za@^gm.k,KdOs!S=Cb\yuaXF;7Q hj |ɉܛϙXo`.(WiOC;7 ->nM}(7Չ{;47 } /M+orG6c\+26vX ><<M naO+42Ufș`!vO>6;v>$ / Jb<Ɲ>u?CB5^ub޴[ Bzvb1ХǛu.IY1xЦ3k}Bew8]f})3iů[T]zZya\(+=54'ͫ"ݦhw ͆4Ѫ|VUw,(% ;{B0pLY{@`%b ŗ&Ͱ',\({W´U==6ZCEƺ`yyLh-Plc"o>RKpNQ'4pPq7xײՓESͨz{jN܌&E@WkB.R S KtuE). ؇cPchrmbP4t-b#+ 9w=hN8_ˀ͍g98LyW&D ؼ ^h \|*V+K=jo|\=)YXD] c@C'9,PK[\y\I@F4n#S^54UKS!z?;/8D sa"z] h"^yRuνG7U{ nGad{<c>2=P 1 m͙],WB>Kk$?n4W]mћ<E`bh6lF.8kH< ]FC-)n7l A v989:X>hC`[TF؄dz0 ZDc]/i[\(ѰP'_p`,w.˄hnqPOwf =ګd45-W\׎ zj P6Z𹁀ނΌc24J_ 6B0bKz0J[fpWL6E1f @fFHii\)j=9grL p@4ZؠH6̶?XqZ K>KY 9SzCed"Xyy-d X p gL99 1 h}Ozs͈ _KфBjn꣐4pIΖ9y9'M!يdcjhU!DjaÏXk[.ÁTBg~/4, մhhYҏqư\OUhUKq4M_a/F@_y,AC{ID=25ЄmXEEk"' }|&[ދ깇G҃";+kfw625tt;K40皾ܛ*<ykbz{-9M[;q]"דgmK% HF'F?:a45~-Z= w&bD ̳U1JKuYUKs"MM\q,Ԑ[-gWS.ko >ǻ-UZSP7}(D)n6hp SDzOG{ۯx$ km#H!Yx*y#oNAn%Z:#.gQy01rrDaQ & Q[!#ڤ-s_ W̟5ȳhˀ'ߊ4v8Ń~yBR vP&_7/@])XtFj/5 -(/htMΕ_E8g$vbϮs2UIK 9oW1KTa"1!W @C76x ^oWΤ\pzp`1LmjFXlɂ1-лzښW-(=`ST|ݭVi)pxDb ]7ozݶhl ψ4Y__={B![EABRxhy@0S+6ε;K*6̎1^s䍡#_6[)te)d)U)>tS` W&ɅxզF0^a>>e=o `WsHsoVC:dxdZEc8*1dT&"s@CsaSjh-.ڑ^8"Bp-uNO-5!WtxRR{-vfџXp4^/x[rw-Edm VMdɝa) ;KmSj.ZT#^W>W{fmq}yIefjVcF9(oOPDf۰ @ D)MWu;Q ?/sȈo&6ɻih6pcཅM!$Ξp#ȍаhŬuaʑTm l-U:ފ|$ !o$ڬ۸,c*nSES-"瘬+ 1k7M ?ހ+ h!à N|OPfvZk:րHX{99=17# 2c0~2{&k{A(3ΙTQ^eU2} s6e1"([~NԀgw4yssMzr~\[L&\āU&S}x`Xq=fEy H8Q3"G=Oq81.5gjSCs6&bMmxDޤ3! } 쩐@C|.2lkh ^cж4Q٢+kV%ɔ5}άam'i,Q.sOl ;KI/^@fM r \k4L NP1W֚ |Oċp(h `s;vs q)%l AӢO2p۬M`zy1/Z0u :{BdӒY㱆+>N>4=ANۈm.5&Pi:a;k.k3u!>g7\9{%fкoOЦ& )~yIJTcP0ޥvI<.䠠-`bS hqhh.ӫe6r fCz;l7e1lѼR6Sp4Z4Zf}5EִVxSK,8M FkzE%zZ h|ѫA%ύHbRF }]jj^AiK E;nD\#͏lF݃z f Wu3L{yҳ ^>x8ytAfZ=ykĺBw&mC+^X~օ> u=I|}$k [FkY]IAJ]C>km|:1ް76ƒعDz”?G<4I>-2g !(~fdznrDJ4Iѧmm$K?V'6|EzԪ,Z;]Tbni|!5%'f3av&Z7xv7aYN =I"nx‿2ׅz沲Oӌ0UCsQnm[ާ2zS=ARvx,Oa$nІ;bH/+\ssfFBnFM!yWw+޽z<hEz<ҵpZ|YŽ)T@)XކT{׍ p57!hḥ"ǧP[LZц3(6F#+ڝW؅zZɇ-߼F1X1ᚁ@@cJr+jǝ#obiY<Z$DNVw3mfz:-\2Vlp  X 4g'MA &44שT7M()8v޸ehI MF欤\LC eO m6Z17ia# M(M Kѡ)& u~zAlF Ѣ= P7Mz69DZGhh}n\@[}5I@:,圆4{h;5b6ŖE\Q/ang!#<;^o)gp#eաAPh|x(ۜL'):ݧ!b=ᢹy\0w4GgZ?w K=1YGw&S'*7dv8{des C#P :Cޒe$8Cf(kɼcX--'$b"א|`: pK ̻uhSZEzEt 'A"EhL<&=#!(wztcTZ  Z/5rg yኁcc<qk0ۭ`(VQ5I\>jA΀*ih܇h‚5EP@ay4wZ NԠoe< m:)@I dc&ZR7DeA|7Eic +n=Ps!v x6'"=ךf3hhA Ku Zf3ezؼYN#1VS ]2V?mG5{Ayf;*pS2gK5Z\ b1z׬j} ׽ ,[31pLi(jLWf-BZ[9^=;R q.g=ZDLi5ـ `ω'צb0"\ \[o mJj:Rh߸ObT7f(̉c/<96t曑Ӳ^4ssWJ&NSv@K gJ2:O@s+.EhfD"cV1кge(q%Skk-LĄè8M=m7:D\F5)9'+[((S@\:5Kgj @z-'E뤌BcZKD*`pRfoF`٦h9EwszT[s +޹ ƼS#$VTD@C(YwfǤU5I{b6$gMwVIs^5=5;bxS-ַw8=)@QQihO@8)=E 6Bz#`2 T!3c\rHɇ)s9&pfky7T6W50v,|*O1,ќМ|ttb{FCǢ;# 3]Zˈ@Os #ī5 &s'>1zk{ PT.rJn[7mu\D VM b? HԜ~>ЊACS+-/ }dIĤT_&PQCϘc (s m(U**̜~%Fm` v6E@3Gm_蒅M=nbn.#Bԡ\ifa,@C <&~ >[%cE-ű2,o~EwOB@mػjCë[‡? tpY63i[-qՉ@hCurg׽CP<4d%Ela|m&<L d؍t@ C+?Z|O5cDPU;}Mл"霠o';0>qi Ms @@ }j2ZtO!i w4tbAx9f;l$MΦPAk>%ZO󨓃NNİ 5I^C 9\C6' E_<-3aߠKI:nQS 9E$BX(CM&5*6U@_1,IƦd}3͞-i\csәzp0`Bt6RҬd~6tbOJ;4+! N4I)4t&{_pym .xa*!gJn;qИu|dE3A䛺X=8ovwC@go~ 7rp@}EcDIJy$b-ebI䉏X)S󦪰044!7,h.I%Mmoy/Jzx?5SNgx6'Wiii3t?bᛝ?oGĖcv@z\B8**5j n-KMn%uu!y1ϖwj_ t D I7Gs ʦNkpj/h;n 'dΐ^_ͻ, xuU٧qyCSqnYLQ. 8jeHЦҍ mxBB(lI*J:P"FQ[1q-KWB5wiѬ7rm)hgݧcPtWtjELFŚLzXœyut84{cu^Ay4oT!$ŴN'Vt*jKVU!VYhsA fTfPCj)Tf8E'Xfr=/r}`Z g~#[k;Τqx`!=,;K1'M_ d(i,Ĵ~t'Ly7tSuaG'LǤJ~QF\ح5]"@Pu b}!ʥ|.\bw,Pς61 ݃`f`Ovœ mvV[&h#b qA";Ac+W!erNŇ7XÔC0K,]=͍L׼#ݢEvòFUqbb%[`\<u]h~)rYKm %Ot>8 ,4$S.( Qlo^};' hnj0IF } oa,_6FSAIwdmf# 5'I7N4;S&YZh)V1Vrtf j5WRL4$ݘp.cN+ }lV,5%Wp H}4ڈ(q27b6HFC-2 s".τ_&4a0y(JVWǎ4Jb"\"g/F'Gz=hy5=Bdi c3CxtASv ~#0x[@>)I5SG#T\aUz<9p&.qL|eSM*Kσ4<'BJ~geEOFݽ6j5t놧5tFxVKp9RBz|KM`N fF;A ;ȬCjyy#FL9ŝGJ5'Ez ^16FvY3/z*OC4;RB0hyf3)ᥛ c͔ *s;69 "d/"|f>@\@C7C Pli9:B?[X0uLWM˫RUO:w>qە+,?T)Bo!k28<ʈt}+hљϻF;Cb E8"੷]`uiL,∴T5_ CtAL+fCMJ3Ƣ5GG_W/U%5p m:蕼nj!5Aqhkmn.06#vF>VnZCnJkmq7M5/ʼجVYe6YŽYkp&r9eAj%Q{l^+h+eTi-lFq(Bih~>IBC'/=s*/oU ղrU[^Qkhn ׍un>4eA`f 5Cpq:)Ck^Qy27Db魘~SӬMiml`b@C_,g'Fi! (t+o{LBbuVdգ6b ]<+&W/NTm`iGз9F3{Lͺ(؉cX\#ґ̣'BCS}J:d4tЍjez HhuS,2bs+fUL] Dzμ8;ƣ[HQY1mxKLf-AFOQsk@CWIu"%mN;9i{Ǡ/D7hht14f5UԦ @{Bjg0 4SDr,k3_:Wj_QZHNf8's^M Z^i&7M EKF8-PZC&G肓'-{ԆX8f5#\C6ͤe?<:u3JOhMIrl +4!c#`1;()Y44 j4׳цw.{ ަjub[Orpy$`<y0<[Dbg ;H4-\h%m*֥Y QjyzC0+JU(Wi6(>:ؿ)"XnS=9YIFsOqhZrUj=2c(G! ;G ik6oo -/d4v8HKm_C4z8`LtЄR3xb A=̽!-PȜ &MQ*\Eqe¦8+/@H t 㹙. e! K̋Xպ͗-_Uf#Eݼg>hӥ kl^O 5ߙb7Ǟf&6#2ˉcJЗdb M{kSg@Cs)cs~r,,ǀʚYcIôFyMn&-xN_o!ˈv| Jr"~3<=C,^{|3OڬACBeI̙=) " Jev{g*7(r+jhN4yy@Hߞ,Flڣ <Ljh­Ш PF >(O=;>^xw}ݓ].Z%܋u?YW~c( vz,8+5sB!1pPZ҃4tz{&d=^ Ծ: [#_(jI S97Nd&kA6+]^~@TkY-#g:B/* F4Zk yqtNsk { oܔq >_g"0hxQd(=1HmIW ZN-$dŘ(V(4?L%5y SٹH|`a &@CSW.JbDo%k_7ԡyfZy2op[Qqe=q2M_؆7+ رi AlLNIFfOkOFS%#b g5khff-9ihS yH_!stώ437D >pavbjYSS6ES{G7R#nB+{'ۥ2jf;x/`ٻ8Ի/xíih/~<5" ( ` σ9_4h|t^mV<5@,j>TjSQa +KC 4ؙ\LI@aح [ֲoq%g*B:YGz+]"Sq cB&WHш)y]M<4&fk"`j58bY GjYߢpbLm]wMqz"60[-zOOZrzg^!N>iS }4ɝN=ej!/qO#H+i7=hikisd~z[@CYv Q.N &^A! aBvyt\<ߪRAFPjl kh>͏b N׊t~|y7y ^hkU#Q !50ZF*AC{!~\41ۨ`g;|ݎ^/5;g2FG]0F@ڎ=!FLCm뺂!r0I#񰋝Cp5: j,t&gtSXe^S"/?%%M20YC44Nδ}-v2i;M ܼ@Bul&<;WQ4TO|V4dgH3[DÎBƍ\XC5 zAs7 SCӱPʤg~&l;n0}}+ZtZ;E950`mHV#4$@ 4t%9&@ZxTf^ E.Fw'!))WS^" p kp5+\-^yۜ-Cz9EDGCk 9%nUYy0zIAǀfVJ^M04tsR0l48aEaqX Hkqf||0t3 t48f :k04wHVlIQT@ ]_:S!~=8 h裐Ǻ@sD}tVkIw zDE Mα]Ҽ:  j,*=Ns* Ί/zV+^xxO36l4Ήr@4t"  bA' SU{9.41{B h BI$¸qr,WYLӵ|vQcW7QS& 4M =ЧH]H>iδsCzˁc"N /! Xt!qAZ<1CoՅ >8J3&ކ?n@CO8bH{dϡ.yͬp ne44L4IK@ezϼ"s#/?=(zsr_@Fcv"nͫn%tӁXF%I -nQjSX\ q,s3|J[S"P,% S>q(1Yx"N{ Br+ׁ6! 0 mRvtФ{9,p+c5yo&[-]̠ 5y}UPa9:C_]4/@qj"cˆ4 c Ђ@|ÀkcaQW IDAT\3p ],g$N=EvFzg" WРI`Ơ54%?n^o6 1c8l4&@98|к>1Y4"}Hjh8o2zYeбЗJ'<Az}M@V#Bjq\|؟uSCC\~g`[ Xhh8iICώKqGC)vB,@`r'OOЧtl~/z|ŅZ᧑EtgЖg4gÔk`(@Cϟ#xԃD78ɹZ>l P S.B@i@& +jwp,7ZA\;~0@h$PFC m{ 9?8hY S΀|A"DG sEϘsuk-i6<"D=4TfÔ1*` p0mgog9~@ ɛx:|ǬhɶYE@pQ@"/iLҳ SѶfM DIEH@>c5Ow!qu~Ҩp۬B>]0p2:3a5Sn%׫NVe!,'| v@z y*5fh^HTRXfmRma)0}trϡWeLI/$aKQ<o$} @-еan za! Ќ4t3t@C:,!0%>8hs# #wC`@@8,zAsSv ]!)W1I41p @Q[@ClGẕ"hH!ЦRkc p@C`28+E5 YQ#0؊u}@X2e0IeG 7fF`oACϜehhAp-h7f @CDFo0 L:B>)'M)/<{9nD34snh[4gG y͏IFQ?G@C8ϑ]xVQ@\@C+_.ƑV#xs }c3pDw+8amџhf~[@Wp?* hs Cs\0@ @C!K0Ё" =on>F1 T@CO8@ pO$@ 0S @h$ . @L4T3@ '@I@ S! =U: @  >A"@ T@CO8@ pO$@ 0S @h$ . @L4T3@ '@I@ S! =U: @  >A"@ T@CO8@ pO$@ 0S @h$ . @L4T3@ '@I@ S! =U: @  >A"@ T@CO8@ pO$@ 0S @h$ . @L4T3@ '@I@ S!Px @ #o|Ǔ{^@ @hh @:*^`@ @ u@Cu*@ PD^@ @ˁ@ @ =vZIENDB`BoolNet/vignettes/sequence_igf.pdf0000644000176200001440000001166314272152006016762 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802093638) /ModDate (D:20220802093638) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 1104 /Filter /FlateDecode >> stream xKo[7Wpi/2"6 .% IFK^+[G]H;gf(F](_;~oIkW׶j_ĠqL)WmɃAz<{{r|щ^@4[8;8%{w[)8QKq}"w$'MvY .]8nI-BןF&^GJ탥'f[fWinV&.z2?O!Q7ZQՇ.ZuVO&.xIwzOYo9Xfpǝ+w ]OH%WKbnpYr_/Gx^xڠDF0 cMRRZAB&+[SPIٖ@7˕X-%Vy=uQZuk꽺]n@.6Mހi{x26smAT}6hr ֚1L0FG>bf b))XK> Q3Fa f~u]"p+oK30r1tXE25rˎK%E2mñ%cc`p%cVO$ pyKȥ˔pՀK\vtd,X \e.d\v ]2́;R6X3.#CE.ˁK2PrˎKp9lo"YFdaHx/:솎a,#)# aFX vca(#^(2"AF22DXO ;c1rٱ%d.}`c1rٱ%ݓ=Cr?GpQVv&}{Lm_.֜#͎?En_e3=s9(oI|VfB~?hǞWtNT酭=Gz2g˱Lّxwh_q9ͷۃ}endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001468 00000 n 0000001551 00000 n 0000001663 00000 n 0000001696 00000 n 0000000212 00000 n 0000000292 00000 n 0000004391 00000 n 0000004648 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 4745 %%EOF BoolNet/vignettes/transition_robustness.pdf0000644000176200001440000001077014272153105021005 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094610) /ModDate (D:20220802094610) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 662 /Filter /FlateDecode >> stream xMO@sAJ ;RO H-z@$TATݵ@q׳@pwΪ/VP^:9Hbl ނDaVq o@|Zy]_\ob5Ey(>|\#B#A*¶^&珫U3]6Վ@.3𻺾ˊwE*Pk07}67pgKNGkzܙ=ڵIxg\I3{E9xa=pC@X@]#bx!˥H~,Ta,ȃnZʥ_BOcyT0~]inic^Xd Z8kbm6{́+) fF́p:^DǾЩ]yWKJ"(6yQLFI}k}v}fI}o&\bͅU)Z+ M9ey{M怶ϛm>6%*h{ot ǥB@&9yެ&H endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001025 00000 n 0000001108 00000 n 0000001220 00000 n 0000001253 00000 n 0000000212 00000 n 0000000292 00000 n 0000003948 00000 n 0000004205 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 4302 %%EOF BoolNet/vignettes/attractor2.pdf0000644000176200001440000003250514272152634016417 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094324) /ModDate (D:20220802094324) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 9825 /Filter /FlateDecode >> stream x]}%;p]>_q฻T Y؉ +j=bwf.U}ןY3Y}џunϿO?Y~ϳ?k^??u]g?~sl Fܣ~>>zƆwVݶUݞȉqŽd;V~+*wyX r/{oCr֥XCqS+Vh5dv5چ>m1qdޖ{dYs_Ђ?fߟ6cyXG+˵\. rFK]\ MXRs.-jEb'[{f1dg=oØ3\ '2&r$.e=M-Qaq0䁺^=!7CJ "_7d'+䉽cCX :#$0kT_!A]-'FS]‹&OߎN>nվ%b8yonPj6 OpT@ .c`1\N;>ih)JrǷ<-oş!t`~b)% Zˋ%$̈!6Vӗ[ּcqj۲eP:.mi eyĮ+ -56,(/GFpd܆G{/^-7膫..q^چ u =-/'>nQE*@ȄB: Qr.!He-Cָ/C܆yQr-W"D&3/Kڲ\hO[pKfZ-9)r'Tg@ .^;WQ_jQs5J[ ]MQw)I&'\+-͒Vk)n^rK1ɉ5|rv>(OE[NMu" Klp|o儼H/ҭ&N,s 'VB.x yh%ص-.nGkG˳π0I nXX߆!.AˡCF>GKh9ʉ*x_5|X˼BW0շk;˃]\Ke9-oЖw<ˁl.뙘7_R?%.;r/{f9q-1kXKbڴ_bbV" "ƴDP*_7#`nb|nu$xbUw e\,DCˎxW 5%U] pA\E'Dkn6ju焉_(Z +c1MD9k|sSAhϻKRX`6fKAn!fBuB2p &^ fϯuNW߫PTߤVϿ=|~4͕|*1iAU 3A]n@[0F}L zp}c8\xuyZR _<>P6nrie,|IG&(J#y~:ˏW0l+ `TbT!ul憄,ڄyYn*jݞ&UAH#'JR幦4d^tMHGZaЄN-uABa޳cńgmX$]+0W2qra.#:K ƲԖR ϏZ3ϥWUֶܝ̴0D+B$S`ڤԁrbjz^JPO  }ADX2qִ7 tpכ1,@"ڏ1=*)<0D>%r|D"KM<\z-q&Uk\兦&Z@BBB.!M:}[⍪(XEL\*T!?2I״HTc|54RјFT 2a|jg[E1-UYn!Qi#֔D@ؒ`sj\[ބ"~&k@,9Hۤqō FOG"f?;npPSv{ |I*ԑjIgF)מ%l|bE=o=V.9X^Tήx 19!_3w[5W[5PPI,^#/Tzgf֑NzE ŋ(Vs;D?ۢӊźF ܸvMf)?bjv+\d rz:Ir9:}RG{v{^ý}_`dv-W`LmɩiK_1+pD6J̷1z ޾5pDm“|Aȑ=#!́Dq s5 gSdNj?A sE9${'Ɣ75ȔvP%zb}3r#'+t`;xt^߄Y+5>U k@?mS2seFp}`/{(b$_gGܴY;\X5)VSbղF:HHUpNjOX3NqX:ݝ=/@@kP׈P`]%ǩ{:`m&쑟gʮRGuj'RZTqJuݡ`! cXb+tKtCWŸNn2~CyGB?ɘ?P[sԉ=sػf U_m_׻).\l;?H$Ons:[>o)J!]j̑`mF\R.vs!KvA\ypu.ۥJq'/SUVu+Kmܞ ëcWrZŸkw=(*ȁraY_=Kmܞ r-Pj[3b%^HJ+mB?𯨭i[)ؽn[\,VKoiNź"Qp*-rV(a]K7RYnvs99~kzkaph糧0^rR 9C}#[Kmܞ "n朆pP;~)KsU }-m>w߭{rɥUne?ܚ" INj)?$YoS)\"*\j[\]sA?Dc.߁2V@nK-뾑bmrɥUn%m!9 C%yr]xILQ~'JmB߬l{ dL6vR*2BkC nv/]n78"7nfm 8m_徙BmrŶܞ/ndlW()'*Y[9L}oX[c\rm[sYH|kzA ѾU50\͙hQVEPUMkT9yQޚE2%V/jϟ@gX蛵WۺJ $72mַh3k{֭ u s!\[_)֞Q0yKTNUIJaYeYMʍ}S:HAIUVU$\&)zU(|oJ]j[ |HQߘt5Gz+>W oV.tWR=_ks[s&h@/ oV _VJ $ 72Է Vȫ@b<#*3$\3xVߘd<5Gƅ̅j(>̘٨w H]"fF}c.Q}22/gcssd0d"*ڳ )&c}\fc92e^W])1e$nsD"m5ݕ IiI}`ykHRQ ͔阙AߔN9"XԶR*Jr\391zk+꾉R }0hiƾY[9"DUK)֞05fsH÷TX)H0އsF+k$LLd[rL԰RCVH3=G$(J +ulIgY}c.M~](A7srwqVm|rIʶܚv0epǍ25xs(ےgq߃.j[\Vm~P ׸֧cJ9^%Ju~maV;?V^Yn%!os=8K曏eFA-( V[p-u}lK.rs.:zdYoyNCT{`7);aY*خ/w|uW^*Ev~ܕ,4h7J/ pR`/NXåev-qxLdXd,./gƽ M hԥe+g3@])6y4J% UY) 0'bDF'rO\ XR~GgU;u85J% UY)~Ȼ:cV'_ /F6BjDw;ہ[p1ainU7L~~6\x.Z ^+cTҰ]UG(,~BlW%6o?tc-sF8Dہu#*Bcו4$#3D(C,,Cb]V0P[QjĈQQWaRIvUV{BÎ!ex]+gwcJPC8J+nRZ#?^GdR)*lp-g0!բa5x4+*1"۝bhNkt.4j7j_T(tH+ǔ8@>AND j*{tSv٤-QplϧƆp=ІnW~3zLJKP` Ǩ%a.={C&e4j܎ƕzLJvpp6z@߆_pp)N:lڑ^U#Wc9v>вJ(R1^`U;2ꕉ*xlWe>ϲɎj֟T}aN!2NoNc8s9&K%|^!Y4 QiÄ[OͣR&1(hphTo^(GUK8P`ң oTLDsbNT{E}JK޺5ߒAs)G%ƭR5kĎW&ƭҥU֊yDe%CL',Y@iMRSb1 l'BҨ]"No 'ޓP8] LvNܦJTȁW&4C*iHVY+a x`oQDJ R zS2hpXP#? ] @|VkK[2@aIHamNӫ nӽ^} Kv- ;Eh*Ubغ.5vJat;aTҰ]2 b"ߒV9v&Rp nzLM^LK% UY+#-&ɹL?y\ vJF@aW$ϣ Kve )do==1X6eGS;'`DbXK`\*inҜz=`!6d%ɩ WylQ(N˸7U?k:,T3'_f/ שӭs`cUd.xӧP;ZpFߘg-|v8t:Zp64M{hANNZY|q)5Ϥv0gH] LK)ͤkQW25mL?KK= )ss).ZܒWW"z{2Q\.;]5g*Ed8#]Ji^8 H2*vax]J3 Z\2lW /RJ3 Z|Wo8HlX#QR! ~.]IK/I[#ER" ?kܮaDfTO?kCLp`ۙL+wxD굆ة,2U:dcSښL3d]`jSIR%f &!JڬLhiV×*3d҂6+:Yo2|'Cum_&0'ih}v1`U'>Lz-1v@ 0dV*_<^Y"oخ5LPQ%ܑ$Wv4F^eL`K6Qn3Dױ]e˘@ՙKrS))xj⒬b*@3Is"<; fNWJ,ke2;|)2DӭLqYG&{_"ٮe,>sDqs3$EL>yW&W<ʐ˄hهBi&WK<յT)D/TQ `ѷU]C;CN2z̪xɱWߋG_^[?gqr3[k!Hi&7cu'j}#+=?;0{K혧?ڡa-grjWTvy]q~|O.8~Jrw,;W+B ʃ6a؄? SC]'6aO ޟ:B{0F k7ˆ)[[PM!čP^R)kUg +ǘ8XO # kX`ٜ@'ֈ})VXX)$,99GdX9Ng(>15$spM 4usg}k]Zc U`fI枣PYgJ9̶Ps[s\oP`\(oPsx~/KQxk0y|>wKQX`}K9,8`(l_5ȿ@`~.н`=G!j[#@r/l~.=x#3pc~=GO1Զ>(> 5?(n[sQLq A{Ȩm}SG3k~^Sm~6"&'ezVMA#3=Mqs詟}5rUtzF3íRį̏,Lp a5G(0>ADGz9?qDL.K(Q䚟ohjEF?oՃs}!t=UDu}JYm 욟_c=$Kh8ϝ{t]ѓeK䚟;wS?xD9~ }:xu>.3?(62endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <<>> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj xref 0 10 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000010189 00000 n 0000010272 00000 n 0000010373 00000 n 0000010406 00000 n 0000000212 00000 n 0000000292 00000 n 0000013101 00000 n trailer << /Size 10 /Info 1 0 R /Root 2 0 R >> startxref 13358 %%EOF BoolNet/vignettes/pbntransitions.pdf0000644000176200001440000001411714272152742017406 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094434) /ModDate (D:20220802094434) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 2282 /Filter /FlateDecode >> stream xYˎ%G߯%l~l2H@2 ^|-,}9YcLOtɌw푎ǿnٿ#P|??ݾ?~8~{9?3VG;sߏx㖎o-[Ծx\.rx3eb&BF-Bi-uC-U2Ε6CY`sUb!ˉBEF}bzӍkS63ML'h.s Ǫ#8J]<0+abFBKaE!Pa^[M8RCT08(=tgx?eip#ah .*WP@,v-t\ (MXeԆ(G!s$(8\F Iw͏nF k+4iι}Y! 9df[>ƕ`B2B 6I!v_sH"*FFnvSqw9Չ8xt0_̞S^.#Ln2[0Y@6%{{.Am=B1{DCp`LWǓ@p9E|˫6ɻt ¬>QX0 &@m͆DPxLiѸy*m?a K^7S~ѱ?wP":P"i oNq,5Uh%4 2!"/ӠAa~)3Dp0{_U.G]$JS]%7^ǰǏ+T/g/|U3dU~ XlGXwT]n,`$B/o?qw XA6o^HdZ4&G\Up$j'zX+Xrd&^iK(4jxr/7FmԾ6/X;e[/}% 7 xhL3ê#5nC/T}7p2ٛZ+ؼ 4olCFmg}yz]MCkiCrj*x^/yrN+S}y|_lCkjSgcP9},X p,ڻ3s \H?qM)]u5Sk}T=էdFpS?HW2[ɫ9-$}^Jow_јsܯ+E"I暢J'~7Fy'Թ +.QL5m+*`z|׿ }Io`~{gol fE\4+97]_q>Ezv[Y1WbNeiffАX=\'wendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /BaseFont /Times-Roman /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000002646 00000 n 0000002729 00000 n 0000002841 00000 n 0000002874 00000 n 0000000212 00000 n 0000000292 00000 n 0000005569 00000 n 0000005826 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 5925 %%EOF BoolNet/vignettes/biotap_sim_properties.png0000644000176200001440000025701213277247010020746 0ustar liggesusersPNG  IHDRXiCCPICC ProfilexWPT]9n&&A@2& I$@PD0"`EDQ3(Qy曙q]Z_{Puίjo#Lf, qI,w;K @%84i[{Z0Q5W2eRЯega n@-䷿hI$dBJPe1ܭDJ$ %p RY BDh=%42 @ @'@XXbhKPrP&+ @) d}|h -3@NQhJ3͸m@(l<`e?t^ ņ&R~@aP50` @(B:l]Ppʠj,C4 h.x} ^ ~ "B" Z!b ;!H#HRE3H҂!HA"dr:jEPt2ѭh.=Vu6ڃ>Eя,Ɛ0:Fc8c|1&&9ĜǴbb`b>aX,V5b`l6[==c_82N3p$\)w ׉f< /-||?A #!$F D"QA$zci5#8q!šđQQqB&\ItR ,#uɎP6r)I$P(Y)ŋOM\ P>s9Ɯ x<Γ78_p~p)pYrpm*6fqqqwsOPՄCMR<$E[0\*6aU^q5iex ]ii'iwh JqMDLrjz f(-++!T--YOP8Px9>9q+bfxQ5Qhh1Q1+Xb7ދs_#Д!Q/R#&#+Y/koHRRRnHMIK[J3˥{ddK{;~$843ӎY\쵹EfE$$i$&M&[%W&/\MKe>ڢ%VihZPm2 I?q=S43=s(4D;;(c'sr2sv8cyg] w}ݒ'=}S~c@AzX}aڞm{X$XYn+;DdbiXiUr8t0p#!G5>z,1cwk(o->{be﯒_- q ~ssZ#f#wGFcLC{|RnSNS?}){/_ZZ}3b3f f9:0:gAt/_}?,mY&.]QZ:ĎY/ e,_Y/ e,, fЈ|}dm= (@ȃ9hw?b3*&04L*fy[ Nb,\Er֦yxI|X -(#/$%Z(vI|PH7ӑPQRWiT]VدJ[J'TZo@ԐaǸdT|x+SZۗuz۝N:wq[.ap JsM 7A`zVYSD\䶨=e1bmtRXդ䥔-Vb6t LzXvr.6cq̮ݓyo ^tJ">ZvB fEeeGSRj|k e=WU.e_>{l`5a7oFފӶ=#s˝컅]Gu3W1jL *e׬!77=b02=zv,f\k|i#& >><Ӯ?}izΟ >˶l6 .e0oHp>!3FuAL9  rĐD+ۉ#K]ᛡ}&0/EM%H^q͓R(UPnVUT8DQ/_ᲱŚx ҖVE6 vt'ugckWg7A$m^y>EWm xyckPG𑈇MQb6m򎵍3JPbl$I)z[ ioHWPȔΒ.Cͥ dZ=7_S}߭%٥%>~1k}N0++/W-VהU8{.7b /E_>rbӺZ M[n_mdyRh7N׃؇[{s=.$k i3/Y&mpHh wm'm>Nt6YЗ/_ۿcO9˿K~+l6 J` !B !DqFJ 411X~l#.!b9$o,G5}̃gO=/Z~#r]Ll _n YC9.qB% e # Mm-.)vúqz4͆yF~J&]kik+-V~B?6޸!07x:;&,+|Ca$_䷨51[79Jݏ?bmna$%&&'IMݾ%rkښmbL,Lj_9 ;vص'\Sx}"}KE,?4zDh|ٕcʵNTW^&h <]R{,M]7Z6|ht jRpk]7n6nagHw\^Gr ||kᬱIBs6}:^H C@@ 0dqHЀTK!B#8@ 6tل9Jbǰ8Q ^ X*ўXD|!Q1K2'^ȩn(%rS3Kw UG 5+[hGC? %""7D=EK$KIޡIIݗNQ=&-+ߧP$4|FeڲOSZcotu_3h4EGJJ=wZى|{+x*Oz`N֦>?QPu*whknu;5*ݓ/@Wb3eߨ oP|8eų sE5+6QDv!oQ=4b0s8 .o?A&30s3Ŝrӌ3kMTyGૡЦK> V 3/!YEϕ^/c&*'!ϧ@VP"*Tbjj^y-Z:ºvz5OpF&kjLY|bM񷭴ZgP8Ra:3 g7';C ¨ዑKI_`jnhԒڴU#BZƅ,9;]λfy\$/Z @G[;2cݜ~AD==!.|ﳈ3f㏞e@x?y*c ib%{,ҖaTd"-glXE#my1JoJpt] GpHC<XU " X= !b!X@) ,)#B!  b,č9?担`iiNi.czXK) ktV԰XCk-L "qct+)"HVc?3;L t7x*w/o-)|KUs++:2*ndƆŇҵ54 e\}abKGD pHYs  tIME3 IDATxwx?ۓlz'PņHx\ z-H^ '(\\b ł 6DDJ@H&ͬ&= ;99J]{ 6tG#@ @ zUϞz=?9묞SI$<$@  $j5:NV:nݺ5553@ @ B$vhTڋ.P^@ @h$I"!2vՊP/kkH>_J\j*VJ 阵%X>?M!EGaD}Ҫbޢ_u m ]ӺsQ`RC;@ @ Q}7r ꨩW늕IhC|,TT9Jqqf3]nN zL7c2bI&m{T*GRyR coW:X2IO.98Qvbjs9@?SDgtL=)7O[dّNrGI1"~@кjrٷUG鞒FCHj88.յ[ dr @_J(^J s_G\2jf/O(,(ae A<@ Z)//b0sF\ڿ#'/ܞN̸GY1%EG;kk`н9OEGgFXVSfw?y~Ư!j>~z3wO> HE+9jv#ߦȝԼ~穻}J$udGJH7 )xx&'1k""o<7%9 ncp_i9mU}&qZ _՘\/2;~.7`щYq ?ډO1l+>Z΄N'ɒ [.~UG_ ЗڟsIn~:jjdE,Іha G.q`$rv̙?_ƈnqO, ^^ůMDMF4}'<zQ*?la$_NNϪmg,BPʙ@Nl~[&=D֛K8kԻ|ӭ<~Y;.=hiv`xʿ<Zr/]Rӈ1(Ytt V: H @ h "Ch -FCL [WZ0R 5D-Z7*MB,8Tmo[vPiT4VxL!ctqQj4:4:@aa*9itDI v@ h58ޥ˘t Izv yLb{S3X3q7+;ź5hg7??46JH~>Z a·?>@Ōm<~ʫr9k0 :9\\G9h\ -?9Yѭrj38[riX5׿7].{f4Kͮ.wJ)|&,>Lyl'JQ9EOo;񁗘Ñ?F3sUė3դyDk0'^LlX53uZvzG$jl6,D 9?¿bXy8oc>xfn7jLppdhy1Ѧj:'>SMq8p8L, }uÁ& p1IU3rfv ''VUp@wӃXLT>' ZґLK-h "e.@ Av>Ð q b*J3He!PMF ;C24VhP`PY mjZb:b5zdnEoR;r6mDO@ hUHԚY6:˱= /[O],9$ mȥ 3@ vgݤ7<ғAz~,/~@sBHY6Cnra!26]sa[ :Kq;F~TD$$]_9q1p<蚢Tf8LTUgȴRjv-p;]e)ԕY 󂙾n5s38j8VZm[QQ TזcS#IFr|kRGs @m-VC:P!!!c2eQUbfEj,:νFw9' az%YqIphvd8Q%T@mFrQ=QX1FL%.rgQWS&ufew+9}tjJ΂VTb2x+>KΨL*Ak =ıc$Cr"$%ArdX * (./C 쁆6dܼDt:gE; *Lj3{NO_bbzb5Di5hq^| 4Qs}XWߗA$f`/%V:Pg)o^"Pdʮ[zs_ϫeu`O{AIzRx8S$ a!{0/x%%?o]7޿/Nq(@EnqdsKm'N8g;E[e4)~n Sd@^ihK}HUi-҉VK9!HIѾ/2^Y> b6Kx_{ [p ؽlS8xcN*XgrCw[2e(Ԁ V^˂×0~p 6I^?塞Cl^@ 8"C±75d@R"'8{ рFQ9pbj~ǭd;g:32Ǐ[q萻_@JIbDcPѩ%J1D)Lj" @*Jr舝;Y;0 {>ϼ>9w"">m =7=+hX-| DÌeydJQ'^g0 k;=weɘ8ᦉg#|=OYRi {Xz1Xx.騡d}ȳ'@|'ë3xmYͷ3Q&??c'2"GkQ;8/|7}{Fykf], '*!cttp8maw83EVD1ᳵf\nj{?ptߢմ97 n~f9WwolY9hjA|ns&L`ۗݧ:ײ*H@ hz-9$OHN'RVUEɁXRNUUj:1u0}DZx3㈎ՁJEB0'^B]!b~DzR )c@1RZZjz& %AK%]6FdRYRDeDLZ616:PG%d8EǨcۑeHs?'j3bĨaeVԕ{L&|z_p5ZKVc]0ħʂVk &FCiLĒTۥ&M[豗ǑMuPטs^\}dFQvU>:icNiXW֖Rp6m08X1,9R-9DYK)(2LҌ*,VpX 6P.'kN4$&뙁->UծM"ΠA wie @ Zgƃ$IL:mҦM̙sR.X$z!8Ypak?>k׮e۶mуɓ'GJŘ1cXz5,rm _=6mD=\̙SO=b>뭷khӦ z^p۹=_8묳(//G$|ItBBB^x!۷o;`ƌѣ6mj2 ']G(xs!n&hӦG`0O]]˖- Z >'+?{ߦW^1qDW@ @ :t3fo믳`~iyf(Jaaju5kK.eڴilذ]vqQ2b?|:w?τ "jرc)((૯r-s*˷|ڵk]۾O[.[>łA駟rWsc2ӧ˖->r IDATҥKiӦ III̚5~;-[жm[?|8 ~E0BP駟7|5u҅l~嗠 i, ǿ&Çϸqx饗\‹@ @C#FFuۼyk1c#F][[+Fgu믿^4#F7neYm6(?dggO>k0a|E׮]{GeYF7ʗd,˲,kN1b|BoX,^{5[~-q܍aG@AAӧ>* =cƌ^gm0T"\_^tET*nJNN,s&|w-z}~Amm-III >˗3a{=W_}Z Q{.?)#r￟n_~sr%s-Fs䅏>cY~~>>`iFLLw>}7o$=@ @p`493>_mp(/!!Y.JR6jRRRZU!;3g駟6*/cbb0`[l!33+s=ywZdYf|7L0뮻%KxlCl2Ə^w s>&&5T h^s5tܙzK/ٳg3uR -IZ @ )!24Ν;)--k9i{gʎ;4hqͩJj։rssի˖-cÆ _I2d+V %%)S`00`+V/o1޽+W3p@6l̝;>;vЩS'j5_}]vk/aÆy4 ?o2 D(gϞ|<#|[B*g2e$Ryj۶mtY @ $-җ`0pb R[[KeeeЙďl6T* ⥗^⣏>b۶m\}TWW{|}sN?l>;v,+W 8T"T_<~CL4h/ . 11PT2m4 ]t:Ǝ… 9ٳ'9s7zj , O>$_߿?| ;o&'N<)eP#kfٲe:tI{"0(e[PPĉyygh4-g2ey믿v Z~=[n;@ I& 42Z^^l0d(GGGcƌiO>qM|ؾ}{SSSzKΖz){Y&(((U*|wm0_J$Æ s-oe@^`AM6l'M$ 9**J:u|]wn۶MEyB=zV嘘999Y~=ٻwܣGu& &~l27c6&~jrbb|9ȟyZ;t _uU?킕2%6sy&~ ;cذa;vjJKK ĉ2 :B{FFF/g_e>;v,ռ;8qj@ %Z\d|qW˅3 "@ @ h@TUUp=gN)z2@ @ =@ @ Dp@ @ H}Dž@ @ 4Uii.!@ Ɉ@ @ "@ @ D"/@ @ =Z{N8A b_ |)Dn> ?= &~|嗹[_ @  '@ @  wUV `̘1 =s{—arg*{~gQ("[/Gq<"=z2~>}zԻbY E[oV{R ,[U㍯d/|=POnIعs(/֗>yž?on8U8}z*ջ@ XVv;,R\W:Js;_ߒ$Z{/#gnoRe>|wTO\\\ݠUUUV^3g$??QXnFu=Xtx&Z~Ν{P]mȑС;Z.1y$\?@||k?-kp ڵ˯sarrr7Z^ 7߶Dn+۶mˉ',o2֬YXHj#B)//_$))hꈔE F꙳‚@Y AUwKIIq%%K0a׺;3q/^쑤JJJ&UW0{`7ʾ锕ǟ=rT8ʾ}tEmMFF:W?lI{T*U*qƱrJ\C%o{' ??RSS=SNum3uTh4M}uSNG%%%ŵo-߮];L*2330L|ל{l6&{&Ry11ܾ >YhiiiDEEa6h4l6zKhK#r/ri* h~uȰ`?4i֯\/@7HC'#Ƚa\摓ky'8ovq^DGG{k-QRG C=먓JKKIIICx())A׻|ْ! .VZŸqUF $>iVV555wyy9-r-5jTmhOr(2z(up,6;&w .@,YޕppGܹ3f}L$IWJ#55>v2HLs⨨0aYn}Ce5-T~~-c׮]ο_.Q〽k}_1@hPz7o~KNNv l';M&999dPe;OlCj{uuup``2 $aZB2<›ӗpݳ}vaq70xhmji @Gyk׋Aٮ]v=P6w=ʽ.0xl=<\!D"!!\1B}$}:j(l-[xXn!b>mlgs8f@ D\s H9{d|ǘvn]q8X^^!۞H299P`صk'K_9ɖ-O%Kj |MK(𷯻._kPJaI56***>Ϟ=iӦ5X\RHJJp ߯}T蘖F?q[laȐ!TTT499s̺~ __j >ٱ9Q!X]_s1BOM޽:ǻ|(d|F5#>|5J>L~~>ӦM h_p{N}3g]RRr1LCyy͙#З1WC8a;|.tcHK/SQ^^κu|hOXP|ır@,3ISs *@x+Njɡ;r8Ym(I/'s0"HhP"!C}4Q {n2w!ҟ {n"X Xt !LJJ6C}8Dҧ4x`6o 8'T4zyĻ?*XBdh[2ik]NN555tؑ2fQxY?p/,aTW 3eNITTxW6ү_{M6c{ctuj˗7^,\B˗/gE{]ukӧM-YfWRZ=)q*++=%b_R! TtP!08{2da2HKKd6yPUU<3fݟ>}zc1f9l]hP˽}r2}kYnn.ZjׄfG,D:O>D cfΜ-x!_C7e[e>@+µ2`ҝ***\h$!!u {壏>y-[0x`BsӨ j*7 ,pȐ! |[6%z\+&Xqp~ '{=vC`8=Fll|;]1(l?|U`w<K_L:/~Yu JEYY+VqB/D'??Cd~wʃwƖbK{>ʺxv5w{dpDFfMIId6>5z!7ki 445̚5+Y7FMa@4J`SwV^ ֭[Yh{s8pl9묳Չ l6Dti|AnhupGbb1s (5=r/ވjJnڕ|mBl +--I&5hrׇ]7u2TO7o̞={O>O?uQTTDEEZ횜7e 9{XmtrS7~=x7ŗJ6wD~}=&כҗ= a2i;n1F%0W9`*OeXQIeWc] yJy ОHž@Pp8sD۬,~G߶1dl67)ǚzVHh OYh+A]=zk / /0}?lt/OmƂ[Iƍ4Bk|h798q[ڞ3fzZxM 4l6#I__657'P9z| ی3UVQTTR;b |ݮz>O<6'wQދ!P קֻ?w1W9?Ő+V0n8dY沂sZ] @p $pz3xbhâvK,wرO?ݻӧ۶mcSob P w\1nh4r9wW WV$T*>]6m껏͗'uʃǐ!C\*8>w77qS+[#R7F`hl+")1RR{=.rg¢O{ٵ=PCn֬Yz̺Çx5G9s28`#6ls[={p}C zS2}{{nS$QEΝZ&??e Mi@#4%F+7x~N\_j(--eƍv T*>(߫Wv5/F熍7 81*ngڵa )P> L"S_֬YCaa!5557rE( He~;t>)BC0m/@ M$ 8OqC>} %i_Z,W:6my_<3fSjN=߃ Ac 3g|#;k,,KDk֬Y̚5 Z" Iw&ᄈZVq7r =ښjxp(/iZ0 <>"Mi(噓y{j[.qa|h/{" F}`0ԓ!SiaONHXpo} 6..xCOOJ)ևS^"(._9J2i6 MRzǏ{ESQE`h9V+Khh3jjj\;w>O9Wank!6BdBU=q {;* no'+{ u-T_7jZ,F#dǎl~ bccX,~u6֗-mO8\}^!:?"5{7|:NyT_4WL&uBum- ))ج&czdHH#19^dV+i)XyF7vS$b̞=iӦ^!//}puU/rssٻw/z`0PTUUax>q'OXڵg}7}Il6SN.A sKPYi87"25&]0͛*3EeSٳ?4Oh4z\$U?]w>ҹt!{m 4DJ IMMnlEPPz.hBCPE%*nSdCiT( 1x !_~h stn=}ff&Rz#Xo*e2g@ttt)FGGڡآ y:RDS Bm/@ a?jD'Csbb!۶m{|y VcOs2[Ae/4Y"˖'TY[Z`YiûW[@]Z^JHhh7LjtuVOX߿ ˨(|I^|_ Ph*"CsRA#EK{w„ ~'7tW8# b"4bro*‚?!E_E`oo CN ]1ꫯe,[Ǐ+>}mbY "CG'C0?{L`!7ef)՗׬ٻVPDQDE\Rsiei@&evݾ^YY뾢i"jin0 tN3, x`8s|>s|>ꊌ3޷G^Vez'ob޽߹sl([eGȕl̿Xp! f6 ٳ+'% uԁ\.Bmi|NLYٳgCP //, ği XY?ֈŧ~*?R gzL?%Biumޕ-J*wH= 喆U嵡,uֵ: ;1_Qƺ-ZP{СC{n>sxzzJK4 ֯_/l~,'L&+wxY["b2g̗k<̗ʦǞl97{W(8:= 2JGEEY}ɞ@1LLjwT5"k?YC~}\*FF#5f& >ى6m۠H H 0DDDXuw{i!779СCw8`tVXmڴP#J-.[bKfEݽ !Y.Q}/YVi frkCygϖ9tn뇄K tpqq5[?'*LFCe>'K 0h0]nsR^ >ey&6֫ꇪݡm:FZGܧ>:NZ\ayզ<՚o͗c{^o+U*O+ 6֯鬮DT˃ ݮ\VLK˭ه>-=KҗE{eOeUأ͛'j(+5:R>'%k?'5:bjC7MSM,`8pd,}^*6d0jժju-=%YƼ,99úϼ /9uᵡ&&iMKD/ٽ{¡qqq)""""""""`A"""""""Rs2U{2]0@DDDDDDDv!p """""""zhʎ;"**9ADDDDDDDE)xwDyUDDDDDTd Cll,s1|r㵀*P: &R3iDDDDDDT-^Zr2 rNNNpvvL&d2GP ~~~ѣr )))+7ݻwg)=ԩ'xYYYχ PTPB\\BJWWWdgg C^^ڴiS{'NѣGh """"""z FxyyQF0jh4h40 RBR Z 777 Pd˒d2 $DDD4j0(d2..h!ɠT*R JUj?rKY#Ѻuk$%%rD/1oKo96ƩKyz0ӣ.|}"""""""i^ d2<==yLP999Ɂ0 œ =J8;;^^^W4Idy ^] w2x𪫲'B5\~1*9FIAlj_g3qFpSW2Lx1~z9'x 2-Y3N#F=9;YEֶN"""""""ir9Ο?R ///TRPThР<==]*P M` EƇ;q %׽]]ejѸ GU F:F|&^75UᗳٱvDƀȼÚi(q*tnQjqHUquBHC' 27'AQ@&pkD '~+CN!pvK=((4 +W#grZ(H 1rVgZ!F,Q*d&{d2"55Q`?QkoA""A""""""" .d """""""`A""""""" .d """""""`B, """~A!&,%C껻Pajjcq.qO#G'*=2 22QkdW' ,D"zd """"ѱF`NHDDDDDDDv  DDDDDDDd 2py@T0@DDDDD3Q2󁨶`cڀA"""""r~>| z1@DDDDDUbb)L, """""{Ҥ9 ə̯ |A"""""灃-) [ ,Ma~=@tKU/ 2Cm  ̗y ti<+=* 2m 4 /WYQ`ݼŅb+ .ADDDDDv D DDDDD0Jy#D3, """""GY۟<&@DDDDDQ  DDDDDDDd|wnfbVmC̪mhYW׵:$`~ZGD Q $2uk6{o\Pl4F.uAp`qajwM&U41@DDDDT#BGtG?GtSȾ_rxT03y\{dRׅt`:'Men}B!b* a# F -Fclltjo+<]Ae%* Q .-  k WHrJ? l;)<w@CE1@DDDDT A"i Z Bjj{ Sx=PQ%2oq- ՉQ AGRl` DDDDD,`X_CӡYfencTO_pBU%p80 \,SGx'xk k׮!?? 6,!UhǞy: H@ZVh߬/r22y=5k"Uؓ(07?' 7F@_d+C՞Qm'*HMMryU՛!M""""j`|TNgODd8_h,` 2Uc  h<"" `0 48KUGшv0Fz"L`(%a4!-d """"F@F 0! =Dr\ %!1Ph4J?IY֬Y+W2#ʈAk1@DDDDTMl;ѣlUm䥗^ѣkdy۷w*]\\Aa0P%EpADDDDD( 6ʹ#aɒ%੧rhZvիWo8$ﳲ5k_G}4mT`0ATż 2= %<<<йsjG? IDAT|HG||<.]d|ɼ?~<{9|=z4Yڨ1.!ɤ@\ 8pQ5 :|}vv6/_N^/TE";;}1Fš5ke|Mlڴ ;wFÆ 1ydIF| Df0ovbb"뇠 |_|6mڄ'N ,, ?۶m?f͚{X|CZ NUVUxLլ ã. #,-HHH@~{n(JGPH{jHKK~Z-*fΜÇK˗/c̘1׮]î]xbL2>,VXիWK̚5 [lA\\.\ bǎ7o?%K`:tfݻ|z-}@-͋/3:NU59#Q-UP1PrqBF8A Fܾ}iiiy&n߾-5Lׯ_`ٲe??Tcǎ!!!r WԩSvZ[':v׮]q)ܽ{L/"-- 3gٴ_q7n:u*,XyaÆVQid Q-h$lRfNV+zƅ8A $T'~ D@@TL4 _}|}}qqqsC|죟Ǝg}Vz|Bll,EUIÆ C)SYfx1m4nJ'N{' u-[ĤIW^㨴Qͼ~5D*.\(DEEaƍe=/_ѣGWDDT%VQq@DU:U4{tz$ (=zNCӡE>`ʕxͶrT*z"g =ј^z ظq#222">z=nݺ??r't{Ν;W999PiiihԨnzܸ~=Q֭[CVCR Jr r\d_]צR{=\?P?(w]``(k*4hwww|c۷og """"t """"""" d """"!Ξ=L @or@0Omڴ`b͚5زe e͛7Ǜo֭[W;w.^N:aܹh߾= ؈GAd "?~ \L 6f?zzoСCY9\, DD6ҥKqil߾7n1bl޼?cbŊ駟$uعs'fΜ bvA@ztRlذ3gĖ-[p=-*HMME1`R=zXDDVZnH'\+8`>7ΔJ( f1@Dd+'''@Ϟ=ѭ[7Ii֭W\5kpBT*}js޼yhԨ6o,T1x`Wѷo_DEE1Cȱ.W='Ap|&L@/*M-=J~u\eN F u6m ă'ObӦMػw/5jT:>|8 DTTDXI2WDXy9W^ѩʃ b`0jqY.AD5أ@Pصׂ Ѯ];@bb"._ """"*{2Qs]@HHT*'Hh4xg0f;w)))w̙SNt ( 4j5kPTT &Ժ<)yţ;G?իqe3O?t?yؓtn10 *,,zN3}-:wxqٍ{KII \\\ju ׯǁ}2@DOؾ}sUrJ'QMR={k׮MLLČ3p kҰE ,~w}&5{I&~GL>_5BCC?6ZR<͛7װm۶aڵHJJBF/#66VZCaa!w9sW^)S*ܮ"F3gķ~ ш^{ nÖ/i&:o߾X`Uuu̜9?J%f̘QP3uh4 CVWXޖgͱ&Mƍ>ڵ+ϟXLhĒ%Kj*sȑ#^~ǜ;w.vڅɓ'ߟA"ݴZ-nݺe} p\v'""#ooo ={6nݺU… 2e ^}Uddd`ƌxgѬY39stRL>{ŋOԩS6m$lق߿_ 2^K,*k֬t@lذƎ+ͥtM_0}tEUd֬Yزe p=kh׮ V\=C ?!M,XgE`dffFFFF_~%-Z$oUQy[s[5JMM fۥ ''G̙3}̙H\vM kErr2^}U1Ǐ+ DTԯ_LHH@hh#11=\zNx XDDT}Wǜ9s~lذ;v4['33  NqĠ9bbb[o> -Bl2 {Add$0m4wSn:Ұh"#11t{zSNŬY!CH5 6olۚʣjxb̜9Sھf_ަFx^۶mñcǬ: (x^zY]^pi#00-Z(7m~~~ BaMy[s[-DzFhZ,\}o  k> M6E~d ڣGvÙDDD&0c /xDDDH!!!Jwww^| Ñݻ7d2:MBL:< t:v܉ɩt޺u  ԩSiÇ۷oIV2mW{i˗/KOyۥYY*/1` .࣏>i5]Q[[l95Jիh4СC_^Q*Y%o}2 QQgܹ3.^h6-Z\.ѣG9r 0` o&j5"""vZ9sƪ! e9w֭[={O>tN'''deeaȑv/ k'*}}ؾ};cѢE? \nGXrяV]'''ڵ &LH6m0ydiFM"JX~tĉHHHO>i>0~xlذGA~~>>dffW_߿?RRRoIc뇯={Dz*unnndx"0sLs8b;ZԩSvZ['R6֤k׮8u4QV^ׯh4BѠuVl)o{?kcǎ?-[0uT_ǎ;`0ӧO;|S^=L6 }Y 00@DDDDTeggcF@@zQFYu^SN0`6m bŊ 7z!͔߷o_HYfx1m4nJ'N{g};S| ???<äoذaС+nbjժUhӦ 7n#G`v/o{?k /mڴ̙34^|E;uE߾}qQoYF8 42^Wd .qF KD51z 㵀mժUA\\!DXI1@Ta5gՑdĬچݣS&W^/MjqRӍ7p]ۻ)((@VVZ gggwG:b;Szn݂_m09J>E6(BܹsՓֱFaa!rssۚgͱ222*Bdff-ߪsNij* NNNP(P*P(d_]צR(puukڴ)6mquuz)TY(vJ%5kVeey6%Y?k0wvvF&M|G.ADDDDDDDv  DDDDDDDd 2]0@DDDDDDDvKrrr aԩS0 ܹcu8l:u Cvвejs:999,L[Fdee v{\iyud """"ŋ8t222`0T* tGdX~=.^PTWuJ%V\޽{k׮P*GS+''۷oסR`0ТE 6 ...6qNN㑚 R NLƍ#::~j5ZhPV DDDDDTt:l߾AAA7nr9Ν;''jV??? 4n©S???TKnݺ9,}n݂VEXXX 0믿^uxzz"##6l7|XT*877+V;^y@ƍrJeuM8q;wĔ)Sj|t/Y& DDDDDԽ{PXXnݺAVCRCviUCnп7ҥKuGIOOR6HJJhرc2mРƎɓVqbb" ƍ'vJ%1`2>} ''o߮u֯_ &5<ؓ[.r9\ƍ[\ƍ8prrrеkWDDDH $:u <@Æ 1p@4ji&k׮*>|8|}}B0oyիxnpΜ97o ?~gϞ`AYu^999HHH˗!ѻwoiN>CAcƨQ~z4iBhh(KWѯ_?4mTڧmHH<\aaaa^I9~0t xyyJ 8y$:w ggg<=='N <<<ԩmcnnnfeU:XQxxxx'Yb ͛iYqq$''#;;߿?ZjASNAtzX+33sŮ]0yd׸ {2R...h߾=y݊ IDATV[zî]жm[bCpbܸqUuԩK?z,991OP-_l`hٲ%݋"@HH6m ooo 2l+)) ѣѤI2vAP`Ȑ!ٳ' 77/_ѳgO[_W\O?ݻUVطo6lARLzެ!nq.o9990 J_*Ue5u}mn?K?SNSO=~g;wO?4#G*99*+0@DDDDD5ðaЧOoX|9޽[j=]tAϞ=!˥`@RR:tݻQF1b = h޼9nܸN|2BBB @AA5kVn:p1|wHLLDΝFonХKx{{#<<ׯ_P|Gܽ{...D&M ԩSzg 1cƠ}*D=Znnݺh4CEpp0,+ܞnnna^^SUu*==k׮ŧ~,DEEY|:hK~Y(YGA`` @ԯ_GEXXкukT`M0aO5DDDDD\޽-[`ժUxȊ=@.CV`0(̺d24md2\v ucݺu0x",>Z177.]zbq5IɊX:/1[lAff& QFҐkK԰aCi[qF?P<'By=\]]ejK=.<h:gJ???dddARWڒ_-^-ZZW<3g YYYf{k bϜ=M4 RoPiJRjT*4mW^˗&Mh4"-- .\(4(ƍCdddun݊;v@Tuv˓VZa„ pssۣXQ~ك8qbVVVgeeaÆfXF'x 6l///}Z}}6[v<+U/???ܺu 8>~-J%J% fD___.5= F¡5ʺu놽{b߾}޽;°~ԯ_hٲ%dt CjߧN®]/// 8.^2n=/c˖-O<ԩS'NZz_ 6/;wbprrhw0p@l߾OFlԯ… Xt)ׯѣG/틢"lܸQ <>>>ӧF#o\AвeK9udĈ23&-\Pƍ+-cj=ztZ@j* .."rU *H2bVmC\ӈѩJ+Ah`h^&ztj8{,"##nݺ$h~ =iZ( gC^^^n<5Ļ׎h^RiqKAF@)V4Gvv64 ?. Q FHHU5lxzzx:hMϯtYzш\ԩSrꈭv܉6m@VCRI\r( rdR=.~WHە|m/B^WWW DDDDD\ݺu>< JUzUdcq=ι#U"l&5q9r͓ejtVU~=LC_TUYGj"Q-gyAvlj.d """""""`A""""""" 7n۷!MۭY+W1%"b۱c"""о}{Nz}a5&DX 2R8q"Zlk׮!##K,A:uIzvڅK֘QiJfQtܿo֭ xYzq%5"DT{2RP*سgOF| Df0o#̙3v5jPOy&,X//JwΜ9Xt)O޽{cx'q)RSSKM7o_/ӧ[no͹/X矑VBb_}1g߿6l@ǎZ/̙3ѷo_OX~}AjXp!7|$m닼<իR-**[8>âElF͛7A~kG`` ZhG% """"d2f̘@IIIW"??=̙3vZhWB`MoDDB@xx8RRRl>VXX`(ԩSuVd{2"""pQt| """`0O=ڵk'+NXREﻻ;$Z ,K&F :t(>C_b#Ν;ŋ899!++ #GpoѢk.L02 EEENo- qQGAr94wbbUdz~k}ؾ};?{wEUݝ=H $ ,!e"hF3* 1° j.7 p,8_df@e N,"j~>mRUIɩs^z%xuI%DDDDDj;wdl6mD׮]#))ŋIQQyyypAU9r$~)Vtgv @ٵkU?ҥKٲe L>'O2bw=qqql۶_X$髌 rrr0MBZhŢG2QADDDDD3g0j(ˆ$!!>}x 4idv"##+@/2 G%$$Ν;uViժ͚5gxMF6m޽;5bƌ̙38wLLL SLaѢE^YeWu#&& e^y݄Ru K.9r(Qر'N'v,**(suyU׾a8w (J2HӨQ#5jTFDDUaÆ x +G\M'Ֆ^BI.dBI.dBIȑ#|w\+:o̝;W(" """""5ڪU'66f͚Ʈ]>ݺuYڼys}z/̦. 6l?aŊԮ]?<_|9%%%|ĉ%DDDDDyhܸ1|,]֭[P\\̙32e ;wVXdII3c :uѣ<^u$!!ᚮiԨQ:u*7ow/,,d|;Oϟ1c~{ō/22kؽ{77&**M%DDDDDz2 'ҭ[7x tիpBVZUURXXH=~bӦM|w$ڶmN0\a^]_E4h~-;A!$TKlݺVZW^.^$RUp<88gŠA/2d}aܹUwU __ \i\лwo0a={dɌ7N7( """""WXXwy'^eݻ*ߴiS|}}2de p/QyKff&k׮SNzu^Æ a۶m ]vqkeʕK/bh~~tWP;wdɒ%ͦMڵ+~~~$%%xb233)**"//r뫪?#GO?eժU8Nݻh߾=v￿k 0 DZcǘ2e ǎ^z1c Fɘ1c=z4l6k ''4),,EJ0 """""R9sQFFdd$ c(I8p ÇnIZZZuVU_f<裄йsgn @bb"ZYf<3WuM$A-l 6dz~JϝO<}vϟΝ;,w)jժE^=n:֬YS:u?^^{M7u%DDDDDjmo-٫W/ eҥqF?Nxx~@"!J2pj;,X~nh, .$>>/L?$%DDDDDBǏ瞻l{t҅h^usLd„ DFFr뭷2k,ڿ?۷o'99X/^|î3''!C`ۉ`Μ9c~!#"";2{lsN'&L **͛3k,zIFFGL<("""xWn_D#DDDD(8[ 9_ycuui}翖:,z;t)ќ9w6#Fp & yT7/2 ̜9E]@TDc:пӟ=-ZToWxӧqlN8A@@ؑÇ^d.] ?ǣ=j`fĉtޝٳgqtԩSYb:uz-[X~j*'O>}%DDDDD~A}ݷՃ~a<1*83iB6pSh%KеkWqi&7oNii))&ci .7i|b.gY3g2e:w dwa4i҄(6meQADDDDװu!~w7d@` -6lׁ{Ͻq?g9}=h~[ >~6kסaƑΞ7mylaX}*YY>K9{⮄{Y)S1 x<˹r_?is 4o^s'.bӦM|]Ϣ{;Ԇp|AYp!VII :EdA^>!:I Q}I Bq1}ϔdT61-c+<}ɾbX ^eʳpJ½.O@|H:]vAP%L0<ɓ7n.A_2d<{sY+XԆ^zѲeK{n㥗^gϞE~k4񣈈\7~;aaa|W?=STTT9EEE,_7xǏ?VZ,Ziܸ1g&GaÆcccYr%/iii޽{we̘1s=4lؐm޷k.Μ9ގחӧOӻwoJJ%( """""5atڕt6l;xG(,,r{G}DII  N:-B>}X|9WO߾}ٿ?SNԩS9sW^yb^w rrr0MBZhb!((0طoǎcʔ);v}n^1c#Gd̘1=l~~~$%%xb233)**"//*HII{epz-$Tcǎ={C1tP֭Ӽ Xh?0k׾O<ٳgYfUҵkW&MĴihҤ M4wa֬Y͛74h-[xWp'Zhfcذa?0ydyKQQ>N w&Mb >Ndd$iiiL IDATUo>p8^m4'H Tz|n_Zlɷ~Knn.b6/_^ᱻU oԄ =z4ח&MQfÆ q9իq,55^z ????~<LJ_~]~[8{,͚5s#%%drssw8_ܹs;w{sb\DIv.^=D֭+-N"\Iw`ٲe>޽jǞ={}޽{_Q axL y)o뎍eʕK/bh~|"AAA<,]-[9y$#F(uV>l?CGRR/&33".[<۷g׮]| rrr0MBZhN0н{wDUm """""rMF6m޽;5bƌ̙38rL>zGyĽI8p Çn1qdEiժ͚5g)LUuϛ74h-[xWGVV{)ϪE#4)--bJKKq\%DDDDDj>/wHH_)((v øM7|^"yHII!99\v;6CCCٴiǏN:喭 6PTTĹsWǹseܹ^oTBII %%%p8ZSn] j* """""O``juFDD^e_?H|,ݞW X[ߟx{.FAhhoB9iƽ9NΜ9{; EpK(7Cvwp3${-[VZu( """"Rl 6*Byb30Mp`Xʮ ib5M ]`uaF ׎S'L\.,[ lu-RZ>ZR|e!LJ?|!AryG=J2TW^p]Q41Młŋ%LWb}_?՝ ]-jKarB͂ł`B`@s&/晴 """""5B^=rV뗻m0dȐ~N0`ZuNp`leOoUw|kJ2ܨ4|ZŠ `Z,8-4r𧤤ģRDDDDZjҬY3صkO_?.eA Ru( """"RC}={~ Q_~W^=odk&..8nVٶmۯ:K\..  NͲ,K0X.J"""""5Tƍl]2Ǐ瞻l{$$$ФIf͚#5wtL:սm&m۶O>?~Aǎ={[oŲeΦm۶ 6lѣZnɼی;{3gҵkWvEddlܸ#Fp &N#S.]J֭+=+VP^=f͚vZ>kkԨQ:u*7o'22p~G*/ g ==px eO<ɦMh޼9~z\a|ǎ#--իWyfJ Y|97UP)eu_H\\ݻiܸ1QQQ4mT@Ռq>4RM)&;Brd"""""508q"ׯrѥKJiժ 00pY"99qPTT$??x>J\\{({wӼys|||lYKzj䭷8޶m[+q~Pƍ1M]… ѣ=z믿Õ%}VYIII/wu7n/P5迸 .0qaq\d%T5ADDDDDg֭jՊa?\ 4/!CЧOΝ{Eu?004ծ];V^}]9}tZ,0 ÝիmZz!ĝ[lqݽ{&:: &гgO&ONI`1a1𵀏Vk}) """"" ;d߾}bнyJݻL֮]KN(--a6hڴ)[ңG-[p},nݺUznvv6Att4>}޽{WҺ+ʕ+y饗HKK_b 0ʒ 6phMhXPďDDDDDj;wd_ٳٴi]vűm6b *-a۷cǎ1el ڷoϮ]+gҥlٲ|Oɓ'1b +g֭7V^СC#))ŋIQQyyyRQ̛3224M iѢ;BIV-N&V_QUI9̙350"##IHHO>}{ &&&)ShѢJGDD0rHƌC-l 6dz~ziժ͚5g)iӦѦMwNF1cs!..oo㉎fԫW<#%&M>|8vH,+MUUy󈉉AlٲW^y}l߾}deej[~} ,֋ >ĂRh𵁏,%,EDDDD.]?p{ (3J/ҕ?4ر'N'#KMMM套^ƏO eӦM?~:u[GHH_)((v è]1Q>t̛n>D8Bʫ.ݎf u'''{y6lsι'`ܹsgT-N맑 >}|',.W#d5jDF~vtK'3`4Q@~iSUl6"""}o݉^ X/|OkQ >V;\q/5$Hu+n4y~P7LibX, ;}uJ~n0Mn0$Å LΏb0*;$HMqcG~u4Y=v]Uyz/_ ,V6 O_kYKKHL\rj8]lN ,`ס$Huұ#~%.z]¨źibq/YՃ:fkNnPYN(9`(=?i """""\eҜeKXl`VYtt80l*ϰPde[LE,PjRͲ9J """""""R>B5R'8F46 (;v)%DDDDDDDW$(U6, o7|N-%N'͆Ջ%mu 9/&&S40/̿0(. ~u$DI!J20)f>Zע$jXp_ąbc@ 0]ɉ) """""""X`:,ajZ\ 0\`1˖]EDDDDDDj6ł"L La8,qD1+EDDDDDDj6FD}wGi)NL|Ӥ N˧yxԣ$H Cva|)NsD>əB?ps=z=ќ """""""5f#^'.=cpbf~9:|Gt0}˗G}$p}ɭoQFWp .$>>4̼m2o<u2m4JJJ?Znaӭ[7^}U8"PA턅b&/EDDDj}veŗ1M &ɭʬYLy{1BCC=zt_b&ӧO'66zѭ[˒8yd4Qt:`r-Wԧ{ʕ+ر#v$JJJ>CGDD;vd^SO3x?A9sn|QAD___jժEii)VMsd-"**xΝ;ٻwGd?~<+V`׮]|wW\nk׮:tڟ:u*+V ==3f0c VZUnG:\qz/޽{IKK#))~NFFG ]taݺu$&& /?zCvH(̛7p֭_drh"a1~2|pbbbxwiР{7e*3`^&L@^^DZcҮ];7bfΜܹ3}fɒ%Ɣ{APPVr}'5#Fмys(..f^ѧO `>Zp!ԍ/J2yf>LϞ=9{,u],^p~Ξ=K۶m/;$pޔ̙3cԩ}V8uYp!=zG|>|xBCC8}eVZń =ϛx/hܸ1m۲qFLt"99qPTTU֭[xEfN'tFcEDDDDj Pn"!!*Ǜ2UxgIMM;p/.. 88أ|``{ԃ7;NzE˖-CBB-p٫#;v`$''_v̛x+bX(**0 \. /dȐ!Ӈs^Q0}CFFW7l4ADDDD***b?~9|0jro',,A⿨{SƍaÆL8ѽiӦX,nQv˖-4kڵkѵkWfϞM~~M&::0ػw/3{waaa]VJ """""裏())aԩS[ӧ˗/0ڵ+lذ;v#PXX~›2 --cǎyÇGDٳgӷo*͛IOOgРAy}12tߜy[v2xއzAw\.\.it:1MÁ餤Rox]KX,Tjpiv{ ow8b۽^ܹs߿oFU<1`:bxG, ?~r~woV/7YYY$&&rС 矐ᣏ>"&&???|||u/YoXZX, ø~ܱcrλZ8QDDDDDrW Xj۷lDDD\Q۵k.wVZ@ل7tSɎKazCZZ= rCu jܹs:Cndj׮ҥKrh$\J2u$\J2ݻGb,Xs窓1e>SuJ2xG 44{w͛BNe֭[ǚ5k~׷o_9u;wOaa5?|vyU6o ?={ *)Z]BDDDD;z(۷'<<͛7Kqq17ofݺu:Ϟ=ˤIxw~Uq-_B۷o_$33FeC( """"RM6֮]-?ݺu[n:}}}7oC m۶Zlppnvuso^N'~x{Jp:L0(7oάYٳ'2i2ydW_2{PF*iL>XիGnξ̄ [oe֬YsU橧gsw\;bIJJgIDIpi߾W[yǠA8q"K.[D^x~GGnݺJ|8111-0X|; 2p@w VZEIMMO>bdBCC8}Wn7oCشiEEE^qA HHHm0eYp/n{u 3gΤCL:{̽B}V88{ls:5`^Q|[.<-bȐ!Y~;wƍn۶-iiiy}&$T)** or\ 4/!CЧOΝ{EuԪU ("N^zѲeKڸxgIMM;p/.. 88أ|``{CAAaaaת XW_E @߾}!##WO" ø>QADDDDDDnxxgiĽ{ڵkԩW\GÆ a۶m ]vyE/OwWqdĉ}M6buVz޿e>lՇ0+tNN\;;h ø.}&- """"R%''s9zݻq\8KƌsE 0طoǎcʔ);vի3f`ȑ3ѣGVQ???Xx1w*  --# q.]ʖ-[g#Gb&̟?x{A޽Yb{ߴix޽;1geƎK>}ٳ'aaa̚5={dpW\Xߨg*=䥢>}:'??'|aÆyg#++ նHE3f|#"ٳ۷oo\ocMJOOgРAߒ/A`my>!憆rp\4MNJKK)..o'M6(P~i۶mtvH론ӧOc=ͥ~X, 7`:p{x9N6 +HLLT+<p .[3u裏|}}Zl6, Vła;v ]y~q]VA``yCw~audddqFu8!!!y\Ů4l2<]wŁ5kmڴ{ャf#""C``J fe_ZZ=!!!8|74&1uԩo " ___k-[ y\T?̙aaDddwDMAQA1%&q 46Imni/mҤYjXIJ$&, eM#( 0",|<|9s>F?~㌂F]z;  qqqcCtV鱧z D.ADDDDDDDA""""""" 2Ѡ DDDDDDvrssqUL<f DDDDDw"** &jkk oooS<ZG 2]FV j$yv %ȠR*mO6 ~!=jLhp9dggcܹ 4iBCCq=Qot:N8[[[xxxH*KZZN:H](++CKKIygi_UGbF'MMMRaҤI&iz=0uTDDD ǏimmsΜ9iӦA /BBB퍂erpp=퍱cZTRhnn6̘1}Ka͚52e -> 9s&Ν \ۨ'׿HLLL&SNٳ䄥K8M:%())Z[[燳gJij%d•+W666GAAPZZ BǣZ7Z2׍7=3IAZMҹI)t= 8Sr9T*z}˩T*+WYlxک?}5Xu$hȄFAHHrӉAB@kk=e|jŔ)S ɤG(brmKYZKd_eT6,>  =c̘1X`&LĉסK[W  !!!ؿ?ov*PYYK+**LNptt hii =XO,BP`ԩnn!_ џo0i$:t>>>5jT}V쌪*i=zНk2dExRiӦ̙3VEff&1sLt8z(\]]uoOǙ3gֆjiK`N؈r:t݀m "qnTM??^"Ñ3hچK9&>=C}CPB^CPbi+8hm"L\ьаg2k׮R*::]P(P(g>|rd0`=cu ~*QXh۷r0uT̝:>|[q8;;cyJl߾2A):Wc_-[qn=>i+_+٫*&&&bϞ=شi[>񳀈عs'6n܈;v )) 2d$"-뻝9ظHZ9oiqEQ(0 0 thooVE[[ ;Zբ_6 h4nk?kkkWjl`v+yߏ?YzsE爖PMUUv؁ 6gHAz駟bĉPTP* P(r2[ ɓsAN4L"""""7R R9r9,Noq-Pe 777z3f` 㑇A""!RWW*6 k)))(--5٧T*ׁdػw/Z-֬YcuKKK+W@CP )) ƍ8C޶@}3}cHNN7z!+jkK{d ""T*Ǝ{WԵmmmt˗/e2Y `Ϟ=k׮afkZ۷X~=r9`ee5ڭkZQQQ Caa]~*o6֭[gcǎʕ+۷7F JWW?ydgϢ իWڊٳgCRN:ڭkZFUU4 jIVPJIIѣGi&,ZA"""""󈢈4AP <<[#G@aҥFaa!z=%K=z4r9{`oo Hضmoh4 %K I<==PCE#77(b̙7o^zC.#""4iOޭs{4 1pssV'NѣG؈3f`֬Y=~9sF Hu^[݌e ±cǠh0g?GQQܰd8::Je(,,챭-n׾hllDzz:Ν;\#,, r)GFD¼9f۾=uË/bfFNׯK۶`,##OƢEǏCјhjAAA(++ױdv Lth4DEEI3 ɾndoExx8qI ,,L*ۥKp%̝; EEEXjZZZ~ ((SNa?~L///\r$6i* &Lq9xxx@" ϟyI\ IDAT444`0I݌ wwwRJLfrɿWʂ\.֐3gtDEE$`l/c{ b$GLyd "":?>> 2Eakkj^/,t[nnnzsUUU%艣#A@KK &LZ3cŖ3f d2*++1פuCHHߏ:ns[u]\\"-- Ǐ$Q֑`ĉؼyH 0'xZ?8ZZZxnyP(#qqqoQ]]X{=z4z-l޼(⩧s=M6aϞ=>OFqq1`Ϟ=8un݊I&t}ʰsaƱ=>Ltq/|}}qiARرc&sݑ&u;^SS:L0 3gvjjjnZ8ٳ+WD||<>#!::> mۆ4|7ʂ/BBB駟ǫ{ _plٲ~t{E~~>L}YǏǿa;v@RRo6"3.t!cx`kk+Vt[c`7ӱl2---8x >ڢ SL1y)SPRR-[`رHHH֭[4233v̘1â.\}A.CEcEA.… pvvʕ+}vƁk.(qqq-JڵkT*{Uꫭz\hH^u3u%%!!AzI&xGqZ_|fr 2 6TUU J^󃟟`Xlߘ7D}}=bݺu_WCr̓d"d """cǎ#kq?o6"""j*ܹs 떟J3Y 5557nE U m@hL&u9RtEBiA!pQ1@DDDDDNVV ɓ'رc9sZ-6mڄqqqصkP(3h]]]oDA.(B A.cI?&Nr dQ 0 [k2@.A>_U9ۏM@DDDDDDDA"""""""|\nQDCmir>00@DDDD4BhE@}drzt:( h\.07_ &N8, D^1A"V"3tg&Ýd.&Z]u |TbxbnHT)J {h9 gav-nhhEt۝ 0|qM""""""d:z^: @Pt"~.p& zƨAz g0  2Ѡ w}d/dC!(Atz(2r,0Pl9"""ᦩm@Dwpah8|\hѶ~a+==4!77z3fq, 0r(÷.48hz c---xkP|N3RRR׿&kjj /Ho*Ο?s/?Xmm-^xڵ5>o]A""""?@gΜ`@YYnuϞ=AɫiiiæASSPXX={֤}m }hڝznT;v 6m~d """ n,ۂŋЀ@BTҠ>`IK444@K'+WXDzeːt ƼQZZ* {[2 .\ѣؽ{7 JKKApUf6ֆݻwcҤI>}E \.GII <<< ??? %:X}h hZt:\z---͕lllkF zLBL6, #3A"""}2 4۷o7^۔mKX:BVprrBdd$233GJEگRzKT eeeC@@<==a0P]]1(q[UU^\~#!!!nCNBB\Aggg( kߊVEQ{d2bcc{{{&8t<" !NB,]SL13lmmQ]]-MwҠEi ,1c PYYK+**L2o< ۣ=xd666 F~~>jjj0heªUc00'$$G]]lL&3WTTHu~B!# t:&L n'^R L&E]6͛7KH"G+09 x&ɶ!UZZ ^SZcgg'H((//Guu5RRRLhjj1s`ڴi8s ***jf̜9) ,[ ׯ_ p̙3thkkCuuu1jkkM߾8uamm=e|آs 7XZ6KUUUvq!)8% 4;F^PPn R,KEQa!ɠT* 7O?4 DDDDOd-֧M={&L{n{Ŋ+3`I7|ӧODze`׮]Ҕ8oa1aK.\}A.CEc=pss0 . !!|0gΜ^ӫT*]VvKfIN2%%%زe ƎlݺU `v?p:d3s\.GWg X2kd#11Z 2Ѱwx =͛7C2 &X+$%%IRpBբŢ׬YcvBBɶ =FZm24WxꩧLqww7i΃n h>u1&KfI:::bӦMq4 ~g2[]zkwV Q"ڤy -h0T*!ˡja0`0(Rv;sA"""""%5ή>Ri q r9Uʲ,KfIF2LљL&t'sz&1@DDDdN"''@鰶ƛoL {^/:0 BZ@BAOn&3$+d """.Q(PWW_믿F||< DDCd0ލA\.G{{; >cGE:$`0͖%莕h>""yc F>[~CI iIn DDDtNJ珯tuu 7@XrqPE?Uƅ#u:Z-Z+8A"""n xjhh@yy9uuu(//GCCC.\-:AS]cDDw(㢒1`|\AECJ㢎'tGW: 2֭~կ~k^{ ~~~xg< kG_~vg:qSN^v ǎCjj*JJJà/r9P(ABJ^AٙL&ɟ9T*T*dee… R^*JJSfc m„ ~͓O>i2ܙuϓ@dc6VRRRPZZ*mj8::",, !!!syhZ̘1㖕]El߾ǬY1%%/^?[[[iMM mۆw~ ߾4CQQQ1xp$''=PBnn.gqdNktmv'뽞`->5!QN=A߭ PX?qww܌!55k={׮]ٳGUU6HKKÊ+nkjEEE&A(,,/~m[666 2 _>}?<b? OeT*\]]iӦ?ѣGZ=$ADBP  ''3f̀mk[IV ~),,NGbӦMXh DDDDÕ'{z ?>DQDzz:rss!"fΜyGo鳳QXX^dbɒ%F^^222鐜 '''?ő#G鉌 "<<("++ hjj¸qm0cǎA`Μ9 "aɒ%pttSNEII >7J\~ޘ5kK\R }o׶ɓ(--EBB"''R`7n@HHMWDQDZZP(̖ǂ smۆoN0 IDAT(݇:8x 6o oo'''jm+_}j*,]&k9t[ xyy 111/&O As4 Ν;l̝; dff"44ׯ=viFiii _?(E]]]" ** UUUQ(../..Fmm-ʤ}9997n\k:+++Ñ#G` @lǛfXR >}<h4|E[[ۀ$''/hnnQ@DDDwgG~=NAVzǏŋ cu;V5j5ƌ\^N5k`ԨQRYYY /Ǐ#&&Ƥ?FWWW8q...Xx1ŋlS"//G@'NVRĹsrDFFʕ+hnnO۵:Gjj*.] OO>r)G'u҂F899I@HiT*s~gtB!kC'''DFF"33dáUT eeeC@@<==a0P]]i-L&B@UU{}TsLh4@./t:t0 =6d2bcc{{{hoP(0uT@toE3cƌL&Cee%Ə/0 CAAn}ADDA7QSSAVZ;v 559!!!ؿ??pvv-z|<j&y }9L87ot$DDDDDw9Nׯ8t233;;;p̙3thkkCuu,Ij455Y|@)JL6 gΜAEEZ-233܌3gi* ,[ ׯ_1jkkM߾8uamm=|آs 7#XZ6___>}娮FJJI@<<88999x71}t,[h8pvBB@\\<<<}Ǐ &ya [[[IE`0t[p₄|ppp9szMRvZ(Jd{n{Ŋ+'1e`˖-;v,u^7͊Gbb52F٫*&&&bϞ=شi?aPHHH3? n33w~I4g-(Ez:NZMբ e0hV->W&X[[氿Va@g$׷eh41`t,P߁Pcӧ~sxjϗز!"CP@.CrdnmzIHABsAN4L"""\v V1zht:s=h4d~6,zelݺ}ΣaO.a5CTJFB{k\͒@{n Q9D7|sj*⭷޺бzO1?裸qㆴ]\\ 6`̘1=z4gj$'''V?8޽[Z|d """A {{A.ڊ˗vvvxqlڴ [lA^^ۇ={`ʕG}4DGG DDDD#իW E礤 ;F}}=aee;w.fϞvJ!""bh8qs~~>DQ׿p)Mcc#֯_/*Az=1@DDD4L?FAyy97oFDDf͚cVŽ;ގ;wJ+qCc@ۉA.㥗^s@nndg@PP 'N@dd$@B&Y,|F DDDt~|ꫯBJZZZOHH~3\r@gK1GKL_p(hDcX2 >VXgy111]vATbŊظq#16l؀SNaʔ)0a}a۶mR -- | :$]/99+VwsN|hhhGA||L߿ֆu_Ė-[xc o6ZZZd """"'ODeee QW^yz`ؿ?.^m۶W͛/BE|^z 0uTd2iǟgWG\xٽ3f@TT~?ҥK?UUUOxs )))xq1hZ|9KrssQ[[h| x ""&ǟ}Y>>}v_&bŊnA:z֯_q]\\JK/V;wنߑaaamQWWW_|opEhQՈ6yd"55qqq6I[QQŋ/@\\y\~]:^YY/O<x$%%޽GUU'zyW%K,kLQVzq|$e⭐x^o]:`S.-#DRSc4&K[%):`" ~?g9/m۶aʔ)KKKܹst8ݻg2{;w.^xL&޽ۯ2<3f -- GFFz]k׮Ejj*x$''#!![nmp<Gn|{PUg(BII 2331f^O>$㍿.ïz1atؽ{7$IjwԣG6YzBnСC1~wzl̞=yn_?& ;v@||<.^QFᣏ>_~/? xKHH@LL d2!$$"+ԩSƈ#Wc*l޼pĉFҥ ŋ EL&tx̙3صkztL0йsg@yy_j0l08pQ/-QVV3tÆ@n!]7C&0i$ȲosAu={6qf2BCCf.=;t} (,,l'N;b1^:t(vUoYϤGk郥KbС4i~aL}Q?88F1|qaʔ)HOOoL鯵kjb֬Y~} ;]?HKKCtttv@DDDDDC&$Iil` Ǐ˗/_ w&%%aРAׯ͛'"++ cƌ1i }֬YضmRSSݤ6l? y+<dt#mIhh(l>sL<#Xt)&Oqk.gin݊ݻw#55<@d """"ja6>|=zϲ;vԩS{6lyɒ%xw^<f*^|E111XnƍM6he˖wވʕ+<^ݻwcĈӧ֭[EQz+&M'OhTUŦM0c #`hiXz5NDDD`ԨQ8t2O=VX!C>O[n]we8}4fϞHDEE_h][,Z . oV'dggСC2d,Xױ֕=y>}!=aaa=zϐl$%%j,[TT|~)h"\tx~)͛S"%%O?]Ʋe˰qF,X;wDaa!PVVf,b ++ @nnUCqqOî߰tR̟??0-Z)S@u_> lWQQܶ^z k֬O<?կ~Xę3g|>ߣg>c+x(֬Y2-[pwcbbcǎ5yL0 Fff&fϞױso0w\_ mINNƾ}/mۆ)S[.-- sELL p8w^e{aܹx`2{nʰx0c @=:p`ڵFd$$$`֭Ӊ$''c޼yPwq֮]D;{ivy=z4 1c ̟?CEVVf3^~fSMM oߎiӦCF[t{=܃u=PZZqЫW/t :t#wPU٘={6>6ݜ0~xL&رx"F>޲_~% F0-!!111Ʉ8N8u1bĈzX 7o6~ĉk2ĠA !$6 h:w (//6xR$ 6 }iȐ!y-==)))8vϘ u]VV3m=l!jC&0i$ȲosAu={6qf2BCCf.=:tlW޽GbzPPP1i$DGG_ĸql2,^8u}y_~-:q% `„ HII1]0d """"6#99scǐUlٲ| F u4UFϞ=#11{ .DGGl6&Mj5 ƨQ~z̟?aaa .׷o_ cǎ5^ǘ1cEQbsyعs' xZk׮jŬY:A ~ "66iiipN"""""2!I4M}`X?~%%%X|9uSFbb"222Oc…xgaٌxwevTTTԻ֒z饗PYYcoP… :9s&}磪 WFYYΝk5l0߿?t}ӦM8}44MCMM  Q[\%%%(**B^^ӱf\]cCZ IDATv8ÇyBqv;v… /ɀ!°sNlݺXe4 Y1g,Ygb+e˖a(((nǛo UUltR̚5 D^y밹={@4}-܂4;{Z qqqx衇p뭷"##: f,3m4 66˗/;v[E=޷ozoO=JJJ'| ))  B~0o޼ĉ1cEBFF>k,l۶ <ݤ6l؀ɓ'7DD޼ kRFn]ס:4M4 \.8=z&Lh5uVQQb4KJJн{kV1rH7EQpDFF֛CFjvUTTɓ۷osTWW6Dϝ;WobGvTVV]bq={;v4 w_X8rm L{ 2DQ$IE ;~<f,'IdYܻ,I( d """"fnIJedggԩS>|8N8u!..rdYFTTTlW0x+.d1- juϱԭ[t }V&fGAvv6, Fŋ.DC"""""jUĊ j8#C"""""""  DDDDDDD nRo66nȊ!Q;6ydXVddd{ojŨQ>gl1nܸOG5#11V6 3f o ɩZvvMo۷oG~~>f-[^y7~W_} |bp8>}:2337@MMM^y K""""v.22Dqq1z2DFF8pܹs;o]v< gΜGyK.ɓ:F]׍uV޽xʞ DDDDD\bb"f3>ÇGYvǎ:u*p=`Æ >/Y=݋|Ь2TUŋ/޽{#&&֭øqi&cMӰl2QQQXrUCSezm1buAQŭފI&ɓ>sNs=Dzz:NzW^;5j:ືn݊}T]6?ߟ?SOaŊ>8d|g?OơC0d,XmX,Xj\.z&롱u  ѣ}Ldgg#)) Vg٢"' 33:u*|^z k֬O<?կ~ѧ? ^xc겹٧gΜ)GEE`„ HHH@tt42331{fmgLL "##qر&롱uoܹs~zTWW3d """"%99/ضmLRo4̝;111HOO޽{})++{gs^dݻ*n^Ì3###=zÁkʓ[x-t"''ɘ7oEw܁k"11cǎŞ={|>\L6 k֬1c;NČ30| :YYY0x}ʩ1m4c?Gs55Oիu:`ĈmvMCcuH";;gf%0~xL&رx"F K|矍`[BBbbb& !!!>]TƩSP]]#F[ 2UUUؼyĉW5e4 Rb٠gn6cY=aff&4M3{KaÆ)gȐ!o\|W'Q>.++CBBUCZ u!jC&0i$ȲosAu={6qf2BCCf.=:t\l(LPP1uy=ypy_~-Tw&L@JJ!ɘ3g;z`˖-O0rH\f2zX߿ܓP^pX&::f4iR@Z٘C!:: o߾E_}Ǝk,1c\U]^O o0AZkjb֬Y~CukHll,P8'p$ ~pp0AQRR˗JJJ^?e$&&"##O?4.\g}6YaXw}[lnGEEE;24ǵ(㫯2+صkك'|Ҩ3gG~~>zjaܹW]ʕ 'rrr^x>|ؘ1%%%(**B^^ӱf\]vFݕt ./foʐLܹ[nmp\}TT0`dYƜ9sdɒz6Ɵ2-[ vo&TUEppQҥK1k,"22zBffU(pXz5"""0e79sWZ8>5>tuu#K+cs &tNDDDD:_r08raX0b,^MC\\q͸O7Zh(x`@DDDDJ ף%%%!))ؗ{~n};oSqG""""V@=C/dL&slf AѣP:u2.\.TVV(--e@DDDDZ^ @Ө4ͧq6x/ {<Ši+OP7p>WKBM`2oo8~8!2aZ:] f2d """"j%w "t]$I4 ,\{7\E111_PSSc E5, BBB%C""""V4.Ѕ PU@$#d<2? ̱Ps梸絋/"''O<C""""Ԙh(h~;\ID7!PĉCUUTVVBQL&L+~!Q+mL{ ns•^kxȖ$ɘW 4*lۣ! "jt`@DDDD {^h 2qAD"=9ł?ϐ$ (BXVXVIEQ$Ie6 >0d """"""j{1@UUMӠ****[XffXVc|p """""""  DDDDDDD ( 8'PUCEz1d """""""}|MEQ:AC=hs.ADDDDDDD>ƍ})S\s ȇ$IHMM k>(BBB9 DDDDDDDCuƍ{/4M~!O:&O.]` .S'~$""""""f'BCCim.d """""""]׍ip: TU5M DDDDDDD.jTUUAUU Aby`@DDDDDDUU( PQQhA "$I2Od """""""$8|8xg AGF>}|.5MÇp8 ˲q!s""jTU˗Qt:Py "A$h0 =@ tsBSzj24U.oW&ͦ#R>DIx@Q'SlPUZ:t(dY вӧOcMnt]ס*l2Q'Y˗a6'>Ap8((((Z0L><'- D^) .`KYstsD6+tAIt7ڵT 4XFچYt7% Hn~p):DU@e%_`g<@7CyID7dp4 ,t믿=cܥAܬ:CDyyy@{OD ܖr駟p%d2d2c=c0Q{*BG|d:A%B*l$Wuhܫ ꀪ&@I D@I -CQ %XC8`;Pt҅=] !ƼUUUпfkiuzsdzMp8 hDI먪…  jrndN`YEd*(u8qܩ5k')nE,Q[ Ll6C4\| /\?طoQ([Y.Kj*Cǎt:Q]] MӌT2d k+Au$Hܶ3/ɒ?Q{{Q ":,``%8EAluD %&@SEP Ԩ4&IIڇEd 7 ڐBuD"L&$']q. ,b@!v0x sid̫PUUÁK.pE2/]T[TVV[傢(ñcǰdAQkrg8 D(OhiA0&eP'C"jE,Ê2 }CmZM&QTU 20pRTQC%C 7N.fI Xk't Պn5nwcwHL&(DC$j`u'O4 Xd lق ]c\_äI ]׍?*z3C"jD9xNDgGOͥ2"vl6#,, )*'XХ!& QKp5.!:LQhKӃ@Ir?,5A -KYl&O$@U(.E].l&] ?ys$ HKKÑ#GoܹsFo! 5k3|{"wc@D ';P |z{b@D-dҥ FE DtYdI\ \nKT |XOt܄uBph A!*IeI(h*: :d j19vF7 UoѩLn(}bijDD r0L 5n=<9;.<88  堠 ca8Ȭ """""""j'N`ǎHIIaO"""""""jK.@DDDDDDDwqɓ'2QصkO9Y عs'd """""""])` DDDDDDD䗣G⣏>j4`(,,dO"""""""&;wBX~"""""""xQXXx6cs7:IENDB`BoolNet/vignettes/BoolNet_package_vignette.Snw0000644000176200001440000026140114272154552021252 0ustar liggesusers\documentclass[a4paper]{article} \SweaveOpts{keep.source=TRUE} %\VignetteIndexEntry{Detailed introduction to all major features of BoolNet} \usepackage{a4wide} \usepackage{graphicx} \usepackage{amsmath} \usepackage{hyperref} \usepackage{listings} \lstset{breaklines=true, breakautoindent=false, breakindent=0pt, columns=fullflexible,keepspaces=true, basicstyle=\small\ttfamily} \setlength{\parindent}{0em} \setlength{\parskip}{0.2em} \title{BoolNet package vignette} \author{Christoph M\"ussel, Martin Hopfensitz, Hans A. Kestler} \widowpenalty=10000 \clubpenalty=10000 \hyphenation{me-thods pro-per-ties re-pre-sen-ta-tion} \begin{document} \SweaveOpts{concordance=TRUE} \maketitle \tableofcontents \clearpage \section{Introduction} \texttt{BoolNet} is an R package that provides tools for assembling, analyzing and visualizing synchronous and asynchronous Boolean networks as well as probabilistic Boolean networks. This document gives an introduction to the usage of the software and includes examples for use cases. \texttt{BoolNet} supports four types of networks: \begin{description} \item[Synchronous Boolean networks]{ consist of a set of Boolean variables \[ X = \left\{X_1, \ldots, X_n \right\} \] and a set of transition functions \[ F=\left\{ f_{1},\ldots,f_{n}\right\}, \] one for each variable. These transition functions map an input of the Boolean variables in $X$ to a Boolean value ($0$ or $1$). We call a Boolean vector $\mathbf{x}(t) = \left(x_1(t), \ldots, x_n(t) \right)$ the {\em state} of the network at time $t$. Then, the next state of the network $\mathbf{x}(t)$ is calculated by applying {\em all} transition functions $f_i(\mathbf{x}(t-1))$. In a biological context, genes can be modeled as Boolean variables ({\em active/expressed} or {\em inactive/not expressed}), and the transition functions model the dependencies among these genes. In the synchronous model, the assumption is that all genes are updated at the same time. This simplification facilitates the analysis of the networks.} \item[Asynchronous Boolean networks]{ have the same structure as synchronous Boolean networks. Yet, at each point of time $t$, only {\em one} of the transition functions $f_i \in F$ is chosen at random, and the corresponding Boolean variable is updated. This corresponds to the assumption that in a genetic network, gene expression levels are likely to change at different points of time. In the most common model, the gene to be updated is chosen uniformly among all genes. Moreover, \texttt{BoolNet} supports specifying non-uniform update probabilities for the genes.} \item[Probabilistic Boolean networks (PBN)]{ allow for specifying more than one transition function per variable/gene. Each of these functions has a probability to be chosen, where the probabilities of all functions for one variable sum up to 1. Formally \[ F=\left\{\left\{\left(f_{11}, p_{11}\right), \ldots, \left(f_{1k_1}, p_{1k_1}\right)\right\}, \ldots, \left\{\left(f_{n1}, p_{n1}\right), \ldots, \left(f_{nk_n}, p_{nk_n}\right)\right\}\right\} \] where $k_i$ is the number of alternative transition functions for variable $i$, and $p_{ij}$ is the probability that function $j$ is chosen for variable $i$. A state transition is performed by selecting one function for each gene based on the probabilities and applying the chosen functions synchronously.} \item[Temporal Boolean networks]{ are Boolean networks that incorporate temporal predicates and discrete time delays. Here, the next state $x(t)$ may not only depend on $x(t-1)$, but can depend on any predecessor state $x(t - \Delta), \Delta \in \{1, 2, \ldots\}$. Furthermore, $x(t)$ may also directly depend on the time step $t$ itself. } \end{description} In \texttt{BoolNet}, there are different structure classes representing these network types: \begin{description} \item[\emph{BooleanNetwork} objects]{ contain synchronous and asynchronous Boolean networks. Here, the transition functions are internally represented as truth tables.} \item[\emph{ProbabilisticBooleanNetwork} objects]{ encode Probabilistic Boolean networks. They use a truth table representation as well.} \item[\emph{SymbolicBooleanNetwork} objects]{ represent synchronous and temporal Boolean networks. They encode Boolean functions in a symbolic form, i.e. as expression trees.} \end{description} As we have seen, the networks are represented in two different forms: The truth table representation, which basically maps inputs to the corresponding output values, is usually the most efficient representation for synchronous, asynchronous and probabilistic networks and uses a very fast simulator. However, this representation grows exponentially with the number of inputs and is therefore inappropriate for networks with a high number of inputs. This is particularly the case for temporal networks, where each unique time delay for a gene encodes an input. Hence, temporal networks are represented by directly encoding the corresponding Boolean expressions and use a different simulator. As synchronous Boolean networks are a special case of temporal networks (with all time delays being 1), these networks can also be represented as \emph{SymbolicBooleanNetwork} objects. The package provides several methods of constructing networks: Networks can be loaded from files in which human experts describe the dependencies between the genes. Furthermore, they can be reconstructed from time series of gene expression measurements. It is also possible to generate random networks. This can be helpful for the identification of distinct properties of biological networks by comparison to random structures. The different methods of assembling networks are described in Section~\ref{sec:assemblingnetworks}. In Section~\ref{sec:networkanalysis}, tools for the analysis and visualization of network properties are introduced. For synchronous, asynchronous and temporal Boolean networks, the most important tool is the identification of attractors. Attractors are cycles of states and are assumed to be associated with the stable states of cell function. Another possibility of identifying relevant states is the included Markov chain simulation. This method is particularly suited for probabilistic networks and calculates the probability that a state is reached after a certain number of iterations. To test the robustness of structural properties of the networks to noise and mismeasurements, the software also includes extensive support for perturbing networks. In this way, it is possible to test these properties in noisy copies of a biological network. In Section~\ref{sec:importexport}, the interaction of \texttt{BoolNet} with related software is described. In particular, the import from and export to SBML is discussed. Also, the necessary steps to import networks import networks from BioTapestry and to export networks to Pajek are outlined. For the examples in the following sections, we assume that the \texttt{BoolNet} package has been properly installed into the R environment. This can be done by typing <>= install.packages("BoolNet") @ into the R console or by the corresponding menu entries in an R GUI. For some of the plots, the \texttt{igraph} package is required and must be installed in your R environment as well. This is analogous to installing \texttt{BoolNet}. For the BioTapestry and SBML import, the \texttt{XML} package must be installed. After installation, the \texttt{BoolNet} package can be loaded via <<>>= library(BoolNet) @ \section{Assembling networks}\label{sec:assemblingnetworks} \subsection{Assembling a network from expert knowledge} A major advantage of Boolean networks is the fact that natural-language statements can easily be transferred into this representation. This allows researchers for building Boolean networks entirely from expert knowledge, for example by collecting statements on gene dependencies from literature and expressing them as Boolean rules. \texttt{BoolNet} is able to read in networks consisting of such rule sets in a standardized text file format. In such a file, each line consists of a target gene and an update rule, usually separated by a comma. Optionally, it is also possible to add a probability for the rule if the file describes a probabilistic network. The first line of such a file is a header \begin{samepage} \begin{verbatim} targets, factors \end{verbatim} or \begin{verbatim} targets, factors, probabilities \end{verbatim} \end{samepage} To illustrate the process of transforming natural-language statements into Boolean rules, we take a look at the mammalian cell cycle network introduced by Faur\'e et al. \cite{faure06}. In Table 1 of this paper, the authors list natural-language statements of gene dependencies and the corresponding Boolean expressions. The following rules are taken from this table. For gene CycD, Faur\'e et al. state: \begin{quote} \textit{CycD is an input, considered as constant.} \end{quote} Transforming this into a Boolean rule is rather simple: CycD does not change its value, which means that its value after a transition only depends on its previous value. Thus, the transition rule is \begin{verbatim} CycD, CycD \end{verbatim} Gene Rb has a more complex description: \begin{quote} \textit{Rb is expressed in the absence of the cyclins, which inhibit it by phosphorylation [...]; it can be expressed in the presence of CycE or CycA if their inhibitory activity is blocked by p27.} \end{quote} As a general rule, inhibition can be represented by a Boolean negation. In the \texttt{BoolNet} file format, a negation is expressed by the \texttt{!} character. The referenced cyclins comprise the genes CycA, CycB, CycD, and CycE. If {\em all} these genes are absent, Rb is expressed -- i.e. if CycA is not expressed {\em and} CycB is not expressed {\em and} CycD is not expressed {\em and} CycE is not expressed. A logical AND is embodied by the \texttt{\&} character. Consequently, the first part of the rule is \begin{verbatim} ! CycA & ! CycB & ! CycD & ! CycE \end{verbatim} In combination with the above statement, the fact that Rb can be expressed in the presence of CycE and CycA if p27 is active means that CycB and CycD must not be active. Thus, the second part of the rule is \begin{verbatim} p27 & ! CycB & ! CycD \end{verbatim} This statement is an exception (or alternative) to the first statement; this can be expressed as a logical OR, for which the \texttt{|} character is used. The complete rule for gene Rb is thus \begin{verbatim} Rb, (! CycA & ! CycB & ! CycD & ! CycE) | (p27 & ! CycB & ! CycD) \end{verbatim} After processing all genes in the table in this way, we get the following network description: \begin{samepage} \begin{footnotesize} \begin{verbatim} targets, factors CycD, CycD Rb, (! CycA & ! CycB & ! CycD & ! CycE) | (p27 & ! CycB & ! CycD) E2F, (! Rb & ! CycA & ! CycB) | (p27 & ! Rb & ! CycB) CycE, (E2F & ! Rb) CycA, (E2F & ! Rb & ! Cdc20 & ! (Cdh1 & UbcH10)) | (CycA & ! Rb & ! Cdc20 & ! (Cdh1 & UbcH10)) p27, (! CycD & ! CycE & ! CycA & ! CycB) | (p27 & ! (CycE & CycA) & ! CycB &! CycD) Cdc20, CycB Cdh1,(! CycA & ! CycB) | (Cdc20) | (p27 & ! CycB) UbcH10, ! Cdh1 | (Cdh1 & UbcH10 & (Cdc20 | CycA | CycB)) CycB, ! Cdc20 & ! Cdh1 \end{verbatim} \end{footnotesize} \end{samepage} Now save this description to a file ``cellcycle.txt'' in your R working directory. The network can be loaded via <>= cellcycle <- loadNetwork("cellcycle.txt") @ The result is an object of class \emph{BooleanNetwork} containing a truth table representation of the network. The same network is also included in \texttt{BoolNet} as an example and can be accessed via <<>>= data(cellcycle) @ \texttt{BoolNet} also provides several convenience operators that can be used to express complex Boolean functions in a compact way, e.g. \begin{itemize} \item \texttt{maj(a, b, ...)} is 1 if the majority of its operands are 1. Similarly, \texttt{sumgt(a, b, ..., N)} is 1 if more than $N$ operands are 1, \texttt{sumlt(a, b, ..., N)} is 1 if less than $N$ operands are~1, and \texttt{sumis(a, b, ..., N)} is 1 if exactly $N$ operands are 1. \item \texttt{all(a, b, ...)} is 1 if all its operands are 1 (i.e. a logical AND), and \texttt{any(a, b, ...)} is~1 if at least one of its operands is 1 (i.e. a logical OR). \end{itemize} The cell cycle network is a classical Boolean network, where each transition function only depends on the previous state of the network. E.g., \verb+CycB, ! Cdc20 & ! Cdh1+ can be written formally as $CycB(t) = \neg Cdc20(t-1) \wedge \neg Cdh1(t-1)$. As already discussed before, \texttt{BoolNet} also incorporates several temporal extensions. For example, a transition function can also depend on the states of genes at earlier time points: \begin{verbatim} a, b[-3] & b[-2] & b \end{verbatim} is 1 if b has been active in the previous three time steps. The operators described above can also incorporate time ranges. The previous statement can be written in a more compact way using the \texttt{all} operator: \begin{verbatim} a, all[d=-3..-1](b[d]) \end{verbatim} This defines a time delay variable \texttt{d} that can be used for time specifications inside the operator. It can also be used in arithmetic operations. E.g., \begin{verbatim} a, all[d=-3..-1](b[d] & c[d-1]) \end{verbatim} specifies that a is active if b has been active in the previous three time steps and c has been active at time $t-4$, $t-3$ and $t-2$. Apart from relative time specifications, the \texttt{BoolNet} network language also incorporates predicates that depend on the absolute time, i.e. the number of time steps that have elapsed since the initial state. \begin{samepage} For example, \begin{verbatim} a, timeis(3) \end{verbatim} specifies that \texttt{a} is active at time step 3 and inactive at all other time steps. Similarly, the predicates \texttt{timelt} and \texttt{timegt} evaluate to 1 before and after the specified time point respectively. \end{samepage} As the above examples do not cover all possibilities of the network description language, a full language specification is provided in Section~\ref{sec:appendix}. For temporal networks, \texttt{BoolNet} uses a special symbolic simulator that represents the functions as expression trees, whereas the standard simulator is based on a truth table representation. These simulators are discussed in Section~\ref{sec:networkanalysis}. As synchronous Boolean networks are a special case of temporal networks, they can also be simulated with the symbolic simulator. When a network is loaded from a file using \texttt{loadNetwork()}, the user can specify the parameter \texttt{symbolic=TRUE} to load it in form of a \emph{SymbolicBooleanNetwork} object instead of a \emph{BooleanNetwork} object. The same parameter is also available for the import functions discussed in Section~\ref{sec:importexport}. Temporal networks can only be loaded with \texttt{symbolic=TRUE}, as \texttt{BoolNet} cannot represent them as truth tables. \begin{sloppypar} As many network generation and modification routines (such as random network generation and network reconstruction that are discussed in the following sections) internally use the truth table representation, there are conversion routines \texttt{truthTableToSymbolic()} and \texttt{symbolicToTruthTable()} that convert synchronous Boolean networks of class \emph{BooleanNetwork} in a truth table representation to networks of class \emph{SymbolicBooleanNetwork} in a symbolic representation and vice versa. For more details, please refer to the manual. \end{sloppypar} \subsection{Reconstructing a network from time series} An entirely different approach of assembling a network is to infer rules from series of expression measurements of the involved genes over time. For example, microarray experiments can be conducted at different points of time to cover the expression levels of different cell states. To reconstruct networks from such data, \texttt{BoolNet} includes two reconstruction algorithms for synchronous Boolean networks, Best-Fit Extension~\cite{laehdesmaeki03} and REVEAL \cite{liang98}. REVEAL requires the inferred functions to match the input time series perfectly, hence it is not always able to reconstruct networks in the presence of noisy and inconsistent measurements. Best-Fit Extension retrieves a set of functions with minimum error on the input and is thus suited for noisy data. In the following, we introduce a tool chain for the reconstruction of a Probabilistic Boolean Network from time series using Best-Fit extension. Microarray measurements are usually represented as matrices of real-valued numbers which, for example, quantify the expression levels of genes. \texttt{BoolNet} includes a real-valued time series of gene measurements from a project to analyze the yeast cell cycle \cite{spellman98} which can be loaded using <<>>= data(yeastTimeSeries) @ This data contains four preselected genes and a series of 14 measurements for each of these genes. \begin{sloppypar} In a first step, the real-valued dataset has to be converted to binary data as required by the reconstruction algorithm. \texttt{BoolNet} offers several binarization algorithms in the function \texttt{binarizeTimeSeries()}. We here employ the default method which is based on $k$-means clustering (with $k=2$ for active and inactive): \end{sloppypar} <<>>= binSeries <- binarizeTimeSeries(yeastTimeSeries) @ The returned structure in \texttt{binSeries} has an element \texttt{\$binarizedMeasurements} containing the binary time series, and, depending on the chosen binarization method, some other elements describing parameters of the binarization. To reconstruct the network from this data, we call the Best-Fit Extension algorithm: <<>>= net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4) @ Here, \texttt{maxK} is the maximum number of input genes for a gene examined by the algorithm. The higher this number, the higher is the runtime and memory consumption of the reconstruction. \begin{samepage} We can now take a look at the network using <<>>= net @ \end{samepage} \begin{sloppypar} The dependencies among the genes in the network can be visualized using the \texttt{plotNetworkWiring()} function. In this graph, each gene corresponds to a vertex, and the inputs of transition functions correspond to edges. \end{sloppypar} <>= plotNetworkWiring(net) @ plots a graph similar to that at the top of Figure~\ref{fig:wiring}. To use this function, you must install the \texttt{igraph} package. \begin{figure}[p] \centering \includegraphics[width=0.5\linewidth]{wiring1} \includegraphics[width=0.5\linewidth]{wiring2} \caption{The wiring graph of the reconstructed network without prior knowledge (top) and with the inclusion of prior knowledge (bottom). Each node of the graph represents one gene, and each arrow represents a gene dependency.} \label{fig:wiring} \end{figure} A network that involved the same genes was examined by Kim et al. \cite{kim07}. When comparing the wiring graph of our reconstructed network with the reference network presented in Figure~2 of this paper, one observes a very high similarity between the two networks. However, the reconstructed network comprises too many links for the gene Sic1: The reference network does not contain a self-regulation of Sic1 or regulation of Sic1 by Fkh2. If it is known in advance that these regulations are not plausible, such prior knowledge can be supplied to the reconstruction algorithm: <<>>= net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4, excludedDependencies = list("Sic1" = c("Sic1", "Fkh2"))) @ The wiring of the reconstruction with prior knowledge is shown at the bottom of Figure~\ref{fig:wiring}. We can see that the two false links are now eliminated. Similar to \texttt{excludedDependencies}, there is also a parameter \texttt{requiredDependencies} that specifies dependencies that must be included in the network. When \texttt{reconstructNetwork()} discovers multiple functions for a gene with the minimum error on the input data, it includes all of these functions as alternative functions with equal probability. Consequently, the function returns a \texttt{ProbabilisticBooleanNetwork} structure. If you would like to obtain a \texttt{BooleanNetwork} object with only one function per gene from a probabilistic network, you can extract such a network by telling the software which of the functions you would like to use. This can be done by specifying the indices of the functions to extract: <<>>= net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4) functionIndices <- c(1,2,3,2) #select function index for each regulatory component dontCareDefaults <- lapply(seq_along(net$interactions), function(idx) rep(F, sum(net$interactions[[idx]][[functionIndices[idx]]]$func == -1))) #determine number of don't care values for each selected function and set them to 0 names(dontCareDefaults) <- net$genes singleNet <- chooseNetwork(net, functionIndices, dontCareValues = dontCareDefaults) @ In case of don't care values in reconstructed functions, it is possible to set them to 0 or 1 per default. The result is a Boolean network that is created by extracting the first function of gene Fkh2, the second function of genes Swi5 and Clb1, and the third function of gene Sic1 from the above probabilistic network: <<>>= singleNet @ \begin{sloppypar} \texttt{BoolNet} also supports the generation of artificial time series from existing networks: The \texttt{generateTimeSeries()} function generates a set of time series from a network using random start states and optionally adds Gaussian noise. \end{sloppypar} <>= set.seed(3176) @ <<>>= series <- generateTimeSeries(cellcycle, numSeries=100, numMeasurements=10, noiseLevel=0.1) @ generates a list of 100 time series by calculating 10 consecutive transitions from 100 randomly chosen network states in the mammalian cell cycle network. The series are subject to Gaussian noise with a standard deviation of 0.1, such that the result is a list of real-valued matrices. We can now binarize these simulated measurements and try to reconstruct the original network: <<>>= binSeries <- binarizeTimeSeries(series, method="kmeans") net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit") net @ Obviously, the number of generated time series is still to small to reconstruct the network unambiguously. However, the result comes close to the original network. We see that the functions of the network are not fully specified: At some positions, there are asterisks (\texttt{*}) denoting a \emph{don't care} value. This means that functions with a 0 and a 1 at this position match the time series equally well. That is, a partially defined function with $m$ asterisks corresponds to $2^m$ fully defined Boolean functions. It is also possible to generate these fully defined functions instead of the partially defined function by setting the parameter \texttt{returnPBN} to true (which was the behaviour prior to \texttt{BoolNet} version 2.0). For many \emph{don't care} values, this may consume a high amount of memory and computation time. \texttt{generateTimeSeries()} can also generate time series with artificial knock-outs and overexpressions: <>= set.seed(4463) @ <<>>= series <- generateTimeSeries(cellcycle, numSeries=10, numMeasurements=10, perturbations=1, noiseLevel=0.1) @ specifies that each generated time series is generated from a network where one randomly selected gene is artificially knocked down (constantly 0) or overexpressed (constantly 1). These perturbations are returned in an additional element \texttt{perturbations}. \begin{samepage} <<<>>= series$perturbations @ \end{samepage} Here, each column corresponds to the perturbations applied in one series. A value of 1 denotes an overexpression, a value of 0 denotes a knock-out, and an N/A value means that no perturbation was applied to this gene. The \texttt{reconstructNetwork()} function also supports the reconstruction from such perturbation experiments if it is known which genes were perturbed. First, we store the series and the perturbation matrix in separate variables and binarize the data as before: <<>>= perturbations <- series$perturbations series$perturbations <- NULL binSeries <- binarizeTimeSeries(series, method="kmeans") @ Now, we can reconstruct the network by specifying the \texttt{perturbations} parameter: <<>>= net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", perturbations=perturbations) net @ As we generated only 10 series in this case, the reconstructed network is much more incomplete than in the previous reconstruction. In biological settings, perturbation experiments are probably one of the most frequent ways of exploring the behaviour of a regulatory network, as it is much easier to obtain various different responses by applying perturbations than by just measuring the wild type behaviour. \subsection{Creating random networks} To study structural properties of Boolean networks and to determine the specific properties of biological networks in comparison to arbitrary networks, it is often desirable to generate artificial networks. \texttt{BoolNet} comprises a facility for the generation of random $N$-$K$ networks \cite{kauffman69, kauffman93}. In the standard $N$-$K$ networks, $N$ is the total number of genes, and $K$ is the number of input genes for each gene transition function. Such a network can be generated using <<>>= net <- generateRandomNKNetwork(n=10, k=3) @ This creates a network with 10 genes, each of which has a transition function that depends on 3 genes and whose output is generated uniformly at random. Similarly, one can also specify different numbers of input genes for each gene: <<>>= net <- generateRandomNKNetwork(n=10, k=c(1,2,3,1,3,2,3,2,1,1)) @ \texttt{BoolNet} does not only support this standard case, but allows for different methods of choosing the numbers of input genes (parameter \texttt{topology}), the input genes themselves (parameter \texttt{linkage}), and the transition functions (parameter \texttt{functionGeneration}). In the following, some examples are presented. The command <<>>= net <- generateRandomNKNetwork(n=20, k=20, topology="scale_free") @ determines the numbers of input genes by drawing values from the scale-free Zeta distribution \cite{aldana03}. According to this distribution, most transition functions will have a small number of input genes, but a few transition functions may depend on a high number of genes. The shape of the Zeta distribution can be customized using an additional parameter \texttt{gamma}, which potentially increases the number of input genes when chosen small and vice versa. <<>>= net <- generateRandomNKNetwork(n=10, k=3, linkage="lattice") @ creates a network in which the transition functions of the genes depend on a choice of genes with adjacent indices \cite{aldana03_2}. This leads to networks with highly interdependent genes. It is also possible to influence the truth tables of the functions in several ways. The parameter \texttt{zeroBias} changes the ratio of 1 and 0 returned by the functions: <<>>= net <- generateRandomNKNetwork(n=10, k=3, functionGeneration="biased", zeroBias=0.75) @ generates a network in which the outcome of a transition function is 0 for around 75\% of the inputs. A more intricate way of influencing the function generation is the specification of generation functions. Generation functions explicitly generate functions according to a specific function class. \emph{Canalyzing functions} are assumed to occur frequently in biological systems~\cite{kauffman04}. A canalyzing function has the property that one input can determine the output value on its own, i.e. if this input is either active or inactive, the output of the function is always the same. \emph{Nested canalyzing functions} are a recursive definition of canalyzing functions, where the part of the function that does not depend on the canalyzing input is a canalyzing function for another input. Such functions can be generated using the built-in generation functions \texttt{generateCanalyzing()} and \texttt{generateNestedCanalyzing()}: <<>>= net1 <- generateRandomNKNetwork(n=10, k=3, functionGeneration=generateCanalyzing, zeroBias=0.75) net2 <- generateRandomNKNetwork(n=10, k=3, functionGeneration=generateNestedCanalyzing, zeroBias=0.75) @ It is also possible to define own generation functions: A generation function receives a vector \texttt{input} of input gene indices as a parameter and returns a truth table result column with \verb+2^length(input)+ values representing the function. If no explicit generation scheme is known for the function class of interest, validation functions can be used instead of generation functions. Validation functions verify whether randomly generated functions belong to a specific function class and reject invalid functions. Naturally, this is much less efficient than generating appropriate functions directly. An example is the generation of monotone functions, which are also thought to be biologically plausible. These function account for the assumption that a transcription factor usually either activates or inhibits a specific target gene, but does not change the type of regulation depending on other factors~\cite{maucher11}. We can specify a simple validation function that checks whether a Boolean function is monotone: \begin{samepage} <<>>= isMonotone <- function(input, func) { for (i in seq_len(ncol(input))) # check each input gene { groupResults <- split(func, input[,i]) if (any(groupResults[[1]] < groupResults[[2]]) && any(groupResults[[1]] > groupResults[[2]])) # the function is not monotone return(FALSE) } return(TRUE) } @ \end{samepage} \begin{sloppypar} Here, \texttt{input} is a matrix containing the input part of the transition table, and \texttt{func} is the output of the Boolean function. In a monotone function, the values of the target may only change in one direction when switching one input. Hence, a function for which switching the value of an input gene sometimes switches the target from active to inactive, but also sometimes switches it from inactive to active is not monotone. This is validated by comparing the two groups of transition table entries for which the current input is active and inactive respectively. If a validation function is supplied to \texttt{generateRandomNKNetwork()}, the generator generates Boolean functions until either the validation function returns \texttt{TRUE} or the maximum number of iterations (specified by the parameter \texttt{failureIterations}) is reached, in which case it fails. \end{sloppypar} <<>>= net <- generateRandomNKNetwork(n=10, k=3, validationFunction="isMonotone", failureIterations=1000) @ creates a network with 10 genes in which all functions have 3 inputs, of which at least one is canalyzing. By default, \texttt{generateRandomNKNetwork()} creates functions that cannot be simplified, i.e. that do not contain any genes that are irrelevant for the outcome of the function. If desired, this behaviour can be changed by setting \texttt{noIrrelevantGenes} to \texttt{FALSE}. The presented parameters can be combined, and there are further options and parameters, so that a broad variety of networks with different structural properties can be generated. For a full reference of the possible parameters, please refer to the manual. \subsection{Knock-out and overexpression of genes} \texttt{BoolNet} allows for temporarily knocking out and overexpressing genes in a network without touching the transition functions. This means that genes can be set to a fixed value, and in any calculation on the network, this fixed value is taken instead of the value of the corresponding transition function. Knocked-out and overexpressed genes speed up the analysis of the network, as they can be ignored in many calculations. For example, to knock out CycD in the mammalian cell cycle network, we call <<>>= data(cellcycle) knockedOut <- fixGenes(cellcycle, "CycD", 0) @ or alternatively use the gene index <<>>= knockedOut <- fixGenes(cellcycle, 1, 0) @ This sets the gene constantly to 0. To over-express the gene (i.e. to fix it to 1), the corresponding call is <<>>= overExpressed <- fixGenes(cellcycle, "CycD", 1) @ The command <<>>= originalNet <- fixGenes(knockedOut, "CycD", -1) @ reactivates the gene (for both knock and overexpression) and resets the network to its original state. The function also accepts multiple genes in a single call, such as <<>>= newNet <- fixGenes(cellcycle, c("CycD","CycE"), c(0,1)) @ which knocks out CycD and overexpresses CycE. \section{Network analysis}\label{sec:networkanalysis} \subsection{Simulation of state transitions} To simulate a state transition and identify successor states of a given state, \texttt{BoolNet} includes the function \texttt{stateTransition()}. The function supports transitions for all four types of networks. The following code performs a synchronous state transition for the state in which all genes are set to 1 on the mammalian cell cycle network: <<>>= data(cellcycle) stateTransition(cellcycle, rep(1,10)) @ To calculate all state transitions in a synchronous network until an attractor is reached, you can call <<>>= path <- getPathToAttractor(cellcycle, rep(0,10)) path @ The returned matrix consists of the subsequent states until an attractor is reached. Depending on the optional parameter \texttt{includeAttractorStates}, the sequence comprises all attractor states, only the first attractor state or none of the attractor states. A sequence can be visualized by plotting a table of state changes: <>= plotSequence(sequence=path) @ \begin{figure}[t] \centering \includegraphics[width=0.6\linewidth]{sequence} \caption{Visualization of a sequence of states in the mammalian cell cycle network. The columns of the table represent consecutive states of the time series. The last state is the steady-state attractor of the network.} \label{fig:sequence} \end{figure} The result is depicted in Figure~\ref{fig:sequence}. \texttt{plotSequence()} also includes a shortcut that calculates the sequence directly if a network and a start state are supplied. It also provides an alternative way of visualizing the sequence as a state transition by setting \texttt{mode="graph"}. The function <>= sequenceToLaTeX(sequence=path, file="sequence.tex") @ creates a \LaTeX\ table similar to \texttt{plotSequence()} function document. In many cases, start states are defined by a set of active genes. Instead of supplying a full state vector, one can also supply only these active genes using the \texttt{generateState()} function. <<>>= startState <- generateState(cellcycle, specs=c("CycD"=1,"CycA"=1)) stateTransition(cellcycle,startState) @ \begin{sloppypar} calculates a state transition starting from a state where only the genes \emph{CycD} and \emph{CycA} are active, while all other genes are inactive (which is controlled by the \texttt{default} parameter of \texttt{generateState()}). \end{sloppypar} For temporal Boolean networks (objects of class \emph{SymbolicBooleanNetworks}), the above functions can be utilized mostly in the same way. We demonstrate this using a small temporal network example of the IGF (Insulin-like growth receptor) pathway that is included in the package and can be loaded via <<>>= data(igf) @ The model illustrates the activation and feedback inhibition of the PI3K-Akt-mTOR signalling cascade through IGF and IRS. A state transition from the initial state in which the trigger of the pathway -- IGF -- is active, can be performed using <<>>= startState <- generateState(igf, specs=c("IGF"=1)) stateTransition(igf, startState) @ The IGF network incorporates time delays of up to 3. Therefore, the last three states have to be known to calculate a successor state. If only a single state is supplied -- as above -- the function assumes that the state was the same before. This can be seen when calculating the sequence to the attractor using <<>>= getPathToAttractor(network=igf,state=startState) @ Here, the states at $t=-2, \ldots 0$ are the same as the generated start state. If it is required to specify multiple predecessor states here, a matrix of states can be supplied instead of a vector. E.g., <<>>= startState <- generateState(igf, specs=list("IGF"=c(0,0,1))) startState @ specifies that the first two states ($t=-2, t=-1$) should have all genes inactive, while IGF is activated only at $t=0$. This time, we plot the sequence instead of printing it: \begin{figure}[bt] \centering \includegraphics[width=0.6\linewidth]{sequence_igf} \caption{Visualization of a sequence of states in the IGF network. The columns of the table represent consecutive states of the time series. After activation of IGF, the attractor consisting of 14 states is entered immediately. This attractor represents the activation and inactivation of the PI3K-Akt-mTOR signalling cascade through IGF and IRS.} \label{fig:sequence_igf} \end{figure} <>= plotSequence(network=igf, startState=startState) @ The result is depicted in Figure~\ref{fig:sequence_igf}. \texttt{stateTransition()} can also perform asynchronous updates. A random asynchronous transition is performed using <>= set.seed(54321) @ <<>>= stateTransition(cellcycle, rep(1,10), type="asynchronous") @ In this case, the fifth gene, CycA, was chosen at uniformly at random and updated. \begin{samepage} We can also specify non-uniform probabilities for the genes, for example <>= set.seed(4321) @ <<>>= stateTransition(cellcycle, rep(1,10), type="asynchronous", geneProbabilities=c(0.05,0.05,0.2,0.3,0.05,0.05,0.05,0.05,0.1,0.1)) @ This obviously increases probabilities for the genes 3 and 4 (E2F and CycE) to be chosen. In this case, CycE was chosen for the update. \end{samepage} \enlargethispage{0.5cm} Sometimes you do not want a random update at all, but would like to specify which gene should be chosen for the update. This is possible via <<>>= stateTransition(cellcycle, rep(1,10), type="asynchronous", chosenGene="CycE") @ In probabilistic Boolean networks, a state transition is performed by choosing one of the alternative functions for each gene and applying this set of functions to the current state. The following performs a state transition with a randomly chosen set of functions on the artificial probabilistic Boolean network taken from \cite{shmulevich02} with 3 genes, starting from state (0,1,1): <>= set.seed(432) @ <<>>= data(examplePBN) stateTransition(examplePBN, c(0,1,1), type="probabilistic") @ You may get a different result, as the functions are chosen randomly according to the probabilities stored in the network. If you would like to execute a specific set of transition functions, you can supply this in an additional parameter: <<>>= stateTransition(examplePBN, c(0,1,1), type="probabilistic", chosenFunctions=c(2,1,2)) @ This call uses the second function for gene x1 and x3 and the first function for gene x2. \subsection{Identification of attractors} Attractors are stable cycles of states in a Boolean network. As they comprise the states in which the network resides most of the time, attractors in models of gene-regulatory networks are expected to be linked to phenotypes \cite{kauffman93,li04}. Transitions from all states in a Boolean network eventually lead to an attractor, as the number of states in a network is finite. All states that lead to a certain attractor form its {\em basin of attraction}. \texttt{BoolNet} is able to identify attractors in synchronous and asynchronous Boolean networks. There are three types of attractors in these networks: \begin{description} \item[Simple attractors]{occur in synchronous and temporal Boolean networks and consist of a set of states whose synchronous transitions form a cycle.} \item[Complex or loose attractors]{are the counterpart of simple attractors in asynchronous networks. As there is usually more than one possible transition for each state in an asynchronous network, a complex attractor is formed by two or more overlapping loops. Precisely, a complex attractor is a set of states in which all asynchronous state transitions lead to another state in the set, and a state in the set can be reached from all other states in the set.} \item[Steady-state attractors]{are attractors that consist of only one state. All transitions from this state result in the state itself. These attractors are the same both for synchronous and asynchronous update of a network. Steady states are a special case of both simple attractors and complex attractors.} \end{description} The \texttt{getAttractors()} function incorporates several methods for the identification of attractors in synchronous and asynchronous networks. We present these methods using the included mammalian cell cycle network as an example. This network has one steady-state attractor, one simple synchronous attractor consisting of 7 states, and one complex asynchronous attractor with 112 states (see \cite{faure06}). We first demonstrate the use of exhaustive synchronous search. This means that the software starts from all possible states of the network and performs synchronous state transitions until a simple or steady-state attractor is reached. \pagebreak[4] <>= data(cellcycle) attr <- getAttractors(cellcycle) attr @ \begin{lstlisting}[linewidth=.9\linewidth] <>= attr <- getAttractors(cellcycle) attr @ \end{lstlisting} Typing \texttt{attr} calls a special print method that presents the attractor in a human-readable way. Here, a state in an attractor is represented by a binary vector, where each entry of the vector codes for one gene. An alternative is to print only the names of the active genes (i.e., the genes that are set to 1) instead of the full vector by calling the \texttt{print()} method explicitly with a changed parameter: <>= print(attr, activeOnly=TRUE) @ \begin{lstlisting}[linewidth=.9\linewidth] <>= print(attr, activeOnly=TRUE) @ \end{lstlisting} We can see that the search identified both synchronous attractors. \begin{sloppypar} The \texttt{AttractorInfo} structure stores the attractors in an encoded form. The function \texttt{getAttractorSequence()} can be used to obtain the sequence of states that constitute a specific synchronous attractor as a table: \end{sloppypar} <<>>= getAttractorSequence(attr, 2) @ retrieves the states that make up the second (i.e., the 7-state attractor) as a data frame with the genes in the columns and the successive states in the rows. The advantage of the exhaustive search method is that the complete transition table is calculated and stored in the return value. This table stores information that is used by a number of analysis methods described below. You can extract the transition table in a data frame and print it out using <>= tt <- getTransitionTable(attr) tt @ \begin{verbatim} State Next state Attr. basin # trans. to attr. 0000000000 => 0110010111 1 4 [...] 1111111111 => 1000001110 2 1 Genes are encoded in the following order: CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB \end{verbatim} In the printed table, the first column denotes the initial state, the second column contains the state after the transition, the first column contains the number of the attractor that is finally reached from this state, and the fourth column lists the number of state transitions required to attain this attractor. A table of the same structure is returned by <>= getBasinOfAttraction(attr, 1) @ which extracts all states from the transition table that belong to the basin of attraction of attractor one (i.e., whose attractor number in column 3 is 1). If you are interested in information on a single state (here: the state with all genes set to 1), you can type <>= getStateSummary(attr, c(1,1,1,1,1,1,1,1,1,1)) @ \begin{verbatim} State Next state Attr. basin # trans. to attr. 1111111111 => 1000001110 2 1 Genes are encoded in the following order: CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB \end{verbatim} The visualization function \texttt{getStateGraph()} makes use of the transition table as well: It plots a transition graph in which the basins of attraction are drawn in different colors, and the attractors are highlighted. The result of <>= plotStateGraph(attr) @ is depicted at the top of Figure~\ref{fig:stategraph}. The blue basin belongs to attractor 1, and the green basin belongs to attractor 2. The above call does not ensure that the basins of attraction are clearly separated in the plot. If this is desired, one can choose to use a piecewise layout, which means that the layouting function is applied separately to each basin of attraction, and the basins are drawn side by side. The result of <>= plotStateGraph(attr, piecewise=TRUE) @ is depicted at the bottom of Figure~\ref{fig:stategraph}. \begin{figure}[p] \centering \includegraphics[width=0.7\linewidth]{stategraph1} \includegraphics[width=0.7\linewidth]{piecewisestategraph} \caption{The state graph of the mammalian cell cycle network using the regular layout (top) and using a piecewise layout (bottom). Each node represents a state of the network, and each arrow is a state transition. The colors mark different basins of attraction. Attractors are highlighted using bold lines.} \label{fig:stategraph} \end{figure} Exhaustive search consumes a high amount of time and memory with increasing size of the network, which makes it intractable for large networks (\texttt{BoolNet} currently supports networks with up to 29 genes for exhaustive search due to memory restrictions in {\em R}). Therefore, \texttt{BoolNet} also allows for heuristic search of attractors, which works for larger networks as well. Heuristic synchronous search starts from a predefined small set of states and identifies the attractors to which state transitions from these states lead. The start states can either be supplied, or they can be calculated randomly. <>= attr <- getAttractors(cellcycle, method="random", startStates=100) @ chooses 100 random start states for the heuristic search and usually identifies both attractors. <>= attr <- getAttractors(cellcycle, method="chosen", startStates=list(rep(0,10),rep(1,10))) @ starts from the states \texttt{(0,0,0,0,0,0,0,0,0,0)} and \texttt{(1,1,1,1,1,1,1,1,1,1)} and again identifies both synchronous attractors. \begin{sloppypar} For the previous calls, only the subset of the transition table traversed by the heuristic is returned. This means that there is no guarantee that, e.g. \texttt{getBasinOfAttraction()} returns the complete basin of attraction of an attractor in heuristic mode. \end{sloppypar} Synchronous attractors can be visualized by plotting a table of changes of gene values in the states of the attractor: <>= plotAttractors(attr, subset=2) @ plots the state changes of the simple attractor with 7 states, as depicted in Figure~\ref{fig:attractor1}. Similarly, <>= attractorsToLaTeX(attr, subset=2, file="attractors.tex") @ exports the same state table to a \LaTeX\ document. \begin{figure}[t] \centering \includegraphics[width=0.65\linewidth]{attractor1} \caption{Visualization of the state changes in an attractor. The columns of the table represent consecutive states of the attractor.} \label{fig:attractor1} \end{figure} To identify asynchronous attractors, another special heuristic algorithm is included. This algorithm again starts from a small subset of states and makes a number of random transitions to reach an attractor with a high probability. After that, a validation step is performed to analyze whether a complex attractor has been identified. The command <>= attr <- getAttractors(cellcycle, type="asynchronous", method="random", startStates=500) @ conducts an asynchronous search with 500 random start states on the mammalian cell cycle network. In this case, the algorithm has identified both the steady-state attractor and the complex attractor: \enlargethispage{0.5cm} <>= attr @ \begin{verbatim} Attractor 1 is a simple attractor consisting of 1 state(s): |--<---------| V | 0100010100 | V | |-->---------| Genes are encoded in the following order: CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB Attractor 2 is a complex/loose attractor consisting of 112 state(s) and 338 transition(s): 1011101111 => 1011101110 [...] 1000000000 => 1010000000 Genes are encoded in the following order: CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB \end{verbatim} For the complex attractor, the involved transitions are printed out. By default, the algorithm tries to avoid self-loops, i.e. transitions that lead to the same state again. This means that self-loop transitions are only allowed if there is no other transition that leads to a different state. If you would like to allow the algorithm to enter self-loops even if transitions to different states are possible, you can call <>= attr <- getAttractors(cellcycle, type="asynchronous", method="random", startStates=500, avoidSelfLoops=FALSE) @ In the resulting complex attractor with 112 states, there are 450 transitions instead of 338 transitions, which is due to the additional self-loops. The asynchronous heuristic search does not return a transition table, such that the above analysis methods cannot be applied here. \begin{figure}[tb] \centering \includegraphics[width=0.55\linewidth]{attractor2} \caption{Graph representation of the complex attractor in the mammalian cell cycle network. Each node represents a state of the complex attractor, and each arrow represents a state transition.} \label{fig:attractor2} \end{figure} As there are multiple possible transitions for each state, complex attractors cannot be visualized as in Figure~\ref{fig:attractor1}. For this reason, \texttt{plotAttractors()} supports a graph mode that visualizes the transitions among the states in the attractor: <>= plotAttractors(attr, subset=2, mode="graph", drawLabels=FALSE) @ plots the 112-state attractor as depicted in Figure~\ref{fig:attractor2}. We omit the state labels (i.e. the gene values) due to the high number of states. This plot again requires the \texttt{igraph} package. \begin{sloppypar} Although \texttt{getAttractors()} can also be applied to temporal networks and other networks that are in a symbolic representation (i.e. \emph{SymbolicBooleanNetwork} objects), this function is only a shortcut to the simulation function \texttt{simulateSymbolicModel()} in this case. It is advised to use \texttt{simulateSymbolicModel()} directly , as it provides more options. For the temporal model of the IGF pathway included in \texttt{BoolNet}, an exhaustive simulation can be performed as follows: \end{sloppypar} <>= sim <- simulateSymbolicModel(igf) sim @ \begin{lstlisting}[linewidth=.9\linewidth] <>= sim <- simulateSymbolicModel(igf) sim @ \end{lstlisting} By default, the result object of class \emph{SymbolicSimulation} comprises several components: \begin{itemize} \item A list of sequences \texttt{sequences} from each start state to the corresponding attractor. If this component is not desired, the parameter \texttt{returnSequences} can be set to false. \item A graph structure \texttt{graph} that comprises all traversed state transitions. If this component is not desired, the parameter \texttt{returnGraph} can be set to false. \item The identified attractors \texttt{attractors}. If this component is not desired, the parameter \texttt{returnAttractors} can be set to false. \end{itemize} In this case, the network has two attractors: A steady state describes the inactive state of the pathway. The circular attractor describes the activation and inactivation of the PI3K-Akt-mTOR signalling cascade initiated by IGF. All visualization and analysis function described above can also be applied to the simulation results obtained by \texttt{simulateSymbolicModel}. For example, the cascade attractor can be visualized via <>= plotAttractors(sim, subset=2) @ Similarly, <>= plotStateGraph(sim) @ plots the state transition graph of the network. Unlike in classical synchronous networks, a state can have multiple successor states (outgoing edges) in temporal networks, as a state transition may also depend on the history of states before the current state. The two plots are shown in Figure~\ref{fig:temporal_plots}. \begin{figure}[p] \centering \includegraphics[width=0.6\linewidth]{attractor3} \includegraphics[width=0.6\linewidth]{stategraph2} \caption{Top: Visualization of an attractor that describes the activation and inactivation of the PI3K-Akt-mTOR signalling cascade through IGF and IRS. The columns of the table represent consecutive states of the attractor. On top, the percentage of states leading to the attractor is supplied.\newline Bottom: The state transition graph of the IGF pathway network. Each node represents a state of the network, and each arrow is a state transition. The colors mark different basins of attraction. } \label{fig:temporal_plots} \end{figure} For temporal networks, it is often infeasible to perform an exhaustive search, as the search space is not only exponential in the number of genes, but also in the time delays. Hence, the search can also be restricted to randomly generated or prespecified start states similarly to \texttt{getAttractors()}. If time delays of more than 1 are included in the network, not only single start states are generated, but the required history of states is generated as well. For example, <>= set.seed(43851) @ <<>>= sim <- simulateSymbolicModel(igf, method="random", startStates=2) @ generates two start state matrices, each comprising 3 states (the maximum delay of the IGF network), and uses them as the basis for a simulation. This can be seen when examining the sequences to the attractors: <<>>= sim$sequences @ Both sequences comprise start states $t=-2$, $t=-1$ and $t=0$. \begin{sloppypar} Classical synchronous Boolean networks can also be simulated using the symbolic simulator \texttt{simulateSymbolicModel()} if they are in a symbolic form. However, in most cases, \texttt{getAttractors()} will be faster and will consume less memory for synchronous networks without temporal elements. Only if the number of inputs to genes is very high and exhaustive simulation is not required, it may be advisable to use the symbolic simulator. \end{sloppypar} \subsection{Markov chain simulations} Another way of identifying relevant states in Boolean networks are Markov chain simulations. Instead of identifying cycles explicitly, these simulations calculate the probability that a certain state is reached after a predefined number of iterations. Of course, states in an attractor have a high probability of being reached if the number of iterations is chosen large enough. Markov chain simulations for probabilistic Boolean networks were introduced by Shmulevich et al. \cite{shmulevich02}. As a special case of probabilistic Boolean networks, these simulations are also suited for synchronous Boolean networks. The following performs a Markov experiment with the predefined number of 1000 iterations on the example PBN described in \cite{shmulevich02}: \enlargethispage{-0.5cm} <<>>= data(examplePBN) sim <- markovSimulation(examplePBN) sim @ Only states with a non-zero probability are listed in the two tables. The first table shows the states that are reached after 1000 iterations. The second table is a transition table annotated with transition probabilities. This table can be suppressed by the parameter \texttt{returnTable=FALSE}. The results correspond exactly to those in \cite{shmulevich02}. If the transition table is included in the simulation results, we can plot a graph of the network: <>= plotPBNTransitions(sim) @ This graph is displayed in Figure~\ref{fig:pbntransitions}. The vertices are the states of the graph. The edges represent transitions and are annotated with the corresponding transition probabilities. For this plot, the \texttt{igraph} package must be installed. \begin{figure}[h] \centering \includegraphics[width=0.65\linewidth]{pbntransitions} \caption{State transition graph of the example probabilistic Boolean network included in \texttt{BoolNet}. Each node represents a state of the network, and each arrow is a possible state transition, annotated by the transition probability.} \label{fig:pbntransitions} \end{figure} We can also use Markov chain simulations to identify the attractor states in the mammalian cell cycle network: \begin{samepage} <<>>= data(cellcycle) sim <- markovSimulation(cellcycle, numIterations=1024, returnTable=FALSE) sim @ \end{samepage} We set the maximum number of iterations to 1024, which is the number of states in the network. In a deterministic network, this guarantees that all states are found. The fourth state in the returned table is the steady-state attractor identified previously. It has a probability of 0.5, as the basin of attraction is exactly half of the states. The other 7 states belong to the simple synchronous attractor. It is also possible to restrict the simulation to a certain set of input states instead of using all possible input states. In the following example, we only consider the state with all genes set to 1, and identify the state belonging to the steady-state attractor again: \begin{samepage} <<>>= sim <- markovSimulation(cellcycle, numIterations=1024, returnTable=FALSE, startStates=list(rep(1,10))) sim @ \end{samepage} \subsection{Robustness assessment} A biological network is assumed to be robust to small amounts of noise. The plausibility of network models is therefore often assessed by testing its robustness to noise and mismeasurements. Typically, artificial noise is applied, and its influence on the behaviour of a network is measured. There are two major ways of applying random noise: Either the current state of a network in a simulation can be perturbed, or the network structure itself can be perturbed. \texttt{BoolNet} includes functions for both types of robustness assessment. The function \texttt{perturbTrajectories} measures the influence of noise that is applied to the current network state. It generates a set of initial states and creates perturbed copies of these states by randomly flipping bits. It then measures the influence of the flips on the further dynamic behaviour of the network. For example <>= set.seed(3361) @ <<>>= data(cellcycle) r <- perturbTrajectories(cellcycle, measure="hamming", numSamples=100, flipBits=1) @ randomly generates 100 states and 100 copies with one bitflip and performs a single state transition for each state. It then measures the normalized Hamming distance (the fraction of different bits) between each state and the corresponding perturbed copy. A robust network is assumed to yield a low Hamming distance. The average distance can be viewed by typing <<>>= r$value @ A related measure is the average sensitivity. This measure assesses only a single transition function and counts the number of successor states that differ between the original states and the perturbed copies for the corresponding gene. E.g., <<>>= r <- perturbTrajectories(cellcycle, measure="sensitivity", numSamples=100, flipBits=1, gene="CycE") r$value @ measures the average sensitivity of the transition function for gene CycE. The long-term behaviour can be evaluated by comparing the attractors that are reached from the initial states and their perturbed copies. <<>>= r <- perturbTrajectories(cellcycle, measure="attractor", numSamples=100, flipBits=1) r$value @ measures the fraction of pairs of states and perturbed copies that yield the same attractors. It can be assumed that small changes in the state should not influence the long-term behaviour of the network, and hence the attractors should mostly be the same. The second class of perturbations adds random noise to the network itself. This is implemented in the \texttt{perturbNetwork()} function. Unlike \texttt{perturbTrajectories()}, this function does not perform any simulations, but returns a perturbed copy of the network that can be analyzed further. \texttt{BoolNet} includes a set of different perturbation options that can be combined. For example, <<>>= perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="bitflip") @ chooses a function of the network at random and flips a single bit in this function. By setting the parameter \texttt{maxNumBits}, you can also flip more than one bit at a time. Instead of flipping bits, <<>>= perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="shuffle") @ randomly permutes the output values of the chosen transition functions. This preserves the numbers of 0s and 1s, but may change the Boolean function completely. These kinds of perturbations are supported for synchronous and asynchronous networks as well as for probabilistic networks. For synchronous networks, a further perturbation mode is available: <<>>= perturbedNet <- perturbNetwork(cellcycle, perturb="transitions", method="bitflip", numStates=10) @ Here, \texttt{BoolNet} calculates the complete transition table of the network and then flips a single bit in 10 states of the transition table. From this modified table, a network is reconstructed. Changes of this type only affect a few states (which might not be the case when perturbing the functions directly as above), but possibly several of the transition functions. As in the previous examples, it is also possible to modify the number of bits to be flipped or to choose \texttt{method="shuffle"}. \begin{samepage} A detailed listing of a perturbation experiment is shown below. In this experiment, 1000 perturbed copies of the cell cycle network are created, and the occurrences of the original synchronous attractors are counted in the perturbed copies. This is similar to the simulation in \texttt{perturbTrajectories()} with \texttt{measure="attractor"}. However, instead of comparing the outcomes of different initial states in the same network, it compares all attractors of different perturbed networks to all attractors of the original network by exhaustive search. \begin{footnotesize}\label{alg:perturbation} <>= # Perform a robustness test on a network # by counting the numbers of perturbed networks # containing the attractors of the original net library(BoolNet) # load mammalian cell cycle network data(cellcycle) # get attractors in original network attrs <- getAttractors(cellcycle, canonical=TRUE) # create 1000 perturbed copies of the network and search for attractors perturbationResults <- sapply(1:1000, function(i) { # perturb network and identify attractors perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="bitflip") perturbedAttrs <- getAttractors(perturbedNet, canonical=TRUE) # check whether the attractors in the original network exist in the perturbed network attractorIndices <- sapply(attrs$attractors,function(attractor1) { index <- which(sapply(perturbedAttrs$attractors, function(attractor2) { identical(attractor1, attractor2) })) if (length(index) == 0) NA else index }) return(attractorIndices) }) # perturbationResults now contains a matrix # with the first 2 columns specifying the indices or the # original attractors in the perturbed network # (or NA if the attractor was not found) and the next 2 # columns counting the numbers of states # in the basin of attraction (or NA if the attractor was not found) # measure the total numbers of occurrences of the original attractors in the perturbed copies numOccurrences <- apply(perturbationResults[seq_along(attrs$attractors),,drop=FALSE], 1, function(row)sum(!is.na(row))) # print original attractors cat("Attractors in original network:\n") print(attrs) # print information cat("Number of occurrences of the original attractors", "in 1000 perturbed copies of the network:\n") for (i in 1:length(attrs$attractors)) { cat("Attractor ",i,": ",numOccurrences[i],"\n",sep="") } @ \end{footnotesize} \end{samepage} \pagebreak[4] \begin{samepage} The results of such an experiment could look like this: \begin{verbatim} Attractors in original network: Attractor 1 is a simple attractor consisting of 1 state(s) and has a basin of 512 state(s): [...] Attractor 2 is a simple attractor consisting of 7 state(s) and has a basin of 512 state(s): [...] Number of occurrences of the original attractors in 1000 perturbed copies of the network: Attractor 1: 622 Attractor 2: 589 \end{verbatim} \end{samepage} We see that the steady-state attractor is slightly more robust to perturbations than the simple attractor with 7 states, as it can be identified in a higher number of perturbed copies. \subsection{Identifying specific properties of biological networks} The described robustness measures could also be used to identify specific properties of real-world networks in comparison to arbitrary (random) networks. For example, one could assume that attractors in biological networks are more robust to perturbations than attractors in random networks with a similar structure, as they should be capable of compensating for small dysfunctions of their components. Similarly to the above code, one could execute a number of random perturbations on the biological network and measure the percentage of original attractors found in the perturbed copies. Afterwards, one could repeat this process on a number of randomly generated networks -- i.e., generate perturbed copies from each of the random networks, and measure the percentage of attractors in the copies. If the percentage of the biological network is higher than most of the percentages of the random network, this suggests that the biological network exhibits a higher robustness. This is a kind of computer-intensive test. \texttt{BoolNet} comprises a generic facility for such computer-intensive tests. This facility already includes several tests (mainly for synchronous Boolean networks) and can be extended by custom test functions. The outlined example of attractor robustness is one of the integrated functions: <>= data(cellcycle) res <- testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testAttractorRobustness", testFunctionParams = list(copies=100, perturb="functions")) @ creates a set of 100 random networks (each with the same number of input genes for the functions as the cell cycle network) and creates 100 perturbed copies for each of these networks and for the cell cycle network by applying \texttt{perturbNetwork()} with \texttt{perturb="functions"}. For each network, it then calculates the percentage of attractors that can still be found in the perturbed copies. The function plots a histogram of this robustness measures of the random networks (see Figure~\ref{fig:robustness}, top panel). The corresponding value of the original cell cycle network is plotted as a red line, and the 95\% quantile is plotted as a blue line. \begin{figure}[p] \centering \includegraphics[width=0.6\linewidth]{attractor_robustness} \includegraphics[width=0.6\linewidth]{transition_robustness} \caption{Top: Attractor robustness of randomly generated networks (histogram) in comparison to the mammalian cell cycle network (red line).\newline Bottom: Normalized Hamming distance of randomly generated networks (histogram) in comparison to the mammalian cell cycle network (red line). } \label{fig:robustness} \end{figure} We can see that the average percentage of found attractors is significantly higher in the biological network with a $p$-value of 0.01. \begin{sloppypar} It is also possible to perturb the states instead of the networks themselves by setting \texttt{perturb} to \texttt{"trajectories"}. In this case, the function applies \texttt{perturbTrajectories()} with \texttt{measure="attractor"} to the biological network and the randomly generated networks. It then tests whether the fraction of state pairs that yield the same attractor is higher in the biological network than in the randomly generated networks. The second built-in test function also tests the robustness of the network behaviour by perturbing the network states: \texttt{testTransitionRobustness()} applies \texttt{perturbTrajectories()} with \texttt{measure="hamming"} to each network. It then checks whether random bit flips yield a higher Hamming distance of the successor states in randomly generated networks than in the biological model, i.e. whether noise in the states influences the randomly generated networks stronger than the biological model. In contrast to the previous measures for which a greater value was assumed in the biological model, the Hamming distance is assumed to be smaller. Hence, we must specify the test alternative as \texttt{alternative="less"}. \end{sloppypar} <>= testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testTransitionRobustness", testFunctionParams=list(numSamples=100), alternative="less") @ The results are shown in the bottom panel of Figure~\ref{fig:robustness}. Again, the result is highly significant (indeed, the Hamming distances are \emph{always} lower in the biological network), which means that the biological network is considerably more robust to noise in the states than the randomly generated models. Another network property can also be tested using a built-in function: When looking at the state graph of a biological network (which can be generated using \texttt{plotStateGraph()}), it can often be observed that many state transitions lead to the same successor states, which means that the dynamics of the network quickly concentrate on a few states after a number of state transitions. We call the number of states whose synchronous state transitions lead to a state $s$ the {\em in-degree} of state $s$. We expect the biological network to have a few states with a high in-degree and many states with a low in-degree. A characteristic to summarize the in-degrees is the Gini index, which is a measure of inhomogeneity. If all states have an in-degree of 1, the Gini index is 0; if all state transitions lead to only one state, the Gini index is 1. <>= testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testIndegree") @ plots an histogram of Gini indices in 100 random networks and draws the Gini index of the cell cycle network as a red line, as depicted in the top panel of Figure~\ref{fig:indegree}. \begin{figure}[p] \centering \includegraphics[width=0.6\linewidth]{indegree} \includegraphics[width=0.6\linewidth]{indegree_kl} \caption{Top: Gini indices of state in-degrees of randomly generated networks (histogram) in comparison to the mammalian cell cycle network (red line)\newline Bottom: Kullback-Leibler distances of in-degrees of the mammalian cell cycle network and 100 random networks.} \label{fig:indegree} \end{figure} The histogram shows that the Gini index of the in-degrees is always higher in the biological network. This is probably due to the special structure of functions in biological networks. Instead of accumulating the in-degrees using the Gini index, it is also possible to compare the distributions of the in-degrees across the networks. For this purpose, the Kullback-Leibler distances of the in-degrees of the supplied network and each of the random networks are calculated and plotted in a histogram. The Kullback-Leibler distance (also called relative entropy) is an asymetric measure of similarity of two distributions \cite{cover91}. If the distributions are equal, the Kullback-Leibler distance is 0, otherwise it is greater than 0. <>= testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testIndegree", accumulation="kullback_leibler") @ results in the plot displayed in the bottom panel of Figure~\ref{fig:indegree}. It is possible to switch between the histogram of an accumulated characteristic (e.g. the Gini index) and the histogram of the Kullback-Leibler distances for all tests. \begin{sloppypar} You can also easily implement your own tests. To do this, the only thing you have to do is implement a custom testing function that replaces \texttt{testIndegree()} or \texttt{testAttractorRobustness()}. Testing functions have the following signature: \end{sloppypar} \begin{verbatim} function(network, accumulate=TRUE, params) \end{verbatim} The first parameter is the network that should be tested. The parameter \texttt{accumulate} specifies whether a single characteristic value (e.g., the Gini index of the in-degrees) should be calculated, or whether a distribution of values (e.g., a vector of all in-degrees) should be returned. The third parameter is a list of further arguments needed by your function. If, for example, we would like to compare the sizes of the basins of attractions of synchronous attractors in biological and random networks, we would write a function like this: \begin{samepage} <<>>= testBasinSizes <- function(network, accumulate=TRUE, params) { attr <- getAttractors(network) basinSizes <- sapply(attr$attractors, function(a) { a$basinSize }) if (accumulate) return(mean(basinSizes)) else return(basinSizes) } @ \end{samepage} This function calculates the mean basin size as a characteristic value if accumulation is required, or returns the sizes of all basins of attraction in a vector otherwise. It does not need any further parameters in \texttt{params}. Now, we can start a test using <>= testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testBasinSizes", xlab="Average size of basins of attraction") @ to produce the plot shown in Figure~\ref{fig:basinsize}. Apparently, the average basin sizes do not differ as much as the built-in test characteristics between the random networks and the cell cycle network. \begin{figure}[h] \centering \includegraphics[width=0.6\linewidth]{basinsize} \caption{A custom test statistic measuring the basin sizes on randomly generated networks (histogram) and the mammalian cell cycle network (red line).} \label{fig:basinsize} \end{figure} \begin{sloppypar} By writing custom test functions, you can extend the test facility to perform a wide variety computer-intensive test. Of course, it is also possible to plot the Kullback-Leibler distances with such new methods by using \verb+accumulation="kullback_leibler"+. \texttt{testNetworkProperties()} accepts most of the parameters of \texttt{generateRandomNKNetwork()}. If necessary, you can generate more specialized kinds of random networks which resemble the original network in certain aspects, for example by specifying a generation function or by setting a proportion of 0 and 1 in the function outputs similar to the original network using \verb+functionGeneration="biased"+. \end{sloppypar} \clearpage \section{Import and export}\label{sec:importexport} \subsection{Saving networks in the \texttt{BoolNet} file format} Corresponding to the \texttt{loadNetwork()} command, a network can be saved using \texttt{saveNetwork()}. This stores the network in the network file format described in Section~\ref{sec:appendix} and can be applied to all types of networks supported by \texttt{BoolNet}. For example, the cell cycle network can be saved using <>= saveNetwork(cellcycle, file="cellcycle.txt") @ \begin{sloppypar} The function stores the expressions that describe the transition functions. In some cases, there may not always be a valid symbolic description of the networks (e.g. for networks returned by \texttt{generateRandomNKNetwork()} when the \texttt{readableFunctions} parameter was not set). In this case, \texttt{saveNetwork()} can generate symbolic representations of the transition functions in Disjunctive Normal Form (DNF): \end{sloppypar} <<>>= net <- generateRandomNKNetwork(n=10, k=3, readableFunctions=FALSE) saveNetwork(net, file="randomnet.txt", generateDNF=TRUE) @ The \texttt{generateDNF} parameter can also be used to detail which type of DNF formulae should be exported: \texttt{generateDNF="canonical"} exports canonical DNF formulae. \texttt{generateDNF="short"} minimizes the canonical functions by joining terms. By simply setting \texttt{generateDNF=TRUE}, formulae with up to 12 inputs are minimized, and formulae with more than 12 inputs are exported in a canonical form, as a minization is very time-consuming in this case. \subsection{Import from and export to SBML} \begin{sloppypar} \texttt{BoolNet} provides an interface to the widely used Systems Biology Markup Language (SBML) via the import function \texttt{loadSBML()} and the export function \texttt{saveSBML()}. As the core SBML does not fully support Boolean models, import and export of SBML models is based on the \texttt{sbml-qual} package which extends SBML by several qualitative modeling approaches, such as general logical models and Petri nets. For a full description of \texttt{sbml-qual}, refer to \href{http://sbml.org/Documents/Specifications/SBML_Level_3/Packages/Qualitative_Models_(qual)}{http://sbml.org/Documents/Specifications/SBML\_Level\_3/Packages/Qualitative\_Models\_(qual)}. \end{sloppypar} \texttt{BoolNet} only supports a subset of \texttt{sbml-qual}. It can read and write logical models with two possible values for each state, which are equivalent to Boolean networks. Logical models with more than two values for a gene or Petri nets cannot currently be handled by \texttt{BoolNet}. An export to SBML is usually not associated with any loss of information. For example, we can write the cell cycle network to a file and re-import it into \texttt{BoolNet}: \begin{footnotesize} <>= toSBML(cellcycle, file="cellcycle.sbml") sbml_cellcycle <- loadSBML("cellcycle.sbml") sbml_cellcycle @ \end{footnotesize} Apart from some additional brackets, the re-imported network coincides with the original network. Similar to the \texttt{saveNetwork()} function, \texttt{toSBML()} exports a symbolic representation of the network transition functionss, which may not always be available. As for \texttt{saveNetwork()}, there is a parameter \texttt{generateDNF} that can be set to generate a symbolic representation in Disjunctive Normal Form from the truth tables. \subsection{Importing networks from BioTapestry} BioTapestry is a widely-used application for visual modeling of gene-regulatory networks \cite{longabaugh05}. It can be freely accessed at \url{http://www.biotapestry.org}. Although its primary purpose is visualization, the software supports specifying logical functions for the genes. \texttt{BoolNet} can read in the top-level (``Full genome'') plot of a BioTapestry file (*.btp) and convert it into a Boolean network. As an example, we assume the following BioTapestry model with 5 genes (2~inputs and 3~dependent genes): \begin{center} \includegraphics[width=0.8\linewidth]{biotap_model} \end{center} The corresponding BioTapestry file is included in \texttt{BoolNet}. You can determine its path using <>= system.file("doc/example.btp", package="BoolNet") @ \label{cmd:example.btp} to access it in BioTapestry or \texttt{BoolNet}. For the import, \texttt{BoolNet} needs to know the type of influence a gene has on another gene. Therefore, imported networks should only use links that are either enhancers or repressors. Neutral links are ignored in the import. We now set further simulation parameters for the model. These parameters are imported by \texttt{BoolNet} to construct the functions of the Boolean network. First, we want to change the function of Gene~2 to \texttt{OR}. Right-click on Gene~2 and choose \texttt{Simulation Properties...}. \begin{center} \includegraphics[width=0.8\linewidth]{biotap_sim_properties} \end{center} In the properties dialog, choose the \texttt{Logic} tab, and select \texttt{OR} for the logical function. \begin{center} \includegraphics[width=0.8\linewidth]{biotap_logic} \end{center} Now set the function of Gene~1 to \texttt{XOR} (exclusive or) in the same way. \begin{samepage} You can also specify initial values for constant genes, i.e., genes with no input links. Choose the simulation properties of Input~1, and change to the \texttt{Parameters} tab. Choose \texttt{initVal} and set it to 1. \begin{center} \includegraphics[width=0.8\linewidth]{biotap_initval} \end{center} \end{samepage} Press Return to store the result, and exit the dialog with \texttt{OK}. This will create a fixed gene with value 1 (i.e., an over-expressed gene) in the \texttt{BoolNet} import. Note that values other than 0 and 1 are ignored by the import, as well as initialization values for non-constant genes. We assume that you save the network to a file ``example.btp'' in your working directory. In \texttt{R}, type <>= net <- loadBioTapestry(system.file("doc/example.btp", package="BoolNet")) @ <>= net <- loadBioTapestry("example.btp") @ to import the network. Alternatively, replace the file name by the command on page~\pageref{cmd:example.btp} to use the file in the package if you do not want to create the file yourself. The imported network looks like this: <>= net @ \begin{verbatim} Boolean network with 5 genes Involved genes: Input 1 Input 2 Gene 1 Gene 2 Gene 3 \end{verbatim} \pagebreak[4] \begin{verbatim} Transition functions: Input 1 = 1 Input 2 = Input 2 Gene 1 = (!Gene 1 & !Input 1 & Input 2) | (!Gene 1 & Input 1 & !Input 2) | (Gene 1 & !Input 1 & !Input 2) | (Gene 1 & Input 1 & Input 2) Gene 2 = Gene 1 & Gene 3 & !Input 2 Gene 3 = Gene 1 | Gene 2 Knocked-out and over-expressed genes: Input 1 = 1 \end{verbatim} We can see that Input~1 is specified as an over-expressed constant gene. Input~2 is modeled as depending only on itself, i.e. it keeps its initial value. Gene~1 is a representation of the XOR function in Disjunctive Normal Form (DNF), using only logical ANDs, logical ORs, and negations. Gene~2 and Gene~3 consist of conjunctions and disjunctions of their inputs respectively. In addition to this textual description, we can visually verify the network by plotting its wiring: <>= plotNetworkWiring(net) @ The resulting plot is shown in Figure~\ref{fig:wiring_biotap}. \begin{figure}[h] \centering \includegraphics[width=0.6\linewidth]{wiring_biotap} \caption{The wiring graph of the imported network specified in BioTapestry.} \label{fig:wiring_biotap} \end{figure} You can now use the imported network just like any other network in \texttt{BoolNet}. \clearpage \subsection{Exporting network simulations to Pajek} For further analysis, network simulations can be exported to Pajek, a Windows application that provides visualization and analysis methods for graph structures \cite{batagelij98}. For more information on Pajek, please refer to \url{http://pajek.imfm.si/doku.php}. The export function writes the state transition graph to a Pajek file (*.net). This requires a synchronous exhaustive attractor search in \texttt{BoolNet} to build the full transition table. To export the mammalian cell cycle network to Pajek, call <>= data(cellcycle) attr <- getAttractors(cellcycle) toPajek(attr, file="cellcycle.net") @ This will export the graph of the state transitions, which is usually sufficient for plotting. If you want to include the state information (i.e., the gene assignment vectors), call <>= toPajek(attr, file="cellcycle.net", includeLabels=TRUE) @ Now, start Pajek, load the network with \texttt{File | Network | Read}, and check out the tools provided by this application. For example, visualizations can be accessed using the menu item \texttt{Draw | Draw}. Figure~\ref{fig:pajek} shows a plot of the cell cycle network with the Kamada-Kawai layout (Menu entry \texttt{Layout | Energy | Kamada-Kawai | Separate Components}). \begin{figure}[h] \centering \includegraphics[width=0.75\linewidth]{pajek} \caption{A visualization of the mammalian cell cycle network in Pajek.} \label{fig:pajek} \end{figure} \clearpage \bibliographystyle{plain} \bibliography{BoolNet_package_vignette} \section{Appendix}\label{sec:appendix} \subsection{Network file format} This section provides a full language description for the network file format of \texttt{BoolNet}. The language is described in Extended Backus-Naur Form (EBNF). For synchronous, asynchronous and probabilistic Boolean networks, the supported format is as follows: \begin{verbatim} Network = Header Newline {Rule Newline | Comment Newline}; Header = "targets" Separator "factors"; Rule = GeneName Separator BooleanExpression [Separator Probability]; Comment = "#" String; BooleanExpression = GeneName | "!" BooleanExpression | "(" BooleanExpression ")" | BooleanExpression " & " BooleanExpression | BooleanExpression " | " BooleanExpression; | "all(" BooleanExpression {"," BooleanExpression} ")" | "any(" BooleanExpression {"," BooleanExpression} ")" | "maj(" BooleanExpression {"," BooleanExpression} ")" | "sumgt(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "sumlt(" BooleanExpression {"," BooleanExpression} "," Integer ")"; GeneName = ? A gene name from the list of involved genes ?; Separator = ","; Integer = ? An integer value?; Probability = ? A floating-point number ?; String = ? Any sequence of characters (except a line break) ?; Newline = ? A line break character ?; \end{verbatim} \pagebreak[4] The extended format for temporal networks includes additional time specifications and temporal predicates is defined as follows: \begin{verbatim} Network = Header Newline {Function Newline | Comment Newline}; Header = "targets" Separator "factors"; Function = GeneName Separator BooleanExpression; Comment = "#" String; BooleanExpression = GeneName | GeneName TemporalSpecification | BooleanOperator | TemporalOperator BooleanOperator = BooleanExpression | "!" BooleanExpression | "(" BooleanExpression ")" | BooleanExpression " & " BooleanExpression | BooleanExpression " | " BooleanExpression; TemporalOperator = "all" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "any" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "maj" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "sumgt" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "sumlt" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "timeis" "(" Integer ")" | "timegt" "(" Integer ")" | "timelt" "(" Integer ")"; TemporalIteratorDef = "[" TemporalIterator "=" Integer ".." Integer "]"; TemporalSpecification = "[" TemporalOperand {"+" TemporalOperand | "-" TemporalOperand} "]"; TemporalOperand = TemporalIterator | Integer TemporalIterator = ? An alphanumeric string ?; GeneName = ? A gene name from the list of involved genes ?; Separator = ","; Integer = ? An integer value?; String = ? Any sequence of characters (except a line break) ?; Newline = ? A line break character ?; \end{verbatim} \end{document} BoolNet/vignettes/BoolNet_package_vignette.Snw.tex0000644000176200001440000007133514272213440022046 0ustar liggesusers\documentclass[a4paper]{article} \SweaveOpts{keep.source=TRUE} %\VignetteIndexEntry{Detailed introduction to all major features of BoolNet} \usepackage{a4wide} \usepackage{graphicx} \usepackage{amsmath} \usepackage{hyperref} \usepackage{listings} \lstset{breaklines=true, breakautoindent=false, breakindent=0pt, columns=fullflexible,keepspaces=true, basicstyle=\small\ttfamily} \setlength{\parindent}{0em} \setlength{\parskip}{0.2em} \title{BoolNet package vignette} \author{Christoph M\"ussel, Martin Hopfensitz, Hans A. Kestler} \widowpenalty=10000 \clubpenalty=10000 \hyphenation{me-thods pro-per-ties re-pre-sen-ta-tion} \begin{document} \SweaveOpts{concordance=TRUE} \maketitle \tableofcontents \clearpage \section{Introduction} \texttt{BoolNet} is an R package that provides tools for assembling, analyzing and visualizing synchronous and asynchronous Boolean networks as well as probabilistic Boolean networks. This document gives an introduction to the usage of the software and includes examples for use cases. \texttt{BoolNet} supports four types of networks: \begin{description} \item[Synchronous Boolean networks]{ consist of a set of Boolean variables \[ X = \left\{X_1, \ldots, X_n \right\} \] and a set of transition functions \[ F=\left\{ f_{1},\ldots,f_{n}\right\}, \] one for each variable. These transition functions map an input of the Boolean variables in $X$ to a Boolean value ($0$ or $1$). We call a Boolean vector $\mathbf{x}(t) = \left(x_1(t), \ldots, x_n(t) \right)$ the {\em state} of the network at time $t$. Then, the next state of the network $\mathbf{x}(t)$ is calculated by applying {\em all} transition functions $f_i(\mathbf{x}(t-1))$. In a biological context, genes can be modeled as Boolean variables ({\em active/expressed} or {\em inactive/not expressed}), and the transition functions model the dependencies among these genes. In the synchronous model, the assumption is that all genes are updated at the same time. This simplification facilitates the analysis of the networks.} \item[Asynchronous Boolean networks]{ have the same structure as synchronous Boolean networks. Yet, at each point of time $t$, only {\em one} of the transition functions $f_i \in F$ is chosen at random, and the corresponding Boolean variable is updated. This corresponds to the assumption that in a genetic network, gene expression levels are likely to change at different points of time. In the most common model, the gene to be updated is chosen uniformly among all genes. Moreover, \texttt{BoolNet} supports specifying non-uniform update probabilities for the genes.} \item[Probabilistic Boolean networks (PBN)]{ allow for specifying more than one transition function per variable/gene. Each of these functions has a probability to be chosen, where the probabilities of all functions for one variable sum up to 1. Formally \[ F=\left\{\left\{\left(f_{11}, p_{11}\right), \ldots, \left(f_{1k_1}, p_{1k_1}\right)\right\}, \ldots, \left\{\left(f_{n1}, p_{n1}\right), \ldots, \left(f_{nk_n}, p_{nk_n}\right)\right\}\right\} \] where $k_i$ is the number of alternative transition functions for variable $i$, and $p_{ij}$ is the probability that function $j$ is chosen for variable $i$. A state transition is performed by selecting one function for each gene based on the probabilities and applying the chosen functions synchronously.} \item[Temporal Boolean networks]{ are Boolean networks that incorporate temporal predicates and discrete time delays. Here, the next state $x(t)$ may not only depend on $x(t-1)$, but can depend on any predecessor state $x(t - \Delta), \Delta \in \{1, 2, \ldots\}$. Furthermore, $x(t)$ may also directly depend on the time step $t$ itself. } \end{description} In \texttt{BoolNet}, there are different structure classes representing these network types: \begin{description} \item[\emph{BooleanNetwork} objects]{ contain synchronous and asynchronous Boolean networks. Here, the transition functions are internally represented as truth tables.} \item[\emph{ProbabilisticBooleanNetwork} objects]{ encode Probabilistic Boolean networks. They use a truth table representation as well.} \item[\emph{SymbolicBooleanNetwork} objects]{ represent synchronous and temporal Boolean networks. They encode Boolean functions in a symbolic form, i.e. as expression trees.} \end{description} As we have seen, the networks are represented in two different forms: The truth table representation, which basically maps inputs to the corresponding output values, is usually the most efficient representation for synchronous, asynchronous and probabilistic networks and uses a very fast simulator. However, this representation grows exponentially with the number of inputs and is therefore inappropriate for networks with a high number of inputs. This is particularly the case for temporal networks, where each unique time delay for a gene encodes an input. Hence, temporal networks are represented by directly encoding the corresponding Boolean expressions and use a different simulator. As synchronous Boolean networks are a special case of temporal networks (with all time delays being 1), these networks can also be represented as \emph{SymbolicBooleanNetwork} objects. The package provides several methods of constructing networks: Networks can be loaded from files in which human experts describe the dependencies between the genes. Furthermore, they can be reconstructed from time series of gene expression measurements. It is also possible to generate random networks. This can be helpful for the identification of distinct properties of biological networks by comparison to random structures. The different methods of assembling networks are described in Section~\ref{sec:assemblingnetworks}. In Section~\ref{sec:networkanalysis}, tools for the analysis and visualization of network properties are introduced. For synchronous, asynchronous and temporal Boolean networks, the most important tool is the identification of attractors. Attractors are cycles of states and are assumed to be associated with the stable states of cell function. Another possibility of identifying relevant states is the included Markov chain simulation. This method is particularly suited for probabilistic networks and calculates the probability that a state is reached after a certain number of iterations. To test the robustness of structural properties of the networks to noise and mismeasurements, the software also includes extensive support for perturbing networks. In this way, it is possible to test these properties in noisy copies of a biological network. In Section~\ref{sec:importexport}, the interaction of \texttt{BoolNet} with related software is described. In particular, the import from and export to SBML is discussed. Also, the necessary steps to import networks import networks from BioTapestry and to export networks to Pajek are outlined. For the examples in the following sections, we assume that the \texttt{BoolNet} package has been properly installed into the R environment. This can be done by typing \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlkwd{install.packages}\hlstd{(}\hlstr{"BoolNet"}\hlstd{)} \end{alltt} \end{kframe} \end{knitrout} into the R console or by the corresponding menu entries in an R GUI. For some of the plots, the \texttt{igraph} package is required and must be installed in your R environment as well. This is analogous to installing \texttt{BoolNet}. For the BioTapestry and SBML import, the \texttt{XML} package must be installed. After installation, the \texttt{BoolNet} package can be loaded via \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlkwd{library}\hlstd{(BoolNet)} \end{alltt} \end{kframe} \end{knitrout} \section{Assembling networks}\label{sec:assemblingnetworks} \subsection{Assembling a network from expert knowledge} A major advantage of Boolean networks is the fact that natural-language statements can easily be transferred into this representation. This allows researchers for building Boolean networks entirely from expert knowledge, for example by collecting statements on gene dependencies from literature and expressing them as Boolean rules. \texttt{BoolNet} is able to read in networks consisting of such rule sets in a standardized text file format. In such a file, each line consists of a target gene and an update rule, usually separated by a comma. Optionally, it is also possible to add a probability for the rule if the file describes a probabilistic network. The first line of such a file is a header \begin{samepage} \begin{verbatim} targets, factors \end{verbatim} or \begin{verbatim} targets, factors, probabilities \end{verbatim} \end{samepage} To illustrate the process of transforming natural-language statements into Boolean rules, we take a look at the mammalian cell cycle network introduced by Faur\'e et al. \cite{faure06}. In Table 1 of this paper, the authors list natural-language statements of gene dependencies and the corresponding Boolean expressions. The following rules are taken from this table. For gene CycD, Faur\'e et al. state: \begin{quote} \textit{CycD is an input, considered as constant.} \end{quote} Transforming this into a Boolean rule is rather simple: CycD does not change its value, which means that its value after a transition only depends on its previous value. Thus, the transition rule is \begin{verbatim} CycD, CycD \end{verbatim} Gene Rb has a more complex description: \begin{quote} \textit{Rb is expressed in the absence of the cyclins, which inhibit it by phosphorylation [...]; it can be expressed in the presence of CycE or CycA if their inhibitory activity is blocked by p27.} \end{quote} As a general rule, inhibition can be represented by a Boolean negation. In the \texttt{BoolNet} file format, a negation is expressed by the \texttt{!} character. The referenced cyclins comprise the genes CycA, CycB, CycD, and CycE. If {\em all} these genes are absent, Rb is expressed -- i.e. if CycA is not expressed {\em and} CycB is not expressed {\em and} CycD is not expressed {\em and} CycE is not expressed. A logical AND is embodied by the \texttt{\&} character. Consequently, the first part of the rule is \begin{verbatim} ! CycA & ! CycB & ! CycD & ! CycE \end{verbatim} In combination with the above statement, the fact that Rb can be expressed in the presence of CycE and CycA if p27 is active means that CycB and CycD must not be active. Thus, the second part of the rule is \begin{verbatim} p27 & ! CycB & ! CycD \end{verbatim} This statement is an exception (or alternative) to the first statement; this can be expressed as a logical OR, for which the \texttt{|} character is used. The complete rule for gene Rb is thus \begin{verbatim} Rb, (! CycA & ! CycB & ! CycD & ! CycE) | (p27 & ! CycB & ! CycD) \end{verbatim} After processing all genes in the table in this way, we get the following network description: \begin{samepage} \begin{footnotesize} \begin{verbatim} targets, factors CycD, CycD Rb, (! CycA & ! CycB & ! CycD & ! CycE) | (p27 & ! CycB & ! CycD) E2F, (! Rb & ! CycA & ! CycB) | (p27 & ! Rb & ! CycB) CycE, (E2F & ! Rb) CycA, (E2F & ! Rb & ! Cdc20 & ! (Cdh1 & UbcH10)) | (CycA & ! Rb & ! Cdc20 & ! (Cdh1 & UbcH10)) p27, (! CycD & ! CycE & ! CycA & ! CycB) | (p27 & ! (CycE & CycA) & ! CycB &! CycD) Cdc20, CycB Cdh1,(! CycA & ! CycB) | (Cdc20) | (p27 & ! CycB) UbcH10, ! Cdh1 | (Cdh1 & UbcH10 & (Cdc20 | CycA | CycB)) CycB, ! Cdc20 & ! Cdh1 \end{verbatim} \end{footnotesize} \end{samepage} Now save this description to a file ``cellcycle.txt'' in your R working directory. The network can be loaded via \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{cellcycle} \hlkwb{<-} \hlkwd{loadNetwork}\hlstd{(}\hlstr{"cellcycle.txt"}\hlstd{)} \end{alltt} \end{kframe} \end{knitrout} The result is an object of class \emph{BooleanNetwork} containing a truth table representation of the network. The same network is also included in \texttt{BoolNet} as an example and can be accessed via \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlkwd{data}\hlstd{(cellcycle)} \end{alltt} \end{kframe} \end{knitrout} \texttt{BoolNet} also provides several convenience operators that can be used to express complex Boolean functions in a compact way, e.g. \begin{itemize} \item \texttt{maj(a, b, ...)} is 1 if the majority of its operands are 1. Similarly, \texttt{sumgt(a, b, ..., N)} is 1 if more than $N$ operands are 1, \texttt{sumlt(a, b, ..., N)} is 1 if less than $N$ operands are~1, and \texttt{sumis(a, b, ..., N)} is 1 if exactly $N$ operands are 1. \item \texttt{all(a, b, ...)} is 1 if all its operands are 1 (i.e. a logical AND), and \texttt{any(a, b, ...)} is~1 if at least one of its operands is 1 (i.e. a logical OR). \end{itemize} The cell cycle network is a classical Boolean network, where each transition function only depends on the previous state of the network. E.g., \verb+CycB, ! Cdc20 & ! Cdh1+ can be written formally as $CycB(t) = \neg Cdc20(t-1) \wedge \neg Cdh1(t-1)$. As already discussed before, \texttt{BoolNet} also incorporates several temporal extensions. For example, a transition function can also depend on the states of genes at earlier time points: \begin{verbatim} a, b[-3] & b[-2] & b \end{verbatim} is 1 if b has been active in the previous three time steps. The operators described above can also incorporate time ranges. The previous statement can be written in a more compact way using the \texttt{all} operator: \begin{verbatim} a, all[d=-3..-1](b[d]) \end{verbatim} This defines a time delay variable \texttt{d} that can be used for time specifications inside the operator. It can also be used in arithmetic operations. E.g., \begin{verbatim} a, all[d=-3..-1](b[d] & c[d-1]) \end{verbatim} specifies that a is active if b has been active in the previous three time steps and c has been active at time $t-4$, $t-3$ and $t-2$. Apart from relative time specifications, the \texttt{BoolNet} network language also incorporates predicates that depend on the absolute time, i.e. the number of time steps that have elapsed since the initial state. \begin{samepage} For example, \begin{verbatim} a, timeis(3) \end{verbatim} specifies that \texttt{a} is active at time step 3 and inactive at all other time steps. Similarly, the predicates \texttt{timelt} and \texttt{timegt} evaluate to 1 before and after the specified time point respectively. \end{samepage} As the above examples do not cover all possibilities of the network description language, a full language specification is provided in Section~\ref{sec:appendix}. For temporal networks, \texttt{BoolNet} uses a special symbolic simulator that represents the functions as expression trees, whereas the standard simulator is based on a truth table representation. These simulators are discussed in Section~\ref{sec:networkanalysis}. As synchronous Boolean networks are a special case of temporal networks, they can also be simulated with the symbolic simulator. When a network is loaded from a file using \texttt{loadNetwork()}, the user can specify the parameter \texttt{symbolic=TRUE} to load it in form of a \emph{SymbolicBooleanNetwork} object instead of a \emph{BooleanNetwork} object. The same parameter is also available for the import functions discussed in Section~\ref{sec:importexport}. Temporal networks can only be loaded with \texttt{symbolic=TRUE}, as \texttt{BoolNet} cannot represent them as truth tables. \begin{sloppypar} As many network generation and modification routines (such as random network generation and network reconstruction that are discussed in the following sections) internally use the truth table representation, there are conversion routines \texttt{truthTableToSymbolic()} and \texttt{symbolicToTruthTable()} that convert synchronous Boolean networks of class \emph{BooleanNetwork} in a truth table representation to networks of class \emph{SymbolicBooleanNetwork} in a symbolic representation and vice versa. For more details, please refer to the manual. \end{sloppypar} \subsection{Reconstructing a network from time series} An entirely different approach of assembling a network is to infer rules from series of expression measurements of the involved genes over time. For example, microarray experiments can be conducted at different points of time to cover the expression levels of different cell states. To reconstruct networks from such data, \texttt{BoolNet} includes two reconstruction algorithms for synchronous Boolean networks, Best-Fit Extension~\cite{laehdesmaeki03} and REVEAL \cite{liang98}. REVEAL requires the inferred functions to match the input time series perfectly, hence it is not always able to reconstruct networks in the presence of noisy and inconsistent measurements. Best-Fit Extension retrieves a set of functions with minimum error on the input and is thus suited for noisy data. In the following, we introduce a tool chain for the reconstruction of a Probabilistic Boolean Network from time series using Best-Fit extension. Microarray measurements are usually represented as matrices of real-valued numbers which, for example, quantify the expression levels of genes. \texttt{BoolNet} includes a real-valued time series of gene measurements from a project to analyze the yeast cell cycle \cite{spellman98} which can be loaded using \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlkwd{data}\hlstd{(yeastTimeSeries)} \end{alltt} \end{kframe} \end{knitrout} This data contains four preselected genes and a series of 14 measurements for each of these genes. \begin{sloppypar} In a first step, the real-valued dataset has to be converted to binary data as required by the reconstruction algorithm. \texttt{BoolNet} offers several binarization algorithms in the function \texttt{binarizeTimeSeries()}. We here employ the default method which is based on $k$-means clustering (with $k=2$ for active and inactive): \end{sloppypar} \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{binSeries} \hlkwb{<-} \hlkwd{binarizeTimeSeries}\hlstd{(yeastTimeSeries)} \end{alltt} \end{kframe} \end{knitrout} The returned structure in \texttt{binSeries} has an element \texttt{\$binarizedMeasurements} containing the binary time series, and, depending on the chosen binarization method, some other elements describing parameters of the binarization. To reconstruct the network from this data, we call the Best-Fit Extension algorithm: \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{net} \hlkwb{<-} \hlkwd{reconstructNetwork}\hlstd{(binSeries}\hlopt{$}\hlstd{binarizedMeasurements,} \hlkwc{method}\hlstd{=}\hlstr{"bestfit"}\hlstd{,} \hlkwc{maxK}\hlstd{=}\hlnum{4}\hlstd{)} \end{alltt} \end{kframe} \end{knitrout} Here, \texttt{maxK} is the maximum number of input genes for a gene examined by the algorithm. The higher this number, the higher is the runtime and memory consumption of the reconstruction. \begin{samepage} We can now take a look at the network using \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{net} \end{alltt} \begin{verbatim} ## Probabilistic Boolean network with 4 genes ## ## Involved genes: ## Fkh2 Swi5 Sic1 Clb1 ## ## Transition functions: ## ## Alternative transition functions for gene Fkh2: ## Fkh2 = (error: 1) ## Fkh2 = (error: 1) ## ## Alternative transition functions for gene Swi5: ## Swi5 = (error: 1) ## Swi5 = (error: 1) ## ## Alternative transition functions for gene Sic1: ## Sic1 = (error: 1) ## Sic1 = (error: 1) ## Sic1 = (error: 1) ## ## Alternative transition functions for gene Clb1: ## Clb1 = (error: 1) ## Clb1 = (error: 1) \end{verbatim} \end{kframe} \end{knitrout} \end{samepage} \begin{sloppypar} The dependencies among the genes in the network can be visualized using the \texttt{plotNetworkWiring()} function. In this graph, each gene corresponds to a vertex, and the inputs of transition functions correspond to edges. \end{sloppypar} \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlkwd{plotNetworkWiring}\hlstd{(net)} \end{alltt} \end{kframe} \end{knitrout} plots a graph similar to that at the top of Figure~\ref{fig:wiring}. To use this function, you must install the \texttt{igraph} package. \begin{figure}[p] \centering \includegraphics[width=0.5\linewidth]{wiring1} \includegraphics[width=0.5\linewidth]{wiring2} \caption{The wiring graph of the reconstructed network without prior knowledge (top) and with the inclusion of prior knowledge (bottom). Each node of the graph represents one gene, and each arrow represents a gene dependency.} \label{fig:wiring} \end{figure} A network that involved the same genes was examined by Kim et al. \cite{kim07}. When comparing the wiring graph of our reconstructed network with the reference network presented in Figure~2 of this paper, one observes a very high similarity between the two networks. However, the reconstructed network comprises too many links for the gene Sic1: The reference network does not contain a self-regulation of Sic1 or regulation of Sic1 by Fkh2. If it is known in advance that these regulations are not plausible, such prior knowledge can be supplied to the reconstruction algorithm: \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{net} \hlkwb{<-} \hlkwd{reconstructNetwork}\hlstd{(binSeries}\hlopt{$}\hlstd{binarizedMeasurements,} \hlkwc{method}\hlstd{=}\hlstr{"bestfit"}\hlstd{,} \hlkwc{maxK}\hlstd{=}\hlnum{4}\hlstd{,} \hlkwc{excludedDependencies} \hlstd{=} \hlkwd{list}\hlstd{(}\hlstr{"Sic1"} \hlstd{=} \hlkwd{c}\hlstd{(}\hlstr{"Sic1"}\hlstd{,} \hlstr{"Fkh2"}\hlstd{)))} \end{alltt} \end{kframe} \end{knitrout} The wiring of the reconstruction with prior knowledge is shown at the bottom of Figure~\ref{fig:wiring}. We can see that the two false links are now eliminated. Similar to \texttt{excludedDependencies}, there is also a parameter \texttt{requiredDependencies} that specifies dependencies that must be included in the network. When \texttt{reconstructNetwork()} discovers multiple functions for a gene with the minimum error on the input data, it includes all of these functions as alternative functions with equal probability. Consequently, the function returns a \texttt{ProbabilisticBooleanNetwork} structure. If you would like to obtain a \texttt{BooleanNetwork} object with only one function per gene from a probabilistic network, you can extract such a network by telling the software which of the functions you would like to use. This can be done by specifying the indices of the functions to extract: \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{net} \hlkwb{<-} \hlkwd{reconstructNetwork}\hlstd{(binSeries}\hlopt{$}\hlstd{binarizedMeasurements,} \hlkwc{method}\hlstd{=}\hlstr{"bestfit"}\hlstd{,} \hlkwc{maxK}\hlstd{=}\hlnum{4}\hlstd{)} \hlstd{functionIndices} \hlkwb{<-} \hlkwd{c}\hlstd{(}\hlnum{1}\hlstd{,}\hlnum{2}\hlstd{,}\hlnum{3}\hlstd{,}\hlnum{2}\hlstd{)} \hlcom{#select function index for each regulatory component} \hlstd{dontCareDefaults} \hlkwb{<-} \hlkwd{lapply}\hlstd{(}\hlkwd{seq_along}\hlstd{(net}\hlopt{$}\hlstd{interactions),} \hlkwa{function}\hlstd{(}\hlkwc{idx}\hlstd{)} \hlkwd{rep}\hlstd{(F,} \hlkwd{sum}\hlstd{(net}\hlopt{$}\hlstd{interactions[[idx]][[functionIndices[idx]]]}\hlopt{$}\hlstd{func} \hlopt{== -}\hlnum{1}\hlstd{)))} \hlcom{#determine number of don't care values for each selected function and set them to 0} \hlkwd{names}\hlstd{(dontCareDefaults)} \hlkwb{<-} \hlstd{net}\hlopt{$}\hlstd{genes} \hlstd{singleNet} \hlkwb{<-} \hlkwd{chooseNetwork}\hlstd{(net, functionIndices,} \hlkwc{dontCareValues} \hlstd{= dontCareDefaults)} \end{alltt} \end{kframe} \end{knitrout} In case of don't care values in reconstructed functions, it is possible to set them to 0 or 1 per default. The result is a Boolean network that is created by extracting the first function of gene Fkh2, the second function of genes Swi5 and Clb1, and the third function of gene Sic1 from the above probabilistic network: \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{singleNet} \end{alltt} \begin{verbatim} ## Boolean network with 4 genes ## ## Involved genes: ## Fkh2 Swi5 Sic1 Clb1 ## ## Transition functions: ## Fkh2 = ## Swi5 = ## Sic1 = ## Clb1 = \end{verbatim} \end{kframe} \end{knitrout} \begin{sloppypar} \texttt{BoolNet} also supports the generation of artificial time series from existing networks: The \texttt{generateTimeSeries()} function generates a set of time series from a network using random start states and optionally adds Gaussian noise. \end{sloppypar} \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{series} \hlkwb{<-} \hlkwd{generateTimeSeries}\hlstd{(cellcycle,} \hlkwc{numSeries}\hlstd{=}\hlnum{100}\hlstd{,} \hlkwc{numMeasurements}\hlstd{=}\hlnum{10}\hlstd{,} \hlkwc{noiseLevel}\hlstd{=}\hlnum{0.1}\hlstd{)} \end{alltt} \end{kframe} \end{knitrout} generates a list of 100 time series by calculating 10 consecutive transitions from 100 randomly chosen network states in the mammalian cell cycle network. The series are subject to Gaussian noise with a standard deviation of 0.1, such that the result is a list of real-valued matrices. We can now binarize these simulated measurements and try to reconstruct the original network: \begin{knitrout} \definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe} \begin{alltt} \hlstd{binSeries} \hlkwb{<-} \hlkwd{binarizeTimeSeries}\hlstd{(series,} \hlkwc{method}\hlstd{=}\hlstr{"kmeans"}\hlstd{)} \hlstd{net} \hlkwb{<-} \hlkwd{reconstructNetwork}\hlstd{(binSeries}\hlopt{$}\hlstd{binarizedMeasurements,} \hlkwc{method}\hlstd{=}\hlstr{"bestfit"}\hlstd{)} \hlstd{net} \end{alltt} \begin{verbatim} ## Probabilistic Boolean network with 10 genes ## ## Involved genes: ## CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB ## ## Transition functions: ## ## Alternative transition functions for gene CycD: ## CycD = (error: 0) ## ## Alternative transition functions for gene Rb: ## Rb = (error: 0) ## ## Alternative transition functions for gene E2F: ## E2F = (error: 0) ## ## Alternative transition functions for gene CycE: ## CycE = (error: 0) ## ## Alternative transition functions for gene CycA: ## CycA = (error: 5) ## CycA = (error: 5) ## ## Alternative transition functions for gene p27: ## p27 = (error: 0) ## ## Alternative transition functions for gene Cdc20: ## Cdc20 = (error: 0) ## ## Alternative transition functions for gene Cdh1: ## Cdh1 = (error: 0) ## ## Alternative transition functions for gene UbcH10: ## UbcH10 = (error: 0) ## ## Alternative transition functions for gene CycB: ## CycB = (error: 0) \end{verbatim} \end{kframe} \end{knitrout} Obviously, the number of generated time series is still to small to reconstruct the network unambiguously. However, the result comes close to the original network. We see that the functions of the network are not fully specified: At some positions, there are asterisks (\texttt{*}) denoting a \emph{don't care} value. This means that functions with a 0 and a 1 at this position match the time series equally well. That is, a partially defined function with $m$ asterisks corresponds to $2^m$ fully defined Boolean functions. It is also possible to generate these fully defined functions instead of the partially defined function by setting the parameter \texttt{returnPBN} to true (which was the behaviour prior to \texttt{BoolNet} version 2.0). For many \emph{don't care} values, this may consume a high amount of memory and computation time. \texttt{generateTimeSeries()} can also generate time series with artificial knock-outs and overexpressions: BoolNet/vignettes/wiring1.pdf0000644000176200001440000001342314272151227015705 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802093022) /ModDate (D:20220802093022) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 1966 /Filter /FlateDecode >> stream xYKo_-aDBJ$r-@llFJf9;[$/_uuu=HLJ㿗ߑjB_/_}ﯗz/XÏG<~[pI1xRs q0<=~<_j)uX r=jOΡCJ 0H_=ꢽKYwo sg)e0OyP]+gJw]gJNA_3K3,~H~ja.t܉%ӧfyu7y oV\sn~ }M:?WO\7} F\f/nO`'7pi?<'o?\7G2:=Zϟyʂ/'ǧ_`ya.]$&h!\q25L_TQ\p*z6/|_ 2idùO=%V -!Wpt3_ڟEGJ9Yt*0)}'r7ڜΩd?tM#9F2>'V m\y2;+׵KH} 5n:6}m=1cmȞ\N{ݞy7W^<ΝQ_] #n"v7Օ܉)y?gzYGns"Gʖ;U,@ټW⸪mT đdOh r';AZeל)z`(?[>!GJWӇ;DdD2zg'0usgWgjH @.//a2dŠԸu δŖ2@[8 O:lBwX'Lm6z)RG7Ք,E,w )A& i9 [5'y0*%T5QS M03tf Nf1]y:G& v(;1r7FXDsa(+ WK+gZH1dfB )W|к\:6I-eqLL7JДS$P+9ɚN FFf t*j,&!ɂӊ >'VTI8ː2hor4蕅 NCn4ZW&/tn BɂaFJ 8 \UtD 0\)_dłP#[8/Eˮ 8WY+]* 4K+O,^y8*j)qdfi)kIbH0 B.RiuĦ7puH}Tm2(Qn.xx?9?&^'ݯ+]+e5['PӾ{w}sz˔=n Z> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /BaseFont /Times-Roman /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000002330 00000 n 0000002413 00000 n 0000002525 00000 n 0000002558 00000 n 0000000212 00000 n 0000000292 00000 n 0000005253 00000 n 0000005510 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 5609 %%EOF BoolNet/vignettes/biotap_model.png0000644000176200001440000017272413277247010017010 0ustar liggesusersPNG  IHDRiCCPICC ProfilexZgTM0 9Ðs F$A2"DEE0&"(b%b~gw_:uޚ;\$NxQ0 ,<:DBƽ|z66(#6Rel=77 ԪtR0#@6%7޿qMFtOU!X:bkۘƌoWd}WH±>}.d XpߠpDE ZF  @%5+\@x!w@e_4-/dl4sK6ohzM@wha",`; ~8 > *Oq#ohQ(2J GYQ~(***AU.QwQOPoPPh4͇Fk:A@A_Aw/5 ÅǨaL0?L4S c1X+Ua8l6 ۀ}p81灣ppgq7pp<ύ$| :~DCQ1񤉡ɡJffH+HAkMG@[D{9KP&|ńBa0O$Db81XMN&~ґ4(ttYt5t7}'ҋӻ_31h280D23401%A$>ɉK*&5i};7xv02313dɬ\|yyEeA;,Xqa-Xظش<پ3;'װ`PpH̩y< "/W0WW+n, 7;<7O(O -j9y_a\5G;7$dWr&2T ~e!!;B^ 5 \eC)',.)*~X7 A {Lv9I~I[t6OR|RRRץH J;HHwH/Hxɬ*ɞ}*Gӓ'(V[V>[K~YA^!@R"bbw%I%JϔMSo*/ȫVWRW-P}UWKRkW~^F+MvMfc-:-sl{;; wֆwj'kwho$M vLyGgׯOԷ/6`3p2(7xc(`gxpH(ڨhxqq IS! K?wi:Yٔ^6 `ajQ`’lhlbog̚:z»wۢmml)%QX(_EY7,ʜf՝3D2j ݏPxGzOҞAOAh{^^^L~>DO+x_7f?%tK@S 6-%&hOе``!!!!=ܡQ„žˆgODhFG|P{6E"#x⢆sgb bbbccG(N*.;nfx83߁c ;V]o$q'%$%k'JLL>(t0LԆ44j!C={22r3fR2۲xf϶naIș5mc;7u|wG,\--H/RPQ$^TXR[m|f\EKWïܾ~823~AmOKyia5n V.~}|cl3o,7 cXs ={.\ G=t0@@o( BH!x#<(EC X!=(¢p|łڇDۡ0v)~;M#C@K&ӛ3(ȌLh +]Cӂ+;2(?!*X-4#$(/!',&k*W(RQ@GVeR[٥5-c{x}aQ S.35Vw iP,=ӝJ/rtt$y|t|-\WFG(Q2GD6WcVc7x\ BIdL4t桕̙79r==<\\8(t,RZȩZwTJi3qg ybYcf)W]ޮvM[;;C»z-uUCGCO;6=)|~EWQcQO|369617yn*xZazw'Ψ}|x0QO?3|r=?[֌77#<$  Y"P `+^GF6O?GLBƈ-tA $EFN&:S~Z%8i+DHP#1T++KNKLO>ȖJJ#§73V3rsym..J)>K<'wT8!+!JJi]z. yѷP3ErЕW[qmF퇮DҾ}Z\`N˽}JBH{8w0{(Ipgԑ/"_ƽJx&fϚ~d3gY Ǘ/_~s^xآҕ_U2@hxaPY1PY;DE@AYщ; m hDhn:.*QC HXC̦,t,#lknpuSg' \Vmw$I.H=n9!O"@0إt\9LEOEZzVھ: *=aQn]s?8jioi5f]c[c;lWC7rpsp*vpvp6~#eלwOozsAuC,BC*PEFDMF|w0.`u <$dTF_iˇd,gqf[/vħphűbeWU(r^K㵸:gC7jȿQ-Ɨ^%\noߍ$[m {ݵ gx>``:{E;vx$>,LKQRno7Ϛ~-GB"yvycEvuǚ:n}`{-@Wd@o`8 C)Qf"&="p/y3ii}iG;D]m:;BHtQq)\b2ZĦÕs;G!x_MN-#,-',FKJydddf8MTTԞj`45Bwit+bbj\e2K,|R*]g),Yd.K[ X Z 9&~*rzt[Ҿrd/&˥J5NkO2,3K&sdsSs *^+v,?tҙryUkkO;+~ABkҥf$Nx67hocz=J_C?x@yxn`ɡOOs<{(X7'&Zb9h)i/_c^nN?--)/Z6^~KׅUՉ5ĵ+kם 776667)7{wh "B#"練$k0!51z#wڠn!:_"V`Hc[#}!j@?5چ<)> DD^eNUDjG0;bH~HqGg9 3Eł 0 V !1x$R#9aS"mQ Gp#`?z&1H~YȈ?6/Ƚ[m[/4mFA~V~ϘТhE ZAk2 dhuZicg[ZcODtDZVభߟm \ܟ 9ȓXdN"y~Iu%/n+WDPGFI?ipYi njÐ!C.ڦ TE@PE@PE@PE@P@zz:Ojkk~ob癠`w7lSQQ^ "("("("F@lqtlmE@PE@PE@PE@H8ceC:rؐ2QѠUӌߡeBNFv.8zޛ )''233)- > `ˬ\\BeoI5?@ -[M6Gde }8mHr2Mh}p2W"("("("x! @;m_|(4̂ҋ9}A=8N]])X1g.,\@S+8 x=_e_|LUOOyQaԪ[O(;Ρ%K(SɏP|й#u,Duh|ZWV1[H61L?("O,'ZHhkY/"X+׌ːl`Դj-+5cjQE@PAXloHp4gִI{}!Cŗiko /ڈPvZ_ O(Xڭ5u߬  t8;ҩhǯS v+?>'@ Fh>}RKiެd>;m("4wһ%D! n0Ɣ9?@7]}&3,K/Me'QjShsΥe}c'Ji<7bitٴu{.GF>&~vP9}|c=yòL>fvֶfmiG?vQ>%X ==("("\˞XR1뱧;VZK]ߦR_MJ,]EE54)33oQ~3B/H{?ԥWm/r;USvX~"izq5ʥ~MYU֖%TPM(Ww{L_eZ("LѪ^iGӈ-ƍ{^|aiSt(n*}HՍ?DrkTˮ~9r;1r󡐨8:=_AJ'M;/W>T.NO|5(*Jn0%iuˉe4ԜVA7yT=͒"jDV ޢsL/Zbr۵'ϳ90vk/KpZ& uCbMk߁zhW-\qWE@P6逯WdlO/خKy.e-_nN%]SGy"Lc[TPTK}.6Y,J_u3(3ҋO~&~QJN(#;6جs(='Bh}_Z+jieV fRԺU.^Pc|ej"(FI|ci}iԉЉ;y4CSK١Ҋ#)"G4]h#|l;Tbke4;G-܃-qܹ TjP -3)tb Zgό\I6U Ϙ @WmۋJ>Nr~7hٔ^_ICg={ v{4|h*/n9|UzdI7?Iwnۊ^quGzU,zYۘOEus>Ҟd4}=|4mqtxBj-1x ]~}ЫOG zvZzO{\ىN)d2HawOrS7Z@>2vu44Gi8< R3"N*}.6_㷥ʟ^#IaaT9m3h.h.sLj*.7^"0J`hYEh{Wv&61oŬtțoE%?I'\ ?odSœhQwГgV}'\Hߕn:7k]H>?h4蔑SӖICo|v*]/.,6u*gY#MtΗ{֟n;rGl;?`}YmUou5("L[H"7{>,xۮּg&N|:s{x &/Yٙfory_UT@imߊrfJ93x2+ےZZ^PqWmGOg*|C:^r%9]GXi O$jmN7d M`E+ 45C}tOоSӾhk(mRN/\yȑ ^v |ie,Xb xQӑejv=ft.WHkxP]O$ow8Ds>޿񿄶* ˦299r/r6`ۡF4wRN 2.u<7)Kǵb]+m+cPЀA;YT՟۰wOb8BR$Z)F12NߎJ"(ZC !gh|۾?*֢"7ltӁgF 4ȢeK)cye<S8ydHʩꨲ֍ ]6*Oߕ|J9LxY <_2kkEeme:4("D%4k,݈d[zOiV~'kw]9iSh*ڸC8Ԕ-41ap)? t;j&o8R-+5*,˦OG?\EK ͧZ`ߣK>{~~2M0{F*t}ڿM'*Zӡz,ƱaksSovLK.o؛"›8Ol\E۹B QqU#2Dhr/xϜ90 M]ǯ'/d@ўTJue\E1Vߓi?E?YWBSgRLяY$o*14.yK:~oKuԮ[bzx). ϜNsjZ^.+m cmHGl݆{+&3E?z g&r!moazqtԮ}bt,q#`o 猺.t?,b7`9UwOK#&<Ź#Rjfv6USA2j:L:wL4Q/_膣GSC:esh#6p&Mn(mKh5چAǟ§ڗnnfTGs N6]ZQ+^N -_9s][D4("(-?g:= h=i7_SJ=p,FHW ~v@$[ _̢|*o!64l,e/湣 fQYé˟b"'7NEUyo( #6Z/:ebn:iI\}aYCw:n}v ڃҾNR8w]t.xr.#e'^M_j`i3)X|/b#i1pcv`vtGw3;HӮ}\Vtw p^MP>M}}t?!!rũ<>t㬹t]kLسAc+~vvG} @/QJ{ =A]ONL,nq'Yg ;:n1v"Γ>'Lh++ʣ':gӸ ҫvқ\EV, \}]}1λ)v2dVG]A:gCycOvǟgV-fL`J^;i}1c苼(N,-g^;w܀shάhhY:v_U(~^WM|[F2yh=RfJ}Z&/3!#M.JW$o9̚{6SńUlhI`W:uoyH^LQtuVbWϣqG\0ٱa;\Z:g&N leA҅W/\Ufx9sJ {t*]'V:[/"heƞL~Q01Uc^@hOUТR),7A]F>8魋G|n 2Muu'֖7Ǎ_5sw(gci[Ƕfɋٛݦ#ue ˨de y|}C?N+]jOņ݊ر})'1>οLx9[X0p?E@PE`-#paOj=+ADb6TS&G9 ?B`YvWomQ4L֥e"4᧵E@PE@P2f9^^q!o׺ub{,Gĉ^e&Mm8qgS߾}=>3ԩS'§Dה=$+$ֳgF{)m8s*'IуczgSڶ?o6zm8eTE@PE@PZ擙 /fm{5 C ɮ80myWiڴi4r0Cp]wѷ~K[mUzp:~f@ӈQ3hc+PuuO?s=E ڴicuSK,ӧC=DC[n?PkcJ2)"("(D ̄tj뭷4 baqۂ)SRtq'lt(//7D0HCp i@s6,hѢE&馛R>}b!S'|q]zн{lcW2("("(F "!C]tQ࠼.r֭u҅ƌ$`_L]v6ڈtm;+oS0cz"HL믿N뮻mAXݦz؍7(f_x:#qnj{'O3<3G_~-؂-[fz 7P~m۶gAW_}u|pv<1q)^;jfΜIÆ :|H.o*999 tAIae[^2|ᬳΊ~4E@PE@PE/@g& ==#4vX馛襗^co͛!/h„ #1`4w\)6ݖ>vygK!ވ,5k}g1Q m{oQ_0mA[n),}>C=ҪUAA+ p|***"/8y Hm^baic(valJJJ?7o4[ 781jʌW~ .l&jؐo 5f%9b(MPE@PE@ `&8`t2߰ RPPaGLL~*}=+jʕ&wҥ~k7nu1³?7<$&oc4vhDN;X74:~!{=^Ӌ׎01E0!ڐ6|se]f%vͥSN9g标9ŦN0h)"("(@:7 Ț z1 'x A#Hi8 0 Ӭ184~ X/l4i$Z`K /a, 06OL?laMCWô# ȳc80C_]M6٤Yrl1$`M,of3 :1SnksÜ[^6`OY!61‹Ui"("(_kBSy*m&^lvMyiժ#婊۵7*bϞ=M9z'"H?!3m Ј>f1T&x0g6jb]{aƳbKfrHʄ޹;Y<6mژvѿyFOժ"("(| :П_XМ9s&^.)C`C׮]z+<|GL)o ` ld3l&%kF|oE|!"=} ô# 8,:uk%8( /앂F=HִOPE@PE@XtXۍW-,s` _Р+NufSPE@PE@hntXͭU+>\Ҕ}>JVZ&]hPE@PE@PLESE@PE@PE@PE 9xzE@PE@PE@PE@PR@ly5\r*PPE@PE@PE@PĖWty_hE@PE@PE@P"о}{]^RDU"("("("=bPhBPE@PE@PE@PR1&E@PE@PE@PE@@PGD?O5"n#}?uOL*IXkC溌l{ꏤJTFp)6X+"("("(@G@7lH-TE@PE@PE@PY2'L_1Z;1sYXI#v槟~Z&hSwx~HHji^GRpPUDA`]6lf-x=~gNh"{$t@SO=Tl&#V[[Kqpf{Ko-HiҤI-%ZbDؾ5ER Ƨ]GԞ單K_1 [-]":12t0'PZMy 9^-<Z=bW)N;6d !H 3'tsQH?`s8?ز`c=a[[c ^t[2d~_ܷo_}]3|?7 ]Dr ##iư瞫*7ʾwޝv~k5km4{l:fap>& }msy~b<|:si1 ȋ6%_h'Nj}~VAw_`Rۗ_~***pp@|)LW+I'n ۽ߵٕ/j^P?t өS'p~…u222bưv-ضǦ#4-e2Bl[=gf:A]{ ?l;w~2mA,ZOx㍱<_|žvAVVd[wЧ쇟6,Ķ=6T 4h[j:uf0P'p(.nOn-egg ĶAV;quayCy"uW:&;cƯTUUIoYz>fP^pyA'#B(>OkA}q68>k|ѣ%sYGƉ^oEnsԾw㺆K[tSumpy8xHt-]aNd1  ˖-#p-**VZѡ*M0 =\O ؀7k[W"!$^ަ ><ވ#biĸqbd]xq, $^ݼ@,;vhޔK_m ؈>}.Mz.⇽<)M`eۄDmoi=)pq?n#f8v(#3#K)ˍ: u Wl {lYv}؆<*`˰<'^: UV1df2|;^Kۛ={r13^?v}`/Y,anpͥRsFcn 8{x͌ aoVóK;|֓ӊ~-8ƎF^yAѣ/lΥ THoQtGO$PG:^"uOk/\0WLZ2v}gp}xjvWa\DX {D>[~D6|*~+M?մラĉ'γFהsQ8KBxv8 Q!L}W]5<,:3|j蠃CMwlcJ6o@>K/믿>f;bd% ~D1ǀٞ\ D#|uqH,ošg+)WVP^:  _nDMNwy'& t=10 Lla }Hǃ5aXPtþG.0t#CF5p8,[@JS"ԧo~x!4m]/vEt%?ɓhY#Fwj*E[ td\ip<^sy9`ˏ64%ev/R&mcw3A'2/ᇞ˗Z+Ŝad"ᇥ)QJ2áLccޫ`%x?6}쳏ik`cȐz1c4hizշ!?NO;^_;鷠$8(`y庐=bY.KsA=ɁtPƚAF)6X|l. nA41FI6VA$/4Rsۂr8LEԵc2G鰯^vE%jԗ&L0nȀ tLC /{'Lء4b7~e`Ňry?hiVad OLhܥb. {̎jL!^m{8v?(=\.tE@XHB,+n].6]A~@oOpx㍍ák4o|"KzfAS meضb,r8̊+<[fXۓz'[TٰɎv{WlRtYYYl!C ~&ᅏ ?7VI-zc+͖'|~Ǖg̰D@M'Q2پ}2a3K,:CJ+ )G\72A={7~(6]%ʥɮ2{ E?EzUW:R!'=bAX\;Nq8` np@6+ IDAT 2@3 ' K)k6K`.m;S HَIiȔR.8P!%"1~n 9vp߫㺄M#b À٦#-Td#mO&HȒ"[H#[06m۶5\oE>$O2уv +{im-ϭ/Xt7zK0q*1 ܷ~ۘx,%7 !^pMuz۶#M#X|p"4؞<6ٲc $ئ!gsusbף>{-Ln\RRbHV]d dp 5&*D#v5טoK^$:b;`p*Y咆/Y^j&"^ x.d>d[ҕptXsHbWҊMl|풖u$x㸢[?=.O,6LEG=%o?@Bt%rۘ>Ghc!v  d;D`.E?Oʏ_Iec ¡+]Xf[]t2耬w}-2y@Yل (j=TMSWرcc Gy$"N" alwYEf< -}ĭ:ռ"\B,7JaM"G0\lڳpҊÁg80g|/xI.F/{\|< l% 2 !^Ae{20nbk iLa:HI nyДp.t?{Cȓ.Û8v 6^rQ?^]Ct^xNp(*Zs=GGqy(r{>:avL/[=vyش},~80D2[ߵGzX,z)S?42~Wө{}m&G?v7[l,LEg$mP˱ď2I c3WD^RXl6` _ ټ _"]C&{Pw^&b0mGk"[aJخo]^aO |sȑ1XFGݨ?4br2aiMJ&fl+pm ``/ D1E Aq\lgҴ"4 .l͋u`Shvl¦ |AH]+VRwkrsiyxF;v [~AS݂lnYL|3amy3IQʉlvA#rAYs#zap .nx?6D~|0xgԨQf`ryte_[m$ :I J^A~c e=!پ<`aA{:6(刱f:t|3ΠSN9<&im_6.Kd\m^Ia)' K:}40qD~+E[ta-.N8[T<1__#=Ơk׳y\|nf@[[TWʄWbЅǵe8p@kaN=^+`[%[n%Fܶn:Ax_lz 2l]%;kG 7K=pbh(dB×$i6GFb/.F |1@ly ?3\/9 #jNѡ"X0 {q H +| v:+p[RCVЮ]L` F"!Ȇ0Sݼt&4ts8lKG51KL\mv+>7nY{Np햼8*++db)֐;mLrƌ! ~PaMz îxAvM<8?:Њ^<á ?ʏz$.km5u>I#kaCo2X [߫=vڋW|p6LpVKް|`a3< zx``x Ym vAb|s=6i A Xl #K6hv];l>y {8b b!yr!+=RWdߴdF 'rmٳn<~^u=~g3|a?lc4pEpsPuR_\{&LwhHLW_uFv8蠃bY r¡CDz]w5?m<],AH]lpyd`p`y |[o5fxx[$Et)GH=[&x!e8A*iRObt/^1LshrW5MKSf;# 8/%)퀺?ggv)<~ה E@XhAZ b@J^ #ܼK6&LyryW^T7m{?6m ۄ %က7"vJZ\V#^bbld8DE!޿={ڤX2c"I,ǃ&ЇC)XxSChC")A uxOM!^<;hTQYA5t_a.}ϰs afdg}_h'wj;ʁ;duץy8K'v'&;AhR~WޭL^<ځpٮM n,um .͋ #v_Ơ1y"_b]>/{%0µҾ!v=/eiKw6/\\? ]b{-xq<> A³Tb{ p2q! Eԗ~+ō;8S6Sqnboc|C㚰m_6_L&E`F %N! gY(syvǎGyCA諯!C6ipΎb?܀c 頩ncǮL8~mF?RXlI|ԅ?.NTty; {\AM<=ٱg(]^^nO< l?|7dlG+2@`U̡'0QB؂rWG1ؕؠ_vٓTTXdw}8j*!5‡;? WMem@̳v9({a'z`~ 71rݼȱ0XrS=;Þ'vICw./D[ꫯJQxԩ1^{;$lkh8~ W) uݼԕFo~.<"۶-sRǍm>q8翭4,Q ^3[[fhvIen^dq2;el 6i<1׍Jl=dP}ئt/7FÎgy&Cb/x(AԖ'駟&|_Lu -lzaleym#FD=`|B:+@a/^D`ݼv4ǃllj?++.9"v8&] /bӍm>7w.W>:AAe^mZغ#W,ϫ8rD6cFc!dcq<`ؔ8pj8`p!|[^tX/xGTi"C y=`^i?-M^n,athݐqxp.уb?{(Tx۲d@-mDa K8ƷmP!/.f+iӁb|6zaik% pB` KD^ g$Ro%Lbɸ>$x?m7mC:'3_ aցK׎Dh!ޛBd}v^h. W,<f<ۃn`Idy"SA;-2XyMy8D,0D럴ޞ<~)yEDTN0u^`#6%mǃyŸHnMJ q8UNYJ'p~0g;J} Mt {4a_ʑG?<+z S )q:Z^*)sBݼȱvZaGB]n^qn ;mp^| o?D?<qD/(vڮ립Ra\W6i؁\>G]/ZX_]Ʋ^zѼzܺ}8*+*TPx(6MY?߮l@y7cGAa;lvm v O]!ү8=ǃ8w9l;%mdQ'3q!^߱cGB .нhŸL,x'׶N'ROxQ_2G˦iёL,$N&?]6N |G96N/yѽhGu&smiKnZ1+-NIδp`Yg֪U+8T>UB|DlG"i75>e!=͏?.?(.Mr:12 T~#v-^}'|~/^?Zۥz-e ïx(y1箭5(v~4?i>9mڴ'3sssn0{j_!7thn,NYJ!S]b#(ubP&Nqq8 ⺄˖cg O]ߏGA&97 u.y?]"|~< >/en>.kδ|^~:W? =QphN؍kC=d!WxD'ʅ)q"}Yp l]/~?F5(%Mv:ȅKb?9 t4Ǧ İ#Y8, օ?(f 9AvWߣjg 2ύcL95x뭷lVtO{3<^P.<ɻ/L@.x1 ̘1R=&7FhH{@#-yG9l@. %{Ѥyz);<ʛF~hf6`FD{^ZQSSE8bsvnB/h^O/r+2 ۺm]R#%l|pqloM=mL9V6⺆6E)=& i,.v,~g &M6 ;^wl_Nv{\ꇡ: 6wyROoq48Jb81xH !KI,mBUI,}YuE`DIN Hpq/dLP2ܬU{Musu"vK+㾎3Yۚ|B?|Rsذa6ʇ"?lı 7hk1u&H>} K'i$f8`}L 88셝gʛFn2p3ág83"d1Z`iv<`AQ'yn#md"/ƵDurlaquʠGy5R&(G4eu'_Qe? aMxʓpZa#1lbˇ<^mݯ6]t/v};,8Cdn];e{غ4yl/{:I۶~X{ كH}$bc{|v&/ަ%ϋ&:oZ2mco,n0::u`!a16rBg^a0`kj8~ uΧQ IDATlWyE`BINxBb_@w/.v^ ["CʄeBAE(%_n] )^ ͵evloi[Ă y /i(#o].>C/d2#-6@mБO6ds>y*D`axeMpbɋ}bbHH ~< ۄ.]xv4EȐ2z#6 ,ĢExL,t0l /H;\{DF21Ni,nBZl@!o y B "/.ڃk"׭+|Emyve"/I[/v;Enx+E.6_!  ["_ )^ ܼ݋צ#vٜ1lgm Gx2 ׶)>yڶ4{-ab'^},Lۼx0'>>Ny?>|zvZl|D߷mj 5{lѶtmgPޜxr׹Z'+Y}IVSu&9|Җf NTf{Kg.k5iiGH ,< U Ƨ]GԞ單K_1 [-]":07k' Xd}Xlv)y4("("("(۷?cmh8("("("(@!A]PE@PE@PE@P!Np8)"("("("$ QvE@PE@PE@PE@Pb1(4("("("(F@WQ("("("(LϗƊ"("("("4a-aÆ5Y PE@PE@PE@P6= t8.RIj()_}ܖ .Dʠ("("(՜[o5 >ܣE`}@`񡚡ׂP0)"("("X՜oʒ;Ud>oкhڬ("("("C`رTUUE锖fl5y222޽Q+ y@HaE*rdAF8㹞Q^GG.7D1: *%(h@H;ݝ[n:N'ݽ[ګV]|cժ &GfCGy$^}M.va] @ @@Fo}[_+V룩)* )H :4,Yi7:a}qS @ @P1f̘y#YV?---mRؘÆ !i8!MXretAq=^(H%@ @6HACeC{zb W𡹹9Rf9黫ӍRSNn>Cke.>6~Wuۮ!ƌ캓]] @TfCN򻲟>^f:TBӂiKwq[~ƺ;P[vh=wsX%>>,_x @ @@Z, zHz k׮wQU2QPZѱ4ayqZ1eʔl{֘G6* l/7%fʸĢs/NiygK#[snk? qƻv|5nT6bʖ7e+{5 @(@\f1ȟz=ztۺ \HҥKO ?vѾ*thsH H+[5*Wq?Dx;[;xF:wM=뎃㡧itlqH%1m;槤@aʮkXx.gA1;dh{f}8hڈ씟qFFW&  @ @@ /X 3E~Z$@!7.);ltB҅mxW7\ڰ4k[+[]co5˸8{Ƅ|-wv[ͯ}lA1zDS6#bU< ieq_/׋EyW5?[^Ͽ&{^E @ @H #FQ>T/n'CKw-n,lhmX}IϽ&:" o 0uظWbxyٺyk z5 nȯ4{{ur" @ P;C >|u5 MR?~|&eO_NthEF]54c`İl&EI,DvߣKW^<,viH<̊x$[̆iYd$0#=ٶ^=9 @ @?z][R>fFtmvCV+KsdK3~pi|'"[qE/O.{*>->yc984~"%㻷-w3+#tHvWn^E񵏧E1#?jeZasۖks9N @K =.ѓ }iζ͆ [!W99Oп]28{!~;cG*폧 W}8[05 K6ɐ/dox1{L>gB:Ǽ<?Ջf:`|Ѽb*TJl* tD  @@R0̢:9;Yթ[ t' @ztCЕ{Dav @ P>C\  @ @@M @ @@e=&@ ++WMlz%;|h[ 4@Q!@*8yZhbZ J8L е&>2p 5 6K Э@ w; @ PCYFZ?  @mǛ5& t7z7&@ Ps/O B$ @ 'MEɭ܄:@h @2"e> 9 @ @OeyOof@c?m  @y2v3ܸtm#b⍏eO;dˮq6: @(@ kNs{GG̚9/Cɻ/ @KĽGnٸ1em\W<`g59@ճU3 @ "&_ C"RprhEa÷?\`sIFW]Cz @nRwFL߭"@` @5/wj~4@/ zSU @t.И#-x8cRǕ 00<^10U @Ԕ#kj@4@ GnC @PQ2 o P%C`UK @/?66O%RYgOTzz[y@@nA @/fl M{}'o"^/G Fb @}+pŐQo|>i;6|} } @B )xX9F -qhq_С&@ k[#ִS|@inWm|M݁Gź{Zo+} ndu@A($@(﷤ގ׌8=X^߿[/sG|Mս =Yc퍉 @Fg~s; Зۨ/[^ @ @ua) @"𿲗P|7a[5lO@P1c @ -XT6xF~ @ @% t-I @ @ 6 @-CoI @HBqA @6,Y_W#Goq1IJeˢ.:~oK'#<298]@@]  @X E~̙͋'O=TtI裏e]u7͸cw+["3$6' @H駟O<1{|C%pH]2eJQF{y晘0aB|1{׿i1w~o ?f:􏻻 @+W!Cq5;S\|śEŠAb̘13ZZZbѕ{RO C:"nWlR J5:K P$W^y%\!yҤI1|N8VXvlqg!Bzaҥq 7kA\qqĺu΋UV5\_{ 'u]]=m7d5/G̙4E@@PAE @b E#+۸q*|Lj#իWǻXpa>C!+N;[/xRߘ1cFxqwıgFVG /Bi:i}hCSSS;6nx*#iKo8C]zW;=v;ӦMqꩧ楩4F@9t(5 @@w߶V>C~՘0)n9)\8SoHT~TO bfCTC1Ҷ%d>cio|./_!| 0oL @`yHf(#'O{wao~iBzk'?ڵkWVVgR̊m'-pHkQ 6lK|+  @Hk5|_n<жv#m=wNY&|ߛz҂կ)+u!31QWWW)M@%l]%@(Ygiȴ]r%yxPE~Ow9/N!bϏTϋ/E"V !қ,*[e'TIo{n[D׿uezF@9<^Qqk @^{mwqq oBؙg(tM+3zy)+kHo7o^'?iHLvk;)~ם8ꨣbĉ?!ug&@Br^3;/^gU8Ziv @>ַb]w67R;ҧփ袋,Y=SL٤]/ tcT iel PFܖփHomKI~zK 0h0u@- <8'x-mI!KZF @BMM qO<j*ΝkfGm @W#[ @ @, tȣo @ @ p5{8c>|E"nn '=P @jB51 A` q?~||1dȐ~=zk4,kSOg}6> @:0ӡSVË/ j[:\2.я~oOI;7 @ "O`ٲeG/BF9%[ OZ UW]'OO3gNNH @ 6o $pW\֭;/VZi ь}{qgG}7Mog |;߉k6?X~}||3q9 7ܐw7ƌ3k_Z@!m_~y o*ocƌXpa-oXOW_I'x<}w%\_җgɃQFuuoDZo IDATOwfVwwM @@? yUր6g]%tS%0{5kVW/>:) Q`РAyёGrH]픴pcek?1B7-?/;) }})x;پ~ʝwG}t̜9Q?  iü,l8#գLz)1qxqެS][@#l$;ݖ^cŋvwK`?yY=i4Kֽ@ Rt( pOV,t8. ճ ?:*fz+mW %8HAEojhϘG>?cG=׿Ƃ bڴiHDzDs̓p׏#]f=СUQd Iy @԰СG @ @@E=m'@ @5, t4 @ PdCGO  @ @@ jxp4 @Y@Pv @ PBM#@ @E:y @԰СG @ @@E=m'@ @5, t4 @ PdCGO  @ @@ jxp4 @Y@Pv @ PBM#@ @E:y @԰СG @ @@E=m'@ @5, t4 @ PdCGO  @ @@ jxp4 @Y@Pv @ PBM#@ @E:y @԰СG @ @@E=m'@ @5, t4 @ PdCGO  @ @@ jxp4 @Y@Pv @ PBM#@ @E:y @԰@c M @ @~hmmYn]455埆J#&' @ @r aڵgŊ)l>|x=::th^֕С+ @ @)`HAãZ?oiL],i.F<$Nmy>Ṙ6i8qb3K%C4 @ @ Ē%K?nK|;e 1显lIobĈB :eQH @'~|wos|UqIo;Fl7,b{!g<4>~idl?v1Ni t(?CzL @:HU,|nI<ҠYF1~B]|1)v; cşi?abvڤN&$  @ @@9*~x~#iH ]Wؽ)Fda,<$ abTLzN+m @ @P܋C8 2(76ĐqX룩aPD̡#Ƌ-#cҥ)B @ P>F nH47Dk]C3Ҭ,thh~E jeuCjv%tLE @(u-Yu.ֿf2ֺ֘hξf4fK֥"+KaEgС3e @ @--)aC &K6gade9C}DMЕr @ PB,p45_#64g3RА Yw QN @J*Rz{} jl԰>%àGС  @ @iBZ>lH8duk.鐯cf:}&@ @[!Mlȃ|ȴ ˳5}R}7eVlI]lL  @ @Ȳlg}eGZ ٚ铎g܄]8@ @'B:$ Ci!,ahʾgHI$78 @@!;+?cQɢ*tJF9 @(@>! cС)6~_ M'XWС+ @ @4! *w>!NJ6dMb @ PFdCB)dHBՐ,OSERB] @ @ 2!-*<2!OǺڄ]('@ @%]xh6TC] 6CW2  @ @@ Z !ْ }]4Ffu'!j:t% @T ٧% ~nnɾڴ}5oIDWС+ @ @! y}fú,lHBIY&tXגꢋMb @ PVDI3G+ iCI3fei*Dl8֕С+ @ @iG*'rHW;-C @ @`kdL3 ufm՘&>YY";fCW2  @ @@ +2OzMfzufwkߔ}ҫ3cpS6!{ŠMЕr @ PB,uϞς8g;M CU#!gӘ˞h̎u QN @J(PuYzȂhf5dCD4dߍYfZ`U  @ @@Rx0hXbudZ)5gXܜВ=Nњ- l͇ubM 4S:C,  @ @@c.M.ubݺXd\}jiUYGcilb :eQH @'8xËⱿW^\ հdUsrm,[2.[>r9bi7S,k:tʢ @O t4atrx;Mi9<-wg 9;!5Cb :eQH @'Pbذac?ǜ>1fT#Ǝx)[nls&{g :S,C,  @ @@9b̘18cɲe1z8fxǤ}&'ѣ&Xt :AQD,k׮'|28crٲ' @1QFśnx.bŊ͑ÇACN3RY:&tLE[n=#.\ c%n @ Н@z}vm?nf3--4>C ÆtNwС; p+=찘4ib 6<֬ɞӲ @ @@ lI3 wZ'С'J!0@>E}L:5ҿH/_>@{[ @С?ݓ@L0!ݰ&Z[[ceݮj @:l4@o 4(_8rݺuެ[] @~> @ @:l% @ @8J @la+\F @t/ tQ @ @`+[ 2 @ @{C> @ @[) tJ8 @ @ q @JV¹ @^@н @ @V e @ @@B}%@ @R@谕p.#@ @:t( @ Bs @ нС{G  @ @:l% @ @8J @la+\F @t/ tQ @ @`+[ 2 @ @{C> @ @[) tJ8 @ @ 4vQ лs F?;vl- @: Լwc#P$ٳgǬYdm%@5! ta |3f NH3sdnXuP@ЇnE2 5).?С ! @ 00s\ @С߇@ @ @: q+ @ B~ @ @S@00U @ @@ }4 @ LW"@ @. t! @ 00s\ @С߇@ @ @: q+ @ B~ @ @S@00U @ @@ 4{ 4 @Z`[}i/<~b!B)/t(0$ @UοFOٶGG̚V^B⍙ @ @ fL.'BQƐ-t(i7 @5_P-$YR @ P(CKc  @ @@q+-%@ @:j4 @G@PR @ P(o(pi,QŋcG(С P 8mehѢ}|͵L"@@f̘QViƇկ_P}cw @qcǏ>dȐM{'nָ袋~׿_}]6:.uL`ԨQ~2C/`5 C=p@g/Ʃ̋ƵimmqƵ+K\@йR P3˖-%Kl=/BtKuO>=}^z!ѣcĉ=  @WgԐW\\pA[.;XjUv 'u]?}/>Xre^^__oo[Uo]vY~?gsΉn!o?`w*7eO?W_}TZIUH:tI{\zܹspOX 8cN+2=o޼H1L4)_[nq%Ĺ_җgɃp?A[ҹiQˇz(N>|͆۸smw/ zzt' tN1  zGFz!-X?Q9/^{姤?:)1xnտ;x;YVAs @@ zSm @liiilgvˋ/^˗/ÇwvZM<9LZ٬^+# P IeJ!PP \$@X@d. @+獛:ujcuuu`-#@+Բ@*aAjիf777M~H3+/'>Q9&L'|2y䑼gmci6lX J7X̜93/GzG͋+ T 6:*Mvin1|l(С PpJV6/{g_ӛ*қ)~TNJ;.v}ѣG{x'/K3l;O}*o>{7tSmo~4q]wWmIOJ^/LoH @@'O>fΎ8|V8Z8CL  @` ~>mQqzE]QYǏCcƘ1cӧ_X`AL6-ҬJm祷_ࢾ>vqǶ;f͊k;: 0#Ic,4D(3`: ء1(@kkkմCW[ZX oxCC06Er z*U2 &@ Ν+_~}>s!U&nhl^Y+W: @N K @gk֬{g'o1yNꪫ]zW 6 @@je$@ZgBqoln}zVmQ @tB  @@_ q}}K58y"ּ.c%.i @` ^Cy[G  SGg`){+tDGOƝO,ϝpe&t; @6(j  Һ>Je @ @` \tjuPP-Y @ @6b7.kkv?^lӳСݗ @e8|o<9b:yM i,ծСvF @ 0_c#^ >-PfL5w- jqT @eh,xH.EL<8^yXpa,^8/Nw*OiWGKl- t: @ l^{D7׾8x\^hi @P`msK>=Cw{S:}~й)eDmQǫÞ :~ޣC]li]t 1(ضM@m~&@ @_ɯ7Ci?7]Hcd}}|nG|&Fs'=m\_+xE  @voxve.[VQ*[gD@% @C`{ @^xE0 Pu#8%+#PnJTG-?:QBPT @9;blռ  kiF0g+xEO  @\uZJ]%@!`G @o1{hQ1svĮF<;cwϜ 5V{m  @@ m @Hwvڜ3#ޔt^oMm\{z> @+ tCc @@f:,[q7"{~u.+%@>:  @@ #"j/L?ae @@ jxp4 &[G~-mv PK,~ȑ#c8cbٲeQWWguVwn/| Oǁޮ@I @. )>`mv^+3Ε @ ᑊc/w @@/'xb|x+Vlt,gqF".]7pCW\\pA[.;XjU\s5'pB\wuձͲo|7*J!Gzb…񖷼ec~la\I @ҢmܸqMcĈmWw_,<8[os9'.|saDzcƌq7wܑv.v^xvX,[* tR1 @ @@/R[ykkkv i-4 =cFz/?jHۑGrH]6H @ :;sbTiP@谅`N'@%>/o|tbHk  Po[zX~}jTo~3ߟrJ^fH駟狀M/Hi6DeKk;<-r}jOr. tvC5 @5,]xqu]y+w)阍zO`=g% iǴ>Be??ң o~ g+"셫zuE#?Dz^{핷'63-*޶a66?W @+}S;+k>l@Z_rۅ<@~ڙ0aB=أmԩ5kk+O Gk=ٶ {8Sn)EZ2m:l @H +c镟  @:H @K.8Q>%On{!͈H RR]W&V !R Q~Oꨜ#{o'tR=}C1tЍl-:l  @ (f͚hEev;oiJpz,#m;N[ia wc6 @k;Nn׾N #}>>k^O??}>*@ ?\H ?~[guNz#Ez!-fL8g}vO- >xHv}.hmOq{G@;j!@j\`0KLmG7Q97-ڎh:d-Z @=]! >lSzmj7:l 0 w7٤+3 e_XQCbk_?1۫^6z҉jmpyNg p @XBb @= ?5eяS_O:#7<~ð @  :pMl( @`b\J @t-`C6 @E"DQ[zLxQ@PQf @{7r+- @ @@eu}&@ @} td @ @e:q @С݂ @Q+8LJ"dɒW?p92~hnnc9&-[uuuqYgՄƢE/q7D4la[]OԤ9sf޶yĉz*N:xG.wqڵk㠃6i-Wz @xO{.P RL/bԨQ57n\MG# @@o zSS] @@M{r2dHwqiv/xTsx;=־0=ji=rH=m&FW)'@ExEGM  @.^y啸&MÇwz?XbE۱ gi퇥K 7ܐqW\֭;/VZ\sM~ ']w]46nUv3; @$B n @E#+[w,Lj#SW^~c… <8[os9'.xcܹyߘ1cFxqwı. @,B~ @Km=M%dK8u vutرcn3fL 4(#HDZ=nO\A@PQG P"}ݷ=P_>5f*7wijjSN9%RH駟zM/FY9x4iےz Aan @ yL=G&&Osqaśw0{'?N԰2b[:ԪWh Ui/m>mig„ mc|ԩ5kk;lnnnުgsqE@PN @guVE v%o\(+:rMt)PWW^{mwqqF#后yyn_{cHaĕW^ 7Ư7/~򓟴?R3շw[Ov?O#3m鱐>;3L @xB⍙ @=>ַT46n?){xcС1qĶ }oi=.}Q]=̚5+FvN @N;6փg}6wfV= @@ XӡH @ @@QE9&@ @5. t< @ PTCQGN  @ @@ j|4 @U@Pԑn @ PB #@ @E:u䴛 @ԸСH @ @@QE9&@ @5. t< @ PTCQGN  @ @@ j|4 @U@Pԑn @ PB #@ @E:u䴛 @ԸСH @ @@QE9&@ @5. t< @ PTCQGN  @ @@ j|4 @U@Pԑn @ PB #@ @E:u䴛 @ԸСH @ @@QE9&@ @5. t< @ PTCQGN  @ @@ j|4 @U@Pԑn @ PB #@ @E:u䴛 @ԸСH @ @@QE9&@ @5. t< @ PTCQGN  @ @@ j|4 @U@Pԑn @ PB #@ @E:u䴛 @ԸСH @ @@QE9&@ @5. t< @ PTCQGN  @ @@ j|4 @U@Pԑӻ=IDATn @ PB #@ @E:u䴛 @ԸСH @ @@QE9&@ @5. t< @ PTCQGN  @ @@ j|4 @U@Pԑn @ PB #@ @E:u䴛 @B-r2 @ ^ B^> @(@wBw,]]'tN1 @ P"B"~ @ @ ,]4z($ʹ/rbBNY @ @ ^:+VtzСS @ @|/  ]B:8k+q0qH)YH(Ȉվ]e BqqpğEH / BKDb.*BA^ K^Hǎnwqet}kRէUO:  @`rrmtteXn{@@@ j5ۺuiT*Aagڹsl͚5c;Zڰk@@@h:n(vwC'Ztww[GGGr.B!   z1(L(Jv7ӧ٠YB(>===BAOd(G@@@ g  BmÆ 622ԭ 4AK{MT(C@@@  4[(,bCrI^Nm   P 1xP W a!@@r)ry\44J< Bc8İaA+B@Xl@ qzQ{쥗^ |ضo߾C0䒘 @@@ T*ۻw wmlllNB/@@@ h>"^(;    OGyĶl2x;v)[B2#   sV۳gwCv__nIp9!   cVipp~Vhb;   9P'?ovK Hr@@@h$n/i<rbY,4-ewP   M+Ի! *uuu 8,=#0tHj   @a1ti=9FJ9I>B   X@J(\V!hУA!bOG0_   T@w}gΝЃA97!.b@0\6   KX[[[.tttY=bo-c@b``ᏠCC @ d3vR+-U)\n]H?U!.M΄] v?UݨTsOjj mk@bOՍ]Am呑pnev]۷o?˾J6:\A G `V"uUR8|!UE.-C؝2Gd\* А});[_߾ٮXcmA_hvu^ξVcU0}^QiD|Zǘ9(ts)EM{r~=mG~Wׇq=„Q@5i{izQ=KfQӗۖ^#s8|h/؉X@Tѩ" ^+t8ydM؝VC2xȣ׌P=G{}=gV[AA7CwzAƖ-\Np Фpqw5éSlƍ2S&=zć~n$Y轐,u}y;؎;`ջ!smwBy!D1TPGU+XB:A`<W @ 1g_4KNTo7<1~70ݣaS}d A!EX:OA V K*AXFZ:̮﷏wz]Ҩ2BȻd/U'jqpv݂oڙ3g쩧 J?g}f<{ウ(pM?1B 9 *ơP)V^M4J)qӡY%p] Tݒo5u_[,و'8\I=SA]IׯVv`؄72˾UC-Rs̼ǨLXwq(y˲?3~RpZڥ W<vM)hx_̞zIP"x O*ϝ;gos={n Q+tU^sC֢&PePD9\cQ*'C8Ponbg}^W0aP\,B_c Wϫw&<ѵ bqZ>)VX;@IK 4ݡ^kzgnxW… sT7zK̟TR^;v^ySMs/%CV&!*CUFzI x[E\,VWS\4o 6vO]Qz`aqdA¦^-_ xzۈ"z= -!FG Vk֑vK:_\>1X߆l@5 '8h:jCvlT,|vY2 *?~Nx{í*96/%CV&_b+E55^ZWUMJe!A@!5\c}tb{Jz֊wO&T0>=  R2N/{:cfnI4{牟oew:xOQꤏR ~h)L @~-yq=@6wlSu瞳#GomgϞ4q u&ߴi=vM7vY:d1hbU>O*NHF~Zί)}֣!vӷѲ{7/t(z/Z=t!Dr(u_*!p=0ƃV0Co#s-L7yNm=vuׅr=E@mhY4e9֗zmn B=EG'AqФvi?WM 9V LP壊JKUnԓ+4LOOO(SyyR4Kt}pY;qn\w?6ӯo;N = t[}F BPpAR*D >X0Z1¯4sN C(KcS6y3v-j6' ~ *>k 1o4@KBvE%CNO<Fj@gs9B 9,lPE+3-5BFU@"v6MBkf h$zq˖-?d/;yh7juz=鷡y  MVxLc5hI+GQF=|;H}mxC1j-]x$se|&F&ۯ&7\ ȫ@ T}1ԞV[Z7GcԧOğA?CW^`a9@@TؠY&Zѳ-HC T\DU@ ŵk]w:}m|NζDK >z17@XPOUu a0ISA= k =r׾]e5B=%VE=ދ@& BJVXI)xPFv,s%" Klppv?zPXMH\YdBtޞ8%y51sN,kq}mp_>Һ% ȫ@ CCC }6}9NcbKG]lc;nh}% C{䘼D 'Nh+2@VLA53!LO8:ٳ'@=)E@@$?o `w@@@@ h|;@@@@>8?tx{P   \lm6+Tm    0+N     C@@@R) @@@@ B,9   R$    @Y(r @@@H :H(@@@@,P     tHP   Y:d1@@@@ %@"@@@ tBc    @J!EB   d!@萅"@@@@C@@@B! E   )B     C@@@R) @@@@ B,9   R$    @Y(r @@@H :H(@@@@,P     tHP   Y:d1@@@@ %@"@@@ tBc    @J!EB   d!@萅"@@@@C@@@B! E   )B     C@@@R) @@@@ B,9   R$    @Y(r @@@H :H(@@@@,P     tHP   Y:d1@@@@ %C @@@@+Õw"    P   +P[+b@@@~-XC@@@,鐥&B@@@(@O(@@@C @@@f$@{@@@B`GϷLMM@@@( O+t[|nM̺"α\,Ki~브eɥ֙@@@@`uKYgUKzr~z}4'ŲnЎ'|!B\*Dz\*D۴AbY rzqd    +, 9Ű!TIe1H *Cr9Ѵ;IENDB`BoolNet/vignettes/indegree_kl.pdf0000644000176200001440000001102314272153162016567 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094653) /ModDate (D:20220802094653) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 689 /Filter /FlateDecode >> stream xMO1+ *D!!x(C6;x^5\'xiwhN?>r(TJ]n @/9&eg}Q0{[O֫Wxx,W[X\6-ʥ!ffoHzO婷𷹹K=5GG؛t5\.Tȅ{='QwF?%칱& {β\q]8qBC~= $/`K\Q;B29^M$㉚ߡyǫ 3*;QլTߡvMԡSJKz爵Cz9!%8Iz^RY:^t|4#zC\DorV[.N=(&} yA1kk9_)qYYu?a3߁> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001052 00000 n 0000001135 00000 n 0000001247 00000 n 0000001280 00000 n 0000000212 00000 n 0000000292 00000 n 0000003975 00000 n 0000004232 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 4329 %%EOF BoolNet/vignettes/piecewisestategraph.pdf0000644000176200001440000037333314272152133020373 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802093802) /ModDate (D:20220802093802) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 124460 /Filter /FlateDecode >> stream xˎ$A$v/=, seE9i"Y1i 7Sӧh#-o?ӿo#L)}?3_#?#c2>ԟm}~϶Ϻ\ѹ?W?o9V~|g\~{O?<덯źg?[G9 ףp]Cs$֛eg_ϛTz37:ºLZgN?o_9w=+ 7u[r{p/BҚ?~lNq|C}Y8|v_q=H³ɂd^$o]rϯW}ibw_ŝ±k!/>JIۤ_]M=pοʝZ-^x5]?ϫ_mpVGiIzG"(|#E|/ߛ?};wm|s=7?_WGYˋ?gxoΉωǟ?Ľůz>"?Zi?w:~.[?=vj5Q{>u.o\sSuDyU~l}YG={OoC_w\+#NgW6 o.12l|ŏyJlJ\);rǞymQi|u*C?>~Cd@G޼AP&9-JzsO~9޼B ЏhLоѡ~;?f 4?|z9D3[:REuQI|19|v~(=:8^E ͊yioG[Rt/Avay9c?zy x!hI3_ŧ,_yk;y1}*wiEC9a |#HQ;rKV1g m5VG_;:%)%XF) z? |y~>m83RR2Ix6x8J]8P;λ.K `q)|DTQ]LE2RżRЌ|y$塰ur'8_S'ø (:G3AAS'p%#Fa@h&( aqҭ7hs KDD;SO_ȻÑ˷K?'_BA1P9k22!/ph©/7|*{?{L$4Pu]Ʃ1 @7+;UI-fBxsoŏ ^B^ι%sƯ/nLO 4x]}=j\P$rB#ph[5Ohi;"opA;Af!CfcRVq6Cޕ1u[;aI='Aي(qAq7٠}{,Q4ޙ* ΟUwxJc+Qzܣ"P:u98Q ƙN~@HG;.NM G}}rOO󯊝<?k5ݙәv;{C^N"hPtיU8 kH;ܹȍ7O_Rk;tƓkt3o|;m2R2 6+aY/>_'bX$Jrs?[sϡ|QG_.=7!Be龿L_|3*6/t;Wc'pus fMbZ6}Ӗn|Ȼ٭eSdC,z2c-W1XĂXAw?[Cw.3f1oB1 6E~Q\~>;hnu'Fɇܵ039 UtQVг-ۛLl-l6n:#8*)OD"%hc w[3B}<{x3x12)s^'?ׇ4^_:Xzh~=4tK~ ˵ѓ7+uH/Z :H%H!k/^怞Of%Xc$mz^濞wN2z[V,"2~|f >b^XûW 8BY䌒eye[Ȼ\t&s)'>r7 ^ٷp d"E#vGmHO.e'J5ˉW B9BBrt=Qƻ{ِ#u=8?j!P1~:we;B[ ?"[<;;t>+fe+‘|)Z0Z&&CF Eȯy</ 3>`&#;Ip܏/ Q5 /Ygj(WjkwG(Wwz6B(Wiȹ ?>ݣ;lEE6S%dytT;x HG+y:6:ĵre";f@@=a_z,rį@OVRw" U2!]y-Dum>%/w/L[G ?w:Du̯u,wh#c7s':ٛU,S#̚T,.ٛ%MqV^𽾜{ kɻH“!c2(=ԡN[eob9yiqK缊;2ly5MY؇X=NROfTyV8nX"4 BRpC%lwX3\l /2_6%Ż{e4ϗbtӠn0?t-!蘫*>QZ8r& jhBrnz3.@WpX3w%)>A NX B$Eųi奺}04cj Zc %tdXz2ͅfAj+6%0Cjd и]]u5 haΦ16Gޝi=D{+jye2bFyԷܼоCp,uש7я]i*lIXsWlgv1tbcPnr̎l#OCmhJ9RZ& !(Z#Ah)XBky~˪lƒ6lPY 9 ҭ>fl蜴a!ߣА4Y1C'ݴ %0,@]io$B#1= `zNtg;Ieo,"z]i P9r2=\aloED܇`52=C#XbR0o| ~x; vK7_5}ҡjQ,?gݲ<;Z PܹAH.Xw/y./Zx.^O/e!13$v|V!bҼ%wvԭ+l^z-%[Z!S%>vSƾ=?}&O:KHrf Vy.,n"u}c#t>.P$!=w Ig Dri_b v֎ZHr#*U}\EQߠ_<ͺ\M#Q#NV%orBf^Ēߐ==0.I.ݧ[ʺ|r <ŗ>PDۏX9xpw'6T{{oRWPOR?pK9jY{Nv!7Y'7(岪xsl8cƛAFc25o7gxv+Qފ(T/"JLcK/4OO&%tPY<;WYIe3g!^\̻Ŀ ʹC"CQw1X"<$&ҰFOO1,B~JVлt{:QEv)teco윋aD|~nNTT}} _7?1uLfRą }iDX3՗^1ĭx VX`yyg~ײCdEQVMU~zznUJgLF+c?L0{'%ZX;Zl."TXXC9@,A"85Uf|N2u6 Bd˱H=C$[= '\<{mYAdܿυiLP.)|d|;7Y#刏!oaxCqqn&fXlc^3U=kQdEr ,$N~SnM&%iz4,j,DЄq;Cwk1s5$òP" ycŦN>vŐr6N$[B)"Mj1I{xuPs'75ȱQx[P 9ASyJX67~ (KIhWe:T.|pp~M8w{zӰt `TX:@ Bm-;yBθb^Di`&֊ISǔh)mghg0a Vb ,_b AH%BxUѬH\YLP Y6Uw䘅`u13F=VDZF +ܞ6tDq&r-n/A o T:c#nAcE z[!#pCpUE vpKlŽ4 cISv9 ȐP+-dث; uy]D^lŅzzSV7xb60fKvenU^}.{~:+8kle{L2<9 T1&&$9J$_R"4 Z'9-J²W[ONAXň^&{[ ɄʱkVܞ+ȎNFDib X&aɼVeu#6 ?%q9kӅXbp`Uo6ޭ?4vRʳF+yTH&Q?yX;`Ml=@Ȋ 2qAZVOONd{;5ԞT )b{RkDV<܅v5^+bGG]Tݎ lwQ yN* O$#iUtԭŦLFҝYxnNXqj"!$+I!T m3 6:E׹ K<+d:B``6VXԷ8eԨ`ăzp.ե>؝l)YLRS3Б&GK?*1PlNyxuykz<<l@)B*5yO,慞UXŹS|U~yȌT)+=.M w5Ʃ^5g`}18j &[Bn?$VXufK9kխ[6 7:cшtmŹ1;ˑmUUyw1>fґ@2}3+_xc,#>ۧxe?WdVs2~a{R(l/wbI62O}/ mg~Σο$$ӂu=b3NgƂZi2[#Tn+3F%`|Yՙ9)l-XKdlT>h060t&5(֛WB.~xX, ㋤*DU^a> @#=ExOUgÑ EHϏ͐翖=&)<5lJ^%g `(%+}▭!-95]e:3$2.6c՛4wlxmC-FYf$EK?r.V%GĂꩄo^lJGΟxR˷LĆk8 {48Pc(z1#U)/?g1fM:CD-㊋K?hf+S& SH}<(g؄ܭO ͡j4"D$3S_ؐ'BuUR")ojhz}6 :8pAP__LkJHjga?Wg9C/ Wz?e;ۍ%z2 ¸u/j݂(HVjc/lcgt%&y)_%֙])??6RP5,Iޮ01LX%yqpƢRkֲHc OvCnF ɗ'!z/'[UiqQ{%g?6,6@9 5ۡfO_6JTSMP5c?גg^ }IoJ-KiCW#K3T$͞Aɟ| oh_:uyl 2d 9%bB 9k\":SDH48aF5B+uO.3!XvM996G fݦM#N[%cUUNy9Ţ+f9)|㴡e~#ql Oi[!jl_cbb.<}ԕݫ{1hea ڇ}nyPhՄrI|~QLMo59= #s5?ۛT,"hcg`b ߾;7WD]k~'ۄ,~f>?ָN;fG&T hl=Ս5|>)cj…/tO?AQ-/5e1{c2gc-gV,%3"ӕO_Ҭ<=@ީv?T샒ts v?$}gքǀ|jU~}|04N̺LsNe휫d+׳d A!¥}9Hfw]E96T9"ˣƆ3(!}1+I+3M鋝~b34١7F aύԗbo%ao_dB#|v'~`ŏ>oyUbV=.Hn#bLq u-ۣARp͛qJmX9i*2Y#&;|ji({;b8"0ihXr8TNoFU" mDv"V{Ri~>}jnv2u)ADjޑvk47ȩ(^R&Ӝ:%sҝ|Y?VtZ @UTS^ e_B Y㭱:;mF19j9*}oAR?Uar1x]7Ec#baw9[R7?6Q:psd^{xzAd]Y>P,p2EhqrXW@7EYAj-uqpud ξK{Q)lFo?1ӈͫ"S}( M|a0rB3%8mym 1#A ] Cy.zقm Mh}1S.zؼ Ԩ 0&]4gt Լ}r r*N#VzjZ¬1Bԛ@n~lЪj\>wV,r0Q$:Fz#ݵ?kcNfac)/N6j'&/U!}!Gt4M[6UWkݟzxb}},n}cBj,܂y"D6M]+[rXX}M娡 F8y.4-f=EH`$ zٗep1[+S"b=8Z uz U!4j3#]=lf9cc\5H2㸯dOJ2z[FAs]X8mX~Z~$z 0$W廏EOXT Zig_F;8c1le*;t2B*3^gb5mc`I?64렖6I!Զ6J (t6QTcϝe}4=X>%ޗw,U/IZiڦrz)=TjIsJ3^rF /N}e1r̨w7ӣ}!|Pͦ =|1=>bЍlӖݯ{3n73G_D(CZ=?Ş_8 |gif~YIv,O}v. S1xﯾE ̾ rZ.:WlA*ZV5@i/66v&tHVzC ,%G_zV_zS#%ԛ0bA*/a_[ț]:V_p5p. YĹH-'\Fa"NvObט?P_[W6܂|@-7u{BE9)%‘ƐiV:>7F,6~tג]ݫI^&X@]݃A%ϯM. !qOOato!go$6ݻ72cda%*Sa Z#4̽jP!?MoRiDɋI+{yuj05.OHzٻm%OO+Yʳk`iM!,k K֧-ϲ|hPD_?VZYTӖsc7y"<VJi&P7KuWcBJ1(>o_} 7W/qŲhmwyOUv ˍEe%I{Z Oqxi%_S0Tco{!6`Obovߏny $?lFH73xWf=H4I)Tgo*bo ! cCM~9wW?FYY{f?o$aK__%1TD14?!1,F'P6$Y׿boe Tl׼mc)WD2!&#줉SP9{Hss6: CO2D04:zYM`n8d=_s'FFW-ݾO=f,b5AE.%#fif/Il"wƣ(݆S=ջgU_Y{]:`n➄IFhfRZU.6uS9ӏe+WHy AZ_=x!$˞}~!'Ӵ{S)PK,xȹ[3KeA;GU$ ]֛n8Y`{>oϺ"zbSh[qvkW*I&.s6 v<;t1Cg_>[ccwjF$_c0Xv j(żɴw/u~Ƹ-F,~ut}5-e>bwYoӯbzpdz]0T_ FF I6n- MbDۏv*s#P=E(vU1YJ_>1ԩ%hYcb}afHu\<͹uJu# >vmY(6AYK3U eƳ&&GS /PP 煉(f`X=8*h7u<vz8=1V=H]jĻfK ,g|ki5F?1n2qM5<8}Sb\Or^E]^F85KgݖqbkӃMjxl{̾ jwD5^vD8(8&zfTc`P:ѵ10hOB)A8if8N` jH5=w(_ c11r]§ӏ5eME }W8h2^[{t>yMip\Pk 48^^`U(|d}By]$ىᅴ">>&gQ"_~n@ŧ]ub/aOI84dIA˗Z&E\$ƋvzT . -QD%5,8rfΩk Cv?e:(6v4z2"l2v5CNN#Î]>yـ0|[?dvwy^9>&~աHl}V_2 5]L*do8߁gfT`ȫ:|F225U ?oB^M?6771j58Uf>,Zm,C`.KY%hrt4gF/u1x~Boz_?t]3c$aKKu!'xYO4cu6Gateum:0GMF57{ ww/8cQz ]NnYN5o1!˳I@ ?M"߀2~ەT'SnNMZfy|rV ytql׷KҦc{qzUٸ&͋E'doqdJq{:,c%k<7pQ?}4Q]g<=CYly%g8\W| _>Mzsxg14Kk"$s4~ /2%{z6Ou5P,TBƖ@$3`5\:|SeIɴ~˿wImdFв~֚ ×ʬ*l͕_*ww~m VɶL06Y`\l,bj+Yi"[ݖ^°4+b޿F7O2&_M³>`NAS,?d/+?55'~+:1N^wUl[N.{f᫊n.?df?T]b=\oFhK :-~Mjh*li^T0DexSvVb7&3=^i[h&.)V-ϓϿR.ԏIۣs G}Cs$XY\A ;Fz&` k"^[Y 2=Xo-YiS5Gډb>y_ݏ//{T){ MSQM;%VSl &k]eKNֿkb}D\ߒńY8VYLdw˰@[y"2,.Kϳ!Bb [gU47ݭʹ,&&uXMQfX'((YJ6#2|G>O㛔ȟ_P=uZjL`'S'bwoQ=MXBQ ?hpx|3HiKgNыZļ 3${'# R>7^"^Bkוkm5U J5E y Yy֠ǰlB42keRY~zCnaoo=;)ty>Þ_kF9T)|4S4 uUû\8ߑO֤{C*R!f٬*4ʥa4Uʜf09\ r\.7WU9%]XS!Ǥ +Y]tuGf!ۗJa&9TvS>Kȣ_g{#Hk$aE>2 G=[r^vuz_}u 3EOٔ62唆,4RUW+ p %%~ әKCupY &N4 ]}Y_lt,YRqj3sSMzj-~N`45 *p.QrAF<%l-i':- 09g ^o]J"4Wnfrt>9`v8ʵpes bXcHŒ\HଘI}\/K٨5qurѿɳh==!g+[z~S'd솊Mm7hLx^o"k `e%dFП_ =&;ؔ}-0meɂqP)ʮbK[gudXmٔ~&irN]wj).+`ɦ]e2 j R4N2aWj;BPWUYU٬v_>ǹP^c=(qBgA][G(CYܽW*-u X)5_owMLTЕT/Qf|+M2^-V|+H*{"H|_yŒQ$, IW%+{/tov1j,.QDdYK؁ylп8K3CDkY> yђY5[P h(_X{07DGh^4wg]ıWk$6{U_>ό"Rmk6|kF,h;NTT< AeJ.>̶$jr֍߿=qG%WqcPa,$ +8`Iˉ勇$yg5|Y;U 5!݋yU ZMJrsja"~yU"Ͼ/wTcDDLڶwW-#߲B3#Yww·HР>Nύ-  Ji)oyўs mjs޾2.",CHhUK)GPU2Htؿvug =0y 5R|G~/o)4X+ڔ؃m ׷įxz$dq}xuxvk0n7״cTSb&a)z]\EĢ֣JhUAz=k=uڅiQ~ſǾ21MpW3/pQͩ$W5Q%!B,c^TT&oJ\}54c(yg׭/Z>y}@zz^fv=(<[S\]SA}r}k=S頻˳Y=7,֪^ͩ*4씪cIA )Aw;"Y4̜jB[w/~YL-=F *;QxhgYvHj$E;&}'>v/>,OٷDy/B-h~ɽ9uB :NyN[~2L M8Uy7w~'*[ !4Q}0Pc}XWGBjп..M5s 峾'<~c}~nӿER)[g Y=7 M47՝Ag>'ӖMmJ?k"foln`}鍮UuF-ٰ}+/Sִ6\݂d(w1ÉFh; bxք={>LH| R5ivb&-VyWY/=_?JQUrŞ)"Ъ _7UX7{??a4'dB[C4^(n_[V^QB5`iy}=fv4ȅeTy;Dp̂!Ba>IwiFwYۅe?%SZxɒ\ko~{a^a-s~GK5{ w[+ﭧÊ7[r|)t6<6)=ÜyP3H&S‡'H/էG29_bux >_,lu]|K +K/e; 꺡!6TsHt;~u,s\ad~l ݏ瞯1?>9!?\W/~/7'!+3pMB.=< {eؗ's]2vOԕ\o!cr<FD휧Ku*v| pKʂp)/hf| 8/3?j8ܪ ૎m۲ 5ߒ~s߻G NBJ$;w`B{#'tĄAxӆ*ZʄAa xui*]/m-Te xξ/11 "bC;{ $"`H}<+> &jGH謺,8\V,E%ѱeꪰN!b BҤ: .Y+A$=Rc{!qTR1hP |W Y&&KޞzuL|f>H}l}!&ıGޕ?V+xD֊ɫ㪳>ZhlbsZ7)yYE.s0أ:%qDl,Ήzב Ӈ/igv4g7qEfxxGKʻ'|^ qR#nɏiE̦:}+tt=s-|ظU~JG\toEϻſ]cLY-/nZ$ޗ^42]kn)dt}d?O̩^#ϒ)n1_}-[_G*JHr^V{#ƱSX5k(9 &Y îѻ侊Ayſ/uS<)jA+"J WPV93{ⵜ7|}Qh~0Is;T߆C7? cO]>{LCA_C$?x`m E?q Y~ [kmi?Ta֋JZƴ[%am 17 R0$Fr6oҧ 'p]\MŴ6-K9KU˻54 !TMm82Uk㰇my`htjq}{ז}WhtyF\3D3ZKbUyXKL;-=2~4UgYllRư>2wdO$4Sv\/|2d}U :Q|;OSUO@{7'Lr*Hj IE([&H@~l\JD7$aQ]E7{`jݮ&:w{zwQ ^1y&.+BS}8j*3% 4"3tT!1"y~^P^K-3qJa,aOt^D}{ɤyurul ˠyi6f*|qfC8e>Ȋ6Hi5he&1r[bҕyX7"W'GZ8MAUHI+]_޻L5y3;սtwC~RӇ+t} ?.~^J_zfݶO'QΠx.z''e4ODccə;eF8*㿼­m9nk1$'e絟[v,bQ/1>zYOW5V㘻!ǙB ϩ5ޮ׼J\HLji'MvQQdgRiL~opl5*7#nɄc̸1B \4eH|JKUr]L]Iű30&DP[tĴZڃj{ ʓͤvdEǝ=Bon( ߀)QR{ ))}ܿ>ʎ,QGzD=0mxes.\&J6g<SE6Kee4!MAyYzz 2 o.ĠhXqu9kdzjV& tf1t2i! QmVM6iJC#istqyo,noŐsB>O0}7#R,Mݰ)nrxXc _uϮl='tA2ezTEcO56)k7|]ʚ*9=ă1n *Mb(l&v}(V\-~'" Ŋ_W Q/BwwG)?n~Sz4M3+GwAr#x\Eg120#8? Df=KOn]\޹n[dwu,ݸ,ᦙXXAF-c"7c2C盘HE]5(S~T \ʯ{2;i%0ʩ0nL_TC}:6P1!o?`-IcB>&O\7 Qo?vL?B~}Yet/+]rO`}~8^ڱ*}(0 |d T0_yDٷ[;%'&Ż]1_+kufnu5!lslu$qLnu+E f{,}vEJn>a _U,ޱrn, }#=,$ Q_ 闫& d?w$3j +~*:79Gmj5g16E&E7i<`=0cGյ;ۅVwZ9 X2^7{Zu>,M(GHBN.ץLX"w:wv"\IL }45as` (WgsWg()O^rS㋯oSͦ%h#Ur/zfTwIϸKϼɫ~ _Lv5=W]lWw>3o3ƕ^%n*Y{Y&_g.u応rPa{&[QCf_*1)w%ihXuS>ΡwebnjR#WsXf6,^u9nWǐ{\ݟ_u+i3n2}~(=/ٕ^:kJ:$sZiؗ%R*1mm)~)j::6'n`Xl݄ñNA[swM82srwQ7bjۧ١~d_M.oK-U5Syx_ch`m^Q>yyxtogcrodS&(vZ1 <R9هE! * r梖d\iZD"љ-كNS4Wf wSQ(| ~҅]A6OtÆ =Y h3'!GUf"o$ՙȬδSi_/\A|EO/8츚Ixjc ղ*BnO:ϝg}=Ka.y_9L7/53ã#?1$Q𑯑I:&n=LUU 0{"FF&*=A/49w(x/,y" q/og,ݱRXuA+xxGꎆӳzbJ:{Ih.?6ljfw%U(hƦiZo]ғuT7\"`-A@F'f0ڱ5/BsK5sw94d2biJLl'ͤӆ eKίǤ+x?W]ր 8G">oMʀ j֮,Weq]?=^YmTNcȽbLșۀIQ Z0TUHD0\2wPuugaT]"-'9mct9GXC*YS@ z1t+M_8F}5ĩ'U?JM继e&$1:N>q|y:#fb8M@ᶕ>js+Pȴ8v=5N-{L/Q~z;“3y#H}+Zm<>U( ɿ+R ="_FXVW%? [WDd#m,wr'eȳW 1P/F~98TMUo ȠaY4to/AeNg.)9x8{s'݉fRUvSAOqс73, Ӭ>Z_i!)-ӈ{}_{9^\CR@;zƎx] WCtjit'+Nh7nʹgĀ4g@t0i[K-X%^z a8-=C\1KX\zX_'Z+=A `~MKY gx=`ɹs :SYSc00n:mcedS|=h^fZ;b4"Kf4 K:-@9X2!s0웰ʖ)`6if"y~h6& 9ȃn+W3ah!8}ov~Тl65,E|Sk|agĩ`6ɡSf_~3d3@nie6ʪN!n`î3}c4MΠjyj >gw=n-6ܴmQ*7/T-fK}Ʌ&*Y#VIS%G@7RŷG4KYi^˔UmU͘on37q4-raMxAkWtL7r$W}<N6U=XMќ)"U٘ Q;{RӴlRsR+4srjH2qgzϣϔeRބ#~ab'½".k"oe]pϋЂ>OJZ(pHR֤Lm-Qu7'?`xv,||sm?`幢Աi5a#I3|TT%'z`A|VCM7$8L=mazy$v#z9[kJ])dG@ݶ$XI: q[*킘q˷x ªSߍxx;qóg _?ߗ G~7U2u_@vQdJ!լn 4ЊϛhgؾR*.+qGر~U " /$=j0b jv݋`~82CQ >Z S4m5$yS%ZMKbFc ֒l SX2ʼnjmƧzŎFs2rV#(ΠIM{TB#&xBڿfkrxʆ8o\6;r?cw#]7 hJeԶ~`:b6E(Mܙ8ծu~GEKDr GFJ\o}~i=6n_9"f1]&]Or}~?PGLA~ YS]U칹#Ţ .aeOx&[GLf*>1LfZQtߙل hBqyB}Wq|, g{yY<1\qC hJ@a(| ӻA( T4i#_4K7hLEqxtwDe%'΁F#,ꥤzobMByV/Q Ź wO/SAkw@Lp"f%)}6!1NO\+z ?1FT֟2U)%Wp7Œ)ڄ6<@H2o927JVw|Q>m#%aA +z㊀D`flJ ̍p\lgBx.'m#M~絰-r{#^3-(xx_Pl g YdYu4q#XQ]I|s0d>V0Xwjn}*N)2ҽ."a~#9тJc*9y"Y'qތPӜ*|M醯Ed0%"ۿ g5s7ay=-W_ϏHpLDI:r=5wXSy:uyL|?KpXJwZXԺ GZa'tM֔dS Ē8um)~Ftߜ* m_<{ 7:>q>G~S}:O_#.ҝ9bQ I15Ȣܮ@0x,-}+EE׾Tӱ!\_N}s Ohcc#i$ ccKsސA|@<{ޚ H+1( `T24RSAJ%QЇՆ^2W?Cw~ǯ,d8'CzNoگ[6Uua])]$R^]1-?9\u|t#|v, tc_ J~㨰SGExt0X@yf}RUyX~mc!{'sb[F>h0HȮ*r3X\o\b'>yFyJǑݗlcBw_K}<GJ?]řoU`dcLYx<}9'Gvk~h|o/87o=^Jz){' ;Oqo}B|f+niT!~GpL6+/P*0C QTL8fպO3j/-lݗsNTX/1QO:Y=ۿ?_QmSk,prZn-{g ֱq) E:zĹA]IE+M]'F"'q*"&Ϲ3b=񱺬=S1P&wg/2&#~מ-P䓿Blp G`hϰnR8X[y},WzapԏG{,׹mq<Ӳ@ YDp,c9Y̕$X n@1E1۰OPGj۟xqIw}ڥyùh Ear%;V i/iE8~8\-yE[jE馾u`:=}}GuSvI.p}XQzɟp#^e ' %ED<3M?RFSWF'xruTN5MadP}+ u_f=b#iN{TV[u*bm/ؼTQI>R<>1B{W~ϗ恐y?a:w}ܳ?+uM|^#0b(u݀HB*Π=|Evit^/3#.im?>Yy"y'+t혚a8'zD."S Lo׫@<'Kvhr\d a.ÓQ?5{5=Cm|_y:ds7^[3;!*Dz2V^ PO?ƫc 0?-"~q3>)f>?Z쇼~6dewx9pR)0Px^@wLuXI˙\|``͌'3tԑ]6ԝ +2q@VfV !pș0? mJ `i# 7)-0}9{|re?Yf:uO[H\d]cE::>̧m] >0}%MP]mba{s_|UX-xZ纗\V}~ʕ1,DɈ%"SP+YnQq{k\ZU}v R28NR{ZSM\0 K@H&Yf#0}lf]SQc@ >|y߬Kd^AYА4l\ 2Z7oj!J{Ǘ>qoɶ({ǩf=x;4A2t?QYM"?y~ϗ_>% uǂw]%CS2p%蒑Rzd&q3o4t6n߮r>Τ]b\|% iլDF{ɯB$@d@:۷[\.^p _܉CnYd.;8kbM[ݺkqR .YbudXTš21P(jF8s ah\w\2:H !h ۠{k;`KW\h;?[T3,MYΉZccΘ-(k.af UF4O82r\rҙeݩ xһ$ w;b©t#+Q J> ᩈ91ё,bq%+U$mr%#-ko@8i&ާtxn5~%zǓm.lG̩g."{>Nhv2L:=rRYN~}{뻻H9%&76QjJ.o}OoO+qhuQu'!x҉?HaN>NtaլJ.jGJoTv8|E;j]q,]Ym z>%(Gu;Q,%fǨtEea^!˒$&\$z1Hw{6y%Shrۢӂ.Y [$/OϏɪ,eV))=U= nFӻ;~$$D3oW޹~1\j;E}!}8]$$EiaHYIzdž[7!WTGĒqoyLVҤe5(_*[,x`1 O;e9'^PxvGd$^ᱮnjK,/|{+@pT=CGI&WH5U/dёdGQp7 &aE荮.Hd6TSo JQCo'&~Yrq nYqֵ>~9{zXL=TN{uXU|*q#"ј)RCqI1Cy j ޑj59oPi~U>A8ӥa.4|x2Sh =dYa3'U(2ppߒìӟw;E(Y;YD2/a~HC!]w4H#u'p137FE!F#~O? ~햎h.s>π@ylw,&֔Jq>I"ivmp@̔EFxVQ^DFW7L4!=n0{dwCWL"“>9_YןIJ`~mݧG>O\!a` E %Q؆`I!laNo-\'t? ^~K|=ǃon*x?\-r8P>_;ěE9(kk=D3:>ګYb-P pkٴPc<9)>g[0FdB^aIonn0/'9xP5,p(sM/X7I\-ki{ |+ā0+N_. u.$B < 'h!T)(b t9!j6Z:" [\ظn,d~Գ#PgцLy!ضyѯNT. 2%aqVx"vA%*׷5ɨjwM4LB7f MVȔs"6E7 UC.7QO!.Ls3,|tOay)>q;<|ciupϐʦG-CL[ XLX߬ۜ:}8<,u S,X$\'ٛybsxdY9Cd'h2k2eANfwŻ~4Z1Mq>,9,^b5@=bzv1놖dpȱ%)n+<.,6=rYHNNSdq2QL}>Ln,7 ǽxZ]r#߼;6NuQlj<}Ox63=$e_jëYGM<޼Ǜ0BnuisK45-z2oeQIV{2>F1mo428E׿fڻǓ⡼np8[}YaӐIsvq Ӕ[T_>*qU^|~ze:pc<&8W؎4Ywcn}Ǵ_Q,qk "2V1YttF]+:vXz vޯaaGa$θ4uq`! aR<6d-mu$mF[OȌФ7 .kX)SD۾WE)3G0wɭ^ko?aqp :O<-n=pc2O0R |ܥUmܖBvppfVJ&͎|m&6`2/Zz0u qr_/.*y9`,Cb)D\%G҈m Qn}oklfz H?xxva]P#Fߏ'߇fdb4>o6jGՠfbwznxE3IÕ G_)vۊדfB}+Kfyq_'|\ϠXKYMF^hn'?Z+n?ߥc̼P~^U}w?i|4p>pkqk"<S|~+ͼ.ֻI8=嚧RTLqۗ 7 "b%Q}ex[ q&[dE~}GUoή+1N|_ ib1_}.Y,DPtw BzgAN?O[yJ~V_?x[s/kQ=qީ@ &: ֏/|y?#~S}7/|>|?΃|[xB\P_2 DC>*"||W+T֏$ v#PoA]}Wչ4j5{,Ǔt2 PR|>4ύߘO(*{ԍt}9X,֯y`}ZIWfD9Ɛ7|='z)1p-jsp#&*o~ i# /kb[ҏ͉Y$߷TǀdG)ʸ~ϲ%}f> b}y0xKq͟+|O^σ,]#&AΉ7}*G;o?xLWV<Уy>7!yrxQwtZ\qiC8)7RiӺX4+σNOx~["~ yYxhCFg>$2+s_/y[Y\;fE9[&~'hvzOy 91~%4xwk&X_z3׻c Oӈ_C/E?+z&i˱g/S_4ܯܿ !K4ޟL-I<P~(~g? fYִcP<x[uh 3էS:iBy U;of}> ډ 4Jnw~>w>NF5e\O8o؞~]M6m:2UoF;7fs<2$4-ݟμ;\vrFz hٶԍw5zz |!'q-}~=qo~m ?+t8/tpIrgG}ig&gu߇NqDʿ4}E?i5/ot8.,wfNj^̰0΃ ΃fK F2Ip)C?~~߸Oe,~ge|8?Cvq,$MYkk>]"냽1υ=Y,;x,po.2G; I<A_qu~?s} O"~Py#z1-Ju?hOv~gI^qs7zg⯂o쒾cau!=K﹝ٱ7i ͥ9zܘ:pu@!.4%VOpY =>'l#F,ܿ@ǀesҧAv}+g͖%Z‰sq4; d}]Ǽ><t#7疤ytW@\:;爴h*mlsL> 0q2~튽\Jݸ[~g_k'x%Zn:'wKW]ZϤ3]En 3ZzCkmZtJi 坩V8l+zJCOi6⃙տſ*΁i&0ܘ90;y:zyyJ|E="Cߙ^x0h?Q?vc8c/Q:}u7y/nGH1<g 4 |7=yȜ7-RePxϯ8OzsG/E|=8BU ۧ?Fo?X܇;~ %|߈eU|!$5_oYuM|ps8~[:|_[oקGf.H*7?4ܲOklFx>++vWy{ϝǁOz)(UXu :Cv ?3LqJ  {֜1 f1Eoa]Uޙ=2{2w7Ӹ fgdġp'3~<6S/gZ:~W@ !T;-ɂg9P'&arN>?lm^\ MCѹ.w|%|^cS'cf\}wu_rEۖ~ݸP!Owy+>w+WxUݘ4(`g<~>(T#7%2fmHٺٓ ^}|nt0cǜ؉7˦6tf5"%.NNqv#9NMEW(eJwtPģ-T W*r@M8}JyO÷O(8gww!O˵+=(p_p<:Gx|؍#]6ؠʹG>ϯ'2{u@O|kq. t|!u>J%uPJo~V9|tp*:(?d屯%vboM$l>>Z[FRDxǙa183O阇/>=Dg=3?v@4?Gsy0px}e^9 *';d/q3,— },9I>ᱱ~zx ~7͟GD}¿` \]J6[?ϚBL-v@c~jQNwgL?rħ˼fW\yv ڡ縧߳[ ^CW?.#|>i>,}iY}3&bں.DLE=?߮?I#97"'#_=_Wp^^)Ww_<.?GkFcoik lxtPb&zyq_s=HA-|A.[8FJA([H@j]$}D C2y⓳3 t`kbGy9gIsy_ϝndWi?^q p.dwcޠR䝅x:O%)."uq\׀ -}Ng(w>>cE~s-G=[U?SGb~OH ҳc?弿qC7;-oGЩOB_,DuL79&HP"|?%N*HOo> mn"c>0yq0D밋sb5b}PN 8zsy<\L}?}|`Sߗğ*z mvs?x$|d?" s (aR<фWXR4re>NO_P_Ĺ>Q T176#-+:{\s{$ƾF~,4r#'-Tu= us5 ="ެwW-N|=P?׽F%!du+U9,)MG!IF8 eyەwY!?x>H_~}zEe_|?`Pu9x; 3߫ rܲﷹ|7!F%~(2i쳘6 Hqou%|g)HmнgZ‡;ۦbUW8C gW]`|ό{~2¼d}pp9l9߹=?ϱ{8$.QGuG`LKqNw "~ ʚ5Ng{k_y5kv_ aY7K,k:}y~ ?=KiјbܧX M&$nj¤TT(.e(} ("/w`^')8x` x?Ͻuq^3|yOQhR/Utooǜ̾,rxw{ .Gq41y M}v*nzO ;Cߗ>H{My<~\zw^>w:POrz'A~Jc&3:wF\gUv@5_;Nhe9o~o!c8޽MM.aCm:e=lLswV>nst"^K~bhEg=?긽?}ߧM'xO޻"gob1KO%~3įڧ?ח}Du s ή7+;B>̐ujCXHm K6l%x3( OȷKqƾ`Rg*o }^|w W{=Ss_y;^MϾv﹄B_8o_y;,[OQ<_[wō{s7ˉ )7u.O }|x<|uj}8x kS-RdͻI&L2J0_&#amoMAuԬK_mz?*a_p P;^^ xo3FP'8%6L|*gA\wYQP5Et=v ){2vxq{҄ iNדy7oaw^wu;a1k&΁v㚝bl#ρzN]jxM:! jשuO>Ӆz b3UxBiGclWeŝwyjQ'*;X=6:^ ~5x擷q]uU+T /+;f|y߷{\ 8t?}oR ?cJnB/y6n4cG(33)^| dP? EC(p]̈́`i.2QE>GICo׫W牘s+}]9m uf/.{B ,a#XuV Aw.?@3lFȃ DzqW>DLdYm@ܙ+ -s|DmoÍJ?bH:~ىoNQߔ b;kեlE-쥈Wվą_[wqiM @{4mD1 ]Z_]*zZ+ˇT5+쿅¾C;c_~}'vݙ+dG{70I1Ex9םo/n=%]oqNv%B!X774 l+t;~b|Qp蟊wǏĦbebNNFt.}+TuF~ )bwqw A N5xxwtɾoE:]D؝_}3C8B2r–f&XNK+};p OJd>~Y>!NGT?ֿ3-tARsF9&o t0BEqX1/CBb`;sV_qqҵ-A];?fW[B4;Li.e?L+BVTL[ +7PΫ4J0*mEuF=|:HYE^ >36=~nu#w|QAwu\BVp\Mѯ4I\YGߛTCphL%Cx}q4{Pgzf#>>@8{cΪ;Be1VҾ#Wwf[:K+Gc.)+z0J_R[Em>JTVNuR3y4+mŒ,@Ew=j05 /J;~<ğDZXhRPPG}=x9/;)0{fg3>Xgr {8BSg: hKPY4_P.c'#lNQ1aź3;|X Y}Gyb$׍)_uֹ:lw㹬k}}ɑXR~^r_>S|zc:0+Æ*J0]ߜ|BfL4b׽hWgL,=PGϸJrVSGMT#SpS#TɿUkL̬:VTD|T'+[33S5XS>{ULsJn~V .S@Ƨ} f#\$dBvLmtɹC_ڧy҉~og2ڏ݃Q" ,! _w,!v/acOz|\.%M. }ϙσx;O#FXu|7w,jŊ Kw0P3Im~ peG`V 'Ս G;}>ŷ1 בmr0te~~xW_84םu2F+רgFoCdJwѥ[f%_n^XS=c> v#7ބǻ~G}"?=x}Y/~j}խYH$%pRwY'LhϢ cBӖX7w// T8~g}N$`9|y@e })}7^S34.d|fp@G@f:yunԑmU[/7s~_~z9 xW(w _PEBzibyX[ G{Ө^tg{݇y8q={*{$oK{`䒊n'vQ`v~Ǻ?{|PXjpc$ohdOg}B\w:|r%3.ƸsSyO[U`%5w,|ǺYT+Bh-}h'!b:P~ KtQᡝ xؘl7;|>yu:~p߹}U|;Εch! :|TNh؟}?;"#>#lY3~\M8y8Ar9@8WK]y^Jr^T{Fb~W%&oGc-;E]l|à4Eqw ~ gQHW=BGݪiE0:C`nrB1dLdgK-@.]tg>gn]|08:R|`fٰaF~:ݼ<[/C?ֺV4{U`64@#fgOl4dOw}]Z/?VF| G,FSZݚ\S~ D>wy yNjU>#;MFx*ZϘncy7_O9xk+c ]ҧh_"Sf V}9EV탴ZՆr_Gw.|xзDA|:pye`/* hΜ1V}hqcX;Y$:x!OURYb]Otƿn]v#'?DZr͗m9o䟵_tO.Zh<9qn|W9e iWϛyfx0 à=!.ڏ̾Oߟ|?<aO5|{6߈%_?y>1JeU߇>O8Kԯ6CYEqs߅<^.}t@qq8`ܯNQO9H֣MW_~>cOG; 7wωa،ޏ?T|^ֈm">lmq[_? `XO=gf??;?B_K} _Ogz_@_ȥ߷S|?}wQ@Cyg5}a?`Py/pd;bFL"&@`og_~@`?'XZҽيdg~P+2p9g~3|R'}}^*>꬟1^%/È?:i=x[<G?$U5럍'ԟK{?e^M>Kn(|sGxzmS'@!_>LtKx3enkbfFo;k=?~o:bY3<_=n TwO?wWw<@?XCY8?x##./gbgACz:~o4{~N+5}`^P-]G +zĬgKlԗt#/_hcuq,~?'o?I߮3G7~$[&> 4_?saM#c:Ŵb,ZQ'Wၐn6/<_𿺇$Zgq(d}ty</{^?ߟzٜ|wO7~֡~ǼS?F)̯7/yUGR4q)bY+~ϲu_k_'~M/׷?_D\wN5dlWO}{q|L?@p>)l4TX^8x#yq_N=J-7+Tw>w!{ 7𓟿ouE1܏[or?p~,?">Toߨg#_g3ωoxヶbt缹):yol_7߳ƃ/tG?3/Z1>z?̃0&7#O/п|e;G~Mw/o'~!Py#gaoA>IlCK |B*Nk!fZ~0 7oȟr']S "s~sk x+Y@O6ne]=_Y"S4c'~>.eE! yjN~v~-7qkmow^ O87_$Krd*b 2[ipP4*#O'~Bc# M?}i7^BZuxYwt; rF:Sy#w<l`+"pz,|ގ-蟄~?+#]엤>cp,F$qN ˨\'-VN~~mcre#y%{י֩;7K[~{O|~co]:nO}XVw-_oV9oW6/ϔ'*|Ks󽽞yO>I*yм=^'.OE:Tzӯ3y>]~N'߯i\pcռ3J|NZprY<||R伖6K-r殱]Ϫ;։¼>~y`WZR};&XOoV}v|xg}o%?O,dp=v` ry߹E6@\6Lh@w~$ļ6>؅{ю:00<{OxA}|DmUX?'Uu3ZY''|Qob~Q_\ 7vP|}pzE1olƽ77scbqy~|/s+˟: *byuݿTW17lMu8a|{(/1NDѕAu7uZ-Ѿq_x ݡqiu ;NoyP[ =T8Ӫ*,A7Po VIl.%Y;ۿUz6(/q\`oNt>p|G!NkqE⊘e=b?wPW]6c/'[oŵ:~:n OQUBR:uWu|8#_dT:FﲙoN.yGA%'5We3X7^'!s5 q ǭm3CKTXw zу_1TCy{]y;ySYy>-ߋ>B>yW|&>r Fkf{ov>OC 7*d+}av\w߮}~-m~>/yEOv?_7_ÂBoS?|~Իĺ4'V~qν?ysjcq\2~h8ms|G_]H.>JxExn_{.S%~jO|z})Rp|]p<4Bxtҟ_ߋ,<؏|wc>1q?ON#D-='f.}gܟO9+ >y_0І[EG~g`/&;`^Ow_7Po؊coWo/-9~_B?[ QB=[€4e3uun`!CԗYNxeBS=9^<߼иt|sA|n׶QQ4nyÙ6]@7=D~wW(}@`^|ua:[;y $#?}˯So޿)o쳳էF |֏yuWu`eEܫ{]亻Ls] i9l|^]Ewy}¥, E[OX.u~.:\GJ8Tc~us= sba"?׭jVr/ ct{[ӟO .)1wM2]>}hxd%Wa_iW~տH?[}z8 T/BWm+%,-N*[[^[[I)ǖsw;儥TuS]Eurjה?X%q? !ErjGGXBM4\rAW uCA^/tM_ 1^}] z~6s0uuhmjlRP*@cylEl>_'eѷ^{xޗI?RZ |Az|kra´K<<[|MSʱlз:Sj]Y߹s^ti*ɩƫ)pEΨO-qu(N_BSu.c[>zTʠOL'=Ias(]+ȴ{`uݗ3Xj{@o{z߯<KQǖftw<5察["Y[,jve4+]Y&+>-U]^GWB,b=wv`Wb.fo9bnzq4n[W?/aߴ%br˨߂ܒj޿9oӥU]h{ߚwtu䂽m #r.v{yiݵ s3kݡK:C*XG(:}j|ohe~+ Q Qy4a+d6 5]uH-7.M lNْ>G2X%hKnTceLgslv< ZnDoc,kl˷Ͼe;p̘O_Co!v.gXc39yv%V4inE+-ڷӰBg_ʳ-b|> 믔,XpL?r!RñxAYWXX6wkC}}שf Fxd_N|=m׳ii[(U '|nhoGXf\۹_.hT2` ypc'cBޟ#7 T4 (wN`+)K}5}뢧Y.U\u}TBC"q6X*7:^h~q^G /.]@h< S0Tۖ(k|QH[/PN7,wtH50< ` @S Sy*@km7|l} }nRP; z]' w+0J: w/>bz!HRtwuKd6v\tsfC1hN2 y7u'p*7P42n@v6 Fכּw55H3p=޾.Ozi(+'^Td9mv(sck)O47`v%[tq37x @ty :Ё.5vkˀS@Nn/@;jITx}Ma~ [xzyٍ>ˍ^oPzR*1 P?2YVYo,~ytӍ"* +WT_+b i]9gk.T^p'o- Jߦ;ׁ)|_kE_w@;7kFyT&p;/ݨZn -eVVZ^ug#U+ 8p}<]?"B*̕@+{| 7+5lSl+-v PF6 +qj!}EE>Í-pW?V`Ëzˠgx_'FPks_WQfUknT76:+ѿ.&r6,9p t݌#mp#u}tw7zp:0}xpqkwoj׷z?y~g>Bu7}?"A2<~;}s^AMӀ=u7Ww]\<t5ʿüFhF~};KTÏ[,.qV[jpy>M yޟW˷ hxAޯn5 w#}xҼr'V;^o?}7㺗t5ZN\%5s89D_R꼶gS<6ϵs®|G ucvv ?τg_KPnu][K~3¸ZyDx粤n9ㆶe`>Y[Uʼrx޿g\pXsr]Q퟿2~yړǩvi5rȺ=,_12رTԆ*$_QLH_d9Q|+ c к Yk[.{O&q&zy2&vNH @,$~ DTהTA]IőX3V'mELU'SIvρEr.)_uc9slR5m,iGyc? s0ϻ<[n6Ó&(J8<*TפTPlOWy5n і>_Fe$ C޹Kw?ScymetO_~EX`Q0LEGK *뉸S QIৼz/w2Y{p0cl )~9ȕ|2[06-j wT %]壄. 0P?%AxTxU5YyHƤgsq0n@IFF%הPwwy6?];JCFHQ#QS2. wc#QI𧸦Fzޣuld-/ LWa1,z"3&0ˤǚW:ꝶ$R99Xqk@,vRjZQeCrgt{xkSnaBҌ&2οV@I`!RZOFO((Y^TOyMIΔzo?D ݝm>{G(~"d;fHy ?5%5;l}W&/b)D3+D`nD%73QHpKosF%7 ɐ5;m}!TTpp:&"ql&>h0vnWec۬GnaGY`a y FoB߫t@RzpI`TT 9OsT8"Fz/Ɲ)O994VJ/QDnf9-u%ϱAql][r%wNŤK3q>7cyȭ 6DߏuMɹ`t/o<6e)]sE<8 *[iA-)<)e)wٺ7AqH"+ǾkK.{>|8L98 mL4>hU86-Ϥ;I׼䶔v^gAfH|S_x'/ Jvc\0vAkF N<}O~s5uyoNCGW6{lRxreM\;F@D- OƮ:({I]Q=9 պ@}ͱk^[r%tx氽mQc85WMڀ |guEqlZ&Kwc¯ume)u?~\Y\]8MGQű½M9v+ cŋucumetOoG?{c_*;8-Lo3S|ɩFq3b݉RMcږ.vy/=~,sXF V9}kqXm] w9-i9<4&dij3UH' uEalZT] ֵ)]Zu9 A0` '{ntK9+ c׈u' =6)׶\vI^ mu&THF 0NI9Tyvsf(P8-I мXז\vIL4nT:'ѷ1V@獵5)~S#H9䰓t`8vOmi˵yco{5_Օ(djwxR a݉&űymetOh*cT5h*sI11#.)dȞ˦c4=rY*D,?Ĵq񕼙@n&6$cBz&0t8Wz"c$z܏H}4`Fayi4/t=)OGV`9[ZWT89.]ږ.v(Jĵ w8\X!g#NX':. X$ ?5)5;m}\mMrJR*!G+s5i,kSnaKEOt>(6Ep"7Ng('bf>3a5jwפTPI@1Py=6rYo`')n3F!Ɂ*u8cumetO_>J4qL9aFVDD&06Iڙ@@ɣPt@ַke/MT*Ogka[#U=0P[#I9iGВoȷf?Gzȣ2<*?df*;"Ai|9qT:׺LN0l}VOQ^UeTwUƊ 3ٺY@9vז\vIu_4mߞ )xuDk{2*gxC`[7QIw$@ַ_% "/H9Df@)u Z"iX%űkqhݎ,$m)u?~9_S1 K>#CM,t؋z"2$wK<iqw}Ķy 8&A|4oPkS({Qi+-/SQfoJn Sy`qB& SL5/;ɡҺ:=t S*a۽srbm1е QgmG~/]Q;8u/S<6)!C.Kasc` 5مFdk:\Hh=Uzh/QA৺&zo E$܃s?Xa`Rr!'uE'H|R9 -i(w9ٌ*l9@w):YOc1 ^F%靶ͰHA]LN yȐ:HIM]QW1@0nkUcrZ|Kvt_𞵎Ԟf? p I㘺06MN#:t<6)׶vY}n@fHrP~s`F2sGejO8bH]<%Y_rE_4/T]aP͹'3:LP^aQ&zA9^FgA]Yg,suEgslٴI3g[][U_ζtD9(]~I`R菡m=n+3f9MQ3}M0l >l}RbB&@u}JRzl0e]Q;LtÕT,{`mfʂ/H% }"oMz&ng .eS/:ʑ*z8@T-6N0K&r8lݺ-7줼&]SWĹe 3xmet?~p2/Kpl6.|fȐ#;׺F.(B5N_rE_f4A|7ʎpWA8܃Wfxbn˫<,xj4'J kSna˯rw*@Bxdi|gNG3HܳSӆEQA𧼦Fz/eErNr~V(_%,(8%gc_NkK.{6 k M.uHd8J1QL5%5;m}[_'amNwHӆE=)~xR2uEUElymetO_>wn kf V)x2 2~o)zZDeU `ϣg+MD'œe-$,)/!# bYW|<) u;Q4v<)v7i c V69X\u*IO[> kqkr6nJI-K!]Ɇ,;Z'kQ+reM]Q=AA~S41ǮkSnaۢ%ϋR/q}}&+IXv#q=` `Jo _|reqpgcb+毬؇P+*KʼnbѬUcxlQvC^\$6?~~pMMbYK٤GvҌ6pT))iۓ 2-+ӈ#_ ;OA*%R Ѝ:HTآ$'-o%zp 4t9,!^״ozRl'b)-1r95)5;m}[=v5W$sbbL*lb;*$u׵%]=~Crb4:B9Hj.H/g=OhZ FF}ҺFzo  gQ9g¼;)l9oZ-L^r$6ɱ7{ymetO߮48'Fzo US8в 4Hr;*YѺaȱI׼Ko}zE[ZKx oa^HqFn/D^QA𧼦Fz/|sG_kDֆ(Wr⫋PtM-? }/uKo'XiW4.'ܙCXRWT NDҽ8ilRk.vDW!ajapݓp*%`tEeirE zYkK.{򹪾hr?T :|ũ8z"fz_RYCַ1Ʌz(9 J "ʹ#ob\YnJآ|\vQYTޕn6 of) LVK)G[bgG]$s+ݺFzo ͨУ49(!2"! bqVrEI]QSDuŌe_BM-oUc[G;wb 6c79؈[:t7a+u )a[/^K,F_Do鱥nJľ/B+*32.śkK.{l0Q[s3 aLڵqr9Q7mrj]$%68it?~p.79x?M2EOI°%uM5咃V>5d1-o`=F wEÅ`N%L@1ӑ+@KzhUQ5%]* ַRXJ5Aje?p"Q|򊠍uM kÕBhlRetO߂SxI 6A&JK{n=?%TB![J?5%y;mHfEy`62 nӵ ւCW꒺Љ&ݛ] 4t-е%.>~}L \&r)Di!hңV$|MJe N[F2nIxn5gmrAyT$ *co]S;`EL5]kK.{v$rRAƣ-X&~eK*k=Tf&Sog}%d-iiMn"ْ6$% 2C1̂^z"%FFݨԨw"G隖靶]=z7g rG;5FY$ p8g]kK~9X?~FڪcD7"J*Fk#Q$.Hz1\הH\Pjs*;p&&m{9\Bk(8 ũYc[et?~A9H9q{T$]hʛ]bʎr;k ,Qm.uMlmNc*t+ornX>+)OL%ű: BtOcr>䗃6se.Tnr֞(ͱl6-i̖䰇徜1'Y銚X1.eK8Tymmu?~{ipIގ't2܅߅(OغVuU9&XF\vIsL5?V3Џ'J Ndݖ`Fz"olQ/ {W~ꝶ (Uu]? ,L!;CNY늚X1G]g@ז\vIh6@x5C`횪L_u=֓$#u#eؤCN{zpǦ-y A/uBt(|QZ˩uc_)]*j؋;gI*&x]FZ#3Wz"FhHH=jȱIi[EDUwۜQpդ`LW:7=fZن+-i7αoAg&If̤}CmnQk]QqD VWh }mm*3Nr_to k1x:ſ RuE,'62Kc& 8jV. iMq6޶"r6,H>Mܒ[Q;,ąہ7I׼K|5 x oƆɿK~2(BA(W.TIu)!¹qIHis<ל6YkUwIi'( XAPjεHSnpˁd* t(n"kRڌ[֧ s&sg {;jҪ-=b#]ʂ4$fN-iŁY}Qn57 V(CӦU K~o8uMIeN[FVwɡ"`Xc(_rD;M]Q LH$mr՝hg]2oDFЀL8:UWJQHL=0HYQاQ[}`]jާ 㣩eEfW1H#[sH>ٺzvHcY˯{6-W }aF#rbS6$(RKODz&KbNi si': >& kA+wݏ|G8vBl v4ؤk^rY*m'\1hQ Lڏw+*qȀzͭc GJkw6{b!Hr3V֕MlI)BK.d@Hԕ'q"QS7=&űymiuO߆Q *ŘHrv/7}Sv.)Y-1VoGהtwJ[_-΅pajo{rb?ʜ8`,mG56)w!]=~ t}h(i P#):UIyWЫŭ7OqYKis0c:`]8#NCL o/,ZR g[U@N.rڒ.v]-)VJe6"'X+D0h6LU6z ꝶ#'f+QX[}pnRŎtՈEcZtme|vD4qm&L5āPߊq4 %F%Shy4Ozk,=5t>Eql ]KSuE'/Na_ʱ ڒˮԁ)!1 ?NOdkPe\QreUGHi˞>{xxYKis߯k TƪhIy ,bk]S3?Lsإۉ _[rE=Ͳ׹ESiL"?b@M]Qٲ%9nM.v];z^d99 ; GK=ktЈl?Dׇt$2-`zlRctOVOu?JڀL/rw_`i]Iԧ61JG]SRYCַk'szSml夸h9@SWT69Qx5&_WKo02ʖs  B1QFHʁ_䰇t#slR5mizm֭WBB)D,%E?jUr$,jN!\t}ͱSMo.@1%` )W4&A{s.R-EH*34jm)%?m},]usr\z rop^It^LփΣ>tMIi[` tds y*Q+ k)>93|q6u;y)xK{˺pF³XtXaxMR%E:3mr:mpmy얡o_[r% ~.o ܝvm,W5).n'S7%X=9v!-i{x,N2^Qf)Es(N2tOyT)i{Dlrdʬ"W+Ŀ+%uM=y5Kk~՞:m+Y2=҆tr.FN[zDz֨٣ꝶX0 ~N59X;))FzA(u9ʱ[:}mɧQZo$EXqX6:= {+#1]XD &`4 kwvhK_^&fy 0]T*oLTI˙Fi]QI0Gv%]=~ʎ=݉ƌ'P#d]E-m)Hdf3CrC.G!ꝶM1~BKz~uIIIѫfI{cu>Gs*ˌb$ڒ.vGEߏ)zpUd>tG1IokTCɺSV}MIi[߮aJq*& 7$e9%MxaNzWM96)69v}k_29hBsA;U[s-(Q#d))a۶|`.Ido:$*w+FgN?A; ӜbM=5vڒ_|imO {ʚEHj,1#.2ݖު=@Y1YEXW kJJkwI Y0CwY? db&5+.cj]Pz$-oBbȩ؛LJ]OX}˜p#C`;l}+Z5Lo &09s+ VVh:Gbڔ.~돿J2&ұn6 c0{f=ecFOREFzoJQm^7Wbb7[JWqќγt4](Pek棼n>jae="a1rߖ<_+' /Nd,vW{95SGY*]Rۿ.=u;<Y,imNLvR,*fJ0Lpi_KᲳMbjp*ڳIiszT_ P笨f4+),|TV0ͩXG=0kK.{vhݟftdL~5]Ķ ;[#џ6t[=yVO=&rg5%5;l}Vg7X1s^IEН~!grz̹KuVcgֵ-]=hr2)) *-wu](,Tq+Rܓз[f wlQ3G:|nFnj@x%eN=L[WTyŹSjS&e}etOBûX9cm!|M3ݺ[h$m=A'rHz(5%u7eY|8ӉY Hc@X<5G>{ya>nYkK.aH4[ ;/k0.ºVb .~Q.?9!tMi"lY ň|n=QhMzz _RYC}>nN0@g#EYw$*vo{z^bc? |metO=Iƚ6y,Ύ Z9ϓQlZKue$⧾&˘zPKFD#nrĮ)]Q&&u#پؤזܖRiU`F^Qx#VDزKޕDu7c'Lzx=j~&z{=H oC&)a#<;t_ _h9=5="idm"ڒ.~򫤷"`0eic]lA71iCVG>nꝶ.$95PrULXcymmu?~(/Tm2$ՉBXx&dk鈨@hTT _6/U~^<ꝶ*ƺps0pmox(> I-YOr8[O8IהHNĉߙ=b.IM#ag39^QJ?5a N[.<ғAtz)GTE;)t!sƺZ.T`[p˳ҵ%]=~!5+9(b.Oؠ^RnZO(^@, JB/Naka{LXfV.9,Dl؞Ï*ZT6495.K=vyBtmeWu*cKoDs~>K&ga1RuCugM Dc#*uEYRh2@^5)׶\vIm 7̜asncW~ERx)M]Q9&fb.ͱskK.{`OĻNe"{7~ G~8uE>kea4 -]=~&AGkm#qAY{ޔTݺˏx jN56)Gv#]m{f䠾9YjE1 #)uEalZlSۉ. ז\vI#D~&_'_Ib)7A+c i݁=McږRvO|.I0F \DѸg)xR$l\G~z(ڒ.v^Wx7H9h[xd3E@|0olk88гcX!]:!LAXuqFkŵRLksmnֵ%]=~"kML['R#)?$)~SX QKkjdn9Z2&[B*ڒ.~r}eh|oZs!BY:ub2VH< 5[ꊚة;^I׺岔v?W:kQ3`L;\1땮'kNu͙9ymetO߮;&'fV7Sbo ̔SWJds&N ,;&_ڒ.~hp˵= 7gIpΤpځCSat'4|tme6Տo;21I0k;wRS#4M]Q#1ueז\vIOp.]He/_QwU}!gTz !u 籋 ڔ.~T l6U]=6D=~7֫JῒOKzߩw5Ѿ:oęi>G'xT U#6uE'J X䱟c-iK{Vᨯ+6$=,761-,EȽ{z"fG 5j#פTPW[O,p=FxZ+@E1^rA:]t/2ق#-is? Q7u_:"G"Z3GNӣV&zoF3&) mcDy!|Ժ =sGN<,=]rE_~ꩂ.b Ճ c"Dq Q4zWzꝶuۣZ4I8A"mCD9ܒ"]S#{1[#n kK.{r"]cs0Zva"=)*"7S@WTuG(ǜ eMͺU~F~ya9Y"ÅL!XW.s>_[ ז\vII$]]cF$~tŷz%i2I)'zR6}@SC}MJe N[.8ywsNE/IyuM]S &*䲋v|,X_(9Daq{$HY5O=Y!aGX::C$CPparSTא[ݦ<OɁ>uϱۊ%]=~qD T3;ҟ^A7}ZZcґD42 `$uM0l >l.\+gdtM'ᬤ+gBUrۑ{TږR~W!Tc^ `l%b҇n+*ؒ3{nNֵ%]g 'rpZT97 ;M(PH3b]QːAAS"kK.{jRJ~'ui?,Z3]D)>XODf!ģf抯Ii6maVF6"#7+  ʳ91+jŜA,vii~zzKݯ@Q'ygH D5'|/8~> `tIף&z}@1jD:Nz$8`BzΙ~2zo';^E0ʷ9;77&0Wvc d#Ѻz-J"l'8beNBRfZU:_5j;PqNY/QϯAwGpKA~.%MA(_RݯH6k*҆-Lܴ/b>jnFMiJ+hnd!X4\؊ߘq0* lsöϣfs*o}=}*o]HcFn+%O*Jt;05 ~ɱ)$JV?)xb޷—͔Vl: V80xԤNީX6_Ok >N<)q=PriLc)ql48p{閖cSzmvy*96ǛIZ‣q.X +.mEGL(7JQۛ|9s36_OIV?)G#%fX݌4-8$ń:QXI-ր!hFcSCܲ/awfr?F+w+Xȇ鵢!q.$Xܤ7QQ)O1sa fBFf`$K!>H+$0 pa^6M]Lv%Ee boMY(A8~r1[NB&qR8=j&q#4!n45跆D P;I_Ҡ,[4VROkR$~9vh]~ }z2#23 JBʼVe'6|%{p_ 76Ҩi7(R.kMC9rUoDJRONs4x1VRvN 2;Ǧt嗰߇_etl&ןM(zBbZ"e+)pg4+)+n]In+>_֙OJr\O`Ҡ(.Ss.>x]5Ct(# ӊŸ+| '8)@cQ/`7msG[͈lj@ :jܸ[)MJ}j&oɱR_kn嗰ߧ'+KŃgWhe(Xsh! 1$\"^33psMCZʳvQOwx2v bQaQԻ<+ c{ MG/dޛ} XI%9WMɇ̱闱ߧk%/J_h)p_8xG70؊q^h)-59i7j_qR^g LةlV 0TʴRM m_}EM.Vtkv38ڐ-j{GVZ攕ިw=JsHj"d/yD2JKɩ+)a-BkI]s.>Vi23$nRpIa)ql47~zEvy*#:.񾳻5Lh$֗1ovD+`g썝ǦĿܶ/awOG$LJL)7V$NQ}P;Dipx@aߚOؗ.GNPcϱK&8zn嗰ߧ{$%(fn bi .=LlQ(pG/.ciT - o|==tq5 \3!4%?/>Y~ꀕ^hY3bzDݓs.>|*kŲ*@uxbΠtn Pa5p\c pbWJ9e7~Iz֭Rx2mmGyI֥a$XF<ܲ/b>|*PA[TEoh<[J>LT+)eX'5ݺmRؚ[4=u>eo!^K Ab5ƚxm1`;JZßc-v.lM1ixe" (Y;ׄݖ Qk4Fӽ-,BN?.?Nc9ߌ+gv5Wc.]~ }~g2NR q*JXU}{"[E8 ɘiEcSB@Q.s*o}=*٥)- 2tXI%HewbodzlJkm;2vnP,n(ehQ$6z2`^6Cq&Y$?Vxc׃:啁2>2^;9$4 i [Pq7{RHyn?~wU&.>5ɪV;6RŴrԫRK֋T촦آǦĿܶ/cwOiȲ]T +j>&w0!( ۅFL劰IM,{8c>]~ }u'lōÁ  ۶gM$\ZRT&7s_UިuY7aMCd3!X.\JpQ}vJ-D5QslJ:^~}zC=Ev\8Z{ >jv2oV-rԒ 攕zp#`ppd.Y@iZJ9'PXI]6ǥzs.>-}ҝ*V;݉# SV6BXjQTs*o}=Oi<>`$]H?y0VR{aip؂v]gXs.>D yk?BmRP‰UnE6Hp)lpԖSVz#iB|6Mt3N]O> )y6;/3ıEX {lJk-=%M,OYxrZx嬣InV7E l{&5jכ 3UXK#sAzb327sn67ZA~6ErCYHv:&jU8 p7(\5Vz#k2?xWhj*@#bhIy3٫XI֚7[plJkm;2v'@hR\#Pyʼkk.W'+eIV,ү7pԙ4'(욋 ށC4xR=Ae~J%'Zy篱s眘7ļ?7ڃyE-R #l+pI] Pt:c:Uz8egנ2BACyQiat U/vEߧ$]ϦhmTPɕVzPHX XQ)xS*Ypg_%dv5 ^Lvsd8JzA:d͓]~ }GVkufqjwHqS&av4[x=+@Hߤyp+P,81NP1bud{I!n|.oFhwDi"<$cS`ect̞[v߇_ea'~y/Gh]:Z'D+%SEvvX0VqjFa1a=)ιe_~}U㲨V %FIq7Px]—->,,7~Y!ӣwv_ϾK,=H\p|OqN?f(;1+'wGBXUfirKsScsp1s!bӒΏLf ~X%+ W ]80x$@v_ϾJ)q!s+S?‘hOBr$dW9fَ,Wz8DK %H<y !K /$ܙ 'B蝸EARs*o}=(ť$*`cvGlv+i4|8Ƣ 4*ќ _YPW$m\ YO uV'!Iq#Bu89i7AZ+SRÛ8ɪR~kZb%ijXg,/s#͹Kdq662~^&†WZrY8 *nHkpS<4'v_Ow:A >١2i:Gnt^q'XJO(h4f,3<6%5] }U#V{O+n6+m< rC xq[S8 oKXh]-Dwd:9i7HtER>HYڤ׮~ZʎMSbAcgӦ[vE߇k%&(pQ~8_?]){YyNB"Yr\<8j"yNZJ7_OJZ֐)Ɂ)0%fG!Cb%YĒ0c'c}-vA򤸗 N. O2QI:2G8 9)2VRrNYpwuf2Hqj<W<l 0@ $יlQ{fjNYpw ێH3W5H~Gaߍ\E]!mO6 ۅ3_ ;isn嗰ߧ6!YQY0"_x,cV~LSq? 0wcӨv_OoFcipߍAiJJFk mzlJkmv4 lTcF)"q)%̨njWuFC۟x'S $J>5}=g҉(~xkG$J~7ΉT=vs.>}2᯾ aS¾? K=% Z`UY.&`E@6YQyI"Ecn q0 攕zNv¸'/^(;6i3,q=> +i9"ʾOk[v%#6ōK:1&WpwK+r,pw{T0?@8fh7@s*o}=-B|S=5x㫊4t+ a-e4=5+`[;s.t(|"vWPFO mi]bGjH&IݣR6UJ|=%/eU򩴦"OBZzJ>ݺW*TJXt{Mu/cwOk {~;[|w/)?{hT_Rc6F}su5&/}=]+ /AZ2Byor]U95hÝXα[<ܲ/awO_Ckv$JSI\S $dfGȚͭ NݞcSxv%ߧ|A5t J[4O4LRsr)}86ZIBܶSaw {8,tx㥫<eYcp%. F9e7mtdC5(D=E4JJNh6:i(B#*BMŸVJօSݸNpi+1nt;r>֐jDHQA U_;J+iM5Nj>/_~4ߛXk\܁8ޫXVPG!Э@8{dA6_ω2d㥍ز,Vʖ`5ܒ~[vE筥v˕ET\iaT[be/+x.G> xNYpLi6 FRzv] Jj+\Y=vq ]~ }^$EbMqN:r8GJjJCv{R\ء*> RA H1 :dlOa؅Ӝı 1z]z }SE8홊G$ً[ƾݔH7fJjހIQH\gkrVzC9^|Г`/n-CMH{sˢ((H, 86ZЖ +|Y^@M~婰ߧ5 ajJ` 7»J{ywm՜v_OIgנi\8]JF/z%_ԠAM.Q.-l!.>ܲ/awOO$h _SӋi'J|XSOpKc 3$RcSnvy*/ecF+qZX"0,tvOJ^[ћ\vYHO rN@cS*.l#)VxݨIZu{xt}3QXӑbbg$uFќ6_#7mrb}(H}kJz{Xö "6~{xn嗰ߧ1AtBMAPDLCo[WQT`Qb)GJ-i+nҾ=zknjpeOQ:*m;冄_l &5bGsN9Ks:z%Wm24THq7)~d n( Fy5޴rN[q KfVi;: |wJ'IO\ZKcaYa jlJkm<v?'BVܸ\}_<ç º =)T<Cm3GYɭ9ymR:FZJnRzUT{RbUODƌ%7a-Yrs.DigSd{9=&j |~p6P56z|o4δV%CQϞ=CI ~Z|e|Ěaa%J=߷L96%f_~s>t_rkLis | %8$VRKC:c+;k6(ܴ/b@+j]81Ɔ)ByZ]y iUvV4|K R :2-]~ }JP OX z!l!.@[G8nz*hnpYp|Ƹs⨮Oog! D! %%ogηYUﳌ{ؒט;+ߧ dCicd>H'mu)_M@s_:6jԞM5Fs̛lA9D tKYɅA{6{7U^ coE696%~[vEfwPR>nr0.^,Jѱs՜~|=%X2uWf4X3y&ءض!rSX4̱g~[Z?~r=?b_ཛྷe=Y&`BE|p攕z|KsYj:rdG' 鰽[–3Y9˱Cd9KjT5ξˏX쓒3IW4`b-A{~cc$aܲ/bm{bcQ&x47JYe 7D=q?rԞ)+n ,w:U]tbxv'Vij&uf}qs.>*glW\ )P TS{ԇ,WK~VXGf$nKdӜ6_Oƴc~v zC=Ne<u0'N}BRXIO밨)coalöcC_kn嗰ߧOgɫ%)Rʦ,߷fDY+?(ؗZQ(yDw_QVE&-J9e7CNfi)65 +ͫTCsFZηhG‚M m_}eY+wjCDa(Y0Jq Q)8 ^+ns}93=2+y hŒ #5)g6?Ke_~F=(<@bv%P7%oR&^Q׃VQS@d,s)bql W6| ~O=ޑd<9ZBQ甕z㖲fkj*cg܀X^f96}rcxl55Nl;G0;j+6~ۢ=K Wpr_nn {'W 3wRp)Q{ehNYpM ϮY!Ggۂɸ3%Ë3lZJ lE g8s.W t \}6yvZ`5 q } B}T9e7mfwrōgd :|RrHnvu"̻ɞb;S5vϋzM"x&ͤ- ʤ RRvI3aKa {rh*MDFUI`EGaU #zZAg7Q)O1F;<T~ɓoAJ{RWs5w*Gkf{n?~M RCX>V>lj?ŭovtI,%Ϳ2LlRF7<vtm39@FS]СeRWzb-M,QSXrxM]3q}q5S5JָYúNU̕XyR)5ho+jMcsn嗰$yjP Pc 4eɟ|KM|1 RR剅2N[v%yBm@j{+:XLH x+i~hXKo5@")6o5KtolN*b p9`0]ӾT@,6NҐ, `Go zLf6Ȅ`Н)Iwx,y}47UϺr?Ev4, fjD؎3s.U^ϿJdwjfAHۓќ12;5\Ejw9Ŵ}^qVGk{_6s)qUR^{G%;B~c՝lsMKb>$e`dmO@A{&VRq^5 ;nF.8ȲO-X_ ]m}-hۻ϶B-I^_fGJ԰(XyB-v{?6ڴ/&G>`3TkӚM t=6%͹m_~23 *Ͷ 2 +A,hPwn 1c%]o{iJ,JBsa[v%i5C c9W75y7{r"NGXI˿pa,(r3]-v4qoғۚʽN"=PKº%U/n aHc&cgBz-{3my9?\. :^Q=aȥ0Jf9AvucS4/awOqe?Dw!;BG{}B tof =z0x~5"n{ۑXI-͍}^'ʓ=L=~k=R{mS c̱)9Kt|J1+bрȻLk K~s,,%ͿFb#ZrlJkm<v4iPj0Xc#5Sj|mv'VR}K \c~f _9+VH"Z5p!d;q+ c0!c1ܲ/awO-拗V͇{R6xR'촃!5ZYCv,c d5vq9i-v4>g9,5ϸDDlkJ JjYbk ./X~cY[v%zwV5 +g؊ vohlJ^嗰ߧη_Gk" P|v&lyەohj\TGfM7ǦwKOxr;HR; t'%o Ki fj.;nAcϼܶSawOM3^[ϛ;㵃;zXC`c 9Kp'k06oj)B-+#a0ާۚ ӭm_~#ﳮbicߛWJF'ANa"c٦c7>+~ >7-͗f%tIMEff'pnI\18@@b%s4ظ^96%5綝~}zSSsy0ѪT_IN.JlgoS$ύff_~oO'5E 8޸Y)mnfL԰Ǡg_{n)?~ob0BW; 6?I\#/][;@/)=̹e_}债{}fa)O3ϊHg_Q>vP%VPԚAa9FJk-fz>Mn]_룞WkbSٟqЙq}]*Tܻ ~;rn嗰ߧy07ߌ+ZWE0i)g!2kq|יdZZYf ~ʉ&snGv'6qxP݊%|2N{Ʀ4re gckQ5v˶H _; wuanVl#;Sb fWvSC:c' xΜ[v%yS~5:ACB10U=RS4yl0#1޻؂Ƞ.Ii_}oM<f!\iw%9[6bF?XA`, rιe_~߿^޿^4q6X՞2^;fԲFj؆ec -=%p0q?$ϸD@ptb]׿55%̋9HjC-vu0:kpcwcyߝzWQO#ƝJ-Ќx:ٜ]`}B.Z2KZ^v–xsg-vt߄j%5 y?n 9 Lc7_+c{T,~I3ؔ6<%{u0ҕ5U$!;o9Ks; b3ǤWs^|bvqw<-SC7a{\Rs?2}6o .^ũ,~AZ]ct)ȋ&4*)[ o|=gxx btH$)N kLR30ؙkJ\R98J~HV@]wH]Si>Vu˴av Kc󯥹M;c< <6%5] KHy{I/WyIv\+)a ]QFJ>).>b*|*s65뻐E2646;ׄt ¶z)MYL/b>mek@P, m|!Hrxt558$39vФ_}riwnx&eIy%ıMA0c8α)鮛] }Ubn->tQyTR ? ID[J*ɧ%M!ՔR7VO}S*8^JE%=b=60 '9XlEE(TN)Z)v_Ohy hFɕb3?>uggZk33zn嗰ߧBD25@A`wQkF(ikWY~e:RiTp%lǽI~e_}JWjM /o"TSg1}1 }; ֚_ob )4v.a9KXKbi (kaDY~E_LrRKJYzn?~.,fgϮabuܓTr% )}ĬafcY뱳X-5Ū5[)tVPrQQ_#}ŵ*2ҕq"kJ.'Ǧ3m[i_}r޺Xfbu8S|m7a>T9[2#% f_~~3rtͶVtw:x&W܎"6 g!n[&|aQ۶u-pHhײZRpUR`G)y켻DMC.##!Vu3%gu''*/N}0x;r, QXJuZz0xk, zn嗰ߧ+yyVɚ ECd6vw~SZJt62ߟn4wA[|ҙ\25̼Cl`%0Xz7s.>=":y x[191"3pcKI\ڊQN19 9e7mĊpWwWO ;a fYԔ5,NEa-$bT^aܲ/a>95-5 E3]#Nqc%|J+OzrlJkm{)߻`ת/aυ.~Rr(nv XII\X$!Wc7ܲ/awORo&/ꦆmw:o}ه^Lsi[3I%,[xvEwiY:n&B㒒xھpjO5谐{X{Z-v:2Qi֠]a|셍M-e@b%;4<+p[H{n嗰ߧ[%K_k*RG6o~zJRc-۬v5td]~ 钊W2ZUTXJ:]cڊd($d_zX QWfoJy^$$1ѐ/ɧQ^;p+i i2ZE]`Mjx> 2kfuji/M7ɊXͪt[V{;jM"yΪ뜛vEߧ[ǟ+AA73 H;z'VRFk/l,=vF-a%nxa+N A>+zqs酢%I]#R4]a}`yPcdܲ/awOӓ*7UZ(@.N 1>T$8$lَJHKĂ"~H{n嗰u4mb׎+z8DvKc!46%Ǡf~~` z$|v څܠޢ[~ =WҎ,449s.>=Gi `.\)lvĜ+壔f>&vWcS_sn闱~{y1T'+kSؾS[pG8uBӣRo=6_O)(/dq5.[xܸn& tl!XKBb/x+^<O_ װV35bZ\kǫBb`JxjpXv![v%925j])9lv6/7VRyc&A=vei+2n]Of9[Y-j|֐ZX5Y9K;r<Q[(EYkdb%e4}٠L|Ķ'vwa-5n1[,5nܛ,͎C2K"=w]~ }zEGHl  hs@WP^,oM8 #r@q$ ) W+Zm ZdEK7kZ$¡rk]Y牥T-5(S3c,qܶSawOsA;R!jP_;T2[xWFtؔל[v%ߧƤ,kA˂#tɺ$A8 +;$KpNhԑ5FSNXdXC%~Ԡ=5͹ >s#Jjٝܚ Vfc :zb䜛vEߧ#OaS%kШ o+w%%n^&Nl_b%hM+3qa1=4-fUN ;}~gװ)9(wmzitƲcW/[9K/u~Ι:V\ 7{7~7ɷ!cg_kYZ8_=q^#FzMБOp9 \/kb!$ͿEw~wcSڽ)?~_-,N0AXGϑAρp֣[Vq 'm(,u9e7ӪGOXO j#7_gK ?:J@[Vlo=v]~ }z[+(s?f2x{J $en/>JJt_x69Kp=UTcr=?k(6xWQi:WBa4vUs.{eNɟMq _ב˂7/QL!kG6p.[7֨3Śs:Xpht"-?[khC($}Ipf 튅 Q5lAr_g)9K *u'ki@WKr\E:w/WJkךXIلi< [h ܲ/aw :8^ŪIzie3.l_hڑXI}E mv5K%xƜvEߧ1Hz:p85rHRgZ/743NcLDܲOE{֓H(`иtA̴6'a$;}Vk,09i7L>5h8+ÇG`%mGMi6V2,d {o8;{FM}P9eI/a>=Nv՝/y4}vAZJ|Pc{Rzb-͗<]Gс%3B^;ܲ/awOWݧi!s=%7I_TޚBvaI)9Yf?~ޔ"nW쥦!:6 8c21^;FJ,6"v>l&ı)9]6KpjO'E\Jޗ[+&byrmv{U!5L>LqsofglXI.5u‚!vw9K& <픤櫑E+>.)ȺpFJ>@Q<_(NMCDfnCEJ>]E Xc%U'[Mpؔ(/awOwl^M"AI>hКc_DZc Z%9|>[v%yax,[ |v B4QxTrz)Gxԓ46$47Cej[@G * ;U#5Ajs0FRZ8͗9Ņ1\`uQ{@AڐXI%CCҔ'e-ogbyn闱ߧez.kfIKWAć0@IDaVYÄ,ccg[˴tU01ܕVojxޱ[F(LPX2nN4FUZ;V.~%5b=Ro42V#bfbo9ylJ*SawO7HZכ-cŭ #|0mqWʲL(A=޼lM~>?4&_Ә3էArOW'1UXw97C' 48.Ѐym1]~ }Η0Td|*ɕٞ vAo^-pi|P'Lk/JNBYnu22sԞa&)+n|3eydj<ptqOJ\/eG;JJ $H5ɱ5]~ }c({/oA)1TZJ{|Gȟcj%#SpV$܏˧718ܓbNB!9@"Z7a:L^ޞ{ QX&xܶSb>"'&Vbdj[6K[Zwkh(D ^j9e7m>xĢ2aϖ;2{JD!uVˢm YU,9K=ާseX[W1(`R딞XKI2@qĶ'~\>Oe5K  :[J 5_ϩ!#-YLe]~IaH\zVD&w_ɭK8 /}n+ը%fjNYpOî Ϧ/1dJkPWZZI~c.shlJݛ]ӯxY kxSV$GadR):Gmy19i7~Ϥf8b3qZ@^J>Nic)qlǠAc%Ǧ#ٵ婰g_eP?|aюϝhD'؎I"b"B^*&C7bT  \y1CjXJ2o&d"_|9Ȯ{'k@RX05<yˉwZXx'e'+۶O ͋n~YW6眶=6_Ͼ($Zn( :⢉*w,HJm5Y}Ǟjʹe>tm .zd(|;rO+bQxہKŨeg#Fï2uu%Q|c,fWOjaHɱA9]~ }URc"X p2!imMqfލI18QGpԞ}C4'ӧr#B]H4jtƈtsg?T=5Ed3ǦĿܶ˯vίߧk%6]AX,p_U *[2•rR,컅isJo|=ZdȂ5 5zn䫿/V kE!4t 1Lh\ܶ/cwOy+c,lgyŶk8f2:7m jnB+)qmc9e7X? >,}Iqj]fc|%+f5xSߧsn 27sV_07욗jwl}b/0sB;PHr/,O9FÈh4UbXƫ;Nz=%~7[O86Z+<4vIcϗIs۞s`wOJIv&dnXGɂb4=[pS;:PsJo|=]+Yt- 2:z3ĭIa) }qTrO*``G Mp쪝$ӵ52,tQc]`{e5BXxX$9Gm֜6_O n~3]E+j{0l')M]R@beʱsKsC~ īcZbE?jX)0-Ucuh\EɝGƎsJo|=}޼Y}n `JLw]0PmK!Hٚͪx!{ Mߧ_eGc{\$6Ç'˂W/_%H~0 u:+sJo|=M1JҞwzy̝I4]])k'#!Ǧk?~`qOSp賸6LFj o3%|ԏigZc%I` }m\-)Y=Kӧ |6.AlQ1+(l QZrԙ˓攕zxMq}v STgW)ovf+iKDjHelcnfɹe_~ӑX)JI c|Y9VA3NBsu9m7m]tW[ vJN6#5vc$ܶ/awOJ4k3CX:G[+ G,aMq0ŠKH@Q-sJo|=LTsaUdI]/.;>CjF`j,i1≠]~ }RQ\3C61rؗm(0qf9R`03ۛ\p4F Hrܨ av~AmI{ma%dE;ܲOGL>gR ~ d$tܿPV_+P81uGi+n<+V2 P_ zN)9Z7;]AsĂ2NɜvEߧ۞+]Qx'`cZpd' qԑLBVyb]! > P83isZ>H8(ր\$&%p=Kӧ±;ېXq95x-nPpW(**Pd35췣9eign' JNz6n/ͻL[I=v37/awϕ =<͓$ ol//r x^/*YL'T‘EP$SK}zVGQDUZc|10+v&L+ٚ$.nkKcSrꯝ~}]dR EO 1g׊$K1Cd GVz#ȳ|u5>M?U=^- Da-]yg @adؔ2C/b>6}"ZZqMZۅ{ÿWqeQk^hkNYp۞ ʧ9U p<)@vnO5^-Oܲ/awO+oC(!_ %}7-3{yӒ}~[4GtaY˸J?:Ps*}= pS Ӵyjẗ̸,пjYXI%bs2 2I_i-ay5}sezī\K q7WF9["[Pa+Q<±EF-IƜ6_Os{)5ɬy^(ymL(EnOّVXIwP %$s.>}* Aq+~~/-85~4BF;|#GGe9ent\0͸؍jQfe ke?8b-e{ԠKbAcg{[vEߧʡTPk:MwaҖ%~9w HXIw.ր؅zR~k_~ E`EGS-_8ܬU!PM`E/6u&Uzy,>cQ(~HfѨ| :Jo}=nC>gנ##2ncQU^Ϋec% OMAXd-<74~gȮVfhnsM%n1l1Ac(4+B1I\g?-ڳL^s*o}=0_|\y3b͍~eKSrmv\$VҕBa!`̱g d_d (/^y5ù&A0XFI~s͎Jꙉo /VK;snb_jڴ}H0,[$pF3qv)9MmG?c-l/fMg3ea:sy<7feEFU.ըtNɹeqHFnĎ򝒟嗰]o=:ޮ7Р*:DS7OJx=6r4xʱO97krCJjrs.MKHgd/I;sk @"cS_sn嗰ߧ] Cєyg5v+)éaU3Xyn嗰ߧk[ϮQ< W8 ;|¨}ƻZIk/awOJ6q45QcB'*H,PHPdYı b5_)H,56%5] }s {$b< ^!{Rrh.ei%l&k&k`[v%9ޅwDK3 ))$Kr軐XJyР؎Ǧ6] }qk@ 7B UN켟]}^XI 0I3W|*9vcLd/awSp0 a ԅ> 5aj,rD[v%Lm{M[65D1 :ϱ=]~ZOi[znّ+?B h!BO%>އKbP߲3m#V] 9. -@t^VޮUְ󔰍]4v{Vin)_~YQAAiR;E};oKı0r(54m<v{w}EOOb$WPXIqp/ةdܲ/aWw2kh;=X=["ʍWĵ_{c@5[ cRڋ~ w{? o y QD k{9HX!;.bCF"yܲ/aWw>yä讀D5Bteau`X쌓+~AbiMN/b]Ѣ}~{X; sP/'.b6VR9ijye%36_%޽Kv{xn op/&rtsvDF)9 ',# @zn嗰߻g_hTXѰUC0@`Iٷ^Wi`1!1cSJ>綝~N>l''#KOF /?H)~XI Ss ؃k_~{Fu\H-h1UO=w}G+nM :xs.n߻Ԋ>Fä,"$]]a;Vҝ5y[[FfMqM>&)ʏ:ƲOie_®~+2`.Π6Gblg>c% Y=yi[vU_0t4`w;^$|,J۩`%.<6==vKs.]?<ȍ{|;{.3~!mTEua+߬"s.T8pgt:7d,g#AbDY26%[vE߻+2R_jH;O¬!=kK@V;CJzLa$o]~ ]{ySl>?yS& ohY's.]s=Z`tVRdtJXII":M;#.]޿p{s Ki{ޭ27b0XIo95,[c\snTnx;rg(UoƋ)$]ԲO{V}$'-|C55e4xno gjrDmc-0va4y;5[v%*+u/ɽovrf!C4+gkNv *={ܲ\⃙wE%1z"\-q vXI XiX^WS2K0h4ܙ<y.sO+FMaXyR-"xӅ<9bְ yw ,Rc{Jc-4b|a#cܴ/b q1'Y5 7ŎvVJJhi,(eYܲ/aWwׇ1fjh|6ıB?4VR˛՚ yb̭6߻=gϪaVpcxHg>>~}/'M큱Ts.{3>|_eW.c4Ldo'1~x\PQ_XKeprGr=/wÌ:ZqN?=g[b c%|c2KuxպU`e黽?^_UOub-pvX4cY{b~ k<#t[tޑ,8}:rf~v Mepj>y쐃gn嗰1rk}uF]`%}|aCc٫c|%7k4 0>蜹i_~-0GwhXe zX^rKv*aDXIi 6Vk[v%z1;š`UŪVI~uGX^X_%D4U#g$֞r:WTahQNVf3Wˡ.o#7x)o0ӬHk-v{w}E@lZnQYs}3߄ֳD3-JjESA7a,3v3K￀Z[uQu1Km/w.bAXIՑh =-Ncܶϖ߻qg:k&0pF):vFtр;Xyr/q 婰L0Kgը݃CWv$_gvXSXp,tϯG4 {?> Sl"9>,YRY1us/'o_] OuN57*w>3F$1q_;QX`_> M"Sn z)7|®H~ XI=90m؂`.)ܲ/aW9g`qgΛɠr0I<ܾ;3+H k:P²@c7Fs7^[; 꺙]rn\ɍ7RZnebuDb$f`VROtʚ cفcD`LqMJ^Rx Vґt(]JK*]~ t-eriG[I""x1p(J~Hr[x{=e_®~Y3C0WA2J c?|f7thMA` 8e_®~6qrYh:.:YWYG$^޸=ArZE7Rc3fn嗰߻^p4 ښ}g }̏Dq=ibo|}kenbTǖxve߻ks!ajxZHΜ`)ql?'@3XylJ]TnUs ?⨬ K _;úJEsflGc)yn嗰߻KKNqVW| 4Zǖl:հ߱bT)YKP9QS9e于o_wO3XWv֐JB殕,+vZÜ'c;Y-{1޳V:grЮHp(挦_XKGi$g]ue_~/6gbٗfhu*d 8#q_ș xg үeq] _!;S.`N;ߧ%OZb#|PlCnogf-"/ǃmV whtUwbG\4XI"EtNgۮ-vKlLpƢ5Ս{n~/sC\oȵd,Vt# J2H5)qlm;2v{7 %U\h_?>kT~V"=;ꋌtcMmlcnɮܴۯks7xجʽKK?^(4VEqUZ|+9KOpH/cs}]~ VppާO V>:/S5@ S(G1ơ.ϣlsJo[| .V͙d.K ߜJb`Iss556!duts.]= U>%A(k@' z \xZ97DBI-Ony9;2v{Ջ{?.aBIU R6)ʗ)+*0rrܲ/b#d#VI|*L]')Sı$Gj2͹m®~tDR $e:ȉ%HŎwj*ѭ)X#%GƦĿܶ/aWwW̅u:ְ֦ ƉXSNƐ:4ۙfN0 :xn嗰Թ)?Sz1-/%>2Za̟vUi|-"S* lNY?N1 (pJn+҅0ó?U8 xTxNZ q_esVTuɕ4yw󷺘%~ܼ=ba/7u~QKliaOfKklJkmv{WJ 0 jeihP{$cn;?eZ`%/{W3 )wvTƲӞ{{$JIɅ`XIie͌VQ2rP6rn闱%'-,"#qw#7a-5?5v.wƦK{]KK˴rѠ a;ZEͱq-fL(Y oڔ]~ "Ogհ3ZGSoH^b?p7V4$"66c4{;/wJh>:[㹝i$[͓h #[`k0؆*m ۰嗰߻6#;B?.y*ࢴTA>Nw) R;^+KvX|? -ԩlew$RkWNy~:F(WIvydlJ>] Iu0]i#sɞ}Hܙ>,XKK"5agbK8QsN]gإٚ>?(̼iF#3BJj1il_#YKljȞSA5O$Gb'#u.>dn嗰yA87e)ryB=|Ju+ik RgLlؔ|/aW۹myؕa}awBNs!\ uZZjc9@lgƦ/b^&3ϕWknp>/LӝtUߩ# ӿh^:xx=kn_~o~j$7ϗ}\)AQ>I_+ݜY_Z0G kNYpwl%F?#⡚x&ZRYm=55 WƦĿܶ/aWwfH_BpkH=5$HNIbB^BpkH-l'/!涽n/8ǚVJn\qIJx[-K)NMGؔלvy*zz5kH//Lcw[3w7Y?^zJŅ^~ h,T^);͕8 JŅq'4*. ܗLӛe-^րJjnHIvX4ͯ-v{Tӌ5xfRQrP@) ) w}GÎƲ#džĿ!c{3be) mmrݎ˻Cs!?(,)aܲ/aWIk1퀭@(`Eg#L_>[cNB8j=*UUv'6* nG:vý">]XXIcѠ؊NM~Tc/aWwO3\rf4dlkL[A<%Ϊ6cĝ`K%xjlJk-|-؃?6ndV)hd^ձa}Bc*s,?żG7ςl0J6wՂV3:O}y+>XI- l&]Be_®~o>0g`H:{wJx3رV훇h3k~v%s:kdFblF>Js0 ؛ 46%?/b^?{չm ޿]atp% 5v^<+i`4(ϰܲ/aWU] ;0h ?0EzZJEg0Ro#c%% {Gn;\ ]}^+tiрO{>`O`FJ:14Z1[v%{apҢV\U8{҆4lХEaU^Ci_~{G-;2^Y@ռeN7+c㝱elJMܶSb}늳m5$㳽ݝo֊|]S†ʄJ֐X2{쒶[v%z33y N'g62+f[EFь ;3Ku|]_a5LQ+e [ISr^ Pp$v>ؒ˺v{w}YoF6sZ,:D`zsż5?`%MGccS_sn嗰߻+i&f֨ArE ÇgVHv5c53𩱻l3KUTՊSP>3h`jE` *e_®~> =J )7;msOr{;!keZ-{3KlmgQ tUcd4൵Pc.)V|8eqxNY qG1^`k;4j`WJ[`fVl [{D~/w+9F~D{.Dsd?MJ|=%LZJ/h ^[vE(o o>&WsH~Dg>x+iњ n)yܲ/aWwWgՀk'"3a:[."c%;. ;ә[v%~iynY5H, =H,tb!@nGvFyQϫ M!嗰뭴#tό*~鸏v[j#Mnˮ["y_"Z0P-HN]=> (ghPr ^ 2#Ң;{G0XI`һ骑i_I߻MN~֜܅e|94 HYXK#itzU\w찊e>{w}% mlj۹>M>#9)XIooe`cߑI嗰ke*aj%g{$c֜wTrlΫxn_~Iqζ:zW+;'8)$),OyVR njh)v{}2“"y`JyOFn>XIw*߬88<y^pV ?y|HBs1S#9_6ZdAXߔd2' >-l܅o~W$b+80Vч嗰?GOw*+AXPxd仢Ds< p;o Z@>aд!Vww+h.7B-ܥK{x ht"؇OvE$lY5n'~3RzѠQ<6%ǒ.{?4kswGkRg=LKvt'̚ˇ1@X]KEPjEbٓxL5uy:q<"Ԫ*eoV) K!jbgaؔ|jmk®~>`߄3yHByVDz7K+z,+cxm~ؔ~<%ws%ϾvK*ɌmxylJ~\ݞ yIik"]yMX#=v ]~ ވЕjhW“k"kp K"}8//"$eƙ!T[oK~QWHMw d`M)yk®~?jp4!:8=#^L}R~G,~;?M"‹ [ݛ&iz]l4os$9 T>|;e\D$Dؔ/6"g6'R:s{8J+qoٯWjٸ^,fc(s.]ޯ,om_4呇s̰<.D]WfJye[S :cK-v%ܖb k:[ş'+'zBc%TcD clʾܶSaW7M' t)i#yT^{mi+v3cM؆5R:e_~dmuU4'{/OF7ShgD؆nܲ/aWp#In bY$]|b+XI;a23yM{glJ^)_~ &$ fXv^Ӄm_;@+p4>Cb9hn~>2K}"ϓ}4>d+Mg$Y~y־ 5[O`{IswŮ~2Ap{[xK}ilfʰ+% = a^`m{q߳}Ҭ^Mmj8V'Wubmve>{j$#צD%kJz/Q+L.ZK/aWw pdE Cu͠g?<{$[qdY"/H4洕R+)PʴDb4/U%5f[RkinO3ܶSaWwѓ9(\ dS&l}6q4ҍt" 4~7wۥ `65`gkvr%tmd?xtVRVAeguݙ[v%>⹨`Y5BJeHi䡼i49;J{,}2V,h췭gIgnً{ Ϫ;^5 +ց ~%-v+29r4ȒY{s.]q̝.Ga_ Q7UktU\ؔלvu'nb{͍l9۞ߏ3x)H{ߍŊӟUT -Ա XKK8i-XTf췾sn{hjIްϾs4` }X2vf=\]XdtܭU=@ׯ8C=9 k2 n]Ce_®~~MyA]|T77(GhNEVR.d) [)9/w׃D5֠VE]H^b]E [GؒcJ߻K*w:'[1 }m9eEq3يWb9jsJo[| 8Y$2r.58JY;,Ġs; +D 6v`7Gve#y0.f1 I79.H4#Dc/S+|`i3E/Ό}"3s.]}_H-%+N;ӛL%_O@5 gyǮɈܲ/aWw ܨƚ k uH ޮ6!5ܨFZEc*=vKE}`< Tܤ{edW?L]>@XIJ3H*a*X}T[v%nTRͭ} ?U GH&t!`υ0͡CI}9Km_Ʈ~6B%E"Jo6Vp;0A-{:ɍ7w۩oV4p?Nnx5K όF> ԉYѠn5Xvm[v`W¶mT#f3hD֘mT֙K-Mca+hAknWs~Z[`O3\e܋= H=4 %|Z`nlc*ynUo~~'oGZ9|g?agy𽜑#i{eKa%qln~%vV'hlJ] Otno 8wjxk.[oi&7vb26%5]~ _gs{[Qp݊-0A[\ QT\n];4 ~*ʽ_'[ѣGԚ [m.dHWaڱ V5ބ%ܲ˯Lri,WiT#f3n&#X~seHQhRCv6c.s.]o|3BHSA(I-Z2ıy異33glJKd#vy*V)7F|Qۙu!hT1`ȯ.U-{]Y{7@F圢J ݈Ӡ~)x/v̌th4F߄~3[v%~cvl<.ʞH|_n;ˍTdHϯ,R~:TpGt6oɗ)kY=XK\ B_s.]\R >kVwr*nx (^?Kb/?Vt:N$\NtӼ-pT9nz#>ό_HY5#$رVF419ޚ[v%#yy5d%a#Qwޮ^^7wr}Ʀ.]=&y8HF=JgL$݋XK5J؊~] ๩~{a&VME:jWF}ɯ[XI%t2Y])sFc{?3٥= ĩ ;Sp3}wv_$R5m4̉L1[vE߻+oIjjșv)+\Hr.v쾃TLBEMyb/yv{70x|(YX :[`,[k1ouCsJ[| ۺ,'끆4=RsZδ7(Ia(cSʒWqc%U K9AJ\pIb \XEryR>c z[On9԰.] 򳆝Cfp7ҟ^X7V_7ߨ̣3ؔTݞW(9Y5*蚑Tpg6"(|o\+6Rݶ>Bs.]=\]oY5QBw\^zl7k%Nd PylHNz_~ˁ_k&}Ǧ? e ~Tk)<֐+Xїhgs~O WW*SSShH,t3Gwf˰bPn[[JV4"NI44/wOihLsw I$E8 n!ifQ)9m7ĭ~cQcyY0o0FM"عɎ`%Qc |%>Bi_~{ځ_kL7&y)-VwVX V#>ŢyPezb/yo))ytS$dϝ;>y3&<aӾ~~}_ ӿ?'n՟*xfv.Gw᏿Gz?f"W&4Ŀ$Mc6ؐ<6/<9?2|m??gP .ǿ ?w?/CU42Jendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << /GS1 11 0 R /GS2 12 0 R /GS257 13 0 R /GS258 14 0 R >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj 11 0 obj << /Type /ExtGState /CA 0.302 >> endobj 12 0 obj << /Type /ExtGState /CA 1.000 >> endobj 13 0 obj << /Type /ExtGState /ca 0.302 >> endobj 14 0 obj << /Type /ExtGState /ca 1.000 >> endobj xref 0 15 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000124826 00000 n 0000124909 00000 n 0000125073 00000 n 0000125106 00000 n 0000000212 00000 n 0000000292 00000 n 0000127801 00000 n 0000128058 00000 n 0000128155 00000 n 0000128204 00000 n 0000128253 00000 n 0000128302 00000 n trailer << /Size 15 /Info 1 0 R /Root 2 0 R >> startxref 128351 %%EOF BoolNet/vignettes/attractor3.pdf0000644000176200001440000001134514272152674016423 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094356) /ModDate (D:20220802094356) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 766 /Filter /FlateDecode >> stream xKO1+2Y5/!*> X RPDcL>3:#C9hl.NhiZy~l߿A+vjj<@WSe ^O~pʸz4'lCϿƟ|;mzohuqiڋi/_jssuC7o4MoA=Pj*-_Glz[[n'sip͖斛+k_4wx =eR @SW6JKyVsf_/S̛~LE?^+Qhv{}jgT;¤v>UY ]%O/j[>9j^yyűx3VYMOwtItrdy#u7B~OqZY~˘?jܙ5&(";-m)1fv~P] p63G *h4sT8yWJpU8t8*koT¡q#W ^^`&^Cc+&UWQ!vkȫp5:^3[öu񵂽 ^^# ܛ*EU88*zM֫:=(\j*&*s"2MaoDr^xksI6QUX`.!? sET |{%q\6QMB%P.a.\2_Ukثp5qU88ofzlendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj 11 0 obj << /Type /Font /Subtype /Type1 /Name /F3 /BaseFont /Helvetica-Bold /Encoding 9 0 R >> endobj xref 0 12 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001129 00000 n 0000001212 00000 n 0000001335 00000 n 0000001368 00000 n 0000000212 00000 n 0000000292 00000 n 0000004063 00000 n 0000004320 00000 n 0000004417 00000 n trailer << /Size 12 /Info 1 0 R /Root 2 0 R >> startxref 4519 %%EOF BoolNet/vignettes/sequence.pdf0000644000176200001440000001136514272151677016151 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802093527) /ModDate (D:20220802093527) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 915 /Filter /FlateDecode >> stream xWMO10ǟVHDġ B[Zww7h'ydL{9˯9xnVύB6|^=6' 9&@zK.pOކa3omi[; rrwr-ڝ qEZ[d]ɋň3Ws~j$;}#㸍7Y <pupm9OwK)q%%s8^x Ï8}}9,}}9,X!57\%c~o}$@K|z/kBG/CIMZ궢%|d+2^q[KnWv@Ca- ve`hvRXԜ%Ir.+*>Jo hVݎ+b<]/qx1*|O*A*^Ńl [ K3(UHԪxjQh08 Us$je3 :G(ԄTP^ԗG3JIX`Bq vLJɕ(# L81YeP &뤌S`"-/3s(($ΩH;'V,0a\ 2LYT`¢f@:ʌWuQ!UuQ&uQ!f2U]THqo2JȤ:2θD4.(2Laʢ:+$d7d;GW\ xqjPݵ5(8;CrC㴏s!zh47EO#g!v2&.f4é}]m=./k8綗DIeyǫrn<޼Mr#L~DcĹR*o%gK0+mޣ2)1eu'pr"4wΚ?mendstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001278 00000 n 0000001361 00000 n 0000001473 00000 n 0000001506 00000 n 0000000212 00000 n 0000000292 00000 n 0000004201 00000 n 0000004458 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 4555 %%EOF BoolNet/vignettes/stategraph1.pdf0000644000176200001440000037502314272152116016555 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802093748) /ModDate (D:20220802093748) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 125284 /Filter /FlateDecode >> stream xˮ$K$ϯ/ȱcY 0 fADD#*=*Xep35}g3_-~?ˏ+SWO?3~GW>?~ԕrW?UY_c`|}_]k.2-/g]uW\/>o_󯕹ZWc}yAXuɿF:q}6r]e WkOϫ /ޭuuzZ}_ܿ&oKr~fy_Eqtu~_>믚?}IOg,;c3kKzQ'Zapֻ=<{과wy<7瓼|q=\>7_?b_ͅ<+DڸrGVV=r'~^H~R״οJBD~К[~/AaGak$Z[?_?[-VY{ӷS߽;3W?<>~#Z{C-Sxq.8|<<.cI >?pߏ<+Ny|ؾvlϯ?iCQ=G/珆ξ@?4K?k>˓_^\<j> } $/_+=GEG:͛zү 07ED;ڲ*燴sDCçNӅç1^?f<̕Eֵ+LJ䀶ڐbXuׇMWPNB^~bT?ŵrϿzCǝu x[{qe~)DTl ؃22=l?*5܆P뱨8-6&bˇY36aan57 ڇ08H9L,: ))b%&W)VCm7r;3?#$޲c9?)A* ?1Sf)!B2bDbַY^֟MF9XC5(?$] kSKf ~eŒB]7U+[@kebneHj$ k'U~7!ROdY.GAjڏڜC%aObƜ=[ #Gʈ~$wutv ƝA1*2c3ο!.j)uUTek X5 5bUa_t`=[Cy6Q_:'{0oJ8mߙ@f}g%,eb4ةf$qBO/x+C:SC\w~){;CWw}%N y$Mi mpk%,ێ"% /= )k*.Bok?h7"}9|G;Wn[е]7;ob^_LJTcw1'Q5eM}NT3&{ RHbTq=_<婆I+НiH|cTFOhbM^_~t}`'gq[P'=o_ X1Vb* =o}6!4Cu+빰25ruS%%}S!ضEYn$j1*)A9XS-ox~3Yv'&5 @ v ) :jb**5-פ^g cbήED$y{w_ߟ7,S#s(qi_wFV79+M[ A/OotO2ƀף9jbGR8v/b_aaf!ӿH [bXe^1U*][W+5ï݇P}HzYliI5vjr] s=Yա2`YHBM;?`_u?QWզt%_ YlMvD4e{|w`T?rHkF$7,˰1ΔQԦ\aNlpDkjگjڏ9^Y"c["icdw V$-bn.dOXŚ?u0͕=d ژwt|EߠBqq6MQ%hG vR70޴U鶣F~U&lI/:M/xKnjY͖Dm[(XKXv L}>%]~<]>I']-$7ߥ] EG(4^M?BƂc%(Ea6]Y(DOa\)!Q,TV8CFtϱήP{J֊ QP,^ʤy-ւng6@ ooRK!Pjlg[F &b)T0j$3<`(a#Ay1DUM!U$]x=H0ɜ09jr*jrz`af;fy$lEz{|! 3{xU›HAw4Zq!ڝ/Z g}q6SؿT|c-s)&ĕCL=Z0&O\Q\bW. ^JlGZOňS<Ϫәƨ|b,!zYDtYߢ.K8v8{FI|,N'7F<SJj6{`콨b1"3 {#:?V<פfBLE|{WJC"/DRA"KT42w&= +:pޛ YA'SDhx?-9v").ϷTd'I˜l3gmReHv & [1RN$4=/Ȼ:,eX`]7G u,Flc*d m" ?7&[N<Lg)g/1&Uĝ9ъ1dcRUb,43ć 9XW}fLQI1ג=.Qia Ja-}{V0Ju i][@1=)7,i`.2]b̑AT@$3ϵ=Y="Tj K!I-kZDn Ti`Ktػ$$fL)]mQ"8 Vm}y5-*jߤ!CU+`ѷx@^ Y Q)!*Yx(XK[K̚sWh9!9i0Җ%d:T4,=,š+1 al&P;KRc3v>!:T1BXƼ5w6ؔBTib0\׼bN$^U,1RvuPo;l%ƻYX÷jfnz)]@[tEginf-;in}I?|4]¡ra\D04C{exe=5P\XD&WJʅ1b8#셝q2DrR?8-NxQ$3&,4`z(z,*xzՐm:Gmj/%!& J3̒NlfJi|"8JG p eH;5G?llu=s-)@܁ΚV1۹`#3WugǬ mƼ߉+ֱ:X MC;?(_E stTV =3{3HQ{po4mhP'QTq,`|~]f#75b/T3P|}Dfpod̄>%㾇H:- 2lU/s+8D$i8[M}&NKjsYsb$/BRݫ0Պ VBh4Q~$2 Co,Ǭ6Vl#nć=jyyVМiU;xIsgػXl1D^0&xC?evX#ބfsVN?ȕFK+ܫ?!0Rôk$z'$qCkȏn>=E ΝMb&{П'b7[ o=wgbIuf{z}і"cfUIQ0{%޽#zP5/U׃ڙWơ ǪI$+.c>e&5w͖ae7M bD2;HH`x"L(<{ޅ;n?JԲɶ{>vx6 YLc"QΚ8ϙvOК!,o)$7Z,JU"9$047Y$--twvPKP퇘^B5`== uSczwYWүk/oe Y*SXLN!1Lĭ^dDs~[zX)' ZQ.*=Ԓw3M~T×CqXi *}.X0LK{%oXp _i3YfB]b % /MJqIݣPW m2=xkROCndc`l< wA9* <źZf,MO_TX}UT@zZgĤq%pcT*(N)-خֳ}x{ Ϳ=yMzACbK^d[rg 2.UQ7|iHل3߇;|($dxwSSLg(qX4G.8p2<9E gX0OJ7~46nr)Sj,½,5Q'r0iEI[ ³}/Z<u;]Al6+{7(rXYiVȩS.^  .sAaWBunA߾p) xܱ Iѝ ^orMĜtc "bFg|f" .,iv,P{Wo9ax#Xw®XFC[b1UOEcj|h&Aa 9xM>y3\Y1xt>_+Vu5H3`O*5r(1fqXvˊ:C o ΣC{lNa֏5ڄڼy1ʺ,$J͍QƁ=s/^ ȍdBtTp 0mBcSW151",>1,o>XS4`s"&λFRFl:@Ͳ䄈YVG:#W?SM` uD3]6X%FN;,6Q#8HźhfXd(c'їâك}޽B[5J kj?( z?z1#GkݢFL>6=.yעbB @F{`^ق|zP"95f9X=6o 8iGÁ`hnN{i}FÞ O9hu;N'E=?t/ښ;O<Їk}4=~Jм}[E`R<Ź1omaVϿMc0BXU8`qX*1Sc!8ג1jh;)9̞S _%ċ#V aRil'(L8RQJ]Չm~"P(%G'67*eS)!4uJY%HQ[I,el &\|!U}2ZbYޗx m0퉥} &! n&?Sp0nv2x;8V":j ~kڬn_$}o{G^OfdtU:x~ld~E k5&3?]#e@;y\ YO,WN{yvG(,Oyxq= 8l4Qlχx?uA_>_(A$Pw?n6U[T1Y4st! ڐL[%4Bʷ΅EỴrCn'_y5h!SVwՈ*(}EtѬoczO?VZ*n 3Mw?&}pq 췏wNZv:|z=}%XQ0|~FqPӪ^جJ+6+a`X猍|k;f*~XUt>_C0146;;'CX/XU7l3=kS8Tэ; ܃ԣj AݥJ3}M\bAtڍ6fCifijQ繇:aqlvhI0F:sՑޑԃح`Ow]9TƊ%xX-24qu~ؗJUmj!w%QM@V XZb֕H`3%!sN%V'}"l\l$ Y !a0Mjo\ ́5 X*#&RI\EyGEX`ROg ܈1lgBޘxjSs){ˋ{'֠*9-9hRߠ=h8S,G'nD^" dXӧ=}! ]vY.=%an ]7lA8 @Zv_݈72Vx jT.NDy4ZYXn`ޡ7eYmڦ#PRlD|Q3HJBecogL6[l3. s-kN7{x'-)B]uwdDߧ=Y(aZ,bw=zFBSfΝZ#H9;3j^!ō1FŲ?d3r&RQnšlφghUT"98ysg%c)V7WmѻS[}"W1ZLR1ư֞͡*,h-u/DS9I Հ] !֯#Ƕgv j &kQTn.ܪ5VK::>5x>Jݭy1YA_#6 nv A_0m Y*9fMQc6Z~t/Ģ%inR-:؂ ]E~ֿ5OS8)ʶh݃];^>ZvU|3eSw.#,71*?P3]\{7d#5/U)=e͚b#]611k@UuǤS6mb/*S{>5[̻^O~kp瓚:cF*݊GoH}kA#䧜h獜kɼu!&kO~"+#4^,'J}>=QT 1CWD1ɧ;gqggKs MޏZc([M! <}\x ˒LtGXfr jH*VGRQ9wkr|05*wXb!罛>gPybDtTJo)ȕ!V/fr7ѯ "B>C0[k,ԚWw |\ִDMZu÷(Z1*wK9UC Ed .S4C *Bjb 8eχßmۙIҍ 0>?w?3 ZF]6%벬,+݃7*7#eE&#ԎOfzRT<C?jS ܣ? 0>>];d1/)jNS>f/BAH7Ia۱+]n_?~jM 5ďBH׵}F8/2(ax6%ۋ@)o&QU|1bCåF|f<6Ԭ96\٤dsYqhp="'tXL6hc& !YdCsЊrEO`d7e+:䲖(-pEl#>`_H|XYq]oCd*B Y Y7_d|b׮ޛ㊋J%δqSc#y'+rV9ݴ8ź`i]eg>yg/VGgVFv2m՟/W0 WGzV+CkRaLm$Y~L\3o7]^- m$@UX^Yƚ-emM0x6ndo#Cm3]vInP [&=yhP/">;<x̷. ?[N76Ww2V9%w@ ,LvXW5"Z"jS\G5`e >E-NXU=&:/MfRc- /B2/al԰2 R*F}8bf0>~`z9ܪ=ÌBDE +FLy՞ 3wU#[U?Q&ت] ޖ^j&<9:u}無}/ogr7}36PlnMMpE9M ODddv4A{3^Ϟ%=WE_߷zV?9a}b p<\ ;wL=kKvfi*x_m˯S~j@]]F'Etz/^_y5>PA4 K 2%ިFnw(G|+ԸV*Y%Kʑ+Ei'鄦LLŊFwm2R`AvDUϱ5igt0EQ_Ւ@z>*{yHi~6M IM݊WBL7O'D¯k>\c?ɯ#mXwIq u$z}Zl4o,?5+ &pqmwm^u2gZ0_Zk7Rk!l!'*δc~NȡF\\0G$JECZBw[k'<ek,U_EА5kh5=o%>Iֵn*}:/<ذÀH Ų _ ֤t6yn*G(y{5k5ߩ\Ko?tD IRL~3Ű\3"j݇x;7!VV/dEj,<: UI^m4خ?}eqD `;{[L5%= _CtVvHW0c 鱖!0$RLRM͢vˁo#A!DZ}Bz7+z^ 8Z$;vj^؎b3bۭxk+Ii&y"9 j5ANNiZG\v\'w|hpF:{͐a0`)7H}V.lTNi=xiIB ]uK^.N>YzgaX \%9աNI[P%Fz,L?S`yNv2tʹ٨)-ھH#xXdK0kwi]lL}>I;f>i42r[= b_C)8ZW9@(g#pn%$Y.f[aU1mO~h-oq }]|TF*LuM۴Qǖb1 Y|t jM/uWY%=(>@+OiMʮm7 ىTWޓaJ 'Hv~bdtPsmmOMHl詉ZQ?ܐ-,^XX".M' Եwjᔫ~5U+~)Ȁr$rcSAMC:Ѧ2wa]|~ōC)ZFםwxTrf.@k44cK- cM0c[Sd}ߢT/v9pnznA=l5hvm5mkZϦ{{ߔw7t%qg )Ǯl%(wu"u;f &ˡ%E=澫ڗ^ܗ5LGwt:[6%ui;?_|ڒsD$jb6[%&mV@c=kX&4 *Zm"l[|CC|IMs=(y /0e|=4 )뎌N5+JET@Q6M5Xp`~O{V{X*DwPmh+&"N YP#4I-ct)dSض^h۰j]j+:¹4?`t`4YodԒvyg PI{UUM1j(啬{22IEy7{ 湯&OK޷fޤjuqңJtʹUC,R]ZlYV sYnשnDrK5~8Ϣu93ira9$X*i}ޒi?TFG9mݔ9ݤ{L%eB2p_L23C*#Ti\+3Ivf.W%E2`T|'|JWOxJK\ (TO&Ibqq5l/,k C}Cܯ?ALR_bJkrUurC*f|rŒYNZ:~JlW.S9aC?_QkuʕM4U~)w韵A=x eWEr績rؚj*%X_*M+~]6[':ZQ)3JXzC|}.5-UGe7ӴcwC=wUw}v3X>ԟQ-k\Fg }gwg^sS\a/'7GBt&ݯ}G٠d0*ߤyYiu>My1dOY^XL[oڮ{u@dc]lɰ`6w[C)qG~ C@E )egz߸7\Mr?3/!G^Z|Z|ݕ](?'lÛ{TʝVre{?ېug_rmuG;Wfp`%U"А_X7#u#pWhZzh"Cx?~>?]Lʯe'.^EZֱ<[^IiQ>'O7SP3\RrߔXm_a G-q ޽%"S*ic+aRa**sOhNqHubM:ݲe w V>-\.i_䗮b"וk9~2lс[ϱSȽݴtCc w5$։ԁnX1|?3p8>{T S)XϟRk1[l[s?'GXdYi$Zɀn=ip& 1|'ϕF:_(ɂ*8+S& Χiyԩju`,7Hkp_}~Й2Np9!pG~i>m}xGO< [`}p$bgj9?jZ>8N-g\ Bvne}x8;j?y> y6]߫b0*>|מ\ߑ4{|D8^U̿akط%'f)ѷ L4J>b]=:8?_61ް"A[&~ZA1.>~/i>Ό8ܱlO0q{G;GJNATOg]n祏&>_y/?K}`IT}+ٜ/bM+`}=I/,}|Y2`n‹|i4+@%N\v>yCR$Uz/owA>G?b(YyMs//[/׉v yH;X:%A-KwLɷ9\}sOxofDR?3К(a|Ђǘ!٨ʡa!T 3\aLm:w$MLk)K2Sv?c84_[%\N0;`_ĽSbK*RQLzjk-`c^rqʒnrL{޿|& NJ} |wxCWguZ5j=g~hvaJ\{]@~|==ۊ=aݵ]x =^ܮA=aϼ-1 yP"Z? X۾&Yg/I= 26.]zs¡K!>?9O{U >R韇_AG>sO0qZqy<;9NvD'?dUaΑOX:}gB zKώZzu;Sy1ws[G=5GO3)|G8^)7Ozh]O1K&Yze7-->=_/㫢x*uݴ^ՙ?W.׫e"u~Kx7euKgugUIuG"PQ=aNT͓%]Wk!ψxUK="W'7wRM#]y}C<}u0ŦE(_|7ڜ[]<. \K'mz{X?$owmE XWpxdv$ζz^U-]CX/Szs kY`^/.~^睻QW|UJoC8~_,3 M⬢ѓ496Oe44OYߛ_8i$2X\kԋooΦM^UW(ԫ.}o!{;ElGk-^q:A{=2X>lC@IǙ^U{/;+_ެAXkfT>?׋k'n.Z+o1asC ime>vT<^  & !:%=kZ<[4qvY>Kpf_z ?ٶȆ.չuŷ]e; .<,~gap?ЏM3KWј,Tķ%{eK/{!t _ٖݚ!3ZߛiCU}/Q\ߟ.#*w/bxU{a<3l@}pWۋTiO C`GzN-?P?'Ջ/ UUg󇶭/ZLy&"@Uib>z{^/>="b'7Jkչ:Gb˵.\K? 8сkgG{+ թ?!Mk_OC[>gxP[_wQս=Y*_ŲH9彰:X194 Z}xx$vsZ#1OS7&_'J=L&P_ g5Gt G'Kn٘ 9em9@ kjƓNcGZ^/nOZyF=yL snGp Wg~Przha[yKlTLYm 8v_P '6M2?s}i9<еš)/Yo&-kzJ@WdG!߸|q\~iW'I?/?iwS]`tpnCLeȓ9 ם.eW+:hQrD׼dkGo7NCJ|q ~vс`8lMBϳ5 .!?o]cqQPщ[là8\PzsZ-?²ZZӾm+Edd2yvWnau?~_~\~$!8G^j6MR=e.[ %8,JNWT\W-Oa1JP5_cdU_?&Ĺ@znvIE?K`90w_W{pQ|C@.O3*Y}#Bc(HP.PȀߔ̞QPk{fTM'N>l ZFmk !VYhMP;}7?$<||tZe\ }'{ZW1 '- A(JnVQ})lKc!&è5PjFJFy-Neb>} 5fuJ }}jz=C2\/˲+S"=mgȤzżZ tjJj=DjR}LumK yM/ yj %!>or=V)j"geI,6]ŒO*6.g璪s1xćZ-z_3M|)=75|%̎>flș#5(}XrPZ(sqHJ w㖒Ry*A\\g[s9?3TΊ̎ٙ{-B*,u="6Ȝ2ݟ6(Kj55Qyϭ]q\(gpm-]q'FvpF^%/Q6%> MTnHqSxүqT>\qZ|Kj-=W]vڭSxVف{ VYkDqgۙI s*-/!uuRx(5K pp?RgER4x=~b>;XSjN{0:XW/!3әP K_(ΑUft"+?b۠Ѳ2+Yiu[r dwRIzK뒘7"m? w%RVV)V+TeT)DEf)$"iϼ ӹcz^s%":l @갨3[Dm"aIĚSiKf@8õj d/kXd߇ܟsk0@v4!^U"ؒ$[l _Cs ȹ_i@Zk$MȺkuqeE,yG M~Bތ߭ɃQ{3 $b@2ۋ?ÚpϧѺIVlأ usy|&hj=u~_1*N̘}WY&5M䷛TkJ:?Yx&8]A7omڷR~tM6גg>| LfP ]3:Gz P-*v{،mMf!w/@Tq}\Oo? l U/vOӿ!Gf`PC>agf9n!~݋̐2ޝ>CBGw*Pf H>5 iE$Q\ Oy6X_K3|U!IIT4֒5Zk]m[%w9I^'79 )mHyLVt ҬN뻻s!Ojtx\*oL%kZ׳t;&ͪ5__2ߵuo(OyGj,6P2}&E$4ehM"Zڨ1сK8}DLR4|T4 JL?'+?oXZ/+[T$ &I,S{(1uyeMڿ~\#'ݗ{fM EY^W޼*|E7A]u_nтGcOi)|FINϯdђ6F pXpiB}Ofo*p LȔd ] O[Nl֬^OwmoA_{"ۋ NXX+V'{v߇pK5pj)߇]h@X|{6H5^OZ{BK!5_`uIRU5]UeeRy >_cXՎA'nvouq/+w#tE+b,\p ]o"|jt' MkYN/RWuO'$ _!QzCsU%Rfqj3yJ"0kl0-UO˲{Tr3oP~O_Ȼm@jʎQ]@;Bytmv.>+Zn$Q\ }Of\bl@URS3}kbs^9Y)!; '{HT&t˰?=o ߎ&|kbՕ}6`ow Vs9DnhFp| P s֐ַ3\ :'Wp?4P ۢ/u >P@k h\ou@tWMg# P Ki<yB%\ ZW5nV6KSԘ75ڬ"t㰁2Qղg#sB}\JZm bO L'AL2zobN:ŋW6^b۝Fy\g&p"̆ *_Neζ~|㨾*#2%/EyG]V^w>(5lJY%j$5'?k'#YlHrVU1V8}QK)*c]\Ҽ$eDKl؍n)&PIk&|yJ6?^ RɻJ-u4yCּ_ %ܛbP ;"0ttJ>A?H`uo'rgWH_#ZLAn9N*mJ)J^'{\1('w#9t=f⺉x\3yFGsf+֔ؼ3lKH?НLƯ<|2wt9CK_~mDVT3~ͫT),E 6d 1[)yhFu_vo:ͮy>?jkҗcJ_ MOX}ݕ\Zϸ6?Uo6XRrz7p@@3ЗIDD\3(uP3óTTqmn5YlGiO]Y1E!|7Do3Gxt<D: |HU J}X_7dA_<6k'*6|OfK'ZMw6cMU%=99Y u?:Kyb]Xc O{7K%RWnӋC?;st~O]>O(X(Ϲ8'ϷmoOo~K??{]1X7W딟/ ݯz[rX=nbjp\|AW83gẓi;ͳ}r?A۫TSʏ^M) EBsz;7[w:˵俪urnzugV+@n[|?T/@υ#?]&s;ؓ:|!CV/;lwO#uj63.(ijսykj_ƏnMY\ɻ1aGxfV;G/yk2>dayS) ~,Ap2±p;4=Yϳ ॏ[Upds_Nf3 i߿&YdCͳx."xV"x1+9쯨ΪD?{"|G@G<&mѼ.Zw{u\Wzy gM{1u&W`ڒ=w&'yw=oe=Vux]-ʿW}2oE:z=< 50{UEؚ_gwfk~aM6|}xg<; }ԎKrr*>SzO/YȗM'yA\3CmܼI=sE>WT{+HNn`,Wf L'.3|CYf 4[.ϫ+smYi/zIGfkǒFLou48T[Y+^FgyY 4?^Q{c7yee'&jf,I,ո{̜.^MtO ~,gIz?O"oslմTgUC =zGyNw^0->B(}oK`{϶&p ݭ5Pwy %?Zm} hjz!jʞ$x^zh:[(Z%ip]DkyjNXYX,ubTUJK5sd[|5řEu7"d$NJqO++D8ЙkU}i)xr} Γd~׬z;֘RqPz)W5bQD%/ZQn_i.K5?;6و+b#&(Nb\XWI椨. 4u^_hITG96$\WWhZPg!7@x:L"cms5hNol7|w+9Iҷ(ϻ찾r=$Oq]sJ{dr\ p%owэL}3c,j wbL NKhE3[ .IGm|Q$Lw|wyWWGC] 0Z@ԦhˆmohIg3h ^:&iG\kOWljǷ7-N6>5brSoeeƀx .BI0 |4a]<4*Ubá4f]޲ nse"3$ q MbS8i.jD٦ ͎HWhR}эCTҎ~4`E20⭤Om­zY]Ӎ&KK@O~Cc >7 zd̡#:$DP7ik8k|+zԜp-}L>(J"]"cЀ])5SI&Nft,ЭK "1*(dȺ{ݹd a/΀A:ұvh8)E3w)Vև'tdu^iK mCgRʺmnlK;yN&3;KH{#'f8[[Y!{Q>q2a/Bkw0zBi8jx1tSo?p]'BӼ;0w[w弿5o w+}qE qq'4ܤ. @ pY+}6;oIOdAMI:$Z>6BF웫aHedF%7fu_N)zofߋIFoJaZ]&uRG[}a07'QYݵy `C7aL쯷dv 9?B~jQ.mh%axwi=.7URiXVI/ Jhybd4Kch$Pw8-@6g6N]un'w=1'[zJ#[t.I*YG*V(VCj6Ŭm/OWh)mW;Ag@Y_}Hk5ITrCoGh';&a /$?DҪ EKuzc'"=yk.<:̔ +KEgexSIեHd3l[u$绋NU:"Fѣ$'=ki~A]x3O:FyG̎7?_ p%[<`AOg:C`\˾dY-Zf6J>V= bAz1E*EW`\i!sZ.K݈?כxa#:\/wNrel4_Y S(G}?>?9?~\{aX7. az(.M=fҥ8~zY EҍH;vBi4px댇Tq2@3k1P;ezY4[Q\Փ] tL%M:jTƟ?\mBCs qFLׁ#b?\Kx>1Q͚6+V= ~ɈQf -ȁ3~C}%˄.L5%BwH3\4Oh[]PiЎJoy?+,FaiZVg 뵵^R>96+ciN:VGCq"*bqGj*✱5Xo>Pq&=bއ穇H ^ ¨XํE2CÁVD"*Ti"~ěQlcȗTa*&^r!% D\eˆ(ďP߾˒u Ӡ:\v%UT=Ry*0%󑗲,`ӕI*aYc\jξ;Tyڤ6:Ǿge> u?F? ֭-s/Ai^t}*瀜`NRs ̐v!;-% H9^O듋Ϸo]бSy#^s{FOYNpJhl贝ǁEkhC.[p2it<{`WmsN!s팫:fuǩ#bz3&ox?_iKmvoo5{RXfIcXT~99 e1F8vJyݿEl SnQyuOQ\4۩"ewU~O, f|\y&T/T>|Q6[iI5vc.R0=?GfsHQ-vuLuLu7Sl7\K-88MzB<Xo}& En,$njǢ{w&Z;H7mW ߟ|Mui</~~TWoX?>e1|Os];{m.TK%sK F+OG|G+#?|NQἹڶJ2Aܛ{z~Fa X<.er,w׶~{ǎ1e{.???YF)^ v_gJj͝1{f1uoxB}7p3nD E}"~o|?3Oq~d]:竆ܟ8s/@+dfד%|BdUHUod?^9S_yc\4lpJ=%vGm,a+<\&8?"&V:>ChA\qR%Q@+ǽPV'9}ЀlzϊS/~Of=| ߯'Ý_@X.'cMg+\s~ qSB E9hr>?z|7|YD>rK|Y8u}b\=yk~ﳞ)3kӏ@^<qz19?箒 k 0ո`sO>tCK$N+7٬1*q ~`7_R.2_<7r7[V{+ ;!NKt2MX*nX%J`#z|[7|{GĠFé|qV(- Q9?? zel dt;OĐ-~}n_ *<_rwaY&/o}u,]|LAz΃;. 2J(qN=Nak5STxsg_K>)a.=7"̼nEiG>9\,}plry52p!i,|4oYip h}~:duM.,Kq:9#CW|\]|7yPM|FDs.ruà!:|~'jK|pEDb$f?_.\:~%]u%sg) J\5e)Ok.]v^*:첋3b>g<p6sw.[[t\ekd)^naGn#tIk.]pGN c#Sf?.ڍe+[7sۺ8UyW?wIr $^a,E(OQ6]YWg>7W΍:Ҍn,^47 GӝE.r_voޙoGE%<^ya`< i1"ܾ#gOC/|?ҍ7!㿫כ)LuΈ9KJW?52$:_pütRLf&MO^3z&mϟLE.}_nq=y,PU6}Yjtq 8⓫/.bD:i7Jzn>IJQX.ɹ5fPbF|@bQ 'PC0+!W*獾#wn\f]&sm3A?l6,'s-7sh:$ uV2mdQi|ڮ*+}:eL!8Nʬ5N0MFKÊ=ethE7pU"CC"`ImC?}K _S4k׋ ?pGǽ )ZƑ#y8s}=BAaLMw$2hl%ǿWnvc3k}G13TlNJI_Ϸ0.$ux~=`۝,7 VS@%}>Gax.GD\_G@ɶ۔09-;cf*Í#pF89ht6o'o<ۮe. =%8\W|5}!ڽc^Pm[3XZ4GߟN1^j+oYB߄&ܖי4?mBz>]nzr6]cw]yR8חOZ۴&eO'u7ϣOSuy)4[>^]` SCqκ-^G[D5跀~A6I6+߆Qi ,)1d2賫?`egG˔(T%E>;۸<3_ЏCm%-ƖK6Y@4΅یToQOǸR]tBCѰ߃`sCm9 v\VAەp;C~㋳XNL<۝A@c #㮻)߲p U3_'Xtn\{yW/U60|ޘ? [ضeqGm|>@TO]34*6vnYߜKcB| ĶK_β̢,o|ߑ|bWi r[hƭlگrK~ .8=E4Hc[n&J8.h`\+d"޼\>f;ݠwr 균cNCu'sVʻmo`x'{ZV _.ߞSݞ/<ㆾo|8烺[~z2Dnd=U[^-ۉ7Y(o=^9XLWS>s86m<\G}_tqRdCLL^[lGMi=teAgye~;,oo7)OUMG)z]qva9q0L{wG{8"4YgAWLo>Źg|:}vrrĸ@te*ojn؆,4`|ROeI@Nig"ތ9ҳšW5Nz#8N3Mz ;|ՎCq*=RE.5$3>wY<9/rSoes b`3S[PmjQH$b܁'Ho)818oNߥжfa[bәnC`6b֥ ´I'QA،' 1'/;PdTn'0gɖMHJU1{6R6[b=.j2bgj\J!,d'(xOO}q\>dP 1I`Gr[JhlFlCu=|> g)M߲@⩥Y sї)z_lFT,׬XGYv<xgļ}uxk|RLJ@4$SXU`<7;/ 's1bjDYqG& FȘf]$+YI{{[6 Q'}Y2I=Mm*ecy>^9e9)_o$p=vW#+eYRsD83x1-SDZy8_MQDRr77?ct`˒[ "9Еu-gQZ MgH$MM[\^M *w|l#1w@co:a_^=Kf^)q~-CO9PpC[fיĭ0x{Ocɉ}ɞhl6=e˱ ks9:Pp>ã#.Xx9NvSbe3MJ'sw}[FC2\?pB\yXSNW9ޛ;\C܆"f &~ ŹrOSY+ϴ߲()j{EG繻ǭӃCIfh0Ȣb\ m < KƐ]~Ǟ7!ݧ_%'X6i2u_("O!^f%ؼm[Rޢm21w>p ݪg^GVv,yv,+y};})H3}NڃgB6 ~@LU-ԍhn(K#mw2G$<BpN󀢏E(k%2,Ï)k6~x?1gmK__$/iȒnd;-׌ ħ@"r~~rn#hgqKZ{i?xσc5921'üΫ_e_k|D3Ӳj"Id~olls[7brlpޓ '?QϐܖeF~7J6;Dže=߇׃ e|_# zIr^%]5+땼来f=GZGw6e+b D<{ct{oظdˮ$ׅ;OΖIﱒmQ4ن=yH?칼->O|n* .QM >K090(Tr{ '߁%_JmX$WuOF6"da^n9xI_es=/i|3m7d=6񼘍|[ry<6׉¹2y|߶.UϏnwKi6s3:8\>voU, #Fxdyxα\A_r/yc3ˑo|u}!'K/OfI5XNtVY7BThN:s~s.]O56ĉ nc+΅esq!١+/ "?Twڨn}֓sX-8֣pNf^(3?n~u6s٪O0My}v92NߥQy͙SVH9YT~!K6=>f!h6mD>џu_xBF..:!qOF?y s` Fn]?* S"3<^h.v1pdfv f~͜E&^:6w:~7mۧ%g.;.}DK-q䙼wٖ<һ}%ko9k2>w}{BMus45o()rUc$V).ɣ[4j*B=%'b.`~ @tn6 ;E$s!߯9E,/D3W ڱ.dQ&sݹ 6Ϣ"{^i9v]%kVĚ.18H9DovB?!nyLmV㯞x,^JG!0gr!\fT O|̿{?_z0 ;a??y٦W0y mm6_{Ffkch68o +kˤWzs桧! ˥FDY [ C?o/K1y)u%O~@sneKS6 }ąSۈ?1\w?@ġ u]nݑqjc.T:qUi"œ28iXb;fxֹ߿C-tс3+#ȑnSGB[LF'`yb rQ ZgOX T@ʖ9';SF=eg+&`QW͡t5l}Ӕcw!'/ _z}17XٝbQE6ƅf 0ʥ':7\+෍|NnOי}N,k=(/{,O l{WMoǙ 3jAZ$.m?TGE&6Ix>+w氄(Or63T߇z}3۞MAWx cmGxL!VMl4#e GG qGF 2Wt"/wg\9tOK=Z~ݫk7ݯ+gfzGм.qo&Ģf㮸li@G9¤?wwٹ{!x zg .ʁ#S?mYV_ꝅ51VѹG$(Wݴ 4 nMb o?2X M]2=LlBsb' NXHr=l<*Qݣ9CliPnX&+\>eD7 ^(s{eQ'&1>7u*+Fs+}Apm~Q-sS#'Cp PC6~O&_Q^gؗOP}rwb>]z>*~5tO7ˑwaj_~_,`@s"IʯG(v '/zt/g˦_q\w~^f{p2'b:xMW߃>h4[#*j\;m()Ѩԑs91=_*^sOj~r}_@}>'= (s-U>7V=Vf/4doNʠfup+ 6D=c<1LxPϸ~qlWW;s{7#^]֞iKT@h QS' BǠ_ ։K eds[֍S}f];Ut9V?]wց`lL[3 UoPbYĊpިbS?">|jėߋ&9e:>cb<{✝swuwҽp*mf'h>bt84 C4Zi&*(~4 S|oNty#AR/9^#9pvυw{6oFxC|v\_ he5dyWg5ո2w(3o6&ᡁm=>~3g~]ϻ 6s~Q;duwW N -LT>ɟɪ#qd15p>e㣳morC~6O![,4EZ{6.b wcK;4w:#7d" wwHJm#LJ })E|e*#29n0s"ٛ0E։1OzU5q9Z>[J<* po{SQB75^PY4dUL6mcONdP#GרrEcNm~s|}&ρG=+IN36hw0w##L V&2I g&m2%VuIr*uOz{-%&:5qNX !g0's9Ť8抋Rgw#s@zYY:mпG}:xF`%D<s>?Os:)/cYLlXsh|sգ*߮Jk0$Saմ1]Rvx̓2 "9a-9ϳhAU4r-_/_z]Two >WrV æ<_;82&:xuF/eS!bSRu9`^$^[3Zo5>U0OMkkFXtaBm"/3pdJ80ugPx?e1G̹Db=/dx&\#&eA.7/1oC+Pm_O53P>eḱCL~1y1CTeM6Ɔ^φ,xzDVs`xEFS JI*[孉9d@pw]OGw5J}CF_Gɉ_m1.0(jH7^O|}ƒ&z^'ˀq3m23"@D `\:b?Y87vI8%X8&V$v YEeЬFa8@o²?D};jْIh} d{zlnRvGp{c =o&pf,XoǺHm_M|O9q TBW{+Du}O ?_M+9ܹHe2SpqT 9b7|npGzlx\`up!z$6R`n-"o"gu)Ep8b1ؚm|𿀜0<*j`Ȁ36 \j@X!DTDz[7K+FaȘ w7ї  `w5 o@^hqUc_4h~4yFVaϼ(㠌ukA #UpNgCkv^,7QxN>ľuF @ uąFGtGJ´'8 GCzPrƆ/Gb@~0jt.o<7ƥ<@)}LgXEȤ#-{(#5ͺCw S6@OCܿ UPכ} QNMds7;Bbq Z%>$8rz]EQA=? _|9ђBB$,UqU };]G7:i#Z7 _*|g9vd\Y-M)VFA74@* 8f*_K&2:ӣS$%5UM7q'^դc v`;kW˥ѐ ! d(&e,T3{Xb1vnʰ+ӈظMIG =*)4!xZLK7M}Q<?$g@:3[dI(pgSYdj$Hɖ✤+mX(>b1n dzʃEorFXBJrgolS9 !xޜ&*=-ʊDX56!~'_]8a+XLL]/L,I&X,-77"]$Wf-m,uku*V6NʤyO\e@)ԲZP//>e}j}T&-ʍ6&6`I\[_J󷰛JxFRe7 Ue gT-O$aj5VOb7Z@((0/s$Z*V$Qʈ޿hF%THJ#6kVf{_o ]NN,m@ArC`.p^K)EP`uI0me+G_e%ue>gjRTBDJ=?IS@,HM$_1|~ӑ Jەf$%y P#aO3n"&,]Ju?P3eK3.+;W 3bPPb`%^w`[p>_JYQ7 ٨\ۜqdOb*UnUy4Ts-9K3PeC3EHwH.Us0w;A6hY6vP)Rv$ON"/sѰrur'"NLNj^ڝaK*Gk+PP|~;Vj,#]Թ- pǨVL)h x3.i\t'+R-`'rZv{+y։:k[D~?DED@@嵹՗gNL4lV{=w(5 kݘSi Ye)઩)Jm)J?־\w=`kժV qxVBUܙyB3Kè"/T{@} {_#dE ɋ@.ip񸤱ӳy'd9&[WȶZA]f~fP!'ƺ8u}*V穼 ֍ XO ~|,#$, cd*ϔ&ZQ׻Aޖ{e*.S{bO߮?؏ _5s]3|MHZą笴B}3).?|]>A%x.'3WTG+5Kr8,ڑyAyۉ8t_㩞G |=5 9Bt87D7̩\"oycD̺88SE03:x2i7 Ԓ_Gs [@&ľf"@<חzCk;_ԧy(9>=G(}K;P0={8ou5/y8Sp}OMJ|JwN=+ɣ?h0~% Q7 ?9;iNm8 vR"rz,s5Jcv dn{tZdjFgHwg8ԂN*F q= |p<'>۽}l4[l9&cߓ̠H.vFSYoQt˦WY-=0GTיS&d:s HS镕;8^Eݎ: `إ ^jKa0S{}ѓm¹ج%#?j^\8oܗ] b3]ڊ}6kNGf:_7_9:ۼ_}&gw}:hYb&ɣn&fj~ eDAO&fv~Ĝ6:.Ί3-ed; 4)ps\&_q6Ұd+hA=y?c1WbݯS>m(~ȇ2j@TS H%u+Yq h>$#c1:xϯ<>!G"\{~>qn;u&LG^@6z7Ny?=h!= 'zqKb3F(35=QJírIJ$kOV\ cVQ}u“*ڷ4ၽXoB;رSKU6ܼ8Gx* -k"`8B EBHv_kԾfǛQGAi:+}RӾM޿z3UM>Y9'>Vhk@~ǚ6:Y߻yGm6ͽoEaF;WelZ\u P76qŴE[ݯV]nk~Ҫ/hE^ o=ȿSufeي>>qOɺT<_s[oX`?[I' ɮdނ9?/E}._1X@ /1$x2_g' ':FW64"u_I" 35Ȃ$s@ R߿N.*}WykߔPE, q}wj<.`Gxm5E|]kU,gW{#mzLyq $]Z<[DHFeδ9 (Qq _;2RV]v'_<4GLHD. [x2pE   ޙj3ϳq 1 X:}_p?vSg/>9CVuq39@Wz뤾]3O.8V= %Cq!_<>ob8LPGlʆ/} n%}Е56~fj.Jye4%~߳4O^߮?"OL҃&Ît}:8|nAe~s[eB8` QtuQpfP`!:EKхs6ӗ>qYif'L'/żu e8۬DcaYtœ}(&Or:y?=RD#ד׃Ƽmw 5Ax)o&}<_(u='Q׹]1i+؝qL7`?%~W`'pJEo午A)O\gުoJ^:fݐR~(}  8b+/a~J$<;pZyT~ż|'gNu8]stPN+CV)g1WdoiT'+osqޟ-W}BpIl7U1,1p W $۪[Αq.L[LR7z9OI)Ѫ"|߹r81?H`Gd#Ξzߗ\̡xG@JޏETSuOP`8^/ ~}+O_yxN5%-;μO"itp`S^`ޙ<ޜ7VgpN4WFm/wr$c4^K~gy…Tpcwq}g=G`k[|?zNƮ/*qn;Q" | @ LʐB~[o~UrI`DDf'a~/~Aߧ^ Dy ows8b{'pP-/qy  ^abe=ϫ*+W}yBIʙw(GVy#9Z;qv?ؼ;j%;.5ˠ #=}E5s8`k>KN`}v>wA\nSza((yO}X};](Go/3xyySg1ïO<}RާeƿG(`')jvhr;[yuios&ߑq`\lW NRKbvo-%8Ke01oŮa67V8Q9;p杉z/p}3Ìwc@ }s%hwg{su>K D{.}W}2WY5>^}}>zOmW?sw_=1wdl pIX;h?cv+ |tz-eh"7 o}v}0D{_uJlx"o?B}+O Ɵ_q2ՃGX#P y_9L,LK}#1^M+e`rҟϙB{3./y^o6p?;MMd<;EkPLb$^Gĝۼ`5"Ywj'O*ҖzԲ^jy2p}M_p u7}]bkӞs 'ĜKҧʷyǽč86Oq&x}SORIq}yzB7|^>I|⋼sw;z9w|fZ9WzM|ҹ{t/tN>}rOγ+:'Os"γ>9>Qe~Cg  \ܯ7Cu#KE?ʺq\Kȧ!ĺ<:yN<ϋ)qJ_:+SN:A d\^醺 JxuiofyJ[Wx!_8=}¾0fVO'Mއ7;:T\4e}^_ӷ<)YZ'W'l?8ZFu6}+ԿY1O }VEtG_<>P}\2í!.drSCbu2K~8N9'q_A8ҷ}`WggO{y[M^W~ eʡt{T(W3$[ }rude1vZ?^Yh$3;.@0ֱ8:u͇xf2Fl!!u?׽|^w֪1 AẐK)q]~ؐ.㛯Ubz&)n knozHsx}1<9:WoItqRi? Ι=[UOC>+.];yÀ4 uܿK;v&Gi6xHK[wDyG$b ёF~8#B%='dR1׏R*|vP=BRFBO "?W]#NSaS_7SLW?YqD|&͓sJGsTΧ7m1(s? 6J#߯JQ#3n~Գ=Yx;cTM{z?f* \8OnܛnoAA٘aUwdQGJut_eCJY* ,c ;GNe|Ӑm[y{{y5Ӿz/>Aߋۄ$P|hΫ[1sI _bUg:% Q+xq:wGsJسzݪ~DT>0}i[K:;LtZ)7yt(U+1Khsׂo(VԅG.w @~ (iqe~^ "){4~/UOB%y)^;~S~療sv^qchVbĺ>_75ʣB5WeV5t.AjFf.Jɭ~o0S ֽ9 q6ՙR~N{0ǺwWN~4;{@Zkaه1Vއ{{&>ә:e"D(@&15ygogG?͐?ws3ӏY+cOPpԍG)[&< 0J?X'm~|NRϊo>/(_ߋ\R"fok^d;xCCO g!WoPf~B\L:&py~w[2#/^0e2A4.T7.KQRGf2ՑH'^]neOf8:[HbgB;WlpfB=F序C{ 'qne<"UC'@1<#\l*m كƂ9:`πqo&\Ro ~/̄ r=O=aƅ4uҧKA4N }b|/Ēv?!4i.Y , 8ܗ|j_y )xل3k/:g;#K O磓ӏD%u>r'tWӦee^ *7q[bHqfҀ +/wwgɻw]1c|4>L~M|b&1WR3D0_ 5ˣy-xz+o2 Eb[7{a>'sqgMTD\Y#|cҧ?.1ZI_MQ<hhՍ+¢ m,~ҟt~ܯҳO's󻊯{_ٙPxç~~_ `R"4'nr [R6<=|-|fY,;72foI|/tWo;xA]}a^¨U/h.4S~Ry3i07{/׵07` r^3y{}Ao}}`It3*HrHv{tfY3rG1`꾊zf|]w7ߛV!_&쪖`?GqLTn7Y&Oxn,7řs7-ZM=مijqq/73 3ClSV K}^7{߹Kq|iR촮7h F Wx ]8K_aE]7Nj_CX Xw1|&%q?-%qI#%Ƹ4_6Kbںkg H w =l\VC]_}Azq/jw\->t3o 7@7Sc^o d-N0_[؍SW+osQL  o+ ') ¾efr)o6:4P(nDނξuq12NC^łyH8k>"ݷnr^Wuq8MtpC:;UԨ7NǑj2]7z/;y7Z57wW{8Y}g}ݯ91"IcL=u~C K?DG#-`^;ha vj[ϼ>0̛A3?Oz;^y `02a,)O_s嬋/K}ωo-yՋ>竫r>_]3h??T~ů W}cq7X7jܜK ߰JBZ l"Iď WdP@/qXt2zNx&|Ngs½%χ\'ƞhf]C}㾗#}:|}Q\'`?֝w?~M9{/|}G^vb'ysCR;)fڠTEU A[3=:2ܬ$FTҜx@FʛNMo57с$w"61$keK嘉A+fr"w 8rު̈́~'8cy&͜oaOq.0R5J }x>ʹ㨴轉GPꇩcʙo arRz~a ۹<䌦(1cr!\kݸc2v̻=zVbFFh Ѳ`d^BFJsd羞ur|"60X8Fx+R{G#\oyg':^ƃ?-+HP=mi H W7#wFn/^Q$2RoetdySrF(ד#!Q|LQ4ߜ dr}X~%ӻɘ=YdR=y l5~+,odӏ\Ό,)t>T4M_y4gmG%HZAaY?3;4O{  jחVs{gTlhO,hMϔTMmw)pUJ6nKM-7<jt,S_?Cycv]r&!`\җ~xTդ*c5fOٮn˵!H*TxVdcfA?7\y5~tSU_UHcyF}F@Lj13Ŭ t9{L_MwЗW8/ :*E;J|*%7@r { vS Js`__rerr5t? zC9]ttGt3־tհYޓ;~D:2Wƙ 73U%`^F-D1~D߿ͮ,XgnU11u֐>趏*i՝6?FT'P舼q?Չg)A gjtә7;b3s}XIka,f 3w@*04LW 4|`Txf {'_o٬ߜyԡ]x>|~3i$:Kq|?/VZCWi3Dey?ϫW>?7VNe=J΋Z w4ƛ/8_e!u('ww=T<VmGӹWasP'VAѴU;H[{ZK\U{N̎}t(Wd7#^:E57dE 숌 .H q~,u{})Yo֪yh3|@4sAkJ+P➂чٿ5In7y1NټqKvnR& @;7i'gK{#VU3MY=l“6FzvWTc%l(JCJ褣?ExsSѧ.gv,czZI󳪔]qs*^Ąg"SUD'8j4F׆=[G-Bn{qw.t7=N~Ru{q hOj|GP4/3bnz&%H,/,wG淰 N;U8C>OeԜOܾg?G3 }[3ZoB+T};d4>Η|ƪUwZatG_:f&_lnY0>ey+_b\yn>#bqy s[9:ڎy~儱O=<F+;gNe ZdXzOոL5^'\[>?fhϱGrt(9W&Fχ>~}nƕ6G(?h%g!:5_)^)>?^H{&=sC34??V53-q1:Wç /N#X_Mʼn>!\YVƆ זϿHaLϕ{m>T7|u~I+>gӹ |^6,sg>FX {%M#5z7 '䨓y9 LW,iW>~]|N>uiXUw3@=qzq>ؠ{6&'3_lJU$VJ+k_Nl+;# {sW}q#T;h(fN௪n=@xΥhn|^HqYup+D6DבpR [MD:_8 o_.=\C+8.w3O8{}Yki*ws*˿2}X_3s_L=s^yf+CLU2NNu'KURolQqu,^[y*g2^1^;OP2RV's90Kj|=6y8W+NE4U蚢A;OQxb߼ܪdrOs.bFrћjb4ZC4j߹({|BXX} eFq'1Y'3}0sSv+KX;Vܽ:S8E3M9'}:r|O[[vrY۰Eϯݭgssf.rIsIp8}Fg+ʙDу\Fnvv9ߦNn̟C/ВQ,ni?Fwu8w7F$^R1zSA5OHknK"LwIMpSEŘwwƹ"Ph+;@]z"J*p Hzbr/*9T"o<co.eV5J:E̝a: Y;/Le4eK`h=}gR4w;-1w.-sg+hY_aB˨Ê"gϮlڻ붪yt:0>XĠoO]򽿉&՘ocߚBu: C x.*]zi턐N]`v]M,}qD_]'=ٍr=.0h}~%|BVBQΦa:Q"T!b L}S\kY IV*6cH'5`/<^YeZԌYr1ĺ/uYztJ_*~6Ca[RP/k0/3KL<^Ð OXjSu17}c%<ϷV]tj2|k zr=nRݗbϝݨSyRw%f]!WL|#TF]WJ]uJDTvրs"y ]`n`gk+ץwLZ5(PmFP]=]lgtv`~c'ƿU]r\LM0-m6TQ5O\fZfo}'m̺CzOiNH%#훘;emmlu"Wvgep#MlfcGB>񓻱W+kN | w:tϽ:v}FW~^8/Jʭq[M 3|'c wb'O3mc;5xşgg$^r{5C`غ`oU Wϯ7l{ĺob:p59A՝x^G̼'tSkn.{)aC4[*+[ O] TĆs{5{<#WSгw@$N~ŒvԝBu^L~u#a~_{ugIb &$jٹ+yc-<^Vopa <8߸ܗq'C=Nd'IaUX7b=m{~ׯl}g/#ߛ[i05- :f! b#Cay ~(]<'5&|ez|R12I2&*5N1/e owI Nbc?=|yy'o]NgG6 bƝ<^)?`{ϙ`e _Zt Cv$7uȻgZpv>eYz4o2[o5Aٓ j :[$9A$4FV9^@}8hЗm^@LƹLw6OڿߥNWhq{eI(a6sOo%ߨU: GS$tmmp¤ePv5W^WeNI^ne9WcLj ފ+ls2+ۙX*bиq@vvwP6 tx:u6wAdQwz9SNNJlw bgbRGgS#LMTDg##2?x{D+7VFT?qD 'b\Ϡ2">KIf#Fl*z(.*vFqBPy™슲 =j j =oE+3"üKN{2 Œ\N8EaW$UG? ڵppb51Iv?ٵ@06-:[~c¯ummu?OUnTd/V’U$k+ c`kK.{?|nܿM4g(}qCQH)guEalZŦ.96(Zז\vIsPԭjƃu)i3(M]Qg"ҺpslP-i:7Uv+Gvi${WJPtEqlZn[Bf&ů׶\RwuޡT>uEMH%g0+]NE{ז\vIe(U9f jn٪5a-ʝDƯ@JPHQA৺&͠ϡw>/FU-Eq*G`Q!G~Wź0cH\K96(ǐ!]=~{L(tā-bQIBw ]SK .`rڔ.~|ӧ`4既l?rXWTZ8ĩJ{kK.{ĻB<.Bygg#Jar pԿdr%2={4',¾8!)%g2uEalZ'e]$ؠR#]=~j%;H@,%.3/|S;#D.(_Wɰ͝ty[}iR\!∑gZk>mZ7˨'l+&űymiuO_>cO9] + * Ew#"uEͱkKoje[SUh~1/+fcx5u .r잛:_rEߧ5чӐWBy\Py+c⠯u+R=6)^\RϕM]#wRǹ/\X1-q2ĎRq;NymetO~ USD( =nCk-FyUWZyjxymeu?~A Vth}ۏ6!$М*4@&M;Ko;0x?'m2UprUHO Q!oU8(N]Tiؠ7ڒ.~>,>՘~pu 3cPgRދ܇,+93.9hɓGO!]=~yz;Ga𯚱bT3MvaV0ܡg"&;J=>yoפvįއoƍ"cNB1!V"l%ákLźCY:5.kK.{vIm)'j/#-`RlFj>:YKdżBǔӺ%cz}metO~nk=S8@H |>v!guEs ]VMʁmu?~fֶ.pbɂZ;.-).{ڱtVhlQv!=~NNff3b.$2uFXjM7IqkkK.aX;U$|6ξ#)n+g2K74 4gQGx'ڒ.vEu1-ʹXGR^$C΃$GmX<6 1reiJ]Sp֘_ ]iPԓ78R:3{$Q :aZ|6kR*kwvI-xk1ísmIyH=xu ˱A}U9Ko?QDS×sؘ"#R+)c1csJ9OXצvQ(w WGayg:GκP늺;IPR9=-i`|=ѝ;46}{jU~qv%څRTg%9Vˮ{9vKc,DJ,ؤk^rY*ϵލ}ypYl2o` ,){b+yInaΓ.AkK.{f"n $*bQ$_=9aHJWTK#9d-nyږR~6>{?'} Cb*8)~<н+e9̿.Y%sP}metO_>ׅx-iNE-oPQChM >o#'Gז\vIaߙ/zćyQeUw&P)Ǝ$ ה /NxWmᖧVNڽ9jSWTnsQQ]TslRV]etOaV98'48֌TpycS0*]Q5rA{F αI׼Ko% )9\Ml'e5O*9kj2g0-㧑`]rE_>׎ qd\:/IP(A1bkj$69߰.{{lRmo+j"%jO=Wq.h,Կz !խTT[oe]ז\vI Wdv BԠ3wC #qu0!!Q_SRZ#ַRij:8{%'xD2,Wyb)R?r?r%( J9fgNLAr|b#)~tHJ9RWTϭ9[N]yc6嶋v{譂Y]0ĉ7MIO2A>&1>0* >RZ#֗r,U-92xTx$K^j(au~K>J_rEαtv%y+4e1XwAWT:ؚtc]5o< }5b(ā);zAXTDJ]sQ^[r%h"?'" OXHl1 hU)p+9{3/9{%]=~Q΄|_gLR܇tSWp!rr:ޤAݲז\vI)) }#5֖qPw3?:44\AKhpST~+9!3@kplR<%-]%gw蘆Rȟrt!قMMI|>hZSA _Mʁ~etOM0B4WcC4WwXyi]Qũy.#e]Bxb׶vYvt1 SFElb̕:+& ]R -P|f]3z͘ԍY.~=Iq eb#]QF֩;鱧{%]=~]-0$2\3Z ֺF=H䲫;- l).a=>IIqfѪ=tE<39KOc<%]=~{jr8g).$G0l*=&-':uMalZũs d][rE~* YmabX~3-)Sĺjg.4E+{&ږg;tO߮ g=HjGOfb?ru:(ݓnk[.{~u69qX`T1 ئ|٥Һ89Ⱥ<6G.K{{]>3A3 "G&KŹ؏|M86-[c -=~;3~a2!#h{&8OARB?HOĝl %镣g5'FzC1;Sa{1e8¶⨏$sHͱ`_[r%]H{+AuQ dzrX[WTJXgAՋR^[r%KjT.#\(`9+XHSm2kjf9A^vPx䲋vPS)8sZR#XM]S3̘պ;kK.aۭ іG8\uCG‡(_# $Khז\vQgr8oPl8}JRkwxݤkQ9QNdzlR׶vYmHBBA㉟f#J*QEfKErnlI--]7Khp'k,$Ź▷tML7 /!npkK.a_3oR\N*G~κ5‘u'@<ז\vQ!a$"iLTB\DӒ]!9RWԕ2 f%IeLֵ%]=~\%#\Ix_oߦ[7+\:9U".~gڒ.v-L0EֻHM{@ȸ޽&QI𧸦FzoK9+fqnl/TXW%USw)}cMX^O7|UڱɊýY&6!%R W sKєz$Vn|@B"u]ꝶ_E'$-{^M+*YT|$3[ȇ-iD4qrO 1KΟxe!9_sDD2qE.Vs&%]|R6Iݹ344 tq_FeuEbK&[=|rז|h./x3??LI\pvugoFJipvvaL wעKVq-Ll7#yi*9ć9F^Ywk[.K{vniJ*sX ɬ}}ƳGTR3`hG=׶vYeGNjgř%F7 b 6:[w+'be2ǒBF]ɥkJ*wctA~0!$&onS{ek@fz0!u{k]rEbəXstƦU}R/`7Sa@.r8צvQ)k8-QV~lʥL7=)GeO]S} @Y4EcG%]sGz#CȂtr3jrxSWTϤQsf]%]=~\;O {5 b\2,+Z7SY8-݂d_rE_vQuoԌŴh'E MW*]߬ue$Üg.]tX02 fOYt@ oV'l}- .R˃O_("ΓF0~V.;%]m$;L(q^'u:N 4p3&]Sy{ineqƮOq-o?QmY0Ԡ(1eNn-Vۺ/Na(c3kά~^r%lf &4JwƀFR]BoY jrqۉ+3ז\vIY^XꆡaIDyb ڼē=HiX- |v{lQ5rؕ3e:WthT{]X5.&Y l9v˺_[r%;OuLNu t _zLy͙mqfؤVjet?~!^ab 0Fc:9XRWTf{%ҽ-]=kk6C|ٛ[="rb ipAr1YWTvK~ˣ_]7ז\vIS?kqp޸,4e >PsC*隺3,r;voz9w<|*N݄Ń rYWs!Dݲ痯mis$ay-9g8KơRH<3-uM͹]xxxؤ|F5#]OߣTBvrC GY(ZUQvkKv:?Λ/əhȶQ:l$c"lfS5\J_αڒ.v}3WDw{ 7:!B{O5{G݉FMs:Kﱂ&O7rmNdmсX#D|G>P@a]QYɹнUJ׶vY}-OyJNgC<8T'=c>]uEϕMֽSy+}._r%Owf0TY(gCuMݙun'I=3צvQ{$Q_krn. ţXM9+(sfw̥Z;^+0K1h sFRS O86-M'pؤk^|5rabA&b4A3>Q#old@]S%;Y49;צv{i:*6t $ȑx2.)g,ݺnԝx X+:}>M9j&'vU'9n_cǚז\vI= dˉ%9ÃA|覲5lMj]RTҽOI׼To]\Dt~E__`,E }91+9,9XFci욆׿7HNCe *^O> :uE[oNC2u#LslR.v\R/+) ̸8K1.t5Of06̥g. [ux kR*kw"6_s|gZYǝ)|F+*krKoHN|0qF7gAR*CGJ$2)u4H|_[r% 5pӫ9{<5۔?9zZTsxs* [XWb^rE.D넶99gy{@yIXB!(5sY(}=r}9x*O_[r%2.yj#`4ʓG@ڈ_֭>)Iql][r%6 ؛|WRLj-MnJWfr-J+C nZ:WR (yBWSlc,G%]=~9!b}s\I*7=9S^ TyvVhڒ_?~[ |7uŜ:JyVR\3$7f9Ж|ů[]-a,FLΠ)נ7zcӻ5X!߄V[a̺(6̱1-iu99<:z_Ie\/[WLԍwM-]~h 4XE!Ӎ&Hy$0<7V+28N%Ɠ~0|metO߮098tbvI>8)IW&Cx$NnΤBv.vmx= ?Qoq~E3 {UY:E5ۯ/ãOqMKi[bXŹw^':3%͛@޺^Ppvi/kK.{6 gwΒw1[6t'm-EݔHOW2$Gz5Ju<-!xMIi[R2xsrw@edLBR+*k.UZcvr%z3-AV>vC?; 15䠐0uk5v %]=~߹:%[yzVkRS"睺J9@oz입˺o+=aƤȆL{,#1|ThF'80Gm=kJJkw6 xC.zYG5 ;)CuۥHS-Ǟv)ڒˮˇA1KŞ?Kp$&Xyz$T PoaQWB뚖Edi\xq.#l_n {b2jp1c+*Y3Y#{+ڒ.vlKh՞V~3*?nQSM#,}TC%grX `j좖Tζ\v5 =v]E'f8rZEiG^sUFR^F{D.OqoMkIחb ]=~j^v2-›ANBQi)z$o3+}6Hi[.8F}6m"U/NIyq|tls.=kl}metO7X$f K^lI_"(&ڣ{vI-n7h{&~G6.ՌxK[cgc^[r%))5= ؙ͙rRSr"[WTDs!_[ kڔ.~ലKO 9HXw)M [U3kNA Vm;E&_ږ.v?J2{W%gWp/|1^֓+5SVfM-]}JQ9BR<4>MDӱT[nq߶zeS?~\G1ũ}fD4b$j^ `銚 aR,9v%/ϕnzڋN}8 xWl hdtO=r}%]=~n) >X\\1露b6S )uE38 IٽI8&z$Ӝl+_ Š74OqMKi[.d(i(h{YB|ZyM^$ gGnTk[N{>yN99 O,$P};])z`=A]뎋iC.~ent599+ɬzLRVNu%(tEeLgg -i[@_Qr|jE ᮋq`IuMuOGP"N<ҼK//,vsZ3PŲ.K]E*wB5tegc֞46 &}@A MuxXѝ(uE=9/uRc?iKtq4=-03%hfRy}1뤮!FsFvzb)]m7 D±}s*ޛq)}/`sRQ+uR86-X cymm)u?~ʞJ:?VD½)v;pӭ+*;l%'jEآk~Œ.~FsrZmq] ]2VR~RSW Xsؤk^re8[AC9<YRy(w1f62xڒ 3f0tP4^aO{ZYmab1-Q뚒FG+??1tpHzX S:ܩa=yD/ZUD״r[>m};V 7c&3J9n'EOxfLA<6)׶\vImj `ytcb@؜G6MI>YT&s*9Kymeu?~UQ턢q2B{,E]H4fTHהH[mpQq 9WnN$MfSz19z$8*~*`WFOyMIqCWc䠝uP𗑁+T4;;z#o.C5S-]&{kSna{"Fyк$-")i(]QSgs1FΏǞ>tkK.{>` [u' I<"<ֺ"bK!^9{IT$p+Mݺ]Urt)-/<}3pr6(~es"Ґv7oY;mFEqp=jqҷY\mYfmu9x4ӈ7dDiI Q#g\ں֓m/XN#5&}mmu?~(;#Ļs0:t@٘AɎOyNR YODqc B4H]SRZ#ַދ]%b /zRN%`].Sp+kr.~Q ywا-&I Q1D ɸ gڝWc/|{$0*))iv7|CR&w_'BuE=l%u:Prږ.v|T3[2 *֑vpIণP !Ȕ3(~ e#L]SRYCַ!MEOퟃrn};*7A%'j)_'j'I5ه\i˵rK3۶ SIeunţjL udWMIi:J9ɹCzs=pzGgIRꊚ>J P޺3vwNF^[r%wr Pb:&tJzD\=!|؉@5)5;m}V6d~U*INY9zbǔʪ׳I>&ͺ~CX#VilRr%,ӝ~'K3u~~Il8RU^q9Œ_dQ&zoJDo U+4Rx[52 kR; ڔ.~҃š~898Hhs3v"kG<xNh`鱭F}.蚔ꝶUU,gآUGR"3l]Qw>xs&;x^G>x_r5z,بf  ^@jj- b FzhԒݑuMIiN[I@A(nNCshQqѓeɩKc⠸ź7QrlRy6,i[]fΠ@XgR 9WrJWLsV;3vE6kc犖HWV_hTA(?zʞLr*[xskK.{Y4 orG>2;zx5]XngaykK.{>$pwrZia`+ʉo.^BTd.0sUkK.{,/3!+:9/3\iǩ+jyI΅,ؤk^r%!xp99X*Q(k$壮8R+*9c3˺C *x{qB$ɉ g*3Q=Q}HDTהT@S\WrD>@EsI-Iym+j:M.rltmetOjǙWӕͷĩ(26S 7fx7s(a]Q%[%RFs-Mu=ToqtZ =hb@ pEއ~? nuE%rvroKT]ז\vIEz](!s9"N_݇ϗ+sPl%ڔ.~rImȂ+=Xq@܇ ,~$J5fz8&zo?Q~.DéDzB9uMg*NN!"M cݑea%A}V_D0[%9v? ˬ*p Ow8/:AY!OJͮnjNaFК~l?(ؒd] }xgْPħs0A%7{{I-IZ#%yZ=7Z:\o bKҙib`dnp ->db ^]s.[Z[4L[L1yz5TbWe_~oi]Fخ\ޕɒUzeYs" iү bok,i;< k;5Ν̹e_}NZy]~A Dh]>h;՗ 4(I,ur[v%9y`g}A d1 IUL`rc%e!Sj!󬱳)]~ }vlڙ5b9TOcJZU0XfUy캪5džRJȽBNVtƺ:8i'󥱒 /5²*8~ }ϮeE7'3% 3,gOd (N&"csN>%7bQ S_ DÈpd[ǒEUQXI)H\&EU̲)>h^r5;@FbPPVGUF|iG`b%e\3l[3; ܲ/awO_Ln-! dJv#aD$nHo${c-dOS]s.{%Ld*M 5(rdLN*eAoѴ,VRVXSDIl&ǦĿܶ/cw ADk*.#͂וg)Il .f-$.ؔלvy*ʨU{9>sXEN׋14_3VRFSsX{/ɹe_~3ǣK֕ А6yZ[xF K_эT&h}.CVd~),gͰ5䀾p_0gw@m#XI+R K]3ys.>JQVRZOT54$xwwQX}(l |ٷ 9F# zBk^3EFgdV_9>iG&Yb%BknmxzlJkmvtv3i=u贉6؈3 bNZLn RQFJ[e{mFp/3baK o55MQp`bc%etFmX;bmêqZ~RpnQ)ORVz#Ȉ3 !5ɰMIA6=:+igXLPa+&Mb+K'õR Ÿ Lʮ {܏ S73c62`u]kΆ}KXK33VyJ{;Ǧąsn'/OOsGzXs!H% &iԔx:|qS {ZH @[ѝcCؚ[v%iƈ453,:I)qqC\v#DH61XcEe_=5YH(X76wOiη(X.gݓ8s˞-k}2qm Ib3nD_J|7;Jm y "~zlID_]~ }Nt$ Gh #ʦ&SbL/^i@kcۚVrvxlJs.O>}^/Fc RÛ <=FT=%?Sfj./y*J Kn\"3oJ~ b;u+;ϺƮ]e_~iP(Ϻ4#M7[ 'ݧ'%9\[v%ZbkT}?]DC;)i5mTWY"4M61slI i= ~Akfh&)m1xۣuXK}u|MN`]{ܲ/awϏAWP߼&) eW)7'Vb]\i Ջ-Ǧ#k]v{JߧBg5p4 <2I 1^;JΉ|)񳿘,ef`/7`}7{e_~WEzOoQ}A-bEr$꥔egڑl>biӮܲ/aw3X*שq i^~&brSߓW$NƲ]&RT#kV]9.}z-xx>]/,fz[f<7Oϯ+=>Js]H=Χq@J~Xh얙vy*|]9d[SI|l;tXݓ(sn>'שdr;jFsfg+O^aᅷ NлYr:LM`=,'fkS7C9k]~ }#?G,AU[$$q~ GilZfL UVW]97uRY`f! |6NB3XcnF*9Vz#i䢰Nό k@iFB'%Fߍ q6VRό k d]2s.>= !5}z^rn^ܫFi7u8 OJ+W&n+ p?>$jj0r?.YXCOJ`ff`YkJk]ʏLti':.^İ=T36, gYv&vRSY{<@.O> he4;rbqR#K;kiHS4{+ ܲ/a1`7 O{!<iU_:Gam(Q)8%-+n/*EIMN;u[ct(JOjXtɱ P-vV ۃԷϮ 3)>AlN 2MMݜŘs.>|D yhk@$w8wDp¥}4ǚ$xaz5v˻@-v4zDm)HAlZ] _M;n +~ D 6VޚcS_sn嗰߇-#d~62#h)/S{nZw8 y%ۣ w&URrNYp87 #{[+pv H|`.!rZq2Bu)W@`T Si+ngT=Y{'@[ ȳNkO45q2m?'OZ_=I!nV#4uj^6oq( #HZJv WNv-m"Sq?|EgMFlgXI#c֐؆oc{n嗰ߧ/XtZe*`i R`؋.dmm)%wMԠ]bUs.>|Due Ϧb2uvǓ?ɄIBe'!@q"397zS Y-5[73%|JĎ Kk)nS,걻[v%W,6T1`Ōmw}qqJ!|a7)IHR+t#yMVyCZ? ưګmt=hh+n0ϳM%W6| s QcW/J<.t>r.ɀ֐ZsCcq&n^Aa-G=H!{㔜XJ3KSBy?*ǦĿܶSawy2k^/U):6=,57m ؔלvuy}$NiENYG^x<\fd1R75ȩJlBkyn?~>w9LɣX#q{js%S| iڙ0E؛.sӞ.>JbÓ֩}qS܃.c`,N 5*G9KSynk^i~ԗx?dAI\1=M;j4O̓Qan<6%5]~ }^^?oM͍'3ŵSj5%}tMcG-v?PvBEd*sqXZȁo;)vRA IJӁǾ]~ }oM o 5n sfVkjXykM"àmxY9 (JЕ݀ebJa6tפR&!gE5]~ }^HNQT O%BBڑ`1k&_QN46%]~ :I֠oA+lRPJ2m_\$+reiJ ؋s.>/|UϜ>&77({w (䕵]OeMBs.>' '7YýO<[ׁ?ތM(Gةa=׾Is.DKAp;4ّhK!Qg/$yH7VR\RBE {d]~ }Nd2[-"×HD(D]fgSbI\qmaMb{a-NB֠db`5v"X-vbީ9Xҏ=vK^/{g ZXJ,b;8[vE煪"5xj% -Jܳ6=,M}a%]I k nzM==7ωIaMCxCI1<̬)q D OːXI5am~VwGmv{t?DzW73q22XRw\#)I/RIJc'EM"sn)5R.RܦK)) Tǃ\{.|7;OFʽwS|/>ʭYAsac!ׂcuY#[}qW5vVyC%M3 w$ hkx~XI=ySpa;i4vOkm<v4qx*th`lxF*$e kiZSq2 䱫&9)T>*&=yjH'(kk")k. Y<97?57MqlJy5ّXI׺ȓbvWjn?~(|{G*N܊'|2/6Җ|$܎?Z=FE=s*o}RRF^"83k1x evr+i#Z3H< , sEe_~SȄR&5̐x-\Mɫd%LҤMev(\s.>mO--_ۓIZM&#zXKJ~eT&R掤'q%mś5wJ$t#! }?X;hl4@ɧ{$)k^mߤ<~ı5kz(@A<9DKuHrD6\XIOfYs9 4slJHܶ/awO#R7jԤԌ$_uJeB%>XۃM$fC+]J#RvyJ߇+\{O)kA yG ?%|~iݠI!xl4\v\NzX]-f]~L8gTH,<0e^e읅"J*?k cSPYv%ߧhb_ߔh1#^}O$['Jd".ud攕zzvj+ҟMuH'6`6v-Y=KSwT5A34E}C& 67K(E7Rɼ[s)UR#<vtI҈ekӅ)ؑH&^)q$ "zTw=LpuO]~ }U '`Ve' >jM[_JIE)Xrd̹e_}  {&tƴ`丹DR縴^+)RSq),Å{^cgثudph܆_dwh>ٳ^ RŒ(ո52AMR%FhL;^45ycle_~uL/ ~>f.v/NW3ӗXK=Y=i@QcWsn?~-afMg' 4QVRq3hdY{H[+;JafMqrżؔ.ߧ+Zkq%.:kfU:\m\?5v[]~ }W4Mjw1zw >}0wWXIӿ<&P MVS{}]~ }&\d욗oDtYBv\nx]-Ʃb:7]ss8[٘-*YoJyrYvFW {kn嗰kP|'dp|=Napעzhc_ܲ/awO RcbB# =%G'۸,,ؗisn嗰ߧa6TQAu▬=k_&JؙƦyu&6KMѩwSawkY *cA1xӨ=F󢨋ٸeE]t("RؓBvv0VRa>5=τ-y*]~ }m*74 ԑg`.$R k cb">/{es'zn?~~#,Yyp|RNv|au>Fӝ,۝XKWYQ^ =[vEce7rr+M>%ngJʖ@b&cgK[v%:6Xp"YB~y6ir~ڑ.?8YsBao< >`pwF_@dqT%uXvqN$Ϳ,΋IRie_~~Qs).6Al|巭7NpאQ[6Мv_C]EvѕFQ,7-!)8AXKcmtج۸mmt5_D; ܣxER_&>m[i'q%8GM1 Ӝ[UȾ-/)YSbfW~ғL%yܗc?ܶSawϾʛѱ{+P~FDt [[d˅V880zVyC x]heb87wJxE|FYNXK- 1$cJMjֽ>*+S#Vz#(/{YSP ϕp5TSVz#Wy^U^lUن= F ۬)s-g;c7شY(snpD|/ lJ3$t7pP(7NBQbGz.;}=]+{"hyʴW<:&mZ2K7=Kl-و?Kq!Q̅,h^܁ɊQzC1$\ײ=v_OJKL$BAGH[')WJzRJ6%ǦĿܶ/awJvUYMj׬|-'Adž ,d*QEVy܏3BM+g fCJși JL{"7^IvE߇;BHWE)I$G]t^hBA;RGqfn``R)!n4Av+iۘxF=:Z~*7;a%k*5/`c=NT=%I엿,k=a [i,[v%ZCan >/\!4pŖup[AbKQs*o}==W-[|7೦WJccX9h޹ +d>i.w^Z 9[v%߇_%8";TZqŶ**lL`]VIН7`E_q(0Vi^&[G Q[ә/ǣ ⤔q@c5VR^T]-8xb[v%WǸgl d> %N%}q$},}-FpQ2sBaoП%u>'sUOJȠx*I,M <t;KDsn?~F&ʊ-.&G.(x 'q> 0QUI!n\Hր+7&ݎg~K<[s9þ1X%%%Ty~G{P~"{7;^Zh"MihT LBP U6,l/bar\MIV}#O:պ@a[`;)q5v_[v% x4k^?',`73NBQK]c\GnFD9e7`nSB੎gIqҶّXItm\dYRxnv%ZY Uw+&50 JO rHmmqy!ޭI˸GgP~|=}9>詴Wu~$2' O%6>cS_sn闱߇/X? { d &+cX#Bk"p0N|i4'i p?>+ou; c/ 96%5]~ }U^/ VJYXukL+p4u+ȗѨ%i4dd K4q)LY$@΃CA;nfplJ^f_~`AS%Z1& ’^_qoU m"4*mvg* p?QAv:M"g>svtij_u`#dJRLti9{96%ߣe_}ukyA*nc+`ee(8 Mb8=jF<'_O+yKȒϦx]$znu-ܝ~XJ@15,}Jؔ|27<v쫜w=;X+rn7JfdTIZ ㎸hFY<*)电**pў⯿v5ϱ{RʈfgIwY##9ſㄐ1P8]h+[́DAq8B@pqOW<*cNYqm_Ҹh 7tu&?H7R ajؔ߭] }T2z*6A]O g0"K ףRг>S!o}=\d镬2&X ɯR6ioΊEw`I%YW%I4M4K=qDܴb^,=~DmPz*&N`1Vzp9i7Sݲ(_-!8ojJSTdJvTe5Pa֧ؔVrn?~>7-c„a3yD?U"QTl)]/?GeuUzz/ ԼL$~-N$)rK{+,)+Ss3N,<6 mv%Sɷ{?\i uNR\qxRS.+' 4.vgGe7>ԨГ,KEoJFH`HOMl{$o]~ },P%h3rKՕVgY'aˊ'uѨ*o}=et3cevATEh/t)ɹXf';މS3Xj|D*kz-vAgS"7sa$[ po@/g.!k z*e7M]o !Qa\ӅUB Rʄ~qK&۱\,V)`{yn嗰߇O%($z̈́+ _6Xvӑp2! $yoڼP~|=M-CO ڝwڅG=٤ǽݖa->n^c]~ W9ȧҊ\oq -Bs&+ M|Q)h35Raoe`a ZÞEL5}f biG4`P%tBX gB`e]H'G$3o[NBVc-=gԠ'vי]~#ʌHj 9 U-%>FPYaۛԐ;Xrx}{-v{}ѹx6QPh94 L |nI{c@S-њca{-SCaq:;w֐o[@(ˎJsWk ʼnŊcgQM"o$+BȟMb{--V:g?Ykd U[4Pʫ#m!SӇ}k*vPzS7AQlXIunM}MlemƦ~Y]Z?q^$G>| ޲RqgYiqs*O/ƑARc4Jo}=*`ZDے4 ‡'ʴ=XI՗)d 40s.>%lXT|LM'q<SJxy^/Ĵkșt&Icdܲ/awCHc5I+^Y`Yʔ2c.;"6c;c$4 W6\Q{lJ1Җ~}ccH2WBsicu2w8 I+p?+܍JᏯ {CW f5}~/%,1񂘸,1ҕˬA=bٗc zn?~>Wf΁֠ouec7NnDž4|I R%_]~ }"ځ ff5b ̾|R=Fb-=l *{2\-vp}Ӓ& 4( -"q fϣ&;U*P۾&Gݍ8lj猔2ܳYl7,,9v-@>xŧT !SϾ[,0Ί[c_⚃1Ԝa9z?Y8t[&|{~I^ Jzy#5}tBV jqM}O>%!|yn+o +1{[ I!n'C?#ñeNȅDHyJ "B6%YݞYEn9]D|\+l[n]^*Wy6BNѭgsocI7 JIf;ӌ /; eeH-v8f["=nƒr M 8'cE׆qI!n4f"nZE%5$ x/66p"|vd$VRre`’fcSܲ/~l 7N ɫ* HVI)%UccR/|xG[v%vpf5#|1.P^)q)D;OІ+if5d;G{n嗰\Uy}+ى&'k &+܄PrdDV%q4Ҩ𧜓 ܏4 Aj.,IWܗWϲYXK#y٬8e۰-<7(L*3DqL$d$QJJYich[(55tKOς[}v }ܐ+}[Vҳ_u}n.]~ }V.mG~6"TO-虛8 D8"5 zjNYp緞Sk[ϩu1S^3|6;R+))RkEuq8*T +<ШtS r۱4շcȣl),Sq)nǨihwkl{|;6SYK7C(@/r*$I aP|Aw/TRSVz#y@(VPV@gቝ bЕ|ZjI$kMׇB1K\d1OsyZ/#cW+k E3_NtX xT zTv_Vk򭓚{3 xE$J<# _)Ռ Xû/bc '?ޙV9%i6|ƱkKubAIJ}7S*R0h$56%5]~ }z5g*$IMEyua N6VRi%6FM(c嗰?~>>W+2gY/$ '; t4ƉӣVg~yNZ qeEW[әyq8M9%uٟbZjY1oMY896?fL~>}{I2oo] ]M:SЪYRA,<+(Ҩ%4ӯťp&J2Q0&$NXIs%J8Q6Aؔ(m嗰ߧi_.Q'xunF 6#l3c{5&9vܲ/awOs ::*v?l zڔχ*;Ikix{΢Xacw9wOs&gL5/~wqB$f=#xyvZcϼ5ܲ/b>_E#.2FT&>Wg#0Ja̯+s.8W(O]x='76oȝnMee$dwLCSGJPP_VyCyO])R¹{JR830vki1[3S R#%){J-OCR5xM$Ν>s-&zD|DosLGs.>Hֻ5d^A -_=Ւ?757fѲrNRi치4K, Gk ɞlsǻ}1ao|j}$yx*wJ[d)?~U] pzWx$u V\Ga& uRbN[pg_e+h#7 4Q%=#(ֿ>WH{86Z!;#Þ[v{Jz6]U0w!1%VRsJyslJk-"K"w^^ Dg . )U\;cYXK-slN/l. i_}E=c}Ywt$:Q$ ef8z InRSը#ϰS֢5G#nD` n ՓX-z0Rͻci"'<6%>vEߧDSypv \8Ad4<OǨlv9}ͪdFtk1FcOܶSawO7)F;?(ʍ}WAW8*֔t~U&k4 0Ǯe_} grT fi^(upf]L8*洕zUFSlTB%S#$՘1#Zsc-=qK *9d [vEߧ(+៞-;0Qc-9[{gΆ*=z\is.>袁[ԟK]ioKf7?m\FJa7o,&5S=K ?C ܜs W^t&dQX\&R44 UzxY7F.!5{q(55E6 3cHDXJϛ Y6R>] }}x3fЩ>LxM9YkN5Vp3X= 1zn嗰ߧ+"Ԧ5k@Dپh՘x@G&&ޙ 4Ԡ' 2~e_};z@\Qf5a{#$v0wGwjk)5(10j)qwĹm_};hw!5 MD_~S,p;z7ŧ[XI}݁JoXj=:zNKu 8)"- 3xzJ|N c)ql4Hl4{>6s.O>]R:7#)֑,$6-0ʃ࣭@GafNnhh;84F% }_|L֐S R\SECkki1YC0a;@=6%͹m_~zߌ S3yDU}WHXݑŽJ |[sW֧ҟ3PuQc'gM"G4U^0y57UhFRδ,{mOb-]IgGOwܶ/awOcHԼfFIx7nN,sBZ Eg%7sNؔ86]~ }x+;5 DnB=1qtwݏRਘVxcWw7n<6<(z#tx[M+ҎE-86Z@/1rlJk-=%}ÍRsK\ aeXK&5 c+zMC=Ϣ#}v 'F'Ó=| o +) R|xK[v%#WyGRu`tV4ˊqJi+1n4Q#y4W=eMɷ}qXI*O`3;snpi- ܁k@~Q0A4ؘXIլ9)Xsƀ$M͹m/bl}%znA[; _kD7 'PXI65VDRkEt>qǿ"M?7+e-mlCݲ] }J&T <+ߥALtmp%d)iؙ甕zEH zϊ26%RsM۹̀^{m;"ӃobM i,㼛r6aIh< 7QQ);S׷5<`Q{#(MONݑ10a%3kYeΜvE)pDu{H6Fo]?S&3lg\XIRmEϏ;s.> ij=iMP|2wn3w,su Kc󯥙 6H-ǦĿܶSawކըx;$M$r p .Ғ#ꛝJJi^N@#YFmO.~ đX&_Rw)c/"Z I~Tc1Kؔrn闰?~s8)ʊE5׸.uWT؊~IQΣY]ҨVz#ib=C᳹45I]QmΠ:%.r\=;/k0&ؔל[vEߧOBvM^WiОd꾖TN ) ARCb^ł2OJ>]+9$~7Fz|o[f_~W}Mjp=醡onGJ5흤Z&6A7V~;ܲ/b>}6|6pjB2kXZMGDӎsb%yfjlcܲ/awSդCwa(}Ml(*;+$5dHn.̹e_~>/M:$59f +6{ǞXIIҖ4M,I^ X%}W-dٳ&Y5pY甕zN}]ӑ>Yf%A@I9mȣ0VRK }>ؔלv%yuXW-oDa RiғMkT^#yF]WҾY\-@`MOm@l#fy3';T4=ƒco,+vey>bgאO1[0^xWJz}SXI{0"K8 9KEg ݝIQ|7%OЄa-uGISSj6 c,ܲ/awOcHA{{Xќ<P N:wQ6[`EΛq/ sq욥Q)O1FipD̓)4$jx>b7A ҟ#+ki!iWSؒ|0-]~)/8,NV<$lf'4Rȃ:pܒV[G!@q5+=FӃi! ֦Ϯi.2\ȮSRb c%[sLsN>Sƣ5txxמ}.?a%qlx!):;YRؒ5%~lV${lJNh]~ }zNR4D,R`f\mHCzKSy,lߔ|Z~)9#W}fjcRյW]o<[RDi5 ،̱)9iu!ⴰɠv/eJخSB}Bfr_@,טvy:sOQg[Ng =ؼ\)eT}3XI=ִ +hc]3!sMe {`ˊϦ@ 'ڌ:lz%IX-9{ҨOF40{Bj.E\H؉"$_3VRU$~ nYe_~zSGHk@IaKIhm /"fUN ;}~rLS3Ɲ8Eَcb%͌ ZCʌkG&>};X3~yC*GIN'zeo"R&O͍@oׯܴ/b>]OkpM#itߘ}^Д$LR`ff{jl\ũcKmv%zpOOj .D`_BE7"XJmF4Ķ|Szl]?~Q+ (fӜLzi5-SjbWu]ٿ\ &;G{n?~" !蕜#HX ƿ1睍ep_3VIosJo}=="mHe-GҌ$'Z^[wh󻪆Hdg肅#*ÆZqVfܽwUfFFx=>|aSjoA41Fj̱)ʹI bvOS6kkSC7o֫݊x!}و0Mnňu8~8js˩m߬= bb"^gƋxLly3q^^;S9j󘠱~"]~ _S~ޔ7[s%9\q*3$%3fG5CvBPc'm-v{Hl \ώ i[c!|7I(>H1))-iԷ攕z^D6M:NiьgAThc6RkinZ cS_sn婰߇_%ɧh>^y wc@+@M\JD3Vv_O./Sf|=VLTͧ=XKyp;zivEg_%mXq6՘zYOS_nʺp@ qs*o}=qkdš5ܻ&h?nS ni[XK8g c'{\-"çw5-bs+ m7eu򪼏b5 4 Ae2RUS hkc ){Dڱ»N`JӒ5~1v*Lcle_~zkkS\K[LI#|?XX<88 ]V\8<s*ot[2ckPן#C'9̷DUa qyc-vx57bJ(Z 5qj +2TL!'z|UtѨ5iNYM&tDP5 \ W"WKVXmB$"4AĢr'Ǯ~rn嗰g_%ߎ-ZLK^ s\$I}f_~SVyCy:Wր[ ⟅Wf\mFAJ\Pv\kiէ5+of~S9@aW{<[[ T>pV FNf] q o;?BE|~t 8igO?a-]L 9mgM"Wqb>hDZ|YÆvvH̔pv>j5lhg,y]~ }듈= >Νи/~/oO-?$RsԠqbKr=-"ǛM'Ѯ_ U@ vHA;@ Kڹ t1cSQ{MjN( p2a3rџ-`>lS)ץ»XJ=yR֍v6kؔלvy*WoߟP 61B_G\;Hq+B;5=jv>|= 龒њ}qj˒evFt%5aa{$]~ }23_kS 1+!y~"deۖQ)O9Fӧ%aȸgx7Dqkg'c-5PRS['jש}Ts}TWM1aQm/KУvƈporhqMo\GvU8/BlbezO# AQvkil cJ= =OpA:4 uZܗjbl}I :.q뭽㜲=v_O(nkVؚdJNɇgv0Z&V̭5%9vϭ]~ }|@cڗ־xpg+i=$#dkd=f5v&[^)h/cw_zJ*Ǹo 8;U9졶2G8=&׵hcgJA@*}=oMXؾ [t 4;F)nM_ŗ7_JJ.-kmZʅRs\ZveS Fw娆Y ^l >ƁRs ?Bb(Y9jCo4K!#:S#,".Lϗ8h~뗖XK|N${v%a1⹼ó#.ƀ}~2\[_+ 0 ~X='A$sԭy̢f,Y-%Av6$ HcjklJ^YKj/`?>^+;c}=ċ3bb)h^+[p[Js*o}=ySktt"k>H)q7ki&'9vM~a^a Vj|l0($)y=[=]F&a+4vuEO-j)rcm{&#(%ϕRTeH&Vy8 J) Z* ӣRiyFӵTjj=Y+c)ɩ܄ޘ+N$LMs&,;&ܴ/b?>\+A qͦJ)Q^ j7RJZo'a 2 7b×~Vy3OG*5њ~ 2 7杒WgFXJBȱ)97SZ Ml Zkoq2Ҋ#%ʵrԗOsVlJis*k "7"ZSSꇬ/UTw cL6ܲ/awoF&%*Ub?V)d`~72|0jjVqpyVyCZ J8-YS 3QH|M ؖ\mٗ;{\]7[rlJ\+9KWӡ|?)+0! 0r_k'p/!`fp9Ѩ˓Sɭ/|*Y2n7 e+mq2` 7АA9e7ތ`ohA~a,Hz08Z~9 XBr!-v8n(hFˎA Xloj)C%T>|=4F6}Ys팃^ I`:buF=5raAc's-vp[8٫P ح{[-]qi$tjZ)P1QrVyCy'6Q# QSReep?;Rrgmv6M)Q0\QRޣ~uݓ~`~FkcYuS4VtbB.GG䫿v+fOk AeSM͹m_d¯ߧ ҷ3dabFcRS⦥a/$O ޹QxD97 &:ᙨR]&^qDAO*=,Lzq=Qy~='_Ϗ)q,OSQD<~4VR=ojHl,*ts[v%F=-sȚͳw01=lͤ9Vs'!3hx̅kx5*)甕R¹Ȱjk,l"݉zS]RϠm㥰RĪMȹB~x |E 5 وRlnI{Ĉ?3VR 5H,r3rc-v|U`j&3ozƾ~fe ^JLMA؊cW9OW4fˆua}q)q&;=$VR635؍$I.Ds.>=0q`dKh4q;Rx&avS2Yc;5gKTmv0JH+www4~ܓiKw" wKG+FPC(s?9i7wnydf5Aq"ŹɩqJy6;Y42?55,]v\NRygnvyz;I,Hrۊ+~7wq;KpVXIþˣE='p\}4}mo)9[6;ZNa6&j얽=75)~~[ZӯMe'IG'=jV8 IjEq ! s*o}=]8r Ss1 C}vVN754²Rcgܲ/awqU`YPO)$]TGXKWJ kEK{Ks~TߧGׁ0-׮As_s6/Kr~sVҕbk5m@ǦĿܶ/awdmV׉F !Xdi,/kH}fp;[ pF w#Q֜v_O߶,I"kWzJXQr"0)xG&.aKԨ[4"w4!@:RQi}Lb%eКA-aI4@綝~}}EJ]xG륛 ڭ׊Їq2ӊ+*Nq!OsRaot\;[jGRߺiI9wJ>=>1K;XɫE5]~ }zTvaw׽Ԁi%NqRb9Gk;;5(N,s[v%#mHDRfmKRWL<=%?Fs/qwAwF0λǜ[v%Jf CBW V'rP |ݣUzzD8 4cKL #<'Ƒb=]kb-]|Ŧ!Ǟܲ/aw;BZ24L%àί97WPS_=^AEkٝqMRX3Omg{սE_f^߱snhVU[_'\NNV8pBJN \ЌMiQx&;9 OO@AyJ]RnH{EW8IC_^; ^x(c_{n闱߇*n4gPl4XVPRg_0,M̶nlJ5# bly;ű)ҾWai*oaLB˱@;HAMY2hێr݌6[ T[eIA۝Z$isġTˣ֜v_@i;^'SJ7&fpkdH )m ~%]~ }0vHqs`Rqr`Be gg 񧞓Vy34 hڝ;$K85vbxD*J԰l6ⱳT-I߱6KQʳYj[r*A& [$Hvit;/45-dmMcsn嗰D Ќl\ts3. RrAEmJ\wA4v6ȹ;/`?>|DoWT! 3.~7ҁb&kB&[ek\* }= .ED[ M~#/8';>׎_b)ql4hblܲ<96%5] }L>޺lb+h7ۻ?_t> Zyb e]~ }2n|:$x>RM;]c's~-"23kjrp#7)ᳯo UUl%l^ښ.t9ؔלve᫷dBצ@>tp"媱[+AR8 Yeo!ڣԜv_ &L@]3Ł=%!mv$VRrU-bɱ?[v%91Jp}dJ 炜$ts&$V6;ZDٍszlIkm;2﵉ٱ{'BVk67ilD }#!{k{'~H,?G[v%ص | ;"l9ݵA򈱒gjeXҽy[v%髗՚/1qQöw k՚sb;AaN<<ËItԼK 0疽8%b=={E ~ZWkzmkQS*XGBOR)=Um~|ťA y#y)h#5,vyݞve髗!Okנ,{4%/^x+%~!XI58ͱGc=KLcRs' tAQzJ\$E(ÝV.֠ );ʱd9M >^IJӼ,+"%^x-%#9xTrI&%ĖmM pyKϿW|4AIlѯi3_;{+&2KnQMkm;2v{# }TJ6bSgy2VRTc R=<6%ocn闱5'IS9QHaqNQ0S5Jh 5Ǝ =綝~ 钊BKE ~E -(poV<2O pl9e7m&44<6Y}R/UR>6{HI(nAݒ4tvXVç]\+y+ @#\ NTRrg~# b4SﱫKzrn嗰ߧ&DFsT%56a=i%.Jj6#4)9KWn_|שRWT/-Ry^;+)SXZcKZd.>h-t'cBEC ZE=oHv%W[QmlCڒne_~~vӪ/*RHKʧc2K>A^MOKkfok (녍msɱ)9s.y]ܺHZ. ;%?> ґEuWMZ] }E'8׊8WT,߲{&']~ }>%ȬGOS ;XJ*G&MGR\sN>:`WW/"=\%/mvr+ijWWs.SDhCR v;.4FJ>ŠRc-kVluؔ_"ƃ׮APE9|+Z_{ZEo m j[vEߧy P/5"mEJLc7xS7*2Ymfߔ5 LHY5vuĜ[v% {e&)..3GZE8_F/MYgqjQG_Ҝv_OPuZbd ${y}%QD`%d1f.y&̹eU;ɐG '͊ Nod { v]g75Cj&陰#_ƅ^_JPnlcLvܲ/awOWBњ4 )>7ކ.~3+5WN,s [v%z$\R/4FHdEW!Yo,%ͿLrF{+Ǧ% %{}䊪(Gf` ~llOpQ_G<<' FuxjDcǤ(yR׾VRTh:@43s^ vܹk("LM(yCG]4 86NylIkIO{m|Hj8ٮ8Cw|7؃}bZT#A W{$'疽b_<-)贞 4&"7A+gJ>w^k4VRόPkt?+,rtr[v%i4_HÌO%.{w~Yzl j;]'?SrrZmnEk`&2&lJS6{FNXK KĂ4oqND~>bZYorDa,9u]R[{AeM"%u§T)H q"0BWDq{J \pMtJ9m7mRE53oͅ8<_YжDO7#ﲓXI3c֐X2zqYs.>?~d|j(y*^/xЭ>XJۧThIb(cSr6<v4S@V|4T#XAM/ӵJ*+~Q/=ۛ{nۋр>~xgV]u憓%\$"TO3u&XIo{ZkCǎc׷=~/dp|ZLCr0/oCs<֓X`%e H96%5]~ }F©x$|-%$ffMXKh$l,Bg9ۑsn4T٬ 8k0 xxA-w|JΚIJmǞ/y]~ }]w[QA~/'߶$qhW!_(dpbXP1Ls o|=]Ry1j&m[Bh@FY+WIIVƦ.tI]4* NHCyp$nfnv^3 kiAtjZTM"GDז_&,-hc (. (l}%*+p a:H{PUzHJ@ґTkH$+;}RHXIXyO={[bꭻ_[d+㛰F >,#%߹;|Vk+޳V=v} 5KS:j6^uJLګzj'N~Yt:c%]RB\slY^i  4_] k_7dX/cXwnb+M}p S?ִGߴح},FO2IxHv+ƚ 6Wc#5slJkm;2vye:M{'"yI6Vu#XI%j?WcAc'N-vpTT P2kCc`gȕ3A٧ J.(4ϳYsN>'=|,}prBrL Y>Xn4Ш0*Uz;\6uq_JELgVJܯ퐰8IhnwS89vت]1˽w,jMvXcfveG¢-^ ܳC{*97f}{|谖bժ0 ȓVNv+)kՄߟHTph [lpw4 .O+fe} ;HޗÔ,6VRvM O6 kƛs.>%FbD߆"@h(2^PMW)z.*~3ռI- (bOM͹m~7A3u,5Pfc.nYSzov{c}ݹ\mE:F9k%Q" 'v2/wR3I̳,DXKÝsRb6ܑ?nvA?Frh[ ܸWǷh>xNL;ѱY>k̹K L;srn嗰)Xv cUCx[7NВ1:f c%w#sF|^>}-p{}^7׮A$k WJmj,in & "']~ }E liEBz;IvnyRr)lgKc)qlGtϣfԁ>a̱)yvy*饐ZmAp3x&'wU8Y G3qsj+wjNYq_%sGxk@G6Q|S/yvk +)!7hƒcSʟ嗰% ju8bPd!Yi >sh=* VzAcK?<0 ie >5:ޙ>pпRѿ3P ;ST}0ͩ朻M*vdSl=[ DOoY5|! ^'ۧ V YE"ڇݷ!ӈ.KV+2<.L}[S}HVvBẘ59Gy՜d?71\ 0EJ*],嵳K(5,0?9vܲ/awϗkr9X803XpI[) #+i%5`O,sn[v%I{y?!wgT,{)bdnv +SJ^O]m;2v48yw_FQ0.=_"L!U׌ slJkmvxM䴢onĞ/jŽ# s6L2  }EƞVç)HsJM+.odb~b8J~3 _XIPh.>~o[;Ǧ}ֳ婰߇'Oߟѭ*>vCwCE8 $_R|iBVJ9eՁӓ?W&AbT+`l㞔|cY7{G/cB%@[q⇨ǂWZqXoAognm^@3KZImvZXKTn(o5׫L31$6X_ e4&X{|* C 8_`"ʅ%vtM혤(0vAsLŕ7'ϔ^@_b!ilЀ[ظǖovy*Y4 ;}biBk"*`ᓋDs54jsJo|==" SYÞ)>0FEa-eP055 .=ʸ]~R NݚYXTx5DmhGWm(К;MK)綝~ #QZeٚ {z,ǒv\'VRͬ[kn췲96%?xe_~.WwX&{EXagcABd<}5vrnWuȟ|wӃY 2ŜPVc|amEpdjsS=}=}DIt` 2b*0zR5nv kؕp&9vǗsnxqxWGކ^ {w6oJH{qٚrmrMt55X'۝rlJ k3~(2jVwwf%VzSiWj~zmY~/Puۏ#anI*yoFJ|DAKKh  [Z0]8 ِ WΫQ)`T)!n(qܹyol"ٜ|i@/e,$?4t*2v=pÿ@Xލr=dJÅy"'!l's453kޱKe_~r+.{wMjk ^Rkq:ta%*4Ʈδɹe_~v{vZN?̯wR>d+Gg$$9Z qO/*?ox5~㯾?oodY?O~'/t*`6=" ٔAR/_Zo?~4vaƆc}ǶcϠ y!ٿ?~G?w?W?aPP-[endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << /GS1 11 0 R /GS2 12 0 R /GS257 13 0 R /GS258 14 0 R >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj 11 0 obj << /Type /ExtGState /CA 0.302 >> endobj 12 0 obj << /Type /ExtGState /CA 1.000 >> endobj 13 0 obj << /Type /ExtGState /ca 0.302 >> endobj 14 0 obj << /Type /ExtGState /ca 1.000 >> endobj xref 0 15 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000125650 00000 n 0000125733 00000 n 0000125897 00000 n 0000125930 00000 n 0000000212 00000 n 0000000292 00000 n 0000128625 00000 n 0000128882 00000 n 0000128979 00000 n 0000129028 00000 n 0000129077 00000 n 0000129126 00000 n trailer << /Size 15 /Info 1 0 R /Root 2 0 R >> startxref 129175 %%EOF BoolNet/vignettes/indegree.pdf0000644000176200001440000001075514272153136016115 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20220802094634) /ModDate (D:20220802094634) /Title (R Graphics Output) /Producer (R 4.0.3) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 651 /Filter /FlateDecode >> stream xVMO@W)90PABjH*$ڎJ3x ^ϲϫsxd R]7Evv#ڦhPVp7ZKX| `^aosyy|3uuV="BAs@ u0{*uE\܌qs]z {PyʨJ-Ϩ<dg jQÍ;a7f7vx';t@A5+Nw_ Hr㽵{'tγlyOjr3TYnZ!!6]) YB*w0 Uk$al,F):_,:Pbc$q5FNƪDxgMqc9wftϏS~)?3)?gd2Y[:c';zë@^jÓ: b6#xƈAy?:H:4:n?0Px/̆3L4NLL\ae_d1˙$Í S} z*A`2//+am/ ]~eFjXm=[ vY_'6/|?8 endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj 10 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica /Encoding 9 0 R >> endobj xref 0 11 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000001014 00000 n 0000001097 00000 n 0000001209 00000 n 0000001242 00000 n 0000000212 00000 n 0000000292 00000 n 0000003937 00000 n 0000004194 00000 n trailer << /Size 11 /Info 1 0 R /Root 2 0 R >> startxref 4291 %%EOF BoolNet/vignettes/biotap_initval.png0000644000176200001440000011040513277247010017342 0ustar liggesusersPNG  IHDR[GyiCCPICC ProfilexZgTM0 9Ðs F$A2"DEE0&"(b%b~gw_:uޚ;\$NxQ0 ,<:DBƽ|z66(#6Rel=77 ԪtR0#@6%7޿qMFtOU!X:bkۘƌoWd}WH±>}.d XpߠpDE ZF  @%5+\@x!w@e_4-/dl4sK6ohzM@wha",`; ~8 > *Oq#ohQ(2J GYQ~(***AU.QwQOPoPPh4͇Fk:A@A_Aw/5 ÅǨaL0?L4S c1X+Ua8l6 ۀ}p81灣ppgq7pp<ύ$| :~DCQ1񤉡ɡJffH+HAkMG@[D{9KP&|ńBa0O$Db81XMN&~ґ4(ttYt5t7}'ҋӻ_31h280D23401%A$>ɉK*&5i};7xv02313dɬ\|yyEeA;,Xqa-Xظش<پ3;'װ`PpH̩y< "/W0WW+n, 7;<7O(O -j9y_a\5G;7$dWr&2T ~e!!;B^ 5 \eC)',.)*~X7 A {Lv9I~I[t6OR|RRRץH J;HHwH/Hxɬ*ɞ}*Gӓ'(V[V>[K~YA^!@R"bbw%I%JϔMSo*/ȫVWRW-P}UWKRkW~^F+MvMfc-:-sl{;; wֆwj'kwho$M vLyGgׯOԷ/6`3p2(7xc(`gxpH(ڨhxqq IS! K?wi:Yٔ^6 `ajQ`’lhlbog̚:z»wۢmml)%QX(_EY7,ʜf՝3D2j ݏPxGzOҞAOAh{^^^L~>DO+x_7f?%tK@S 6-%&hOе``!!!!=ܡQ„žˆgODhFG|P{6E"#x⢆sgb bbbccG(N*.;nfx83߁c ;V]o$q'%$%k'JLL>(t0LԆ44j!C={22r3fR2۲xf϶naIș5mc;7u|wG,\--H/RPQ$^TXR[m|f\EKWïܾ~823~AmOKyia5n V.~}|cl3o,7 cXs ={.\ G=t0@@o( BH!x#<(EC X!=(¢p|łڇDۡ0v)~;M#C@K&ӛ3(ȌLh +]Cӂ+;2(?!*X-4#$(/!',&k*W(RQ@GVeR[٥5-c{x}aQ S.35Vw iP,=ӝJ/rtt$y|t|-\WFG(Q2GD6WcVc7x\ BIdL4t桕̙79r==<\\8(t,RZȩZwTJi3qg ybYcf)W]ޮvM[;;C»z-uUCGCO;6=)|~EWQcQO|369617yn*xZazw'Ψ}|x0QO?3|r=?[֌77#<$  Y"P `+^GF6O?GLBƈ-tA $EFN&:S~Z%8i+DHP#1T++KNKLO>ȖJJ#§73V3rsym..J)>K<'wT8!+!JJi]z. yѷP3ErЕW[qmF퇮DҾ}Z\`N˽}JBH{8w0{(Ipgԑ/"_ƽJx&fϚ~d3gY Ǘ/_~s^xآҕ_U2@hxaPY1PY;DE@AYщ; m hDhn:.*QC HXC̦,t,#lknpuSg' \Vmw$I.H=n9!O"@0إt\9LEOEZzVھ: *=aQn]s?8jioi5f]c[c;lWC7rpsp*vpvp6~#eלwOozsAuC,BC*PEFDMF|w0.`u <$dTF_iˇd,gqf[/vħphűbeWU(r^K㵸:gC7jȿQ-Ɨ^%\noߍ$[m {ݵ gx>``:{E;vx$>,LKQRno7Ϛ~-GB"yvycEvuǚ:n}`{-@Wd@o`8 C)Qf"&="p/y3ii}iG;D]m:;BHtQq)\b2ZĦÕs;G!x_MN-#,-',FKJydddf8MTTԞj`45Bwit+bbj\e2K,|R*]g),Yd.K[ X Z 9&~*rzt[Ҿrd/&˥J5NkO2,3K&sdsSs *^+v,?tҙryUkkO;+~ABkҥf$Nx67hocz=J_C?x@yxn`ɡOOs<{(X7'&Zb9h)i/_c^nN?--)/Z6^~KׅUՉ5ĵ+kם 776667)7{wh "B#"練$k0!51z#wڠn!:_"V`Hc[#}!j@?5چ<)> DD^eNUDjG0;bH~HqGg9 3Eł 0 V !1x$R#9aS"mQ Gp#`?z&1H~YȈ?6/Ƚ[m[/4mFA~V~ϘТhE ZAk2 dhuZicg[ZcODtDZVభߟm \ܟ 9ȓXdN"y~Iu%/n+WDPGFI?ipYiogoD@ B;|Day<"  .y%qjyW_?tA!: @@Yf͚uzzdL:u>ꤱ1)+F@@0 V?{a~*@@Hz`W233ww4teB@@ ,7C{w_Ժ2u,]+ vɓۏ!"{\/5lXn]^^.K,ҍҥ :T k< Gy4p)WxNuYt<"9rfm[G ^k?{Inq&PϺIzPyW[Yn+9l)<yȭO{Ҙ-^2d-1Eͪwe=sF;Snrn=q81$ov {?q˪w L k?NֲՔ/?Da?~Qc=h@^ưe/Cv)~%eo$4hl֕I:Y!K4mѣ%O{eMR=ugh[Ou-ܜ\䤵!v]ibyvL)/=IALY߸JT+4D:H|vx2 o`,@B 4}O~z4CSˆϞ _)ZVv+r}#֩{Ey~KS+.^>^u+R^r?)L}L.>p3l5"vڧdɛ:F2N;'l릚1m!g_.e"KۚayS ·kNL^ܴy]Y!үJ:ҡ ly_~#KN]gƌ:q9鄨ٖHݝ]7ogkS^^ƞ:;ww+92p"/̕\Iyib-ʒ]SPAlc{1?f"hU9Eg؜jRT*=&Zˮ?]Csɩeպ-6Ҡ_T3sށ>S; %oГF˷)m䎖- e}UKoʩ#|o˩)/^)MS\vkmHP,ٯU:gX z=M>A7j6Kd]e3Oߣ޿˶.s@; gC+٩'k~4ֈ EV8P]W~_.j6Ok]f ri|KcimwyK1=u|qwֽJvaTfKU:T!ݺvݺJݥu"żGˤMl,+%eʍN&8@8&s;ofEd+2U&;|N$^7r+wɌ)+2}}2oYEv*[le)o#~խ'NiYq`XOG>- kݗT!q쏥)ywe5E.gN +'s,.;EګYӨus<}D {Tdzglz`sLs|`+f.2j~ANg~p?Ot1oR;ϑ;uS>.4Jy2eV{N[KAMuΘukTKx4nxpzx@M]V~tv\kk`*ݵzdsy ֯ hkZ/kֱ8k^7WJMt8';Sr2gsӺ:&CVo  $@Z\t=9?=ܞrOϐ?V^z Y3.KS3dy\w0)ž|>]|UX!C-mp uwrͤ#*#OVf-4Y|y Lj⯆7nN~ޢ䩋orv_n.,]XehOK_cϾ^MY^:eT?7mt帑u+ 䠋ʽng#xM~~)'3ɿ䣹2C_hҩQ?-ԿM6WOA~s뻟 *;XGt *Z@km;ekP:7Wi )#[mtcT5Kh@^,r:DS. aOw&g>ut=rCjɇ2S9頑RCteɎD;L $URVSsy`TgG$zY_$Eba]; _, ;La[ZoN~vyp9jz)2Tv%2/'YY.4q|ѿ5J )du\9wiGZ9P} l)Z? Mk~'|,eG_!_j7n:oWH*jByFq͒w+ˉ3^Lf~"iKri odٺkP^Djo 7 M/@zgF+=$9l=zumȺ=u[wVZڿk?=W.Yz(ֿ\错Lk$G*6k:_]!tHC sE@Oɮ\#L*2?-?#mlFRW \wme#L}Pl=;eE+uЫPW[MuM'p>ҭHٯݦ-7jٰbM V罿n^_dJ,`[&~/G /ZQįw)q;l|n//\%ǽ3*#'#UUk7%a6䴛X gj:5etar̩R|U2i_Ev~)m B*P~ye~k5zo5Z_+|Ϧ@;zFmyug:."\QZ);[~!=ohd 4r:"@ *i{Yr]/wnv^ xWUX/q{P,G]f̵ېAhLvP@{D9h[0+G 3;i8嫃'Ӂ:bM{yF@]\2r97M{@r|9="h=t8~T]R"dDnxD +|P6PƏ,]sGf;EyD 1ϐ?˟~~t$'G6^.5݆ʐ|Yy I;o65wZ1p9pBƶ:4p`yөh j3GUؠ{]\|?r|/cA7 idq`sR Rײqν^=w SW ޑn/r=2HV4?8-mԠ=6U] 7}uoa3O'o& J#_E1i[I{H&3R*.7)r c |Arʍgʟz.?ٵvܖȲ5"n?nl}S-}r9r HQfXzn;Z66_Nw);jvޭm@yuy܏> o'u7H|L~Tƃ&%]֭-AfI"9zڶmQ~K;T'sN8\F#P5|~5yXv#'Ȍbs6Mz/jC~G+ꛑhMY>s{vl 9sZi/ћ­1rÄr-sExO#m_X?|X&ߦ4_~sC'ɣ~@ qKgyhC'ճϾ^:{Q!|+fղNq]*4'hCMnk?4a-@nAfu] -(qx-i(Ųp'{.k9uUz/RZ0 WV~#^WVpnRнdV{,dJzTjuhO|YLt-5*,a XЩ^WS"KWilY[2 e\w,@.Kz*d^@gPڻcs$?Z-]7?s/_2tO>^iwqٖu)ӋzHuS]^s t<Z6^SFA/K:[eg6/rg],mNIo%vdUh{z_+Ef*?˗-S-m߼4Yn^ҧ{Vm^)%KIZ0ݜAh˗m_ZYVlmSu_{kSVao=/n;nQ0U2s尧n!~ٰb9ol}lHAﰑ?@I㾏-VRcS*u $?yꩧB.ز\n 5},z7|핵 P=:ańֆif⺁ua`m MYе@> W66|'Y5긻<=XﵻTlhU9$wL!DvrFS^g7Хn~byI*z&ZO˪1ïS/0TKd mвWͽLλyCPOбu;[LN=g9ojӌָhGEu?SCyfݘԮ<9GAzu}Dzo[|zv"_b.+ @ X{O<|KeY]{n 5(//w'?\O-7^] |su݉&;dv-uu`ͳ=# @vYT#C;zoZ0.^lu#HL @4 xc=-A| Pݠ3<@Ӧ46@zK-Z$%͆ »߬OvVpN1{"3SDثW'kr/Hn@oDƑ\@ L݇zHf(2 IDAT#vCl¦`_:}Qae~ 4l>4R_ Wɣ-_1GPXQIQJ7x r'L M]v=l9ioln[j-S26w7=8^dw/[.l=[ IQO?T&N,69&T 5 cruC]"9<{8\yMA'5u"NI ;o  of-4448u&ᵞ<`т)[pVAY`J&[&=}?o:Fz{*;8 @[5Af-ȵ^7uOgC5`_rslqX_~Y#;4.5ၮ[ϋX+.Edv;KCerR;}bcyRU/RӘ!߬󉽏#W @ ƀERhv tݠ7KS7|>nMw?ٌrvYdww9`~4)**rb wߕʑG)?qr:sH>,Eo?/NdfeIN0'k?V?W-6oO}C>䋮]8B6-벯?_/K>t?|S:weuMU%e> u Ƒ\@ L᭮Zph솎u34P^I{UWͳ{dw/-.ŋ;?m?  ʦqŧ~,]TnFwdɒ%ݮ=ϼZ]FڃBeu~Q歨+f޲7n @6Y״(`Ag6=rgȑ#? Xww;#&MCHϞ= *_~ ) FG$+Q?C-!MvfY<9ylxud9 uʓ>%k/g?'L#)-Ѳ]"z>;%ٝ emFJ%;o\,_ 0)[JzC/J*/P2s%#du-:}i6߮3j=t\eg,MC:,t,l#S]6[Jߥ{`,] mk&N>{/c5K>$S [G(W+ky]e _^)9eȾYl]ZL+o^qP' @dlQ,gۛRzێ5ԧ`Pm/ҏW,=ݏ=5 x-Ґ{Ӡfu2vʖsJΝ2@~~ 3w}nOիW;BGץK6lMX/PZZ*NZBGvk]w裏:?2ydg/ ݼ-_uw_y<,`=¶Ns+lm5_W܀|,M(uai,P5?WV}kz @-u˜=.:Jq7ϲ͈[AR[UC5%/4RV.8nK3nGdЎeHmIƲV,.۠Dd:8_hX„%`u81}v([ik {\=ѬL ~66  x1ToYƍٳgwg kƌ#{gGv\{r;7tAZӧg-z/Y/em oA Xzw^η`0KN:65tq-Ѓ'_'_@AnH¶/PcmP ^V:D?-F]n}֬=:^һCuEY>z[2w=:C44HemR'|)qC^孨+V8g䶶)Lu%;(倶a}H &E:T4'^Lgn|ozvm`WXZX{WgJ5@Eug7xQ@(S˧~ꌫ-w<=rя~$QSNNh%V  :[A{yW|,=;meQYR@7* h֣kA O>:J `/nSXg[v0+=}/}؏g/ v޶۱&DSQvک*/ON:u{y4ٽ}c{̈́x!@"y 6tar9Ț5kULDKQQ9@Iy V޶ʱ(`Aݓz6ຏi A@]xۅL@ T be_vGNQ"g6m%͢yo5XV\)%\x˗KNNի-a[gR N+a+\ H/ׯA=#cǎ,M<_7{Ɛijl;Bs9Gf꫃/--u/BrssC~_B Cgݷ =n>^{]p3bĈv1۷|2`6b F&L v\={dgg9oVD >=s2p@o+Oo<32jԨl"Ov._؞z)9%++9йiC@h@[xw }AܹVV~w~ǂw}矗c9&8'@\.Zs vmeѢEkA$ƍ~ؙgƏ/?9s洘駟Ovayw.s_W<{!r9s?w^Gۿ,Fw2'si/~-;Ͼ|x2;=);蟸66}Xqƍb;ݚҜyNG9=U??DgKʼޒ^}RZ^usoW_uwi=^OOurγ<9R4AE*Shx@G['t<_gYl7N5X9m}R_W< mE:l}d(Aҋ/[7,}c]w-Dlv|u҆k;.o {v[:&RM .o@C';xڎwȭ* zv\jn{~L8t#*OCeQG}3׽-tĖP [7ݐ[f~3g=)&]hyD#B߳];j z'y_X>n^-O{ݚ}2!*ZLaII3:Rlo|B_Bkں_=w[<"q xmSd; {9Wy晲`g|&{tӷ6cڇ]jxCnݺɺuuK^dw[xQAyO}͵ =>oLqgvv%ݭ7 g{u9n[Һ[>\u^v'ߝ r ":V|bOwsudhH?`m?jdDCɣ}H{ܲ^0ڮKOJBz+o}ͭsӆ>on_ln{v\ Wz6 `ڻ|s+klwW7<_>)U2˶v+B:ۤ}PDbI)GvZ' ->`:EK)O!QvNԚ}Ʈ>/,|O^XImٷUUUą ʩ*~i}-(ʓC%f#Сou&v$|}$ŭaˎgC lu:unXnb >EũH5-˾eek>cM ,Ubݷޑ ͷ}Y^3K/{JA}+l2-޷bҹs gi =1![ޛ#&eC槂iM .o[)I`jY}+f2V@ < xm|k&̄  @s-Öy: -m  4'Uli\Y/ߋ֥SK[Z@k;x`3gNv:+ږ߷o_Wn6ill l)`^{9ݛ2QȜҷ~Ůb_.]Br) kZ[oU/^,wuWl;dٲe1Or3&.pE9d6|>}QWh)}K-c&_iiimd_'9sf2W# rwSO=%999poϣ>wELL]Rf͚fa7~"Ҵ3e&)(p5/_|=Z#\99䓝Zlsצo2j?2q4(!O@ f_~cOK^ZQG%vg}bZ vF~{С29--w={tINWWպy@"W_+iK,/\&O,6ΦoF'Otyɱ6:z@7c4hPjkCUI@ lܸѩr~~~̦'h[ZnX*or%85.`gKl|>}ձqټ'eee"-))qٿ!)x%+Çˉ'( -s޼yi$[ pġh-h ?#M-oiٳgO9krKMMM1ׯ_d/;bסr)K/JDl@^뭵!tX#1cZLKQҭ[7YhQ6th }Rew_K5kh͐\w8}1q>3s\J%D=5=z8vk#4Yգ>*sx㍒)H{iwL;mz&N輶;R3mzb_`Wؾ2!jv?j 6L>c! v;we5js snذټX$DkUiwiw{ȑ#{ͽM#l.0uTYp>2n8gAh}Z-oi Mmdرb^:[FH `com مm/'7|S̉6 _8SŦĶSmO>)&Mb>3@}pDkG[nUv@h[bB l& jsڵka IDATNg]Pʄ@ ̘1C&L}ŊΗ-8#+$G$5YkRh͸&N VлDeBH! We  N@HC iiHMh_ybKLi*`!㸕OU[5%ʱQ5MG@[H[XtHChO> D^ؕoL6͹܋<@*4?(-!rġ[rx?W[O}{ɀ^E _nf?%_Z*qor5 $klӀ7F?O_{m88?4]l++vͫq2罒˗/~8ݪN}hWcPn@S#EOn9k&;$dŸoOMwO' G( -.݂i]_9&_z{yb=> &R\G6C]A>cw;./#bƎ ѳw_:F^ˮ2)7`y@ uO37N, %Z9wp|Wy7}) ~צ_W篓FvUӿӮ[03! @1A3v|:k/-u;Or7XL䅧 [/'^i{nc-@ q x7*v͒TV78AnyU+sٰ=tګk g mXQ\#e2jy@f",#75uKѲtjTdgzrсh0Hے-[]U]}68#ʓ+q6jqvh|yC?@JdCvQ(Y>CIYH&h x[[M'kZ~6һkW>TNvІu [#~ W\`zԧme?  55YUR릷! u#lCYeY_'v1[9b@h@cPx>+HgXs~oiJYg2֙فoa>Ǥp?^#I>V_Oe]*8祲R?x v^~ܗqA!@eetMƏTqԨQ}yS t S3  @ +/# [7-@@U]y@@ ~?a  )"UliRj  [Ӏ7(l@@pp^# oJ5'A@ 5  @J TsR@@pp^# oJ5'A@ 5  @J TsR@@pp^# oJ5'A@ 5  @J TsR@@pp^# oJ5'A@ 5  @J x¡2  *4|a  )%UliRT@@ %xS  @4h2G@H ޔhF*  M7 @@RB7%J  D &|@@ Mf  x0@@ %xS  @4h2G@H ޔhF*  M7 @@RB7%J  D &|@@ Mf  < x~0@@-= x}>_L 1  -= x  K7^l@@Cx;  K7^l@@Cx;  K7^l@@Cx;  K7^l@@Cx;  K7^l@@Cx;  K7^l@@Cx;  K7^l@@Cx;  K7^l@@C< x~  WK}yj  !^ŖRs6  @ 1`@@ x(1  @ 1`@@ x(1  @ 1`@@ x(1  @ 1`@@ x(1  @ 1`@@ x(1  @ 1`@@ x(1  @ 1`@@ x(1  @ 1`@@ < x~ Pb@@*4| E@@OӀ7)1  @ z S?@@ x @@@T M~  @ # .@-L@@4 M7G@R]7[! i.@o o0C@\7T@HuToa o>  @Hs4P}@@ xS  ~?9>  W^Ŗ>ϫ  @ x[zyP}@@ MFH   zgIN   (@B@@ Β@@P7"! x'@%9! $o6 EB@N;KrB@H@l  w   ( @@;^, @@ xQ(  wY  @ &`P$@@< x~w%#'@@*4|i(T@@;bKO^GN  x#@#  $o6 B@FGrA@HPm  7   0 @@^o@@ Axa(  78   @ &hP,@@oxq$@@ MІX  zH.   *@ C@@ Ƒ\@@TӀ'h5)  @ x[z|ds   *UliV @@ xӸ:  @Hc4n| o:2uD@X7#  @L@@4 MƧ  @:C+SG@@ xӸ:  @Hc4n| o:2uD@X7#  @L@@4 MƧ  @:xt0   Uli:l@@ -= x:" $orE@Q7F0# $orE@Q7F0# $orE@Q7F0# $orE@Q7F0# $orE@Q7F0# $orE@Q7F0# $orE@Q7F0# $orE@QӀǸy#  YӀE.-s@@QӀ7:@@v mwb6  Oxm@@v mwb6  Oxm@@v mwb6  Oxm@@v mwb6  Oxm@@v mwb6  Oxm@@v mwb6  Oxm@@v mwb6  Oxm@@v mwb6  OO^Ϻm@@*4|)DLU@@)UliO  @$H*C@HޔiJ*  I7 @@RF7e  D <@@ M"  x#0@@ exS)  @$H*C@HޔiJ*  I7 @@RF7e  D <@@ M"  x#0@@ e< x~P@@ x[z|u@@*4M]*  2)ӔT@@ o$! o4%A@$@Iy  )#@2MIE@@" FRa  @LSR@@HT  2)ӔT@@ o$! o4%A@$@Iy  )#@2MIE@@" FRa  @LSR@@H~?6  @^Ŗ>/抰  -= x#y  S7l@@x۝  S7l@@x۝  S7l@@x۝  S7l@@x۝  S7l@@x۝  S7l@@x۝  S7l@@x۝  S7l@@< x~  WK}j  ^Ŗ^k6  @1@@ x(-  @1@@ x(-  @1@@ x(-  @1@@ x(-  @1@@ x(-  @1@@ x(-  @1@@ x(-  @1@@ < x~r՞" $WKX0   \^ŖEHi@@A7Z:" i,@ƍO@@t MV  @ qSu@@ xӡ#  iT@Hthe o7>UG@A7Z:" i,@ƍO@@t MV  @ qSu@@ xӡ#  iT@Hthe OcJ  ीW  ^ŖiT@@ Axa(  78   @ &hP,@@oxq$@@ MІX  zH.   *@ C@@ Ƒ\@@T7Ab! x#@#  $o6 B@FGrA@HPm  7   0 @@O^M@@ -= x}>_7   x[zzS5rA@@;^, @@ xQ(  wY  @ &`P$@@x$'@@ MFH   zgIN   (@B@@ Β@@P7"! x'@%9! $o6 EB@N;KrB@H@l  w  ~?H@@QӀ%%eF@H@bKOtH  i.@o o0C@\7T@HuToa o>  @Hs4P}5h<E $*jd]uGdc/IDAT}k5 >3tuuͻHSUUzjҟy@.@z S?@@ x; @@@ x@N~P}@@ ެ0C@:T@Ⱥ7-L@@N.@'G@.4{Q?@@Beˠ7%T}  uP2h::C@=o%F@(C[" Ԟڌ# !@-M@@jO[{mF@@ Ŧ  '@୽6  exbS@@ ^Qb@@2e`)  @ xk(1  @2@@f@@ oXl  P{k3J  P@84"  PZ T xs\@@2Beˠ)  xa    VK" $"@M  TK[-y  7f  P-o9.  @"D9  @Ւ  xa    VK" $"@M  TK[-y  7f  P-o9.  @"D9  @|>_zp\@@ ʖAo.3A@@l4V "  PJ[J   f  @)o)# dBf  dX  o&J   a9  @&hF*  PJ[J   f  @)o)# dB!ZL<9Cr<@@N,h3fL'  ϟ_lqeJW& ;B@Ȍcx3ӔT@@ @@2#@@:zvv/^lʖ!GV__o-rd  KziݻwRW%RB.H   @:SKRy@@T xS, @@ 7$A@H7B@@B xCI@@T xS, @@ 7$A@H7B@@B xCI@@T xS, @@ 7$A@H7B@@B xCI@@T xS, @@ 7$A@H7B@@B xCI@@T xS, @@ 7$A@H7B@@B xCI@@T xS, @@ 7$A@H@C*KE@e>Yfg}f .fi./+,Tk?ub=zF߿PݏZuƴ ^:>4O?-@-~a޽ 2vi'|V/]~wW~W;\!# fʟ1Ix+ߎ@ %MMM6}t{wsα~;bR1|/zkꪫl]v#FX}}*oΚ3m߮ޕoމ PC pgzguuuQW5T#Ӥ?_o Ç:U]9gLWh Wƍ[a @jS@Ocu_~e;#l6rO˛W*G*dƷk>/ښki}XP qb;ʜ{:,icę@2-xb{mycѭ[!?{ 6EiUy=l0ꫯl~UvFe!WehYl˖-u=*kVjrHb#ðd#W߰nYx=i$2Qg49|n(ϟio ]vğ\B.quUu# P!}.((iCW=[ KyWZz~㋛[vm[矿˜Xo5[Pq Ŧw^?ہ)h_Xk׮&؜9sXcbXe![SK^z%[;{);Wvս ]w=Sk7Get„ _ܡ^n?)K.{~~ޖ1׷s@L ;'m}C}SP)4Fݿ ѼJh3] uG،3lk$Z8~=p۳ O:%֫Wvi4asϵ}ڸ gO/,SpuȵWWG^xu?^}ͯ+Ё7KGx ؔ)SwXiaf?۶b >K"Yg٩j7|ۙi[bŹg~s_nݻ-w:s*_r% /sh!ڥ^jk{omd>}BVqW^q_n{#V! y A:Ǟ.-]Cם:ec-wPUns k߰LBO!Wpg!=}{m7Ue's u_5r;{{<ޮgϿp 8t#'3N?}7<>&^687D桇^={i^z[oeG60ͫaL @R#^Nꯏuҥ7z[>x[zxx̛7}%|Ǻ;87VtGyY_9]Ozw5Cu3fpU>5җlcV^l\=׶z e"PSHg_\ԃ_m m_gi {_͟{1c6l'|=쳦Os=^ofnȌϝ; d|^0 @fWQ8E냠7ԷC.]X[ /tJT>5NؿxI=x#UFm`z۴iSȑ# s>֭ZUaן8}}~üS}}ckG [\p]}*yLF5}m:Wj8p`=zotM8ѝ[շnîwRS*y25 !dU@[f.!|k\( gm[iYg=~Z0[g^cVn%? {~/8Oާqs2 =peRuE}.:_?sL7LC/^ޣ>c޿?_폣ezG-N{+=2-4g?ׅZW_}FF.'t0Rۍ?~u\S޸8@2%V݉AKj}bO?ۇz׵hM=70UCf{Uz4AcQ*ڻL3_Gv*w1b˴eSs ￿TN]qev/ iP Ӈӽ#{~5j +C_חხzwe!S$_DQ q5Wj[= zvih j:/5C:?u9-~?iCkJt פo5mֶڏ[oյ`@ḽR)} z@jQ@aO?uaG_oqYO>0<Ǝ>n;X~O{k{̞ybK.S=TԳ?! Çwp>A+rVtOYEvҒ`1 .tsNѤt{]lue2^+dò@ЇonQGUL/d`Ҿt¯okƠЬ(xokKym-hת΁r&?{mI[;RvqVY @ ߎKOj Y/NicPe2WQY{h"u0kl22'쏙ʋWʘ! o; WẗN3YARc֬Ynܥ.:t.d{jigDǶ1cV 5.Te}B_u={z+u A\I)l^|A՛=x]ֺ~Ysƴu 17|G@ h\V` _~kh_a'Rkkccz^GXU8cgBO˜~; @|/ CBc]uGZ ѽ{wu 5=BsS֝1-Wnۤ +> @ # e v}S%iת3?{0doG b}O1IEsxVL;nݚ;^&D@@ 7%;B@H7B@@ xQ#@@4 x* @@ 7%;B@H7B@@ xQ#@@4 x* @@ 7%;B@H7B@@ xQ#@@4 x* @@ 7%;B@H7B@@ xQ#@@4 x* @@ o>  )7e Bq@@ xz7@@ 0!e Bq@@ ֓! Lޔ5A@+@oXO  2zxS @@ 7'{C@H7e Bq@@ =c`Z~ezh;Me3!  _?]Sus_k|-mx  ^\!VZCo|m,IENDB`BoolNet/R/0000755000176200001440000000000014063127656012027 5ustar liggesusersBoolNet/R/print.ProbabilisticBooleanNetwork.R0000644000176200001440000000263013277247010020737 0ustar liggesusersprint.BooleanNetworkCollection <- function(x, ...) { print.ProbabilisticBooleanNetwork(x, ...) } # Custom print function for class ProbabilisticBooleanNetwork print.ProbabilisticBooleanNetwork <- function(x, ...) { cat("Probabilistic Boolean network with",length(x$genes),"genes\n\n") cat("Involved genes:\n",paste(x$genes,collapse=" "),"\n\n",sep="") cat("Transition functions:\n") mapply(function(gene,interaction) { cat("\nAlternative transition functions for gene ",gene,":\n",sep="") # print original expressions read from the files (if available) lapply(interaction,function(func) { cat(gene," = ",func$expression,sep="") if (!is.null(func$probability) || !is.null(func$error)) { cat(" (") if (!is.null(func$probability)) { cat(" probability: ",func$probability,sep="") if (!is.null(func$error)) cat(", ") } if (!is.null(func$error)) cat("error: ",func$error,sep="") cat(")") } cat("\n") }) }, x$genes,x$interactions) if (sum(x$fixed != -1) > 0) { cat("\nKnocked-out and over-expressed genes:\n") mapply(function(gene,fixed) { if (fixed != -1) cat(gene," = ",fixed,"\n",sep="") }, x$genes,x$fixed) } return(invisible(x)) } BoolNet/R/toPajek.R0000644000176200001440000000223413277247010013541 0ustar liggesusers# Export a state table in to a Pajek graph toPajek <- function (stateGraph, file="boolean.net", includeLabels=FALSE, ...) { args <- list(...) if (!is.null(args$attractorInfo)) { warning("The parameter \"attractorInfo\" is deprecated. Use \"stateGraph\" instead!") stateGraph <- args$attractorInfo } if (!inherits(stateGraph,"TransitionTable")) stateGraph <- getTransitionTable(stateGraph) geneCols <- setdiff(colnames(stateGraph),c("attractorAssignment","transitionsToAttractor")) numGenes <- (length(geneCols)) / 2 from <- apply(stateGraph[,1:numGenes,drop=FALSE],1,paste,collapse="") to <- apply(stateGraph[,((numGenes+1):(2*numGenes)),drop=FALSE],1,paste,collapse="") vertices <- unique(c(from,to)) vertexIndices <- seq_along(vertices) names(vertexIndices) <- vertices from <- vertexIndices[from] to <- vertexIndices[to] sink(file) cat("*Vertices ", length(vertices), "\r\n", sep = "") if (includeLabels) { for (i in seq_along(vertices)) cat(i," \"",vertices[i],"\"\r\n",sep="") } cat("*Arcs\r\n") for (i in seq_along(from)) cat(from[i]," ",to[i]," 1\r\n",sep="") sink() } BoolNet/R/markovSimulation.R0000644000176200001440000001226113277247010015511 0ustar liggesusers# Perform a Markov chain simulation with iterations/matrix multiplications on . # If is supplied, probabilities for all other start states will be set to 0. # All probabilities below are regarded as zero. markovSimulation <- function(network, numIterations=1000, startStates=list(), cutoff=0.001, returnTable=TRUE) { stopifnot(inherits(network,"ProbabilisticBooleanNetwork") | inherits(network,"BooleanNetwork")) if (sum(network$fixed == -1) > 32) stop("A Markov chain simulation with more than 32 non-fixed genes is not supported!") # the C code requires all interactions to be coded into one vector: if (inherits(network,"BooleanNetwork")) # deterministic network { # Assemble all input gene lists in one list , and remember the split positions in . inputGenes <- as.integer(unlist(lapply(network$interactions,function(interaction)interaction$input))) inputGenePositions <- as.integer(cumsum(c(0,sapply(network$interactions, function(interaction)length(interaction$input))))) # Do the same for the transition functions. transitionFunctions <- as.integer(unlist(lapply(network$interactions,function(interaction)interaction$func))) transitionFunctionPositions <- as.integer(cumsum(c(0,sapply(network$interactions, function(interaction)length(interaction$func))))) probabilities <- as.double(rep(1.0,length(network$genes))) functionAssignment <- as.integer(0:(length(network$genes)-1)) } else # probabilistic network { wrongProb <- sapply(network$interactions,function(interaction) abs(1.0-sum(sapply(interaction,function(func)func$probability))) > 0.0001) if (any(wrongProb)) stop(paste("The probabilities of gene(s) ",paste(network$genes[wrongProb],collapse=", ")," do not sum up to 1!",sep="")) # Assemble all input gene lists in one list , and remember the split positions in . inputGenes <- as.integer(unlist(lapply(network$interactions,function(interaction)lapply(interaction,function(singleFunc)singleFunc$input)))) inputGenePositions <- as.integer(cumsum(c(0,unlist(lapply(network$interactions, function(interaction)lapply(interaction,function(singleFunc)length(singleFunc$input))))))) # Do the same for the transition functions. transitionFunctions <- as.integer(unlist(lapply(network$interactions,function(interaction)lapply(interaction,function(singleFunc)singleFunc$func)))) transitionFunctionPositions <- as.integer(cumsum(c(0,unlist(lapply(network$interactions, function(interaction)lapply(interaction,function(singleFunc)length(singleFunc$func))))))) probabilities <- as.double(unlist(lapply(network$interactions,function(interaction)lapply(interaction,function(singleFunc)singleFunc$probability)))) functionAssignment <- as.integer(unlist(mapply(function(index,interaction)rep(index,length(interaction)),0:(length(network$interactions )- 1), network$interactions))) } # check whether the start states are allowed # by comparing the values of the fixed genes fixedGenes <- which(network$fixed != -1) if (length(startStates) > 0) { statesValid <- sapply(startStates,function(state) { isTRUE(all(state[fixedGenes] == network$fixed[fixedGenes])) }) if (!isTRUE(all(statesValid))) warning("Some of the supplied start states did not match the restrictions of the fixed genes and were removed!") startStates <- startStates[statesValid] } convertedStartStates <- NULL if (length(startStates) > 0) convertedStartStates <- sapply(startStates,function(x)bin2dec(x,length(network$genes))) on.exit(.C("freeAllMemory", PACKAGE = "BoolNet")) # call C code res <- .Call("markovSimulation_R", inputGenes,inputGenePositions, transitionFunctions,transitionFunctionPositions, as.integer(network$fixed), functionAssignment, probabilities, as.integer(numIterations), convertedStartStates, as.double(cutoff), as.integer(returnTable), PACKAGE="BoolNet") if (length(network$genes) %% 32 == 0) numElementsPerEntry <- as.integer(length(network$genes) / 32) else numElementsPerEntry <- as.integer(length(network$genes) / 32 + 1) # build result matrix reachedStates <- data.frame(t(sapply(res$states,function(state)dec2bin(state,length(network$genes)))),res$probabilities) colnames(reachedStates) <- c(network$genes,"Probability") if (returnTable) { initialStates <- matrix(res$initialStates,nrow=numElementsPerEntry) nextStates <- matrix(res$nextStates,nrow=numElementsPerEntry) res <- list(reachedStates=reachedStates, table=list(initialStates=initialStates,nextStates=nextStates,probabilities=res$transitionProbabilities), genes=network$genes) } else { res <- list(reachedStates=reachedStates, table=NULL, genes=network$genes) } class(res) <- "MarkovSimulation" return(res) } BoolNet/R/sequenceToLaTeX.R0000644000176200001440000001011313277247010015150 0ustar liggesusers sequenceToLaTeX <- function(network, startState, includeAttractorStates = c("all","first","none"), sequence, title="", grouping = list(), plotFixed = TRUE, onColor="[gray]{0.9}",offColor="[gray]{0.6}", highlightAttractor=TRUE, reverse=FALSE, file="sequence.tex") { if (!missing(network)) { stopifnot(inherits(network,"BooleanNetwork") || inherits(network,"SymbolicBooleanNetwork")) if (missing(startState) || !missing(sequence)) stop("Either \"network\" and \"startState\" or \"sequence\" must be provided!") sequence <- getPathToAttractor(network = network, state = startState, includeAttractorStates = includeAttractorStates) numGenes <- length(network$genes) whichFixed <- which(network$fixed != -1) if (plotFixed | (length(whichFixed) == 0)) plotIndices <- seq_len(numGenes) else plotIndices <- seq_len(numGenes)[-whichFixed] attractor <- attributes(sequence)$attractor sequence <- sequence[,plotIndices] attributes(sequence)$attractor <- attractor } else { if (missing(sequence) || !missing(startState)) stop("Either \"network\" and \"startState\" or \"sequence\" must be provided!") attractor <- attributes(sequence)$attractor } # escape "_" in LaTeX genes = gsub("_", "\\_", colnames(sequence)) # determine list of genes to be plotted # Open output file, and print header sink(file) cat("% Please include packages tabularx and colortbl in your master document:\n", "% \\usepackage{tabularx,colortbl}\n\n\n",sep="") totalMatrix <- t(sequence) colnames(totalMatrix) <- seq_len(ncol(totalMatrix)) if(length(grouping)>0) { # reorder genes according to the supplied groups totalMatrix <- totalMatrix[unlist(grouping$index),] separationPositions <- c(1,cumsum(sapply(grouping$index,length)+1)) } else separationPositions <- c() if (highlightAttractor && !is.null(attractor)) { header <- paste(paste(rep(">{\\centering\\arraybackslash}X", min(attractor) - 1), collapse = " "), "|", paste(rep(">{\\centering\\arraybackslash}X", length(attractor)), collapse = " "), "|", sep="") } else header <- paste(rep(">{\\centering\\arraybackslash}X", ncol(totalMatrix), collapse = " ")) # output table header cat("\\begin{table}[ht]\n", "\\begin{center}\n", "\\caption{",title,"}\n", "\\begin{tabularx}{\\linewidth}{l", header, "}\\hline\n", sep="") cat("\\textbf{Time}\t&\t",paste(seq_len(ncol(totalMatrix)),collapse="\t&\t"),"\\\\") if(length(grouping) == 0) cat("\\hline\n") else cat("\n") # output active and inactive states if (reverse) indices <- rev(seq_len(nrow(totalMatrix))) else indices <- seq_len(nrow(totalMatrix)) for(j in indices) { separator <- which(separationPositions==j) if (length(separator) != 0) { cat("\\hline \\multicolumn{",ncol(totalMatrix) + 1, "}{c}{",grouping$class[separator],"}\\\\ \\hline \n",sep="") } cat("\\textbf{",rownames(totalMatrix)[j],"}\t&\t",sep="") for(i in seq_len(ncol(totalMatrix))) { if(totalMatrix[j,i] == 1) cat("\\cellcolor",onColor,"1",sep="") else cat("\\cellcolor",offColor,"0",sep="") if (i < ncol(totalMatrix)) cat("\t&\t") } cat("\\\\\n") } cat("\\hline") if (highlightAttractor && !is.null(attractor)) { cat("\\multicolumn{",min(attractor), "}{c|}{}\t&\t\\multicolumn{",length(attractor), "}{c|}{Attractor}\\\\\\cline{",min(attractor) + 1, "-", max(attractor) + 1, "}\n",sep="") } cat("\\end{tabularx}\n\\end{center}\n", "\\end{table}\n\n",sep="") sink() # return the matrix return(totalMatrix) } BoolNet/R/symbolicToTruthTable.R0000644000176200001440000000117413277247010016271 0ustar liggesusers # Convert a SymbolicBooleanNetwork object # to a BooleanNetwork object symbolicToTruthTable <- function(network) { stopifnot(inherits(network, "SymbolicBooleanNetwork")) res <- list(genes = network$genes, fixed = network$fixed, interactions = lapply(network$interactions, function(int) { newInt <- .Call("getTruthTable_R", int, length(network$genes)) names(newInt) <- c("input","func") newInt$expression <- stringFromParseTree(int) return(newInt) })) class(res) <- "BooleanNetwork" return(res) } BoolNet/R/parseBooleanFunction.R0000644000176200001440000003300113277247010016260 0ustar liggesusers # Split up into symbols. # Returns a vector of symbols. scan <- function(expression, lowerCase=FALSE) { if (lowerCase) expression <- tolower(expression) # add extra whitespace to brackets and operators expression <- gsub("(\\(|\\)|\\[|\\]|\\||\\&|\\!|\\=|\\.\\.|[a-zA-Z0-9_]*)"," \\1 ", expression) # strip multiple whitespace characters expression <- gsub("[ ]+", " ", expression) expression <- gsub("^[ ]+", "", expression) expression <- gsub("[ ]+$", "", expression) # split up at whitespace positions res <- strsplit(expression, " ", fixed=TRUE)[[1]] return(res) } # Parse a Boolean function in , # and build a corresponding parse tree. parseBooleanFunction <- function(expression, varNames=c(), lowerCase=FALSE) { minArgCounts <- c("&"=2,"|"=2, "all" = 1, "any" = 1, "maj" = 1, "sumis" = 2, "sumgt" = 2, "sumlt" = 2, "timeis" = 1, "timelt" = 1, "timegt" = 1) maxArgCounts <- c("&"=Inf,"|"=Inf,"all" = Inf, "any" = Inf, "maj" = Inf, "sumis" = Inf, "sumgt" = Inf, "sumlt" = Inf, "timeis" = 1, "timelt" = 1, "timegt" = 1) isBooleanArgument <- function(arg) { return (arg$type %in% c("atom","operator") || arg$type == "constant" && arg$value %in% c(0,1)) } checkPredicate <- function(pred) { if (pred$operator %in% c("&","|","maj")) { for (el in pred$operands) { if (!isBooleanArgument(el)) { stop(paste("Invalid argument to \"",pred$operator,"\": ", stringFromParseTree(el),sep="")) } } } else if (pred$operator %in% c("sumis","sumgt","sumlt")) { for (el in pred$operands[-length(pred$operands)]) { if (!isBooleanArgument(el)) { stop(paste("Invalid argument to \"",pred$operator,"\": ", stringFromParseTree(el),sep="")) } } if (pred$operands[[length(pred$operands)]]$type != "constant") stop(paste("Last argument of \"",pred$operator,"\" must be an integer value!")) } else if (pred$operator %in% c("timeis")) { if (pred$operands[[1]]$type != "constant" || pred$operands[[1]]$value < 0) stop(paste("Argument of \"",pred$operator,"\" must be a non-negative integer value!")) } } # internal function to step forward one symbol advanceSymbol <- function(errorIfEnd = TRUE) { pos <<- pos + 1 #print(symbols[-(1:pos-1)]) if (pos > length(symbols)) if (errorIfEnd) stop("Unexpected end of expression!") else return(NA) else return(symbols[pos]) } getCurrentSymbol <- function() { #print(symbols[-(1:pos-1)]) if (pos > length(symbols)) return(NA) else return(symbols[pos]) } # internal function to preview the next symbol previewSymbol <- function() { if (pos + 1 > length(symbols)) return(NA) else return(symbols[pos + 1]) } getSymbolPos <- function() { return(pos) } setSymbolPos <- function(newPos) { pos <<- newPos } # internal function to parse a sub-expression in brackets parseExpression <- function(temporalVariables = c()) { operators <- c() children <- c() symb <- advanceSymbol() while (TRUE) { if (symb == "(") # a new sub-expression children[[length(children)+1]] <- parseExpression(temporalVariables=temporalVariables) else if (symb == "!") # a negation children[[length(children)+1]] <- parseNegation(temporalVariables=temporalVariables) else if (regexpr("^[a-zA-Z0-9_]*$",symb) == -1) # something unexpected happened stop(paste("Unexpected symbol:",symb)) else children[[length(children)+1]] <- parseAtomOrPredicate(symb, temporalVariables=temporalVariables) symb <- advanceSymbol(FALSE) if (is.na(symb) || symb %in% c(")",",")) # end of expression was reached break if (!symb %in% c("&","|")) stop("Operator expected!") operators <- c(operators,symb) symb <- advanceSymbol() } if (length(children) == 1) { # an operator with only one child return(children[[1]]) } else if (length(unique(operators)) == 1) { # an n-ary operator res <- list(type="operator",operator=operators[1], negated=FALSE, operands=children) checkPredicate(res) return(res) } else # a mixture of multiple operators => ensure correct precedence { i <- 1 startPos <- NA operators <- c(operators, "|") operands <- list() while (i <= length(operators)) # identify AND operators and move them to a subtree { if (operators[i] == "&" && is.na(startPos)) # start of a conjunction startPos <- i if (operators[i] == "|" && !is.na(startPos)) # end of a conjunction => create subtree { subOp <- list(type="operator", operator="&", negated=FALSE, operands=children[startPos:i]) operands[[length(operands)+1]] <- subOp startPos <- NA } else if (is.na(startPos)) operands[[length(operands)+1]] <- children[[i]] i <- i + 1 } res <- list(type="operator",operator="|", negated=FALSE, operands=operands) checkPredicate(res) return(res) } } # internal function to parse atoms or temporal predicates parseAtomOrPredicate <- function(name, temporalVariables=c()) { if (regexpr("^[0-9]*$",name) != -1 || name %in% c("true","false")) # a (Boolean or integer) constant { if (name == "true") value <- 1L else if (name == "false") value <- 0L else value <- as.integer(name) return(list(type="constant", value=value, negated=FALSE)) } if (tolower(name) %in% names(minArgCounts)) # a temporal predicate { name <- tolower(name) # translate all into & and any into | operator <- switch(name, all = "&", any = "|", name) nextSym <- previewSymbol() if (!is.na(nextSym) && nextSym == "[") # a temporal iterator definition follows { # discard bracket advanceSymbol() varName <- advanceSymbol() if (regexpr("^[a-zA-Z0-9_]*$",varName) == -1) # something unexpected happened stop(paste("Unexpected symbol:",varName)) symb <- advanceSymbol() if (symb != "=") { stop(paste("Expected \"=\" instead of \"",symb,"\" in temporal predicate!")) } # parse start time point startTime <- parseTimePoint(temporalVariables=temporalVariables, TRUE) symb <- getCurrentSymbol() if (symb != "..") { stop(paste("Expected \"..\" instead of \"",symb,"\" in temporal predicate!")) } # parse end time point endTime <- parseTimePoint(temporalVariables=temporalVariables, TRUE) symb <- getCurrentSymbol() if (symb != "]") stop(paste("Unexpected symbol:",symb)) } else # no temporal iterator defined { startTime <- 0 endTime <- 0 varName <- NULL } symb <- advanceSymbol() if (symb != "(") stop(paste("Unexpected symbol:",symb)) subElements <- c() while(TRUE) # parse parameters of predicate { oldPos <- getSymbolPos() for (time in startTime:endTime) # expand arguments according to temporal range { tempVars <- temporalVariables if (!is.null(varName)) { if (length(tempVars) > 0 && !is.na(tempVars[varName])) { stop(paste("Duplicate variable ",varName,"! Please use only unique variable names!",sep="")) } tempVars[varName] <- time } # re-parse the argument with a new time point => reset parser position setSymbolPos(oldPos) subElement <- parseExpression(temporalVariables=tempVars) subElements <- c(subElements, list(subElement)) if (subElement$type == "constant") break } subElements <- unique(subElements) symb <- getCurrentSymbol() if (is.na(symb)) stop("Unexpected end of expression!") if (symb == ")") break if (symb != ",") stop ("Expected \",\" or \")\"!") } # check if number of argument matches if (length(subElements) < minArgCounts[name] || length(subElements) > maxArgCounts[name]) stop(paste("Invalid number of arguments to ",name,": ",length(subElements),sep="")) res <- list(type="operator",operator=operator, negated=FALSE, operands=subElements) # check if argument types match checkPredicate(res) return(res) } else # an atom with or without temporal information { nextSym <- previewSymbol() if (!is.na(nextSym) && nextSym == "[") # the atom has a time point specification { symb <- advanceSymbol() time <- parseTimePoint(temporalVariables=temporalVariables) symb <- getCurrentSymbol() if (symb != "]") stop(paste("Unexpected symbol:",symb)) } else # no time point specified => default to previous time point time <- -1L if (length(varNames) > 0) # check if variable is known { varIndex <- which(varNames == name) if (length(varIndex) == 0) stop(paste("Unknown variable:",name)) negated <- FALSE return(list(type="atom", name=name, index=as.integer(varIndex), time=as.integer(time), negated=negated)) } else { return(list(type="atom", name=name, time=as.integer(time), negated=FALSE)) } } } # internal function to parse a time specification parseTimePoint <- function(temporalVariables=c(), allowPositive=FALSE) { symb <- advanceSymbol() time <- 0 while (TRUE) { sign <- 1 if (symb == "+") # ignore positive sign symb <- advanceSymbol() else if (symb == "-") # set multiplier to negative sign { sign <- -1 symb <- advanceSymbol() } if (symb %in% names(temporalVariables)) # a variable was found => add its value { time <- time + sign * temporalVariables[symb] symb <- advanceSymbol() } else # this has to be an integer time value { suppressWarnings(addTime <- as.integer(symb)) if (is.na(addTime)) { stop(paste("Invalid time specification: ",symb, ". Time specifications must be integers <= -1)", sep="")) } time <- time + sign * addTime symb <- advanceSymbol() } if (symb %in% c("]","..")) break } if (time > -1 && !allowPositive) { stop(paste("Invalid time specification: ",time, ". Time specifications must be integers <= -1)", sep="")) } return(as.integer(time)) } # Internal function to parse a negation parseNegation <- function(temporalVariables=c()) { symb <- advanceSymbol() if (symb == "(") { res <- parseExpression(temporalVariables) } else if (symb %in% c(")","&","|","]","[","=")) stop(paste("Unexpected symbol:",symb)) else res <- parseAtomOrPredicate(symb, temporalVariables=temporalVariables) res$negated <- !res$negated return(res) } tryCatch( { symbols <- scan(expression, lowerCase=lowerCase) pos <- 0 res <- parseExpression() }, error = function(e) { stop(sprintf("Error parsing expression \"%s\": %s", expression, e$message)) }) if (!isBooleanArgument(res)) stop(paste("Non-Boolean formula ",stringFromParseTree(res),"!",sep="")) return(res) } # Regenerate the expression string # from the parse tree stringFromParseTree <- function(tree) { res <- switch(tree$type, operator = { if (tree$operator %in% c("|","&")) { paste({if (tree$negated) "!" else ""}, "(", paste(sapply(tree$operands,stringFromParseTree), collapse=paste(" ",tree$operator," ",sep="")), ")", sep="") } else { paste({if (tree$negated) "!" else ""}, tree$operator,"(",paste(sapply(tree$operands,stringFromParseTree), collapse=", "),")",sep="") } }, atom = paste({if (tree$negated) "!" else ""}, tree$name, {if (tree$time != -1) paste("[",tree$time,"]",sep="") else ""}, sep=""), constant = paste({if (tree$negated) "!" else ""}, tree$value, sep="") ) return(res) } BoolNet/R/getStateSummary.R0000644000176200001440000000544213277247010015306 0ustar liggesusers# Summarize information on a state , specified as a vector of # Boolean values. Information is taken from the state tables in . # The function outputs the corresponding attractor, the distance to the basin, # and the next state. getStateSummary <- function(attractorInfo,state) { stopifnot(inherits(attractorInfo,"AttractorInfo") | inherits(attractorInfo,"SymbolicSimulation")) if (inherits(attractorInfo,"SymbolicSimulation")) { if (is.null(attractorInfo$graph)) stop(paste("This SymbolicSimulation structure does not contain transition table information.", "Please re-run simulateSymbolicModel() with returnGraph=TRUE!")) geneCols <- setdiff(colnames(attractorInfo$graph),c("attractorAssignment","transitionsToAttractor")) numGenes <- (length(geneCols)) / 2 stateIndices <- apply(attractorInfo$graph[,seq_len(numGenes),drop=FALSE], 1, function(x) { all(as.integer(x) == as.integer(state)) }) return(attractorInfo$graph[stateIndices,,drop=FALSE]) } else { if (length(state) != length(attractorInfo$stateInfo$genes)) stop("State must have one element for each gene!") if (is.null(attractorInfo$stateInfo$table)) stop(paste("This AttractorInfo structure does not contain transition table information.", "Please re-run getAttractors() with a synchronous search and returnTable=TRUE!")) if (!is.null(attractorInfo$stateInfo$initialStates)) { stateNo <- bin2dec(state,length(state)) # search element in initial state index stateNo <- which(apply(attractorInfo$stateInfo$initialStates,2,function(x) { isTRUE(all.equal(x,stateNo)) })) } else { # find out the decimal number of the state which is used in the # transition table shortenedState <- state[attractorInfo$stateInfo$fixedGenes == -1] # simply use -th elements if initial states are not provided stateNo <- bin2dec(shortenedState,length(shortenedState)) + 1 } # coerce summary into a one-row dataframe, i.e. create a # TransitionTable object with one element res <- as.data.frame(as.list(unlist(list(state, dec2bin(attractorInfo$stateInfo$table[,stateNo], length(attractorInfo$stateInfo$genes)), attractorInfo$stateInfo$attractorAssignment[stateNo], attractorInfo$stateInfo$stepsToAttractor[stateNo])))) colnames(res) <- c(paste("initialState.",attractorInfo$stateInfo$genes,sep=""), paste("nextState.",attractorInfo$stateInfo$genes,sep=""), "attractorAssignment","transitionsToAttractor") class(res) <- c("TransitionTable","data.frame") return(res) } } BoolNet/R/loadNetwork.R0000644000176200001440000001551413277247010014442 0ustar liggesusers# Load a network in a specified rule description language # from file . # is the character that separates targets and factors # specifies whether gene names are converted to lower case loadNetwork <- function(file, bodySeparator=",", lowercaseGenes=FALSE, symbolic=FALSE) { func <- readLines(file,-1) # strip comments func <- gsub("#.*", "", trim(func)) func <- func[nchar(func) > 0] # check header if (length(func) == 0) stop("Header expected!") header <- func[1] header <- tolower(trim(strsplit(header, bodySeparator)[[1]])) if (length(header) < 2 || header[1] != "targets" || !(header[2] %in% c("functions","factors")) || (length(header) == 3 && header[3] != "probabilities")) stop(paste("Invalid header:", func[1])) func <- func[-1] if (lowercaseGenes) func <- tolower(func) # Replace all invalid characters to be able to load most networks func <- gsub("[^\\[\\]a-zA-Z0-9_\\|\\&!\\(\\) \t\\-+=.,]+","_", func, perl=TRUE) tmp <- unname(lapply(func,function(x) # split strings at separators that are NOT # inside a bracket block { bracketCount <- 0 lastIdx <- 1 chars <- strsplit(x,split="")[[1]] res <- c() if (length(chars) > 0) { for (i in seq_along(chars)) { if (chars[i] == "(") bracketCount <- bracketCount + 1 else if (chars[i] == ")") bracketCount <- bracketCount -1 else if (chars[i] == bodySeparator && bracketCount == 0) { res <- c(res, trim(paste(chars[lastIdx:(i-1)],collapse=""))) lastIdx <- i + 1 } } res <- c(res, trim(paste(chars[lastIdx:length(chars)],collapse=""))) } return(res) })) targets <- sapply(tmp,function(rule)trim(rule[1])) for (target in targets) { if (regexec("^[a-zA-Z_][a-zA-Z0-9_]*$", target)[[1]] == -1) stop(paste("Invalid gene name:",target)) } factors <- sapply(tmp,function(rule)trim(rule[2])) temporal <- length(grep("timeis|timelt|timegt|\\[|\\]", factors, ignore.case=TRUE) > 0) if (temporal && !symbolic) { warning("The network contains temporal elements. This requires loading the model with symbolic=TRUE!") symbolic <- TRUE } probabilities <- sapply(tmp,function(rule) { if (length(rule) >= 3) as.numeric(trim(rule[3])) else 1.0 }) factors.tmp <- lapply(factors,matchNames) # create list of all gene names in both sides of the functions genes <- unique(c(targets,unname(unlist(factors.tmp)))) isProbabilistic <- (length(unique(targets)) < length(targets)) if (symbolic) { if (isProbabilistic) stop("Probabilistic networks cannot be loaded with symbolic=TRUE!") interactions <- lapply(factors, function(rule)parseBooleanFunction(rule, genes)) onlyInputs <- setdiff(genes,targets) if(length(onlyInputs) > 0) # some genes are only used as inputs, but are not involved in the network # -> create dummy input and function { for(gene in onlyInputs) { warning(paste("There is no transition function for gene \"", gene,"\"! Assuming an input!",sep="")) interactions[[gene]] = parseBooleanFunction(gene, genes) } } delays <- apply(sapply(interactions,maxTimeDelay,genes=genes),1,max) names(interactions) <- genes fixed <- as.integer(sapply(interactions, function(int) { if (int$type == "constant") int$value else -1L })) names(fixed) <- genes res <- list(genes = genes, interactions=interactions, fixed=fixed) res$internalStructs <- .Call("constructNetworkTrees_R",res) res$timeDelays <- delays class(res) <- "SymbolicBooleanNetwork" return(res) } else { # extract "real" gene names from the list, drop constants #suppressWarnings(genes <- genes[is.na(as.integer(genes))]) fixed <- rep(-1,length(genes)) names(fixed) <- genes interactions <- list() for(i in seq_along(targets)) { target <- targets[i] interaction <- generateInteraction(factors[i], genes); if (isProbabilistic) { interaction$probability <- probabilities[i] interactions[[target]][[length(interactions[[target]]) + 1]] <- interaction } else { if (length(interaction$func) == 1) # this is a constant gene => fix it { fixed[target] <- interaction$func } interactions[[target]] <- interaction } } onlyInputs <- setdiff(genes,targets) if(length(onlyInputs) > 0) # some genes are only used as inputs, but are not involved in the network # -> create dummy input and function { for(gene in onlyInputs) { warning(paste("There is no transition function for gene \"", gene,"\"! Assuming an input!",sep="")) if (isProbabilistic) interactions[[gene]][[1]] = list(input = length(interactions)+1,func=c(0,1), expression = gene, probability=1.0) else interactions[[gene]] = list(input = length(interactions)+1,func=c(0,1), expression = gene) } } if (isProbabilistic) { wrongProb <- sapply(interactions,function(interaction) { abs(1.0-sum(sapply(interaction,function(func)func$probability))) > 0.0001 }) if (any(wrongProb)) stop(paste("The probabilities of gene(s) ",paste(genes[wrongProb],collapse=", ")," do not sum up to 1!",sep="")) } res <- list(interactions = interactions, genes = genes, fixed = fixed) if (isProbabilistic) class(res) <- "ProbabilisticBooleanNetwork" else class(res) <- "BooleanNetwork" return(res) } } matchNames <- function(rule) { regexpr <- "([_a-zA-Z][_a-zA-Z0-9]*)[,| |\\)|\\||\\&|\\[]" rule <- paste(gsub(" ", "", rule, fixed=TRUE)," ",sep="") res <- unique(unname(sapply(regmatches(rule,gregexpr(regexpr, rule))[[1]], function(m) { sapply(regmatches(m,regexec(regexpr,m)),function(x)x[2]) }))) # remove operators isOp <- sapply(res, function(x) { tolower(x) %in% c("all", "any", "sumis", "sumgt", "sumlt", "maj", "timegt", "timelt", "timeis") }) return(res[!isOp]) } BoolNet/R/print.BooleanStateInfo.R0000644000176200001440000000050713277247010016474 0ustar liggesusers# Custom print function for class BooleanStateInfo print.BooleanStateInfo <- function(x, activeOnly=FALSE, ...) { # Create a TransitionTable object and print it cat("Transition table of Boolean network\n\n") transitionTable <- .internal.getTransitionTable(x) print(transitionTable, activeOnly=activeOnly, ...) } BoolNet/R/attractorsToLaTeX.R0000644000176200001440000001450413277247010015536 0ustar liggesusers# Create LaTeX state tables of all attractors in . # Genes are grouped according to . # An additional title can be supplied in . # If <plotFixed> is set, fixed variables are included in the plot. # <onColor> and <offColor> specify the colors of ON/1 and OFF/0 states. # <file> is the name of the output LaTeX document. attractorsToLaTeX <- function (attractorInfo, subset, title = "", grouping = list(), plotFixed = TRUE, onColor="[gray]{0.9}",offColor="[gray]{0.6}", reverse=FALSE, file="attractors.tex") { stopifnot(inherits(attractorInfo,"AttractorInfo") || inherits(attractorInfo, "SymbolicSimulation")) if (inherits(attractorInfo,"AttractorInfo")) { numGenes <- length(attractorInfo$stateInfo$genes) geneNames <- attractorInfo$stateInfo$genes } else { numGenes <- ncol(attractorInfo$attractors[[1]]) geneNames <- colnames(attractorInfo$attractors[[1]]) } if (missing(subset)) subset <- seq_along(attractorInfo$attractors) else if (any(subset > length(attractorInfo$attractors))) stop("You specified an attractor index that is greater than the total number of attractors in 'subset'!") # escape "_" in LaTeX genes = gsub("_", "\\_", attractorInfo$stateInfo$genes) # determine list of genes to be plotted whichFixed <- which(attractorInfo$stateInfo$fixedGenes != -1) if (plotFixed | (length(whichFixed) == 0)) plotIndices <- seq_len(numGenes) else plotIndices <- (seq_len(numGenes))[-whichFixed] if (inherits(attractorInfo,"AttractorInfo")) { # convert decimal state numbers to binary state matrices (one for each attractor) binMatrices <- lapply(attractorInfo$attractors,function(attractor) { res <- matrix(apply(attractor$involvedStates,2,function(state) dec2bin(state,numGenes)[plotIndices]),nrow=length(plotIndices)) }) # count the numbers of attractors with equal lengths attractorLengths <- sapply(attractorInfo$attractors,function(attractor) { if (is.null(attractor$initialStates)) # simple attractor ncol(attractor$involvedStates) else # complex attractor => extra treatment -1 }) } else { binMatrices <- lapply(attractorInfo$attractors, t) attractorLengths <- sapply(binMatrices, ncol) } lengthTable <- table(attractorLengths) lengthTable <- lengthTable[as.integer(names(lengthTable)) != -1] # Open output file, and print header sink(file) cat("% Please include packages tabularx and colortbl in your master document:\n", "% \\usepackage{tabularx,colortbl}\n\n\n",sep="") res <- lapply(seq_along(lengthTable),function(i) # accumulate all attractors with equal length in one matrix and plot them { len <- as.integer(names(lengthTable)[i]) attractorIndices <- intersect(which(attractorLengths == len), subset) if (length(attractorIndices) > 0) { # build accumulated matrix totalMatrix <- c() for (mat in binMatrices[attractorIndices]) { totalMatrix <- cbind(totalMatrix,mat) } rownames(totalMatrix) <- geneNames[plotIndices] colnames(totalMatrix) <- sapply(attractorIndices,function(i)paste("Attr",i,".",seq_len(len),sep="")) if(length(grouping)>0) { # reorder genes according to the supplied groups totalMatrix <- totalMatrix[unlist(grouping$index),] separationPositions <- c(1,cumsum(sapply(grouping$index,length)+1)) } else separationPositions <- c() # output table header cat("\\begin{table}[ht]\n", "\\begin{center}\n", "\\caption{", title, "Attractors with ",len," state(s)}\n", "\\begin{tabularx}{\\linewidth}{l", paste(rep(paste(rep(">{\\centering\\arraybackslash}X", len), collapse = " "),length(intersect(which(attractorLengths == len),subset))),collapse="|"), "}\\hline\n", sep="") cat("\t&\t",paste(paste("\\multicolumn{",len,"}{c}{Attr. ",intersect(which(attractorLengths == len),subset),"}", sep=""),collapse="\t&\t"),"\\\\\n") # output active and inactive states if (reverse) indices <- rev(seq_len(nrow(totalMatrix))) else indices <- seq_len(nrow(totalMatrix)) for(j in indices) { separator <- which(separationPositions==j) if (length(separator) != 0) { cat("\\hline \\multicolumn{",ncol(totalMatrix) + 1,"}{c}{",grouping$class[separator],"}\\\\ \\hline \n",sep="") } cat("\\textbf{",rownames(totalMatrix)[j],"}\t&\t",sep="") for(i in seq_len(ncol(totalMatrix))) { if(totalMatrix[j,i] == 1) cat("\\cellcolor",onColor,"1",sep="") else cat("\\cellcolor",offColor,"0",sep="") if (i < ncol(totalMatrix)) cat("\t&\t") } cat("\\\\\n") } # output frequency of attractor (basin size / number of states) if (inherits(attractorInfo,"AttractorInfo")) { if (is.null(attractorInfo$stateInfo$table)) freq <- rep(NA, length(attractorIndices)) else freq <- round(sapply(attractorInfo$attractors[attractorIndices], function(attractor)attractor$basinSize/ncol(attractorInfo$stateInfo$table)) * 100,2) } else { if (!is.null(attractorInfo$graph)) { freq <- round(sapply(attractorIndices, function(i)sum(attractorInfo$graph$attractorAssignment == i)/ nrow(attractorInfo$graph)) * 100,2) } else freq <- rep(NA, length(attractorIndices)) } if (!isTRUE(all(is.na(freq)))) { cat("\\hline Freq.\t&\t",paste(paste("\\multicolumn{",len,"}{c}{",freq,"\\%}", sep=""),collapse="\t&\t"),"\\\\\n") } cat("\\hline\\end{tabularx}\n\\end{center}\n", "\\end{table}\n\n",sep="") totalMatrix } }) # return a list of accumulated matrices sink() names(res) <- names(lengthTable) return(res) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/scanStatistic.R���������������������������������������������������������������������������0000644�0001762�0000144�00000007227�13277247010�014767� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# determination of P(k,N,w) pval <- function(k,N,w) { return((k/w-N-1)*b(k,N,w)+2*Gb(k,N,w)) } # helper function b<-function(k,N,w) { return(choose(N,k)*w^k*(1-w)^(N-k)) } # helper function Gb<-function(k,N,w) { sum<-0 for(i in k:N) { sum <- sum + b(i,N,w) } return(sum) } # If two significant overlapping windows were found, these windows are # merged. If the windows do not overlap, two different windows are stored # in a list listadapt <- function(lcur,lnew) { if(length(lcur)==0) { lcur=lnew return(lcur) } else { if(lnew[[1]][1]<=lcur[[length(lcur)]][2]) { lcur[[length(lcur)]][2]<-lnew[[1]][2] if(lcur[[length(lcur)]][3]>lnew[[1]][3]) { lcur[[length(lcur)]][3] <- lnew[[1]][3] } return(lcur) } else { lcur<-append(lcur,lnew) return(lcur) } } } # This method searches for data accumulations by shifting a window with # window size <w> across the data and deciding at each position if there # is a data accumulation. To test this, a scan statistic with significance # level <sign.level> is used. scanStatistic <- function(vect, w=0.25, sign.level=0.1) { temp<-vect vect <-unlist(vect) vsort <- sort(vect) N <- length(vect) range <- (max(vect)) - (min(vect)) windowsize <- range*w N <- length(vect) binarizeddata<-temp res<-list() lcur<-list() # shift a fixed window over the data # the window is moved from point to point for(i in seq_along(vect)) { start <- vsort[i] stop <- vsort[i] + windowsize k <- length(vect[(vect >= start) & (vect <= stop)]) p <- pval(k,N,w) if(p>1) { p=0.99 } if(p<=sign.level & p>0 & k >= (N*w-1) & k > 2) { res <- listadapt(res,list(c(start,stop,p))) } } # if no accumulation for a fixed <sign.level> was found, the # binarization is rejected, and we search for a accumulation # with a higher sign.level. if(length(res)==0) { while(TRUE) { sign.level=sign.level+0.05 if(sign.level>2) { binarizeddata<-(sapply(vect,function(x) 0)) return(list(bindata=binarizeddata,thresholds=NA,reject=TRUE)) } for(i in seq_along(vect)) { start <- vsort[i] stop <- vsort[i] + windowsize k <- length(vect[(vect >= start) & (vect <= stop)]) p <- pval(k,N,w) if(p>1) { p=0.99 } if(p<=sign.level & p>0 & k >= (N*w-1) & k > 2) { #res <- append(res,list(c(start=start,stop=stop,pval=p))) res <- listadapt(res,list(c(start,stop,p))) } } if(length(res)!=0) break } reject<-TRUE } else { reject<-FALSE } # search the window with the smallest sign.level. # this window is used for the binarization min=1000 ind=0 for(i in seq_along(res)) { if(res[[i]][3]<min) { ind=i min=res[[i]][3] } } # are more points on the left or on the right side # of the window? Based on this, the binarization is performed bigger <- length(vect[vect > res[[ind]][2]]) smaller <- length(vect[vect < res[[ind]][1]]) if(bigger > smaller) { threshold<-res[[ind]][2] small<-tail(vsort[vsort<=threshold],n=1) big<-vsort[vsort>threshold][1] thres<-(big+small)/2 for(i in seq_along(vect)) { if(vect[i]<=threshold) { binarizeddata[i]<-0 } else { binarizeddata[i]<-1 } } } else { threshold<-res[[ind]][1] small<-tail(vsort[vsort<threshold],n=1) big<-vsort[vsort>=threshold][1] thres<-(big+small)/2 for(i in seq_along(vect)) { if(vect[i]>=threshold) { binarizeddata[i]<-1 } else { binarizeddata[i]<-0 } } } return(list(bindata=binarizeddata,thresholds=as.numeric(thres),reject=reject)) } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/zeta.R������������������������������������������������������������������������������������0000644�0001762�0000144�00000001440�13277247010�013105� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ # Distribution function of the Zeta distribution dzeta <- function(k,gamma=2.5,approx_cutoff=100) { zeta_approx <- sum(sapply(seq_len(approx_cutoff),function(x)1/(x^gamma))) sapply(k,function(k_i) { 1/(k_i^gamma * zeta_approx) }) } # Quantile function of the Zeta distribution qzeta <- function(p,maxK,gamma=2.5,approx_cutoff=100) { vals <- cumsum(dzeta(seq_len(maxK),gamma,approx_cutoff)) sapply(p,function(p_i) { indices <- which(vals > p_i) if (length(indices) == 0) return(NA) else return(indices[1]) }) } # Draw random numbers from the Zeta distribution rzeta <- function(n,maxK,gamma=2.5,approx_cutoff=100) { maxP <- cumsum(dzeta(seq_len(maxK),gamma,approx_cutoff)) p <- runif(min=0,max=maxP,n=n) return(qzeta(p,maxK,gamma,approx_cutoff)) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/getTransitionProbabilities.R��������������������������������������������������������������0000644�0001762�0000144�00000001777�13277247010�017522� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Builds a matrix of transitions and their probabilities from <markovSimulation> getTransitionProbabilities <- function(markovSimulation) { stopifnot(inherits(markovSimulation,"MarkovSimulation")) if (is.null(markovSimulation$table)) stop(paste("The supplied simulation result does not contain transition information.", "Please re-run markovSimulation() with returnTable=TRUE!")) initialStates <- t(apply(markovSimulation$table$initialStates,2,dec2bin,length(markovSimulation$genes))) nextStates <- t(apply(markovSimulation$table$nextStates,2,dec2bin,length(markovSimulation$genes))) idx <- order(apply(initialStates,1,function(x)paste(x,collapse=""))) res <- data.frame(initialStates,nextStates,markovSimulation$table$probabilities) res <- res[idx,] rownames(res) <- NULL colnames(res) <- c(paste("initialState.",markovSimulation$genes,sep=""), paste("nextState.",markovSimulation$genes,sep=""), "probability") return(res) } �BoolNet/R/loadBioTapestry.R�������������������������������������������������������������������������0000644�0001762�0000144�00000021673�13277247010�015261� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Parse all nodes in <rootNode> # (i.e., all nodes of a certain type), # and write them to a list parseGeneAttrs <- function(rootNode) { i <- 0 res <- xmlApply(rootNode,function(child) { i <<- i + 1 attrs <- xmlAttrs(child) name <- unname(attrs["name"]) if (name == "" | is.na(name)) name <- paste(xmlName(child),i,sep="_") # find the "simulationLogic" node, which contains # the necessary logic information logic <- xmlFindNode(child,"simulationLogic") initVal <- NULL if (is.null(logic)) { warning(paste("Gene ",name," does not specify a simulation logic, assuming AND!",sep="")) logic <- "AND" } else { # try to find initial values in the simulation parameters logic <- logic[[1]] params <- xmlFindNode(logic,"simParameters") if (!is.null(params)) { for (param in xmlChildren(params[[1]])) { pa <- xmlAttrs(param) if (pa["name"] == "initVal") { initVal <- as.numeric(pa["value"]) if (initVal != 0 & initVal != 1) # only 0 and 1 are allowed for the initialization { warning("Initial value for gene ",name," is neither 0 nor 1 and is ignored!",sep="") initVal <- NULL } break } } } # get the Boolean function of the node logic <- unname(xmlAttrs(logic)["type"]) } list(id=unname(attrs["id"]), name=adjustGeneNames(name),logic=logic,initVal=initVal,inputs=NULL) }) } # Parse all types of nodes (genes, signals, etc) parseAllGenes <- function(rootNode) { genes <- unlist(xmlApply(rootNode,parseGeneAttrs),recursive=FALSE) names(genes) <- lapply(genes,function(gene)gene$id) return(genes) } # Parse the links in the children of <node> and insert them # into the input lists of the genes parseAllLinks <- function(rootNode,geneList) { for (link in xmlChildren(rootNode)) { attrs <- xmlAttrs(link) if (is.na(attrs["sign"])) # a link with unspecified direction (inhibition or activation) was found { warning(paste("The link between \"",geneList[[attrs["src"]]]$name, "\" and \"",geneList[[attrs["targ"]]]$name, "\" is not specified as an enhancer or suppressor and is therefore ignored!",sep="")) } else { geneList[[attrs["targ"]]]$input[[length(geneList[[attrs["targ"]]]$input) + 1]] <- list(input=unname(attrs["src"]),sign=attrs["sign"]) } } return(geneList) } # Load a BioTapestry file (*.btp) from <file> # and convert it to a Boolean network loadBioTapestry <- function(file, symbolic=FALSE) { doc <- xmlRoot(xmlTreeParse(file)) # detect the "genome" XML node which holds the nodes and links of the network genome <- xmlFindNode(doc,"genome",throwError=TRUE)[[1]] # find the "nodes" node that contains all genes/inputs/etc nodes <- xmlFindNode(genome,"nodes",throwError=TRUE)[[1]] # read in genes geneList <- parseAllGenes(nodes) # find the "links" node that contains the links/dependencies links <- xmlFindNode(genome,"links",throwError=TRUE)[[1]] # add links to gene list geneList <- parseAllLinks(links,geneList) # build up network structure genes <- unname(sapply(geneList,function(gene)gene$name)) geneIds <- names(geneList) fixed <- rep(-1L,length(genes)) i <- 0 interactions <- lapply(geneList,function(gene) { i <<- i + 1 input <- sapply(gene$input,function(inp) { which(geneIds == inp$input) }) if (length(input) == 0) { if (!is.null(gene$initVal)) # input-only gene without fixed value (=> depending on itself) { input <- 0 func <- gene$initVal fixed[i] <<- func expr <- func } else # input-only gene with fixed value { input <- i func <- c(0,1) expr <- gene$name } } else # dependent gene { # determine signs/negations of genes inputSigns <- sapply(gene$input,function(inp)inp$sign) if (!symbolic || gene$logic == "XOR") { tt <- as.matrix(allcombn(2,length(input)) - 1) func <- as.integer(switch(gene$logic, AND = { # calculate truth table for AND apply(tt,1,function(assignment) { res <- 1 for (i in seq_along(assignment)) { if (inputSigns[i] == "+") res <- res & assignment[i] else res <- res & !assignment[i] if (!res) break } res }) }, OR = { # calculate truth table for OR apply(tt,1,function(assignment) { res <- 0 for (i in seq_along(assignment)) { if (inputSigns[i] == "+") res <- res | assignment[i] else res <- res | !assignment[i] if (res) break } res }) }, XOR = { # calculate truth table for XOR apply(tt,1,function(assignment) { res <- assignment[1] for (i in 2:length(assignment)) { res <- xor(res,assignment[i]) } res }) }, stop(paste("Unknown Boolean operator \"", gene$logic,"\"!",sep="")) )) } # get string representation of the input gene literals literals <- mapply(function(gene,sign) { if (sign == "+") gene else paste("!",gene,sep="") }, genes[input], inputSigns) # get string representation of function expr <- switch(gene$logic, AND = { paste(literals,collapse=" & ") }, OR = { paste(literals,collapse=" | ") }, XOR = { getDNF(func,genes[input]) } ) } if (symbolic) return(parseBooleanFunction(expr,varNames=genes)) else return(list(input=input,func=func,expression=expr)) }) names(interactions) <- genes fixed <- as.integer(fixed) names(fixed) <- genes net <- list(genes=genes,interactions=interactions,fixed=fixed) if (symbolic) { net$timeDelays <- apply(sapply(net$interactions,maxTimeDelay,genes=net$genes),1,max) net$internalStructs <- .Call("constructNetworkTrees_R",net) class(net) <- "SymbolicBooleanNetwork" } else class(net) <- "BooleanNetwork" return(net) } ���������������������������������������������������������������������BoolNet/R/generateState.R���������������������������������������������������������������������������0000644�0001762�0000144�00000001753�13277247010�014744� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������generateState <- function(network, specs, default=0) { stopifnot(inherits(network,"ProbabilisticBooleanNetwork") || inherits(network,"BooleanNetwork") || inherits(network,"SymbolicBooleanNetwork")) if (!all(names(specs) %in% network$genes)) stop(paste("Undefined gene names:", paste(setdiff(names(specs), network$genes), collapse=", "))) if (!all(unlist(specs) %in% c(0,1))) stop("Please provide only Boolean values!") lengths <- unique(sapply(specs, length)) if (length(lengths) > 1) stop("The number of specifications for each gene must be the same!") if (lengths == 1) { state <- rep(default, length(network$genes)) names(state) <- network$genes state[names(specs)] <- specs } else { state <- matrix(rep(default, length(network$genes) * lengths), nrow=lengths) colnames(state) <- network$genes for (i in seq_along(specs)) state[,names(specs)[i]] <- specs[[i]] } return(state) } ���������������������BoolNet/R/simplifyNetwork.R�������������������������������������������������������������������������0000644�0001762�0000144�00000007050�13277247010�015353� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Simplify a Boolean network by dropping all input genes that are not relevant # for the output simplifyNetwork <- function(network,readableFunctions=FALSE) { stopifnot(inherits(network,"BooleanNetwork") | inherits(network,"ProbabilisticBooleanNetwork") | inherits(network,"BooleanNetworkCollection")) if (inherits(network,"BooleanNetwork")) { network$interactions <- mapply(function(interaction, j) { if (interaction$input[1] != 0) # no constant gene { table <- allcombn(2,length(interaction$input)) - 1 dropGenes <- apply(table,2,function(gene) # drop all genes that have no influence on the results, # i.e. the result column is equal for 0 values and 1 values { (identical(interaction$func[gene==1], interaction$func[gene==0])) }) if (sum(!dropGenes) == 0) { network$fixed[j] <<- interaction$func[1] interaction$input <- 0 interaction$func <- interaction$func[1] } else if (sum(dropGenes) > 0) { # update network network$fixed[j] <<- -1 dropFunctionIndices <- unlist(sapply(seq_along(dropGenes),function(i) { if(dropGenes[i]) which(table[,i] == 0) else NULL })) interaction$input <- interaction$input[!dropGenes] interaction$func <- interaction$func[-dropFunctionIndices] interaction$expression <- getInteractionString(readableFunctions, interaction$func, network$genes[interaction$input]) } } interaction }, network$interactions, seq_along(network$interactions), SIMPLIFY=FALSE) } else { network$interactions <- lapply(network$interactions,function(gene) lapply(gene,function(interaction) { if (interaction$input[1] != 0) # no constant gene { table <- allcombn(2,length(interaction$input)) - 1 dropGenes <- apply(table,2,function(gene) # drop all genes that have no influence on the results, # i.e. the result column is equal for 0 values and 1 values { (identical(interaction$func[gene==1], interaction$func[gene==0])) }) if (sum(!dropGenes) == 0) { interaction$input <- 0 interaction$func <- interaction$func[1] } else if (sum(dropGenes) > 0) { # update network dropFunctionIndices <- unlist(sapply(seq_along(dropGenes),function(i) { if(dropGenes[i]) which(table[,i] == 0) else NULL })) interaction$input <- interaction$input[!dropGenes] interaction$func <- interaction$func[-dropFunctionIndices] interaction$expression <- getInteractionString(readableFunctions, interaction$func, network$genes[interaction$input]) } } interaction })) } return(network) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/helpers.R���������������������������������������������������������������������������������0000644�0001762�0000144�00000025624�13301250335�013606� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ # Encode a vector of binary values <bin> with <len> bits # to a decimal number bin2dec <- function(bin,len) { if (len %% 32 == 0) numElts <- as.integer(len / 32) else numElts <- as.integer(len / 32) + 1 dec = rep(0,numElts) dec = .C("bin2decC",as.integer(dec),as.integer(bin),as.integer(len))[[1]] } # Decode the <len> low-order bits of <dec> to a vector of binary values, # where the first entry is the least significant bit dec2bin <- function(dec,len) { bin = rep(0,len) bin = .C("dec2binC",as.integer(bin),as.integer(dec),as.integer(len),NAOK=TRUE)[[1]] } # Generate a list of all assignments of n variables with N possible values allcombn <- function(N,n) { rownum = N^n sapply(n:1,function(i) { rep(seq_len(N),each=N^(i-1),len=rownum) }) } # Get DNF representation of a truth table <truthTable> # using the gene names in <genes>. # If <mode> is "canonical", build a canonical DNF. # If <mode> is "short", join terms to reduce the DNF getDNF <- function(truthTable, genes, mode = c("short","canonical")) { if (mode[1] == TRUE) mode <- (if (length(genes) <= 12) "short" else "canonical") mode <- match.arg(mode, c("short","canonical")) # check for constant functions if (isTRUE(all.equal(truthTable,rep(0,length(truthTable))))) return("0") else if (isTRUE(all.equal(truthTable,rep(1,length(truthTable))))) return("1") # generate truth table entries <- allcombn(2,length(genes)) - 1 colnames(entries) <- genes if (mode == "short") { # heuristic minimization # the 1 terms that need to be covered uncoveredEntries <- which(truthTable == 1) # current conjunction list conjunctions <- list() while (length(uncoveredEntries) > 0) { # take an uncovered entry and expand it currentEntry <- entries[uncoveredEntries[1],] for (gene in genes) # test for each gene whether it can be eliminated from the term { geneIdx <- which(names(currentEntry) == gene) candidate <- currentEntry[-geneIdx] condition <- rep(TRUE,length(truthTable)) for (i in seq_along(candidate)) { condition <- condition & (entries[,names(candidate)[i]] == candidate[i]) } if (length(unique(truthTable[condition])) == 1) # eliminate gene currentEntry <- currentEntry[-geneIdx] } # determine which truth table result entries are now covered eliminatedEntries <- rep(TRUE,length(truthTable)) for (i in seq_along(currentEntry)) { eliminatedEntries <- eliminatedEntries & (entries[,names(currentEntry)[i]] == currentEntry[i]) } uncoveredEntries <- setdiff(uncoveredEntries, which(eliminatedEntries)) # remember conjunction conjunctions <- c(conjunctions, list(currentEntry)) } return(paste(paste("(",sapply(conjunctions, function(conj) { paste(mapply(function(gene, val) { if (val == 1) return(gene) else return(paste("!",gene,sep="")) }, names(conj), conj), collapse=" & ") }), ")", sep=""), collapse=" | ")) } else { # canonical DNF conjunctions <- apply(entries[truthTable==1,,drop=FALSE],1,function(conj) { paste("(",paste(sapply(seq_along(conj),function(lit) { if (conj[lit]) genes[lit] else paste("!",genes[lit],sep="") }),collapse=" & "),")",sep="") }) return(paste(conjunctions[conjunctions != ""],collapse = " | ")) } } # Retrieves a string representation of an interaction function by either # building a DNF (if <readableFunction> is false) # or returning an unspecific function description # (if <readableFunction> is true or "canonical" or "short"). # <truthTable> contains the result column of the interaction's truth table, and # <genes> contains the names of the involved genes. getInteractionString <- function(readableFunctions,truthTable,genes) { if (readableFunctions != FALSE) getDNF(truthTable,genes, readableFunctions) else { if (isTRUE(all.equal(truthTable,rep(0,length(truthTable))))) return("0") else if (isTRUE(all.equal(truthTable,rep(1,length(truthTable))))) return("1") else { truthTable <- sapply(truthTable,function(x) { if (x == 0) "0" else if (x == 1) "1" else "*" }) paste("<f(", paste(genes,collapse=","),"){", paste(truthTable,collapse=""),"}>", sep="") } } } # Reorders a matrix of states <stateMatrix> (with each column being one state) # in a canonical way such that the "smallest" state is the first. # This makes attractor representations unique. canonicalStateOrder <- function(stateMatrix) { smallestIndex <- -1 smallestVal <- rep(Inf,nrow(stateMatrix)) for (i in seq_len(ncol(stateMatrix))) # iterate over states { for (j in seq_len(nrow(stateMatrix))) # iterate over elements of encoded state { if (stateMatrix[j,i] < smallestVal[j]) # determine new minimum { smallestVal <- stateMatrix[,i] smallestIndex <- i break } else { if (stateMatrix[j,i] > smallestVal[j]) break } } } if (smallestIndex != 1) # rearrange matrix return(cbind(stateMatrix[,smallestIndex:ncol(stateMatrix),drop=FALSE], stateMatrix[,seq_len(smallestIndex-1),drop=FALSE])) else return(stateMatrix) } # Find a child node named <name> # of <node>, or return NULL if such a node # does not exist. # If <throwError>, throw an error if the node does not exist. xmlFindNode <- function(node,name,throwError=FALSE) { indices <- which(xmlSApply(node, xmlName) == name) if (length(indices) == 0) { if (throwError) stop(paste("Node \"",name,"\" is required, but missing!", sep="")) else return(NULL) } return(xmlChildren(node)[indices]) } # Remove leading and trailing whitespace characters from <string> trim <- function(string) { string <- gsub("^[ \t]+", "", string) string <- gsub("[ \t]+$", "", string) return(string) } # Generate an interaction by parsing <expressionString> # and building the corresponding truth table. # Here, <genes> is a list of all genes in the network. # Returns an interaction as used in the BooleanNetwork class. generateInteraction <- function(expressionString, genes) { res <- .Call("getTruthTable_R", parseBooleanFunction(expressionString, genes), length(genes)) names(res) <- c("input","func") res$expression <- expressionString return(res) } # Create a DNF from a count predicate # ("maj","sumis","sumgt","sumlt"). # <tree> is the expression tree of the predicate # Returns an expression tree in DNF expandCountPredicate <- function(tree) { if (tree$operator == "maj") { if (length(tree$operands) %%2 == 0) count <- length(tree$operands) / 2 else count <- floor(length(tree$operands) / 2) operands <- tree$operands } else { count <- tree$operands[[length(tree$operands)]]$value operands <- tree$operands[-length(tree$operands)] } table <- as.matrix(allcombn(2,length(operands)) - 1) tableRes <- as.integer(apply(table,1,function(x) { switch(tree$operator, "maj" = sum(x) > count, "sumgt" = sum(x) > count, "sumlt" = sum(x) < count, "sumis" = sum(x) == count ) })) return(parseBooleanFunction(getDNF(tableRes, sapply(operands, stringFromParseTree)))) } # Get the inputs for an expression tree <tree>. # If <index> is TRUE, the indices are returned instead of the gene names. # Returns a vector of gene names. getInputs <- function(tree, index=FALSE) { res <- switch(tree$type, operator = { unique(unlist(lapply(tree$operands, getInputs, index=index))) }, atom = { if (index) tree$index else tree$name }, constant = { NULL } ) return(res) } # Determine the maximum time delays for the genes <genes> # in a symbolic expression tree <tree>. # Returns a vector of time delays for the genes. maxTimeDelay <- function(tree, genes) { res <- switch(tree$type, operator = { timeDelays <- sapply(tree$operands, maxTimeDelay, genes=genes) if (!is.null(dim(timeDelays))) apply(timeDelays,1,max) else timeDelays }, atom = { res <- rep(1,length(genes)) names(res) <- genes res[tree$index] <- -tree$time res }, constant = { res <- rep(1,length(genes)) names(res) <- genes res } ) return(res) } # Convert <geneNames> into valid identifiers # by replacing special characters # Returns a vector of adjusted gene names. adjustGeneNames <- function(geneNames) { # eliminate special characters res <- gsub("[^a-zA-Z0-9_]+","_",geneNames) # ensure that identifier does not start with a number res <- gsub("(^[0-9][a-zA-Z0-9_]*)$","_\\1", res) names(res) <- geneNames return(res) } # Check whether the internal C pointer <ptr> is null checkNullPointer <- function(ptr) { return(.Call("checkNullPointerC",ptr)) } # Print a synchronous attractor specified by a data frame <attractor> # The attractor has the index <index> and a basin consisting of <basinSize> states. # If <activeOnly> is true, states are represented as a list of active genes (otherwise binary vectors). printSynchronousAttractor <- function(attractor, index, basinSize=NA, activeOnly=FALSE) { if (is.na(basinSize)) cat("Attractor ",index," is a simple attractor consisting of ", nrow(attractor), " state(s)",sep="") else cat("Attractor ",index," is a simple attractor consisting of ", nrow(attractor), " state(s) and has a basin of ", basinSize, " state(s)",sep="") # print a graphical representation of the attractor cycle if (activeOnly) { cat(".\nActive genes in the attractor state(s):\n") for (j in seq_len(nrow(attractor))) { state <- paste(colnames(attractor)[which(attractor[j,] == 1)],collapse=", ") if (state == "") state <- "--" cat("State ", j, ": ", state, "\n", sep="") } cat("\n") } else { cat(":\n\n") numGenes <- ncol(attractor) cat(" |--<", paste(rep("-",numGenes-1), collapse=""),"|\n", sep="") cat(" V ", paste(rep(" ",numGenes-1), collapse="")," |\n", sep="") for (j in seq_len(nrow(attractor))) { cat(" ", as.integer(attractor[j,])," |\n",sep="") #cat(" | ", paste(rep(" ",numGenes-1), collapse="")," |\n", sep="") } cat(" V ", paste(rep(" ",numGenes-1), collapse=""), " |\n", sep="") cat(" |-->", paste(rep("-",numGenes-1), collapse=""), "|\n\n", sep="") } if (!activeOnly) cat("\nGenes are encoded in the following order: ", paste(colnames(attractor), collapse=" "), "\n\n", sep="") } ������������������������������������������������������������������������������������������������������������BoolNet/R/getTransitionTable.R����������������������������������������������������������������������0000644�0001762�0000144�00000004363�13277247010�015753� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Retrieves the transition table of an AttractorInfo structure # in a readable way getTransitionTable <- function(attractorInfo) { stopifnot(inherits(attractorInfo,"AttractorInfo") || inherits(attractorInfo,"SymbolicSimulation")) if (inherits(attractorInfo,"SymbolicSimulation")) { if (is.null(attractorInfo$graph)) stop(paste("This SymbolicSimulation structure does not contain transition table information.", "Please re-run simulateSymbolicModel() with returnGraph=TRUE!")) return(attractorInfo$graph) } else if (is.null(attractorInfo$stateInfo$table)) stop(paste("This AttractorInfo structure does not contain transition table information.", "Please re-run getAttractors() with a synchronous search and returnTable=TRUE!")) return(.internal.getTransitionTable(attractorInfo$stateInfo)) } # Internally used to extract the information from the <stateInfo> subcomponent # of AttractorInfo .internal.getTransitionTable <- function(stateInfo) { fixedGenes <- which(stateInfo$fixedGenes != -1) nonFixedGenes <- which(stateInfo$fixedGenes == -1) if (!is.null(stateInfo$initialStates)) { initialStates <- t(apply(stateInfo$initialStates,2,dec2bin,length(stateInfo$genes))) } else { initialStates <- matrix(ncol=length(stateInfo$genes),nrow=2^length(nonFixedGenes)) # encode the initial states # first, encode the changing part by calculating all combinations temp <- allcombn(2,length(nonFixedGenes)) - 1 initialStates[,nonFixedGenes] <- temp[,ncol(temp):1] if (length(fixedGenes) > 0) # if there are fixed genes, encode their values initialStates[,fixedGenes] <- sapply(stateInfo$fixedGenes[fixedGenes], function(value)rep(value,2^length(nonFixedGenes))) } # build return structure of class TransitionTable res <- data.frame(initialStates, t(apply(stateInfo$table,2,dec2bin,length(stateInfo$genes))), stateInfo$attractorAssignment,stateInfo$stepsToAttractor) colnames(res) <- c(paste("initialState.",stateInfo$genes,sep=""), paste("nextState.",stateInfo$genes,sep=""), "attractorAssignment","transitionsToAttractor") class(res) <- c("TransitionTable","data.frame") return(res) } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/perturbTrajectories.R���������������������������������������������������������������������0000644�0001762�0000144�00000014530�13277247010�016210� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ perturbTrajectories <- function(network, measure = c("hamming", "sensitivity", "attractor"), numSamples = 1000, flipBits = 1, updateType = c("synchronous","asynchronous","probabilistic"), gene, ...) { symbolic <- inherits(network,"SymbolicBooleanNetwork") probabilistic <- inherits(network,"ProbabilisticBooleanNetwork") stopifnot(inherits(network,"BooleanNetwork") || symbolic || probabilistic) measure <- match.arg(measure, c("hamming", "sensitivity", "attractor")) if (probabilistic && measure != "hamming") stop("Probabilistic networks are only supported for measure=\"hamming\"!") fixedIdx <- which(network$fixed != -1) nonFixedIdx <- which(network$fixed == -1) if (symbolic) { maxDelay <- max(network$timeDelays) flipIndices <- unlist(mapply(function(x, i) { if (network$fixed[i] == -1) seq_len(x) + (i - 1) * maxDelay else c() }, network$timeDelays, seq_along(network$genes))) startStates <- lapply(seq_len(numSamples), function(i) { m <- matrix(nrow=maxDelay, ncol=length(network$genes), round(runif(n=maxDelay*length(network$genes)))) m[,fixedIdx] <- network$fixed[fixedIdx] m }) } else { flipIndices <- seq_along(network$genes)[nonFixedIdx] startStates <- lapply(seq_len(numSamples), function(i) { s <- round(runif(n=length(network$genes))) s[fixedIdx] <- network$fixed[fixedIdx] s }) } if (length(flipIndices) == 0) stop("All genes in this network are fixed!") perturbedStates <- lapply(startStates, function(state) { flip <- sample(flipIndices, size=flipBits, replace=FALSE) state[flip] <- 1 - state[flip] return(state) }) if (measure == "hamming") { dists <- mapply(function(state1, state2) { sum(stateTransition(network=network, state=state1, type=updateType, ...) != stateTransition(network=network, state=state2, type=updateType, ...)) }, startStates, perturbedStates)/length(network$genes) return(list(stat=dists, value=mean(dists))) } else if (measure == "sensitivity") { if (missing(gene)) stop("Parameter \"gene\" must be set for sensitivity analysis!") if (is.character(gene)) geneIdx <- which(network$genes == gene) else geneIdx <- gene if (length(geneIdx) == 0) stop(paste("Unknown gene \"", gene, "\"!", sep="")) sensitivities <- unname(mapply(function(state1, state2) { stateTransition(network=network, state=state1, chosenGene = geneIdx, ...)[geneIdx] != stateTransition(network=network, state=state2, chosenGene = geneIdx, ...)[geneIdx] }, startStates, perturbedStates)) return(list(stat=sensitivities, value=mean(sensitivities))) } else { if (symbolic) { att1 <- simulateSymbolicModel(network, startStates=startStates, returnGraph=FALSE, canonical=TRUE, ...) att2 <- simulateSymbolicModel(network, startStates=perturbedStates, returnGraph=FALSE, canonical=TRUE, ...) attractorAssignment1 <- att1$attractorAssignment attractorAssignment2 <- att2$attractorAssignment } else { att1 <- getAttractors(network, startStates=startStates, returnTable=TRUE, canonical=TRUE, ...) att2 <- getAttractors(network, startStates=perturbedStates, returnTable=TRUE, canonical=TRUE, ...) tt1 <- getTransitionTable(att1) tt2 <- getTransitionTable(att2) attractorAssignment1 <- tt1$attractorAssignment attractorAssignment2 <- tt2$attractorAssignment names(attractorAssignment1) <- apply(tt1[,seq_along(network$genes)],1,paste,collapse="") names(attractorAssignment2) <- apply(tt2[,seq_along(network$genes)],1,paste,collapse="") attractorAssignment1 <- unname(attractorAssignment1[sapply(startStates,paste,collapse="")]) attractorAssignment2 <- unname(attractorAssignment2[sapply(perturbedStates,paste,collapse="")]) } attractorsEqual <- matrix(sapply(seq_along(att1$attractors), function(i1) { seq1 <- getAttractorSequence(att1, i1) sapply(seq_along(att2$attractors), function(i2) { seq2 <- getAttractorSequence(att2, i2) return(identical(seq1,seq2)) }) }), nrow=length(att1$attractors)) stat <- apply(cbind(attractorAssignment1, attractorAssignment2), 1, function(idx) { attractorsEqual[idx[1],idx[2]] }) return(list(stat=stat, value=mean(stat))) } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/testNetworkProperties.R�������������������������������������������������������������������0000644�0001762�0000144�00000033267�13277247010�016564� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Calculate the Gini index of <x> Gini <- function(x) { n <- length(x) x <- sort(x) 1/(n-1)*(n+1-2*(sum((n+1-seq_len(n))*x)/sum(x))) } # Compare the Hamming distances of the successor states of states and their perturbed copies. testTransitionRobustness <- function(network, accumulate=TRUE, params=list()) { res <- do.call("perturbTrajectories", c(list(network=network, measure="hamming"), params)) if (accumulate) return(res$value) else return(res$stat) } # Test attractor robustness by searching the original attractor # in <params$numSamples> perturbed copies of <network> or by perturbing the state trajectories # and checking whether the attractors change. testAttractorRobustness <- function(network, accumulate=TRUE, params=list()) { origAttrs <- getAttractors(network,canonical=TRUE) # decode parameters if (is.null(params$perturb)) perturb <- "functions" else perturb <- params$perturb if (params$perturb == "trajectories") { params$perturb <- NULL if (!is.null(params$copies)) { params$numSamples <- params$copies params$copies <- NULL } res <- do.call("perturbTrajectories", c(list(network=network, measure="attractor"), params)) if (accumulate) return(res$value) else return(res$stat) } else { if (is.null(params$method)) method <- "bitflip" else method <- params$method if (is.null(params$maxNumBits)) maxNumBits <- 1 else maxNumBits <- params$maxNumBits if (is.null(params$numStates)) numStates <- max(1,2^length(network$genes)/100) else numStates <- params$numStates if (is.null(params$simplify)) simplify <- (perturb[1] == "states") else simplify <- params$simplify if (is.null(params$readableFunctions)) readableFunctions <- FALSE else readableFunctions <- params$readableFunctions if (is.null(params$excludeFixed)) excludeFixed <- TRUE else excludeFixed <- params$excludeFixed if (!is.null(params$numSamples)) copies <- params$numSamples else if (is.null(params$copies)) copies <- 100 else copies <- params$copies perturbationResults <- unlist(sapply(seq_len(copies),function(copy) { # get attractors of perturbed network perturbedAttrs <- getAttractors(perturbNetwork(network, perturb=perturb, method=method, maxNumBits=maxNumBits, numStates=numStates, simplify=simplify, readableFunctions=readableFunctions, excludeFixed=excludeFixed)) # try to find original attractors in perturbed network attractorIndices <- sapply(origAttrs$attractors,function(attractor1) { index <- which(sapply(perturbedAttrs$attractors,function(attractor2) { identical(attractor1,attractor2) })) if (length(index) == 0) NA else index }) return(sum(!is.na(attractorIndices))) })) if (accumulate) # return overall percentage of found attractors return(sum(perturbationResults)/(length(origAttrs$attractors) * copies) * 100) else # return percentage of found attractors for each run return(perturbationResults/(length(origAttrs$attractors)) * 100) } } # Calculate the in-degrees of states in the network. # If <accumulate> is true, the in-degrees are accumulated # using the Gini coefficient testIndegree <- function(network,accumulate=TRUE,params) { attr <- getAttractors(network) graph <- plotStateGraph(attr,plotIt=FALSE) # calculate in-degree using igraph if (accumulate) # accumulate using Gini index return(Gini(degree(graph,mode="in",loops=TRUE))) else # return the raw degrees return(degree(graph,mode="in",loops=TRUE)) } # Calculate the Kullback-Leibler distance of # two distributions <x> and <y>. # <bins> is the number of bins used for discretization. # <minVal> is the minimum value to be used instead of zero kullbackLeiblerDistance <- function(x,y,bins=list(),minVal=0.00001) { x <- cut(x,breaks=bins,include.lowest=T,right=F) y <- cut(y,breaks=bins,include.lowest=T,right=F) tx <- table(x) ty <- table(y) tx <- tx/length(x) ty <- ty/length(y) tx[tx < minVal] <- minVal ty[ty < minVal] <- minVal return(sum(tx*(log(tx/ty)))) } # Generic function to test properties of <network> against random networks. # <numRandomNets> specifies the number of random networks to generate. # <testFunction> is the name of a function that returns a distribution of test values or a test statistic for each network, # which receives <testFunctionParams> as optional parameters. # If <accumulation> is "characteristic", the test function must return a characteristic/test statistic value for each value, and # a histogram of these value is plotted with a line for the original network. # If <accumulation> is "kullback_leibler", a histogram of the Kullback-Leibler distances of the test value distribution for the original network # and the random networks is plotted. # <sign.level> is the desired significance level for <network> in comparison to the random networks. # <functionGeneration>,<simplify>,<noIrrelevantGenes>,<validationFunction>,<failureInterations, # <d_lattice>,<zeroBias> are the corresponding parameters of generateRandomNKNetwork(). # <title> is the title of the plot, <xlab> is its x axis caption, <breaks> is the corresponding histogram parameter, and ... supplies further # graphical parameters testNetworkProperties <- function(network, numRandomNets=100, testFunction="testIndegree", testFunctionParams=list(), accumulation=c("characteristic","kullback_leibler"), alternative=c("greater","less"), sign.level=0.05, drawSignificanceLevel=TRUE, klBins,klMinVal=0.00001, linkage=c("uniform","lattice"), functionGeneration=c("uniform","biased"), validationFunction, failureIterations=10000, simplify=FALSE, noIrrelevantGenes=TRUE, d_lattice=1, zeroBias=0.5, title="", xlab, xlim, breaks=30, ...) { stopifnot(inherits(network,"BooleanNetwork") || inherits(network,"SymbolicBooleanNetwork")) if (is.character(testFunction)) testFunctionName <- testFunction else testFunctionName <- "" testFunction <- match.fun(testFunction) accumulate <- (match.arg(accumulation) == "characteristic") origResult <- testFunction(network,accumulate,testFunctionParams) numGenes <- length(network$interactions) if (inherits(network,"SymbolicBooleanNetwork")) inputGenes <- sapply(network$interactions,function(interaction)length(getInputs(interaction))) else inputGenes <- sapply(network$interactions,function(interaction)length(interaction$input)) if (missing(validationFunction)) validationFunction <- NULL randomResults <- lapply(seq_len(numRandomNets),function(i) { randomNet <- generateRandomNKNetwork(n=numGenes, k=inputGenes, topology="fixed", linkage=linkage, functionGeneration=functionGeneration, validationFunction=validationFunction, failureIterations=failureIterations, simplify=simplify, noIrrelevantGenes=noIrrelevantGenes, d_lattice=d_lattice, zeroBias=zeroBias) randomRes <- testFunction(randomNet,accumulate,testFunctionParams) return(randomRes) }) if (accumulate) randomResults <- unlist(randomResults) args <- list(...) res <- switch(match.arg(accumulation,c("characteristic","kullback_leibler")), characteristic = { # get one value for each random network, and plot a histogram of these values if (missing(xlab)) { xlab <- switch(testFunctionName, testIndegree = "Gini index of state in-degrees", testAttractorRobustness = "% of identical attractors", testTransitionRobustness = "Normalized Hamming distance", "accumulated results" ) } if (missing(xlim)) { #xlim <- switch(testFunctionName, # testIndegree = c(0,1), # testAttractorRobustness = c(0,100), # c(min(c(origResult,randomResults)), # max(c(origResult,randomResults))) #) xlim <- range(c(origResult, randomResults)) } alternative <- match.arg(alternative, c("greater","less")) # calculate p-value if (alternative == "greater") pval <- sum(randomResults < origResult) / length(randomResults) else pval <- sum(randomResults > origResult) / length(randomResults) # plot histogram if (testFunctionName == "testIndegree" | testFunctionName == "testAttractorRobustness") { r <- hist(randomResults,xlim=xlim,xlab=xlab,main=title,xaxt="n",...) axis(side=1,at=seq(xlim[1],xlim[2],length.out=11)) } else { # plot with default axis r <- hist(randomResults,xlim=xlim,xlab=xlab,main=title,...) } # plot result for original network abline(v=origResult,col="red") if (alternative == "greater") text(x=origResult,pos=2,y=max(r$counts)*0.75, labels=paste("> ",round(pval * 100),"%\nof random results",sep=""), col="red",cex=0.75) else text(x=origResult,pos=4,y=max(r$counts)*0.75, labels=paste("< ",round(pval * 100),"%\nof random results",sep=""), col="red",cex=0.75) if (drawSignificanceLevel) # plot line for significance level { if (alternative == "greater") { quant <- quantile(randomResults,1.0-sign.level) abline(v=quant,col="blue") text(x=quant,pos=2,y=max(r$counts)*0.85, labels=paste((1.0-sign.level) * 100,"% quantile",sep=""), col="blue",cex=0.75) } else { quant <- quantile(randomResults,sign.level) abline(v=quant,col="blue") text(x=quant,pos=4,y=max(r$counts)*0.85, labels=paste(sign.level * 100,"% quantile",sep=""), col="blue",cex=0.75) } } list(hist=r,pval=1.0-pval,significant=(1.0-pval<=sign.level)) }, kullback_leibler = { # a distribution of values is returned for each network, # plot the Kullback-Leibler distances to the original network if (missing(xlab)) xlab <- "Kullback-Leibler distance" if (missing(klBins)) { bins <- unique(c(origResult,unlist(randomResults))) bins <- c(bins,max(bins) + 1) } else { bins <- unique(c(origResult,unlist(randomResults))) if (klBins < length(bins)) bins <- seq(min(bins),max(bins),length.out=klBins+1) else bins <- c(bins,max(bins) + 1) } vals <- sapply(randomResults,function(results) kullbackLeiblerDistance(origResult,results,bins=bins,minVal=klMinVal)) r <- hist(vals,xlab=xlab,main=title,breaks=breaks,...) list(hist=r) }, stop("'accumulation' must be one of \"characteristic\",\"kullback_leibler\"")) return(res) } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/plotAttractors.R��������������������������������������������������������������������������0000644�0001762�0000144�00000021434�13301231210�015153� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Plot state tables of all attractors in <attractorInfo>. # Genes are grouped according to <grouping>. # An additional title can be supplied in <title>. # If <plotFixed> is set, fixed variables are included in the plot. # <onColor> and <offColor> specify the colors of ON/1 and OFF/0 states. # TODO: remove old definition from comments #plotAttractors <- function (attractorInfo, subset, title = "", mode=c("table","graph"), # grouping = list(), plotFixed = TRUE, onColor="green",offColor="red", # layout=layout.circle, drawLabels=TRUE, drawLegend=TRUE, ask=TRUE, # reverse=FALSE, ...) #{} plotAttractors <- function (attractorInfo, subset, title = "", mode = c("table", "graph"), grouping = list(), plotFixed = TRUE, onColor = "#4daf4a", offColor = "#e41a1c", layout = layout.circle, drawLabels = TRUE, drawLegend = TRUE, ask = TRUE, reverse = FALSE, # new parameters borderColor = "black", eps = 0.1, allInOnePlot = FALSE, ...) { stopifnot(inherits(attractorInfo, "AttractorInfo") || inherits(attractorInfo, "SymbolicSimulation")) if (inherits(attractorInfo, "AttractorInfo")) { numGenes <- length(attractorInfo$stateInfo$genes) geneNames <- attractorInfo$stateInfo$genes } else { numGenes <- ncol(attractorInfo$attractors[[1]]) geneNames <- colnames(attractorInfo$attractors[[1]]) } if (missing(subset)) subset <- seq_along(attractorInfo$attractors) else if (any(subset > length(attractorInfo$attractors))) stop("You specified an attractor index that is greater than the total number of attractors in 'subset'!") res <- switch(match.arg(mode, c("table", "graph")), table = { whichFixed <- which(attractorInfo$stateInfo$fixedGenes != -1) if (plotFixed | (length(whichFixed) == 0)) { plotIndices <- seq_len(numGenes) } else { plotIndices <- seq_len(numGenes)[-whichFixed] } if (inherits(attractorInfo, "AttractorInfo")) { binMatrices <- lapply(attractorInfo$attractors, function(attractor) { res <- matrix(apply(attractor$involvedStates, 2, function(state) dec2bin(state, numGenes)[plotIndices]), nrow = length(plotIndices)) }) attractorLengths <- sapply(attractorInfo$attractors, function(attractor) { ifelse (is.null(attractor$initialStates), ncol(attractor$involvedStates), -1) }) } else { binMatrices <- lapply(attractorInfo$attractors, t) attractorLengths <- sapply(binMatrices, ncol) } lengthTable <- table(attractorLengths) lengthTable <- lengthTable[as.integer(names(lengthTable)) != -1] oldAsk <- par("ask") oldmfrow <- NULL if (allInOnePlot) { oldmfrow <- par()$mfrow #par(mfrow=c(1,length(table(sapply(sapply(attractorInfo$attractors, "[[", "involvedStates", simplify=F), ncol))))) par(mfrow=c(1,length(lengthTable))) } res <- lapply(seq_along(lengthTable), function(i) { len <- as.integer(names(lengthTable)[i]) attractorIndices <- intersect(which(attractorLengths == len), subset) if (length(attractorIndices) > 0) { cnt <- length(attractorIndices) totalMatrix <- c() for (mat in binMatrices[attractorIndices]) { totalMatrix <- cbind(totalMatrix, mat) } rownames(totalMatrix) <- geneNames[plotIndices] colnames(totalMatrix) <- sapply(attractorIndices, function(i) paste("Attr", i, ".", seq_len(len), sep = "")) if (length(grouping) > 0) totalMatrix <- totalMatrix[unlist(grouping$index), , drop = FALSE] par(ask = ask && i > 1 && dev.interactive()) if (reverse) { plot(c(), c(), xlim = c(0, len *cnt), ylim = c(-2, nrow(totalMatrix) + 1), xlab = "", ylab = "", axes = FALSE, main = paste(title, "\nAttractors with ", len, " state(s)", sep = "")) } else { plot(c(), c(), xlim = c(0, len * cnt), ylim = c(nrow(totalMatrix) + 1, -2), xlab = "", ylab = "", axes = FALSE, main = paste(title, "\nAttractors with ", len," state(s)", sep = "")) } #rect(par("usr")[1], par("usr")[3], par("usr")[2], par("usr")[4], col = "grey") axis(2, seq_len(nrow(totalMatrix)) - 0.5, rownames(totalMatrix), yaxt = "s", las = 2) xStart <- 1 unitFactor <- (len - (2 * eps))/len startX <- eps for (i in seq_len(ncol(totalMatrix))) { for (j in seq_len(nrow(totalMatrix))) { rectCol <- ifelse(totalMatrix[j, i], onColor, offColor) rect(startX, j - 1, startX + unitFactor, j, col = rectCol, border = borderColor, lwd = 2) } startX <- startX + unitFactor if (i %% len == 0) { startX <- startX + 2*eps } } sep = seq(0, ncol(totalMatrix), by = len) #abline(v = sep[-1], col = par()$bg, lwd = 3) if (inherits(attractorInfo, "AttractorInfo")) { if (is.null(attractorInfo$stateInfo$table)) { freq <- rep(NA, length(attractorIndices)) } else { freq <- round(100 * sapply(attractorInfo$attractors[attractorIndices], function(attractor) { attractor$basinSize/ncol(attractorInfo$stateInfo$table)}), 2) } } else { if (!is.null(attractorInfo$graph)) { freq <- round(sapply(attractorIndices, function(i) sum(attractorInfo$graph$attractorAssignment == i)/nrow(attractorInfo$graph)) * 100, 2) } else { freq <- rep(NA, length(attractorIndices)) } } if (!isTRUE(all(is.na(freq)))) { text(sep[seq_along(sep) - 1] + len/2, ifelse(reverse, -nrow(totalMatrix)-1.5, 1) + rep(1 + nrow(totalMatrix), ncol(totalMatrix)), paste(freq, "%", sep = ""), cex = 0.75, font = 3) } if (length(grouping) > 0) { if(!is.null(grouping$class)) { sepPos = cumsum(sapply(grouping$index, length)) abline(h = sepPos[-length(sepPos)], col = "black", lwd = 3) text(ncol(totalMatrix)/2, sepPos - 0.5, grouping$class, cex = 0.9) } } #if (drawLegend) legend(x = "bottomright", pch = c(15, 15), col = c(onColor, offColor), legend = c("active", "inactive"), cex = 0.7, horiz = T, xpd = T) if (drawLegend) legend(x = 0, y = ifelse(reverse, -nrow(totalMatrix)-1, 2) + nrow(totalMatrix), pch = c(15, 15), col = c(onColor, offColor), legend = c("active", "inactive"), cex = 0.7, horiz = T, xpd=T) totalMatrix } }) par(ask = oldAsk) if(!is.null(oldmfrow)) par(mfrow = oldmfrow) names(res) <- names(lengthTable) return(res) }, graph = { args <- list(...) if (is.null(args$vertex.size)) args$vertex.size <- 2 if (is.null(args$edge.arrow.mode)) args$edge.arrow.mode <- 0 if (is.null(args$vertex.label.cex)) args$vertex.label.cex <- 0.75 if (is.null(args$vertex.label.dist)) args$vertex.label.dist <- 1 if (is.null(args$vertex.color)) args$vertex.color <- "grey" if (is.null(args$edge.arrow.size)) args$edge.arrow.size <- 0.5 lapply(attractorInfo$attractors[subset], function(attractor) { if (inherits(attractorInfo, "AttractorInfo")) { nodes <- data.frame(apply(attractor$involvedStates, 2, function(state) paste(dec2bin(state, numGenes), collapse = "")), stringsAsFactors = FALSE) if (!is.null(attractor$initialStates)) { initialStates <- apply(attractor$initialStates, 2, function(state) paste(dec2bin(state, numGenes), collapse = "")) nextStates <- apply(attractor$nextStates, 2, function(state) paste(dec2bin(state, numGenes), collapse = "")) } else { initialStates <- apply(attractor$involvedStates, 2, function(state) paste(dec2bin(state, numGenes), collapse = "")) if (length(initialStates) == 1) nextStates <- initialStates else nextStates <- initialStates[c(2:length(initialStates), 1)] } } else { initialStates <- apply(attractor, 1, paste, collapse = "") nextStates <- apply(attractor[c(2:nrow(attractor), 1), , drop = FALSE], 1, paste, collapse = "") nodes <- data.frame(unique(c(initialStates, nextStates)), stringsAsFactors = FALSE) } edgeMatrix <- data.frame(initialStates, nextStates) graph <- graph.data.frame(edgeMatrix, vertices = nodes, directed = TRUE) if (drawLabels) labels <- nodes[, 1] else labels <- NA args$layout <- layout args$x <- graph args$vertex.label <- labels args$main <- title do.call("plot", args) graph }) }) } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/print.MarkovSimulation.R������������������������������������������������������������������0000644�0001762�0000144�00000006032�13277247010�016603� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Custom print function for class MarkovSimulation print.MarkovSimulation <- function(x, activeOnly = FALSE, ...) { genes <- x$genes numGenes <- length(genes) cat("States reached at the end of the simulation:\n") if (activeOnly) { reachedStates <- data.frame(apply(x$reachedStates[,seq_len(numGenes)],1,function(state) { r <- paste(genes[which(state == 1)],collapse=", ") if (r == "") r <- "--" r }),x$reachedStates$Probability) colnames(reachedStates) <- c("Active genes", "Probability") print(reachedStates) } else { print(x$reachedStates) } if (!is.null(x$table)) { cat("\nProbabilities of state transitions in the network:\n") transitionProbs <- getTransitionProbabilities(x) colIndices <- c(1,numGenes,numGenes + 1, 2*numGenes, 2*numGenes + 1) if(activeOnly) { inputStates <- apply(transitionProbs,1,function(row) { r <- paste(genes[which(row[colIndices[1]:colIndices[2]] == 1)],collapse=", ") if (r == "") r <- "--" r }) outputStates <- apply(transitionProbs,1,function(row) { r <- paste(genes[which(row[colIndices[3]:colIndices[4]] == 1)],collapse=", ") if (r == "") r <- "--" r }) colWidth <- max(c(sapply(inputStates,nchar),sapply(outputStates,nchar))) align <- "left" } else { inputStates <- apply(transitionProbs,1,function(row) paste(row[colIndices[1]:colIndices[2]],collapse="")) outputStates <- apply(transitionProbs,1,function(row) paste(row[colIndices[3]:colIndices[4]],collapse="")) colWidth <- numGenes align <- "right" } binMatrix <- data.frame(inputStates,outputStates, transitionProbs[,colIndices[5]]) cat(format("State",width=max(7,colWidth),justify=align)," ", format("Next state",width=max(11,colWidth + 2),justify=align), format("Probability",width=13,justify="right"),"\n",sep="") apply(binMatrix,1,function(row) { # paste all states of input and output into one string, and put out all columns of the table in a # formatted way cat(format(row[1],width=max(7,colWidth),justify=align), " => ", format(row[2],width=max(11,colWidth + 2),justify=align), format(row[3],width=13,justify="right"),"\n",sep="") }) } return(invisible(x)) } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/generateRandomNKNetwork.R�����������������������������������������������������������������0000644�0001762�0000144�00000012312�13277247010�016700� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������generateRandomNKNetwork <- function(n,k,topology=c("fixed","homogeneous","scale_free"), linkage=c("uniform","lattice"), functionGeneration=c("uniform","biased"), validationFunction, failureIterations=10000, simplify=FALSE, noIrrelevantGenes=TRUE, readableFunctions=FALSE, d_lattice=1, zeroBias=0.5, gamma=2.5, approx_cutoff=100) { k_i_vec <- switch(match.arg(topology), fixed = { if (length(k) == n) k else if (length(k) == 1) rep(k,n) else stop("k must have 1 or n element(s)!") }, homogeneous = round(rpois(n,k)), scale_free = rzeta(n,k,gamma=gamma,approx_cutoff=approx_cutoff), stop("'topology' must be one of \"fixed\",\"homogeneous\"") ) k_i_vec[k_i_vec > n] <- n if ((zeroBias == 0 | zeroBias == 1) && noIrrelevantGenes && any(k_i_vec > 0)) stop("If setting 'zeroBias' to 0 or 1, you must set 'noIrrelevantGenes' to FALSE!") geneNames <- paste("Gene",seq_len(n),sep="") if (!missing(validationFunction) && !is.null(validationFunction)) validationFunction <- match.fun(validationFunction) else validationFunction <- NULL interactions <- mapply(function(i,k_i) { if (k_i == 0) { genes <- 0 func <- round(runif(min=0,max=1,n=1)) } else { table <- allcombn(2,k_i) - 1 genes <- switch(match.arg(linkage,c("uniform","lattice")), uniform = sample(seq_len(n),k_i,replace=FALSE), lattice = { region <- c(max(1,round(i - k_i*d_lattice)):max(1,i-1), min(n,i+1):min(n,round(i + k_i*d_lattice))) sample(region,k_i,replace=FALSE) }, stop("'linkage' must be one of \"uniform\",\"lattice\"")) containsIrrelevant <- TRUE validFunction <- TRUE counter <- 0 while((!validFunction) || containsIrrelevant) { tryCatch( { functionGeneration <- match.fun(functionGeneration) }, error = function(e){} ) if (is.function(functionGeneration)) func <- functionGeneration(input=genes) else func <- switch(match.arg(functionGeneration,c("uniform","biased")), uniform = round(runif(min=0,max=1,n=2^k_i)), biased = as.integer(runif(min=0,max=1,n=2^k_i) > zeroBias), stop("'functionGeneration' must be one of \"uniform\",\"biased\" or a function!")) if (noIrrelevantGenes) { dropGenes <- apply(table,2,function(gene) # determine all genes that have no influence on the results, # i.e. the result column is equal for 0 values and 1 values { (identical(func[gene==1], func[gene==0])) }) containsIrrelevant <- (sum(dropGenes) > 0) } else containsIrrelevant <- FALSE if (!is.null(validationFunction)) validFunction <- validationFunction(table, func) counter <- counter + 1 if (counter > failureIterations) stop(paste("Could not find a transition function matching the restrictions of", "\"validationFunction\" in", failureIterations, " runs.", "Change \"validationFunction\" or increase \"failureIterations\"!")) } } return(list(input=genes,func=func, expression=getInteractionString(readableFunctions, func,geneNames[genes]))) },seq_len(length(k_i_vec)),k_i_vec,SIMPLIFY=FALSE) fixed <- sapply(interactions,function(i) { if (i$input[1] == 0) i$func[1] else -1 }) names(fixed) <- geneNames names(interactions) <- geneNames net <- list(genes=geneNames,interactions=interactions,fixed=fixed) class(net) <- "BooleanNetwork" if (simplify) net <- simplifyNetwork(net,readableFunctions) return(net) } generateCanalyzing <- function(input) { k <- length(input) table <- allcombn(2, k) - 1 canalyzingInput <- sample(1:k,size=1) res <- round(runif(min = 0, max = 1, n = 2^k)) res[table[,canalyzingInput] == sample(c(0,1),size=1)] <- sample(c(0,1), size=1) return(res) } generateNestedCanalyzing <- function(input) { k <- length(input) table <- allcombn(2, k) - 1 remainingIndices <- 1:(2^k) res <- rep(sample(c(0,1), size=1),2^k) for (canalyzingInput in sample(1:k,size=k,replace=FALSE)) { newIndices <- which(table[remainingIndices,canalyzingInput] == sample(c(0,1),size=1)) res[remainingIndices[newIndices]] <- sample(c(0,1), size=1) remainingIndices <- setdiff(remainingIndices, remainingIndices[newIndices]) } return(res) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/generateRandomStartStates.R���������������������������������������������������������������0000644�0001762�0000144�00000002777�13277247010�017315� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ generateRandomStartStates <- function(network, n) { mat <- matrix(nrow=n,ncol=length(network$genes)) fixedPositions <- which(network$fixed != -1) nonFixedPositions <- which(network$fixed == -1) if (n > (2 ^ length(nonFixedPositions))) stop("The number of states to generate exceeds the total number of possible states!") if (length(fixedPositions) != 0) # fill fixed positions with the corresponding values mat[,fixedPositions] <- sapply(fixedPositions,function(x) rep(network$fixed[x],n)) if (n != 2 ^ length(nonFixedPositions)) { # generate other positions randomly mat[,nonFixedPositions] <- round(runif(n=n*length(nonFixedPositions))) } else { mat[,nonFixedPositions] <- allcombn(2,length(nonFixedPositions)) - 1 } # eliminate duplicates mat <- unique(mat) while (nrow(mat) != n) # if duplicates were removed, generate new states until the # desired number of states is reached { vec <- rep(0,length(network$genes)) if (length(fixedPositions) != 0) # fill fixed positions vec[fixedPositions] <- sapply(fixedPositions, function(x)network$fixed[x]) # generate other positions randomly vec[nonFixedPositions] <- round(runif(n=length(nonFixedPositions))) mat <- unique(rbind(mat,vec)) } #cat("Using initial states:\n") # print states and form a list res <- lapply(1:nrow(mat),function(i) { #cat(paste(mat[i,],collapse=""),"\n",sep="") mat[i,] }) #cat("\n") return(res); } �BoolNet/R/binarizeTimeSeries.R����������������������������������������������������������������������0000644�0001762�0000144�00000017022�13277247010�015742� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Several binarization methods for time series. <measurements> is a list of matrices with the # genes in the rows, each specifying one time series. # If <method> is "kmeans", k-means binarization is used. # <nstart> and <iter.max> are the corresponding parameters for k-means. This clustering # is employed for binarization. # If <method> is "edgeDetector", an edge detector is used for binarization. # If <method> is "edgeDetector" and <edge> is "firstEdge", # the first "significant" edge in the sorted data is the threshold for the binarization. # If <edge> is "maxEdge", the algorithm searches for the edge with the highest gradient. # With the <scaling> factor, the size of the first edge can be adapted. # If <method> is "scanStatistic", a scan statistic is used to binarize the data # If <dropInsignificant> is true, insignificant genes (that are not recommended by the statistic) are removed. # Returns a list containing the binarized matrix list and (for k-means) a vector # of thresholds and (for scan statistic) a vector specifying genes to remove. binarizeTimeSeries <- function(measurements, method=c("kmeans","edgeDetector","scanStatistic"), nstart=100, iter.max=1000, edge=c("firstEdge","maxEdge"), scaling=1, windowSize=0.25, sign.level=0.1, dropInsignificant=FALSE) { if (!is.null(dim(measurements))) fullData <- measurements else # in case of list, paste all matrices before clustering { fullData <- measurements[[1]] for (m in measurements[-1]) { fullData <- cbind(fullData,m) } } #switch between the different methods switch(match.arg(method), kmeans={ cluster <- apply(fullData,1,function(gene) # cluster data using k-means { cl_res <- kmeans(gene, 2, nstart=nstart,iter.max=iter.max) if (cl_res$centers[1] > cl_res$centers[2]) # exchange clusters if necessary, so that smaller numbers # are binarized to 0, and larger numbers are binarized to 1 group <- abs(cl_res$cluster-2) else group <- cl_res$cluster-1 # calculate the binarization threshold threshold <- min(cl_res$centers) + dist(cl_res$centers)[1]/2 list(bin=group, threshold=threshold) }) if (is.null(dim(measurements))) # split up the collated binarized measurements into a list of matrices of the original size { startIndex <- 0 binarizedTimeSeries <- lapply(measurements,function(m) { currentSplit <- (startIndex+1):(startIndex+ncol(m)) startIndex <<- startIndex + ncol(m) t(sapply(cluster,function(cl) cl$bin[currentSplit])) }) } else { binarizedTimeSeries <- t(sapply(cluster,function(cl) cl$bin)) } #colnames(binarizedTimeSeries)<-colnames(fullData) return(list(binarizedMeasurements=binarizedTimeSeries, thresholds=sapply(cluster,function(cl)cl$threshold))) }, edgeDetector={ #switch between the different edgedetectors switch(match.arg(edge), firstEdge={ cluster <- apply(fullData,1,function(gene) # cluster data using edgedetector { cl_res <- edgeDetector(gene,scaling,edge="firstEdge") list(bin=cl_res$bindata,thresholds=cl_res$thresholds) }) if (is.null(dim(measurements))) # split up the collated binarized measurements into a list of matrices of the original size { startIndex <- 0 binarizedTimeSeries <- lapply(measurements,function(m) { currentSplit <- (startIndex+1):(startIndex+ncol(m)) startIndex <<- startIndex + ncol(m) t(sapply(cluster,function(cl) cl$bin[currentSplit])) }) threshlist<-sapply(cluster,function(cl) cl$thresholds) } else { binarizedTimeSeries <- t(sapply(cluster,function(cl) cl$bin)) threshlist<-sapply(cluster,function(cl) cl$thresholds) } return(list(binarizedMeasurements=binarizedTimeSeries,thresholds= threshlist)) }, maxEdge={ cluster <- apply(fullData,1,function(gene) # cluster data using edgedetector { cl_res <- edgeDetector(gene,edge="maxEdge") list(bin=cl_res$bindata,thresholds=cl_res$thresholds) }) if (is.null(dim(measurements))) # split up the collated binarized measurements into a list of matrices of the original size { startIndex <- 0 binarizedTimeSeries <- lapply(measurements,function(m) { currentSplit <- (startIndex+1):(startIndex+ncol(m)) startIndex <<- startIndex + ncol(m) t(sapply(cluster,function(cl) cl$bin[currentSplit])) }) threshlist<-sapply(cluster,function(cl) cl$thresholds) } else { binarizedTimeSeries <- t(sapply(cluster,function(cl) cl$bin)) threshlist<-sapply(cluster,function(cl) cl$thresholds) } return(list(binarizedMeasurements=binarizedTimeSeries,thresholds= threshlist)) }, stop("'method' must be one of \"firstEdge\",\"maxEdge\"") ) }, scanStatistic={ cluster <- apply(fullData,1,function(gene) # cluster data using scanStatistic { cl_res <- scanStatistic(gene,windowSize,sign.level) list(bin= cl_res$bindata,thresholds=cl_res$thresholds,reject=cl_res$reject) }) significant <- sapply(cluster,function(cl)(cl$reject==FALSE)) # remove not recommended genes if (dropInsignificant) { significant <- sapply(cluster,function(cl)(cl$reject==FALSE)) cluster <- cluster[significant] } if (is.null(dim(measurements))) # split up the collated binarized measurements into a list of matrices of the original size { startIndex <- 0 binarizedTimeSeries <- lapply(measurements,function(m) { currentSplit <- (startIndex+1):(startIndex+ncol(m)) startIndex <<- startIndex + ncol(m) t(sapply(cluster,function(cl) cl$bin[currentSplit])) }) rejectlist<-sapply(cluster,function(cl) cl$reject) threshlist<-sapply(cluster,function(cl) cl$thresholds) } else { binarizedTimeSeries <- t(sapply(cluster,function(cl) cl$bin)) rejectlist<-sapply(cluster,function(cl) cl$reject) threshlist<-sapply(cluster,function(cl) cl$thresholds) } if(any(rejectlist)) { warning("The following genes show a uniform behaviour and should possibly be excluded from binarization:", paste(rownames(fullData)[!significant],collapse=" ")) } return(list(binarizedMeasurements=binarizedTimeSeries,thresholds=threshlist,reject=rejectlist)) }, stop("'method' must be one of \"kmeans\",\"edgeDetector\",\"scanStatistic\"") ) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/print.TransitionTable.R�������������������������������������������������������������������0000644�0001762�0000144�00000006227�13277247010�016407� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Custom print function for class TransitionTable print.TransitionTable <- function(x, activeOnly=FALSE, ...) { geneCols <- setdiff(colnames(x),c("attractorAssignment","transitionsToAttractor")) numGenes <- (length(geneCols)) / 2 colIndices <- c(1,numGenes,numGenes + 1, 2*numGenes); if ("attractorAssignment" %in% colnames(x)) colIndices <- c(colIndices, 2*numGenes + 1) if ("transitionsToAttractor" %in% colnames(x)) colIndices <- c(colIndices, 2*numGenes + 2) genes <- sapply(colnames(x)[seq_len(numGenes)],function(n)strsplit(n,".",fixed=TRUE)[[1]][2]) if(activeOnly) { inputStates <- apply(x,1,function(row) { r <- paste(genes[which(row[colIndices[1]:colIndices[2]] == 1)],collapse=", ") if (r == "") r <- "--" r }) outputStates <- apply(x,1,function(row) { r <- paste(genes[which(row[colIndices[3]:colIndices[4]] == 1)],collapse=", ") if (r == "") r <- "--" r }) colWidth <- max(c(sapply(inputStates,nchar),sapply(outputStates,nchar))) align <- "left" } else { inputStates <- apply(x,1,function(row) paste(row[colIndices[1]:colIndices[2]],collapse="")) outputStates <- apply(x,1,function(row) paste(row[colIndices[3]:colIndices[4]],collapse="")) colWidth <- numGenes align <- "right" } binMatrix <- cbind(inputStates,outputStates) if ("attractorAssignment" %in% colnames(x)) binMatrix <- cbind(binMatrix, x[,colIndices[5]]) if ("transitionsToAttractor" %in% colnames(x)) binMatrix <- cbind(binMatrix, x[,colIndices[6]]) binMatrix <- as.data.frame(binMatrix) cat(format("State",width=max(7,colWidth),justify=align)," ", format("Next state",width=max(11,colWidth + 2),justify=align), if ("attractorAssignment" %in% colnames(x)) { format("Attr. basin",width=13,justify="right") } else "", if ("transitionsToAttractor" %in% colnames(x)) { format("# trans. to attr.",width=19,justify="right") } else "", "\n",sep="") apply(binMatrix,1,function(row) { # paste all states of input and output into one string, and put out all columns of the table in a # formatted way cat(format(row[1],width=max(7,colWidth),justify=align), " => ", format(row[2],width=max(11,colWidth + 2),justify=align), if ("attractorAssignment" %in% colnames(x)) { format(row[3],width=13,justify="right") } else "", if ("transitionsToAttractor" %in% colnames(x)) { format(row[4],width=19,justify="right") } else "", "\n",sep="") }) if (!activeOnly) cat("\nGenes are encoded in the following order: ", paste(genes,collapse=" "),"\n",sep="") return(invisible(x)) } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/reconstructNetwork.R����������������������������������������������������������������������0000644�0001762�0000144�00000022761�13277247010�016100� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Reconstruct a Boolean network from a transition table or a list of time series in <measurements>. # If <method> is "bestfit", Lähdesmäki's best-fit extension algorithm is called. # If <method> is "reveal", Liang's REVEAL algorithm is called. # <maxK> specifies the maximum number of input genes of a function. # If <readableFunctions> is true, DNF representations of the functions are generated. reconstructNetwork <- function(measurements,method=c("bestfit","reveal"),maxK=5, requiredDependencies = NULL, excludedDependencies = NULL, perturbations=NULL, readableFunctions=FALSE, allSolutions=FALSE, returnPBN=FALSE) { if (maxK < 0) stop("maxK must be >= 0!") # determine method to use meth <- switch(match.arg(method,c("bestfit","reveal")), bestfit=0, reveal=1, stop("'method' must be one of \"bestfit\",\"reveal\"")) perturbationMatrix <- NULL if (inherits(measurements,"TransitionTable")) # preprocess transition table and call algorithm { numGenes <- (ncol(measurements) - 2) / 2 if (numGenes < maxK) { maxK <- numGenes warning(paste("maxK was chosen greater than the total number of input genes and reset to ",numGenes,"!",sep="")) } if (!is.null(perturbations)) { if (!all(perturbations %in% c(0,1,-1,NA))) stop("The perturbation matrix may only contain the values 0,1,-1 and NA!") perturbations[is.na(perturbations)] <- -1 if (is.null(dim(perturbations))) perturbations <- matrix(perturbations,ncol=1) if (ncol(perturbations) != 1 && ncol(perturbations) != nrow(measurements)) stop(paste("There must be either one global vector of perturbations, or a matrix", "containing exact one column for each time series!")) if (nrow(perturbations) != numGenes) stop("The perturbation matrix must have exactly the same number of rows as the measurements!") if (ncol(perturbations) == 1) { perturbationMatrix <- matrix(-1,nrow=numGenes,ncol=nrow(measurements)) for (j in seq_len(nrow(measurements))) perturbationMatrix[,j] <- perturbations[,1] } else perturbationMatrix <- as.matrix(perturbations) } inputStates <- as.integer(t(as.matrix(measurements[,seq_len(numGenes)]))) outputStates <- as.integer(t(as.matrix(measurements[,(numGenes+1):(2*numGenes)]))) numStates <- nrow(measurements) genenames <- sapply(colnames(measurements)[seq_len(numGenes)],function(x)strsplit(x,".",fixed=TRUE)[[1]][2]) } else # the measurements are time series { if (!is.null(dim(measurements))) # only one time series => create list measurements <- list(measurements) numGenes <- nrow(measurements[[1]]) if (numGenes < maxK) { maxK <- numGenes warning(paste("maxK was chosen greater than the total number of input genes and reset to ",numGenes,"!",sep="")) } if (is.null(perturbations) && !is.null(measurements$perturbations)) { perturbations <- measurements$perturbations measurements$perturbations <- NULL } if (!is.null(perturbations)) { if (!all(perturbations %in% c(0,1,-1,NA))) stop("The perturbation matrix may only contain the values 0,1,-1 and NA!") perturbations[is.na(perturbations)] <- -1 if (is.null(dim(perturbations))) perturbations <- matrix(perturbations,ncol=1) if (ncol(perturbations) != 1 && ncol(perturbations) != length(measurements)) stop(paste("There must be either one global vector of perturbations, or a matrix", "containing exact one column for each time series!")) if (nrow(perturbations) != numGenes) stop("The perturbation matrix must have exactly the same number of rows as the measurements!") } perturbationMatrix <- c() genenames <- rownames(measurements[[1]]) if (is.null(genenames)) genenames <- paste("Gene",seq_len(numGenes)) inputStates <- c() outputStates <- c() for (i in seq_along(measurements)) # iterate over all time series and build state vectors { measurement <- measurements[[i]] if (numGenes != nrow(measurement)) stop("All measurement matrices must contain the same genes!") inputStates <- c(inputStates,as.integer(as.matrix(measurement[,1:(ncol(measurement)-1)]))) outputStates <- c(outputStates,as.integer(as.matrix(measurement[,2:ncol(measurement)]))) if (!is.null(perturbations)) { for (j in seq_len(ncol(measurement) - 1)) { if (ncol(perturbations) == 1) perturbationMatrix <- cbind(perturbationMatrix, perturbations[,1]) else perturbationMatrix <- cbind(perturbationMatrix, perturbations[,i]) } } } numStates <- as.integer(length(inputStates) / numGenes) } if (is.null(requiredDependencies)) requiredDepMatrix <- NULL else { if (is.null(names(requiredDependencies))) names(requiredDependencies) <- genenames if (length(union(names(requiredDependencies),genenames)) != length(genenames)) stop("The required dependencies must consist of gene names that are comprised in the measurements!") requiredDepMatrix <- matrix(0,nrow=numGenes,ncol=numGenes) colnames(requiredDepMatrix) <- genenames rownames(requiredDepMatrix) <- genenames maxRequired <- 0 for (i in seq_along(requiredDependencies)) { maxRequired <- max(maxRequired, length(requiredDependencies[i])) for (el in requiredDependencies[i]) requiredDepMatrix[el,names(requiredDependencies)[i]] <- 1 } if (maxRequired > maxK) { warning(paste("The number of required dependencies is greater than maxK! Setting maxK to ", maxRequired, "!", sep="")) maxK <- maxRequired } requiredDepMatrix <- as.integer(requiredDepMatrix) } if (is.null(excludedDependencies)) excludedDepMatrix <- NULL else { if (is.null(names(excludedDependencies))) names(excludedDependencies) <- genenames if (length(union(names(excludedDependencies),genenames)) != length(genenames)) stop("The excluded dependencies must consist of gene names that are comprised in the measurements!") excludedDepMatrix <- matrix(0,nrow=numGenes,ncol=numGenes) colnames(excludedDepMatrix) <- genenames rownames(excludedDepMatrix) <- genenames for (i in seq_along(excludedDependencies)) { gene <- names(excludedDependencies)[i] if (!is.null(requiredDependencies) && !is.null(requiredDependencies[[gene]])) { conflicts <- intersect(requiredDependencies[[gene]], excludedDependencies[[gene]]) if (length(conflicts) > 0) stop(paste("For gene ",gene, ", potential inputs were specified both as required and excluded dependencies: ", paste(conflicts, collapse=", "), sep="")) } for (el in excludedDependencies[i]) excludedDepMatrix[el,names(excludedDependencies)[i]] <- 1 } excludedDepMatrix <- as.integer(excludedDepMatrix) } if (!is.null(perturbations)) perturbationMatrix <- as.integer(perturbationMatrix) on.exit(.C("freeAllMemory", PACKAGE = "BoolNet")) # call C code res <- .Call("reconstructNetwork_R", inputStates, outputStates, perturbationMatrix, as.integer(numStates), requiredDepMatrix, excludedDepMatrix, as.integer(maxK), as.integer(meth), as.integer(allSolutions), as.integer(returnPBN)) if (any(sapply(res,function(interaction)length(interaction)==0))) # some function lists are empty warning("Some functions could not be inferred. Possibly the input data is noisy or maxK was chosen too small!") # prepare result object res <- list(genes=genenames, interactions=lapply(res,function(gene) lapply(gene,function(interaction) { interaction$expression <- getInteractionString(readableFunctions, interaction$func, genenames[interaction$input]) if (returnPBN) interaction$probability <- 1.0/length(gene) interaction })), fixed=sapply(res,function(gene) { if (length(gene) == 0) -1 else if (gene[[1]]$input[1] == 0) gene[[1]]$func[1] else -1 })) names(res$interactions) <- res$genes names(res$fixed) <- res$genes if (returnPBN) class(res) <- "ProbabilisticBooleanNetwork" else class(res) <- "BooleanNetworkCollection" if (allSolutions) # simplify functions and remove duplicates { res <- simplifyNetwork(res) res$interactions <- lapply(res$interactions,function(interaction) { duplicates <- duplicated(sapply(interaction,function(func)func$expression)) return(interaction[!duplicates]) }) } return(res) } ���������������BoolNet/R/print.BooleanNetwork.R��������������������������������������������������������������������0000644�0001762�0000144�00000001330�13277247010�016224� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Custom print function for class BooleanNetwork print.BooleanNetwork <- function(x, ...) { cat("Boolean network with",length(x$genes),"genes\n\n") cat("Involved genes:\n",paste(x$genes,collapse=" "),"\n\n",sep="") cat("Transition functions:\n") mapply(function(gene,interaction) { # print original expressions read from the files (if available) cat(gene," = ",interaction$expression,"\n",sep="") }, x$genes,x$interactions) if (sum(x$fixed != -1) > 0) { cat("\nKnocked-out and over-expressed genes:\n") mapply(function(gene,fixed) { if (fixed != -1) cat(gene," = ",fixed,"\n",sep="") }, x$genes,x$fixed) } return(invisible(x)) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/getBasinOfAttraction.R��������������������������������������������������������������������0000644�0001762�0000144�00000001015�13277247010�016212� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Determine the basin of attraction of attractor <attractorNo> in <attractorInfo>. getBasinOfAttraction <- function(attractorInfo,attractorNo) { stopifnot(inherits(attractorInfo,"AttractorInfo") || inherits(attractorInfo,"SymbolicSimulation")) if (missing(attractorNo) || attractorNo <= 0 || attractorNo > length(attractorInfo$attractors)) stop("Please provide a valid attractor number!") table <- getTransitionTable(attractorInfo) return(table[which(table$attractorAssignment == attractorNo),,drop=FALSE]) } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/loadSBML.R��������������������������������������������������������������������������������0000644�0001762�0000144�00000045463�13277247010�013554� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Check whether N is an integer using # a regular expression. check.integer <- function(N) { !length(grep("[^[:digit:]]", as.character(N))) } # Parse an SBML species list in <rootNode>. # Returns a list containing a map of gene ids to gene names, # a vector specifying which genes are fixed # and a vector of initial levels. parseSBMLSpecies <- function(rootNode) { genes <- c() fixed <- c() initialLevels <- c() # iterate over species for (species in xmlChildren(rootNode)) { attrs <- xmlAttrs(species) # if available, use the "name" attribute as the gene name # (and replace unsuitable characters by underscores) # otherwise use the gene id. if (is.na(attrs["name"]) || attrs["name"] == "") # for better compatibility with CoLoMoTo, # remove "s_" at the beginning of identifiers name <- sub("^s_","",attrs["id"]) else name <- gsub("[^a-zA-Z0-9_]+","_",attrs["name"]) # gene names must be unique if (name %in% genes) { suffix <- 1 while (paste(name,suffix,sep="_") %in% genes) suffix <- suffix + 1 warning(paste("Duplicate gene \"",name,"\", renaming to ", name,"_",suffix,"!",sep="")) name <- paste(name,suffix,sep="_") } # Reject logical networks with more than two values for a gene if (!is.na(attrs["maxLevel"]) && as.integer(attrs["maxLevel"]) > 1) stop(paste("BoolNet supports only binary genes, but gene \"", name,"\" has a maximum level of ",attrs["maxLevel"],"!", sep="")) # build a lookup table id -> gene name genes[attrs["id"]] <- adjustGeneNames(name) if (!is.na(attrs["constant"]) && tolower(attrs["constant"]) == "true") # if the gene is constant, save its initial level in the "fixed" vector { #if (is.na(attrs["initialLevel"])) #stop(paste("Gene \"", name, "\" is constant, but no initial level is supplied!", sep="")) # warning(paste("Gene \"", name, "\" is constant, but no initial level is supplied! Assuming an input!", sep="")) fixed[name] <- TRUE } else # this gene is not constant fixed[name] <- FALSE initialLevels[name] <- as.integer(attrs["initialLevel"]) } return(list(genes = genes, fixed = fixed, initialLevels = initialLevels)) } # Parse a list of transitions in <rootNode>. # Here, <genes> is the result of parseSBMLSpecies() # containing a map of gene ids/assignments, a vector # specifying fixed genes and a vector of initial levels. # Returns a list of interactions in the format # of class BooleanNetwork parseSBMLTransitions <- function(rootNode, genes, symbolic) { # iterate over all transitions transitions <- xmlApply(rootNode,function(transition) { # parse inputs inputList <- xmlFindNode(transition, "listOfInputs") if (is.null(inputList)) { inputs <- c() } else { inputList <- inputList[[1]] inputs <- c() inputThresholds <- c() # iterate over inputs for (input in xmlChildren(inputList)) { attrs <- xmlAttrs(input) id <- attrs["qualitativeSpecies"] # verify gene name in species list if (is.na(genes$genes[id])) stop(paste("Unknown input \"",id,"\"!",sep="")) else inputs <- union(inputs, id) # check whether attributes of the input are compatible # with Boolean logic if (tolower(attrs["transitionEffect"]) != "none") stop(paste("Transition effect for input gene \"",id,"\" is \"", attrs["transitionEffect"],"\", expected \"none\"!", sep="")) if (!is.na(attrs["thresholdLevel"]) && !is.na(attrs["id"])) # if a threshold level has been specified, save it with the # corresponding ID for later use in the MathML terms { inputThresholds[attrs["id"]] <- as.integer(attrs["thresholdLevel"]) if (inputThresholds[attrs["id"]] > 1) stop("Threshold levels must be 0 or 1!") } } } # parse outputs outputList <- xmlFindNode(transition, "listOfOutputs") outputs <- c() if (!is.null(outputList)) { outputList <- outputList[[1]] for (output in xmlChildren(outputList)) # iterate over outputs { attrs <- xmlAttrs(output) id <- attrs["qualitativeSpecies"] # verify gene list in species list if (is.na(genes$genes[id])) stop(paste("Unknown output ",id,"!",sep="")) else outputs <- union(outputs, id) # check whether attributes of the output are compatible # with Boolean logic if (tolower(attrs["transitionEffect"]) != "assignmentlevel") stop(paste("Transition effect for output gene \"",id,"\" is \"", attrs["transitionEffect"],"\", expected \"assignmentLevel\"!", sep="")) if (!is.na(attrs["outputLevel"])) stop("Output levels for transitions are not supported in Boolean models!") } } # parse function terms functionTermList <- xmlFindNode(transition, "listOfFunctionTerms", throwError=TRUE)[[1]] transitionFunction <- parseSBMLFunctionTerms(functionTermList, genes$genes[inputs], inputThresholds) return(list(inputs=inputs, outputs=outputs, transitionFunction=transitionFunction)) }) # now convert the read data to the BoolNet interaction format interactions <- lapply(names(genes$genes), function(gene) { # identify the transitions linked to each gene linkedTransitions <- which(sapply(transitions, function(transition)gene %in% transition$output)) if (length(linkedTransitions) == 0) # no transitions are assigned to this gene { if (!genes$fixed[genes$gene[gene]] || is.na(genes$initialLevels[genes$gene[gene]])) { if (is.na(genes$initialLevels[genes$gene[gene]])) { # Assume an input if the gene has no transition function and no initial value warning(paste("There is no transition and no initial level for gene \"", gene,"\"! Assuming an input!",sep=""), call.=FALSE) if (symbolic) return(parseBooleanFunction(genes$gene[gene])) else return(list(input=which(names(genes$genes) == gene), func=c(0,1), expression=genes$gene[gene])) } else if (!genes$fixed[genes$gene[gene]]) warning(paste("There is no transition for the non-constant gene \"", gene,"\"! Setting it to a constant ", genes$initialLevels[genes$gene[gene]], "!" ,sep=""), call.=FALSE) } # build a constant interaction if (symbolic) return(parseBooleanFunction(as.character(genes$initialLevels[genes$gene[gene]]))) else return(list(input=0, func=genes$initialLevels[genes$gene[gene]], expression=as.character(genes$initialLevels[genes$gene[gene]]))) } else { if (length(linkedTransitions) > 1) # multiple transitions per gene are not allowed, as these may be conflicting { stop(paste("Gene \"",gene,"\" is affected by multiple transitions!",sep="")) } if (genes$fixed[genes$gene[gene]]) # a constant gene should not be the output of a transition stop(paste("Gene \"",gene,"\" has been specified as constant, but there is a transition!",sep="")) if (symbolic) { # parse the Boolean expression, and construct a symbolic expression tree return(parseBooleanFunction(transitions[[linkedTransitions]]$transitionFunction, genes$genes)) } else { # parse the Boolean expression, and generate an interaction with # the corresponding truth table return(generateInteraction(transitions[[linkedTransitions]]$transitionFunction, #genes$genes[transitions[[linkedTransitions]]$input], genes$genes)) } } }) names(interactions) <- genes$genes return(interactions) } # Parse a list of function terms in <rootNode>, where <genes> specifies # the assignment of gene identifiers to gene names, # and <inputThresholds> specifies the assignment of threshold identifiers # to values (see also parseMathML()). # Returns a single character string representing the function term # as an R expression. parseSBMLFunctionTerms <- function(rootNode, genes, inputThresholds) { # iterate over function terms functionTerms <- xmlApply(rootNode, function(term) { attrs <- xmlAttrs(term) outputLevel <- as.integer(attrs["resultLevel"]) if (outputLevel > 1) stop("The result level of a function term must be 0 or 1!") if (tolower(xmlName(term)) == "defaultterm") # this is the default term => no expression { return(list(term="",outputLevel=outputLevel)) } else # parse the MathML expression in the function term { math <- xmlFindNode(term, "math", throwError=TRUE)[[1]][[1]] return(list(term=parseMathML(math, genes, inputThresholds), outputLevel=outputLevel)) } }) # build lists of terms with result 0 (negative terms) # and terms with result 1 (positive term) posTerms <- c() negTerms <- c() defaultValue <- NA for (term in functionTerms) { if (term$term != "") { if (term$outputLevel == 0) { negTerms <- c(negTerms, term$term) } else { posTerms <- c(posTerms, term$term) } } else defaultValue <- term$outputLevel } if (is.na(defaultValue)) stop("Missing default term in transition!") if (defaultValue == 0) # if the default is 0, the result is a DNF of the positive terms { if (length(posTerms) > 0) totalTerm <- paste(posTerms, collapse=" | ") else totalTerm <- "0" if (length(negTerms) > 0) # if the default value is 0, additional negative terms are ignored, # as they should be part of the default value # (otherwise this is a contradiction to the positive terms) warning("Potentially contradictory terms in a transition have been ignored!") } else # if the default value is 1, the result is a negated DNF of the negative terms { if (length(negTerms) > 0) totalTerm <- paste("!(",paste(negTerms, collapse=" | "),")",sep="") else totalTerm <- "1" if (length(posTerms) > 0) # if the default value is 1, additional positive terms are ignored, # as they should be part of the default value # (otherwise this is a contradiction to the negative terms) warning("Potentially contradictory terms in a transition have been ignored!") } return(totalTerm) } # Recursively parse the MathML expression in <rootNode>. # Here, valid identifiers are the gene names in <names(genes)> # and the input thresholds in <names(inputThresholds)>, # which are replaced by the corresponding values. # Returns an R expression string representing the MathML expression. parseMathML <- function(rootNode, genes, inputThresholds) { name <- xmlName(rootNode) if (name == "apply") # a bracket { operator <- xmlName(xmlChildren(rootNode)[[1]]) children <- sapply(xmlChildren(rootNode)[-1],parseMathML, genes, inputThresholds) if (operator == "and" || operator == "times") { # treat "and" and "times" equally, but warn if (operator == "times") warning("Interpreting \"times\" operator as a logical \"and\"!") return(paste("(",paste(children, collapse = " & "),")",sep="")) } else if (operator == "or" || operator == "plus") { # treat "or" and "plus" equally, but warn if (operator == "plus") warning("Interpreting \"plus\" operator as a logical \"or\"!") return(paste("(",paste(children, collapse = " | "),")",sep="")) } else if (operator == "xor") { # convert XOR to a DNF by pasting all odd entries in the truth table tt <- allcombn(2, length(children)) - 1 tt <- apply(tt,1,function(x)sum(x) %/% 2 == 1) return(paste("(",getDNF(tt, children),")",sep="")) } else if (operator %in% c ("eq", "neq", "gt", "lt", "geq", "leq")) { # comparison operators have to be converted to Boolean logic if (length(children) != 2) stop(paste("Operator \"",operator,"\" requires two operands!",sep="")) # check which of the child expressions are constant isConst <- sapply(children,function(x) { check.integer(x) }) if (all(isConst)) # two constants are compared (this does not really make sense!) { children <- as.integer(children) return(as.integer(switch(operator, eq = {children[1] == children[2]}, neq = {children[1] != children[2]}, gt = {children[1] > children[2]}, lt = {children[1] < children[2]}, geq = {children[1] >= children[2]}, leq = {children[1] <= children[2]} ))) } else if (any(isConst)) # one constant and one variable are compared { constChild <- as.integer(children[isConst]) varChild <- children[!isConst] return(switch(operator, eq = { if (constChild == 1) varChild else paste("!",varChild,sep="") }, neq = { if (constChild == 0) varChild else paste("!",varChild,sep="") }, gt = { if (constChild == 1) "0" else varChild }, lt = { if (constChild == 0) "0" else paste("!",varChild,sep="") }, geq = { if (constChild == 0) "1" else varChild }, leq = { if (constChild == 1) "1" else paste("!",varChild,sep="") } )) } else # two variables are compared { return(switch(operator, eq = { paste("((",children[1]," & ",children[2],") | ", "(!",children[1]," & !",children[2],"))", sep="") }, neq = { paste("((",children[1]," & !",children[2],") | ", "(!",children[1]," & ",children[2],"))", sep="") }, gt = { paste("(",children[1]," & !",children[2],")", sep="") }, lt = { paste("(!",children[1]," & ",children[2],")", sep="") }, geq = { paste("(",children[1], " | !",children[2],")", sep="") }, leq = { paste("(!",children[1], " | ",children[2],")", sep="") } )) } } else if (operator == "not") { if (length(children) > 2) stop("Multiple arguments supplied to unary operator \"neg\"!") return(paste("!",children, sep="")) } else # an unsupported symbol has been specified stop(paste("Unsupported math symbol: ", operator,"!",sep="")) } else if (name == "ci") # this is a gene identifier or a threshold level { id <- trim(xmlValue(rootNode)) if (!(id %in% names(genes))) { if (!(id %in% names(inputThresholds))) # neither threshold identifier nor gene stop(paste("Unspecified input \"",id,"\" in transition function!",sep="")) else # this is a threshold identifier return(inputThresholds[id]) } # this is a gene return(genes[id]) } else if (name == "cn") # this is a constant { # convert value and ensure it is Boolean attrs <- xmlAttrs(rootNode) if (!is.null(attrs) && !is.na(attrs["type"]) && tolower(attrs["type"]) != "integer") stop("\"cn\" nodes must be of type \"integer\"!") val <- trim(xmlValue(rootNode)) if (!check.integer(val) || !(as.integer(val) %in% c(0,1))) stop("\"cn\" nodes must be 0 or 1!") return(val) } else if (name == "true") return("1") else if (name == "false") return("0") else # an unsupported symbol has been specified stop(paste("Unsupported math symbol: ", name,"!",sep="")) } # Import the sbml-qual document <file> loadSBML <- function(file, symbolic=FALSE) { # load XML document doc <- xmlRoot(xmlParse(file)) # remove comments from the document suppressWarnings(comments <- getNodeSet(doc,"//comment()")) if (length(comments) > 0) removeNodes(comments) # do various checks to ensure this is an sbml-qual document if (xmlName(doc) != "sbml") stop("Not an SBML document!") if (as.integer(xmlAttrs(doc)["level"]) > 3 || as.integer(xmlAttrs(doc)["version"]) > 1) warning("This import is designed for documents up to SBML level 3 version 1!") if (is.null(xmlNamespaces(doc)$qual)) stop("This document does not import the sbml-qual package!") model <- xmlFindNode(doc, "model", throwError=TRUE)[[1]] # compartments are ignored # parse species species <- xmlFindNode(model, "listOfQualitativeSpecies", throwError=TRUE)[[1]] genes <- parseSBMLSpecies(species) # parse transitions transitions <- xmlFindNode(model, "listOfTransitions", throwError=TRUE)[[1]] interactions <- parseSBMLTransitions(transitions, genes, symbolic) if (symbolic) { delays <- apply(sapply(interactions,maxTimeDelay,genes=genes$genes),1,max) fixed <- as.integer(rep(-1L,length(genes$genes))) names(fixed) <- genes$genes res <- list(genes = genes$genes, interactions=interactions, fixed=fixed) res$internalStructs <- .Call("constructNetworkTrees_R",res) res$timeDelays <- delays class(res) <- "SymbolicBooleanNetwork" } else { # create BooleanNetwork structure res <- list(genes = genes$genes, fixed = sapply(interactions,function(i) { if (i$input[1] == 0) i$func[1] else -1 }), interactions = interactions) class(res) <- "BooleanNetwork" } return(res) } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/plotSequence.R����������������������������������������������������������������������������0000644�0001762�0000144�00000017114�13301230027�014602� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������plotSequence <- function (network, startState, includeAttractorStates = c("all", "first", "none"), sequence, title = "", mode = c("table", "graph"), plotFixed = TRUE, grouping = list(), onColor = "#4daf4a", offColor = "#e41a1c", layout, drawLabels = TRUE, drawLegend = TRUE, highlightAttractor = TRUE, reverse = FALSE, ### new parameters borderColor = "black", eps=0.1, attractor.sep.lwd = 2, attractor.sep.col = "blue", ...) { if (!missing(network)) { stopifnot(inherits(network, "BooleanNetwork") || inherits(network, "SymbolicBooleanNetwork")) if (missing(startState) || !missing(sequence)) stop("Either \"network\" and \"startState\" or \"sequence\" must be provided!") sequence <- getPathToAttractor(network = network, state = startState, includeAttractorStates = includeAttractorStates) numGenes <- length(network$genes) if (match.arg(mode, c("table", "graph")) == "table") { whichFixed <- which(network$fixed != -1) if (plotFixed | (length(whichFixed) == 0)) plotIndices <- seq_len(numGenes) else plotIndices <- seq_len(numGenes)[-whichFixed] attractor <- attributes(sequence)$attractor sequence <- sequence[, plotIndices, drop = FALSE] attributes(sequence)$attractor <- attractor } } else { if (missing(sequence) || !missing(startState)) stop("Either \"network\" and \"startState\" or \"sequence\" must be provided!") } switch(match.arg(mode, c("table", "graph")), table = { totalMatrix <- t(sequence) if (length(grouping) > 0) totalMatrix = totalMatrix[unlist(grouping$index), , drop = FALSE] if (is.null(colnames(totalMatrix))) { colnames(totalMatrix) <- seq_len(ncol(totalMatrix)) } else if (length(grep("t = ", colnames(totalMatrix)) == ncol(totalMatrix))) { colnames(totalMatrix) <- sapply(colnames(totalMatrix), gsub, pattern = "t = ", replacement = "", fixed = TRUE) } if (!reverse) totalMatrix <- totalMatrix[nrow(totalMatrix):1, , drop = F] plot(0, type="n", xlim = c(0, ncol(totalMatrix)), ylim = c(-2, nrow(totalMatrix)+1), xlab = "", ylab = "", axes = FALSE, main = title, ...) len <- ncol(totalMatrix) xStart <- 1 unitFactor <- (len - (2 * eps))/len axis(3, eps, "t = ", lty = "blank", yaxt = "s", xaxt = "s", xaxs = "i", pos = nrow(totalMatrix)+1) axis(3, eps + (1:ncol(totalMatrix))*unitFactor - unitFactor/2, ((1:ncol(totalMatrix)) - 1), lty = "blank", yaxt = "s", xaxt = "s", xaxs = "i", pos = nrow(totalMatrix)+1) axis(2, seq_len(nrow(totalMatrix)) - 0.5, rownames(totalMatrix), yaxt = "s", xaxt = "s", xaxs = "i", las = 2) startX <- eps for (i in seq_len(ncol(totalMatrix))) { for (j in seq_len(nrow(totalMatrix))) { rectCol <- ifelse(totalMatrix[j, i], onColor, offColor) rect(startX, j - 1, startX + unitFactor, j, col = rectCol, border = borderColor, lwd = 2) } startX <- startX + unitFactor if (i %% len == 0) { startX <- startX + 2*eps } } if (length(grouping) > 0) { if(!is.null(grouping$class)) { sepPos = cumsum(sapply(grouping$index, length)) abline(h = sepPos[-length(sepPos)], col = "black", lwd = 3) text(ncol(totalMatrix)/2, sepPos - 0.5, grouping$class, cex = 0.9) } } if (!is.null(attributes(sequence)$attractor) && highlightAttractor) { attrStart <- min(attributes(sequence)$attractor) - 1 #lines(x = c(attrStart, attrStart), y = c(-1, nrow(totalMatrix)) + 0.5) #abline(v = eps+attrStart*unitFactor, lwd = attractor.sep.lwd, col = attractor.sep.col) rect(xleft = eps+attrStart*unitFactor, xright = eps+attrStart*unitFactor, ybottom = -0.5, ytop = nrow(totalMatrix)+0.75, lwd = attractor.sep.lwd, border = attractor.sep.col) arrows(x0 = eps+attrStart*unitFactor, y0 = nrow(totalMatrix)+0.5, x1 = ncol(totalMatrix) - eps, y1 = nrow(totalMatrix)+0.5, length = 0.1, angle = 20, code = 3, col = attractor.sep.col) xpd.prev <- par()$xpd par(xpd=T) text(eps+attrStart*unitFactor, nrow(totalMatrix)+1, "Attractor", pos = 4) par(xpd=xpd.prev) } #if (drawLegend) legend(x = "bottomright", pch = c(15, 15), col = c(onColor, offColor), legend = c("active", "inactive"), cex = 0.7, horiz = T) if (drawLegend) legend(x = 0, y = -2, pch = c(15, 15), col = c(onColor, offColor), legend = c("active", "inactive"), cex = 0.7, horiz = T, xpd=T) #return(totalMatrix[network$genes,]) return(totalMatrix) }, graph = { if (installed.packages()["igraph", "Version"] < package_version("0.6")) bias <- 1 else bias <- 0 args <- list(...) if (is.null(args$vertex.size)) args$vertex.size <- 2 if (is.null(args$edge.arrow.mode)) args$edge.arrow.mode <- 0 if (is.null(args$rescale)) args$rescale <- !missing(layout) if (is.null(args$vertex.label.cex)) args$vertex.label.cex <- 0.75 if (is.null(args$vertex.label.dist)) args$vertex.label.dist <- 0.25 if (is.null(args$vertex.label.degree)) args$vertex.label.degree <- -pi/2 if (is.null(args$vertex.color)) args$vertex.color <- "grey" if (is.null(args$edge.arrow.size)) args$edge.arrow.size <- 0.5 if (missing(layout)) layout <- matrix(c(seq(-1, 1, length.out = nrow(sequence)), rep(0, nrow(sequence))), ncol = 2) states <- apply(sequence, 1, paste, collapse = "") nodes <- data.frame(seq_along(states), stringsAsFactors = FALSE) lastAttractorEdgeIndex <- NULL if (length(states) > 1) { initialStates <- 1:(length(states) - 1) nextStates <- 2:length(states) edgeMatrix <- data.frame(initialStates, nextStates) if (!is.null(attributes(sequence)$attractor)) { attractorEdge <- c(max(attributes(sequence)$attractor), min(attributes(sequence)$attractor)) if (all(attractorEdge <= length(states))) { edgeMatrix <- rbind(edgeMatrix, attractorEdge) lastAttractorEdgeIndex <- nrow(edgeMatrix) } } } else { edgeMatrix <- data.frame(matrix(nrow = 0, ncol = 2)) } graph <- graph.data.frame(edgeMatrix, vertices = nodes, directed = TRUE) if (drawLabels) labels <- states else labels <- NA if (highlightAttractor && !is.null(attributes(sequence)$attractor)) { attractorEdgeIndices <- intersect(seq_len(nrow(edgeMatrix)), c(attributes(sequence)$attractor, nrow(edgeMatrix))) - bias graph <- set.edge.attribute(graph, "width", index = attractorEdgeIndices, value = 3) } if (!is.null(lastAttractorEdgeIndex)) { graph <- set.edge.attribute(graph, "curved", value = 0) graph <- set.edge.attribute(graph, "curved", index = lastAttractorEdgeIndex - bias, value = 0.5) } plot(graph, layout = layout, vertex.label = labels, vertex.label.cex = args$vertex.label.cex, vertex.size = args$vertex.size, vertex.color = args$vertex.color, vertex.label.dist = args$vertex.label.dist, vertex.label.degree = args$vertex.label.degree, edge.arrow.size = args$edge.arrow.size, rescale = args$rescale, main = title, ...) return(graph) }) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/simulateSymbolicModel.R�������������������������������������������������������������������0000644�0001762�0000144�00000016300�13277247010�016451� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������simulateSymbolicModel <- function(network, method=c("exhaustive","random","chosen","sat.exhaustive","sat.restricted"), startStates=NULL, returnSequences=(!(match.arg(method) %in% c("sat.exhaustive", "sat.restricted"))), returnGraph=(!(match.arg(method) %in% c("sat.exhaustive", "sat.restricted"))), returnAttractors=TRUE, maxTransitions=Inf, maxAttractorLength=Inf, canonical=TRUE) { stopifnot(inherits(network,"SymbolicBooleanNetwork")) if (is.null(network$internalStructs) || checkNullPointer(network$internalStructs)) # refresh internal tree representations if necessary network$internalStructs = .Call("constructNetworkTrees_R",network); if (!is.null(maxAttractorLength) && is.infinite(maxAttractorLength)) maxAttractorLength <- NULL if (length(method) > 1) # if no method is supplied, infer method from the type of <startStates> { if (!is.null(maxAttractorLength)) method <- "sat.restricted" else if (length(startStates) == 0) { method <- "exhaustive" } else if (is.numeric(startStates)) { if (length(startStates) > 1) stop("Please supply either the number of start states or a list of start states in startStates!") else method <- "random" } else if (is.list(startStates)) method <- "chosen" else stop("Please supply either the number of start states or a list of start states in startStates!") } method <- match.arg(method, c("exhaustive","random","chosen","sat.exhaustive","sat.restricted")) if (method == "random") { if (startStates > 2 ^ (sum(network$timeDelays[network$fixed == -1]))) # more start states than in the full network { method <- "exhaustive" warning(paste("The number of random states is set larger than the total", "number of states. Performing an exhaustive search!")) } } if (method %in% c("sat.exhaustive", "sat.restricted")) { if (!is.null(maxAttractorLength)) maxAttractorLength <- as.integer(maxAttractorLength) else if (method == "sat.restricted") stop("maxAttractorLength must be set for method=\"sat.restricted\"!") if (returnSequences) { warning("Sequences cannot be returned for method=\"sat.exhaustive\" and method=\"sat.restricted\"!") returnSequences <- FALSE } if (returnGraph) { warning("Graph cannot be returned for method=\"sat.exhaustive\" and method=\"sat.restricted\"!") returnGraph <- FALSE } } else if (method == "exhaustive") { startStates <- NULL convertedStates <- NULL } else if (method == "chosen") { convertedStates <- lapply(startStates, function(state) { if (!is.null(dim(state))) { if (ncol(state) != length(network$genes)) stop(paste("\"startStates\" must be either a list of vectors with one value for each gene,", "or a list of matrices with the genes in the columns and multiple predecessor states in the rows!")) return(as.integer(as.matrix(state[nrow(state):1,]))) } else if (!is.numeric(state) || length(state) != length(network$genes)) stop(paste("\"startStates\" must be either a list of vectors with one value for each gene,", "or a list of matrices with the genes in the columns and multiple predecessor states in the rows!")) return(as.integer(state)) }) } else convertedStates <- as.integer(startStates) if (maxTransitions == 0) warning("\"maxTransitions\" is set to 0, which disables the transition limit!") else if (is.infinite(maxTransitions)) maxTransitions <- 0 on.exit(.C("freeAllMemory", PACKAGE = "BoolNet")) if (method %in% c("sat.exhaustive","sat.restricted")) res <- .Call("symbolicSATSearch_R", network$internalStructs, maxAttractorLength, method == "sat.restricted") else res <- .Call("simulateStates_R", network$internalStructs, convertedStates, #as.integer(length(startStates)), as.integer(maxTransitions), as.logical(returnSequences), as.logical(returnGraph), as.logical(returnAttractors)) ret <- list() if (returnSequences) { ret[["sequences"]] <- list() } if (returnGraph) { initialStates <- matrix(res[[2]][[1]], ncol=length(network$genes), byrow=TRUE) colnames(initialStates) <- paste("initialState.",network$genes, sep="") nextStates <- matrix(res[[2]][[2]], ncol=length(network$genes), byrow=TRUE) colnames(nextStates) <- paste("nextState.",network$genes, sep="") attractorAssignment <- data.frame(res[[2]][[3]] + 1) attractorAssignment[attractorAssignment == 0] <- NA colnames(attractorAssignment) <- "attractorAssignment" graph <- data.frame(unique(cbind(initialStates, nextStates, attractorAssignment))) class(graph) <- c("TransitionTable","data.frame") ret[["graph"]] <- graph } if (returnAttractors) { attractors <- lapply(res[[3]], function(x) { att <- matrix(x, ncol=length(network$genes), byrow=TRUE) colnames(att) <- network$genes if (canonical) { smallestIndex <- -1 smallestVal <- rep(Inf, ncol(att)) for (i in seq_len(nrow(att))) # iterate over elements of encoded state { equal <- TRUE for (j in seq(ncol(att),by=-1,length.out=ncol(att))) { if (att[i,j] < smallestVal[j]) # determine new minimum { equal <- FALSE smallestVal <- att[i,] smallestIndex <- i break } else if (att[i,j] > smallestVal[j]) { equal <- FALSE break } } if (equal && i != smallestIndex) { if (i - smallestIndex < (smallestIndex + nrow(att) - i) %% nrow(att)) { smallestVal <- att[i,] smallestIndex <- i } } } } if (smallestIndex != 1) # rearrange matrix att <- rbind(att[smallestIndex:nrow(att),,drop=FALSE], att[seq_len(smallestIndex-1),,drop=FALSE]) as.data.frame(att) }) ret[["attractors"]] <- attractors } if (returnSequences) { maxDelay <- max(network$timeDelays) if (returnAttractors) { ret[["attractorAssignment"]] <- res[[4]] + 1 ret[["attractorAssignment"]][ret[["attractorAssignment"]] == 0] <- NA } sequences <- mapply(function(seq, att) { seq <- matrix(seq, ncol=length(network$genes), byrow=TRUE) colnames(seq) <- network$genes rownames(seq) <- paste("t =", (1:nrow(seq)) - maxDelay) seq <- as.data.frame(seq) # add attractor information to sequence if (!is.na(att)) attributes(seq)$attractor <- (nrow(seq) - nrow(ret[["attractors"]][[att]]) + 1):nrow(seq) seq }, res[[1]], ret[["attractorAssignment"]], SIMPLIFY=FALSE) ret[["sequences"]] <- sequences } class(ret) <- "SymbolicSimulation" return(ret) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/edgeDetector.R����������������������������������������������������������������������������0000644�0001762�0000144�00000003510�13277247010�014540� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Provides several methods to binarize a vector consisting of real values. # The methods are edge-detector-based. With <edge>="firstEdge", # the first "significant" edge in the sorted data is the threshold for the binarization. # With the <scaling> factor, the size of the first edge can be adapted. # The "maxEdge" method searches for the edge with the highest gradient. edgeDetector <- function(vector,scaling=1,edge=c("firstEdge","maxEdge")) { distance<-c() binarizeddata<-vector #sort data sortedvector<-sort(vector) #distance calculation for(i in seq_len(length(vector)-1)) { distance[i]<-sortedvector[i+1]-sortedvector[i] } switch(match.arg(edge), #the index of the first edge with distance[i]>threshold is determined firstEdge= { threshold<-scaling*((sortedvector[length(vector)]-sortedvector[1])/((length(vector)-1))) index <- 0 for(i in seq_len(length(vector)-1)) { if(distance[i]>threshold) { index<-i break } } }, #the index of the edge with the maximal gradient is determined maxEdge= { index <- which.max(distance) }, stop("'method' must be one of \"firstEdge\",\"maxEdge\"") ) #based on the edge index, the binarization is performed if(index!=0) { for(i in seq_len(length(vector))) { if(vector[i]>=sortedvector[index+1]) binarizeddata[i]<-1 else binarizeddata[i]<-0 } threshold=(sortedvector[index+1]+sortedvector[index])/2 return(list(bindata=binarizeddata,thresholds=as.numeric(threshold))) } else #if no edge was found, a vector consisting of zeros is returned { binarizeddata<-(sapply(vector,function(x) 0)) return(list(bindata=binarizeddata,thresholds=NA)) } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/fixGenes.R��������������������������������������������������������������������������������0000644�0001762�0000144�00000001574�13277247010�013722� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Sets the genes in <fixIndices> to the values in <values> # and returns the customized copy of <network> fixGenes <- function(network,fixIndices,values) { stopifnot(inherits(network,"BooleanNetwork") | inherits(network,"SymbolicBooleanNetwork") | inherits(network,"ProbabilisticBooleanNetwork")) if (length(fixIndices) != length(values) && length(values) != 1) stop("fixIndices and values must have the same number of elements, or values must have 1 element!") if (any(is.na(network$fixed[fixIndices]))) stop("fixIndices contains invalid indices!") if (any(values != 0 & values != 1 & values != -1)) stop("Please supply only 0, 1, or -1 in values!") network$fixed[fixIndices] <- as.integer(values) if (inherits(network,"SymbolicBooleanNetwork")) network$internalStructs = .Call("constructNetworkTrees_R",network); return(network) } ������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/toSBML.R����������������������������������������������������������������������������������0000644�0001762�0000144�00000020404�13277247010�013243� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Indent <string> using <count> tabs. indent <- function(string,count) { if (count == 0) return(string) return(paste(paste(rep("\t",count),collapse=""), string, sep="")) } # Export a Boolean network <network> to an sbml-qual file <fileName>. # If <generateDNFs>, a new symbolic representation for the interactions # is generated on the basis of the truth tables (in disjunctive normal form). # Otherwise, the $expression elements of the interactions are parsed. # If <saveFixed> is true, constant transition functions are exported for fixed genes # instead of their true transition functions toSBML <- function(network, file, generateDNFs=FALSE, saveFixed = TRUE) { symbolic <- inherits(network,"SymbolicBooleanNetwork") stopifnot(inherits(network,"BooleanNetwork") || symbolic) if (symbolic) { if (any(network$timeDelays > 1)) stop("SBML does not support networks with time delays!") parseTrees <- network$interactions } else { parseTrees <- NULL if (generateDNFs == FALSE) # Check whether all interactions have suitable string representations { tryCatch( { # parse the string representations parseTrees <- lapply(network$interactions, function(int)parseBooleanFunction(int$expression)) }, error=function(e) { warning(paste("The transition functions of this network did not contain valid symbolic expressions!", "Generating DNF representations from the truth tables!")) # There was an error parsing a string representation => generate DNFs generateDNFs <<- TRUE }) } if (generateDNFs != FALSE) # build new representations of the functions in disjunctive normal form { network$interactions <- lapply(network$interactions, function(interaction) { table <- allcombn(2, length(interaction$input)) - 1 interaction$expression <- getDNF(interaction$func, network$genes[interaction$input], generateDNFs) return(interaction) }) # parse the DNF representations parseTrees <- lapply(network$interactions, function(int)parseBooleanFunction(int$expression)) } names(parseTrees) <- network$genes } # generate a network identifier from the file name id <- sub(".sbml", "", basename(file), fixed=TRUE) id <- gsub("[^a-zA-Z0-9_]+","_",id) # open a string connection output <- NULL f <- textConnection("output", encoding="UTF-8", open="w", local=TRUE) # write document header cat(file=f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") cat(file=f, "<sbml xmlns=\"http://www.sbml.org/sbml/level3/version1/core\" level=\"3\" version=\"1\" xmlns:qual=\"http://www.sbml.org/sbml/level3/version1/qual/version1\" qual:required=\"true\">\n") cat(file=f, "\t<model id=\"", id, "\">\n", sep="") # write default compartment cat(file=f, "\t\t<listOfCompartments>\n") cat(file=f, "\t\t\t<compartment id=\"default\" constant=\"true\"/>\n") cat(file=f, "\t\t</listOfCompartments>\n") # write genes cat(file=f, "\t\t<qual:listOfQualitativeSpecies>\n") for (gene in network$genes) { if ((saveFixed && network$fixed[gene] != -1) || (!symbolic && network$interactions[[gene]]$input[1] == 0)) { if (saveFixed && network$fixed[gene] != -1) level <- network$fixed[gene] else level <- network$interactions[[gene]]$func[1] cat(file=f, "\t\t\t<qual:qualitativeSpecies qual:compartment=\"default\"", " qual:constant=\"true\" qual:id=\"", gene, "\" qual:name=\"", gene, "\" qual:initialLevel=\"", level, "\" qual:maxLevel=\"", level, "\"/>\n", sep="") } else cat(file=f, "\t\t\t<qual:qualitativeSpecies qual:compartment=\"default\"", " qual:constant=\"false\" qual:id=\"", gene, "\" qual:name=\"", gene, "\" qual:maxLevel=\"1\"/>\n", sep="") } cat(file=f, "\t\t</qual:listOfQualitativeSpecies>\n") # write transition functions cat(file=f, "\t\t<qual:listOfTransitions>\n") for (gene in network$genes) { if ((!saveFixed || network$fixed[[gene]] == -1) && (symbolic || network$interactions[[gene]]$input[1] != 0)) { cat(file=f, "\t\t\t<qual:transition qual:id=\"tr_", gene, "\" qual:name=\"Interactions targeting ", gene, "\">\n", sep="") cat(file=f, "\t\t\t\t<qual:listOfInputs>\n") if (symbolic) inputs <- getInputs(network$interactions[[gene]]) else inputs <- network$genes[network$interactions[[gene]]$input] for (input in inputs) cat(file=f, "\t\t\t\t\t<qual:input qual:qualitativeSpecies=\"", input, "\" qual:transitionEffect=\"none\"/>\n", sep="") cat(file=f, "\t\t\t\t</qual:listOfInputs>\n") cat(file=f, "\t\t\t\t<qual:listOfOutputs>\n") cat(file=f, "\t\t\t\t\t<qual:output qual:qualitativeSpecies=\"", gene, "\" qual:transitionEffect=\"assignmentLevel\"/>\n", sep="") cat(file=f, "\t\t\t\t</qual:listOfOutputs>\n") cat(file=f, "\t\t\t\t<qual:listOfFunctionTerms>\n") cat(file=f, "\t\t\t\t\t<qual:functionTerm qual:resultLevel=\"1\">\n") cat(file=f, "\t\t\t\t\t\t<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n") parseTree <- parseTrees[[gene]] cat(file=f, MathMLFromParseTree(parseTree, indentLevel=7)) cat(file=f, "\t\t\t\t\t\t</math>\n") cat(file=f, "\t\t\t\t\t</qual:functionTerm>\n") cat(file=f, "\t\t\t\t\t<qual:defaultTerm qual:resultLevel=\"0\"/>\n") cat(file=f, "\t\t\t\t</qual:listOfFunctionTerms>\n") cat(file=f, "\t\t\t</qual:transition>\n") } } # finish document cat(file=f, "\t\t</qual:listOfTransitions>\n") cat(file=f, "\t</model>\n") cat(file=f, "</sbml>\n") close(f) # open file and write the complete XML string f <- file(file, encoding="UTF-8", open="w") cat(file=f,output,sep="\n") close(f) } # Build a MathML representation of a parse tree <tree> # that represents a symbolic Boolean expression. # Indentation of the XML nodes starts with <indentLevel>. # Returns a string with MathML code. MathMLFromParseTree <- function(tree,indentLevel=0) { res <- switch(tree$type, operator = { if (tree$operator %in% c("timeis","timegt","timelt")) stop(sprintf("Operator \"%s\" not supported in SBML!", tree$operator)); if (tree$operator %in% c("maj","sumis","sumlt","sumgt")) # convert special predicates to general Boolean formulae tree <- expandCountPredicate(tree) if (tree$negated) paste(indent("<apply>\n", indentLevel), indent("<not/>\n", indentLevel+1), indent("<apply>\n" ,indentLevel+1), indent({if (tree$operator=="|" || tree$operator=="any") {"<or/>\n"} else{"<and/>\n"}}, indentLevel+2), paste(sapply(tree$operands,MathMLFromParseTree, indentLevel+2), collapse=""), indent("</apply>\n", indentLevel+1), indent("</apply>\n", indentLevel), sep="") else paste(indent("<apply>\n", indentLevel), indent({if (tree$operator=="|" || tree$operator=="any") {"<or/>\n"} else{"<and/>\n"}}, indentLevel+1), paste(sapply(tree$operands, MathMLFromParseTree, indentLevel+1), collapse=""), indent("</apply>\n", indentLevel), sep="") }, atom = { if ((tree$name == "0" && !tree$negated) || (tree$name == "1" && tree$negated)) indent("<cn type=\"integer\">0</cn>\n", indentLevel) else if ((tree$name == "1" && !tree$negated) || (tree$name == "0" && tree$negated)) indent("<cn type=\"integer\">1</cn>\n", indentLevel) else paste(indent("<apply>\n",indentLevel), indent("<eq/>\n", indentLevel+1), indent(paste("<ci>",tree$name,"</ci>\n",sep=""),indentLevel+1), indent(paste("<cn type=\"integer\">", {if (tree$negated) 0 else 1}, "</cn>\n", sep=""), indentLevel+1), indent("</apply>\n",indentLevel), sep="") }) return(res) } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/plotPBNTransitions.R����������������������������������������������������������������������0000644�0001762�0000144�00000007210�13277247010�015717� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Plots a graph of the transitions in a probabilistic Boolean network. # <markovSimulation> is the result of a Markov simulation with returnTable=TRUE. # If stateSubset is specified, only transitions between states in the set are considered. # If <drawProbabilities> is true, the edges are annotated with probabilities. # If <drawStateLabels> is true, the states are annotated with their gene values. # <layout> specifies the igraph layout to be used. # If <plotIt> is false, only the graph is returned, and nothing is plotted. # ... specifies further parameters to igraph. plotPBNTransitions <- function(markovSimulation,stateSubset, drawProbabilities=TRUE,drawStateLabels=TRUE, layout=layout.fruchterman.reingold, plotIt=TRUE,...) { stopifnot(inherits(markovSimulation,"MarkovSimulation")) if (is.null(markovSimulation$table)) stop(paste("The supplied simulation result does not contain transition information.", "Please re-run markovSimulation() with returnTable=TRUE!")) # assemble edges from table edgeMatrix <- data.frame(apply(markovSimulation$table$initialStates,2, function(x)paste(dec2bin(x,length(markovSimulation$genes)),collapse="")), apply(markovSimulation$table$nextStates,2, function(x)paste(dec2bin(x,length(markovSimulation$genes)),collapse=""))) if (!missing(stateSubset)) { # determine edges to be excluded based on the subset stateSubset <- sapply(stateSubset,function(x)paste(x,collapse="")) keepIndices <- apply(edgeMatrix,1,function(row) { (length(intersect(row,stateSubset)) == length(unique(row))) }) # drop edges edgeMatrix <- edgeMatrix[keepIndices,] probabilities <- markovSimulation$table$probabilities[keepIndices] } else probabilities <- markovSimulation$table$probabilities # determine set of vertices vertices <- as.data.frame(as.character(unique(c(as.character(edgeMatrix[,1]), as.character(edgeMatrix[,2]))))) # build graph graph <- graph.data.frame(edgeMatrix,vertices=vertices,directed=TRUE) if (drawProbabilities) graph <- set.edge.attribute(graph,"label",value=paste(" ",probabilities)) if (drawStateLabels) label <- as.character(vertices[,1]) else label <- NA if (plotIt) { # set default values for further graphical parameters args <- list(...) if (is.null(args$vertex.size)) args$vertex.size <- 2 if (is.null(args$edge.arrow.mode)) args$edge.arrow.mode <- 0 if (is.null(args$vertex.label.cex)) args$vertex.label.cex <- 0.75 if (is.null(args$edge.label.cex)) args$edge.label.cex <- 0.75 if (is.null(args$vertex.label.dist)) args$vertex.label.dist <- 1 if (is.null(args$vertex.color)) args$vertex.color <- "grey" if (is.null(args$edge.label.color)) args$edge.label.color <- "green" if (is.null(args$edge.arrow.size)) args$edge.arrow.size <- 0.5 # plot it plot(graph,vertex.label=label,layout=layout,vertex.label.cex=args$vertex.label.cex, vertex.size=args$vertex.size,vertex.color=args$vertex.color, vertex.label.dist = args$vertex.label.dist, edge.arrow.size=args$edge.arrow.size, edge.label.color=args$edge.label.color, edge.label.cex=args$edge.label.cex,...) } # return the igraph object return(invisible(graph)) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/chooseNetwork.R���������������������������������������������������������������������������0000644�0001762�0000144�00000005626�13450617101�015001� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Creates a deterministic Boolean network from a Probabilistic Boolean network # by choosing the functions specified in <functionIndices> from the # network <probabilisticNetwork>. chooseNetwork <- function(probabilisticNetwork,functionIndices,dontCareValues=NULL,readableFunctions=FALSE) { stopifnot(inherits(probabilisticNetwork,"ProbabilisticBooleanNetwork") | inherits(probabilisticNetwork,"BooleanNetworkCollection")) if (length(functionIndices) != length(probabilisticNetwork$genes)) stop("Please provide a vector of function indices for each gene!") if (inherits(probabilisticNetwork,"ProbabilisticBooleanNetwork")) { interactions <- mapply(function(interaction,index) { list(input=interaction[[index]]$input, func=interaction[[index]]$func, expression=interaction[[index]]$expression) }, probabilisticNetwork$interactions,functionIndices,SIMPLIFY=FALSE) } else { if (!is.null(dontCareValues) && length(dontCareValues) == length(probabilisticNetwork$genes) && is.null(names(dontCareValues))) names(dontCareValues) <- probabilisticNetwork$genes interactions <- mapply(function(interaction,index,gene) { func <- interaction[[index]]$func dcPos <- which(func == -1) if (length(dcPos) > 0) { if (is.null(dontCareValues) || is.null(dontCareValues[[gene]])) stop(paste("No values for the \"don't care\" ", "entries were specified for gene \"", gene,"\"!",sep="")) if (!all(dontCareValues[[gene]] %in% c(0,1))) stop(paste("Invalid values for \"don't care\" entries specified for gene \"", gene,"\"!",sep="")) if (length(dontCareValues[[gene]]) != length(dcPos)) stop(paste("There must be exactly ",length(dcPos), " value(s) for \"don't care\" entries in the function for gene \"", gene,"\"!",sep="")) func[dcPos] <- dontCareValues[[gene]] expression <- getInteractionString(readableFunctions, func, probabilisticNetwork$genes[interaction[[index]]$input]) } else expression <- interaction[[index]]$expression list(input=interaction[[index]]$input, func=func, expression=expression) }, probabilisticNetwork$interactions, functionIndices, probabilisticNetwork$genes,SIMPLIFY=FALSE) } res <- list(genes=probabilisticNetwork$genes, interactions=interactions, fixed=probabilisticNetwork$fixed) class(res) <- "BooleanNetwork" return(res) } ����������������������������������������������������������������������������������������������������������BoolNet/R/print.SymbolicBooleanNetwork.R������������������������������������������������������������0000644�0001762�0000144�00000000762�13277247010�017736� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������print.SymbolicBooleanNetwork <- function(x,...) { cat("Symbolic representation of a Boolean network\n\n"); cat("Transition functions:\n") for (gene in x$genes) { cat(gene, " = ", stringFromParseTree(x$interactions[[gene]]), "\n", sep="") } if (sum(x$fixed != -1) > 0) { cat("\nKnocked-out and over-expressed genes:\n") mapply(function(gene,fixed) { if (fixed != -1) cat(gene," = ",fixed,"\n",sep="") }, x$genes,x$fixed) } } ��������������BoolNet/R/getPathToAttractor.R����������������������������������������������������������������������0000644�0001762�0000144�00000006310�13277247010�015726� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������getPathToAttractor <- function(network, state, includeAttractorStates=c("all","first","none")) { stopifnot(inherits(network,"BooleanNetwork") || inherits(network,"SymbolicBooleanNetwork") || inherits(network, "AttractorInfo")) includeAttractorStates <- match.arg(includeAttractorStates, c("all","first","none")) if (inherits(network,"SymbolicBooleanNetwork")) { sim <- simulateSymbolicModel(network, startStates=list(state)) res <- data.frame(sim$sequences[[1]]) attractorStates <- nrow(res) - seq(length.out=nrow(sim$attractors[[1]]),by=-1,to=1) + 1 if (includeAttractorStates == "first") { res <- res[seq_len(attractorStates[1]),,drop=FALSE] attractorStates <- attractorStates[1] } else if (includeAttractorStates == "none") { res <- res[-attractorStates,,drop=FALSE] attractorStates <- NULL } attributes(res)$attractor <- attractorStates } else { if (inherits(network,"BooleanNetwork")) { table <- getTransitionTable(getAttractors(network, startStates=list(state))) } else { if (is.null(network$stateInfo$table)) stop(paste("This AttractorInfo structure does not contain transition table information.", "Please re-run getAttractors() with a synchronous search and returnTable=TRUE!")) table <- getTransitionTable(network) } numGenes <- (ncol(table) - 2) / 2 initialStates <- apply(table[,seq_len(numGenes),drop=FALSE],1,function(x)paste(x,collapse="")) currentState <- state res <- data.frame(matrix(state,nrow=1)) attractorStart <- NA stateCount <- 1 repeat { currentStateIdx <- which(initialStates == paste(currentState,collapse="")) if (length(currentStateIdx) == 0) stop(paste("Could not find state",paste(currentState,collapse=""),"in the transition table!")) if (table[currentStateIdx,"transitionsToAttractor"] == 0 && is.na(attractorStart)) attractorStart <- stateCount # stop depending on "includeAttractorStates" option if ((includeAttractorStates == "all" && stateCount == nrow(table)) || (includeAttractorStates == "first" && table[currentStateIdx,"transitionsToAttractor"] == 0) || (includeAttractorStates == "none" && table[currentStateIdx,"transitionsToAttractor"] <= 1)) break currentState <- as.integer(table[currentStateIdx,(numGenes+1):(2*numGenes)]) res <- rbind(res,currentState) stateCount <- stateCount + 1 } if (!is.na(attractorStart)) attractorIdx <- seq(attractorStart, nrow(table), by=1) else attractorIdx <- NULL # special case: start state is attractor state and we do not want to include attractor states # => return empty data frame if (includeAttractorStates == "none" && table[currentStateIdx,"transitionsToAttractor"] == 0) { res <- data.frame(matrix(nrow=0,ncol=numGenes)) } else if (length(attractorIdx) > 0) attributes(res)$attractor <- attractorIdx colnames(res) <- sapply(colnames(table)[seq_len(numGenes)],function(n)strsplit(n,".",fixed=TRUE)[[1]][2]) rownames(res) <- NULL } return(res) } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/stateTransition.R�������������������������������������������������������������������������0000644�0001762�0000144�00000014150�13277247010�015337� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������stateTransition <- function(network,state,type=c("synchronous","asynchronous","probabilistic"), geneProbabilities, chosenGene, chosenFunctions, timeStep=0) { stopifnot(inherits(network,"BooleanNetwork") | inherits(network,"SymbolicBooleanNetwork") | inherits(network,"ProbabilisticBooleanNetwork")) type <- match.arg(type, c("synchronous","asynchronous","probabilistic")) if (inherits(network,"SymbolicBooleanNetwork")) { if (type != "synchronous") stop("Only synchronous updates are allowed for symbolic networks!") if (!is.null(dim(state))) { if (ncol(state) != length(network$genes)) stop(paste("\"state\" must be either a vector with one value for each gene,", "or a matrix with the genes in the columns and multiple predecessor states in the rows!")) state <- as.integer(as.matrix(state[nrow(state):1,])) } else { if (!is.numeric(state) || length(state) != length(network$genes)) stop(paste("\"state\" must be either a vector with one value for each gene,", "or a matrix with the genes in the columns and multiple predecessor states in the rows!")) state <- as.integer(state) } if (is.null(network$internalStructs) || checkNullPointer(network$internalStructs)) # refresh internal tree representations if necessary network$internalStructs = .Call("constructNetworkTrees_R",network); on.exit(.C("freeAllMemory", PACKAGE = "BoolNet")) res <- .Call("symbolicStateTransition_R", network$internalStructs, state, as.integer(timeStep)) } else { if (length(state) != length(network$genes)) stop("The state must consist of exactly one value for each gene!") nonFixedIndices = (network$fixed == -1) res <- state if (inherits(network,"BooleanNetwork") & type == "probabilistic") type <- "synchronous" if (!inherits(network,"BooleanNetwork") & length(type) == 3) type <- "probabilistic" if (type == "probabilistic") { if (missing(chosenFunctions) || is.null(chosenFunctions)) { chosenFunctions <- sapply(network$interactions,function(gene) { distr <- c(0,cumsum(sapply(gene,function(func)func$probability))) r <- runif(n=1) idx <- 0 for (i in seq_along(gene)) { if (r > distr[i] & r <= distr[i+1]) { idx <- i break } } idx }) } else if (length(chosenFunctions) != length(network$genes)) stop("Please provide a function index for each gene!") res[nonFixedIndices] <- mapply(function(i,f) { if(network$interactions[[i]][[f]]$input[1] == 0) # this is a constant gene with no transition function return(network$interactions[[i]][[f]]$func[1]) input = state[network$interactions[[i]][[f]]$input] return(network$interactions[[i]][[f]]$func[bin2dec(rev(input),length(input)) + 1]) }, which(nonFixedIndices), chosenFunctions[nonFixedIndices]) } else { if (!inherits(network,"BooleanNetwork")) stop("Please choose type=\"probabilistic\" for a probabilistic Boolean network!") changeIndices <- switch(type, synchronous = which(nonFixedIndices), asynchronous = { if (missing(chosenGene) || is.null(chosenGene)) { if (missing(geneProbabilities) || is.null(geneProbabilities)) sample(which(nonFixedIndices),1) else { if (length(geneProbabilities) != length(network$genes)) stop("Please supply exactly one probability for each gene!") if (abs(1.0 - sum(geneProbabilities)) > 0.0001) stop("The supplied gene probabilities do not sum up to 1!") if (sum(geneProbabilities[nonFixedIndices]) < 0.0001) stop("There is no non-fixed gene with a probability greater than 0!") geneProbabilities[nonFixedIndices] <- geneProbabilities[nonFixedIndices]/sum(geneProbabilities[nonFixedIndices]) if (sum(nonFixedIndices) != length(network$genes)) geneProbabilities[!nonFixedIndices] <- 0 distr <- c(0,cumsum(geneProbabilities)) r <- runif(n=1) idx <- 0 for (i in seq_along(network$genes)) { if (r > distr[i] & r <= distr[i+1]) { idx <- i break } } idx } } else { if (is.character(chosenGene)) { chosenGeneIdx <- which(network$genes == chosenGene) if (length(chosenGeneIdx) == 0) stop(paste("Gene \"",chosenGene,"\" does not exist in the network!",sep="")) chosenGeneIdx } else chosenGene } }) res[changeIndices] <- sapply(changeIndices,function(i) { if(network$interactions[[i]]$input[1] == 0) # this is a constant gene with no transition function return(network$interactions[[i]]$func[1]) input = state[network$interactions[[i]]$input] return(network$interactions[[i]]$func[bin2dec(rev(input),length(input)) + 1]) }) } res[!nonFixedIndices] = network$fixed[!nonFixedIndices] } names(res) <- network$genes return(res) } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/plotStateGraph.R��������������������������������������������������������������������������0000644�0001762�0000144�00000021263�13277247537�015126� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Plots a graph that visualizes the state transitions and attractor basins. <attractorInfo> is an object # of class AttractorInfo. This requires the igraph package. # If <highlightAttractors> is set, attractor edges are drawn bold. # If <colorBasins> is true, each basin is drawn in a different color. # Colors can be provided in <colorSet>. # <layout> specifies the graph layouting function. # If <piecewise> is true, subgraphs are layouted separately. # <basin.lty> and <attractor.lty> specify the line types used to draw states in the basins # and in the attractors (if <highlightAttractor> is set). # If <plotIt> is not set, only the igraph object is returned, but no graph is plotted. # ... provides further graphical parameters for the plot. # Returns an object of class igraph plotStateGraph <- function(stateGraph, highlightAttractors = TRUE, colorBasins = TRUE, colorSet, drawLegend = TRUE, drawLabels = FALSE, layout = layout.kamada.kawai, piecewise = FALSE, basin.lty = 2, attractor.lty = 1, plotIt = TRUE, colorsAlpha = c(colorBasinsNodeAlpha = .3, colorBasinsEdgeAlpha = .3, colorAttractorNodeAlpha = 1, colorAttractorEdgeAlpha = 1), ...) { stopifnot(inherits(stateGraph,"AttractorInfo") || inherits(stateGraph,"TransitionTable") || inherits(stateGraph,"SymbolicSimulation")) args <- list(...) if (!is.null(args$attractorInfo)) { warning("The parameter \"attractorInfo\" is deprecated. Use \"stateGraph\" instead!") stateGraph <- args$attractorInfo } if(is.null(colorsAlpha) | (length(colorsAlpha) != 4)) { warning("colorsAlpha parameter not properly specified. Parameter will be set to opaque values (1,1,1,1).") colorsAlpha <- c(1,1,1,1) } if (any(colorsAlpha < 0 | colorsAlpha > 1)) { warning("colorsAlpha parameters are not in range [0,1] - they will be normalized.") colorsAlpha <- colorsAlpha/sum(colorsAlpha) } if (installed.packages()["igraph","Version"] < package_version("0.6")) bias <- 1 else bias <- 0 symbolic <- FALSE if (inherits(stateGraph,"AttractorInfo")) { stateGraph <- getTransitionTable(stateGraph) } else if (inherits(stateGraph,"SymbolicSimulation")) { symbolic <- TRUE if (is.null(stateGraph$graph)) stop(paste("This SymbolicSimulation structure does not contain transition table information.", "Please re-run simulateSymbolicModel() with returnGraph=TRUE!")) stateGraph <- stateGraph$graph } geneCols <- setdiff(colnames(stateGraph), c("attractorAssignment","transitionsToAttractor")) numGenes <- (length(geneCols)) / 2 from <- apply(stateGraph[ , 1:numGenes, drop=FALSE], 1, paste, collapse="") to <- apply(stateGraph[ , ((numGenes+1):(2*numGenes)), drop=FALSE], 1, paste, collapse="") vertices <- unique(c(from, to)) edges <- data.frame(from, to) res <- graph.data.frame(edges, vertices = as.data.frame(vertices), directed=TRUE) res <- set.vertex.attribute(res, "name", value = vertices) if ("attractorAssignment" %in% colnames(stateGraph)) attractorAssignment <- stateGraph$attractorAssignment else { attractorAssignment <- c() colorBasins <- FALSE drawLegend <- FALSE } if ("transitionsToAttractor" %in% colnames(stateGraph)) attractorIndices <- to[stateGraph$transitionsToAttractor == 0] else { if (highlightAttractors) { warning("The parameter \"highlightAttractors\" is set to true although not enough information is available in stateGraph. Highlightning of attractors will be set to FALSE.") } attractorIndices <- c() highlightAttractors <- FALSE } # determine nodes and edges that belong to attractors # set default edge width and line type res <- set.edge.attribute(res, "width" , value = 0.8) res <- set.edge.attribute(res, "lty", value = basin.lty) if (highlightAttractors) { attractorEdgeIndices <- which(apply(edges, 1 , function(edge){ return( (edge[1] %in% attractorIndices) & (edge[2] %in% attractorIndices) ) })) - bias # set different edge width and line type for attractor edges res <- set.edge.attribute(res, "width", index = attractorEdgeIndices, value = 2) res <- set.edge.attribute(res, "lty", index = attractorEdgeIndices, value = attractor.lty) } if (missing(colorSet)) { # define default colors colorSet <- c("blue","green","red","darkgoldenrod","gold","brown","cyan", "purple","orange","seagreen","tomato","darkgray","chocolate", "maroon","darkgreen","gray12","blue4","cadetblue","darkgoldenrod4", "burlywood2") } # check for certain graphical parameters in ... # that have different default values in this plot if (is.null(args$vertex.size)) args$vertex.size <- 2 if (is.null(args$edge.arrow.mode)) args$edge.arrow.mode <- 2 if (is.null(args$edge.arrow.size)) args$edge.arrow.size <- 0.3 if (is.null(args$vertex.label.cex)) args$vertex.label.cex <- 0.5 if (is.null(args$vertex.label.dist)) args$vertex.label.dist <- 1 attractors <- unique(attractorAssignment) attractors <- attractors[!is.na(attractors)] if (colorBasins) { res <- set.edge.attribute(res, "color", value = "darkgrey") for (attractor in attractors) { # determine nodes and edges belonging to the basin of <attractor> attractorGraphIndices <- NULL basinIndices <- which(attractorAssignment == attractor) if(!is.null(stateGraph$transitionsToAttractor)) { attractorGraphIndices <- intersect(basinIndices, which(stateGraph$transitionsToAttractor == 0)) basinIndices <- base::setdiff(basinIndices, attractorGraphIndices) } if (!symbolic) { # change vertex color res <- set.vertex.attribute(res, "color", basinIndices - bias, value = adjustcolor(colorSet[(attractor-1) %% length(colorSet) + 1], alpha.f = colorsAlpha[1])) res <- set.vertex.attribute(res, "frame.color", basinIndices - bias, value = adjustcolor("black", alpha.f = colorsAlpha[1])) if(!is.null(attractorGraphIndices)) { res <- set.vertex.attribute(res, "color", attractorGraphIndices - bias, value = adjustcolor(colorSet[(attractor-1) %% length(colorSet) + 1], alpha.f = colorsAlpha[3])) res <- set.vertex.attribute(res, "frame.color", attractorGraphIndices - bias, value = adjustcolor("black", alpha.f = colorsAlpha[3])) } if (drawLabels) res <- set.vertex.attribute(res,"label.color",basinIndices - bias, value=colorSet[(attractor-1) %% length(colorSet) + 1]) } # change edge color res <- set.edge.attribute(res, "color", index = basinIndices - bias, value = adjustcolor(colorSet[(attractor-1) %% length(colorSet) + 1], alpha.f = colorsAlpha[2])) if(!is.null(attractorGraphIndices)) { res <- set.edge.attribute(res, "color", index = attractorGraphIndices - bias, value = adjustcolor(colorSet[(attractor-1) %% length(colorSet) + 1], alpha.f = colorsAlpha[4])) } } } if(plotIt) { if (drawLabels) labels <- vertices else labels <- NA if (piecewise) layout <- piecewise.layout(res, layout) if (symbolic) autocurve.edges(res) do.call("plot",c(list(res),args,"vertex.label"=list(labels), "layout"=list(layout))) #plot(res,vertex.size=args$vertex.size,layout=layout, # edge.arrow.mode=args$edge.arrow.mode, # vertex.label=labels,vertex.label.cex=args$vertex.label.cex, # vertex.label.dist=args$vertex.label.dist, # ...) if (colorBasins & drawLegend) legend(x="bottomleft",pch=15,ncol=1, col=colorSet[attractors-1 %% length(colorSet) + 1], legend = paste("Attractor",seq_along(attractors)), cex=0.5) } return(invisible(res)) } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/getAttractors.R���������������������������������������������������������������������������0000644�0001762�0000144�00000025767�14063127656�015021� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Identify attractors in a Boolean network. # <network> is a BooleanNetwork/SymbolicBooleanNetwork structure specifying the network. # <method> specifies what kind of search is conducted: "exhaustive" performs a full search over all states, # "random" generates <startStates> random initial states, and "chosen" uses the states supplied in <startStates>. # "sat.exhaustive" and "sat.restricted" start a SAT-based attractor search. # <genesON> and <genesOFF> are lists of genes to be set to ON/1 or OFF/0 respectively. # If <canonical> is true, states in the attractors are reordered such that the "smallest" state is the first # <randomChainLength> is the number of random transitions performed for the identification of an asynchronous attractor # If <avoidSelfLoops> is true, loops to the same state are eliminated from asynchronous attractors. # <geneProbabilities> optionally specifies the probabilities of choosing a gene for an asynchronous update. # <maxAttractorLength> specifies the maximum attractor length for method="sat.restricted" and the initial search length for method="sat.exhaustive". # if <returnTable> is true, the transition table is included in the result. getAttractors <- function (network, type=c("synchronous","asynchronous"), method=c("exhaustive","sat.exhaustive","sat.restricted","random","chosen"), startStates=list(), genesON = c(), genesOFF = c(), canonical=TRUE, randomChainLength = 10000, avoidSelfLoops = TRUE, geneProbabilities = NULL, maxAttractorLength=Inf, returnTable=TRUE) { stopifnot(inherits(network,"BooleanNetwork") || inherits(network,"SymbolicBooleanNetwork")) symbolic <- inherits(network,"SymbolicBooleanNetwork") nonFixedPositions <- which(network$fixed == -1) type <- match.arg(type, c("synchronous","asynchronous")) if (type == "asynchronous") { if (symbolic) stop("Only synchronous updates are allowed for symbolic networks!") if (length(method) == 1 & match.arg(method) == "exhaustive") stop("Asynchronous attractor search cannot be performed in exhaustive search mode!") if (length(geneProbabilities) > 0 ) { if (length(geneProbabilities) != length(network$genes)) stop("Please supply exactly one probability for each gene!") if (abs(1.0 - sum(geneProbabilities)) > 0.0001) stop("The supplied gene probabilities do not sum up to 1!") } } if (!is.null(maxAttractorLength) && is.infinite(maxAttractorLength)) maxAttractorLength <- NULL if (length(method) > 1) # if no method is supplied, infer method from the type of <startStates> { if (type == "asynchronous" & length(startStates) == 0) { startStates <- max(round(2 ^ sum(network$fixed == -1) / 20), 5) method = "random" } else if (is.numeric(startStates)) { if (length(startStates) > 1) stop("Please supply either the number of start states or a list of start states in startStates!") else method <- "random" } else if (is.list(startStates) & (length(startStates) > 0)) method <- "chosen" else if (!is.null(maxAttractorLength)) method <- "sat.restricted" else method <- "exhaustive" } # fix genes according to genesON and genesOFF if (length(genesON) > 0) { network <- fixGenes(network,genesON,1) } if (length(genesOFF) > 0) { network <- fixGenes(network,genesOFF,0) } if (symbolic) { return(simulateSymbolicModel(network, method=method, startStates=startStates, maxAttractorLength=maxAttractorLength, returnGraph=returnTable && !(match.arg(method) %in% c("sat.exhaustive", "sat.restricted")), returnSequences=FALSE, returnAttractors=TRUE, canonical=canonical)) } else { method <- match.arg(method,c("exhaustive","sat.exhaustive","sat.restricted","random","chosen")) if (method == "sat.restricted" && is.null(maxAttractorLength)) stop("maxAttractorLength must be set for method=\"sat.restricted\"!") if ((length(network$genes) > 29) && (method == "exhaustive") && (type == "synchronous")) { method <- "sat.exhaustive" warning("An exhaustive state space search is restricted to networks with at most 29 genes. Switching to the SAT-based exhaustive search, which supports more genes, but does not return a transition table!") } else if (method %in% c("sat.exhaustive", "sat.restricted") && type != "synchronous") stop("SAT-based search can only be used for synchronous networks!") startStates <- switch(method, exhaustive = list(), sat.exhaustive = list(), sat.restricted = list(), random = { if (!is.numeric(startStates)) stop("Please supply the number of random states in startStates!") if (startStates > (2 ^ length(nonFixedPositions))) # more start states than in the full network { if (type == "synchronous") { list() warning(paste("The number of random states is set larger than the total", "number of states. Performing an exhaustive search!")) } else { warning(paste("The number of random states is set larger than the total ", "number of states! The maximum number of different states is ",2 ^ length(nonFixedPositions)),"!",sep="") startStates = 2 ^ length(nonFixedPositions) } } # generate random matrix generateRandomStartStates(network, startStates) }, chosen = { if (!is.list(startStates) | length(startStates) == 0) stop("No start states supplied!") if (!all(sapply(startStates,function(x)(length(x) == length(network$genes))))) stop(paste("Please provide binary vectors with",length(network$genes), "elements in startStates!")) fixedGenes <- which(network$fixed != -1) statesValid <- sapply(startStates,function(state) { isTRUE(all(state[fixedGenes] == network$fixed[fixedGenes])) }) startStates <- startStates[statesValid] if (!any(statesValid)) stop("None of the supplied start states matched the restrictions of the fixed genes!") if (!all(statesValid)) warning("Some of the supplied start states did not match the restrictions of the fixed genes and were removed!") startStates } ) if (!is.null(maxAttractorLength)) { if (!(method %in% c("sat.exhaustive", "sat.restricted"))) stop("maxAttractorLength can only be used with method=\"sat.exhaustive\" or method=\"sat-res.ricted\"!") maxAttractorLength <- as.integer(maxAttractorLength) } specialInitialization <- NULL convertedStartStates <- NULL if (length(startStates) > 0) convertedStartStates <- sapply(startStates,function(x)bin2dec(x,length(network$genes))) # the C code requires all interactions to be coded into one vector: # Assemble all input gene lists in one list <inputGenes>, and remember the split positions in <inputGenePositions>. inputGenes <- as.integer(unlist(lapply(network$interactions,function(interaction)interaction$input))) inputGenePositions <- as.integer(cumsum(c(0,sapply(network$interactions, function(interaction)length(interaction$input))))) # Do the same for the transition functions. transitionFunctions <- as.integer(unlist(lapply(network$interactions,function(interaction)interaction$func))) transitionFunctionPositions <- as.integer(cumsum(c(0,sapply(network$interactions, function(interaction)length(interaction$func))))) searchType <- switch(type, synchronous = if (method == "sat.exhaustive") 2 else if (method == "sat.restricted") 3 else 0, asynchronous = 1) on.exit(.C("freeAllMemory", PACKAGE = "BoolNet")) # Call the C code result <- .Call("getAttractors_R",inputGenes,inputGenePositions, transitionFunctions,transitionFunctionPositions, as.integer(network$fixed), as.integer(convertedStartStates), as.integer(searchType), as.double(geneProbabilities), as.integer(randomChainLength), as.integer(avoidSelfLoops), as.integer(returnTable), maxAttractorLength, PACKAGE="BoolNet") if (is.null(result)) stop("An error occurred in external C code!") if (length(result$attractors) == 0) stop("getAttractors() was not able to identify any attractors! Please check the supplied parameters and restart!") if (length(network$genes) %% 32 == 0) numElementsPerEntry <- as.integer(length(network$genes) / 32) else numElementsPerEntry <- as.integer(length(network$genes) / 32 + 1) if (!is.null(result$stateInfo)) { result$stateInfo$table <- matrix(result$stateInfo$table,nrow=numElementsPerEntry) if (!is.null(result$stateInfo$initialStates)) result$stateInfo$initialStates <- matrix(result$stateInfo$initialStates,nrow=numElementsPerEntry) } for (i in seq_len(length(result$attractors))) { result$attractors[[i]]$involvedStates <- matrix(result$attractors[[i]]$involvedStates,nrow=numElementsPerEntry) if (canonical) # reorder states result$attractors[[i]]$involvedStates <- canonicalStateOrder(result$attractors[[i]]$involvedStates) if (!is.null(result$attractors[[i]]$initialStates)) result$attractors[[i]]$initialStates <- matrix(result$attractors[[i]]$initialStates,nrow=numElementsPerEntry) if (!is.null(result$attractors[[i]]$nextStates)) result$attractors[[i]]$nextStates <- matrix(result$attractors[[i]]$nextStates,nrow=numElementsPerEntry) if (result$attractors[[i]]$basinSize == 0) result$attractors[[i]]$basinSize <- NA } # order attractors according to their lengths attractorLengths <- sapply(result$attractors,function(attractor)ncol(attractor$involvedStates)) reordering <- order(attractorLengths) result$attractors <- result$attractors[reordering] if (!is.null(result$stateInfo)) { inverseOrder <- sapply(seq_along(reordering),function(x)which(reordering == x)) result$stateInfo$attractorAssignment <- inverseOrder[result$stateInfo$attractorAssignment] } # extend the resulting structure by additional information, and assign a class result$stateInfo$genes <- network$genes result$stateInfo$fixedGenes <- network$fixed if (!is.null(result$stateInfo$table)) class(result$stateInfo) <- "BooleanStateInfo" class(result) <- "AttractorInfo" return(result) } } ���������BoolNet/R/print.AttractorInfo.R���������������������������������������������������������������������0000644�0001762�0000144�00000004476�13277247010�016070� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Custom print function for class AttractorInfo print.AttractorInfo <- function(x, activeOnly = FALSE, ...) { numGenes <- length(x$stateInfo$genes) attractors <- x$attractors for (i in seq_along(attractors)) { if (is.null(attractors[[i]]$initialStates)) # simple attractor { printSynchronousAttractor(getAttractorSequence(x, i), i, attractors[[i]]$basinSize, activeOnly=activeOnly) } else { # print general information on the attractor cat("Attractor ",i," is a complex/loose attractor consisting of ",ncol(attractors[[i]]$involvedStates), " state(s) and ",ncol(attractors[[i]]$initialStates), " transition(s)",sep="") if (activeOnly) { cat(".\nActive genes in the state transitions: \n") initialStates <- t(apply(attractors[[i]]$initialStates,2,function(state) dec2bin(state,numGenes))) nextStates <- t(apply(attractors[[i]]$nextStates,2,function(state) dec2bin(state,numGenes))) binMatrix <- data.frame(initialStates,nextStates) apply(binMatrix,1,function(row) { state1 <- paste(x$stateInfo$genes[which(row[seq_len(numGenes)] == 1)],collapse=", ") if (state1 == "") state1 <- "--" state2 <- paste(x$stateInfo$genes[which(row[seq_len(numGenes) + numGenes] == 1)],collapse=", ") if (state2 == "") state2 <- "--" cat(state1," => ",state2,"\n",sep="") }) } else { cat(":\n\n") initialStates <- apply(attractors[[i]]$initialStates,2,function(state) paste(dec2bin(state,numGenes),collapse="")) nextStates <- apply(attractors[[i]]$nextStates,2,function(state) paste(dec2bin(state,numGenes),collapse="")) binMatrix <- data.frame(initialStates,nextStates) apply(binMatrix,1,function(row) { cat(row[1]," => ",row[2],"\n",sep="") }) cat("\nGenes are encoded in the following order: ",paste(x$stateInfo$genes,collapse=" "),"\n\n",sep="") } } } return(invisible(x)) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/print.SymbolicSimulation.R����������������������������������������������������������������0000644�0001762�0000144�00000003747�13277247010�017137� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Custom print function for class AttractorInfo print.SymbolicSimulation <- function(x, activeOnly = FALSE, sequences=FALSE, graph=FALSE, attractors=TRUE, ...) { cat("Simulation of a symbolic Boolean network\n") if (!is.null(x$sequences)) { if (sequences) { cat(sprintf("Sequences for %d start states:\n", length(x$sequences))) if (!activeOnly) print(x$sequences) else for (i in seq_along(x$sequences)) { cat("[[",i,"]]\n",sep="") seq <- x$sequences[[i]] cat(paste(apply(seq,1,function(r) { if (any(r == 1)) paste(colnames(seq)[which(r == 1)],collapse=", ") else "--" }), collapse="\n")) cat("\n\n") } } else cat(sprintf("Sequences for %d start states (print with sequences=TRUE to show them)\n", length(x$sequences))) cat("\n") } if (!is.null(x$graph)) { if (graph) { cat(sprintf("Graph containing %d state transitions:\n", nrow(x$graph))) print(x$graph, activeOnly=activeOnly, ...) } else cat(sprintf("Graph containing %d state transitions (print with graph=TRUE to show them)\n", nrow(x$graph))) cat("\n") } if (!is.null(x$attractors)) { if (attractors) { cat(sprintf("%d Attractors:\n", length(x$attractors))) for (i in seq_along(x$attractors)) { if (is.null(x$graph)) printSynchronousAttractor(x$attractors[[i]], i, activeOnly=activeOnly) else printSynchronousAttractor(x$attractors[[i]], i, sum(x$graph$attractorAssignment == i), activeOnly=activeOnly) } } else cat(sprintf("%d Attractors (print with attractors=TRUE to show them)\n", length(x$attractors))) } return(invisible(x)) } �������������������������BoolNet/R/perturbNetwork.R��������������������������������������������������������������������������0000644�0001762�0000144�00000022372�13277247010�015206� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Randomly perturb a supplied network. # <perturb="functions"> perturbs the functions associated with the genes directly. # <perturb="states"> perturbs a maximum of <numStates> states # in the transition table resulting from the functions. # <method="bitflip"> randomly flips up to <maxNumBits> in the functions or states. # <method="shuffle"> randomly permutes the bits in the functions or states. # If <simplify> is set, the perturbed network is simplified to remove irrelevant input functions. # If <excludeFixed> is set, fixed genes are excluded from the perturbations and stay as they are. perturbNetwork <- function(network,perturb=c("functions","transitions"),method=c("bitflip","shuffle"), simplify=(perturb[1]!="functions"),readableFunctions=FALSE,excludeFixed=TRUE, maxNumBits=1,numStates=max(1,2^length(network$genes)/100)) { stopifnot(inherits(network,"BooleanNetwork") | inherits(network,"ProbabilisticBooleanNetwork")) fixedGenes <- which(network$fixed != -1) if (length(perturb) == 1 && perturb == "states") { warning("perturb=\"states\" is deprecated. Use perturb=\"transitions\" instead!") perturb <- "transitions" } if (inherits(network,"BooleanNetwork")) # deterministic network { switch(match.arg(perturb,c("functions","transitions")), functions= switch(match.arg(method,c("bitflip","shuffle")), bitflip = { # choose the function to be perturbed if (length(fixedGenes) > 0 & excludeFixed) functionIdx <- sample((seq_along(network$interactions))[-fixedGenes],size=1) else functionIdx <- sample(seq_along(network$interactions),size=1) # choose the indices of the truth table to be flipped flipIndices <- sample(seq_along(network$interactions[[functionIdx]]$func), size=runif(n=1,min=1, max=min(maxNumBits, length(network$interactions[[functionIdx]]$func))), replace=FALSE) # flip the bits network$interactions[[functionIdx]]$func[flipIndices] <- as.integer(!network$interactions[[functionIdx]]$func[flipIndices]) network$interactions[[functionIdx]]$expression <- getInteractionString(readableFunctions, network$interactions[[functionIdx]]$func, network$genes[network$interactions[[functionIdx]]$input]) }, shuffle= { # choose the function to be perturbed if (length(fixedGenes) > 0 & excludeFixed) functionIdx <- sample((seq_along(network$interactions))[-fixedGenes],size=1) else functionIdx <- sample(seq_along(network$interactions),size=1) # draw a random permutation of bit positions flipIndices <- sample(seq_along(network$interactions[[functionIdx]]$func), size=length(network$interactions[[functionIdx]]$func), replace=FALSE) # permute the bits network$interactions[[functionIdx]]$func <- network$interactions[[functionIdx]]$func[flipIndices] network$interactions[[functionIdx]]$expression <- getInteractionString(readableFunctions, network$interactions[[functionIdx]]$func, network$genes[network$interactions[[functionIdx]]$input]) }, stop("'method' must be one of \"bitflip\",\"shuffle\"")), transitions = { # turn off gene fixing - otherwise reverse-engineering of the transition table is not possible oldFixed <- network$fixed network$fixed <- rep(-1,length(network$genes)) names(network$fixed) <- network$genes # calculate transition table table <- t(sapply(getAttractors(network)$stateInfo$table,dec2bin,length(network$genes))) # determine the states to be perturbed statesToChange <- sample(seq_len(nrow(table)),min(numStates,nrow(table)),replace=FALSE) lapply(statesToChange,function(state) { # choose the indices of the states that are allowed to be changed flipIndices <- seq_along(network$genes) if (length(fixedGenes) > 0 & excludeFixed) flipIndices <- flipIndices[-fixedGenes] switch(match.arg(method,c("bitflip","shuffle")), bitflip = { # choose the actual indices to be changed flipIndex <- sample(flipIndices, size=runif(n=1,min=1, max=min(maxNumBits, length(flipIndices))), replace=FALSE) # flip the bits at these positions table[state,flipIndex] <<- as.integer(!table[state,flipIndex]) }, shuffle = { # determine a permutation of the bit indices flipIndex <- sample(flipIndices, size=length(flipIndices), replace=FALSE) # permute the state table[state,] <<- as.integer(table[state,flipIndex]) }, stop("'method' must be one of \"bitflip\",\"shuffle\"") ) NULL}) # restore network by assigning the columns of the state table to the corresponding genes network$interactions <- apply(table,2,function(gene) { input = seq_along(network$genes) # encoding is reversed in the transition table input <- input[length(input):1] list(input=input, func=gene, expression= getInteractionString(readableFunctions, gene, network$genes[input])) }) # reactivate fixed genes network$fixed <- oldFixed }, stop("'perturb' must be one of \"functions\",\"transitions\"")) } else # probabilistic network { if (match.arg(perturb) != "functions") stop("In probabilistic Boolean networks, only perturb=functions is allowed!") switch(match.arg(method,c("bitflip","shuffle")), bitflip = { # choose the gene and the function to be perturbed if (length(fixedGenes) > 0 & excludeFixed) geneIdx <- sample((seq_along(network$interactions))[-fixedGenes],size=1) else geneIdx <- sample(seq_along(network$interactions),size=1) functionIdx <- sample(seq_along(network$interactions[[geneIdx]]),size=1) # choose the indices of the truth table to be flipped flipIndices <- sample(seq_along(network$interactions[[geneIdx]][[functionIdx]]$func), size=runif(n=1,min=1, max=min(maxNumBits, length(network$interactions[[geneIdx]][[functionIdx]]$func))), replace=FALSE) # flip the bits network$interactions[[geneIdx]][[functionIdx]]$func[flipIndices] <- as.integer(!network$interactions[[geneIdx]][[functionIdx]]$func[flipIndices]) network$interactions[[geneIdx]][[functionIdx]]$expression <- getInteractionString(readableFunctions, network$interactions[[geneIdx]][[functionIdx]]$func, network$genes[network$interactions[[geneIdx]][[functionIdx]]$input]) }, shuffle= { # choose the function to be perturbed if (length(fixedGenes) > 0 & excludeFixed) geneIdx <- sample((seq_along(network$interactions))[-fixedGenes],size=1) else geneIdx <- sample(seq_along(network$interactions),size=1) functionIdx <- sample(seq_along(network$interactions[[geneIdx]]),size=1) # draw a random permutation of bit positions flipIndices <- sample(seq_along(network$interactions[[geneIdx]][[functionIdx]]$func), size=length(network$interactions[[geneIdx]][[functionIdx]]$func), replace=FALSE) # permute the bits network$interactions[[geneIdx]][[functionIdx]]$func <- network$interactions[[geneIdx]][[functionIdx]]$func[flipIndices] network$interactions[[geneIdx]][[functionIdx]]$expression <- getInteractionString(readableFunctions, network$interactions[[geneIdx]][[functionIdx]]$func, network$genes[network$interactions[[geneIdx]][[functionIdx]]$input]) }, stop("'method' must be one of \"bitflip\",\"shuffle\"")) } # simplify the network if necessary if (simplify) network <- simplifyNetwork(network,readableFunctions) return(network) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/plotNetworkWiring.R�����������������������������������������������������������������������0000644�0001762�0000144�00000005250�13277247010�015655� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Plot a wiring graph of the network <network> with the supplied # graphical parameters. # Requires igraph. # Returns the igraph structure representing the wiring graph. plotNetworkWiring <- function(network,layout=layout.fruchterman.reingold,plotIt=TRUE,...) { stopifnot(inherits(network,"ProbabilisticBooleanNetwork") | inherits(network,"BooleanNetworkCollection") | inherits(network,"BooleanNetwork") | inherits(network,"SymbolicBooleanNetwork")) if (installed.packages()["igraph","Version"] < package_version("0.6")) bias <- 1 else bias <- 0 edgeList <- c() # construct list of edges from interactions if (inherits(network,"BooleanNetwork")) # deterministic network { for (i in seq_along(network$genes)) { if (network$interactions[[i]]$input[1] != 0) # no edges for constant genes { edgeList <- rbind(edgeList, cbind(network$interactions[[i]]$input, rep(i,length(network$interactions[[i]]$input)))) } } } else if (inherits(network,"SymbolicBooleanNetwork")) # symbolic network { inputs <- lapply(network$interactions, getInputs, index=TRUE) for (i in seq_along(network$genes)) { edgeList <- rbind(edgeList, cbind(inputs[[i]], rep(i,length(inputs[[i]])))) } } else # probabilistic network { for (i in seq_along(network$genes)) { for (j in seq_along(network$interactions[[i]])) { if (network$interactions[[i]][[j]]$input[1] != 0) # no edges for constant genes { edgeList <- rbind(edgeList, cbind(network$interactions[[i]][[j]]$input, rep(i,length(network$interactions[[i]][[j]]$input)))) } } } } # build graph from edge list res <- graph.data.frame(edgeList-bias,directed=TRUE,vertices=as.data.frame((seq_along(network$genes)) - bias)) res <- set.vertex.attribute(res,"name",value=network$genes) args <- list(...) # check for certain graphical parameters in ... # that have different default values in this plot if (is.null(args$vertex.color)) args$vertex.color <- "grey" if (is.null(args$edge.arrow.size)) args$edge.arrow.size <- 0.5 if (is.null(args$vertex.label.cex)) args$vertex.label.cex <- 0.7 if (is.null(args$vertex.size)) args$vertex.size <- 18 if (plotIt) { plot(res,vertex.label=network$genes,vertex.label.cex=args$vertex.label.cex, vertex.size=args$vertex.size,vertex.color=args$vertex.color, edge.arrow.size=args$edge.arrow.size, layout=layout,...) } return(invisible(res)) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/getAttractorSequence.R��������������������������������������������������������������������0000644�0001762�0000144�00000002632�13277247010�016302� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ getAttractorSequence <- function(attractorInfo, attractorNo) { stopifnot(inherits(attractorInfo,"AttractorInfo") || inherits(attractorInfo,"SymbolicSimulation")) if (inherits(attractorInfo,"SymbolicSimulation")) { if (is.null(attractorInfo$attractors)) stop(paste("This SymbolicSimulation structure does not contain attractor information.", "Please re-run simulateSymbolicModel() with returnAttractors=TRUE!")) if (missing(attractorNo) || attractorNo <= 0 || attractorNo > length(attractorInfo$attractors)) stop("Please provide a valid attractor number!") return(attractorInfo$attractors[[attractorNo]]) } else { if (missing(attractorNo) || attractorNo <= 0 || attractorNo > length(attractorInfo$attractors)) stop("Please provide a valid attractor number!") if (!is.null(attractorInfo$attractors[[attractorNo]]$initialStates)) stop("A sequence can be obtained for synchronous attractors only!") numGenes <- length(attractorInfo$stateInfo$genes) # decode binary representation of states involved in the attractors binMatrix <- t(matrix(apply(attractorInfo$attractors[[attractorNo]]$involvedStates,2,function(state) dec2bin(state,numGenes)),nrow=numGenes)) colnames(binMatrix) <- attractorInfo$stateInfo$genes return(as.data.frame(binMatrix)) } } ������������������������������������������������������������������������������������������������������BoolNet/R/generateTimeSeries.R����������������������������������������������������������������������0000644�0001762�0000144�00000005546�13277247010�015741� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ # Generate time series from a Boolean network <network>. # <numSeries> is the number of start states for which time series are generated. # <numMeasurements> is the number of time points for each time series. # <type> is the type of transitions used (synchronous or asynchronous) # If <type> is "asynchronous", <geneProbabilities> describes the # transition probabilities for the genes. # If <noiseLevel> is not 0, Gaussian noise is added to the result. generateTimeSeries <- function(network, numSeries, numMeasurements, type = c("synchronous","asynchronous","probabilistic"), geneProbabilities, perturbations=0, noiseLevel = 0.0) { symbolic <- inherits(network, "SymbolicBooleanNetwork") if (missing(geneProbabilities)) geneProbabilities <- NULL if (perturbations > 0) { perturbationMatrix <- sapply(1:numSeries, function(x) { p <- rep(NA, length(network$genes)) p[sample(1:length(network$genes),size=perturbations)] <- sample(c(0,1),size=perturbations,replace=TRUE) return(p) }) rownames(perturbationMatrix) <- network$genes } ts <- lapply(seq_len(numSeries), function(i) { if (symbolic) { if (perturbations > 0) { fixedIdx <- which(perturbationMatrix[,i] != -1) network <- fixGenes(network, fixedIdx, perturbationMatrix[fixedIdx,i]) } res <- t(simulateSymbolicModel(network, startStates=1, returnAttractors=FALSE, returnGraph=TRUE, returnSequences=TRUE)$sequences[[1]]) } else { startState <- round(runif(length(network$genes))) if (perturbations > 0) { fixedIdx <- which(perturbationMatrix[,i] != -1) network <- fixGenes(network, fixedIdx, perturbationMatrix[fixedIdx,i]) startState[fixedIdx] <- perturbationMatrix[fixedIdx,i] } res <- startState for (j in 2:numMeasurements) { startState <- stateTransition(network, startState, type=type, geneProbabilities=geneProbabilities) res <- cbind(res,startState) } } colnames(res) <- NULL if (noiseLevel != 0) { res <- res + matrix(rnorm(mean=0, sd=noiseLevel, n = length(res)), nrow=nrow(res)) } rownames(res) <- network$genes colnames(res) <- seq_len(ncol(res)) return(res) }) if (perturbations > 0) ts$perturbations <- perturbationMatrix return(ts) } ����������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/truthTableToSymbolic.R��������������������������������������������������������������������0000644�0001762�0000144�00000002541�13277247010�016270� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ # Convert a BooleanNetwork object # <network> to a SymbolicBooleanNetwork object truthTableToSymbolic <- function(network, generateDNFs=FALSE) { stopifnot(inherits(network, "BooleanNetwork")) res <- list(genes = network$genes, fixed = as.integer(network$fixed), interactions = lapply(network$interactions, function(int) { func <- tryCatch( { if (generateDNFs != FALSE) parseBooleanFunction(getDNF(int$func, network$genes[int$input], mode=generateDNFs), network$genes) else parseBooleanFunction(int$expression, network$genes) }, error = function(e) { parseBooleanFunction(getDNF(int$func, network$genes[int$input], mode=generateDNFs), network$genes) }) return(func) })) names(res$fixed) <- res$genes res$internalStructs <- .Call("constructNetworkTrees_R",res) res$timeDelays <- apply(sapply(res$interactions,maxTimeDelay,genes=res$genes),1,max) class(res) <- "SymbolicBooleanNetwork" return(res) } ���������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/R/saveNetwork.R�����������������������������������������������������������������������������0000644�0001762�0000144�00000011235�13277247010�014455� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ # Save <network> to <file> in the BoolNet file format. # If <generateDNFs> is true or a mode of getDNF(), # a new symbolic representation for the interactions # is generated on the basis of the truth tables (in disjunctive normal form). # If <generateDNFs> is false, the $expression elements of the interactions are exported. # If <saveFixed> is true, constant transition functions are exported for fixed genes # instead of their true transition functions saveNetwork <- function(network, file, generateDNFs = FALSE, saveFixed = TRUE) { stopifnot(inherits(network,"BooleanNetwork") || inherits(network,"SymbolicBooleanNetwork") || inherits(network,"ProbabilisticBooleanNetwork")) expressions <- NULL if (inherits(network,"BooleanNetwork")) { if (generateDNFs == FALSE) # Check whether all interactions have suitable string representations { tryCatch( { # parse the string representations lapply(network$interactions, function(int)parseBooleanFunction(int$expression)) }, error=function(e) { warning(paste("The transition functions of this network did not contain valid symbolic expressions!", "Generating DNF representations from the truth tables!")) # There was an error parsing a string representation => generate DNFs generateDNFs <<- TRUE }) } if (generateDNFs != FALSE) { expressions <- mapply(function(interaction, gene, fixed) { if (!saveFixed || fixed == -1) { table <- allcombn(2, length(interaction$input)) - 1 expression <- getDNF(interaction$func, network$genes[interaction$input], generateDNFs) return(paste(gene, ", ", expression, sep="")) } else return(paste(gene, ", ", fixed, sep="")) }, network$interactions, network$genes, network$fixed) } else { expressions <- mapply(function(interaction, gene, fixed) { if (!saveFixed || fixed == -1) return(paste(gene, ", ", interaction$expression, sep="")) else return(paste(gene, ", ", fixed, sep="")) }, network$interactions, network$genes, network$fixed) } sink(file) cat("targets, factors\n") } else if (inherits(network,"SymbolicBooleanNetwork")) { expressions <- mapply(function(interaction, gene, fixed) { if (!saveFixed || fixed == -1) return(paste(gene, ", ", stringFromParseTree(interaction), sep="")) else return(paste(gene, ", ", fixed, sep="")) }, network$interactions, network$genes, network$fixed) sink(file) cat("targets, factors\n") } else { if (generateDNFs == FALSE) # Check whether all interactions have suitable string representations { tryCatch( { # parse the string representations lapply(network$interactions, function(int)lapply(int, function(func)parseBooleanFunction(func$expression))) }, error=function(e) { warning(paste("The transition functions of this network did not contain valid symbolic expressions!", "Generating DNF representations from the truth tables!")) # There was an error parsing a string representation => generate DNFs generateDNFs <<- TRUE }) } if (generateDNFs != FALSE) { expressions <- mapply(function(interaction, gene, fixed) { if (!saveFixed || fixed == -1) { lapply(interaction, function(func) { table <- allcombn(2, length(func$input)) - 1 expression <- getDNF(func$func, network$genes[func$input], generateDNFs) return(paste(gene, ", ", expression, ", ", func$probability, sep="")) }) } else return(paste(gene, ", ", fixed, ", 1", sep="")) }, network$interactions, network$genes, network$fixed) } else { expressions <- mapply(function(interaction, gene, fixed) { if (!saveFixed || fixed == -1) { lapply(interaction, function(func) { return(paste(gene, ", ", func$expression, ", ", func$probability, sep="")) }) } else return(paste(gene, ", ", fixed, ", 1", sep="")) }, network$interactions, network$genes, network$fixed) } expressions <- unlist(expressions) sink(file) cat("targets, factors, probabilities\n") } cat(paste(expressions, collapse="\n"),"\n",sep="") sink() } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/MD5�����������������������������������������������������������������������������������������0000644�0001762�0000144�00000021450�14506551754�012142� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������4b70769bfd8edc1a783f323350f07d02 *DESCRIPTION 9784bbd31ff5e76e9a8013fb1718d14d *NAMESPACE 57679970d38c17ac9c95478b9313aed0 *R/attractorsToLaTeX.R 0e037f01fa88a832cb43d3a9d5e9f5dd *R/binarizeTimeSeries.R 7b9f3b1500dd64c40cd4e9e2baa369ad *R/chooseNetwork.R 7c81eb3530ee3fede7742d9729de77c1 *R/edgeDetector.R c7fb28f26b946db5f54730be6d492516 *R/fixGenes.R b96b8b67effb0c2d55a29cc6f19323bd *R/generateRandomNKNetwork.R 9597332899ac07b3145917fafc789d15 *R/generateRandomStartStates.R 2c872695c4fa33c90c6de2431f19e689 *R/generateState.R 5650d6d8b6da147a254e9681a291a90b *R/generateTimeSeries.R 4db8f585d2e3477db95a8db2720a2e4c *R/getAttractorSequence.R 140740c1ba1d08eea3e27e9da3637f48 *R/getAttractors.R 08764b48eccb7812f9c333c122d1e689 *R/getBasinOfAttraction.R cc663c2b39dc50cd45bbb83d7cd36d44 *R/getPathToAttractor.R 9637fc5badfec905a1d865d5e65d3839 *R/getStateSummary.R a45f67785e1846f8482c9ff10debd95c *R/getTransitionProbabilities.R d31c9950c1a42c23eb5585c23e98bb25 *R/getTransitionTable.R 553c3f023784f01d73c69c469d14ea53 *R/helpers.R 8e0fdeac893b8bfc8837c9d94e9ed1f9 *R/loadBioTapestry.R f1e4da50ef5dd5ea083b8fcd060b3f77 *R/loadNetwork.R aa19fa3aaa70362a5d5d18bb114c245c *R/loadSBML.R 817f7c8476aa6b32443be62885e3c72d *R/markovSimulation.R d3dc1ab8d227e4775adfaee9973732e9 *R/parseBooleanFunction.R 75a4ff7284740122216a79cd7f9508e1 *R/perturbNetwork.R 6e8d3d79095844cf1fb6cb7c75750cfe *R/perturbTrajectories.R b3c6b0765a241bb1d4e4a150f47d3d8b *R/plotAttractors.R 20fd67145509cae5e9701fcfa93e210c *R/plotNetworkWiring.R 9f64811ec997a7aa2fc262725ae6f7e5 *R/plotPBNTransitions.R 6404119c6511b8c5741721d6cd237276 *R/plotSequence.R 3e92ac93c5ce1934d542b3eb7985aa44 *R/plotStateGraph.R 1d3e5b86636a5b54035d7062285e34e4 *R/print.AttractorInfo.R bd5b5182c9a4321e0051be7f40bcbf6f *R/print.BooleanNetwork.R 09ac08c8cb2ef098c96a86de93e5ad7c *R/print.BooleanStateInfo.R b4ce1c3d7c29f9b9d92a5428ace77b0a *R/print.MarkovSimulation.R 55d7e998f889cf528bef3d68edb38562 *R/print.ProbabilisticBooleanNetwork.R 2a6921108f7704c4949bcd96b82a2cb0 *R/print.SymbolicBooleanNetwork.R 1138169d9ef31f04670bbc2544524e4c *R/print.SymbolicSimulation.R 0adfd6c034e0bf75c16d351c4f2e52f6 *R/print.TransitionTable.R 78216cfe9045ded3a90b43edb6e0d21f *R/reconstructNetwork.R 00623749adde58c327566c72a67d4027 *R/saveNetwork.R 8db261cf9b75f737bc6ca7f49c67dbd0 *R/scanStatistic.R a9cfa06573f8eeb0aefa2329c59689aa *R/sequenceToLaTeX.R 5877e9963cac94f7dc2b245079826450 *R/simplifyNetwork.R c8a4ab49f15e1e8888d4bd132e1d9271 *R/simulateSymbolicModel.R 595c68d880e16c31046313f648cc34c6 *R/stateTransition.R ea0fbe49b283f4f0c073de77ab78fbaf *R/symbolicToTruthTable.R 42daa52bc14fc6918004e35203e07907 *R/testNetworkProperties.R 568159a3609b108c45ba2c39728fa6ce *R/toPajek.R 47bc51ada1eefa53c11e0171a589bc8b *R/toSBML.R dab752c2c82ef4e5e93224ad6934208c *R/truthTableToSymbolic.R 811f12cc71a25cbf23ade7eb93bb2162 *R/zeta.R 26698e02ed7503124720c32ef70da6a0 *build/vignette.rds 6323b9a68ede50d320ceffa342711988 *data/cellcycle.rda 2162a3dfd9f29f06223413307dd177c8 *data/examplePBN.rda d58578f1cc7da58378f1617a6d8bb021 *data/igf.rda 8919de127f7ee2391900468a36c5dcd4 *data/yeastTimeSeries.rda c2ba2ffc7f8eecb769b2d151a0a567c3 *inst/CITATION 49fe6c2b2f5db31583cdedb90833d8ce *inst/NEWS.Rd fb4bff4a00b9ef7f7933814535609bbe *inst/doc/BoolNet_package_vignette.R d67c2471fb9f1075461b6d2fc79aa2b1 *inst/doc/BoolNet_package_vignette.Snw 195bc9de963d2ec89d00ba1d8aa9ad1c *inst/doc/BoolNet_package_vignette.pdf fcb0ddc4a26eb5062f05b55032e5b151 *inst/doc/cellcycle.txt 27bccf40991bbe762bc274cbd7874f40 *inst/doc/example.btp c18e73532d5371152f71d625415e81b2 *man/attractorsToLaTeX.Rd 3f38a60cff23b336642ed070e649f36a *man/binarizeTimeSeries.Rd 66463757d6cb6fab74e9a955a6164267 *man/cellcycle.Rd 418fea2c14f3bf578fc2d51de83baff8 *man/chooseNetwork.Rd 3b280a61e2e25a9432dfd0dab1d6d18e *man/examplePBN.Rd ee848afa1c4ca77773b75def1fbb5597 *man/fixGenes.Rd a7075800d913cf6125cd658cee8fba4b *man/generateRandomNKNetwork.Rd 6233be4a99e3679c3387eacc6021c9b7 *man/generateState.Rd 0ef226f76aa0a8be748c788682b9b09d *man/generateTimeSeries.Rd 55cc8cc9f64855597ea40877064cfd57 *man/generationFunctions.Rd b92864ab58b032d49bbaf7e4b403040c *man/getAttractorSequence.Rd ce20637e139cf63628d21531d479c5d7 *man/getAttractors.Rd 66c799a2190e76139de901c98178c102 *man/getBasinOfAttraction.Rd f5b9134d6cb133543a1d3649b8d5915c *man/getPathToAttractor.Rd 227db2f59e2c70e412acc8d3bc76a66d *man/getStateSummary.Rd 394097ff1ec32744befa8ca978f25de0 *man/getTransitionProbabilities.Rd bba61ea4a4e91e29298e56a5d8907d10 *man/getTransitionTable.Rd 55e1e5c8c85820e3d07687552d44944a *man/igf.Rd 587e3d9f92b152e985488e938940ac71 *man/loadBioTapestry.Rd 4977fd501e88e2cee72643a701912b63 *man/loadNetwork.Rd 652f08ea8e4fb8f8c633f7fa9d900f3c *man/loadSBML.Rd 355384e357d123772fa178b50957e972 *man/markovSimulation.Rd c5aa37e4f7fccd0dcc45ae63ca2e43c1 *man/perturbNetwork.Rd 76979ad66ad56be54d1b7be3b8a4aeb8 *man/perturbTrajectories.Rd b87db947fd701f08a278ed96f2368ee5 *man/plotAttractors.Rd 47b0d009ef25d726d4595aaae5c7e125 *man/plotNetworkWiring.Rd f16447c951cf61d08cd476c8b83f82f0 *man/plotPBNTransitions.Rd 8d67815eda6244e4f9baaabda715b012 *man/plotSequence.Rd be7e29a2f7ee50329f93c4d9e2b9d0c9 *man/plotStateGraph.Rd 3ec938a75a9dcb49203ce32e740ecd2a *man/print.AttractorInfo.Rd 2735292192997eca8e0a624a0f136d2f *man/print.BooleanNetwork.Rd 5d61892283589cdb01ef269a488e3d66 *man/print.MarkovSimulation.Rd 60153469a83673fe623dc62918ac84fa *man/print.ProbabilisticBooleanNetwork.Rd 7de039167ec5b192bd12d28bc49d4c72 *man/print.SymbolicSimulation.Rd e0d5cb6760755507a21c167f9426c592 *man/print.TransitionTable.Rd e5b5ee63c75be0c158d32677bf07b36b *man/reconstructNetwork.Rd cb473a0b145eaeac4d8f5c07a68b3ad5 *man/saveNetwork.Rd a8503e56eb5ff34e2b334e88742ba057 *man/sequenceToLaTeX.Rd bb7a087492001b4fabe64d2d8506caa1 *man/simplifyNetwork.Rd b50dfe205d07c1435afefe8ec1d53115 *man/simulateSymbolicModel.Rd 6e816d8d86f0b4b06bbdf0ddc9b5f0bc *man/stateTransition.Rd c5b8ac0b669c25b9f6b7946b233d7f67 *man/symbolicToTruthTable.Rd dff636a8e481d63b3b52604efa9f0ebb *man/testNetworkProperties.Rd 8e8514658481c4feb3ff6aacf0aff459 *man/toPajek.Rd b304afa7f76464603efbf169a2b46336 *man/toSBML.Rd 6a6f4f827e1512236927e239ad2e0719 *man/truthTableToSymbolic.Rd c2fac985948f6c23a281a70597f2220e *man/yeastTimeSeries.Rd da975f995fc5f2ef57170b3d3ba53178 *src/Makevars.win 56a684219ad834529e4c4c6e9deb9ef2 *src/attractor_info.c 8b25f0694d6279bba2e28c947e304524 *src/attractor_info.h 4f5885dbe22b3adae3da6a066bb3cb06 *src/attractor_search_interface.c 8e4fdfd767d86b61f15c5c245e8dba77 *src/boolean_network.h 2ca57d54ac06972d96cd77f2be31d821 *src/common.c 8b9a314ecf353576c5d9199a8fc9d97d *src/common.h b4b6b972bdfa49be58d163a0ff9e9558 *src/init.c 9ab5e72eecfbf58d09815285c86b1f32 *src/picosat.c 2c29607ee624151f84ac09f55535010e *src/picosat.h a869a6a74b9c0a1c4c796003c1251d60 *src/probabilistic_boolean_network.c e99e9148907849c0b79f373a2714639c *src/random.h a18cb9116413559c5438e6f25e8f7149 *src/reconstruct_network.c b5e6e8d104bc2f031af765d728de03b7 *src/sat_search.c 0d6515ab8ff7605f16ca10eb5c6fc9e4 *src/sat_search.h 351d201ca2f926bdd1b5f4694de19902 *src/statespace_search.c c085761b2f853545febe7170a3715eb2 *src/statespace_search.h 4d4e389c0ff626a5e0db88416991e94e *src/symbolic_network.c dbbf4848847aefb8b756d749519bdf1d *src/symbolic_network.h 44a2f71d374da28a5c80e674f62bc976 *src/symbolic_simulator.c 460b4e88a7af5ba2c60231ca9f3644c8 *src/uthash.h d67c2471fb9f1075461b6d2fc79aa2b1 *vignettes/BoolNet_package_vignette.Snw 327d97a2c7e1bebc61bd3e20a2082b5e *vignettes/BoolNet_package_vignette.Snw.tex 45d3f76bd49d22f8d6e0ad5cc2a14c62 *vignettes/BoolNet_package_vignette.bib 8a78420b2b9d23b39e6ae9fb79d41ebf *vignettes/attractor1.pdf 6bb506206da5fb61f62cb56c5e935120 *vignettes/attractor2.pdf af93a2fda5c13d9e21b95ba71ce30a9e *vignettes/attractor3.pdf 80ef18e9875b6901dd4f1c5dd83842fc *vignettes/attractor_robustness.pdf 59d4130c0da6d1dea71b37d6431374b2 *vignettes/basinsize.pdf cbc02d945670e5381418720262b10955 *vignettes/biotap_initval.png 530409792bed5d5a53140e85554b9d61 *vignettes/biotap_logic.png d4a2fcf1d0a873afde1c021019649014 *vignettes/biotap_model.png e02e5fea28346a3d8162b4feaa6ffb05 *vignettes/biotap_sim_properties.png 1d058f049a3c1d94592bec3e06b77480 *vignettes/indegree.pdf 52b1e5f5a9b41d5670fe7a23560495c4 *vignettes/indegree_kl.pdf d6aa77a2d43960ebb98c288990d3fe41 *vignettes/pajek.png 1f6831762c8913a7e10160a83e6c7959 *vignettes/pbntransitions.pdf dd4f4251f46fbe03a206a3b7ea99f281 *vignettes/piecewisestategraph.pdf 7f3d60160632e2f09add26bb1bb035ef *vignettes/sequence.pdf 01ecf83ac8b196de6d75a20716f405d9 *vignettes/sequence_igf.pdf 4ce1d630304d3f6cbc96f7844e0a5f15 *vignettes/stategraph1.pdf 6674bb5b871dc80697a69ccfd24623e4 *vignettes/stategraph2.pdf a80586e3af1e3220e721e12569e0bdb9 *vignettes/transition_robustness.pdf 0c82f879bd44520423c98c743f5465c9 *vignettes/wiring1.pdf ae9fd9d09c1072c33c57d5e9071ae27f *vignettes/wiring2.pdf 5f6087613151132a3ccb468023836627 *vignettes/wiring_biotap.pdf ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/inst/���������������������������������������������������������������������������������������0000755�0001762�0000144�00000000000�14506502647�012602� 5����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/inst/doc/�����������������������������������������������������������������������������������0000755�0001762�0000144�00000000000�14506502645�013345� 5����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/inst/doc/BoolNet_package_vignette.pdf�������������������������������������������������������0000644�0001762�0000144�00003013547�14506502647�021001� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 4462 /Filter /FlateDecode /N 88 /First 734 >> stream x\ms۶~t:%_x$NRvi^9"6Odɕ$> z!%v(4H�\, 0 09 B2ς,bRϤ`RkIS"S1A&D!nK|˔Li2&0iɴ(uJi_J3RxR Ĭ` | |`\J+^bxFwԘaޣ24RLQ ,l`FJΡH C0R2X[RzSSǕ\ ILtJf!He= - - NCYP0@6 @2;! /P(Pu4sl0*#A( yA*8H)([ƍ3lI@A Σ ʮ({Ier2= , C7u@P nAJ�CVa#|p2 ;b|T`_ `?/+Ɵhr>$]'S;L=�J ^s0x]c_9;:E/՟_&ӓYy89ܫjXWd6 圕ՅF㫏Hu=Ut;dr5/57MHꮍC+1RR'XJĜ:ѐMD[)1M\iLb]*W NNmN}N{Ej̨ʌMWLÈ26u)Y .&X%-d<%Z@I=x<!:[0�?ӊ1>f3P:͔�q5!jAUNaA,ez5L" sպt|5/5RyzEdK:=PBJop)#ѽES+s~p1ɜPl<T&4^֋E F3zlM3Im^{}l:jG:qXgM5uI}/%.mBBKhJ1O`iݎ݇a;b8aW|MU2/g+C')߼j_WdAdC^dE4˩0PZwG/{ng,?''xV/3|0*6:ڈ0Ce\c [Lylx +<j5k/Qj~&;]? GN좿DmHӆtWڊu;hv䭅C<Q}>,8y OU}v<BD4\#G>'x?c>q/ϧU_&_E*z487@v*!>Gɫ$e\Tϥ>a=q4: x^ %awyG=!z#Rtɶ]i` H0k%Z8 j/N!8 0[:iTl6=i y7}C V.G0奞A-hA q+~_bwy5%Qu:OwSj&"{V}+N@nXH ҂lükaD40's߅g{CKpCt[V0[cbjPeB6^aQѿL˻el|3栌R{Qd,4?8fJ.bPH6i?x˩;RM4%l^3,RRM~$=4 # *S.)ghrA)]}!I[*g?s~^B %To _PKVz1Si=Mq:~Q~|8M{q1 Hbquq2jiѵo\C].) zr\MQ<iUi^ԉ>gW>j!I5 'ӊnkWFS/jX`H4l հzaܢa;J{׷z͞`Z1־oyka{{j W5KEƪXWP{bXz:XSiTByI[LF#Y?#^}-BմMFlT)㫋`>Zrt5>BNRX=l*JmљK�ȺCP$)z}ОNF|;8}D{$U-B)<Ϭ30 urP?5l - ; C,&eA5oɐ, x$-~EI /hK*TBe!xAhd -uAXRCf֒#laVLZeLQb5e(ȇ%G=h:mC8:Eдm"vɒj?wd+53N`w;lmk/h9R`kr)\aNZ\FV.f2,iU  t>#cia=5w:OgCg5+{Q=ޗ?O'drY!n!~u.UaC.Eȁw3çIp!65.DO9ZtTqIj7 EÅr c$Y!df$73426ZM{o ?YFuQfͳ7?u6dC v?B>zj>X^5 h~n2>5AuTք~Z@iFd:?={ ٠툝oCuU醣Fl 0¯kbjeMzUu m(,enӡqP.u.!Myi7ljJT ̉*$ ڃ٣I"4tG*v}ӅySHQ;8]2ԽБ7k+zW j<b]*`yk\`yulEc'4FxTcx|ЌΣvnv8v E -uOo�,KZnTc<e-6o8)N`b'7FN|{w]ȉɣçiMv^ZQNmڄmxLi\cZlߤ0qpX$XĔ ڋ%DJ8 =6p_\?S,.)AMbRV&ذte. M{d\+^S$PmhL=Dy]褧2F<F6Z;Cq<֖̏նpqow,J C_JH[ =iR(W3lxD_Ua923OB=4uJpl\Wչp= x#'3,h/oA#%QXh]e]! B{wPM[ Oc3" Z޵(LA !i}A!d i ce4DC~)i +z U`ɕ٢5c0;-[ܱVɂ6B-:P9MQqYL5=;{WBtBHb%G-X%o!gxӅtg͔25CH0}[;umGz-fB[WA{{(cCZZW2nVB.:; cC^!ZѼKbE#$aؒ={G}aܿQ@t8},=!T eVߕ%K@67)AG} �#+Z@`!3.baI $ט!}0-p1p@:mI[=4ObmGэ#t>>'|7;lI>ʕ#nyXy[~ݽ¶vEe4nٿj;7';[#_cHλ-gI8)SVQb 3uceL}g2tZ.o{D?sbtus r %7ϫt߁;UǕHb^jI߲vb^!RQgaqŷ uh,n!D Jf,J(.Vnjv0#)|~Og/Fdz&ë Z&e5Oas5]c=~PU>WNN< MヒvDvOKi:WW ~,󝐅SRX`IDA;/_d>?in#;%AaS Cyj2dH{ۏJagPhԽbDMt<Ē䰨yrYtZѦb } aBFot- ,%endstream endobj 90 0 obj << /Subtype /XML /Type /Metadata /Length 1387 >> stream <?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?> <?adobe-xap-filters esc="CRLF"?> <x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='XMP toolkit 2.9.1-13, framework 1.6'> <rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:iX='http://ns.adobe.com/iX/1.0/'> <rdf:Description rdf:about="" xmlns:pdf='http://ns.adobe.com/pdf/1.3/'><pdf:Producer>GPL Ghostscript 9.53.3</pdf:Producer> <pdf:Keywords></pdf:Keywords> </rdf:Description> <rdf:Description rdf:about="" xmlns:xmp='http://ns.adobe.com/xap/1.0/'><xmp:ModifyDate>2023-10-02T10:56:06+02:00</xmp:ModifyDate> <xmp:CreateDate>2023-10-02T10:56:06+02:00</xmp:CreateDate> <xmp:CreatorTool>LaTeX with hyperref</xmp:CreatorTool></rdf:Description> <rdf:Description rdf:about="" xmlns:xapMM='http://ns.adobe.com/xap/1.0/mm/' xapMM:DocumentID='uuid:127a6a41-991e-11f9-0000-cd7a0280774f'/> <rdf:Description rdf:about="" xmlns:dc='http://purl.org/dc/elements/1.1/' dc:format='application/pdf'><dc:title><rdf:Alt><rdf:li xml:lang='x-default'></rdf:li></rdf:Alt></dc:title><dc:creator><rdf:Seq><rdf:li></rdf:li></rdf:Seq></dc:creator><dc:description><rdf:Alt><rdf:li xml:lang='x-default'></rdf:li></rdf:Alt></dc:description></rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end='w'?>endstream endobj 91 0 obj << /Type /ObjStm /Length 3526 /Filter /FlateDecode /N 88 /First 810 >> stream x[YsF~_1re [TɲdymXh PHqA�Hڪ-0GOO_ 3$ S&2+sfe)u32/)ѣP5MWiz^9(xRȌv*cƀ $3U+F2ìT:M@ Nyf*GE*cE. .ͼa^kT֖yяv;t0= I# 2R'YhbET0!րh sRƱ(%,*b&UWErƢ,zU,h1ekX&Zejf)e:+*Ê(j!ðTSZ⧣%qv]+e"ERQ)=r@o\$diE!/ 9-Xg 'B6q=4-Q\ Y`K< MZUF##Ie 4_gO?1q8,b6Лx}=+s'&^ghlQϧ7A>g1zKK^Ϧ|'Lɿ-?uN]]ML&S1q  E\Щ9-@k[u{#ַl WD>IA,yW)f8 %|~p<WLFAד|> D(qvyF'TIJ1XKli~ شVwz( ~&M5>x>X<qؿ>ɇWt)/"b( &/ǏP.LwԿ\AzI֏FT<rC^`&=z-l Qt8cO| XoU^Y/~91 bib8 KM,`bkbQ,tҰBOMbjO faUU0ÔI"o.ZֆH\f Ӈ8TW6])ځ8'8prx܇]+^xl8=31.fy.L0\%gӪriI"Dҧu,;ukڕ<-J<O&B +x?LLOnF##�t<D*ޤip-$HkI!㤚@<41$j$q KZ#)f\xzr sjzP2jEywyWyH <bm$A$C1?(I@<n#IYN"F[WDiEdHSLdk\%:xN 5`jn-׈Gk<MN$֔P04=tbYLȲ^ZD],h=}y|t샪b >a)ԯ!bi:BJN<3FM?] trgA>/EiFuTAԟE'7 N]nCiؚ_ a^˯O߿�BGM٧$`�%Hٍ(ݮm(~CH4P ,"H:-CV_M.u]m*jFÜ=EsD 5*6 U@yZ`n50ʪqpQ틋Z݅+;Ꝟ|y#cXטpwάŢLi~Sj{NOn %;cOđ8FX"( |Ux 16Lj/-NtSH"J*N"y5PF)^jL!q;x4bmZ{SħRn2];8juo*K\ܮ]> T0~彁筬11 Ű׹n\oagnV)4Jv=r3S(ڬ]]HS_)WTc,[OjI>J/3ڵ |U#XЕ _D#SWӖEh b1goz}ܺȵj29U$1]#ې}wGo|co:OPbj>1avE$2 ){{SDbyc2F-r*_wD(Ui1nʰaH#g,Msq1rEt~j3s*n&`:MgΰU%)#W3ˍ6eS4J\iڀ׫JըCe(06ZD`uKWkQad#6+s6ǻxRbt6#.eFӲw ,"\5Im3wOdS#rwݐ[)ͬiW N<$I΁$D*u#alJt�Z ,a ss;!;S4mhŽel(Ͽ98:xtᠿ])ĝ.d oΈq:D@']Uy.t{?g/FEiEzJ\)˩eBI(E :JUygؠj9ݶx)^עD&eW,C?κKq9|]|>"G 6MP(+!|}(Qт7&+xF);Y99[޶~*uRhM˹wq-  �Fkn$(ؙv 兾<AZq:X ڐ\C=Mo`+7+vL j~õeBxk nrԓU҆ѲNPi޲#oٳfnЈ2KV76N`F9=оNტu͵ljbr}s?eF;~^e܅꼇] z-u=ֶZe+<^k֝ -餺]y}d&h�:$㖽MDcXn@ɚ7qگ!;7oUvo6ABJ#w۰<;ܶ/eA<WjE�!ܸ$(%/:y,Sxx70-kԿOUw}[<=[@OUVϴ9hLJL4òz B_6( u LpG*O$Y{V]!)\k$8П,P\0\A 7kDlE& wupeFgX ~}s1Mq�C,rhg٪`1NGZ,%~˿bCq>rïH>-UM> ;h*t'zzy3 \1^iՊ{43dYfs諸�;E'iXk( K+UVKilϞew <ɀ+' i*g#ӟW)Y$e;M`endstream endobj 180 0 obj << /Type /ObjStm /Length 3076 /Filter /FlateDecode /N 88 /First 812 >> stream x[ko~~A}?"m& 7mL'u@R3]")RTv}̜9;3˥3%BW1Sp1\@3aB*_3cA`6h'(h&M ST2Ce=LyE 9Bc0.Vڣ %'%4JndHEW3P/όt+0%̙1*ƐNŬ"bzHaP0ˬW ڢQpfNə3#KT9jq].5Q0/K#c^H(=BoIxřA*J2: ԁAhj FŠȤtų`u,XXXC/v&@\@ UP`5NKmPi,!5 J0*P_@% T"@)R;(*.%7J$!xQJ40 b2[,-]Fa9`Tc1pnQ浘}-+kfwj`疕T(HG7%ڑ b&fڋ:.X{9YV<זgb>TkST;>s\h4>fQ۷){4jK P&U[Ҋ@JFqXxߦC=^F=>,4Codtх]^02ͬUBG'=fo6H{f P(i -{XX!f4u9X(F ѥ=vH$o)ZOZ:ݷ-[my Cr_l,ZF`mJfm.ȵwݒk n)ȝniǢ?D  LUA{F  ާ6oy6mfaIho@+3+VaX`Xi$4lqHKwrJ˶^udJL)J:$cFڻG- o]=^=® @&pYA+|6}{w=ݖ&D&[{̋m{M(`dUɒXM׏4NM3crnrK:SoEڙNӶ {j^h0a0k#qt^ڴN 59PC2i;tl&nky#+f. #`ZC( y˄;COO'(s]^d<tkT3.l8ۡCK3+q!f™0vێtL~1ݮhpdƇԛ#aOi 2/'f˛߮~rֱz>]Xbm.DخOLM2>qjl}zcm-ꟺ+~4�ĺXM#pW?TwsUkr1m9F|[1k𗗋/d.>ǝc9K.|:0<[OgӋ;�?V ̀/4[W~eujǻ닟1kLO8α(-=6@Y(!lum$F"~uK/~47dT5֧rmmO6=6M-"rׯn^`Ƣ,mb,�Zmj6taCCt]0�W?XBa{nE>ƶ?s*7ߜ vTF1.9cvtU|,a챁#Zl .򮜔oiYPE,WI):tNha\0]|61.pKgƷtsWRNu)�2Qm<|j*T"Wt<{JtxUWXW!yETiV]\ 7⶚R[m#�# ;A),f?3b}X8N(]밊}A#R)/8NŒ/㤺 @Mc~6i` :Vʙ-^jhefbJ c%y9yW5T[ mM eq.Xy[O(N'<ؚ ^aG}+z~2ʨ2=__~j=N\<ޏم=h86wR*~:>?'cq߈prZQ/!vR,/�r˛_�p Jʏa]5zUiE~{cJ"t\} &IЇAb:L\:'�cM!yH^ӛQl'?f; €" &E. JH&heg+"Z:~T㖭lmO6zDk>aZ5js?AmRgUR4^pF&d.(_?2P]ٕ 02=nkw"$瓟/RAq^>NDKds6Or =hV|��\zS<vt1 XaD" j wzxeeҼQ,Sxzb9+zΐL!ZVco$vLlfSg3m1ݗ,70Y/^FBSw0+/Bu6c=mw UEh- k+39:crmd<֒A,ҳ7IZ^˟.p66> "y6nދ0ZN櫸36_.>}죑Qߖy) 2sVNppHRR:%sn<j[\!?[sG' CP@i7ߴ/g[ vbeF.^HX'=6F [Q-#cXJz oY-iζud#CL 2%ctk2A�HE6{}9ݞO^'endstream endobj 269 0 obj << /Filter /FlateDecode /Length 4962 >> stream x\KFrC :!Իj>"Va9nG؎= %ȑƿ@JcMCSſ㻿C>|?j tOxx̓nyxھs%B4M݈B5u0NT~JW#Twq~4VZ$ Oj=- j >_<J'<_-w(Br~T~a d6 vey]tu#ODQAH[u@J -=q`1}ղG}tq:1<^$G[:T/n)M;fV}CTEĔyg- ځ`0XT? T T%h!|`a˸<Ud'lҶ rmԭ"e(_/Fx^׋G K77TA*T'b-1TԧsDl:"\.@D}wGQu;pppoģg饍+{R^ZĻ7gF1͐ivcq�wf9㩪L]&u@dZjٷ+/`4\n|ʧߟ(@>;AAs-? +gFeh}#3;(ƫ LL ̏44@ [iQ‚ДKZw=ܕ;|DͶ2,=%Qق 3w 0KFpcz9tYƄ 'D.Z%! ;qpq6yݔ۴־y�]�}-01:Dr1gkm�OOnu ~p1?~9NfԁUAM*ZK՘#sPG Z)63 ЗѶ #BiKнd70YYMARD_)NԜX?ijϸmfE97ů(zB6KQCj )/*4(A(Zw,u]f16L 8mOKF+  #e_8t۲iXSD4\%(aŅ9(4ZЁwrpn]9DV4A'Romo̽n|-tՉGYlIr"!bfɅvra`)8)e rT!S&$?6M9Ypq&9kBծN@|c$Nnp+蝘aPmsT' 3  @֍A[0p/nގǛ<z:81g[Y�'H}\7^0A؆KL_7gwegvWZV3àKfE_O4ytA}q]A 倍jɞ@plnаOP7< !ljm;kA#@e`Qr wO/=nVDEA"qD&fRL'Y̙ Ib $fzu� ?'9< <"cpK]&iWL;~@Ic?ηUR_Ê*VS c%@XLJ</"3JRIbt' `qi<bZz�SvQsрeThLy )>tcBUeJ4U-08faL7TS92 &Ґm`jݠ3[May8͢H>Yq'hƟ/Dž$%�2[.3WOCz1Yn7AUt04nB2iW4MA)BFe7[  ^DPnSjwvU=f`ip={DyR.FS &`gU򺠀cΈt }2e`~3tJqR<t4Qה14;DotSոO~78ő-Z|n{tZYQUӦAϋz B11Š鮜_=::L4<퇤hrxgq̈J4BGx^lOdpl<,|kyx>Bk3>({S[4ĪaMMd%' h]f28*q\i՜Ym>_\T9՘&K)b !<uօ*ZFE8pZ|xI�rPƏp8� !A}27&]FXC&4| bYu4X̥%:x/=WhAt sr RHV}Z&@`GriUrɖw@1c=3Yep49pY}:zv D6'obQ�kVnQ(\A(QfMcߵ6`*=JFDu"'dN0']T߂yna`d_l5\⥏b֛@״ɜ{\Pi0=[b1~N6" ?ă Q&eSt^/#wˈ}z ]uysxαv4`)z  Eˢ3nske1ZDcI6�lᅦxm!lw@aי^ `wqn.2`'7 cˑS|0)/q"Lr-c9<F Tnl3P w4 L 6:8ñ"_�@5 ]9_NIpzhuՇ;>l K^c;NGeMrEg+:gAs7\(8x4}?!(0dF8 3|E9YLAԳ L!EI.S@TV&gj% gE&K~3(k2�2_)jZ%ˊipU߲-w 2Mv`Wh7X˒C9Wk7E4*�Xr"lQIe @5K`(7qHkp0IM(#5Y^?}D'RL ٹ9̐_'D| ;9GDo(Uͺ<+wy +c W|isR&_@B@am7;y7'EY0t+do0X v1,`'euic)̔p 2qdk& A W AĐ7=9:"<@+"Dz9;jհ?Y/$ӼnfEj;$7 ˱}nE S,6+'.`=̻-3n9Y[o'٭iFTt: r5r~>hkCwY,̺}:vaHE(c%c !Dh@P6 u*'"\< 'fJ{Ĵ ^#ΉI4ڷ8v/I;N r_,~j|"9 s_*L&^5f^8:pꌯR8b.-<[DqmhQE)ghHuR[b|ӂs(�MJȟ*!qBAf̵ekEUĊ+ty]|3a5fG>c&|6"YYKvݭb.㣐<;_[Z?hJtT rv -%``ގyiH %}VW=LO\s<g7БM`T}r8<w]iϑZVTgXGXO%pT!ftX{Y!M;P$/P7Zh�m+7y!OM!\1=[֤TZH9jJ%3]YLx + zK.}%f{pI,P>nہqҏe�Mc%; \o4PR̟ښ/3b&W@=孷$R2r.<Wk^Ƽs Dl3sZ.jHlx1D->H"5qz!%ȇ|mlUq/7s0u!-�D—FX slӢ8#c4|ި/*QTr9(BYjį+ 0߸Mu`cUb~}ާXS%v?p( ^b[y3D- @0na0l?pvB!؝%'L(,Mm8hs\R^r,l(99*3y=^yCWknNI$(V4L^nj&w`ӫX<,Ն@K]j7fY v�]zV/αTe�< 5ԛRnԚ#Fh0Rk�^5hwk=D}zZhΏ/OzZ+{@n)@F1Z_*} 3JNEd9! �4Ëy0]Sz +fslS٭gqF/N%k׈3f>,HK} H)~S3`8ȏF+[;Md k5)lr&W_ks5iekb ŻT'JytIy4VVu)c 0h?6Z#Gw]Hendstream endobj 270 0 obj << /Filter /FlateDecode /Length 4615 >> stream xZ[o丱~_"0r#y0$'$A�2yղ[;jWu~}Fjg-bꫯ6٧ t>x[Wn?޺+tq{x=[ܖ"?KvwYPw;WZ:V֦VD2OMӿG i#}P}3480~%$OBI'FWylgyrI YC 1:qj%X}8SG8鷻(Krڌ| XЅkn?ݤYy{_Khv oc[pTĥz_Ti=+25y'3W @#V0faaimA:L #+RnE` "lvZ;,-I0ͤ0R˺EYۛ+A:9MjWT=:^:-3u~XPl&}8U/XP=];Ͱ˲ ]¸Mx8TffO̝jh |ޣ϶'ޔjyuY?]iFTX3$EGiRx4O&wxF[}.8[ğWE{ ozlJ4bӢ7²بh} U '{ãEpL!ai^}0؀n6<L v#K�ԅ!pn.cԱ}:J3ph<ê1ZgaHP։{8{SB{Fÿ5߹nHFR;.2slNԬ}qronN6Pu`C[%%1^U\}ƽ<ꠄPK ss{ OV <(Qh #+|jw׀`r} N4`nV ^Rt $Juף)~<?KЎM=w1�a!ybat'qY4бTpHl0t ) q@eZ/h?Ql|KSP$Rk"ؘqHQ¯&3lo B+IjE+E'b. YW]ϋr? . 0>ؗ"F"-p6tҏ;/24{dOP5%RA^'v3xE0F�lj{J`?v9@hkM %e17Tz �@@;(Ӟa@&+d �75Z}bʦg HV嵄^f2>I/4N2[~j7u0uB;iV[g&#Y�{m_$w=%{f#`P(t qb^~#a#ŽrE1 ̕oV&1vc { KOn2rCs^�-Kj6Fw/VAۑ1M{7ZagQE 2":z^Wҹ4y^&dRSM{ QZ?7֦fc?}uJ [c (9ʙu뭦elN>,g^3"2uGZ�@DSEkq :|֯&2TݑJձΏKi5T zB4oj~&lK:`.3QQ;9мfsmxhnx[|#H2x �sN#jZ9m :kՆIf�'!;(/d5:%!hQ:Z<l�45BFC/E(m9ልfLnb88?ַh%K!y78#]nM8xsW݆jMMX]hSHz%b"SAe6[A'tqXR7kM�R�y=bZK-~F% /F#2lR4p`]3 x;iD'FlHqZ.;KWo=Q$>2q\_a. [FQ &+|3cUCF@k~QrXUUYfiIш0݌|XNDX2.QuZK#-OkЌjy!`[|#ˏ ]9yV;x'!lQPz iHpf$~@.k=Kۮڒ9t92K7*f26]#%Kxz[<z5_M×4TZƢTNJ.H@YI%o0Om! \Ű/447(oZZ5$p#RI2B$:f1s J 7}wԔS71?q9azƿfqbtC<(PF!qSFW9JTb=E~ ~2 M_]J DrxX'k0cWP/OX]Aa08hP =Cfwo\,)Ce(Y }nfVJl\,qYlO-ٔwZܒ|z+M?H䴜}@:˘`I%m?%&z u1ށ7:tC(mJ6 r-8=,P<S ##r|4ʫyFeya&r%�G| ^1%ez6D!�sL e;+WBDW {b-܆aVkJ*fhE|j`-3dI <j!R4P* \jO\#~#1 QHeEU q*Hu|eemO+&d`\ '0|ԚVDt+Xoz d)q= bG5lj4AmL a=yM"1˯]/_ I2zNk,F>D01YЄSr~ݿ+嚟 l>'XԐ:S@jyYB9WlV2nVT\GڨurpEpNã*(0ik c7W-h@e*!'IM etU� 2 T1X,K4uc5ym TM,9N(deYڶ<u&րڑ-CBEb#n)lC}XX) B Nk\1 ?9wp9.HEXh] 4֛uN:ag>U>_ɶi� Q"rT4hJ,!'mzQny<P~I/煆>(w[$d)Hw`q+?Kcvu$:pj'4F:wPqRE ڧ:w�}m.+?3$5 /lsl6'A N̿5Z0Mcg1i &ɰCxUqBo.;=aEc]$=d`pxhwK.x2)ZW l@i:P{( I~ag|#C_L˝>a.\(}^zOR/R!,Ћ ~>77&8{γ=>>phNo kN b!^Xu Rՙc4fq"xڇhGYKy6\�_ę,kXzl:Hhufmt}\Pڪ=Gi$4PpSX]u 0"s0'0-uh,/OQ^鸃 jY僩3HYI|s2 Ȝ.,nR50G(I2.<땾gRdHa^s^ψ뇧jM&!}^rCފS@`$3| ]K<Pqb ȷ%䱔~R$Qit S+*#uU#X;5Q~nNʋTSKǰg+<V،!aP 0p"/RLEE}Bӽ<1tȻ]O, SSuf]?o,mwg<)`YJmW]8Ng`ݚu^Im\>[P/O<%�rN@xI,ţq^?AB]d S�ߚ|}}%%/̢lRtQ.'f!6|8-5r2_Nȱ"$8e K)_(.<N9:܄?ʌ@dy`Id E by{kp� Ȳr5{"z^▖˥"D$5FFo(z5q{,M,8hho6t+yKo>L Dxq(?dUb=˧ xVsF.r)u|8;EvXoA ah<tJendstream endobj 271 0 obj << /Filter /FlateDecode /Length 4635 >> stream xZKoHr_9袙O& i N9PUkVQCFz#_U Ab2322/"׻wӇïzOwvg>⮩jʚ6Zs8mJaClUY,}T٠RnZ7[#u4XS m㿼Ote%z6tl+Xh7QqEuhKFec(4%-[TRҡFuB7SCh94c7œ(9rK]|O-P5VNg*MAw]i]@+Z[J-vAZEieEJQs5hJekPwEƘZ. -F -pGX=,Ʃ ,Ll<,U%sl?|`Ol=dF¾8-*zhhloS#DQ.l+kSa| GT]i Qŵ` #MMۚ 6+̃-PFt8 )P[ `>sh|-$SxFoŀxݼ,О/#�V#[I Hfˈ fP 4G<ei ?tњ8z W|Mp0aKYkNKwtvpwowv^eQR+]8?uהZ|2,XYu5hGX:CKӆԬ3ǡ߇M14ehZ7lݙog@ et5X™aNt[e (MirYfDKpb m]<Dw-np<zPCJд!|VCv&&bNcZT>?Lf[!N.VDvAQ#_(ðo-(>ygvrhZ;Iq� &A1 L8z>@q008w4^vM7˯tmH�xPAkΩ(uέk 1`1/k0`<F} ]孲Sd5*{j9oF0Itԁ_>-=]ylHi<!qE8eϏ@V+t86�3�Pډ�xSV b\+]+w%o o-ſR1hS;)e~9~~^#Jk" ,@`mWčՌ ?uw@Nت)laؖ]:\SEu+˯ ?e>۳X2q�� W�ҟpX-s* "g U$F Us p4RQ) KV)T?f=H\$^ f<| .4TGXC]1&!i$Agv4hڊ&+& &4I�60R;ËgZ")%2} , I%1V VBrҮ&[` *Y#U`aؙ9in)%0mFl 3 u&b"8AH0 :"lB{n(] F޾ 㝑xYsV̗}Cl9| fëoX5W�ro3s1VZhW6pOΆ F}^Sanl fDuh$סq�=gC>˟y(0fb 1!4` )ዟ*Lm &M+5т7q]UJӠmjԐz39}fls&YZU!h;{7~a MX c!ΎH]m{s>єMDדm↬Sc2AޢZ9U.ALL]0}2 -k ǩ7 H$ C;k1z7[vLRKt ׈9">�dI 9da!|# T{U:OkNfd^2k_h�f=j􊄤\u~& 4 H2oA{T4.t(ʐ>x�n24ô*/t,qV|á[@/O`3kBUB$ڱJϦJڮt5,Rya3FpJ ȓ5󷏘[꒳\Ub7A�.up"'6>CqNj!O}}U?[A[1`m'v+]nT7pa 򞞦$;W 'ɰBNt IV1/ 8]{L^ʠ(A.j<1"r2 2RkCO`;ym#.sxhTGz;8pb220(`֘e)YO]v/ cm6Ug�hRrF ^ >VAUV"Ѹ!=[8'D04)L F<T_|Ii+G8qkeyʆNߨgr_U hNy| N(\ĎOXy$Jx9 4o q")Oqt]u4P&!K9:eG} ā_*vfƢS8C$l9u)?)+j8A2z$g!r)Ho kL3}~'1]S<fz^<jURYXdϹ.yaKUTI ϟ*W!R2ԯ^Oݯ9*\ <2H.x ^0+t0:rLA08&AӧY~obZg,k*ҍqPi)KKq@sxzBdhy <|ș 8v lm5@g3 >m EZeh'oSRy};1PYr/~,#4~Q~^:kFE3eM'yv4Th& Džr]DꖵLr<b+S7Mcd6X?:Q'\_(uC K,BB*xh6;24d}p?+[>l+wIn[*/ Pxz'mA!0q sl(qX}ݓ0j6ŃysS;bgcana!2o8XFg/qsԡ[cbx"آ啿?pϩ2_Df%&G=A�ds}}s\Na~_�4ܦ.ibCHUM~M~SG>zB@ZqU 5{wi3C)^dW�nCS5PwŹBZJëfuU:ƪX`NҮwYw1V|S+Ho* ;AWYz:hn bDlZ{n{ /i9x!J"%%7*/g7?$t⮓8 ,??m/+ 'o .dbڭ. 0HѧC,[y*);QƼux9 D0PUӫӘ94D>B8utuGMS�)~^tOXIWNY9^f^=y|@oQihܳ;vm:Lc^ ӟ%̧�` tki!}wJH#ֲN(dA1_[=Ew(j; b:$؞%U:*eomz3L䍫@d닠~{ QҸx 7p[W14a 1)z5š{h/ÒJn9R$餐CcJ\}D?w|]MY+HuS+e=B$� T `2QLPTxbuG^-?V<`;_](0Fߣ\@!zuups-"Ɩ @r7ME/} ]6]:_3fM7 M,SyVtf3i )~իiȈR::*_5A:<"_"XscL!_Vk|hm \^2o9 tWJpnO| W 1R;;9+yfJs},UǙOx"Ȳ|Y7 ֜ia{VOțJ3X_vx.t- _=|~�Kmb|J9 Cd܈6J:\/Co pK-aEaѣ>>]endstream endobj 272 0 obj << /Filter /FlateDecode /Length 2621 >> stream xXY~<--AA:@ʓg(3Z"$OUAqxm 뫯a#1oÍ3g{\|6,Rw7ve|xǛwqJdeưxD+-{u9PًKxv0MS7q\o_yl{q芦ʻcwgkj.2Y[ve]);U[|zU^bT3*D%B Ɔݠh-!` 60N˲KϾq/q2m%{fWCD߂/XN [`)"xE$#I l 4XXnksL]GWJŠ]"$؊U$Xkw?M\dO0-�$�zk:fAefiߊ %l/s 0A$1v'3E֒p) ,!w! pJE>Y u{%H>Oϣ_o7ˑ .4X!_谀2tY<P �fXjmhY,W~66L(Q<4z=Υt |FBI&:NF\i mєEVB$^gdݾ2Ͷy[,X)ދo75 vTE U1n޻bɎsiP]Npw uSx}$h+8hRjJNizCS|xp^}B]$kP"+pS٦}Y ogqЄWAS-.cſ cQQyX-~hMPpH]w^3e`(pj;AeBdf tayyu t"4VJ6D&!u6<.5q59^jBNSܟyW7g:6p3Bn+SG^K"oˢg7kwhZo jжlOA$lWh0D@<|AhтB[h9 ) 6?<C/RhS$|\@BgPK aO<"TY󹗲nq,g"V-bBģnBxDTlf(U(NC6HWB@}`o%CQB5{° iLn>*q=zg25 P !犨4AL#ez_ );+H7SSDp14#,3pԁ"V<Q)yS/Ntj^ܱe˪9r!]mǭ_gz3Q.$!+)"!Ez5[ܕ@ Jövϸ5禄68+x$,n "cxF+*P.lxr|+:uڂvŒ" L`ϚCqii+zwoc +.{G^'ZV1Arl��8<U"ԕA{#VSSze;HG/:$JEzaaɘELkZyq�Iȹӄb<B$!`+:猽UTkf饻;/ZCS(FB*dXvMCxo /^YuTpTbL$@ʴˁFQ Vd? f U-2`tB}H*tqEG:MNkZVΟ[: Kd˷!{W!e;F6?V@In96x؞eDґHN 1O/S"NzaJJwjq-ް%,ZxK'`GPU_l2eْm%IR KRȺ&F:0Eت ZH0NY}]hxr<mhkyJs<By�;�/zwo/XQkj PM5ܒgHͩ|maoA|}(-RC篯9ISUB3杗YU?7� pJxq-ΥC[{quwv SVD1Q?TѴn'̀:O:, O7۸7϶_R.R CsHڍ5&HH/O7-{84nN].?jv(F@*~Saͩ,`d ۵~EWMƠyYZnZ&ځa&S n4$M`W?xqx}2 ͇v |uJ/5QCM`ٱ-"ļ==Rz?�a$ ;jDF)W[ÚU,HZNlk d\[([ );,lK?|jOGb4΁@=%SHBN;gՔ?P%��Lך>Z×,ۦ5um�>z&�!Ϗ'kNʸb樣%OAl%MDW^cբendstream endobj 273 0 obj << /Filter /FlateDecode /Length 3341 >> stream xYo<,@mHQU$zhISie[sl]+i8o?lDnRsEBۍW7/.>yLJWMn %7WNjkqtve:)L=O})}(#z (}5}\L[UŠ.M<+26(hܾV`ܝl3ouݾN=02V#RI;-lſVr%u `]uLh6_.L\.~-*H=qxB>hZܞڿSS!eĻWXlT~8)/[Te98ԙW.W9p[O =oD۝ӥbY66f?wR.lPl`<v߇6඿:jAjT,53 5v?Ez^ʐПO|FZn<E-YXS}AyՍǛ|)>mRop+Ɋ?M1 LxM/<|FRg)yRkf:/_|%?϶6YdkYqF u__'E"'i<)LYtspyg|$W`k%ze c5 {HQ%)BLU۹dlɀ�2@ j%|o)#,VMCՍODH`Z:e?;,5&E4c_SX'4‘Jۀ -f<.% $sRiV4\b"sU7eg77_6+;ľ+,rÙJ7qkBKg<9PwOk_g))X5W޷C K B'Tvr(qE`+܀ ̗4]M.a͇6ccaq� (y^W }["tD2& {l}92|*ˊ|b K@'pEA.)~?Yh`Yp LL,l-5CE0^|)!:\FyN$H,Fąt% {D9ksTd9䥸oY *>LDi~-"P?Brcpܹ|. s0Y7'>8ʈ၁ 'C&@6DQF.zb@HT< E!3 As4egGmӌDƹb6L^iP I(aCTC"|UJ@ei DR$x>C7DVʍsx�gy l7UZ& 8ca Ϟ$w]JmbRJAi 6aW^ۃSm8MR!=>hic3GpF; 5"Ovqz.T,gPc>n#{>z Q(+|-$̷DxPw *σK!&<#$=5h?$Bm$cZR, V kgP㜪=,sA�N!1;7Kr2Y RPBQ^|l¼|c5ƨRYEؿk"pZQurґ# 7Yv�_bwbht+K_ z/;q쀡L ?BeI޻�Zd(qOCp,2NNA %qp [wg 6m?ԓ 0v2!(dq Cl;ϺꪃH PJb=K R%H鶂~r-rH;UO8%D&x�,8H"h_t[*,P &cMj?RT~Un'Zmt;P|◜axѽ<ݣ @h �и+=?lxflhtm 6@c'-ȹ0fxu�kA˩7-iDž؆< ?9.ύz:axkp4[-ӏ?</Jh�1,*h3 <Y+Жu;D !qN�rpfHKJ{dXpZ6“-d Eر{#DAR&=O$Iґ~38>T7ծh }Dx@' ؅fSsh.8 G ZB�jġP1\^ga  jD-mdȠ{ EK B=.ixh 5phnQ0Ǯ9֏c;wP|C{˫PLeНQu)H.TsuШpPn.W<hSAI[`242jDiΝ\誋SSY6SLF}"r]*,F3ZLsMG6�?M2R?@"U@%Y+>40K&&lA,2S-%]<6ϣ{ MJ@~:A\d(Nd;f<(*ȯ10~YC1ʸgLqs-3)t3[.B99.O$P679qx} {+,6![+~T͜4�.>Zw\ ss9٢�ƣ#ﯫC}ޭ͕R }!dH,8QJ2s]zߍ:^6{  Nǩr0o˞=l\P�,FistA\ -d2m%'c�4]d> Iu'dTk㓼H0kq3t<?F4ć'O{x]RHKD>3?MMqVV?匀VFO2n~ -PPX%ѭ1.*1 5~ͅG/eN8LK鋅}/k2OI-x6 6%eƇqD*(]E26\EWSuC֏( f0ZCI\ G/K_<_S+>4X UWY>Z 8S#jR0f}I:VIr ]|uuwPendstream endobj 274 0 obj << /Filter /FlateDecode /Length 2277 >> stream xXKs7AB[' TI*$;iMQ6cԐԌ> YT%H|ZXrŧoҥ۸D&~wT Or{X|dX4{7q.e[㳆˧?uݲ9*\$߮Vdv"'u#>jx [=%/Jv˛z%-JX_=F AYɬ`ەUxdM#fW2cE.Vk܄N$;E74I "ݲ[Vn :ѿO%)H +h u')и)5 bM+{2/=`-w, [&o>\+wջ|%K4{WE^ I4JQ�ջKݖeU?CԾ"ރh~R6B+Rm}ye*, -j_bj&!NM;ݑWC.أApn1,1TeTM gG})p_x�pf5d~ +ax468<TMY`80xxq!rO5 *U]!0</RhC ";U}ydO#@P�nxG]Gʄutwұ({zcp]| c%5G;xo(x koᗇ2CAI!bҘ˜L"oD{‚mQ<{٣&DUR荂=+eVk!8%cNЯb@8 mCN $1i$!BBfJ[nn#X F@ @+)+=,qB)蔢L(6{j<ToA.dLbp|1Z2сZҐWHE!FKgd? R{b_TQ %BfR&SVP}K( u^٩W $}d\]>gQ~u0(%6BKh{4T|>7r>BzɫnHC:\I 8%*x%e�XN``HT/'iURԝ~ 59կI52 nߜ gfbH s<\iFZ O^Q.)hMU5`SqCuPvÎc.ZP5_1pT mD(d f$p2n2;&q#(s<y$Gk�נ؏UY}3Poʙc͠ʬ?aA5lU@OS0n�$eRe}6'Iqqa_}^=u[oa|Rng|56Kԇe"5B76 Л7D;CbvD]yYUo%[$6u|ñ嗖_L=B!&" v[zhCNjϲSH00>lHx#fQ(/$ yH4tX@Ulzl=!]TtA)BZy(vlr 5]Ѱ~�qp1m:ﰸmDI/c %|gE4I fЈdg�?)W�f6ԓ(9< a'Z͸J #Ψ"5Yų&H%jqRAoT/U3үk;ZϚ{񼳆=n )?5('m(^$监~ʬ;u47Pq"^}Z` |9ng>9ߩab1g$Hb]( g0+d;R}qN |v6>& B!kCń$`VHY>Tl'Uk9\׏F|2vA΋" ;e75Kx4muP;?@bE$1JtmW mgwj'sC}Y=U3}1xt|O~x.TK< ԑˉ\}.4õБFA?zD&H}vW U3Ϭz/ksQ'LX~_4Pt\Qt0ap.�cLendstream endobj 275 0 obj << /Filter /FlateDecode /Length 3211 >> stream xZ[۸~<DcHQY` $E lQ]EɃ"kb5M{.$E{<�EQa,<\sa~]dk[ǻ_$]?afsϮ\3,6wC.\(ULމ?-W*Ym5UR7Ko )>,7r ].6b8USnl{\Q?^ˇexis1,QJ1΋E dD_J~紹X+e\ \l�#"[gRdS[? US҂B3EZqkY3MN|l& ضk-FʉO 4GT&vM㩫A^)Q ̣&b׏+~�mҊeU]/W&l[P-mТ 9- jtL;8Z 9NlPى|d~ET%p�?/WZP欐(G@V89rS8-R"}@OKeN=묘yg%ԧ)Ɇe ۛ}UEE1|("=.8%`OHߤs8̮قU_$x\]j%I=SzqАز)IY<e>0)L ߂?'a%�^ x6ѠtjO&䭧8Ǧf(߱bK#G0<HyG2ـkmgs(Yx5S8y"h%B`5݂Ȏnml'*ď[L.o$nJL+wc�)@^Cd&`nePs+5�7x#ZF.,sE!X7U<rI[B\7}à( _@a9igk=zu8̼D8Bϻ[)Hǿ8p Gw[ƴeУ1-CzTVL$á]8:kb@T$o=-ʉ3W|<+ yrAP+cUG/FI Ng^a<i3yz5]?q1"RO1m)w~,{p%SP,fdB=" o 0 NE·*tɩ Z7҅tDA@u4 ً",BIHBZv(�:�!hj!Ԓ D$Q eDa,%mBUN BhXNj T7R7s]Y7TsUkT�یd kMթ%Jlpj$qIYF.GvNB7p˼L qҸ¯xcZwAIc$eD_::OG lC:g NG�uU=c.|<B;?0w3QF@GtBggs`ląf$ iՆޜd!&>]k)5ME6#$i&,g'롲IeCŢ-e^@/EiڧOOJ /pT8eDP�5P.+M׈3zʈ3@KE"E2Nm*WrMv}\zuvp~e,??xZlcwJݹ.ַlV"+ARxbIܣ[$,UZ'q VEE ]%?u ^1A2n!qY@rJb=]\W/bBU񮡊)䇔^gtZ 祔d1uaƯ*Zql Ѵgw3L t]iI鑓vΩv+Q8?ATz$2r:zU"/+J$ (I͇hs M?4ҳ$Ea[�5þ:[b1 ɱ?O Т GO#OU?˒k:;~:bǰdo3A~=A0mPI}j6�Mؤ/rv> IZ',5 }"�JʳIP_O$pKtdCozʓxqA]I|g 9ĮIfQD ss] :>-O5ݲ]$Td9RtSU CR<Q3Ų7EK*':2zP V({5rmcP˙̼3l#h!l뫒)> eX;0ԯ/VX/fk7/VNJR|)N<UV66˃'E w<Oؤqbs ʞ&w1(|bvIS)L)+oB8)xL{{aj M6O9L^[QI̅LFˊar16*MmTW[K6@.顶c`d̔(|�G,Wqi ,,Yss|#9 3Bұ󭪺JXW:H-3ˑx8%y4O5J@el  k'm<oL?mE:\WjR2%in^A`^c>X)dU]P}di4op[t$.!G4sӝdOa~$Jyϸr(- _3$\g $2 5gy^诶9BLj.M>_^"�qΠŻÒN❅qakGȷ//4 S靇~px2+U'P2#Xa~ T {λ'346۸ayM" ͻkhx.HIDMɷal-\f|0LFfcϦ[Y}Ϡ b oo5 +4=첟Z%zJpo<HʃfrS^4 N]dT;&!rpx̬ X9.B:9endstream endobj 276 0 obj << /Filter /FlateDecode /Length 2370 >> stream xrFoȁiL,STUqUR3!`�P-@)v}JnJ_oE+<n~s+.Mjw(j*f+t;|fkt*Y `8-[g8%$8ZQԭH#R2ř3+b6:~r[ Erkrv$޶x&IxZs3roa@ddt(zJsQkmRL3�RiQq EK+)(}C**+Ƃ&cg4X hVvky6R̒AL}Jܨ L@:` n#c8đ}Egvа%pԨ_a 07o `coXE"oʦ -/թzl׈g\@"/B4 tB7dLEY4%VO>+'#<,o!:z[%i"1p _eՏhW4Zkimaš�-cd⠘QO}k+7}D;AjS{EF-zBBCW%Z=˄|'` 2c_cK7#}e)HP0Zۜ29x @�aBc7sMz X`Bw1)!bf2-Ԡl JP73Ī?0(O�.Ix= { q{yBN )J{rEn.DRPBQ,+S"Qҗ)eQE*ڈeRN( h<{pnG.t{Q_J+_gE6?/4!|^UQପ3P{NΠBK@`0K/7QLPQP3O"g}U>PṍIAS/ŋΓ.^ 븭6d`;LDR)c0L<Qn.9O> 8|-d룇U⒀YǪ gS=e&Am'^y)y2hJJhuQ]]P[Э8K�=}>Tb_ e_BQBT,ww?8 xQ&:N h20|^R 0 9 c9W?"IսBHP­oSӡ^28H6hd hPXIx6$j3c5ѷqDisI*əPR2Z%3XixK3iәel57 9Ls PCɮ4))'(B_-љNćKp(|bM2D+!~Kp-: H%C]T+^L+fV/0M$⫌oPW ի^y6]_Tԫ><~͈)W0Fܩl m{ޘOAyOsE h$mnHm�}x]`�w]g'jahm�a[&hv,0h?_Эy`'TC+f4{h]AR 4! :4U\Uen~T`D=#z۶CV^_5bj5 D'\NRx`hS U@r_ @(9OE_+B7Зܷ;oyu^f] #P fIz8s`(m]61/ yqԭF5ez^Nۿt7Oh؟, SQF6=Dś�a *`73y4-$d ZP}q:5±va$-*ȫ.(;64b>ϨoH/ZظBM -0é)F3^craZKe3YSQd)&dClF䒻Sin@CA4u üIY_Y`=OTX75X79|TѢseA|<*xrch?{ 4?L,|NًB~ $<q â ҩ9]Uh5߮C2&ک(?)?Q0<ˮJ7J i/CZp[*W;,?npiendstream endobj 277 0 obj << /Filter /FlateDecode /Length 4224 >> stream xZ[o6~oȃjEfd�M>5@m#i꺿~υ4cwzV{R]>D۳o;{s/Z +m^"Bq kwO~j-DQV_{S.^<)cJ[rZ5ٖ %jE+r: 'BZjlp&D!6}!'rI}dBa`Rg{z/.ʃ~6VpnCt Pd3*2 =Rؐ[A[Cd?|?Ta$"rgݦs(dvv2 Y+-XKrY,rv]uI!kz2p[-G WI*Q V"ɚ~ju)N.Qv+K0K.P:V%W!qDQe">/pd@&*}IDB?50u @�O֗TmE㌵IK{|0(!jWz($� (AY1M7APfD'spٶ7]%tF+.XmMl4ς&!^  QȬJBV^_7"M˦b-`AU kHf\pDwq#*ipA8yӶ jOLYҔ|ޮ<EeE3gu@T Cx\`& A'awQ'oq/3 H)TqSNʈi6:hEvQ7իgxdɇ?g r2!Dا\ &Ie .a^kgY{"Ĝ͆ubE nY$Y_ ]x Ofwps8 XBo|PKb.i_W D@;à V@N{s=vffmM`Ƣf1I, 4cu?SV(gzLM`IY&G:"mJߴW]9Tumw@jMjT¹dRn=Ocak ;Y!ܖ_mBނ "77.rW UG;xʞ`w 4ė-0&d}5|Z*"j98|}as ~781b{$(IRGC5*4 }6prHVg)"A|d!,ϾhbQ;_:8<q@^8r7~ʾ L#FΌ7 g`ki t=Wm~._}t$X8?q=GG�9G�7fv!0T W{$r-ߝ܏"ŎI@t)N, ;I˦'-+$%|; 'Md$G^8�7nx . МUZ2blĜ�d?q+Ea(ӆ;94e5 W!;<]2{^.=;fDo1i/zS6m- IтBc+"t hRn7E/&.Fθ`z  @VQ݉va#!5cVzd`:$'DJUL0i>w1|o\P8Wyt = $jܨ fM7<n NlQAkAXB *ZP%Cjz3w`t4z$8%SJ, (b."0gMخeR/:`8;0Ku!N| ,9ɝ~rL%PAS)|U ※ON F r=*Q2@L 0�3]KU5<L՟i?Z-ֱŋNawP1b1098쏙MZsF`њ;44T~\n,:&mG]QySM{y_XҨXO_j")>xμ<љ1 rAZ D_")} t!8C\EUaf2q94:nWCI@wߘ.&jϬG2nH;Io_˙d!Rt!~¸Pl� $V84%+? 57gMh pصhblzwO<0#|s#Q`O$YYGҽ1NeԬk_`e.cSxY+uR{,o4NkE0G^U�]/U#͆ *�p"FGÒa98c?q!΅Ψ8Xࡉ/Ӧ`_!KP#knhyoi16q$[F72=-EEhCL,H&haScELFtʮ ^!L"WDF /pü._|v1;C,_O7/@}~?%8i^Jk}<+Uc?&> VP*dYn O\@ܢݓDki s*̔u/=<"VF^eF9ʻ's؎F7� sa/`ya]!4F,,;}(ھ4x$BpVT<P`u;%H+WiedMp*jQ5L י<�A@a }6LPD뢡PL]̘g~ HB$&/#qR ~3ؔ9ľϊS~*v%0NS;cfiX)d!U< nnc3†4PflGQeX!%QTg@(pFIPs(UFYyS^c8>t~|a5GT4�ϛtp5&4Ӏd Gjt)T! sLs΀�~רrW*n& Df1 $7up;[P-U$)njq֧L=Uk)c/aD4fU.yNnƢpʆ/yt SB"!�v}vMǨu@C/:h.)H ,{)eAQԗJo0 ^_�SnNE-`%jSa4B:KʘzXA4@牦 `z\bf X}Y'ٌȅ{~]ݔأ'}!ݤ>c:*E.N`M sy\}HйHR\̪X`1˘?mCk m"صɱۘDKG܇ߣ>ut+P+9qcrt$!jƕ<[8}\ltL8u Ec c2ʅz<Dy!uHJpCn,C#42WVQ>q$uNSq|梅@v{so0�8OaUG= }UvX#˜G81 Q#:3?tTi㪹jn=|*4|QrE ,y5@H~n;<fwjX*XL"nz,ǎqͿ ٴ?p>(Iuz)'Q&r*CƸ3WAfCl\.!]uyhʡϢѼ bYf |)Ս5|0ʹh5(fS,slD W\ѸɿP^=etXX,SE7˿u3\˫t bATVUHqKH(7,8!}GEs؛y^X7m S۷h~uB%kb~}QWd7p9զC<KcUZLC.P:J\jxxT5a舋 a*?T7endstream endobj 278 0 obj << /Filter /FlateDecode /Length 1256 >> stream xWn6}7UUN5(ME-Ŧmtq$9;$%QAm̙3gC&#*fq̰}tVEp}�2Af\pā$4pqG1Fov(SJp +Bҡy% -c>'Iqpn`l-ċH8:mH  ݅+I$GU} %XW&0IuMe3.Ҷ TD F#⤏ʚpj4/(UyZTA2`MPj\}wDyZnV9Uzpcƀp+JP(Q )ʩ`M$z81@&[XDզKǣ)W\IUFQ ٝ(\Hɀ^ЄGT WP } (R D�EPWYDX;ޤtz?Z1E'*48Kth@fq2.xEZ tzr"l>(2I})f%)*( wUWeo^)5)1&M{PrmR!.,Ϛ6[9P *DS *שi l�Km2wĤBc6vrpZmHM$ve)f ?lMc"k?/ Iwgr)m�ӵ�ۻ<+yŸs̄~~B|NlI=AgmަVͼCT׻N۪v&]f ,a.~ҥ>K; =šX̮8պi05:YشHj>xF^̿:+GSdd",<ͿlEQ(|0/8 p>3z8 9_S7b9oF$b19'B~!b<H|dO"-f]=nz¥|/LvR~w<'m91%-~gxvEr|y2h0lǭ X) M]v~ʘElh[s3c c%G zLD^q>N$tmpMma7*!=X&NŮʆ+`#I27{]x\hju=hn~wAPZ$QxYy83SZP2LŞIs?]?k͇ endstream endobj 279 0 obj << /Filter /FlateDecode /Length 1496 >> stream xYKsF 7S}1dim2=m3H=X.Ľ؊;:hEb_�|�!)$>{baiVd9'6U<uS �)6YngI5_r !ǑJX Vy;_HlMEVsa\s޻<F)>a]�վPm>k]@$xX ,O,$O,xKZJYY]4m ?=�v; zثsg m蝒ܰ&LRxy@nr8io,W_7'+'s~tH^޲yn:ݻ)+Ƹ,�S edp�נJ@RN`yjQq R㪧WU(D9 Jڦ_$HZYs-z`x0-{+e�8#U[Tj{.Mo莞mEΈT8} BNWi᭗lP%^~IA "C"(Y==I9ڧN:ڞDT5;mh5 lGQlBTVsjاM@1Zud4GI:4k|EĮ%RQzik2 �pDQaF&H5@Œʨ:ϦwP5y1(CLk"/JgV!�2hэReuNFa@A} X yiѮ:#cyJs 09}8 !] xFb#T &T9iVf/MA. m4o9b1zEߴYb CD.�`=! ViU|mJ"'>Y I=”Dnjx I* 1,9ILwн"XRQ8-?bLxY:n[òXJJ|=UcJ Y㪄qU_&X`:˚P|wNvuW1⤣LϊjS]lӥY1 GUIf?2wIEAy4(;Jy6fD0=JuyIq,.4dIYlh!|<dB<Ʒ X�e?ձoi>=^Hp:; 7/q(ޱ'|4fR:?ty�Sm'!" Ms74RE8sU-+ky=yC`1X<&`Eh�qj70r:v]'0b1`=T#98I#�~My}{8+[m{cu"V}X#t$лГ�vo03i9gޙr@o%x J+v5L)Oηo�<fѐ0vZ2=<[?<endstream endobj 280 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3825 >> stream xmW TSgھ!KUTbj^~jŶ3]lw@&-lB@@=� ^".ui8j3n3˩:79=gfܓ|y}D`�!Dl^goV)! 0V419bҟB41)Ω0o2LBKyE+sSRsB#rRBK SsRRS"A;9yEI%ɥUi;vfe/|eQb#Vk9Zb@l$^$6"#he"XFK,"#V+UD!&I"AMAR�`I zStL#4Cd 'OlbĦIMʜt3_9N"Wᄉ9V`D5ۜ{ l@OC ~]4_Wy+ WӨw(P.ҕl^+l]D&!Ka(׀d_ 7^poDJvwX%-G/DC"<c~oOGB (EoUFDXHy+Bc{^ h!8}q<2l9/w=4qNyq_Segq.mD4[$:n:{`]E#%u 3fd)P*Ji.AwOp0Cp@IH{<oE(-v/<g:S06Z)SmR#ZG+Y5Z_=qU**Zгmkhlѿ꿉 }=u=v.Tʒ<?*x{}Cz!2>X.뇡adZ(BG5yǞ!1tQ4x޺ۙQ,|$DFh{W  j{yijPQ*8@/H|Ϳ=N_}̇>pC4ó0TWRZ|%sl;q50 'U2pJS/L߾'@uѷ6P36s-yV='?ihaAfN6ZMhμI9u֚Ҋ"b*\f.3!:L=K>dϖ5;'3K׫Q +:%)7j17\vc96;މ,)B~:SHޒP&~w(.{ܓxZu.\gT )MJTAT7lQ3)φu#h (|i+Wڕ|EwCݭgMdXNyY$LSk"Y;ݮaҬH^$f.b   {FJ0v'A�G=*ͷV"Q]s{aE[Yى:Q]}WIimMfK3m"- ճVa._� YpjAFSH57KKʶ$Uk 1C3!tT}atpR:<~@zp͗xn'Ga Or<-EN]uoaM䦡̑GTYm~q@ u;"Ɉ>T/p+<ޮ&(<-q3</v2%8A?oG(3Y4Zx&hjAZ rE!2XˑYVA/ePœz幩B:ƎC!Ra#ntkn36NceT^U-L#1^+wHa|ʁMNDi1L'&C3` ހ�~>6$32iSrvӕ(ɺZ;qypRVNu6G^eN~WOI YʓXt0eWTE[׬[Tj..'rޢt&K,Fr:t7.{s0cqf5 {M]nbٌTdRPUX]/=OJط@R^Rb:5Z<x)5kִMe4f.._ev[=rNu]-SKS[U oD7!vutA2cEu6JM~~kSvvhs/Q4�")5Ry%+*Z+֏9%ǩk a,:֤q-'NQ҇5Wi[epЧ>(WT̰ɒ#+QQK;km[ w&S>gMzS5Zmfs>f?2҅LMٱeKH*4M~lvÒ^A[BE8O,F 66ήOʋA14W /cԙvXKr'o.GAatv6w>y:.[Qx%9!:F;^@ߒXwht2eU5<Q*tuYPǨ P>GB<ڷ=PՓ?W t@@0*e]{sjSP xa^+^�ePeBì2 _u~9P{Άn֠FjhmVongvFF"1σGRݜfO+祶l/bMO:dF{:.Ԉ䩟QҰw]UGKz;!QS+6D˝-Ly]D!/p\:`fLW<ֽ0|ͅ?]ڱG;߄#'ݗ팕;+U䀗ݺq g첺\O:.Eѵu+ݑuQ^oHKDZRNޞ'+3lC~c_Xp"0 }t7Kّ@|{._@ɭBJ $Kr̃|CgF$7x%㫎J| cW⛹d]ӱCvecrGMtV(Hkd tS/tStَE^)݆H!mNo!a2eYyi%K] 9/ԱGÎ]#7baBg k s3CG>䢕TN{c㛤R:jneBtQQ(T3Wk֠EhqS0C( H߭}s,mҼ﯏]njڠEto4Q*I6mLATSOO;=eLmM)Lcz;CA:&K<_CJ<&Odg (enh=bd+y�SĴ/?)ǘ~K'B[ܓnd<' Bh<y裗YK/8x¾?ba܌ 3ߒ A/Y(^7~V.w.,�<YʓQjC6_~K<Wr &,gҐ@ܓ2WНWQy!7dzXLϦaխu#N0]<qIZ ̖MPJfg;3h=AzO)U͸u0[FDyzaNzU:Z{Ս5Nfq78Fı †% Qendstream endobj 281 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4768 >> stream xuW XSg>9kXmuW(aM ;ɗMBbĂV:ZNej[qfN/N\y撇|}0#G0`Te;g͜9tׄ</2y11>#_CX㋣0#I i)7&"S'.KM\(ۇ ü4qYԴ̈d"DO6sޜ=g1$f32le &Lev2˘]rf7Y`V15Zf3Ya60M3c8F `F1^k _M#&#㽑)#z. cGmon~e--^6?>s}|[k֘1֏u.6U#rcp+N^HF'**[%ZEo)lԾS[o7Ӥs[EEcB\n^ tХ*2ȆedKށl6M ic6dIϯ#Nҧpy8?M!/,rOt 1'JNVxi%7>)}{KH'8,lMtn) k`~|=/GLPb>uρUN?x'_>~B %Ե{�8=*42z1g/~T'^*9dz<q{6c 7qШ+ꂍ;x%abQ(zl-*\5 zҫ>˥x ی5SЎЊ<ε[ا O^Î@l FƟ(ŋA|n]8xkH9 `ޢ(25Ы=f G' r8_xŵ&Gd+(qGf [g#ŀ3nw+WlJ+Qrrq$VYu,s3_sŬ™r-rFcˮ+S(jxoFV`Uʦ1Tx%7c6`'pLdFGJu\s=%Ґ W6q }9}q(@+[BrbwKsM$ .K2B!)[k1+nqu{zW7hO? ?|F+(fc×穲 $@GGKKǙm-!Hx#4sNr_D)%E&Lx ='bLKtH-RFm n"T3WYEA7PZ>Xךխ_V% ,'#p54:\bh+|˕imy!O\/3gf3&oE0_N YG^Eƈ懓^Gs?&vk;ٓ*P)QAXS8I` mx G=WMzS:Ot[3>lyt65őɜL[oeԜu??PPqd0Xj: 뺋{ +NAkHzCߓh z?z@IeI7jYնhKuIUǽ85(o֗^�Iޑr G+kRVů#,|$qR'[2+ِy);nؗM׎0:2R\!j4?74Eʽ WDG  d]9}|ؔ+ɭ>+^\#>Q<p8zi욉b$Gkj<n +Dӹ;ևj[er(3[T?9-4C 67WU5iGC;C6%A&O%'('lVX>O+YC==l9otREkSks^9al(]q~*qtRtjPw3s+Jp܌ɫ;sbe<1(C%"HMG~Sj)J{su{i;u$>q$%('8G4Nu:_Fd漖m'YYRJFS'm_D�Qa \yarǁQmgbG8 ~/kk{MzkdԖ'QqXy C#8MCi<A8Ƕ$w;kK`atm]_kpj-;_o,k RCrTnZCߺz]Q7 aic>DqW5T{m*v[d*_y5�'{ݸ~SR�>M^&qh|*nzug5'9ZIؕfA MTg}lti :43tW#~'z'9\c$&GAM^QԼ}تˀڪJ%P,q]j;ŝNR/eˡP |GN. ];K<M Gpc87(٘$ lA 6'OY`S]񰁝3UteH¬䰠 ڎM9(ȏKcwڋéNvwr qfYe'>n퐄ӱl"ߋ}pMhO5$>PmdDbtz>d#"u_s`#+Gdp(#)?L^P(Vx[\T^OHA$ÿƛ[7rPf:{n>, E"6ԚƆڪظTFQՀƬ} 9Խ0kvUdNtW̞mE囧R(G;i;1 !.#]u@AԮ9KdvW0lO>7z]dh$8s1mE9jkaetF^$ܗq,~pyg/rY:JúZ>wU:7BHx%R#{^*;sH_wBwN zqhqx> 4ls""b0ş'9yl?mķ =VMouNl@a2ҟ�bS* ᣪ'zjNi:#p[%ٔZU (/n^o>;[Wؔ=S-leqIpv=+OT*ũZFvGB8Аa<Q<LZA>E1 {WnFmJ+K|qejxa#).*%1nWw~xإ RxOzH.;whhmQQ{:Y).G98[d$\Nm]Û8S)w^ c4i]8gt{@ۯdgMiERpsq*eehk,;K&mzL"#<]ROhWCK띫Mf} /t,{"2n,,eǷӖے<Lճ&:~3u卅a5̓mch*=B#/y[BD;?, QK #n'tz@./}/RE3u|qɊ-<|M)3$fCB 777;vȀx6@*kC5aڽ` :՗]ƣ'KY.|qu >0UCD"uMr[\<-[Q,T.;gq2BNv]n*SO~{5tT* (,Ԫ Os-0Sj";�)t`zvqsߒ/%u=m= ]N4Mg/3)zfU"ۘfp/[3ϏWxjRgSBbJ \Wq]'t'[ݿ?(#p'vzaq=Ŗf7S_>Oh@#brX{GZcMj8]~ RA;a/R9S]K ]NϞ y~1ZFр�/x OIvuǴМ0w$/|Δ}q).냙]7Uo._{ D!Kq<פk6×;ZJm`R)bCjڤ6(@r uu^;=xm(,sZ,WFZ }L1 ƱT{4OCJwv-ޘx\&DD$D,m;'VD;[;8`95*/,PeI+BRSMOYr0\UG H3®&,tlDSN)O*,LB(8pnCo.--"oׇh54~V i ,%[.mb#[b-斺�k`8EY"A] K][lZƒ שb/%ޣ�Sendstream endobj 282 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 9963 >> stream xzxWfhXQ,JFBMJ-tcz `c[mْ\Իteur,wB' IHۤ##?Xw4܉ w#"""z<q1-<82{ o֌gߍK~} ~Y$F'ED<=lvzZ(;Q8$&=!Q(<=mHĚxkN¹YJ,ٺ87>&/aIb춥I˶/O^2uuښQl^~Nxr&O:/xѝA1%&K)2b*1XN 'V/+Ub5I%fulb41C'$sq<eb> O,$^%D"D,!^#b:N#.3ēDa"Sx@ $ ADOћE%i#zk S!纯~G:+UL'꣞֞m墳}_Fk߯'<y/*&}v,S˟yãK˹|0pO-d<`gO;w<wrH!i>CCs_a^5 /_rb7/p9*<:ztؕA<n]&,!.(hh!?DŦf౻no`u"@A X6ub',)J0 �ڐ BCx-=u\~9d@ bdz=M]c\]L]op`w!>782o0Gn][/G5gsdcqՑ[͛i|q(žekEֻߟs̍Lt.Bȴ5`: M{nK-X}SNyh}8{@.B @Pq1[ceɄ<8^ P|E {KDŢ`BubuBhצsj(W BF rg툽7e_kzEYH;-`k%ZZ]RSSls*4|EH%tL#UӏN9,ɮ֊n?^MbN ,*1 Y$Q)|Y?F[3IY R= )d4^$٢ s堿A!8^n~[s@wK$AϢ8љhް| Mg<x;, A}_@A6mG\b;sb@c'%PZz"T*$& %,@zA�`;{ )4f5͆Ar {7 7] b  SmEl0 =E&G #> 5G&xtKᓂ| FEDχ{C|֦=<88A]rw~|m a2aH3J5 BllHիj2 KN;čRUSnJ+,@9B,+ qP#÷GSx4._(&h%ހoAϐ,v`vkts -d.7.:_@|*u**pxxI:nt4LW*G#/â[5LuF,2) \beZx8j I;��}G=Wښ{J:NMXq !բ<H3cRG/:c3:ֿ&z uv8J$dYN9x2sd9 B2ܱhX<~*5* v}Ͷ;۠:V)!dioظqӛ%ؿϳ~~~Bq{A!Uiv^!v{Y~ȦJHpx.g;pϷ|̔GGB$HdJZ�ε'p* bGe<2$=I5 \d0W5ބW"p,(6i522=k4)6Ʌ'4/PX;{lp3/ >ZW} =(* boHP* ,*|EzXj/fuLI:8߁o#ުЋ##xEf\LS,k͠X/[2Ra۾JTc9zXMJa@xjz*J"\" RqB'C,JͰ24U9٬lͤTDZ.ί2PueWRc*}k)y<@KAM 2 DtkThr=llOpִ#aGmsƚ*xRxF9xaX Rfз�D-YnhtZzF*`B+ea@R[+3=wϯ?S: k{;1Amx=6nLE)atiUBl> /wJ9uzZdC( 3t'29OؚÌiuxp:CNच !8R ML(pQP_O6738໊o\lo9Yunq5(!%a*ڜĆ>yq/.Vj 5hz-/j 1EN{)r(c$Q\@4}8"3WFHGR RJy{�IݳV! mVM_\}i/ p(BCa UlՑ;W@B䖌<X22>ِD03η!�]cC*tȝMNڠ [X|tr;\Y L4sPRh= R,2AMI~:=N2 y{dJu/KEeߒq93qk+Eg=;u]vYm5!RsXKu&{ %+ EwVC& qm$V*P~&N0jm:^ISQWRV&M\.ʆ{Rѥ"NbKBQ`$|6^gxjH=ZD1n󖪖,j+69թ|(?ygEt6[dStEXAtZTIkG@(8'8zn`n$Mi1)E|eGˏV9E82.-[SlMiS?(RrV-Xket̏FE ^~7i0~@edpK}ZhjʨYsuy<mZSKssMխ"/j)5pC khv:~ )ªsp#y5[Ip;-ulh-5Z2CoT#|Է㎾TGPS][ef0 '+(kÖ<;hmˠ[OTʠ4Eh1(./.zr,$}Ż8UnENtmCO%Y@u%[r~%F!܂�ס=K繇{P!*d˕<Ro0Ə0U ^!6[NӮ|yewl 8.VVJǵ\Fi4FCcy!2GUVTQ\TX+,.,<n̨L ʅ\ީZ*_a7l y "u=QrM&&N-*+Bm%<z bAjf^V-cdUjv{ (~ҙp) .fd R2Σ@4G+T!, a7Ԛ„<xKGcXߒM(X5T:kN@EMf͸+l5"G"E�}&KR *bozM=?"~ci>m܏Y5N%PZJH̋R q( ˭^PKLT@s,`{SWͷ[+p[d%VU :^˜6՝Xg?�2C"ňpp0x5@d (ϩ/Rumb`.O#r awcpZ:Qfm2)DrvP.V+hS <ug2a7!a'+0V):.-X,a]쑸$.hUȦ*{U>\v.uJeGqSu2yge"CEU(i$VX{tz Gq\hn vk ;1V#YQߗScQ?NR9N,v~HUI*rk2w#I+%dsaόe\^7 F<#;y I".y$?ͺ~H[,b~Ҿ*g^_,\')$X'؀LET{fpmxrmWuj|s~Sgl8.0qj$'I`?4A N3!/c?diޣ${:oL3"aw(],}.GÓ?UjtA@YY+nĭӀqKQh5`H̨g|MY*9w} mg}6?*ꇯU%QXn0p5 7I Rhd)p\ HAp!ڈ^oBɏ� zqm06fk.X&1keI00¾X× r~'C?F^q?D7Yc3ӅRqɶ(7.Y!Fw\8)2\t^ r̊@uyq Dwczx�[_6ӿKY\L~턽ւC/P"ct5}Ł!ԔZ Y' 5$$c(-9nzR4�$8ƣwLnPo6PoBw7-,J @e'->gEb}Xj,dMEuY `լ@Nd%E%5"d(6 3h\z+EYJ4mq)LMD+_^J(p\}c􇬳ߨY0|}w&lV͔3<ZZa ]D~ _ucV8Ӽ/P?"]YTFZ$km;?�ȥLBh-("zrM&l GJZeK=-!3` g'G(1xuFRB "ޤ|cm]њ[GϛdW5?Lb.ˑ ؊jzޣfŜaH:gQZgo#ί 9+G.֟zb7!<N':S^]sv{:׺FO+s9-9mS|U^>6Ya+wxr1=ڙgy>@wƺ=xr<'g7S?Ϳ;"U6P==WY^7J8BD1P̪ꄁt}h2uFAz869x\$rξuP|WO7\[|ô!>P]8|K^(RcFn-n7NS#U5j u5b<~y߉y ],0.)5cI/t6{nIzvʤ(h]Zv A.wowq\KЍ'ʹztTRu,e83xa];9K}a\yNNvz%|ҺPAVM-Hfx] BX ]L[WjAYIcPu t~T1  u6!2B٬4m *wy>7?H8.9PPbm ߕ*–\\Fvv{Q dO)Kې!e 2ӄT8k܁9C{d{а{I8 P *(xYU|r)K#|e.HheyA>n,Iw6?mtbHIGk @ek=$ 'b\UEVH^8O珠a+\®Í;;.? \|\JvWqGo%LYcИd4Q M\vE49U&۱FoAf;sPuJș-5?xxv~9炍4RIiZgFYifԘՔ Če9W6E`I8bq>=R2gY`xϢeѲ3h]fY*ZlCp80eu[]n,YlG^DA}vgpZeŠ X0$=c wU8wl3iM:<gEXU24&es< ZFԟ�Rr/ph*LXƪr iT)u2.ۦBPx+ݭ%efBd!rVx"m 1<" {+ٗrNޢ=eכ&0R^T|~j}+M\SS\by9ҵ- (:JWV(iť&܆hYaPXvMA= BF r-"yEpP,1{\;gJ(UT@vGc7L-elץ"5Ϳ/$#2A%"Y Ou {kPwQr_0Sh6R A2D+%4ApGKEG깥7R9gRJ hޒw3G\ߡUI4pl£)í,viv;Kv)TkAjYF_"V"5_PQtUhwZ3JYoĢVg58h+[jts߃kp*jupc[rX} 7n]p,3 %ƸPٙ dzK5 \{ےWb_ǣQ:@`umwe 낞.4EdX BO!uC}p9]ז,cx?X[JQ9K˳�f!SΌnS)(͂UN 0k G"݇q[_W'>6 x/YlZm1GaF:,@Hĭ¥ښ{翺 `${9z'uw}Ue};:2P\å`n9G8[#9MԩuœKxٺNuIivd_zl4/J?&`6*ӱsCaCG7+%<ת/=-R955U!QqBp`(,g_fX p`8Vi -`%zf�|}J,k"ϤUjhh4T|cؐ q1LxDvEERџ>8̹۵O`ĜSuu92Gaߟb9܇f=ؔ=kȀ. .pbgj,W/P | {p?/[ܩ)j=^N6ah3uoy5<\;KuR^xz}D/7Q�E TXʸ8AZQh-n)/;Kl٩|-'ž(PY=_]~ϗ~T| 3 ܱtR]}Ke;h '@eH23+$5eMbQhCIp1|cȂφ=Qe syԋ!/ {aAй|ꍈW3@=][7}/9)(kanv@U b1kL{kv<KVQeLdCU\iT!9 `XG=~8`p c"geΙ&SJ/7ux|¥tw~4wF2&fȌkl^a߱mǛmv[Z]&oa=x4c}7yz$QHyfi٦q z2Euڷ6}g]|n2#V$xWv-U,Ug<5E8CO:;~)}_iL ~D۩b ٜ$0?U@=+l7JmACWL&Ko?`4NtxֿV}ri)0t馇:RS'.Y8 uU*s,:~.{u4{878}Y4>v\|XW%c.QS1兯A3` oƜvy.L'Sk-s{UI%u7NT뻯[a;5m~.r)6R?g&|Lo*?>l&t>&ـh#xx;>B>X4�OP_+cx/iiglRд}x/τZVH3qFb�D" -}4 <6g'iFifR1k/9y_2LAw|y?aDk/c%J [:@ NUnt/ؼJy/�Nn `0'%Vަ4AK0T|?EUW7Կ+�MHAPG*,,,Q0űpJf3~+I8< r41L>I^Tt) eWd ]ז[#˭S0 7C˕j%: d^YIQaK4WT讒._50ߧ(\)Zmvp՛B_d6gdx5",])+DNP  :w]Y[;q_,Ie sI32)%Pf-/(WSŸTǷ]Qj?<�{ݷt>ƒ eن's iiA_,dj[E�(jLvધdRxU]] -׃̒]J>iqw7h~x"(~12Apl dPqP}uU}| 2v vR8?ץ7a~+Q+<W*!o+NZxXգ ,~T �Bl*SU]SUY,9KCKg:k;E m"qwt.&7ֆُ- ]˖IZGKw,)^p R~f}yԧ uJQf dW|w7˺W!)0p|7Jdg|]u1<\imfYNu}ꊭiL`#Y!f9,5 ل`c;Ǩ8y),2w/Q[Qi6_@'LG=!gAWB�CC^-$ [eendstream endobj 283 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 9928 >> stream xzxպ(qK :R-( EA ҫ4  %{^^HB &uG"z<NJkssfCs<Y3k}}~=^ _]ѣGs~(Ȋۯy7奇~]r/ hi~Xa=Z^Z!.]f1l"IE?ðE/-R>iW ^f̒-}sNuoXqaɢM7^d#W-{Z<#c7x'<>q|j0 {c!|1l8-žcObcOaKl8 c`#4l*6+Ʀcab3簙l<6{&ab~K}X.B=�,!ahzaXl["~|0kr=Nf?]sB֜9Ie׿.}C}{{ߟq׹>j/<;kyy o|hÃ):HSLӠI =m<bpǐC؟_C/><I>Yէ [<c8=u䜑ѣ_{3-EB8>~DKEH\%U 5p̮: P1_י[|z (Tbu4rY?:BF <oj/$K @/2TcGlbG#j$qYpo_ssxsk)J-Ji]pQW|D\%rH֢ 9ĦnR)4Id\3K|$* j:3dɐ7QDr=l%-;R .]TT[xkeSƳuit'i%:sln/�#BdN9 !_,S *! jbt�xztor>1M% !)\.*DA~8.^ȳ5%jFIfy5Z\r JIEⲽ4;ca_=4 n S0Uv-G1tJUbj| biu69΂#uoodϝI\VH3A醂GDAՑo%M+W _/Z`$G.,te"T\6榌)Q*yXߕ -Y<z 0v6a/@q{7;#j`_ހdX `'?|_>/1YɹҭhRiw*kWWvzT}ކT0v`×IptTUFFpAB@qr8 |GqĹh!{4'6,+7I"V<wS!้6EBOER](AP&O ҋmvJ� qBIF<K_ȂON-~gό"yЩ?]`5f??r 쿜B%! % r�G؇nGw p ™] (pCV|I!ײ SC.tE:~oؒX|_}XL2 'K$i A}mĊ|Gle6{{ݎ 8 َ]<bJ9wYsׁ\ʽ|o 2.!2-*Q(B>z+?MQ; �5O"/IZ"6,F`1( `0뀞,шs }5 YJ$R=jWahF:HD67 SQw RSp4UD&PIbV( hP]aScpjJ" pZpa(lM e|% yTC\V~2iX*>dE _@ԏdFђ(gz T>!3||tf(~>]|GN|WԠG񒈡~uutwӘ_S;s?Hh?L|g S* $V2 W*#1X*86G<"ĘCj,+c$QB5 ġ;Qv3)?>N3"1s4pZH:KİY *DS%CqAzŗç~sSǘd9 {^uͳoPPy"|UB=~Cb5 M8;yv ;?Ͼ 1^�ߺN=DYpx|驼xJ%QC )' /&]"Pi=P~h*8"50/fS,. 0]^@#b(![$:ܨ\)aF$C`{t /H+8 =T R#Xr%;{QMl!6s!-#D the[D 1\G$ki"59=�v}m$%!z?E;$R4JITP[.)OXP:oݛ 누1ZF8B+@j(z8ӊT2qds>R-r"\N< F*iHHYTWߺYTQAG g1AN \WPJ(T˹j<*hctM]4ilˋJou xD,c}[n' E<E%r?LJS9[QN5/<� %BZpq]3ԃ�Rc-prٵLDȓLJݨp"V'R�1ZPAW,RiV/GN BAH`nwsӹǺe] '𢶸/[P3vSZV M;hd7el9Hb5 "c |7%\>0,)kml >{xYhV良\VGmk#n ωT(j#�%NmY8ApHѕ0}F3QHCtA x Whq)}+>W|n9CFBX.3 mQ@z(b*H7[2.]r`+q'cjƩUp5 w jw+/Gɮ0 |�kŜi10z\ j\z1O(l6jʇ6zmǹ :ӻM؛b?K=Dz$ >e褟rBx"՞zD4WCLDBՆ.JV&( 7'!xxD>/޵V%( %yzF M@0]H#L(|շ x*$3Cl  @="@Mlڅ(\aRT1:ݛ%!\ǃXU+ F.Cz$3OWJVtH E3YgBB&ʻ+m7{X5]:mBMyv[t@SԒe�=I*ST V..R#b;hq6Z,fkMRQ2Vqr5=HⅠ7{ JCJEʠ*2z�Lf0ed<ot*rNYV^f{Ͽxl& B`r䓞ygDmmw`,iYgVqX"+€LYAt |hL gvll Y}%s @pnu%] &/؃5dQV\8QuyldaaIcҘ5d-njTo5ȏHHɭeW#:Iw>0'ŕxw^xnq7-Эh9x,nke. rXKM"6F\w? DRh˙%-kB5{=s\e!8B>Clj(A~߳C>l`-RR`_|vRNPe  W,K&G ")~ea`+ӗ.N�j ȩsϜyS|s ھj lhe8Jy`I{XbKe G bGIjԕHnꜶiQ@k5$KSn3nEz"3ȐDne: TV!a<u-?QYgq|1i|FK8>}ŏYO%pS0$fpSbf^&-y3{; `|OH_M8T섚BS 0:7q‡sQ۶ݻm߀IMCúQEGAdlB|Fo6`?gko&vY2]6 '> ^lXa*F\hU\շ[wԴw `.Ro3.g""~kbWTQ}zrՊnYw_sø0:D28~ho|wBU9i" 1h8Z(幵ݩY)hʐ+n(9@!) w{WOp* M2&4)B XiJQwV|N9~4|S|R)Sa<3^\ ȱ/^* U1b$ͨě�āJAVTdp::}Dۤy!h-Ƅyegk7Z<b %IsMt7d"ohxfyd a<5^& X_TU.Q�ցu JƘDg;!MqKIdiN;x4&L jWy7нB9{6k>6rnuPJ.SKv($(ר;:pQHRڬ#K6md>%j[6o![O.\\&fPn4.Lh@SȖ` 7`D*1ͪꀎ!@!bYo惻 \Qf$oPϹ{LXsAFgj)3m84$.TBz$WQ#R-onM7IɖR̈́>Nf[gS>;xG6W䏟Mm`fԱ|̎^?3B*L0T $蓚h-bG>DSϰK[gIwZr5glk rjED $6n #|s#DbUL{&q_-Mv/@ 4V8\*2~ܰace(D]?Iاnd !.N].IhAo ˌ1Qbaז/G BDo/$c2NcݏYx "ˎ2| "qZijwT/Tmv7qsBb oUKWd3:[J4p8I"M$>Gq\+Ȍ;vXJ�ōQGa..W(e#aTwe-@ << ΞA`m'h1sHk#a2>!28E�Aic/T׋@ Qcԁ:^'!H$r.a;dD@4(3 ̈6Łe={l"<f"[zFWٰ>Z qF[m("s &qSH5BnFV'\NԲ7&hб8ѺW WLSG3JmD°&[v³rn9 \?.2?y[DVz%}ˑ5uMuwE c#aO2)n">MKaiq�rXaErBODZ4/Ʈ]/Tx,/%jy;Ǹ/QB˼K\cc%rKNm?H"(VH40?'4dz vK}}ͱS!!2q1T{B…|_Np2-x k,cOw›͆<Kɳy-KPxLNgX¥|uD~0"ʂodzv;X*K5̠Ȃ<g,?Wo,Iی wqSkC}zQ&< Ըf%*n>4i93DL"_r}-aJ `s nz& ,d fA3Oa)DM*Ix.č"8Rf`�F|kg¤ CwxSBRUju̠)U&~KGwDV!ZokxH"^-FcTQW~ syt!(!7V쥷"MohDWg| 2 #** =}9)guz^>],t@Q&/Ujb*i@xLx";߁:�T"P9֚kyQ.X6 d #ep2w!,` i-EZ?{$y߇N$�M} LS/m\ƌLXR^ pm6x-u/ KX IaHgDkQ'OU x b$N'3l^@1@MVkˆ3FdC?.^<8j"FxNRLv.]FvhLx7ƍ *5!�~TJS%Ws@*fdOh*cTKחT+`MTL@PkݝGE7A "9ǣ'~tfВQ=mG[7YE+cZ0xӏ~jw=|;'_>x٬lVyTTOԇT$A!쫏4�գiM+6U.+ʓ+DZPM'k4Jؾi#hXj(K.wӼUeRdQ,%vĤSjm1=珮7$DY+̫H&]F"0#V>%pIml_Z Jԇ25`6ɢ,*kw*֠,~Gxb[CsrU͛tRXE$ ©^]7jSWo"bv�׋f%1~_<"8 ۟yO׊wf GN 6cT+[&cphR*0BۅC8b ef.rm[[ڏ~ bpk'@f$`D)/:]yF 3VŸs؟ZSpL*.X4;.o2n)}2T aC �yiϼdr`31:>d8^U)=;롃~,Zf=K}N~=Uu@TɒXS[bgGm8>c`+o f)d;?ǻ&?#p:[ 'Sa:!ΩXDH5aQE⏂&IK-c.r#h$)v=\_V1Kn^wq^#ݨͥ@cmb4 b)t;b&O ?A}rq͂Dpi ÿ"gk LZ[W87?yN8$J{m0 _}eoAI}:vfO|sN:'`__e<Gt?{I.ZKLi3v}@Y]( >i;~L\7'OظpAAi]7"By䫓m ރ'k(mEuu}oX ͖]QMPۏ[ُppEAwƃp Vt<ꌭZd+T^~z~,rI:wCBSG`'S?@L<lAjQ#qi bQKpp2| XgSYlףGBH`wNRG@(hm@Ӵkf|̸{s`2>GNƤŅRHRƝH;33R+uW_:"E=!["a_ɰ@39x25T;*ܹbc ZV L㛺5kI>ŖeܝNT#rOr[lS'{ؿɻ'߅=R0l(O5 F>wYu&\*L$[Ls-Jpi< LKUBIҞڠ IImgI]$ėOߓ^B{eczތZ!\J=kZ:]\c6W$-4/Y& MP(SEt/<Ԛi^P-ђsz:35E~,7:BW'Cϸ +i5J$J\o}𕃗< 7saeHPi*uj@9@Si~m@T) ~5A@"f 'nwhnWMsPD rtZҶDi?'2¶g濱kDSuɔg'$HS7nW*in~/c\?]x@g@l6ݱ(8K_ƗpF.2\c5y+n(d/8mGfż2,:uiaE WO&u(=yvnlmxkmPo)p+ NB OR;a'3irNgnrCM�1#Snp#$ѕI|pH...;{%zFtː) #!;? X@XQGϪ\*TT) K&1)]G&Vʔj|&}";1z9CKe0�S~7r>_bfmMEZul(N;5PM mHM4(^G`G lc(�jF+b~/pZ )8Zͻփl~t#Gd2=:v_=бZPqLm1`sKgg R , u}OZ?8h|uUᓆ(ɵwrsnNv2xW)|xJLPL^Y/k %*5U*e<OW=M(-HK rd<KmTIjAPkp'"t�;jqE|X84U•HL{P^!1VD7DxT vX}%bR@ki%z0[ADefOȻ>>KM* pJi9v,.63_Kش.E�8ڐdFj)[AdI 'O!_pY2- C#qOQ wQ_b!<%JWKO|8+r?>ԇܷ1Cendstream endobj 284 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3286 >> stream xypg%!$ҬLeHH $0d2@bpml۠òlY-VKou_>d|`s8#$@fS)b0N2>9T'VVT<}ɓx|>ju.~\y3C\3ƶLy7}@ 9ș܏DmOڙqϗW `*N ,Y<7 .(ˊ e Ui 9LyTR:Z~PZ\yp seMJZRR.S/J' }i@.UT$ubRD(PT/)-+?$<,xy6vvVZz LOpCxOOZ4鯂KWMrYX;ScDôo<-g93d3 ; i~F/Zv> 1x�` J&~UٜYPuq9NsX00N8ʦIOca'CScS(-毜ɥg`F[l; Appm\S٫xCDbv*@5c]ZG0 tPx:PݴAi;ȡ^31$ �snz ?bt4O7~b['+\L1=J~"9Eq'AD ^\.Ž͍ ; C/rөܱUyio1ckDk|s13N�b*:n օ}CԽGnMv(SXqkۀX9`-4x@|{a)GXDʀ%3&s3mM̼$?S +2hCmQmЁ: tW0$^ZMQaY{o@z=S7)6j4e& p&!gzFLi+z=ؓFh-ݰPeo*/b'8ݿ`uI|>\3_ f)e:l`'L'�,~H i kJ+a\yB4| l밄4ae ;zm؈Gk UCqyLLŽkKuMl>f젂*sXXL>94x'Ga° tfHPWAQK&[/Jfͺ ypN b.~) cT'- iMEТ~4c&"2>A_֋F2]̈Ө rYd~&/L5P{ѿ! --wb)iAp}6-h-$};L`3:h?kkeՆV:y,Ofڲaabd}Yt5U+ OcvA#UY@7 Jdoz؝#-~vo6 F)CIT\x(|<Dpɐ"tècÄI v�_=:<H`tlmTx;wE/yHkVhɭj%TdWl܆HҭRyuK@ĬMHMuTn =ƍJ|v]i>` VSd36J[N8k �0FvNŵ]IO2xA+AFyB`O{Rg$Va\aVX{UyobTQ+ bPߎ%l,Mn@'~_) Y&M|Yz;N5,ZQ&6jp"?Ɠ#pT;w*w_)~+I=:dZ|ή3Q;Zݷ{sg~Ь?>y,^ _B6CkO|}J?y.F栒Lxl(;ZXAG`#6q $~3hdm{1qss;YWS~z+N"aIo4�$&&"j^ݷ@vaȝ0b[VSQ3,1lT9Pl? >jupcWbFJ6N`};<*CЫآwԘӥ zX<[w44%!^Q^&粀m@·Z �cG34};Ed\~$ ]͑랐66 @\f(:BkH;@Z)i ܓJa~qpCJv6fHhB5*S\8#.Wwң[#Wh7L ށYOsްbUoj Edw;7we<?~w[)? `-_2XbwO;͚:+YЊg@KORM'caщkwSD?b�M%T E&mml$=:p4| w+y-j2U ]9TKf>牴\` |a E˂̳x}R%UIՑږ#m$E5vmzC4NoL&}\U,:s_R$<"x.1{ӣ /"N$E#wB{oÍt:O}-30 { E:ۚdT˳ v肽QWrEmڎEtp:BvlZp8hc14Nѽ=_e"Iäqc3 ,*1%$ I%Mu0Wb_R4MRJe6 ٴ'##cA n*ꭔҦ?:4~Co߷tny[ a:\عT1MjZFNnK3ZV'h#/.W+DPa Qz[M4Nx@6:*[eJ̭Jf 0&\apjz'/NLKyrrx_endstream endobj 285 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1147 >> stream xM}Lwǟ/O>7x$.d-@Ǜoe۰jGZ* R'U|_6CdQ34 {_Y.r߻M)dML^ZUdߤ(TLnvbSV V|paK,bdikUSk^Eel6% sT>]ȱlVh7,F EJMZ!in̘?p-U) RYXk2jL ]XiES|^n M6SHQTސ`qR2MQTfRSQT4{)央}Y^6*O=S ⾻rq`=f#FX[7C&d6 fɸ8p_s~gI m=O#UoI V@68]k Xi6ā�x.<|4(\.êO/+gd3*S<WR89<74YZ/Q0<ah2g~j:{k{^yc׆.;q&#=E udtfk'Ess6mq7ֹBE:;_`ì38ɍuxڥwZ%D(<1 ;x]XgY_}U^4\>hds/tgdo-ސuŬsp X"4Wܙs5`|#$%F%˜-Px9|M93�%X֨rB%;<̓H\=!xQJM } SNї<wC u'L6p8N|L>"2u+_x8C.qep`I= mg[ D2"Q�۾ۿҸC>~8q:T˜5owiҏ$ Hd Av6H_-[3jߣpՄo0υkJuлg;l۵Ln}ls;˘#o"`d@g4A1 AlToL ~F@=&endstream endobj 286 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 7944 >> stream xztexhDE0C%BM i%lIuVqW@bR$$K ݽ?{?ɿ{?9{ߧ dL\lW5k|ɴMGÄdW? 2N+ KuL]rlZAP_۠jh-Mu7R~+~^|Ez^kYW[V,ںx[Ҫek޻x'zf"-Ų[eKdn---[%GZl}eJe/͕͑͒=({Ya<#Ge dʮ=#.ZvL.SJdH/eGp*dE?䦹%K,Hɏ/k|WخsW|5#1,O **~N/׾]\zM7nVR #}F4&M *d؜Uru3ޏg[|iUrX UfGg]<-os$NX쁽MþXYXt~H=)gC]gY7*i$oT6o/]0z4>h%휃O|m}1dID3K0F{pBǺ]G8.~?-De.ŏBf/D'|`< G+NpMxJB@5"6Wj֋FS54Ơ1#~]ֆ9gB[M@ppmgE5.�d; оHd[ɓ|.Ԇխip~>Fr3羭ZX~Px '_$[F6n+i z*Cd;iXhQ~l7=Yfd0҄-d%O{8%6hf5|Ƈ Ä "@>B *d/_v~o:}$N:Wt le@No/ vE*('9T@G� ?[6X᮰olk}{t䫭Gp''{}@é.NL/Wp|@朞p;ܱtΜGY(^ RCfR? �`9o�bwi}%@<ۿCz{<}�ȿ8=vpBzِW8j?ꍐ"i,nl!.v{Ck+X"T9ܲ Htjzx[eks#m-Vsm- K`;>*4<3d;֖7[+z֡/k5-CǮ`072AH?||8 !& W94COpI_D.ԮpW٪ՆŚ%euF ׫Nh6yC3 bd+ڭv3vircDA`bBdp%JNw1:8h@0ٝz6FcH h].^tǝ!!jY|h(U:^,h5agm,8R:s{]U܍5ѿ@m9ܠ<LHT;,n;mpvYy paʗrGGV96du~}DѪ͍N-hhx -ɂΫ y `,pCLhc>!泷956Jyj ^%wf AVO"'xq(1.o1BmB$c}ž"USjMn9YX] S*ReS=o,ԬnܰWC]2N yO ~*2`d 2`c`9b҃k�XL?pYMS&}wR !㊙X'.B} ѴStOJmn}ƣ0E?HpN E;w`A`ʣB K<̢D%ni˒kbR/U2VU[:k~ҡv=jYw}y(K^~rom`o~gGBE1/(RR8 | v;vz! %xɔY0T9jv* L|hqhW&0gӔyzxa~"yބk҇Y YimRwEv@gq7U*;5W2V,_N  ©SٓH<54t6Eyq`r .RP[L }V-m|``wz'n͔Fv;:L7\ZZ~^gePl&Ff휋gހ7|oC71Xup%a^tP̈́M)]Wǎ$}#PI#$cVWvm k܌T|}1p~W`S{[Vn *-�Nܙ;1$î֡uN< WyӝP{L&K9zl&rY﫿"4v?Y>V-Ɍ+ռ:S~|Og|=;bm+_>Vvןp'-tp). KH䉰Xy\k!ZŨJ%KK򸍤H~d';<f)ՏKgm, T@ysT*RoMDNcN8Mo�"`Rv};|ݶᚖfU3C6fJmƙmO׈W> 6A‰ v ʸ9k[iņ-E\=g\ڶ{ޣ|Ҥ潥Oo{tŒWp)7槢#x=hl7lչ}hّ$-@So+ {4d~ k{,Veިf 5TA&o# 搮ŨiuS n+5Mհ^M;r #!(J*T7*Fak :AWj @VhC`ݯ%;,T{ c.8օ}"hOB'n:F�׻0s+1QxH)-�Yߑ@Kc/NIH@V\Okk[**4mt!&/7-80)0'E^_qi:ڼXj*52VIiӅȐ/V}B%ff$ lVبzwcYP@ )]zYҸưVsv>f =f7omЃJ[J%e&ޮ"tlyBRƕlgL$v]nAOvdh178UUUJSi F<%t~9 ׹x8 1{࠶sgr %6f/G;}@D> #B#4r P)Ec5wLQ�'2-Nba{uwܹtl |Pz̃ARFJcZSq84N;Porzl{yqTl09Xci[΁ܽvijVɞR4ַƌVo/БŇ{9byx;o3M. y!sB/q{|g d>:1-F Ja2.oKwK t._vR$Kh_-x%J9Waq4vӎB$9ƢlYK~lsXT\Z؉7ԇ ?#V<fNr%)N4*9Jf+w+Q=QF~3%EX,nRH.Vk2E.$IY󴜋Fђwqe2Ĕ+Bxp +$_ J_{ce;4"}i.M ;G :gAgOػc+rfΪWW7oMPl=�M,xI.J`gMȿY[[Kc …wn?,$aj?W(7 huJ+kk/xE S,Bݶ%&(;c,^it]~"9pQj=&6wF+[ҩح&uN"7)m[LzL:]GM[4#8t 7kSfĥلޛ(Q6u@{ձ)ZrX[ �Ed]Doi&f"%!~3m$>uНp?ph4^^zHxm٫ybISJKvDp aZN i w4C%%7Vv,Ag׺ +=f`bVnFWn@WlB[,>KR8v &q1 ;Ih$\(3,%q9,F7)N&rhGߌ;J$+#0]Ԇ5K_rIC'|omAt-ᵹՔsq}<%oaJ;7L3n)͗}%щ Y|JXItmuno} )݀|>U|sJO= xrq|yw8m DB=h[@G/UÈ8) X$4LƧ9QAj6fC*Z-*|u % %SFSX6< RDw!<qZE`fBVcDp _NqBZE6IVZ;oo F'so {=MK¨s@?"@aRv͂;HwǠ6;hNզ6ȬHf7$EDR7=V4a!T}$݊?Sr 6'%ƿp>m-+B |KS֧Vh;_Jݴ]]%v@GT=nⴧb©$NNvNǂÿ͓!$LInS5VZ~vA򹑧=6G erb,6-H0>8 ӱ:NۓgY Ęk9\@ #uFJobUwB=MMRZX*AMy}7QGP}'YbD~jm5A5.*۵}(`Y$&mi1(cYR'H, G>u67Tle С :|?]+/t }@\y)6~n-mT|K;:6~0Na9 Ÿ �3u8zu"@žs0K;?'i/JytZZ2לٶTIFZBa^w⊌aJkUxeN%gRgb\aq8tybTUbj ʿD1"b~Fzj^-Kȹ-9 ZZ,ZVSYkVC%Y.?Bĩj8o1AcPwn8>%wNret9uU+Zm؇hbL%?aQ/=J;c]uN]gt3n u4]W}'?QZf/lr�/:ZtyXNFF,^#N>Hm wyB|SkOƵz۾ LC^;I걮+ H\c+@'e$ʕ. SN`ӻ+63�W`IHiS{&͂>@x>5y-N J'IX<߮z  $J680R~oFE+kHvz+V1f=%s=Z\!ͳG)vUϮZUv\{T`dzC]R(WwF> <0kK[gwPCg([*Y ;?Ao)R^T6{(iVҀ/'۱sym.xQ%jD@o&@wGDƣ$( 'VB4:1_a9CTeK~\ƸJJٲMGA>.?2H+@RXgɑemL4" `S&c\ X<x@U0PJ ]ri7ɖ ^ՌmA?R_PcCc:G]%uu}:o~C¶2fT\9u]1il19o߹Qr)_F;@ Ā[zRd׶HP I[Kvޅ3ɷ?&)8}65ۢSƅY'J=u$u8~ @7K^ܺ efA\~B6?Sxj-88۱3Ƈ߇wȜjkCM.j4Ǔ`y3?.L�ޜUX6W nOA*nq۬a  �)~`mg䇜|KR*dhт?!r63FwD(TId|C %q$Vq2&z毊WSԐ]zg[WI)<jU& \g҈vF%V-Kߤ8]N)F�%P; v^:H]8~B0>F}64tr##Hz(͟!-Xψhuᖬo|ݶKp9xoXuX+ѵjOG7_'UKi{d>f ֭+_ǸI?yYpVR[ _qgҸۜnҬغeX� �u~_ḟ͛[EDvQ2E:lKb CѺOzt*)fx9̧tlX VD$[$?-ڼIcV/oYq'o8"fHC9ɍcX&XUBIq;/<s_&MNqs]+?^.ub;j(['W]r8#X;ۓԞ+rj{ڜjo‘vǭB.*B"xU?Kʇ|BЌuԝD @K+6[9i C|'}5+B!ISDNHI'uV"^*^Q/֭6`n0Oqȑ~{kC}ps':$@.s.z$*%\FGZqmp;;6ҋfI5" (5"6OqѠd)%:~zבDŽ=X>9wS=I}Xh6_yKlUjx!n?^>~uyaxd ď%endstream endobj 287 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 9227 >> stream xzxUU!lA99!7#TP HPHHrzu{INB$&T*Rd+83qw;ᄉ;s{$ֿQp`˖?:i$JnS(umA(ЙG񾟤yx0]t(Nmc{a{mPq[F/o7V1l:tŚ;n/Կ0q6%pHqd慲E[o]RQrղ5+]5aÏl8Ic'Oy1cs?Pu/k1k*k k k,k)>ˬqeY+X+YVVf&^az"V)kk"k6k%֣9YXYYSX XOd-b=źkk(k:N]a,k=k8˺cXXlɢXYXϰ+ݦՅ`"1N#s7}кA=8xÇ :|;wN.˰>\nޗG~V+(YO(j-eG1Zr9fɘ ~wߖq w)=~P6m` mrC-=;Ӎ='vwLQ#ɴ"qT8-i uXHq 6c�<h9@p ?~heieKYj !P'KAkARYI rhfZ ZEF4$q5t<8iOLASCEt9;@ ykwmMH,!!kis:�V}EˀXHš& Mp8DT)pu<]^^7.^HfYL 3ȷWR%21& Ivsya;a[)\WMuĭp8i2w^YbujUb4Baa[ HZR 5ƌ9FpdM:HH=@C3"%S&$'=%P(TX}Q)^*=ʳ->!lqz~Fb@[]HEh7Hd~8M^0=v[p(IqLmkchT㐇poLԇ -:Ohӿ**@˂O+ac "깖{?y$i9bQLb*]HT\̌WfP3~n {??mݜ}\@;pi>zM@!q˯H%Wq SWW~3Kf kr>&_9.pf^=iV/=oJ0 N%`5ˋJCbb_@E?;v}' qf¥&J6E;i'A_˃ Z#nCž HŅN:6HNVOSCTS C#ҫ4kFi 臸<�nӯSn805|MH\пSeU_W@-ʵBQ\*Wbzp'I=Ӝ+h8޿.|rAF[ swέ-"F,0h<UsƝ/rDh5VA[,}]DEx#h@k]T5[*UklZ U|whY>o - Q^R5|F7ls^z/3EdZE�]HȔMgB!˞N8.P-)Ka+VՊ1EdBavg:"g u[  c ۃεQ&1@"1WIR0a-EcXI[Ӛ0 zsg{ݵ3c uIE:JgI'\oüy5\ f ЊhbRAг9JbS+A'.B#Pip)stlmqvo_RV$= PZfy_h zpQ0tWR܎n!H sFR'Ej³;Pw^$g%jnwq)uP*H�S9e]4OD6M2v(`1>պ5RG$g[*VEzgәPKbh/^{=ڇ .#km y:\d uDQG8 2@f.�Fh0+%{l!d b} {~>I%ioO)afCy'1b\GrnгuzMrIn!nyTևbnGU9U~mjBÞqb|*!KR 0EHpjUʒښ`W̝pD Hd\IUPDOwj>'qDrTϴmV,~qK#MYއQ \s6S/)Ҙ&Ar,HűPaMQx3�DR22:DFyXRRRcBRepAAMKR|(.M�J#Vq+N4n<(m@=x;4cEGd>Ęq (7(c)ebQ'h)U8 %ˈc1J@ZT]dr5o0|2=^ @"�<PKbR$CxW@'!*(Dhh8%ք}o Ho>;Pl5bwM_~hLJ.-$`k"*( X鄲*M^m6ump3W+[6;xQuDFѣD-eᩂKXsGWuvMPk4=ް.qnG'ͽTցi EN(*ʁiy΄;  @ezKKk$?l~rS4$vFwd)8=-woVذۗE,xR/6 ą^8H(#`P}O;TURQL.L$CJ;JW,>"9">"YfX< :D!#'[O'DNSBQ,^ |թĢ~o@ ]ӂm 9Kl 1nTAM&ʛY]Մ;;O!q!`zQ`4)ұXי|`?z:8 E2,9eF%/R5҅ExC b!$o. &}>gqas.!/ 1b,o4N�#jS.g6 K?⟥5ak~MXi'rQHr,It>}KNyaƘlW+@z]LBʦ&w?)'5+jyzTZRy`bL"r58F OeWݍ[ȳq'riVܰnB b)kmer t)tY4pF0x`Nqg5RL5 *(k"[�&^P;LNn٩@,53v0|n0?qyWu'i:9QJ@h� 3u|=cBKIZ ʶCG>WOLq:'?]\OljTĬmRʀROr|XtVWV{wƨ}wt>g14τ+ՠ*Lu5xuµzEnkycړ<!sD6^$ʋ{ީ=f1`;t>JFV;こ8pMbʸuS�?ߡAJFaB$^%I;@ɰMg3ah"pw}'=7׻p9sԶbNHз顄 gtikJd^?v]@5FK.ckDBmׅu<G+)W i@$16Ns n%w7$՜?ͥ_%.SN  hY~\ߏ5lߌ e\" "L!:W';+~[n+@:m�7&p1f¥Qda]� h9cɔcyVׯBϣsqhr<4+P3R^&l)G ER4lm |It^:yo/aH~ ޽X>VUYUPeGIU4)٪g IA{up3/C߃gaDb'==kxT2YW[S_[_Sje}ȧ~4pB" v[Z;2fr3Xde7FeJ/^`$QXxړOѷwӉW#}qqxSkKs%U `,:+@^Ten.eA`-3Wh4hpOՁv*#t+TU¾jר6C-R9x u*=EÍx)[<,?*e< "{M #2| : FqoIЎmݷ9nIciqC'@?mw$̾-ʭZvlX̐:E擺$vBz%nWF9LPTYU- tEQ̷{+C0;wv5YH|�kM"k\Zt>$ʪ:b<rmHUV" I4&ua(phM1 )D A-^-B? ۹h!}h?�$f$/D&Lcy%ng`¸p\LeQ[Ui{G`ZDeɕS!Phhד8th$l24ƀŬtIBY&}\o#uC ֡Z8oƗUr?\qx�VÝz0Ib M6OmR`1K`*#GVUk-rbK!Q12q-bӢlk6$lιQ\Xm߂⼇"N#ʓXPe~{[K2v?;mx l@H Sb=m~ wqE@lɊ]kx&f\D]|oS+܌/@b~裲 6̤>֬bqXon+->_qD4l Vn:ev3c<! &vhl{ ;gstA7:$M 2MyHbM\,Wj2s~8a -H8?ʛi�1FM. }o;1 ։u(5x6Z|fp%Eh] -ɏHaf1AS<"\tXg)N;AK[';#pH1B.CPݡ+.|q:I^s*jN<Mى1"Ƃ ')F/~"yqCG 4]l·q'/\50i!2iDEfC0Cx4ǴTcVK+[`gڸ1fÿOv՝p&Hsy۝m! E+)g|۹{e\/R=CsT~]hzvZ-Խs)wʙ@yNמ<fvb  k1#އMx_SB`TGFD ?LL!zz8E;!'c{ ? 㱱j8RD-%XKXFr<'/ٕ9({oFnsv<|#V D(fH~ܐWgdοp~`:"/t>^D-Q-LL|>sX1,-w <^Oȸ\4;<;`q,P!#U{"`%ܮ04-yk]s6'6lói!fmYo[ 1c5_ϞV['ad*[\s}3k#z5ȫhQ3JA(,)yg$jTL.u:�gnyV9"4Dd*$)*5"ITPέBTo*M23AEH|^~:l-KqTmW SDO V~c$13E4B׷k/ McXdhE>aA/ҠqUX*$ɐCU(rEG�gAgחQ݅ڌqkuuiiMzNWKk'<[j;R ރ+iMDh$%_2uxًDps{J,ZNq?8as<IVRUȤPFCD n ݉J_XƉ*"#WGGaBϔLKLOC2�H 8-h<=r 4~tfXOmD>@wDs'N-y&xS:}m W[S[it'/t31f GS8QW,T,fz5$ @Ʒծ?R\;TL8UiQ,G鴧-ۈl/~f�9#i~7Za~pgD5$MQ{̜mt(qz>sd?rknT(td:Q¶+hks~074V?mB!>[xM| A}Znɤ[v^HNKvykz iX"O}άfFn36tq ˵/<͜L!(䲰X_E2fw6Fؔ=;/ H5aϢq<Gb!knv 73)d8I*֔Y|D9N}r ϕ^`#]??grz iZ4PC'MT2 ׊~K2%kFAIUHQq< 8?8U`޺RG::aLYqLPn5 6+t{o+nmˍmWJ3Ei}9{ sj!pv"|.3H)4N8R!9(*DKxK< _ DC#;hq}lYnni4u9w'Z\c' ;<FB%+P2xƭ Ve^e5ΐ._'$tX1g&VJ 0%yLUSS5Ϳ`ûF}[zMj Eb̹Ĉ %@zv:( S6:}hF Ln%2|ջ Ne0@CF*~8vAWE^i\o.3o6m2oԯȒmN>W&r<t"ts>,V$q!߽^o`.3m71GRɱ8xпs {㾛DtԇrK,sءIEHPj/Д+˵FۍviLY\ڗ661.T3Y`ɎJQσ4;, r]!OړA3JBJA!2 (6Ij]�]–y+b*z`MJPEw @ri&ǖP1p-)ILLF&+Ho$L]31??KO=D[x ^H~Rִ/veft73_ְ&/mJ`7SLz> ux_m D˸{PaáJXZ YHC1& VTg.v鱼TmForX G)t?/h Sd*֠!TXˋoT|C0+x+?^0aH#XBWY=s# JM4\G>\<o#8GсSTūU<#G| KKaM>M8߲3:S3͟J<- ?ݗWn~%ID״mN :qy;\aPg7cKWnݰ^B6[62BJFc+xeue楄奏uwC2HYbcrL7nD\kAxьq&wnW,XlS̰I&`QMʯ5cM=$wJ2Q sV+X sH4]VEX7 ?\<fb~d-ݶZkA!( AР3aoگM;ӎi 2B.":ܺϯibڨ DRqŚҰhuEń 鑐.\8h4ԳV}=%.ahBޠI s,i46r~ҪSCTuAG&~!1zTVcXd10oA4H hbOxty:sjYK? ⢂kctu㸳"?'8C\IY 6=4f, ?fх,B+ .= Hʀ2jS*(,r`U4J:;<dƌb4DYV۠QW,og:,k0 -ͪm!`nM&tvrPaY <endstream endobj 288 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5312 >> stream xX tS=pa4aRrl)"C`[ڒN:Ii<霦#m: X DTDA@ WW}_uu[ok5߷>,"(`XF%Kf $81cͪǹ_"AqC0,S"X,⵹yE7榥^7mvDIQzNZzڿI9krE7^1mS-3ܚgo?-}n\b31B''D N,"$b53DXLD,I#DD׈eyub#N B6!%p|",�־끙^, (R_ҲIs''}49wSj8uhڢiic3g>4!ï?|.r.fx$}ѶC轰KqR{Qo[ma6f2QHmiRZ]"`:XUU*hɋ%1hfFf6f4O_K])BE� fOg@U\o'dV,i XCA3žd+F�d FWg׿;eذ8ߍyoE:*8f+ "VՏz '` Pݚ#D8Su}= 6}Tufl ƙB܉MmobC9pPU_lJsƟzVPMZk9!q&/NdSQ*q_&~L fB/JjqBdA$@M[\r}>i9z`;:-<]ϛ4rޥ}nw_u/qW "J.IBi(Ѓql${A^(, e_Ey^g7$2,u-{/, <`v-]kdDT)3u$:t#z|u7ARQjT9 kj>{�*)QY[$IZVAaj$6 }AH'l_hHD2, * L󃪅bjkP_&>\v4^p]fa̛Y1yL{QqTׯ(kwQDq1E*qJ>W0B8x?n MWw$H\~ Oj. $#ڭRT}* +T.D@=, ?BCͻTK@=}*KP,; ;1,f\eh/YnuLIRecؑ6B'V> ewC,FJK9́wv5IKP-Med4Rکo"R^ERHE"Af&Ҏfk2D+u3ݲVu۬/~7 e@gsWMgEUfu5F=Fk z2.--")OJ\lհ= N1 n(>ʓ六%´C8/2(gel.QO cdyOPa/l&c,qsSͨIcҌB9캼} t>_΅#da̦ޢ39bCrjґ΅SS8#ǯo8v ]/^]uDзjEsQIaTer{z[(1u.divGŵ7ٛMNrU:u*ZK!JUsI¤bYT<I/9.!l򻔱Ri<Ǚ e%-[<n "nܷf mI,72Ym6 O [!QTEkpaV-EDcHe2HWt|_eܣ= @ ܷZ6D>bðBPjLOÈQ[MY4}>C:MVWņL )xkkW+ќQx54<*jh7;<KMc3a7޷kNTcu'>[924r\eYeacQG_;fTdsZJ#-9/)EcJb-i{+T4sFa9VcAOo 6[PJ: 7'-;7/k|BJ2+͊Bn@Nʦ@JRT2AREEZ"K嘪m=߄�fVp�J tx3 UasS2+"Gwg]inkGuJcTڮPU=B<4> u6T>#);v7cw!ۣE;ŽKxHLBɞD> _cz&EU^|>4*)s4O!z 5>;TNg2K=S7l\Nf' !wC>A5MOy,4hjBemz]#EU*#m\jjy}M9r8Ao}m?L: (LnQ4\L%YU"N@OJ!;ᯎu_GCX0-~ÜH$D{\%m!{=0S6moMΏD(qPD'=d^Iҗ)+ vo{s./;\+j׵p} ~)')UT2+>0Vy{y3/l ZQXd?$wF kkt4Yc?r1ݺe 2$++E̳̒rY֒aѡ!ۀ-usur[;hDfA@iw ܵ`1)TĆ8|f+3̴/'yF,^ʏ%Dnolp9JS N4JڳLjJ)Ry)h-JyGցuf.,G|#叽$Ũ\W\BfCY[TsSԡjq ('"ӣVPc|EF`=Q[q;@ΒnmfIP̃+_]3Wv,b]Qi%/7%Novy}Au}{gV^12 fyB o�:c|6o@z)T}V9ժYyb iw;;ܽvƮ{xe.{|oqx n-]\0Ԁ rj-̏#֓ӧLZN$#{wQ.A`z`P1B޾ ej8U;vz#,n d~*Qe9  2ƭhS:4Pow95r *\<#NQneNZV0lJ#͆TK ff FMT-JYH96@0'Ng+sJ]8齯>}3*F|Gc9QҴHi8twR+!p8p{_7_G+ӊ7\?l# *{^@??&�PϦk `~)jkg wWh+UKJaiE!z Y`ƭzbme2Ul*Qk k|Ɓ_]rk1edUbr~JA6K{q_ + 317Xz&g\*l:Wz7fq-}a"/w<+oD`N_o8GRXgK(Sdr{EjjfFiCKξmr/D)_{ WL*RRV J4-ЁGʮ9+9GFFI˯2u\k1ߙѐ۫=:zzV;Yc1U!GW{D%xEjZDa:g;ژԷűWջT&ye?hUQ谍QTn*hk آKz[ 2U4zkvc оfu7R= ױf|ޙ{9"*Ky4`{qf:H{,]?M~.Z(ύ_sy>.jaO% c?k`ybTj,ic-\UeUZ`.s;,#`/TJ&IMp>{?F3?0gE;'~(?x^tE#a:'&~:~iOBmoiW-8iEiYuy]k$ڊb3ruxL<_?`h< 7a9YNk@ <Nz |a^qG2-B;<YU2Ֆj>6fw4-WQBfgeEDl6{T tP&bylc?yh<I2S0Ӓ*@Gw~n+nc a*NLVmiwv[5UTˣ*2;(X5$3$w2YvYbLM^ހs{s$X}o?xn]f7r7-1Mb=Jѯg<Գd <={pc={%BC@�.r`!�zy˻ȷSX<)Yʊ랋\*점qpDGGķK/!Grث!`OAOAwzFN^6\WkI4gp{2CwP4-^:7>~n!mI3L!&U$P<%6* JR@*NA3PRSe}Uk;X'Ɯ\.E^e:Il/Zp!~^ &=җg™=W]5M\eEʣٗ3z{z.D l6SyXtiov:$B4S'�Ǯ endstream endobj 289 0 obj << /Filter /FlateDecode /Length 3605 >> stream xZKsF뮽$["MıI%N p@@H;eg [[ |u;K~O؜gN8=ۓUꌫD*#nߟ!̧gV$5vsgiJ}C[ikYIbl>X[//qewoU]9xn;lS:v9hE̪ ^H5.?=[>^Ka')7޳lOmp+/+m:=� LXXTrun~ ؝Kخmr.2o,mvCIz. KqG41ƒg*omiܼQAs ٳI8<sƝgOԌ3}j9 Kٜs84ɜDѠ:zJxJ s{v7*!=˛v棾˪eיRٛR4{JFˀ `Hig*�16M*٢ݗE ́<elR+)&ˬO/�Qҧ_gMCO܆f�Q׷IX }zX3 6`ᬍ)/mݴS(03EZ87g [l9.nӼifZܕ*[f^ߌS]uÂ<506c7"�64ueh @r7఼ASH i8lښ{!-G&Ui²l@!n~1w݀?X058:jʇ88v,ZlC~-{_7p(f6p7ɪ=E;M:uģu>A8�u5IZ&GA'V 3H>T[TLFM>ʧuw#= ibg@c@- ,=߮M6m@xbUoeUSk2~<L4V)ܟ`?e0s^e<;ş# 5n�ɣ=RKygO G7+bOkS }7Y,&! {]0p8ω AS߮&AXÈ.rw6QpȆA ,AYa~}=˼O]g!T3aٶu8~4İMdeAa,]h,2D*QNeQv!q=(Kz(8B\a_LL6#ȑ P9T<ɣV| ]b P%B./ۖ4z7RJ>Qa- ?M3VWBd_|%n }pB8?~{? t}|S*GJ DzI M O=2z 8N^\yQ|[<<[/T $ "u`(gӁ s�\(CQG7V6Kh:]@&shCӯd9 nbIP ڏE=Pek*"EM~UT L$쀠H!1@׏(^ح&C=UMyQP^zm )uKl*(,Ūڮ%^]̛'959FEʪN�.ւ\ꠝB'… u1܌u>"_FօEs{@�ѭ[q^:Iom!?(Ut[2KrZJo![A2KuBdUYyRb!nծ̶J?N}V>x&@g{4Yy_ J !<UKT2:ö&9S!E! %ƙ,2!a!d*~s|APă�V*d J|S�M^KDH*]Vw8o�o<)*Iϖs͟cϢ:U^t]=Yofc!H~;X[wcS幞dE,hY+S9g߂^YSz _zC;d#;Ň@;(ey9{!+>EE@Br=#}6~=tXc!�^c3=|%'5FM:ǬCZɍA L!q>BW`ה`<y;n5iw}�d@r^ 8bP`'[Zq@Lfyn}Jy|'@wsHSKIP4Ӡsv4JbUb |-(P >QSA% h&}r1r(@H.K ^ېMLE\炳ߎ8Wo*rA |{{6<RJ }x҅Xcy%C Qӯ2q>٨PCi^-HoGV]@4d͢O$6_lwE$JQM(\<@Х\+ʇ V"!6iǎlܓ!g wwo,FzU,Ka97y~H:T<SV)%FvV^ J9gYǧeinqKܻgavɫ^il "&)JeD&LCzr ;^'t{Hagq7!QbfIM%pm!5"$݉4Q#;Ku 'CZŗ}7^5٢?n &CX_)V^_9D>#: )3jUX?83} )i@#"'=oQ# ܔS-?Z5YHa5гzYRLQ 23|DGb{X%}V]M03B]Te[ņrN[w}"< _nKGƪ!UxQqG6t�2jX @y;XKK) {9H` q|ۓ ld+PuKẅ |]ak`X%9z{a)Hu{%>5fAb ؋<hN<;~w�8.!tã+ _Rgiut9CE/@5\KsLEBWEe a7ܟ{a\v*WFf݋ x0i/~$5x.2F)_cU,tO Ng*t)åtZ'R*?0 lv-=&;,h? Ӂ8dm]/gjihi�7j|]S,co|{XC-CQFDDžТZ.$ax²bFrRd*C0DS)8g9&+ ,) \ݞ|?endstream endobj 290 0 obj << /Filter /FlateDecode /Length 4206 >> stream xZے#q}7=6ѮEa9BI IaiǡX YX>'1;\�:;3++ ;ٖuH>]nyޯ~\T]ueƔ׫lmZgX eblJBcPJ0"\ǜHaPJcJ+ۊO!2uvƎ @ړhqjbǐhL3%,cC\,njM^gX-,mt­^#>R߾!w`_]e ŎR5C?vH=7j n\9ޠ jBb竕/+SCM sNrL pCGgPcw::I!$¡H]$7:&*~45Pq 1(a$ z|84F%$VPΫj.// DH]5)u`i <Zl /Hq7S*+c]1.4k %#[M,dobьt:RH&2r!u d{DwX_^:LmɌ[0pJ\�)'>ϥ6sde(ÔMGiJ>OVK(1ge夠qK=F揔l`҂b4:1M fTlNu)e**lG2rdڛ!OM7)%ZLZzYspd[i_d=b8VSa+{pC:RYߟVÚ_W_ޯ ,9S茙(# (s%bXBb#=\D"ɫwc@*DWr\BUAƁfN+[PW *$)-1Q2OUPBdrq:W ]tp8�cʅ:cmL>5^H 2$ 4R-F'PQc֏\B} ItIy9+Q%B/# q%@ E,Q"WªÐ,Ȃe;˭$x" 'arP6SIY V`WPPraGX@|#hB"R$2`BqJ r"%dv^BXjFO EçPɄxɚZԯ .)l ӀF#EI'B!!kG,,IAʴ3B챠Xc05ob-=`54ƚaA5dCaAAOJR0^˰N V)YH%6P.%]z wMJfB%s Qw։g$I#T#BZN `g`}|^QGY:kW)-MZ+caUQJ஻մNJө:ERY0N]nUz&O-٪J3RoP ]aMTdX&ΐA$0(c؜Cqv5%Y^MNPb8Fb#Yr56f1vj hRvM cA)F1/(�5cz3aETL# dR1J#:yNڥ6xF N!lDB2 NmTxq1AH*f 34@_rL)^@1CP0�;O:\j°P؉ڥX2Qx1:%Hlovc 9咎,f*H0ɘAP.Jim,:XVD\d%PrCOjIE$KKm85dBZHo%KW�r𝒥A�A)v:HKM*u)t?_S &(' B#<!X~$xa`r&20 ;7,a�ögXAOr[d"F/MhF=6r~c Y8`5 u()02K =bR&|G7z1b)pyXZOd,& <'GdboOw<Ui}Hv?[ܘx9 +n58&gI EqcW8-)89h_}(N;]K"ӣh'&"'yn^@) דmM;A[&JLϜAA8;= ֓f EYحf _x(5݊ѭncv '5 Z@cs5?CO&+Ŋ'&Ĵ>S8&Uv c,W;N �/8 {bY(yG9|IADS,oYfz:/ϔFtvZ`<DMP`2D ۵\2=*[pH^hϺ%&%5A[Vtv,�C`PD="N`R HL18 L%,oZi^@wق1Y4nA%S{y Y:'+rD�ZHz;WWb_Hu T啕Yawk3%[lB6G8�Gv yl?O(\<ҋ3�Dby& g/RL^ �/@V(-)!mJy$$cmJ女<_g]Q#`膛%<FЬo�? Pf Cݾ:ymxlL/6S_]Up=<=owoH 4<}0\; `1lOZ7۠`ln?<޾>Pp<\ ?zKqzDm\Kqw|B-a0bLiOO?@9<̱!o|c) ysEˆo/;}FCmKw_ 4l;_.-Jx4@T 7o|7aVO.M䥑0;x^3r.L) 4T!GL~xtڃ[r{IwÃTݏ^O@{^@Y|ǃZ,x<\%zEKg(x^`u,U,q1Oqn'y5to Hm].Ƒʠdäiq\SSo?"\1Vn]m4d}HpڞNaxst؇kD[TsUC2qkxa˿mx]KO?lۿ)\م>Yxߞ{u85/Yunx|?]w_Z ^2f<Ϗ[/'~W_]` ׭NNzBRlwo.uLbݽ|؆>LҐa8KV{vѕOge_fe`rfӯw.|s^jv׻Xӷ!O7LomWk"�6]~]0�a[yh]r᫷]qxK9/6OdM C>gq>�y͆v b38CMğ|#ӡ<M''l?&?æWV<{xScɆ,9z }oq?(_Ӷs g:�j&HzFxs_( BIwJne 98*B'Xij5i2Sp첫O }x,0I =Kԯ;z_ =v}:<` vRR?SlZU]1Zb=Y66mC7*z�{ULJdQ^q0Lx϶cvLi>!tou81`{KÇ7Ii-eZ.w#;M=>N__;'rm;U^�Nx[;~gCd3FaybyìEP"PˍM=r=]g-IQ4j\{CN_�!83c vVey^;ȩ:na ܫpq|z|35Ti-MoNcs�òM=.BGDo9#y?an8M#7Ī&Cendstream endobj 291 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 7414 >> stream xywtT7 *ȌxAEޫHoIH${>JH(zū^{yvo@Xa}}wJX a [<mqƍc~yX68j]-:~֝'aWCF]3ͻukHIɘ5Ho* Xh( Y\^ .`X_Loh*&Kf7Qli^U-^RO<vjSGyqė^#+[bfga-`-d-b0k k)kQrd)'X+XdMe5555554kֳ9XsYXw^f gɚĺ5aa a e*cg,5u+k"vKpXlޒʒ_Lrah-oP*/> sئ[7n>oGwμ4w>g8uϏ{獼kd%o._oƖu5jOϐF:6>cd ]-EO@WϿo#9<R/ A6TȩRJ Kу?M.37YTL8r/˦"yfVj`9<b?Hpv[?6v6G=_  2p=}rXM[?gVh<.e;ѰRVv=w}CP,63l<`f b^$I2ԛ`}t)k5rI\L@>THRj pE<w$nE?>+hv9%y6E7FBhye�/fm<o6>6'{Ѷb²epjq^wDqn}#9?]܉D5@8o_/hiuo7?oHZ $jT Pk"vT_{N(_^UvH@;hY)p޹O`ܕ ilޒ/BPWͥ>HĄ#*C�yeO4^µ4!Rw?=W]Ctc/z,z/i(R\/; @"7 q"[k>]huGvG!zCWW*(H?5=7 1};ys '_{;-:mzqe~=jzuB ҩҨBDDeJJx'E#wЖQm婕GѷicGCtP[FQ#[ERqןթqpv꒣i^ׅ1ێ F,Kh$=p?�gs uAoڛ}s r&Mf:ab狅pIa&ސ]/kwx /;k*)"A'Z^ .3K̩@:z`ӜUL&�J^ U(g.'o%Ě_Yԃu!ʐ�^"k 5PU> g<Α$HI RX=p7;oGW'[V6nc?8T1cA͆7N6  F1<-h6 ˨�q05d-ts_ ֈ$Oo(Es12ۙMYzDH֋=Ӻfkڞv!5uǯ<*Ak+>7qXiuZ9 ;a vCVJ H't&\Y&E ps:^Vݸfm-ɑ,\yYR<,OeD+V;qPekPN5aeO>M* uɪNwVQ]&lOxC_Sࣉ Ǎq'_Γ\AO_!qCҨ!~ ɣ`Y?ً2X|8[7G?ۼ9PKLSK&=1 :_@6*!mn$乛<!|,(#r^n`Z_l\lpT u�&??>R@00eoCQԏCA4*N9(tlVR/gtwRTr LնL*)-3x+t{#9=8(pA8P3L*hğ $"-p/L @3FUxy긩�@ֶ+6_hЗp_ W$N6;K4s&\6".Pctey˺o;TX!ۨRnU:Q8ţٴ:hhT%!wyG'zK>~VnDdM>!wQ @һu.oҝ h s`hbOsfPRC5$/U\2RHi4N1m gAum\ںXS"@$ҳRXy~=$vzvބoX,s~hPb12,bb]uߌ#3&IA{RDݲ{k[׮D"D�㡉C6h˩BBj ,L҉:Œ9K8~ٗQH-=�Ҹ60� 7i<݋MA_]9cFTT"7,n _:gzdzM6 yBPrmi+[ -K3p+dj}@ &Iw"c QxȡjkD{П]l|7;|-YLS`g6/Į\_)0k-Qt/kk4xgaEOdt *)Q~q 8UkR/_̼2@8Yk҈VWM C<tv DhԞCrG(T"*!Te#$7D7.U+p1XҚ_l`eH7+j[,sGo_/-&VPP:RV/ei"4~s[H^EWrR"c wķ}]&퀙ll zj Y ;Y _HQmpȱDR&pV}5м|#`t[e}ݗ}aDNn�s*&Z9Sתj53oן׽oگk�"F&NqؑhHoI/BɺMO F}3M>eܒĻi?_oR7_,.~GN9!Ur e+SW˴"P3 'KC]&=&w51�̙UQ2V<S A\ D4SE1[0<p}KKK9$Gt1 ߁ A_ڛT\$ WBl:tVbstLc믺U6!A3e22 /36U 9n-.Eϣ\t;~8wl} *nNU6Ij  6!1u枏nG? MnsAvޢCC+]ZvBgxKV:XWq!pޑ4e3o'ttgFj55MNP`074 6Z `Be*v_I4#} (ط< Z]BpFS #fH08 t'Dh,/<lfS�9Jͮ6ɷdS-"sWzknt8x5Xt7"K/2a_,cT\195ݘeb8UDXZC3Ն&"�=oᑆU*]qׁFF&I{J?Q{|֣ZʫKOΠ A`?-,8=7=*]\5.$@~E./T`"L@Ocx B@Vm'S֒5f $@~[2Wx{CʠP6fF1`xGe@xщɼʠrݸn�MUkVTP >E@hkJs$ y(y}'o? O+yv)b,_x'?cGM(Ӥ!nvqŖp`pIfН+]|'¦ʠw8LQ%Gbw?В9|$rXπKC_o0 zشTcS;ѡ+ٽ*<o,dUfM.w<;<w0KlWm%7ds,!X jd)K7py ږx n#͛*du{5ιҥM\bfJa56n4@s4ɩB C^h|JUSt)CK`68e(pHG.nM,>'no h8"C{1n34S3sԔ<}~Ji'eڬ5]y' #|BHn":@4x. mFu+Kg,z)~nUUVT=4tPǰKBL\~  l">4$ Y$iȷ9/``Xo{䵱` ̴곶T[ YaIy�bc&0b)5辛UZ [�rqڀѿ�|:$byn1+2-P@}!)uJ_Ƨz` : 'g0A>ηr~~lqSh2qEwÌClGNW@b:lEX jK1Wךku T%Lg>Jg]dS׺x5; h7`fNA.[崂g\mT].ja罰qvoaO_.z#/i~C$._p;fp;lRqŠ!lsNƕI�TB{8nhYw`X=0"0#33 3c@}rY;y9Ӝ@<J&DŽ[KsX՘JtRy/@Vcm€ʠyV_;ld{} VZQи".UPi_äV7WUU%lPZUf(:i' [ѭ=fvEK6WWq;~z5Tu9sjG3h!_vNOx8J~εL&hvz(<ݨjBmX,=8 $e,33eR4 u5QJkm-,'6w4ttm۹npGJ>pev*YBN>/[Sڔ)FXxh-2{i(*bqI? /">Hoסk}\JB/uI*χZ%GX8ZQn51LqFvNf]{@"xs2) æ:ClKQ<YeBdRK<ةfn:-"z,ϡkkg`g&lKaf#`knl�]>*|iuf޼:?3=\(tbETpR(͈b4hwO1;qb&x!"DF\hsEzήuZYOegT1Y!Hlmsj%źHPTr]잷[OAdo1IRJ!^r<͒?@F#}@~i՘{ϼ}z'\hԏi+HȌ2ls[Y]AHd3TJ3̛d\ %hrC*Ap~^4|Cxg}D[ܝi}X桄=+υ_@1/3-U$t)2 v\TCO2&b  ?F|drY<\%Vh&{@W}ߕ 7{| Y]Rx|{,Rta%v(|0zh`mv;tI4^]%-kmkxNv&y}׵_ =_orR4 805_�*ffcϮsZ5X$:J16SہJ_mlXj%ڃ]=!2ubMGCGd,%ԫ`'*X"aW ]P'c (#*Q% mzOuD!w`#MZGLF0~ɹr>s*)bx |[pΓ^Mx e?2_[控oK[ Z\[=|7a' \:3Pgąڬd-pڽ} //<69eÝdHiEhS򈸖| r\O|k7/o"= / mOW ѵ\'O*A/ ܄ p~޳~=3c2@kZ.xlqoI u(-[~w䣹H2\k%5IZ7kIzA&ʡ2jfLQC 7x2V6ii{훶GVETMV0qs\1UTtwɄ>pSIpD, Hy'\AeR^9~UJ E2Lǣ@<|={ߊ!&]#<iC@BBV*e)c@]nW奼(-f"nI  -6]U;:Ó =wK,H#DZІI64R$ $tLqsIœE_ WqܩGT]<qOwS(:$�$kBJ+M[ 4dyaP1{Tܿ]嗢@6P_AT YB})f,SlLON6vc#Ip\6*ORz/Zc&K?uZ|渝 p.q e<'}-;D!؈64Pc@ โnꄢQ'U敿Or&v2ۭ8 /:o{ c+ lVQK]F+U3 sU0~:0 z5hӭo#o~a,4a Tendstream endobj 292 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 861 >> stream x]mlSeǟ{;{VvQwo�5q G>u#ɴHe뽽ܾܞt}],>, 1)|1sY $aP }mwwmfIC6X׌;iF 7ҟl׃ a2}.g!ccHKC<ToNa@{Qz F]@Jfv!Zp };P+Fm%ZȭE xKGB{}|eqý[Dڏ]A΅+!5k=%A w|wVzDG6W8r'2*38`SK6Eʐyjub 9XG-"mDsofyaGֶz] (Uf`SWLekE΅ =ǯ䞅czĒW=ސK s=}{,JvDp ڸB!:y:F%=<ox@|@6u58vQr:8!}ñH>MKtћE' -*'4%Z{/ڦ+O%W&㾔[ڎ|$n-T}\(NhXh3m3/ /L"\UF]Ue52Vg)#K_6SQLmosHT<K2_\!G C<O??5K_)r18\H32Bck\kg qn4%Y~ܛtt1'GPSd d$`*Ǹ͟ԉfS5Õ@endstream endobj 293 0 obj << /Filter /FlateDecode /Length 2724 >> stream xYK۸_HJJ,-$jJ%r8z)RKR*>�HRs@4~|od- Mv#S77vQLe "Y*]'Yl7i2['͈((۱;8,W*86wmd*&3@PTS89=~[ /G.hKeű-3‚g.zʆX{RߥEʩ=nS]n-Z#c{v7R ͟?]A*AÅW])|x&”Vm/5F|#Ȍ8Ur#uD?KD+&xʁ ?]kOnA{}76zpZy.nL~3#e #;T(sL$jH#_P[eNӔ` hOn+˜$Dϒ ۾۱Rh3; bO*ors+DCG^(CJa>d_W%ؗï׏޹g߶Nn,#=ϿSS=pL$J&JGz:ݦ|5|o3L]ù *K {�֘Ibkkr/BOW~rj,;x6,0`Q%E)~2Yk~5+k 8TI.0Uo3 d1*V*eJ.f w2Oΐϡ+ PD.D,:0@?eb ɑcL�_LK &9|r1P,XE&-6-5ʈ1FY 8siN]GGXRxΌܥg +2!t^5}ljx'<yL :e2܏qH@7&<E&q kO �?C!?:@Tt}3֐0ꛇ:p<%d(vd7d9򹒭`Sa%̠ľBmݎ 8~q~1%<mC'ИɑeP#@]@TF�S~wd3* >DCw]XB֗`8ٰHFr<5ϭcalp Ҧ80/}vWSǪA,@@:P]mSo_F_|BD,uW'M_"tvbw|(B#k8\^FlU>EpVbDh_teI_@AN+/~[C̡1_(#>Ľ+Tc@ޭ:? m#|ARBYP9Jٖ,"/;pܜne'*ejcTF T[[/|uEj~�%q@ <ٔ(E @,tNfsn<VUp;\}^J&YRL`~Hu߷�a7_.GȬutMW- @J-" ^*()S]"xa.`H(8s3QF19EQc/5U Eԁ/5V +AiVO>Gw_{wyY4I0tK ),DRz%pI8LK;tE"6uJfr=}}5osMu> sԜ۱ EƓÞ6[k&|H Z�WP+\SR rgP,?AYrֺ@u_2]s8pKLPqaAjjN5yHԑѾV(;g2qEH ٬8My'"+ 6Fuf+M5�'R"W:o7p�3+hCb]ZL-(<qO+\K!XE}>OKLښbU\LTFM'I vm܅SD7>G`f+ZJ^\!#6~7yE9FtP7vnۃ+F(A芒mCuJL5OQ1K)//PYeCH>c"bo<slpagӔ|vYJi`ȃ֚skZ;J ?WL�5!P'TCó3k(x#) {.RF2Xs8bPoyx ,t'j±h5=\k2ZZӳ'%vü٫5z#mJE? 3Rq%G/m1^jRvK2ôនl6' l3.׷9JBgâͰ,!9 ˚Iv'v<G\qGeę (K>54̯쟾~rl%4)ZJ$ьDv΁rR<etJB>|&p f9EZ2'<HqObaӕzWz $Qϋ tEMErѰA9SA?g}lpA<% z:_ sɔ+:nTa/aJe辱ͮ0;}@b5XEPu?">qdvlzYPE Rz~d8*X2{|3^<=Ry~zy ׇ I'5[X436vs//΍endstream endobj 294 0 obj << /Filter /FlateDecode /Length 3309 >> stream xYIo랛W'ӝ" `189|ؔv6(erId{~ȽHӍ<zOno!-6t}jSMtQ.IЌs7"z_zsKq-eDuvsk{iTiqpyQfhO͙6ƈ6S&iTRiD~l_E)+ pۿ1 G+eYlnG4 U=hCRgҁ}lUoRs3}OL\}izF./P5vtT2QYv2c{t{OD@[ sS<ԞG#"S55wbے(^u>m8Vcx @e F%gUE6;d=܈/7g2fUa0vOg,2Ѣ9/McR?r*)嚷_ae)P7R,&akKu EF"[p|*b{lбSYz~MuxlǿN 5Mɤsrl ]x{wObKTwsljjcWpZ1p$9j)>y<urQv l;&_ 0 \LW%R-GP^,qOP68ɒEz@x.05{o,7/MU<wKfSJTI%hZ&hLFg&�PI M!(Hs�6Z:Y[Va:(Qs&hSwc[#gs3iUq5>)Btqfi4Y}n-T<\@IEՍ].kG-Zcsk]Ó]gEt ҂Xn %N v} JT]A`\ ܤ$Fp?]sN([##f$ /XX�f<øo M!pQ:d)�F�,ύmX*G&hZSp)^ga閣GX.lR\V1":2!]8rδY%)Μ.y p-i,K@-6'K35b<jRwWpBy dxôSu4>zj ,KpؕF0Zv8G$u@ ?MS:[&ne'h<298j(LX,<n/5<9%ANx.ɐ^ ܖtan̽ĸyEa=G;*$tE|҂L!ʛiUdO1U%D6)20&0/z^$v$* (:Per å qh.֙hRjj}i`՚, "�a;JdlDbH'(�csn>0ɜ\w'8yoRQ2.0znEjF<{셑#eRJw$TfT05U5qt7k)7bjnWӳЊ>۰ {3׫amd!c+-\>#Yn=Ǧ|,+KbD~ڈCw�[ͩCFIߝQqb|U.;�}N ݚ@K, slz&9Fh0?{)m2Eb4"ϊ $evc cHa  =U7[SeC^G~ -aml=~O HîeAx@r Nd1}hՔƂ⻾ރnr͠Ǒ<J uUm�Uv S�>?U\WcT^7:dBmk<1��c&L`̐:Xx$FUK Vpu dHzYrll1,h2YG08U2I]CZڲ@S,Uǡ?~g-gDQ) rHSHC\d9) rh=ɒʺnV]B}0am {1k~z�J,Ϣ[!}!dy2's2g ' C5UwPt]TÉ!S;ɽRfqByf< #oת?^Z<>PF�;%59rd=7N`,k[ԫ$~4]8o׎ӝM,&nü0bnkUy=YXP뒇8#Ǯ18\vϣ, _;w3mG\tUUIXK*afOٞI~J�^6F2fe&:cGR?G\+�FZkQ3bY/Wa'qnjq|T%Y]3z#9}L)8R;6nGB1Uю'j.f֡ΩZѣ%61\ɽԢ\E~\:ԾK x@\\rlZX&K.WZ;-5B+iH'T1(A�˽Eк.c@zCRJ!|f6<T0 7/ U,a ' f|j0[)s&o멨toPjR.6*H1B$lOM<̖I,tC(\ ky'�qD:凒qG_Ń)IFnƊT-f>RqmqS7> Xb20)*^K5VǯpI7NK5@a :xĿ?ƔKH)l|]+~b.B4+Mq4pwk Ͷ#z/v>F =+'H[&"XAm}YL։W\aC"^y(q1&Y"c7+7|gN].':俺bgwcy% ' z"\LT9KąM1j嬮4J)$ۛ߿=vendstream endobj 295 0 obj << /Filter /FlateDecode /Length 1842 >> stream xX[D~o@iN|^ qi%hJ ⡇7qSN}i8ㄔñwgg7㼋҄G)"vw N>D_8OlgjpGxdHg"IUL&2^rI&F ~?KLMsvs6_*,Iy*[LT:Ăãlfʰ-xF mx;m5+m{U&Ve ]Dhill;vþ ֲ)x \ `S,xixOj=DR7 | oPnv.`�go%,+(/pt"dPnPJ#C'02p%Wx a9dorP旪ٴԩa0c]]V|l$@v!Ǯl6%hvӏE]UK^ pCdr؃.4Vf)[LkuqC7l$^j95)ڮJ3Ϊ8\ Ep3�50:eїݰČ:$ 6Od& jg.H}d[%s()"īLB\$Ge4`};6k\IsvꪁZ�TC1ЫfCW4}u>u1'S*IB:uVIu2BZQ]=Oc,i'�C X0 D|7X9N@K1eF]۴cOP]s_P zЬb+Z/4q]�*oAZLݶ ."<ΠE"fM0)Hw])tM]&d2ͯ�vfG360Y'd]OGř94"^?P+]� h<V|M/AUPM1dMDx̳R87I|1r* * KRxHO ^jG@*J!BJK?4=15H!v3PѾrUcNJ{SFlKyhAI֏!x]w"ov@r w#Vexozam"`}Y&P=ׁm..)ȀL™Zޕͬ6v́(b�</0[)ի%^M6Own")=5mMmqEt:t J�NհMӀP>BUy|ON̅^`᭮p.b! /M?7]w#(cmդ\ӄph 6\hq8ѯ!{RΣ)\p {I9.\ |>N9]GWs:n4t(ͽPQ ?͚t 6L־ka23  yEg~ZFzsNExSMZO(Ɖ$v& nBmnG3=4Ad`b^\8bpA+g*Q2Zϧ|j4~U]yHwy*4n$nx'NEX TӤ{,:nOoñmfov<32j]$Β\ (q !�8e\c&_ o[<'.<dLG?}L~ #&A**uaFuRu=Q"nDyW%Us97 T$,cendstream endobj 296 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1889 >> stream x]U PSWI [TvR;ig-̎QѺ <%�y` OQ C[Ү]nN;ֵOˌ{3vvvw;sΝ? &D"ѢWVZ|R,M[.>>mħYO(K$ $%p\ x˖bX$z muqeR\_A$+un-.U.#\YbE&/&b C(4*a#% DJAV=A$:Y.=QX,S H�͟DJkNJs9# 8]wb0w;;QEMRM]d+5CE"[1LM~(L]fߚ[&L 'CÜizCYrQz ut2i?&vIr|_7ٟc)lh`i<-B�?ʄFqha, <פnh0Kd,2EޗHmZ& >"؛zQ"$XO2o|WE8 /3NY8x_ ܂2F)ɯRJ`5^!f?)PbI2ȏ9| BɒF5esQ#Dh7]=?I7qNj҆vCZ[̦�o;6rs4^i:<=sv1>e쌃VB/`* V/2}X3X5#÷.P [f &ȪmyKQ tO $GD&2M7@i'iL6ti 9~uzSCB+[^9m#$# R]>{ndCBz\@u}ʇqaM2SI v3]23ګ@G#5 $+e �Thsq*sPJh 3`+){W6auLVM=ݡ@O)w:I<!li״Ӭ N:Yj+M|t~ѭ>A=l34d]`(<ЃؾeWBX|zJ!P,:_‰XZ\\èXc-0rZ CSc6Wu8ߌ›oB{<^/G´@ 18sL!3+  ?kWOX܉]m3\;-8"mir=/>W%itAUzJ]gj=mڮ0C!{9\u[Z'1uX~,U9>׃2w3+~吉d^[a>%3n²; TIk [ dtOXwkA'̍=M/͢hfhp@imS4zkJEWI\.x >}HsV  Crߥѯk>R:Zv#/9~upf^vmѨ=ℹ8ŋgf&@v 7l΂S=a\4]ݔd͸\Lc#5 WI2ÂSE\{Tw-dLs  @>hz*{^[d+9*,r5$7h;u+Xh*ѕUTHSicpӡ*`I(ecK󡻋P%mĿ!1 endstream endobj 297 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3174 >> stream xVytSU~!R6FZ  #8J,R,TB&]{4}YI,Mt"R@2 RA=79 sf+}#<o qϝ15?qȍ-SIѯO=7+ ahP따pQ$=>=F-rl功Ld'AQKŒ<ش"Q|/̞;(A<Ekg:"AD/12b6XN%V78b"1xW)\ xxqm=AAk`x1Bܐ}!'p'21oy<vo/ ևR|r^gP| ;naeVn16A 0)6-&5JXI7i1IJٲZKӸ %֯D&]s>,jRWīW% " _ jb5\<DEg]h |w2 4 qYq<s/b۷Zf v..Nf{$Y.ݿ.&rUp7"f>z pE1<YpO*f͆X@aG(h<-FADI j5m~W 6x[C mNsS^[ԒՓf^ 7XQrnfF.)_T^@  &[^h:^62$dGZZ(ZQlU?07se78T}Dߥ+'H�?aΧYRv U*5j--٬VE8ч/xx?E�@G.MPͪewҥe$Ǽaъ&~x(-D|<qm9ZYm%bm8 W�58`-G,WCAMs)9硱*@G.w4( Xn(.#�hehemC`%:]u.Wv[E[ h-׷Aa@�˿B}& n^ym;bIf2JЋ ]J?{|YTRU*X4KZ*Mr7.\s*F&OKԉӮC'2_R*;-f2Q`Yey8pt}(N~̃' @Go`tZ_]$,5Rj+Mߞd�%J\:ay4 8Pxp P\B.wNHe6YrVp{}UF Rs/;3{lb`_GUaa8CMj<nc?#p]}Գ= {]:1:&<ITFW\9ٮK JMw:�ߣ>%&e.U_;N#@;vG_],zU,z- y4J @pxeG}3LHy H̶g�v{{RaSV)\asca(>St`,moIg$o2F#@@sbPU **3g~~V$dO�UsĞFրP#'@4pށ)vr.;oHF B&M8#gtE޼(8ZNǧ?8yq"4Xs<a>ꠞAJZX uy] mu[}ܩ=}\ mZ@XS(Z iф+[�?T˄SF0^@ݠC`@J^ʁM>ǰ"[QUQI<8~q0:Ql7i==u=d5 (S۸EPѽzLc7Vc<7|"y8|6~DVUZ6]'K!ٖKc<i ~1tgY,�*c&2}C_&kЗ0S ͿiVZ e"?/&)ڢ)dɻp絧))xgѤ%͜{c$ +)4i^;(GB 8 ,@&j& g D!;qN[Q$~ⶵիjq,LW/Kь4A4NNSBPxC|U%F>LeL2=ǠP�]-]=l-tbU(YCas[G*aj90] CHĥ�!@W+fF;AFVBg8\k7.pO2n"\kfWw+\n?$<aTƕ tzLZpC3n=2k zz#RfcQMrnlMzVHQc֛`؝߇6fJ< ֚zl;OGcZy!̥r<fW;-pʚshQ~dH䮑'\<|ET}q2GBPh 8SqZF;HdD%6rmmr@,gL-ͻ]=^NS8}% edBJMzQ=5V w#/]BיÃ!ݡKGV 8_)QWVjaY$԰يpҮL6mJ(K8i/&?8r'C?\P(OabƂWQݍ-ͥNQA5T!o ͪ?CH@%)-, zf$87nv/\[ƷTggԙh]w@ĝQ%̵ryjɓמTkL'K5luZ[ b̘R\ٍBoqwX,t?ׂnm<dw5dn9^vzꏳ#S+�bA�V,vM N7.{fmՊz'tA'�e<C֏Q}ʣ)l?\ Hl8;!LCBĿX\ۧendstream endobj 298 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 773 >> stream xU]hYmj2٨ OER[ڗڪi15$&`;MsDM2]1Q~D /e_vOJEp+86˪sw0jl@cSGgK)mnoM`ڱZbMZˡ07>-D`#ZO"(;X|kֶo7*mA){ĀS?%xdy`=h :|+{S})(':C e1wJ}b((ŀ3؇2sA4i Ȥg+V,4Ųz˘ d޿߸6uNe}8mcL>OP WC14̭d7zL3q.A-B�H LJ(_ݙy s!y*[#Z+.gxn)*>_i?fnOԑahwFOu//κ)zK(ޝMuxW<rMv8KD~MĭS%(c1FK0eo+伆s@ ya}l++4̺1P*JiOS>`$[=Xl=v;if.`dWr/ud*KFYfeqsr(=W9Po362Lt!RlQ 52x~ȶ&mm]aZ٬Ǐ}dendstream endobj 299 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1014 >> stream x[H[1ѝv!-ӓ7 buSQ)Nò\MINiUc^tV몽@e>t sast/}/?|7AQye " gc_t2xq hݫ-~ᠨZ7P!{Kr($ʫ*JʪT2B*VbJ.S\E4k K'(S CX+h/>YBhdnY;QQSYJFpjS2-QiiJ4 g:c,R"h8osX302=rh}2!L?n#A?.@2OV<̵ٕ;�r4X_�#ֲy5E,0dwԻ"ngtjB_6ӉV Ә. 07Du{#xˉˀFd@IġL>-rǻx_RC/t6I?/GvMv_tI38"鑉`R8COw1l]l�m$5h L+glD+m|arD &5䕰>Φ8+mF@ߗ @ .Jٲv{>H=o؉m ,)nolݺ`Aev(f՟ZϞlpwKn7n *m.-n6C7fBx6k5o>Nd:2 u}`GypeurRn%s:zx06N'{KW7! Q>�OsիV\,1P}Iڧ!7oIgr~{O�^ԽՎ1A9kTmjP ͭ*?J/g!Y7L2cca,`Ec/-}2~[1;odAendstream endobj 300 0 obj << /Filter /FlateDecode /Length 2758 >> stream xYKof/@3&dA>pf( c9&9_]$GB G"ZE"Z_|uW?kW腏Y.noǾl꼪.^ħrJR3Ul3x;kMثMUFVÊN^b9ַ&ߔHZ&N58*;|xY۶4w`R :p(Ѫ/OzU8O6V$b^ $Q[?]ޢLUe J ީ]aӤ0΀G2L8Ѧ/]ђ?h Q,y{_ %|7m֞A \yvCX6 e1+wot XUu6' zq(%FEɐa0w(0yUͫUzw(j@dwaЫfdCh(!HWW 0Z5Uײe X -3aj<jq Dhj=*eaKW%KMUoo01@sj[1 [SwXO}1DNbo6a-N wTWl('|s=Y4 *AmǍbm/c~ qKAtQBt0 hrҘ�z@ G2)2254l}_"+D,UE+mY"Լd|նiۢznp ݄)Oq ;h/@;/wM qN gT孬_v.@-Bz&j/cieV٨gw�h5f,RKt�P`K <eU PvП>lI tCFu>KPՖ60JVS j'!'+=._ϕ՜c1>+&B$L8)T,0ˣ A˚qñGb@I: 41ٰnzpIPT-Ye?YuiP T@@ t6mA~HL#==V1"< J(C&z4;q3Y<OCxKVAN^Hs+NZ6nZF D :NLOcXO^H{bAp?'t4Եdf}>3e^V�/:U5aQ's_  chR ,eCRqv9(#C:uXIgA{%q!2jӲ1}O%nT3}S|E8@qt}�ʈz7d9Ta kfZpmb{QS*l,pA$|3z= P]-##)yFҌ*`_u|MW.voi N+|.wC:\C"sy8pv9=pvK'| QyQ<`I،gbHB>#EUX3Iδ'Ի'  Wh~įa>sӸ=.`j7Gfh F?%ZtQosدKe?&R;`�Ѣ]3Fߑ`p[- <:<u'+TͶ qBHyGGl jq&UNڥ#/й^̏`S 8=!RXe>م<HԔh.N3Y)!D�uL-f#0>d5lX5lԀ*V(4ݗq¼@ {& ]{b_pr ϛ>:@>ƌɆ=e,&/emO@miݛb/nͯp3h)3$Xq@7BJb RgNZV?W2@qO34N Pi2|==ŗO҂$\‘I 0e!u-g}vwz!f,^ep1g{4SqY?cBp<shy}gi]DZ$JG6P{SB'V&<\np?RVH{+:t0qIzRDG0*4%�{thҨaUbֳ-d{`B+\ {:f<|S|_Ҵ z"|dhL ΁Zqhˏ$pO]/Q,=~iO'ʆ57-jtf񞎗[[Ad2󵽤h68iHR>9ܓzujΤ]ŗMC`롺2- WK"WK3ocHS C )f1ChJ+:@�yT(]!;Zc)B x&}hfaݨpHF N1\[n$dG>|9o7rV fIǚgi70R3߷[_|Q'L}xX;nltIч3-s<6^bj68zfs9&G6<_t45>`gwF}Q>i"l 4&Ƥ _?x/endstream endobj 301 0 obj << /Filter /FlateDecode /Length 3692 >> stream xZKoYe@ð"@" q�fj#gG`Uu=*<973Iojw^eUW*?/U֜_mމ}[,I+vbʬd)v;?:QUk@?zvpb߆9V뛮 cyOtCK'r0iTV8L&ҾQ<ukI-Nvhv~xW�SJ}\"*JYW;;Psb )rTۺW:aO4S$ӌ*´7aʉk۰\E|+#yW;}za9en9缾^2]UNoǭR93~3V?^ZǪ: �xu1>,\5kTu".nq ۛdC{E?fը|t^kv/gg̯/āD+rp O2"N@O]pϸX^tg:$G֧X, ")dWmD8F2.<9=2ߓhu8:]&ȍJ1ϙء&]R[DY~�WʃKDҐԼsZNGe0* sNPS�n ' G UY16*>и$⸃l9&c9aR<ra $?⫮ k MQIvmoJD�3DXžO,D|;* #1Ɗz"7�vZ-Rjg+cDSG!\x?1B^�D_hU*.=2 l!5J\3r1<M^d�{7ljW&*kn5VcR�1QX<]�qu!)/E ~a=(f7 NӜ$WجDfsYdtհ}͏xg~ۓf9}�-0tD" 0 T%߿d!? j@2]F&v'mI|Ӷ#z }(( hj8-Y9`,\R߁e-~^@p!^BR@*Ozg -n5.|17RR"\Mû 'TPj,>gߖ*Hv$~u}(qv�#pXa;RUPPIH Kf-lWZvWw<41umZ? nAYx `>UȇruRL~JuY ~o|zX<D’$7j6ҥmc,wmAI^JKL;T5pWZ] 0e90z2\ZJAU޶+Y6*Q|s^�)(EOy+tJVNȨ!v>Ǔ_}x`t{DbeN)jwJHHV#VsYw΂uH7.QdxJB1J;.]uhU_ <XhK,tE"JB09ŠMO&!b: T/nKKWՙE2b:OvV/3k"{:Ž#e3om@j22ć!£T ʫ`߿.}X$Z!|1!Q&q=8#DE <-|n]9M0.%s�ʬ4`/Pg�dT"T x.- ;+dB_?C^; yL$>Ik#/гikGXg-F4{3C]nΟ Vq ?~05FtO):vjg, ᜝X36Vq3 ZCџ yImMk]'8"$"/}R+E\X9̐/CeICϓo^ eĚW"nM5\VǺ׳X|: +Q5.P?UR_v �> :?"w[ 8^\h.UtS_M;(XGnGE8Wl4yH'@3k[iN23iB]Fr3sWM3j88`|SEJ|"U/^0փSL}Cj*m@Lz{wa./.kRB~XH*e&SNCaG9H^MmP0r-h!0*2=Εg6.2Sc@U`ߍ薙LϷ8n.A1'`FS4f"H ܓqfH(iRe c$`2]I6 dn3!,h`9!5h9 $1=g4`)(GL:9s˜I"ʁV'Ӷ:@K9[ČDliq+Ϲz/r zh} z Jbv>*@T.=-+߀inC^ l aD8.!YRݷÝ؄d[!P2B&#վO 5*y 3kD/)XXƔf9Ԥ3A\H?#y`<[(BwwwŁc+_'=:{nY(9ˆpmvf)C{'%0*Ԏ[IŠX+9CHp5D@9Ovm2CK4U0U˭Gߘ#!u@nº[7K[AڇZfϬbpkIBVxfZib�.x)dn*)pBj<qUđ^i9(t5wp+Ufy*QGȞ̢fbiajO *^&6rZ_ 5-et&+YV-,[ԶҔ@`nޭWEx~šXnv5_.r@>, ܀X-\J02AA=Nb*+^7l FШ@,fUS(.#֫v܆=r|꒾0u&/aqyagւo9Qu}ZS;Y.L4w+?+Eso^SrsTsSi+1f+(}M2lJ''Qc3 G}.DD�et.r׷ӯѕ?W�csI/P(O+qjظq3&uLJIYKm 9@k+u薎x\s=C{z2|`0c C ޡCa$:vo/z5OR#cfD(K8LAvX4. mCA ;Q'«u3 Snc8$"7ek޹=Q }H bEAs�7 &k':@Gv~WL:6:D�rӴ㱉 j(ē\Ga dԹp-?�9endstream endobj 302 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4223 >> stream xWyXS׾=s-ԪU^VqlUjZDQdȜB&d AT"JQ[k`j:vǻ}{w?|ZN $ C3WlؐLZZY1~blB@X!F/]ȸ$0bH*=g"1!%bQ5;sEnJ{'?AL\8dr hve43mr6 #&zb 8IL%6/ӉD:E,#+*b5$1xH! 1H$(b(1x _ z:acBgI+}C}N540l谲#7GFFGe:;cx?Svg"Z"[%pN$6Mt0 %IR-G2]uZ$SbkOcZ$v!5j|87k}k/ v9h4G/15xB/KTabKlIh{7J֭?k1(\Men5ͻ#,Deܩl栞lmVpw?�3/.uLds_?L RZ"ll~#bP>37hWǃ\iAH^�=p^_lc =w$�<I8u I:<NhMDOuQ ͢T$js ܷfq=[I-:gm7t}+#1c$H4)D*owƭ t<4@i [tXQ/ʭ.ʌͻ2 Dəp?~yN@/= TD=A@w**xځ0 E .Uf:h-i&-ėGxHHGP#`QFY7ЯŐF+ҝ<m�r3. 894;~[>�fwcݑQu_T#Qd{ fC22Yb p&'-b@-T^)5[0݁cz1!L |M�m(ub{#ps"M& S8f"J" JoKbNTh8 {2`^"}9;;vDQYQ L1? 2?`ljv{GTд@2_X0Gd}pB\Z;:_TH<0DŽ?BϐL\%yAq-5|%}42P3=$L&od%^ڵ:3'̏Q86zÏ})x>E0a+0ȎLkϠc$Wa~j:>^TJ) ܫY ‘pHʕt 2^8wXpTph&y&/,f#OsX怸$fG\^W.@?5pZ}ŭbU'9F3 7OXͤD.Uj-M3pdpF,$)(/J! $!/c_˜m JԥRUE#,+(ރajVYdN"i p\11&FN|V(<>.iC\kb }׍'_.aXwbY $ ;Ĭ & n73p uzgUF"&ȆFn A#{ \QY-uo%h)ַP]S#0=F,~/Kqh11O-<^h?bm9DbfQ*r@fL/[kWEE-7}x_߶qg`B$ᛸn& J* k1'B  GI"`i@|d4PR*Vd'\rǮ;~v8Nz­)Bn* y5!\6%HMtXS [?|N W pYoILb6�Y j6Q(90cuqR+7[ZkO il6ͲV4VG(3DB9NhģBʋػ- _d2 |o�&u ͠[s<۱5 5 GɟNzz|r*/d Q2TnՊX|W7`MMx 88}{꯾{c^gP@c� rSۯpx$!ƿ<Kv7]w =>8r.vv 9RVsEZQ&)ڥAIUr={ A=kV`an2|_< 3,U",OqR+*=dN7‘dSނㆀC#&t2_㇃cـ~WIgOSK2nvM` Nݗpr$Yf@P;FH Tm!حX|ڕm�_k)ZƚZ&c{^hŜ`4�USd2 Rs54ZGFXm�ɨUT(4i-z جOrN~Z,|NW7;6sm<8}Jޣ[7gegg*2 |]o(`Y "(ֿSȺ|}Y쫳P/搠80UU@)) T.fg SE}_ |-nqX%u#ztv l i(�wMpy|M [40&7dWo_N& 8J4s\l sW)s>yDx7Cj{h5)ġ$?QPkUީ䄕Bs}qYQSr|CǴ'kU~p\k08L  YO̅g8Î-ThCI X)gzRm�}{#1T[ 0 %.@R[)@ 'ڽM[N>/3[Xv Ҕ3v"MR ;ׅ6v,[ p-L}=Q.Rl#Pץ4m t!ՂolL$J�@{-_N!FXΌYHQ!ϻr54şwjW)8o:?@J y%+]0rFRhv6Vrۇ['/.x*# t\ tI&[kjCcӪo?JBS05L&/<CgOw|FÇ9'PFD%mmMfwԳor;rcSS'-y~WPZXRP3L-S]K2uq($h{E$# ]o$f/hzd)CkZ_#+5ۜ>T=|"' n |>M>˘ـK% ,Mܨ:Ts.ǣ |;Ff>�kW/Bkb/k!4 v ٕߖj(x{uER޽/С=[e2PҔ(m8�yPn~H9(wJYXQ)T| CM6S5v{wO<}Fg\r+ r[\ *؅7tpj5ʐrI(ұZ2͘4U< h4>kn޲mВv]@sGyfarZ@+b->c&�ٹ{ ;\OMd.7WT$eT-~¾9un@<oPRtpSo$c�}?m..;>[Q)~4=.4iT@dm%h�4:?tW)F\J,BV \z8p"NDobv9e9Te6GU:bK$5ԏN g%9J-endstream endobj 303 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 211 >> stream xcd`ab`dd v 5400�qt~H3a#UAV4nne ~g((ꜟ[PZZZ&Pׁ? 7~H/(>GhXKdiVB~FM|w<C =*'rڻڤp=gRߡrq1$p20��[BIendstream endobj 304 0 obj << /Filter /FlateDecode /Length 2164 >> stream xXݓ۶_L�$H83IO76֌|y(HB"~% )ݝcG"~eWb_f_q}z(w3!ϳ(^421L J5kml4ִB�hoT]{yLNd6_u-bRd;–ţHC}~1mݕc;h_=7 "'&fFP4zP$|J}|PUe],c`,'Q"Zd?:*3V·7%>(eeXŬlzϨf:](TQ@)خG$U4bV-g'NL5}p\-)wڭ�}L*K25_R|uA<r`9h%G43͵gUW9u@nʹ )_{܄u8Y^mG9 CK0㩳u6A+HJjV.AOBY(XѠ"UK P螤.%@MrҔO!Y}.8XXĚ% 24 XjkuPMeQc8UׁM7mg at¾Q -u4 UZ!CoL(𲺫;Lx'-r%llL!y}oʎ["HKٟˍn.aUAO$YWñ.LS坽3T:G P 򂾱 vi&G#7f/.ڦn=Cc"4x1vc?yk[=fyhX0XVh<OG[mu?arX9,\E3F =hgk6/ay Yʈm W`B1SmMUXYS G#>*s1 :II!'9kČ#� ">DGNI٩ca.(xqH/` a~nپOw2L^ RBUL r=L�M^ Dӈjێ5|| .c]TOr6IRz!)�ۀޤǑ& IZh'BU#C3۽iW¶lHKD0 9d껊gW +"(~kіy^pToX!\=@,-`9 vÔ8OqZ/ �-6ClPBh_`<2Gpb9]<*:'=(-ȑe(Vv$vܴ7.@ c|8H+y*B2M+K>`YJ yGC#0ڜ&-8'TN<H@-*+{Ga@'*VLVoyxNd&u") !)v}rm.<O\MDyg3 ?f=_?[CPc)< ELי+SF#Wr5]25oZL:+Fk{Z4#o"i5ln&<d\j5I0C&!a;k9Ӿ|, b}=%.̒i< :+Np23:6F ƶPzvhE*c*FEVnoB\@3D�7F5Yh|a<ax%Ť. UuEXS #s}׬5n91*ɧ&u KgRW|ћ$؜jħ"%2Bl7yn QgrzGAOxηw$Ca ICg'2\6|& Ny3 i;N-e޷vSkPp'1zSO[X" t"\I L/L*Oҡ/("5^^{ gO ǹc\?Ba~-ߚ_i2q2 J·1H[5){3uMedLexz-endstream endobj 305 0 obj << /Filter /FlateDecode /Length 4308 >> stream x[n\Wr7~d`d@vhLQ9Yd!37wwOɗ-=m]|{m_w(亥-  mY\NEaI5nUvT%:Q G9Ai]m.l!vTmP$yA(zUY!eRr_O9n%XZ1@r^qs!% E҉-(Uu޲7HܒnziNo'gHnʁ*[)|vz v`lziV-Cb:Dm Я_<Wl8SLVê 7RiaanjC$e'M.9$etL% 6b6y*uLX漥e)#isM5u|'4I[3mJ*y]M�J{f �- Kd:(HD- D%8k@=^ 䉀mѢ EUAfMTZ(F""ҋz"XxH5 1PEfPLp ֳ,qC$Z=˂$Ej&Xɺi@OtkWwpJG4(2ЕAبjB4* AilS쉮W75 |)pJæUSCZnVW"ߩN{]b<_[u瓧M/ɍK QL+ՔHt0I073[jޜj^}lq˚F0yKnkGU:kf Q֪4LU@hEQ%mFrҮ1:x3 fB9K(k^ItÊH2| 75ܼpn^k? 7hő`r;܍r%GՉ4e$At L 94Iv 9:myA`@29C@$*ӟRbwsNHÓr6+_jҜ{L%~Xde&c% eMWV 1 !Jd ( 9~\hd)R5N22t^HfHkbufZf*$Hl4p9&JwXHbUhahAVeTm׌|R"B)k}DTE1+=?^ieaz*|O  2iY,2dCCj BPaZ#yDX%]ŗ@3L&5)�eI, 餱 A6i!@9ěq2.[NeT//̐e6Siy˪ChlHӱ5)"I;M7iȾsl'SP FX"H,@(M|@PUr H76M$VA(Vq Ej\6Ka .-=JDTQrШQQF4kY- Sؕ&ms.[ @D$AR Mg`!㚤:Se<4a"u:<0D< + << �΁$1vl'Y3Ͱj.x}!Y\!o1($l!s$$U"2I5jV'b.LCԦ~NZ%:\j<#.@0\ZLP$h$Hh,�x ѣnv2.h R=|2-"#xDǺVcf=?a6+h)Nn0VL³KŢb,2$}1~&XːR4]2g;†&'{`1X+&F%f+ia*m6oxFpui>\ 06R9I{1y=c`b\giך":6[ wCR7͟x۟sǥc6 RN&rv|gO�K3r7-oInO0K/;}LIolWwwW.+ l# 6of502fgGn@^N;ˇopwgEWìB21 ti(ZFxbJ e[&ۼ+;g,fuRu@_e q!Q )κneC]mmޗíR,- VȜ�c~ YߴyC`El E?$X%[LmF`%ggHTU%iCUZWX8Cgc]W(:8 6(̬5q0"ϡ[0Ci.#xj7<e@$Y w%*jXa9amfհs}F\˙dONT̹�%qɲh~SXPfYsM 6dj6(md#R FDG&@VFZmb"Zh  fܠ"I\_@_3ckmjTC*0eNhx({v2XE/H1C!)3-53?BWD݊VjL8)Rr:(0/tvQEGDt@) 7͓T̳^QLCUo /TQ_DZNwn6=Qe\NvaecPVkyre47Q7lby6Zjf\zvhnP/pQ%Zy GgV[a̲kמ, LPACYWxf/�o+6PnHٜölkEoLMI{tq)Yv ϟT\PDfr!$҅XYVm;Cr .2n`a9g[4&}�#N"yX vR^^ic{$WVMHGRԏ_"Z)]ƚ8ֈ"8N"]@t?i %%1r�N,)IŤUG]v}PZ! $?ȗp@H�Q"IɦuA1{=K)vkti<פa? D݂-Gk*_ek9ĘMm$vv ^=4A)lg j%h7+HѾI�-sdWQG iү5A:d!;*{y@irHb8:\_ YD.ôu-Ž]IިF7:ͪpr]qeB>`_>V6RlppdX%huFANOKK>LlS =Wݤ xG5X$5 VhX:NJT=jhHdMsiW)ӵ罹H2:Űpt[\<�yTé`)Ԙca– 4ј+F:(ײǥ2HnGi1WL-tA't$x p6&\J/p]>kb+boRzw'X<ÞX1|Zqx˴&1nhfԙ|lbiyb,\Ӵef3~n5o6aIfҚ4<FjZT%;/qE#J"GAS@-?B;HgbφPPc8. B'gKƄHIG/% B!|~ u_ Źpz/?z;|}3ry|~?<}ηqN<_?]pТ?|_)pyrlmO>?ãKYƎtW9/̻O?]~{n0Z䔋^}'fR?~\1n1Jx/Fwp5(hۣn ~:dN]cJ>>^Ol뇇?$Q&[Ԡ+Up~# ^ԋKj8B <d[#_e^Ղg& 09z=;uʿ_1endstream endobj 306 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2564 >> stream xUkTSWGKDI SڇV֊`� XCH@ <" HNA /y (hU|NU+R:3kskMS>M1 y,Er*7p/0QLH'8?߷y@ 5A ʗCĹ_k-\]|7B&$\ yȗgfe+ʼm銽ܐuC䩪l_~D76}OXtWPvj2^vQpj#zzRQkT DE<\/N7}}: 6 m1}fW4Dp /џC,H0R"8ƞjq\[f w5H <l|m=VvyLM120Yeèӥk4(`b4`&P3elZ:ԙWU[c6l/$�~?⚸(VaQ&ǜ_G/dxE|D cp-qP=T_MB0bڊk"Xm5΁g/̇~5Z#|ƖUOǨEes%i,5#P,/{.L">k'FvW? !hXnغN W׸30ocv+ף ufFp w(a>ڨsc~{B~LH7!q1Β0DV۳& mv>>}N|܍e<R؟ڭl<о 2%b ؈5"OsF$# H+k/GJ>|_18>p^Bpxo _ZfPERm(-+ef["ڝt\ۅb}Ƥ¢m gz[qoDhf+Kaߓj K)fqY3d286(14l TkwC|*2; G;㥁}2%&furqlvDF /uFZ4ZÊ OQrk41ߩ=VZ[X[k^FrC!O}c\/-ua+w{cuR24Zjq79WѲe!3\nwOWXծO^SzgnПCWX4Gr.۔)K4l͎ LɒF6s||`fiq fqOf&A–q{ZĎ4܋T!57 %륛_嵒SyH݂EZ/oUW"emo!"[ #֦h*'*aBXr I]Ѣ3%6v(zw7a)N,'ǫ^w^jPLBac}uܖUͺHm<4Na ދ#s(khDSU*q F%I ֲ\UʛaQ]Rg3xlO !%d2X^|+O?Y9>;Y`0K]S2NiY]bQK#-kYg2n@A_Rav^^EՕעUy9r2x~X%g 9FR;Qц9XޯL,Jqy{߅.}u>A^HyL7Ika"lϜ:|Ϥ?Yrb~}! -yq44. }04Xz\|$@c$dF|~0.p)%ۋ}"`!l2 h/fd2 02{fSyb:`&v4~hyH=a+zl2uz V(H15z6e.}d2VTA? gD ˈޥI16_6^=:֝:r>n�}Pl:rȁ Ԯ r,,NPwx"0=/�?II-',&v>+<>uK0< y)W?"'rYȊ`#Sh'fH�gAVY"ԏpafH&%B >=.  ,xANa(MH k oNE?ټ8{)tm:<}y9*t%%d#W=^@5&CUji5- m)bjS<+>~_М:RNjp{D\Z,3RŊ,mNvOyݡ}t:iK6-D_mʝNǍfs!bb:=C jVlUY='Jb`S.l k׮)8Z6+,]qL;Ο 5{vV2y%.40>o Fendstream endobj 307 0 obj << /Filter /FlateDecode /Length 2962 >> stream xYKs7谥J d+q%V| U);+�KI忧Әr)�zzzzO`W`qwLۅ-ެϾ)ŪHt=zQ,VA,ֻ+ޚE'"c> Uw+ 5:\aXw("}_wpVA:LU-^'Z=6(" a K2 a֩-G+?1S7 scscqG֫E y Vfq3WEgg?^D+ws fMiFbT'<BD=a\u9Ve3HUS3 _޸e-{&RP;m9 )Iy>D럒K(2 |l3{nL[f^9Z<SƧG"U//Dx?Z<h^ �ׄ;W%D}ٗ;3Yw~:a*ʧpAa8Rs)P�5֚Dm J TmptLݎ`\y Pc${[vy1�EӰSFGkȨ9`KXDa}#[._=C =9u nMC-nCM_iR(# wO3BZbN@(WD/=O δIYRO$)n;S ZGG** �?M9q isU 졣#H:R`qea_ci񩵏 8;Z`>s(1(bnʛB=WFP+–Pi�4B'TZFf2\>A"S|pdb0՛kL DZ ,H-1Vx�U2=]-spKw9Efc~8!Eox݌%�wQJbaA>t : ! Sbwj#" 7~JXZ؋U9Cb~l#U4||(E${Fzރ@,ĉ5R9 j8TSE%l;s"}l0~3LP%&M"Fbu稝JZ�1 $0 >8f@cΝCQ&TBإptNyL Nb3 \/z[Es1EҩtNdߢdm'%H vSWfpFL3I>#fcLBkE'T@΅p 0 <pƧM~0=_ 2yovS')Rns m*平eW~e i^-NyOnNBNw[]+}G!hc ? !B~1ϔՖQwIDUu=`OYB|gnCN?8}roڻkvY$swB9е7謱7k$90)]WWǫ+ @p-N z:t6>8LV+½SRQ08m f+h@ɪ A艈,�\),ѿF:ۉd>4u?Xbw;F3^aYULJ%gC6tZ~b)ϊ<.1*'EI C}`Fdb&Erj^ˆH)lYf{=,{3W|NDYB<^Z17kHBiY&'iK"SUoJr4e <s~2`U(}K9U"ŌP;؆sMY7=M V0Q>Kց:FOeظiپK*PBhr>ԕr\!Ҕ {PGgt~W,�be'yTv/::5�A*l MmV±(+<tَ]<>j>=Վ�R{޾9}$ք*:zCdק]s3.!&7z@ sVBm<k ߢEQSpumJ"qU<JdPRF <XK{E9"e(J!jϓ<#M azGGWVUL! ]چFhvzyQ`|mC(.~&3k0/NUHLE`aSYkSu-Ā1$-DSeQNs7m@4jL4~ŜH6N!P%{ʋ)XcԞB�-e<w ?aUe] )ʜϙ&zf=ʩ| 8Ap>h@``P�O(LRmz@ 7R`}�pY@قU#ϳƒ@WeSa 7&mŢ4YP,5N>inrY &4O^t-gMǯ_ Rpj`hvnW6EN0ګfZ<i[O[܍⿟ـqw<_g)fM& Li@Hxݔ<sҟkj;|.p|͛?7<ŸWLe>-2X%)S\@iFMƙ+{?3MU`5'5Q L"xۊ!1Ɯ1Z&X=>o]A摩?Zǀ(=<K_.ZSU49t|f{ݒʎ~;rL?(jtjNի<“@Q`,endstream endobj 308 0 obj << /Filter /FlateDecode /Length 2210 >> stream xXKs77'.;URV.;8T@�Ry`HQwkLL?<so~q&Tj=yL뻙]!gR%<5u;~Miv06beN°nAJnW{2 9{n7Ϥ73z_? ^fS{~d( /tf:Z~k(v=r=@p[IRT* $M5)s Jr?4ceƅg =vK/wc˱y9a?\ʋTA z*vE;"'{+-LqNeuwWSsvQ`1YH%c 8+Qp9Ŋ}6Q͒ROpi %-R6n5M2Fud{"_bGD8T3-o[-0.>?Svc0`J}.rJ 9a_2>1gsTC^s͔w-לK8c\UbH՗Qz$mJJn>I%И<oXw?S+]|m*( aQO<#>٩t9r="K?�s;e}z.=#g"櫷zB0X\FQ~?m2Ggi 7Bzð{YlX)ϹdCE ~!38,١GzʠcG!Sɂ-ݝۤ> f멍a-fcӆ3꾁? ]5vȱb0ՖvJ㩾 |c:lٙc+FW$;veL$?D_%U#39OdOR'۵ڪEnq=b&nj`Is˝ۨNİ:Ql� =l!ȋ׳(u7 պ_gti jyWMjO3VA`ٍnT;v>�O@�UB Q˰Ut?'tw #T@I5) ~+lE\ݨ<ܪXq&, qKfOʲ흧4S~nL`~1҂q*܄PZ"[ط@ Y~q'<-)ݡ줹%CCEB`-}]�La<T̳Z �'K re,""ѿ6pV3\O I-ҝQ-ɍǷۍX˞I <~?F)v( Fw;ttš|Aja,{&/'eV,rk"S`ٞ%x!S<>GWicnB"k9%bBsCZ%r9LXC%Ws":CɜA,˜hc nze4QI;ĺ'.b}R>zMNCRjm2t~qh6:R%XW{*DlfAgd'^]<ԊdXE.%<šJ㶶Ы Ϟ` V! @;hLёJ)C$GԚe@=>.�s*e@=rr� \I~SA~!6*iaJVeMe*#=ۅC ո0J}G8c`ө ){+K,wNPY_[y(K3`+Y&dMvS&E2@bMq=NI:<' Q~V""(gkP4'Ԣa Jy*pzVs�`x��_9vs�I[umcCǥۮq=E Q#c҆Ӕ*Mr.X{tFw@ k U[lxE<ORBP!}i h5S Hsw_e"'CǮǻIQw²[Qhk".\\~jwG⎶)p'v :JfO4pM@|iۿ +=X<B"|a!zK+wgzv7ɠZIƎXáz?NBOQkk"?-uiendstream endobj 309 0 obj << /Filter /FlateDecode /Length 2044 >> stream xXYoF~oȃ*=$H8MpU<P*b# IqC]=fg4`c?3co?xh<_ 6VtsH[ddFd\uV62b,P2ap^d>z9ÏNäÑ 8wdƓ2ʼn^ft5R*ޤ5"؆t9q@),:eZ땿#IbR42?uYp\XHRw\Z%K3RqB;)X1%Cѥ,cR1P1)|UWn[ 5l̲K'81#,8 0Nuvo[K I@0P)01N &D TA YVQܳOY4dn؁\ݐ(J3&EeUOV4 RWU&1�RdP{xѕOy퍾dآw2B ;Qp$G)aE,`xʐR54?#-E"i;ݑܡ_.a7bnk20V""N;q1YW+ߧXɆjps<DQQDwH34JlHbh8,b;Q[WF&jPƟy}l$ƃT)p<v-x rO�hW.8F�4l`R/z^b.֑Z_|S*A]¤cɯ]YZrjv/_ް/ 5$Πӛby*3z=q%a}^m++ȸS�'59MAIw{DG|E ٧("f铣Oԅ=j4 O|Cxѷɺr-te0H9{!XYEKb JE}I`#Wlr1$+"G+GX(,4E"Lii21V:ǺTu̚\F6嶸1c@٣c7Iu ;U+-%J#LABt" qp0ŕ@sW|D7сu"PP�bi8ᰰaʾԖ 6fy_32adka@" y4 Ap` 0w}_˺jO18:B8r̸v"8ٰEsnr|aێSTQ .Q͡fL=ޕ 72Rڎ)$qrcC'\)0d�sli7xl3붯ir2usŭ844XЈ2++ �.!TU e `]^i7 ?q'yAҺ>98}ڎC�ƀyOC{%Yj=G{"Y'.o:m ,:_Q\4m;Se\7$> ߹qǢoNN,ߡ 6Irz! 3'�gVכbD޿ӷE/}tgmB}1l&1q`>ZPKN=+Ȭ:q=T"mŅhH][ܘEӵ.z](/M}z?^! CN?y,ƌX<BcO �Y}$,آ93TQ!Sjb.mV:K@P NF,YH�žf:( pW6s~Ql/0};>G7[>2{>ᘸڵAERu&o3aVMBM2s-�5]hO1NVQHzԀ/*/ k\հ_CFc'-D`ul7e<mqY, wS64tTt1.)#ߧS#* ~^el7yLz}#C}`o{>| ;ӹGyFn Ibn1endstream endobj 310 0 obj << /Filter /FlateDecode /Length 3275 >> stream xYmoߐEV$%J z.A-hjC}i!k^v%G/q_yD{W-+3<3:ݩ}J~RZ/o~+YmoWB]f|u~uKS~ćl2ݖ&}5ovߝ}ײƕx(l^Cw޼y~揠fVFjjsʖ7mM֤i2=`}7}2Ter[2YIw`a44s7cY Ie鬒.Ǧ2]&Ase4"}wO֮*@UY*~046]fɭnGvT`<wpoQۺ=kq:\T(~4B+qnÊ,97" _=6C+Ԃݹx Z~VvUXn.AkKJyRyߜ/udLs2j>SLp=,_M*<\{d9gepIg\?o< `$#>ixz =y%ڎ ::�:cr8Vb$a@eKM)8(Fz0v'炰fI rj'We3�Gk%yCIavz7:|pNeV[D-+|JLyb7v26O2A}5�,ny7vg^EÏx&s?&EMN-OTp"߆y&é\׶m9(�bB1 -bqMMB?6'vr9tR7: ~JNMo^q ?s@LmCw` ^Q9 AqK5sġ0] ,'kkX+VJ2qZI]�4]*|2}dJp>,͊`j}U{A(Fܐx/.ՐYfHN?4$'_slnLksA$ZroQGJp*p Tq "tj24.¥[a$<CU3`@wܝG<t[ Zii+4MJ9j]K*c]/ f fE%)w+!,-|D˦6?,ߩ̈, x{vm' C+|Td ^j|D 3@'YQxȦ_\m8–l?`\ȼ?u/fi`tb}., W&'A[$@Ec!=)9LVX-CwXwgFa07S|0e a!n"SW=D?ÌtKPJժ9W?KtQQ`n.%,Pps|,BY n>A@>D= & _G"#<fTA@EpjfDENV N1�+:i"*"17bR4]a|1 O|[Z.RBعb, bEc32>l8⺮ s~ Ȋp8:2lYp|ʒkxEpFv o-2K9ފ & īDk/S*_3})^piS,c $bFyJ2AafAvTRziWhkcA"eA7gǖ8&+7;Vv RqD1YX mE%%fg[jOD4,LBRMt>(+�Aaő,6n g!{qUtJIL6X@5.Kԛfd)S33MYeyZxP)snK V=D (al?kCƣW*(xhf<Q,V*d~�7βmB:܆}, 5(Q\Rc�Mʤe(ȉüU;7nԎ'0<l.N]%IþxugľT|` =~]4qnШP4n Вy~+> xnPan0e& srEz4-}(8&4Uy{*Kp'_Nk�΄Þ ]\I̻0Z-4hbFOdK.y7/;$ @_v`}هv9]*abb^`@̀H!%<\k|&\�gA"aD rWty3Q(R޷auբC-TV<!b o PQҗMm-1*|1Gᦥ6�hd>9 2jq#h(@#=z,a;tb;MVzO e1ɷ=<d: Y*/wAP,4rКҷ#jk9)t' VW]s$fr$ݟ}Ĵ'Cnn=ATNAX]^!Xzq;%a'rX${1tp] ˰qjU,ެkHJvn?QPst]4,XeNqMmRxAlV]$ɞ Mx/[PF8u䎶'rX9UQQċ-&P} ~UmB6:9k(?s{y {_GC2NSf4_Lq¨X@Y@cQQNE!=_⣖sS!γN8דT#$uÐ�<ؓ i`l7R{ o_⏝v@j)l`Z}߶AYHu~8J͍<`uX0 X拟oX*c%ddd1C#[B#cWQ/r 3=8 ;,*²[5@�n>}q7zX>*ч&4w+>}ܿ"0I/l9 *0 ۟夈~&  |pV)Ḍ °endstream endobj 311 0 obj << /Filter /FlateDecode /Length 3211 >> stream xZ[~o'}X4ImmMlwW1%%*;gfxn°EΜۜӴŴ?w|M^SJK1F<t_On'`{™ ?]LmP"ׅ:stW\J!sb67^eG=7ɻʝ~D RةQV徜nU9m&@,s-,sa@qadKk=� # oP\BFۢ,rqa͐L\Y@0B (#KApDO}|3[2\y td^IKR˰~B O6tse4cćk,F`ZUP7۴˱ Ky珴L )DYe 3Sraw!_1lNE)!!l grb_OLz(I,B?$TePV.)($k ˝@i$Nhmr힂rc"Wl_-I9es$K8(E ].|’ %/Jvټ y/TE=/~Bhs%Npn8˱x qMP-p(Kv-A=3v;nM-A=?v;K퀞e;-͉cP#B?dBZK/Ox#?9c[\XY-Gj%&jOWnܡ~ݝu 4Nt+(+GÖCN=TS 9=LMxsr:n090nLyQZӜ(bj @)ՇGCx 1~ys|ۧxO胎1֍K{F=יyJ1]7[o-$:EN ib f v}{܃olgc}8VUm Ә/MxeU,lv?氧XouNuvh>=pDDg#�٦l/)-Mclv& gz"wY*]=`k큵\SN?LO1<IQJu_ !}} #%/Ko zydBN\L}dodzӽ)8G JMuh0,T= 06WWPk׍H!JQ9Iց:X}؜93=|b MKuǠ=U}^w9<a;<TJ9~ø#v"ٵOWՌ@s9"nqUCTQf[DUmuٲj&RK֣Wwf!c2zjm@+@&ZsadNqd7Fs"( 29fOg1$wrYx߬\mrIFe :(am"kmNCAt$Q)顊gzg|Կsz{uL >XU )"¶uƌ jġn[CK�> 8f_Ww/8Cy=[aih69n,d`_a<HYƤjZ\ n}޽(7§ݼ5*5T؏ /u'tC҈ghhL\y4pA&70mm`ڠFxsjKȝ0zn)v2[d:F66[!8DqK[ᐁН9:-DJo#wC\iP^һKg I)PClUf ކ+$q$6"~Rp¸\Q1q`rAL�c*FS3T p#0vF"TV_h4eٙ{ {ۤa CZ% X ٢źs\,u>q;Ў0r9JcFs FAbf!eb"9=Ξy\>m|@@S.*{A7/^W[N*X^li/mƝfPѥC�`.%S =N@o&| ( ;\;?񧑠7~F Ldo™ f+RJ>;-Lƙ11l0QvXӘظQ б3aH"6i;~B3sP*xzKcZ*uׄ/DW8*JU}9fwﴌ@v1̈Dp=s SYbSWQ涔' KX% s|*e]ZC/v%w( ZzAd« 9hDϾtsE]= 'CŒ#Qd ^TĦNOijUT4z(J*z_MvD(gȣ-9:8n�$hiuԣ};Th MmGڋsG |KC;;qãUC",_Px gǥ}qldH6zfӚT0$oآ1/3<Dפ˾NܗUש%uCڦ @Tӹ3c F^(%Rq5 _~jwߕ)D#ـ`jz{ũ#9E?<Hu"M}'i!,D#6  U}|B=6k"qTӧ/sHT16|)C|Rcs@xݷiGQvެ?W3rpKSgB0Lh' .Y:^1T{q\D)FDK3ŁRo{J.ISqqǓY+8hڭTy!ZUmuooΏer͎E"\oܛ| o{IěKƦ]@馮Wפ/xǸ]o!nN%[b;'?6!6Crv8HIh 'wۻ=%ogvSi@r�endstream endobj 312 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4039 >> stream xWy\ײv"cNT"+ aU"v%Q1F& p AM@ qaq�Y$5μ33LwO9U_}U1ư,kos,7 !{˕ 2!Sq##9ĽXv6Lq\n}nFjrJTwչ6b㛴159Ǝ^d%[JJ IU޴fi|b;g݂2n (g܄Đ5a)KHS9Nu>}Y'rb[&1%$&c2,cf2q`V0>#,`(Ɨff!3S�&1tf13 fBsf$c(QȌf,X1c(9̥3F&v.[1sa׆&6:atK)-㬹f6 g?v*S78q$}&OMMU?1gDH=fkycpL݆],NuN#t*91*\+m"́)tp R{)jV.i.+QJb%=AvJ'TaW fEڵ!ZKśѠѷG/^)Fu7ƹTPg<nd=\~H a39'Tڐ}})<ad7ʘQ1%|f+vleK{G'pH_;&}A_GK|ZEFwx8uZL&S4uL瀑.mMFs"B$O@ӲMuK~Z B1p[S7BS=\@ lo楟NeR}L0چ(7 8chA.8ɕGTnlB<w: #pEkv^) o2qu �s034qZYh8b!K}k-;0H @&J g<o?^z31BkJćxuۂtdE剝C쫛Kt4G`f=x[_+E-w5w!jުZ1_cE3RqO B7pݕ_P:^)(žf(Ԑt>J˙Czd8;_GFd]0J"r/Bk"K:x,K}\&LMK`<MϘm+N8!y?~ YU^=t4}.hvh-LĢHfCF6GFOq"VRFW~cpYGZ�Ĩx 7 3<f_ #b)LO\!׶z{ء^ t8LQoE7j([wlٙ$ yKf;D+)f[S9& 49SР70^!- sKEf*^Qa=0J KS*|[Qf"O;x*:VԐLpa4"G{KX/][+=pS}  ;tRۼֿ^!oU}Bpt^^)mw&~࿍od!b{cMzg'3oJ E /#35mߢtfiIA=%AQ5N6>aGj/TAՠ˱� H+!V N, \V $V> 25n/*PM%"]^Qr&5(ia׌7DZD N`GD6Uktxը8RC􆄐tnmc($#n_чr#ێ|r B;|c@l̿j,-R-dN\|ڇV+1o0/gE˲Xh|~ɀ=lvš 4M=x@)Y6Rj87`Sթ Iy}xjOY9X#|?^n,]t^GbrxWf0_,/>Ls"2MmL;+qg.I@QugY-j߅@'iPG %jI%$» NUKw� F1%u"m~Hu^*_P5_]ܻ<lsl)rߢ1=lqE4ZrG\Uxk�紒Jràr&cy$FB{8jx%D1ӊU,.Ve@ߣFa=OlWL]Sr@9ܡ58Ԋ~8qʥC \H#*obEyO|�"zXCötiG2X`t1L:%' 6sg5ӻ$EQJ8^3L<V(!@g\gYTig|AȋO~:LsJ\u `l@o!#:lCϙYGJ3To,fQzk4K_)^TF3m8ʔml)Z|@DU;۹Ĝ~6vm /AV(1+!mSzV0䁖MV^Wpp鄪]) C=Gʋgh6ڟ"*L; *aŔB`#}lZ/ه`5%ݻ25�{~L#s:6m8A2#NfؘFVImɾdxʃ'R%ye覀9wy0))>~>C7u|2u/zÿ?] ;vibFTO RGlXX?^=e8akn=icCY Jtb U]9ADp 64Q*t�<]s ձS&;Ǽh6l,n^]>Ȳ7q"C.|k$=~8zj^ԎQ6b_(NI[><T :n-\~d%X_@ܬpP½X_oh X+lCLIttZ?2:>=ORfݍ7ޙX <e/WXԗˏDB۵r[~S \Yw,omqjO<T$ iS@O؃^)q司˕"Y})^1;_WROi /^8?'">PJ Jׇ@6zb> tbk! D~IAq9.Is XwjS[ayTDwՄ/=)sf7?uǠC+ !tw'h!_NEC x,a'T `k<R_Q\T2r\"_Xr/Vx5guBX2fhӑP?R1@8">?*{~tEK3꽵d{Xu}C' sY ~vrJC^r[H>k8@Y;bVY!$KP0Zu)EQx-4}[oHf3"[-E-bqV6RQuޢ</'^ϴO?"Uą/[4VOEDɍޒs[Σϩr6چU4ؚGlD8$yfa%L7\@[ >pq)E}>$XIfd`Im/^)ÅYf1.:~=2֚65o:a%endstream endobj 313 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 305 >> stream xcd`ab`dd v 5070�qt~H3ag,[|<<,K.;�#s~nAiIjo~JjQBP~nb #H 3{0GX9 ߋֳO[d)Kgz~7%l}u&M͟?-jDo[O{wGa\W\kw>6e/.驛^;}nCX\]QRoB焺.yE|] V?f}띹w\{帘p20��wendstream endobj 314 0 obj << /Filter /FlateDecode /Length 2037 >> stream xYKsΙ|`K3qTmRvT&P, pЊ{f�.G랞{Z<Swzi"4ӿ/&olg.n' 1u|jJvrJe]x&k-3amSocݝger&@\r5^[vXהu j(%]ͤZ{jp%�?a5e,_uD-XqoP`~"DtjO__huJn  mY ͕}"Q6Bm6R%=M;VK4ղ:kEU4D\^ėkwŪ\-L/ _^l9VʮX8 |.t3#+Y1"MA αwWfs- ;g`9{ 2]bK/'vy5A l8?_oḀ{ͱ B!CD)jVJn>zjU7!60vkܳ6@@uGQ i]+'$<q,~7\wuL%y5]MI0mHMv"((z@؏1S r8G,pdU'= aKIY7_uYjWm&>uꈌu%(w�)F-х6ݦ&sV\>q1(X=}aUؒpsVky6qӬ'rbޑU#쿗/XSZNlwcQؠ3!/ ۋo;fŠ@(@wa-q$āŧq6jUD%)"ڪ v"$8yA(D-Hȕ$d@<œ* P%2c^ʙ^__P_7 ]sI"/#y"c'<DJJFs-qDZsc3x;gD jc_qx;#\v8xI۳)脒X<dl됏zy?v4Mo]j[qR&褺�h`f+SnbpNϪ lF6ɔ* _pd&Y 5 e-̜5 O/wl'h/7,oҀ> <M&˛Y͡#C݋MM)vo ;O# ZG !+J )o ]\b);:xȢadŪF? +wS << aݷWh$cdBen)$-R.=ٿLZg ^NBڒo3UW^W3ZtpB&59.Hd\̾Cr Ւ ~A( ]e7Գ>Ta/{8"Ms;(N4%PU%΅z̏R eQrឌhB451F]^+DXgِJRiNAZ偻 ۝q- $e!>Q 16sr ހ`yXdQ LsW77=6/ۙo60GZ<UghyB'6? jS@aBXaM;ryH3K$uE$H F/qlxN)mnx=aB8Ik,1OM6J]SV3ia5AC}sj2wVkyhYdU?RRqʁE7E Kcn] Q5]7ŰJw+C,jՃMOR$3MTQ'M ^=WOvU.gh<'7HPVhms 8CpFpqi 78۽$DKdu,2ѷɏ+H1endstream endobj 315 0 obj << /Filter /FlateDecode /Length 2932 >> stream xZ[o~o"OΝ3 @f؍v}iFJ3Q@ XweΌ)9( ji rk3YXsq%L>6uKN: *{}{ JAMyݠ\iZl} ]<"YBL '|xQ*"#T5��(Q3`-<2*rxEn a=³0=ubn&Vd_7͌SL)YJf~D<[O670:j cc1" @ފ3XuYrj$s\Ҝ2WܱM3"9ӹ@8c7_6;({[7|)r*cޜqйɐF˼s-8EŜȍ\ls;Bިàa\-ɌAPAA'm�Z}<DYrҪ4@!P&Y/A*1&m\�%m#Pʲ�I&Dh{`g?\QD}Rg݁& oAp{6?|(GAiGTtp4 Q0)ՈOAi"*IC�i61 bN`tRDP:)"*#QL1Ffv$rh0&C$dJD!bJ0HL~ Q4IC�!R4D̉I!Vس%%b^4)NHsN!XL%!ңRAhQh1FX7MCLQI !bNAb~$)iLQɤtR$Vr <J8(騉T$u$"v<5+*E#u)@GpD]Q*t{tE$]t:(x*]t2tETZБ$, dR$ =(ICJAizԩ4Iś*(xw0G *,Vn~tw6-|Z :$cֵaݾ)8`Z 4 D*F=Mi0^7ʽ*k*KX{u99Un^2EPi$TdR]5@_0Ks as*?Af" ߴ>$)+18h>9$ea\kf=W=QKǹmi&U,f}on~Œ6]l]vMFϜA(?AP19ʩ{mWv6|gh\T Hwa^ݜ/DTl>Ie`'A Uܭ6tcdW^-=ÌV)->[z[j\PҠ~&IEࠕAW1wre\ U!X44yqq`\Zj l'Y1i]`mEJ%ǔ4HNJisqXv}-�VUVLKݠ-&D A&irHWDSh_;FGB¹Bʅ.ȋ<^?]!ȶ]˥gYH\LUn.awiwwN� Y R/zk- [�G;-6%vbd}Ize}6KQp_?V)mnwgEU *Lv/HhW_qI.il{z CkM 2pa.VUo9#/}C;bxU`A{zCSÐcHSi~kΧ[tnt!j0nua\1gQn\`9$w-&^3Nfnܴ$ת5Du d^<]C<^VK/fK/pXXx=Q!嶍A;`Tdݮr4Xriʫf Qodq >Zc~{6|UruvN* {6U<D~�=. Zv~qgϬ$1MT*6LL͕˟Gqրg]j20V[M $JBFF;QbTb �q1@|b{]ɺ3 5atDQ;'WPXK}Q  k/Khܸ*h\# &/( )/\�PvٿΎ nT\}t~pK4#8u;<.~Qr$v1-tCM?\\ࡒrS]zrܧ׃-'^+A+H*XQRj{]X pq曨[1^ [؇qIN;Rs1ښiF0s6x}}SqN\@Z?jSa8U0SOZoYA S])JW~\`%p kC,.Xq=77a_䪟! jFp!o$- &Pf%)e<kK&p*٭+\').%qATew%)?bš/[[S7wr@ʶp ƫޤֽajVc6&rk3"\s8],7KANd<r;8T~G(\qqUҸcC0/W 6(BQ}]B}E3\_M|S523Q&7|sbfa SW N7|`rHzGw w/ȴ2%B}urS+Lej=endstream endobj 316 0 obj << /Filter /FlateDecode /Length 1407 >> stream xWo6_QHAW MÀafLd9eb;]Ű->)(fB6ѫZHZr͖"M#ųJ6we.RJ3(Ti11]M:~XE׏ˮWꂑ[S&tpXVv"OkNiT2G9K:EzVF2POH^0}ܷVU/lwu llAuegnF OOW@I_y!JB {U橢QѬf yHIyg9}~uzOo0=jx9$xZ(v#ߙք40p|gGLL1: rBR׭G<ml`ٝތ\W×&!W[] du1|rrQq:$rfRv^at�t!+O/W$H qzx{yc#͖U}LGDކZP窭^\_gE.\y8),ߢSWo&R܆B{�z)u1ʦЫ9V.)d'XHbl<b ӭrExӐiSV.w.wkDUkælL3.Δrޘ`!'wHW%H}\TgF2:Ji�RH˥ CZ现}p"Ew Vx4vqGW9nS�倩ccu[‘w+F փ6SyJȈE n�Gsʤ[U\Cz qNҜ, L%C"l[kn㿂bdE�MgvmNorbfn)t[uPϙ~6#-"I[nL-e9Aֽ-"Sc[V9s2rC$'A+#!-]l `o76_qtXq,?4DǨ8'ÆDhhdn4g0?vv܆ZM]]ӛ]ݭ  T`9T@.ԡm\T@Lzmb{2'# S?/i#�+8z0TP_x/࿰\ZA"/By=m `49Z~P F6)GCt`60QQ?DӒxy'z=T7X8<q#qn07F ٧˷Cil/H8?) `?(g. @C #;LSExl Nendstream endobj 317 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 6792 >> stream xytSW5^B V%!% bC`.YX֑e.l0i BC$$&u2Gy7o;uzY-^==^+{eܸcR09`g|&Ǘ}A-�X, s*+CVm9@\UXðWg]1rnռ ͋o)ښm;V*{|1^yy&ei<Æa؟epl96[=Ğ ?c X!&6`sy|l�{ { [alaX.caOall 6ch6 #Y{hvasrdxG&$^W(V}s ?~Ұ{,{ {Ac6蓼y?788d}9O}3=r(1=_=e~. a.lИKT<W*m6#4#,r:#Qѿs`e5+ iVRd{1ՠQt_Zͺh7�)w�T[WʌuRf3qƵtv^u ಮAo@h癄4\ T ͺy,Y5b^@<wE .k[1koh? ;%ӌpQ-U=>>^wW}4l:qvF*dW]Uxc뗯Rٿ nR *4TMєp]NksHV\7|Q#yqnPφM~r|mrSRJ�<džož+u|Z }&|voCIx9u weCSj1)>v("Ϙ0r0u{ϤS! A ,F+g?Lx786ϱ�n>fU2YSR]m g^`F0|̆tW`NTjiͲodln)M$8>xǎ ;PηztQ@C4I^aJ* _ ?�ЍŽ*öxfUk֤AU,R/NB:|WA!@_q>ͰnJCus Nkouܠ>NO]8p6WF"6RwA7*#gʡ@5ɥY"_XGlV T\,QĆoɐydٌ j^zXGH$`ac70CGu^LfC]٩LJN)4\7z3+S&U\R dz@2Fgzk# 8q4N3A8A1|Krbk󧯺|SK=:*ܗ&a]00mХO,!&09P3�nt�y)<\PSg=:E�Q΀: vQw`3рfS w)GG1,GkB2<$ 3BD5j9«dJ~uHy<SĻVan\=  n#U %*A69g2[Y-2Ń&IJM਱o*#X,hXK] W_7כּ]p [LĊ3k"47=ã"8czZoꃥJW~"8^̽ V�>[uD}aVOp ܼCW6{A#y"ͳ6K$L_%ª@.*Toe '3=/2�CЯRz A UPe_D@]hY Y7S 5PHY"tbf¹2 SpP5/<^ڱŬJbJ TI[MT%l 33^^xzcQ!p0J> 4> s VDZ. (p3?dק'n5򍡲pR/?x\8># ż"qRuڟ*V`ZL}T"Q#|ݎtg l 4<Tj!ELe%Γh?HbDèa8uHpxR:ljfdxv&MoS=،�;wE'GApĵ;ay+67'xL+~m&Fb6 o`ke$\P ~ )~2 Q/g$hrx> iDsG2cN]jHWpM~(A O=:Hʢ2󂫽k9kiAw?/|1|!r1r1ⶺd[hV$$r)Vg&xC35bt >8^iD9$z(Ίh(\DD4WPsR|^r.w|MA҄5eM8ϻ jEI\l*+J2Aj`u.Q�m-f5p9<JOuz@F+hC,مr1 :gvuL\ɗ^ˮ0w!Hiκ^&قsӼBeÜ(mlkhtDEO~:hڬmR~FIe̓b%߬Y-g<GAKE:"PMUC5!jU(j i{6=&#n� <JdM֤s�;i"m6 lv4D=p ,_ąR%Dhf́XXcp2;!)0;6НiD_1FYH#=@L<("*\Nn Ңl:}״yf] T@okUy5Rx�+|Iźm`/[(H»fGpNF%V1{ !B58Im:QT Y]9:W r*pALVB{1KC4˹בpiC>f<`C?ap8<Af4br S̙SSEZ-%Ai Hy:Z)jGz$ ՞Q0Ō&Jxi8ӛ>z${7$=y!R^rOC "tZD$Kp1װUpfVd>Y5�(*aRhYS||I KO2+a6WQIWYa p` N.xz.,sA90RaVY1fUvKlo̙k<82|N "-=U`n�r vQ4}pC0tʎ-:J@) ٰ{x77"{�@1%*f^ 0|Ph}[Qqb®4-D`$ /wGi8%$"A[ND x 6qۉ�:۴6цc o!15c[ ]69VamC;SUt) )kǭg;Ld*LZLѲS <,n�ց-?4#\8|wޥܖUvqWC+ZA8|˝/{~jd1Y?+ƈiv5mV@~_gI=ր߁ {K;i-<=_U� KX+U*΄) V+PPzKujTjP{a~fPor\!~f_uJMwv>q|6JMnܸzMсcG|];p/ @�;.ɴ@Z f2ebZ#Ӓ�ja(HeD,;#Mo$Xߞst.Qu_?A"xe$믝і뇆3*e"t(  0{j㫗H$& }$RꮴkWe`'3T(RWM[eZz"Ō#[pEA#V<h7!򋉚)/y_N]mWaӥ'�ӕ K[豇qb�{k?}^Q�d5!qg9Ȅ'FZײ[ƀѤ�/M+C݀C..ظdxҷp1 떅w[#ņ4v7`|\$qIQ`,$HXȞ_Ѕ8qH|xFZMO&*p$`o 2AB>:!)u0нIۂ{ tހHjtNlOF Fk.Ў X-u9߉�Ҏ3<.x6ݎ3/2rggG-M %i&J>.XbwzqF 2Ѓ3g?|v} h }mD,DHƃVyWX1q|@Qe2 l98(GcQ!W jtC<5J"bRԹ>uY<)!ČtU~^γ]]i~WkF^Yր9h{GmAȴf!$ڙv بZezIU.k*!{| >U7|0/[NzHdB 2<^~wZH gpE6\$i+Ӊ߻M&Y?5? xT ut6oMk(F!x5>G|PDO*nO) (QŽ*$Jjx�Yp  ly[$JN$iH^rӫT\y~VlhbK  C.QyA'5LΚQ4]H Sʆvfi`�e[(Cjr)Fa.؎pqbFH3�3�,kX_:Ҭ[\8ž iuj٢W8#ZðO^܎§ZMarr`nfۙW:U f? uoوhPb>v <-MG`~pyԘP)</PRq4ܨއnn5/ ;:[| �$ǴO�Q 4d_,x por҆,QE+֕v:?q.nyz*Z67Í^ 4P{1ekҪҪ՛j"QC_#7cC!b`PxAM^b9|9n ۑ8r`7&mC0|jY\H-1shh+d2#tM!W+) sKn$_s-?Lwnȏ Pُ:Ar9 )zEڅlxNc_DT+ \Ÿ>E4)g<boJbH*7/[5iդ7&%!DyP$ٰ~|C<]8i4b%HDI񀽍6e ,Mj&5+8!v%ajn|۱У NY8cfO +cHu@X< ˷ yREeKNJf CrwlWaoA֯ԩ jd#Dc$rkz,L_6, `^?OɱPj|xSvҁ+t]8gfe&dfOG u:Gx{UU;yS~kyrz<^ *`\r Ά`a2( ),:#p9%:1. mG@0{F~t壕m9�rϳ%0y{M4 Ko_~fRerVfxͣ_u).\ 9w^ 7NM-sPbU+`\d 9AJf{>rHyawăl32 )=SiT&1`r\$dQY|el>=ϥsiFҊ=@T`i_Ѿ}E` Rd5;OOF@K`E}J'4j*d9qZ#gFkT"0 ѩx$T>I={n�;^ .{ *&*rF-T)Jw׻.۹yw:8s8@ [ #o?{T6Ca"X.#Z~\s~_T=PD%e[Z<"d|iƠ2 @�,DO\u;Gklp@bf-PSqZ}aLae-ҋR,ER� g_0mWa}Pg0qRpV'Nnѧ_Yendstream endobj 318 0 obj << /Filter /FlateDecode /Length 2306 >> stream xYYܸ~*Vx袑,`oA ڭ[ѣX"YUXGVj+..y(u~lkCd?nxZM eo{ ӡJ2L"]&+i$ LE{eWN t8wQ:,հzQ\#NhB]*O m,3EM_Ub(HJ#qj:/3y߷y7mQ&Qb?o%,: uYf؈W~]ơFۡ@HU`~ H&uӷm#Y�Bb%_rlKpO8uWMM[dzS Cُ{~W> <6plԣ@E)v%~ KCwqmyUsfA`'C� J`X& 6GyORKYESw}}9}d\|8+r U:fnzQ<W$K]$'ǚy @}~w._:m:wW&֠;^|bJsutOLx Q24HM|ۧw|,S;׆~AԻשC%v 9f q ZZl*KlJ%bs6A+)i"Pz|4,}ْ?}F^ZUj'#'ʫ5?Z9+ 'u+]rN"]Kt%_K}.LWt}Mu]%1|kڲoc9VZ.`0.+KӠ/$D3�ޱ5Ƽa} fHTT яy4$D,m~)'5.XJd}(ksȔy<SaCQ]W}\- "6dZFbc�B $hJJ`4kvh-{O6Şa1;Kٟ<OwFεDtnz?� (!@2HTiPu΀a:(GBDE JSydADкuFR=tT#'$)6Ur+yfhSL;8<j aRײLH4ӌ5?V0`슶sɤ<x7 wf/לAV 0 cប|yĤ8VwO\GѰ)}h 8y"ۊ]h ]UXn*L8ovRAۏv9v–WR�R]ѻw.*/D\NV �l!! _̴͡cxxj$h΂W~k(MK ( 0zS$NO & <B"3[Jpk 5tg*y_sl]1i#P/sx5i*NW n͜~!'_-(oGY4 )3`j(G+pEN\7Q { }0s�(?{ANM-f{¢bG�ܸ>onT]\E&&=ǤL]J?tfI J 8ZDr=8ƅz$T+pA6 l[BGMl,.�_i~n+̢άd̑\,h D%1,|r}4-ub*4+Uw~j\w xZTMU,'MRЋz,la^uiG#HU#7(x3`%5x0ȝW\fÊvV0DȏчY_jn;-X\Z43k;=b59rzz̡߯H|<&SVVS!WGA:˞$Jߒ%Z#hiJɐ1:rw"1<y$4cޒma :TP6b:sZN{6PMW1#vܮ=$ƀ~ӍɵϦ+F95w˒j z'}l*kHRX<1Bh5c(.I; IMEGHP=hBl˗~/8wE蚿+JL^xUT,:Fι>K֍ypbତgI�58(u^c.|JO\+B< _BTdT۪>IkfYJZៈ7�endstream endobj 319 0 obj << /Filter /FlateDecode /Length 3211 >> stream xZ[~<RQEJ[ 6iEȒ#;q~}υh& 0#~pX\sǻtNו=>ܮʤ4ʬ6wBtU,I^mwP\|X?Ienhs6?USw8C%i9er+Ŗx7Y$&7fw'TMCu:<z[Lű~r)<zf\ώ-ibnlfY1UO-MZED_ m?]?a_M3SO~#?ȲLҬ$y_e+Dl.^�NR9v'IR<UcӍLT츍VTCXln/ݼff PwkEKf}=|DUu N!h|}{OC6C PpP^K@ ܲ,A\#z<6pplGɊZi:(*n6ďZG쐉]"Rh@ֹD;bW-_)<{jLLɿr~σ"EO9r0PDRnn?FsЊ:ԙgp4X0Buo :]`fe( +AM&Lt'A#%nVݓnm Qf$j[|&deP棛ӼQݍ"^g8T~Ԗ쉽x#/Ӌ۶VbOP}1_%{'MtB;^Zo-NA" Y9oꐸRN|"A IgHя~vTʴ!vz[4a.>]<?`RXHEQ,T,c]uLҫNRKn2W^9syWeFөmPdPi4}LZՖ"Y ܌ay%!\6Fi4-dL nz^h+:l~PB)}gek4L&N<#Q6O(I|z"btΘͼ<37y"9ClU?Dȧq9,;ðYfֻ#tp!`|-!/>Z /yC&!zL 0zkO@:8@c?\T#^0lP=- b;a;DY$Op-R&mԠIƅP!MLlv(Z#b}4 Ӑ* maܰ3* Haw6U*Y�?ǰ7+gy ,vFɅlsF&e{#W3 IO^>zV%ZI<=!k#(9C(gIkfx?( |)90E}Vfo4G|oahAbM<N/,hH1y\'~g~C 'tm +Q ^ 9P#Z8 IbHؤBܨPdE7.Ҡ(Mޔq&uf!WiF "^s)^"-W=ٯv+G :^-&#IF$pK r?Rǩ"b((E'<쁼�B;ᱞf0DYġ+uA"ȱ]|RsWH#4/ A֨7\xnuTu[C2A>  p PK5A-W<KGɷZL2LVD`߱E6DH^~yF!qaEL qq$tqMKsf؞[ ̽s�#Dg "Dܙ,*r At_O>-½^b훵gMlƷ_^K�P)\ )�7rovC'<Z&QL~`s -(~2z6XtDĢ~,`?ͫPAcȷ{sear(uzO_%=oI㛲%'ok[rۂ1}J ͅA(:-_=)Ub@QӔ!A>p_!bdJE" Sٖޖ8$Uqb*lӗ2ꢺ_E!k苵͜b*9⫂=WYl,n5h|LdK>QR�Am`<!mTBVHX>T:,/M+h@hC=aZ\%wp#+O],RrBPXS` "5y:'%iCcigFcUcI.GtVcm<5-g*Vݴ]_sC_dZ/6&hXڡn~/ سa^ro/w ((vId7 Hu`K.nؐcKd/1?ț[_@(?Tݞ@ga_N9,)ϓ*C2 |ćU'O{}Nt8ULM_Xo8٘RnIܻZOsC1b3 _#9>6\|–PW Eιq>=7m X˙i| @Ϙ? \hխ@՗cL {"HNUR-kRٝdVC(}'npNt@xJދBg|{>ܓCGLI^h.͜AiF+nP*\DUK�=ԙi\羀z. Z0 ؁fp$%ߚ9n۞wtg4#|N<A(.*O^rq/i UV _WX|OK 27aL | ͎8 ~":uY_~@tߐnR54>2 G7??jgfT=5m3.+y )Џ=OhaD=Nbnԧ@q%*(1|c(Zd^lSTtj69, (ZCgv  'nFSժ֘&6]N줹H eqCK5~KRh@L-JJa@~7ѽvendstream endobj 320 0 obj << /Filter /FlateDecode /Length 279899 >> stream xˮ$˖__KfѠh*2(>6WCqթm||9⯀/_WJk_5~_5bj+ ?r/+_5oZk%~+PHA+9}e|&PRWX_E+`KVfXkemE:J5ÿFJa 13V i|~+ȕJדkJ_5z +9#WL(Vf +3]%5<Zx>+q1֯ϤWҡơ_+֫zkM_y'U=7׷t^U.I? ׀y<3F{?6wS e[~9v%X)]N-X/i mǻ`w.& uA6mw(]>ג$r=p.^\$߰,>kT+?J}mo#�fU_2k %K]G{c_?%O"_x__ym^YKDP7֗t)I/[J*wjoZ/Ѿf{;W5Ld}|<?=xz y:=qݣtZםˤ%͵uN%r{A}>Sy]ߟMUֻi<kSsu1p eDR^D~q'k +N츭m S@w}}qPo{_SKD@P޻}i$\ֹʽۯ2˜~k]|R8Sf"_5MZѹQK2r>֣(� z-,TmzjxM'Fፆ!.핻ΜWM\l-~ qߗy!cr{Lk+IS X]8yKp z֥]]BKFWK¾<nYVy:~2Npv(m/m%{xzDZۆZmGBWM*馗zi=h]YW?UG'M:3[0I|mp^}Z!:�)m.RquN7%K4hz)!߾Gz9-5xkI[.4R~u_, CC̎Y뒃7Nt Cu'tyn}zJKBqOn |Cף;Gk};CS^S@7-;8mq(.ihzǾ'W%s66z/.xXgG3*;.pz뼓.:AEi2E%`C ,s:t U)7Uv=D | tZYb~'.�N|;u+d\y1-( ]CHj]?4uޝ.K݊.a#, ~? xǡx{XWLxc�n ,L=R<Hofe~'DéBU=|<p?4EjƼEIS䥪},ew̵|/ ~q9ai{˿deeI֡dߟ\x(+OQPvUFӗwUJѱ4 nY: =3-3O˞R ;c)戝Og:=c}X+28k-,5xZX`1Ydٯ^R%Bp8ef&F˖`(tR@**S0 ^߁gHz>Uz+Mޯ[ϭO^ @q(83TBloWe)h$[XoJ+VEtFw %byא rw;};mp֍᳭CXnAzKG?Az tt)hjja0&_ʒ3u݋uHhӽ_n[StױH 'ꮇoWP]h_[oX N(Cp#1%.�$})SN>JqVD[ʭ2Dh{41_өa>!ySW#[?Q.Pt첺+B ҾG Vs_^h{eH|FzhLdBC}s["4wd/348aHoQw;Mq-2C1ɔDsH wqܟ</ϸQfC)Htu`B?#RU ?iۻ "@TMߤ(E9ٱ:<qM'^f (pPfVxzbƗ ɐhC>"X։#: ߷~@Į*,i}+}j K ։3("u%R#~ Qt}EuC9p*ZY.hGq䈕.(>}mCVydz)f D X|V-,&OTbR٤N^5WRޚ +TP>d0 2\|ZGQz7pÿ7.ƏGAݮ.t(҉0t˨td )K<dT<v1K#_*[%j/IL,/ft]pJ;E8#HTiʟg/YYۀd.υWrfTKbl=䯻,-e^=](Puġٻ4TĥC0nzJ9$3{-,phE-ѮǗ'B-u2e@^rCUY td:쥣Odz+:Y:Cxi+犔晁/Ka*=~M@|VSꓧlpe\6r -aq2{c0^/YT^Ey-UDbڀs=0]Or_YEQl= 1JMO!'PޞSxgq췇lHKŸe'Kn-%D$dVRSS> G?ӓ0=U]te;KL~g&n@//`fɺIK$<eqםp=1IyU[-egq{W1{TջDYrbk9ELq PqCb!z{}5W$1oB. ׌?T~z'P8v̨çY[I+C,էCWnLSeVe`}+1%WP\ЛLR]%Ņ$D ]ˠSD~p_,{i\e^F:Y C!"&UhƖBm֕BJ9"4 *}Hu-͌uB!tn'aͻj)ɀʕ$xRN. 5Y{Q`p?rU8~I͗rVV*~kYch^,[dS|ۯKcR;_1p(VZ78gʡ,eOs!<U>3 (pNH[͑p]6E9ͷ3G2,&Q\]++Й_^Q<|vb(,YD/}yEL.ilaQ(oc /^RC PJ]o:SD"せe?&9xƕB?4vNhAqMyvkz8yz{X1`:BZ{g'|nPy Cw@WW5Qk!) X LpOGdBWԻLD8`3#؁ԃ *4JqAK Y ʈs.fi=謶> cd2 A٩#m }SWqI[blsG\pťx)m94i9 p7za%PYyXwNp]*Jg<71I.l0A=bxԫԙhHSP2 g T1;K g%-{@-Ex~FL|E(K6pPr^p$R(,iZOZ9Iff ?�06 P/[Re.dm<0^+̊h{cJ3>|,0^Eg]jW kG Z-ΠD??sx}I#Rpp"<AhS2O#a>j*Mks*90fwLj@ܯܤa_.yTkikth8չ)=Ugw fs֞\֣ Y-Ծ4ēqr*rw\ž�kL3"/8^>béYQМ=`D Ȉ^JQQCvY?baxHDRn e0[dz`ji(z]Ho(n9 Sw'/r.OH�N}nX3YiFA9w|Q\ ?(\بr'r#/"zD�,% ;BR3LA?\płcVsZŵ7 } =aIvzEe@+󹁐LbFqK~W݅8@zUlFqQG<^(\y *WFNzM[N:ZdR,2H'atKyG(БN}m`ѾmuHhhfQP,;4#\љw5H#'XVTg.(+= cpŠ�zwZG<E|�pd'\xEE !R^BXuDK|KBq _u:;ȿ%Bd.ɨ:C$] L0}I|@V`j 90č`i1]l6Od aT^AzfqY(�00s8E:_L*傲.p2Q]vwӺjD�Sus<#ic{D)bqu4*, t\4eCW\j+MAOucrh&akaƗ2 zZ`ծ\C/6en<۩?RP*k%: &8AUZC% j_mlN3?)"8@{~`w_}."�]c:ڨwqCAd ː;EI%V{+埐^)DıRęhke@ӌ$("|Gc_mK p r*09`$!C Et(&Ll iQ9:d$boî!gC(H|J٭Ԯ۱*p ] ˘R:&QngN�<tJ~yGD_Q1N,r-T#%[I.U@\T�L*[[ h (S$&PlRgŇ2\Զ+ eڊ|= — ][<ycREUG.̏�*!Nԇg)7 ӑr.e�SiQ08u E팰uL܉yHKȄ2b P+(-�;( 5=4F$M+�r\`v{tuk&*0Kk <3 ٍB\ CP6 3|ۦCKB=<"k* Ud:N_QmyyPd56 ^ɩrWU-H.];Җ� xNw"~0Ox2:U$h[jb0'oi`2Px@/ge ۇ}CʥvZx8dP_7 Ӈ~ [ʅsup3-.Z$e�mt*S>!h2@Cⳓx==Y M  y%Ze%?mxɾg'ώzŠb\v0ϑJ#r(LlMi1:}PVC0Q>8;aM4{YVńI]-MDn̄(7l<td=:ap\e G?HJWw$6hZo2ƹ6U<m(fs$P߆`-~/wB" ]l"  s ᲀ]\�TZB=ϲ;FwoZ?pE-"qWxPr;HЧ8Ռ�9UC AbpS< -&gw菭2t~k%`MGC!ک"C, .xzjN N'ȘVq 'c$�k?f%A~X<h<-t.vTA;ӽL_8\ yO_OWnZ-ْ><S)'Y�^HSJ7o4v,~�[hf6؊$bewoz4TNjک/T;SQRYd X?S'lRA3%I Dad?v5YCo1YE*ԥ9:K^̐䑝gK]W}12vIG'q Lo?tΊreuwqéƹVߜTeąo+!FCS]3Uvz5jZ0 Dž ш+jE"0"MّfyB3D7 /d^?CeG ⮙ yQ !( M˿ c (W6мZZ;<)N=<D!`?\dt -c|tq %Ҩ oINX˹̈́eI!Xn @& w<C6EA6H#Gݞ6t51 |q Ut(B01L(1>F\85@LW[WX8uĄw[.Qw!ȟCJh~愩Epl29]M ht1 {Q IY#z xF2[IH1t@yCJ٩(\fK@kOۑzM~}1iBL{T dA΃ ��b?)[ Nd8OPziW"E!5RGOI材LrbG'Ie)KQG~#偌B,n۳M@`┸A-P|āQ(2) Df Aj*KVw8+u`c&# ]ړ6 ՠO=} [Oi �FRA]0zI z%]ܩ=f‚#Gp}R\ع@TפN{M!f{Q0$08rx3-zbgҍGDm\81@ĸ*GGpӏ zɐ$\g=U`NNI&7> (Ő0M^CP-xYx6+NfeۙW?@1LYM@Gp4RuMD#d8Z pjAɃH`b#ŷBGw ɗd;h0�akUVaޔD+ޖNyk�oW 1F"LSvE./)R/od`2:D߈/"DF|ġ",414U9\lΌ~{; DV;)*SeZu* (О,av$?$უێ u[H*/7&c )fsYv^&3$&g!p]Iaț.l=AH3\ <sܾ~tD/i@E`Wf?rfYy%Gi 5�jlj~ըj]G] =]_[>=�.8h'D4~WM;q2E!5|rը>&BOjH!W%xi'7XxLnd%Aiv@8!PN_Ů+]攑i�8C4<drDȐmt'ZX2.(] 囄 GCTr;92˃3j}ۃ["$b$x &d4b`v 8T5"wJ^lӦ{T{ }');,pG%~{`R)Z`!+<ϳLTwh]>b re&L6v%eT. 9 Rx$j׳l?b5 ]brNȹuD@G$ h;5t;lSe*ƺ䱃hAHzCNe r*hif~n8ްu Y|=d o<kGB(,M%ex+ +;4= ($\T/Mj!=Z쁲%V�`b*vcȤFư$b~W/Re*1a<؝j%g[w 1e{,bzzJz|Dq@F8#Nyh �#"WrgwVjKo%ev":H5·Z sY̢c{!1ij&Τ G�KGa4,1Erdv&CmHl$ѴI=`9i\"iQ4F �DgFbYvșz0Rl8g 32aaijO s%])tB9'J.I"<B�%A;@Ԝ7_OQ!0(>3К6<vl>cmՒCo|xYЖ=llJ wkrF:P;R}yQmW[o1�e5gw<+rQ)0aLů M K硏Gcq}]JޏxRWΩCT:@E:0 3'->'>(0̭Q1Aq&wށSdv?+.J@+�Ժ$t ѓ# Hz;$K bƳp dClc hMv t:`!l3L(ԙץ[4NnK|"e<W+1O(#6dP[ƳX[M$)6=C-$m>(|PU!m,=S#UrAlo2L Er4R#i AKG:A~Wy6 sS 6Z-F3H+d�I3i;�&Y)6Oև&hO7|;YZpߺzFoī\7)]Q5χ#" vumuJJv bU2j.%D}7Kh[:.(ؑXL`@P/\DaYH?x8?Z ;Sn?;8½KCfSsz;4Gm]T� RC�vjҡC>46E27<уOtb%JPJAP@lά9+DkPWeR(2:X#<..<TJUw:%Տ^ LF;zwϪ1*<drB2f`OTl<pЙN))54[[e0MLX as`ӍiT^=K9ian#C[Qq ́tt&=5Nr/Mܡ8q=h z} _ M%ǸHmUy9$呤8zwڼg <@2`౨ =6T@A1_E0oJjS�-]e#ed71W5l 1Dȗ AxT-Zr,$,P-�>Mƻ;0wܮYJpI./ E$\4t=!Gڷݲʻՠ,EtvbxkC9 ofyQuVjLY[:^*p_)/׍]5uyGEePXlѷ0uV$[f` i;;oҨY-lK%8&^n9NׂNB̽w}NiQG)CZyԟ*5@@+pU *C==n3x%1?2(d:-( G >uŨLش{}-p$\zUq Sd۩o)0 ߲bU : sQ(xYbHcȕoEA�I8wlvca?p&PGηM;A?9վu uY'}6y|YRljqs]"5"=\"57`~.ye9bOdzC.tBȧ3{⺈U<l*P'c"SяA9@ʉbH7Cc G"$/Iٱ;N|We+E@%0׾)W=ɯX]<F/#oDUE $O%�}wҫ ݣ�z, kȧ `VeBQ4AP>Ϯ I@ 0�Hfs~c/M~u+T#Üle[R+EE]R&A6RoB:"y R3T?4)'sg/=90lT#4Ty㚚7du4+䘿ugV0[`?FBm%]mycKCfS̨*t;tu>35oMv/0KyE [Tذ8';x]0J:<+oő[׶gوyʗ&I<f{SPK9羾dYgpF($SW7 ZI#!"<ݛT3#Z%1.žh 1Db9I!C0tn6Ν,#-O . 01$T9QgU)x"OYA}4o";L7^c:ɥY5b0+GR u8tuWS5۳Z3RbTTR/L9rh!pC#: m!߳4}7;O&ŁDxlF̞]NpfG*8s׉p1Ln -GO0 %%g]io['WȦUf[+ȤKޚ<ǟtG4Q?EK C_ _E\qL̉PU9&W o1l<tl2J3 qؠZNAY&O,UKZรXD=ҕpّήWwޓѹ]\5`wwg1 7g34+bKLx @ sJkIېKZС9Kp`$f\z�p;mE/c9\#JYE7S\⹭<qA%r-LXPq{wUu4l"vCW.l&t큕G/>ZIrWG<qO}Y8t'n76y*z!?!SpIBl0o] yû.2gwIsvF;ATwrkއe= !.<ϼeB�Xut1noܓn[L{T`UƩC .P6D>,+}^? P^1hf@a#) kcAFEkJ)x9=6 (ĜZADB00 ,=81YGeJR'e@d;NPD.y}9\HH&Ur5zK]kx?X:VL>-�߆h򦢂w3{(xrX)d<Ё�Lh*RV7p(o|�ֈSPIjspyd'};˃5T&&H2#':pp ` \A΁=S)M иHG}=8ʌU92\ʩ.6rv"#AS:L�fdpJc֎6ط*y<cg m8([x[IbzRS2K~r]'tDlEY`y+}5wyU]P^!(:宜1\(vq�Ul!α\~OpJTTI#Cj3䢉l D22tD(0\> @W{]7=ELmY3`&$!nnQG%!O eiڐ9  <&[`F_2@Go!K@ve؃!hyԈA(N+0(Ϥy0VȊO xR9^x?G"q k g+rCFQd D%3y_5oy \ YzNgJH"k%L㹹$xwJmbș)3&E" ]u_:gHсa@:ϰ37#Uf`7i(57wxU`"27hB qxMjYh$6 9R{{ǁ鍊CԦqT2AF :F=Ky"G*Q[s䋸_+`A4YQܻݑGHZ/=rP"ju |.b2(vG PH=AO�AN* p!{Yb�* gQhaI쎓y48jz:#yI[4@q@8i ?u{z.0F#{Y~QF<;O;|8=݅!x)m=COCz:' ~ԂBs#٢Jվ<Y 74 mCˤ�=r7ex5 ~&8ES�yCH;DuݟA圚w+Em5=)I0d%O3bLq3d:f#))%r(m;|VA7EӅzpց;l[Ѻֺ1:D0 &w8ޭ?wiB.> }6YtZ_ ХΙ=X_^9t)\@dTP_#$LBp'5T1nTY3)r Dq:LLK46$ Q.֡VQ7.|o"xGS<h&Fkuv9�zZN)7 knHy:OV Ez -?NN?$ ~WY͂3 A9l9*V~>Z'a\p=3!3�D{:D< !D$:Ϧ1ze)n,j?=P% :jmCKgQ 7F\tKT57g %B�.-|RG`&M6{^ ̫9㰑pRAp22sBϥ8̌?a+h<|/(C"֤ĝ!ߐjFF$t\F0$́CiOy 6ƑjR'2)áM'nb$pW4޵=ͷ n&tXGCB1A76Hq ϪÍ y6U�gYYi:˅S}Y0uOg{PgmBy_PvW\`%(XqBؖN߯]*[bh Qœ㰧/We61O#NeuڠZΩm0bjl;\6S鄲ed o> n%/!&=&x؆:&>):z8 +J?(yAbM3@PFj`Tn;?N9-#?ㄊ{ f`0f/$& )p)^W.C-sFhi'B,٪ؕBgJUu>4UU.0:p'kuz`=90YY=HVd E('T3}SH`g&snZma#d>Û(ĝ: 0:LJIr~VAh|aw֡WFuRј<!?,RaU ][3aZ9Epur c*WD,~%]OӼVlPbw$zTƽ!<N٫[: _B&{I93sK@O"BuPrT>BЂѳi0|q8h%#'`Bq]pR۲RdUg1/�oɚZP#W4LuO6Bw8/򇉬M V_4wpQY<"MA۟Ԭ_~<4\05CQg< +5}^\6ĩ:(_?R UK]8ASj<U b`Fg;ȧ б]bG۱ ,U 2ѷgݢ;8&aٯl#ќ^1L!aܔ`p(-X頧 Jb˔ݯ,L$,&t<Up~C} yѮg[)S�Bz0U#C.tP| b <r*õ|J#VгŦU=KzLtH ep\:+,ǁEa.(nqlh* 1bve_ۺEp|h|SM^5ש IS%] ~L|_92lP`$Z&K` vn? 1k;U^8L.F"f8W-}$d{JNb6co&`Ml  HũPcLR\8S\5I�'|JW!{)N R C~ePg*Ƀm`Yǫ4"N&@Jg<.|~Tf{P`kȾlTDPZUg cs"`x귒E^D_, 96բ./Cg,g&E͑SD҂yqd<==檜H,ә{44s6sOn|= tQ0PU?@GE.9Md+甤='z'hx3^pL"MČS淼hDt;Z/4Nh=�:PN).{}#82.űǷF.-=KbzÓ#6 b?zz+~j:'V,@ە(.ЎqkjE5yco=T<=|c4~UHzzmN|8hʡM5 mVGS ]kf.ĘQT*㯜ˈ˱.Pň9ӔI!o#McM"Wv74׋S \YM=휎)"L嬓c`#?)teX-Gjgf9ZaӋBf`q&b34[><CBV2tWу2\vwp/K=v0lqѼ]963Qp_O!)NN{ɒlCk%(0uڦK΅S[Ww^@Ԉ9|ـgMJu'Z 9t^ʃ jH#tx^^ſC' + +_K^ *N vf5\,Z$~"l)T",}G?&7hIlt+:it&U1t"pZag=yrfZ+N;)Ʉi tlţ%Q l2aGf-NqtOa"D�IPίN#{lWA #bgLOM¡$(/dQZ:oJrβarbe{f]ݧT4`T !X:h *m5۵™ [r55IB~:IiUr< eС=qD{(fhTɵimWj|AMuHLZMq|B7ii.JFZ%jZHádI1W=-d /QkKo 'gG0#+owIy3MG6Si%{ԓM1f<p*J(SK9{:WāY+Q_E>P�a3s=gpDu?*TjϨ]-iNӦq?]3dy)0I$#RK HRѠn-Ni&XF$ml%W,ozaP.dfŲ+&vWo[6$-"طNŧ1l+Oϩz#od4rcn7KqKT2e3|ڿ#k氢4I M?Heqnq'k _қ2KZ*$ ֓t4ŋq(=`zdtU~֕l=iw 䒿O^_ROfiM\EݨQF?><=j$NY>8׊R{>$=T5y)RζR&1wH_L=bp-LƦ+ okE!E<2/dl$,#iVm4qZyBU -A{fu{+yJd\ySh7vSс�gfHM֩ DdeQ&{A)$0BFnsӢaO@'Ρeӯ2 ##Pb{VgkU+dUF.f?G'V@]Gv 7x$0R(+@5H3n)M&˼4Rp(Q,jzRpXյ= ;:04{  KDK]"e)fJ8ћ^س~k`*yLr2P(ɞW+:!1*s\aa$1D_V="<S='$mOH ,PEWd+Πx pBb*<Rk"AA, 0ѕG6aĽbnc&`<ץdWe 9Vl,5ò;YFXT"Y/q/CEdQ\+i>s*$31W65-W�^b 5Iɧc{%kB6we8'wi0ԿQ̴nV8`:cqK\87qQJ,L%#|<Mh:?CԈ'9ۄTv6ΞΜ^xZ t|Ǯ=T(VgA !66!OVD7BQ#>W>q!M[M 'cj ͇&k"G9H )Z%q$2?0ݭ<~ X)V'>h3ea?4z2Iw> ww4t^KK7I4,ڳpAE,Sї&A !r j3*Y]m5+vĊTŘ4現eV褷&=ĕstۡIR(繒NQ}ƙ`0sIaZ?f,kT<qV╱t*`eV lHod6ҁ C t<nVDPh7Xq$LE/ߠԃsܨ }xGSex*:�~0RIʚ+8H8) "V֌+QOᑿOݒhs,DZ3ʴ,V<bhI_0vBk+J׿ɣGkJr(QPFTv6hnMQcőWV蟄2yl'ѳ(RL y"3!ŝǷaPv2eWʽKi-oৣ0, m( d0$P GQjNw+{;XW*][⺚ắۏ MUc6JP 7Ten%^*u ''`_[f,2u>ɤz2V\zpC y'urpTN]:NvXW⯟M5RCʖIvJi̤ *SʼW-M|Io6F [emV9a}$5ت�]9[ۂ_ғ 15Db*:>" XYܬ6%# tۅ-𷲲&Jw{A[W4zWV?f2 $kE KZPճX*.tKDcVYۙ_}fTf&Β"&W,o4J'- ",Kb1U$ 㚰з+.(%-e(&F٩DF]d; ?i iHv[)jĭ.85~!z{/|*!bTt&J։L܂MG+^iք]Ԇ܋H?fM&woa#0)ER]q٦Iϡ@fi6&(+[훋=ͶbPw,e18ŕ`=1 cdG>m� GQ{:wQnG+4Dدv�a5Ūv{ysQwb1c¿0Σ(hE4v%u5 m+U!elr�?y"7U7ɕ7ory&8x&C8&;g# V=B^7ZL\q*b6ݎþAx7tR2B}9%T& <"J5.&W+]jPuE (_Ivxja&-iӟIVhDs#m.^gV2fF%0X1b":{۞VR$%6R(-%ɡ93Q p5OyB R+ݾ`JbyrD&hw2F9/B0˷dC<1=u/EK~}W\]t;\û(^#7ڥ."^zҕS]"^]S/ )Uͱ+H,⪂(5b6Ĝ["c}Yݨ }>=o7!<Q +ӀVA/^Q=,o^]'%{1R]a}R9, fcմδe'rmbj󮚾璥oI(wk`$kH$BmuRjW'qRpzD٩1RCQ%�mõҨTج~,'*o,՚z_ 9�Cg-T:oHU6pC҈鸷R^/-IW򽂻|neq/~1:+ܝj@-j+2(YHxӨ2VՒ+%Rvr ,p\դiK*`V%/*,40kų-" ?1H݅.8@qpKAz)bDh�c@Eޖ9f(Z>(neZ'�@4<6?$p]LwDKJM:VH VuF,QJwgG]ER:;>B6@ RyjE hJi)  Nz`HͩE &/c64˒+6B|8β$Z^5+C j6hվB>63F%/ _?}2/ LRPDS#0k(YRSs:;^XkG}8H%$-<1p/cc!V˩Qj*j+H7's ! -X$-EAMcB03Зi*@fn[ O 'C|dmjU$hSh`qCwXg*BhǕle6A| -a"UrYq|ξ˞F\JjP+d,5&�zcS$#c73C9S^ ٩$ [|W N{5drZ<Ã$3S)3~$K5fs>db꼡ԭ!e>f0xۨo'kJz CG :\p@0Ǵ�ZwZ+"6l*"vrhqT8CiFDs39Wܩ`mƟEi25]i'!β[h% v;(aZTBpXT%5^VG6Fx^3/g6ݴ;jf4y[bV=Ɛ+:,#?_l alED34Lg>>C�%r0UQ tҲ"=W]FIob 6hQ>cLjopà)0\vIQ">R5�ml]kmEkoF@9 Un&J<8\V hTHr6DF.o;k- LTLN ^~IlQ& ΆsN$ H~}$KCZԁ+lt}}%.l YS4< b{@욦t(]n;u9A\ k 8AI dR"S S[\`Kށ_::5ۮٝO2%2If=2|nxςtS>8n8Zr_zS9DrUV嘒-YQ|?9v'W<?r ]<uнQƾ]*QL^ z\aJ ;J2e*,o"7 7n./ҰEӹ>]Ӵ>oFΜULζ)fi"٭"loH $ej0bK9քC?�{A[ ' thwWN(rJLb|r[F`nHmd(G%[?4f`l=$JXNEWSW^�W\5PT={:!fk;53Ex^x:oTSͦgy[+:6#JĆ+f9Jbe[Qt^ŒŲ&(:5|Z=f.]Hp5F\\HJJ[jR0w'(&MR*&B"Ҵ~VDҕ[ 49KɾeO%v[#7|:%thK+c `M⫐_)Ұ;Q_~yTLOҔm8 v*Vw2v)Jg '}5n̔%5-0Idoez$]Bx:}S*K6+AP PnTVh~pQGOvJeEkr'0K-*XW lW|oq۰X{EEJߙudV,șzvg  yB,Quu]OG둙v'L 䬐D~,#44_=S.'U<\j^׼W䖸.ժp<"h(Ejnncn=!kHn|eقlŊtC< 'YGv1@k&q=#IQy&f7(t~7:wW^"0sMMr=djZ:ΚO`\e$#<r#}EkUg |.Z(0s?"-Y,!<5uڎU!mZ|NÛJ#j ,OF*AXRT p`i.Xg٨*|YNr3wY#*Hk`_wA&yUtG^89 8.THH@KdsΕQGVN!S7Qׯ Y:n;vse4JFUiZA{!|rH#M&ٕTL?s]$ У9nؔ:|fm[Gq ~γupc< S'QsV~vWJtk*3&#a#l\ }Γt ׌)n6 ?S]T>S$By+uȫtDGr+ŜPS]]P%1F+[I�`H^GH֙@L"}GN!؎\aUZ ԅ/R Y48@X0홢&VPtAA' 7D=QFh!ŏRZP;:rPbP#v1*ܜj/t! m~.՛aHt+HM—DL9Ȯ,veEYUV]W61T忶rLcbd h7h?{P9:[`Z~oM<i iER'"O$I׊jd(| 28[c%\S@ޢNkj;AL: (X'g=EH_{Ө&L~1 SZW\z4_&#.]yfI] B A4+4ZePiE qE?WvIjOXB'Qcpn]U $LھN&-~˘RATD'9̑B hy'\,Vl*7/Pv:vK @TACВ; \Wj䷕D@%]Ja^Ը/@)oRF3�k);v Qq!;h[ mkZ�yD'jpD[Xdb"#}Uj3#jT>I.4 D]B>=?@Sb"g^hK5-N9s> CW{BxܸD98VR|rD5 9ac zr ?WmzH<t(" 1ّj'2Ɓ( lcǸExM46܅+7yXAה OYzFjʵ/g+\bJk >lF,M'+(͇*HjQ\+ "dR jl̪8 u xܼS9n�>4lLI<TF_UZ%gUAJ J@ P]r>k2UMcpAO AM@M3XxNX4GTIU"B;LiMVQ}+"rVk(9ﰄܴJuo5Vsk:fgC(aք(&0ɗHCfZv 9==q|զ4Q 0Y+4ʿe�-.ߓ&O̷eGNg/Q |iפQj.c?^ǖό9aMF%I9GA8w*8 Qڶ3D!m,S8J fP( |}%iS<k%vFUC%65XUcPnÂͦkXqk;FRVhd'15! mcG;\>HӘjY$F[g5<0h,enRL]5%םE '(]~|ѼxTxu&v'Q5O6alX1VF>T9z`+;I8OLMIEL<fȻ�m먳3WzR4şX}|)yK >jzc>YMH2_+ܓw\4Ba4PJN@;14iV.X]MN1A]ޙk+qBϯe`Zvm;Rg LM,%d*HP@=,5ߜꋦFa\I*#wHSQrXD1ܵ|2ЀsJ(&Pxcʗ{ĥœ޸b&0̏sWeҮ5vy9-(750) QwxF<P QDYlf!>Y hPPST|(]z?2 #էݙ vte!D[*_+A-3g\Ãscj1%2 DƖfE\n|T}QcHNbC搧X>=xɎsj(X]EJ$uuCF s֋% M#$iE$JWx{LO1m5]c5=8ٱS2<IXHYm ~ kɉQ [)UYfӊi8 uhfh RYD5ŇU=ȹ`D 9a5D$%RdtS5fSvcEyM�e(m[ Sa']( .ZUȪaBB@h(fpELnp۟B~wJCdװGJ$4=nʋ+ˆWs 蜰W®XQ@_/bvH!F3Cͭ9K]PuaeSk$w@[qeo=FRQ¶;G(uK!9.}<b'X]?TUOҥ[wo3jtc`bsgUvūCDI0 ]K<^ 9 ]\Fh-q~( Rܝc/rN-U-]ve*v"y !\&S2S@)zX3WB@Y|ZN-0Y41MW 7Y*)شrLw"Yv&u!43j dbƫ*7wip'+E>]UYݨ H##-|3\eMnyPU+F8M".+#Am\[F(ڑ# :'vGDJߟ(Lw05׾{3?ݲ ؖfIorAZ+'xOpBҕܞUmjj#\16-ٰ|abg2Hʼj'$Tүj KT,w3]=05g}\)}�21tkJv{gFp`Km?$&>wWN+G:L2RlR(oAgN *HYa{K) kN},LYƵBQV$ q Q1-w zVCpt<,l &^+U["6#o _괡ɚ�eoLyr7ைB4f\~W(ik\oQ$B\2MŜ610<xg}j cI)8ykBpk�X/[BҀ%;T:;YC*! A|<lr׺5]ZĆk_6%p}�%eY 7'KOL ʣ</.oex@e\a*Tj]iE>%%E]&r2< h ^3j*aY8؅ip 3]ï6Sh^M[KÚ߆Z.+{1r^M l 0n`/kmTnyPEj.I2rd(7 W#`h0:Ž4Ki!ue5 /Msȗe^=M�R?EހE# ɝк(w҃Ъy8EC#A;#)樚u5 -fEn0T}GލE[eee\BXX*2ڮ'EHꎑ6N'hshTGDIeNUgV$83?ݟM&ئOnf?FY+yB2{=ƜSMC95U8hMr[& 6ҷ+YPgizaT)4:K{fxɯ_~2n$x BTnlʄ;c I<L 'oUu X+L]Và WHDZ8LuH判{ PE/WJL]H}~$cWd'MK:8R$;-n2 f!{& |=fmlZ4{gXȥX!Y5qOa o-Z|`=qz")'zB+"cWgfishTJSY7DT VOliNS" [EZp9}΅Y4"r0.AGd]&lJ0?bQو:�Fr%w 5e`HcQCmX0Ŧ kBUraZ_gD0c)q%mt,s=̀<4r^E(Z)ߞhk`ۧ 6b] Xf.?ˉ ۢgQ`%_5+nRp{p[q|Fwy]˕eE 4$jztuN IJf_q)]O/̾ QOQ _ AxDYv=|%C4sbc/z~癢f-zFz,3Dn!b [>e_*.V9UӾdzz#AVr^aZr\C5eYGhwpT+P8yүjGrp�#JH"z?pؑEUcxtBg.B/ uwWs-N;=yG#[2YD5>in[R@H2 $Oe>a{51c-fT\:j /"uǔ،~\aj5 U~ R8G~w֕RA)B䲄sS!{TsCe;h>KSsDI׽E?DJvZ8 M.TBt }!dlu-<DO3PsM*1JGrKr+`;pT8L2n%Lb3L&Nޣ%4{~EpLAXᯐ؆"2- yԳ2V bnJ#Seք 4,WQb083M2WskZ#]mIS_jS H҃tX_ȝ,drExŮt$B3Uzܰj~ͩ*la@ ^&f6 (h#e+2f:Rũgwݔ;8j՗X=:at<*\}BB ">~Ry+T[lȫ#7J;Ė\zZd\[sq!hv% Hϯzצ!sBUc/5)ڏ8y$yH%'˽M"4v 1 H^@w ;ieĉB�-G&n)8էw>c\ݍ!J6t\Й[Di̷Nc9^v*4S^-V#f16T@ybd";CJI*;NdDsVAVu玪ۡҩ<y{bм~p^`LT8 j8v# 뤓1R9uZL~UZ&8ؔ!WK ?}e )ψXȎ}yj7eB@r_fbRO*J1 gzccE')!}=u_L#vz9UdT K[i>@njfZ:4+E _Ecs"b  Kc9l^ 9(1�?)x_یF*)1kP.#ʞAq=VI3h0l&2f U#vOodVo eSCP?!TRW؜>$Rѐ)a&9pknŪnw?*÷2SpPjgȨV5Lj!_>參ۓk(ХڮOx$)eHv,NܙmU"1F5=0T5=F`)w{Z!Lr::drcka1!Q 8p1pB#RCހDy/*XjaD>32pQk訮'G@˨̗dd;3�)!"7T"#Y Ɉy3RHt*F Fnd@utK<qI` }L|>,'}M =6nk,hW7kL_S?F<!5$ IӅS5{XŝpdLPBYӷ<֎wK]KvJ쬀clGjj<$~Iƽ׸cۂIs.-'ϝy.=? ]|Q E �-GěaGuXI.A Bl#)T=}]9q�U@UdMq!�!o1-91*O{G;ڏ}[簑O(s躐Y=K6b~Dv> X+t8P'$^S;z#!x>?r+1qAY! pؒe̯cܶb ],F+}9N] 6Pb iz9ib8F[ոǶr ޢ3b.~Bug(ºB(V^,*ttxɟYŸ;:״B?gtJҝJo"SHeb!?r{v۽#yXΑkRiyoj-i'W e7pfkJw+z&ދpέhf j~p@DmlσM9>F ;0i䥉B{41PW<Hu_7yCUMu@#,kSVQγ~L#$Ma,br(uɰН} m/eYgkuQm) ϐK\B[-t-Т /U8q(Pcˆ+Zy괮QS/~�wd= ,m^ycsy)p bz[[ 02-9ygwiV*>B\iZhlmib\T-EZ:%n WӲ=PE#u8Y.ikÕN�WǹcF23~.|4jSiܻtA3C}rJs{!20Z1ȝHa5p~Iɱ{zub3ሆV3xpOӲu+<97͢+K8Vfg=Ps;,RL̖( 9Ӛ\i2m*ȳB< 6[-殅-epb=$񅄊Iq!Y<0^GJ|RLg"}Thr lr爟K\ykoӎC_zVnP\60!jxԮIj"1R{o>kA/FTD49#+ve&f8'3zO8$W\bL'^nu+ dH# +v HNF7Rj:ybA>o`KNSZL3%/lFch:\:.ؕ,CV3%ye`ܧ4"߈C\ABa $bA3 (EW .o$lpH >[8roў!ztPb'$ 1Ň ҊhT3J hjAp|eg#AoK#PQRMٓtnG3s%kiŪ)piO3 D^?ק k.X:m"5 �ÁW*#>a e<m˺}$hU ߏH+!oZC㠑iJF!ʛxcxav ߯"d7E ?|�b4iϽJ!.,sf J&g/le>S}%JߧZ_"胤ID$#ոRse/|;@ [㑔Ny|Ŷjg̓7^|1΂`Cl718m;�E~l4VF3 +8:T J4ng gj3 %Z�kZ RW9&PҩJ_<=6tK,($,3[sz,0{ �T~Wғ)LJTż#rZi)p)sHYz[wWTū s̓w <cE] }tęnˇuwNIPT#E(SOOF5NIt[K"p9[7_N IUR&y$D ,L<ROBpDz~]|&21m>]bTu*M {˨ij>ߔY1$UuPe0TΆZ`!"h}Sܖvӄs8L7ː)PfڵmQh -E>I!:ٙ}þ(_۝*s@wZ$.Wv =XѺ 9}p(8W$]ۉI=;IbLgR`STA]kESWm`o/\7$}6C1nMK|e0@eE ;M<_ |3 ;o-_f"V<쓃vfz_3O VW�,Ғ',1|3,Y)7w=AD-p][Zƣir@Hbn͘Y+I$+�}k~~hZO1r.k�ɣ\ 5fʕڃԻ&ӶfJK V{$ 4t\-۱R')XIuP[DzX3)f;2lefWCC?٧[$m+aWH{֗{7Oz2mv6UL(Np% Ff4'||-e MRV$_>2Ez#į6B>HmӆF_+lr|lz W9 p'Ura{A30JPKD=>8GvrB!^|AHfY޼>K"As?6·yss MWX V o]$ɨkɁhks,բ5A6n`hU?\䶺K7Ilj~z9 vMq+m0޻U+Aj )#x& 2~0yR0c|Ý ?`͔v-;N$9ۭY6.0*?-c)^Wgk2Kʾy}тxTtɪUHJ& DrK`ҷgKɦO?菁)%"ђTH,֑ `IuZ;TT\$,ԲCtFq@BEAb .X!pՏ�D7 k ==tr{sEXcI]0N/ee-uV|0URӊm@I]5Mqw"rUʐHp#-RN>P6>k7µk  a~ @:=Bu O[3K`Bԓ1°"A4e;+w)"O4DqaUSC7h[Td,Bf >v᫒_K*n:ŘbG17zr `nYp]ƹl&m$n/4#uy]gReFۖD#i7s+hLdM2v62ⳝՕ[gGx%#⌁*IF"Ct rT䍱cd)F6[#lO=Ck0,Fi=$ם^IL L4#ɬ^4Ѝ1?"&^f㜗F}Q�h SwL= ?6zށޖ)^ՌNShޟ+%z!b0JcD^p_ӈ?{6QTN6nƍׄ.�c+9-ıҿgA)7>cV~@_ߴu:"iZ!K?gTng6ىoΓϥk=DFGC$~:߻q~!t ͪ{.t6Dvrv Ǎvfpڠ%#)"G'x T7.h{5p[,e;i)C>udx#=mC'S WO\$󸧮kk~kn>_6P{8( S+fv'2w �}Kf2K>IW@=8?KF$Zc!Y)ʊb(4Nv/Q4 Ddkja9\n ,bMG4%jS4apYu~rn'ʢysle(vltN:Yڊ5Kbfh{ǃU7azAPZ% |䭼ݷmS6k?~qꤸ?q,ĝ" h~O|w?H#zfwX,2Ixh_R]`Q <J,@ӯ/d"b샼!N?;1WBCnGo%O7MPaS|i:.3-Z@1# 9 kIP< {h%죎`T~lMHzX6ߍZ 3 B$iA2Ktqum-j<i`K"YQ6 =ʉ׊#7uUEI\)q|L[iBcX;R ""di#^@x8!# QI(V{, \Qʅrʼ6;z pٍ2UPm̪+})YfL-9I[hf߈VlnMư|>(l<rE#Ӈډ5966`= nb۝΁ԁ~�[nGbQW,K,WАJ* .@Ҵ h,)ӀgG !{m⥻6w}+Խ?&OBgGP+h%$&n>8 ܷ>]!zLcam7CI#++T˟LT,KƘ!bʥ$cҞ$N'z"Y:k6ymo劃GN�yYeVMǠ+ I"pHBfli&1jl率#y,rnsߤF8ϵcy/ǠLX \ M]:f\EnIjbuĵW]dO;IKb(Y&}ez~$|jF3`i\r+p0X0uHqun)KW$W &r}ST B"E8fk[VޞU, vPeDR,&cy>TX8ST)Vuj  a$̄^,ʉs;NpD\Y;2WƵnc�R)v-ԉϺ[6 )I-ȅຏ^PO!=st06]6;t!;w=27))x4u5SY 7]Q'+q@RY^0Gؕ*gE!}3JRZ}K| CxTƆkv?FKX[jrX"pOH̺u bcZq2C�~LGll[n;JLV/Di! Wk`nkqB9d:na <c <6�-Bخgi@LLn-e$p|LIpi) y.{DpB[2}+ydzVpCJ]DT+@ҀuLcfovBԺW{:-J,H±�7tF�nnQ!K\*;8? "Mmqp%xAM!Q[F1_o_D!E0Immut4i7?kؤ2-akBM.7R>~W猘 lQF1VC+srKKSOꓞ2yښ"5$VMI$59)w;[Gbk@R qOgoT {026#k>J.Cbלi`eh#z*YVnd,E%V.)?^>DZ]kuZL9/g,@RF/i P)V'sD)2{8 *"jnKtF),BED|n e82#MTNeJBgVYnMmdYgJ'\ Û0"\8 J[r"ey6ioc 0hK|t6b`u6|Owo3s^uV,!3&""nAtX&e !!E7_ǖy~c9(%ßUh#dJt)asV>`'o^uKX+@N3)V"V'Kv2{/,n fla,Rg� S+%ӌR'{s@kƥ6,q$)~+�MwbKv=&(Z,͋I](Ĥ4PG[%I0#C܉A`G SMTjSNˠʵ{1� ikSim3%k)Zp3pR-i?@�,8Tr/[32`|r|˴*Uy5 5NX*Of6r"-Q`ֳzKa[?6J3Aq4R2'i_U,˪kJbgppECm [K@L|.$7co׻h�-cc[h .@l+vIK<KrP톡&[:I~r|ʌ/D T%Z r2.3L۫XXON<HF>e™y9ݝwE6~-n9DI@86> "P^Oa_7% t 9z& J\3hgdG#n6U+E-e3>^zvARK4*kr9O6w]`53<7Qn@g;#d Mw6Xoˡr~~WHȅ(:p^d69fN` /FOa#όXI*C( bV'#1Z.7M/( Ʀ4BVNQ'g[rj@9F6Bz|r(i,5<;3B. B$pUuJvd !'}r޿NZҗIV C奝Ê瑗u,dw4k̔k5Øu˱ZJ@h+Zll3|<UjA@sc <aޮ|+jcg["m W`,V׻}3y<cz822<.5P.H Wf;:P(a{g (7H Nr >t%%<$Sĩ,1J 2pLOcsY.o;i*x[Wy7a!\rmpbN78 O#zE5$r|ywgGsJɢc-|qE7<'S YEIu_oϩGR#@t xu:S,3Pnԛ qLF^mV9Q^3aGADljx\=ò;qƬeO](GX,وR9sM5s.T{+BwKG5+>Z>;3B9KM=]Q_ #EGy^-UL&ClqϤO-ZmAיط\!!f3zݣ7B+ "yd}RzcԠ8:(胯R#}?KdJj.-,ץ5@#׈ Ѐ#XA$奶#P++VIyݎCu *l۳MXSSJ?7nmbeyB]l.*9APt*tP}$hՠPZPEA \P^D|rQ�o`8t΋~V\J[ieb^\YW,6L"F;H(hUEW-1q"$ZiE}4EMVR:O"zA+&WSb:; ?B=rOFWSCCj=w2G|Խ!qn!+VX[f<?2q院E"ĮQ8 Rs0+'5z@Ya?lY*vJ2\*pͦIgpӒ$40@V$f'6LzG6o\_bZH:)4&k_6\v<rxЏiKdO Q 2utosw-|ȽeϏwu~,mƃFWYV0u"f6$zװK LS3%&^?mg&)C2ZC 4pf%Թ8!}A(QM8K r 떤_cJ5B!Ll?stߵ6ffd0dܙwFCG+?Ԃ5Zt p4x 38l><C먅W9^Rm޵E *ZYC;.Z Á܋=@i-ZY!>ȯdn#^W֡TzN:++ȃWIqxR%=r OU>Ǩg\S5=cZG:GZ4{tlhۚ%oc.VI !~=-9= !ҳ$\ ;Oq-Ɛ^'XU\s̱uI9mfIX.faA%VSJY.Tj-Ӥ֮]9]ULfVugg/cM {}.G~6ۖ40r XL2X!LvZW0ju;*Zofh2x \M[7Mg3#aDBpsY%]Ll~ͪߛ٠<yS Spk I*hߥx~Ġw.vq3Ћ rHr^w4R6*. 4 ]f͘fK�@!k5It%oБ㍃V=28+)Sc5e sn5wh /=CP .)TySvq@K,Z9'bIY8]>[c"z;JHoT#ІR.8{ˊRۈߥқL_Ǻ % r8H>ʔ"�XYKG:ROVLhJPJXNK+%6ADB)!e\T S)hMM+NJBj yjƖ"^#5,zu$Bfk]d{:b8 QC<>ԘkȻoYFNv-;2??SZ%Ճ<aXѣ}f~5M[ %K/O7v1QlIJ:,5&KY&c WtkU46zg<AB0K<{9!- @Qv+Gѵ:D%7MR_XGP"NN|"h²qkfe +YG?>/vld} DqlLqŸنej9J6eH0XZ;,~F gڐ)%D*vxic| :%+tNGxW?WU);LHq#v9wܥ޲DYa!MwQPOPH-\bv -r<zlJڀ+N bU;ۗU[}5z|xXae.nL4T8D# U.{LԛB3QPkѳͳ߼n_JDX&]׿xbar(0MawY#Oc3Ls㒵Qwp@ߦP76EWO;<">$W߭B|?j&F̖dcKyxhaibhf7.7% ?^;cv35rWɸ#/=j' ޛh8I1ˣ-?YwdN piaKRmN5Xtc>\iЌ.rWy3Jb�c։Džm<?D%Y0{%5NAt7MR:+&ٙtU7z9_Fn7vs\aN;P mgsP- B7+DjYK//Vzq[Lj2Z0ȕӊ8︝WatX;sd=LM(&_֒ шelUn+1; +ɍ==5jWV#Zn3"V1M72 0TQA{RR+PnS-k|O\`m.[AYe>wM+[|v3-xLB;hKR).h厩Gp)$Q]}Re x +WZvpb-tqr-U6eM\{) zti7 qf;' I4mF+ȢcnyFT C1rkñ#9 Q98raOn 2>gwQzcF>-4)x @<'gnD`Bd j,"15F;6HF%z~LJ,}"y@\g-߉ǣG4^I)_r w,mx|,L=ӏВY\Ǔ*یIWUC3o?zSGD4yZ }eA`e -x11 éUSwVJbK45کʛjO̍rR7[Uy.5&KQ(#Ot_!42aIS=,D6gا5IS+Bm^aUd=@(~ [I)~$kf9o92܎m3:%")1D4Tt drA<5]&r׃U;{ز-r@1>܁|-mѭ: ;~âT#` _hFPEhXgHTX9#ϻE<4귀"63o.J <@j!W[hgdKxj2C}Y>Fe\_ȡzuRHyl5BHtKV22WVیwٝnR*d�!=äah."QyRL fl,M2ri$5I%[gF_c^>tyUpU$Bf֚Bsm45L*Ǘ=I64&A:hdgJ8gQȩy=٬@B!so[*g.cwt!MB4 {lǓ+j N$o8k+BmQv4G)P+UCfzȝ ~50R .8a3}Gz7K4*[j*QS$*2]ip vj)|[o P>I_"bBpA(TgA+&( UY,([-m7c;�.bW(/'ʦIkz6&S+-1#fex{&dHx$z|gL|FJ" [6xP@IrVW wW֎%/;C6PAěJ gŁ&"99q"K !rT|&?hV;c9*q`)Q[򔳈X>L8=ͥza}n|,B#a܀d|sԾYJ%9d]1x#Z{pB%yݶrdBWŽsf.ThQl,Mϒ|ȊNB8DTJp<AE"6NO0VV-&Sb15{|aVtYN+vu1s8o#Lgqu4ho"Sva>KLP CRlNB!vF$rb. `YuڳXXJY:j*TMKrg\'kԩGÏÓ_ZAAKI +c%Q֠b7+uc iS?ݲ?bd=%bK?KLk<"\vQ^UX_tJ @ri:@=Gccרr, }6\Nyt$6+!]6|l;?(eۺqzK3{S44]#=V8SlVX6$`i$.s48�qp|ٺxѴiB-ƀl˜?b]NJ/(Ea|�Sx;c]EޏUJl<iZe[.Iօ6[]xb%ڬL Qdcu:%ZVxkcP-1⠽Ж\ QuIBMɬ!Bc@[ V\*ß*\S_71k"7]k e++p< n1*F[Vo6U#Q{UH < 5kW53(`ЎvKF28T iS̏50P< K(lXp9J~,n:ΗG:/59;˲ŒOhGjiEh: MW2^�Dn)JE9sQ>\ר8G!7Eg4PȁĻ Rɫ׿[F㩄vӃt4j_h<=nCIrX,PU" W!T"%oc#2HN,{Fv٫:*_#foٺ !NJJC3T}fgtyl8j:@))o 2OZFX$cH ĕA2?Vl{&G( j؆ћB(88OvWVٻT/ CAt~uWB 1g㤲Z7_ o7ƎƓTP/iJC(YAZz>5FzbSCoZ׬)+0i1L]͠$$;ϓt ub#uHH|-;*uE^bO[pcJ"C$*ei <Q,KB O=Ʈ4%_vj`N&2mŅ 4qUh�NS%UF;4bJk+>ʇOu!nOZvc1i!+J&u,6+ e2w9ڿb$ߵ$:MwL$^_fe?oZc\+us ޚ7JN�º< N3 !φp$~J9BYSfVk+ hJ6;!`Ab[_To8\u)[wM –}۱4h?Pjv0yDK̃?f9X4{옐Cji}x*.t'hl.HdNDFfU;b6cCh젗`h)RoӗL-L-5qDqkCxT<+2(]ak?MeE9#jnky 0sD/gJm#h?`X!b#)fՖR!$u52(/ b%<jIpJ,=hʹS7Ȇ{?::]hݸ$j9ѭiq荬U#C4Lj`vM5kF3":\OprIa|O+ _ fϜ"vFk;TPQy�[*ceԧt/5!Ay}[X5"{EBvVl! �%Q9~,><0d~WÔn ߬/91<RY"pzS9єߤy9�ِ<}AnxGR $ԃ ?/8t 2|f#¤aŹqFhK3O=_䰢YW#zɜ@+R0!tw>}Ǔ~ ̺CFִݬNxvNIQr*#,3O3ގM?Wi|oa1 tR9o,H.CRĻ!mk/'k|ՙ?ã'3Wmm^G ]V|r=3+9Ϡ/1AZiޭr4fǍ *lQYW]u,zPΦeoe$=u 3_-&�##\C*XhbCˌZ&j@S5⿱#_),>p9Ƀ#<J薮!Cdϳ`p`u+DyɽL ӣj:ʬ#KT6ψZ/sGE&$Cg0D#yԞN##aNܚ]M!t k"d1ADƅ-f'P\ W@O)~v#4@_`rt; őRb~\a]A?!4RS`! #9 da7JȤ7)]͙}{CH<Ke!=05Vv;,w Zu /S98Ԉ,8EyW=p/2 vd֥ SNF7뚺eJ5hTzJQf"XHc}/uwm^+rhmXymv-6nq4i}Ӈa-sHe4;"_3(9Oɾ._ g>+hu|KNhYBCɀS E  Yz 2^+ݸݚJS'GUZ\}?^B zDV桯7-c} 에dZi6p:/R>sBΗRXq?dž73 G~ivz#zX.8hX>[;lձP/h3wvKW$T(Huen,Յ$n<$V3HВ#\:E٧Q3Rrdp0CU8>5ز(ܔ2LS]U<8U4PRMZlT${8ie}phoxz{L8;J_[վ&C]hBMލ醰 yr->FE>~7͑-dn͇E7 4l?Crc- Hj* lgvlGyŐ$?gMY<mV}=UxoK=:ۻT5q J/vxBy.IQC!5�AP֏ Łrii>b[zμZRW%23ܚmy!o01b/u]ic!s!t\Mb�|M: 0ʔ?R 8iY:)DX@{ytlOVdȁ/mJ|tw D>RDܲC' ԊEQGW+=O̷w֢EB$tG|mFRp (L2ǂ8@TE,Zpev̚fd֣ͫA#N:{Qmh׌'tǑzj֕͝Y5aOhB)1|$F?^$GPssYqEGnp`Dk,4 `m(| mqHH :8rwt6H2467Z O(]l<-2xp;XհkHQ!S5*_Md/ξ/׋<m8b^N b_C/S6CnJqU>"BL(e1"Ga ɗ$WsiMVDe璢f&9Va:dlQ ]AC, !V,a]@Z]xWX^QT2%; ,27 2VEzߘ(AWyX5{:g$chؓuROYXk. ZԒ雃)A]C(tx"ML9]lq š+.[^Zg<w8xx*;)YZXIq""2wvX*+C+=1mr]\Ti XP+eP'~ȖĘ7ޔ*v@-ob1OnTsEdİc,ST۵h (tjXV pf?p-Qt?EarbŒ [*眖'SawFpUtL02waRŁ06B gX㝹)(6NU,owqKl^<"\wb[,Rh:Vߕ&x?{疭�Qo :5#.6Ӂ4ŠX,!(g[ B$%Z2cl3jLW[vm\;VP@"ȭ#WF Gou#a ;?ߡ7($qkPjko$Ay/N%ʕyjף%$LsO,pQU]0Kв|1=+WsVigL*C|AqҶjcC٬|*H)*eJ].g$OfkRK;E H3IEk*r;;&fYkV ,eMA`wBEW3u,%ӲB0Ǥx yR{ȟk_>@X 7 *\sd9lJEvhCXғ苇{N$ �qq |0#_? gxeV;W.=᪥+,%W 8N6ːQGc<_$'toRaCOE\JU~:Z=$lĞ W#O]#ptEDh^\Wxn&:25]= s^Ȉ[l˂mT'e~}S,nr/-h18oF媺:Үri|3MwldV4"CA!QBvo4r7x83WW3�2H:�7L|8exqRR< rJ9ȔmP*ٜRbԔTXg w p.Ϲ]޾cW9빽3UjgH&'3@B;]V1,}/e;0d:p<_g HȁgW,#l%-NB`G Xv>̰F Ǹ!mKE&Qkp[%8 CS$ǐUA�fkZ(cJ&Ic?&,Tz 􏫗w$劻F [g6\ʉ}-EBF͍M/.$ d>:KwqbKU_|K|n`K $VpCcL숃56Ef0Ȝ࣪ӮZG O�߮4ix0$idVB&|d8-j*y3,[6tyEmrty[_!Պ'zB(`i[}<K&ejfOw/]怬O9`T%`:mp)e2^)h65eG1 n pDtsH] 7mz 9j޸x'26ҢvA3 ˥s޶B޲32R�u8L+'M\|~b;i}ƛP''/0*}J L{?t8!4F>{]qNW7Lbmj~cJ #WQksW Pȭer@{\}3(#_Bߒc7ښ9 z%7>YI*CN `ȧ*RGF\䃒҉IQ0 u" 6S7bX65owe/vN@42Tω:e�%G N#_gUlhDySrx8wW'C]N`Ȩȩ•z LxI@p`>M {;d/d1%s hm@FE SwLHҮQr.ᮚd\4_+1h0 dobm}P))Fs.Д6su ^J 9%S5Ρ2%Mfapx+]Z9)$0slي27?pIdz*5�ʱ_KGxF- Y=M ,V *jV<W&IԗZB([!k_(I0,@ғWHM׍y<Vbk\m%žS>V]>KN!%8Qdn?Y0ϛ dxDzI[7Q4}, (g`a#2pO.pXYt{a[\4<!$ P<x1O(3=wzޕkϽ=_E_+A.NVl+e>avfcwcx:GKV^6劢z\|aq::Mo}ha^ʻ:9󃧓l�nfoK mY]sl粕pd{s D^jD3 :A9;붺B!\ X%[6++ʀml'|rjjl D+[(X frŢ0G枳͸BϼmjdUk| 6aUGG٠Dlwaܒ !<>d8qDDI ( ;N`K1Cx&K.&ڬӧXc)dQvεu@y<󌕼ynB8Ֆ@~l'y/b6oq+ĸ]n]3qW5 *"PN4:(<xS=YaDže{IVCv'Xb<ܪ0J%DB[!,cNUS55ٚ,>Q||p+dD)8Ċ)3.!<Ƅ,ske 'Ю =zjYRe +}8ă;2^?e#ʏ-_$琂GG23DRlnGS$֙*W~D @3uZa>N1hZvZ΄U#ЯP5Zib9i$"k˓rv-Z1b7o8)o V63},X;YA~ I }7:jm~<'neo F^$s z^.-a_W2ŎS9;&JVSyTZLK執x2UwVd';T`<7?-' âo3$Y7OgvIgZ]k[!籷\J;/zi阳-ns{a>qb%$7g<9MYpF/G#pa$+oW48C;׫IsT3Lw{'VxK ůz <n.5+CTSS+BXw,@P\�M֜ӓ�hG؟e6YRSƀ[&tk 0Г 4JԬhAlD=PwD>q Z & feW1BѺjXzRƊ RC 8PJw6>KШ%ߵF!ɕu! {-w]T9Oe5oSdT#Z6c% WT4cgb̰Չ$$ Uh=ԉՍvɗ:*c!W+&_س)L1lJY#6{ (R>%ZĔ eqBA5xqX>rjn%o (|!l6�R B=u'aJ}]l/ƼЊY 62 l,rsW$W[%"S"mԴش i4 XJa!KbdMvh'] d^" >,猻z3Qw51J@$_(dKoj_It[0^yfNZAd=$I"r3Y!Y(&/~ u[.>ljձ=/b@iEjKTrND xڄ�Z,zc9&q.w�pawr,peFY+ww6bp^+Ո{O9-3/F6} 3kAf'78 >OC f1e IC6U Y|6<šyw9ђVI&I4˖կ֠9m M_fɺ2ۃ `RRعՐxۓ(iar;9N>f}rԠzB6~IB MF:!zW|C4@.pMcO4Hл~Q'].S.{Qz}pHG}Kӌ [,eZ8> u auJ=O|ՃYN�O좭[7R JjlE1ΰ:01*[xD̢c<JuwWח FnZIhd!ѽpv6?t%@kۺ%*d݈JX!xyF<f2ڹװޒaМN#Ԫ`1� ypOהoJoO%3eu_UH!L*Ŋ:.3Y{NsN C^^-?n@D\; =wA:h޸E+sa -$JϣĊyZ\n,A+esuy sxAl,ptJT1Py/Itxр0kǑY-)R̵%QF-|#˘珀u}h띅' gۣ5Bqۄ2dthbH tͳl"YuG,WxWÕ?@=qiG: gW{ov})Ccl;2l~fDʹDD[犆&d``6uiVo޽dض񋺤cW(!-ð%|mFp{,{j'g8T9ZmKv31쾩cO_ 22tn9ϝ�3Eó r|&:Gד#~�"1|Uj08`vj`w%O$2qO -J`A Bsƀ2 ?CCmÜԄg,D!I-KţCd{T ʤJ=Z++fߵ |*FWN!{i;T>lv)*P]C 03K<K![Di~v{$BJ]N/fYG~D7g~{ We6˘L)+ T�e;G¼) T%D*X %`!,�Mm[>IǙ-M% rñ8vCrM ̺v>M[qei900x5#5xy-Ķ`Џ w\IW4d2%(Q#>jnۡx"A Iv g<5bö\h77<yχ$uA}۴[Z�QJ\;eqҟVKqP^m+cP5>e)J̥ S)R-"p ]}1 8hAs QfnoRחge.a,0׋9 ^ky/ y^o ޴ímwJt0Arf/n&`KiC8PCplNUJP\O9b%b3V\ɿ7F*J؃,e4EArG]mw֔N# XOՁT-&}Kc,i[+Դ҈`XJ(3VvъkXܢA-Zٔ pbZ0zKzmxLqVGzHGP4Byΐ1v{�IM3>,0yiDf` ,w;t{=ȸ,z?}iKs'5zyB3yѝ4,�xqk[<&^21 #!o(cy !hmnBcR3(/ːw؇:* \gQ`[Z$TV 5s4b+2|%Y]PJ*csvbB<ۨjn$.I,EU8dgA͒y*=y2qM/RAe;:9 Hy+V2J\ꢗ'V ce:1N_u�WtGtP|A09RVŠ^r댯CCV ˯شTc;RrVW?Ebpŗz<IaK}8<+W#?`r;kd0Pe{Oygȫ<P?*A3/gTٷRߧWꝙZ+TMWʁʁ~-OZ�{._e&Z)$RI42cl2S:_[\ޅL}0Fq6;9u$G#9t"EQ"f}Q@C>J¦cSQ7y |n(9 Hwf&SXfʹJEʴfZ�9fdacMN<*^+F3<TV*kF,7p MM3 NyW ,X31#ȽBV * < 5k̏B>$^2SfNW//[3N[4# s%0hx`P1FXvy6ǵe'aa5<:M0 mJq]i2BT7i}yArF`SmAIʢz<Ȃ5w$QBq##F-.R侴=4g.0107sqQbMɭƾ嫱C^WȜT&AF<S`Ƥ#Hx>B.mXƮpȰ<-(6l(Ac Ձ%0Z#=q-X&,_z4n,K`M:ɽU$,G-R`2U 1\}T䯯v%׼ 1/PFgd;ht#2Aݻ ߄[cfjF,c@m`K #p9i�js+RÓ2A{2" iPs"תfWo` QV,eyV]:zqW)_tH|6e39LEYKfH3a{ !!ط뀘aVH�w@[L+GrRdՠU FQzG+tNd3Ϥ&p&u-i(|0ҖsdA>9yٟ'a)Zd9vJq~\(MÊ9~N)4EwCZTsAGC5vGi0U@MɑGv,LXɮ:5] Ipoʯն &Aޡ1]V.lQUۮ>Mhvf`+rᛱ.7≌-O' 6_:tTp8uil[T35RI�0c@ZEguq}Ki]P’5!G#̕Z0+' AF.Қm)YlUn>mͷaT}Y?'tNsRaXٷ;_rTÌ4iuT({{E JJƏ:,7J_AJ�9'SZBkq2۪cKEDe<m-xMݏuálR9ziElT3Riӎ)$G5;Hko�s >o@*=Ǖ.xl5H<wT*+�yŃƊ(E-BT"z &v'D)][�=>qׅGcӖjd]Ԛ5\ue'vEe,y!ԕtiJ-bMj2ff:(.&/zti,ߌaWvHaʨY1C蠂%='HPƳBLqhhm5jt@Ala9F<{0iR'<!{d('ur8n0I延ŊsL?}*-xPX-o~P0P UثZwr*͗4& EO]8ZU ",{zL0qp9OZ.VFZyts䃀  -pi~(cN(-GP^qZ !e g+֯ @& �zsesdbVs43ӘDsgpW l7;X!R]u£J?8{Uuϗ~kk8cM;م q2Q-Jr2A<-ƐYf~mJ6Fw4o2?f>3lyA>y(tJˡ-Ԟz Ló~™Rvv?8{C:<bR&sxOEFj("3f[Wۘ@"V^Qoi5trV6ܥϩhj Ɋ $Ghc W*U#Kzh'ߤ pzЂ{Iv`\,ȢjH\~,l/)[;"t8CPS1'pƜNj)zs3kA@ve],a }NP+Ģ7PzlkU&II .T>�bߛw7h )z?d_$飋{G2|}"P]2;T0AއIއNwI_\5}X8s{ $eW#J!"3+]>o; $pG"Y}x{kǭ9olO:v%)4PxAڮGp T8, ;#0a)E€2} |lV4;CWܑbFzڣPF!0$H9Ál ;.׳ܕt?(*Q݁  PewYJA7'ITxN7ۖVQ2UWTFKe74ۤY᥹67-Yp$=lUhB_Xk&Ee\S72$]U\I^֎9$s}I,>cUD^a&TUE$ͷ=j)vNIqsIn+bD@-ř#43.do:\BVث/LvO5QGH 3DV dDU)=5x(S'YS IB FBl03ez"VvK{הHqa|A [Foթ:p..SJjc+o%Pa+3Hُ6ӴLks*CɱQn#3ɄlryN = |[?Md=ɣ"kO3ming:,UiQU&'ԝi"/\J-KPC%y&qF1(0K7-^-d/n5ߜBh�(0)-Fӗ#w n0hD;]5٥,W > 0jR[r ID6߅'(}O|}S#PRVvd-%aB2Nsm8yb%DBDZ=- 5àӷW!ȷ?ʲ(SKn*JI R'v4^r_cB뙟[95̖&$%40fAS@pH#q|mXV!c~>I3TWquKEKqL$&&`YB %*9 N;QfPtB^g 01s$~DQM qJTw. pAbx#4uUfX݉/Yh.$cGԑc)Ҕ, ӑNJc6B Ìs6ߣIxꓟD8CGWĥ j'o9,~#Eu \ɉ@:oj݉I)Ic{ZT�65X>\kf I�$5CQ,[d4ݑOlߺ_y#E ]);q`T=cvP{$ ~^4j*6noҨDӸ˳[#ՙ#|9٦?FإowJrlܰsCM֬{]<;B_A#\߅ߕ;-XPMj>v hc;y![Ndx1+pϥ.<a\ 9sCP ە"*}fWj)# ݉.ηo4ě[rzxS-MI؀vDzerǒ!)iU ~S:u:M+q׬,)/{ ~}]Gvz`z7d qYuxiBEto'F~im OyYg2u,<N]N\MٛBܽef17暑u FEC#IaHNjܝc<ʷ1Unʤ̉W5] O4?6UTj&=UsC[2+~5"2J2+-B lNt=hvSu 36C̩Уz,'3U;o*i5iǬ@S|v& XCoSJL-f8Ʊ/{9?ol{.m=c%i۳}{-Z޵?K]~s)4@$M}D yQ%M%3b>1N!irHd |^j'<rKO=FaM.Lҵk[Yۨ^7.?;&AJe.(C`qLIDk<r:dF*{%No/e7 ]v8H|[?e$65JokE7v~w+}f)gg[KE|f |j|6u?CaHS`$_L[! mȧI1He5g�bzFƗe:3y�de$"`^ Vdu7"̓84M}Vq=|=eJ:I*u%%?q4{D7lͶ(s&P])sKQ+E*%"HMVn-bLl6К٣~1^o`+xϺn=N:eo}UX}yNxV{fM(}sب"A˽敔AM$/:]4,|^+L 9kЗýxP,[b??HhFr=ZyG'xbxw�Oͧ{{v/9qK;D,̬fF\{c?a׶)^\稸8!Y*' nRwͻRedfA atLs3|V?PŌˠj9K ϥL#zt@6~w:2 Ry雜|r}Ӝ=:fT"z#hVz&3cKnǢbU -ƅdHѻԩ=QRn{[5VOn[ݑZp&ӞxwGz`ƪLwdY|ӃsS\= _s4MqE/7TWvmU>Eŏgi1AlrZK rL.N]ʙ}k:p~wwaftdx{a+r A)g)eu2VI u:ϗr3(*%@mPplcY/"Q^z(9h@7/4qoRSIysِdO`K<{'H? @ . #tٌ0%y9? lq$P&.I#ШRw?g⁙ I}7/? =Ćn*w<}LXFГe tfN*Hc`ٲ"x621 l4{M ⾽00^㣀О 2vea]g)Mj _JsX(‰G2/R�*J@덒D獯)}es%}ޫoVJ](hd:lg(?>ɊnEq}vblpmD)W $7 wC ˊTp~e~W9E>P1NOYuYUч&I? 򊫼DEL^ϲ캝ܔaІPеMM9R2\?7&pJݶ1�Q?ebr)utw+O$Iت.!@ U>bAgPa漂 gF,p7Ul %-$ʲHY�fq!AFc.Ԟh9T)`ΤU\H~1ov6 pn>-T/%0p\$8 %LnҦ3sM͑*/`o28@mkpr(6ю,Htո,"]"lN LU{Iѹ7cjÎ[՚mTpE m;; $ lt۽_o_M #pڼl1+~؉0=U=]bIDj!'$D0ENanCu$7YOeAy&m;u\kx{,/w|E&aI Q]ΔPuKO̡4%W_ԁ&\8aYB$ەnm$s.A :ހ % Z[k[2T7Ϛt, `ƦRۉqIG{ʓu,hR[iohj)TҬFܸ  \nnoc{e npj^{<Kۋy+4H{&*Y]q!W:%8I|2BBH۹D5*ΩuCȘ�.V?˅HqJͨƧ՞ 2 %w!S;?u$0$x朠96Eu9g[)ZKPfgD4<ZlldwGi. pQ3o-y&:2>vڃ;|tFzF ғ{^b*�Q>n�.Yqf!3 1b@r,L-# if#w0mb9.$0BCL)Ն1<nn�+Of[f-I ]sx4,}-Y2%bV4׆tjb~4HX/"{dYt7"*>&}K>?Hė{Jy6C[Qu']eCqMn'ﱳmǓx3@� |[ot q�qwlt( ;ؤ0c%jzm;" ,VX'm,gb;#1j&ONa@q<I|33e}/dC#)@c~8WOС!!fVh(sFW~8^Ϫ0;4vݕpl]]]WIG>]YYl'״d΢lܲ#:RS:;chH $:/)PqȨq5߹s Cv*r~7PVnl_45i?*K5=| PuT"mzsHzq x )ЈY^ X=m:e]dB!\<-;~gۤW.̛WaP.̋v˟u"folY�poqOfAɃƗp̨F հ6ܫ9Ŵhnf5fU!F.n}Qn^lt=5'0oD|(11G:_} u"EoǤ /J9HX˺.s"Dٷ}C9A;0(6ηI?~MÞ;KXµf] .JD4x䠚ب[郀]}oL[~S# iTQy{wʫBA2Vȁ9tձI>J4POԱ:BOfҜ]OYqIԥ0'0,Xt*{g5x/gr<{*f;f";8kS*19S,n:n"#^<Jh#7)x Eo]DWQІ&)*Gb8߰4s:W#Bǀ:ӧ8Jk. :s[:wJ!'+gިaM3! n6&ЪiΌ)Y9dXq"7R!GnC0K\8rgi@LLLi/ nv{?Bl1|$lF +]� J@ "˷&{<ڵKwS ,9A^ iQ81z^TLsA-L^ rEudqI Ʀ;ϸ"}EyKZZWvnF%nrlK?!"K#$[JBϿsl˦˙ΌIq,ϰ;)*,C_˜aE$l%S1/]|XҳY-a6},4-G}CNC|Qx~[;ƈP08ʇ׬Jgr22¡�^CƄkCC|l�+X=NUWּo~=|U;|$jopVX:|J70Ђg77%SQVj"!Z <c  !aFӮauR.ܺUrWl   +nsvR[Rz#jK Ft<O1a�Fx{1gۡ|X^x0IpC/$$M֐Q;f2$9qkLbhvs:Ӝ6)hW1}uaܨv1Os#𚪼Ӗ$:a(fe $_TXк${u(FƮt03&ޓWN�#V4IKB C"d$f81E>Y 룈Pfa yn8{"<τ٩숊IQr0>^d'dS%#^8WmwǾ$UtʕXgE {I@3S՗#;DFPE0r]KMuxl$7)F_ CtG[ ͷԒ7D&[f!ޝӜ}EM9ڇJ5CinIa/ak* |vß8Ff7%1=cտ\Gr)rs ^kqp,U}e,?c[pSdT"S'& xm3M`5^doJͶ0SIx!A: ʵ hD%|x)NɅYڒQ. :l3nð̈́߬^k/!Y!&ndG;Eڿ?GOU FjG4>xߥ>n2*%ͱLjcqQhf+3%߷ysYr @O5P$]&^U e v{M|nlds\RU=晘ܤ0%RbfwAL0ӹ/Bn>i&%�6ӓ(H{1�aQMNt?J'�@{DKċ؃șl3t~ݯxvZڄS,׋)ϝTE(ȓ)3e*Bwe->6rT~I8qbNU+zl i|zp37 }GyM46#f5/]|$0<Cf}˟0~=0~n~J]3 8 W^$6׹f-IFB(I>#v^±(yD - >+Ża7J)C3"6 P(~j55w6D%)d$t!%-1ɲH%Jι�4J231ngfJ/|Ò#U<*=Y$8n䨨̽#.YV a W3_ X(7kEɱw9X9ӫzU@](ѐTڛ/,j27*o (.oyiȎZ"J8+vXnͷ NJ޶B8UwW=_= woʃ[NJS"p6%L%^֞{Y`'p2ܶۓppj-Qay^@^kj(MPu#}Vz$+wP/ J _k-g9=31/Q q!I%DKjZ~( ]ѢoZŔqQ`sxv*}gZArI l;ǫ?M%1Uwƨ4!q $Q[z n^،Enf"M/ 2L~n&e-.D<?'a|%wm˶SG6&{na|z>rV Vq\e¾Fǐ}N侱oi'̐W.69 N(�&8 Y[x=?J׍gO6>D޲E6߇Luv3\#O'dҁ7h{ Mp=Mw&4/Tdw*^^ UGdn!GnA{ss#F44,X_@'=@CtQ0,ٻi!G$|Ub&m[sm;-e(5c#tw&Ã%U1x~Xηi ~9)BB@p2 o,r-M)p`Tz:j}-JHRAI" t-҂4Qq-%mxTc m(f~DZP&x8pӔw48,Yi։a*>">S#ZET Pxū8*eOQcd&�Xi0p,˔T;i*aAK`|lf"3MyO* ..aP")0(-$R 4`2;%9w`"=b!DKorAr" ~4T-'oITerYȓp6?I]bIvȧjc;".siH4G$VWʅPٶ Az'kXY 8jC|Z蟻I6{gr4v*` =HQgruom7p3@xGsE!-CiK5u(^ywl'M}!gǁS0z~$ٯ3w G I~(JK“9$g`o7?+yRPS;rs'R!&y?yb?H tPBy4M0?镜UɾOp<%hwaҼy,ˎŇ]ގ s >Ȏۙ!Q4%؄VkD{ @Cf~"Bfwt=1ǓPS6C(U>Xxr Ug`z=g9x(iIP7 w�m/緧; (MgX[\HNyQ ͢c Z,[N2ɀzYWudB>9l*&@֝XHk[wb$J46lm?cD0uxG`)ilѪn3Lo[q=umЃ܎s`40-FI;(yx�f=7&)yU,0Tl?͘?LnDTVǢ9Iءo(s*=Ar 꺱?ɮBsbbwAYdOu9 o#ԯCh[Xr6D$ɽyxs L**@GHF+t W{qt=ӮAIAu4f"$R X$^9}XCNNVM!["afOJḪ ǜ e3Oy=$guI'ߑ=,ܿYMys7T~/ьKD yA~gL$: ` !7Mfvm$"-h125˩ <<#gA2d-y2-#g߮l,.63!Wy$H*1Ϩ4E0V .9ZUҬ2`Wxlpѥ8w&[Y4jX [%V<~<fǟޡ} ?9=>Dz \K>)Hu)I4#s*QCT^Pt} f,iD${9MhWp?#A Hҥm:V.TVPڬdb> .�x.&hb_[ ZUweMNY7�D%C S7CҰ$dG9DK|s4bfC5q'O/D!y&RpΧ=?fr.{{e}Z iΧY|˳'q%÷6^p)K?yU+%ͺA ٞHl=�bҩŮW]5^elY7wd' (D~ڻ>$xmyrےВi ;) \ƛ]i%I~Ē%%Ͷ.L:O(2`Z1ٝuPxk椒=3z^�,"U:T݊~Q686UǍD \4OeXlDP#mD ͒~Me:^ҥ#PKGRہc4(TTPNYkx- 3\@p֧I'ne.Ϲ*H$?ua`_]b|QCߑ~%iXSPy7fKc "_pFNrWDw_#??-h$'YT1k':OA)F6T ;F`ܧx'fջҚ$]# =nΧBIo^e}dڨ'ZG^Kď,3V3'GL^Lo*Q #^c=Whx+�4,O.M2{0d*MpV:K2DTєk|I-Ÿq D g0(0x ijO/ЬHLm13$E Jo:tHf $j d'դe@t jSz&[aoY٬ί"vS1 շ%%!%xU *rdF+*o{0x|cioPl- N_FNﴑZO܏CߎLzeÛ: :˭orE1u1IJ$8#Ԫ) SČ_l>9Q}A2%2g'XS\?M>fjV`Goqμ%'c1boGgvt0f]_�ߟwnUݧoō&YڋO]^Ú&{Kͭm{NWY[<ٖGmY`U=cIir% koDݞ^>lR\;bEnU3NoEy'g⮳4" 0$85x7+FyI K|! ]U9r+=/4엠]SrntK @5dG2 wO$Ů 8EnY@kݎ\pɽ a͹d6uөX}ԚکqH#JgB>YЉlwl?{RcEfxPWXq+dx &U"yxFy?ğx{Sk\xҴpukQ&4 pwlkX PFsv "b*)"~sjðFȝ'FBrd{ hsgt-@4.XiZ8,`왁3$o|w6Y�L8s+1O :)¾ 8(JLjbKozôQ|йr)CDAպzl]&o~|VdӰ))fE,ܾ|r3^95_lp5ڏ`!Zp1\aT::dW߬oni<kW :#3oהT[~AN[n}Âj[Sm; $ܻ!~SSa'NS�4t%tW/'~ܝWP! `xI!7Z^m�ZI`]5NwE @(9ƛָE29B nNڛռmdx�r; wqQ]2._:bQw'yM>o][MZo1Юo1Ke}/S~^6obyLÒE =Nەg¶\45Ƃః75F#júr{ww+Le* ءD0ofdo~,|_sH!=?WtsKۄi6G&}ApN¨`^#("k{`{rx,rP0a5Iݺd5 o;E))QDij3P@]i[4Sf$Ǐ&_nw5IsliB0SwGe*zDM`! 5M%䒜D;\cey)K^ eL4;2YMp#3 ɔ\QhOf=T 4b^S;xw'(汙 ;xL0Zx/\ zļwLg]m9jV\m'/ A+Tf8^7$3H;[3J\iДq6+KǼYn0ȅĦζ4D{}]C⟵=`‡vgg=~|Ce 2ɒݜ,'I^ҽ1$sɜ\n7$w@?e7vR{x{*~<9;?W@ F%N8$N᠌! ^ Qk 8{67璤./8vnrK&=$k& "'ZCJbnn;|JتsАE7Yv"� >uI{&B4;/iZ4AI{PVD~bL:4Zn,[ۧfC-o1N\o&r+(k'F ~x&-JpneV)T֔(dk(1YZVSW`fgDMtȎdtVtJpGBZZn"U3VT+z�J*PdA{rWbuZ'h6Gs-@d7VR7.t5G˂@6Ucὣ۱>**J6!"ZNDf|Vƪd&v5G &DU#|�KDa[^G@ƷbYPlj 068g HRFD?'"�z7,e O/ 09P]PrjNz9d?Kp(rЁ׭^+U,j(O,g RڈopŚn/NL+`Sé9o,Y(.bD 7zg~<),Rŋ{xꚒaARQ)dIf%T9WAMoKf[u^a(`:<do{&G~d3n\^ΏVqjB8WukdzB!Qr82fm+ނfE7#|()ĐM5B2Rušwp//*zOw096!Xf[yJ. 4S{VpM ';nv5ЯxK=S{JcA|HR[~P$"b:ft:14tɢѓK"¼\,&1tpޮ3Efx71pl`Eǟ+oD:ju�#W$UVP ?^›fQA]&$Ie6_X ҆�}g|{F�!noVwhQpႍ~ӓUoYgEi,UJ=4 %h|EI,aK MH-H�x !an!Ck Є,4@|lD`a~6K0l-pZëYI7 ؄\!W@Zn&??Dq]Z,&^ Y,c\O1:uCzvsmRa)EuHXe1| ν4V5puv*gy�Y"+& f- <3lg"Ł (s8FIMF:ST  ;om y &MS=+ n:y+AQ`pA˙2{>>C8?n6H213CK~fKP.]آ{ e^de3<>X@V& i_>nA&b fx!Mº/Ѳ̝2$'=ϟ$ CB{M5@*f�hn͏ݶ(tR4TW~�Z?y rs<XBu,\ u?2~Ttάz=vr[bu^a*ҁ&kޱ7x]`Fz#]Fg]vq4)jD`J\s; NLFbq1LJ`uI>pg箜:7W5[=ۗ'`Gh*Nz':*]ke5p1Q^=}K^^_UTZE-+ܯ>hW XP3#x,[hMceGpLә&hxP\ r-,\pi1i&c<U.9HN ,rF=$ W^ 36Gm3#?#]Mp蝜9~nQ"&9&-NE3[\_w� Ght _7�g^歸3 h nյ< *FrP0a2R"ePvIlW1, z̉pHEvYUL 8%AVф6K<a�adp&ҫlt� #A+DӶ:H7qn:0ҟF7 5 _9nMG/! p#c׳xrx{Uz c3"E3P�:ſW!9[ uO+�w?{+!q !MB49_ bS" u63>bk&lÂ'Mc Ǭ!q{D888CB{ ;t'*~ 'f͜+D ).HـT*5PU,oBɊtkoQg.ں~!4R:(#I%l¹^$ tF`GNfAh^Ն0MU{_ɱ&C$q -r*|\ѕCK2 K g b;_M6ڝA:~з[-YIz2QdIЗ f<. #[TmmSL+<{$>98[l!xWKv~L.K>_p qr8Xs`@�n 3:]Ӄ¾pZ4ÿy'ňHAti"_~# K%·soH}W‹뮲R?(J-� �.b>pK8g Nf%u,&%YHgg0�-),/%xhdg MFR'prSoNIJ$yl4[T1ؾ'yp&sAL14*j5Z,a{Nɢq9oo1�tF L5Xv2Eu*-ǺNﴩCrJdU Y[p6CB /og?(CxJhJak%I%a}A+g/ekZ 8ދuP9%aSߛ}5wY^NO;[*ߺ$/ HM ]":{C <E ݵftCdI#%%unIMrr>saI dVL8!z>LDֶFZuPt2WiSDڏ,jOC 7/di21137]c:\Ilt.+gu/QpVJ\!fZz/vW?'ފ7{q~26ekr$4.Y,ԑQ S}6bxyx?Br?>|ǧ:iﻉHh@5m݀.k,Uu]QZ=*+bos\!Iv`ۮUx_𼏯Ǐ󭴽OCm,Bߖ]K4WR|;ԣd5FudVcCjUDX7GJB|=;3 Ai6`!U!)re1>#)p$ a,c "zh>&>~G. 9$LF5XőZbF}/G6+\|F:9uV=|>>>~<Lep)ڴej-qyP>omLaCQ:RlwCڮ}#j9_q:0 mH@c3_×럷O>yIH k 32ĩ4-{X\&'ЗR| h1>۽C,Y<o4\DۢY(wbWsٶO΍L x8W'ٶ+|~ntN ӆV:$6 B*ie]CQ;zF6P rl:Jy.Xxb�:«%nM=lk޷mS.Xp.�V9]BmBwF;vjUPFh(KdGq(?=nzF6ޅ C @h3_"/GxWX XlQ>6>ƏԶ#6: |O� w)^a2~$mUW +A83v.6'u$F{Ϲg3v{ 5>RD<= 7?pn�*b;y.94N 8MŸl~:{X).s`(OTa7{UY_!5m{2Ј{sP3X 2syFřmZ%ϛѣH<|$(ڬmԾqO*U=zBupژWHzFh>smߟ{*5}||*ƺ2#!0hFxvmH�X3_*R#|^]fQLACKf|>[QsF6 :SVHq?Ψ=moYwa$ 6"޾գQmaWG3BE]nyb# 42漬mD뺂7G9p$3BvmW=|>>>~Qu=İMQGX6վ褫<69 xFȨ8smW*GxoI } ̒ avޕl{7O 3ic% C1Bs4߀c#V>㷴VWdlG2M!\7~" oԣ2NC9#4g{*}}|ǘwJٯ[mA1~4@4?g�ܙm=|>.>ɲ+lBN;:92hC>!Ki19]x*)`|wby?}1 oHba ҏu}j)v;jIc9#xss[6rc "zh1>vKo�xS!TfI\ |lھF&p9hs $;7 ض_W=b>?N\5{$5]Ѭ5(:,V�vEHTHO3e @%-|3I)$SWE]{^.m? 1c#HqF6T"g3v{*}}^lMGثbmԁUM [${gCH_2 �g|ah<o`62*y$Rn%D@x:%FNF%c2buk}|I-3#&BO^ρ@m<gDD!:Ip]Jy9`u�C*)҈Tfc�zblBCao m΀ $IS.n@rf`<{hy ʉ*WxP+G|@ľ(bBK"ˣ~ɥcG_1wwP bfNP7hp$$zm΁+\b g0әm=by^%Ũb*_&zNzY_$ؔǙ@m@Kh1*UCG'D D⤶bNszTF }�55z,wf`!%-*�f,`oRc4{m:ޣ:F6@X3B:ә_gC7CK'DL IW+@Weڦfy 5Cfgx4g__\/b~:c9oŜaB e8`HRs(Hl93%x_*Y@uH?DJ<A;_&:{lE1>NnT"[>3%o[1.< {y{IЕèmos"$H:#tΜ9ض+|#֭FkCdTfT RK�M$胩>9m>B4™m^{*}}32I9x}Xȃ_mEB&PZ4ZQIFoh=֪ok1z IT3 N`x;GwI+9p$ 3BҙmD !#^dΐLKf%?Pv򆴴yZ39kg _uk}|jSR_H#D'\ V2){>BIGR7} 3ZU4jɮzi f@g4hg\n=~ ۥy KHqFș n>GΞJy?lSski +B1o0M+UQDTmgM&~w@<^f0dD!p\/Vz}]ƺh9~$�{`k X.v86dݡYu06qۜ. c!)p=by{bYuM! Kn!KaS1J~Ň9~1v{5~6ĂlsЇq$kVU;XzYڑM)y6.6O.ɐd Ʈɽ ?4Ho9~G�W^ZϤCٲFa�==#D;)8$0G(�D>s TZIăЄ`#lE j97W䂎<9f`{h>&>hfK CQZ],RͶD)B|'J`#&`.x_fQ=osr.&mmkCyQ19-`z`q=|>>~ddY$z:(AJK*9O;jדk<̝&@mй>!b|&`iZ%k-С~ZY$rD6(NцJR lAGHyR`I#<Sp Y(.`Eњ 1mEr!t!ڜM"G`řÉ=bytFҵ(/Gb }%Nݫ#W9B9pI׫ _P*gIǑ}8\ͲsŒ^Iq^1Z-Gb 6>79.d9a68Xh //Ÿ2Sgq4$,^Ie=yx3ԣoڜ>TK7-ʶoQf+U_)p$gYl:ZTMQH jiZ-ϣwk 6+:уgos&J3m|h�w%Vp CZ$p ~ר CfW`C@a>9ׯu1b5r#֭Qo@TH`\T\dG8ehБ|6g@KeT&Y lZw5=|Vex=oVXnvj^RR;NjSf?05xP?nӣ&�$1K6@pL(@Y(Gg\6FRZL`n&̱3_*GxowG%f] :W):=O;JbͮG?lZ%ϛz͛I<d*D#* sLUmoIB#xs($JgCmGqCClXP,RWxF̋΢hѾ3tۭG!>Vm΁+$H9# ̞9ض+|W#<㳀e4HTsO5}?j[mc0Lx3wOض | #iC#$WH{\:tzid>n&mN|x?> Oco|~>t:/ ϲIomd7R{)4ۜבYPQp`V=|>>~/gy,C&ӛi^mv]vZ_C{A.ۜB�e*F,o$j*Z<nT`'YMU-roFi"d-|dc8F6.13@P噂mk#w=Lј$93?ӄ>ʴޛ�)_>n<|>~D ZQ/X7 Q/ -exxkg2ܙzzFvRhFYvLm8=bq�UNw (ً2` gvp33񐙛={bhg:+ zh30n Cn5P ^oG"gеz4^̼9p$@`ym)}[nWxTCp,6醁e؊J}`*9= cosE0=s 9*㬛#|oYT.k>JzC8f.jC۾K lGZ<:@Nq &<q�4&xK7Ь)Z d &@w {%[_ۘ?ZHuSnihB5S)Gt3@c(-{*}}|Z�fVPr6_!h5(Flj"p {nG(k5$g`3H$V<F<# PKiDX�2GĨ"=^;�_nx?LX`g#+l6>CI*q47dj= :6^ ;gkb #7~f)G IruS\m6#Vgos_GbsY6}ZU<wP_O7IaX"~&0{;ᩱm@O{Ԭʺ A;\^9m/GxH"EB IGt66tE~3D!@G9#˼ׯ ynV|ƐdځV^fv2j40{y1h gos]#Fv̡]UDXFxǧU2Q/"1/scwz,ǞM*oZ,3h ×#sScF�ZBQBVokײci䓊`Fr `tUԫ ɡ͈ O ][aH3$E 삐$LڙAmxa�)&_lO}% Х*%No3a{@<#D;w IBssmWhW#<S^MaLoQtA>@4<!{\ 7X%j=|~6#;һdX9HzF FrhCek\}ڞPzcuί~;䂳ڐJwK&wm5DŽ+tc5F6@@D>x g>`V=|>>> U 0L%y;TY6+1AxET%V -;S VZhr_-;GPX+vz#U0dE툶n=f֎m΁+$);#*9ض+|W#<J ՛p!;Z]6fèAGvt$ת zh@3pi#/?Bzqs@KD`YfŴ$9c>@u"uHSS |>.>T[a\Ws_ kl4N!N˽倁A|KivQk "aFHV3z &*KX>\o=W#xs $Bg*G[#<G"c1Z w<YTRFb"Ec\sH#aCm\UGxPBCqII@#Κ;Z¡2mCP�jk Qj\ j5DXxŏ~ 7Y(k<A6@G;=&(ő�zhB`{*}}|n tTXֶamVHYDV6 t ;F60vHL#dYέ �Mtq""T,iI{2PG$F vFvsdT$*hl+8=|>>F"]NEHPR ˽ ޣSk&gS#�g4qX.ϱ(ܦBA3YbːHiX~4r;\�؆)%xXFx!#Ha 쉨m0�hE>~1;!YG zh,Ә"3MA%ϛW"cw&i-Lbz6"x>&x't=.3A,{Ģ9M|,6T~$ q/~rRT/2f{j39|$b ^g~Ux_#Zʢ !g ڕbX6> A39$B?s̹$<nsg>}yX  *j鑀 3jm;]fK`E!E:!:#6K=?ny6;!Rd2m8cŰHc$gos%+ad`g~{*}}|~ (t@!Cxd AU{uF6.A!8y`Yzus*k&�Ř ¢TFХ6@3 tXdrp$ƴ>C>o,; =|~ lmp}}v4#�^%(ڌhk6:XV=׫ R@ ۸ʏGՄ-Ud q ?RaMY $5?dMq<śPXs/#d2"䨉Fn=|>&~s0frd"�Z gjsA/ԣl~m΁] 3BG晃m8 񣮟u'AlɌ"zˠe i"TXez\ms;Ta՝x_x§/>Oi8VK2cgx'3##R>iovzae06Ѹd3F,%9Ze#3{@Q˞,I1T&=<1)9BPӟ|RSQHqߣTy]JY ՘AY)s_t{ͷ܆.DʧjkZ_bk',$�5fn/_$Zmo/i U鋝 #Lkg(YU9.6@|$T7L+39k){X̺m(p$pĢgai#֭y%DK6v {A883=:1BRCR#\jkl+R=|>>~T4"e:>Gwy5ʭCgT\1$c$gQш%D__2&Ꮐ8Ũ{gĺ4F4'<J2 bhc 8c,> L pLL#&Yt^&!L<5MYhg�G2|/ l%jRh&Rb#f B[t*4_+\#17?2ZӘm(T{ 5~Sm$25q=ES DŽvF6P~� #T*b~*V#<g1dƉ1$ ň3 _HԾrG(9 DV93osmW*#V>{8Y tGyZ0z6WAf@ږ6s9=& B 3Bi"~ވUx-xgvgƑq BՍdoB/R0V p1]bȧ0n3{9=F%2i%==),}U F)T,}!.aL`qs-j{*}}f_CL?3-CܶƘ˭]4|!1J8:3d5G,|hHμ?$C+P2aZžX̖WLjzN4ӫC2X# Fc 'c{ل[.YETep�vG imh;xH vF șyI*GxǟHn,嚉ݼ7۴BBdըhw QF6P OBD# 1u{*}}|%,[f+ *�[*άѶ,uz?>B9@%F0vmW=by?|8. 7 Q$ZAd#]-;8sz0\|F6ud z2`9lUY7GmꕿXh'[ ԝ]کѲrowso=m P<o1RGZ#aO >H;EP`31Ror_G@S`cj� յυoNWc6H-'@Z5i2piΜhghgBIid&c]JyIV.ІB+Ϡ|ٶ(Vso#D[!k=4;bUD2Fx Ua@.P?.fdeϸCƟ av7ݫ@P9'@l~:{_XGQIS_')P:,lHiN_&g�$Ϲ]kD /1i`,vIG,I٥3Զ'\Pyz2� %d1kϴf`.5xXhi].)PWgaو[ll 7N8HBFHEF`6B_Uj} mɢV"54ڶK]˽E1jos|%ƹ02zmlKN AkW |/XIM۽e[$_A#e92*Z<nGxYD%=0 ILnR_FxK~ E~.%`p\w5�ϻ[#i`]ơE#va3լJ AAй LPo+@y <7ZcId1۪',jwbߊv\w�?WG;+%'$Jر M}ZWW?"Ȟ& zo4Tx26.`5emB"I$P�kx`=|>>~$uw!A,2%C`xۘMPXaomh!VwUZ?=ܸA@aElE.}` #)QD @3CQY-@<&.Ay){\H<;%<{Km-ԑ$kcg 6UYnkM|ıh #YVWkӣ%;F Bh ZӔϡ6ι%OvIFf3ll]YJVp:)go'*RPzp9F+W=ywfőTRvEX?U޶V#Ds(%#2l<@Jy19 Ԑ선mᗯmTxz߷|!aadM歉uM(!'7U ݫX]CKMpGmԐg@G5Yr#9pK#՘9Ԇ nO*Ve^R iާ+ॹP6')`ORĞoC�#8ͻќ&4V=|>>~�;ad�?t}I:<V+x%m<)6�%e^% uw37$\]uc� B@e>W4j٣ɸ+SVT󹟝 GڝP#h G'L�y*x "jiA/mH٘JBBomy7dD #-c4%$0qxba()5w|TcդDT\3Dh>*.;#2SPn:@v>X[) MD),9b7QΦD ZѺ.6,{el֙@7`EO^[! {Ya[i y|%pGD5=vR-ɶ z"d퓄*<[UrJ*cqBi$-EhDI;Hb(U[+SBb$)ࠄHXxtYa[i yH7Q:37OxGjό &}߶I1u)3%SBO*�}Fks/%R~Io$E()?9Kay$seA\"9l%<n\6])wY*}qeUSV73DT+k[qW .%DIli?'Ύ> 7Q‡m>d[koso& Ƈ%�ߒ/Cbmv| [i yptBgQN;aSܸh\jkօV*љ>3.$5:ĕ 氉{lLI,'oBG"L..`i"X+ј_j T%ϔ"xt .+a%19QĄOcQOW~>h${bl܊9!7E5RBd@W\+<#)(c!T�j#@|*<@]s!5z4pO6m_mP7 Y G+9#1bY#VIy|bj�Q8S@tK�b#Lq _6fgݬF̕)_g}`*( rJ²u,b-+!#-1b�10_`8^lq<ıTqq<+cQ"ֳz8ݞb,aUyXR.+'蠖q<HϚ>rTTǷCTUl)—̊) A÷7mwr M W :5B%AᨩC8FȊ䐕)9NJq᳌_U9uOJZqtpa2;r�R*lL0 kaTNZbcQʚ`;påKg@A(EO9z[ɒ$͓_Iw]8rfG0@^|aoP|\%!6.饃6S&%9 :*D1%ŵPtEEƺzXf`_o2N]NH½:??e9l%<U0%!SM Vt 7f5^+"ÌQL_9]K"D9OHrL(E#V[s_;S]2S54xilI[bLa%+~$4e9nIxx2BeUxGNDgO!8b`xu$)58@q`)Wee-vhJ<EK]l%6?4V۪?o<pPQص((^@"̑FKskd aS:l*!Fz8$k`KMJOhJkR|r٠m?'~DakGQ%h=CXnc渿&Z1u`)- uob8Re9nIx,]_u*j _ysαf %;Q') i%AeRGsNZa[i y|9l琔h9/fL5$ՋQ۪:0BΔɔncAl8JIx#gC}{W�\v/%Ymj??&9k$�Hjb)!za+a+-9wyPNߥ)'n[VZWtDJj2Ǯ(K0DO$/ sݒ$B\;淟SDTeSdJBEIq Khl VMRVZs_(ćU%Nhq^R.3G;$Y^&&Zs_@u0CExĵ|WBlBܽ6MTdQ E !ATbg,`-9�CuYdD(Ȏ؟h p)q&*0l* ˡI.$/HĈH%9$nq@ʢtttS$wS".' oY2 +ZOue�寫#,m9l$�Hl"V^W? ,T =mڤX7cbW#.w74Ô=1>++ rԚKcŹ5%$^T ). =پa[qJKxyi,iʉJ %WGMN3ˉ8#4jx% {S l F0<ޯhN%&܆UEհ8]za-sqD(M!Y/TQ"JSpbQ#_ 8xa ŝb~\~nL24 wxJ:1bWRqlwDXkkPo 7z ~c>ߑVÅ�L9(j #mޫᎀ=r$`c=Nm5Jn.I mhxLA#&$M$O^_w0)'k'9x/x4Ƣnٽ8S4MYxx'7R9\Ix~>iQ7lntc=G]'FlPgzIHU(,d\ba+%5J++v\MmW7FCUZBglqky_IqWD]KIT"C6!,G,2=b8t1D<zPPhc`YQ$RJ,i8JIx Ye5s*ʥQ�[>iB%j:g) [Våݟ6 u>dA'ElIgwu1ãR91(z&7(e[\ݩ!6 i?m[6t5~|MQ&"_Ab$^TK#)_hS9Ja fׂJh[Y{'V# ˗֘b3q^rKBU!I/-%U ֚+a+-9WW܀cYIθ&ZйG0V^ C3&Ėp"Z * †b=>Kl 񜃭prf{4~-uPw)p Q%,O ֱVVZshV7oW ;gzvz#M5b902s/`L!6~ZZ3(giI5Ρ^י0)<"tm8]Z[E_&hRp%!1uSM,Xiđa+a+%5~Eա;Ϳ/ �exo$Hkf~fqH0*TU6S֙meğaTUH<xH U5bPJ1$č!f$ZxB)@ 'y|T YUSxG"o"4aњʶ荊.dĈƶ8 "'^H&1Zc ň["0HE\鐾mɗ?pƔQX!D5i FL0, +""NJc [nKOd&$-Dž˒`:($aAyұ\Za[xBo1.X(V#cp LGˢVI`pؔRV즄<NU׾1Mp[dzÁucHRWb{M,. GRP鎲@ i.23YnlB{ãL\ێnkK0 %Sz )>U9?0,D4v,JXfʄ?׉#f(& _)lc `"V 2sݒWGyNlz%J }q<%Q8nK>I00eA᜔;Z1bd9nIx+`ݠ"N k}#o0~kt&bz}l<aW@gf "wsPR8~Ryt=CIMya+-9~B\]Ng+8Kdn{)kѲ͍q¶)mnV#햄<6nt%;1XOA^b* 16;s ћm$! v- ~U*FZc_K9Go,GO8jK#ż_s/f/H*[pv.-!M+c,q[O‰Be nMVg蝽N{RNl�R8P6*Ql6$LQb)il.є4Ig,<1˖X%6%J1u`(0)t氕{Y3$C5LqH @#huǓ!CR@+ :xLTQ;<ڂ�,iҖ](Jgtc@i `7=Gz@"ZNpژCzDtu-JkB=RYIBmkc &C")!1u _ ]%epgYa[) y|1vv)(Ȥ\Q$|| ?h|ysO 7DeL hC<S&$I^ɀQYu-׭>4XN½Zk~(r(i4R1Wە5E*8('htN#Da咰vH秬GZ) y$#7Q_8ݛʝ5b6;[IM%:0 A qT~~.ss7HFv|E9Y1vBv aNX|r K/�EO"14<Yƹ !Ss0NzwFFW8&켜%>sߪ%K(dw#FɌ Spa-9 D݌n0qx!N/H[sta2 y`S0Ԟ2N'˿nW.B'͔ yye~rȥ$V�h`ߔ${250F.uQVVZs_oV4T턿_e+y& ͺ1fL kMJGPIhZK~ sJKx}DldD mg\x֑xg4#�bHPcWc* VN1sgkާVx4T苰q$n.[`L!ʂ%!2Ǥ2x_w:Ke4L JUeNJdHt;Ÿ∜I�4 E0<K>a�ksopcv^ҐIc\[cĨqY;j\UAeE 9EH sݒ׶U! 7loM/l >VÍ)DiH- `J#JJx$P>^G01Q{RIa%_iArWc=#]QDhQ. xᅂ969f}kxb*͔)~si 66xWhJ3En?ylY Bt2Oi7*ʊ0%!RAoQ66Zsau3wppc>#X7Pm 7PĻGKm@ uH)9w$M7&JD͘ζ2> rT`M2,!:GtYi$<U*<Ll(b'1 Ի8vR!5`)QԽw9J ݍs{5</V )'[ȮQPׂ =V#ؽXVщ)?$%+wm+ha%b({C s DQfwӽ{B<"H)[^'TF$l}031\*`{^Ҥl,@hezm\42lj:Z/11CSFMyIhZ:??e9nJxmEqQEah;`lc˞8 %iBŚxQh)bKwK<!+CV<$9"5҃uעkwV,qc–8Jt`;dʊoKPԱʊH%9pC؈L gok eP>Z(tB:(",၊ͦ ¹oGZL o"l,w& ÌZ%wtpm^QL)9"ԭO#Dp+ QmR(l6ßx?퀴SQnICG6zb''Cx99|5ܘ `_ `q@)̑FKsQN+B#;т5up/_WSJpXosfL.LI ]~y]Z:@< =bCTcIˤ0m>O51S8�wq'ۤe.#MuUaVmy%!E ZB켎I* sJKx-F;UVz2&g5xʲ--0_9tB⒐x('~SvDTADNgQ >eB| f w-Uߪ:9 f- ]E‘5~Cg@p`Y EkpaDA  Z3x|v$?@cQ$$VJQSB-?!#dErJKxŻI-{TWGSbĔ`L JGiIjo= sJKx*F)";TŽbězN{k,n p`GY6msp[a[x/;QFx%HXB(C'[uNr\S, #LYM ryL:F%+a+-9x!Y4AjTZ#kdWOO8{u#M,BZQrK†ʥcSCB6R';MՙDyq>=Z"99C]I0vD%aytkc։#햄<($Q+^Luj7ƻ/ɠ S2Ni(V`)ƋbRV\{ݘ[CmZ3W4q‹r'^: Q&E>~#QmroBfglOHj}b}"%SF! ,0]:c0<*^!%M;.T5DkqG51j p-%C$b�cj )K;]aWYSZx%e.WJoV|KDz>qN#Hjg 鑑!+CV<.7REwۣkxvM5SvЛ"F$I/&kc_]PwjB$#Zgt%.""X™}<*]n3YI1T|~&ª| ؑX*)#QVSs_ߠMVO3VR}7pqb|)%$ZZHIذM\Ya[i yȍ]k%%Ғh4P(j0ǡ/WeAu8F sJKx몟WF?Ԣmvޅ Z'myJ1U ZÔR@AI#̐VKsou8QN" н l{beuu$$vKܧsM #* Bdn=9x;2"ט쒶'>n/1ƭ1SЍ=~)!šwEC$pW:q&+đVJkmu^Z7S\#GeYgkXtP'Tŝ5{ J9Պ07+ }|@T3\EMu/U: a$aW㎍R|M01hȰ q\+ K0nΓ)ʪڛ ԑai9nIx7w'zS苃ڽ?qWFOy#B5:npI>.# _pNX4soR7OwF]X1u`)ț. +TA \Mx?-358nq۶OE%ZGDč%Ttב"\G:!+Ss_%QĢn83;RvQ4\՚c`rtX I`8JIx< &F-:12v\(œLk房$@�y(E7VHXß3xcQּF-؄D^VRoc>I0V:{8F sݒץ?WB-bwOO)pzaBO m,!ב*<҆dH%95 a5)'#m;8kyMQc?R@AoPҽA 54oPm>ח#Ol J5A+U1L mI}l5<qs)}h";ڕom`Yhq1Di؇78a;kOv#戝9I0LY{&+-8 sݒǿ7.&e]8_Y`ju0f@ݐ" dž`w/ e.۠fA'8:$mW[ϝ {UJHǤu6FHCKG?氕Wt8HJ)'maw/*x"x1s|$QT%aoH @<ADN*=}JmkL$\ׅV38ĝ<8a?ΔP:p9%I :*+a+-9*mj(wq{8^{؊+96J .=Qrpl|IZDZh+̑vKsuma%jzW=AE/1r 0 <ڒpQH*!m,I `)7fvSt._yGPGޏcbxu`LlVob-m0m,:":;bG0Cr'K(\tQ:SISO~Bi$r=yjېd7QBڶ1pr  <.}nQM-9: s^<_-^,g@ᆪq2*ˆΡ8NyJ1u`i :'J A#l9nIx+Ե ܉~vQ'خFJ `tlxapЀ}?kğZ4p30#4L3DKH:5)FYDԱ850<qUC@(YOFۏ 5>o_ZI 5NbSCSC}n=9zE#`Y;X6掲q:(YDqOgL#LA%챧:{+#햄<,C9QC.UR۹ǺG`Lc$nerl* ԁtrSO:9JUYpɑvKs_UJXDU㮪E ෝ>pF>%Z J1US:9&66Zs_ƵO ԂDgE Ƿ (Sm$!񤰡kIh:Y:??e9l%<~*;ģfEP]!Qz5cTbsWJWDi) ovl9nIx]7;pW7S6eI:UxetP s I+ U_(;˞ 1VVVZs勒 wu"µ#.+ mjE,%L Wm)@X0qJ<oqu a51DN%Mu?%v.^kQdQ;6}QSA HʊK 9i MGM I|]w,숰/^$rrxu&u.c0)%^H&ecJ.A0<޻=bPXmg#$!eR6DՔ<ob氕뻌#CDG�\Ii]<q%:suq,oҀ֓ V!#dDrՒc]U.(Ɉl<#|xp ^U-5) V>K“2Pagҭ9Ȑ6JkgAorS½k^pdW=am*'ʽOIJ0,,ߖvEJ+'H%9*+BDcG}tªOQ.*T+0f�Da*٠eG?fAm=B2#) ^ʀ0]_ 'ǎǒ`L爲JJX:Y1~(xLۮ ` Ր䂶w5,=uZ=%SF WpPvRp!+Ss CƶIJ'<EQ!8L8"$SFrvI8(^"e9l%<޳6\l-nH‹qq"Q{cp'7\뜖a.Rn_C{VZi$<uђq*~D<GhgώÂ1FW3]U,p)`[0W*q) =1k o;ȋa) WH>PN4ck3GTuoc'JC\Ih&pYa[i y:>wV6|OʁCQTloon~ W'*ċ۷ճ_1 fGVVZs_VŮHq)>:o O-=ۡQGH)!\a-¨[N+VZsBlξߥ)U-*kZ4'Gù$S(ŖhȳjZ!R^*[$JRNJC=O/`t?c{$.RJI ;KV sݒW8?T6GqQh71DfT)ƪsf%:e?/q(ĸ氕ǻ~Չ]wˤ B-bG8 GWrWJHL1”8K`+Avl9l$u3ɦHIX"`DCj11Kg-O@* ٦`#5m0CYMYz=Ì$}m#8]eF0s$^/͒^ݫ#m0L]msEaoև+jVƎűREJ0aJaI5( sJKxnG:.;.,,;tY8xgH<RCjD`r _6y`h IQ{dQ\Q ç7U$MuXHr\p.!PEiXTBcOj<PDsGҢz;30j<I4WK1u*) /\KXaɑvKsGw{dYR.T@_̭mͣ0\;G)37I=%^:??iErݒ!aQ/ƓǶhlʏ(ҽ'!u)cCݎ`L!zSXJ &zs_ހS7,`1mc?1+ c$$nHJC2IXd.unCVVZs((7Qn 0׷ёgY1Q UD~o XN8FsFKx[Gؿčs=L9Q`3j9vfdDXOKzRg,z8> MU2_x/|BE9.lt|O AͱԀSo X$Ւ+Yˁ/R#b2 `85:qEfJ0 ,p<bIh(M sj xL]K}rGR#zl=qy#נ+\2~K~Mz6H=>i2됸!"Mő E儱㐸ɑ"ۣ`L8$Ұ- mɖAC0<ގ ÎLe`gt)٘5D!xCNBˬ3F'D܏ 0 6יk߾(sTcs$tZP(ch(\QC164( mf q{sˈiC"vG_1*BlrK aNmƋa 5*%?氹0(_ce¢ q{:1Vx--?8xxS.ĺ~sؾm-C 5(r sK|ٵY=%SNIJNmK(ˆ!+Ss_P[Eq4ߗ(4=q7b8yNР\s5%o<R iF?&mxX6Fmhm TAfC RIPW~'/~~�3@ xN F0rr?K>g nI0 r?[SV&zdIm lj7&Տ-q3y33J1UĈ4uXB<Ja=Ҋd=!Xދ+o~فiY2cEDeJHL�*WoAw>q{w=يr!Ч9nFZb8<k89%9& #L9- ʨbae9l%<K2y7Q ؙq]ҼM]>[́)즨#}r?K0e.%?;7 LREz0/m;AN Srb9/ 8Z$qw7_R9Z xuC@7$*}A1.Xz,#RdIϡt×*+đVJk/0RBЪ1!(c?fC sq $/JTKI`ye9l%<~kٸa+ʅ-/.ܥ7O6}c~v(u0氕{K3pMEq`K0cqL(gUHxMq Z īIY- qTK!6  CE]9Y,ă$U=#a9(O1%(/1u#Cѯ搕)9nG6%^;Q O)QrSJҠ8' R'MHm I|GKܩ{Rx\ p,g1x#2IBbW,(:u#9deJxA,0 [%D@@z q) 'ޑ1BΉ@ȉ"=z.  ՔPs,jP!L%:tʊђ$U: 氕ۻ(.15g_qo$$ӳo˦-G2ThؕcYM/ڮǶ'_\%GxfR@vcx\2Ip+:0”w_@OZa^z8R6E9 tz1^kV�Aj Ʃsd6~M  氉oFwyYԝ(Xtgf5 _W QG(>65ixv -C�sgδjP}gD(!qQ ^F"΢8kHQcSަ0$8ua氕 ?o_FSaʈ˥{:xvNtf+JBbU/ʰXT㿬0$^Oj\mvDr/7#2~'5щyМ5<*!* y|8"l8hJxM}LÕ7rUN[JkKa-u戶f}`|fQ_vL+oH%9l=w1(ʅxqm0K(iK.fħn ђp.z8T8l0m,ޏcdBs)8*٫bwvPC8wd%KF®`pf1BV$G- y|3B؎l'I {DOZq`[^GQԖy+ĺ6(e%<ǫX~#)&.SP A]& gf8yƔ4UΤ~5)L+$w! o@*iA #xűqH 7MP/ y@+/GM yv7e3]Z4�xTIpW c<J6ÀS[N@xGʃvk(3'Kp<" EGzI[S1w(/3lj$CL8~Li2i�ts[)UMzGS|c ѥ ğ7&r15`( R@]cȆy̷;k3p 7n""AkL~(yn.!ZObb9zG5bf}7JCQL9#k϶mp>3D_/.u:I n*j\v3OYa[i y^ّ-]ˉZtv+jK;m]P-R@\Ž%A+Uҗ66Jk-z 9-P@}d4P}?,̴( ԁܿңJǢe9l%<~^:M'Vx[<k|3U8:2NeDY]N,[7C ߢ7hkruN49ޒ(hg}%DI0nސ*J%5YX1 qK\X`:;egb](ԲĨx\%x\3QVU {A70G- yȸb\֬sz(p&BJ6^YSN�,!‘p(A @|K+)Q$Vk1b[Qnm`LA Zc%Dk8,Z0zЊ䐕)9x͔XO7,Iس)v${-c]N GR6Tu- jx-bȧ^p_#EcX,Eґ0V OQkOHR#G,)~`0im2NE5ljzoCv="lzqu*J1uĈljj cuk3i$<ѵ{<Wa1KV7>Wq) ƫNuj/:ᷯ0G- yņ|/(lubP-Rb#"ֆű!$wȞ(prVD8F sݒ?GS IT˻KpZ_@7~+ԁ<[ i ~85<|4'f AqQ >k*bxqζ)y%agEԱfqZa[i y|cD|&%Q}"` ^8~ӹRr\5@=OoO9l;~{XfJTX=Z"^Y=͢mm`c!)q:c4 sJKx+rj;\Eax3dTXaP #) Th9"RqI##,JN#qRFRJQ-fxC2GQ)a/,HMq& <%aUUw fH%9Z̏0XP^(2;_9:c޵oI#K秬0$.0;/D}_/2> |'a ox甂M%sBKxLUzpAj$T6|"2ȖgzY3}b1%$^]ĔucKXN6a+a+-96tU8)H[zu-dP)`LS}o OA#l9l%<ĎJE\&&h[B%Q Rqe #`8kXT+J.R i)ƿ ?G'{-ʅkM?(wje!4*ui,!1u(LJ+Ib q;)qYlMEcx 8ztZlܕMSB<FSb6Iq氕{QVށEފHaXJ%3dĩ%$^WIJW$%4E[q氕ǿJFQ!eHHÛSU 5NqlWI(|) o-AAV1T#<BmXv\Ȕcaxi&rexu"gBHO=c`jخ hB2WL8ytE2{Q{ Y(U;w$~aCosD`$@tBל*O H%9GÕŢ&W{́}O?x%GlCq[ihO)COÿ^b}a\,+MDgX`mR`~I^{ TN23F x⥢њo"DGG~mfݸX`ZIH Ȑ2aeb[I4Be5%<gUŦO 7ğTq"mDkGRÅ(^2 ,54$N i6j,:Q`1ֽoUDFx*T:ī^$%N:W2v6qJKx㫄`uψSQT>v= Ɂ'#iQշI1u|~\8J1"Ne9l%<F+*à_D3 jAe4NjE'"+PKc4&.Z1u J&Kx?E& 2;Er\Wbr!KĮCkJ:MIBȠؔt%4},rs_ek_/<fR:@[4gWqcꮭ~kb%7;Zٗy~V`[9|el*J>Y+』 ~í{M QynxC*7h8a XaN fH%96\_ 7SvY`ջVlNJ6>ljZ) +$%JgoTAFah Y|kc`?GXArO܈ČdJBJGJ ԟ a\.OKjfm@o=&JtM w-1eB :_ (qpHϢ 8iIxcj@!SԱ�nJq fH59^qv]FBQZX7-hԴ߯3~%wcg[`[) JgK1vAi$<񏫧ؓ.CaI9vFt4WOod`Kxu)bJB=U~~3F xK%~E3'}D^GK8K]qCPدԤ,|!ZrEW Dm6ßң h#�I'Gc];vqn & H.n j(R`wL粸٣;'k1$l4ݯgtkihr86uJ ԁnSi! {(k0ƖvasݒWΗӅ3EHHWg3o:9 8&RDɽpIBduG)+bl<gU3=a.Yq egubΪƔ)JyH ! >mG?G>Xk1XPH`*t *$4LCZ-Y|ճYFM18 ^K)<0yƸC>Dχ\:aM/p q;9qM&`IYk㯼3G<KdF+qMq.b';vF�i$<'{qE0>@j]2&8PX$CIb&ĸH%1`BR6tDߐ vpS9=$$"^vqА{W:C0<:DXORx]p1U WKaSX$÷il<g p n = .QZq qhۧ=*74*-�s@ xN%PtRp5aHB(aK'35<{@%u(S[ N'v5h 0"E6I 7+:@r  ёXClҰG+ 49&0<*]:nr ]ھǩnU3osCd7IJdzmAeΙR&Rkc@I ->- :ڣFy]-Z?qYIHɤKM Q!#HYx'厑E9ٵwE ^M̱«"5oDcnrk+đVJkkkaִ) ug;ULNJxJ(LzF)aa=AzFbGrH</ցF{do@\=�m>q.JU6O<9p-R:%Qђ7y+J9l>-PNTju3Ύ~ɱk9n'}成6I0RS�Җ@ee>[//:*v�//LPimCg5@Fc-؈$GcL5RSԱ:?0G- y>yuv2Z%bnjc:xgQkuL#D9 HoI@Ɵ[QxQ*ڕ&BN N꾏+{I fJ1u(\ D! W-H[x[<KrJol�W<wQ8+%SKQ5:[JB\I1KYa[i y|33aO\Fvxp 6%ቛ"HQ@rM??e8DIxM?f[Rv0P-v%NxUgpm3]7-K^sfϥ`uoi[`h)|yl}R\r^uN>.alC1l W/௯,O_҉??^ iܘe IavFM b`$ 5Ӗ n0:#.8E[8I`0Klƿ *=t8/%$%ji 5[P@7E 0bնrcƱcS`/%DQaD sݔWI:͔۽N[/ {#GbP8vܕī:%Ǹ`ch0<hAͫ9Ur7q1 }qZ3ǽɚ$T,m% :"HTڂF$L.H z1ԔvG@YAi~<\S)SzuR@sfW!. guk0e1n@/ZB`|EQ7p`+ f[i y|}[$>ORڲ2ʈ3(5EYóKrWIOQ!|Ts-x\|Ćƞ('{96䟃='h0U( 6le4 zsȨYc_DqDgȉх!"+GsBIxN˽N/mILRNEVeB^P[ؔ82:ȡ[:??i9l%v)a=;?BJ]?V19o|`~{Gd$SG0@Òpc #GVVZsF D$D8KEnX-qUI8<&H�ajP0 +Ur|ćEi+Vp&yv5<r(h8)|G!ss]3GC߇`L1")^J h1Jp()5u n/MJQ9hdaF5^ O3rxTh'Xid xN R;g-}c%|&UE<ze#$ϩuT'T[a[i y|5jE ʆ[3h%*qmH}^t�S$8(: 氉})+ʵbhw#-.kbw)p0+\.Pز6QsIj5+BT=b񊸱;w^رfͻp7)ʪG%I> 62@\ ~X~ 2NLreC79GfI[c_.XDv5pc5\Q*7p贷գMJQG)<wGHWu;\}?j$GĚIjI //oHBxuI1*x])kcøsm bcH }|6I0ORu pc3D J+CV<ÍEs&JoJXXA"jOqBr6 I '8$aEұ6y sJKx7;KD5ΠGhq;e7d|3}pHʊ Z4iđ&Jk_/-GSDS֕,'G<[u+ C>l\] QpΆc6m⠕%9t`BEQ�}P"wG<:�] ?0t^Á0`<')ۥyRA)`-9Ɓu(N[ȡ(<G3!΀QsOÙc�QIHjbJpJ80e?99Q!xRj<Kyw[bE/ZYIRHQpznb<6^sx QO/%ey76u#1NsC'G_ToDV@ -0C,)|m+V{370P8:cP8(P Iবt~ sJKxى$Vɉ$Q&2߯fr7'5<ʀ$db|~sBKxL[<P$7a 85%Z3͙ P,~J0^pE%!0'ϔR`Y MAlQ#̽~pmq 7ܜ>q8�C(aG-G I,x5$?v.ʁcڊ Hv8Vcyѱ( -D!2$!H%ъ䐕)9dEo({rbC1riՒcG@a 0e!5>BI1e9l<r:>@! oܘ6·ߑx<Lmq]s,,#d Qϻ0G- y|yn:IQR.E }$xlN2% <cRA)#a#%97#6&$C;cWoPؿ#v5!6+y q: 7T$lw6@|BD(45W .Xax& OakRO88&6~Æ%*0`8M|ȳݗ\C5$` a׼M1IxKåP'";]%GX=);%-) xnr3)x( p $lY:cGM y#71Nj^#!+0vG| NDX{8:�CjP ?(qJP-6Qsw#j� (=%toLO<(ƑǻoW}>)Ut[AJYI y|ңL0䑘ՐMV%`RIHxbRЎVE-~Š Xg[i yK6 qKt-qhK \ q4"qb&%SFg$ijN:c0G- y_Bȇ& /zKmb-İso#DYpRb6,Zm#gBAE4z_B%LcBJ0^uoXU'KWdXnRVVZs_dS?EQc -5`uwՅh1ѷ] s|;b|2Z kTm\ E`#%S +FΉc=X`ASFQ{HZ['ğBi$^b.=N!vKp<NmQ$ cQ49NI%A*p~y+)45J!|h>O59> ۷^]" =ڶh㮺_)^oV�2~EY!_ۃ7WkA-SYܒP:)L [|"9nIx2so_qmdxkǑ/L$:0h$Dc:<!<o!+Ssxg6E==.uGΚɱ#L3Y:A#l9nIx,zo7Q5Q7_p²hʳp0m77'04�`[9q[5ZIʽoP/@@AϙcǙ$SFOZBW=qYqVVZsgQq`u4%=8mlHKgR"ĵKkxT:֔/ Hl)|Ub3rDN fc?yʦðI2ܯkTl'jOwO*G6㞦Nb9 OJBv[9o֋Ov~~""/ KA 0R98 c,H,)E; Iaۿ1Ʊ`m)L(=x z_^7GY9\Ix+]P2:tnJE@StDq3^ ?Z;'|%p(-)bilMޫؾ|%V"iQ/Y0XN)$Sg,uk a리0G- yAqV%b=hMX_!O47('P:1eQFJY:V2ٽh} B( nɔ z$s'{vPxURcR[%aut_V#<VBBs%%r'k:xƙndRlDZb ԁPcl ڥˡ0<Qy oEAtWWcC∌6IDA%%*(S|@rݒ<q1>ɋ&q<"Lq]wq!q\5‹0IنKO r~|f<i{czI1?w^%n7>#k"bo(#ւvԁ�Q>6 }0,YeYsңn\"ۋ_}_Q6lD!$X51: xDa8NEM%eRn,pT'.ǧ9v9F-Jʊ) +mRA͓0GMY>}xaߔ}V9gwu$ˑq8#L_$R::H%9YeGZҙp[cZO�K):peChIذMb sJKxq(˅QBc\beN/5cCtI0]+pUTFFC6Z</)~$de{IB <]s}:ne$,8斎e�Bi$ޫn^LԼ8 &i~٭q0)½@` ppF_ 8T9fJi Y߫y_ d$(.(qMj5=H3lj);`Škw) kX&&ZsG/Q(Q<\\\<.j_zG\][IDY~=|\ܚY1GPiPU OJdE:-¾ÿuz0``:0<)Q\IPQA)+a+-9kETjqQ^v 6.d@@S 0\t=lB}s tV0l9l%<'~u(/ߣ˃wݕΉZ锱ī,/_/:ԗ氕ǩ;}'/X*^.Vs8bJ1u(& &<&DL氕Wpw[ wd,]nV낛qI>cM 7n>b%AH* {^~B+>@o%ɰC<q1 u)+JBb wnCV$G- y|UdW%~Lc4;|cXw6TYSI秌0,vzlJa@ =b.ڢqAWJI0.?IAK(gWVVKc;7ShkA+P+j Qk2 % /K @!m,^aűH g& ÔhnFDtco؋4%SFVS)ùe9nIx<LS&Eaolx +mb'_(Z&ީ4 s `2j sY 9+c+vXXxT_!4R vw;VL ƁMbQJaḴorHB4MQT/udyx?}jM Q% 0'e l"?ޑTIRo?P0~3>N+;|5ΛDhy\(pu 3xnhGzN#DY/ QM:氕Ǘ7|eDAx1Mms[;lYB!&E*) du4^(+a+-9c)2MAYiw^rڸE'C~=ޟ3GvIqElQMyۤ7x?mh7{b`CvohDDrLH P&4veg+ ֊ #̑VKc_pMUkyoj:+&kaʆǙ&R7eDK&Q*=BycPV<%wyKeJG_K`.Xǂ}`2sI0nÏ)W"mR1}n=9/j9"#m+s/&F7OvKċۦu6'qDNk4Gw3ع*/B IkZg`H zHiiȱ@l9h x˧dFR_?]"'.Jq?h /<]t#)+ni3uíژa[z\uIappPxNVha<XkxrDAsLQvFJkta氕?9V5Z5);E [/4t XцM뷆G˞nߐr}\r#nomQGlm9_uW{3 ' ) <᤬p-(K!R`hY|586^(Mőo@66.B?\ÍW. 65{RxY ^Sx81-Pru1FئKS O^ <25xwԢD"`p9bghd]1%J08(EF\F%[rԲܲd7ii*? ZPı%!$Ot8q@2*&~8Q#&D1.]$>-.d⹾uvZOGw4[Ӓr( m0Np~0 uL~Ks'&wy_r?!h a:'!s!-iU KKkx[^k_OJhB>p[Gьvm|EZ"]-&N �2T[NX"ݦ,> z+-FG[{ů%5 R`~Tmi@KELJE"3&h |lD5?jQB'* H#P Z'x<#&б@(tO&'l\ XI 7M TR`,#.,a9O Hf{y F^i'=yP@{=R %6Sh ! zxBxn`!LMRT|G!VDsbmDoMP9SZC;6D#EJKkx ]Dȸ-<[�ж>|X=i` ]Ǔı>D \\ӜH%B1*Y ?҉?7"wD)7YuKy8EbEvD#yCZKl!. iCD7蔆zV߄ KKkxTT,D4̉7Gl/Q ?1I4pI[xc&F$ 2iCH >o/cs,l=8-lM ZEjO}YhR&2Γ9vi<?tn0o-]2[monF p,q,|Yq- 4 a/,a/9xzӂ!.NWc$L5TPd~mr�R2A ,a5Ou{/@nNh$pZF&18w`z7xq:8 ec3xza[x� MEkE{"(:՜%Gɬ4,`cõk)ؐQ&H;a h/+az R27}RW;WID6JCқOҔs%oixԧfjrP a@;*eVv)%AҐ4l!M+ qʐ.zs6'Q{rj-zdc7r,tۘ+;k@ZCҋK oicAsya {i y|~g`k\GX4/"D&"iO2\ T%5<' By~ WgΜ.ue0 Rh$ؖIԐtckIJ?5o(m%5<~"Ɗ}acʸ@6:zlmWL- IkQ/6(-O KKkx9  ߈q֘J1 v5Bm/@)0 1C+8�H�`h9㩑'bk&ϹD%�P$+̽oCޜ9>ZMA"V+xE09CjYh0۞dd!i�9OQjƅ @ȕH9sN`Hw٬hĸa"cc"$$[Lϟ'Y#oe4 &%5<9vXnPi"D8vb2n"#`"vEf x]ҀW c]։ԛ8\ǛLM;L#Vl L\�HL~<>kt+8HEDRV�'qm9o I7&>g�4j^X^ZsxjG(2@ؚ8d;7p<=i)4$8WߥaeRza {i y|6NG;s.^DR?{Loil!1SC~'glJ@V/%%5<-I,;qؿq@șG\tH7JbԶR Be91.], IǮAM0XVcNc԰ܫlF/jya {i yG=h~79k J;M3[Z5LK|mRdD>F�T q-a9㸰C@FDg2緤pR{K �orQ732ˀh,l (;h) .vnF'X 8|�!}kQBpeH8KIZ�s ⶸ?.ks #Z:XWђ!c�$"OLNU9-ݽl1C^X^ZsKbf.ˮ&)i]w Pu+ј1s pwZ L-rB+)6 z* "qV ) =9=, #yuSϑ4,`]DlImu29q0^[X|a/,!'1w$5;9XaBwDh /%ȋ} s׿2`W45&Ywf,{QN =27amX4e:4mPѝ-p&K}n=9O*G$gr`,ZhJbW- `Ng#GZ ZH59O"�~Rb\>IX$upX�LڧѦw,[ZYkIx 2$[8xuނrq3\`Kj(6p5%N#xjiK$Kix 'ոF"69[DZv-' - )|hX[@ñc#]TF-`'ZwSX`󈓜ӏXVDG*Qi0} _rIְ7iEk%5<G`~2ҒP.2jI㆟h,Zg=iH6poh{L6HH5@}ÈgDs\NR뵟hg:Vkb%�Ƌȋ07D� ,.Ks dN`K"47�{PJ9@y!3Q' 'lF�^DM yÝ \;w6$� iq,A`60#K&@"#D>tZßx?G486{<�y.oK-JKt^rְ팶Ķ{+k,`51ϚPc3`ue3MI""k)HrQCc3n_�?%4& _l^p w[:Lzй&edr!}nAZCY�4UI),S!ռ�rnlO"PmMg {8EGb)mNt[7`?KE)x}+W'asp7@LHRT LFӘll vIk)xi3K}%MxNE#fL\I$9˅_NJCS@ՐQ_09Z'̋m`!i2OvAZKiQOaCkBya {i y|VC z%69: $V6`�s(8ۡRmߤAXͣ2l�G}:hNgN2$k\2"6 써QmLJsk d?N5Qßlgh/B{b.IPCl -Ó~ȓ⇮kS#'cb{[7" R ^\%D>K[P~pHg5sڤ@y9͌ݮ.j9l@CY"$޿bh s"| *p*ϝf"aT4*.tŹETP!`щH)74>O1=onH'zmD;h ulǃR%fβF'xsYLTN�id;~Iysz9z wD+>uv&؉rH> vIHm )a9u7 /~$JDoTs@&f]MRo:~I?kxޘOVtnsIճĎJ`zS1Y؛ PAya[d,;o~smHht] +cXu!馲D!ml?pn KKkxミ[3]0'2XOB^Oh"S;%`L8sЁiP6P Klʶ{ XA/0Kr~-1l i9 WNk�/"/,~Ks)ohMrNhiL4Kkep}j& [ ?O59N'[gG-Dwdh P%q, y* iilL ε6H둇>Fyw?OH3`Jc݋d� .gq-mh(C4�V6DDz) y ˞Kcr4>:8GLj$cZ+\)H:Gs6nv2A2 G+xe-A4~ LS L\gxݡSI�, GvQ0'0BN  %X^X^Zs]*{U]9;;eǞ46=q q~%l!^J7ecɗ<RZD3o89NtqO`Q$.Q( i#A2Ij@ 1B^D- y~˸#[ 8q;q.FJR^RnW,8vq9]5--a'Q-9!sh⠤c,l-L6<K@ҐtgVOqbw iX;,c<>PphV;1w]UTyqEr 0}SJ x|%kjx⃅Ɠ:d' DE9ȸ)k'h6J Yh�3T[e{g;4<f~/_6sM[#|L$sLI􅋕524&5h[6Ha(5vkx 8/Js5p` [D`&b@2=]RM& w>O51w D߆D߉7޽مl:D/ӛEg0#55D> Ty!R^x?5giMr:E6FI:e4RB$$c=`6x߿`Ab %<g~W6qׂN/)iWiX6yDԎN DX,Uč�`,a98KʼnP.[w%AҐ.sƭ`*P4!Qt:vR eDc׺33mk1Bऱ\u+(& aB(*` 1ͧL'|lp<CU)g[rQwI8mS. n!.N5{ v3xs ΋DV '_teC|Y>'M`A`]Y \D9M Id-4\\h;$j 5%6fӴg`vay-eJt Kg:f2S3bg~wT"mkuID;\KC̪#PjVO `iLE:KIkxC91ā!(b[#ދqIc'%S5 4Ĺ]uIG^<>KȢ]\/`xP3&b1 'xL>8͋ "Q <>1 m۲]Oq6[ ^f-tOá)!/Ss:5 \+0#j/nl U%ѱ/ i#F$'Jϗ /'$QnCkR8@{BDKX ��C1JLq .MkH xx d RG<8ڱJ2~X[.vHanIj^)_4 `8q iPuA:F KElM*wٰ - /h5D-cP7`z<|> Kjr1\\= NaN4X:[Sh28n4m�h^a/,~KsBHWFq;ȱXZzpM:^v%%IiHiH С?%5<-}w\hrL*aĿg?eDR>Ոrt)7<~}цiCYM75iVBMFA| $WbiZKI˂2v!bVjX`'}H)Ÿ2a'~}q.fB,P4NL~qk[і x%5<8d\!Ax{ݼ,fq ~TGӁ{R\4*h.?Gm6K߱E--{KA�hͷitҋ~ms>,p @ T?6" a~�sQw+Z)zO8pQCNuWԓF-rϦ`M=+"vNI8xR}ޞQMC=bDKD?qRT%i^4+l趶|1*cܯYg _oTWf%iixNY!iwba?'H©E kK:)Dz(@ۙƋ͜߅XYc|۹l oVμ7/luKZyocdYhYP8'VZ؂heyi|+wV=Yz�XϤODC<5 tih 1^X^Zs ),6GXaɋMW'{lzKbtOR~[Cvje@t ).Ks 02z=„"d4 !K}Ki@Jf R( KIkxsmv"X;qbÀL5~s3i'�nXLFә g q+0�8i NnF�OShq @%Li0M?{ ƶ8f/,a/9*;sgGb:Q.brW$[Ak0MbHl@c8&5K5 WㆶoG� f#;9="Gj$M1"9 xg ұ(5-:8Ga B0: {G+֔йIɅ'cfGh V.X.Zs @ۍxH;`%|)+Hc"\-cP8 }l<1x7 ;qN nԖ݂qi<RKZP!i>5,ExR{@'';&Xqq&+$*pJCY_#4엊eôJ?Y"<c('o ,Q 8TQ>}Ktѥt�ꕂ2WNX>Zs隣 )hOWGEZv)\~ ! Lvtb#lr<gFEj5%�)|lU9?li``64~k ĦO6H)/,a/9/ܠ\$}z YeN\t}]mR":Iiڈĵ}5ZC-Em"%ejxSr %9%Ă�4_-li0m̘6 R^3M<޿eC~^M[�yw-94ePD$M L6t85>D㏅.]$>q�?XE DSTqٌh 通YT(pֶҐ4m`9lOԾ4md75Ԁ\N΅V$Ab@zh;Ԓ`i*0y^[P+$E*x@{Dw)`>]@EH{( iKbc!MjHz8Xr4^=,6D^<XaƋpXG,9g۫'@ʥpTPdW,N!0 >{fDng9ܭ-QŢdؔ` `z(5qPS\6V K{S}3'"7IDQ ۦYfNS+H1\%5& c}]>{A@V W0 )%Lc3xi $54Ijt<G"v(6~ +?{ķ:Y ƷlI,%5(iX\@L9|C ڸXk`AnWOZk5K4nZHc$ga9WY SA Ms`QĉjkfND!E+QѸ軰oKf %l,./,a/9:}`ŹWqqs[.^_xQ1 {a/8P|Kñ06HR^X^R{\ϨdMqN\Hӻ`?Q؝*%VҤlq_i4<gp%kgY@hqI#7fրd iCqt+ 9�c?'7`qebq Ѩ`Zy@#fi:h3&Td=Erz8p`,a9OۉDD-5=;Z/;h LӂYh$-:[KgL M8\q54@+}@>2_죒E0hβ!gKzxq8'"cϫ(Y{ұtݻ$(z-&iAR8!oy)éO񽦌8NN4}tq h۶q(iYB Pd4ts Y5s|q?װn`J, I7 ,N'b4 **9%5<>%F\(R#qJ iBkW8I)IFI$GH*2drs>dkdq-:ڦDm0-щ":1_/  mP<>ۋk-95&w@ hq T:`YbS6C RC@ _mF^<>7ʋ[֙&a\&&e qLsJNi0M5&iV=|W%)~Ks"v ՑeHkӟyD /rYC㈄mtS"8.@gg^EqSk)/hSb5 ܳK ޷ m ;qM{m;ppqWܒ1=ucMFDyM Y|b;w-SՎmK/P5BiѦ[&3/KɼG?~gq3]mEPTIkE%zUj(#+6ϥ n+&  js oD \0ҝ V{!:I "i@` OO9 tP ^SxQms/kvm&Q�}hhJqYR}  g]@8YlƑ`5'WVohm[J@ (Ґ9'^Rz^$ۘ^_!3遅YLE"bns>T`z5dtr4G m<ދaADFhQW-C  Պn%hۤ!b,8 Mr"%S�n[9H;m�uGj2 TJ1iHztBݦF۴AziL {i y|bH<o12$(eҘi2]Wr,#5mLsap ⎉NRk}h#f!,B%=�e$0jsp44*z{2@y` SάxblM9" L؝bxՑO~ɗ+F!da \yϫ *oT"O)ရuj}4^o izJþU4.%oix4E�h tƔq4]/ВCȺH[*(>\FaCLt0.D 9/WqSrK]EoDNwՠ$$8 a9M.S ,>C`8Av�-O4zrxJNN 1@5mAt )!SsCBO* ckʼnk 3�"0%ĻLATdW-9pտ !%<b lD;@=lǞ4.v`秄+$- )ν)u]L q",a9رw[\'ZԋdsG[@\D@D+D,LjӴ qVe.'cv@#<q~=O (ѧpY uO7VShPm qbUHWZ he N+xD*ňDC<'^x$/cP*SjpMHc4D!hNn:Y^$> V05mH ŵu/{Lk+H;wʜ D؂i$!=1O7'٘1N\Ӟ\CHZqkbۤ4m)֐u 󧼰<qHp9;q6`qD\xw`;W]8sXmӴ"9 - + .i%oix.Fg&8!2^cՊ-f$JAMHYpb% vP+HhYߨĂG;v?bC87y"Tt6 5~W lUs߯� ,kcP31> dMlˏGgIBㄒ)ÙYwV姍ՙ%5<񉽱 :ZNt65GK\ϊV'`6Ұ vEit%5<9scĚ2#Q}^oJhI�3 j{T,Hhs2!":r SlRuiG4_$">Jp e{TԳ7Q4M~QHm g -Kc"ۆFGb0g4JtWVSj)K蕆=kjƢ\S)LxQNX"^l:>ëq8__!]WhG܎#y4b&$!>iH l#9 xYA2gcH ;)Yc!pImŹd "{{f>"74()Ґ.Њ4l�-Q|!/,a/9WN_U  ]٩&c33Q2O͍Ҷ%5<\FQ*- tk"I}UŒ4 4_i2sAZUB759+fqomPq@@B k8Evw 4)40gA7 b/== [װ~s-h xT$73sؙqTAt&NdpG#EJǻ _iff\h\}976 $Qwnfc$ 4s"6hrPh'E(κߘ3=į8%p0Y4SIih@I$c}@z-Y+B-SI,Pv5"LTľtlv P6aLO :YxK_+.AΥ$<qNvW ;ܷB3 k=xxM 7G9AJC+xNsq Գ;sNj:: =JGn$�o ݲX!yd4.29%5~/s G5mdGd<)ײKѧᦝ2qPaR 6\GMe%iixN.щw645'b�oRdW⃠ƇMݜRp*,vA4&IvvgQ;w hY"(? Sbaj0M!NCB_ihH(M %5<ج(-#Fr;!874) 㣦)lAt )NSs1wzbH6#V~�ې7`+. i#RiH(51͎yܨF=Ȳ hg4Mf~I_~ML91vxT b^dt ܮ tXlPlݤ Hۄ95.$ۉR!,lB-,NKsFm*8qB˨@yeZ9}`ni0MԱ"KvlF⩼<>PОϢ9}驪#΄%g1iHa4gCEiP KKkx6n �+59[ŴcH:c)q2l&i!8;x|]0%}_ohw0؜c5xHZܢ#Qt( f4mĈYn[+m4<2 q p%=y/‘.وc~oZPbĊ*`6#6DcoE/R"<O)İaXw<Y<sq*8i �i$[LFp]FSx=ѧq` )w:RࠃR5?-iGȥ@jƛ�g? J".H =fH {M)3.{Ш5MRBy(!鮨@rH=&c< l7q+oI#}d<.]R`xXiV x<g~"׮6>H9Hؾi^Fѷil1̹3m!g؜seCt)a/96?یG<^'Ath ܨi4W$M k(zRqn[ #}vײ!:B"%4~*Wv}|(t\r}q5#G~OER ^#iƉ7 }=(*̞yK1,RhјB/;qFF:Il,M a@Rl㐢ɴ+ T=ip ׮HiEbᓆyX(Gi0ݴu.β󑵆1$k%5<>J_P?qMΊn1ǞkMh4z] 7M8zR𫔓["S/KHsjm;+c?HBBEԐ:A'B! 2?Ƣx>NH(;4ѱjpv@OBTlK *_p!Ivb,'&`l" $k,`9Z|<CCxn: ʆ.!Jisg!d4Bya{=4}̵8rxæ ⵦum'ӴcpV) &uuXљjWAf;- n^Du)KA-9( E/Ӛu) &A.y.n ?͜U 7A7Gv, Hxz.N4^vj"MY$-h QZ4 8գ4ƛE /|},;pҮ'εr~u[ۢk'i9LMHR>X>ZsE,$յTm֒\jcNT�AiC4Ԯح$%5 Bߙs.}(CN:I9V1Y" o'%`4'(7Zޢ'u[@ŋk0K; )gi(8ˈ 5,V!a/,^JkFg 7>.�"`g Jbzi0Ma}?%oix9CgʕtQ6+/QK9V` A)IrST&jX b 0/WKmz>i0Mg\*\+6H)/,!'1/e.(c,wj >V46N͒IIZ$D?3b6`IEkxN}`\XEel[\G[qXrU L*h8Xʭ \#Xg 3gZ x ԏ߉-RN?lS`Hǚ*~2i i#ĉ#aGmf ]<raZP;sPLF"}K +y#'ԭT$l~>҂i,B ?G<JoZv'mtb ́-i.ǁʻx8њ àk'eQ%ikg$hD,&J7hWFA{�mP9`(T O-F|},qKd#W -UD-U-HL8&Fw3%}Ni0MȨgA&\iXPE_6ٗV۫L@#lGXظ#%vL iYؠlQ^X"<K#w;'F $9šU8s[di-!>^@;]1"ىFQKGnN:+v!K 6N Iww2'0Bj Xv%<&^I\Nꄌ ]ȸ0;;@)0I  j<c9et R'ݿ3;ctP}iA|D $I1֝6GKP{9(g(`,LOWr(y=dc\9n94-%%-zK$P>skMC}$sşM_ \hXV$b>'  SKAGvNY #%5<'@'wMrƂ-\P%ށOi Z60T zeC44EJǧw1boD9uH9: 6jZ,AHT`ik:}i49ӡ=O#Yg΁I )D8yIZD`4~T^;WZ,7hj(Y^X^Zs=.#'#ר.?ш ݾ"nO�+S4mrxbJ ,8ӆi^WfZ^<PRXqV|{ȐioYKc;+,q4^Y.l\ <vL4<h ]6"| IgEf:֮~Iʘ4?kl4< 81E9QȦ0~\D0jいt#Rqf ;h)9cau! .9,Z#Q'tgj7iB(}cr5 ĸYP]vh2YAgNr<[Y5X<-^JbCokOO PjHZ-s"o ߷2 v VUm+rc΁'oJhOV2K^gWpo6uAZkgj]~'ܲXƏYe\ƶ%6fEwE&S[JA;`YsxVHhD1gZrzQE,z ?lt]}*&MQ礝tqKt])q8x?:nP츘#O4IgvsS~Ģ[l�1B.]$޻DCM΁;N\ndip"j@D4ޝ൩!ޡdY^ZsjBa;sO`*Ŭ3WF?RB!ƓnrtjPϴ!Oz25<,h;lu;q]_ \3t<:eKMNa&|i`&| Uya {i yߩz+ՌokG>r$hD:G R &MےeaQ>.rk 3Չl!>։~Y'`6D40l*/,a/9OFLRsrr�Ufqa=㎀54hl" dd/{{ipw=Ɯ f{֣qj̬c}Ӱ̥D<mҐtWkI7:KC;�6Dyx/4SqMQねakݖ#ؖKKQDFHNp4 3(@met"%ojxwc-s 9m=h(Ԝhd@I\v4m T =jJj&<޷SP� 8RcIǺ{X~aF8nKö{b Dz) y|N>'9 0<-i^`60e0%6H//,~Ks[c㶶@A!S"#z4p$.@,Fiqˆ!/R^Zs[c(6oB8'A!o =Lj3fu dq6VPU <gn8mC߉}Qrʬ|v=`ftJ1, i#8DzAe�oN5igz&%פ4m`8l0U)]6Hc{Kܹ~&ۂp[t2XO-' I7N!plM/,^JkhKMƉBhrwo~v-*G`,U!&ɈLo*)"2!:Fȉ{ eqx (8T6Qc0P4$f6Dڷ5 .d4H"@Y^Zs#Ɂk�4iGq?v $ L+$lRU/܇b\2ZCNjltH KKkxc򶌐ʿg� ƮvGP'$-^,N+RNL ]rvQs]w3d;qsI#n(K% I2YI R?%oixL gyZXK<Y[_qjMIV0VPNq`{h9|ݷZL8dl?L0ђF)GJC&gGQihAl{V{dK\\ Yr&#ڭDyQl i#Yp<C #%oixGxgYU}@۷(Qo$,j;OrHufm$TiH;&nJiI$Kix</Nc. G-8',(i�Gq66# 8t۾%쟇?g)zX 4.w'*�@�p1Æ KB4*8]=5aZ ,ya[x+_h؅ [ྨ2^4^)4msJ!6mAZ)xa {i y|Vi4g01E9IЩl?DMg]V`&jDK8Œj$c}@z-Y|1ny#K<6!,}4 %0|~W ? r(cC2{#xc]B`ţ;haْXYLD 0c�9 @ 1NXNZc1jyH@MMKv$ULX75XisRC璚6H*/,~KsDZ7MċC^]"(sIadnºJ1FK 4-/,a/9O 7X�ƮG�ay ֒V4u%:26Fs'SY{ިe~s|[!NO\O-\H,x/XJl Ӵ#ĉ.Qo -!Zy:Ix(ڿ(/N[T�f9v"b6(p79C\!w^xE'H9O u) *9,v;d&GMnF2'oit}AOya {i y|JuNa\1`Fֆr;/81d~% �@}bt֑i:,3Δ 0Q'9bA[fLPHϙPÓ^x_FOb+`MYtvx lնqrV{Y(Pn#E9CIkPCih JC&i̙<ޯ_;Q`'N�^!-b`іi<Yli0MĊ_(*}e4&>;a ;)Y|Bq'By7}+z3 8"Jb%^JjH;kxS.bs>Nw\'6ƥ#6<#tSB/N IwAjpAe^L yFxqE4cEe\[R T# jCH%FVLVE3ZqAA3 &HcYH1W"WĠ7e'>gntg>gi`XJs pŎvzQGsp</Q'mxVC> &i!$5` \鲆?>+kva5zƴԀw¢ wql܏Pt'y2WV WV@?^ѝ[˦/ޒL=IdP+oP<<is_Oԓo g hNձ_?Y 56F(h<}<ڥĹ.BDˆVHPC4V6D llL~Ksۡ7Fl@Ѽ)ʛzD1 T�]Ǥ4m &NDSmFM^X^Zs_,ƨorNQ 3Y"JVIi(K xj >β!Oz25<lxZPlH,èk%2KCҺW)NC4,)nn KKkxMV`} cE|AuL]V,ч\i0 1 yV0i(9O[sk'e] hF;<t%g j~do`KCߙs2fAMMFd9H![,!N#qI/,^Jk'q]wl;q.yKv)vHӴ#̉Ba k*wW^X^Zs<U8EG{tt$G?]% Ⱥn̉:M zˆi^gD5gӯ߉ôgD5+LjOةPq{' iHsyjh*+/E y<[ 'N䵏HLqv,q hD͏Qk=ȅ|]1Z}yyq0n HF'hfsNKlXJhqxk"�!ݩEJokx5oт(^7U7 LY8E$:QRA? @•]G<ck0ՕE^xqy%V8YSU[X/BYA]YYs%5t4+ѲNX>Zs:P4 sb3@-8_ŮIbƱ4 0өApiCt)~Ks?<vn~s,k5nzD[#V7}:i-8԰ǭm+q)~Kst(6awD[؜1.aqlh& .!oNt-*x&99߾{@`q"='ȟAs k,q !Yisv11W^X"<!_waXXE>(8x͢Pl$nKg4$8J !OŹ%a/9o*B C8{`{#UA7y;p&[:F<4.05~ٱ6AȔH9ϸ :;"# ±gJ)qb. gQi[T6H{a {i yXsO(jGEeڽ!x M;-x|-&9=Gv!ow^;Q7Q}{D}h`ʄ~%}bI,Hi0}aGF #%5<6=?@9q#u%X%qD%A)0ͫjb2@Ϭ\]$`%!F 0Y a�UMC3X__L)' D+ٶ}E?ي4߉[~9 u>9q[#C�v6EӴ8 sAg ya {i yB�oi GXG!&DKђro.5^NNN,5lƅM6Dc)~Kss:N@(Μ3 *M?̒=y,duf*HKGq{4ȴH$* x7i'GDjqnm: $2"5 lQ.4K q[=ҥL yҡfG׮Ҩ]<HTj4w5M(W{A$鈧D-9^k!a׸kk?\B'νxT4 ,o,xG�'c<C&aYyoԖә% mϣ4Z$C\ 4K=i*ʾ%cixgCj&l'X.dK2Gl<J"2p( E7~ih[ KKix ޻]7]h(2quE+ɏ͜FwT+sR~҂hCJE)x;6&9cN[|,7#jRb0L685u6B%%5<ޞ"]LӀ|" }cx*rHai0Ma΂5ŠCl9g>-!,gl'I0 &%c/s '2)ڛX ]8a >1NT RZc^SU\8]& I7с`W ɍM20IIkx< 'Os2P8"%k#"4T+JCSs"yLG;37}D߇7e*"J6KDK I/CN@A ;ӆhEJg~G~Yqoʀe֣DmK4nx4 0&4eWhjX ]?KlI*pQp鬁/И"+ڥ3N[5A2@Oy` {h )|Eڎ?9g q]ziB6X)L * TsSDiػ&A 2sKkx \abs$}@ ĞE^,‘aI"pIiujd^qBw8{gw�q&R},6)0M1"9zv!e+")^?On4Y;sNjUn4M(\8g$ٔ @mq{` ;̈́? MK0 >Xv^L/Qn:֬% $aZ21}vß(L#f2h̍Dci\({%X FAB'H ;i Y|1XwfQV*$ũy7?XX,˩4mh#ga _mc(3D- y_n {M\o+6σI]wpYG>aE/Q g<KR�+ =>xs(2݈]};l_Xsx +zKh zM g6D#F/RB^[cxcW\XqMLno`,.:CH xcʗ%q~SCҋʿsV4P)�vhtŻak@!Qq%:JJEץ+ j*!]7EJ{=\s֦�YgAlR"'XnY`ZirvR xRY7UU19sk ɳR}:HiHy1T> e2e_;~^/)6ɹV\;u/l`%�-Rcڑ �BiMdXUlyIR<*C*(.EcZRg$.&!T�sVkJCW6z#Ĺ%'sLR-0Ah $4XiҜ:k`Q #$ojxk2!!wD $žX ΜUBӴ j XIEJ ]b;qd(]-£#KW<Y/_MNCh`YMy:)8)k,<iL#W~ ʉhvgx}_j= ^2m55M|&]>X>ZsM*PH>bcwe&Pls1i0MJ"3C"G ъ!g[xcsE PTr6^wF쓢 =,;4$=OleKÊԲA:NB75ed8QȘ_#t ׵7x5D4]' i#Ĺ^FHÂnecQ?;_skrNvF̜Wc sS Mj\1x;"yK]73jܙ4�~ |0,pzZMDT<" iTsШ4(V(5ϡc7:f;S^SC*N"IU05 0GlʻLRDz- Y#cѓXVF2/,֊t_n  }b I罤9;`KÆ;²彤<>)$pqy�vG[XG~6- Nq4_;'褐h�s i$r&=ETr.\P ;<#n`%q5n4m (cNcL[�A#EJb4=Mcs9]@iel(Rt{r\ԧe4 xPkJ`!xOS:\KN'uHՎICҮ%NbkSl)a/9ƉT-*2_a(VΧ`v$: I/ܝ'2̃Da ѸH^ZsN,IB`CY v $dwL޸PZjH+kF\?a+/5ibDJIkxxsna)Ĺp_\\fTas 8I"4$M α(=QmP"lya {) y|:ah\,:<6-d5KC^qID]iO Jmv 8FQ*$Jk 6*\b쿉s�dO$u32dM0֕B}^uUT8~1Ҡ,,%5<'ȅS׍ɉ;#Bpqiվ &]rTT\lB8]m~an_nAv!݊@q7+2 jϕÓnL*Φ~+|1Y #%5<'AYvyU|q⻏{q/~@t5iݬVDlI(�il1e e D- yyĉ똋 zi?PqE4/mb ESCһ]Dෆ q WR^x?%#9^ S8(7HzJW2i7qPF""z43Y \s_k5vls?bË^65~ǭh <Dz( )D[aνn+RÌH$I h%v. laAjEdY^Zs>% ޜ@vž{kKF<:i3qPs☴ƞ%Pr" w=Ź }u _VF'uvFjHILNKr2G&K:AENp*v_YN䣭M/$V6R]7,g!5l�e4`u%oixs1.cH=v8p% U_P;I04$*4!Eicqcza C77ʼnjP�" ؖxAK+4m�<L@4Aa)/9ϒx)~'Q+hw@ThIn<)c`T;9.0<2mQEwtنl74l Hm0,%IiHEb9]!ZYB^<>Px11:dM`w\ 1e ޖ]^T{Bjخ`w#0#EIKkx[v #lkspm[)bIkv$GYIZo/ND~R@!,a9jוX0q#Q\ $A;&MPOtӅ hU-F>cP?Y@Z#{$*b@l;ƒ XYLDs#]_ƒ%oix$]s|GcgYEu? 5pF҈T3 %N8t@r6H)/,~KsM-& #?'w~k鼦z^LF3N5˕,6 KKkxsݺڣbЍn%Ƙ9=iɮΨf,{Dq8'8e,vßHA3c/U1Pf$6ʼn7lq- ',!=1#kwfEbaNfجhoާw' 6<~S  by` S 1꣨~vŹ@f22iv#@u*0\1Њw+}ن]D9M I|67ޣv!RrWG=im:[[<^t3_ rJNXNZcU ͹kZy/|�w~]NQh΂4i_0ǿ&r|(>8D[c#$G#y1ԓqj3qLXNN,S2 0UDm ~u[,qcLDϟb ", $ .{c M)Z>x7>֤=a%thK iΠw,ײ+r(yPch�w_AZj}փ<Q{P(3 k ERo%bc={)TZ@+WiQvsRd^y`JEya>�S(iy o!;Skoq\BN<ב"`Xs^uz w$12ke ^BSw\3#JTg�I#+J8({(�@&(fŊ!֝{ZH!(잡zMOޱr=b|S3QˈپRX݋+|.moTi|dk,|MPwfGXXfxK1SũP?QzʹT׬EY 0<䬘o(?tT#=;5/xG@G$XlpԱB1%4gX7x3Hzܞ{}wW'P@f/w ?u8�cbGk^fX' DB7/ZO\}è27Pt}="zK]`KF ¯2D<ez{7p?zz5xЇl)5rE-$|<?RFbɸ&%ZX#Q2ž� M//y/8 B|M6w:QzIRGCwoX9Z5  P{|?߿GQ^~5uښ; k{Dbo5n߱3G!Oݍڙqth K}z͟ѳjk:c${r X3 ^:̍(S5\GӀIΩxa�s` RP@*oq&Ǐޱq%:Q5V%jtjj`v֚jRXfb{w!amբHe�{O�x zOGXXfxϣybU{�r5P $ gkw*5z=̏y+3tїL~?KǐsscܑthZ_Љg'k5ԅ / #7goy^$YaP?(t3n$bAWյDw`_<ЦdNFT֓Ͻ= hs$),B7[گ `Myϰ^oFQ43lo5!zܞ{<`I)Y{f714k]&ѽw�2zY^#Wϰ'߾FHmҤDȤ.1^5G|!85~Y5wk~kqD ӪfA4ޙkz-ZZ3<~FX);S޿) ~ R#�L ~D=z=bg{kLw_te{eAfW$  ~Z|}TU=~Ox`qpRxo5n~ c?gx|2Rj┤d8Ҋd[ZZeBٯ*ěaߠ%^#3"z <7gx~+ń bT#0$p%c$7dy2~3M-{zXct/C) h{$=2AhU6_Xq~( ?իf} ESw\3#^dJ?|O+єIMLwżAR4b5GjC/5oT=~G+/~yC]1ۑ 2/#Qy.HC);(qyaz$^*�m?~3<dz?q2kSS=dŃ{6B2$F߯T5V2z]|3CkR);S޿>g~lu ˿/{%Z௿#W=AUsf/ac=K<M*vϗ x5 'R>Cs]߯A{De8evfÏ>`V5L'{y!̶^~D{uZ5HsSr fOw oA ( H_?߮6ko%Eh,\`q/Bh1/oIt~9ORsz{1qן?_~$5W[{~0} ^񗟿?˿"?/~_~Ce/ӧ%˵\M/H,] 5߫yYkj?RD+WnS6Dֶ" ERǁYUdbr ԄMMd&$ ChFf2T 9k�lX(TH. h0{5ң gO 鵂 U<]Kth޾mĕU'::|^k#'@tj+gM`ueX?Tg_pMS zvqJ~k$5Cd kƙ:D�"Zy}>"qw.*"0_~_~T/>G^PR,S߻5"#ˎ#[] Q϶OOGq>>8K=ӛ^�dϴ H+i]~Λ#tʬS}$v;n`e|V\-@+aH& 6?4_6* 5]ٛHqQŤ!Eք{&[fg3ڠs1J)>, `9MurIHсF*E'ԂGМ'gّO^sʂ .{e R{1eJN!R?%0Lg XsT~D!|W4G)bӎёݑ1mEE^QRy46-<V}R7'):{| #Ι RSgiff꿬cJ8Th7TDuv@91rlNM`\0 pF`_ȧK L½zP2`Dl7 ՙH/{HNJH^jZ:N `x Iԁ k�: 5t�p/Kx4[,$ eTm C?0 uR )ctd |ϟnR10]+{Z^'՟FXywɇ vDbMt sGFWy_?_Zh'>m+Sܴ8ddѶ5Дc><,SgJ>f:t5& ;mQ%<k>:1;K˶FzUY<<2[n"h2«qs",ZDnۏ{U֚'-y~najԷX71)Uz]l"]iHS7>v˵,$lqai.'+)5GPtA+M 5.$,o $qCE'Iuh-B$ S"Z&9MC=>ץtW 6zA+5k=V>:b'2f4lZ4a:NUCǨ54ת6<g'E!g>Ძ@*ogOEDөEʠ+f7;S4�fUב!gX< c@'z22/_D0!סHǓd\99}֓NL5oD]̗\ Ѣ!B,#y/Gjh%"N O6]>mnT>|q#S:l~SHg kOra6":JOB[Ngo7"˔C _Ϟ Zdv2fֽ<헳1~KtU>cNbP@)(+y4IJ5W)$@�1{hՈ"&쟴1`WG@zs33 Zㅙkt.9z)"Ed^N w ~Т2Ԟ߅3?#"gEb\2]i<2B=LJhLŦEL lHqZ9tGZ.`ͣO]E5kC9!@,n̮DgE*"u$s܉-{.BIU?iyDZkpZ&#Q. D X@:(Ş�/"ϝR/ dLy*jQ92?%"t-_�XV%Q<ͅ!5;ߢN.Wv;]q~[ilKA=`Ge\酞PK1p\ JˮO.2Dx«Wѣ/]r"GWkyf]e %\_L(/&"|x= 'Qs>Q wWA<ٯm>+tݽb9V}L!aF].PlsTmă0V gg�_g<fxM :֋~lI<mG\n׏٭Bײcٓ# 䋾-a ~+kԗIOR;3qݙ^ltU'] gM--*?Yf$u>º63ST򞽺�%=\B1�a4v>aH w*{ɦ#(3q_{]I:fGѣNR5TBZไaʪhw!x[)főr-TяCɏ AP,1(_? GS;eG(Sݎ\f$WQQ#/pDWyPZI Yk ';3-|Hej3Gnm}8j@~}t2TB=T"xbAB}2Rr ϵ nǿ jNDm+} 6q؏߁ڛ D3oשwD?Z�DL,1=)hPˀ6wfƎZ]-u)5tE #U�ϸP\WQ WJ(5+=t;P*Aog ki94 OFG˝I>IugG\üېXp-hZBaYa2KiOG<qZ΄p& .5x-`^kq4gwx@3ǮҪZѪ"o+HduFTSA&(ہI*ɸ9xlDv@\ѿ[ZF:ܔD)?m KW癍dM-?)ɀ\{CgH#f[lhȼJbɦi[9!vV֓dpG\2RHDqli`i˳c5,)./d9;圀i^*wȏ򈁂*HoL7Hʝz%T(@ ~0qSM]n$ʏP8C9!r˽ޘ{*lwJvc'+޼=u$O+49Vhq49b9tIw8 VZ1@R! SÌ!dRa:!N+],}D>-wH^>A2J\yc2&/ϝݶ Pלm%.K:+\LYcFS`p>Nʁ{Y=i͏5+<s43L:Y43|v[w2H(Ir} >\Nďrt{ٓdkʑN H(p3 ff˃>~e Ň4.Eg,fb9T8L`9" l_:({>/谍E=C r-(C2ЏbP><fΈ:sůeyfC3өۗ8g:/iy))* ?J;\>0�Q~/"<6K $eoyC7!D瑮pf+NݕT͹AGk9PsG[ET�ib|m'ߣ�7*A{dK3T[ H Mazq `lV"~V-`5pkaOv< fU"?2}l}(HY0Lca~^M(brTݏ(Gyǡ+Ej#)a4OP|)v_ܑ]dt ӟtA|s,u^cqYM\eȱ ӛC*4q$*amjmȻN<~)ɽSND>R\kH9<NbB8ߪM&pO=yy:D 9XVHV8tZL2wS ˝\Z&OSv-EK`ݗힽ7eJ3:jdzOj/S{L E;Uƙ|5cꚫwGQ7*-n[ǚ7%ZTgU: +FN6nN1,`Fi3+jڪ8m" p6[-ѕ9 { R4%pa jkC+9 kޫL5*eaRQ%t *]6'm�GOø"xW^3Ąbj␳U(CWNGf.nfnX_AμB? @i/ KR¿ǡMeOr4$ љCT!Y&噫A(]W2- (DOLVI 'v첨.j@.(ⅲR"B<L<(BLQOq(Ɛ ̫*LEi''o2l+ c|xN<ƻg(u Ո/̋5uUj@#WTйk,%}M(H"+&W'-jB<ZR琾Fy*U'|KW(*fau }Z)fɷ*3iB94W LpdaUfx ]$ Z+(h]Xzr%`�(O?)r!rH]x%Gyx2Í�|@3OY0_>,$܋D `>TvEe\) 5\vBD0sI5v\DC4Vf·/(| u$CAl wNw1J V>Y4LF,(FN7Һ3!ʾcE3mЮ'v@0]+. xvߜ`d�rBZ$!IaYN٪dJ>=1Eumakl敎. ?`&k7͠\~DpDQ{;Vzv$.?yDu&b鹳!Ž K ]ϰ(яNΉpFgt1޳">pk. ^d0(4c_rg'DUւk#ßSܫcuZ̨~g @9Q?gM2>7j?)P)jP:}")Vv`n =aYT\=ۇ=^[?>D2r)Pdk\.x"hّ;r|or@F ڰquIv)nZkw>{Hژ�1x9�A#Do c'|pBcXnT7!H]_TRYdPNGtur- fԇPy]> pg2~odi~ds86~;vŊOׂpz!J]=0�J2b3peH~^#C<a𵐆e5Gj\ܓ袶F0ǾL[^_= dYaf<QCjG(!<P1*Wda͑Vd( o<Al .<PЅꈻ\V lDAQqB%s Bǫ }\_kXq;\}Q)V>MpeoH>ok$u}y�xo:Rv<hS�z7@9%fkx@b:2"0,@Au4!5=!w$46=6 MgfΓK2,<ƟWOśs#uT NPʼd�ZAqpI<v٨^w4/1 *�YХ =!Pnn9- } յ0&,Ӳ_]zJW tv5P -?YTt U@X'E4WlT鋻�L꘦T�R05}vesxx+tbKmZpuyq^eG&=r(yQ H.~@Æ#pu?S=Y^ar8#t)k>P#Xl"Gx0؃mlAJ&D= LXaWf0NG�6W|H?}~ֻ7y0S#kO8#*ҤdamvW(IȬ?x2&,)-jDe.(1tta}ʢ{5�X9V!ZEUKM0캏tSB.%R,ERL"ÌR0%w4*LAD#߰gaLRlUl*˱Ug d>X(d(dw>'EБ=lϗ:fonxdTݥ,m$?ך";ES9h7 S0<9HrD"rRϳW~14)Eu"UA҂,<![ ē1Gw">y&"9T&-̪ #hJ^ՇPe=K\"%x͆/zWP�Q<*%ueh+^v/g +虘xܖ rBOXNmp(X(ESTޡ=' 15U6{ #?>ETQjL7gW_vxThGO Z\ݡȻ, *9S/7~=<1L_p"3Vcd $ù~\(yѾT�L|eOqAy/ p~v` @HL "EZ< 1"99Za|g@}#{FhEƋ:uuՒEDLYK9IVg<Pw(V28?BNՠ"r,LcaWwj[8>x ~M4]|dsM]XCE#L-b\-U%s'be:Խ}{ƓmWXU,EnJ (avשHU 0-0^wӝr}`TÓ"x aV e`x~W~<V >?`$qD0|@ PUFؑHA3Ar%gо>JU0yRV"pdV"$>ѵN7hm'ә\b@'(g' f۝;e)xv(fv3g\| J'[83[3ۋ֞GR,ZnuVeZ4w?scUJ@2-恛lxǨ,eҰud >4nZv ue}qB41\Noy9e|� M$^FfS9ok*2 nGQήKA"t j<Dr#F#kO|C|CGĉ292^ڙ2Pj,U"I:ϫU".+'>^|4O)); pRA&[T?w9(~M=ڶaHqUFhY{E._5SNf3 zvO>FŇVoJ>v/t;xψ$ 64v;}:C "?H1 a2.F e8^~@)jkt07CG]\0�З(j>,; Qe!U?,L"84iCX4�g絣MHgO,q&+9?4f$¨w7WYU9Y)g!M7Cp55Ct0no$oeLscZ[;4y-k{5威\b;u�PAt{#em.DQ\٘YmufOg_gW:.,,ZuZE &m5ħsDJm:I ٘6/ 2oZ >i B&<AbrZ'xEYH;(vr$ T0P$GD+?F6R NnPf[f&8Jg'C<&W?vtW'^bX-7RKPs tac4&�&i?>u>M};bUʖi|LFV ! >ܹmՀ(1!Nz l2! ]D~W9<\F ؽVkTD[4%SY+@x݌kNԺEu:%}4("2ESJ\G\LX)^7Q�+e~`A9Vh /@�9*o~&ac  &ZQ mKjq` cGuIUvB^a�f™S/q9Ur ZݶT:Em.H&]y]^FӖ܉1 {Bn?L[007J:C"✦A�V8~M2B1SfXpRD fe*\ĺHV.K2Շ l%"ܹRUo&£ӔxRM@DVF�JB9 !e8qQi앸}98EQA$%XiQ~E^W6~FGMS0/4lÅ6kt fBq<:I~2>2 -}?7-.YHt/ E �x~K >+ЙN6-"c9'iBBy't:̟]k^k >Gm(k %' 9&`?TWgЦs3 :QDbhN(ɝRcA>C#^C_VM8K[{3RG oBȒfbLd{Pą=s5lc.\\$Lֲ,ṇJ_(iA9zx/<zb '/rOf K|dS2D8:|bQ�Jdp($[K}:6XK^+0qscȱuhՅs~jW32qc@:~'v(^F3%ϰN[>d�%PlG83XUvRE[qs"G[t jg՟8hV .kUZX\@ ȻST6)QlC^Z 5uJ97=6cw<`fO^N6ХRF=llE;?e1pPh ϨV2'[bih՚�8ڏZ٠<kO =86m~Cj@"W;H<WdmiL?{֑/ɾZxPO\HQֹSʇ~f2!_ˑqSdw|F@&/\p\l ƨn>r_"C%#Mo\_{㖺طa9iΑ2Gf9OyRJŐ;xUXsf53>Uə%Byf#B}BɻAڃCw]'m:3HbBQyhM:χ"c@,[veYEp5&{EɦCd.'d ^sa�Q:> 5)$k{eC) ܼŔ{=Dl>U4!+cq)agVhܧb3{S/>ăO#"�1e+16U_t[Iy}caȩƏԓ!79XFtDī13b#g'*t)u8K[ ntquփ DoI><{~Y*vVM-$y05twjtk*2-s$a� =BTֲ ! sk?0E:z%mʷ4Tي�a6UCĠG j\+e;VzX,E|# ':tW F]kBV\ADu>z?yc)׳>okśhjpЂIb38;(fE�N LlA =6%k,3a UcÖyHG-?Y7g!tzx={<s9Q$mf!DCG"fƈ8I LۥA g8<{_)A/p[7>餪MRIek,0>ma�6/Pġ'0 4%-NҸKl<J"Iᔙ/dz'ba&]SRD)( P3CE-lȧ8QnXZ"ҷLWG!\*N?_6X-P<6.4uN.9$j!g w� : +z w95+"mCtqP VZF<['nOhoy\DlCBRTM4hlۤ%KͷI'A`02fI"891drG?\ fH42 b6RE'@0"3 /? Wa&PQQ̆~p yI/ZRhOߢÙ?h5jg`5W֊g-蠌Boglw~CWv,$aH ZHȵdL` ԵUu"U~r5hShh# 9>ܡMEna]1JliY)rdCT $NS->sq (K-ws!'+|ʽ,M>0GBq'895ACO*.9 j'5nDZ4?ZDO"y*L\P/oO%T`SSw"/fhGdPyes7@Ey#YASqP LT5dzjF=ӉvD57={{Hl^n*ESlP<RG (FEr`=>$G UZ ʏFRk4(J!ޞdWuDUpy|wx2PFKbȎi/kvSW1#оg;~@*GP+d.<a*nۨP|`Sb- PqIMy$jF+4E|X<sIM]eeo%*'+ϑ'E[[%}@|R';i9:T?r2.?B[؋14ksD>0"˶*)>,KЂKhp)(^N9̺Q^}AE_<8yljˎ,%itw![ fDM>B/6IiRJޠ/dճO g^cIX�߲mKf=~ J%iZ*d#Bj)p4_( OV9l8=w q;o'E1OZS`?[$  TT6<.P­B@\}SyPh</=h?{ ه 7KR>~ 5ԲwnR@fi~a>C+ԼzQV=ATIFZ|r9nAC=M.xrkBqѣڔ̎.m<X~3G�/+ HL&sʼnjA'6%? he$jҬgu+MItTWӵLph:*Pz�~ uET#zYgr~g o^fר>{BghZ<Y(/,~q],-KEC(4"-/: TUWfcEᛇM!9c}a}: MEEX `H/= )kRNsDbtYmF iI$lrN}MQ-Hiw="?j,%)y `.Gy`-7pN<,6y̪)X*Q> Y(8+mn4..Xhe9@ aֳ wl pi!EJÒd:E/PL*+mYV1p@Xq}id㱻zPO8k@v} rw~ĉ0YԼB�AA{Ax0N\(s2,8f?3F3j>&oBghԸ �埔2f[Z~6Y#⢉Òt^9i]9߂[Հg/"N�t@õ,ŭٯ=_G#1y>mUӟՔVaBհ.0+ewLymWGBM'|̀0Q�ff1;L<oP 'QbsWׇNXϾZּh%B>J)?L(щӰ51�bGzͧ�>Ly(K-f |="?nv~nq 4yX;^)r2[Y޼Gqb5aLUi =H-es�wl'VVP|'o"HVBW3\b߭(T %U=lп(U@/3,wH( OIT]T.6mK ~*7B٬-@۩dq/c'R@@R:=rhaO3mLv&S3kÿ3iX0|C ݽMO0)@h~ &<21J:46Gw~`-`:yK_ ȋ h=7ziki}Vi tkm6Lz&e3 id ZNzN%%L!n>8-+d,R뢍ZFkamVyQ'�M-1v’b-cEMpG A3,xJ>I#R]#rx>̮W.;ԋsgq6nnRӳ&(&.;/#\^qMFYx#J.rx]NnE;ZOj6zWv IB h_t^ D.zoRݲ uNޓm7>o'a$mQm_W,\e']u?ڢ̘tkޚ[�U2GS 53 Z_\o*KiLP < kF'Y;H{'9&jslDږWWs~f8054<Mr[kW½G 6qj2,DLN '!ZիCxtO5?2J)ҝ=L)?jnʭ~d&sxd=nS0}jp"-VU߇v94꺚�A&sFha@PYl2 #`Mr::U$:#-|5od-L]C �`Ag_'/D)r$teF98USbanұ*)ܷ)3~>�zM~ VO'rAf#KUd \rG˘F!+�\:fl %8 zuX5^v00 XjՔM#w<{R^tZ])񊸟v#n1*/t$U'Y �[Lcb?T¢N-m **Q6.{|HEL%kN6~bA-Q#_|/ l!Ł^}:m(#QJNrՏoz1rs.%("kB*䆥ٛ1} q|fHA{1E@٫KxOKbq(rqjG:Ei^s~&p[О׼htHyrȧZNnvNnJFlEȐyrL7EFׂ@Fy\ğ9Oz1fuvWFKD#U]H JE? б07+WK-}dR>UR^كU.t,8ꯌ(<ɏ,EY^, /Nn7u|: Gg JO_pbӓ2>۬HLpg@TRݗ]jںVg$؈l/:&0Vc)  nઓFsՙ1݀DlKqBZ^V?Y %ٻ{Ӌ~KV]"By:`h5Nh(b&c)ElW+WRC&U2ajnQW]h΋~QY2>"s@3SDZ.>`$_ĶN9fӯE9w: +)MR.#b$ &$D|n, -ҁوlMd5>]m#~=dHFu eeXQzfh1N!10MII){\Й 5/LF{^s�j^ # }RRr!s $#+ZE t^ÜH51w !2LWfF>]2aSᗧl*]g3('Yc<kET> @Uq8H(Sdfy|oHDνNiD,0ɫ"e(_Ч-e(`tR28M'Pg*=, "I?غc1|8E*~,_d f^iz`O*'e@UfDcQQ' մF燩](nW+o<}h/#�5fOX\7a?Tc@4fI&сF}ٻD۴{S韶~z]ۻ&{}_"p ǽ]v}Qmōwi,SH) K4yiwp$%sҥ\v\OBA8a_saWvc]<C(eR 4-h;e_PkyxT?uvϑ Vw^- t3YOYπI>?徽>k5^W=֩EbN 4bRg$t]`7ORL-<Ȫh<KwCF#?/~r< E(q?0 f@i<d7̯37; u6gܡUϢ<ϋkYEȰȒ1%5;`G ghCa$W@WbdՆG֠WDP<dSEnq; P85j*1oҢfz</ʍ ILEqWnsruدSv-8ufTcX ê Uv}x*#JAg NQ>}*E``j1kJ{.fX喬Ui MkKP:t˂Ռ߁6."ԥeH3 <5R-ꃉ=/RRJx%}M|eJ_#e%4MseM vUJf$LF/)JZ-5[q\KCU/QDPw#}Yǘv3]9P` .z p=/˚z fs<:\oo[207@K$?ZB�$z82&Q[ X1AꍽP ڷpآ{dra,kؼ0TO]iboYfMY{DR!r9݅5!Z,j�݂Qt7vSa|l4qɔm( v(]RԿ^9]7/z_W$8 uǑE>L,qy.>94Jk.}û9zEzsdjeX-(5`flB ZVMɺ"IhT63*jMri3HX#-*m) c:̺Iеھe&2YY˗%ƷXX#dhKsgܸ3; .3sim]P&bɮͿWuPS:~K| O7d(ԗo֑ul[zMR0+yߪVЅ7M kXĬobSH_.8Г9+Zur$R?�\FMĈ�Liա*:?V=3aCC2t3>mZMpWB]W.3<a7j[eF!gd%^6{7#/Xd~JMɤTRj'*tL5k_VAOu[O UJ&[fP027qyǍE +k](5~9U(BAi "ݰuW-@$E!%Wӆk1 E״ŞHgo5Bͤ-S#dJf w~i)Yt?�IQQk$6Ֆ3R9FAӯHL[@3MD6h pa n}Xg+u!7`zo4d˩&b|yX6>nThwBdI P9Y-Sv'޸x6ňnxlS[6+߼LL6dc_R-'jPP?GwnegSjS><>r6DŽKZQ pKGU "%!fOuU+MacY #};Daƹԓb]7oUuwqe-۸5% c<bo*w3@mp҆}l%+ ۜkk+(m@brjY1XJ NELʐRb&Fk֡rdlM%p>΂[}:aH�18 MDwxz:ޒ^|Sr/.BW^sj oTM,jЁ>:KEx-a8މMeg0Cas{J�alPj_sD]T0m ׬ee2&S;mt{i4`IY˩0?ZWֲyDYgJACWX#8 jr[-2ܠ+ջf])8OHL6.l%3V :RBflznbF+z8Ul'刘* ֩΃%&3j7NR(1EAX}{8O߶aa{I5'Z$3oYiy1In1:C1QUy)!rb\cAyJTUXY(=DʗFGsQz[9x׈9PK* nG;%b{8Ž.^F^#~ñŰ\31-tDh)v F"]m6"Nf“<\Q<I \J5 zIӄ17ҥ jxCE~Ecl@?X=6;P'7rvڳ rED]_f X ݖxܛIPce}Lvqr,CRB7oE%B~uZ_lZV)Lľ P U]τ=Sfl:mEah\ة(['խ2ΰYۆ3(*d]x \iQ= @W2Vb^B')ڣBY,+[cQWyZPm3ҾCɹV #6o2{xvu#sU&`ނ9Yv_-Hf(?: V򲰱khͦ\ٚDqEM�* 72ĭ݇ݵ_-dJ^5PT;݁g;$}8s) \~h)v9I=BF!bg /�X$ԁ C4jv+FF1ZP 5ӊT{K|8֒UuVA\򆚊ܫzc~޾$r{R* LUYʔޅn#ڔFL˪,hfmg,Y K n']I#6lSL@ӥFѻe@NX{`-k[ۭ6MxPk{Em{SU:"@.m `Z˳8iD%y]JI%vn<�ߏ9겒]~ ;Qe:Q:2˙&�Fbd-p~ە!]~JFu2+:e(E7h]W~=|IhAu۴q+Z'UaQ;MMGps8X1˶mNu$�[.jz-pWV4ƪZwzw ]`\L[^;&Tv0]'Afe'5!~4Jl&Y�bV7UpLTCD" #B(n5CikP/+gQCrkFƓat.<lo뼅sF5F?(R&߳CINcWj H2+ɣHfP?]Fn-Z}7#jˮ|4XI"A6QD,pfƕ*T6ɂ]Rzko̺!"Bem=B`HUi-.!&'18 uKH^=ZZs ݆$ {߯<pDDkU# &tL4-R ޜ!ȩzA ԲMU<<K"EUŰbFTLJ=&`dDSrd%'&'[̭U.Jy0+p=@Qr_i#ƧgM$͛e%Q3UOI (X(W!HU6�Mf6�;wA8!:&f1_ V�f7-�lt9_ƭ딆kZnMc6kePD?Y0ע�r Լ* sk] QYjG18L%rKRZ$a#ÜslFuEHNSiW#Ì=9XGIeBUBjY.hA*!Hׅu]T~ޜN("b,jT   `Y3GY])&"a)UF|[K$ը bFsc iA"F7qt Yo\(hǴU̷8<ME>.rȌ5쏖$(zyW!_8 HҪ,=dh/iGBI4"+GGvCl.$Q"X\OzQ*:Mx3mS[Օ74M]˔-*,j>`+C)*8`J#RMr,HVM߻3+ViTz"bNB)o\؃AтP78AqjElo\Rz_Xob#fvW'05V0)Cld%$<8{Z*Dp{Ej Mu[+3.m[w<F`O5eVdIˣIe|XG>'bJ%vo\]UDEם=BuddU\8Q6¿\It\ bQ|N E6Ct55`(B Ύ c_Mɨו.K0=k Ow*գ[i/|Z83/Mqgf(%RxJZAGlCK\ =J 2 ~_$F}ia9'1Fm>3hъ4U٦c M#ŧ GWڎ߯nA k`ul8%T:M-<W_8ҲnaGQW ?`p.h/WDNPJ-yaEA&� >2FȻZش5_$R2v~tቓ!^ ȝ>؎;QKH4@Z`%Vd^bD "@(ڕ޴�+'FZ^{+i秼'SU *B-.7\ xymٟZO*.]_-MaTݻ2C|l Ѿ0ǔ$NjOzIeN]c4h]0J#G!Xj,[ח}Iϼ|s(E(ξR��٠͑y1I Cl-?𡾾l`'6CFo8:_A ʩ UGPDS7L6.2"{XH~Q*VwKOIvQ5&oa#ZɺR)":ZtauF(ʵ;t�5_8YҬ.Fa2!>ӕZɷnNW2?,?>Po2}q=FPH숩Lq3`FyUM]IA=00j$Ne^.kMt+H2ԘAsʧ1Ǒ65d y֘PЁ/ FzQd565vi5AV&SƔ.-%P2**ܥAVIq"'T9@3D-a5J3Ú!ywhO$%&E'xߝO,z94ss$t1Wx0JhjY)ᨒ_Ủm%<�N5IfV0FfJECWfr\<T|u|"�tnkAdϊ%F(uoY>䫯k',r^ϩjb _Pŵ-i4ih )LzOΪՌz#F;O ٴ*)E[=߇4yX*Y%/̉q]iyʠ4D4RPT!dy޵ߊшL.ms5?BrO' '-پӒmT|s�1|quD&N44U¨<ݴyrʕa`O5G)>T爢ѩtF2j$,B\v2d%j5TdYEfNPd{XIZb-eV:RjUlMqwG8]izÞlREoMY5ю *D@&Qw[rRBhÔu]xjǁn4X 73Cm)M{'EgjqЖi$� LaoFԝ~vuf۠a ###HE2<IE`eʃ($ӊwݧ Ub[p+|m^iq\Y۟䡏7xb+vB'4j1útp=XgSmZ: #r7syX?7i,kRR٫zD5t D(Wf$Fё̨yX!ZDIנ| ΋Uڷ6thړR+2XupWS]]CU:p[\dXs\*}@@�(H+VȪ[2YI 4b> :#<BKFhQ<ḂqE;j%_ZAh;AQdm(r+K|P{3νoDX-a5G<Y%e-T0%` dk״CFBAa\@Npv5&4bܝ˾C}Y!NtFks%|e hm'6w%ӻaixǪ` I #BP(uؗBGrHwgV 7/d?R&jџlAƶԇ; \d[HK{o}I I ig-!K}+NJ& Uz3<;~iKij N-5b.�<GߓsUɻ]Bfx!75U!ںٛMWDA=-"5RWE�7I kI$}<zj35rT\/M%fsDŽHcA:dcm! F A�P. '5V+A"$w|MVrZFKuDlc 匲*$5ۿMxc5 5ܩ)|mhž~o_LI&,et<'{)UH^J@t|jE]hb:IB=+(0Tf1ڂ#Q1\}1oCEɑ{x?܆tam;#_`CDFTn+$YdBOе&>Ub1Bv`b!Qa=&w; Ѽ(jSf*"@)6zNи6dMۤ0Dc>U־s2+tnKq}IlW 6~ y-GK1"mp9#nzD~, G8c$U*VPBV%O4~dC56Dż:eQnt4ZOeZ+I2n_6/B6xʜ c~2 ɭ|w:Sq臆+$_66YK\AoՆ�L/@O,:JLI4Ⱦ\mqMYv(")ϳza~~bڽ#}za &86@6Jv>5� EA{``nyLi'jwKd LF;pZ`RUs[1j?!k D%`qWB!ʼ:@G)N}##)qQdq+bdˑAO1]$x$qd./H?8V3M4[fV.F(d̕yƗ֧VH6dqRůB2$"w2nC0H`QFJPgՏG@_*͖8L`Fݐ*̼A<Ď\|(HWd-EI)lzIt=\l&€ UdiRbYԝÏYw*u1 #KI@\Y κh`<ԴFL/8z%VLai%Iޤ�q{C(zLU}JkgR}&H'&AJMII=fGnȺrLt{@g2/-p߲H ~ -dD)AY xaZpM)SzOW5,HQhS)(L<&z۷t/ѩ$ u=d֙#}n~3aLv,6(Ue~MG` 3XQb&A6aکe pUT UH:+RuK]JVͱ[bbAKO1%.@N#Ts d*k(q|YeDMp| IsR<Rd)ng2Y&eXJ(,VwhPȚ$si22 Rs|j8LLdoͨf#P!jA,7&Jc!"^[j/}>2{lR1ݼ|%>dZ*hr2Gu)%5偮JŮM6-!pⅽzE$l vQwxݡ7Oj n6ȲAl. .sg $HL;(L`erj OD>RgrT^AULCQlkea2VϿI~OQ)aZ[Iqz*^֝ctݑ,6XIrh|)1 ] Ņ@Zdؔ zITr+񫌰4s(z6Qyi ~yWN5tZ_J1nfGK%|ey,HyNPs F_s>d)P,%,n$RҒg.lXPru f1W0drq| eT,\JDIe+ 6b2wqx~Jکt�|`N EY(p,H6vIMY(nIܓuW'Q�X2B_'MH5FlcFaPV35FG>LEUezfDU0�W$G&sxKd #Wɾ GKZt2EF"c$Uz ]8}9gbp.p42-v/VSf.E|sj֯6'gIJji[AAebG 9$ZdtZ޽S3 &Ie.<M<9.l8jH$b3x2X@$\uΈ_b*d;/o)7];ZБ.&Cy)dx5L~. DUKw'ǒ"M9]4 ZhY &MC2qӝ_ֳ8"s֯|zydZJJ7]e) $#e-ЁMS^/:CpL=YX\.GoQTs MVXYqjTz,Z.|_\$;�JQp~BS%YnʒZVBl6'7Gs8qLjA፹>D]Kw.]T<%qL3ha�x6<qǭlfd]f` IҌl+b*`;ԝ \3pqV?{Dr*s[:Bz ě'|>a}iibwƸ ϽbogTy4aԥHX ۫|JSF "PU:y&Pc"pq;E7PLdlxvmVw ^Q7*ޒxG4ܲZ6[A]ZK OMy<]ؗ 7xV9 KM.Jhi^opHn)ֲM,57ФqϗclW ,(,͍$\QFgw*GeNkDPg-66{SQH1fK۱4 *Kgf WK4㚸�Qd!v6Έ(]p~?,3o{+(EûW !iHnu!5i^,:EB|4WU`"5^@!K{X#t3],4�FRt”r¬®|+WJ͜JGCHR;+p2Gf#X#SˎSdn jDy}֭y�H-BQC Yƕ4~/!op9L\v\rpM}EYwڂ<5*(Ѵg&֜ڊyS [3cQ )!dX;,\V3KAsfh,ǽbeH%�q&;P2Ov^M Ghw~vܗNO6*ol;`5B[(,XV4> 3jZԺdPw-ܤi +ک wE3)g_9GH5Zvtފz֓n2,J,C#ޮ[�TY4K +g"]\8< ,(>7+~5p"Xeę7zp݊lrY/It�( ԝeYWpbuU,(U9%d0 >9\flmV |Ny*XnbH]mM- pLsԀIzl!eϔ.Yan[fS"##kn^/~8<l)-*2>ƒ&|O&W YM? lqdx vg@gҟ`J XNI ȣ,VHe_IS}?x,m0d\ 3ӪL]Ds}S')tS%]ق:$L]5ipO_]|;̏ByY T@'Q"�EP sw²PEZz <(xXkѥaFBvHӯ0%ҥ"dJ�%~.QiRI;(E~ǍC#cx^:QZSoQnBxXT +ƄC^!@Ћ]IY ;5Y:ichqD\} #pDV]1a1,}R4sydeI'K˴3ھKyVtu(N9*Y Ш#M Hdm}lP R_<(�Fݬ]K AAM] 8H?2j<`ZѦ܂֦y/p04:/hX'/ܬǢ9*Md[ҐbmY˒/.GJrۀR >ߚ XX6r196,)ڞzȫdC34Fτ1ߤJy),ޤSWiNWvZJ)=j;,"vŵ}9`LK5ã۷gzx-|uڱlde g4oz=v[{)]׉U 1XGrQBG|pDB) 'ߕYZfFb`=Z͓˽-yWN7Tu!JǛ粮0N&5r 3EQ4L3 J wc)Y!@sg6ٍ< `$d)R:#<OO6 Z拓mFV-1|>٭|Pnl?Ovy$3f61�> ?kЌvΧ#`!W[;HPd<wkZ %D*j=*Xa3ָ[WJC^mh`Ljn�#Qsy[~/A[SsM)ժ37r1C}D bwj|U+J2Y3'B1tsc?1 B{!Wn�B[֕Ao'W3dܪ=#aنCTRcT̅?1Q]Ęffͫm/mYgPQ?CñQLA]ܼrM2%NؓCr୛9)ٷOV-&:Y/rp9d:ƽ"TH͜qz4sցny(Sv2e;e,c][@_]XJƭJb ! bHԲFt>eν{gjGTIzXMY8SyݚgMң3]m}s8OC,rYζw2>ͯW'U1nj�]jGҧg$e(" ʍ\Lbʩo-ʚ'UNb{gjl�oԏT)"KR)\_eQž] >XW%3 ynͫ2f[:2kG:̢q%t>rxSX-OI3�C vKJwرۤESVjW("ΥpԦ:{LjPY̘-IХ.ZWqjؾ)ݹmd)M+CWki*$dL9GO-u"݉'|_SY.E=+s>NP O =*UKO0آ$_o񙲯keb@^J3Ns|Pm%πNP) ߆(?nAyqS.n"(�I'^!׻c?oLы?-}34]H-z;JCՎ[?XZXVS*yh.23J<G{:r` gW錈h, NY5eՏ&:}dM#)F rljk0 1% SK,m,{Ŗ؄Be˱ǃB-'S!>D lfؾDH;ߌ GL=x0fK VL %?>{aɑ1|x]/#{htdau8G!u`˜-yGiEtK54iRB+byKNU|`k/9&A(o;Ȝ6IM! eoUȞWӲv�aJR0Rj%3%+iI+L{ٰ@2Lycs}-c7eۣpq>�Z\>G$VL;N�̱ⲫqzq?3qG^OC4~-[>ımuŐY82DgWl/X,i<^N!d*KM8!Gg,M- TLtM`5m!,YXo<@ �fNJ |7é{¸od1\Zz$ߺYPo$gU&$;c2IMd#[mgR/ W+B=iq1y]Q>DJNU1m=d βi'>q v̆@;=Q`fCF%3r=dlhEAPZԪakV �T<fz0i07L`j>!18ʵh1rE[ZXkhEܰ٣,c0|g"$"khv"qaFBaJ!&@{k9?lu!}<X#D^7H$-&)blmiR <3iw!NT>ؖA= %ũf} kp^/QSHA:>~ЩY;e** =iy!@z~2$- VF? rA֍8w G$\3򲘑A_'-:;)obEɭǔNS-áZWL2?9o1kE]\8)ko)XYɦ f );n˺6zeJrRW<9-.!I }©GBCdz)M0ە.4iXv3uыcX5A8KL>E9P}[ByuelRLJy߾ 6$Ki/C`SbR^5R_?sQ"bTͱ;ߜH;/C]boWR|JZ%-ҘbQ$y0S+2a!s o=_^dK& 3pO|=K{MS&t33$tt )pp0[Aғ$igf:1o/%_K2ɡ�*7+ֲq Y|4M_i^<$6Z@0VѺ/XZq|AEuRN<Qt+dg)em#>-zhvG[*j|&;&+%:9SI |C~1 V xY411xZɌUuS&9(HA̎9QvsI|Ԣ9Dg~A</@_Fi|Ykʦ� *dU °B TaQFgȓh^^@Вwow%ܐfƾ 2 T7CohÉt(mڲ9qC Q[ _@|Q=<=T߮$y&'27e ϗא:�<FcNȠ)<CiJߡ)ͰkWux[,{ E MX-۷F u3︬j]}ߕٔJL=ԩ�8XmޱŮ;fDlt;iDX(510 NW){&1Ϧk]ywRh. @Q9k {U+EA(4>pjr$,0;.C=HY1% 2ܗZ Zv`@ *3{c$( LD" иLGQalpӲ=ޱkhHh% $<J6Aީ7|f3*Xewop1NUͩpdZbϭREb.)8*^Q7WihAb9>)/t2CW xz$"E0 >PG K�TeU 82Oe)WŤR5, X(Pxռ;eH[Lec HzQΑنA6- z6a*\ R0@s`+XmFnI'{ Q"NeezVU{V#q5s27h0fEZJgU %ppLTK J(RV֎_.P9#ʬo,#RCmۊDtoݚAw �XxǑB8y89n=Lybbol= ؚ}hpݸs`k,߿ã>~YB$ﱜ@e1qHNenNBK˗,(=:4f4$Cɸd Tp[Bp Ljk+/&ԧj_fȿwXkv=C1m>z"<e|�\ɝhS5xyZ-,+/xE5L뿻QA/ c$*=WE0LymaO'{f<<=4$?.gdN&g[,k"=Uըg :3dUt12ʓ%.OuW 8m9iw]~M?I"U4g ԵWXΜM�oh CpݠIOxչW sd .d^U2(h40I+Q��knH, R]Д\pZ=>Cnh!F.2h E^xp=Tax J,9xu3EA]ReYUkllQ&v>c_N:n佂Ha1Iͱ}'#$9XN-ɷU\wMa9AmY$EsYDlH =*,bY?qďSڐIA~Ef� 5(0.55S S 8k޽ oGP]JƯ,4{B}#]& ~PAUm-lB#"']mo7,'M]M16:GO(\zmn(GakY?՚^Nl_GS-鎾@:#,t!( p|lIq,Su%q-)Y2y"foY"7Ke)ܬAsUZ ksESR uL{G*>s+Ia)qGU`4P?JX'לK6B�?70*WNflNuh9U M]?5kT x2j"!|D⅚mQԾ+Z+ڦ Zw`=>5�. iCDΦf $' ԏ;\u`+9U 4cq}vH2mIdC+ MUoӖB.tEW:cքM.(T�`Lt_I[pGOpE 疆 ȋ?'~|H`'/\u ?xQo݁,YtM IMLv)%Fj Қw2-pVsY-_>ӆtlHY*ɧxG Y/{a!K#K_ H{/nv%JeP|FN@}B-w}\dZO O2%:3ԙM$vUw%44TnKRQ~g1%+3X98 Ļ,6Ϗ-[F$6j�nŌHZ9~ըnۯ  ׬>Ɏ.h]a|D3XHw j<s F ]H�gi!%)M1"yߔ#>Ihvcp{Ҍ.,OR9 �8$ 勇hx1wM_A NĔ{{G(ZZ *w3fo GHRL/W\?:ܑ=EvMHϚu/k' W r{R5SPW5e}L,5@p˥[Y@Z ~3}1?㮬dȄl#X+:=0XYF@0s8W6On0< BC#=tp O 8!*~_Lsp;Xq)!eҕqw AM<k8Yke `eC̗m94\HUΧf rڔ [ I׮הe4,B;t61[AV_E XpǀJ LJ$oC!7If?ɚ.lJ8Mm;w'V wE�D տaDUZ)-B'C1L *Esx\d|QbN00O{W$8s3?Pb\[Ǫ5ta|-xS5&oSoɝx_U(gy8q5C9[0B+Qүsik'�ʻ J~ iGWi]L6h??�^Et!ҦL"#A$1ս.sYnItޤ-!S+sAP vݓ]l}/lm `>Y/.Ԡۀ;Ƙ ODH֧=:lSN)=B l5}}3NDC> Aҩ.=n%qMꚝø_H6Fٿ Bnh�'i4)uō&8?˳e4E>2ޏYy 5f R*,pc ^lR%XL\mmBˢL!LܠFK 0)vAyPBP­4|ٸ j @!% y dKbbuʽFRũ/93+IxC*z.t,,aqFikYŅ1b{ci#3T @k`:>rధ&4$s PAd`sTgnɻdiْ.ZЯPj"ѱ!ymeR|? |d%]W]U"W]>tKCK"d+5, Zh5-5WARXBb22g^\k}}Y#E=p#F,`B9  /BcىwXRr,&hk(pr?s0HN1yxp(hudHm~yf7O(?cű̚5*bRMnXP B)7Ur?lFXܑGS<7Yq8Cwr$,߅YZϘ0`!eqנIbnj!4Â݉xRBilϒ>MsY'Pgkb�cmI[o*2Ӌ:'=h7kkb~>p㗅d/]8"U j̛H 3 Uuڈr |"ʢlB!b|pFrƯ'RSWZ76U[1RڜGXQԪtրyd)w}l~Rv%z}ru:nY3, ƈD:r>Up:rЛnV-oQGn6p{!"/ )1XLcL>O u% WO?ׁ( e: sŗHoW<#ANDK Gm- 4SV#.]T% ۭ KaYKdoH+g[Dصs=A+SAYv:L(:<r%01Kɡ)ŏһ,qpD7pbRPѼ S-Qd8 `]QwN` 7o e&}xѦ 8WBu*f\ :$M.z7Q.ј m Vs[1֨%R~?qkL|j^@Er ,˙71<j%U8X $lBwf 7tfB+@/M <|ꊝk"D-d|0vXaƢwmzd.Ue [d"EѨk i(OR%w$=]=A1][C(qi$H<~s3ȉ/k"8-fvIX }ܻ 7Bn6+cT-93Dۏ$Q7 oI96aɖX ><]3v$-^# %F ,YBr`lށiș%1A1)YQFMd|%ɤr3VYK[0b16x1TRfATov.8s*m>-ݫ8):g ݬH[n7V@OҨa?iB܎2-s6gtA\ sPm1Pe]>/]ZU:[L!yAt]g(뙣JkEN�wD:P*[a[�w GtŘc0os*em#Ք?$SK~^#qDѧHȺynp- )0dɐV/'<l#,`NqhH U`R8WELq$wQO1$}VSOhH9}=^lʬ=b&N~9Ʊ%䙧 >(||$ZP=!YM'&ZYBe9koQ@Zv;Y]{'FQ]|T\{WnbbLٗHc>L`O=sX!:Yf{v J5h;l 'Im>Ϟ 3uPd'b Q^l?ՍCn6w fhr+C{ed^/bb mL`ɮWhcS fa�2u}35o k'jUbB{S-|6f ٝUEYwSp/ΑE5 b=uʃQ#TV |\r F[F`߽6w $nLbl}ܙNꑖ5 ?jmCfݽjK/`jEQC@y*q!т -*E%RPvxEGT`+ l_k~ST\+b cF`X|6ԺK77"Aȋ' Yt?8Jqr$ ']q6}8ՖCdUWInŸv+ ,C٠"|bYO=̐f{D gH*-SY[Wޑ@Blnb911Vҟ`.Z"(WJ#}2=hU|xu,*M$MPdZl[Jȶdb,G4qHͣ�Q˄p.W5Ir{;T4o}y̼]ÍprX#oţ%D-=W&0bqctg"ynrc$wQ[.Idm &!wT9HP6'ʖS)[KE #jʔQKfqZUp0:Z$Ae]4C( ib"rlc?OZ;L9tWXDBowZ58,d[߫"khR!{~\ &hf0Q1o$"tq7 .wplS٘{^n$N*Eĥ͔yh~[Yp׮PolB/)t~jC{d=R#i� oa|_9ߺ? z#2)k6(t7 \b=j8B(�PCxaP!)\NS ğD$oI?$s[u?叭*Ts7ol:ܪ[NexFte%%ṔJZar9A=L#wiѰ•(5�o2P:q/BJ@uJE`[$tY{<.l),rLIP#꫎v'j[[<\Wt 4YuW AEv豪Գ.5qp۷hJ)UC ;mDY;w2^dTC*t-V'K Pn%ݻ= \LU|3H ] NL;b\1߹v-Ps)Z:@xjo8  TJ{Ao:4ػvMv`VF`v>nOԜ34e?T! ,Ao Nsvk;m˲utyzʒ}k>nёUH%JxFDtBr`J'2# rYQZVq{J>(]fye!~tw i쭉e2Ź?,~y#˽M?pbE|񅾏? ii >CuS 3,#ܩF!ؚ~KH(UzARf1#+,#MY Q*#IC棬S"P.oP82o|lqN_x@(fAȍ=8J_uٮ h gOkg$?}qnlEME; $[SoZKjL҂,0eÜ;;k~a9,}F(vB5,؞l ,/oA[ 0q9>}ZLP*=k^Ge;tX`cZޭlu$} _ I'Иw %Zn}e#l5Baჷ;LUnKRr)$wDPsu8<`_R+:O1-Ny>)U):mfpI f><yAUsVV}ĵ!.%~�>ދI8GOӧ"M]U_W@71 \cKV]E<K,vK~_5`u@cI9RYn>,ߨF�fqCW# ϯ$BvٓtY΂z6}䷧ ѡO00Tc>^K:]ʺ.̺nuf=HdN74tY-;MZ8L!F2S+~fJEl$p1n"%IUOG9rl 9?l(K$QlW-{Kj{ooVs1yY"VL5B:-Л'Nap֦ )㗒c6Q#-̼c'ej?Q*GTo2z2k-FvZ|[E&=0D)a@cp*mV*WwND&c>d"4Dyx[6� Lq5"2"7Y5 H(|lYͬ; ZX#YDPZf:J=*m_Vpt3r5Uo+�x2?,&4 qprIz1H2h9*$[q l5roUNXRg3BG-G`76xTWOs)ubt1=[d:}G0PjD *bٳ h8MF|M)9B` 5 zLI)aktkuCt$nN 4A\"ّ|A>#B.4r K?TM5%骡DTɏTwoeQ~5eٙ.;2JׅKS:nF/*|SL:.V>$eJ,zZU=5UIUSL-wʊpT^B e H.}Zqԁ[3Uȁ11ܲUde(n;,fNig3N$:8w6ӖrTR j '9y,<~kt4Qc.8ޚySZ]Ւ5x n5^{8<JvOzw{8tҍ%,L 67I[?YDk$%eٲ6[9UɤD)E^BYUQ؃xaۘJy㥷BM^⍢v9;Pjrnm¿u}dg/4ocPZ#>eEYtYM|xlP@ٝ] J"5|_ Yi2SH*-Owf\eej]r*�c7jۓRL.OTY~ımݬ"NAt !AT<LFڸmHbvf [PmҒ4 5M_oHt3�6W5R-Ҷz]S55Zz톊ƒ'#Pp=NQ^oh%)ȝ"hhΟ/YEQŷ*~$ZNw)u;Y]sQS&A5&ՀbL0ec20#Yȓ! F�~#fʝqL̴FpS7uU Tٝ1q&{H?*n}qQH`30%) iL{Vp-B4mqB8:cC`݄Ug݈gl?rh�Pf-O$~7Egy۴z%IǺa&˛K|M:%͠zءb 0Aں| Ɲ$lՓ玽ȳ72WH2d/tRr)5̲ǿݏuqn+B!(y&tՂ1 :i\hSјj&{mk_"H~ۡ,DeK xt՚2zL$YZă]Q6@l(H�NZ-ɂ;g2 ",S9VoNQz0D#e9Wr tbQY?vJocvY_?25%`5oKm|yWmE9ަ"۱5VYܔ-K8IuUҘ֓*EW+<MC EJ9.W fMCUT JeJ0 𤋮xͬT#Vդl2 dqB%ߘ:t`ڀ+ ]yF4ŠLmB3t(+8,}/̡J} P!:&FNI[<H] 尐M6ߓ9FuV5|N(/e|O }@N w=j[Oey4E<$xn$ \{7ƙ#LMny 73ÍC 7c!cfh]'fZ˦OS`9BEfSU)5}.1&'ihgW+螑3:y$>鲘'n{Iù{ 7p/Y2NLP Vlzw \dNJ)0A[mj)l O51۰LT9<5Ii: >Dm:'2`y@dpi)8 N9dz[mXQ%ܟNft!U+NşeB ^M.f+Z^s$D<xb VKpa=3x^A¨GYQԽʑBק(8Vs"hg0V<Ӓ1cea7?Xs:wQ]](KSG=[;=]5zV3c b,v3anԑP\~}-10/ߌ 1~OQ|et=Jk ү  %?گ*O4U1LMLaw0 sEٴK_SRiXe?'=<d/gB9{<Tޏ9(ΔzHb0궔sU.­␞ezLi>'^Qoh(>{sMD_qiR! EjJdT e^J|QSzG_*kW݅MY5yܲ4”S $$d/ !oM"n!$]bH[a-^?!dQQ V>kYm Р%6|s M|dݎ vHU k(, eۨSܔY|.¥}b^Цf5^Iə/&W~n537u~=i\u3’bF#(/%Y3!ӵ.ZJn/-+ԯ%ֻiꇞSg$gPyCA[C:SPͭI@}Fmyusu_ϻ,8۟y_W=%vJ1rV׼kv}gEҪ CMщ{)*KFth]Lˋq;,/\jPONP X ,n-"kRyP tU 4Hn@S/xAX8x ,,f>",eT;D.GU\_jblKIޔv�[w;//Xx]߃bwIʬgj.z"gҮ7UR4�p18DzNadθ‚}|c$=; Oқ@+4'QCLda.V*A bP#fP{Rr@0=FN |vt1S4#Yr:RΘ#@1KYM;/Ud.%[e$jKi6Iw0y�iq+l{r0"gI.e0(Z;$l}t\/8)$mFy\&?q$O +`fcZ7/rK5^aaס_(4kt;?Ѯ8Xɬ |V&*ӮE]tp]RK?*S|rL ~hS ` %N+C9</[8‹:H1Ұֵ?A'4a]&3ϒg%=}4Ȱɘ]Zj q>0lhh\HmbV^}Gtpr,kp^jY}ЛPbTR:4]|')Q` Òa(ҽh< A0d :JqTmj7^i-v՗|LFԷkYaEaq5]+͈ybYtD cDݩ GK`D5ޖ~*KqS˻ y(C!/͝R:zBthd#"= 16uim5G]#8O"9 x\3dQY=HSBcAx-@)SflmJ ޴{Kvts_O5Y|'K֞2 yyK{`HT[.YکUI�-ijVF'b[0y7o:3DS%%(-1!ԖNq3[m~Ofb= Sg_Vk4?X|7ŀkV,X5{Н?ȥ\OW$h _?mm)9j?FiȰZF"<*N"ў~F9])Mbr*/2n[ֈ 't,5k !̚} AJ8mˢٝtIʹ\nc}uO=ӄѠU(152�PfDs (K$fԾޜ 9'Yg;3[  )JlCԗ9"J-V4>UO A`29-āY" J*ߪN̺A/Unu'lI! K:p"ߖA'#t`Lɠ note,LIj]\ۜ )ڮ58tWISD:� v4x ;E7tҩfS v:t\id|o؈Axo ezp ٜ]tQ4,YlNIDULK DηDٍRt4Ee1鵌??ykך1bm%R{jwrV=gǎ,m/�:oUM,͗Lj,\0lX[N;`TqP.^1k@y^'[,t j[< UL(EK5W|5Pt= S9あt<KIZJjrDxŚq�F1OXgx"(lQ L|$;2kX#4(RTR<n9.d}q`’wANk*�< Y;f]"\nLĿ *>EGLX8`C= -;Cbڗ kr0̏ʿq4J~#XE@2 0#U7,edb{Gbgh $!3h"5ļEakk $]͔X8E Td_� &@k"CnX߮dݜ/|caU̳ < Xg-FKbuyhSBVeNsܷ2.{f&z=hg[:iU}:EXz U+D@.Z̮Rkoi]?[dƟs)g+J/P1V!rUgUqƒF-Z\k|=U ;]qqu\Ed'`#&jWBTC7Ӛ%Ji^|ug}勮T n}y,[7k-;rRf8 "? {4m!n@�u-A M ~J1u8)FvƬHR9}:vݳpԅFPlj  ׂ*Ovr2cl 6׊f9J2g6-G\Rcd́g ݿ+B+ny^qi-N-"=;<mZtbUjXZLv 22}2f]'r8_Λk[SZ#cYv$@mdeC\2=kkaŻBj5H,5f5^|4 <J|EMqSE}]|W6-3jWXxE!2s/Zj|XPq =d.4C ʉBz&%.]7/%!AeWgQ~c5-d $uFcHRтVd1Jp1%nt0: UIPύ@2 F #C?,@MDHT3H^^'_j|ﮝcH 8UXޟ.`Q[:RkS"dͻPs%U)adC,vvb;b,v=W!\"MnC\&Uot)>ROWJU jcn@(tCr]9i ]6X 4ʦ3}YWiܦpq+e݂wp=]ԭ}nу�cpf7q7p,q+Aץ"f)"B8lB-k;ڊ[󘠔:1}&ں7°! (7g Gx:^:Iua[v3߄p8z2ey6q'")QnJmҟ͜cηr6VZ1dxw@$*ٿw+}Y^_hM,]izGI-\X)1S]T\q醍vw@[U_{Yb]Ǯd9Gh.4)Nowd+RAK�}$wKYz`='{qJ]ntl/ eVk!|ܗEa#Sef`"ɎRUr#{ZW!'%5V2:0Zߧ Gfm^5+rL{B|cwӍzg6/ e}Z/Y$dڬŘ+Ki;x wt/؍@Ab!5U*:p5M�`YKYrΝrՂr/*bPR"!5PFKЎ}ҡ�ҡV X>yx%_YҗcE;AD͈r.W)ϭ:Y@LH3`9v&BWmÜ.٘Mݥlک ]9$aԡPK2q)")F=c9IH>2ӚISO*gfanU7*uY : tAʉ] ®0l/"R M9育-QkǵaTX'/>a .F}~m!!~W׌ZX̣u6m}[?[$$&'}Z|yKeGZ'ΜC* SyCr%W@Vh䠿^ߔvV]q$ܡ<gN'ٮܓYXk~Ӻ(탴m{ę|tW|YKsOr]Dlu~!r 5D/>"iָO> p C(ú6&}b9fhIs·U�CY}tLgNiK#,9tD1SQ )ǰ\$+VPeߺQ?Ttq0&٪!L\6CDZSk+d^,c~cJ#4yؾTI_KɑNDxb^&6`hu:>:~r%HP}QуdOS �pZ�j} )v9! FW"\M\kwBZgYڑu{n_;]q<+.p%wUئՌjje0|HT|qr$`sZ29svrwycG{̵Ŏ뗅#'VeFjмzٔ"U\z5?ϣ~xܿQx>(<bA eƵ$X8LQ] sT2N8`2ʒC(fCȌWwEC՞|ɩ(o(̪F̃Mcj7{tadY0 Lt}g_ߣ]rv Q og=MRRCU s%OWɰN9jvank#SPҳTl^ʩVP j.8f{vEND9>Ƅ D62L|ws2Owz :-TP:09-ܓ3T~Z5$zJ;/pxjOn8 }өL¦5>6HG%:l˒k:]׮K=BvMY;nmkHd\ZK-TJ ވKBȇW>V>xY@*cS\y-k*Ww(HV#gd@V-N/(_  dgٳ -ݹPL\21B)\A.tͱzPEA4m<4/4{ˤ>;ӂ @z\˵8@&-X~Ej AhA(AV�aخVɷdDg$_ !4jiM~D&Oko+VB= 5`yxHGKz@C/^ ɈA1\ QKηpsSڙ8s/sH@)i*Q@ uT)馊TD>SB R;k,$ nAUSt ǃ!gB0([kKm*z$?w,&JR%wA nS?FJw#ґ+O UK޼d5 ם8Ԑrآ%Z!/ޢGL,YϲX36$(r5I^HQLjX FH!f c޵"wyj1܅|Y7P<"8n%kLKGtEM%殌t!N-`aٸ%RU[h97)Z] f vyErfE?O%B$y͹*9Mh6eMT!jnlDLA!cYd؂l-o^~]�Nbn,1!Ytg5pg GU $"Y!{k6i8gjs٩O.qbOG׃d;|a?.cC@]ф4%f tLeLê-KP^hB,elcVF+tC, |gL 4?BO{hzSE267Rwжpc6 WB ;bA0 tx:Bo̩C Z*-UP!Ϫ/碩.{ \3ȭWX$!*o\pܳvIyM[oNi`I>+D@T Dೃhޕl�YRȌdBɭOV*q#9NJ? $,JAvWI]<<ïh }V+]Ǧ}sX<eAxzc K^w9vj2$vnG7W#-|oIk�@.vؕyXp*`^J8[?ՌCWg Li|5iԤ;k̟$AbEblzIVK np%q.g0޼ o<4ʾ9x<f޴(1 ZgGWa^MsĮE{aػD٪wna|Y+`)X̝Ԋ7<5E)4uAҲ';.Sճ-Luڄ%QӤ˦3bGblK ]]Ԍ:!y` -9A{7|gm*Ԉ*aA$CK7+P#T.WVt$8!5Pv!4\,ɭΒZ;@'/pM-֢(çQIvcVߑ1_ْ84Р�j[y$R<0d3ZL[}Vo7.T9~OL3a07 o3 W:ծIv 'bǡ#f IscAW#&~r=ES>gM <RDK%5w2>[<0kN-/kfmB.(\L >cB@=_( Ķ,I&Oh:NrJqD}ҋOonG}zӏd=ڏVCq#{(b~U#]-;r{[QWUiqV& 0@{Y`$Fה 0T@k1貦;@hy+BtJa3'9;fSGRޅzWCΆ\7}IK?Р6rwݒX2;ȃz*(zOePq evS1$+%G#2CwjEՠpn&5%9!w 4ĭ>Na~ Ę8ǩ:v uR;F0(dh zoغXXW,6΀{]Y9,c*WoǮm!UQ[\>In8K ѓ]"3"y4FmPec&-U)wHA'E2n3f$1N[="qjIF@R/px5Kۈ�3tGq.cWTVN־]i\,Zk�|e@ve6{^Orէ9[Fcm@TqEܽ9++ [UY9j1^:M{EqBQ\9TqNDF#jHN\k:ޚG!,}/DiRWr(< -hNJ x,dr@͟G"ϻurg9Kߣ̟a45ɡ)Zu#e�=bf}4G--h]JY Kuz\뼑#\70#Or(-~ Qd!9/i|6N9kfXd�>T|>:Z}iq ,IC3e R%8Eg_4Gs[EIqǥFܖEQD-f<6C g S{* \}vs*"#QqEn:LO'l4*;n$: 1w:! n^. $>'V {I>Mo:ˠwIgF.| #C(LIq~2L)E!fX)Ym}u6ʈoTgtͰywYϸskF(x&&.\ ֙� BPOzOy?a?S7K4"D9 {ж\aA( ܊ Ek:Xf`yQ3 ji^yOYwgC7f- C}sɭIgVH ڤ:�ibTX;ʔMq7F5:q7gM ĈD$�`wsގwQ7IGePdJ^L(KP Kb>:% ̅XrY2_cJ3&s 3ϱyDJx3{ j[sֺ̄K̗yJ btI%)C_`@ZHnC_4ɔ/W\p`4q94_1m#-<ƫ aY~h)W5mbZ<q"-jN"#mK e`Hs9F(3Iϙb NDe'B,*-~7q܊j WQ$%:kH0Eshcs5l'-Brq'KЉD٥.fQڂ^1djj&qJ7k^﹭&H+QRE$͝.xIV&U}dN;IA 8^Q ҕ(tx-fǣN&-yYDj1?X`#^9O!^E)C/}a\|2N9v`6fEױh-μkI�NU k9}ZYΐR%ki/G"n.e=sU\v3$[JwX,WoYc_.o۲s9ž群/Z} .+&ɡ+ ' MՋ -nR3ZMjNZtCdla|5U(T|1U7$ZV%$?E n.N ݺdC'E.K=Ԉ\ɨTܴ<Cܧ]kQ&m@n{Rc$2*Y9!d*tiP#jE.S` b翣G Ԍ!?lTq[)Q?:Db/z*LA 0G$cV.,c4qpZé/�)(!ΤZwaE"j_fK>ƨZQʁQ-E 4 Rp9"DǕи+D_ MvriOhz3@A.չoE9%3s5"1WKGvpYɢlpWv,}%1f7X uE*k)8+8o 7 AM]ÄY(UҢAs \Y9&-AQ㻩 YWR%yvYr!"=Z .JK*ݣS zfYbFd;1m4D5(. axwz8A@{oU1 A_ 7[p0\.V`01aeߢds ,7'%Sԑ\<芖XKQǞ( 5̈́fp_u PsK"$P_c]~*M1EQ2UAKgY[GUfˬC۽;rwα+QwĩQ_q]@�1{;9xwǰrZw;iJ2G^5X7GtZWSi%d R;],xjfY jgE(^~36e(r.yG3ks,dfLrslyB& ?E}iчzũ¥93.D ,Y{W͎wq@\=zF/I 4Œ_ dQ?\|*YVM]q7;-O^ooomiiWzT˄ W\RFglBEmIH=gTXGTf֏X: L%9JW:zQ3q=#+R ta4x ǣo4$6RµOSv^saFV/Gm(ꕢCpS򟥡y2JC彔~JԦ(Ǒ;Pyx-}kK+ |hľG'g ޯ19fCZ01Y-4Es@%:@L%XTr02+Vz>YTTwS=U*WxZGِh_O%PV_A~拠*ߔH_:iTK1 o{�+]Y82D_Jު?(b6Vz`T@JjZ:, "ʧ} 8+,ץGvx֕Ӊ˧ bN=s\,Ap]2iꚙn#RVD h?Y3[1se&'#tߏd/IᩯkSa%2lY6N2#&i 7лAƕ?ʹ u:xa TvҺ.e7u<(PFBuS)ɻ5TiSRTA#8#-֧e3ćh+|q۲|s(�NsbT^k.(R@ՠaܣ;?pǹ#j>Mgα'RIt9[NΞ\m%{:AQvPx) ָdL\ީ囐GO!Z)'{yPr~v%K7nMPYSq?#5#e>eyYȒ&bw}jaOiDV :iT2M[ 24\^B *\daH˽㷋Duޙvܕ>՞{OC=jDw0AOEf}I帮<W+bl?y>SfPG53'")^ DkP]seY%7U%w) wOk|iέo^ɲBV\_Mڶ`.Q,Ŝ5 ei9}Gw͇6h/(vcQc2('ki{T͖we,C-`#X"&|]p,<MXf9v5 7p"MT<eZܫLE"b<^yd]t$^9E`Ms6f3`3:r~m*|e;À Snr䜖EKebyifdA xqes&y*ldx�nHCב<;y_kn$ yP3JM<')0P |Sٴ6XgFGzs:26/#R/j(̌rw=>,iSdrfFO͋o@q |:\6GwPhJٮJ'ܯ>DP#1#d</䕙^2LPcVfqhkiub2;rVhP$a~}=eo~ LSn I#LKD1m�g{){QH<RZT~S-btLNZPTJpscs�+ ?_(yD)WB73Xq dh zCZgLyAXu>WvǝP{)<&ZTsJ zh@DQxY>{ IQ *Xlz,T, [ a`"n8Q:)t9[*BCSX+ڦQܬmS^�k򋅲LA|^"~p,3lKMV4jtV3*v24?G2 r[mHYJ6 EB3D <C2`rZ^U?IUQ 3<6hT퇄[ܶ?V;W:{ 穨 ǧblW d1I1yB,\DϷ÷=(8{(2VivhKLu&/ۄ͆%rO4tFFn1T�AI7?ld 9? Dgi&+,Zm[INb#mKZ7G߾K?h;Z>[F(ۄP0x,+?�SPr%C`F+*҇\ H[4RƠjNZ/tp ]/q,M�jK7CQۇVy;賓93+9}/#tty$(q, Jb&jgKGzſAi8o1Kp]pExa%Z.UowlB98B=" `Yc?Y.oTrtwTrF8@-ڈU(,6n`)R_!Z5s ׆n}%;@AR4|:IOĩwAXޜ:K�3$C^0/qOGۂE+Y f;S kobAezc77>Rd Aɗ㣐U2o6؁R¡ۖ8Z(mS8k⩳r\B|{B%Ei@uuen׈˝rr[h{�ؓn"?W󨿙 eߜCrw)Ov(QnJ$P(R*Xiߖ|rTĕ@ G~ tv-f?ծkp�;%܋Ml66$v^_頼g lk [W N^ӿͶ<y&Uu6ɛ@)k2N`$T"'u!'k|})SOI^]M%I 7ON(swGeT[q9WTbL8lm3l57rL&)DJsp +bkk%t^&߈ɀK8G ڍky{6! 6UҢU,Z�:ϨT1k2 ` ͬ2 $Cr e(Jm@K}@}$:FC08,C@a|(Q83 C7eK;wpKn^J~;H^$몲XzdfQNgFe ]ȤInQ ^Ҥ|>o;Y DgR҅5‚rQ6Eo g*^mr,C}J/ B3zݏCg. %eZC y'aAv ")_,F ep8-?LMKvnP,aXNI+-Ww'SwqrSj?KN.Qoe{9c }$QnRx"yw3a.Y:# ͗QqW8}Z̏6!7r7ciFV# DKW ID&h{t5[t(zu8/ s$,xBy ϭQTtn"FRb<\B%G2wWɽtBx-Pckp 5{yQ)N~ aa"khYO %U5s&-rFPF*e`;M (Pqx堛]eG^PhnJs'jGdvn*7ŠThɨ4p4Kp IކpH((: tQڙ~yV'$(};KdZԦ* B)3 b`~ S}p儼H6-f>'ei(@ƠFƩ5m %owVDwzK#Itl !2WT@<f0I1$e><֙ȡsWQea`32ZQ xm6*3 +ܒ^&OnrCvuf]\nR&dV\:$h7)c=%y$θ@UHEὭ|߷Zi}b}rZo ;NTw}@ }]Dctbxwt F?qPnUcR`vH pHeP&qAMb`FO(J 7=QfT4'R&n> 7f~0r+ S0Ir 3$ʹ6KjDr^ћuE&vL#XfS%67;Kڵz eWǻNZNWuk>gok :%HBܬA[8vogRn'G[n )C] lsX>a|`&oW7M^Mݓ &I1_8R/iASd>d~c:q)qW\L=CtdжgU_y<@ϻӓ<L6Dx!lof+@ծ傯c\ŋ׸*:O\UM*-qD\UDޮq| lsb,jZy 8ӱ;9;j[grC| l6~5/LJc=,9x gsIrҩpV)kr#8eV!*hw7Qjv<fmpg*} RN dAIow&e*atƏH@F|>mE?=JmKl<QjRjBV ^%,op8q!G6=ÝCm*rk鵀obFqFPB,/-qlgP(t&B~(^\ԊeB=%$@: A >Wdh~(1ѫ# 9Uo pC>TNe%6uϫڮ`wty@=(5YjCAQ^,s4ɘ\eʇ“R� a]k]BN0(@#@q&>fk3c:_ l]ZvlQxt"[9T&rb4N؎J%1WMi ۼ2̇ej-r Aa_J697*e!C,Rc =c .Cq6/`(|nO-XM~(^eP ̞?hUi6py&ΣៗA_WeFC tMwe0shfXAyQF%nY~h a4="U,qKu,>p3YJ g2vX.wiX FRV f++XAأ ٜ`Jr*Mm{ vv@<^s|J[W%Yx(RFusk+Trۿ(S^&Def4KE-GsBlTֆEUßg*GeA,lZ>|TPCk*ܻ](<غQVΪ{m=Uj&"2!J0dt;Vy%]V;%9,UyMrK ­rF]I5k%v.!FXeO*eIwhawCw/yNKARqaOmWB$P0qAyQ*B77UFs.HJJ?-w:`VةP* `ApWڈ@\XZ>-GĩƗHUiD~{g]?yQQ."tL&zg$d[*U5/Ld+4ꔄr,~4l@n1iXo'#BFJ$ NP`*S54t2.1V̶U&kqTpEQ+dwnas<Tu|r;ry,d1n:։# 569UŊޒ*41k@܊9}GQ/B*K*KCRT? b\Wy"Gve)ޘ&ɲC4㝱HVݪCY2H}Iw}Fp_PKAVyhT4/:g JuE7wyp3G1 1I:.PBRTSlýctE7\sjOmʢQYCqY :پi^QnC;⼬ ^AXPVY9,x4V n;bڕ.3ɕ|gmJlc-5r+l`YGȅ܀L;�riO 5I;BcͥG~b(_8R!Kv6Szdl׊PiꮃIjl0])iBƨRJARQA5lߡ d8K$żjH5^& 03Jx%SL R]PWZӍ$(tkq+nH+[]\5/]i ]#W'H=`sZ-j3_d3Bae0^YIV#N*@FKQE}T;QwC;`Mc.kru:J:N ܿ%i\m=WF:&6Ԙe;njN%Ω~CPm%NsGx7 +`+Ǻon[鷎oe鲕V_ DںW Q-DBP1�jUYH1Lk3Wj$38 bKݑ=M7=) Y5)ffU^;X}GE k=vz@0|+p e˦*s?fVHvIni9D^I9fJ 'Iz#1 hMxAKpԼ<@֓r,$~9T.~TbߊG|Uxf#mDm;<r4BCaʃRNgp`$LyوLD2U'ܴ+-(�J]r5Q`t9Ё| ޻_%,aRyq`X[v!k[s9aȋ `It!TJc0f&x)H~ScȧϽ =YS-&F.z H(Lɿڝ$-q(ýse9e]8刭 NS}hJ Iy-]nz_ sSu/T)lʟS'l/&A7h/΄.rA~(>VRFGܝTd y?HCMA`]4~H^I OM 62u xЬD[ҹ/y&KC/:ίV9*ບ*?c- 1{֊d2Jxj*%cF| SzZ :w5Ly ".05AL.BWKo46VJ4ک 622@f@y[3ZMP`}Qu1>OT;.W-{�b,W4"rKiR؎NG c;la6Ck@fdd~ogۚ nA+خ;l᫁�Ig!穘 ݝs ‚d>)Ӑ)B0!ap3 !;(RJ/8ᬓ *3bDE| 3{t/? n"~`.N)H6~G뼣SB u]g䧹+dhV}sqB؀״OLrVx7HZ7/> O CtOLOo d0ZNŚ*{X]n 8ba`q :9��OWs PrPVœ* cpN6m+ݖ.6 b݆atWPʒ2]G`NJ2$]ťpK3Ezvv|u{&۽9;i#IaAK_UJvE͋A KR{7YbNY$U(qGw*A ~"mcO$>gت5i4<E6'z AxGe& ~ed]"mi &kL=Iơ8 oqɠ15軮(t%\3zrU B+ %:`Ҩ"0Ѣz4:1 T Z`EZ">lmXղXCe*V+oӢ̴uD)VV/a8xG4-4<BSMBd`Ϟx^Зbb7銧Pse`dnv͔2͂#¥U`"45n (_KgFƇ2HyذT"lZЀD̈́{eiT?]# '˖yTf:6F&SHoøjVQd|spwƼs?BUP-ŝ~g”-ad6\O'8TcUIIxuzf%C~PFO2 Z*e6aVQ!7JNb7i]AiCy(KCYy(Ur(y v*TT0QAUV�/x)͇wP(oիm2{Cl>%Q5\5LKm+i\ł50|قN+}3GЇBO%'H:mfmSzA'a~;\v"Ow7LIᥳ<vAxSU4 K\|Bd6(a-Ub~Fv|Ka|X^ż�ݔ 5]鲫`L/]ųWde|S.ZShmyƒq`kw"r ])%G1-#XS H?|ԽӚ(4lGɤO9o\Ó]8y-pAq <NӾD F5p2 ,`f<qw5]=v4FO<b$fFP1o Oj3z9,f"n0M iCi0>4axJ'Shj4C7]KO 2vh0vvx l91$r7؃M<s efMGaFnI&`C q6fWWzgX'od)q 3ZQ̐["$FյxX % 1svW$!Bt(UXI6SFw)DԐດiJM03MG72Qu-MX: 2(],4i]\3q*Qb,lReNA(pX~} hƤq.A-R,E(Ϲu+)J"ot_J'( LǍ&.�2M6Q;أ*<MqƄ  ^6^UHHpUlf1񫋱Sl _8 CB)&qI"`jxw8�-N:K*s>uG}#Kܪ8`98vCF9bS|�l'/*F-l4Tٱ`K0}2(ʸgmMS(@r#f^5rM.L2C_ԡY;G (&&^ ʆ@L@|"Щ5hzwznYqr]>֠/ūQ] M`"vtfEYpxqҋTB)2#WE!K8pӧcnpټ2/⟳VΛ$5D&I tseԭ|F:ƪ^hqƮufqdF7_%4V4}"X&CàW"pvs(@"d W“̼+4}"5o€-m%sIԲ##~ X 2\b] NO U.U%g v!YgA4уhO|0u-b~~efzaE\HT]9~nD-oqnPѧw%R�TT(98QOT3+Z {*z(-fJD@]W+az;~C+Fr}J+Ǣ)+VR$D%]:V=%k)D.DWu&cܓc4f}8_%_L B.et<Tk Hf|3}&\#zr^H} b:(e}j > 7ByMpl%q%&K](-IUT LzT]SAr޾)qM^/!NijC+2W%㵺ʥq<ok@Dž3ʲh2o+{}Oy2Un(]6*<HȎUK5 Ilaڒ\`~oTk4%LA%&b:wG՘hK4<] _DF ( Aѝ2u&ֻ71<[aA ~{h^2Z&K}n@d?z;4VCiVyK^sy\j8V_ t}Lf<ݾتjÞGsˎ)5B1iҋ>?#䞡zH^5ŊsDDTi5>e=kۢ=:exߒol+O0dW7١.{_rmX2"4 ,Ze2/%oOil4y.?Um2PxppLŬЩ$cL_ A pWPUx%!ӄX&gL-ʗ ifo <;mvS T^S\Vl[)ש934% FYEy* ŖUZ-HI=ʸ~SVJ]PaduɅ4u-Ӓ I+Kpᇖyf҂bM8CߡPFz>e$[f$AfzFmɅ 89�۔Llo=[#yWS\ Cڋ-52ަlL2Loe<E<hB"ǡsX.`;DLE8TRKUW#~`)Zkd+[nhƜUX1øB@a<;eIwhڎ\ܥc]WZUIot?W7H,ɠj|gTJF@l'((cic2"lVON|r}y$.UYYUVar/V#c BX]ydZj/!.तKfC*#nm-'cZTo"ݻS>;U�0k1Y((ˏ<e2jMv 4׷Aj=T6sa)`ZV|m?٪U5ۀb;Bg?B yyx-YQz¼y -R.fB*> 3qɋ*]FAx L<3b +()sp^7:2k7Er+  ,G"8 ]M5҂<I=\̗\kF&8:eC.%ƒ^Jx]leS^l/Qvb:VO6BŲk`YDtD#eEesN$͆ENz(+S筆aa> 7 f0@NzMID6P]?.Yy %LZ<ph& " &edbv*'>] S~$J|E%7;-/*#8&j;2y\;AE3ee.P_tApdB"6J$#8CaPm8#bTE;}T$Uʇ69Я{UVc]7Ĉ}(Ñ-͙`)zfM=>̤Y]Ю/\8 e$S`Z6Iawo4{xJf7:`&d?(ָu]EUC^g;h g�u;R4k|g+Fd)Ep%H4}4$X*] #^$Ԡz*\ϥ$<{iU^Z⡓a}S1)'{21Ȅs!K=_٧59$!^DQm6Qߝa+KZ1IgϫBCybC9 C}IFÅ9x3@8! > зP4˵SFXr(QF!cLMmE }TCS[Xk�Fa:$KǾ)G7v!39^vN1a(f  KjL҈{ykT`LW`qLʕU}T?1αQÕU �oNō]yIkҐAȑy (=.ro4R7+UISe%_eDc892I$`2J%lF+epV1NV}Wf/LJjV!`\Ӑ<EyVQd$CT^C6j5u-}`__'MDPF_X6JcJI~�;"8M;rK7z ~"+dVm۹kl2 ?rw86\/[$PB,f2j}Ŵ5BԼHH҈*hT=K\.Rj`T҇}D2}̱K{|"|Ő'ˠ@4P{IRLNUM.|kI9-NzELIIl``V)uCykcz)Ue)徽])픱7MM{S"COQgvY3Ҳl�6!EI9$dcP,7#%DΠH٤$rskxAAB ګ]ϱ$o̷#HrS::}(?8{;寷a S^嶸Ped/J)lht磌DOAYۥ&˫-ުQڼP L^-7w"Y+h/kar0ͤ9xј/ U9Gew9EL LYƈrc%9 E1h.yI@(`dU@%Qrݘ �aUiN2_HY�0-c|)L2YRLt2G&4$ tcf6Lě}݅ES?LR!agO~*c͞!W;˄zzz"#&Of32?4}B\1vk<PFVo0z!ɇ\ZlI`%IV4zX%%{IM:Z` i7Y o#sh2Inaj$CIdőt6ֻb"߬@ϴ>wVVv16ZBQ|@É4[zɸjar$W͖V//J{Ym\rXۈJ ĵagfr[gO}݂[dw B3*-իhoI9mU92۠aƮPSw\rxIdWcKWUgp,ZW(ƑcⴡRhR%8Í9W7N=c]rXHJ2T^IbP Ea,3&+,wpwM壛б*Ƈt�9D<31N-`J9mҜ-ZӢ՚V] k,@1J:˲9qc| VY+7qI*2Qe'R!i,y(X#ibL{/zrƯ7wg&e VUf A"X=@ DrU/+ۻHPGv?l!S=GKb-22b`?Vj#뻗J+NLҝ(Oc r-Ç)@OG=?\DˣWAR@vdt璺f$խ4D&͂m=2nL2 ŭMGw&nbb*3$TŹʿ.7A,9Ch%H*V\ |G0%嫘ƴAѸ)p#C6fbuUf*%9gWncyŚ쒲,,iƴ[LEp;De@b }6N"LfVnR ;v 7miEض!A1ik?JZ! =OeR~,]r_$YvHN4|x3j.CS;['Q{dtQu*;M+6AP)¢:͵{7vNy*ʂ.Y$̞csj=?޴ 6~u&<~%7tSt C7qr+QEBqirwi yl&'p-d8VWlk=5% �235Xb.&7e|qcW RhZ<d:܋@[6qeqwo-in܉bPSi㛤S`wBQS%4Eők( _BQ#CQO23V$*_BQ~ E}\NMGE) .z6d4`&r';C|4uQۇ! v~yZx侘GT{Z&rTu9[Ռse Ȫ.=)RZz>Fvef<;Fxk:ыʴ}|KC1qFYb"5垀\Q E L\c"IW{dWM%2ǮX⨑ M|JA Oϙ2ZA8\"M7Gz<h+44p5T,ƚ/yrn2ŒP.J%@vb9 *y(`O.Xt2PV&ԽzIj,?*Ӫ5g /EyM<c#r @٥eKf hfECoGo%foā#a(x?(3ɀLR7 il"p1c`cF^ @Le ۭ))Yq89¦Sv]gJh�pb ܹǰ ̬at.�n `r~* �cޫ؂۔ t g CceB *3woخ�HAK冢 HI?>7|O6Eۯ@ӑp432u2gw5c܅*ziqFA'Ҳrw$6@r @#0acH>m$f[M|22x*)[CL~穕71y1%) ^? 7\8 l3nͳXۥCA2_=R{)3$^# Omx'3ϑݔ d*tY.SVC隣 �:M?K9P}̆'%@uݽNڗ/p;5ڈd k- شj$L8Ma4xv7.! 220ר?^ڻ2P$ Րh" 2WTx[wT[Xd"+ߙ% $#^ JOR!R&>�d6Y:eܟe,V }`P+8(X>C7 !bWo qS: t5{zFYXgJ:'`ג8ɯpwl/]p�V�Nr ύ% \e׻a�a(x-Dg\ " '>=y?2WxO<{ɋ7#STj7X ԡnv=:U\+"(6>VblBIٌS3WPYeǁS> h/+Qh8.:VdQƿO}׼$*4c(D܍:.m '2GiNB40 Ma,R&YMUmT|6Y2%zJ| (1{!ž7@ G5Anzsn9  $&J}z޻MXSQ /d`a):oa</049[N= 4ۭQb.)xiyNU:L2l<R޹A-n^U#mǺ{Xԋ�17C`!MRЍkA6SAbm ZaOT T R$VF!Rzq4O4 B&Bŋj!%i"_ +,2@[?P[{I�g>sՅt:eFQ,.@j#8Fu}ڠy'CY-*6LSw3(Rǁ'ޒ#SU+V }"CBMcJЫޘg# /"0ԣվ\aҹ>n˻ IͱѶQ67_,xqWfn8߿߲It@W ^0SH5M)5s@mB wh5xeS6I  H�s0ISFJ$_7KKy1D;W}bH8).,H i騧G.Ѽݱ)qWU em7g [m'!jWN_Rc:n+z<v')LFK M:8$B�7)hi4}^(]pe$ܤ0*(FzW&|.=@"[f F'Sw MMBG93&YOFy/ *Al*B9�u ݕ@㗣/Jpj°xӋVdݬ;<?pawe{:PIرy#/r:y(9۟zGXSUPm['X:L�֚ o1N:f@p4Ɯ{wq :'m(nz@ig@BYH:7`#NJEͨrG7< >:ӱ@߹aP6=7 \J ] :^vvr&0BaSBoteg6ey滻twKƗ}u7l\;�DZ#Gt#CQ͇Q9/UCZ ;C&_=5P( i!YJݠ~njd0C nm׹Jr @})>և5)e$WA\D?xs<"eYI`BWv�V;8Ck X2 "x;`>_r3Xb.]x\ Js$NZ& cZBGGuA\1͛�q%)v9U)TLpyÝ֪W u۪JAXgkٳT!goUn&w=diC{Sɩؼ%õ^5[V�"ݘjKvi�dc)s_kD[y&Qb$:mk`Fb#T>EG5t&al]²eӅBvw`WK[DΐSޛ |Os9, $)PhP NkLW`2 |ֶsJUB8r+nn4Mߟ'ʸRʮchc{)E~3{*}{J^%wlUBn^GL\\&f@ex|_%}1kߴ] AT*ܓ ߟ'hKh"my"(>#V陃mW=|>=?dID0@d*Ҥ`!&t DoRj݌aa19=amz6| "zĺ5=e�y9](RXI05a_KtQ"&Bڈ<ƧO?ŤR|(O*7AI޶O{�}ۜOB3BF噃m{W=|>=csI|])@,TmRJE|1PԘm{@KBѼfكUâliȨkl)Q`TAm*iX@ %D_4lHb߹J;ye"|�myb+Reos<!Js@om{W=|>= X-䧘N[C2;p0"{8bmǽѭ{P $x0&`۞%xXFND|YFXT*p#2zn,Ǘ#Ds:>!Y)}P*G[#+#+Bٴ_@ 8oR0yobܢ$ Ĉǻ g|4׿}u}/<fڂ Ẵ9 & )Ў<شoddXcq5e>3mOh #_L쑅B! ŊT!oE۶N#6$kXc*#<\-steJ%F}&⟛x4EP2?R¾{_W޿~tf- BA�Q}U#`MHhڮBSw؋c>@1qF `5x_p4SXnՠ 5iUA�oD ׫Ü6tm{@ >_f`)<N+] !/xNnS~zۜ?¢_gm{W=HpgV&Ma۷R|dG5?[mb`/ϫ П̨x1g/eJ؁BaJ'iU˃I*Yt`g�osJc̪)ض| |+ s CUYe߮h~62t(!6'`c 5r !֨oSEJ58b6I>HK<QjMmSj: O$ۘBz *=vL"NXF[\BT*AɅ(6MVάj`NTnghs<AJ#6_g*V#<A"1:JDP:,d4\FU舋;#xs @ 9#4+9ض'|#֭-;ڸՄ{(N>mؖ ˩/4T06gϡXQ_|fИmx_{]~N'MPPzV-8 a!'&'D�jhYw_/Y3>N+\+s"*Њ,FFͨ ژߙ(pFH$l%Wx|&}Y?qgEIQMG]U,syvHL<#D[ѡdb% h%g _Ux|r3fe#Z}QQs,gc2u(c>B9p Jc0SCm鴊xޕHfB|X5 @aG #6_2#`{*}{<| e+Z(!Ȧhg>KZXyos{ (�p̠6nW,;5;<J 9v0*?_AqzZ.ghs {)^�\l=Z#7*GdBPdb6J zT P'#f?ihs9 b <$A6|Zzus{<MpwW1(Iupf0dvoD1#xsA81BD9ؖ+_{ĺ5=yJ8eZ}mPuXԡb9  ?G pC,_<QۙAm1:/=|sNŁR6c)6}s"\0:~lgȋ( Ca͍3lB=b߾Iޕ)8 MpS(߁:rPFCS㉸-1:5i9kM?G> B!ha2Դ>=G6X8suF \왃mE`W#mХ#J!ؼ]Qb31qmblmaO8ZgJ'`۞Ux_p'[M);`@J7VK{ F(* /BBl?Xy-&Pvu\/7Uqe}])y[{^]J{lˁ=, 4$ x3eEj KïhFz6 'Vn o[| Crx3Ge`Yg˿>8Y KʦzjEljs^Fv9PXyZgkW#[MsT3= ټA'{ Id;C>9=Ÿ5BO,s{*}{<ž!-8U '!jMrܺxm|aң(g\x_p{oA!M?̜&G5;_;іb~(VyLM6b6+�Wx~{3pVAUJI�JI EG>>xSNuFSiH9kxoMo)ͿK!4{xz9MH`mYg_2{n%)FPZi<&-&>Mކz9p A}3kIq+Z卙SŇRAypLYڟ�-ڃۜObxB#>{*}{<R 52( �JH ("Fm[,z4w=q ħ9s( M䚡Fm']]jC=ncosNIԨ4b͕Cm\Euk{<G«HTcMFcXxj'K2D19dOhc`82۸ x׼6쌞(^LϵllRӃ39.Vd:l#Unpw A%Q .O[F7ݽ8~bFNP,UCm*\Eu{0=GBd܅f?/aQ>KEJ43\;IL `A�B3{R+п})t@)X)JG@匶]{y[cpFv;( j_# lˮUx_pUوbd!;`"︤T3ܒjEjk<! K_ƙCm{Bn߂UZ.e"zNPCk,2!ڜ<Q:Ơ/S)OnnDF ʙ_ v'da]ofDe wDRǽ SKL &`Cczpv0wqqPdی`@?s/G6}87 ͋F(G1GS;Jx篸&YPEVZn  *DT$̌a�ljtD F?ޘxؖrYʜ_NWx.ꐲ#:!6 \i]=Tc5jKZp_oRs+pn j@/,X\m}pHxR19>CRq<sxTYuk{<A t`Z 4ޢiZX{vyQ1{Ē5WNaF<=zi ̥a2xm|w-|7AxmOhC+n: aE3.Tʌ�-8w^]oM<lԯHl+�W3e)-�A DTaE$eos␒,r)D$EK<Av3 LÒ",&LDTJ{BwmNV$%giUx-Gʠ,s# *CBܲAaNm= K ,F '1۰kiUSq7ˠ` Ŋr,g4>[]tA]Vã,WVflXo?`5Pm[a'XA�՜ќ=ld pǯg]=Zu,R-v,N}(py8#x6OvJ6q`!WZUxޅPMBp v_:!m 5<=jokhs{"(>B9ض Wg߲sMB/~](\k%õ`0G=|zC1z c9ض'|W#h�%&P~2+e*jFL#y*"#xS'�Yh>ڈb"Y5GœV|8elC:ea8dy`G\do뀏;=BrFP[s Qr#WCm{Bn2k l]#dTUwyzZbos<!e~{L>۸ q* yAQ>m]`R9="SSh15BcumEZUxޓkv y ,X ӂ-g42 0cy5k⭎DlG"J ޕrfWX. cׅYR$̀oa_,j&~ 4ۜO2Q0 sL9M*GH*gH2OcS?Ũ:цЯbd]F6\-g8Eʇ{ĺ5=eb* fQX9xv/6,l?GȕaCr!IȨp81>o_?}_f,qNXymCVPIMs\ѡ2+6fN`VY 0Ung !֬n-ufFBUJIv?-߼ Oߺ &gO*x8&`ڳ=|>%Z tJg)1 WlQY2Hm owbos$9gJؘm$i#֭&a@̐X s mVaNq`HK 3ڸ<1}tоE͠d|2QepP%m~'Cyۜ?J&Ԇ<;CY[1NnAhׅBgv5`zk2h :zTV׉9(c"gkWM:Eszׅ"{ *oP> nYE*D}F6NA~SeUxXFSeĕ1&ff?mZwkن:W/ǽ ]b5tg{}ߐ%?g005֨HuQ~iy`ghe;NF`])D8K<nE+]:n/ZΎ� k6;Զd8c".x$ƅ25֙Cm{BJϋqZI&{QJ`7z6PqR|os <"4 9Զ'�x2I,ί Jc'a;6f=,p\6\DU Y3W+|CnY'WhDZL�xD eDQh],@s�9UD2FǓCFP6њ+=Lxj5_Ffz'$xm0S|i>}OzuXaBz0C TěU7k"{ۘpBCKL⟞ąb 즇P]rPh̀!ðu]p(F0#"#4M*R#<&b[jU(K�ńJ!ɛLJ=TxۜCzlC"G,jQ:΃S26wyg) bO@ YvӠL4�1/ko(ZЬt1rxTme,+xF6@:(3H'*G܃ufgIP(Wbɋb>}mE۾ޯ=>aٗ9Zea8P6bB=br.*`yapi3lyWlגhVc{m&EU<7e+_.`T1D2Y  L"B\:FBa&m!4*R#t^1ۂ*㬛#<y'Nf@{8(@(!28(bhwJc2PИ,s4"ljᑋ& 9! m3lN`͞ )gos{"(R)ˆ�xލPTFDD@afhMIƥGT}o?]( !1.ls*G[# {7 .PH+*Blaj!h?#x8CP  s�tUx_p?04HPk!zr*K2Yr\{sE#(6 |bOi/OMV-ẋ򹁌WAEEż;"R>#Ds Q"G#49؆Ux_FxS,UMZ@vN )DJ4E:EC뗧G zʀHjK;25eRO5CYX//,*VU4/d Z<#4\g!reӒ‰C(,V#:l"4!ak_6G'$�]8>{Ē5a9|K8l<R 4T-@=ZF](@jCMTXFǷR UpA<o):L+C ۸*dQLۜO2W|+:/sPJϻp6ݕ Aa@8!YܠkE)_{]\#9Ukg _uk{|#Ggbb)iJD$39.D3P;t>ۿ9np8 `U. x6%=mV^ѴjE=:-6zh .1;}[<oDulutuatZ AyeʒP>%Fpy3(3B r`[YXUKLYEe,dU'=,,cg{#D;HQPVcG�&:B9aY*N_po9"Gbj()V֕҈m$[dȐұe�osCPw6.W{}[<><?' ~Y$jٛ%<A!;�QʊmOp G,Z#_i+uVԌ#S~ReL({ͺ#6ӕb�ocXcH;>p59ԃ+/Lfx2P U`Ӈ" @9UcPƠ#TF# l#�IkD po| us(ƅj6*MiG7+*u1ɼx|iL6DKD∛(GA%:]2!攳&O=̐2/#D;E(*X#|9*GS`]{J-(IJl3&a:eˎ}Cb f_5c+| J^+P* >A&XGY*]d?V>#dFY  l ׯ+Wd.Y$63MH=oDўǣ?N&�S/!zh1%?ս槓r*BkfuH6o,zٶ6hKŊ79>DIaRlϙ{rӯ?]Q5&&UcbJV#6N֕RkG󸷧*](d1\9i X7("X$|EF #CW󂥓vنI627S$X@ <%Wk?=|>%L[<j)T&aW쯶@ 릟W` Jo?-tNo-m Kf(pΟ#pΟhf'h{d|@M΀S-BbL?n/㣉-@<>As]1 A՞p̌m#xs Q iuk_pgd WSv NUt#pn4!D`uN8G3$,bH`)2+-Jcލv⠴HaO݊HXJ`7ra;#9~s(�uCmip#]4&XEꧢL Pʮ,K!{zۜҷ(y29G 9؆Ux_p絘|f_:ck05t"HjAQ(V I 2b4cO +<n jq1 FL [髠voQl�0=<LJ Ow|1|@:նk3#OJ7R`b*c3" $[r=>CR8B9= &3X*[[* P<;B2UjWh[ryۜ�ċ<-# V=| ϫJ(ӃĜ$e|M^ۘ cw $Abe!Ls-Y^:}[|pYfea8xMe96gպGn25bTC1ušaXY WxȖ P{"<˵ XPpF6{!`yb9ԆNUDXF7RNy~(k,0TZ.=ڊ{c�os <b !i4+=b)+Pa_0M'h,p[[ DShb�os{ ((Nb!zǂ2`HfޕXymMɼ0\ݶc�orwB!7mz 4@+ǂq"JAźbQe" k%6EDsn= ^F6@(;0F};sdU?JOc!L dH- 03"+J:9znY]M!{ػ1BgF7Vg/q&*6xa<P]mP6Ua%eh3}n1GFO>}no-@r&.7J]Ӆ]#ںAm͡Pd&Fm)՟.Exތ5Mmׅ2Y"Ejf5R.=6bos<%gsV=b/rR =PڠH=Y~Р. r $Qm(QBY]t@-:#A(a9npYjY #s>(,k\=xBiocxܤ"/<]{ ٽ/ΟV:%_?UgIQcno ]^:T0=ϫ,C�Pb.;Ě@le~PxExB$L65&/ehg_Jj4]i9Vֺ"}KEya7]ߒ:+9U ERm<xi!> %W 5c0T bmj$ Xy}gYFY4:sT҂0.^cpk\L)fq4ҹ)á?,qf h4[cvvM +8Z +Gx봼0UݍO /qv;ad37qީјWݎv';BA382 )N) AuR2uĝ`fIT; /`+mJ֦Υha/a/m9k(8x|qj '}70@Bv$1^C1v"PxU7)8uFdN0I6k2O j Ru#ְ2:2nUڜUSQj8ב8]ĕ+)l`pIʍTbÔD:"1C0&V0Z`!(A}ixu4ߴMK:5 r6Z2t'q1҄t1˪i}|~u>q./~s_8 `8L495)mq-5:)BM+) 7-D Y\aVcՀn#w"qcrp70.BtSi`M@)iM94PO�b5?#C$N^'C+P*#1ciI Z#ZXH 'lKĊ=ְ)IH8%kVS+u0 Ʒ BUD4Reek'L`m9wpHHoEԥXMs`>ʍ:f� $xh).{ Lae5QyԺُEwиߊW) BhBۖn=| `NfҿER}NZ^u>DSA,۪q[Z0.r,\IF6Uqְ2"=\|[đ!ScgK:v2f^X#8aD..'jɾUe\<^3ı,;(,f -$9Ob:pO{a[^JໍFgeykqyu67Owia>Se֐{60}m*6JE~O]:V5w-$\L 2p;q>H {i q%!,' ]j+Q+~<D3%f͗kUa)el!3kEx|*<Me b#>;Hf+vM OgNI,nFv?O9\us*shNj`>9[ .T^X^s_/A'3Z Db~,"i7O\'JJ =aFwl6㚔踥-iQ5quE,t%d{dy^>X.s _saGx+͒["`1([R]B"=?|qs嗔 7Nm:^ =ӯ,H.odž8 ŝ,6 'ӫ)Qė,3"؅ nC*2W? u1̥5m8LvkPbZHLI8#'З c C1񔨺-1GAҐ;.g{-)n"'D>3=z4o0!vzg5Nq ~D[H0j*Èh!/R^s{AH3`) ^-"`)jD 0K*1µcTᰅKA-5oYx+<@0T,%2p,% q&gd`>>?\"].}lV^X#8ށ㱄QaBKKɁG~0Di8?ln ¥H]{ VV9HK*m9x2$\dNK'Bvt̸}h5GKh3jZHܓ>˒8v~W1B,^ޜHM.#NP -"6/G.]T '#iiD�(d]΍m 6bNqW^s3(ђ`1qX+v8t)! Cԃp Ns_|}x gɱs?@S 7n?ܘ֦þ.X# sd!Βd<ү'SP`2',b&Zt,=#J>X#(5� Y%;CKjʭ@w0 c-RREx& L/~sPK'5*<7N# FRcSrSEjjZ>*B'>k_ƝTH=[|Sq^O^S/ Zb]'DI L/Eh.1u kIYxk*6T.%;ܑ.p Ōd�.f}Bz_Q|xwүSr*^ 3, 3bqQpn~׉nَݪaEOEk_X$^+B[g~'IL2U)R\U8SEY*mtgPYrVRܫ)F77ܜƬ\2y= XҿHS=FzH!G~Gǒ8S>š[##dF^U,% BSANX>s9qTSRPE﹗4-* b#u*\dNiB0_B3"}HZxψíWSf$ddOY0Ȓ1": Bni vN^ݞ dk٩d,0B$@bZjZ/ B< L{(R81T miap[3qTV caZ贝}tSAHe9Xٷʅ"Ixt0&18Z 4T}kIwG\?B0v ^xj3x`chFTy۾1*kO .'Lb!alKB&am9F8hgο' jX ?<WX-сb :.c<sU'ޤbTt UjzU')9N -CX7cH/e5F=H._Sr vUU05ؽZM/`d5ze-Y-H}G {a[xό]5"煷7t0;^Vӝqysj#-͍aW7ܾ젩,<uRNH\$^O(X}m`iЭvWjmAX}$'N^U^!o4.FQ&CSFJNG5RsbеK6cш}~M هv» k4xvǪa/e5uKł* (ZK&c hDնXHŔ;-4r8ǔְW,Si.WPMN? Aln<&Ϛ%tQ9r_: {4gxk$UpS"Q|!,?ɕ75HT7-$K:iXR}kְYP)Gy`L9}Sc2Η-Ai!(BϥbĎ k߲􈛁rNx`>qx阨xxj:ԈX0><%Q`] L/a/m9xy .A@P⦮qIٔf[( i_[AJXxh&eb ;4?~+egKb k Yneyb ƧLIQ%-`c!#H[iS+m**C]X Rע}`>>?SRX--DvX ^kS^s_F ZHĩШ?VA^b0dE&N71^94 < 9%U1Kr+ uMnQ\'.YES҈,g=-N>KA Lya[xQj]d + PQsŴiWb'cho5wP===]J'.d*Y1w6 QF4Y$bڹ׷]bMBO߇ɫ W$h*kEvKbaSvaM iMмۂ _KWDFpB^L qCovVa$9x^ca ǵqu9HmXaf INFB{FHH m q|]-:-CÌ{l<x״R}JKi}cK%/a/e5xB:Er2,qT{c=ꑜoҘ/ gV[wBK@H/e5) 8"/~=qJXRCƑXsոx9WկMIM-ge }n92p<I|HvnEqPm::Bashc1 Brkdʻ8kӲ[MM[$QV"{wGy不cF[<>qD)/a/m90qo+eJ8<xBDrޱ@T5jaT-Lv)J&.]AhOR^xϔx0S8~ɶX3ķM(^iaMskJb ~ȿK93X R^Gɔ #IdmBHsmdTBqSb\E`>v)HUFfA,֦sհ_syNJ%KYi'owI�P d 0fh!~rұ/ h``m9VC"ϝ|&/1fʝ5X>-$fh!ɸt! Cc8>ο7 _J];$9^_3)J_ 7D@UHYSi$ Up,9aF~ޘ c55v^0C?,(a-:1K+Axh\ 3z.ƿ 4O[GfE&!ڂ1@ IB<'vĘ5-<~7T3rK�UK8'gLa*M2`*IY}]qJd)# XÉdQEe;ӣ$z%2|֐6{roڢ}1QR>޲|UF";k`.B!C[od|bd kIx śŐ).ꗗwJ{=XU6e=|~Iaڳ\|F:M1|Eew$Ȑ+@xZN^/ Ɗ2Sd9ʹ`9 ̒_D, q>qC/RC^8 R5R9_66jܑFhԋlA]@R E]djk[x E+\-gK;5Kk#yk $<V֠-RBVi,>YrG\|-%/-LUw V]-${GK6B$dEă=H 9iA|hLGJ1jF2%*^lQ/Ɲڂ~=Tۭ1ƉH {-As]T_P&&!qU>%΅ ه'H {i q'ǎڹs$^ؓ#*6,$VP?ӂ1P) 7hi_d p8ǥ!/sqxsto7%QP*N_65�Y96:@IN(8gxBji[x+ s/ #[r?۴rSq!D1nشtc0�.NlU& VjK[x]F^vƙfRZؖ;ա^zƁ4`$IO- T* s104Vխ䞏7ڂ1))K 5ha/~sw+kĵ#Lq\ɕD3 bT#pU8I-l -,x/j u罩 ^l׉v*S!XYH6</TXWm7PՒM&>:%egza {I q|ptaF pmYr1&8K)ĺWsB >Bp6p{zrcQ|w[,<F"[Օr8 v\ J,uAƟ+RwTւR+�u=s?5cYx/Z@HEF$5Y qca[H*Jo 5bގE#8ޯ-7%qxSF7ב%|S8( ( ,f{c $IAh@RAfF'y,db {?w=hRX;^+XZ0<}G z15iJJH1{ZYA0*�}q6G̊c]3ŞD" `5/  BTj\e, WY#DhZƔF>jě"/AJ.En*0B9$E/\+\6rf9M"iY1]F( A#"sG/3~a| F891B!SrM4-p= x?}ODoX 0jFH3񇋡}ո!LRc I|) 6>8wRSR(uPQU ӂ1v)0Vv_5oYx]2 ł0kLɁ,%-w * !ݨ0ΤbH(Q -$`` { KX^X^s_׍GC9)N㮳Y</&ajŸهvӔl9xˎ,<r<bF\Q^0 &Zx F&qkJ3 r 6[G}֧}ar҃Hi9MULTR``9ȓ+\5ȅ2-$vMJ򡦅Ց kK[xMD/RLIǽ,ʕƕ+V<σ&<1;@Kpv(\5gx }%VX$<̻C:cf#-<6[T*ra\ҋԐi9X@*9,y:g+ *zVxb]$-/jpS>NQIŵXc v>] qw`aGK >IcpE4H#7@D-=T]o <]V.GɦcI:'׸=5y%E0b֧F,󓂆�ټ}v@ 5-<~kcT%ȱ}aLIy(+HjjHȭey}C|.s^EvK8>%86Ʀ\ỉ;BaLs.R^E$MZ0fY^̣i�1f^y!R^xOo A`;"0"rA8ۅQć&)A~.?? iLEAaػ sJՈWOθW11$5" i!1tL?-01pA} k߲ tK*WoG-WGEӫ(ƹrd>$;oM8ak#ae9){KƍM@Y{yAmYSd $5&@]&tAA7,V8N E"oH7n$IٹLBXY7"5-<UE̋Zcf(8yKlA�>-$F:A >[{|fQ&Zb@5KZe T 8X,ȥzb$ ׆̍l=$Q xR']=TއXEhifC!83@\FlsZH:SJ+i>\jsza {) q8ʡ:ESrVF]}و@_jdonII^h{dONPڂ8x*IÛ\*{&TH\G ScӂqU)atʹP6ha/^k^Ÿ9YoJXn Xq&#ʢg%-<PNw>c,<~#"Ե�٘'FMn;E.ɧnX5d4yTɾĊ04[?"ȰԔ v Q#UAd[ n*8eATMW;r!5-<>77Ƹ[%>Q@ӂ0mwZ#BbSPIJcا-D%c8gN%<.SR7` "bmԄ&ƽF[cNjgZVh!ɉ Pbgr>qN/R~sG1vkJW]#P%L2)mcjy[6`.EJ v-{ uye~+چu&%q_3nRnƅhk M q*-aaЋHe9#۹uSXdtT( YȠ-]"aM6 4$FMJ#fEvZ6|:YĂ-%j25bc%"ۂ__ ]MɆ=Gp[6{t{6}}(l.rfi6dvr츫b eU`$aZ0H Ǟ}m/ae1E}2͒Fo:jFLh -$*i }gڌ kK[x=^+\,/(\bݯ=!b 0 2`O�)Bba|# GMwŔ(m:E%AFLC]5 Si�D%NtSb$:Eخ9Ŧ`!V#)d bw#۪Q-f Z$g^HcM qHVtjJՎ箨ğTkIkx+D;-tq,B5IW5}`X%D1/?FlkXxÚFKL/Ni.ڿz2f7.6%HSK8z!]NWY4o6`Xu=%% CVf` (1|j8Q+8ɥܰ7Qsa.jT姅Ģ暒Ix8 (/a/m9d(<&&ꔈ:N-r1{0˕Xu LBM8DF솇mH jwn ;g OBnMJN.ʆ *).R4SH.25Nԗ-s B9}Hx?<ҩQ~CRttDp źsŸE!Νŀ@E6 5{h>4J׊z=)'KΟ LɅ["HЄ؏.8q.`])W׶0W8Z kK[x׸@RqGF[/l�v,dİ} g1KiW1CvzbJ4/`G)0"#5!.&KxW.f k4́" RH"B'$'m ?Gۢ|b.=JBVi@P Fu5W^a#a\|of0X ~QW}¨)(l%ax҃Tjp`ѱlk~!X#%(e`Mѹ!qh!1P)Jx2'x.}Ҙ~k=E_ 9 _~2XB];\y3 <>g<"Uc�_KxYH\G0MKU!b?b fZK6KvN]"K>}(^3b$N#2"_,PPŋ.5*j\L U5aJ iax>6Uf^H#8^dWL �;R]kéе-bj(C3-~)DA-5-<}0%Ǟa }M'%1{y`z-$f{ŽTǮB k߲~x%]{ռWb<dkArix3q%̞i!Tk}~ҋԐi9"TvC؅ubSKGm+} ?ְqǟbby>@'dsSdMɂ񩬭EpsdUt,Uç Tف8$sفb"=29r?:NA}ږ??? ]X oB ~A++b6 {< e(niab| DŽK5 }0os״2L]ɦ)a*dtr\1e|FDcC j>1 kK[x\`/)S@ %< 'Z#ł1)ApO !>O9yV-}$I+_8-ܔaX]>/\sybv3 \ Usb{ 5-~FjrBFj#Wh|U#cxӄ1L{!1!,sհAIf4KbAxfuk 7Bq1 7e[l } >\wk b@tuA ~izVƪq`eH|% }#vX^X#8xn+�"2.񀽽*F؈=`9i!ƚSR5-ld,>!W {i q|eHV$!K");s�{roP 񇥜U#kVnD(u,<"6NdḴiihil"ټbRU<kӲ{_`M1T&OFC]5b-ZXRYvi i5MwVb ,(gRW'0X�#5F!Q-$޸@lk!*uհ4.~(qw̓L._V +|cOtT*X@B)9NR(X?n t_cx �O$v;eYn $8YTFJRǪqPMZ0fha lBA3F- q|e`*ߔĔJ.o,Kзl;]#s`jH3Շ&<H"ø`E!,pz"Z:,I&fp-5.;U~ h׮ 3q6߻B8so1#v.y,!7b$툰\JyJעPP+'fERpZg{ R>k o8UReLY YX'.e9cj-n[,,W-)XBRه0֫"5oYx -T#) z#/b +{~iAS_dza {-A|Ol"*`fJw^dw? F!-L % i`T_A Fz) q*.KڸGNSij=5.Ά lA%LE1%{i`]><kE[x==Qzq)}UYdH^Tj%qL\4zP],$=΢-tĉ> ^EطC;Owe"#1^uQ+`>$\j<pU>ְ{:">) 9=DfwVLU}}R$vч-<:u=|})}njJu Re?W1P ;L(d -$i 8>>5-<fFq[%7ΐp;b$bM4NPH=%$:j-g؎wpxX o̔AUԓđ75ֶ xJ" YȲaSmxh4P )%;* 9TdVEeWAD8\Fg`T?hJE[}T(^X^s]yڨ̵Y$\GRz Ǣcij0qUN`!.b i{ZqRpR2xV !ȲbS#k`|tgZN2-te]a kK[x}_YG$N@-`!l5;#V X4R6'ex5JVu&3<J.Ua]pjF`>tLI` <f} nza[x4'6TFtJNUFfńrxrs>d9Ymx$#%qԫҾpA-5-<5 TP %ſ{#\KZl1у@xaD XK`He9eKv]8[%'�mG+8L Yj `Ⱦ A\nΘ <GHta1T/%dWO`kxCӂq [K6m!X1Na5oYxwH' б H,q1-;}ND>qb![xpB8Ga$G@L"U#bAPpBM:q)E-;B^ 2tQX ײΚXRUWBܖqw,a1!NehR<JLl PiTӇHYcgfZH94ڒ{]BCN85-<u{|5S`r3TAm 5Nզ `ohm~ I:}]a鏁EU<}4 '#)f5[H1mJ0O q֐6{ZX 8rXeJpz; \b2Omk(d %;cBc VA8ޛ5Fo֯4RYFPfcwIZwBbMIaTZXy!58b7m QoC 2צ8Ÿ.GS|ʴ20Oq0Wşdt,-ĹA8޳Օ\$<|-6;?2FjOBMeJdsf+SczI q'ȫkUK".< ]Yyp1gt-Zq%mAX})->F- qɮtfMI  P±#b_kP=1#*KDڊ :,AB[Ǧ w/IR#_~EX:J" flH3p/ jظ1:Ҙ~B,?F‰(A09Z0 ֐[Yt؃ϏV7O|0(s :Of{1U2= wȨ(/LP �O;c~+ژ pu#(ٻ5 ,ThÁܶ gSA9nq|Su( nc!" HL ڳCx,G:\,u25&mFT5�33 /&$ؚl3]_Cd6޿  cԨ8(1~W]cg>'lnp$IG l߱+#>KXsE鵱H07%)(r_q٠j8~SX7"O1sksr+N`c npt[B6 ~{p)Ve?MIN)_UzįSVn{KXvFC)9 ƨuJIh`<TkJb3X'X8p6 ֽjK[x+bBVR"9 JՎ?ڸU#(bx 5%L>'/a/m98 )XyYMe_mS s|]$A tvQ^x=zqW[JpeT(2ʰF&a4:Ío9"AFy*d3U936) yS wv)#ғ]o#XxԑN"OTA[5YX h"X r <G1[%Gj,82q u+D  yi!.B">X]>(<غq>cX{Z2&%w5?녵9-$զ$JMU"X x?QMp_J/rFpWUfx~"?5je{Ò[(<摯x.Xs_M9+Cٔ;ƕ77&V(FPł1 %Om!X{#[: <vX0X7J54c[U8+MP1D:f8֐n{IqKPy1^<4 +Մ$ƥ`>yQ¶3}+M ^X#8^*~.nk*NrXGlii}%Em aF- q|q=eb FP= UlB !™\.W+<�y,fğ5-<~S1N`@mv0ϐ% S"tZH,);-t>r֐6(ע5fN R}#CT2^N]̚sscvhA"Zz vvxO'j_schνwj[Oa'J#",>'>L*.nY+]t?5: 7Xe OܞE"d0Ear&Ħ8"]5\ 7AOIܖex#  Cj4Û] @NɉDНd[~DmbTWpwv)o6?: < 7ERX5)ر+Hn{ N7k4dM ƾ?[$o 1]6"5oYx㋣(;+VVcPڰ >S¤QD(+ ڻ bl kI[xEq1@+o b#.ơ{kj-XRԸȀ $a4!e3}(^_cF@*%YȢ-ŤW̴x)xJ:`qְ#9X#1 .;^Wxk UNG_sjp%=- <TM |b<rx?FoԦŠS'(ECip0Wwi&NXNc=qvrOɅ*"Ճ>[Dk4\ЧC/QAf4yK >n".b .K�LƂ16Tl].xQٷ?n3w�JԜ-9X5&Pj 1@BFc`hf4[5㹏}Ή,<^ld,ٛʆL.^+R|"/G0VPq 6 7UX$|PAV]TqN^s#$/rAH ߱Ą53?n,'VlXl=^>QhW5!Ek�_a6`uѿU"ޤ+xĘ\.O R)%!-Ej˴q `Bn$OK7a12SE4NJk<`.%A-lAb-iUCNcGP](J=;w܋6I~] ەbJ*Od0"5oYx+HUFJ"̪X_PXGׁ֨mxwa4F#V8:A-8WQB,EA*VEюY<&U }Ӿ]| c6B1j"Uc%=ç$#,)5Ǿs+1n($s[ZXRqbu.}NC^X#8q' D쾖ŀcٳ+ƪQvȀ\ N<+}X9~Ǣ.k﨩jiDkSPAdB"A NpõtjĊ7YH|:2%03|f S ;ivԃEA ֹ aԸY07u#ama=Vf露ZXYMdKix(kJ"w8*MX/^8a ;)Q1oMX$* U[cж0<fRfj*y1%E1@>6ְ<O uLVɐb'L8qegГ,LS"PN1GQe4KYx+B�:d3Dn)x $RxФf I,;lA|r8~0, OສWذXD림m51*KBb>Oӂ򳏼O/a/m9xd+_:%) 'yd0vj\EO>>?SL ѲxύF*Z1%'~#YOFd.ז8q{:-$3%BĎha/a/m97Ica~}Pݛ_'hj[ƂMo WϴL+Nz죛(8ީgehZ~<cNG0=RZ/bCSTM٧-$'\[ /si#v/&IΤWĂcc:BW@*0J=%4[7Ȩ]+E JmXPQǏTLłOզ&{Zh>c' kK[x_uOI`1 WLwgˆT APƴ&IHG<->Ȩ pЭ;zb$np?%'"k$%ǎj{e:`,T{g'.ʒIB6൐{ Lam9wЎTД%j|Wz(L%TNi}( {n%wZ&c38ށ;ؠ -% Hl?e< Ѹ.4Xه)X}"b,}~He9d A0K5b#zcyD5NiL 3%E\JGq-xGN̲[Er2)"xp€Gl]l8 𶐸=% wBVxjd+$Va{Ij�ec+la"V6q~BbdUKn AʌjCXDEj|վUh(F{'%`E6Աf\&f(e}'SL_@3YfEj߲;{whA5Vڏ:uJScvtDIC1R5 <sƔ\O�/>>K8}llJ%If^i~9ho 'ɫQk"QPAtUX5">U$ﴰ!k)kz!R^xOQ5<VJA޽et֨BM ƻ'-4xza 9iA|--jAodig[c05QnOƂ1XFi[o旽[~{ɽκhެ؋w[1 W`hJvjGΣ5-<CF騖 <JŮp<U_S{2O] l)ِNwOȝsğ5ixk95d0KCgy(k 16LK=8A�} /l< nyzoiT,RRYK.ei51EƉb%ӂq1BJ6L [>1- kK[xMg2':HTsܯoAIBi!1-%jr4ߴ?qX5vS˜w6^ cwZ5x{UJ&1U6>qNN/R^s󸈞d8_ &ylHE81 W(zQ "ZXһd!ز1R@5 <(*qIerdWȬaEay(il!1@ R6�j�.y!M4{GWloE"T6\ &>ƢQil}tWi, ͘Fz) q|a46hLH*Ldj0d).RRFæ5 <Јt;yŚr(=0;8`܏@M)hPdM@ 5?xI(CRRwe ް Hger ۝ <ia#؜>HazMQ|Uis�SU)qEDΊC!H1ԸeH6ŋ$?N{~ΪxU.cՁ/8 Brކ_y^35UYmQ-ma\@)ܕ&.^mj#/1pG&ƟMPct; XLV.+I'R#(kd]4*D#qz00wv)sg m ^ぺ@4(!d:` '|8 ,2(+"5aĉL 5"+NSl!1P`1P(�.?? kIYx`<PpTz_^[/ĬxFP.ł1A:%ˤETA^X^c_/W1-Z ^,iEǵh}`>dSY8A-5oYx㋏yО1%׮J]Uh/UD|r<UF-<]05- ^eM%L^z_ejX %9"׮"UWOߧF㛑rT%vh>6sާHi5[$ 0 :,q'1vr[mcJ:DY%Z(a9T*5eZxx=0%;8yvbjh4 }봐}&$9BB-pȴְ;V5F>*P(qI3QMgphL U+'mϘF*:vwu-`BMc\M LbZ_,O4-$."}$I¡wCL q_%2 qёn6#^H9b:1djt\d{Av nwLŨ]3E+Ax!j$.4)fw[>FחW NIZBwv^X^kD C)a�hi<>0%? X$fJW#d'{ZhXf.s_/>=nDE[v,Jj+GkK[H,wZ8c)}L/m9w|8N6]ES2XCZq|ӻ m6A/hPMZxSQeZ}G|H {) q%xO%-yebĚ6GKa90VLi!-v7 *q.??DjI[xQ^1#>%TDԴ$Vs8T'هJ4BɞP }ְ̥WDH\D^Q=gԸ3<-$6u`J$̆fo> kK[x_Eq9�~Ur.)$ IU2dFYXp%qف*5hm0A(T h`͋ڮ'`ʤ1M.R G&6MQJ"+w}9a ;IQCrXJPΪY-8#&r[5 H:-č`}Ns'#,Dv"ъأ%9OoN-|դle8ְpnc(S1TLDGs2ͳۮ8=ۯEXO[v}]K֊,{qJ)X8E/y+}`<NHXudɉ8l_;+aڪ!m9/xD~QUf #}g^> i *LIlBAuuA  <GUaSq ѝLc/"L3R9Ti0Z0FDA p@U]G 9r2-<F>J>8Gg`b5 ><Xl؃K#`. oII_BÂnA,Vv.xV9 )96r"nGc%-p-w@O~ u >sA|MUkQYrRZH iƘ($pZHrڴp6' x\C:L&kUQ5)aѩ1h(yJx]dnl:aZ83R¢`P)DdvT q}( Ugm8Id!jFvGQ4eZx`P$/p8+!)0 ٢m 0sJ"Tp~98>H.s_|,?{Fz)i,h.:,,YjLVcS%m}|Ґ%Ba 38ޑIdQt%hΈ Ss Ƈꦄ^N/X:NfMQ)Q)"EǢܖ:$ ;--yIְ}'ڔtUʪ:Np8Gunw\Z#?eF4@+.pmkE[x=1nܽF]%bgѡbx#ᘳ@ZJ 8I:3ݾ#zv@ 5 <ڰ1VᲈFRu/kXlp6u¢ .LuB̞ ,JGBTEЅнMe� 89YH>BxCC"ʸ,}#C^X^s_!$o O|HB`? tD-j�~[H\iw}6^ : `ћ}g`uz1 XܻFhabt7 6Ilܓt,<F.w׸T '%Qc0pîQWs 0k ԥcg˒,:[8bP.oYxkeqqZR`ֈyřI`.0V'}R'H)!rcR` hQ|l|΃DjSr51 q'vs)(/Fϔ xK8$ ְ{F,"{]Lx" uO%kk[PLp۶1ѣN9p,']\:Alo'~k<d .#㷵f}+֡K=^sěKR:mYO0N*s_Q"oR%¶2X6#ȔRӂqjA+ԲA# <ONlP$ID=pTpuCdĩYInot調<N;.AFItCGFA0 HH P["^ P;ly͍"i@aC ְW?8PE-uJ 7$'|57JqtrF =:L5(̙@cR!]OaQv1UjJ ɩ}Ÿ`aj4ڦc\x\aU- q|}^]"))S@U)±jk9E*D1ciorJ`dx >s o(=n}\<%)YwqmE-đ@1p45Ͼ0Z_ZPX0"o`G` h AEzGB�D!1eũBx%'$ƽpZ0b۟t±\}^X^s_4 cSwVz1\BEe= qFý?'lnTj9r,<U1i}8N}H5HB<!I~(WZH O/a/m9)D*?-Vd`]t?CƂ}6FbF�BM9)) g6,fQ iWo)UfLΏ QRG84wTÚɠB(I#hS ~>H yxOɎKT2,q5TUbFCi}$l5bաְ?S+JIfЗĕVdHK`@)Ax3=ՔlBUx~o:{]6<x72쁒!*wcI>y?51;@Kٺ4O][#=~G V[MInGvEޝ�Yhgupw- `qa<;5[x:W;q&-^8k"j<#ib=.XșI 좕<MV6?E^U{\: gGvl%"0ǔ3*45:Bӂ1(@Ŵ0c1 ƴ(/a/m9Ly 0-{K2-XshX2]ʢ#wZ0f0X`A-5-<^{Ż>%Sq$ca"@ͯq"7{ZH\Бias7 ޾jK[xN:y6gqn)⁈k>>jԋϔ-$H YE> kK[x}ID,'D$Bt\w=1"}7<DqoVhaIQ5-īFCyp"kxbK0$UE-vxS!7xK B⮢S_52gjfN/^kܹdUΫ=λbS=堡3}X{lLFVV&BU\N,=�iTd8\Lp5`I0 ä+.fsҜ`v( lE5q He55"yYZ*@1{ё"ui/c*xNOxwFJ S†KqҰ2{x#KH0A]'*`1^Xph 0&G힞]R$pbdEXAiIk0nZV81VZL>Ӌ԰߶,ixEQ6S8ѫWu 7&趐(&% %5b̢JQ$ؕOAǢipR)Y˜X "5$eM iDR"Gi !?njcY]Ս c{bkhJ MX*60wQM'a'm1 \IhNڠU<$mD EIj=GY,hR֦s3F- qw/Sy `9#ðfĺnZܑ^dHT^_c9_wUt*7FM*9 8E$f.&Tصδcv-%B[v!ٓ>Bz-QgÁ 4Ll=΢#*1cҊ>5*BbC`6 %B &^^L z9-<{s̛$]"،?<[$8&m`>tvx6Z>g԰{ʕ%Ѣ`1Iӂ er}Շ1zx15oYx hd%F=V. 溱h:VEl)O Q,}~ְ{Sy|^Q,AcYo*8%- ±z0GO5l[,H~jVX>YW'N񎴾8)aTc||k2<uG~ ^H;o-)F"h[L=1IQ3kjQuk>"C ~[֎Ҵ1jO|Vk='܌Y[06={67vpdۉ7ƥiVs{!XT[~l{&,u0$t©Dy HtY]zHe]ťZxa=>ER E{IxͩJS,6ok,R&f㜟e|[_:^}j?j+;Ұ2;N#vE mVz7d 8&uSoH E<K*K3gĈ(y 9iA_A*^Kf~?'h+'8&5NF7cvD(4dxAR^XCNc7sQ9-z6:n<BnA~N8nӀ!{681׹/Ǘnae5wMKbpSԔuFo|ѱP0񦐩[=4d!> P68 l;V^bJ. ϶kl>Ǚ8֊;yS H -8 }c+/a/m9]"O' fs~b_ޘ͍ Y$[߯{llXhY5]YX%6YD>)96`5\%QqѸ?Ύ ,My7W2)ٹI ;*Lza {i qĭ*R?ߔį<DG{_k1bsc.gca$lSMSs�>xX7$8*)R!('2`DBRkxaAl }з csLĞ鶵r(Ә97N=}MIOlU}=~҇Ha5B(24D�畗8]myaS#.Bb$bIx0-40H>q+/a/m9B;z"[$q Ndq޸*ڴ`>’dLYk+Yya[x?DxP!.2,h_zÊbDyOVE!@G&jl^w.S.c ypCM-ʰSK^#͢bM\ӏ'A%nqeDv67fha PX͟#x(=qJN{koe>1N1Q}}j_X,$."yM†Sqְ-"WSBުȬZ/ q G@MD]ha id B!+Gx+ s; 60 l(,9}L)pۀ1묅)1ip1 L�zq(;3rJ*ztEgܤfllIOe ?i+.laם!ĿqJ"%Xqd1qR/dkDb@=`7ټWr,<UdSD LɈ(TxLuQOM6sE6B@Bi@E_He584ƣH.."e+%eⲗĊُEô`|ꅱH vC.\coZx+[{*q5<X*"՞7Hț yR3p-Y-Ө)D㵲U_ؑuVID }<~^Sa֯m?SS卵/>rNzK,Wi G]ϔ`|\^;X)A'ԑgϴi$<c(_wCҊ6ll'ncPA:E1u(FYN /QJM+a+-9x/No5fʮkY<I3ǡ5K0vM 3Z:jw<0G- y|.W4[ӥU?~VqPV%$MaC֔IeA Ǵ^l ?ǖ*jFq%4ozN"!+H'i%(T(u V&zbwup-4eoT⮮#X'o|;ׅIxgum56i6/EǫBc Dv<h.x3q<#'/&dk% 0 0~/@']6#^?"զh1),+%\M6~p\&#?ImʔPi9l%%񕗈Ԉ<Fa ;GX4wc |a%֕RB0%KgRFT0:??i9nIxVlvPMQ x㦾 Br/H/~1wL{Ӵf%ԉQLJZ@86:pcT؈WPѠ)!1UJorZǮr qH xN뤯Ꝕ-"7d#"{+G{q2\CƠ RKLɨi9l%<-H\@i%|;7V]5GX&ꔘ'¸+%$*a߅ҙٔ D)}W|bvJ0BXR1wYa[ZmƗtğKDF0V;%b@p H 1”{ұ:1} ]}!3F xK."Q0OdR\"n}D`rX8 &GQS IHL1”`%A|H+đVJk_ $ǐ4B:jNh Ů/Ws`Uf=GONES8>Ix+e*X~JPcIml%Pyy{c65VX9 `LJ'׹SBE1d9nIx XՍLm1He*>?po ҉% f~-*??sF XeSxUQw`tcxW&;A58yI {& ⟁u"+a+-9 L߀ܓh߄ g-jS8NhAhm?Κ N�4Wß S4',JKzvÍ尘ذY�Cj@ʾ( Oxne9l%<gUqoRTn]Ȋ{L#yG XU&ez1B!y`-9c#\tl4Yˢb^%e'=RZXDelzUp S" #:#yBx:ɟG _ڧx`~sLoߏƤ%ϖIiHoQC%{sq$wq5%S7Qg6u,qJVZscF|ȡX-0q;Kcñ#5zL5H\U_:)6!"hj 0У߇ Fl{<?hPMa&vVkcEM`�e/K>n+Q$ FO¥?:&):ePk "P 6-S>y4TѐkIQJC]h@$ǁ[): 5Sxa"9nIx/yO ,N],fǠߺ%$~dM9xŝkq氕l $U]']ʃz&f2%x(s`R:Cb+9aZaiI|UA}} ~WX\f%F$(N !);zrL r,:c0<8w`\W N #Z\kh4X!J<_8P@9<~h/ 0?.GQ9fO.([# ɱ_PD臚jJ@gcrL#!-`Wý7{\x5qhS}&w.שGI0ϤVL S1^òb:g" _D#;\8 ^)a@,I?uCV#<؛b)Bv„:Ɩ3sژ֕Cq})`ã]"P{Ҳ|n<|1}ľddo vXu9Αb} ql=vȒcG?)P5[Jk;0<G]ww)-)~FUV:/ϝ}5"ޮ88%SG0]UJ}A#l9l%<^~G\.H_Fmw5Js_̖ڔiHK0a$PY&uTWI+̑vKs_5\յBν3ězMixA*~:Är8'L1@Zs _ӃqJ) f]Hu5ϔ]}C}wS0Ug*ɖplh҈Ֆ7]Z_(W3b _&�Z8T=2%$VZ4H Rv V10<} Y! XBBܤ(0ss5G3$SgN^,Y@bE a҈Ւ]Tt5)̅ڝMghNarJ I:HB2ª艗氕s"Q 0$(9ěAF7E:)!#-1yTEI9Y@�iXM.qa2%$.:o$ߔ ƒ*+a+-9/):T ܔ+ƌS1rf$X:0”M (!J2u)+1<BnX0</-iME5p|$ IsܯJdHZ1u|~&%B$l pV٠m?'>:|5.~W 蔂 ÌQ[Qe o E6%8O&8J0h9l%ǩ% s ӫAiӱAb;ƾpܻu !SFCԩc̏mG?*Pp<Bm FH< J/ üSR(dqA8sF xks߄{ j4A䋼'=_ y)?)gw <ڧ`)+΢v_Ar ; ]\r- U_!k,R0U|~¦.aM&L*!ɑVKcogꅻ~ä\<x6F '&G.)!1u`(N}pThύi8JIx㫴 8Y(kR]n\EM(ץ͜$SFRX�.udi$<UtX9'߅r5--E a ]u1, 1U`(f ZlHő=8llf.2Vd߅لy[i4-Fg;j+:ZBbLJ̙1g:H+%5C 1Lg(@Fbq@h,H0K3=%0B sJKxo?z%agyJ\ Q5;N TTN Yu*+!#-1):ow~v񪤡??<^*/ 0 QPȗ]dts(~k(x.^^k0F<ꥃ8D]$$*HCpXAxTYa[i y| 1za )+_jW=84.1F MA>FSBbPFS<Ў|~K8^#{Sc_X{.6Mh@0);{L o@'6׌l}8і{ 0 D|Ry*oRG0m,xyr'BOӪµkPն|ξsxbwLJT K{ݤ~sȼ߲_8\EL7$>.^'CY#1T lH6tz<w y4EciQԤT-!wl"{4n':RM �cl K ̵NNƞ66Zs_h$ [M k6G=3xkS=_، EBM VIJ FEE|V$<^dO$,peSlX|,-qEJHz[R]mC c12 Oe/sXvuVHX\0~0o )[oi9l%<'D@+;ބ:F�L΍3b3NHS1U̟DsP?bY>b_ٮ~Ȉ["bD< =θ+? ɦ3P?EOa~8աMv]Ƥ‡7TlWM7"woھtO(0KǴov 0`Y$,):b9:U A;x6FSMPԤ=UV]`hY~ѹ+ᤠ׍^VsJqxrDUSKhO sJIx}4<I98Sv?X;ULj|Y!5 KUS>qȷH)9p}S4`-T۽@],8X^v3%$nMʉ.Pv8FЊa+-9-iaA+%"k 3RYҁ3L蛕$R!F$m,.5^ue)R_=˲(Fn<A'GC{ "fNkA3}ɑ&o.n|-V߅2j݄*C_0JGu..'}[$SG0e.%Хb氕^fMPvnfH +]Py*]TQaf6Ǝ#J," �i$<'u3̲OcQD<.Wӝ6EuE(:Tw%\-c1T@bZ!R^rj~q}}VǢ@nBQ&;?/h!S rOˁD⪁8<6Ai$&UJZ[>&'j3q!wm.k`LIٹ/J ;3m6ßx?qs۶Rk !v'v0 KA^TsJ0Ej$DϹzx"iErL)5KƲrѯQL9G8$`^¨ĺ+E/qJ0]J5g!ÍN:+<ޥ7%cmtRP# aHk^[~a*b'GD=/:?2P%ȯ S?]R›&)mԊ^F]06W;طe8�s MýS9\Ix~�7grҘrpb4@wq>l R 5 aGsO vsDKxNf]<jJd /oĸLB7UGl%{:BYOШ~bJFhm[ΦWqroJHtŤ} ,Q窋i9l%<UGzGFB9t/{rk=>q{|rۏH0nםyS}}A#l9l%<uRnB] 0b ;WƱI0GXBb=%aeе_ai YW]9"U0 ,XBlfWXceg떄r`˒T@dl?fC{F< tx#(jhY&G8`1%$9yHr63N+H%9Iq0:NX;Lr^K6{2p8qgU)SFeJك<uahY73qqsbR"%2[["&#S[ H0|RG$o7;X19nIx8np!G/MQ ՎqysVÍ)LaS (r05TA&&Kc_w:YGM^%І^/޵4$ #ĵ/ÍLBդZ[`4YS*Wnq)$О!"1wGۮH4j/r킇#̷a+l )߻WhR m䖸R[$CZod==$ǹ Ϗm  k]m1uqs0x'Ȉk \mI{wK`A_]VVZs_P@ƦJ G?¯u?CxGkȚzXpeR8r&e Acɂ(@ɐJב0:P4)WS/~[4Uq9A7)GZBgC50G- y|fXlXu~Jw3H-,܄+v3mu`H g3\]XR2u吉)9ZR  &o.иAyѪ,bގrDIQ름10<?d8*;=m.l#Y!2c`L!J<J! !MdVVZs_䇣$|NJd±7#/֣D^I\Ӌh渟R�Cj@(6)85�~~ zs ]ĶJ 8eĺ8Hx@N S�r? f'd>(k.ok!qQ'e0\SIi zĩ?l0m,' p' -Xevq$ߑ t? S~_йWH ¡&$,9Ʌ׎I`8®j8 3*AS@bW{IJ~K@Ġ15c 氉Xq'^o)q%ݡ,?8Q< Hq>)o/n#đ&Rk_I\N](p{=errH>HgF;nx5Ŕr<'M~}l<i+/CHLDĭ/&w G',."J.ǑHyIxaЊQOJE8Y݄kܘ1(a=V8`LI9:?? qH xN+ڈ;x%aCrƷc\c{8;[t.MZظpb촥VW]Y;ܓVR/Z2peU0p]eiKIb볨�LyI׼_ྮPRt# Ȑ{zxaGX0}ԀD ^c�MHYsxyQ|"MBk޵1!p7zpH}񄔯x kFoR??6 l<&ud~} rj3s@O`ž =>qQѤJ|M il?yFA~Uv[(<}0.$bkFVjz(ABc}%ĉAj`4iW9 Q2QZS",":Wq,JA#& #D JB^:cHYxާ3IǍorAcdxLPCuj8SB,DnpHBVVZs_U[('om# V�t\S:zҏtYrmr8Kx^#Y+P(`quOg79a z@1%@p3HBg9fP&&Zs_6n޺zm2vUK<g** �wX2j<0qQSbBG P!! ыo_[?(yzs`un(?dkMwh%Ȥ nJ;V9U$mi?'u'5s}L<X]9pu, RB|�MD VZs_ h8�$altxDFx_ rcbWJ ΃p^X-GSk< V[c2*h seRZw ̖@ݾZ-|s #ԔN1V#햄<^Odekl?<L5#'TXLj##/UPK }0:+H%9o#O;TT'~ŗ:MmL` /CST N6 i< ^3)'w LH8+@ͱ)!qq);RB;~b:7VZsϟ>#_ы2,h[zt󁒄Rzʥ:V/<ދ$-^oء&a(TL^TV:_n 1f6�cj,J/C 4�`۬)|T5}AcR|#~Ƽ~KSB͵OMרc' F{?Ĉ氕WlXY]]Dp !##ɱXJ00%ve~/H` H˿ (G{(ׇтRk ePMz(d76Z(E(?!I+#햄<޿Z‘ьZکZ}V&WGs\j){&717??sD x;F\T!@d}4p,\W21 vG^ NZ~Qi9d?z/y<R&- x�t)'@ `eTk|n. ??sDKxN$vDIWDmł /hyV9º&C- �eyHP#z=n)_0e@2d xN^(/GƤ<5+oJjE4Dw&2FR@ܿ n$ ~EgZ@~MwsRa7W ĉ򢵾pDH0JʸmN Uy$Ÿ"9deJxAmC&v],s13s$co<5 =K)AZȧ10</Dj d$pR<hZygHM&IfJ0es$l( L+a+-9o&ni8)1bUmݢyqSMcԸJX9\LS".%W/1BV$G- y⵴J9yH�m\qٹU,77 H\IJS}Kd/ f{l'=,U7g0TjwXԀ0MS6RB ,@` ~^#(Hsd}'{@W%VmPwJ0%&K OXe9lem~}Z(eljQˇ{!Fzǥ%Oqzj qWH75*b,+<NMKIjz F"2Ay8eq]֤D|8s εg6')5,A{> /axՆ *}w:b)M)7U�,M$޿!,ܯ@DO}j9:k:]9S%:0BKMgN ֩X9l%<:֮$ˤDI\Di]:qDH0<)=%C sJKxPޔC֤hCBǾi3ز/.�"0(kKp3g<X> VVE1UhY5yt_Uݥy')팚Ҽi9hIxN>6R.Q=L&$#D[BD;n LXEޅ9SBi:c0G- y|%.fJFu姏H?4CN;Tu.PX* ,̐VKs_WUOwpQEx> �xR* =Z? xoUO4UvFצDyѽ^;4#:uJI9TzZfR^x p$Ք\vn*ehCNْtw,0e\e *,,IpCczU4~](aڽFTDc똦LUa9v檦ԁ5(Ĉn氕xRA,6dJc41nb睵irxb*M( xL xL ,&&Zsjd!϶A$JK2u(Wk~sb ^j) b$sHKx8 _3JcNQ_GH0ʼn\)b~ F0<ދcKr2hR̆NEMA+GT0 ԁw唰9:N:c0G- y|bL}\28)Iʂ1+qަԁ y6]Mm[ ]Lm *!+-5/+6ۙa\k0ޛ3!, *{_o*ن)1*??3@^ݨQ%\Pq_c)ֳ%D(jN>,U餜,c GD "LcKzI 6գ xkPPS4XљS eaHK9i6@-xn؄~K}.`S1:c~J0$Km (OU~民ŗ\9FBՃױ؁{.c5]+Dž+`ijV 8MHh I|QD h@فWOGs70b*@/9<i*QZl a -1WN76V?* V_'%CC) I8GR!dl<u_uA .F.BδtGqD1^?!O p[<?Vl= 3Q<ҷ8 8IF$qXItP #'ZB1u+n42<&u(gg'w. yщ}᝔+k N]Tm>67dԠj2py;l<'G9 V ZP2P6u$qt\.3m&5H$(07pe-](b TY(E^Ih Oği9l<&uWkff).dKmr8"y%aQp  %vS0|0U?8d%>mQ<tf Z#"!Ll_jt= 2 2$֎wR#>%@Խ,xGF|jae0 OL aꥦp4|O`[9|mU >jX];"l5G^ě9ՑSi9l%<u?اM~JӋJ` <]q?Wgx$E.H4i1<'>cWQIA}yCvICd1}aw>f(\4)ꔦGZ\G6Þ[:msHJڱ1?pRE!Ӌ?8\$EMJ{Xv.xx{;IA!;a{x<M[ٌcH۳ο E."a+-9 Me{8-6mڊb%9H0Ϥt|zchu~氕(q8UU%fPޮb(ӝޛ@䔐ʵ Aa)!<7L8qҊ䰕W, Kf<RhD˂+M{IP`LXI$2)!-LufC䐕)9邝!ꌥ1%'5DE˘8b1fWs! ,"/t#[V#<58)}Rp"h3bI"mc0cBQf ݎ:) δ_Y,5&đ&Rk_Q3M nTA z59-AX:bDR(!bFxӊH%9w]~ʁyՖw�㭀16%Bِ:2ri9nIxkSQ&<;9"4G-~恲㷕塦�A(L,stE>1`Y`4YSjO;&#Wq|?`3g @KXP<[7MɄmfHc%i맋AEGKW/I7Xq vFa)6+ʮ mʍQdJ0*P22:c0G- y!}.Mǻ3,z GŃqiM|'}J0n^(S:c0G- y|ҠTF5D嶣 nD  /qEq9ܘvCJ2c۫/E(WY˔uD䰰]c7ע$$;)XA"Ya[:cv5*\6yPgs rEqѫt&L>+M0aZxR+/cs?exI{M/ja茥ԀQX: oH ĺ -?b~?)Q"$!-Ѝɱ` O(zTN [:c0<(`z{LAiD-j6Vq-'SqbX:M Ń:u)0<ޯ *jJ۹Q7B}lcűt=;p 0REQg, j1$kceU.1Mëik,V*Y'`LaW6IشYǖk0G- y|-ܻ 9s�'䈳&F$>2'~H9ܘ p+%JiC,$ R&cǎW0 `*,A920:Vc, Ncv sݒǻTCMu¹f@; sN WqGj]$4<;9Kj35ÖYtz'⃝~J6ףˆqt)\#p ԁʔnc8BnJxӭ;{z b*6tζelߔsqoAVqM(q-)2lI.<A{Xmф؍{.P7>upGca8 @ 0!~H=>bEg`h9OۉBǙ�l+nUjpGQ^8V[9E1%Sp2 TvM1BF$,z4 @/OX88<G?g9<NJ NXPe9l<jLs.fcmDTEmfEYe"s(plV SUV#<glU\'Y5 wo@ k| eO\f]Mi0A$.M]fpU1b]$0 061u5' H+ ۱UmߦĦpCnygyFK]T]vlPxai�S)c�MHYs m5\] bBB _/ըd8kLn/BCC6ks _lhG߮s5L(4ؑzƛABu<q3 &{a,쪕<-0-8/b!bJa( tpSf1t$GAۤ)!)&eCq-1uYaR^xqUTguRVѼNj2 㫗] (("3)'vТ?"XaɑvKkE=wsa�jR.e6mZ M' +R맄~ L+a+-9yuT^\(<FQJiF67>(prN ;gRbڦxe8JIxJ?J$T>#!B+'3}xcjPd(:Z@?5~3B;w|5jDcx3x2XTY5%SDV6:\pZa[i yx?9ҥ%1K!_N4DC)!R<IaƔXf)u4bJ+a+-9ȧ޳%뤰j1x{j5pKֺ:ә8ucK](Ѳ%i$<Vn](҅5r!#.# >P"qc((oy(Jxrep sJKxV~1)ӑ9{82XN KQO)xw?I)W^ PIX$B _D8DI܋نG?X1u`(V! {:MyVZsoGqitϔgٹ6hҏgay+<_B@M9^`< hQּAx~X2ܟ99nQE} 10ytTLh_Pn,%oU DAPtI!"9deJxn=/`˩p]#=b7vջ58 %!1u)oߔAV[a^#HV>F~ŏ/G/X+ɸ U0!ڳ÷޽46PxG+r &2`)lV"`dr\0o ~Psp5ucE1x;V%Ù3)WDGt(T.;2b W(#}M B4!} Xe9l<ð�[Fq$pBӀ (6*/][89QS1U`(F4}. =1uq}wl~oRx;U9P%j$*s'`龔_R"zʶ((ҏl>ˌY>DTH7']jprs<KBa# #R`hH%93"SI߆z%[9:_)yl' JoYǑl9nIx}p<8qp.G8ť^u * scI(,f 9- LSc䦎"i8ݔW~;EPwM[߯" )>{I{LҖS1u|~&eL^Hma+a+-9wGߤxW`j3Ī+}sDYe<rϣ[AB@=l?'Ucca4Τk]cMƶr8L }锔c Q/:uXW[i y|yWTv[BOۻvKk]<#eC&% ߔѡ|a>0<(6͹./JmD2xW+Cq >? ec{J>5K#+du](Q:^AXHl7LcR1u|~&Lk X%a+-9"^!J"{~lO<VWʿ,.Ÿ"9deJx} ?2)UcdKeq/XWʍȟPXa8M1:}ZZs _%wF"(P.Ď݄1."ZLuL CE/,`} �Dl6ßx;p[qcRsT7*+Z5s|1)!񦜾4*.ջ`[i y|yU&X"甇S"qar7*z#[_8"@ޑ0`.VÌ-_T!6[XHub%*KZ ~eU1I-r(m TG]l<gSE!rqA%e\v~QC>qUޤtvQJx.??sDIxM1<|%N (*>^ GQS<zm: ޳$[10N.ss)9.3~JWc*geƮ\$qؔ`;+)Y� IhUgh.VVZsFBnBړˆ{Sy*tmÖOpR H $44oT@l9l%<'9fCf6l.h+XΓı XѮf H @~ 氉WeY!HJ&uv u T'qch LC3@tj i4<cEέARJQ-(#zrD"@ps.k&#>a)2!9dbJxNkuD](&ebmTJa3`Lq(6ĺi<VZst_R.^<\K fF ]:tF#d{rME_Ê#B '-#͕ƿxWY(|iWƳ_C*ah7W54۵P=^ Te/ JodCX*oNvσ76Fv#.D'hO TFS*,YƢ鍲ZxJwB3" Ŏajg\kad{cTVX3V T7%쨊0u쪛00$޿a9s%O(<DxXѥzQN@0@E^�:.j4<ZhRNz/*Թ) p cIr0j+%L\=zP?e2GZ) yC֍\Z'E#PSi|ǣ5x=8 YqYl V#햄<;s𤄏y}m;# ߞlD6z9%$E;xJEhg6U( >JpUIש>8'/rqT@q"*{8U [/*[1Oai Y|=9YwD籮=, qD@i܈-ȜCKhP"LB&%Dw} 5ڟٌ.)P: ER!pHKdqDe2IPKf( VZcYdw}~LKk6Q*DxEL7q2L쑑{haQNXB u~Ҋݖ]ToM} ~n=CԐtAa떺2P@b OVA6!m,ׁv^/L hJD1+z\)!dIzTxnuYxPv#)2'䩭1uJA v.&iB Z)+a+-9ّP $6[A\q_`P&l>GVۢ�0m>}י]FWʃ߹;B^ C=�cP@PL Q'&B6$lLY|]G_SYZ? $>ޟU (DYحzn* D&ybW?'M[R8V~f @?`JHuZK|K+đVJkE"R!. |+oqJT�~9dTpftY`h)|otm:'ĮZADDPAy1onB=)W#SBʑ6Ss O`'դ/O £ f?ehlS)CUON#a#%9:8Ъ3\ēThcCQ+ u{r-1RRa'R۽!9h xkӘ oxէBy(+:s\+Y1U`(q8M M5m׋4 x87r,^<F[7ƙ1)\P }O! ^p]7)ANZ ތ:Sʞu9ܸ*}Rw8q_pLʅH @hu&Vp9%L\em d!+-5)L>!4$oaL=Kă#Dh|6% zSq氕YMJNJ䑡&QUMcjgl'= K4M_sd"IG+ OШ{p0)^EyF́ Fl+éI H I9X &%Uh(`-9ؐ^>TnCUCsR"&x~ !h* ֍rDKXfYEe D.�ޘꑯ bk2/RB}fR:Eq氕W'%E'TYLn&A)ARGV 8- ;ӓA'Kz.Ydyx|GƉQAIHL4)!E1Δi7%s9Xr _H/ʛ+�cQSm1*Åm0 Lō{ߕ 2'0X8oIHޱ<AVVJk_^A D[~"l5[1~q\h7%7V㚄N )SH%FFZc_RwBI EP]aw2πm=r`(' Y@<ml 1B&$$ދa^袟Ԕ �lv+FXzX"}a8!i7Z_&%j9F> $O XAil?u>^S=mu6N^ +ׅ`J00eʮ(j40G- y|]I1^߅r.�uqq+q'(=%+1:f0G- y|=,OI9=Jlޫ] cKr' ZB@ǤtSb<:vhM..zM210UŇ-:" ecoKNǢ8F sݒ=kgIaǨ{x75EW1J-5ԡ{~P.)ASǰ&0<35фS ۑGgDFpwy&v5bJ0AaL%1!I+#햄<eeqP.j 1 G+ I@s15`)pKZ@0G<wdI1<U/8E1uS_9% Aia+a+-9Ī鋦 98$�9"0 =¿q  xZ 8~Je']\/iFm@S)@/o' C~*6a w]{rNcV2?gu9ܘ 0@d: 氉'vzF$N>5w'76F?#X�A(50bsp<hZ<g i1<'K緹BcR:[%xBc&ф"xwƤ4N SGsƴcU],u?4f~}a٦gXv, qmJ HXx {j q[i`N9dRzrvIa3= ɥd׶3`㨼׫(SBe}A ǝ0<⽘IXڈ ROUhq䈣qSBbӠ(p⪕~Q!+CV<޷ScǢN4&RB!'ӟۑ8.lW!Q)],c.P[i y|fX߅Pبhr\0.R39r3%S`ۗhCR)5FDވ+ܧ�7lIaṨSmPԈ\B1EsDo2%LoRmm D8mP3x6o;pe pJow|'Ggݔ`  BG4Uai Y~`me\(F$WA0^quV$:b)`%"q-:c0<?d;?XRX,Jɉ3Q׼9vN nEpuCS0~MOⰕ`KUS"VƃF8 tD 0D0ZH0"iBrђܷ[DnL-<*QZjB;O'GG`xB-7v ȎFSsڋL z@fl^܇_ G?x�lIѥDdzECan4Aɾ{L, 2E{ ^,)vY<u]~q$\~r-%MS!+v[s_bDΠPbеeT!;Yc<Y<c`NRRSr dCrdL-~]Ēx]o%ڳMEI ԁW'FHy#]}i9l%<1 3e/*sݑeac``|8nRWS`1\70< \0I#),z KOc^tpgM?R1u`)g i$<~ zi%_9,{9c͔vW&܊Ȕ ˔'ڢ8^2Rx_=_T|cpn); :~$kcX((~ac0qS΅SvlV#톄<t\ h߂[gbcxpXBe'!%Uަa}H:v=L'WϤ(ebGk£}]'=:}+.%!1uҔ3) p7jxj+a+-9o肍52 g.u<?Y.Ƿ^dʰB~0㣪ˢ�0m>O51Y9&v7fl,1‚-@O_cK1&&Zs_#jX+5ՄC.߇_Di3A`bYr6,!1U JNAJdQ?mP3z }#u)1*Nݙ<3ä}q\*cHJ1%(P9ud(sZa[:p*wͤl?8N8@mr ^t6L $1VVZs_#KSuRNzFOԩC} *yV)`:OʎxO�aHY|9NܠWL% z. /m.51ض5%KgR" (!RRѣP:??iErnKx^ݴCKw`;E90[8z)}xS0GRLחj fnXDzbNqb WR$c6B@w53_* i<bElc4)]o'jM+],XpDǶvM )xSuA퍬0G- yTʜredG$0C;K|'{j9Ppǁ[:8Rm?z 馎5?aR*z#Ec!ǕOBh-O`\BS6^qOklM+a+-9?YJBķ0[{X`_LXcaعx"ҤD"P0@:~XT=(щ5xRMV떋1෼ωtɰ#Ex 0 ^E<tX8T4 66ZsˍK[2o{;%ǮŜA۔&GAWSO$ F rݧpa\(Q_]M]!~틗 {hba4]1`Z `7Fp&X.L#M|o::{~PYYBxD# $cQvd]ϭcԶ:#Ww~.N:z#X/ ǖ+^פlh|lr4Wq:dgWl^w o13TS·@n% 0N8! sJKx F=¹9)A: vcY\en51UѠ7g[$KFr2>1!ǗV$<޿Ԗ4)lgtJO8V8Nqwb 3۔mgb$uEőVJkCCO&0) po;zc]I V9*R1U`%j@$J\[~< Nw _UYgCܘN).Є\i,JMyM©CM\M"ݱ4ǽxt`/ jO* `-9`v0CzRBV{:"Y JXX9ܖ`LLT] =SGq]Za[: ]%R7x 3*?3t͏cq9|j)11cJ;ys7o|Pšp-oAm~.Í1aWuu֬+G+ _G* %"?ycӵ;L<8 `rĉp|cK&|,⫮}(lJ9վ7,h7/B EƦ}"ExCV$L y|GwV9۟O KE+24vZciC &2p'8%&'tVVR{> q@,]  vgcX2%o$m#/+,`,_!_wF&Ir2~sgxs+Gӭ%K1ln GG:Ꮱa-9?1h:\ c@k+ۆm$GKBjK@sl+GZ- Y| ;sFa񞅂L,RO/7@ ;ymR")8, E1%&Zs7k ~ʅOeʖ׸l DOƧ/)r~Lxed? <Ohʠ[<XxKS%'lr]`7B,`?Yrђ κ(I92z%<xԏ l T𫋲<K3i}@]M0-΂ +ς EڂnN�Qi0zMÍPnE<^>{!,0e9𕟸oh6) T˜( zcsJ׋an<i1WPSz ; exMl |h̰7XqVJ.S)`|U&/ 2S\x"V Q."5C/GNn,񑒀ȀŽ4U]V4ZՠdJXw]b1 +f䨃g`La )a3:qH%9'Q=;Z6.HBUe􄟼Ǻ\Ejޔ,Ċd< O DuMUV -SƮs0Ge@J0LO5.rq׎f1y,;)j^w$ΌĊ<W*QBCGxMUNwiği9n<uFk"'M[,Cp 8M(ʍFD~Re~J@zW]6}dž4BУ(ޑҔ2Hejb\^'IS6,T]I۠h NnۘRЋm>Fؽ|p4Kh)!*ÎE1<z.q'2en;Vue춪;mutO  sJKx㝲qHʉ1;hWqlbyq؆sJ0a@ )a *x *N>])B\95e1K+j)!j3O/Ҕ0LC搑mP}B) -wEk+8`LDA [B:??iErʔW 7JwR {՝[@׶L9p&A4<Q0U Q|/0W?=z/EJPGlEfxyLGS@bhNB[)`TvON`-18?9xih.{cևAssSPl HI%i$,d Z 搉]CMLdž]۫( ME/G^G_F K>*mrlN-.zQצVѓ¸ uf&Rxlj87@цVPIHHJˆ a1BV$< )4U 疽^JL9MmQ9QÖ ,*K)ơ$t~ҊH%9zrVl #1Į$p j)TAPF6Zs_$0w$._)TVn$$X5JxcGDx\)_92w zuy(+{Fct */-;3E-!r_4- lL /-*އR5 , viphRA§YD2+)Qub%`5qGZ42<&.\슐2kcu&TgW Q-qWVǠ/9%7SB a+a+-9+,&e>bv=U=°OowX O<vM̑VKsg19kw!(!kqohV`"&{|B)&ej^򝦘sYh3IT+)Mg̸.?FBਃ*K<XMP4ha-9ZX3G%3Ť:ǍLb^YtW8V*NN렔5)3R`A#l9l%<-)(B 6^jdξpOŃ3 Aͱp{۬\.~Z(%^� E2X"!ʕ X#̱p8%SgRvf5d2MZ &zs0Rv`j % ]f\;[O0Af| d>#Ƕףu>6eAx1*yq H{㈎M`LI cK=0<ޏ~*W}7z\KǽExL, sgc`�Ih{xh㱕 氉= l8۔Mo'|5G +CDE1U5j SBS!ޢ i<g>S]%Oe%EhziNTe)dh-Sߺ$$B)I }u~H)5GRH"QX  +cqJ0 <&5lc*li##,ޮ?gŧ_C+mN;p ؇gYcjR뱄XJĔmHګы0ʈ7I:jEK fC#cKF"XvI9^ Q*>=Kbl`il<vvstGFx92.pb*'TgRQWI*+ &zs_]1ZH.5M$^͐thQvzdN̋kqw\tlu7pC6Y3m$-)#Y:{dX$?Q` !'%l8 *!N$>#}4NJ{j!w{sz&3DкgѠ4l:N2 S;u&eߛ~7Dϵ|0W:hUzVD @r 4=<zU~Ħhد'�24hZ"a^ysGQHZ zPL`@IXw{QˮY�`TB]9<}eԽ9(Q#&)$o2'e@Cb DEۄ7jM5H PU/Ty<@$`SDŽDjUi:9IHt2g8¦qf4{B%KհC"EtC`2uXAn4eL0_~SL65b!sܾo^y7M3zS "4JJ) ,,1q+: %Ӕ]� “qT$ I%HmḲc'/4(&$ RLTaP@MM# 0Ebࢍ(' d*V8dȡ}~ Q1'6 JGiv8x5 4u6@KNKa9Uy9q|pK,',Z#h^5Jz9 \5h6 &!^<?u�꼀O fZ("(JSMLAVZ^Ԁм<6HnHd I.q3/?c1c0)0:ș7ԗ<F\QsBGU8Ma'>H)mʠ~lN`~ zi~(�YK`D J4P(L !R *lmBc @1�-Z yz9xZ/lML^PwWBI$TMR'qi3Z 4BP R5,dCOz(;F([KP7hβ"&Q'+PRvRԎlեIa1;1!lfisb\�49t)@7`DAѰpo t@Aq2wsZ/'qi.*Q�P@2o.Ҵr'D;G5(&x2BSL$)iNy-xIc!�>⎪OHIpK0Z C%"ϝ qРiҠ�͋B%Kհ'�LcSLN%3M lm�5R"!Ai©,!de6@sҢxjX1 .}( 9K,6m*s@Aj0ڡ LL:qB%GUO!<<SRw QP^`rhnvOmJH(ct9,IJ Y! ̦<;7 h" =Ûwq*2@6QJa9oQa}DGyVaLaGK=aOMx>_Nak 6!7=ta0JI;C,H$WP- q(}\7ɾ_ nSLjjNAf%'LMmF HՠtA=Z@ cg4a*8 xHMo3DiSf,U7dgi(py*XLaIBhW%I>FNi 6h^9 iV1uҳ8eRhN/TBT y<dIO5mhp7A $c颴dtjWOPՠ6Ul DT3QMIעa1h,sʡGJP$b%[(Q[#@I_5VlZ۪~90zb1rp3%YFf"7,Uid ЩAGaG(S3 4BP [4,qLͨ@PmN*E Q!T MMAhA#31i)6Bs*0 [5,qj$ ީe8-ig=gg)A%4P JG 5vMC`6ݜI<g��eJK8}=ЂsDphHv1 J'8(g4 1Q*Z֥Jߢa9ϫ$xu[y.[/?~wו_T|fS>15Hd^Sr du/VO7i#Bs u ٟޮӓ=׏̚^O9˯?nˆVqvmZ/V?~K,؏z,ޤiM/eSy w!}y%<a*?SM8\v_Ο_:p뇜v{aiޚ~DP7췃0+5$B\z|i^;΅rx򶻰ۄ%-% 8Ο?nDe="g>Y6GTҮxefZÏ_+A•8n͇z8Wv~y\] |3ƹ]Lf*Y~ k~]Gz/|IIwvЫ4 >Toz <E )7e.3iX+[:;pJTox;EIQa~;_r\<(r8\EQ :+b4ߕnp|W1BޏOįOuŦv撆6X0M)\.eV"2,F3)TfZHނendstream endobj 321 0 obj << /Filter /FlateDecode /Length 1558 >> stream xW[o6}ׯKj9}ڡ3u|idEwH"i E]nZe+z4iChs%B;ukk.o_IgZ˅V·7͸5v ᰯ=ioU?m֫m:N .H[O|勸Xɝ1q lonc|l^6;gj?y 6V;ounF!Ém=,B~jJse )g$4g$OHPt]H8#M)v_y<x;Lt #RB1-t80 X[M&?F#.F&3%)H4d"̩=i'*%�wȍh㤰GiH _t+%bQX6{X*Y7Eu܆;6IIL2p}% w4Q-t4x&/ϹpîRل Ú(-E^XY x"M@q$F?ϤԬ@4Fvfeb)I*SaHRTjff1+#5O5+#5+ىXѨSӑ29:Tc~+5 Lj< LyT8:lU8p7ǻzʁ}?^b~䵑><:TB׮SrBw%NІ$Nv \ŇI7tp8ӱ-ӱ\}<ZoBJHmH[l- I{s$,;N УJZ7߯!f([m7t@7xn_Wi_%0 }:b)I+өbϧ;i`& &H 5#TPQ)VA* H7Uf.S߰6�@Bɩřo42f7hm ݀9gu%tBiš4PHƤa\HpF(sW $Ӯo8#騥*~F(P3a:ݷwh? 6#SVqF}'FhnfwNR~qZ`'x\C*S_ .Xz(%{w/IƑ?r]%Z3UyQf{$ #. #M6ӈ#]tJ{iͣfW7 Яd߈v?z aPH]?Y舸MYZyn,w8̕-; fc?v>sm\>pxn!1"juUC:W ^I!> 󙒽fo1Fj�s79(>ޯOaU;t�S@$_Bpۻ8Wwv(0ITݽ~C=+Nn'UOak-EIDZcMB"2HZz-#v}$afx), igH;cHDJ_Ģ CaH]堄P%@PFGyM q w1?J endstream endobj 322 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /DecodeParms << /Colors 3 /Columns 961 /Predictor 15 >> /Filter /FlateDecode /Height 708 /Subtype /Image /Width 961 /Length 53134 >> stream x%EϬ ]48"ae`$Ge$(KF T`�0#0 3C0{:u*tu}vWWO;k шs'������(7yGνY\q+V}O|>u]wWc�����ȊKޛ˯L^yvevw �����ȑ?o^7-~{]1������^6w:cfmsG1*�����;O`^0w]tѥ?o����� wVyќwCk>q�����Yq?żC?>������Σs [������8gzCg������k}f덦W-[Pr�����@>߽KV'=UvVw_ym]΋wE͞B����ȟo-l-=gg-~bW {~0*N)۞YۊC_3y.]lk͛7{[mzW`+�����Õe{=-vUW\6yV⬝_+vOzw=췿_g/n7r賯%;.?tҁ@/[l_:ٳ:￟z[Ok�����W|+Gg;S xԇ?[3v|Eᡟ4kw˧w0eԟ?<R̬|YSiz֩Olw)[;ۏ nagzӼuhJy晋/>3ϟ?<ȫvmb~޻͟?5|JIo},;c_3/`fW)M3sؖszu[`B s(vY$e4={`D}Շ~KFE( sZ���W| i]cՕ?-vW.wm+E/{7̹wx~?ikE__qɛ}VLsY`۽-ln_Y_q,i ?xoq0q)0 z)mE͛7H6YvG}Ŵ֦Awy.Gqo}޵kGvrGG_ Y|ڼW)M3cbz[Ea A윘<@ čooϮ&7x@םy 7L/:zjE;ɗ]߻$u���^t#uxUW<#'o6U|GOMo{{\io~g<t 41.sO.>oޛ+ܫN9)no=r7Kw9߼߀WNx3-ayޑgqgyz뭿/z˹# /Yb -Y37{iq17yP7ݺ׳c0ŃSJq|Ţ~{'G(g&ϕ9͓wfsF���V{A{-K+}3-DCgqV]񘏞R6;˧>OHt\xRoWUdpP�q=`![Vׅ;o+z/^e;bʢFۢ)7owmj9˾:iױt1w:kOBZ)s0۫pҦm ?C-銯>kUefnyw=\|0wp'|w\֪AQW G"l򰜻weKVQ.8[qӯ~񊢌-?s)Tj߶WjF[nvUL/*HpQ jy{47]a$���Ȕ˾<ܽpꭷ)VqA{yϟ9?# :.S:o^!ͥ :}?\}_'?ox'~ g[>%ʷV^"ޡ/~}3mEENyđLTʹCιs+Î?=_gsB1CccvVKyWyeMgf^|)\lb1\`΃ro}:5yre-JjSM^v>m^8b~fGlz+F>3Qϰyբџ_K);Wj"lBg-#s0olH+!Z���@v|9o -7^7_ Bgzƹz[*}ʧNxf%LV7޾mU'uW+-J~_~ o;|Jkw4r f)o^9Y:Z%{oK_}OX -}a;ݺe۸佗ly,>WJIrOհأf^L3 UYZHwYbVɷ&/d;ֹƩxIef FKްj}C&m=j዇SF3'}>|8*׬(pCEFB?���ɥ];too/eް;ٛs}6ͬ6*>wq=|V_f*<)VqV8|%7*>n̒A7>+~u*1.+WǕ>k`gf56r>ҵL~ޅoX\b{mteT*c+yk`'Ey!;޲w?_>w[S\闞R_BM$sZkhw:8Xpe_iT.>Zʡ^&ƾϠ5;͖ʱ^c 'h/MљTl{s7$׊���;߱^zI~=e>ïu_|m/Wc*Z,g4*Nb㓎=_`54Ӯr-2/e=^ݾ|]|C;ٙz`M%=ӼyWOIZ<rE\9WjOqE[}C>͏mFu} :d9ݧ8rSrkug:3!Ɂls<wNK>3c< [K+}|ī5rk񯡵>rqIjgyb6KQumNO)sfVkSmRSekYT-,ǹ ]5Xtd92`70<i9qGdf���r w?^m~q.u|I|S*NxüS{ϯ~xMS*n?)pˡGf[ux_]GδW:=\y ʣ4!? .z<?׸+ӊ3YnǂOg~>KhWM뭯8̃yԤ]2WfVm\YW3%l˫/Dm}yeӕ|[ս'qS{Z}XY,vmC]>͌`JXEہեwATefueqUzuG3͜T3L=8֋_���ȍK.߶/~o_\k[7psV{'?uۡU|IGK7<U㊩/y_7Zz\uÕr?Bf}z%d+pJOE_ؙYӖ<w@k]PD-e~*U1\uE_ݒMm>pnt~/KXd w#L3^AGY!���=`&o}J?ҡ^_gy_\ʏi~Fuv?~w{մC__3EϜI(H`:q)f2S}$+/nגw~W%)x|���;}Eӟp *+>}rzEF)˗Ono6Z0K~FƷ ?rK鍭䋎__ݪq^/?Gƺ����s%l^mæwy׾q&};8}{uҮƟ>_~{cV# �����@=\w~Ů oҧj;M_޴X)O}!  ['>j1ʇƍ�������%z½oš/u������#G+������%s?O+.7zx8j�����@.,. ա7U/'������&YߣMt8>@����Gͺfߟ �����}̿,~sR�����Ȍo"С_6wQ^C|諾T]ox{~P|_{gǔb+O/>np/gNL!a5sӟ7<*>p˖Zaz9Ȧ>v:MU-_6ouBIf_o'?Y1d_yrkp&!m��xV|sDCt*ߍ.?ν=n/9q˗\hڟ>zUW{ vk[{|(^)dɛ+~ͮS^([=]9AӧmpCnzᴉF;Yr⩷&ikQʼnj=<m3Ӿ/'-��VY mj+E]u>+j\K>w5TeM-BԤݞ ]S:mNϚakOtZqDz]OVv[F;97zfZՉk��zӞ~P<>es>|O?s;0 |C{8Ʃi;V|U|~%*Qo9PaK{-QNm.{béNȔ?У}#Oغsi\iz+~r>Օ[3{uדnyRf=, >6Eޠ^򸓺]O*hz}`c.2K;RM  9mOѲO{sä=ynb>-M4}'?qu8Kq+n,үkŦgiv\EY=:vnUG8F)č:2sV(m��4ӞBCpt |dUsAWK\|fI+7oW;gI KP*? y}K37مL-Jk7 Vj5uoL#|nooz{y-vVF]ͰJnw=ܞXC9]Q|,vHu++ۭeMTYA '^`gyqgL%mrr@cOӆ9+=pY(ŁF'V9?^O;[׮\rf:<Ӆ7q)wf[ �� UWYᆻMt9+{_̹ wgN}z!ï\Z#u=ߛ6ž)C9l+6}Ԣ\N[Kc9T+pg߇V^cWl`J9ez[} oώ!cu&6z_8.{M #5(pjemdmW/[k]3\ݓu^"wd9mνfqQ?]/C9]+\Q5*{oofgBup4&5��橫<;z5VCG,|ײZv~%ǿn?k}cïci zy|UEЖJc.5mjU~knc+]Q^t!.a].:}ת,"ûo{׭{\E}b=S3D~3;gE|3G{ <msڮVr˻U5>6PWw4qb���h<qׇ:|"ṋRW·S;mt늯ssڞxO}/[!m[8(d͇ 5cmvԺ U+sX_qù?[ZI) ?2QB[]YrG.4w!٥+Tj%gj2uH?5Dog[Bfa@/>Zɋ7["<g9K-ul6b~{Sg=mӺ JoU5j/ԯkv3 ͸jL}��A;Mt8k=?(jkn{tt6/8鞿3tqW6{CVރ.ͥ_?ÿ9=]1ܩLQ,mbϞNvoi: ?1UQ?Wl+|8W=6VN,)7sgD3K-;}Mݕm-,c**i|t T~׷BV,MqZjq'?;j8u_۶UkYuj`}Wxǯ}Q\~gn~lR���M'>&:f?~ơ}Y+/|8Xx{͕g7. 2-{om���U/ wdƊKO�W]C|\I7vhVνdW���zœV~LCxUӷϣ~߾rqm]ع ֳCL^Z[n+���b[;/8􃏴TA������2I+=Phv������dɣ+c[������Yr2Bi������&[\Y�����@ �����@^Xuph�����0 zVu1ph������\C/C����IgU>84������v����������� C_Qu¡����3p:UG˗á����3r>�����2Е@tաRu¡����3tj2WJšá�����rGU684�����x������p諪�����L<~tա8O84�����tC  �����C_]uá����3pT}UW'�����L8S/3C/}G�����`8c/˕^WáK�����OꔊC/:_�����`8}dšVuá����3tTC> �����W:CC�����pk~ph�����0 }:y ������+Vա �����Pu+C :̜9svm����СWu?+C?ݤ7W���W:aC~a84$^9  ��� z*}COC t�l�$gʡN9G8w'84+q)ph�ĂL6�b+Wա  sGAw�Ȗcd~+¡AɞhFb�?.ͻN �q8uޯ~"]wj. �BXn'HǨSӣf{U 'RsPRXs)�Z"l��58*U~߿=M5Evx1i.\;r �!89LGD� +VTW¡A#iDOJ\;r �-> -kR&"�$aOY=PqР "$Ta* �IhPsH6�ɔC?Vr2?\Rq{uECC#qm[ � ў.&T +WWC5Cs;v<S�HOZMy ��M0pU.աoXZq j gŷ��A6E� 'Vq~ǿ¡AO : = Uv�� P^ϧ(�C?SY3}ӲC84$CFAh84�iB3ٗrzКC*}Р6q`fNv:4�q3QJx �q88oCu~ P+'F�HK\@`7�dXWqWph%qdnVTWs8_�F\@ǡ@k U_uY1_0$gu6�Yg!�4)ofU D:s$ �$]$qh4h�eЫUzCUu?з8F�1ߕA]aAhC?пW+|׽phΫLr~U  �HЅF|b um�8O:,|=xsy_9/͚37C�b2ӓ} @ z>^8 56Q$l�vhk�d׬:>U%}=phICܡ��dlMU5P?]ǡѦC^пUU^5M\�Dæ>Ii 4# @k zC:/=t貥X{84EtbFt�+2bcqhi�4g?mG^8CKg84IF9- �{J}M|Ah)~:esơoCjK RPS94:�@\AC&^{{wphTiN&.J 4� 6e#J @ 8V֪C � h)7 )ܡѦ~vա ѴF �$DnRl4e7áhCۊC[84HL g#̌�P&ų5tdwh4�3p9Zq=~RSAh�@@rmOAktBFO�Ѫy6h�ƈӡ<5qCNth4�k5,h�h)^Qǯg xKސc6li��@}s9=gB"Z6�L~P{[ߠY"qh�Ι͒B ^㩏W;巾{}I#phAPFO�ph.Af 8ʏt砕= )XРcN@�BiBWC�aAcY F۾EO�'| ak 4�c ӛAO�N'-*nam:4! XCܑ]B �gnm٦ڶ8Bphg[`|Fжl ͖`sL1u�@*Р �4Qϔ팠ѪC{+�C h�@͡;56њ284�<܉n�`rH)8Yi`A`5��B_",oӡْ�dt&^ �Qǩ\ͰP в0vРLkS!��jX4n�84*5j7>�`&u1ڜ:oD# @РØi�Ȱ\ѡl͖F T��4nڡ# i�L2phyV�x"(:.-[3�84<��>/iߡ /,� 846:�6rcrhѥ�@ t84�  Pt mV~9ѿ5�(C΃\�@M5z\T_ 84<x0<E&SNUw@Р'@BsP&:mn!�+c90 D/71OVoq ,>Bh� < &ܩ]wv @C.84Fҡ~  LuR4Xen(C(�ph|�B0 <*]wh4�AW `&�@y.dttס@*Р{8׶4`E[FGk)  ph=l6,SATL&jt ]^/r׿Z @*Рc6С{ETL,qMF#&,9  ph1\MBQy0‹;ThM^#( ph0NmD.y$h`©TmpH !ph0d Y$Z$*�`#Unԡ\$r�84mOf+LB �u4Zhj̡)3v?:5BJP"[`dqgoQvZȹo sc+J&C S d_mfED͖Bz/uM_D 97ph0Bs9rhy < zC\ӡ'υd,�J94Vו^5tpmZCg�HK0g%fS\3�5C۲OUamfOBsD83]$$.D[P'Fי: MWA>x^D.&3>3UA∴fDjϢ zx%*ڡ.aG&!`T VOC5lvU Axp$h.-.G`rCa>;ʡGQmPƍ�$'Qշɴ>*;tD(m �0`<9N h(1= pNYao`<rhCPCkyWev֜+BHyF;ˉhi[ Ɔ3BSpbS/<BU)hY7*@7$NN!ݏ 49t>}A،瓅O= ۶ KthgDv?ȡ!t)$(>!c'Axj.)*C\(G9:7VOv o}!>)9Z'? @MРAMDg†fӠUL 3bmvElƈI{:x &3]3Có. 4y9` O0}s9Ȳm8G @C*.'4'y& ]CxMniVh?km[ 4"&9Y7T!!{Cph>]Iܛ; s B7T@K&C5%Ql~CƂNYu]T% d,6!kAzϨW# Z3;Ŝ-EfC|�STW-Mܛ%Y>Yn%T�z�+d6 CG� '` ^63J.bs<eMHC# ; &+ڙ`<Zhf phK7Ь@p_OZm:kA4Ƣq-{Aphp`h Rjai +/)Z顑h^޼I94"0!hwjԞf C&Z|ygD 3˂BڜȆM{r[Zs84lO,D]ݏdh�w&%=)gVfLrLjڶ_+ltE纫6C U/ 8t$ yt2VQ)<fC^jJzօڧnWO8g;+MNsmǡ;*x4:8?eʲ\VRbl:̀Ԛl3s BSCc%]th/ M6H:j8sl9h[.:Y٘q>&ԡ[z:tChsH} _VT3P١CA`hgW2%|2| ١BBZZ�x"4kud0dj̡sj:4Y{c�: .y73%HshuY[\V=sf[GC陿AFЂ @ǵ]bZrwZiω��t84ChT&Wm~Un.nbpTjq @ 4,ݎCFtڳo4>i709a6:Z v}n( Tuz4J)qn#�D/fAK_o:Cn#o �NÄHѡw�!;4[6O4�'ZKж{t Q1TArj񥢠1 !84 A}, 49ȡ͜nthO.n:lh`p\Oo{~fKޮ8OU\P8t2&6Fnj. cљl9&ћ:lD,r)E$kԎ�hɘ`Yn 5wh3C�CBԹh�ƈvէ :E'-U\,[|?Y' :%lck݆O4h֡rV vzI"%A=Q3�m^*1\K 3Ȱe?78t2pM&-SQPd{ZH3iW?V+�4GCf\˶ s,7d:v5>j�@hG̓ncyqh4C#fj=Ԟ,(@_IAd9ZvRPytV˶`q?0 11"A :5fӡm.aڙ!fz]=>@33\m|U^ےڒӒ;tKphve"Zi<ԙ9Ilٖ!ϐ`;hNI K_CEFgzOÃ"N.Gt4 C;31"A88.M:kjΟlkؚ{g"YnBlw<у$tf$f0}li=SHվNICKj;zٮ9_DI 6!=SXV1=Z@sh!Äuh2R Y%yz>'0:30Q$XI1W!UCq6* UD2{C@ ph+rTXjB.9[ڪ++ڦтCkg6je :p3 B3C*SYQeU :@7g(#BŦ8rslIy?`8Z`k&#To_-$ˑg�_}nئI\`{j9[Ø֡u �fPۂ&" a.KXLDς6Jsmvio~Eg&R[ۊg{#^2Ƹ։t8zY=^"Ѥ̈́uA3b-pW)!N_)$Av 9ișe5\lłxNa򠢜qh48Nɹ:W?HǤ?e9tY%�b@NTg<;ϓ6ۊ$M\7Ͷ@[@ƜcԁmWK3?ۦ�` u!]P 5m>j&B.Hq&r:tk R_PCA~M6 AC3Fd u{F0iVbMQ[@Kl窰Մ i;M`+fkU65Ϋu OV|m dSB%NI237[y9A8l7{f{ qzy'͡ͺ. V/k*�:[9@Esd%51[', 9 &=/84}b>-ZNMvA_$w [ZkXw(V1PBw 84Z@ vPM2=rA!fI?C#hTmU<CuDи{,ph_#gAlDaqy<cyL{F!N&Atf7xhlWG]*d֚ Ҷ1ABC2hա.>oy3:.ϖsl&KgSN]l8�5$jhC]`[Tڬ$P�?2w8<hαO :R)ʡ;-ЄDw"4 B_QH:GC#lf!Tw6DxgZh-~OG: Qg5&7g-8Frg]@h�dyGQLYQtB9.*z =m,#aLC{ln[v9[CEd;>-*VFQ XsΕ&]GAg-V13WC7WLl.۰Kvrg8Ȓ.bn%tkn$<_en4*A˗7Wӡ=Zsh t �h3NS (h[q"%`K4ouqSy8!ȹ5t*�z:mn)'b3laPRCᒙ̫ L%ef_ZfܚCScz:t�Lr߾et!ίB l5m�N* О3R8-n9 hΙ7cCgHn;\sh6a'Qg-+4%A%GCO[[T~k{ӡ7msiOF#qZ&[@{3j=VэwMِ [UemVGwwh<8t$EFn{'.&жJ!s0BwNeZvh۰;!n"9F :V�䶷m?l۹1! zƜעiwO #KSmlg4VfM=A$3J 4AV;ͯݶV [hD;MthRn=o9ϮhvB �NБ3$nfB ͞=G9mޡ\A/i.3 ~6|mB5|,?;- Sq5LV;~ֲ;،ChfhC  zIeh:4Fk:4mӤ?YHA(:7ۚ+SU(mY[n\l39,VnO6#4 !#  NSFmj?0OD2LKcޣ:ubBAho)r:-M5+Uw:C}fW tk$g6и,~]Iji=FQy)V=&_YdBVQth 4xt\m00:ݡO@r&ԡSISec70ؙLٱРO]\(,=<[2^5'-Bb-dU [D{@@ϪA\N"쐙0CDjp�x;aI�ƎQT(6OFJ}"cqogG#i'&ѡJӡm۩d2FuD!Р7<q-[7d)ܡ huNyosN<1l0 IОSBk2Bc9vQ84b'AԹX|srYZ&ڧ|B)4KA^h&rB2La,cwh_F!Р7D]B&oCPt7_fa5|f h~(FfSMq@D3M89]$5@xev1 mn qM.\TAܝY;!ALCI„uVFdl&A '66ODsJ9xlư=Wr3Y~ZAĠfD^mϘq7hNS| cj{&Ig Рx&:5fAF3f(Z-Lp;ɾп(K4_94/TJaNCii5݂;2 Gi�[<]KZ+hsh.#nys0qM\< *ίzŰ~^'BB&Bi4.OuV ӧųYrBC-D̙dP _v~+<ut_ k":q  ҒxzF׿4[F=6]Ibs4[9-GC[ V�LC\~3'J[= Z^|Idʯ3@:aN<esJ[it}jb+SsY5j\{ܸtM.h846KN;ڿ<嬋B8dS, |[mLT+%K;6V6ԩ~,lrAoLuW l#3]% &Hi4=CjX@A4YMT(<5:jtVeỹ.F3{ 6DY#>yB8a/=S.p Bg+c2�j?0dI~\P?P lV4;\]qzzmA +EthhC#dRgYltFfϊ+-FM\K\M.h8 u--JN(_=za6ܬ|И+%hPQ?EN]43O]+ٖnQ?Ci)vCϐġ1s<d[@Ojۚivf-/ظz Р(SfEkBA LsvCϐܡ;U\W CFe }<؃p9IК8t*-\,.9FHuίek-Y55ZhphbPffkPfͤYE� ]D5 ۮvAmPq p 94Am›P9OC{fS610M, l@Vu:Ү%aBkcsh 4u�ً֡?.\=QЁB3WXx2Mz^X0^@ esR{ jUuڇF":ñ8W:ѝvIƜ/Ik)9!T[.0Mt!]wpSo̩ I^~׸ӛ;1J: 7(Lɴ3Da.L>[y[S,bO]pSo̩ -r X1}v踻:qhUkq,"μd!la{f6Yѓc{<sx+4ؽJͩeLխ4=a[N}9@'CG8D\[ow֯X?+>Zvlms2[ [M{G ]ICkŒLBٛ ?u:-QPs FE4d&H>I<);-ڬ06BU8ƍ�HДKZV$=K; BTΌj, 3z[ f'Id {ir9iA)u]ԋӯ~B"mlΞ+֡C8[Llж=|_eжdVmիCh*hTN67fҦCn&�sX[CgPQ ;97mAhaаi+*ɪZ#!9 mcseSFR;#)V4F VDuhX٪zfTths"qXYOnlC&0+^:6K CmR@ ߡU/u$_dsz}E\<G񊆚oX]\1r':K\=;2|ǡC;fPB4?IHO2{eM Y9BZ·ny`(/OCg:B1,aCu5_ߠa_ h<';^mB& X0�5a&á)oC 84h~:>|b*6oPal\S=@$f9$<%jmNh�)MFV/lP ̆0 �5C{& =q Ch9>}{{ǡi JO<V'¡AϰY$845]9;4|+FiCn4w"C'R'0-dKrP5ashoD gFvt�zh͡KͶcmW{3G}5i(`N|h:_fT&7CH hGܪC@8{;9PNB-<)nG;7 `r<C}hN7@N`s9l1 mfmiȡ,m~g< >-رNC_{i.?4d#� ^94_\-٢*)ȫC{a B=ks1I8-ݵNCے(5C`تyeP:4yR&"thvYٖMi6OV;CےLfVՈ=FC:?X_Y Ĵs@BZxfy\shu6g�C-.89r7ŧI %~LCL/$Ϡ9t@S%n'A"Ix,0QƃM9v[Y3�}Z`" 1j3LH:1V;g­uEl-<bN@S-D01VIph9:"im:4Qd8[ʙ HJZH6G;RHF}!UO H4Z{Hnk4s?`?VDMvjH FBф94y2 ZX=5Fk90o4JZhGD9h+]z:v0ph{^v[Bh]}=WA*?̻bt 94YtӶ 6\gz€CgQH+g5<5j!Ҿ^ɶh1&)`ς4kGPkm5dk-Qxڳb [PtCM9}Ҭ9M۹ƝGl*ٚ_4S l֧C; +Jǥ̉WZHXEMqFmD0LMvfq'm]Єu7NK&Z+exJF\f*q?lU7zO!T;q֖&!DYw`.id?|u\ BF7VWM薀 Y 0Ԅ84d6j l*+jfwf2~0С)=az\ .M}" a(pyZˡ8>s+aZmReW .GxC-$ᐗ0k?)Qg9tg/uFȸo'6<B;Hܟd7^ kMQڜwq@w< =Eм{$BҴth5:㊍^�~:?ЬVH0 R1sںU[ Bmu 4;PKɦn]Zu4ZiRPЛ9t٢3QHe}$,M]+5ހTX�`9"l~Kh\f:8"la5i%r8zDSj0]�NNQBC 7Zv-쭄9K,dNhkI �R$v6u3Ͽ&8x|@qX7q whRHS偎&]5LXSnvyl&BrF<Ǝq9:ŮȆz1yW' zAPlSԯ(|T?1CSz'Q1II&lkN@\Y%߲Mȃ6 &9f(B5ڞfuhs-F8ڷzzR>}"l 8tYmMmF(BW#ĶL@73-B[mUcmnT|c #q 6<:[Vl͡/&nػ`?h$ÕE4� h_PHCc6">R/vv8[XuD ۼ},'-Γ'll<X{V}ǡɮIlD9bQ[Jby;}س;jM�`Z \FSl,@ /1{Ά=ʡ tNH(fMT6ᩨnGwhMնsz6=Țm$q84HXIg#U|ClcX5gwY;93AAj<3[Jvmkh4 d'kжq!g\uj6p-mCg FčV8g=.76R mMß]EϾԯU}<8Z0*c<mĆB±YT-thYnJ3G+>c8{?:ZBh/"rv>kaPq-`hdW#1{#}dcΤC43ـ,GǦ<[�6ʫQز_)lY(;{< :x}~pvi.UdUԄmhN9E>,۞w9EY 99o^B\x3<'ˆ}P@ڽܜ3mB66+'Ŧ6|%B ph/f4uhWzoPqaSm'do@#`g39(Xp&9$5 l%:(@ 3�A5m`qQ[6Yxr̛+9 2K*6ˌXZ8D,471-ef6$n,Uvà6@cqyg~f:34L3I}1\[fQޮQOG 83rP+4L\5r2r&iDdLB9]^f.yl:Jg‹G<fw)tfqln48ӼdٍX0Er )| ϸZ}.gSҶyהBh0F̈-K Er.k"mm&cX6#;R6A!�JΦĔNU[sEM ! -C$׀"O+cT!|.;~4~7+2ljܙ7uPk0٤[%ۄfe9:Giqje Eױ[gCs 8:&I۾eg6mq5h0vT3c#.ۜOQ8}z3Sy ,m :khm!ġ_f^W&Ma{;h7[|1gVS}*yf^j+OVKKqێql.8ƃbs;C@GC_+?Iשt9(pcCԺ[1GBY m:k, c6_i;Z+jKؐs9ȸ$Zlж9Jfe=C>ReH̖4IꍽqQlOP՘Rd9I C6?8Bl9\rCwAq{o{2Uoe͌5ao*84+ݲұeܡF<ZNl\iA˚50j$̈2YZho{!CgyhcGjVQ%+SBvr~tL.K((*dlfڷb뫭)>F[CgPw٣ñã> o9h aD17N7)diX_qhus ?M5">#\폧$-8!h,;4ǎ?=a!k؏;L|˰ɕATmgQKKT}1ʬm�']q\}fuֿqU:( Nl#q/itQ!sNiT4O94/WM&�UW<hRS[kh��+'Pha rj%rR0K"r%ilDt[(:+{##P9fB:2f# r|Z^)�er'g$5!K+æyAG2^DNSuvhrhG ]vR72 C+}BTAM'&ԡshx62imCA]T8-ٛ�9巆6eLEȕ> c+ʫ?\ODm9\|T.TfeT".bB]Wu\6 p�\|*䁻LblP@N nyE%uhoAq;�8aBVT]Ц˘(^v"wNMXm6$ƆRt$@!jq*YU~e~c },&12H9 94q}suꜶesδ rh Zؘ%{!ChMEMfC լ4sCӡhJ�"j˖l3P+%)vh"\2kLCo3;d͆yl К}Oqs$ж :/UƼKIAsخJV6\Dώ(9L0ɕnRnBu.bkhsh4fLCm67v -EF;{k2Djc#9)Pr|I !;4:y)T:ڌʃTd #Ho�g ձ6Zp!-Ρ2w \];qDŽh6@ܴߡ/$L -`9 4>o<{mF@iU^Tm~0+9+;�O.br ng[ imܗ^qG waZߙjB>DVLkfJǡz%S? ��iC;/&ڹTDEz) i-}HǭKؠg?Ėu2<OMB]模ZEV6e>A"rjJ*z�v)J6Agy<Ѷ)>hsb8ڜ̟ F\Ahl(âaJ4j 9T 8:t&qh1CNyF ZrJ9`8]%d@Q+.!3'1MjY"ڲtvتjs"t>8L]h~ v$'\thǡ+טg.v!EhWlyh[-BObw+V(|\C{aGvt(H;hQz٘=Ay7@N H!Ŏ$W^`Fsks92=7Jph.6�dB5Ws/ڲF)u \i<ڟej#>IU`qD?r][ҵTdHlj,'qA.k,rlQ7�NDt^pHϦJ +9!r#a!K-TN<�Pe ܡˢhX޶q-k”P�L,&/Ŵf bОQjvg6 ayFV>B7"�Y!ktT-fxq0yy!l#uBganyC盌B"HOM!H!W."4ڽjy@Z'<f Bnf&66 6Z[͹I:. Zk7Ê>e䆞mm$uF{huz�< O!D=n oݓ8th"-RB1fclZxP;�']uhi)渞ir݄&L`Hi;N毅@f_JJrhozvCCvhR\῍|k >jaGuݢq5d{- DžϞ4Mk"m;4#D2_ qK>l%3`m4a{6E6ah(<MY6�I3UYYV{q YBr7w6 ɕm¡#JXQloӴ'a'J- T&whOۆȯb @LC+e٦"5쮴֓=PtZ [)< OwwY6$劢C$F3\ g߲imfe*cm�K'£kyJIVΜmPwŰnL,wwlԳD QQ®&Z B]aҘm8nAoC Nn96tYb Bw%ݐC��!{4qQ6MACTZ9C6kn#b �]uTRm%dQFcӡOú �d�msXm, !жɠNJX'�3vh'9{C;&]lf|۲c'C?C@hY˕Rx;6̰.Q`.بC^VI+J zF:Oih.RO0X($PtV!;vN݈vLT(C5)e!JMr>[n<J$;4_I_4>]A薟=mǜ^uJ:mV3,A+ǡ=fI@C Fa,gu Î d'h}:K̲F~Y-ю hJw '?Yu�ԡ~־J㿭h3ΑI5dpc|Lӄœf"K&!#Yղd!D1�6u+6.f_$RڜǴp` ȁ}2guhJ>K9n!'Ɇ-84cb�9XҠ3 r[ KJjkm3 Ey2ĖahbAjnL)ټ-)ϟ`C d ^VM%!BLH͢h{�ȂrC3MĿe#rɦCJ�:tZm͍8#qx:dAY[@n_);-�! \aϲ=t, �ao hq=$M0E3 CXM-N>Kn{ גzCrY�J':͡ 1GyT1EB4j?m`π aDQC$I\Z-n˵*&547MJ,aA�UOHٝp,J`6g@hϓ9$2]v{>fC ; 2r�&N:4FPb6ZhDx-X (r#hFЕ⟮̸0[Wv<\Zafg �@vh_=0%d߅DcOvȍ :2 K}mK aUdէ}~,< �ltա Z~dۇFSKhl:g@0RH] !85thQ6ɦ<T�L:Oz+fFq/(i?C{&3-7gD0UxY=mLn6� ,B Cz >O„D p{q8$Hi3YOLhum!�][O͍MewHyZ&| d#f2g!fi\<ph�|C#n-&14-]2;g8L2V[BǺ# ?Kͬh2Zq 8t<V&q[~%ج4AiBy2!$ B;#Ͷ`0pڒ ?cZY sY�@ :\9ؓȣ)t="Yl{ asLt Υ1G'T4LOȮr`mY��8t$Mc5 ďEaGIN&|=$zׅzyC{ )3ҠT7 @px34YG^؍e'Wԑ wD'?ĝp$E mK䐄Uel�?px2Z,=sm6O!6`A}6C/heJ'ҙr8F|s̶�PTmZ%)dc+k|M7+ter;9~ -ǧ63&{p7�D�Nx5uhrJl8cAairu?hS-U? <y\icM7^T%۠H:=BܾF"ʶe!WlyGV]rLC܉$OuhilW\@o`U޴rC )l-u6SS g√n'"CHr`)B3`Fm s0vF܋khWYԁ=ĸ@d;Znqi4Ոa 7;6jY 3W=/Fӎ %Υ|2Aзj\~PZ-7vA`@dK''YƨA9AѺOQV}%f%wη:>'e˙EMi{x;_a`6C:I;)ݜY~y_naiʰAyי|vinduE&t؆`s$b9y[kf9c[ 3�fkCe{bŌ4 r8S'm$<6l)<ބ,3BYxۙ)>Kլ.ˁtjcjDWK#ME%ߐI7z꬝diA{2-CJ-tHrTT?0n(ZiZiY]i,%B#"-PRl\<6 C-7pa\avun:SHjEmxlƞяM W0`ɁTgZ*n!;9c?2ڃǃrm]Juh.xs-ڜ&)mRhNR/ Um!l*}N12�0.c!Ľ{N]؉YgŹT[d&oMUiٔ.GcklG3 EU,?0<c[S�zI(z·5tmGr- LMoEeo^43UR9}ɼF=Ο^#{Βf_3{/ s>ȡ)[ 7d~¡#I_jfm>bewURUUknVd,+`s_ɼ d;;IVeAI\{֣޳}~ӵ g-p`*h ܢsZʄ~mʄ;7nm 4^|xq:t4 8Ϫs_C0r¡iHjj` da>} #Ρ< rf9Օ'hûK-Q8<b! /#IHu#Z5ƞ)!uD%҉3FvY8)Xb氵 :0+alB} á;CgX&L!^&=MVK*ZU>57t̄CѨChV('!r]5p WdtN4F%W8>RVc NV>~!t7=g]9-HI:,3#ɜ.gм' ll$̙l "Nc]i4t 33AV3ܼ9^\ml;&jp`؉XKt(:6%GyPیdzl던Q=' ]iJW3ּ TԧOtHC<�pvI{:tN¡#H) fϭ`e%mI)Z_u:֕k}':f^oo{t}�C$.AVvs6gD drLZT#8S5ͤ{j 'Eg$Glum?M:=Rѹ&npx7A)W'.V++X^]'iUnsnm-eX.ReZ'%j(C_"OM;"2w K:ڪtHKGZ/ܩ'yƦ퇅5ΜQ Ɯ,Y(7'؞4@εJT;ÖAQAhgH/i)_e2`bw`n@>3Б̯V-,3Bx2 eDR>({_T B> LL>{㜑s;)4q#z).Y@j!%ks|_[<-fO-<YY�Zzd2g"h ١pP;l뢂a"ŭ}N(_G:zR]Ajgϙ)ہcD'f+tZ&s7¡_ 244hGly?L.d,mкdod{q${h| JTf^zS D3{Sz JPR d 'YQP}vTm<](w~9OÖϪ Q*;9"O.Oa]7 )p<nb6䜫(p^ Ck˲Ӂr6-V}@C\T^JŤL[@9Дe7 n֛կlFϏuN9߃~fsH,1¡))ap_Tqhۥ j2i;s(#cYch6>yl fo`U朓{t^8ڙ#$r}:F̚guL4OB4OCP3[-湺r-)"_1k2bmm:B7422s2C*!,? p�cdVM *'!]0").{&^k[sDKd"MdB׌@OkrĝGySnWh(ZKpIt+RJA gQ>{IԾ}O#.Bn"yKWV=]7*�P&8:{-y!oQG81ʩr=*Cw>όNuC&W}?@9Nt(Ak>(D3o)L۵C :ګf>Wg+f>xa[82Сt^?,9in ՠT|H~'r @7P<+jia/l.sx,]s:tf' ~uΝ>&M &0yY+:Kimu:xeqzqx8"0X9Rk<#s6[w@7^e(!:f~ַ݀jYbW0}n1?sP4jz' *p .'/&P0<=_ps~ wYeP� 7%xtfٟjXZ,-#sӞ7Xk!sock:` ="Y~oAYyc ^ "<F#ݹfpJ.\TD5  kZݴv32ҊjĺtdE7s*Eo9UG_e�3W~5^Nau%Z s z12ϖg:t'MťG';ye ,s89oJ0huh.F8H/̶ݞСA3]4)f�hq?qmD|sfpr�7poqoe;)3\|( Ų/ F}ǰ$<ݛOTTXy',Cnm7fۧ#Сcx+";̖Ji67=V[^t.E"Q5դ>V+s7Y..�8o`\T qtgbI{nە|:(KZS ν1}t-z9ӡoũ/{Ls"#aiaz:7s,r={aNFM٧+1 ~tQA9rsN@P 0Б";sh]/?3' Pm@?R^~UU/~DD0.i?Z󂭓tʻYСbKXV8DIȀ^C}0q N!Quh|';|zXagO̰tD/# Y!N$x\L ق 49h m^lҡ�|@쮢.G~ڛ{+ɕ^p ߬y%V KIAq7U0'a9wh3] 5Ms&z{ t#^" 뎻"i;kZ+m O.t= bm?khқjc  :bWY��mp':\MoV{ߍL{:K= ̒󊌆ߡw_fءhU ɑ \m+cZ.ʇQǽ#GCA董4fzw92�yzC0A֥!ԛ٭Q=Mob5}[f#%nB\E/l*/? ș%[-sTv@Ǚơ)9SZ69YСNI78"׻;6Cb79^Tr&5̚=Şߚ7Ny_5` 7Df`wf$ '%^0y8K{}Ns:tSƩe<j W\˟ E:h�O/yqix#quÏ_ùVo]R~b}aͥsJnU5h[ t8hJRBг~fJ\Ni<p#UոY-vqQ/<=%{8Oͅ?yQQ}Ns:twqseҍ\ [p} E- s7&֗ylt^ z|W =+shqZj:/ze`,i(0~Sv9@nc0*CڜAkj#nŚE{wb(ZϟNy2zfn9n H˗.o? yHpp/q;xM/vKjt1u Ey[55(qJCL{֫kJw۳ʚp`^CT  Th=M[-Z cZ\oZ/gmsC?ΛGЩ$:啶jMW;4�i zWЀ>I,k;๿c7N9)z& 2>ϼ :t<R^Şj6 Z `b7CNС``( t_ܤzf^By-~4:_o83-92`|S-h^"50-6p_1Fo?_hNmP(,G;ֿ:t}P[6p)cv;jhpo0b0 lTu^*y)(g?GMͿ_~өU78 Бi:𠐭AhW Ϸ :r Bw;HȹUEhׇC^ߐhV�/45CfxX9\}ģ8׌͋W/TjG wyW�xAwL=$L)X=uCBuǰء7I8"TV[6`ctlO!_^+\tu.G>e -/,Gjz#?[m h:Z6`wC2'J~u: NƢ}Gu G` 8(_V<S(*MtJFx䀘Zqm'C/!o BGPM\6 y);:k ~Wҏ8|cyJH3s/Rq@^x,;L9}�50` ?A�z2Z Gq$(i8TC:G:8Ojx^\ƔF թu9Rl[Gr DnZbՒ'bHW9:]nSС'e tkh6KqtHQQ3j/�MR37!φ1xF{XvHd'0�83!{͛V{$yQt{gCtiq}K\pG?C9.#`\;KD*pXA(O'^Vpjdߦ5<4ؤ8+>DM@-@q1 NMn/V7#8q-_gi^)B3Bq|&LVw+tӜ/:pȫ7x0!w`{]cG:Asa#9{{η MH^+m%&#%L�Y #ͨn݊ĵAK+mU|=uItcymήm_:>'6åxa<=23:"-~ ^jzmuk0vI4=Ư[Uj3Aq "9Z$Xn*yюPMp*lVlO6^~ b]F2`#,4miq T7gzS[/ΗZ yСGq[U܌F٢6qs<ԡY4'KWK88Kxȶu}js@UF|:"T<wHvł#y'!p{~*M�p͝ZGzb^h4rm)R:Hta6r}^ rٛN�nrPԙS�. , -9_2s yv~'M�nwh8w5W,O qp7mb˝1�\|`9X0[@s3AMT#̀`l.GĪ_p)lo4ޏ 4Sv+\/SKhL= ]Q6h6}&N-֯n>5a]6Wn#tւ\`?1)Oz f94<61 Xa.Gܰ}]COvvhJKZ-p2Nv3QDp /&nr4aV8t^ +űv*GV~ߙN{v Zkp0zG^ O߿oh0gwAoX!bdn~ѝrmLZ>yCNKSutINqhW3ȞtLx`J׭kM1�x9]߼CO:H0S"^=}뵆,j)7`X�[/hDxEVcmˑ{=R`"/̳?  Dcb;th:t\Z8ma9;j#7Ai]�]£ѽXS>=eĤjk4֚ŝ$o�7N`&6D^7pH`NѪ޳pp Nġ1D] H׼%s8ԡ/:SL*9 0'hƭuhSKU N$y?ޛv;vz2XR;"<~RHZrϡ N Eѭ lr9_"mo{;Y;Wz<Qa ^'-`�v"P-'Kc:t~Б٫).̀NS\:aQ_Ӕ'lRLY;ȻM$. VS$EQ? -/h.+AϞӷoZ]#f}z?4ihE#w~͟/|jy"ȱFkAG$L!|KX:WOa;n#=*+b8gw];^ϱ̀V7BSdmj]B;+ rhF~23*/?9},oUv_Pzuo.HtɼjfQ-k#)8dusu,Ҟwx"ќr6qX5xT =/XUjzY|OFyGVk´mAeWjXkO #C%'8@WC& cVrE\v nCrǒ L`wבqssV ^θE6Mɉĕ!:m<)->^|QCƏ/ ̟;}%&:N:'<ߢxGMMn܅St߬=�N,=Rdhfw[xsM2€lru4A^^,<SX﹈Ha:aIv 'Xʉ5q,/paNq,[}"R{Km^k޹�GD)MAW+x|^,!Meߺ#a76xfv?[e5 ڔK :/eyt(:mbFmG4h5tϱi&7O~zkxHHcp풚MAۭL0qFYgM`.VGuOA3Plt;th29mh[/<F& ^}NF5xnx#d9ᑩ)"_?Zhs([U<ܩvhq:Tub(zt28?w-ߡ.�qk#a#tOD\gN' ՙh@;\|2eШZQu ^Ltxڱ^֬a f/>J񽽀Dt]/':ںyQxG$CvT;WXN$(;njY"so P'(|o 46x@u$=ޤP'suZ̩yк =¡S Htwlz?dxyH7ON0ġhVqӫ^Cs9b.I^OnBy1&dF&.N-S:4i 3x8XԆyZA&r<z,zY>Z=hGQ3;N`3~ 8h3m@4ګ:̆H~o.i|&!J]M EOСK�SoԪh:x㷴vh;~jT]NBds[ϯ iL5G17iEmɻ�IMy~AуyӷF#B&Y:tQ;;_@_hwlC7i~=@"#O:t>m3ys"HJ|*\T=a$(FݠCw2ˡEE'b?MD{utl| o>Mm&.xP0,<i~C;/:&/X^$/CQ/0_bX[y_h5A&%i rlJ/L$Xd*Kڌ6Fc iG_7=M>հAu(sѧ3BAWtfHNSgѭGF:4 0`onNe[ѸzjX}ۦEեJu0E:M9-R'<̝sHjĔv~ĈM~hM 6P6sGFPW߮0>Xh*U|' 4Q<5F^%! z5mJI񹬪FA3СII NOmSMr9dܡG64w%/ XB&MiNvC\oCSx:GcX%/&?C}eQc&w`ߐoAhv"*Px dc yiqqC#Eju.XHg\˪2]՚\JKкEפ/EGW䫭x $>, ~)|<nF8]mZ&բ& ~),e�&J�qj0T6\*@sPSQ&xg7^TN}/,۵f6th<adECg3@&&+d}wYPԌƦs@޿(zH5zVAM[tC;*Csgt +jQ4>>գ:۰=żOLWVs00 ^!|:贎s7?ͦspFYqx >+}U=F^E0 6hyzzьlt7.:(ӧܡ5UZɦXdb͸r0E`~h ~Xì 4їA/MΩ^ܸC utN/F"}Yw(`$riAr9Ck.P+ڥ3vai/_<ZM/{"ŜO]#;ER[5h{)z'^DZn], BÍSСLQ]I575 */uo!oc@^y/nA۳8λ 27v2ރ6wJnEqh=)ן-MtO(:~ ;C~S*(;9¡ly&A_*ɳ6'T{ESqzӕԟt\ӡWuU'K({vO07d38IC3"MdF"UѢ$N )uPfHTrK I X=\qk,.$H#[gPUGLӗC?L$,@p[oZZ] <9POpiSvq@_,U^ BWܽ>D˯^!%kbDQ8d{#ulC}:^~'M38y=r"&>SO#wL8ӖD 橧sk,ޡn̵痷؉d_) .ِizСwYޫEۍ šjֆSEtN+ 3XN-o޼"Ā.6 )C[HGў|_oO}:<bҭw)ZOq fö"q!Mxi8Iɟ$̸@sAK%ԔN1,p;5,a?M'qIMD6%~ߚt;+0UWXE,'h3.ʯh9r +Sk\8.j`f_^&qIzZq%(rL\nd ɚ+ran 廅CV�@ˁm+CRn92E p F^q`he'DSsAh3 X>J^<wQtO޹gq^q[ǡC ߖA9|ޛ=ٰIz$|F=: )cSza͈7L67xflXl}v蛏8 6Cuw}sk:2&@:gd&i+%s7!킓/h=>,dRțKǭ0Vtf~5 kyfW,:\ `,tXbpM}^hAlnLk+luɗM4"#mk!|YN]HY]}FZongɻ#}l `+,t蛸ml=b#A }^:fm'Z ZsKl2p}ݮ62ĉ_O\b%l^BS}O惥me�Bie>f,\ [gOg,֤@#�MtD%wx i6QUi<6n\ň\~t;7x%Jl}*jzy\Ѧ=6S!u&9<}} S!S[9w.9!k|כHp.חC߄9^1eoݿn9cisx=R`\c( cBrhH[gSfKG}и먦DbUC웄? & 5i Qh:.҆Gn ?lvO9t0۲ /28167+R.pqGZG]T=},]Y# wB<0k[N5sv=ւ˽EL0]VWJ #.T\fMA^NoT4M ?o:3Uq tׇڂ=ƸGa-qlH/ƕ9o$cVsCNI ?ٰ0/Vd.dzСն<羡-i;gW%@]!$d:҅phJ\ܹXa^ С:CM&,#{iaiIhrRBj9W,] /=(xy@z|:cx}rL kf=p }7${֡/R=e7xLfSPun'fBsy+Bs?ss=JP@(ȅ\utD\>SξzA޳V˪R/ o9Y%8{0yDug 57/6Y W4@::D=`:׆`cc^s J?B4Mq_@l>,Om$(w>s�Yw%;4S<m^zl jfD|93!ɿiЦIL_?HNxCtСwⴓf]o; vusK$ /|[+5Axu8t8UpZha%ݪ/Z:Gޔ6=oF䉫6F8M.ٜ /פxU]W;Ko6n#MM;С 8%- oH/M[$a^G9WD)2 CdgY+/aIeyƋTuh<OizS,Œ[ےȃСT6δdۼhV}aYmM^;9]!};\DW %uh>5Fl^ z/"YZ>yK%< YߦKT=@$Ω3Kvh/,KIwrqdw4s| BދHUYoUK4_Ka:#h4d͐tfێOȞ�5Ǔys}h4510[Ę:x|}�ٌm- ?ѱ{ ‘o(~>\nlH1Hk CWY%wMg _ qHC:.v |9GЯ_s &am}dg3F0^$nznLqu+CGx0;M~tw =WJ|,њ6Ά=fP]HI :d3d@_@ӝ-z_8QAZ\C~㗰=+=X*Ahyl҄`-urӭ"UpXV=7 _.L䚺 f=+t\|ItíLڡO uMֺ-jL2/ j R$$x6fCKB:xM0_ h~k(NFA~9WA)"nE 4z _Uիnb!<zF7^`̹lMֻO:rpȄM;Pt#\};\YQ}(@+D=A-<8~oZC4BIkQݰ)U'Z:Z~Bym{yk/C~(D!.EVCAh4aӬEf\7šesZa#r֙oNfo=R[!Mqys}h%|"نV@gA�y61ʡ8vo 'r zF&8?`F:ryirbMs(&gp7`\s_MNtC~:KZZO,~СAh ;k[[L ˌPDag04 ̡*K5<_19[i՞E2t-0[n/$zCkLx-0@f'v[ 𤰌3'Um"Ah)�I^ug ECfyС%OZ]okNN+Co). f\ߚ_O ſ~rvsvى^yPW3r"y7+įkvns?  3ơo| r3Mh @ZZxNsV!]\iɄvif{ K LR"-~ Yϧd>'9?ު? z_pW e]\"#VUlvlZb]KCw )9r?X\:٢ʁs)q֟Qf89'_)P?zw"p t;I-n:t-C CΤQRC{JmsI%s*v8\H =9Y?i}<1Ahs(|&. 3fwjz!;;4p.]y^8S%HZhVT[z fզC]75#Цyy tNġb]=X!X7r@%~b8W^E<Vlz֬뎸>DB4꺜{ p[It1s^X/9qjW4DnТ|^3Sw!nגC{wph|C 9(~G58t֋CGE9Nundn~؞Cc7 ^hƬ@r.9-gSk"MQC:�5)-Y}́z=}X<g:tхtŊ3yAhs(]{%ءWaZڜ RJqh3텥9C|ešh'}*5C{S?6!~C}ס (ƍH�}} /E;^=ТZpY7HD}$f{|DRK'ݼU�Rw`9wf?ICC!bq.#gA&9@"mG[^weUPEXj GC9ϻ~C>&]}p܆7: ٰ|0r73Mк*5C!oа3ȜgZ[K8+:8j毖 tS ;@�Bv(nͲy;J7Gx'6-x:ax qul[ǣwh[S_uL[.dZ/%RB`@D'roMKJn~[܆ \WQGC &}:ICumʓlEСC7qZ-6)?nxCt[!7,j޷且ˮ͸]_^luT޼} XC.V)_H)VdF%gZwnp:tG_5[6u@7D F}:mjoB3X ௯룧K8)[[sВ94΀ 4ph{[ZٯaZ6ѡiy{d/V`N Së-i:!JUYЀ;CoJ<`wb_Wg]:;D4 ՋYBfފ-~X8* Smt&.uA;hOAޔ`_^ BȻ/:^9D4ݡ!tա;`7Xkl\k B{+螫D\G#Сw$̈D2 ';4hS+F6^SYt1goސ2"ޱV[ 4)o5^Ym l#f!~FDK/I P2;r.b'UB-[ޭ ~R ̀tt=0 3xO|}Mtk)490 f~we3}7"4(Q. JЛb,awMyF'"xqZEpC?& 7 )i}]s OK*5#0H"Ӟw;u#t 0GUZqh:Ü֦-˷3)=¡�9tD g\X;u?n`-CS19. V+ʎ3"@=oUEIu*mОzvܡ#]f٬ׁk̩֔>8& `Mrt?#m" =whFR>#J w$~fZTom`whf 8AhmSF;ڳ~Z)Dv$H^o"\|: q@ ТorC9Џ _yC6Me}.-<\B}UVnI<�ϱۭXwD Amq>SHVC>bkC7&m^`{D�ȹvVw@:3'(|>l '.kWe|e󚘑 s\}jС# ޼g>lXqڜ:X}`th~g"X10nPոq!-0P4t+jzvzȃ8tÈAC|`5_~Tu羿Ccy"b1"ߦŹ痾j1 V{CUZw(?6_}tX6ɧC7_VDݼb>x3Ղ7�}Rpֹo+кo~$eg<+~Ϭn5B1b ;=0hix{Cvh72oͻ3;D|]w 9>]}Ba_|j@5A`Ț7zHwh/G Ē# C> /.+_9Wuj;4nvg)3MF kfV x9bݼ8t5"#<{HM}f75R\selis?BeC{`QD0(Iպnx:@ -ʡ͸⑀C f:4:fi-ff@Oӡn8})9R!^au+v>VLa`?¡Ul$@bv#@>Т޲m$yz݌dP5;a]yo$H灪2f\z_<8"{CK qO#BB~Z/0Z`Tinyʼnz;ធ{@˰CG< jPȸOh'D97áoysޜm bS ќ{C}qh=W)yqzY"uC*@<v]UJmh5g ?C8]Xq袅yܡywM*hpAHtӁU6\`!a5o'NW)nv܉9s['q=|"5D`)d)ӏ<vVQK8t!@~ MOTs &uhlʀZSqǜV<<1֑ѿf$'؃;X!ާEs :;FZZC7y-)Dj8K�b9cTjm*^)`SbOy)v88tQrH&aa2d/+.ɷ^!^2<gZ8MFpg~MHs}E <E5[tmo| vh}fw,2/:�Mʡ\O>1ŦX&8V%?;y`E>Mu7qc|@^7h 8w։ :-ZT<ΡS|O>.zS9̙b 9J䵙!j`ʊ^MfM:!GRTk28 y : zS-*}0ҞjЃ- @.@-\yCd͑S0g!ʒm"-a?<1ˡ y:1ȼ j"AA=uz8V~5G˚dL�$xhϟkVd&%A 7&-cmCvr<kiz#9g689(/e7ٌInm#,<>rKD{,wӒ79R5q`H`gAK CsU<NCzYg$+yŚb4=qv ǍCv�ǣ4}evVhקC#C<ΗD{Z2Zqv;^ya?"6+ʡbA.G5Wk4 <(}ZBsio?B %㱡CAJu 5b?SbzZ{ZOnZOsd>|ଅ-ӡ`үɡ :GZs9|'%ܧ :2$Jv j5ČFpĎulE#Бy5tܡ!F3`sBE4Ҷnmk9꺼 ˄OYz.fk=lR[QBX;~z(/ =WyFl(#ջ`z)СHu (>z3yܭ61ѡ+Q 9Bhi*D9x1}T%$4 7l"�0Czn5'ҭ>m<ѥ`C{S8SN$N`ws/д޳-ꃷ :G9hyCӡPB5¡ߛ+."sL9x+} t"5eءeo4#B4'i#k7"pB6w27C2c&] LŎht%HyW>_!DCWX~'c>sAN+C6ԟ B^0K,g E9L{!((ՒG[?96y>bL"BZל,9:49`vh=rh<Mb0~FU9wrQcsD&K{`5>@9ռQBy)ݠC$`".N;4͑3NEL5͒/SX+ yr:+? nbMBV@&I.A|D:OȮ:)-Ǚ6J6;f0}NT-�ݚ.sCs?RСɩDLblhrP!<QZ 'mqouyȻS"bՄ6w.Vsϡ%UpB4thr*thHcf C~;KA `qqs,mf�&DU :-<~`;lC!Dtti0ȡ#]~ġ#C%k6PO3_+ơ:(CwXMȫ{r"wB&x t^ Q4yB)S ۸w(l@K}e@"~2 |s9 ǀ46x m9:5# ZNyтy_fK׳ rU)lA視Lvhh:4MH?&rHɳGZ+~\{ϙUȜ nہ9n4Bܡ"p@KCnAh%=7rc:߉@9j;I~e.ߝVMǛ&VnЄtCyՁCG^Wz(WYף:׬!5af='�q WbB&_�7A :7C}jEFC_W)/B>U\I С a7Zٛ s9♻K}kء[a8j-rc�^N?2!C>KR8t"Wf9@#2Fm<\&2šqsC#PΧ!dthB9Hʚi5ڡm#r.qՋ;אMH38taUE+9}seCKvA;.H1u-_rh C&Nm3#BFТzJs[/!<n0H_E&shF.oġď2L.=y;thB!AA k]MCLw,j4WB`Թ ŸC:ЄI:JrM42s9<;>n۾(c.SCbs|�*ȡρRMH;4+B^szH(4:m x;௿.{Aܡ%M&B&9@F^C$!?vs:T,wKh shy=l B`(5?#;M ͹W  HSHd9y}CIMR4ۦ 1o|̂MHGEE:īZ3LGؿth9 4ު�qh2v;|&ЄD١#-§;8)i<E>�E1Fp>wjh +a޹,r账О0thBܜs4س,.>}6;t[r5z:4!!BG}j(Hb fa$8 'G4f,^-H<5V }L孹ڡͩW:těqЄСGaj$)NVحTuCKLɞjtt;4XNtЄ9C Co81>/'ߥ?DܡDrn4j՘x]5F6bЄԹ-%c0֮s9D}Gv:CWCOr‡ :78{X B' >SX] Y694X}"9}١r‡ :7$rtOB/8nNjguС]@{4O` ^^"GٌW+KF^N :z):4XS'@6vyAk* 9t<-~w:ΏRrCo=id* $:tqik>NЄ ngdq4W nU%sCͣDZ("Zg5@m6P!7C&qCL!Ah,C绝"WGqaQHqlr|CV"3!t> Ke8KhЄ nsYf |sm޳%pT5.dMg͡w;7L}&;@&G)@2#m&Qvh(bD^c3Кa.SMCCb`Ky3f9dc32D|@5hܡ_),ʏ=cqЄP?<� xF//ߝ r9BSכDRo΃A莝nj- ЄUyġ%𞿉;ʷ >x2NCw t!xOzr'thB `Kwq_N5wMC{%u&A&֡spd|R|MB~ĉWO/͆b'r'M  ¨3:4!?xrOTARXa0N <>C:4!?x4EfEu&X^lqYS^mB6`^; >-nh=N)7O{LqhF>En;4:n--!Єl1>r'c+"Sg{5h'7DnLqx_BjЄlG4:}%#%LoW#9C*! T�:4!A&`CyzIlqhY65u[OǁZT'qĕ*hBM>0qF[?S(Cf9-9^dYGSthB΂MqDO"AhlX??WOT%+GG|4ޑ-M&YЄ<G^=Q}qZCsSo%-=ϝDn"M8h d)Hڇ>N^&dYQ :4!;'~Gٿ6ۏ_JJ~ЄlM+}dCϛ89 =С :4!#U8C<cCx!>TlE&d+ЄlM9ly'] fLw\yr:[HY3ew.|LSԣ`|35#[ݡ:4!J3thorɮ*!uF&dCЄl H0W#-|:2BDҁuZBC&dSVu%OQȔEBth2Nɥ儐EС ٔjZrD{ȡi9!dthBvdYt8Eo:0Gh苫5-g$dthBvdF2iQHthB^�M3h^Xqh' nq&`]b.!C&dSpHC?ⅻ@$=rBZ;BB6MT8ZwCGuѡɡ4եw0GDGCrEӦ^̇NK̝M/!h-thB:bMCs~̅MkCry..~{wQ?Єl :�M-~#΁MC&Є@uK(.:49&r&ЄA<� .x\\2 ythB 'Yڔ1w+䮐@&eС 9 {iu}nI:4!;C&%ēw_W9.κ¡)dthB'uC Є:4!!a[o+GFā9ECT:tЄ:4!o{z.Gաuѡ:&С ?S8ס́9:4!oMȷ0gbCi r thB Si9=![A&+&c%)YС y1thB>84X{lObA&[ 4!MWxG.wC&+B:49&rzЄ|>wh2!KCzЄCxrth-'yXu :4!$dC?lKС !'A&27r UFuVZBM9:4:4!߄M9>G|:4!SF&ЄcnQA̚CrthB1xn9hrthBM9EYL(Єr ^xoE_@#Cr thBEF)$@&Є3 9vXW 9 :4! C CXX 9:4! "/9CB~L?N:4!dk8M CCBr"thBȾ0DG�'[9:4!d_;0韐CB܄B6MNsB:4!�8M!d+ЄB!A&B! :4!B!mС !BiM!BHthB!BڠCB!B!6ЄB!A&B! :4!B!mС !BiM!BHthB!BڠCB!B!6ЄB!A&B! :4!B!mС !BiM!BHthB!BڠCB!B!6ЄB!A&B! :4!B!mС !BiM!BHthB!Bڨ8?M!B_CB!M!BHthB!BڠCB!B!6ˡ<]B!BwhB!BH +εendstream endobj 323 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 336 >> stream xcd`ab`dddu 21H3a!#,[bnnw}O=F19(3=DA#YS\GR17(391O7$#57QOL-Tа())///K-/JQ(,PJ-N-*KMQp+QKMU�9RD8)槤1000201012q{%g>?Duyt%us/>}h9ǟIYurls{m^]ca^3<{)~'Nc_u[|><<f20��*saendstream endobj 324 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 422 >> stream xcd`ab`dddwu04�1H3a!�VY~'Y|<<,~ }=I19(3=DA#YS\GR17(391O7$#57QOL-Tа())///K-/JQ(,PJ-N-*KMQp+QKMU8SB9)槤1000V00D2012,Sv1.q]9͘9qҽn]]mEݑ={ycgvOn+u..,K ~^U-þwτ%G;wb0gd73cMa[swMk\=nilc'-b>s$lyx{x�6Pendstream endobj 325 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 335 >> stream xcd`ab`dddu 21H3a!cO=VY~'Y|<<,k$={�3#cnas~AeQfzFFcnjQfrbobIFjnb ZRaQRR`_^^[_nPYZZTW�rp-(-I-ROI-c```4d`b`bdd Ӧ{i۷g~9+;\3wwsTa[}?9 rlt'݇(odW잶Jt9M\;i:v'r\,y8Ly2�tendstream endobj 326 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 433 >> stream xcd`ab`ddds4H3a!s?VY~'Y|<<,+~ }O=^19(3=DA#YS\GR17(391O7$#57QOL-Tа())///K-/JQ(,PJ-N-*KMQp+QKMU�RL:)槤1000 &FF-?:~4!=1+ZQ:nެL0}ĥkKwXvwn= UJ꺫8vؒUU]r%-.:e;uC'$>Cnߺ'8_~EGvs]VۘZ(RИVWiӾ/d8}=Sn9.yx�lendstream endobj 327 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3605 >> stream x]WytSum'(t*70>#S ";mii4i=ߛfO4MJ7J+":(30g3񽧿.~m=͢Ȧܾp+V|<.NߗBo욷Z\RɿP-9-6-[?_Mege=rmsSKFlssul߲eQkUT/ hP%W,/oTUmZ}ocEBOmS;"j'UHvSǩJjBNKYfξSvǢy9egDЧwϯk9 ݋~JF-!q2 .M9ۗOyɢgis!{dʊ,*C"*VhgdIutlt,O打K.^nW $m;ڋLr~Wi:諁SAp K#] C_XZncX3˲f臜wUeg%7r}<vcIînJ,]u4N5 24Rȥ8"i<p&  "99 ᭖ *ҫH<?)\,Ե5�ţV g-X&hIS>/Mt;~%v=aVˁNJTԜC\_9 %#O'Rm?ǍR2-L/͌g}q/IKrG½Aa$ g7{+~^ko05*xOFSXlbJkUx՞%dZ~0լhfFGF\\׷ZF7ZSAIa+ԇ Ö >Nfnȥ-umst y}pФ9u]G=䳾taހ+I5yӹCyUILiO#?xN脹ډx[@|:ο;7kV&6cGxPPO~wʵ5MЃVhNlD6њ;}} )ҡ/fqY{L+Ze`U倗VkEW+[UfCLŸ`q~ĉn1BCѨjn,1a88:mws]]-ϺГ+w+wB *"bFV[I RFS⇾}y闦rK?N� їG : \\0<ZBz;5hSvҬk W*QƏDCS@*p8%7[Tj70C] TkDUe5SB >۟$~szHݽcb7L}SZ2 ;m-f$|%@(EÞT|tnaF9 `ػ>3oq6zx^Wl1:@Zk,4?v}4yp 6f1i7M",'°~Yaٯ'wK,?>rfaJ Pl`F>8^+42ԐOnrc*ˉ96rNKa7幗¿Yx~ӊ]Mzu#>9WI\^(wv=а0CvW "u+ ?4+F|D&ݒəTf |F 儓f\)o3Gh@$#H52fjϋ?_}DQ.JwPYlF)H<U0p4tsљ]ۨdV0N =NoR<p6(t{UmH&c-ԣWG_هz}Q\xKsœtyzYnE@5<2txҺmdy#<YLџywP�NWF`fR)S76%fPyYo7 d$t[Dq2ō%'=vs>DWji}Žשq DJm"!`';> hw'y/F^Kz VH9x,J!tzbN^_=&gxF|3Awq;zgK&~b 8w1-y%Fhr70F 94GG²sqUJcD̷MM(86|EbV3g)КڥoI0da; Rh'ez?Ouތ7B#su) ;W೮z~.\NYURS0ͯ ި:ÐW!;=<뇷0⯭@_(p෗ܺc@#QMṹk1sknV]m n*$fL81ed@9rA9JDK�99:8X0{f,R\* J~g(LƋKOe0Gz0<%A ^>cQt0{;%N?AG9rK旤zCi#o4ɪ1W)"];N` [FisZI8C03q*NYc(66+6Y''0{p<x2$ 9#Qe"ҡ"}GBHFs1o'Gvfs+fsZ dézN;s;+f[7Yk>_7n,3#Z $`=bc[H-ޖ lIC7=q^x_} 薆n#%C֪fHtSXi Z!g< pD ϴMc|uM|GP ^O "=|MɕڰaE@8v2 (bpFbfF`2[x-s^tXT!怄ؕ X$S%hhhp&T kl釀|c_NxkK prZ@J[,*\@ =3|jx; 1[)"csJ@ƉF.㣒doz8:[H5Ǚ0qP<ʍK&OL%(qXbS:H">l /~)By[:8Uj[,2 NK["Gu vް!5˶Ni&s3䤞3QӋsUg_(Siq&݌dlgtW,2Ktz+ Ts<89_Š'{;�d cLX`ĐLdl"Cç�ya$/EjװەEm CN=ɋ0.IE!Ò >IW+Z hFB7$z+>um!kS޲ f".p-襅r}3] t0endstream endobj 328 0 obj << /Filter /FlateDecode /Length 1723 >> stream xXߓ6~t߲ J| M}lr&>.V>s>d(Fɕ.-raʎM˯c_d_ HD~690˭.$)WݾYpM?nmWvkҾ^,\<Ϟ^d/2E?sx &%e*7qD3)T6;'5 7B #3 rc>cL?cӚj e-(/Ff(]*b c02C >#eT}psiт@1 OVeA\漠ʀ:#_~ g-u¨d>Ypo)!ttld!dS~NQ ;؁7[=I6c[=A %/̉0S6d�qW bȶ2Qș %d)(`:`!>1\YA[@dA5^(n4U8ao#hš`7Ԃ>I~ђgP;ym 0Cv#T( MAqDq 3zKNRv3 Xf&ל'\/w|q|99kz܅.X|]JI0g7-^K^0hjE)LRdԪE"#&!r$A7A)FPBD*:w]l?%G)^2}t^1upPQSr%OdsDD"4s*oȣ]bLmIv>t�%IDt龧]Ol= 9؝-r0L0.=`=uGs\]J9wm*r07bXmS-x,^p K xOզ-n,d+Hx _`OkZܔuNF:HR >(.Vn'hՕW`W7U[ / )5]|{ u[n_'%!fƿP0( R&m<Zm}Q) I4)ۻŒQ2Ԑ˂4z;X_Q5xm'UOAJ) )~7^G Oa"u05CT]Aqn&|" xVu-#Z|*7FʀD2/r*l˂UVWl/r{o 3f;Ycŋ|S)Pj G><֣VaF(W L(JD+RvGi{٨A7wWE) ǯΐr"l7hx6q= wհvvz-hyD;^>j } ӧeIQ0WW?yaAoM[500⿗-npn\gU]PeS`.@5WaK {v8 oU`J? 8^Lx72km p­Wa D/G22vq("H!P}[Ek],Ǖ,Xea@KYLv㌂R31*ʱ{(+:s󇇃ЗyviI0ĉA-e+˃3T|)p(C *5endstream endobj 329 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1289 >> stream xT}PTUowۗ¼D݇ɇ a`B7,MAbY+Q>Q'è༝Mws=9wνѨq˳Kmy顱,|e6?5MZW zݗN=tů ^.yނ!X Eyl ][ 24;Zh.γdˉŲ;5!Dc-*Lޖ�2%$')$3YAV/"gD!MA.{@S^QWՃq"ԹrAppJ5IăIL1ቅP 2KN.:l# C-jP>029GH "*x5K˖<~|uNI,08@R҄vk޽tZ 0GhRz~hLSm?@2@B9j^�*_չ-Ɩ]͕vÒd DܞseXPV~{,Zx^_M]]gh?b[O)PQGO]+7tp6cܽI2M#ѓcW둺6CS1\-*&YU<(Eǣ^t[L8y+Ww&d|C ]ݣj[5vZ64-3BŁv{ҸRsyblON|k}j=R!w#FEl7z;kn8VH2#LGpHF%쎷&R1.}hډ]ƦΦnz6ʼnnq3 r Jzҁ}}{/> 9Ƽ05c~PN#iYE)4hٱqLUtޅVS! 3^ge, snko|8Z^dh)y"ŸZ:lorr 5¬5"8:-лԐe .mY%P&J5iKǦ&d2I1rdopb#+-nQ`g' Vr֕*Md)DŽ(Y6-2" `˰UdJup੆ubF604Q\؋|AL!<c"Pn@ KDaFEA8fCS C֪8'>S�c4Baaendstream endobj 330 0 obj << /Filter /FlateDecode /Length 14358 >> stream x}[o%¾~:u&L23l`<;>Oёʒʽ~/.LFD`01t./כܔlZn۴Nnks[ߗ}KzM'7ӹoiv כ: 5mno(Pe=W�M мo۶۹҉Buv>弬5-"Nm>ϋv6tԶy_jYk{?W!kuqz^vBYVҺH:Ƕm/F \m6P\K?2."=NC\j%_'Ye5S/Bd=j3~,d-Pk99.`ڠs<W_ϥpP[12BuYB&钉QfP઱W9O%mkA]Iiqu~dcϲVĶqEt]7,:\/۹L:tgu�d!b Ul&sݦy }&Ԅe3o2c[PM:,2%NV][sIBuCM:t"-]$T]U@ԕ&sծd v]ΥUmeSmdMl6ر hu̹R1YhOWl.DDSҽbg)*n*KZ0u[1#�IG�k6Ǵ`ZêRc mP2"tdgZUD6O1_۹>6 վkø߶sfP`ֹ$蛬B[ \T-ő?H6LR"ͫ8`qu?A4tVK6G(mTXA8n: !x y޽sUٔŶWE͜ Ud K;N;>@XZy2yM&cnѾ [|%f=7Q"ު'JL"jJn݁d Ȗ-jo 4qku=7,5es]HqW3AfZE:=4IfbM'ں EuuM'.*ȚyM3PIhq!=|?Ѿ[ڄUH(VP Y&Sd]5YS eB/E(@D5C`\9|* P['TхnMjģlVD#%M]@,h\F_6s36ZGuT2;kJ"CZľpػX-2EE T{l.2~MX=kR s-2MniUYdlTbg@^'SW:Eش@%K\ v0B1M(.Pd*Y$Y5P##ʻBqEoU,b66Yr^;cwd2 vT䫁prZ|i mT6d/\TEHNݨhD: #A]b4i'Kc%hVXi76!~VjsnǪ6WjP] :MMұ %u^\Uvĸ v2lMW(kIGʼPuCQd#]g.ه ^Ѝ3ks˯BMmcЧsAբM eH|Z�\˨&7r9UH|5b5/j]iv!GE늺,]=|1z\@\ʐpRdFn𕦞#\ x^ݖN(8! QM HߓJ*B o0% dQ5[0;:ֶh~n H6^-awt̬*[& -D%}ޞd Юޟ4Ze! Q ,f3%X%o+ *7:N3aeL˞W!njD/"#@Rien(b诠7*,3%uPt;:+�{mzsJLVH́>Ԫ{LyԊ N0m5ú64a7lkmsJ@rRR=6XlWAT]fA SNN3?ؓ{PTTmàrhCY&U_CW,TJ&Ab 59J=%EmiRB ~߄6ZBYBUD1 Q. n/*U)P"DL =uM#xK&\@WaBgC[ ZѰ-4ɩ [|6t(:R3b72!v@|rdԃGT+i)Fh;Q-N)fG찭PӦz[j "֛݊ì6 $zSoTYӀzU :SW?Ic{ g)4TG=%MW"HPJ5 !<ANJ0#P=1-TIQH5 Lep4Tj(*@hgjhך:Y3]=BxѣQHe i,s_ZއbטT.;Z5?X;Ʒ@!#$#(1d˥p :Q"0n@?t I*S(-@g7ѠB \n?uqvMGPIqPzP Ep\ɐ^R%T ee1T\bP$йqwd(. S_;,N�(ĸAa PÊIاB7J؀4nf.C+{VrpĬU%:0@܄LqӐ'ة>I_0j(1-Xf"'WT6m�EwU% IhVSWkęCtJUS 1CXʾ()t|mIQUuJQU ݦzI(咚AxBSG,٬I̴^(C%v# np"l4v�%ܻȕjXm=M0D3p:=B!ɴ:|_'_kyLF(zp;oZKdAj4WڹWY&;d[9KMW&7y(m FvWy#QqDԔ;YI�]Y\JTb&F2=؁剕 OttQjߩ]@}ct#hm3yJ%XCUq߷Uk)8`raEÿ�gX}>3ra^zwo^݅3f-Ul3ϰcqn:ӹ›3y/札A5A4+]ֽGQMuC Mv[xz8w@—VU^d) T{|u t&d[շEpdssUS';_,p͕V"-خAq/nݹ6mLTXj)w;ctxܘLzG"k_LZ@P;ϓW78މgFD4὚>ѥ{8\3c1J@8_H:LU/L0_z"h̵9Jtjεh a@e!dd9̀ %3(((u7p(CO"Ś.sj;Xa=Ew~gB;Ț-n� m ѯ1 :Ba D3c"^7P$~ "Rr:Xꝫ4oz,#mG?QFi1-ܯLǀ9diJ&!Ϋ%Ө#;ͤ,8 XSƘlt8ԕW8ea : +N&ry_u՘g$v p9#.Bٱ<sAJ ZyCY=�(g*4>.7Yyu+[9#Xgn.ΝDg^j wMM`\\e!@ dN3b*5y*'C@(îqkbN0`el6+3TGg�/$x|.yz[jqoS@Lh"VF'R"۫k\L=$%LX}SluZK6KerMq[y<=mP܁'B �J@+OG4ٰ@`U r'^-^d(>:J@N( 35Cr q%|C~C`mD^(o1MHj[Fӄt 暹Gwt4w?Mq7n*=|T;uP*׮C3!ndjZA撺͎3!%DB1J= J&^6D?6eXYvD s0(Z g;�6s IgExUg-gf BbӈT??u=8>U 3!K.r Vj3{Bj4n92nI {m5ҍ,=R#:8S=wYfPk}<P̬@M#n)jK=k�#H7Yu]Y$•KgڟERi>D8C3D4ɵ-$-F2cXۈe}g;ڎ32;M32T懪cL31mF X"k_/\$wxd{ yLڵ5z=xF ޜu#U-WeUZ1 6f*;8w%׍,K Y&fay''}A; (#H;C~z&yFi=|j8Bӓ4ĪFSq:NwU(C(¿ j1[Twᑴ4Xԥy?|u L unk"դ,՗ҥ!t-Cg1֏\}lko=a<AOkV?HXE:dp{@%cd\|ԋәY$3)dt3} 8뱸JКU:b(XGV;{A y |I "h&# "nIBy*!s-Qet y8ʙNc8p-;wC@v!]%Oǯ(_*t8+ه k}|I*"6 G>9;#³0kDR#Rav/^xg˟e&^&M7|IX{/^9W5?<F=ZMSefeV'a(kA_m`ʗ" Jbxχ1@zޮUJaG uH/M Pqfס©p10 cs4irR!+%xB:f!?B!&Rl![T̡F^xLK JQDp{]GěPd8m6C`a|~ɲGPnQ􉊍ۈ-bxs]0^(3 f!BdNC�@uaMFd`8pA4BݨѤXuu`Fx~A:]!˳o*Sz:g_PNaxLJ14YU.,[7+vkR*Ǭ|~Cz(1DEk[;cс/7AB@axZЄ =ի76XUm�4F mzC,_n Á r7Af!) ۤf;Q0-(z# 0dY@ ?cQ~=saYVTw|sC[],z<&e qm ̫`M`¨X|&x]h C 8;{)vG⍣nv3j6,+z4 j)//_d M ^fk*Is 5C,_n  Ñ2gu̯{U_3ά//#S Pc2^Sq%I%©p00l6D gܐ"ٻA9/_YMA4EhRӇx'~we}Vs]fW/Q xriwqq&(m5El`Xudoˠ!nbxLJ17ہxwv kkB ޣ|a �Y^fh5zE'%=|I"6G.k'+qךV)Mget}((9(  K˗ nbxLJ1c4USjQ3�FC#4-L �zqQҢih48,jj\LT\;GDzE:iro�,<> ^.h20L@.x  &w\kr+3J3dAzl$egeEy!iNuhGb>դ}t#d2VDx5 FÊ#D(dlOyke�tzMŵle8Sh,_UO\.EMӋ3k2#gߺD 6@,yloEvp me40  H6Gטw|f1߈xH%\wݘPlh&\2 $4& \?gjg̽^e4<@N0x}\nI7a`X©p0 scE~dMdIHd/7uH`+̶qQLGMgu28 4:#ڐHiC]<%$g։2]ler5]ϻo>o~@1Mjtf/TعU3V0+�daTxbd>gIC8C:ߜ:pHs)p'}ؾת^Iow1OwJbN>|%t;>s5x J-ŖJ?)kFfǺ³&ÐEIB-Se.ZUNu5TGU/ VQf8>;@$c!ʮoH+pT8Dm|sU 2ll&] m uʼn :G,Q"I )4GRnlcO )7a D FPf_bY}T8Dm|su_?j^<߹"r�<Vk|Q{=0=]4@Pm\A>P>Vm|}{ȃvA2mlºlNTJ t²wӒ p*ÑcN<mpqmծu!慣Pqb}sT8Dm|7!(5i y>A12xBog{+z"+4<$8@l,_aJbF.kBK5b`DBcPٜ1XAɆW}V.#C 3U=bw!XgN|K"DYa"b`$~wkS^)S/%D;ܡFrb`08pqRAa8A}g .XRۭ9(8AF 0~ nbxLJ1}8ҵıK{ru<:H5|A@v3ٿZ#r!9jLo Ҏɪȃ5 e|hp̏ < vL}AZPNc8A6fO/.睵\qYL2" CfprD?ȅqf^:̢5f=Yte p`0DY9YttAB@axCF#ezS|߆�90Dَه$T:#d7zY!CtG7=CʚY!΄-e|r:|DD8\gxzwd!evLj{NE~1ηy-&k4 'ۛ#xORN!8`|[O˔S׋IU&3 R_ #`Ȇj4Y*0X&UVAE@݆ȇ1ǀse ۪~ӇY!=NM�˞5LnK L~.<;.ip�0֪m55h*-k1ޯ:їL>Kl9Yì`YȹT:#\dԬa:>R=ٴ5IE^뜿le&f8,_x2e2$!{>W3o;ʀ˞;hob`zp AՆȅODPq@&^粤n}G=[@�;ڀ! &m'&ugD8\(geBI$g 3+쑙:Sߋ^k^4L<Q?)`@3g8cq틬aGg0ea3} s|ʒsL9 184_̚]}![V+;- l(/+fٸ^/vs\~𡏲Q?lBtYya/ t �X{}\N0{rAɈ~IE/>K67#jDb`;yPNc8qCf; m�>vI�#/l7fpW`X-`1 6IC \0Ћv^N1!h/RjU:W\ zL18MMb[VL?~ayy&Qvβ#;Hi'LܴΓ]>}]$Ƌzt~ZB K Q=on&J0n<Tw|éײk{I׊^y]EJI#]'L! /L(#ZSXx9#" GbrX^ĀL:rE©t G>Qxg`jLbL^0V@X*0D}dK/ac%Siq?ѯc_kMiؠ3.&(O?5Ҳa֧�3Nc8qe4u3`pzx3` '+[0q[6yVΰqB݇q12FJꗲax/g?! Qf|Et;g3mml-|OEN<r$:lѷxäof,LB݆@-_Rjg5-λ'j kymbX']y,ZB8TctE g?mȝy lW}D>6`8M Y8ZGze$;3nCe/uBhoEv= ~a*;`9N H6G <È> O_NL5H{j>0xy󳴬)̴p } t#$V?5fgZy/gHB0$1DR>ZQ}I" T:#|Ytk{bMex1{@ev= od@i.X CRVӠ:$etD˄cT%Sfg .xI ښ8WeHΜ@&㘈X/Hqe{M)"Nю.JDѝ0"Cln_:wln52|ǀFGEpjD�rA$~C~ƋQUIMK&1 dͤB`TGwT8Dm|ϤE _~֞^DqB û]OU_>X$t;>)#Q3O%R"[gQGMӛ Y}|I*©t G>iE8~J3kzBsq՟?zdMGyACߙ?:iHFNP|2DN]H�ްHQu Td>YIC8Ln&[+^Kn3[`MfIC݆S ȬxF.6RGΔkQ(AՆZ괬Qd\aTi~,!Vr}Do,Zk}p0-}aC>", " HGpp 4Ƭ/( i6΄h9?eمID[#ig Mu5림]M[ QvC|QS=1X9vNDuhYsvoBfW7AyWWYF?p~u+5v{B{`Czʼn^s~uRaI71AC Sc@FCYj&a<48DPm\ޣU0/Axxߊ�&D` A%a%t;>|7'<<o|dI>"j7L +fyL*©t G>Ͽd8kW<"OdoI3βs&F't#{2ȟ54:gw$/{$~X}bXЁ-ȵG+LؙoG.QH Ǔd9<G.G8TY:sRy6Y?HgedUV GC+kxxV}iZRaAax5<bKb~o9F|,1x(ه&T:#{3FOqyO%K Qsbt'IC8L<j4s/?Ya@"`ZAIC83_dlhѳA)9&(O*0#1T{"|!Jp,g 5ccZ?Y>f}MY혺=':v�)gS3ˊIzhXiBM@EO&R%&ZeD8Of\08~6sڄ˞6h[b`j\sIC݆qLzj Ts,ΤGZka0-!1kҘ}{EAC8Ëґ3[ilis$`/F#tEtmY?TH'Fm#8{;0D~هg'T:#Ƿ#%|фx7eH f Q65LN L><%<p1Pf/7ezo_E7tw?}}TO?|(u9ݗL~No4./*r{{{=XUi'zw=> _Q,+etyd(Š=nt.5Y|@ jpgvtzpDF`>Z#;kW,bW0*vɇLjÐ}'u};=}r{P V2R}LM Gד)Gw Hgn3a`,r _Rc @Jloϥ?9<M> _^-?|\Oň[w_ߔ4i症o-{bƝMU,ዹzz~� s9? ,m�|/711tˌk;FͩOw4R c,Hw{pw?=<yk5,k-)q`)@G-{XNOOm DI o ąOW9<λh"}[U~ĞyޟtlBӵr1M1Pp|* Nϔǫ`dZNZMj[ӇQ7m-(  gSƘXvPܼo:̉F\D,i Trc/2OHgͩ;, ce5FAG9zg*{wVcQ=6\U@1IAd>.2Uߊma5p(-*%G ~?޻rEAX|(*˗_篯_JՀ2v/ouo@Ue~,?}8!:1nznyD><!EB(<vHm]JEaQUr]hńI~9.FF/y?Y$<Ȇo(; f eҠ襞K}.JbAvOuƞ^Ve3]qkzkS2}ˠĞ`Vl5hVpۆ"{{ V2IXa.c%}ܿ}}yrS[F\[dޞL|RKk3ڼBA\q@Y^2SURwٛT4Q}HYlC꽙b[b/,j^XTKvGIa1ii8`KGݬV0UցƍQs=-} .96F IxK[&dh4A 2}%~jN{L `Y `ƺd}޽>?}gBMs^AA (m"/Q]/oNda=>ƗOΙ.uȽTqc (H;.9wgh"jMUm{YG-{_5gf1s8١_xuճϟD(ԟ^~oշ05 (/`J F/pZ޹fg/z9\b5YghIѺ_,9GNw{L-$ɜD~c*o[_?]Bl`S ??ٍ4ha^u/jdǁgWXD%/beF_^[\'(&{V粻,a|Le )�Ԓ^ v(TAoE|0U#AmoNA~V*BU:_8"aOJ~zΖoW޷& ,3$=L&W7sHT *&s*Auȑ2YN(241tw,7jj۠ua=!}僪.v1cv(GOA"4D;??\>0o?c! ű? 8Gϱch#~t10EF å= CJ,jFԟǨI~}0#i^H [_ h}Ũw6\UsB'ddr8 (>S 7G$uѼ->c0s>ؼiGw@}H{x3Y_}o|hq|AXBs>oV� 7\W&0q~(×;qstn/"zC^TME}CsgTbw{=v绯+j[1wh9f"+2jm.dtfu0"|֐+MFS^^oEd-\endstream endobj 331 0 obj << /Filter /FlateDecode /Length 1731 >> stream xXKs4o074J$KP`+< \6%cvTgݒlgwfY($Xԏ~8<K˛ūgsX>]/\rrgYX:,esris \Y>37?}%o/W.ȝVrb[2ē ҂9F9N n<I^3+h@|{ڶ{_5QЬ+Kpv/}MQu盍-vv[$W6wnH,.p vnfHz$_/~:!k&wtcCDW&unh6CU75z-lXs3_H%UM_#53y>vu.gq3w }3]ّc|DR~nNpIf\F@u?#łb& d6/sU^U}LZ¼KPPyɵ5,|` ^ֿL@ʔpT>#U&t3G//hI!s[h 7Sʀ\A5)u3E 1ݹn~ƨlboF|/?EJ+1I<FoL$Sd|XƄRi,{L7spGBOrK;vNJ` +GfS&\!'Ts•) eCOVYQlc_Wwn\6 ^:J&턴g UG;�ڙF䦐0`8'4 2oxamnr=@1N<xBX2w F4UqpmI}\*-f\17;5؝G؟oXHOB$ @Č=T I`ю‘g+hq Vh>DOs#�PS#L]{H$Նp`ڤ4%<HZ %�HNJ4$z.f 6fd-``Qة[!M;#u緁sVv[u;"km+R#'qL3pvbB Q{ ` jerlA@a& n\y۪ iGUî6I(VҔ6Yt�~ !FZ]U5X>0: *x`T&618ȟ dKsF"B3HDtԊZ}.^N@~{KXXDۚ:W6-&]H6Q[M`c8Z؄ʦSe=Rd.A7 SDJ HaI< cB*D<yE+L1!O5L0w> E mƫ`ȭ{^s�+fSVu}V@*[!i:'�0Ӑ50vIe}f㰖ð"j ;V`hm*4!5ZƁ ԡF3mpLA;h3հ h=s%JV hd!DMm? hK{+^)]IsŐ"2|B < -ͳ=[=WhJ^IpBA jB_4@ȴM%:+u±M>1!gmMУ-CIz3#endstream endobj 332 0 obj << /Filter /FlateDecode /Length 2777 >> stream xَ1 yn `/ֻ΁MɓZ1&E;MR-z-D.Rus.n/]Hzf[eW7C.|J'WK񸮗+J\I(Q[ UE҉b{ <,n&>SA˕LXՇ-7:"2N_wx�Ey)hQ]ҿ̀/e$eź Ao1@ t�_vuŔ -v:liWR}}]̙ע+}=W2yfWKѾj$V�' D;{3YG]]_ }$[k޴uG{]˫i'z)*4UҁSxj;FיnfW%E* ȵ_e87XIIZgdQi&.E[^*iGߋ%KVdrR`6S|ο,Wɶvu;<K4?K Exd&W@@<J|Q5U]t`JSIx|uӋcW6<f�.pA#�Blo]+J)t!qۡ:e,%P%`33|v4r rZsy;(cI][gD XEW뢎_jޮ٥3/6]m̸m%6e\Feuf3UbS1PC&5rT+puh \�_v?ܶ6n^d$Flv*) ΈrpA;=#7GQ/&<uhPMAbGSud)!i* X(m@E$s]8Ή?Z^|&"pMՃ#l}I~27-/r0swNerK᷈1fUc8^M,Alciٴ]{!H ݴsoCTTVMA c vՔgGK�n` /eJ~F&+)yND ?aέ7eWoșT :iu4 nDȦC^*B\eѭ$lđGκ`s�\3<yu< ȾOŁm1BD1*@f[40xPP?Ν%$cY8 ڎo;7w4z?C/%27!~+Oi(UpA 1KKܮK><çcОx+,՗&i@%�d, b] GkKBC<,GPăn;1ny8dx~err*:MlrVjWd%6"ij�'ҹjUdi Lҏzmy6pZi; ,] 0Cڮ5 ,xjf`z0-͘䌇qo38gPzF?nROʕƌW=FG'eXĢtJO5e)*yC&}CI[s͒\gtPYפJ LlO`+~dJT7c-DSђ;eDYCTS&Q-eϣ3r\0ҚCEYAȜ{uUϵ�LLX MJ)(E`} �ͼj8mvqóF&vPEHALjMh@J$L+* NFh$4TjX?j.jJ z_0csu9lb40)ĆW܍9BwX`]CGoTQN=lOv?�@DQS'^_/3T v1/?鱾Dai~~ 'Cz)LM+!kJO8SgxL,)vDDd@.<9N-ON n1d¶?,x d&}1q矁\-#nŸ.Jo ١䫛کP)nh(1_U>ω*焒sqy(Iu%ʄǐb$ P2Q͋k1@Tx8 $d.Џڂ;o\{s6s:tDrTid@ֿGqFJs}e]bA' MIm0A42JBhinvM(㬦;M\4t'HOpDmm]bIotz@C+(MT'}E^7ޯi2/PO@q]3NfMN9[&^GFmַǥ<(TBut^Κ&@49Eu"R8r5)8T">{�Y  pw:&OԲB+_HR4N+䛶 [Ԃ"b\,O,Ԉ58s2Eki‹iR)x%˼ES+n:a?e hʆGBd,3)}-nS8f^{7GZ=p|צ\E$M|ReSa1osy&a$J0 Ι[Ȍ h4#=cj3ޱ3zLj3Jn7%Dj OBD.c0|\^NY?WLck >/*& 4}6ώq&zieu|YRj(-W�ڄlendstream endobj 333 0 obj << /Filter /FlateDecode /Length 31696 >> stream xˮeI6.hj uWVSTVߗ'2* Yco?_~_lsklο?i_>ϏKW<˷?_~?~7\?__4a9s?O^uݟ?ǟ/_Kg?δ;+/%(g>ޑ?|tTy{|ϧ<|>y{{<呷j.)=/z<ƿv&yZMy&yUqh Dž3ǿo3UpGi#G2||, ݿo_YgNc3<Jo/?$ؑ6G? ȶ}&N?k*_2?-t^#C'ワ ƅ9cx2}bg+߇ڹ|Oϙ䩶[\~w6l?يx Џ"V߳m뼿يhߒ@<o~{o[W"#SS? I ! |oR?ǤRf[[kOd+nE<7oE;¯d+k\xG>𽭈|A g2TO*S?>͆ŋm~o7+S?يx[x+⩿y+يg^/L7eЏ,/-k?f3,Ǽ>CFgO`<C~"~y;x'[Op߱e߼e~ljLoşlY<-~̶N<{brF~VşlE<í~ԏOx+ >p5| QRߟ{^?|mN>_roof8_ֱ] dR[:>u~zFG$culΓs?'Ffgq102΂8R1a+6 ޡ3P?3B{]1-_932[#S#.Gfy9{ # .ǏS7?m5>k!Eo={3qH쟣c`X^ݟ#E[Q $τi6[\@ϙSl<9s}7߾ߙ܋<qflWMϣ'y)?`o·`'୼Ą^Gzm>hO>W'~}Vsw('%myɗM`wugQt]wLg];s5n⑪Ղ9c30rh%Wc}3؄ 6WYR;p~#+h/ILxDenKr\9gf j,pS9#[k5%y9 g%9?y9[tm(fAܓ*´4i$SJ (+fzsޤI]hc9gHzюݙ<'߹:y&s}F*(C]pS鎔XNuo3˜%X]_y~CNf;Sx//GuMygp#|ulȹ;,uĔs>@2>Ho98(ۦɳvFcQ?~!SJ-~Ѿ3< xdґ]1~b`<t6-qvGԫ׎yH0÷3wiGlDL[|##K6 Ur|աQgE9 ˙ Mr)YsS f<+101Ϛϝ�8m=#8~trA LI#Gd|#TN YYq{6G :<0rD X‚%57 *:#'r&.!Q9HKPb9RJ)0H=G5t>FR,'fSlz.n#!&cC!܋âخH[z|na `/yxG\=,Ak�\*;oix맃WB'YW$>Z ʙK)9SiΩ~穬s`, 2o=Tmp:#Y*Ꙩ}p]Hx(kOU]h/!!m<SE(8E <^�ʼnx |}�Cw`6~:ɉ:\AjM.3ztnQKQ8Q@ qFF(]oQė~4Lc+;Au$ J7q=Z3es魁w htvmX4tS/!/Q'<|9]S� 4ҴGh@;[PS%h9/R.lb}H H QV|g ,u;?P~[79q||[RB.`$'wra�<�A;ԍ/q~w"Q9?K]ȃHOX"n<92+9eZfe4JG:3ĔCpG.~f@dl۱0-7s@{ 9H|!4TO0 ψMPtՊNZH|3>ב*2Zl NXFνXv޹Cg1m2rc[10014z^o9#t`gj>فsF(*|dx|0qY2U-@K6q];D_, å>?pJ݋wFĖfcǩɇ2H}o>�Tד0o}뗃 3MBk84]'ۓE�q=zqfio{#>$Z_$C񂫋3.z ϔc&rţ7廒:5w>IcAr.@P^^+ayxJd#umL.xi# G׺tL햬kto|b=[8*;327P13VE;#̴whޝ騾 n6[<41yLnrc9{ɗπtayOӪ)Mɧ3BE䘸+4r>69[Gi93/}}9 Gb##FC]o1Άܰk{n8Vc*qh,<Eȥ ' Oa:Giv#X{&QT&7?'wɾ{w(/7{# h`@fj./Àup�su@10]@mrޑ%0ӊF12gXѴ2vb>lLQ cA{x CޯCgamYQ 8*Gg8,eHǏ{'*8(- Gk/\<sisf."?~gA%YHՎ"c_`x)Lnr5{Ȣ=MqYٸ@f9V*pozlYTݞ ˱#&ab+}x P~8>K d?㓃pfni.`d'-4MI j{z$TRۂha9ja]CEVP1.HY-H_sѾ7 DUr &oo>vqgTir8T{(Ir噪RpI ՄHת #z@~`,Bga'3!T NcߏPUƷ.Qc7FD:^AӇ2,csF;RBZV~1F|Roy'.繁Ebp3 K9'EtF0L62GTLL-Sxl: Ig$<G+'jYӿyBZOa<fo/A淉[lX`-q#ʐ}?GL 'xSHp^bq° *@U<#"%yn/~9uq v7KŖvTGK^7qonF<&sfmy*`SHٺiR?-3 &];$3~b:ъ?5A.;L}:V-�N]lX;l3VU!'jlx2uO8Ėr.|Rq�2J "Tގ@ێLt+y+-XK3k$[Ʒpm*(F^m̽5׻ $XϏ,~(FF{n^bn&-}v:z~Lo5L^|6$�գhdҧa -:/WJ*!eBehw"Ꭼq`أm5}X?Vh陟Ud` DyC]t.II7,ԷÜ`wJ�ptVyŪJș3t(+/@ˀ,7oTwp?|p-A)N+mpe낻)]&gO)ɱZy;je98K3g{aeі}a 8sF˖k${)~% +(,׭ydY@\@.uICRV6}qȑ<1\kIjoq0 3?L=H~;fF`r_rGtJ++U\f}g),'~9>:vCwӋBG]4I�v$0yMriSf^$*tЫұ; *tȚatݑ%vӖP*< s9̴'VY" cj2  6ؚF'kӫ$>+̛^}ck0ND<ǩ{YgBuNt#y7JK=%G; ] -- l*.A2uv~adoq ctM'9Hg0=A20P؄וx+dnխ3 '>ag)FXCYyX/L4!C%h, 7įJ}WcCf~nR ƝN 1Éu%qԉ¸"�\{5_!:ꁯ $!]4_ x^e=֔$qj^[%7j[{ZSrIS'%�3tH( B-ZLBe T0a)b@e]4 Bqj70<c"]5έ". }oB@ E(v lFBSB3>S!w%b ci{dhF>] ke @J]Wn<^I87p IྉbeaZ%i.77a M')x] 6J^a=DV!~` *I䲀<㪦gv9jhF I_"ʤNR[A%::3ݩ>pRBNNcಒe 1UTQhD< d5մqXӊ3m:#(Ύ8P |nZT"(-F<ղ1ڵYY(/{>R@T h@QCصָS@"$Ff }鐅*89ѹib'ҒC !I0!ue꩸Xi*9}eα}.9Gd UxG q@�{ Ia֌پ&c**xPxrB)7[GxX QXVf笝ħ- 3-M$uW>cA+?dm�޽ɧ wd>hz@3J0ʔr,xRȐbjۤي׺BhyZX0<|K輪- 14?\ՂOVG =@/ZHXC#LUFrdT$KcA[b߃2aV Z}aKқAW3"Hy#@E9s^:A%9IT ~ _Rلe5/bj8"mߺNX`9�a 0E bTR" bS䐝!R_Io@uVW]f@SCC*;IvI:#N: fߟ8rl Q`Rfu Zda20:OgYFȚ?O5۵OC LZ[O+19p;[oJ* lbUchUBNLI&i*1,訤; cGAD-ed%OjXRgc6eRª\UUZ&uu ,Vd~XU3\@>U\Ů*K+"uiЕL}%G7"́"k Vڻe? c)<�SvuHC*J^'[.W|d퐚Cya V�5T"\^rܵhUQ[nĒ(!GK'ˆyYUzbU#?p"4;$/=eYhI*3Bw J2TD`6Ph@"GS%F8i9LUhhc~5e"jʒE;5ᲊ/ +DPKمZ?򰇍p%pneKYyeIU -&2Ҭ!"沙3zSoOUi2y,繯It'ŒįB\T%p̯Ige*j8?fP\L�0C_]Rj/2tגzӒ⠁.^Qx >RR8qӹ!<(,Zx1wi/UIɈ`) �;So� it1r'었 8?w}f5;W{.k-}v}z�+bs5dnIMLׇjsiIC lT{[qH*zhgAtJ) W>pzLx:�nagC-⌟c2�bF#G0?ÙĦ d6(B9别p:vĎ2@5$ZV�ک>H*),S+1nي8y'| ~~ fngsQS6S7 nV>%WAh*!@ >T攵̓ TjKd=jiv4Z3l=HT'^#Qm^E>@B7dR4iɻ�A{95{SOq,B%)Ci ;BA)jIzCqa]B*WJ<ŪqݭH*Ǩ-iNK y5ζ_$*c蠇ȓ5*򯃈%X86K++k'd(q \gKXYC{A^@N-Eu?a T" 3X&ZEDbOy"u#t2jjő^Wdq3~0+DxB7!# _+vO93[ t` 3ŤrˈNn07Y\ 5N$L[ddI\a1u}7iIO#7pCPÅrοl+{>jZ)|1+nػHjq*qxؠIXr>bNZ*hxPӵ^ '2*? ?X<VZ*tG'JSz tj]1Ώ캷E8O3b@!E*Xϰx osUENX%.M|<'�9/Rx͈X5( ƶ@mR^7'6Чg;tȅD -R5ԾlW@X9UuW#]^Ll/#ݜ G*%RʼWX,uvȶ\O:Ҙײ3.CV7!H:[&*4VlW9|WH `R)6v(+?Vd2k�<FBPo';lC<TmI:T#D+21PHO$h'# ]/]UjэJYzr藑⢐AJ6o*Un%bfs b_3Nv {4Zh*m?9yV $@%\/Evic3rf_W͋,C7 lsp*X} jI]=T{uJyӫ8urc#dv/(2 %P66@}-*@\OU\| `={,)+GkS�#} @qP]b_˕҇q^>HqHY'@I4 1% Eu ="4u)p@x܌|a#)'q+kIDV'3Vg#eAm"ZK"�lmBؼ03(HÒ+: ضWA.^�y!5}tm6vx~` M~,߂zNZNrlЛUv.H!\9ZZֆ\֣/zd*RA46*_~gjEy~to̾|֦&mP(&Z)5:kXi)$8 dؗg.)>t~ޣ◮ZCeDH]ΔUGKh[P~\u쫶I, x xrjP6pX6|+;]>v¡)- fH 4 9ĦBg|'Bi4 ѡ," IիQi.,'61WeeξDP+qU�QW{^oS)N-r\DZNӵo?<`Z(sb,`.@ !o159@6,(,.2ܢ ۔TxZ[@4ԕLd Pb x)Jb%a ub4Eh TPN?>1`203PK4%kKl^+ \PcIxmڇ!B=jkg^ 8X/ ߝgw<&%~4jBż~pM6@W}t*eBɽX8lW!ۑsF*n+5QUͫU~\oU&V٧U#("+`'+e:=$>Qi0<", ZN*l#^5Zb2UKg4NS[_\̠Oo}kwdUٰUԇzy%W| @N" `5. o%CU#2_!v ^R =VTScj(b- 7ұ*͉|2Fr"`drd=2bcPý\ Hp"{Pk.{O*1 O;Y>"t)� Fz[ ɉםn{Mrep[լAޣ4u仛{-:#3EV_N\P R!-Pp^D'XfZ6b|!zNܖ+@Y(c�iE e)pY@|vd<H I"0ar@ \Xgup(G4t2qO9~UC *"N*ʦ ֔l&NSVx4QVm!fWJnr>l^ *Ste&6&airJAqH?Tzؕ\Q +fb7ؑyg(h}F/Y-MHY{jFFOa[ `]]&  P:/IƬ%f ~Kμn"[ R .WzqϜ✝YbdxD=reĜ-bDt}a/(F)AQ˥lLp`,yK6ϼ8el {mKpf`Hr2eRn#3^!7Ҽ >^hmdQme2VԧE mM$dɦf5^mQLٔ}]pXv) gkWKx$8*�XqL|$9rїjRRsL|t`duqdX\N,W HӺ:R~rF/@ulPZvE|7Ag(tq LAJ|KDdU8d)em%>0/WYT'+3Z ō,%4`71f"SbQCdG\h�Xg1s=!I0GmZk\*ɕvED[)톿i�}dE.f1)a Y \ }zISE�גBEwViȏs 6PU:z$+c$V 5bzr4 a)"y X~0ϐ ŦΩ f@BRgD8_den)p)'ǏIQKƞ3e#Zx H>K؃̢ޥ KK,zvRS8g~[UyWgGJe`ڻ( zY2 p-W@"%&&J&7s#)t'1s{())n#Mje7Js$ƶa9KMڽ]+w"(vj*0b<(w};Ȉ}RNg R O7<,?< S;Ԭy6mz %xeP*ֲ8EZB3^�_ Vqr-CL'KM*i?{!�Y&TF*h"aU"һ'1gkJtk;7mka%*+b7>-L*XֲGAMeW!Im;ou[°ZIC-j{TùVJ$|z;U9_ICrn ܣ30Vsʵ K>] FR4˹'ޢ4R8/7 t94i<XGE4 A7KxXicx�xI|G>jY6]l@~&W R} jQeX8h FI9xksO=>_v}Go%.R3 naA(-|}h #Lj;r)LɀGKwc{;ㇽv$GYח:)Zh)ּjh }cboCm.-z5u鐠JD{OֳYr=RV>qPo vڣm/|ר4,i,q4dEܵ!oAk }#n1ES'i3g WTB1) UuH8e)д접rC@s6 s x K޴JW.Řy3Þ]u\{'KHHU MS\R!+搚$guTD%Sag9hk"y~%\E1POJߓ5ݰNX h0+= e<b-坆p[dh*CUdŧ&?"m.ڧoΌ2n~pifh)銠vpP6+fdU-uU@^ndQr=śy}nzM|In̈LÑ_f:i*U(Yh}-jaWu%)4azL'|f2!rpmU}!jwTn*J6d~âfmrU !-&>>t3eCxBU{M1bѫ\{ka*5v-8|۩R NSټiĶ$kuބM΍4[$?0h^Ԧ/ǃ35i235"sss$y4չx!7ble E@GV^(](dXT{*y%%KZ˨Ckk&%|Qo(a ʬBߚ-|=5cYøbgȰ$~XUV/Q*Q$lDaAwvfyBDxNɺqK%h6Iy=R%6Zn_:0Rb #32^ٮôژB+FVַǚVNM궪іa=*`DoY`Z#pܿlHaK\le,8d؈"QXD% Ttp-^Q zHauTj?5 VbVIg$%EʑҸ%{\j֩i( l ֍bVtR{VMwKNk2)/ EQGޕBVZG S vu$*ٛ#w"TwuM4uwsÖ LXhs.VߋˈfPzybAwX̗?fkg9"r*_>HPEj&i==W P5" Bys߳b TГ۸Kt|@ԴJ7HU� %We , դzѾ#10vrN*$_e<<[yzYJ-Q󐿕33BiPT[SV})X}AUcryKr dԆ 9FɲVV'$/1D+Y̫Z_'zB8Q+ANdF5MN ;z ӌ^JURS`JO.n7*JW]NҪJ 9=(+.~H65ݜ/t9Ӳ0w *`ˣ" #sk!R FfR!8A_mӦr,TY=jzƟ5Ьȯ"Wr߷[TCv9.U2#V*[T3lU\ XlkYd.m<qV?IYH\'r&{A)b4r}-aoae[+9SJW{s/wVWۧ3GXhKɰӔ@Xj{ZKhFh u gpĿWԢ? yRB Kh 2\AF "` *`F*@nt(k=,:j4mʎE)=x0" t,erbD(5EYNX G,x- 5l!4/-46?Ub]ϼ$~iE,hSrVJm܈@r}4%^`8Vo^{wmMK [as`G13 ̂7! vI\a˵JGj\d+u/f{R�-bUWԼ\k<+ŽnNV > R[&eU\ۡn>0jʌٕˌFKYA*p�TV *EaޜXKErުƴY}!jq!!+GY(=*BNY#!%5 KnI;#K⏒VR β] 4WcsE{E߀TC S 5p#%yɰqGk^~"p%5xJ;DPo/ܧr&fB"Rn``S\v XԜ[{<TO<.{#N |6"{px3bWm_"uw@O1W',b-HyV%@.JN,v֚TysD3S5ː|FMq_&R R=Jz=G0x;su-~+b\UOcjDX܅ | _-" "] cI[J6,{+7V!t<ƨj6e6 lb[i|!" 7nZR*c$=QR wbtX+jku}W02="_+!\ØY3, ԕ%oRQVtᾑ]3;k/#۟\xD, .:#Cn&kM"1ZDsY9KVbzH)a(+*GY1x{�W"^kƤ_=8ԑ[3]5NlLM_FFL%4:m- y uK@^nk|kX-'\8gՑ2T7om!8+k‚~YH} cV65ǁcS(G[>/3ydD>u&m'(]Da5 L()c4@] ()3DSEIz y;GLs9~lh%vE*DbJ5ldcx(Fr.lo5I쑠JM/_:hCISRݚ.LN\{<HTW/%j+°%tqG!@He9lՐFebk m]T#)V:k#ʧ*Ѳ-6||e*'ޜR` Kҍ5.qYxu  U|#įp]a6WQ"X F w'̦kJQƚϾXȉl%uJ%RyH9<z'�Wd?yiI[R},G.*FGE-6X;F+##!HSHZ^qP38Qbi_5斯&<MrXbi�dQB5Hq򵗊5duQB0ؗU$x&ٌY ]-d=nƒ:L$MڐP}Lcf]q`l|OA1=J1U缏a"xԃ3ԌAnRJlW7Y=E&^}} UH~L0E\z>TYFLViοlr2/"zb$9er�5\}4V} n\^[0|:eҶD()z]JO0\|3u7mk2LIJl:'1kb@7WpQRӳKaI׀#aY<mEK,k tw9(&K#9i!>o"Fʾa�A0ѲQ<,m>^PsQquQXD]xC)1>XPQa3H2QLrț:/w%H:e(?/Bw;@::2zT*]́!,JvL墦Q U8洋ޢ(QK`0}* x.*LH7vX&=#DjD &75"i4 75o M>Fc1sDS&*kEA&ÂeGO cM07914|P <]u ͬAm&w.0hݻ" RJrkX8Xɺ8yr?,\#v}yh'c ȶQcF VLyP&P�XCƿV* F>/k ذq ފi=,\SG%~E*i2BX^ဢF8t <큦B?EEdc0(+hm,(KT ?bjSlb,p;xR2SM hfR)mres+%^'�sl=9K셙x3& '2b/0l)FG?/VvK[a,E10G@с˰n)a,�&nV93U`#vc<vwmFEU7Hǣ+kDWe&8oZ]0%'dgIJ4Q\|53u(bϱCBH5Fv hm zRVa8\]o^JXYډO%{X9rZQ 93"Zr2Hc6DuNS*ܰ$qwQۄ[nz=�]l ˌ[99KreEπE,M͢A]x&ޕտd8?;s7JVƕNky=e5Mc# W=#hdϴQk-'r=$-�t^w/iRֺsEp%NqgE:)cH�̆7]Mi(u,hr?1byPZN")@ּ4Z-\+1%)ŠcW5ۊi؎WdF+0wʐG\ӊNt ?/y(Vl|FO*ٯ}7bE \6OǥCoЀV$!̴2mt${BT 'iHR UO->�U4r 0T8 H?P-ح;C  4N5Th@Э; o):`E)Ԕb+61{˭u3IhQP%8ÖV<]-n]p{GTK4lψ\ca)͇iUjyMULR!V17i85P]z`q3_EY7 Ȑ&�y1B-o[!&4S7*(}00 ԥ9r6:;$ P}Ջ#TS̚ V?"KyIQ-谼 qnxg7[ruS~[ gę)ygؙ# )TSvD'ZZI4f66^vC0!mrMܳ^%z]0jȸ ;ɴU;XU+vJ׎u^YqĜus6irAqhE.izr` ?E+z[UɅ?/%rl,ZNq mIokT6`rJe/?wK`܋n_N-4mU(e{~w֟sxŸWtATwFVea04[D_WN!640*R%*G,CSߟدuqǃW*d-.KԄ[Ix ݍX1-U|a̜�d:]/$DP@t%`Q� )? #Ei6;2. Ԗ,BfզcO^\VE7H-Pѥ6G0yфgsɎn 刑}UV\V*z!F\*N~AF4N[a9U}a1yD|PcvXK5pE!C ZRTue¶Bl8icsFJv<FjG5붣S4mnGW#NhˋRwiFL2$,jh_$H:Y3fsψbxQ#5knxv).ϙM%2Cfh4R>#f Te ˘/֪=gvUoaBFxXEFpLS8 ӖwhDYRyl/CkFHI>iѳqp쉃Qgs_[DMsHf'v.v<a:a߯i R;E=Y* Xw7N~Ys;K~:gшL O0jZY[h3l9] $w/M[$,%Br7%Pڸv9c3##L-NlW?D[5Tigw9+{E56x :̡i.PÄz½^)ʳ<3^ Mq*P<t*&RVddW6cp0r e}v7W (6'죦+N3C3@m!%JՀaf*(cp]�ÞB_H b=Qo=oYt}~-ДU܂5- XYGudR؊Ǹa{M"rMm֚;{=vfljE+ʷvFVl[=C q( cir$ho'5�/ZįIArGl!B#bUJkaGպnij<⏐�mjɣ_HB[CjF41x3{ ͕%D-Q6"U1]CM4Y?vӏjaW$3's%Ɏ}uxB|(%#kMLuݽ DբShha)UQ%b [ ,w,_9blmVSj]zNϡQ)˄^lXmKvY*J5GU{wLڂWWn$]Yog P ;=<”ĊH0tCv&Q4OEki)zh<bP^g*C&W*quiK˳T0E -7p.<y5TE95Nd(4ܫ�ۑ]ٴK*ٿa6tZ!RūRV}LZԾZV=ڸ7ԘR3Bxi l)Zw.kߦlcI#K8 +pM3ۧf)Mq0LE56)vZC bG᡾EbQ 7E6zEljlv/ލ+طKv/dz+;*;6�_jW۴G,ݣ}rP]/OcY}isҡNdCbBVbG!xE/ȄN?Zr,UF"M䞺8S,P)t\̽GVU`7MCK+d3sAw_bΨ$0ͦ%o�'S mDOݹ 3/k{C2_[k,]Vj.q.m_'fnc:"gPA]ظ~=^tGވbfₛeq%d罸2;ӉdG2Q"D UkL/=8s 쐝VQz˯+5)KNJˆu:JjDpFd!Jۄ Է n}n-jH;@SttgI12o_(Ll0dz¬ֺ3=BD5.v/FnZMv\\"�1-VKWd#"M$�v^ˮ <̥:N:w7 dmvl+h^H1vQmSg{ĆC5֨mQyՊǜ >c$(߻VeN*d8tbLw،zډ-_-(BcgЗݥ P �ykr!^oμV\ 0ﭮQNJ1>ͺY*&nCUZ /,cEstV $:GЍx0#2 G2t٥SU9ι ^49_`=SnV<:-йPPͦWQkZ(#~IǪ gXr&yC~Se] K+5>ƑbPXt.Fi=P_m9|W>z͖6~i&SPj+zh.8:l4> _ץ4L w4nkz 7*\#(vSZfcMbm \O9*yJE" R*01ak]9)gsfS.cRӯqlE% WS3^hVXtrZ7ψ}-?}3W-xyvu3k/&82K#7I(#{IfC[yr~ݬ'7�,nC^x4`a]pU870%Y~G pfISj O a>\P%s8릓zF~?p<d^S. ` eT Kn/Z+yL5[Blrazv֎eT7#5؀XB Gӛ|w5;RgҤ$Qt`ҴqÖ(P5KX=—r 9ҥ ʑQEEa`'Pcܦ‚O?+),~=GOf4q%YAMܻNQ`q*VxH9ROH}:R%r4<óQmp]S2xH ޹ݠHOPK(%o^j@yԱg} 38ӵspuJ)pdq!%c[}h]WgK&)B$&Mq8Vi;n5KGUF`DnbdsK_f]ZdbJnoR-4_fߔmC#x(2[țcPu#bVB JȊYkjtpy Ui LYCL6h0 `AhG3= CdT- n1d):ϤDtc3zXy B9BdHxGm8 ,5.wk0[*/]Zx^*aĂC'YU %"]~rTV.KW't|N+=Ʊd/y x, 3ײIݽeIQ�)K f',frfFuh:ďoF1Mo o*v|LFТbƬZC%tZ]QB,IqdQ`:`{B> */v`څ p :p`HQrB<\] J1"]QjZA2X tj 9ƺuVi{nA0m["ZuG\]hQH0DV;9υ3(W5ػ(wk&Er]֯汢x TDh.y_xGtExU &Kv'qdx&.@P5v},YX󮬃Yr�'c P4z hv1r2-h<eø*="9̅PָD7J-^PWQc:;';B�rּEܻ=pH9SM4TT+9$g4G S{Ң(6)?3۷(5!J؄¶*6kYf,G5 :k[Y4ᆴ~ #G -D6iپ."Zw4;P#aaSVT?]zH!u褝tf-,bKQq#` I \`r9GyLJIa""Ppde™JKD+K\[LOSb*e`2_++ _'F'A#GN'^ oa+lDZVP*S)>W2-EqWTy`k.M�(2c~&G KYV\/J 6r p0noLiU8ɺɱ5^պ, Ei[QiQy8h6wugt3#woue%+?#9Y{VPAX H$eaaUqq|}"7%^ J]m]D>΃3y(yxy_3U(ݍ%xF%-6 "Px9) 5ýM6S C|GЛW (na7 0pn= / n*0MU ɧTaq2`da4r[A&=Q=t" -q;I^ =ӛ}%4>j.*0SisQEߵ>1^W.ۊx5dGvSU3tAb1͗9�rۏljgMPOheCM+aE,7a ѝ"L!PΆ5y$]]{rk,9|(ݨ#IU1Yi7r'"*%1Xɏ (Se/ߦɮ]*Siʵ|/QUloN`9tKhT:\B۬}ޖt|MyOmG<ݕI)yi�1 Ru(S31KL�0LT/1Lb*ALT/1RAKy_t(a*ѽcUP(tNA:0s^S/6FnuLꨩ>|&"y) H;^�B,eBBRXa!CkK+2+4𥏧m Z@agVO@[)Iѯ1Nz3-?5^emЏʨ := [dU}Ȕ+hD*G2úygUoN7u@DM0^`JWb#h ;d)* +VN֖g0a+Fm:E*> [g>8###�U!{XP' X*3%ӑIBUgY/_<qElJKMz#kgH+=EeX FnvBum3-b�1eVŴN2WjOάh6aYݣ<GIW<sh]sH#q>V$u (8#߫8G:84:)u5P WP*jyN=2]NNjk;UF[xgopT}E  =jd<MU% $Uv{2LJ. a1wF #EroVdzӧƭm?<?P\" "Pښm@~7(Ʈ<5 +3wV.OE8mٰiD+!LnlCa1%bK,'%xꁧB(z*K_UV1M)@@gn=ȧ޷$i=/&Ӛ^y9a av8( Y =9uUpzw_'IxRf2TjfM~E@F Tzֶ:F,z'isl~ 5 NW e88T#M4(K;r/HWe~o,F9T |aZe2+ͲoF.`"3G@՛$GjXgȑr )yjlRHo L!հl]Af٪Lj ^kj;5M<L9; -SoHj,#Rњ"q8B߄Be�K1};4+#7|y>S /d`r8wIe`{pl\5bDn_ ?X*-)ݩ.9Hi p0eMߤ fH#+7o-"kwt%1JcPkYLU1G0g/~"yD("e6hI]g@>>FL݂Sa FsK9ɮ}oPA< *ۺ DV!�rXΐg:cd0H='n$=n QAݗHgӏcr}7摌_hMw@1e9eߵ&r>!W_i*p@ˈD[lb%L3ɤPf`,璲$ 0lEJGF{d8xr)'A8kzEPI%a-&9: Z-Ax; YPJ+ෟ,icz9^b?z(LUɡMe/'p2EK#৺*`{^rk=n;N+Z5bf^.s-jEG[9nFt FN(�,^7pݛíJ7H~g]me,IW@Y {'yVWL5]@bxѫl_mKFc|Ԥa: DIIT ڽZYe`C1"4Gx"Ei'ϞNFndC-vx?0RFf#Z Ղg'J'PI.əAҁA߭5JXdG`W1vŽ)z]WJH༮bķV\8b|w_`ayQ)oMP _B pŰs} KikCлĺLgv}soX-2tۘQCƖ keeG�K<){"'UrL#쇀S-@N6er ]޳hNY]B3C <Ugً̓ԕv2i )P^ŴbdtiT"*-Ib3}<F֢QŸSW `L!T4I|)fP3\e).{gs�²;b|+tnS4oj$ѤƂ|'^T]*.uiJ(6t1yD-(ŊaHDz85x= 5 /<9JU p$8oko R$ i ufgB+ œ} j֤&VSR4@4~l6E~t"R j@fR,S5P#W)ρYIQ !P+VNͰrAECduA%0pV j8O%YۥKԥGϷ8`G$7#],3B[3&Lsué^liR^ ZܘlYP%X-LE'e$&_{d,qҙ]  DrC. tf1O˨{YR-'L}/@NqN`](;#)CLxoZvq.bEoeJLdע= [ Q0sXЄO-%G&[=̠U�Aj/ c^h( 7R x+ T\ꁜ[Dܒ<  zגN.d0&]e/%=ZψKކ �Ǹf/JLEf}%6;vK-hȺUz* 0:iu+S\|>K|Cg/$BPұxDh࿪d۶1yx;ih7(^SKSP\[en㬒Z@>>TP,$(ueg+ob?9bPZ(_X-|_"\#/zk7/<T$f;~C嵊x‹ >Ghݴ,ۯRXS_s sRGP\[?˗HW#;J~A嵄x"3VM襬 j샨Bi=Cc[?7b)xCU{)SZRBHw@l-ShG z=n ~kT}6x!OcsHI#3VT[s GpGTqOξZC<k ޿B6Vk;/d]|ggv0N�gl!^Y|tiIIsSU`x1b=QlG &(mͺtʽgR`{XЧ&  <]L rpcD6J;/N=3{LtBSvNwv&9`Ų)CԱ_ 2:)nI8:^t/ ̆C2ڄa=|`-) BBaCKX-*�DsGHLG$,! X$5VVCĮذlXEђ ۑ0bYa$sWzKakcQa ӁSaY6IEbT�/i~vB?ۆsnr1 Kfs%i'|(H0VDHؤ8H iv^U67Ba$B 'CfEQ m*ib1 ))6I S0?$Y�_]~vYKt{[[ RpSjMm)*a*0L ZLgU6Eh_ xsU=.�n*w FԤ,P*n 8{!Ԩw?eꍵ<Vx #{ͦ`y~I t t z;"#&Qf2WթdžM:CIQP;$ `pD#05yJ#DVS eFVcfY hȨ-$ c3]%ڌ B6pXDCq1w)ҫk] ^T8*Aa*jӸA8 p+]n3:69Uʼc ۞Yj+b3t\^XU$?2YBԱ_du ϷC`Դ"(nI8a$¼ؚ60:$x[Y1) A1 2%8LY Vʇ!+BVdMsY4[>hfXX{9$ ᘅ�!^Sap+­t g?^GP9U%/db/xnV* &}�b$5@T@x N&mFbKPף`y'Zmv? vza`w Lٔo eT(467Aa$sY~Rs< ʦQYcSۦBQ)V 8 r CV~eM&FbTVDz=<ƣltcˠW&$8L2-$TpKZ2ǭTg k01UP9#+nRYEFS�S'~\�G p] m#N 33dU0ۆKQ;d*Aو8L`p S\�ǥFz, z:~vjh ?Yl끀?w31;8e[( _p ] v,~Î|+RHk8j|EPQH?)FmtZZ;lap !#& tǢ puZbyf! ւГ zK@N ئ�&F&8(Y< Lz),S>Մa>A0U1LD =&4pZ^hX@[T�:`Xѡo%A3jaEAhQ&( pS0K SaD 7c[s̆ 4 AMnwF̤^YJpx~Eb 6D Q:gv W*I@FȰ,x�pg*"`hc p*V.a@k Gu&®D*`Vˈ`3β(RnHj<0,MԳ#t6)d 89!" H;ZsGЊWƍ`LKbYI#W.0NޙC#Q.j%Ege[|b9%0T@AP$S422$y!e&K =#vZ2m SEI!LZ JԳ ::[~Q<$Z`Ц Me62=N8<(V9J!Ѕ[:"(deH8Q2(U2ҙBβ6#ɪ#W޼ռP[+İPx XSU(d 8y@Pa<2 $(Dg֭~[QOJpS (8X刕eys*KMt g'و`1=1 43:СЈ{{c8w. `�0EJHKCF8^ʘdQJpx<bp%ЖdxnJ̈́w&Á"BH¹Oq8fb׎_cAfZnK8'Ih�+TK5ռKK*[ ê$8\6;`y a$<O]Ǎ`0&ums;re^.1C`Ȓ0loR+z=[ Mlpr),#jq�%8J >V) KA<^Ea}c+<&Ǝ4s7 @Byo!!V$EGC`cAfS T0:T13R3d7ePX� k~ʍ0QGYAyI,=*Ai4#鑁Yգ[q G9z.<! pXMݻvzrpAr=2n}ӆڶ!emuua;U0U}"B\|F8AX-g/&7<`JʀV65_&}$YCBb . Tk6zMwNpQ+^dzbAIAL/Ww�S+2X$eo ႍ\B*p'5Le_ʼn89|;.%GQ񩃰>Ӂmtg/4QL{m&#4 '2GKfH38r&ppLHXM#Veq N! ]Ƀ=Ca5,Vn v-b ޖ tb["aoKPAxNVzWfX.4ceIaBeB,+h rlQpPGX p+-,b lV{13dJ=va^RJftbX'+%,@’'p] <F Bsq:� ӞʀP�:HNVJ;?ܨL1tX se,IF0ސN1=hW�#V<_!n~B0b `C.,f"eʭT!, j8A3C}b < ,fVk9.~b0iV%Ѫa]#9Vק|4gxq{`FVg #+ˆ N&A]Fh1x*aP{sa& Uijae6 J b& )3!(hpvB*`Y3jm+fV+%,Fd$)V/J SqfPIPkA8 %쇖hiS; �2,KF F`=bgO\Hp:6H.a\Yx>%m0Zg'ُ?H/EKۃY|&Es{߷db.XW ]7Ǜb>_bojLlv vVhk.|1Hp&nE0Ǜ53xs]Vݯ^ncƣ=ܔŎȦ6&]o=V$ViGk?]h>`a `}Y[K][ױ{Fu߯_D!}ٺ]]/wNto_oNPOGO,ܸ:޸nޢօ%vݲO)ITզn3λ㦟YO}mߜM#{;]zMBMڽ>|~~pwON44/?bwJ_ۀx>/_?>H5񮑪ן^ܿ?ݢDzfe[|V׷,m* pU?sx͘o2[<>c=fVݺ݌\Cx=i}o's!ޞ]im{>t߿}p?zn7Oz/k틁K2[ŸLv}NSNֺWѴH{#P/՞kuu.՞|Sg8o<42~k [^m^Î<B΃_0h 9B`b]%j-a송)ܨf{՞_$˜}ƥ/vӼ%Oׇ`\'ollm5:7.CGRԛvȧKWۻS>yʻendstream endobj 334 0 obj << /Filter /FlateDecode /Length 2673 >> stream xY[~߿0JǎHJXt  }:'Z^+GG=9^DM ؇,p8dW .Y=xەoVoww_|+չW㝕+$VkL9L)V9OVkʵ( W){^ g/ܒl0-Hm<eX=76x x$''n;]ۡ/TS-aU Q֙UpvXulL ٗ=RsWqxz؎k}XD\ EC ޠ'̜?9ȀkD*/rX=?x5^˖T/3,KSz*Gsw $ r-Z'|]s.}+a.X9rʽ'R6Z+S%Y?XA3,GC(.zpl`Ǿkm%O,U [9F8`e{/STRΑqi\p`ﴊ@-uDK/.9UYf?v=lM]?kA9K5gx%*eL;5.s 2fxIǺ:?kZ{y?C,Otp;�߉,ExPDv<sA $ ;E"Wx2\V[ůB0&- #^G? J*S2>0Q6(YtM[o[7j@ † HP[Ԑʁ5CSֵ=5@sWqg<iևMa^v㼶j?L7N-lPAR2A&҂=/Mka H3"&芏CTzrrREE tX–_&TbQD#CMwh(]꾆[w0E[89 3J@9/CK/HS!S qGϊPƴ]9r̋ [p[<Z;ܱ=fVg.a 6HUf%A&iL&o%v+ᕜoU0uX|I-8* :si(=C0+S6%i TsT=Т, J65 * JrXH%jP!${F㷡~́[˵B]sĔ,Hz Y{+A&eq~{+(}u5%|]z:a0rf7 ȇ3cPвRA?M"j፵dc՚Ie5e_ @@@bb"}q肅mC6 /YqIeOV,Eb ^,#=܇|xbdcSwxFd[3{I0r.onl{@ ] ϩ~RB8)eV(zP3/�'YꓸN]@|^=4=ZRH%Z(jy 1ʂz٥0Gמ纄{haLYTEߔ?};5|>[cyH[nk'zu]o))յ+.}N"Fȱl`r>FST X֕db?Jtv>цt<DC6qH DHl{-r96gĺf/  %]V5>KHrǘI~s3PhK$k:*?P <W� ui߸6?''q[ o(8I5PC˶+KXզ !,H!M,ZCHމ : >g-E{S/(SġoP2B4ώHH~yMH:j!BI ةn y1�𶯥\XF�'RR�<hVq0uAU$|j!/L%+*0{ȄLk<X3cHZ@d :ޞKRk?,Lw~5]�';)΋m|͟π<f=C8((8袙O~߁5Ԏ`~d (I4,4,ጝmc3gh,P H'abެ861~׋k- J3NΪ$5\oQ<BO6No2gngnFnf߹KI V,-.i_H;xMW'2͓Nyʪ=NT1Z٦UK7! &s72vv��<3}@k3ݻ]aF6G|H0a&{TY ۤXS=[Ȭ@.z_ ̌vܗ}lѲNԛlf5N pPD&ź|[?6_#`i4y@5|1]膡z [@3~<9~\s}P[g.3EYL$�68uZP"{lr;蔇J+P,(NM}Ax1:ie6U<!+ܼu<Û(b<[\:)5P(𢋸5 < $pAS2rz#jw/[oV#endstream endobj 335 0 obj << /Filter /FlateDecode /Length 2209 >> stream xX[o~_tk"u_ h"m<ŋEfbx%`^Dʑ(&3fSoEy9O*G_^N]Oy$tF,'j4fʋ麜ܓ2`|]& U#iJI!NTO8'HfC/)e)MwhNԕ>Η i137I`(y5W6B}h6vWύce0 j?TngI;㧸Ty+%%͜QX€GnFB/ >|7KJWiOWсB�`ڤ$=t"p<Qv H΋BIy%p\FrT` g!baB 0&U[=v.1UX$Më\C&xtVx#D8టQCr}]SW1 qd]dyW7r,� A�AAd,fs</I!vu jȅ?'爴EHIW] ̚!ɛȗ&Ww2bW.78S2x@\J� j۩qІzLO*y~35iC5ЉR$^nS;!@*�”�m;!4bg"9iP>t8KGӥL*`=@/f*Rer+fx3ST$X�N Cjع =5LSBJv),XJ1Э /OF|N2ip1cc PNҡ׵05$H�g1$|Գ}y2ZE_.Q?!G:1 DYNR(g= .;@CfDdz<k*V:X Eui?(�$>›Ǻ)q�tjj~km+@<YPLjׄd1<bZˮ<<j.0pI~oU_ C @$KOOmTNuH=.S$ǁ<I(4& LΗ= F<,C5m]wB{Em-ef,BdESv=5V\F0ƣn.HCrqwUrvKOOO{ixͪyVܬ$$+=!W;: =̧yA80'}";& T"piUeNkq%f}o0ЅPxC8G}NC`f)˒L!&b˫N<>[dfsɽ % ԝbTVKB}F}73S;[X?KAt\_"4!=#q;O~e_k-s3rZ[;7֧ko]>/GsUd`E/4Itn~"y$7Fg nX2Mߩ N<4\>%DLT[<ǝNMU{F'Y.F iӹrU;1*;f?788X)KL0I03%yWbP49?"!9p8 Iéybb N\m馫Ite5_:ݣUtn'=ud `q({W@.=ϡHMqB^Un \R)Ωޫz SJ?6mFiř^IP#sǬWugG}VA0nt. z:n9xpqzZ&K_/w/HA' ?wqf,_S ֗ su[)/_$KL *n/ yuQsX7u{ncbmw?{sۀJxc ,2ͼ=hWUGu oDcme|my^/Y!I1ܛͦz˒~kkU oJT) N(g!y_EB0;K,/jyz P nDStZvXȹV`x;6*b1{c}b.Zno|GiZ̋V!BЏnoד_/^&\endstream endobj 336 0 obj << /Filter /FlateDecode /Length 3883 >> stream xZYo~oa_I4cb{#pk CjIʯO]}p47N::z>\2?=\w.2z)˿\_|ƔզU~y}{3*,ޤ>\M^ϫu&jS&ip#erZbSUJijoQd9LL׌q$ͩd빉vkin0K[3f^Βz2uImfrL2We805VG[0bfQ2ynOI4d).H唿? ]ȯw(럟7Jix5vƶ^1bR1dpL^%:<SseLnvn,7qec9u*K%V2yiude&|hAM7֗k͈ql|U X2;E]9-v膻v[w mU9KJS%Ѵ<K~/hCá{terVsTVwTWʓ h+E?DΪ 7IkwX0pfA˺( CI0Z%(;ҵ<2}ݎn O[n lTҲ/qv<˛}CFt5j,ٷw?m;UX(? DiVXѡF4^ހ?W6ib^*T+ l; ,@rǘ@vbvWH fFRij0<-1 rM"44 Ox{ြ+hcn)=^'$6g,7Mp*O4H�9|q&/+ >@~jQoX` CNY|3@~<>8;b ׇ�j<i=~ꓜ�Ԋ"9JFaI >'KpB3�5vV|~΁{?WEIܨvtE ,\\e%[EGٵ`^]j'SVQ&>esv 6D'.wGxlpTYNMxQzO90 ]]9T4Vc,g:aI,-7�GA؀ �0̀+iژǡcΕ u??eʐaX3!q cT*x'NU@#V)j AF'!Q-)Yтx<ʌh4p؀ǕgDWO@t<XEA RB` 9k*hhػ K!%>>a ( kFԘD-Bf2`Qy+YMX@#GR|0@moObY0' d haq>W%q/�œwH|\&CGVMa5ԅUVx@,iG3?S}?S@ cށn@\3eoȃa,M_Kv+1,U^@ 2We6ט!+?ԇ{nuf"=蔜HUrF^~# yT=z-Ny}c84VaHH]WOF+`v  ה)E.n�YۻE�daՙDj4+tz* m2˵p Κ Amx.q?TV0Rx^-6eq:: 2| Eh,bR*ҝ+'A_H$A< F2XO4ގͅ+Dz08|Ԓ_Hu BL؛Z[20 PtFHZYp#Jٗs]hasz+cR' d!Yx&9[}d\$%!e`DD3yA@dKg;Rz(<10G78qܔ:Oe% +_@~yӏC7�t S3 $!.=a[$3eCc&OeMӬ89u^۰\,+OdGT\v,ܒn)lP#69c3)NV=VP'K0 Ԍ uGFAC |JSǎZ$Y4f\5vZ_Iy>UWw r>{;>[{CYG IA$n"Ң 16""GA~Kp=sZΕoY! ~˙:Ai{r'<Q�GYg+{gx$pEM!FKwҍd hc{<Q =p `䗵ɴ{.n!=n\ K3bVL,Yy 0,:7,; e~&-,7ZwARؘ*4\~kVUލ+) R:'͹ tK+UN~L[őJ@L6*w0]bm~S}sKJl8%Q w<5*nE`u;RdbrB*jey/鮛fXYPJ7Vns bpmҍUu3cD]c)MJŘm56k60(zlb|juASo'IrM۷a�~I *�?VeCfN Fh? m0G2N]dl5J4$C?$kNҤ0;07s]ELBC5 gno;AOOX &IfzZ5y!K�Tϝ�) z5qZplNr:u ;=�AF\n966hw|ƽj8 oLiRB9*u{E 1W0Ys y۶_JM^ͪ``0P߳Y']7W A!ӹo8d,0k8׃8zkX>{gJsbA jE'-J `dVn Bh8]eT18<8wk<Og [J6QnG׆˫x>3{g `zF{A5 ]d.¾ =#|6?c`7t69q;pUf qU #\v,~B^_Exʱw.LꕆNʲt"r8`MFHMrlV;r+Q%%^37 c{s+e6@(lnjrĠ8Ln'" A\~"` yxq@:J~գLru7{˚u]Rݪd|ld;1QY2a$y4?v8ҝ8OD 'nvVϱ#ү{ bCۢg0BЇ"F|TNzΨGL<ԣ3P󪥾}Vci'nxHމ)is+;du4O_E<BmN )rYW:V50\=4w}}c=O2AqêWtWhZ!:u'CIBYHuf2S|_ Gk4ѯUx<{~O&GeUevT Lb`w uR^CTa:{_ | s'0R yYKüuirM ڤα�endstream endobj 337 0 obj << /Filter /FlateDecode /Length 1674 >> stream xXM6W.`oC&@KR=$=8^eYi})Q$IE8>gZf_U!Z ˥QߧSSU*QFn]w}tU-Z _>TmXpk0,�e޲ön <8?C}^˛4W/hd\ n(aNCs|[>Uו٠ꯘ>aJ sKY{*"}=P[520"9|5RBO*}AAhlӭbtk-jl=S"ɜ{{l\Zb$!cP^je+)\R qiiUIҁK7ci{Xtf95Hk{S9+h2KKIXJMNXf?|#vR\WH:$ӌ5 8/Ċ. Wz` ܔ '.I=R\#KTS)XFbRdH Mf4c n37)8(YVkKNr“#4WT3bs,)Gey�kyJ6DEI~.F!lKTvȜj!d cx V!k孫W7@AD:>X|?,5v)oG)},'p1uvadB'x{gn~|l/(ʳ]soڇMsV+SZBP.,0Zf!4]!%–)X #K!t?`AS呺+Y=2.X?i$(ʟӊ\,UW^E/}`caWpxr֐DzlT0~Jꚠ}Dx_4J(IJRF$#5/z}D|8ӏd,~-1=ZP;r>΁-7tE$7hrȘСH=3VkvT9~e4&s>[LHNpIv@IosDVO2 嚡MuGLR^(.tJ7J;# S|fh L1'gk;|&(Ц&RXBtZ+mRwsS[?%`4dW}l h'"[* <Ոuy&\!uNY7w"wG7e 31}Ɇ4K!|0 Mhѐ E]&;C#E__mppURl{pjP0X<Jj@ԓ㗄PJ?l{n޸.LBⷙnق)5һom &n"OȱCs^ !azbQet0x{Z-:NzHpğ^U_޲qe} 8!8lڗ~߯w!Cm.[i+fUxݣ]C>&'%o \(8-\ƲqSi>,gXш/A>C(= ;B`츠xk>$n>b/l'V6j/i._*!`2lv,h6) dHA\ǔ+SXendstream endobj 338 0 obj << /Filter /FlateDecode /Length 3031 >> stream xYmܶ~0Am$.`I8p[gNUzw^HsQZ3337*?uWOW ]2_B _dUīLXx!05㰾IS)$[|x0�S,zhMQѮr-2 %ٹ%^VQn}C+qv=iܪ4ݖy]z"i,Y'8"!ux +qn,zI=E!1n,;|Tpj-rxEtprU֚'f':})ȴ%Ia}yt4H2XWVt\ I)G*f2:}YueoBHEo7$aF"ۚMl gºݙQB ]۫ Ps.T-=%8{\x۩iJ{[Zohzzin7me1it߹q0Wgq<#w:#Ȩ`z" mx dϜs `|ɛGVsw$1Alۻ`v~k骷3w='̏52k~m_{.lU,Ar.rO0nda q\.{pvEFvRTVGETM d>}q?Xw}Cv(I ނ^8ޤLH}o-M&S;f,D&b#3>W㈁ﻻiXP[3 k4din7"MW7>Bq �<0la? 6&>d 4Witr|m9MI)rf<uGpPsrFr҈"W�,;M@,N(DXR̈4}Õ-b9z|Xin݊h8tSs-9AkS.ԝ`4M6R9mu-p*uқ%S_YIl)q@K >`.\[�ddGƟhk�ڹvK'ޱ2c) fλ@Xw',;wvwIC Y6%#.A?mcFH"䡾,[0i,E RhJE(N,"h�Nrf%+KpBۀJϳ@q+@E<SJA:g\ ~XrOk9 _i%^0;o/D,`/'=1;3|*dbA`}Q˴-$:/m("P]=%5[ ϴxEco4" 1Oלj38ew 8}ɢ4�Ϲ+!Z;PI% ckc[ѡn.F̓{4TQJ1#JоlNQN1D~J(!O@: G^ |6#ߺk3i" ϖbY^w(ֳO7\&JE%3\ٽaVy\x2bRiI 7@:%e˅~GWO>-2:TJT xj 5Oki1O#@^0aX߮iv yp.&J w b)( g/=A҂ҲoAdz!$ৌ v!G_<_4mkU(X)30ߧK/(E2[%Wy23yNs2D]l-Me賯]2@2C=ՃAp d-ZjHNe\88{o'kq>".%:$|2:]H\!M3r QZ琤ڂswkw>"4X~t-CG<v9&tg<(׾#KB4LT& @$AO;eO ΂H[ /.)^x`K!1N8ϔf Q )P!3/'\A.˷,Č^-Vo Қ,ccDSv2yrH ]M@pNA&&g/$P N#qN.á�(G Lײh|_p1s`\PLA:h[.Huf4M/.[<�kD*RFMb7`6ue. ǐON]cm=yfk(s8%2/ʶ}%yF|nPpY6P.5! Y&k2|p辬k3yRCB$vocC=tgwꝙBK}كܙH}y j4at/D@Kт=Y:E8B9NDW.?hq >!(p;6ioٜH$Ұ~ǃyp7Fit e}wgu3r{&]7@'%_Vi?ჽbͺv&I%/uwMit0 76ǃEC%+A+޴ :T.ߝ7X+Mݚ C+pk*GBKE '.A9vǩ|Wu�DXE[ 9uXmT BuPt}ǂ?)9G4]_ pPF~o񇜖),[t U#"Ԝs ="92.3~xv#(([P; d{Z2K~~ygae9>J愺}Ϛ(/FyKhOqy9]m8>![@)2X7e? B@@%JT e+h_e)=GG2bd:6�ګ�J 9|n endstream endobj 339 0 obj << /Filter /FlateDecode /Length 1054 >> stream xVK6W*`ChljlW*d$7H}"%Qv40 oGᗞx)UyOK=j N;k8u񽰚pGh-͌vh7@]RGoS;.z(V皌ͿP;hM._cxi(:@\"x;qw!}3/׺?})_CZ|@-$ fft3A[~Y:UY/A  VA23hd03�cX8yy GUZ(45BKІ GU(Мx 6X 4(Τ =sz16ęa` !3P l̆IDsͬ0IYn3P ͱi@`J)@Yg98N\aqWhc'IqeTrnEe&QΙAou~�2m)14kRaN*$lK$m8 Q. 8II0B[aq !PwNwjOKy'Qi`x*4F7:H^e%*6ӻZVNZ 9vUC{Xη v'<-Ԝ362vL.VHv"WD> Qx/ Y<ggbիp. G) !jHCʡUt0N6P:F^> #*if+ri�}e�K1̶ #iסFB.(\J<2~*Ɔ_]!<=]҅::Vx5aE+XЪ0Q:=I:_/et׏z"􋚣\K-=}=TS{S\f.6ƒ \x8>g rDBE܅V uw",ڦmJ՗T(#]U!ņaT嬬19m׏%HXZwgBRYWG.endstream endobj 340 0 obj << /Filter /FlateDecode /Length 1488 >> stream xWߏD~dKU.HH8"!MSǛsMQA}8ǞfﲲY~QfŻognV[3ST_43eV1^Jf5i|ɵ)JJƝeEFwX˲(eɸHkYUA-Jgsrl6dk;) ֍@wҐ:QrӸU!]I}ȗLcvh4S;x3Hpۤ{)v]4 Qۧ4 ͘, " `L&/!km~\PZ)lb5CjHJZICrV1Rs@x:�9Qs< 7v*#QBSp0 ǽMX(wpȽk[<46/.9#x\ Dq�1"VH ?KBqď߾6vJP0S A(CŻs*`҅6A:®o9UwG Xʫ#¾!@f"x̽AgKG+YEc(M3LǛn7yϙ/bXy}+YBi 6 r\ x饸*TM{ L] =Y~!1 Umo:;f%{" }f9�eʖPr&_J&'0}qߴ\mro n}m{`kzOnm__ū_AkH ޴^0CLhb=K˓RU}ZvZ,!`4W�X5A%tp4@ORb YY} :k7C Uy<Iކ et臐&tOwR`"#IX0gL|yF\O{E:Fv{ MA& Rc P콽w -i� oI4 6k)>piGqg<!+0޹c|]>_deJڦ;9y dLm�6[azSo@# EW8uO*15ttl;xTFDd)ʳ)sm<9lab�7Ǜr$B!,>, $c/sOotp#ZTjPQ :-| .E3/u ԟ}tSHXR/qfw\ )vֈ5;J}+|FKsG^6� xFjq7ps?Wj9ܠg7 F,ygh iaD>å~i \B`^K~ЎiY9##vwdz�&ЮmNjV쯮<g>9,i :M`/@ De'^O \_zw�1|lPy'19yVi) )OK vB?vBf;PrPDS[hPendstream endobj 341 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /DecodeParms << /Columns 1053 /Predictor 15 >> /Filter /FlateDecode /Height 678 /Subtype /Image /Width 1053 /Length 2448 >> stream xߪ&TN ("qf2QTdtAA:%*E"B#K/K{#YNG#w\|3{�~_K�yw�˹3r|q+]8.O}k`Aǧzs`AWƧc`A<<#}e|G� ,k,셿,qkG� ƸpOG� ztq`A?,qf�淳G� zr|7G� ָg#}{{#}gܻ}u`Am_=X˳G� #`\r`AO=X틳G� zz<5{gƕͭ#}a`AώۛG� @6>?{㡍:�#P vuG� :�I@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�:�M@Sh�4u�ڮf�tC@1>?{�+f�츲5{gg�988=cq7vNqi?8{?uS?przO|>zendstream endobj 342 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Height 678 /SMask 341 0 R /Subtype /Image /Width 1053 /Length 53401 >> stream �Adobe�d�����C�    %,'..+'+*17F;14B4*+=S>BHJNON/;V\UL[FMNK�C $$K2+2KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK�"������������ ����}�!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������� ���w�!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz� ��?�#¶FJ]v?c4p(i$_I–#Ƨ^ifWF' D⮎%(UQl6>6:ҵL%j:#)Vf�[ YHNB)Gsv}cy㚟OՅp7$gyjMP�6�T Y \QEN/4͕Tuc*G5ţ$te1SnY-T$} ϭ[ mkZ+$yU'4Q]y!eaA)sxu`>ix3 *Ǜ]i\jsxty/66˾sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxuB6RP^H\ HNkүX[ GֹsNsqסqa4RE Py]vr.Z7 n+7/-6NNw0~Sn.4. #6ᜎƩlM:;kK I�GOK7\$-K *;ێTڌ4(Kem܆c;9:<ԯursw6xS 9StWf|F?i]Q`ᕠI$8eϵ;Kbn3ޗoθh i<ח\Kd 2\sV/庱u #]+ć$|4|it֦YB8$ w E3p[a8`9XvZ뺚I+ܡF?vc=(SuGh"3H͕bLrǧJtZsn1qi.yQ`26g@13VoIonfHS'v8�~_vsxty_:M~M$,B'G b,wͬ_-A*q s~vKxi6v(I֖-2)H'=z}b?5ylBA";qBP¨&{yeqz^[s�b_ay7\6{*6;"f |NIҬ_I9S*m!X$!*wO�|jKF q%vf[<|n JɓrrWiFiUv9� �|A,Eb2xWJ{ #sxrwDCZRhڜ+ b.�?.FE�tqK4Tu$oθ-IT{c)|Jq�G­Y}6fOkg`tG ɜڀ:~魼**sI##בR#<3;\.0.0X{.6.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7^mj(l%Hrm3]\F�[K|+bYK,gëz5,u1L�Hog�ѯZXlxe3Z;le=?ٓ�]c?`?7�.my"u026rqZWb6%gP#1 A'�sm)kq\KOL6:�l/.kn㸷dU KRAw S~2E�қ-L?c?sNu{l#i H ^X@ ֯lZmDф9]Mj E� SȿVei| )Gܰ 60Uf[iIgd8sz`d}T�l/.j E�eE�q`?7�f�ug?k[.?Aec*W[BeSB"N0�{PO5O�"��@ٿ_]nM*h&.�w�VrѺXX9R{*1]@(D&N~DF9j E� Sȿ#u5U#piT�l/.j E�-Y" #jcQltcWq"6`XBs�>6o�G5O�"�9D0 A 8?QD_xI˟-Doq(f�t}T�l/.y +ك3ZʸNbhfXv@8< Sȿ>6o�]T�l/.j E�ևo7dsX}IR[wg.K�sҮtT: 4V?@e( f�t}T�l/.&WQ7iF8W�hs1 [_vPҦ 2܄me`8= ϰj E� Sȿdլ&G7T.zn`0" Sȿ>6o�]`7xt5_}'rNXc j E� SȿӼChŽVi�IvI}{ K+;2OhbA# ր16o�G5O�"�롓]⹊I$]8o c�$Ѡ7f�t}T�l/.*u9-5*7fF> Sȿ>6o�[늺 ̐ga 2 {F1Qj ~K2۲RU#Pg5O�"��@ٿ_]nIӧ`Ȼ2 8j++e!A(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]8Ǯp~�aE�qVƟ??/.X꣦??/.(ZIb�$%4ہ,C:>@8k8՗󏤱t}V?ǧ�]V?�[�P6~)p\XԢ:<�q7s]P:tXQiap�]V?u�Z9ϟ?�aE�q�bՀ|�tT OO�cE�qmjJ%W#??ZAϟ#�]O^>]QO,v*вF1OO?]Nj-X >p?_]bx�|t_]vP,aOXOj/~(6Z >|�sq1o@X5+J4|�3d:w5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�uR3V7nSM{uyWO@W4k�^0յ!1H�V/y.:n<�x92}ýt- ũ#t^LdGT+ˆL(+�xQDg<9@[pz7�{o]�罷o.%V"p$A 5~�{o]�罷o.+}G×Hlyv2HYchWvw�Igeumc.2qV�m�~�}�� �3zw.֩>hFbsqMca{c3IVmSJ�=to��Ѣ�{o]�罷o.2|WZ`e; ['܌0gD5ň^e¹n:�{߆��=th& .%kG{<Ɇ'd Uq *jSSyb7�{o]�罷o.4h�7�F�m�~� ZX,KS7:+ �fxwXͣ/>$) $mt�罷o.�7�@޽cs=ΏJ`S73 !c# \{;Q^N\ZDUb2 hxҶȻiC% S�{o]�dQ+9-~N[2bWRf@O*jݬYth!GM˹ @88[�罷o.�7�@4Vv�m�~�}�� �>&?1V¬y�:ݭk:nkl׋j$(]6ޮo�7�{o]�sˢjQy`)>bEV Cgnz95-~ɶg]c28<go�7�{o]�f_Y�GΝms40OL:+;}�� �Ѿ�{߆�FB;o&oMy Hԫoc5�{߆��=t.E YH 6qP:Z2YHgվ"3+4 pp+�=to��<Aij\,[" U(̬3 9zs]9�A=j�=to��Ѭ-wG]YۙUVQ~Sך�{߆��=t>]M{ulk#0; Thhz[^][HaЇ<A�{߆��=t\߉`Ӟ!0UU qs?JVǷ"gU?WQx<%w-;o��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F�=to��Ѣ�{o]�罷o.4h�7�F�m�~� +;}�� �Ѿ�{߆�F?ӯD�=u_῱?l?@B�裑fL7 a3)?|�"�]@?޿�M+ O,pG)fvu$Vw$Z_ :Orxb�҈^ґ"oTf� �C�}�Mo* Dm-B9n2xoִ.L�Z�}>ve<Z?$-XD%Ԭ-<ɰx4i??�W׷-ΒPL?fM*E#UE`KZ;n?/Us*^rBv*y >[]3 Eb rsR9V7Y"|}*P;W=;~4ˡ�dgj񿞧o¤by he�OڣKe6}2_묟U9罎of"l&bFٸHxi\syk}k</Ge888!֥q�?߆�⫝̸^E Ik%Ӵ3 v% 6`<u{hjg=Wvy6#nznm�U��m?V++Y-DsTy,U$w $UǬit@/Uͷo*u�P}"EXal$naGaqCy&2fFx1$GdԐ>Tep'q�?߆�⩖sKqkȥHO{j?] LK�g?Ω"K>~87wkqq$,p)12yxRȗK#ڀ:I�='h5x�z1zf-^id%Ǘ l�t?Ӭo;F+紷HI\j~enx]QI"XOOǵ]{,OsL8{�M^VWV3Z;V© @�4V r�]h.~wC|#?)5!5D- "HX󀠌NɥV G$ ,'IlI8];K=*2IPhSH݂$Mekw[ ۹]LD`Xr4.(5[m~Fѕf ;e?F_⦗V.`mY#y> mBcıj6F)-.ܠFL)YPNH�GnV'YXʑ=ϭI-w;S$?J|d78|۷@[G)%ޡƱokçO4kg>m@?Zr_^7]_z* X@ 򣃞Pr^꺶oMCH@-]X_qWcie$ee Wk^+:n-Bp1?3g�+<p>@~kPmsp>�faǕoO1cmE�~�1�u�٪�~"� �Q~"� �V#zXͧV pҨI?G6 c,K HM}\ �K %<�zd)p{隂�\�&F!-_{P39 +"icUQJ�W>f_nqdd8'鞟l�i�l�wv󋘄#?\.5wL2r@t=@](db #ԩ˜ s�\�P%�V0N2GN{S[^C$L-9X� I�rO7?G}gʰ9V3,Rz  Ƕ܆'9g" [HpU2 igL�aj[+ M>9 -2#:V:�ECE 9.XuS3JOYzmaGB }ESKk~kI1H [f9~Ʀ[{Y% PdZE9lŔWKO�I~"� �Q~"� �Rcg5ԡ8Pг=�W9%Cy5#%ǯmE�~�mE�~�h@q-l CIݑ/myrwomŜ*2FpqP� P: ީq*nI ~@XrpOݍ${͂{VVLʒ8<սo*WS7KDR(c,jY2dxcoʒ}=ť%HN:n?/UAiS!VfK[vA#""(FA'�ͷo*[ s}ue&ЯP4]= ԏ.<9B#w46ͷ0  '8:o*=ķWyߛ'vFznq~ӡ,$OAY�A _6_jw1[&v.9�;Xn錎xVִZ<[y>c<0*pD`t%nWP?$rNҲCnT*y^xB'HՀ޹x4+Rbnhg U9|e�8 _q<8*8I)#Az"<A@$��~%…4@@$ǭ>yV3mLԃTHnG;hD�gi7:8R;K充�i?LQ(�{�YHc2Hvqu[!ׁja*ą�wW43c[* �tږ�?R]wȓ~blYVF2Uµ?lp4{A@>\20\aQ ˂�ӷN�;EHU�~5NV!.8~75Jz}NI׽�hO�z'?\\rqm2anZ<�_oL\1c c?֢whl1S(�dsץKߗ�* l }/s@$72gm<�Sw�?ߓ�U7T2M&$HQ aipv W9c)T2:DX0<~E`k-ިLG,R<()c*Yf-c,< <�8h;YXw> eʌ#SU{/-�]d�ڬPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^a`�iקט|k�7�t��?{�xD-/�s"@c 8d(��@�:et,YʮKgwC<s4mc A rVziTkWUwTeX|2?xOp:o?ʓ)`�kP6I{*b$(4Pl(��^�A�{n5NJַ^\*.Dx 2L3ckijRe..r=*+ *s4ޫZ @'< �5CrA�o{]3c�k-yiy"Hr?rpFwdMT?[VtM+Me^_>V9 <uARwr~>c}F:cE<<5吱-(c{g=O~�NߍP `?pO f{["I.=H�g*y1$0a#!r0X7۠?SMu=GHu(/Y1R% 9>_*#{HԓSgL b';O=A�A7)iť#8N(죁Rmq`6ӿVm#h% H >U+MFTIqo|#wzM�~(Iڊ +N�wJfD2?s11;}I�UM:n~\ r*x8Q'&5n825Ie^< Z7zM�~*M)"Ȯ~{lg1eV! [ԓfI],DˇF'ILϵҭP:9rI1ր#n.2!R @B?ԱxS=vFJAIHR6mFR=(Ul|O-9OX8 3$s d`fy [FʜnxFqA |g'GVR[΂8'ӥ3A �X}zVV]^SOG0+5<oK*��2-_Ns GGQS°Emy (tU�?*jvזQCD]pڻ|ei  %g8^pu=(4#Ж <RIW'h�Ge.^=д Thx$k[m:(IEG=\{Yp>G+@{mG.D3,!=c%y=MixCGԠ6hylh\\iS8'khڶ2jz[Iʫw8L @6 '��r=31tolTFU&dڱ%e%q{0ˀ[&3v J46 $mp2A㨮M}dqt&bN7Fkf#~JP\j"̞lcsvwct--m r~$ 6q\1 ʰ#|g&~{X'_g_AW/:_A-AmP>d gzbZl,}t X�q���(mr.?�n5hb<M}f%]t߇� 8<3O Y_Emp&A2REUp d۞WM-t)ȷIyb5$�0:(Q 85szM�~(t߇� �n?_s�\WnC=ݳP-]eQ?$K  S8;|?r#DdvRR 7c�n ; )=ϥGtp43#73lq�pj[d1=�~�&{{q$clڿn?ݫ @ICTu6&HFv^K�?V{-/#asW%;{VVtdVER+H!qی720zO�~+;ZH5kGϻqX !,$s)�ѵ-i* OP]HNU`gKo��y?KdPaG)_� }Bi1J�mw$H\`sZu˜p56E}vM'1FA2p1�3r .�Ph\ g gz tڮ'�;9��~5hjmXL @-Lh'5s)TB v3<Wo=&�BBҠg%1+*j)َwcw3C#F*Jd͟<neuX5Oy/_iH : !S89QBKf7 dUBFJHhY5F~)/ ���m��l�s-5:u.gẋbHAU_ F*{Y=FWIr|ځwuqkjviI$q[#.'Ec4Rd 3ob,QǝxI�*ͻ v|ɿCʸ��q4{1yu{\[a#*˅ 6m m:̑͢I,.G"#`H VnJ�[p n: L6%q*۠?PeZkqEwqϗXP`'<VM4N\"j?/\bHhۆ㹬ֺԭխdތ߷2Cʎޫ*Q#CA kM:8nB/UF28:6V�©Zα7L#f8 <WxJ�Gz_۠?VlgGI,O$@ �]c�֒+X"HHB%p�S.c5HbD<`0'(S1~ݧ=1ۯ|��)z nvswR#]l!=�s﷑Fvu=@z_%"4S^z)4S$yF-)ϭJlmec4|&�Ѯ[ěi�vn:~uM��e5mo2H'`[~5$xrv4,&*J�$+gob@|gk]Xr=k1|>I$c'g[�~Gj}-梮ch�V:=n?]~~~1ʆL]۳NSTѥ ;W{@+3o`t�q޷<Q\%l#"~"]n\m?uNH*FA `hVΎl{_ZD,m.~=�K�*-۷ygv3׮8Ҧ`#%j+FpO qڀ)w|\a \RP?*5)ue9VYQqr) 1oWT(@aKa{?RM:(-nm.PHx ٻdk}r/n�bޡ3XrYk #]<kF9Aړo=j]#i#Y$<'"JYIK;Ǯ:~¤K+꫅@�Q?M�]d�ڧ,C ;� O[Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@yƿ^^a`�iۻs>OJB]4W)UK 3si/RI?\[{-L H;ֺXL?sv>̾ ?�w_ /�G�%�jz^Z+JWzfC<lc*OBviRu[I)vp;�Nu��57r1TՈqt$ACqW1�lFG]Rz�%�hӃy$MpSj!7�C?T?ڷ���hX*f?8?K��I[i�q4j;O�5;{x�I?�w_ /�^yq�<?/&Kl.4Ii$$'e[*I9 { �I?�w_ /�V�߅� ?߅� 4*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7 #rFcw#Ӄy$Mp;�5� # j}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7}7€*i�<_&8?K�տ}7²I*(/b _p;�5wi+2 Dpvckcҭf1[}._qW:tq/T`%�~�i]Ab*>�ȿg�m�4Z:]Ί��h�;yHQv)Œs>&U}ܠ%9Ǿ^ &6fiF`[}�/Qfu]\G5IewP�yk (FMƪmhgȶ%[6:B:g< 0ǮY$H70)?U�.�=?�h�S�5ڪQ3Y3!u{ٜ*Nߕr}x!9&es rmct" �{O?�罧M7Va>{Y2刏?/oǶ=5Ĉ#U< ?^8�S�4 �{O^ҏ,پ㏢aw}G? a�^�"Au?i�}�]ΝZ^(B@NQw֔dm(7 ( ( ( ( ( ( ( ( }_OP� @_�ǍrokN/�75@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@c*4@X٬�΀,y!;FEy/���0ׯҼ�~hK�"�һ~�ȿg�m�4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( }_OP� @_�ǍrokN/�75@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@en"Y 3Z��]+n);_YFRj�0_�(_�+F~�3?=U�jo�Qjo�V{7� Wfw�ϥ?G�ϥ?Z4Q?گ_v�>��Es{@Ii8kUoA7TԞ8i8_#mc4DRVcQE1Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@duY>$�}�]y���0ׯҼ�~hK�"�һ~�ȿg�m�4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( }_OP� @_�ǍrokN/�75@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@giq�Ѭ/?5/?YO6?720pES͛=f@IS֭xEC_�H?�*Mr8O^ߩ���?�׿�[tRq8v1?�׿�G"?�kn9=;>Ky]g H?j~mLo#ckrMmǤ�ͿaX�ȏzͺ2ˡDmj�?IQ�Jȩn:R1]]i۹dTf7 9UR>TaZhÚGOEs&{q+c-+m!5{R7_�T_O5dNQRW�Ee�j]&_R7_�O'Fu�@ƏK~k4{�M{xI�Ee�j]&_R7_�_jQYڗ_ hԺ�MGVm^s[u.FJҨpf*K ( ( ( ( ( ( ( ?'^|I:�J�a�m�a_y���0WE?o�w%�~�i]�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�OP� W*� �֝f_�ǍrokN ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( �R��AY_~j_"m/̏?.ŪzA�\U�Ȼs_[Rj((q4q8.:i7i+aq$,h址<k·PV)A =kZK[m!C=/XYx]{_R<�N,]F>i+wv֒$4nG*r*jʹmmb/�Z�4FNUx?v�2soi5y  [w�[�ȱwl$*CTݚG-yBn 3455 0�S袹͂(((( �O+R?b�y?J֦Y- +#`(�(�(�(�(�(�(��ε �ğ ��FzW|_�o� �u _��W}\_�PEPEPEPEPEPEPEPEPEPEPEPEPEPEPTk�]r~ ��Mie�x&F�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�/?5/?Z5��]+)qF'S�"�\Z�ǤPOqjg�5U9~&*M_ֺ"]*FVpE+rъ e?8=E(+I]��Tԭt[ V?4cg h<sm=HSnoK7cf}ֿX1_q��>?��>?ߏn-VINEgo֯3 %;#xl^Gd^\Q_q��>?ԶmgI"uf=OM"Gsu?u0kѼ7]Ūwa ͱE+K':PjON+=(M(((( �O+R?b�y?J֦Y- +#`(�(�(�(�(�(�(��ε �ğ ��FzW|_�o� �u _��W}\_�PEPEPEPEPEPEPEPEPEPEPEPEPEPEPTk�]r~ ��Mie�x&F|,-Ħ3&X.Zw�@�G?ְmN?֚2^&FtG�nk]�*�Qw�@�U<_K͛y?t~jzev3O'ڥ̎$G.Nz� �k]�*�TpxE6"+-:zU}G:u6KHNd'@?�q�ֻ�U�֫Z]{X(Ssyu-'̃Ȋ,6G'<(u|f B ^f-sL5oi% X�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oVv�w_xs6/#gխU^PT6kߏ5%�Ȼs_\ƿ EmH+v1[ďZT�'Co� ?3i�(�ß�&cxðkۗKm:Ll1۸d{ OfQ� ?3i�(� OZV}w:kD<q%֍7:%ٱԂShuc+xoM<9�AOG&�ͧ Mqe6k ;?nWezŮ)ZYIcn~� ?3i�(�ß�wmq6% Gnv+omU=vծ,e cO&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�+fx-Yaw#a@.?b�y?J˸�b+ZGf4肊((((((((|I:׬�΀.Ҽ�~k^A?l?4%�~�i]p? _��W}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@S>v?Uʧ}_/�75Y�q�\Ӡ av_\ԟm5t a D]Nq8lksm ~\3Z�ϲgho}F}/Ű%Kl ?27~~8\7?/exW$M2[nt�_�Vº4ivJna_|ր8;_ɣ^Xu)n綎=ѫ�X)^g_բ9ƸSq wZ?t�_�غ/ƀ!ѯz5 Ba!@AQ\Ŗ uߴhְ XD7dn}�34b�쿙��Cos{K(o^ O[[;{00jz� O>i�>߱V( �`�X?أb� O>i�>߱V( �`�X?خk6VZЀ#-g_7j��~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬVvejo5m8ccVgiq�~> 2ЫI UKCk 6c_f=*�Ȼs_[Q`�X?أbB-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(?QϹ�ES�1jO?k[Q�}rk''jF+?Ԭ�O+R}?VcKyz((�(�(�(�(�(�(�+ �ğz?'=+>/��ц~��@__�WE?o�w�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�U=C�c�5\zߵ��@j��<n?#Zu�7ɿ:�(�(�(�(�(�(�(�(�+W3�_�ںj|U�! �趠(((((((((((((((((Կ�Ehv�wC#Oqjg�5UC?.ŪzA�\V�d/Ԛ(4 ( ( ( ( ( ( ( (+?�OdD#�'F| �"~�^@?b�y?J˸�b+ZGf4肊((((((((|I:׬�΀.Ҽ�~k^A?l?4%�~�i]p? _��W}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@S>v?Uʧ}_/�75Y�q�\Ӡ((((((((k?-g_7j�騢�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�+;K�KVgiq�~> 2?�Ȼs_T<S�"�\Z�ǤoN_I@(�(�(�(�(�(�(�(� �OO?k[Q�}rk''jF+?Ԭ�O+R}?VcKyz((�(�(�(�(�(�(�+ �ğz?'=+>/��ц~��@__�WE?o�w�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�U=C�c�5\zߵ��@j��<n?#Zu�7ɿ:�(�(�(�(�(�(�(�(�+W3�_�ںj|U�! �趠(((((((((((((((((Կ�Ehv�wC#Oqjg�5UC?.ŪzA�\V�d/Ԛ(4 ( ( ( ( ( ( ( (+?�OdD#�'F| �"~�^@?b�y?J˸�b+ZGf4肊((((((((|I:׬�΀.Ҽ�~k^A?l?4%�~�i]p? _��W}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@S>v?Uʧ}_/�75Y�q�\Ӡ((((((((k?-g_7j�騢�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�+;K�KVgiq�~> 2?�Ȼs_T<S�"�\Z�ǤoN_I@(�(�(�(�(�(�(�(� �OO?k[Q�}rk''jF+?Ԭ�O+R}?VcKyz((�(�(�(�(�(�(�+ �ğz?'=+>/��ц~��@__�WE?o�w�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�U=C�c�5\zߵ��@j��<n?#Zu�7ɿ:�(�(�(�(�(�(�(�(�+W3�_�ںj|U�! �趠(((((((((((((((((�PXַ+;K�KVSr4;37ėɡ_#iƭWmukm/9^xEC_�H?�*Ӓ|^N;O\~k4h�2_*y'߂4~,ѹ�eG.?5�ѢI�7;F�7? kF9'߂x'\~k4h�2_(~93nqs�@ˏƴh ~,ѹ�eG.?5�ѢI�7;F�7? kF9'߂x'\~k4h�2_(~93nqӭ&me, үt��Lg}WDT\'umVYs�\/G{-kj?�OdD#9W1Y�׼Veg�^1ZM[AEVFEPEPEPEPEPEPEPY>$�}kA�?o@a^A?l?5 ��F��ȿg�m�4/� +((((((((((((((~S>v?P�q�\Ӭ��MiEPEPEPEPEPEPEPEP\ϊ5oW3 xg�E�tQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE���]+FԿ�Ee???_]?U?)�wP�-W�ʷ'/~QEIQE�QE�QE�QE�QE�QE�QE�Vt��ht��eWe3j;Gu�'F| �"~�^Zڏ�#Y>�?H�eLKW1Y�׼Veg�^1ZM[AEVFEPEPEPEPEPEPEPY>$�}kA�?o@a^A?l?5 ��F��ȿg�m�4/� +((((((((((((((~S>v?P�q�\Ӭ��MiEPEPEPEPEPEPEPEP\ϊ5oW3 xg�E�tQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE���]+FԿ�Ee???_]?U?)�wP�-W�ʷ'/~QEIQE�QE�QE�QE�QE�QE�QE�Vt��ht��eWe3j;Gu�'F| �"~�^Zڏ�#Y>�?H�eLKW1Y�׼Veg�^1ZM[AEVFEPEPEPEPEPEPEPY>$�}k6wcK;SBo)(.fu ��F4Mr}8t_�o� 9Pv8ԏ4N/�CJ贈K�"�һŠ((((((((((((((~S>v?P�q�\Ӭ��MiEPEPEPEPEPEPEPEP\ϊ5oW3 xg�E�tQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE���]+FԿ�Ee???_]?U?)�wP�-W�ʷ'/~QEIQE�QE�QE�QE�QE�QE�QE�Vt��ht��eWe3j;Gu�'F| �"~�^Zڏ�#Y>�?H�eLKW1Y�׼Veg�^1ZM[AEVFEPEPEPEPEPEPEP\&ҵ]pY��-ta3 G �/OW-?l?5A,A+r��W:�ȿg�m�4/� +C(�(�(�(�(�(�(�(�(�(�(�(�(�(�*�U=C�c�5�A�7ɿ:̿�֝�QE�QE�QE�QE�QE�QE�QE�QE�C^��m]5s>*�׆[PMEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY_~j_"k;K�KVSOEC_�H?�*u~= �krMETQ@Q@Q@Q@Q@Q@Q@gO�!_�VgO�!_�VUv^6gQ�}rk''쵭�>?5_Zĵq�#{jV]V'Z>1DQEdlQE�QE�QE�QE�QE�QE�QE�_>ۭg7I_Nv$H![tta;b?!6�zb�a�m�aCvԣcb2 >8�{/?l?5Xs/vu _��W}\_�W)QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�OP� W*�3-lnwwxܻ3gqZܬ��MiEPEPEPEPEPEPEPEP\ϊ5oW3 xg�E�tQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE���]+FԿ�Ee???_]?U?)�wP�-W�ʷ'/~QEIQE�QE�QE�QE�QE�QE�QE�Vt��ht��eWe3j;Gu�'F| �"~�^Zڏ�#Y>�?H�eLKW1Y�׼Veg�^1ZM[AEVFEPEPEPEPEPEPEPY O( kA�?o@Q~U+Ⱦ/��ц~��@__�WE?o�w�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�U=C�c�5\zߵ��@j��<n?#Zu�7ɿ:�(�(�(�(�(�(�(�(�+W3�_�ںjowۛV(#%ݺ(ڀ:+OfQ� ?3i�(z�ß�i �ޢ4m?xs67M<9�AOG&�ͧ +OfQ� ?3i�(z�ß�i �ޢ4m?xs67M<9�AOG&�ͧ +OfQ� ?3i�(z�ß�i �ޢ4m?^53WiN�hB((((((Կ�Ehv�wC#Oqjg�5UC?.ŪzA�\V�d/Ԛ(4 ( ( ( ( ( ( ( ΟC�ΟC�WmGw�"Σ� �OO?k[Q�}rk''쵩jF+?Ԭ�O+R}?VcKyz((�(�(�(�(�(�(�+ �ğz?'=+>/��ц~��@__�WE?o�w�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�U=C�c�5\zߵ��@j��<n?#Zu�7ɿ:�(�(�(�(�(�(�(�(�)X@@eE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~`�X?ثPZϬQ OE�W�~s\1Yb#Sc¨9jk�׌PMEPEPEPEPEPEPY_~j_"k;K�KVSOEC_�H?�*u~= �krMETQ@Q@Q@Q@Q@Q@Q@gO�!_�VgO�!_�VUv^6gQ�}rk''쵭�>?5_Zĵq�#{jV]V'Z>1DQEdlQE�QE�QE�QE�QE�QE�QE�Oֽdtv��^J�a�m�a/�CJ贈K�"�һ�(�(�(�(�(�(�(�(�(�(�(�(�(�(�*�U=C�c�5�A�7ɿ:̿�֝�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QXڟ6om̐+I({DM?I-eRߖjMn?/�kQY?7d�V�w�A[�GMn?/�kQXXM6�+YMoCbiF0'PQ@Q@s6P5o�Bj髙�׌PMEPEPEPEPEPEPY_~j_"k;K�KVSOEC_�H?�*u~= �krMETQ@Q@Q@Q@Q@Q@Q@gO�!_�VgO�!_�VUv^6gQ�}rk''쵯~nA$߃\_|WgwOVx!YH@#_ivG$`x NҠ�_Ƴ9?R�?NtԿOZY3'F4m�oz]��L�}K��d� ?9?R�?Ÿ�_Ə_u�k73}/(�L�}K��d� =OaKM/_u�h�_Ƴ9?R�?­i^,uM@X.cd2ݣʎEڧy39]Xzֽe�EjS )+`(�(�(��ε �ğ ��FzW|_�o� �u _��W}\_�PEPEPEPEPEPEPEPEPEPEPEPEPEPEPTk�]r~ ��Mie�x&F�(�(�(�(�(�(�(�(�(�(�(�(�?Z֬=Rm5iW(v#o<_|_un#[yr ZҼaswZYXF%#~4LҎVZXT00�KΎRT?+;NN�[>#5ۢ)*p:<Qyw6K]CL^6.A?0q+c<Gme] dA#B:Ew>e}_gU0> .'ie&J$s#%'2 2+[kM:n5TΝL&[w8VƟk@?T/T } Zaswa(0)xjKk9uC!Y [>Fec@�mw4 o&o7�]51KM<q3GtY8]}s?? o�_�0PM\͇ [`�Кjl?jQE5Pe(8QQT�|_?J_bJ*?>/Уϋz(%OSՃ zE 4-QLAEPY_~j_"k;K�KVSOEC_�H?�*u~= �krMETQ@Q@Q@Q@Q@Q@Q@gO�!_�VRsĐI1?Zʪm+.֓JOF]'q/Qs�A;Žy�/Egg\�N_:w�_$?fs�A; ~Ks4Vwu?%� ?'q/Q?PrC�h3�%I��%YGL�E*pA8w�P4�BZpiXQI{ZGj?Z�_�A]5?G-QEQE�QE�QE�VA�?oZOzW|_�o� z=+>/��ц:/� +/�CJ�(�(�(�(�(�(�(�(�(�(�(�(�(�(�zߵ��@jTk�]�x&F2�<n?#Zt�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�W3@�o�t@�-[�@5s6P5o�Bj髙�׌PMYzI=Ɵc=kRO�Mc]^~_6Rc��O�8EWDjQ�/}?|�j{*ʾڧ?�>,TaVi�q:п�뼟jG[ӞR.g}WhEQE���]+FԿ�Ee???_]?U?)�wP�-W�ʷ'/~QEIQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�ǚx�!YW�P4�BZ?�(Ox�-eKKQ�ڧ|Ve�EjWUoC�66I(I* ,oƐjVrӋ}.#�1׿Z�׼ SBͮS̈+n'ӊ Mg6ajtF4›;\w$7�ﺿK|Ee�4N(KJ]V�_-}xE�| =$7�ﺒ]H`I\U[Vo�<"�cpED?j#*Xwcz|I:׬�ΠԻJ�a�m�a_y���0WE?o�w%�~�i]�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�OP� W*� �֝f_�ǍrokN ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ~ �`�(fJ�^0M]5s6P5o�Bj�;T�7֍gj�s�ʷ~hڇLѢhif`'b/]QiZdO+BJOpBToT`w#Rli�Oe}Os/Vv�o�]�Ѝ?cO�ȿ画jvQZs+ ⲕZ~>4{9{GnQT4�cO�ȿecS_U?"��/kOރW2giq�Ɵ�?U*OqIFaCS#Nq7$ߘ)�wP�-W�ʨxEC_�H?�*'~QEIQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�Rd>o)!P>VLU<Sk%ŬR@ͽqXIm-07Ekk% IYw\szT�4��ޕ�?751N5コXҦ+�XtmAz#b9L\Q\+/~o?�h�wMuUj˙ ʣս΋W#&Oȱc�Ѝf»ҿO&BXdV | �*5s撶J(7 ( ׿'� m&�!=jOѷY>$�}kA�?oRh]y���0ׯҼ�~hK�"�һ~�ȿg�m�4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( }_OP� @_�ǍrokN/�75@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s?? o�_�0WM\?ŻkWVSHeZDC#f;l?jխ[Zq_]@rKO>NVfXn-9UR[<<PaYڧ~i�&k+U ,G3bf�`FL ubhqMqʾH=ђj Bu (#rzƮXDžr_+)SJ6Iҡ]"O"/ȣȋy'*J+˱$�ED_?RQE`}""/ȩ(˰s>~D_?GOTQe9r?"/ȧ** *( exEC_�H?�*u~= �kɗ~QEIQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�W+k^"mk1EK&H', 6Ӛ꫎;xX8duC �I `~ڵOk B~nIopsMĚ\K2\6Ƞ-\1efz(5 kbm/I� ;~]dD-R=5섯v� @\14eݩh3\�Skmmr] `f3{ #Y鄱/�^+GZ֝?4ʼ7[wmrNx^XG\g& 4Ҧ�Ӟ=xW<7m{"YK(p7I uK]#Kkԛ"Бa;$'t9ZjMXE2mu`�q?�kE�QE�V&�!=kn5 U|?w捺?'^|I:B=+>/��ц~��@__�WE?o�w�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�U=C�c�5\zߵ��@j��<n?#Zu�7ɿ:�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�+Wao7k>%7l-0$0'�gRj|__:~_?̗7�G n?*iŢ9�oXVӢ)HmL\MeZ^{�3_7�ǿ?o3q�Ui_yc$ -]Cqc=:}(/?�}nܿǓ÷rI5yU`H?kiehI;NTcNm+ ][G8UsFszzB9sGWdTTY==肊((((( �Ȼs_T<S�"�\Z�ǤW3/Ԛ(4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ׿'� m&�!=jOѷY>$�}kA�?oRh]y���0ׯҼ�~hK�"�һ~�ȿg�m�4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( }_OP� @_�ǍrokN/�75@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7FW ; iYgi-bȤ�6F~_y(n"MKU[٧ԖymY5z֬xK]6TVR,X(*3zU:eι$ol[w0i!�_ڣXu8Uˍn$:쨠+7zjI >$ WeX0 2)SE>�(�(�(�(�(�Oqjg�5UC?.ŪzA�\U}?I@(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�M{Bz'}�bk?�;~uOֽdu&zW|_�o� z=+>/��ц:/� +/�CJ�(�(�(�(�(�(�(�(�(�(�(�(�(�(�zߵ��@jTk�]�x&F2�<n?#Zt�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEu~= �k]?U?&oQE&EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPXO?׿'� Tw3ߚ6 �ğz?'M ��FzW|_�o� �u _��W}\_�PEPEPEPEPEPEPEPEPEPEPEPEPEPEPTk�]r~ ��Mie�x&F�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(+?.ŪzA�\U�Ȼs_UL&*M(((((((((((((((((5 [uOD��gS4mA�?oZOԚa^A?l?5 ��F��ȿg�m�4/� +((((((((((((((~S>v?P�q�\Ӭ��MiEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPW]?U?)�wP�-W�ʫMETQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@bk?�^��_G�@5QΧ~h۬�ε �ğ4.Ҽ�~k^A?l?4%�~�i]p? _��W}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@S>v?Uʧ}_/�75Y�q�\Ӡ((((((((((((((((((((((((((( �Ȼs_T<S�"�\Z`" tC'$TVW$7�?%ѿ%o�}b;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V�F�G$7�9e=;V5 SKJGV5m;;u$9i.92{qF5Yq[;Kڠذ#+Ⱦ/��цR @ҫP`rEy_���0WE?o�w%�~�i]�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�OP� W*� �֝f_�ǍrokN ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (0*zޢ-5~o�<"�e�ȇ�/Q[*j(YxE�| >o�<"�ME "�Gm�_dC[(-5\,~o�<"�e�m�_�/TQp!-}xE�| .D?e��SQEȇ�/Q[*j(YxE�| >o�<"�ME "�Gm�_dC[(-5\,~o�<"�e�m�_�/TQp!-}xE�| .D?e��SQEȇ�/Q[*j(YxE�| U2CBjZ( {Ih.>*6n o9"+2d̨<>P>4 2]'LK"(vm*=:o�a�m�aU6>| xW|_�o� �u _��W}\_�PEPEPEPEPEPEPEPEPEPEPEPEPEPEPTk�]r~ ��Mie�x&Fhq-ih)#@Vzg䄎a֤н�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'hн�q'hbн�q'k>_ݛ-GBrO^Qij΢]H�{/�{?¯OΦw�)]�� =suuS�._ j�.}CQ\S�.>wR}H}!'NI]QX�/�/�fYEc�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84Ec�h^�84h^�84EbR: WHȞ�@(;:s#:Jv-ql dU�]ku-&˃N*^C;MnBo*ijᮮQ)D+S@5& 3i\w8B�~k֓KTspG+�ג_�o� �u _��W}^mi!D%,_8-8ֺ {�/�(� {�/�(л��b: +л��b {�/�(� {�/�(л��b: +л��b {�/�(� {�/�(л��b: +л��b {�/�(� {�/�(л��b: +л��b {�/�(� {�/�(л��b: +л��b {�/�(� {�/�(л��b: +л��b {�/�(� {�/�(л��b: +л��b {�/�(zߵ��@jл��b\3I̛)1h�x&F$L݅4FYbx]N"8?ʢ3z7NA�,hV1ZV \N[g'�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7<y +_�~�}?ԟb7 `ԯtv� Gۯ|�Rtk Atw1I[Q֤XJU}'_[C54K[��:�%�5ұ=gv+EG?QMc(?�_|/�:ukt�/[ ̫[I�}dI�}4K[��>?/{ݷ1OԚvxE\ ck:}n[/hm⺌NL\ɤ*Iy (VnI�(m>ߩ?q琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�P琞!=a?ԟb�PFp9< cw{5RZ:J͹˓�R�KX]i,VKǿq^A/OHI `�a?ʡE>�>q�OĿf%VKQ˿}sZw}rO+ \m? HQ0@ x���0פ�h]�1^geO\W̋ܞ�w?�KI�Wg\g?�UEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^CB:_q+׫~8GK�/�u�KI�Wg\g?�UEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^CB:_q+׫~8GK�/�u�KI�Wg\g?�UEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^CB:_q+׫~8GK�/�excx{FOY<]nCIc8:_[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t����4Q@-?G�h�/��P� z_O�Q�?oK�@�*?3E�ޗ�Tf[�: �E��t��_~+�KIH2+苌`�endstream endobj 343 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /DecodeParms << /Columns 1049 /Predictor 15 >> /Filter /FlateDecode /Height 675 /Subtype /Image /Width 1049 /Length 1907 >> stream x1�K 6I, H3p9{yV' (e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JR(e�JU"endstream endobj 344 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Height 675 /SMask 343 0 R /Subtype /Image /Width 1049 /Length 68311 >> stream �Adobe�d�����C�    %,'..+'+*17F;14B4*+=S>BHJNON/;V\UL[FMNK�C $$K2+2KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK�"������������ ����}�!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������� ���w�!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz� ��?�xtXG�0>M@5&D҄Q֬yi;feu$ gRN;:9{IZ5忖H47-P{۫EsvzYI,~ZJ fu$[TS]B2]ٽ7ھg3 ��^Z߭ 4NJ7Njc+&V(N,͆άZhRPw5YVw l`zڣܑ]&ca&'56.+ Tլ#v /֮urRjZ#WoΏ9:a]oΩyywoΏ9:9:<ꗛG@|^mm�]oΩyywoΏ9:9:<ꗛG@|^mm�]oΩyywoΏ9:9:<ꗛG@|^mm�]oΩyywoΏ9:9:<ꗛG@|^mm�]oΩyywoΏ9:9:<ꗛG@|^mm�]oΩyyb- y%)}9\ECxh'HsY$-N~aɬ{K<"Au J�օ3m8>v[sO<�\j`qov|ۺBۏy3҄蝈1oθ5a,[ LIX Ǎ c9?EezdŨM~o$ɕ`rs{P5U,@OJ˷9Ҭry"F�RGjNZ}d+? wW?6GQ㶧x'b2G?rV+!zs'}qMn?]ifR~$uĶ:9�ީYkJ+�GԌU{yc612fXcOs:V*x\Ek=vc˷;å ;)uhaky%ea39YB;0kjWRדΫ>$yL6ǿ0&iTU`%q#�?oΏ9:4w...$F7!aԩ2>|7iVO4Ĭ,v_ǽ;K<op3sqJґ$ؼɉ峰YKr~e9X*Kk$.y,q1<#Kg;%x7+6zxRy'O왚i.ݥJG=z=�LKRM7<>+;3i*mi*x`pr:=8}!I1Po7Pͨ$3 � ?NrU./aa4-ܹv^vр뚱ܾ1hmg *6Í/#GZ; -g/?pN#iWwbUw1;Il R^qQ*۬Ns{Q~_go~* ;#g j_9:�ao0'?h?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ &*r U�ߕ� oG@ka`?7�%?ٓ?a\_k7ec50وf޹GoJ63͎zii�I Sȿu5f-j;qݞ{b.:m..BLF6 Xw0\#4 0~˪6=<oG Sȿ쨤mqStɈ/.2r4Ac'z׵ }GL626p<�VdK15ĬT} 7Nhc�@ٿ_]`?7�^%ݧn F̄q ?֯h=04g|lcw֘_`?7�f�uSe忔TIl Sȿ>6o�Z ͵qF5 [o)ڳ zu5!.yh&9,@_`?7�f�u6f.!J}Aphtc 9g6@?49^sf�t}T�l/.*(�@ٿ_]`?7� F[oUuAI9ڤ]fŵb&"ᘪ@sf�t}T�l/.Dd'm9/nc9#𨭼A^H.LY~F zb6��@ٿ_]`?7�kv[O&zz?k[\wzRkm1A'`c= f�t}T�l/.*(�@ٿ_]`?7�S^x=n 4]iDeǛZwZȶ-¢#bFBh f�t}T�l/.-K[ƍ.)eTFҫu];YRK[+\ e /5O�"��@ٿ_]t:,8sM]7f�t}T�l/.*ԼCxڔ+<vwR@<n \s� Sȿ>6o�ZxL}6i^b厇q�SK[E&/lW2Ҁ06o�G5O�"�룳lob*ѲPpH$�$r3W�@ٿ_]`?7�ʲG[,;O'=RNy /j E� Sȿ<K _jNM1#/ 2O SO5=,I-/V,w�\��@ٿ_]`?7�oiw1[z,Ī|0#sZT�l/.j E�eE�q`?7�f�uQ@o5O�"��@ٿ_]vTP Sȿ>6o�] T:p}�6z9:}=?�aE�q�bq�}T?ǧ�]V?u�F&6ch$Ԛh?Z1>=<ؿ zX(8j9�u:EK$z\mh'��j(6:9:tb�Mz\k�]Ǜ=X8l_]'ص\>_�cE�qV#O�XCcNOu�Ɗ�LRVtVF�3 "~zu^]?={?v4P {?}F$P2Þhj9ӧb�Ɗ�ū�]b��gϓ�Mb�밢8�j|b�2z/. (�gϟ_6/.J`2ۅ{3Z(L"]iRu'$ Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�~6o�G5O�"�벢8߰j E� Sȿ쨠7f�t}T�l/.*(�@ٿ_]`?7�ʊ�+mOPUo "Uyq*x~x-,8Oߧo��t{H|7}[y:1L֤ߴr(X•Puf\Fk�=to��Ѣ�{o]�罷o.3<U{3+RC8y\wj6z44 d%hն zgm�7�F�m�~� +}#R6py֢9㠕X,e{Vmse{=k X0^1=V7�{o]�罷o.4h�7�F�m�~� m?I+*�dGp�PcMj}jM"DdZ$Qߕ[FH]�m�~�}�� �ޏv GQ1%XgKxrMוU~lpɘƱ:cz�=to��Ѣ�{o]�罷o.3jwknno u=Mgg\j֗V2 mDˑ<b1 A@`I<q�{o]�罷o.0lt\ިUۏ7 TZ~DfSKYd-r9;Ih!ˑlAcdN�=t^隹�OO#SKpf@?53i�[v6&&kv{k+2 qV7�{o]�罷o.4h�7�F�m�~�gYެyhOY:ƿoX@#H,FC䃁\V�m�~�}�� �B_躜7Vo'tvtWWBN~bnF)N{`<7$ 6u FN8�7�F�m�~� Yj dkR@B<+�7�F�m�~� C7 <k'ۦ�=to��寴 bI-qkbVT|ݽW3> zƟ}) =٥0>`[u�7�F�m�~�{GεV,4W< H(xOVv�m�~�}�� �sz:ާ\E0@ƒtRw�{o]�罷o.9H|7ieH-�B{c$VSqڵ4 [YbM*Ǹq O5�{߆��=th0^Z.k^l*1�<t^kȅ()-E[b�7ӷ�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�hY�罷o.�7�@4Vv�m�~�}�� ��{߆��=tEgo�7�{o]�T?&�jInYd-ЏB=j7VXf�( İK{YF[hy`'%j$Z_ :OrY 5x'NKzl.5Y^hP97jY`|<3 �n!ID6-!p?ެl4[Vf<62]?ɿh#P G^UE{i`85sO_ oʲnׯ.%In݀gb4)@~~"� �W/4MzlӴ;Mʳe#!9#i-Pw0qNQ`VI<"*zO9i.P;I{J$oQܐt~I:>^�ӷN I~"� �U;VQHWpIBG 5AZK{y%P RF}e}4+ :He˜N ?Ju{n?/Un?/Ud\y?hH> $S,8/2|e3rǾq-l CIݑey!E,А P� d볁7mco+ 1*#9@ijêyx?V_m/n,y!A 6![TՀu-ż&O6'(ԁwXğ?�Vo�B-o J.7m 2yΛ2,gמEc|Q7ƚUeDiT!vM V§'+p@=@&$��~uw!$J#U91jCvhƋ9p?ZgR�v?@mK$BEHT1G(ppq=@sxH5Xm'[WrDV F<Mb^x.(Ȍ� {pM|4i.4& I$yTZX,f.@pd hj\I7 䑞qur~Ԯ5{Vr\A,r�:ц$6 za�ۃ?!@m�U[P:}OquPBv=FI<V5 4S= s;O� –ڭ五z\WQ `(CE՗Z[[\Z)mdddo Zn?/UpzuշHy-ͥ%AqK冗j0F~QvVkw s]Q2#<(Ŵeh*s'֚cڧQ�#Ju]Q�-G6 $Ax}zhMo*Xͥ[1Yc6Τpq�Hz_eVt(<CHD6v1Xm+ܐzuQ�zĺ:jvx?=mzq�?߆�'Եa&8\GӜQs^9IpHє2G@m',)J�'8ۏ7�Pi??�Kݮa5ӫ?>T^18Uր~"� �Q~"� �V3^+̶pЗCs0mݎ1<I,NFCЃPhUF*@)=wJg=O~�Nߍ2bk_<ڼoH1˛k<苜''隖uB[D#QG��m?YP!?p[nnQ:ٷ˓cPMFX2qOLB�i(L$c�nu�,JAbx i]UdfV =G v�⪕Վ$\JA\1i=ͅx+Բh51yYʯNT02?pU2in-c b8tHT=VGK�v���-4iA�?I�~[kkkZ׏k|Aju#֐ 7M(;g<7ӧh5x�z1zftKI%xH`;ǯm]/�A4&ۏ7�Fۏ7�Y/xkHkƅ摎)ۻ:oCi:3 Țb7`FF^G#3Ҁ5v_6_a=ݪLe gI:IV RDڍA�y9 ckBҡ�F4Km"2!ԒH0$TJegp׶=m9u A >6ۏ7�YK-rG#m@�}THm 6&y$mMՍo*5�R_CcKߜy6MzSn?/UTҵbHd Yml ծmѴ˂dgSmDxB8-'k@_lS1||>:o*OqwjaB|qCmPІt_ _d$JKK d@j冭sSkM0[*C6:0۷ߨ#Huc։52$b;u2b@yhۆ$g=}^X�Sv6-q=jdyVbyՑ匩#[ne{W Gr,7. 9l _�\�>0ˀ[&3v<jn�a�td78|۷E�G�ğ?�cJVT;T<zQ[(f6qQH<dps�`ebb HI�?߳4#7�r:ڞ]C+V)��3@ owg[,6 IYahܨ 8%y}s@ l$̀??V'd#t8Mnն J4V#!B3rhy0H<:zJ%fRH#=N@BH�)t/ߋ�hఃΚA8c9'; LH]0V]̻1+*M!lEd 8@(_D�ghğ?�ѯd7RY5$=qk >d�rPaav$|qF蛕B#֕Hd:ӽ 3r":.!��-A�~O�V1DD4L@tT2=+#MJ)yGiYd6H>tnmKc<g躈LdUX|<`q!r\j�&�hJ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (3O�IZ!rU?&�jĎ"GW)P +=�f넮iX#[ϲO�PNԕEwGn@hh#88箱�U�W +k3_ڃ<_ZGK#Yii4r0du*:H8#wqKg<hxTy#@%OO,\ZI,eؠb6�.��7p=z{+7YjyY襉(:{UP��8B} hdI꒕l�=xZid)][yhFʍij|$�TMhS9�ZNk襋hvf=٘O�dTn !7rGw۳OO4Ky,E!\[{lM¢䕓PO=~ꀼ�[+Ď�*MT�r}t߇� >�šml-4g庳r#L" *LUWp$6d}A<[;ld$A@ Ak;H"#A~gIISǥMg�-1/4SG�AʩmgX]&˳a_{U߷A7𦝄`^xz==ŭyʳF,Ap~bv7dtÚ_(ȸ #.<g pH =&�T&/跓}�"Nqnw\qQ&պj�ORj6)jasCc8?ƙ\%ţGLYp<y�١hZ"QIdcMrhʤ {{[Ĉ$+gJiPt<n3^d_,`:sUQ�;c�٪d(*#*F@UZ+%HqiwsU.缊_"ݶIE%x]Z֩s\^,M@ۘ+8e0z䜞0%ePB*t|$�e\rKYu/2^N!S9D>W9 ږsutiq$JT}8'_}W�BEj6sjVM&~5ηZ|B4%p}(u\-ҏđPt8<EpڥƐSK͹CV)H[*oAF9>�«j72KjymFkWel z`�wv-u}hVݢE&BԌd]kh,l]thmj:�~M=ZkWh]N2IN0+OzO�~((?�Q�-2?evdY݌36.\+y]TGCj+FpO qڀ1~!zEbc (=9AqcѥRwx3nu 8zeY_mprC AV}gkps^<_FzncQq92jI4|/j]$eoG* {X5i nۇ2ȼ}UD4dwzXCzegqy`"8Pn(I?�.[I;7HBC q 'X>\;\N0zU߷A7}Io? ikd9XDDɺEwC'Fv]Vv[`E58P0O='۠?Q=&��O �[_BĴL :*@;W=;~4���n` RWAWqUs=ϵU쭵]bHvAdNŁլz.5*X'ne##""h!cQF��Eu�??j�C5s ]$)6#cqu�?m2Х -猏{V\(.{+KgBf0PD䁌a `qu?0v�Y:yݝdAl#bߜE]m|7Gk`dn �SGy Dq#*]> O[ɰ$YyҀ3?.ƣ.$-lr0sߵ YndI`r�ǹʀ+hNڐ $,N}yA9Aۯ��y�U,ImafAIHR6mFR=(ݤ[]D*taEpԴ]7zk٥+y0ꐕqWo=&��^v݄!O޼3,'@Gn[8W)auWIA/@n2Nn>3p&|Bm#bmoVMw"XFkYTn8P2}?S �B5j^%!ݩ1QpѬq䑻i#<$t':z<mE2ȹ\'v-ek $FƿdP0L9(C&A<6I7T X\3I9nmoJ[eJ!�hmdB^Z&D(eV`y<}rG=%3 ɰw|vN� '%`.d IU?vqSnY5)Q&1ſy_;U߷A7_Fյ ;Gvk[r;H>fܿ)$F8 Q]h<XJ1n 㐆d{uhM nU/N|ךeiKͩ7jW&P"SHciYTX�3h%0#V7Z<mE2ȹ\' <WxJ�GzD6MG"tkg!1ȪiT9#`` �lb��)?Tno�PV{ؚ5jdQhTn8AQ1ib)aO� ;"VK#yZ=mf缊 "�(H?Z֮X*<Jm\X�ZLLүߜw9z{b<ָ��q:mvY$qhS r?¯#BGd߻%X8>ϰn-PdEO:-8_y9ǡQt� pq�Z�ː?5a;\G+>?�'kN[[m8|ϖwnq3~�8 �OAD H =�K\{]Ddc".y�3>zz?ov73űl84,͏N?S\ւT<T+==}v9"Dc#P ۟~�h={B�)?R�F0ln׵$"GW)P +=�G$"U9%R;xsc%‘?*˽Rxh},[38#'_ToEİ͈0zcͷTc; 0۫ ;EmH2zVrMŤ7rt}6?.d~![{]".fS)/$PD9ȓ`yZѮ|Krź;];Ngd"Xd`z$l:Id#${Зr%hz(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�̚wb ɂ~ﰩ��w_ /�U+IlZY-1(i" ~S}]l1П@Ӄy$Mp;�R,mBpBz-֡ K,or20vzVJhuw;8?K��I"TϗT}4jHE[(�koTz�%�hӃy$My>ɭqײq�<?/&Tz�%�hӃy$My�8?n?睧�{x�I?�w_ /�\6-Ƨi Z4rN Di�~+ eI#HMOb�%�hӃy$M[i�~(i�~+ʟp;�Nu��5oM�}_M�}_ p;�Nu��5oM�}_M�}_ p;�Nu��5oM�}_M�}_ p;�Nu��5oM�}_M�}_ p;�Nu��5oM�}_M�}_ p;�Nu��5oM�}_M�}_ p;�Nu��5oM�}_M�}_ p;�Nu��5oM�}_M�}_ p;�Nu��5oM�}_#m1FHr�%�hӃy$MIsWZ<I*NU0�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�o?�o?��TӃy$Mp;�ot>+9K @0>Bp@U4X"@�w_ /�G�%�jUZL v1/k-'A:і9lfhtRJuF}\6�K P3aW ,țbɴ 3�C`}k/-]26g`y8Au?i�}�]Y1|TVD6mo5 nm ێ}n`z,�(8`Jl �{O?�罧Mu˖}vZ[*9yq`e�;c9j${ScNb ӁAu?i�}�G ��0bhu!|MJygfw1hYlel<bI#Y�S�4 �{O^ҏ,a� 4OEcw8JjēZTv ͒2qw6QElQE�QE�QE�QE�QE�QE�QE�QE�B_�\S_�F_>?�+=B ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ]W ~�۟cԚҹ�i?ʳ)?&^:i_�-+R?�G�ҵ(�(�(�(�(�(�(�(�(�(�(�(�(�(�(��F_PB2�o@i�]OաY�V� Z�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�dlMe^w0$AFe9ZW$�t�*&wsQMhrj<W}-�� <W}-�� Ѣ�_ʿ3W}-�� <W}-�� Ѣf�*_�(_�+F=g{U�3;�}+xmTI #Vgj�s�PWR}?5]9Frq]{~fQ]0QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE{KUh�ǴYP�/�}2A?�O �#���iZ�?@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@PB2�oWꄿz�F�O o��@jР((((((((((((((((((((((((((?IUWD�MsjDUtO1Y?O/U3?񛋝**G5Wܩ#i=E?{{�O4k?�%cB2�k {{�O5E.yw+ñ���?�׿�[tQ.52 iĂ%<[Z~i�&A?Z~i�&ۦFdUfQV 3-pψgk[h^!U~ַBUhDhF;+&-VΕpY1W4K~k5>_WV_n5�?.ug5a'Fu�@ƏK~k4{�M{xI�Ee�j]&_R7_�_jQYڗ_ hԺ�MGU-7P BWs4QE%Q@Q@Q@Q@Q@Q@Q@\�ǴYV{KU�Oy� � /?s�\_�A4��?Y~�#���iZ�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�U #/qO~K�!7o��@jЬ�O �(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�DUtO1V?IUWD�Ms*Q _)k?�^��_G�@5[_@*M*L iǼn?4M+aӠYeDf 0*[9ntA)b ^.#1$ѸxЎ?q&#vco\Yb$YWnz+~h/G(̾�} %g6]$.oq!E=2vWC}?YΝf34W8ǵoN|OO[WJ�j*/�u?~�}Z*/�u?~�} h{�Q€%S?G� �O�G(�ڧ|VgX\[HQpǁ9~�}*u#*IYlO�G+3RZ*/�u?~�} h{�Q€%S?G� �O�G(Z*/�u?~�} h{�Q€%̀d zNV  �2=�p�*΂n_({\��M>y� � �Ǒ�购J�yJԠ((((((((((((((K�!7B_�\S�#էu?Vg}ZS�5hPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPw$�t�*&qOO'm?똬Wꍗ_K^��_G�@5XO?XRQRh!YXھGH�tZ/ҸK=NQ-2Г@3b;?*jMl⥺; 0(sLjOi�踍 dsҮY6+l͜6}~xhִP:t{d~A\NYi-LH$.Wn88;q�uc^d K*u;I7svZL1N$a^كیހ=s!Ļ~I1[[e4Yb$$98'�ַ,<\2Ndzz�;gywE3Xlg_)oVK}*G2-p f3u 6vqs $5gCP nBF'b�i1>+ [MDB~_ �gnۊWs5Ki8rK[=[׊-IEH NCfA�^uղV; ˹8uBwc;U'UխkmQrG"xuVc_6zoKmݪҸPOg=MaE/vLq�`}A=xo, O6Ag5y K ɖY*&S琻J튓wK~nXjc2yBY�FOC@E !*AGzZ�(�(�(�(�(�(�*?f�?�[�i?ʳ: �A?�O^:i_�-+R?�G�ҵ(�(�(�(�(�(�(�(�(�(�(�(�(�(�(��F_PB2�o@i�]OաY�V� Zv<5??%'6܎s ψdZK]*fv>-!W${{Cw�@�G??GejZ c �dzuu $;iq>c(?? �F^nBijnFxZ-m_F%z,N@-ӌ/�k]�*�R6rYIUt֎,<piAڹGSO\k/kF4WaY.c&w.B=@eȼpC95=sot;(Khg5gOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�E`�i ?4m?�oQX?xs6M<9�AO@V&�ͧOfP� ?3i�(�ß�qOO'm?똬ɼgֆ@5BJ?yUx~-695{Uu@/Ȭ~_ke{Bz'}�q4K.Hu;i HkSOfVdsGޢ4m?xs6~>ZW D>`sS?8Gm?Eg-Q-&ٰ@:ю1O?Ə-?���~ޜ�Zy�4W�g̳K>Ր�Qi�?@�AZO?Ə-?���O?Ə-?�����}O?ƀ$� `tp0*?-?��<�ghZN�/�}s^`z `y�4yK���_W�/�ghJ*?)}_?G�} (�Rƀ$�4yK���_W�/�ghJ*?)}_?G�} (�Rƀ$;=�t*"PA�Ǽ@.?_+F=�p�*΂'�uq闟�/�}�W�yJԬ�Ǒ�购J�(�(�(�(�(�(�(�(�(�(�(�(�(�(�*zT%�?7}ZS�5hV{էu?V�c_H�!n CAūqhC#s~~a]֟kv!`OJO�ea|$QfQL?&1⩯z5O%ڢ?N1]?}?U+ZM,Y*I)̇s�DӮ5h`/")R5 0f~4rK91 �;Gb�쿙�?t�_��C[rIE $>z*=b8{×ZwX@#f'i�b]?}?G.�>t[;i4w{x9,ɫ`�X?ة!8"X]I@i�>߱G-?*_}}`�bQ@i�>߱G-?*_XZjhvX9o𮶹(x�5�o}}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(6D}�,ǥVlmJ&LcU?i�\d�?TlWru--@5 Fֶ~i�>߱YO?XRi�>߱G-?*&Wz�~TK[x8"F yT�ZoҨ�x�&/KE�ejַ֖vut墪c9 O8sguEw0 -&D[W<7�z OQjox.-`'dik:;E1&jS,�ր:oZiyf=wt+IX)[lnހ<->"S=4[Ds*,�sK%ŶYYh,݌th7VJL m!>-{SK٭[[<\Ŏ~5;TQ}z̧Hl>&%Ǣuװi@&j3<#yt8ǭ�Ix;NQI@J7e&CxF OvkW*y<힕ka5ƍkg=,zwX 靘�08�uȰZ ?©ͲČv XcX1[ޟodL 6aDRquu,opV] .O}nl4+kєI PXp3׭ v};2γ7;9Xia˴G81[Eg ;@RȄѱ(yiMKibYiEY>KaiX'³5m?1:~xs}5GV66;s0_<s�tk6j˦Iq]oTf<Cpv,Gw0fv:σ?ײNb!Y7)<t5imx}]EvuR%n`玔׋F6tL"A]k?^Lf{ |*(RK@5`%4%\K+܋VQ $�wZi A82 j)i-ݸe�ceqO{T@0ł̀1$d z⸛)Y/>Y<`m^1i�xXۖX)Y:;O�XuYo,,]͗ETr@$p[kԵKI$ U7f<PtE q@vj:ݬӈ!n!.X.qH'160�J^xB@a8}:θmn~:@ɻKu#hf CMC \xwP|h}N;v{eXJҨPބS(e#P$�t±55[i4A*pB_fP($q-V.vBV&FC+&ːG8( 00Hna�֬PWW ik5ĹFv4mFOg2M5ϣ_KyTu$�W3]is-&?Df=�vuǼZ5Ǽ@.?_+F=�p�*΂'�uq闟�/�}�W�yJԬ�Ǒ�购J�(�(�(�(�(�(�(�(�(�(�(�(�(�(�*zT%�?7}ZS�5hV{էu?V�QE�QE�QE�QE�QE�QE�QE�QE�@տ fJ�^0M@5Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@� O*??ʪ �b^6_~e-{Bz'}�bk?�w9cKQEITO~�WQ?o�M�hQEۮH`()A)ڄUHC-3UeZIW=hb&(%{2<p(kˈ>Џ/-es�62l zi7"F`YQ7Jn|fIJO*ƴHԪo?iL.qz)c7"ȇS"()F<SecCA3sQI46vŦx[,P  (eeGVzSssƥ,30Ďr!IU˩x%gxYgE �k= u݂zI2oTNu8=)hGl$ {1EL �n5Ђ{(?*iۛ}A"ZƮ5zdn#^v�U;Y�4E4�m9=0]>`ϗn `{(!|:?'mԴ2"?*Ŀ40<6y<x7wRƶ7"N1${�׊i<ay? Ewo;)uOXPQ@O\OY#Xyg&^H+?�t(^WTA՘Q)D=NA BW͆A"+<Bɓ -$�jY\A fP[mQ=j{5a;Q"-4(KKBӃ-ۢ1#'m䷵IeED/�w Z+*kղE#Ϟc@̾<z֔N$[zzеRC YH#Mru\@VcS_΀;ӿ?Gӿ?G /Vtq��gA@:i\��M>+<�EjV_��?ZV�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�B_�\S_�F_>?�+=B ( ( ( ( ( ( ( ( l?jW3a�%V�?&(((((((((((((((((?IUWD�MsjDUtO1Y?O/U2�!=kn5 [ut (k'?m�? Ҩ�x�&4(�; Ix iy;# #`/泽{4>mkE;_K$vWnu%ᴂ_?PHE|FYr=:�6DcẎ9NrQP6K3s[<d>K@f-̽7a8zV4�Z_G q΋:[NӜGJ�[;uXhdg'_J|61wl`B:&K 9R2:ڄ<Kmr<s 76]*Nܤ1RcN"2#f߀V'.53]j`݃Ĉ @6�v$jէCS0 spq3(PBD>r,~a*l0LWz v`j։iqrV_.Z3 _[WL 'i 2 9�U܎08ȣɏnsYv~"K["`Hv8<V"2S ih ㎇ڀ.I4i,io]jGO?rg]r~aTno [t8(f 7`>5z"X# B6zqiS `]XTý-�QLHHZFNJ?]wOW$EC# FA([~gCJ ;6Lp$M9s֬Q@\[€ӐQʑQG۾\՚(۬C%1%<EEmD%=I>j�KHeX3hLưx6v6c#nvsV X$hmLNyjtUDUPQ@ $!C"e="8cFT`@giVgiPˏ: Ѹ�i?ʳ ?s�\_�A4e�&@?�G�ҵ+/�-+R ( ( ( ( ( ( ( ( ( ( ( ( ( ( /e�)ޯ #/qO��V� Zi�]Oա@Q@Q@Q@Q@Q@Q@Q@Q@s6P5o�Bj髙�׌PMEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPw$�t�*&qOO'm?똬Wꍗ_K^��_G�@5XO?XRQRh5U��TO~�@QE�gjʵD+"\S�e`G`IF\[^ͧFSXV8$m:-Owupvj$ ޮ[Jg9Z)!.�23@h X- Q`m;F} ,1Ica"@R]̤2p8'unj m٘5ߙڹNe5DGr7TnSn M`"7,� tW!䑂)f'i^0?1c.1s�ċKm{;So 9icJc#5ZCm 2u&Fc$sۅV;K{%zʭ�4 VDK1i=ovmoF)`}NxkfN_Tx"9TδfB".~D%HiSMg?Cn4ݦ-Bhc۔ʧkmnagId �dwI ّ"fSFw$ d`b)-� KH;EPEPEPEPEPEPEPYw{UYw{Tr=�p�*΂n?_({\��M>y� � �Ǒ�购J�yJԠ((((((((((((((K�!7B_�\S�#էu?Vg}ZS�5hPEPEPEPEPEPEPEPEP\͇ [`�Кjl?jQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE??ʪ �b\� O+'Ue&R׿'� m&�!=kn{#?ET ~D��A5yU��Q@�FZuT @t0x`xȬVRΨ!HG#�d0�G^E0yYEqh;҉r:³ǩ.aq+>`-8ҽ#J^FTqBK'b2[̷))9uq+pO0G$7gѳֶp3s@@V?9m�K\x$5'qu̝m=+Y}eF3 uǭ?Ҁ8;{_+61>I(v[E:g4teoV]τ{z2FTghZKؤ@�=xCom^/K\Lǯ s216jxD@.ln#".0]#:נg8x N:ڭ B*>_cb+RR-�QE�QE�QE�QE�QE�QE�QE�ǼZ5Ǽ@.?_+F=�p�*΂'�uq闟�/�}�W�yJԬ�Ǒ�购J�(�(�(�(�(�(�(�(�(�(�(�(�(�(�*zT%�?7}ZS�5hV{էu?V�QE�QE�QE�QE�QE�QE�QE�QE�@տ fJ�^0M@5Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ǼXMzm.;@)\ֶ.?IUWD�MsuU:!$;&bWӾ ܒ+|k�h�2_O?P#N{u}\~k4h�2_*y'߂4~,}F jK[+M,3lJ�jOY~NpkH,j3KEhdr~1 .t#->mU|1j=mol FAֵtoIg�<Qqq}ixKM�#p"']2-/,e@r1c{UM{R-O CyuR>鎝롇@d|doOjqKk-\5Hs >GiwW}x~'|ywBֹ/(p%n%\~GOR8gT*r@?6Ll 2`9=��ȫ{[Z� j@0~s=*][JR;[\[9xgH "1{\ۛhJ9p9⬦jZk3ɰO帏ݛn�g5nE֗1.dKw ;@cxf.nTe+mx(^%Iha^ "Ke'yO VMa,0 @$rG-~5ׇcu:9,@IzG ZznP[cMD F8P[M3SZ26 #Y[yqZNyQ~I$LM2tկw۶fǃ=i[yt${u,ʭ3@�;yz7] %c}:{kB ( ( ( ( ( ( ( ӿ?Gӿ?G /Vtq��gA@:i\��M>+<�EjV_��?ZV�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�B_�\S_�F_>?�+=B ( ( ( ( ( ( ( ( l?jW3a�%V�?&(((((((((((((((((?IUWD�MsjDUtO1Y?O/U2�!=kn5 [ut (k-j'?m�? �}2�q?%eg(̿O�C{i 彨s3JO \D"K"2�q?f_'¤#̿O��}(/?Feg):ƌ0DPK3�sDnƲFe9�neg(̿O�IE�G� ?% @q?�}JZ�y?Feg)-�G� 3/?RQ@_'Œ�TPy�}2�q?%eg(̿O�IE�G� 3/?RQ@_'Œ�TPy�}2�q?%�d&??TtF{KUhǴYP�/�}2A?�O �#���iZ�?@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@PB2�oWꄿz�F�O o��@jР(((((((((x�5t@տ (�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(;U?i�\Z�Q'U]A6VOF/~LOD��۬M{Bz'}�nG,~)](4*�j'?m�? (r_hJnF*vzJ1ݛRV[b?FAx��BX(ou'gghP\j\7u*dv==Joxz{{ 5)0۸`=hC3Mom6<g=j}>PϷ$_h6D'ar_<s+_j:kogyV+3�=k:�Zpܥ;YE}sUﵭ�Z[ɦX =T13G>�o-7vz41V{-H&;pO?JAy\ ӞN}{³[ڔ#ǐbW+)~|Աqrig7}I9֟p+}pj$"ڣ-vޠֵiZO WLc@ '<ڟ?3=Է2}͚/&MHd5 m<7T sG>�o4u}KP駱hU$4ʔ ;Wux^3Xcپ@]o4^z7U|oއG>�o;JA޹8|[n續' 69 qO� ֋�=&�Fk WqҷJZOR?M�~/'Z/=> Wqu�IѣzM�~֟p+}hkzM�~hoh1_KEs_hoh�E�ߣG>�o:Z+�E�ߣN<$k$ۜ=M�.ttQEhqQ@Q@Q@giVgiPˏ: Ѹ�Y?ʸ[_YAhNw`;VʣHR44A?�O{MRK nRo!*x#iEٕ)+��?ZVe<�EjT(�(�(�(�(�(�(�(�(�(�(�(�(�(�*zT%�?7}ZS�5hV{էu?V�QE�QE�QE�QE�QE�QE�QE�QE�@տ fJ�^0M@5Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@� O*??ʪ �b^6_~e-{Bz'}�bk?�w9cKQEITO~�WQ?o�M�hWkxf}X rtpYAZk4TBn70YOC VX9O4>mkbBݪmmyZ#̲Ex,@}~ZVʵMD+"\�XYf,WAV-djJ3ܸ}N{ tE@3Gd<? $},l<f7CG'vU,"DliO4KR$/~q"Ỳiƪ/V ˀ6@{Q|�O\ +W[8+juaarϥ#7՜9R@d˦\\iq}R9d*T<gqxzs^HvK5BP*~n%!mGWm/ʎ a'8'ێ>AIs-7#'<|Sn-WéZشhUqA#j.t{ :i~pQALᔀIx%}8,%+m6`g9]N-6h{F$*I z+/NңUtbgTzd¯iMwlkɧ]w,'+=]$wv"eOkh]NsںHu=&YPXɝn'hGQ~=?RVz}47rL+⡋Oj.4̬U\�3t?{XjZeVM{W3,hU(JPppyQZkEܖtR Q#3׃3juΧs:F-,efw`t׊Рt.%%bqzv&zI \ @3<5ڵMDZ/3yF @3*ocK(J\I9Yۈ۴'"bVH$j�g=C^-{vL9zObά< pvҪZIXto]m1ӑѧ=)2DH e68{?Ү,5PVߝHL|$h}}`�b*[=Bdӭ<H<LI6r$ 9i%ϦǯωO:ޏt?{i�>߱\if(ckOEQqyT&s5ib)QȺumܿ}f7^EQ@Q@Q@giVgiP=f�e�kЮ�oʼ�ΗaO0ɋ +v̠Ӽu5C�Ӽt#_�-+R?�G�ҵ+ ( ( ( ( ( ( ( ( ( ( ( ( ( ( /e�)ޯ #/qO��V� Zi�]Oա@Q@Q@Q@Q@Q@Q@Q@Q@s6P5o�Bj髙�׌PMEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPw$�t�*&qOO'm?똬Wꍗ_K^��_G�@5XO?XRQRh5U81�M^~D��A4s_G�W9/tYey;Ŏ u?tT1ڕznɫ9_BtOuQ�N�<6� ꨩThb�Wy~m;Ϳº(T/~? ?G!:'+eOhb�Wy~m;Ϳº(T/~? ?G!:'+eOhb�Wy~m;ͿºAޏeO�1,|oy~mԷJZ=>�!:'(�'D�w_u#-ʟ`�!:'(�'D�w_uTQ _y�;ͿBtOuWUEʟ`�!:')x7EDc܄0序ºz(P_?x?5}?G�|(2?5}?G�|(�j?¤#W�y�� �`I*��?hv��?�Z�9*Dt5܌=Qyt 9t10]@ �Jk+#{�y]-sb܈"@ d550j�Ǒ�购J�yJԬMŠ((((((((((((((3\Dt1ZB_�\S�C m-Qd"p >FZo��@jР(((((((((x�5t@տ (�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(;U?i�\Z�Q'U]A6VOF/~LOD��۬M{Bz'}�nG,~)](4*�j'?m�? (1Uq2iii+Cw*E",衏* y_(9i&V9?ʜ֖jͼ2]F\㹪2FGg*[yR$QB�T98 ӯ4^-N{}-%ܒ=vz#Y4DZ{ɵKk/:c|ЯbD"w�+JIKw/Y-'U #8!KGQI%6vJ^G@$J޺Feym(l۝ۀs1Xr~<h�ϕ瑽;B`{ȵkOkm_5^.rA1u1~"dr[:>၂?ZfծkSi|HsY$9),ԾqI (?/=poAnƱ+,܅r ]{gLbi&(쩷 r2Xdp=&>YCL՝cI{.~{fb!Yr2px8tb]<?tIW"m4NPRyw1 QQớC{}QXTmʬb2H'9�\Mq=@[A((a۴;T>VQ>%]6މ"!F/ĜW^}QYB2 GڛqE{ ֗yh-%6~9P CX.Ag# F7WQ&}cQSV;8yv~�3íbBؐik"."ax ~~՟m�dIR<k1o0izt7QgI)#InVQkmI/[[4 =4*q�/�](�(�(�(�(�(�;=�t*Ѭ;=�t*�q��fDܠEiǴYP`.r��y/�}2A?�O �#���iZ�?@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@PB2�oWꄿz�F�O o��@jР(((((((((x�5tKiG&nY,d8٠Ί�ß�i �ޢ4m?xs67M<9�AOG&�ͧ +OfQ� ?3i�(z�ß�i �ޢ4m?xs67M<9�AOG&�ͧ +OfQ� ?3i�(z�ß�i �ޢ4m?xs67M<9�AOZ H ր,E�QE�QE�QE�QE�QE??ʪ �b\� O+'Ue&R׿'� m&�!=kn{#?ET ~D��A5yU��Q@ƪ[ۛ+ [ (36�Ǩjڞ^]^XFl"ɖF)OiivAK tWC>"׆o!�l p�oC{kq0I@vC}B9$h>+];WԥӴэ%q,xYq8#5bR`"J4*.\v�'hV %T3"Hzjjv-p{lgVcޘs{M͝ @T269'Mmk٠Y@luϷ4dL?j'뷭P6HxeœS[�'钦|Pvv(S WC+wTUO4`jJ$V`aJ|sڧy 3X WqMjڍk4ˤ/DEAǶ=*um4HZKv #z�5-minhĀ`:_l6iX~=v'Mqk?쫥f!A~9 H93ڤ%MjHISSk|M ;I)vH(oaXr�&O6ŴL+gUF5h[(֝-i0PI(@ŦOqԣCyRFmh@s�褼BD1g�~x?XW;@1$q\=={lu=R;w(qFA6i,6nb4YB09ހ;K[{ؼK"7?QSW1Z|Ri6<oțW'=+^U�l͕eDc[?Gqڀ4(�QE�QE�QE�QE�QE�Vv��?hv��?�\�i?ʳ: �A?�O^:i_�-+R?�G�ҵ(�(�(�(�(�(�(�(�(�(�(�(�(�(�(��F_PB2�o@i�]OաY�V� Z�QE�QE�QE�QE�QE�QE�QE�QE�TR3nݱjZ(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?(�~X+}`�bZϬU(-?+U�(�a��h(�(�(�(�(�(;U?i�\Z�Q'U]A6VOF/~LOD��۬M{Bz'}�nG,~)](4*�j'?m�? (" cCKȱw'Ij�<\銍&[^ 1 3€7hk{˯* R1mPsR{3Hp0}8G@mib+߮v> !sU˩!3)-P9>ڍI0K(}F$zY2^'3Cm9=sޭk � �'\uR=)dRpy}:5KQ#% 9fTrAݟj[eOszPJ|dgJw14pS3^}+<9�nˈcH&]ʥd0G}=ml%]k1{K0q.TrKic7J[K!^TH!yQ1,BvWK(7as[iwߑ@!)t2*JŷmRX`?tN8'TDX<.01ڀ6)"F SYKsݜr<l6�6We H"iΨ38;onȞr^g*݄O4 =v((((F{KUhǴYP�/�}2A?�O �#���iZ�?@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@PB2�oWꄿz�F�O o��@jР((((((((((((+uɩ=6c%sܞ(m`ɯ)cV?n�+qZɻ��ף&�^5웿 ~_zk;*f[\ZPA9F/i 1%jI= �(�+� [�цj~�?a((((((?IUWD�MsjDUtO1Y?O/U2�!=kn5 [ut (k'?m�? Ҩ�x�&4(�G$eǝ=3֘GlWϖTnZ DWc{>5/|o.v s�>=>) U'8HЭ\gPޠU [hw.ƌ8œ67u$:(@%2Dvm=~\'anRTGΑI TUċH眎:U/b]w?(OiX9޻sGs E2׭$#[2sJڜ";wUUPYAb!2cː>T1TǒI95QHQL.#�1=fR|dWtghsiI Ť�AQh#7NOv-#*yiF�\ڄsʱr. nbU%NU>sJ)E3גyjZ3ARPUv\.3nuqmhhq) c9'�Ykw(v Aݜ[x(-�X~y9Z#8�~<Uhjp6Ϳ.�OZ�aiLɰ9<8laVR^Fe Mb6pͶ9<pU5,;rpFHltb4*'9$Oz}C[ d* "ԡv]%ƞa_QDZR XGas@k6ޣ'z5"ArI"R p0?JMn0T?Σh,dobq Җ% t2Fs NŽ1X|}�_(�(�jW&NU B= �~xOւƭ]y?�΀7k;N�x�ʴk;N�x�ʀ.\ǴYV{KU�Oy� � /?s�\_�A4��?Y~�#���iZ�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�U #/qO~K�!7o��@jЬ�O �(�(�(�(�(�(�(�(�(�(�(�(�+N�j!?l4.㶸FfxT:3P=r�;wiuC NC(FAML_m}*42$l[>+&?h ޱT*1C:{U [`}FkFբx!6��wYxT|9yy[8ehvA,s2ƚ;ɤ^ O~~N4MTj >l7$2{qVtmM Pjr,ip$~�4KB(`"g `sωE/4j y:euHԼ!H]�p3L MK`PX2A;P�ȏg�^P�+UZIӚ c5F8$m7vh#MƱ"�d;J츳 o7�G|]�@7���~iMvAi|*<3 rt�@ hg�n?�F髙� [�ц:j(4 МP*?>/Уϋz)]w+IEG�=SyT�]Õ$��} 5QEQE�GqOO'm?똫W$�t�*&�z~ɔ [uOD��ۭ/QE&_Q?o�M^~D��A4EP+'{ilaݕ#@4ɠymU FY N:uvjiK&~Q;SfTiH܁,L8{h;F\]FqǽX[yCl1I!Xr@#޴cP]+N2,Xʃr@v3 kpaՖ]r_ƙycu#^ Q%ʐ�^n&IK"犚3;*W<ImIռϩoO֍>M & +P89U}Pz7IeIrqJݢ3ӚbCT{O >Akr6]yJ-؝d qڴi1@i򥵔Ety7N=Z0m yr9�cހ2Pp3Ԝ/K`g S"CNqsjcތ{sLr&u⋽>Yݱ}F$kGcހ3kf{6-yۊm$pKAmF?269o<{яz�->+s3UVWbpyGoe25@ $3OFrd]qӯ5Ym.Q-nrN89ht(( ڕ^iVZx^0O@H#V=?E _>uA�Vv��?hv��?�\�i?ʳ: �A?�O^:i_�-+R?�G�ҵ(�(�(�(�(�(�(�(�(�(�(�(�(�(�(��F_PB2�o@i�]OաY�V� Z�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�W3�%I��%�(Ox�-�t?�-\]5s?� q�_0MXi޻p."Y˜ :rkb�pOk>T�o�/}?|�j^ʟ3GO�8?�Q�*{jcj]ZȇFH r j�� jտ�ʢ1jUm')JwH(p(;U?i�\Z�Q'U]A6VOF/~LOD��۬M{Bz'}�nG,~)](4*�j'?m�? (9^[X@xSp 0UAMbO˪FKHmdVwIH$zW}E�y~֍ż 6Y;<d8Z]n7ķygc"</c5`�Gp{p#k�`�qw#5ilK.Gm8KmdKUۆ ,HnH>р:�QE�QE�QE�QE�QE�QE�QE�'zSGzS@�KH:Rt4Ҍs@EPdQKE�&EbzA-n#F84XCtBii{&GMq��gAZ7/Vt'�uq闟�/�}�W�yJԬ�Ǒ�购J�(�(�(�(�(�(�(�(�(�(�(�(�(�(�*zT%�?7}ZS�5hV{էu?V�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE��@ kf�J�^3�K@5s?� q�_0M\�4Vt� ht� eSxږQEWU72 ei>!pݺHsu�RN2PoVRpsU?"��/e}Os oA7ի�?ejeq@�MXW1w!G%V~ۿS%#F�_E�}V֟/^�li�GƟ�?T{Z̾Ƨ򿹖?IUWD�Ms}< qTڟ&8ʪw4pi>emFR׿'� m&�!=kn^/QE&_QaTO~�@<�RƤ#�4yK��eȴy+T<itVq܏]w? ��}_W�ޤ LF"[<~o!Epv8)}_?G�}罂hEF;r@RD,bS7 ߕ�RƏ)}_?QFKPgS$[7nK oO�O/�gh�4q ;de~چTbs3ǵ�K/�gh�4XHÓ[^Ve^? �<�Rƣ8㐬" g S%C}/�gh�5Z}@Cf2I1R~$T�Tcc_W�/�ghBx+W97^ P)}_?G�}c Xȸi9J+W16a wgg�\Ɓ�m4E$S&Y`E?hW_o�4.:Ɨ_W�ӶZ�g�}_W�ԔP~RƏ)}_?Iup\K.gl Lms$ўz{C@rƹF+꫕?b�8R'�3�i?ʳ: ?s�\_�A4e�&@?�G�ҵ+/�-+R ( ( ( ( ( ( ( ( ( ( ( ( ( ( /e�)ޯ #/qO��V� Zi�]Oա@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s7�P4�BZcGk+ˈR*THg�n?�Fn9D"4.߀�W3r4i-\.&xVrF �?;u�\ѬxUu1OT 2 jƫI�ފmJݿnRS1zS};"L8BAIGI��[5)U&M~F8Qbid~D_?GOTWUc#"�I�|<".$�ED_?RQE`}""/ȩ(˰s>~D_?O���$ bk?�^��_G�@5VFQt (k'?m�? Ҩ�x�&4(�"(p2\uT^+;VC ,˱eC{0[g8tsӢ9|N�t{ "ZlFheP$hebՋDWZʐdM>(j )lb2p=>X_ɸ<K&Ìn6 4*)f%x' [ j4cjMq%VF?5-�a9Oe*aNziAnm&lCH`Vce,lU|rvan-K%+ cw|F'ed6u3+o7DI&ӷil.#bF<�}1֭K5ӼHK gW3z"pMi!-;6qnnQ@٘-A,+ /=y栶Z|?eMٕgdr0mU؎8a3ؓ!ݻ4ko+ZJ *p dR<Q#;W' zR*34Ky|_Ȥ zee6v;UAf'�) Q$Dc;G:#u4=)hh�DDEUI*@CZ\yytI7ُ]�W+u�^p�3]Ur'W_5QD^t/Vtq��gARY=�&L�uq��?ZVe<�EjPEPEPEPEPEPEPEPEPEPEPEPEPEPEPT%�?/e�)ހB>?�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(^{i"Su굈gGm^b靬A\|է&q]X�{@mG[U,>tVd6d ޲F3juMZ?}�A{�7�ZM[An0[K*#8:i+EsZ*I&U`'gZ^{�3O7�ǿ?o3q�Ue!{>&>N5IJʒ0?괼a_r�#7u##>+2e$JF[q�Oz|Eut#isy�68+tu:0ۏ_6gRꤥ~EV!EPEPEPEP&�!=kn5 [uOdg_@*MJ�*�hB( S�u�v^Lt۶PE`Usi F6󴫲)!xDKO%h2[L[jEPdg q֟q{x׳H@UHlNIpx_^|d<:u<Q-M沰%p(<s j2O֦&C&0wU\7jmbiN]0SM8S#'*ʎ$L#z/.J7o2A\ܟZ0gmR �AL cm m'=y Fko8F8Cta2#&6mYQ6g,H9J0L4HQO�Pzdqc\3FJk&`ě{?&cGAs{i->I>ր(O{xדH@UHlNIpx$iKNHgmѢ�8Z,k++< HC:Y2 2&n:?~$Lצ;QPn[}*i֩ -nd'$/*X�rp@ Lon%a栲 Qn$>QZp_lٜqQ }ds7=�qLCP{fȒ5a�M ,~,I.띌yj3i1(Z�͒A=*iOp\VٴL{WOiX9޻s\iַ24Yv�Em;,<j|["iNtvbS%^<k|dzQi"`@1@]ԐʨTNkbCc"VRI;Cܞ.qU�(�1] Qe$0:-}wYq uj8)?뵚$!C"e="8cFT`+u�^p�3]Ur'W_5QD^t/Vtq��gARY=�&L�uq��?ZVe<�EjPEPEPEPEPEPEPEPEPEPEPEPEPEPEPT%�?/e�)ހB>?�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�( 4�,- Ne ?Եx<iݴqmŦyR1NAwtPjx9/5FV8,*wO47X޽ai$p [Q@Gejx3Dae|j~|H.rU8Z? Z[[\j/v]\4nc37 Vj;|MҮ`xm(wgz袀 ( ( ( ( (15 [uOD��۪{#8RQRh5U`]�A5yU��K�щ���}?4b_ƫv6S.*N{ͩALYi;9@_ƌK�ԔPx�|�}?5%%hĿO�ILX8Rp�LK�щ�ϱ}q"*K%B*3 _6eM|иO3@�|�}?5wR[3,�e[{y&b~4˿iVFqpB'\A#b3G (O�}?4b_ƖcNC"n3ƫv$}A"#6q̡z%hĿO�IM쁔rLq/?F%jJ(<K�щ���}?4b_Ƥ#ĿO��|(/?F%jJ(<K�щ���}?4b_ƞK1 dp�&F]1�4OkWD�f=HΖ=�p�*΂n?_*K'�uq闟�/�}�W�yJԬ�Ǒ�购J�(�(�(�(�(�(�(�(�(�(�(�(�(�(�*zT%�?7}ZS�5hV{էu?V�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�bk?�^��_G�@5TFqt (k'?m�? Ҩ�x�&4(�|uc%Ν,U>uiZұܙcȍ"9��!]CʒhGT49=gm)=3@[gk4nn|)�?.* &[BMFi.Z #L'}APst}6E >9́1' uLVQ!!ma@y<S@j [ ڄy9Y6,]e<Ωmu uiSRGlB%Pg|9ZGZgS,»$5}濾.b #"[*HeV9+;P>>{J) obA1Bddj–hH`X_}Z]-卵đƖ%bBEZ A�s(xKwWdaP vٜUyͩ[E&2Rv sɭ𾖲ϸygb3AX` LIjR}O�`x>Huxee[ u'+J$kɣytp?<WOy,זyaV zd$*Cȩ {P?AX.!`E۩�c_z~IC2G?3v�wc[l-,Xjy'[]}g ϙ �F{aG5к {bG!IuV%{H-╂Jtd1ǥt7Fu3qak4.wY} #I&g$<40,\{P?ᛩ�/-M3s@dκkiNicm"SJr ( ( ( ( (3A� Ke� r> y 8�c]J 0AR\�#yuU1]ל?Gz�ǴYV{KUId�/�}2A?�O �#���iZ�?@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@PB2�oWꄿz�F�O o��@jР((((((((((((((((((((((((((( M{Bz'}�bk?�?ET ~D��A5yU��Q@o,.IDi'4bign.|sa,#WCrHp ckv�KKYqFW;èҨiN]1aťb2]P֚ɬ68dxH\ C�ުi)dMx-/fhc('x ~>yޛZ}2oBfDZ2#c%_*9V;ivjtn7y>�=(km[Fb3i`JcvsU.|Q4q\çlmE$.>'L_ \GC[eض>1Z4˩.'ӬZ3DbO+yׂ@55O8;V.\Le'w5 0N7sҳ'f]V1wŷ7(;�V�q ]S3K ].R6 #8u毮:}OYl.�aOs=-Νٍc1۽yZ'nF&lpAۧ@4y{#gW%WqGAtj[qwJn8w!e29¬YxxZâFnw*6Oxr}xFOpsPFm8S&@�w4�vI3I[xnYx(anHޤV EXdyrPK SkKiumrmolٌRޤ0+.FA: HԴ+(ѵX2O w@&a=խXo1d:՘%֙Gﹴ!N~�Ue{Rng 1E*Gp I9{ fkH\}`6?x1pxY4[ZM9IRe S^xvW1[ nBt MHc!�XSiI&v$;,r:x8Bp7 E<g&4]5&QV@}uް6mYFqt m G=1]&o=K y g0C(MdǠ0[j mz;u@!U~gE0'cp#$ClR@WUoCe1=bM>`7c*cyV)ollEGHȜHNx9_M/l?6oO ~o{\y5[G K!`�~`{s:?.&t.i$AE"62X򣟯PEPEPMZtۈCdd)"<5K}^Dx su[ Vbx2öF3MCbg FFJ�ҮWD�ftOjԉn?_+F=�p�*΂{\��M>y� � �Ǒ�购J�yJԠ((((((((((((((K�!7B_�\S�#էu?Vg}ZS�5hPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP&�!=kn5 [uOdg_@*MJ�*�hB( ]+^indo)ߏ+FXzSĶz*]"i];[U<U>wgmo4N#bi'#givZjZNںM$plPHXYoiu,[A4@~tQe+wԲʥH\%usiq0MȶMp*3OxNiCitxWQgTF[*9�uhFnk0q�MS{mciT0q\ϮY-}SmXʺ2cݕ' Ҫ=\i5ڢ̷lc+LlہPu-s s7i/今6\K%1됭+մ_]K `.ड 9ϭw4kI#g[v2=kR B%{{%HxU`\+Nj6qw3^-#<G>CJ͕�1 l\98<��t%?oJC/ȧ< I%Q$]@ȥ@�2H=+"P:pTO&Ow{;ֳ,jr%1FNӳ<J�X>w6cwJ#Q@d=:4X\ M`]Bw �n3Kye=YKk!0Bbdw#hw 2q�dt󤾵H(]èzTWzT-cTx|_=F>yrme4Ẏ� vO'*ot"Z|l<nGLCڀ:;K캦eno͋54Z,1^[U,@@J`OhrN@Ol=Kuy!He:PZڕ̰帙ܢe]ŇPzTsyۦ|\rޜsp7GukK&q0e%TRɌ(^O$~ $<)cwpK+~tzu<c4Ѿk\ƷRF$U.9SP:͍卥wS^0$ ryE!ki[HcO%HN<84�[%قX!3R@Bz7]wmAuh# ո5=޻ZiRZ!ǙMs}=&o1Ogu7<_SSm.tBR<"Kcl@J0Pצzbڶ5Y2�®W♮u.-g{y ^G;BH i-!hԑ"l<@(�--f>\(8&c}mۉI=>֢ykRIo" |! .exǿι]F+꫕?b�HR'�3�i?ʳ: ?s�\_�A4e�&@?�G�ҵ+/�-+R ( ( ( ( ( ( ( ( ( ( ( ( ( ( /e�)ޯ #/qO��V� Zi�]Oա@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O?=V<#.fn5k]V�[Mc%(JEeKJ]V�.Yv+C4ߥPS+'<`Qh�Uv�`SYpNm�ssjC[�UԴ�<{_�?)�G�?�sǹ�i�_Nm�rZO��Tii?�o�}Q<{_�kmEn+T7>O-'�?��}=ίNm�v?m�WkKI�W9�c�?ƹO-'�?��}=ίNm�C-ƕ57\ڴn.FJ濴��x:;�4i�_SKI�-'�9_`sӱ�oG�?��x:;�4i�_SKI�-'�9_`sҭ|"< ǩSi�_SKI�-'�9_`sӱ�oG�?��x:;�4i�_SKI�-'�9_`sӱ�oG�?��x:;�4i�_SKI�-'�9_`sӱ�oG��?��WSA�?9_aǹ6jtT`)[=EC45!Ρo�}SK{_k*nSLJ-_: i36?g[@#ڏ�#Un󷈲@<N㚃QݢԵV6L$~OV��?ZVe<�EjPEPEPEPEPEPEPEPEPEPEPEPEPEPEPT%�?/e�)ހB>?�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(F Hvagm�_VD?e��SQEȇ�/R;s�,"�OE "?/S~o�<"�\O>xE�| ?�_Qp)�g�G}r.E?(Ϸ�QEȧo�<"��/U(Y��_>xE�| E "}g�W(dSϷ�*\,�/Qo�<"�\O>xE�| ?�_Qp)�g�G}r.E?(Ϸ�QEȧo�<"��/U(Y��_>xE�| E "}g�W(dSϷ��/U(YE�ϗ&zP3RQ@Y/]FQͭ[C^(=ۛGJԿu�\_,,\O&h\,NMw*UF[ Iyo*�W�yJԬ�Ǒ�购J�(�(�(�(�(�(�(�(�(�(�(�(�(�(�*zT%�?7}ZS�5hVF3[s ;enw6I?:�֢SS`39�t�;By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| +By�|By�| ++R̐IƳb5y p90%GsW=Ms�m~}u4W1?g�)_s�m{)iSEs]H�{/šuT˽G`u4W-�ϵ;T9"mt*r9GVSgEEc�h^�84h^�85V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??G?@V??AoG?@V=w4[4s9�ǪRqlI16=@hd)�nw7�HZ0Sqm6H�MKA_�OQV9a�?x_¯rR %ì,2 pH%?c� V7]mWj  |D1\}*z��?\͝qIO`;�~_�PAEs��~_�Qw�O��tW?w�O��~_�PAEs��~_�Qw�O��tW?w�O��~_�PAEs��~_�Qw�O��tW?w�O��~_�PAEs��~_�Qw�O��tW?w�O��~_�PAEs��~_�Qw�O��tW?w�O��~_�PAEs��~_�Qw�O��tW?w�O��~_�PAEs��~_�Qw�O��tW?w�O��~_�PAT%�?w=�ߗ�{:4Kg!,j0'zG>PjRNZe<Sw<^df6MRy + .aEO1Kۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�Q'?�Qۯ|�R�X&w/Oqd&u*0T1Otm�'�Sp嶹,z?5FZ!)P w�51k/�η�K_3[b]  �OfZ?`}�'u]�.Oi٪t٭A�>̿f筭/�boSK2s<kCsGw}9b> 9 >�r-n^xP$Iv:b*FܒlQ'?�Qۯ|�R:!=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=Bz m>ߩ?m�'� !=!1V'nI�(eץ�P PB]m#O׏J&Bzwn?�r{ǵbE/l$6yi ?#R}?i�_3@EkQ#enldÞ+j<V2G.�� }KA_�VL2()T3Ϥ5@o!Vj� _U�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(��:fi�)Y((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( o!Vj� _U�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(O/Jv碁ݏ�?C+� hH|"�6/�~G~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�qG~?� (wQ�q¡4)ؿEƩyڼ+nwd֞�=&�4Q@endstream endobj 345 0 obj << /Filter /FlateDecode /Length 456 >> stream xO0>N$zl@D.ݠ46Y=c7.^69ı=~yG&82 ű<O{`obюy4 d^0+bCRJt{o˕\4uaL5l7iBr,t\p*!a`?OTH a>}זsmM705?eghRBD Ij %n▞EpOx̻"Bhʤ~Jah.<üoő)h@;Ph%2E("zS+V^xNK,)Iȗ9b0iE'K~q7wDG|C&)^8>Ŷ~ OUTJ(5mP8膅¥|ʷj[::CYsDѳ\d+L9FJd�endstream endobj 346 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /DecodeParms << /Columns 702 /Predictor 15 >> /Filter /FlateDecode /Height 603 /Subtype /Image /Width 702 /Length 2036 >> stream x]egVs8XAWyiә HXq*Q�ƈ11@HK ,%̌i亞<s=7N:}[Ͼ~w\&~g?+`w/}zL:=~|{x`ҙ7Gc�w�OZ&l߫7_Z&r<`ҹ?VoIόgzLzn<` OWoI/~zLzi`+㕿�^hx`o^&zL0.qx`[?�._&]n�.7VoIkw쾿zL2\_&ɗ 0i_tk7%_VoIWK| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%Lɗ0&_K| /a%ؿzL:/]%`콷zLڗ/]`Ҟ|�7VoI`qqggg{{{;[cc{ɳux||q|txGNپ[[N[q|8:><IG&qrOݾۮ˽NGwogendstream endobj 347 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Height 603 /SMask 346 0 R /Subtype /Image /Width 702 /Length 20942 >> stream �Adobe�d�����C�    %,'..+'+*17F;14B4*+=S>BHJNON/;V\UL[FMNK�C $$K2+2KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK�["������������ ����}�!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������� ���w�!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz� ��?�Gm5`QkhݶeIM:_3=<͊Rjƃu�@;\jWĆ2ǥgRN+CFiQ$lZkmY\`[EiE,@k}V$ínJyΊrrZ2:3Jho]KLT^p,T<X$GCZc]l7oyO&ɮMk$b’�CSPG)Isً\\uk3H楡'byoγɊ'%)Ia]oΩyywoΏ9:9:<ꗛG@|^mm�]oΩyywoΏ9:9:<ꗛG@|^mm�]oΩyywoΡ"{PyC[ki,o.M{і`@S@@ZW49Um>0u92`=k/ԙR^DrǷ9ܠ3P&GJIIb'(p1!dPff=$)jAz^˷yńK  x#Uu[4癶po,W�=Gր:9:<뇰YmK|E峼�#vz'֦ZI3#~r'hI$W0۳0b/^{uKRMqW).$2Hغns0{Jo;fFHl^.[A4py*Ac'K7\v鉧\I,Oi+ag f3ؒ1ڢoKig$goR~�\i2 (u<zfIs(BT1:\,>4QIi1:@t^-)43 #qel)sxuYY}.>kj_hN;{~K Zk#Tyȼ2)@ϩ�vsxty ezdèM~n$˕`r��}xj~yy&aIϘ.-Bs#+AzjqLdd4Ie%&HsdWFt=*MJ d f귷i-sr@ 䌁# M;9:<K!-<t6zJc>Qs-%/hb4,uTVx<-Nl'yu C5Ćv\6>E yc6;MIu*ya r{}sL{ԶaH2̀T׭/Sx㑸 GOZb[ 3rѫx}Oқ/Eܒ[iREu!y@qGJ@tsxtym}uzFd&Lkrʒ6uvlAkb|8p(y+r`iQ=|m8;Ʊ\>9jQ 6%y`@9Cy7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?sxuKͣ͠ sxty/66.7T<�7G?Rhh?p�kY)nB;J#?ͮGkm=/[_Uǂ6yj[}AH?ٳtc=i[E#�jP4QbOl=yoM.�@]u4P ̈u |��tϲ'aqU@\Z?BTocM̌�7VM,re7�캏��uL[캏��t}Q�|?.(.�@]e7��˨�>o�Gu�#�멢9o?G�]G�h[캏��t}Q�|?.(.�@]e7��˨�>o�Gu�#�멢9o?G�]G�h[캏��t}Q�|?.(.�@](ԁ?.(>|�H�<O9�?.z(3�M#�6l'#��;s �|O9=�c] L�H�\G9G�қ}H ��;s �6gϏO2?.(6gϏO2?.D`OO2?.z(ɇNX'i3$&>}|zy�u@,̏��uQ@Ǒ?ad]!I'G�QE�sgȌ�6l'#��ŮF7�66�]#�맢9#S�?]'ٵ,c�(]&a9�J- 0,'t��˨�>o�Gu�#�멢9o?G�]G�h[캏��t}Q�|?.(.�@]e7��˨�>o�Gu�#�멢9o?G�]G�h[캏��t}Q�|?.(.�@]e7��˨�>o�Gu�#�멢9o?G�]G�h[캏��t}Q�|?.(.�@]e7��˨�>o�Gu�#�멢9o?G�]G�h[캏��uJ= qk$)v1UQo4�@Y~�cH�(Z�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�ɥH!iX,qfcI#Yacq\|{Ν NI�ͷԁrWE*\nj4O},1�h���V#꺜r8?-p>\'*;ϱؼ�#>m۶n:n9*펓Yc�>ѩ�ϥ?�hˇK"֦[ bwm'n:g=|$O<H�$d �=G]펛Yc�TZEV2.}M7r�oHť ܱ*-&%]7cK?}!?���wKĺz̖]_D̂;Xsp:W!t�m� �Q�>Ed沚+q4Tr`v�dG楇/[( I/6[XN2r#@?�m� �Q�>Ec6%f>Dz!m #(|Kg3v 0g8ހ6?���?}!ƷtW:!6VH�)*@9=桶dhv=ܾ\@NURK(OoZ��O�{oo"���+"?s,D^WoObս?\7էbؕ!Oc�,6\}RGGnj/X\&ҧO>�( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( 1�ȱk�_�=wc�bS�@z�<-�"Ƒ�^P�+/,i+R*\³͉9UPBM36�U�^@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@o�<a�bQ@ J&⢰I6FR:תr|^K8YvkXUJ*L u 9R2!==C<?_/s=yqM7|�)fG9/s.(+av.(pw|rO&%B%Xnϧ$`ZؚoC�|Q�ϔ?Տ>mGaOowP QbiG&�>P�y5a,:N6<U_0vm~5CM�(?4.+Գ(6n' ǵK7̙D?i܏0F0j?M7|�( kOږ+́vŽbo۲H-}*@&�>P�bi@?c[kFcO8B</ %*7l<)䏛<OM7|�(-&iq=j+~3i`jb[1;U�4M�(�v֮ҰQXu(1ҒLI Hj+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+y>o�<X+yv# $l O k�"ů~WE_OGyC� Ԭ ȱה?�J�^OԘ�-�&Tw7ZfcH2p?SR`z 0=-G4Bc_1&{P=;h$fH]3M�?Q*/-~\6y�.3ʡ,&*2v�[`z Z(0=@qbO8i" :P=�LAF�)j+Ce#/\SJ“_ZD^UMӲ�Yc 5-huskRT,{'Ҵjv:_A�v_?#GO(4F[2Ȓ#4M3qڝ蚔(lrľ\ CцG#K~coN{hӲ�;N�8?~a";/N{j=JOKF" eҴ:[ӭ*0#v+H __iCҲ�*BzJ(J#RnRW69 fW(|,p=:`z Z(0=�LAFQ)h`z Z(0=�LAFQ)h`z Z(0=�LAFQ)h`z Z(0=�LAFQ)h`z Z(0=�LAFQ)h`z Z(0=�LAFQ)h`z Z(0=�LAQ� K�%p�X��1�ȱk�_�=�u�cH�(Zo4�@@�tZ�-�aѕ<7tBDp�zͭ6c6FR{i1!V#,JJ�98:8Լ\v.K+[owr�m(dv$H<]]ݷڡCжLӬ!Ӡ1Arř$0tK�/\ʩfge1c85.;yZTiH1a++9F�c^ț?�Ew V;vV3.윜]Ej:.&}'|YbϨRNMjs#9H؉sWeE�q|ڌŨFe_;{f5oq()mWzcLe�sY`cҖ8X]/Qk(ŷsJHχUrNxxjZoQ Y-8nt Z�*� *Cw=T3WEM*6 8Q%:(^u Wk) w#vqR[^j:db:/mN?*wP�b[&Hfbͫ]Z[\Ӯ!4aUXqj]Oԣb\D\: >h�r9y1?�ZC�ԽbhyMG1?�ZC�{)& '+Ӵn<>ӷzVєm10q�-}}*1?�Zi9BřִU)gqv٫>B�*s}xM@O0�[Ѭ$/4Hr@*TLTߴMQEyQE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�?z_�*(~�A@E_O뼮Qo4�@Y~�cH�(ZGj/y?P^]<P".QY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��iY2�u?#4h/S?GO��ip{*X~�A@E_O뼮Qo4�@Y~�cH�(ZG:�s�/'j*QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEK�pij/�Pc�bS�@z+�"ů~x[E#�jV_X?�V�E�/'j�tZ�_? QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�_�j?z_�_?ZK�-p�X��1�ȱk�_�=�u�cH�(Zo4�@@�tZ�_?֨hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@kZޗ�*�-V��I\?-??,Z�@GX?�Ve[E#�jP_֨jG:�s�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP/Z֭C� �_ո~�A@WE_O뼮Qo4�@Y~�cH�(ZG:�s�/'j*QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEK�Pn/�Pc�bS�@z+�"ů~x[E#�jV_X?�V�E�/'j�tZ�_? QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�_�j?z_�_?[K�%p�X��1�ȱk�_�=�u�cH�(Zo4�@@�tZ�_?֨hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@kZޗ�*�-V��I\?-??,Z�@GX?�Ve[E#�jP_֨jG:�s�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP/Z֭� �_ը~�A@E_O뼮Qo4�@Y~�cH�(ZG:�s�/'j*QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEK�pij/�Pc�bS�@z+�"ů~x[E#�jV_X?�V�E�/'j�tZ�_? QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�_�j?z_�_?ZK�-p�X��1�ȱk�_�=�u�cH�(Zo4�@@�tZ�_?֨hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@kZޗ�*�-V��K\?-??,Z�@GX?�Ve[E#�jP_֨jG:�s�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP/Z֭� �_ո~�A@WE_O뼮Qo4�@Y~�cH�(ZG:�s�/'j*QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEK�Pn/�Pc�bS�@z+�"ů~x[E#�jV_X?�V�E�/'j�tZ�_? QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�_�j?z_�_?[K�%p�X��1�ȱk�_�=�u�cH�(Zo4�@@�tZ�_?֨hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@kZޗ�*�-V��I\?-??,Z�@GX?�Ve[E#�jP_֨jG:�s�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP/Z֭C� �_ո~�A@WE_O뼮Qo4�@Y~�cH�(ZG:�s�/'j*QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEK�pij/�Pc�bS�@z+�"ů~x[E#�jV_X?�V�E�/'j�tZ�_? QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�_�j?z_�_?ZK�-p�X��1�ȱk�_�=�u�cH�(Zo4�@@�tZ�_?֨hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@kZޗ�*�-V��K\?-??,Z�@GX?�Ve[E#�jP_֨jG:�s�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP/Z֭� �_ը~�A@E_O뼮Qo4�@Y~�cH�(ZG:�s�/'j*QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEK�pin/�Pc�bS�@z+�"ů~x[E#�jV_X?�V�E�/'j�tZ�_? QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�_�j?z_�_?[K�%p�X��1�ȱk�_�=�u�cH�(Zo4�@@�tZ�_?֨hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@kZޗ�*�-V��I\?-??,Z�@GX?�Ve[E#�jP_֨jG:�s�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP/Z֭C� �_ո~�A@WE_O뼮Qo4�@Y~�cH�(ZG:�s�/'j*QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEK�Pn/�Pc�bS�@z+�"ů~x[E#�jV_X?�V�E�/'j .:fq_z'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h/W�}y�µ?y蟙��Džb�Oz'h~f2q�<�Gخ?<+S?y蟙 \?xQ+� ~fz'h2Cyj?z_�~fԮc@y\?-?,i+R-�"Ƒ�^P�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�y\?-?,i+R-�"Ƒ�^P�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�K*CI+E,�S:(цb 1ر<~Xhqw,t:}܉ٰҏ].�~:sib`odXmǒOP u�@/.].�6(C1{]%DZR)*o{k\f !]`0F9�]E�︿>u�@/..<D[, A-bWpKcm9iآ˾wc nV]۷ zh2]%W!w!#EXf_e/!A #s'4EPUHр?1�XCHc.2?n(R5]�@(.w�}��qus5jCR,Yb^I&e$ h�]�G.w�}�om9'K6iQkhڒK>f_vy<�M�qtzЍ6+(';^l'4�2Aw0%\<c {d~@G<ǾVڹI+936BFI�]\0il}w_]\c]7Zi2A4=KTI$�]E�︿>u�@/.=t%YVs)ݴ)_\c=>ד[sw[4M@ _h�]�G.w�}�"˚+8&ݮ9 O@43\QycX'X\rU'4!1k ӻa_?O4k$Nd2Rk6}FHb9Ҁ4k�"ů~WE_OGyC� Ԭ ȱה?�J�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�+:ES%PПnz֍5dRA@AA+;P,0Fʐ@eACF>D6y K?����̼^Lz\Bڒ\" 'T{u4Ț9k(QQn�z֗P�� h�r�CȷMzrŵ[jlN1Ozf~&ԯ]`@wڃ�e�?Ə�?�'+&{m̬RsHta]OUk n 8x5&("xԱHjCw4U tWO2 [!B~4vͭX|##߂*/�?�'?����_ u +]Ha#mUrO$?]_ˆmيT{:C?���?�\@M2eHi$uDQp��?�'4kbNWϕ�]8i"'ǞwsW��` K@g,gvrAG=7ckF#1̊C �Z˾'mIu>- BVXȠ2I=鋣 )#u(�4�5ݕK%ʬ-|ǽTX$5ICQIV?�\GP�� h> 5{<L/[hL*z~zUC}-Y]*5͎wRe�?Ə�?�'D�$�iǰZC[ɏ>KvuE j�up�X��1�ȱk�_�=�u�cH�(Zo4�@@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@p�X��1�ȱk�_�=�u�cH�(Z                                           p�X��v�endstream endobj 348 0 obj << /Filter /FlateDecode /Length 1532 >> stream xWM6srXOQ M[i4]-zՕ%GwưfO OE/<->-}M¿>y^\]<qdoHOT)L/޳9̸Ӭ=.WD()9ŊoiJ#XnÉLn]cGsݴ]ȲM\&Jaڷ+sK*-q*nYִqhqWꪹ[xʍrBfO+5"~m}xe0\y!DꌶKBCYvj 4G4;t-er w%ko{)ϙ5dXlaeaC9mʰwmܔ^]>K7B }9]\sHͅ[߳ig Zx C3buV98nEyzx,hV tJ"\'+ʇSAaĔv^(Cst¤B'BIM/-JZ)(eyjzו=bz2v]Ǯs!06'c>ʱ Nx0'Y,t&Z@f6rE8^$mH I<$1ַF{6?Tu=ݿb(')gm8 ( M`W:i9)'p c 4ZmR_B]fHtRefM~XƋ3v4.$Axj j-p)ʥVjvjQY mK$Ij. O1-x.&АG83&wңx*MLVFR0qXk[ w6gaY|O8Ťv`aSζ`-Ŵ@u) 7i/BERhHB;iVc‚AK(߉|pğo..SqR 4<"T9['{)9rP݅-&㷓вg5 P5J4#:!J8𻛌?Uf6AV]*HP1 46et}RN EĚ #x<�QâpZJE~i(9L4ەHؾuq({G,C𷝸NwXD" L8EE} �?!�@8b5<D2& U\vtMn^ή<{ P%}wܢMB)F Q̘5slm*7/+GLP%dסؐƹn1p@;iZs?3iengOeT/ܻs]'fVb]%lX,3alT}B" *[oR{BNKx{!yIf^\:z}KobG-u1<@z)T03"<|Ms?8^h&'B3$.li>5:u,«+VX*M|u-Hv= hendstream endobj 349 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /DecodeParms << /Columns 700 /Predictor 15 >> /Filter /FlateDecode /Height 603 /Subtype /Image /Width 700 /Length 1955 >> stream x۪cVs4N\qHvٕ D;Pnl"IH%Mn]8Pk<'ϼz}8y'6cf3vlglSkǝ0ָKGqWw�S}�sVO9WO9VO9_WO9_VO9㉟WO9ɛ'O'q`x`x`x`x`x`x`x`x`x`x`x`x`x`x`x`8 0gz箯�sK8m3.\]=戗q 0GdKWO9%Kd[=戗,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kx/Y%Kd,%^Kָty#^Kָxe#^ƅ'5_[=sWO9`8;cc3v6Gnۣ9nwx(v݈;rlݽ�}endstream endobj 350 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Height 603 /SMask 349 0 R /Subtype /Image /Width 700 /Length 26472 >> stream �Adobe�d�����C�    %,'..+'+*17F;14B4*+=S>BHJNON/;V\UL[FMNK�C $$K2+2KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK�["������������ ����}�!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������� ���w�!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz� ��?�H]NI`I]2y p og5+8ٿ?c@G:� uy=;~V^jRHҴ@kk8nRƭt` :N�N�`6 Zvvy<I>�LC3qhƄҌ)E`Y4;WAKe?OLI?U M ^~g!VA<V2pZFKa#VT} Qߎ*yR,xOy.+[1;J u$d?t� Q�#O�X�–-W?8@><7"��,G&�@?�c� ͣ͠4i� Q�#O�X�¥hh/Mbh��?|<�G�F��ؚ?4�*_66"��,G&�@?�c� ͣ͠4i� Q�#O�X�¥hh/Mbh��?|<�G�F��ؚ?4�*_66"��,G&�@?�c� ͣ͠4i� TwfmNzgͬfūC, qo72Buy(:VqK d@�bh��?rMnqc hf3X Yއ)|!}OVlMn)M!R޾hRq.4gE=t iJ�[Fr=zt:2ݽ{hyVp~^5MbƐ(臖\J.74i� Q�#O�X�¹uEB6Y 2F>&�,Ht�=]K/B7 gc=:f��,X+yL/dowuLI{빴R&/1T$1O`:OO7x+X1N��,Xڄ{,[#5s@:u\Wv7x{FçFGcɤ;ؚ?4�*4� [ )V Oኩ\^&`B V vvk&[XƅVZO ߷A@G�F��ؚ?4�+nom pdO|Dc2O\gӜLn7kv+ <� =h�#O�X�Më[׺yZ�SpێzsOKijٗWr1#4R;Bq& „' S��,MM#D|pqkXҥt;U mDU'jcOEq]D+pP$EXհ#:~bh��?mFU,V mc+VNvx!0G`Tx/)XfW6秽D5=2dуmMْR«f&961s:&>-[f]\P68=)se .pF2}Mɛ�觪_3_"P6a;c3oG�F��ؚ?4�+J|jZkfg9Ϡަ[hp|BW%c/464i� SJЖU0H�u y?A Iw n=D sui6ym=qG`44i� Q�#O�X�¥hh/Mbh��?|<�G�F��ؚ?4�*_66"��,G&�@?�c� ͣ͠4i� Q�#O�X�¥hh/Mbh��?|<�G�F��ؚ?4�*_66"��,G&�@?�c� ͣ͠4i� Q�#O�X�¥hh/Mbh��?|<�G�F��ؚ?4�*_66"��,G&�@?�c� ͣ͠4i� Q�#O�X�¥hh/Mbh��?|<�G�F��E'49[si6`�Q & NŽfkA%wo�DžX?�V7tro,ySm!? 7|w�5Q@6YnU-@�̒�,MuP#I[Lv$HkM?ꨩpwhVG#_�Y?7�> '�]uC9ϭ�ѾO�Y?먠G|w�4o}n�O&('�,M�[��w�> '�F?�d�k9ϭ�ѾO�Y?먠G|w�4o}n�O&('�,M�[��w�> '�F?�d�k9ϭ�ѾO�Y?먠G|w�51 K6YvtPG$M2GqŊ tȌd[c»:(쩺rt`ϏV;'m˰Wһ(+,l',˴d+z{S) fM.G1q;>/vtPcRN1R o~Onĵ5eIdVMO` �tO@th!�E lq򎃅ޙ0DCQI,U. vP!,Cڐd9Y\ �d};sO])ebgryBD%ta3 HX֊�,,TF-+q 9- FIeiA?/?vP,k0Q642vGB2G$NsFr}Hʊ�գ6GJ!Әg*Öue{;V*֒Gk8.4&E9UŘ/6L(lRW,PKZ9*qi�6>75@54zt;[~XF8TVi Xg Г9Ί�J:&78fL5֖ .44c|{3~ek9ϭ�ѾO�Y?먠G|w�4o}n�O&('�,M�[��w�> '�F?�d�k9ϭ�ѾO�Y?먠G|w�4o}n�O&('�,M�[��w�> '�F?�d�k9ϭ�ѾO�Y?먠G|w�4o}n�O&('�,M�[��w�> '�F?�d�k9ϭ�ѾO�Y?먠G|w�4o}n�O&('�,M�[��GyC� Ԭ ȱה?�J�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�F!T�$w$;#< -\ҬP>]}?�aI>[HWʶhx QOi/ʸ<�}ho\8{>]}?�(m[{" m\zcOHY%28v`~I;Pq�@?.%NN� �S]Y c&7/=?#Qj7+ i]&Cq�@9G?Tы5#HᾂQ,[FޠҺ++`&쎯BW?r ^p�OQso<F`ѱ]랼tİ0]H fF`O>{%l ^p�?.?y�}�+ `4wA`.ハEYue\ Fsߎ(k?jo�h\*�Qq�@9XW0"F�6$9�q֡lr]Om4RJ#%=qG]0Cq�@9G?a7|vH${cDSu|A ıF쉊 Q91GO/mcQQSuiqm0_2BA< c{5/X0wuJrTUȓ.E;Z(5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (2-�"Ƒ�^P�+/,i+R*+6#"pIc�=�oُ>Pf?oh1�S@}�y{� OE�Ac�=�75=ُ>Pf?oh1�S@}�y{� OE�Ac�=�75=ُ>Pf?oh1�S@}�y{� OE�Ac�=�75=ُ>Pf?oh1�S@}�y{� OE�S$;)U9rF+E"ܠA##R\)3]B܊G�0躄:%BjF /?wyOϻ~cn~{ff�?Ə�?�'$Eb_d]En^X>~`Np�<Zsxa"aR!Ő F EX�r٣/�.O YQO='E[!UV�f�?Ɛn�ƚvw&J?T�|�jAȈ&ޟ19W� *?��g*5|rG2os!\|֦²=ͺϵ3)Fy`3ʏ~)�Ə��j}^]+_K=nB]@®"~nL;z�ߥk�eG�?W�GT{�O4{o cZxM/hbiL=eR$LOj#Elc$ �sԎݫ{*?��?� ys. ֒M) ;c1EᩗUk/(o9;8^�S�Q�?_W}cM"| f5iVEyyfp *'֕g274}�y謍>c�=� 1�Gُ�{� f?ojz(74}�y>c�=� 1�Gُ�{� f?ojz(74}�y>c�=� 1�Gُ�{� f?ojz(74}�y>c�=� 1�Gُ�c�=�Z[k`i-Q@~�cH�(Zo4�@@-$d+ך^Oӭmހ*�ik�hӿ�/Ko !i.#Gc#%h;x=@-=!\?vݸݜ Q@ ӿ�/_?lKRγ? c F 8jvt ~h"9N>^@{w�I_ON�_VZ[m(챱ݴ0[o;zUX<Qaox4Q΅I �%oZ�w�?ֿƏ=;�ZW[8ܴPd; �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_p;T-O߷jc+ &?jrIT| Uq@ _ON�_C<Boy#FDn�tAG^ƧMrU_.KstAPzw�Z��?�5rR6xFё`Տ8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy8P_�?ֿƏ=;�jy¨FhP38�4ik�j;ݵqVEfC21`0 n@3=jĞ (iXپSʁ@�ik�hӿ�/Z@,v#|n~)kL2*l@;3z< q@ ӿ�/_#Y7>q8F;wm1o8q*x^_0kw4V %yRA�M_ON�_Sj6BwFwX#r �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �ӿ�/_O8Q �oqms6߽l}qN�AL^JI'ߒK�%Q@~�cH�(Zo4�@@�tZXS}ޓ^O{˄RxVamj&ŴHqq@0L!i iԻN3jΒumYTϒb#>?_^&mVOKk(C&@HIE zDKu2ȂHdWv[($(xvd5#x* e �rO\#K՝kX�`��<"��a[x`[jf^Va!@K =xcoeOo)Q5dh1>asxG`�(F{wL&и 15sȧ}(,/P|<w`��<"��7ȣȧ}(,/P|<w`��<"��7ȣȧ}(,/P|<w`��<"��7ȣȧ}(,/P|<w`��<"��7ȣȧ}(,/P|<w`��<"��@�8�aVJxamM6BUpmK69,եl#nH(*Hf{[(!eިw+ @:�ϲĶ]FؼYTϒb#>?_^!}7d b1aT;p_^[Ovɧv2$w2Rv@ :J/uXd{;;K�X);Wo RyO�Y4tv0Bcd'+-wke`DJ,$*Ts=GZexE�| �oGN,/QX?_y�<"�exE�| �oGN,/QX?_y�<"�exE�| �oGN,/QX?_y�<"�exE�| �oGN,/QX?_y�<"�exE�| �oGN,/QX?_y�<"�exE�| �oTo Fq߭h}*}?fM7%ʷ2`@Z�θ<L[JʰYTH9G_/#RZm,l#!\p ^#E^2"r6gq~=9./o8J# Y � 8-w>Fm^]: [1o 'zci7 ߟ�/fH<޴EݼwHEIX?_ 1]Zk2Lc !&EmN 00=^cớczmi,Cr~^qlV`��<"��CP�E � ȧ}(,/P|<w`��<"��7ȣȧ}(,/P|<w`��<"��7ȣȧ}(,/P|<w`��<"��7ȣȧ}(,/P|<w`��<"��7ȣȧ}(,/P|<w`��<"��PbQ�CK�2_ȨTB�`}礇K�-Q@~�cH�(Zo4�@@�tZ{jڭED~R<@3X�i."M,2K47<Q΁woairB,-]V7b<H;xx 3PӤE0�:G' IU�0z8I4Fd1a&B8J6ai�.V$TgpCax �yo#1}RRMR-3| .9(]c6Ϩ],w%lr3y>�=:iumI$uo�lj�5_Q!{u+?5?��?5?��P tWlj�4lj�4}B_̃ۮǭ^I�F��F� 2nEy'Ƨ�AGƧ�AG%=zn�n�P tWlj�4lj�4}B_̃ۮǭ^I�F��F� 2nEy'Ƨ�AGƧ�AG%=zn�n�P tWlj�4lj�4}B_̃ۮǦkv/eIH户M>\U"{ h mXs ]jAWs*Ee8]̇8<V΁AhkK*jE~I8%�ٮ*䓋o̮K].o Z33*  =h.P-JX噙xXBs/�Q�Կis�*G:Xm)reNJz}mVO#_R��/�P�Կis�(�z{j_4�Ed�=e�=/\�?�ڗ .�kQY?YmK�?rG綥�K9@VO#_R��/�P�Կis�(�z{j_4�Ed�=e�=/\�?�ڗ .�kQY?YmK�?rG綥�K9@VO#_R��/�P�Կis�(�z{j_4�Ed�=e�=/\�?�ڗ .�kVneqvZk[$U\�qzv��ڗ .rNFhl -џ2*R�'ZS%kؙK\eN{j-]Gv T|9]5ox+ sȊTC.�`z+2c&yNYv3ַ7)u&䁴I8Wԟ#/mz>k->(<fvdzrmOVV[t8`gnL�#w�iF_̅c$�#w�h�#w�iB_̃ۮǭ^I�F��F� 2nEy'Ƨ�AGƧ�AG%=zn�n�P tWlj�4lj�4}B_̃ۮǭ^I�F��F� 2nEy'Ƨ�AGƧ�AG%=zn�n�P tWlj�4lj�4}B_̃ۮǭ^I�F��F� 2nEy'Ƨ�AGƧ�AG%=zdzH~�AUti!yI?7&� jBԖ(_X?�Ve[E#�jP_ְQ24%br\4G-?zKJB)BڱY1 L屎[K t0ȸ_ҽR�csn(簷Fh .bI!*xx<^E[?>v+O�w'y/E{E}{3h�waxQ�!<>=WQG�<^(�g^E_z+(�Cy/E{E}{3h�waydžu }6ki.-WD!w=Ҷ5}_"yeFQW9 n}*On]UI � >�A7��֢'}zo4O�oM��Ƶ I � >�A7��֢2'7�\G$ kZ��A�ޛ�q�?.?j('}zo4O�oM��Ƶ I � >�A7��֢2'7�\G$ kZ��A�ޛ�q�?.?j('}zo4O�oM��Ƶ I � >�A7��֢2'7�\G$ kZ��A�ޛ�q�p^yMKt,X~ ܤ0p;NS&qV<5E̲yin!|{ C@4M#ƬA߼oM^./? xhy|Ɠv>f@8{Eken_ğaxS�g^E_z+(�Cy/E{E}{3h�waxQ�!<>=WQG�<^(�g^E_z+(�CyzO{Z׍jޗ�)e�?a�yݶt--QHf_X?�Ve[E#�jP_֤��?y?RZ�?v(((((((((((((((((((((((((((((((((((((((( �F_!�,zl?z_� h�GyC� Ԭ ȱה?�J�^OԖ?rG�/'jKOGހ.E�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEB_�\S$?z_�B2�oIޗ�(J(2-�"Ƒ�^P�+/,i+R"�%O�\oQ��tZ?�Q�7 QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�PB2�oMK�#/qO$(/,i+R-�"Ƒ�^P�(/y?RZ�?G-?z�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP #/qO~�ANB2�oIޗ�(J(2-�"Ƒ�^P�+/,i+R"�%O�\oQ��tZ?�Q�7 QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�PB2�oMK�#/qO$(/,i+R-�"Ƒ�^P�(/y?RZ�?G-?z�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP #/qO~�ANB2�oIޗ�(J(2-�"Ƒ�^P�+/,i+R"�%O�\oQ��tZ?�Q�7 QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�PB2�oIޗ�)e�?a��KEP_X?�Ve[E#�jP_֤��?y?RZ�?v(((((((((((((((((((((((((((((((((((((((( �F_!�,zl?z_� h�GyC� Ԭ ȱה?�J�^OԖ?rG�/'jKOGހ.E�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEB_�\S$?z_�B2�oMK�-Q@~�cH�(Zo4�@@�tZ?�Q�7��?Ii��(�( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ((K�!7K��F_%(/,i+R-�"Ƒ�^P�(/y?RZ�?G-?z�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP #/qO_�\S$?z_� (�GyC� Ԭ ȱה?�J�^OԖ?rG�/'jKOGހ.E�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEB_�\S6/�S�?C� �( ȱה?�JGyC� Ԡ�?Ii��(�֤��Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@%�?a�:_�\S$?z_� (�GyC� Ԭ ȱה?�J�^OԖ?rG�/'jKOGހ.E�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEB_�\S6/�S�?C� �( ȱה?�JGyC� Ԡ�?Ii��(�֤��Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@%�?a�:_�\S$?z_� (�GyC� Ԭ ȱה?�J�^OԖ?rG�/'jKOGހ.E�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEB_�\S$?z_�B2�oMK�-Q@~�cH�(Zo4�@@�tZ?�Q�7��?Ii��(�( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ((K�!7K��F_%(/,i+R-�"Ƒ�^P�(/y?RZ�?G-?z�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP #/qO_�\S6/�PQE�e[E#�jV_X?�V�E�/'jKOGޣ�%O�\o@h�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�/e�)ޒ/�R�!7� �( ȱה?�JGyC� Ԡ�?Ii��(�֤��Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@%�?C� Y#/qO$(/,i+R-�"Ƒ�^P�(/y?RZ�?G-?z�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP #/qO~�ANB2�oIޗ�(J(2-�"Ƒ�^P�+/,i+R"�%O�\oQ��tZ?�Q�7 QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�PB2�oMK�#/qO$(/,i+R-�"Ƒ�^P�(/y?RZ�?G-?z�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP #/qO~�ANB2�oIޗ�(J(2-�"Ƒ�^P�+/,i+R"�%O�\oQ��tZ?�Q�7 QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�PB2�oMK�#/qO$(/,i+R-�"Ƒ�^P�(/y?JI WE�(H2xb%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b%c�ϤUl�?{3��>Q�T}�o?*b�<(_?M�}G�Q�I�{37? ~�7�G}&��-�<(b u$F5Q$'R� ]�<(J'8Eo4�@Y~�cH�(Z�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEo4�@Y~�cH�(Z�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�R�$ޖooca %^�pxPRnc2ʿކ5R�h�<�_& 8J4}cv8?@ �9?b�W/�QC[&m5b  9wSϲu/7e"LgiR2=E�?F/w�r�4h�<�_&HK),dIV_1Y8$x}jzݜA*Or3gP?aҏVjxf1$2,{ȫx{mYX$tlqϥ�hE�Ui/ǹ~HWTz$ ,VI`a#?5jʶHb]t_F/w�r�4h�<�_&ֳ5]f[{K8K̦BBFqp� ?b�W/�G_���k6oOiWPF/,'d# 221G-7VmE4Ne2Հ`{zc _���hWi",p<<A SQ"KG"V*FA�QYc4m-,9;OA`օ�#B0DQp:[+S>`Cо3�L5+vEOFFBF/w�r�5y\GJ bBƤN&ыy]�M1+�?oatKLd1 mn ǯ<Z}ȷtF 뵈cؚ�_��9}guE+yQ #Fʘ�Ã&ZwVb6C8=C@Jy͉,l�@ pA>ج[ǵQ{'<@TQE�e[E#�jV_X?�V�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�+5U2G:RznօEqo-4dAejzk$4V̢'*S=:?Tawm\vV &?R�/&0;&;k{m�jݲ p7d瞴'PxkV)|v1Xʀ[nz/'q[fԿ/7�ڗ�14A<;}%IHTE`�e)V:&¥pҪ0{Vٵ/ �~b�h6�Ay_M�iA'RMAz005Vnyس7Ԛ�EPT+ | j1 2i# x&{PNv.?`@ _"]"MBQ1ex)XʍT}R�/&j_�uu(狀6ut!"V,lIv\f7@NOt`9:QmKߘ>ͩ^o�@~E#AYfԿ/7�5{\OxTSh'3OfrG5~k*FUF��V}jA!=^+B=.@9> ~EciWkRӖ |VCvU<`lbծeI6�Ay_M�2M*A,�`3ӞGM i6&Z$yB<6�Ay_MfԿ/7�  ]IiLbưA3J9uܣh|{mVQIs|OSS}R�/&j_�#a63J7߆)aTt<*vZ±Bz@Eo4�@Y~�cH�(Z�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QE�QEo4�@_9E f(kE .;]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4]$u ]s:?tWΟ)�ƏIu ?�@E_:KgQ��?%?3�S��}E|� .�AG�h�\�Σ�O4endstream endobj 351 0 obj << /Filter /FlateDecode /Length 3407 >> stream xZ[o~oR,ps 5i qE\*E˴%R!},T4( ٙsev||wu?淳gFgu?q5U/՛02̓u~Cw6nXvu\)vxt|?όKi~~><)ߙsp%ʓOlOnhS;z&cyFtoO?? R]gξ^T%vMdE|F6E*0]HIF>!d̗`W7ޙ[4>2IԤm|*pg'<F,/<PxSBgwG\:9p_/iy %_rwҤt=6 /~دݷ`'g|TQθE`[]o^#Wi;>(Pfl([6qztד}* Zw 9|&J'Y,~S,w+T#~@NKPŧgz ;(e-pl:@z{Czn+tns<,LI7Yg=;۩ؽ;} zphT#mwNQXvzRNTi]z MwnnZ YǷuClo^Y(mK4wN+\JĨ>tr SBtmCA嗯d=$J5J6fԹ|Ł/9}Wc0VѾۮoCX_D7˟C=]\�5xM廙BERw۞29!rdü9T?@#&Œw+(mμIaC84eoy g|L;oJEm ))0y-jy \1?N'#ִHf2ݼ=,a]ܢuDr6r1/ݿFŚĄbv;^U汘=~^kyIZ2?�Y\?@de` o_Sڠ/:y\M Bf^L2n ]{NmF0z;KB~}ܯ3LVOWo9g{ J߇ȿtw?\R,n2jlctLS8݃}o"(xQ`AAa^(\m ţR|RGDRd2 l8B�ve4GػD(aJ蝈H,boDPo0 =2葐T":a8Rh2G )&4.+$ f뢢PD{'B|Rr)/ |L(!}VΜQ{3= bbCqS6y`Cm3"h*f�Z7uTP͚'ud Y>ier\V=1M!D f' !`lpS8vgm."yrjJ]Sxltp4eo;Q0zg[zRdb4Q"6c&P$RR%E+ !PN(:1RR0ًb]Вz;1F֎ < u,F%%J:RJab>#)5qR?\�UJ�t,)` 0㣆d#V8(W>�P,,|r4&D:0Y5,z M<)FA vǦґ9"DިW%TxHa�Fh`ޠˠ zHEcx\܀4qi*Eo? ՟F&!N]N xsgp'. |ui,n /|;E� f @"xHPZGD׀P|ղi4, 8"˞|cpG|م΂%i65c#3kem_]8 �E*MyKтESщBF()%"UZ* H 2w_5ʽDDci+%ݕY(H5 bSعTRd�9h4x,zH/Aw &l {^An:d) -B67gDE.)uh\ҸÆnl&u:xX̕AQ2bj(UVLTYwb!k.Q軘3*v`%jh8(U(:r֪'45HIⓞBdqP*TUj}j8BkMmc9e"fLP6,>OR98Ju| Bmid8d0I@V e;`F㣌Kt@asHk*B변=*eaxƚI$Bnr~+Nu򽈂W1DA]=pe �0EBuX#�V:(HcoI)fS n%JgLD""Zh<TmFf�xSL@\"q6I@f# +wZ"|-Ut^C^xlqRё%fEk_O^E.v6rciû2YfΟH�EHw0)jV_)ɫhd Hl/e~G;6q`6#%s&SZf~N�ōu#eGIF]fr[9\ڱ g^GJL(2kZh$0omdup4!`dej6jv4- ;Ը Ϯ #%dân37!pmi.d4l|(WQqGӻrC33ݟ(fn'DDtruXA=7 xX(WQqGSY9\97xR)@0#y C4rxlۢr,VE q>8 kvWYُKeU2Fm~ֆ/)pˀ˵CUάL,͖3+›ȚK3@? ^|7tUxi{<=ӖSZr(ǵsYތ6{ _C6Xt];K5N뇷qh"Y{~ʹ+^9? i0}7bO(&ևg .]:%&ׂB?]t}Su!C{mCvSs K&uw۵xAV@N{}o'm}~9p#' 8|ݽ+�kh营5O8;fM'0xR^endstream endobj 352 0 obj << /Filter /FlateDecode /Length 1189 >> stream xXn67d@AEԛ i&Ev+c,i=#s%y+s7^\-՚z- S$c+[-& lJ. pGg^Gk V%iVmWa_&g'03Pj6$1j#F7 \~^!lj[@R$8c<$-r(fse-`,RxX^>)/'6m"}1&V" m:Vq7pCT$MQ4#QxӼ8vE?{y4 /½e 'g|y^3Z1̽ʆMYÜk9a++@_M9F<;綮Y3cli&KESڭ@s)He 1:eѡT𡷟+M""HR k[Z `1nHFd/۶by{pG"$ H<]O{8s!1CMyIrA5AMJ>@i49?74`51|vKsz Nxs8JB7KZKF#~1_vԽsY8&6Y[MNx ) ,cc<ЫaVd^6*[er&, /lu1'n= HI2S[nֽX*Rqb7 6vAG= ` {]M0t0^(Iљ\G+-]|u� A@<r"FoS<ҐCZ tvbv<:GϿgH=T 77}ьlwL1ѵK 'oy[LSƁ;URc~^@W ̥[кg툡zTav S 6֬+s5:c?CSkHL}nT |VoåvE~v)붺fB2Xߗ&=eMim]SMDY~_jNәdme<6]mYkw pP |WpFRQo0cùyZ%"qhy{A{q̷.N~*[@Gendstream endobj 353 0 obj << /Type /XRef /Length 339 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Info 3 0 R /Root 2 0 R /Size 354 /ID [<723116ae522f2fb5fefe5ffe3554cba5><a0c50013c3a7b167735c184f05e53f68>] >> stream x;K`4ibx]Iuꢋx8(8tr_ g8ꤠVDQpuм`DBx8|82Xada)aƌi~3c\vFh7ւp+_㭈mE?F@[sK%zbjAl7SbJfyBqGlbػ,TX,qzR;$3y+4T%лYhL /?$B4W)ms-V햹}k.VQڢ(ϓ-u{)TIt0ьwcUD4"M-ǭ< endstream endobj startxref 791809 %%EOF ���������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/inst/doc/cellcycle.txt����������������������������������������������������������������������0000644�0001762�0000144�00000000750�13277247010�016043� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������targets, factors CycD, CycD Rb, (! CycA & ! CycB & ! CycD & ! CycE) | (p27 & ! CycB & ! CycD) E2F, (! Rb & ! CycA & ! CycB) | (p27 & ! Rb & ! CycB) CycE, (E2F & ! Rb) CycA, (E2F & ! Rb & ! Cdc20 & ! (Cdh1 & UbcH10)) | (CycA & ! Rb & ! Cdc20 & ! (Cdh1 & UbcH10)) p27, (! CycD & ! CycE & ! CycA & ! CycB) | (p27 & ! (CycE & CycA) & ! CycB &! CycD) Cdc20, CycB Cdh1,(! CycA & ! CycB) | (Cdc20) | (p27 & ! CycB) UbcH10, ! Cdh1 | (Cdh1 & UbcH10 & (Cdc20 | CycA | CycB)) CycB, ! Cdc20 & ! Cdh1 ������������������������BoolNet/inst/doc/BoolNet_package_vignette.Snw�������������������������������������������������������0000644�0001762�0000144�00000261401�14272154552�020764� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������\documentclass[a4paper]{article} \SweaveOpts{keep.source=TRUE} %\VignetteIndexEntry{Detailed introduction to all major features of BoolNet} \usepackage{a4wide} \usepackage{graphicx} \usepackage{amsmath} \usepackage{hyperref} \usepackage{listings} \lstset{breaklines=true, breakautoindent=false, breakindent=0pt, columns=fullflexible,keepspaces=true, basicstyle=\small\ttfamily} \setlength{\parindent}{0em} \setlength{\parskip}{0.2em} \title{BoolNet package vignette} \author{Christoph M\"ussel, Martin Hopfensitz, Hans A. Kestler} \widowpenalty=10000 \clubpenalty=10000 \hyphenation{me-thods pro-per-ties re-pre-sen-ta-tion} \begin{document} \SweaveOpts{concordance=TRUE} \maketitle \tableofcontents \clearpage \section{Introduction} \texttt{BoolNet} is an R package that provides tools for assembling, analyzing and visualizing synchronous and asynchronous Boolean networks as well as probabilistic Boolean networks. This document gives an introduction to the usage of the software and includes examples for use cases. \texttt{BoolNet} supports four types of networks: \begin{description} \item[Synchronous Boolean networks]{ consist of a set of Boolean variables \[ X = \left\{X_1, \ldots, X_n \right\} \] and a set of transition functions \[ F=\left\{ f_{1},\ldots,f_{n}\right\}, \] one for each variable. These transition functions map an input of the Boolean variables in $X$ to a Boolean value ($0$ or $1$). We call a Boolean vector $\mathbf{x}(t) = \left(x_1(t), \ldots, x_n(t) \right)$ the {\em state} of the network at time $t$. Then, the next state of the network $\mathbf{x}(t)$ is calculated by applying {\em all} transition functions $f_i(\mathbf{x}(t-1))$. In a biological context, genes can be modeled as Boolean variables ({\em active/expressed} or {\em inactive/not expressed}), and the transition functions model the dependencies among these genes. In the synchronous model, the assumption is that all genes are updated at the same time. This simplification facilitates the analysis of the networks.} \item[Asynchronous Boolean networks]{ have the same structure as synchronous Boolean networks. Yet, at each point of time $t$, only {\em one} of the transition functions $f_i \in F$ is chosen at random, and the corresponding Boolean variable is updated. This corresponds to the assumption that in a genetic network, gene expression levels are likely to change at different points of time. In the most common model, the gene to be updated is chosen uniformly among all genes. Moreover, \texttt{BoolNet} supports specifying non-uniform update probabilities for the genes.} \item[Probabilistic Boolean networks (PBN)]{ allow for specifying more than one transition function per variable/gene. Each of these functions has a probability to be chosen, where the probabilities of all functions for one variable sum up to 1. Formally \[ F=\left\{\left\{\left(f_{11}, p_{11}\right), \ldots, \left(f_{1k_1}, p_{1k_1}\right)\right\}, \ldots, \left\{\left(f_{n1}, p_{n1}\right), \ldots, \left(f_{nk_n}, p_{nk_n}\right)\right\}\right\} \] where $k_i$ is the number of alternative transition functions for variable $i$, and $p_{ij}$ is the probability that function $j$ is chosen for variable $i$. A state transition is performed by selecting one function for each gene based on the probabilities and applying the chosen functions synchronously.} \item[Temporal Boolean networks]{ are Boolean networks that incorporate temporal predicates and discrete time delays. Here, the next state $x(t)$ may not only depend on $x(t-1)$, but can depend on any predecessor state $x(t - \Delta), \Delta \in \{1, 2, \ldots\}$. Furthermore, $x(t)$ may also directly depend on the time step $t$ itself. } \end{description} In \texttt{BoolNet}, there are different structure classes representing these network types: \begin{description} \item[\emph{BooleanNetwork} objects]{ contain synchronous and asynchronous Boolean networks. Here, the transition functions are internally represented as truth tables.} \item[\emph{ProbabilisticBooleanNetwork} objects]{ encode Probabilistic Boolean networks. They use a truth table representation as well.} \item[\emph{SymbolicBooleanNetwork} objects]{ represent synchronous and temporal Boolean networks. They encode Boolean functions in a symbolic form, i.e. as expression trees.} \end{description} As we have seen, the networks are represented in two different forms: The truth table representation, which basically maps inputs to the corresponding output values, is usually the most efficient representation for synchronous, asynchronous and probabilistic networks and uses a very fast simulator. However, this representation grows exponentially with the number of inputs and is therefore inappropriate for networks with a high number of inputs. This is particularly the case for temporal networks, where each unique time delay for a gene encodes an input. Hence, temporal networks are represented by directly encoding the corresponding Boolean expressions and use a different simulator. As synchronous Boolean networks are a special case of temporal networks (with all time delays being 1), these networks can also be represented as \emph{SymbolicBooleanNetwork} objects. The package provides several methods of constructing networks: Networks can be loaded from files in which human experts describe the dependencies between the genes. Furthermore, they can be reconstructed from time series of gene expression measurements. It is also possible to generate random networks. This can be helpful for the identification of distinct properties of biological networks by comparison to random structures. The different methods of assembling networks are described in Section~\ref{sec:assemblingnetworks}. In Section~\ref{sec:networkanalysis}, tools for the analysis and visualization of network properties are introduced. For synchronous, asynchronous and temporal Boolean networks, the most important tool is the identification of attractors. Attractors are cycles of states and are assumed to be associated with the stable states of cell function. Another possibility of identifying relevant states is the included Markov chain simulation. This method is particularly suited for probabilistic networks and calculates the probability that a state is reached after a certain number of iterations. To test the robustness of structural properties of the networks to noise and mismeasurements, the software also includes extensive support for perturbing networks. In this way, it is possible to test these properties in noisy copies of a biological network. In Section~\ref{sec:importexport}, the interaction of \texttt{BoolNet} with related software is described. In particular, the import from and export to SBML is discussed. Also, the necessary steps to import networks import networks from BioTapestry and to export networks to Pajek are outlined. For the examples in the following sections, we assume that the \texttt{BoolNet} package has been properly installed into the R environment. This can be done by typing <<eval=FALSE>>= install.packages("BoolNet") @ into the R console or by the corresponding menu entries in an R GUI. For some of the plots, the \texttt{igraph} package is required and must be installed in your R environment as well. This is analogous to installing \texttt{BoolNet}. For the BioTapestry and SBML import, the \texttt{XML} package must be installed. After installation, the \texttt{BoolNet} package can be loaded via <<>>= library(BoolNet) @ \section{Assembling networks}\label{sec:assemblingnetworks} \subsection{Assembling a network from expert knowledge} A major advantage of Boolean networks is the fact that natural-language statements can easily be transferred into this representation. This allows researchers for building Boolean networks entirely from expert knowledge, for example by collecting statements on gene dependencies from literature and expressing them as Boolean rules. \texttt{BoolNet} is able to read in networks consisting of such rule sets in a standardized text file format. In such a file, each line consists of a target gene and an update rule, usually separated by a comma. Optionally, it is also possible to add a probability for the rule if the file describes a probabilistic network. The first line of such a file is a header \begin{samepage} \begin{verbatim} targets, factors \end{verbatim} or \begin{verbatim} targets, factors, probabilities \end{verbatim} \end{samepage} To illustrate the process of transforming natural-language statements into Boolean rules, we take a look at the mammalian cell cycle network introduced by Faur\'e et al. \cite{faure06}. In Table 1 of this paper, the authors list natural-language statements of gene dependencies and the corresponding Boolean expressions. The following rules are taken from this table. For gene CycD, Faur\'e et al. state: \begin{quote} \textit{CycD is an input, considered as constant.} \end{quote} Transforming this into a Boolean rule is rather simple: CycD does not change its value, which means that its value after a transition only depends on its previous value. Thus, the transition rule is \begin{verbatim} CycD, CycD \end{verbatim} Gene Rb has a more complex description: \begin{quote} \textit{Rb is expressed in the absence of the cyclins, which inhibit it by phosphorylation [...]; it can be expressed in the presence of CycE or CycA if their inhibitory activity is blocked by p27.} \end{quote} As a general rule, inhibition can be represented by a Boolean negation. In the \texttt{BoolNet} file format, a negation is expressed by the \texttt{!} character. The referenced cyclins comprise the genes CycA, CycB, CycD, and CycE. If {\em all} these genes are absent, Rb is expressed -- i.e. if CycA is not expressed {\em and} CycB is not expressed {\em and} CycD is not expressed {\em and} CycE is not expressed. A logical AND is embodied by the \texttt{\&} character. Consequently, the first part of the rule is \begin{verbatim} ! CycA & ! CycB & ! CycD & ! CycE \end{verbatim} In combination with the above statement, the fact that Rb can be expressed in the presence of CycE and CycA if p27 is active means that CycB and CycD must not be active. Thus, the second part of the rule is \begin{verbatim} p27 & ! CycB & ! CycD \end{verbatim} This statement is an exception (or alternative) to the first statement; this can be expressed as a logical OR, for which the \texttt{|} character is used. The complete rule for gene Rb is thus \begin{verbatim} Rb, (! CycA & ! CycB & ! CycD & ! CycE) | (p27 & ! CycB & ! CycD) \end{verbatim} After processing all genes in the table in this way, we get the following network description: \begin{samepage} \begin{footnotesize} \begin{verbatim} targets, factors CycD, CycD Rb, (! CycA & ! CycB & ! CycD & ! CycE) | (p27 & ! CycB & ! CycD) E2F, (! Rb & ! CycA & ! CycB) | (p27 & ! Rb & ! CycB) CycE, (E2F & ! Rb) CycA, (E2F & ! Rb & ! Cdc20 & ! (Cdh1 & UbcH10)) | (CycA & ! Rb & ! Cdc20 & ! (Cdh1 & UbcH10)) p27, (! CycD & ! CycE & ! CycA & ! CycB) | (p27 & ! (CycE & CycA) & ! CycB &! CycD) Cdc20, CycB Cdh1,(! CycA & ! CycB) | (Cdc20) | (p27 & ! CycB) UbcH10, ! Cdh1 | (Cdh1 & UbcH10 & (Cdc20 | CycA | CycB)) CycB, ! Cdc20 & ! Cdh1 \end{verbatim} \end{footnotesize} \end{samepage} Now save this description to a file ``cellcycle.txt'' in your R working directory. The network can be loaded via <<eval=FALSE>>= cellcycle <- loadNetwork("cellcycle.txt") @ The result is an object of class \emph{BooleanNetwork} containing a truth table representation of the network. The same network is also included in \texttt{BoolNet} as an example and can be accessed via <<>>= data(cellcycle) @ \texttt{BoolNet} also provides several convenience operators that can be used to express complex Boolean functions in a compact way, e.g. \begin{itemize} \item \texttt{maj(a, b, ...)} is 1 if the majority of its operands are 1. Similarly, \texttt{sumgt(a, b, ..., N)} is 1 if more than $N$ operands are 1, \texttt{sumlt(a, b, ..., N)} is 1 if less than $N$ operands are~1, and \texttt{sumis(a, b, ..., N)} is 1 if exactly $N$ operands are 1. \item \texttt{all(a, b, ...)} is 1 if all its operands are 1 (i.e. a logical AND), and \texttt{any(a, b, ...)} is~1 if at least one of its operands is 1 (i.e. a logical OR). \end{itemize} The cell cycle network is a classical Boolean network, where each transition function only depends on the previous state of the network. E.g., \verb+CycB, ! Cdc20 & ! Cdh1+ can be written formally as $CycB(t) = \neg Cdc20(t-1) \wedge \neg Cdh1(t-1)$. As already discussed before, \texttt{BoolNet} also incorporates several temporal extensions. For example, a transition function can also depend on the states of genes at earlier time points: \begin{verbatim} a, b[-3] & b[-2] & b \end{verbatim} is 1 if b has been active in the previous three time steps. The operators described above can also incorporate time ranges. The previous statement can be written in a more compact way using the \texttt{all} operator: \begin{verbatim} a, all[d=-3..-1](b[d]) \end{verbatim} This defines a time delay variable \texttt{d} that can be used for time specifications inside the operator. It can also be used in arithmetic operations. E.g., \begin{verbatim} a, all[d=-3..-1](b[d] & c[d-1]) \end{verbatim} specifies that a is active if b has been active in the previous three time steps and c has been active at time $t-4$, $t-3$ and $t-2$. Apart from relative time specifications, the \texttt{BoolNet} network language also incorporates predicates that depend on the absolute time, i.e. the number of time steps that have elapsed since the initial state. \begin{samepage} For example, \begin{verbatim} a, timeis(3) \end{verbatim} specifies that \texttt{a} is active at time step 3 and inactive at all other time steps. Similarly, the predicates \texttt{timelt} and \texttt{timegt} evaluate to 1 before and after the specified time point respectively. \end{samepage} As the above examples do not cover all possibilities of the network description language, a full language specification is provided in Section~\ref{sec:appendix}. For temporal networks, \texttt{BoolNet} uses a special symbolic simulator that represents the functions as expression trees, whereas the standard simulator is based on a truth table representation. These simulators are discussed in Section~\ref{sec:networkanalysis}. As synchronous Boolean networks are a special case of temporal networks, they can also be simulated with the symbolic simulator. When a network is loaded from a file using \texttt{loadNetwork()}, the user can specify the parameter \texttt{symbolic=TRUE} to load it in form of a \emph{SymbolicBooleanNetwork} object instead of a \emph{BooleanNetwork} object. The same parameter is also available for the import functions discussed in Section~\ref{sec:importexport}. Temporal networks can only be loaded with \texttt{symbolic=TRUE}, as \texttt{BoolNet} cannot represent them as truth tables. \begin{sloppypar} As many network generation and modification routines (such as random network generation and network reconstruction that are discussed in the following sections) internally use the truth table representation, there are conversion routines \texttt{truthTableToSymbolic()} and \texttt{symbolicToTruthTable()} that convert synchronous Boolean networks of class \emph{BooleanNetwork} in a truth table representation to networks of class \emph{SymbolicBooleanNetwork} in a symbolic representation and vice versa. For more details, please refer to the manual. \end{sloppypar} \subsection{Reconstructing a network from time series} An entirely different approach of assembling a network is to infer rules from series of expression measurements of the involved genes over time. For example, microarray experiments can be conducted at different points of time to cover the expression levels of different cell states. To reconstruct networks from such data, \texttt{BoolNet} includes two reconstruction algorithms for synchronous Boolean networks, Best-Fit Extension~\cite{laehdesmaeki03} and REVEAL \cite{liang98}. REVEAL requires the inferred functions to match the input time series perfectly, hence it is not always able to reconstruct networks in the presence of noisy and inconsistent measurements. Best-Fit Extension retrieves a set of functions with minimum error on the input and is thus suited for noisy data. In the following, we introduce a tool chain for the reconstruction of a Probabilistic Boolean Network from time series using Best-Fit extension. Microarray measurements are usually represented as matrices of real-valued numbers which, for example, quantify the expression levels of genes. \texttt{BoolNet} includes a real-valued time series of gene measurements from a project to analyze the yeast cell cycle \cite{spellman98} which can be loaded using <<>>= data(yeastTimeSeries) @ This data contains four preselected genes and a series of 14 measurements for each of these genes. \begin{sloppypar} In a first step, the real-valued dataset has to be converted to binary data as required by the reconstruction algorithm. \texttt{BoolNet} offers several binarization algorithms in the function \texttt{binarizeTimeSeries()}. We here employ the default method which is based on $k$-means clustering (with $k=2$ for active and inactive): \end{sloppypar} <<>>= binSeries <- binarizeTimeSeries(yeastTimeSeries) @ The returned structure in \texttt{binSeries} has an element \texttt{\$binarizedMeasurements} containing the binary time series, and, depending on the chosen binarization method, some other elements describing parameters of the binarization. To reconstruct the network from this data, we call the Best-Fit Extension algorithm: <<>>= net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4) @ Here, \texttt{maxK} is the maximum number of input genes for a gene examined by the algorithm. The higher this number, the higher is the runtime and memory consumption of the reconstruction. \begin{samepage} We can now take a look at the network using <<>>= net @ \end{samepage} \begin{sloppypar} The dependencies among the genes in the network can be visualized using the \texttt{plotNetworkWiring()} function. In this graph, each gene corresponds to a vertex, and the inputs of transition functions correspond to edges. \end{sloppypar} <<eval=FALSE>>= plotNetworkWiring(net) @ plots a graph similar to that at the top of Figure~\ref{fig:wiring}. To use this function, you must install the \texttt{igraph} package. \begin{figure}[p] \centering \includegraphics[width=0.5\linewidth]{wiring1} \includegraphics[width=0.5\linewidth]{wiring2} \caption{The wiring graph of the reconstructed network without prior knowledge (top) and with the inclusion of prior knowledge (bottom). Each node of the graph represents one gene, and each arrow represents a gene dependency.} \label{fig:wiring} \end{figure} A network that involved the same genes was examined by Kim et al. \cite{kim07}. When comparing the wiring graph of our reconstructed network with the reference network presented in Figure~2 of this paper, one observes a very high similarity between the two networks. However, the reconstructed network comprises too many links for the gene Sic1: The reference network does not contain a self-regulation of Sic1 or regulation of Sic1 by Fkh2. If it is known in advance that these regulations are not plausible, such prior knowledge can be supplied to the reconstruction algorithm: <<>>= net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4, excludedDependencies = list("Sic1" = c("Sic1", "Fkh2"))) @ The wiring of the reconstruction with prior knowledge is shown at the bottom of Figure~\ref{fig:wiring}. We can see that the two false links are now eliminated. Similar to \texttt{excludedDependencies}, there is also a parameter \texttt{requiredDependencies} that specifies dependencies that must be included in the network. When \texttt{reconstructNetwork()} discovers multiple functions for a gene with the minimum error on the input data, it includes all of these functions as alternative functions with equal probability. Consequently, the function returns a \texttt{ProbabilisticBooleanNetwork} structure. If you would like to obtain a \texttt{BooleanNetwork} object with only one function per gene from a probabilistic network, you can extract such a network by telling the software which of the functions you would like to use. This can be done by specifying the indices of the functions to extract: <<>>= net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4) functionIndices <- c(1,2,3,2) #select function index for each regulatory component dontCareDefaults <- lapply(seq_along(net$interactions), function(idx) rep(F, sum(net$interactions[[idx]][[functionIndices[idx]]]$func == -1))) #determine number of don't care values for each selected function and set them to 0 names(dontCareDefaults) <- net$genes singleNet <- chooseNetwork(net, functionIndices, dontCareValues = dontCareDefaults) @ In case of don't care values in reconstructed functions, it is possible to set them to 0 or 1 per default. The result is a Boolean network that is created by extracting the first function of gene Fkh2, the second function of genes Swi5 and Clb1, and the third function of gene Sic1 from the above probabilistic network: <<>>= singleNet @ \begin{sloppypar} \texttt{BoolNet} also supports the generation of artificial time series from existing networks: The \texttt{generateTimeSeries()} function generates a set of time series from a network using random start states and optionally adds Gaussian noise. \end{sloppypar} <<echo=FALSE,results=hide>>= set.seed(3176) @ <<>>= series <- generateTimeSeries(cellcycle, numSeries=100, numMeasurements=10, noiseLevel=0.1) @ generates a list of 100 time series by calculating 10 consecutive transitions from 100 randomly chosen network states in the mammalian cell cycle network. The series are subject to Gaussian noise with a standard deviation of 0.1, such that the result is a list of real-valued matrices. We can now binarize these simulated measurements and try to reconstruct the original network: <<>>= binSeries <- binarizeTimeSeries(series, method="kmeans") net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit") net @ Obviously, the number of generated time series is still to small to reconstruct the network unambiguously. However, the result comes close to the original network. We see that the functions of the network are not fully specified: At some positions, there are asterisks (\texttt{*}) denoting a \emph{don't care} value. This means that functions with a 0 and a 1 at this position match the time series equally well. That is, a partially defined function with $m$ asterisks corresponds to $2^m$ fully defined Boolean functions. It is also possible to generate these fully defined functions instead of the partially defined function by setting the parameter \texttt{returnPBN} to true (which was the behaviour prior to \texttt{BoolNet} version 2.0). For many \emph{don't care} values, this may consume a high amount of memory and computation time. \texttt{generateTimeSeries()} can also generate time series with artificial knock-outs and overexpressions: <<echo=FALSE,results=hide>>= set.seed(4463) @ <<>>= series <- generateTimeSeries(cellcycle, numSeries=10, numMeasurements=10, perturbations=1, noiseLevel=0.1) @ specifies that each generated time series is generated from a network where one randomly selected gene is artificially knocked down (constantly 0) or overexpressed (constantly 1). These perturbations are returned in an additional element \texttt{perturbations}. \begin{samepage} <<<>>= series$perturbations @ \end{samepage} Here, each column corresponds to the perturbations applied in one series. A value of 1 denotes an overexpression, a value of 0 denotes a knock-out, and an N/A value means that no perturbation was applied to this gene. The \texttt{reconstructNetwork()} function also supports the reconstruction from such perturbation experiments if it is known which genes were perturbed. First, we store the series and the perturbation matrix in separate variables and binarize the data as before: <<>>= perturbations <- series$perturbations series$perturbations <- NULL binSeries <- binarizeTimeSeries(series, method="kmeans") @ Now, we can reconstruct the network by specifying the \texttt{perturbations} parameter: <<>>= net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", perturbations=perturbations) net @ As we generated only 10 series in this case, the reconstructed network is much more incomplete than in the previous reconstruction. In biological settings, perturbation experiments are probably one of the most frequent ways of exploring the behaviour of a regulatory network, as it is much easier to obtain various different responses by applying perturbations than by just measuring the wild type behaviour. \subsection{Creating random networks} To study structural properties of Boolean networks and to determine the specific properties of biological networks in comparison to arbitrary networks, it is often desirable to generate artificial networks. \texttt{BoolNet} comprises a facility for the generation of random $N$-$K$ networks \cite{kauffman69, kauffman93}. In the standard $N$-$K$ networks, $N$ is the total number of genes, and $K$ is the number of input genes for each gene transition function. Such a network can be generated using <<>>= net <- generateRandomNKNetwork(n=10, k=3) @ This creates a network with 10 genes, each of which has a transition function that depends on 3 genes and whose output is generated uniformly at random. Similarly, one can also specify different numbers of input genes for each gene: <<>>= net <- generateRandomNKNetwork(n=10, k=c(1,2,3,1,3,2,3,2,1,1)) @ \texttt{BoolNet} does not only support this standard case, but allows for different methods of choosing the numbers of input genes (parameter \texttt{topology}), the input genes themselves (parameter \texttt{linkage}), and the transition functions (parameter \texttt{functionGeneration}). In the following, some examples are presented. The command <<>>= net <- generateRandomNKNetwork(n=20, k=20, topology="scale_free") @ determines the numbers of input genes by drawing values from the scale-free Zeta distribution \cite{aldana03}. According to this distribution, most transition functions will have a small number of input genes, but a few transition functions may depend on a high number of genes. The shape of the Zeta distribution can be customized using an additional parameter \texttt{gamma}, which potentially increases the number of input genes when chosen small and vice versa. <<>>= net <- generateRandomNKNetwork(n=10, k=3, linkage="lattice") @ creates a network in which the transition functions of the genes depend on a choice of genes with adjacent indices \cite{aldana03_2}. This leads to networks with highly interdependent genes. It is also possible to influence the truth tables of the functions in several ways. The parameter \texttt{zeroBias} changes the ratio of 1 and 0 returned by the functions: <<>>= net <- generateRandomNKNetwork(n=10, k=3, functionGeneration="biased", zeroBias=0.75) @ generates a network in which the outcome of a transition function is 0 for around 75\% of the inputs. A more intricate way of influencing the function generation is the specification of generation functions. Generation functions explicitly generate functions according to a specific function class. \emph{Canalyzing functions} are assumed to occur frequently in biological systems~\cite{kauffman04}. A canalyzing function has the property that one input can determine the output value on its own, i.e. if this input is either active or inactive, the output of the function is always the same. \emph{Nested canalyzing functions} are a recursive definition of canalyzing functions, where the part of the function that does not depend on the canalyzing input is a canalyzing function for another input. Such functions can be generated using the built-in generation functions \texttt{generateCanalyzing()} and \texttt{generateNestedCanalyzing()}: <<>>= net1 <- generateRandomNKNetwork(n=10, k=3, functionGeneration=generateCanalyzing, zeroBias=0.75) net2 <- generateRandomNKNetwork(n=10, k=3, functionGeneration=generateNestedCanalyzing, zeroBias=0.75) @ It is also possible to define own generation functions: A generation function receives a vector \texttt{input} of input gene indices as a parameter and returns a truth table result column with \verb+2^length(input)+ values representing the function. If no explicit generation scheme is known for the function class of interest, validation functions can be used instead of generation functions. Validation functions verify whether randomly generated functions belong to a specific function class and reject invalid functions. Naturally, this is much less efficient than generating appropriate functions directly. An example is the generation of monotone functions, which are also thought to be biologically plausible. These function account for the assumption that a transcription factor usually either activates or inhibits a specific target gene, but does not change the type of regulation depending on other factors~\cite{maucher11}. We can specify a simple validation function that checks whether a Boolean function is monotone: \begin{samepage} <<>>= isMonotone <- function(input, func) { for (i in seq_len(ncol(input))) # check each input gene { groupResults <- split(func, input[,i]) if (any(groupResults[[1]] < groupResults[[2]]) && any(groupResults[[1]] > groupResults[[2]])) # the function is not monotone return(FALSE) } return(TRUE) } @ \end{samepage} \begin{sloppypar} Here, \texttt{input} is a matrix containing the input part of the transition table, and \texttt{func} is the output of the Boolean function. In a monotone function, the values of the target may only change in one direction when switching one input. Hence, a function for which switching the value of an input gene sometimes switches the target from active to inactive, but also sometimes switches it from inactive to active is not monotone. This is validated by comparing the two groups of transition table entries for which the current input is active and inactive respectively. If a validation function is supplied to \texttt{generateRandomNKNetwork()}, the generator generates Boolean functions until either the validation function returns \texttt{TRUE} or the maximum number of iterations (specified by the parameter \texttt{failureIterations}) is reached, in which case it fails. \end{sloppypar} <<>>= net <- generateRandomNKNetwork(n=10, k=3, validationFunction="isMonotone", failureIterations=1000) @ creates a network with 10 genes in which all functions have 3 inputs, of which at least one is canalyzing. By default, \texttt{generateRandomNKNetwork()} creates functions that cannot be simplified, i.e. that do not contain any genes that are irrelevant for the outcome of the function. If desired, this behaviour can be changed by setting \texttt{noIrrelevantGenes} to \texttt{FALSE}. The presented parameters can be combined, and there are further options and parameters, so that a broad variety of networks with different structural properties can be generated. For a full reference of the possible parameters, please refer to the manual. \subsection{Knock-out and overexpression of genes} \texttt{BoolNet} allows for temporarily knocking out and overexpressing genes in a network without touching the transition functions. This means that genes can be set to a fixed value, and in any calculation on the network, this fixed value is taken instead of the value of the corresponding transition function. Knocked-out and overexpressed genes speed up the analysis of the network, as they can be ignored in many calculations. For example, to knock out CycD in the mammalian cell cycle network, we call <<>>= data(cellcycle) knockedOut <- fixGenes(cellcycle, "CycD", 0) @ or alternatively use the gene index <<>>= knockedOut <- fixGenes(cellcycle, 1, 0) @ This sets the gene constantly to 0. To over-express the gene (i.e. to fix it to 1), the corresponding call is <<>>= overExpressed <- fixGenes(cellcycle, "CycD", 1) @ The command <<>>= originalNet <- fixGenes(knockedOut, "CycD", -1) @ reactivates the gene (for both knock and overexpression) and resets the network to its original state. The function also accepts multiple genes in a single call, such as <<>>= newNet <- fixGenes(cellcycle, c("CycD","CycE"), c(0,1)) @ which knocks out CycD and overexpresses CycE. \section{Network analysis}\label{sec:networkanalysis} \subsection{Simulation of state transitions} To simulate a state transition and identify successor states of a given state, \texttt{BoolNet} includes the function \texttt{stateTransition()}. The function supports transitions for all four types of networks. The following code performs a synchronous state transition for the state in which all genes are set to 1 on the mammalian cell cycle network: <<>>= data(cellcycle) stateTransition(cellcycle, rep(1,10)) @ To calculate all state transitions in a synchronous network until an attractor is reached, you can call <<>>= path <- getPathToAttractor(cellcycle, rep(0,10)) path @ The returned matrix consists of the subsequent states until an attractor is reached. Depending on the optional parameter \texttt{includeAttractorStates}, the sequence comprises all attractor states, only the first attractor state or none of the attractor states. A sequence can be visualized by plotting a table of state changes: <<eval=FALSE>>= plotSequence(sequence=path) @ \begin{figure}[t] \centering \includegraphics[width=0.6\linewidth]{sequence} \caption{Visualization of a sequence of states in the mammalian cell cycle network. The columns of the table represent consecutive states of the time series. The last state is the steady-state attractor of the network.} \label{fig:sequence} \end{figure} The result is depicted in Figure~\ref{fig:sequence}. \texttt{plotSequence()} also includes a shortcut that calculates the sequence directly if a network and a start state are supplied. It also provides an alternative way of visualizing the sequence as a state transition by setting \texttt{mode="graph"}. The function <<eval=FALSE>>= sequenceToLaTeX(sequence=path, file="sequence.tex") @ creates a \LaTeX\ table similar to \texttt{plotSequence()} function document. In many cases, start states are defined by a set of active genes. Instead of supplying a full state vector, one can also supply only these active genes using the \texttt{generateState()} function. <<>>= startState <- generateState(cellcycle, specs=c("CycD"=1,"CycA"=1)) stateTransition(cellcycle,startState) @ \begin{sloppypar} calculates a state transition starting from a state where only the genes \emph{CycD} and \emph{CycA} are active, while all other genes are inactive (which is controlled by the \texttt{default} parameter of \texttt{generateState()}). \end{sloppypar} For temporal Boolean networks (objects of class \emph{SymbolicBooleanNetworks}), the above functions can be utilized mostly in the same way. We demonstrate this using a small temporal network example of the IGF (Insulin-like growth receptor) pathway that is included in the package and can be loaded via <<>>= data(igf) @ The model illustrates the activation and feedback inhibition of the PI3K-Akt-mTOR signalling cascade through IGF and IRS. A state transition from the initial state in which the trigger of the pathway -- IGF -- is active, can be performed using <<>>= startState <- generateState(igf, specs=c("IGF"=1)) stateTransition(igf, startState) @ The IGF network incorporates time delays of up to 3. Therefore, the last three states have to be known to calculate a successor state. If only a single state is supplied -- as above -- the function assumes that the state was the same before. This can be seen when calculating the sequence to the attractor using <<>>= getPathToAttractor(network=igf,state=startState) @ Here, the states at $t=-2, \ldots 0$ are the same as the generated start state. If it is required to specify multiple predecessor states here, a matrix of states can be supplied instead of a vector. E.g., <<>>= startState <- generateState(igf, specs=list("IGF"=c(0,0,1))) startState @ specifies that the first two states ($t=-2, t=-1$) should have all genes inactive, while IGF is activated only at $t=0$. This time, we plot the sequence instead of printing it: \begin{figure}[bt] \centering \includegraphics[width=0.6\linewidth]{sequence_igf} \caption{Visualization of a sequence of states in the IGF network. The columns of the table represent consecutive states of the time series. After activation of IGF, the attractor consisting of 14 states is entered immediately. This attractor represents the activation and inactivation of the PI3K-Akt-mTOR signalling cascade through IGF and IRS.} \label{fig:sequence_igf} \end{figure} <<eval=FALSE>>= plotSequence(network=igf, startState=startState) @ The result is depicted in Figure~\ref{fig:sequence_igf}. \texttt{stateTransition()} can also perform asynchronous updates. A random asynchronous transition is performed using <<echo=FALSE>>= set.seed(54321) @ <<>>= stateTransition(cellcycle, rep(1,10), type="asynchronous") @ In this case, the fifth gene, CycA, was chosen at uniformly at random and updated. \begin{samepage} We can also specify non-uniform probabilities for the genes, for example <<echo=FALSE>>= set.seed(4321) @ <<>>= stateTransition(cellcycle, rep(1,10), type="asynchronous", geneProbabilities=c(0.05,0.05,0.2,0.3,0.05,0.05,0.05,0.05,0.1,0.1)) @ This obviously increases probabilities for the genes 3 and 4 (E2F and CycE) to be chosen. In this case, CycE was chosen for the update. \end{samepage} \enlargethispage{0.5cm} Sometimes you do not want a random update at all, but would like to specify which gene should be chosen for the update. This is possible via <<>>= stateTransition(cellcycle, rep(1,10), type="asynchronous", chosenGene="CycE") @ In probabilistic Boolean networks, a state transition is performed by choosing one of the alternative functions for each gene and applying this set of functions to the current state. The following performs a state transition with a randomly chosen set of functions on the artificial probabilistic Boolean network taken from \cite{shmulevich02} with 3 genes, starting from state (0,1,1): <<echo=FALSE>>= set.seed(432) @ <<>>= data(examplePBN) stateTransition(examplePBN, c(0,1,1), type="probabilistic") @ You may get a different result, as the functions are chosen randomly according to the probabilities stored in the network. If you would like to execute a specific set of transition functions, you can supply this in an additional parameter: <<>>= stateTransition(examplePBN, c(0,1,1), type="probabilistic", chosenFunctions=c(2,1,2)) @ This call uses the second function for gene x1 and x3 and the first function for gene x2. \subsection{Identification of attractors} Attractors are stable cycles of states in a Boolean network. As they comprise the states in which the network resides most of the time, attractors in models of gene-regulatory networks are expected to be linked to phenotypes \cite{kauffman93,li04}. Transitions from all states in a Boolean network eventually lead to an attractor, as the number of states in a network is finite. All states that lead to a certain attractor form its {\em basin of attraction}. \texttt{BoolNet} is able to identify attractors in synchronous and asynchronous Boolean networks. There are three types of attractors in these networks: \begin{description} \item[Simple attractors]{occur in synchronous and temporal Boolean networks and consist of a set of states whose synchronous transitions form a cycle.} \item[Complex or loose attractors]{are the counterpart of simple attractors in asynchronous networks. As there is usually more than one possible transition for each state in an asynchronous network, a complex attractor is formed by two or more overlapping loops. Precisely, a complex attractor is a set of states in which all asynchronous state transitions lead to another state in the set, and a state in the set can be reached from all other states in the set.} \item[Steady-state attractors]{are attractors that consist of only one state. All transitions from this state result in the state itself. These attractors are the same both for synchronous and asynchronous update of a network. Steady states are a special case of both simple attractors and complex attractors.} \end{description} The \texttt{getAttractors()} function incorporates several methods for the identification of attractors in synchronous and asynchronous networks. We present these methods using the included mammalian cell cycle network as an example. This network has one steady-state attractor, one simple synchronous attractor consisting of 7 states, and one complex asynchronous attractor with 112 states (see \cite{faure06}). We first demonstrate the use of exhaustive synchronous search. This means that the software starts from all possible states of the network and performs synchronous state transitions until a simple or steady-state attractor is reached. \pagebreak[4] <<eval=FALSE>>= data(cellcycle) attr <- getAttractors(cellcycle) attr @ \begin{lstlisting}[linewidth=.9\linewidth] <<echo=FALSE,results=tex>>= attr <- getAttractors(cellcycle) attr @ \end{lstlisting} Typing \texttt{attr} calls a special print method that presents the attractor in a human-readable way. Here, a state in an attractor is represented by a binary vector, where each entry of the vector codes for one gene. An alternative is to print only the names of the active genes (i.e., the genes that are set to 1) instead of the full vector by calling the \texttt{print()} method explicitly with a changed parameter: <<eval=FALSE>>= print(attr, activeOnly=TRUE) @ \begin{lstlisting}[linewidth=.9\linewidth] <<echo=FALSE,results=tex>>= print(attr, activeOnly=TRUE) @ \end{lstlisting} We can see that the search identified both synchronous attractors. \begin{sloppypar} The \texttt{AttractorInfo} structure stores the attractors in an encoded form. The function \texttt{getAttractorSequence()} can be used to obtain the sequence of states that constitute a specific synchronous attractor as a table: \end{sloppypar} <<>>= getAttractorSequence(attr, 2) @ retrieves the states that make up the second (i.e., the 7-state attractor) as a data frame with the genes in the columns and the successive states in the rows. The advantage of the exhaustive search method is that the complete transition table is calculated and stored in the return value. This table stores information that is used by a number of analysis methods described below. You can extract the transition table in a data frame and print it out using <<eval=FALSE>>= tt <- getTransitionTable(attr) tt @ \begin{verbatim} State Next state Attr. basin # trans. to attr. 0000000000 => 0110010111 1 4 [...] 1111111111 => 1000001110 2 1 Genes are encoded in the following order: CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB \end{verbatim} In the printed table, the first column denotes the initial state, the second column contains the state after the transition, the first column contains the number of the attractor that is finally reached from this state, and the fourth column lists the number of state transitions required to attain this attractor. A table of the same structure is returned by <<eval=FALSE>>= getBasinOfAttraction(attr, 1) @ which extracts all states from the transition table that belong to the basin of attraction of attractor one (i.e., whose attractor number in column 3 is 1). If you are interested in information on a single state (here: the state with all genes set to 1), you can type <<eval=FALSE>>= getStateSummary(attr, c(1,1,1,1,1,1,1,1,1,1)) @ \begin{verbatim} State Next state Attr. basin # trans. to attr. 1111111111 => 1000001110 2 1 Genes are encoded in the following order: CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB \end{verbatim} The visualization function \texttt{getStateGraph()} makes use of the transition table as well: It plots a transition graph in which the basins of attraction are drawn in different colors, and the attractors are highlighted. The result of <<eval=FALSE>>= plotStateGraph(attr) @ is depicted at the top of Figure~\ref{fig:stategraph}. The blue basin belongs to attractor 1, and the green basin belongs to attractor 2. The above call does not ensure that the basins of attraction are clearly separated in the plot. If this is desired, one can choose to use a piecewise layout, which means that the layouting function is applied separately to each basin of attraction, and the basins are drawn side by side. The result of <<eval=FALSE>>= plotStateGraph(attr, piecewise=TRUE) @ is depicted at the bottom of Figure~\ref{fig:stategraph}. \begin{figure}[p] \centering \includegraphics[width=0.7\linewidth]{stategraph1} \includegraphics[width=0.7\linewidth]{piecewisestategraph} \caption{The state graph of the mammalian cell cycle network using the regular layout (top) and using a piecewise layout (bottom). Each node represents a state of the network, and each arrow is a state transition. The colors mark different basins of attraction. Attractors are highlighted using bold lines.} \label{fig:stategraph} \end{figure} Exhaustive search consumes a high amount of time and memory with increasing size of the network, which makes it intractable for large networks (\texttt{BoolNet} currently supports networks with up to 29 genes for exhaustive search due to memory restrictions in {\em R}). Therefore, \texttt{BoolNet} also allows for heuristic search of attractors, which works for larger networks as well. Heuristic synchronous search starts from a predefined small set of states and identifies the attractors to which state transitions from these states lead. The start states can either be supplied, or they can be calculated randomly. <<eval=FALSE>>= attr <- getAttractors(cellcycle, method="random", startStates=100) @ chooses 100 random start states for the heuristic search and usually identifies both attractors. <<eval=FALSE>>= attr <- getAttractors(cellcycle, method="chosen", startStates=list(rep(0,10),rep(1,10))) @ starts from the states \texttt{(0,0,0,0,0,0,0,0,0,0)} and \texttt{(1,1,1,1,1,1,1,1,1,1)} and again identifies both synchronous attractors. \begin{sloppypar} For the previous calls, only the subset of the transition table traversed by the heuristic is returned. This means that there is no guarantee that, e.g. \texttt{getBasinOfAttraction()} returns the complete basin of attraction of an attractor in heuristic mode. \end{sloppypar} Synchronous attractors can be visualized by plotting a table of changes of gene values in the states of the attractor: <<eval=FALSE>>= plotAttractors(attr, subset=2) @ plots the state changes of the simple attractor with 7 states, as depicted in Figure~\ref{fig:attractor1}. Similarly, <<eval=FALSE>>= attractorsToLaTeX(attr, subset=2, file="attractors.tex") @ exports the same state table to a \LaTeX\ document. \begin{figure}[t] \centering \includegraphics[width=0.65\linewidth]{attractor1} \caption{Visualization of the state changes in an attractor. The columns of the table represent consecutive states of the attractor.} \label{fig:attractor1} \end{figure} To identify asynchronous attractors, another special heuristic algorithm is included. This algorithm again starts from a small subset of states and makes a number of random transitions to reach an attractor with a high probability. After that, a validation step is performed to analyze whether a complex attractor has been identified. The command <<results=hide>>= attr <- getAttractors(cellcycle, type="asynchronous", method="random", startStates=500) @ conducts an asynchronous search with 500 random start states on the mammalian cell cycle network. In this case, the algorithm has identified both the steady-state attractor and the complex attractor: \enlargethispage{0.5cm} <<eval=FALSE>>= attr @ \begin{verbatim} Attractor 1 is a simple attractor consisting of 1 state(s): |--<---------| V | 0100010100 | V | |-->---------| Genes are encoded in the following order: CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB Attractor 2 is a complex/loose attractor consisting of 112 state(s) and 338 transition(s): 1011101111 => 1011101110 [...] 1000000000 => 1010000000 Genes are encoded in the following order: CycD Rb E2F CycE CycA p27 Cdc20 Cdh1 UbcH10 CycB \end{verbatim} For the complex attractor, the involved transitions are printed out. By default, the algorithm tries to avoid self-loops, i.e. transitions that lead to the same state again. This means that self-loop transitions are only allowed if there is no other transition that leads to a different state. If you would like to allow the algorithm to enter self-loops even if transitions to different states are possible, you can call <<eval=FALSE>>= attr <- getAttractors(cellcycle, type="asynchronous", method="random", startStates=500, avoidSelfLoops=FALSE) @ In the resulting complex attractor with 112 states, there are 450 transitions instead of 338 transitions, which is due to the additional self-loops. The asynchronous heuristic search does not return a transition table, such that the above analysis methods cannot be applied here. \begin{figure}[tb] \centering \includegraphics[width=0.55\linewidth]{attractor2} \caption{Graph representation of the complex attractor in the mammalian cell cycle network. Each node represents a state of the complex attractor, and each arrow represents a state transition.} \label{fig:attractor2} \end{figure} As there are multiple possible transitions for each state, complex attractors cannot be visualized as in Figure~\ref{fig:attractor1}. For this reason, \texttt{plotAttractors()} supports a graph mode that visualizes the transitions among the states in the attractor: <<eval=FALSE>>= plotAttractors(attr, subset=2, mode="graph", drawLabels=FALSE) @ plots the 112-state attractor as depicted in Figure~\ref{fig:attractor2}. We omit the state labels (i.e. the gene values) due to the high number of states. This plot again requires the \texttt{igraph} package. \begin{sloppypar} Although \texttt{getAttractors()} can also be applied to temporal networks and other networks that are in a symbolic representation (i.e. \emph{SymbolicBooleanNetwork} objects), this function is only a shortcut to the simulation function \texttt{simulateSymbolicModel()} in this case. It is advised to use \texttt{simulateSymbolicModel()} directly , as it provides more options. For the temporal model of the IGF pathway included in \texttt{BoolNet}, an exhaustive simulation can be performed as follows: \end{sloppypar} <<eval=FALSE>>= sim <- simulateSymbolicModel(igf) sim @ \begin{lstlisting}[linewidth=.9\linewidth] <<echo=FALSE,results=tex>>= sim <- simulateSymbolicModel(igf) sim @ \end{lstlisting} By default, the result object of class \emph{SymbolicSimulation} comprises several components: \begin{itemize} \item A list of sequences \texttt{sequences} from each start state to the corresponding attractor. If this component is not desired, the parameter \texttt{returnSequences} can be set to false. \item A graph structure \texttt{graph} that comprises all traversed state transitions. If this component is not desired, the parameter \texttt{returnGraph} can be set to false. \item The identified attractors \texttt{attractors}. If this component is not desired, the parameter \texttt{returnAttractors} can be set to false. \end{itemize} In this case, the network has two attractors: A steady state describes the inactive state of the pathway. The circular attractor describes the activation and inactivation of the PI3K-Akt-mTOR signalling cascade initiated by IGF. All visualization and analysis function described above can also be applied to the simulation results obtained by \texttt{simulateSymbolicModel}. For example, the cascade attractor can be visualized via <<eval=FALSE>>= plotAttractors(sim, subset=2) @ Similarly, <<eval=FALSE>>= plotStateGraph(sim) @ plots the state transition graph of the network. Unlike in classical synchronous networks, a state can have multiple successor states (outgoing edges) in temporal networks, as a state transition may also depend on the history of states before the current state. The two plots are shown in Figure~\ref{fig:temporal_plots}. \begin{figure}[p] \centering \includegraphics[width=0.6\linewidth]{attractor3} \includegraphics[width=0.6\linewidth]{stategraph2} \caption{Top: Visualization of an attractor that describes the activation and inactivation of the PI3K-Akt-mTOR signalling cascade through IGF and IRS. The columns of the table represent consecutive states of the attractor. On top, the percentage of states leading to the attractor is supplied.\newline Bottom: The state transition graph of the IGF pathway network. Each node represents a state of the network, and each arrow is a state transition. The colors mark different basins of attraction. } \label{fig:temporal_plots} \end{figure} For temporal networks, it is often infeasible to perform an exhaustive search, as the search space is not only exponential in the number of genes, but also in the time delays. Hence, the search can also be restricted to randomly generated or prespecified start states similarly to \texttt{getAttractors()}. If time delays of more than 1 are included in the network, not only single start states are generated, but the required history of states is generated as well. For example, <<echo=FALSE>>= set.seed(43851) @ <<>>= sim <- simulateSymbolicModel(igf, method="random", startStates=2) @ generates two start state matrices, each comprising 3 states (the maximum delay of the IGF network), and uses them as the basis for a simulation. This can be seen when examining the sequences to the attractors: <<>>= sim$sequences @ Both sequences comprise start states $t=-2$, $t=-1$ and $t=0$. \begin{sloppypar} Classical synchronous Boolean networks can also be simulated using the symbolic simulator \texttt{simulateSymbolicModel()} if they are in a symbolic form. However, in most cases, \texttt{getAttractors()} will be faster and will consume less memory for synchronous networks without temporal elements. Only if the number of inputs to genes is very high and exhaustive simulation is not required, it may be advisable to use the symbolic simulator. \end{sloppypar} \subsection{Markov chain simulations} Another way of identifying relevant states in Boolean networks are Markov chain simulations. Instead of identifying cycles explicitly, these simulations calculate the probability that a certain state is reached after a predefined number of iterations. Of course, states in an attractor have a high probability of being reached if the number of iterations is chosen large enough. Markov chain simulations for probabilistic Boolean networks were introduced by Shmulevich et al. \cite{shmulevich02}. As a special case of probabilistic Boolean networks, these simulations are also suited for synchronous Boolean networks. The following performs a Markov experiment with the predefined number of 1000 iterations on the example PBN described in \cite{shmulevich02}: \enlargethispage{-0.5cm} <<>>= data(examplePBN) sim <- markovSimulation(examplePBN) sim @ Only states with a non-zero probability are listed in the two tables. The first table shows the states that are reached after 1000 iterations. The second table is a transition table annotated with transition probabilities. This table can be suppressed by the parameter \texttt{returnTable=FALSE}. The results correspond exactly to those in \cite{shmulevich02}. If the transition table is included in the simulation results, we can plot a graph of the network: <<eval=FALSE>>= plotPBNTransitions(sim) @ This graph is displayed in Figure~\ref{fig:pbntransitions}. The vertices are the states of the graph. The edges represent transitions and are annotated with the corresponding transition probabilities. For this plot, the \texttt{igraph} package must be installed. \begin{figure}[h] \centering \includegraphics[width=0.65\linewidth]{pbntransitions} \caption{State transition graph of the example probabilistic Boolean network included in \texttt{BoolNet}. Each node represents a state of the network, and each arrow is a possible state transition, annotated by the transition probability.} \label{fig:pbntransitions} \end{figure} We can also use Markov chain simulations to identify the attractor states in the mammalian cell cycle network: \begin{samepage} <<>>= data(cellcycle) sim <- markovSimulation(cellcycle, numIterations=1024, returnTable=FALSE) sim @ \end{samepage} We set the maximum number of iterations to 1024, which is the number of states in the network. In a deterministic network, this guarantees that all states are found. The fourth state in the returned table is the steady-state attractor identified previously. It has a probability of 0.5, as the basin of attraction is exactly half of the states. The other 7 states belong to the simple synchronous attractor. It is also possible to restrict the simulation to a certain set of input states instead of using all possible input states. In the following example, we only consider the state with all genes set to 1, and identify the state belonging to the steady-state attractor again: \begin{samepage} <<>>= sim <- markovSimulation(cellcycle, numIterations=1024, returnTable=FALSE, startStates=list(rep(1,10))) sim @ \end{samepage} \subsection{Robustness assessment} A biological network is assumed to be robust to small amounts of noise. The plausibility of network models is therefore often assessed by testing its robustness to noise and mismeasurements. Typically, artificial noise is applied, and its influence on the behaviour of a network is measured. There are two major ways of applying random noise: Either the current state of a network in a simulation can be perturbed, or the network structure itself can be perturbed. \texttt{BoolNet} includes functions for both types of robustness assessment. The function \texttt{perturbTrajectories} measures the influence of noise that is applied to the current network state. It generates a set of initial states and creates perturbed copies of these states by randomly flipping bits. It then measures the influence of the flips on the further dynamic behaviour of the network. For example <<echo=FALSE>>= set.seed(3361) @ <<>>= data(cellcycle) r <- perturbTrajectories(cellcycle, measure="hamming", numSamples=100, flipBits=1) @ randomly generates 100 states and 100 copies with one bitflip and performs a single state transition for each state. It then measures the normalized Hamming distance (the fraction of different bits) between each state and the corresponding perturbed copy. A robust network is assumed to yield a low Hamming distance. The average distance can be viewed by typing <<>>= r$value @ A related measure is the average sensitivity. This measure assesses only a single transition function and counts the number of successor states that differ between the original states and the perturbed copies for the corresponding gene. E.g., <<>>= r <- perturbTrajectories(cellcycle, measure="sensitivity", numSamples=100, flipBits=1, gene="CycE") r$value @ measures the average sensitivity of the transition function for gene CycE. The long-term behaviour can be evaluated by comparing the attractors that are reached from the initial states and their perturbed copies. <<>>= r <- perturbTrajectories(cellcycle, measure="attractor", numSamples=100, flipBits=1) r$value @ measures the fraction of pairs of states and perturbed copies that yield the same attractors. It can be assumed that small changes in the state should not influence the long-term behaviour of the network, and hence the attractors should mostly be the same. The second class of perturbations adds random noise to the network itself. This is implemented in the \texttt{perturbNetwork()} function. Unlike \texttt{perturbTrajectories()}, this function does not perform any simulations, but returns a perturbed copy of the network that can be analyzed further. \texttt{BoolNet} includes a set of different perturbation options that can be combined. For example, <<>>= perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="bitflip") @ chooses a function of the network at random and flips a single bit in this function. By setting the parameter \texttt{maxNumBits}, you can also flip more than one bit at a time. Instead of flipping bits, <<>>= perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="shuffle") @ randomly permutes the output values of the chosen transition functions. This preserves the numbers of 0s and 1s, but may change the Boolean function completely. These kinds of perturbations are supported for synchronous and asynchronous networks as well as for probabilistic networks. For synchronous networks, a further perturbation mode is available: <<>>= perturbedNet <- perturbNetwork(cellcycle, perturb="transitions", method="bitflip", numStates=10) @ Here, \texttt{BoolNet} calculates the complete transition table of the network and then flips a single bit in 10 states of the transition table. From this modified table, a network is reconstructed. Changes of this type only affect a few states (which might not be the case when perturbing the functions directly as above), but possibly several of the transition functions. As in the previous examples, it is also possible to modify the number of bits to be flipped or to choose \texttt{method="shuffle"}. \begin{samepage} A detailed listing of a perturbation experiment is shown below. In this experiment, 1000 perturbed copies of the cell cycle network are created, and the occurrences of the original synchronous attractors are counted in the perturbed copies. This is similar to the simulation in \texttt{perturbTrajectories()} with \texttt{measure="attractor"}. However, instead of comparing the outcomes of different initial states in the same network, it compares all attractors of different perturbed networks to all attractors of the original network by exhaustive search. \begin{footnotesize}\label{alg:perturbation} <<eval=FALSE>>= # Perform a robustness test on a network # by counting the numbers of perturbed networks # containing the attractors of the original net library(BoolNet) # load mammalian cell cycle network data(cellcycle) # get attractors in original network attrs <- getAttractors(cellcycle, canonical=TRUE) # create 1000 perturbed copies of the network and search for attractors perturbationResults <- sapply(1:1000, function(i) { # perturb network and identify attractors perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="bitflip") perturbedAttrs <- getAttractors(perturbedNet, canonical=TRUE) # check whether the attractors in the original network exist in the perturbed network attractorIndices <- sapply(attrs$attractors,function(attractor1) { index <- which(sapply(perturbedAttrs$attractors, function(attractor2) { identical(attractor1, attractor2) })) if (length(index) == 0) NA else index }) return(attractorIndices) }) # perturbationResults now contains a matrix # with the first 2 columns specifying the indices or the # original attractors in the perturbed network # (or NA if the attractor was not found) and the next 2 # columns counting the numbers of states # in the basin of attraction (or NA if the attractor was not found) # measure the total numbers of occurrences of the original attractors in the perturbed copies numOccurrences <- apply(perturbationResults[seq_along(attrs$attractors),,drop=FALSE], 1, function(row)sum(!is.na(row))) # print original attractors cat("Attractors in original network:\n") print(attrs) # print information cat("Number of occurrences of the original attractors", "in 1000 perturbed copies of the network:\n") for (i in 1:length(attrs$attractors)) { cat("Attractor ",i,": ",numOccurrences[i],"\n",sep="") } @ \end{footnotesize} \end{samepage} \pagebreak[4] \begin{samepage} The results of such an experiment could look like this: \begin{verbatim} Attractors in original network: Attractor 1 is a simple attractor consisting of 1 state(s) and has a basin of 512 state(s): [...] Attractor 2 is a simple attractor consisting of 7 state(s) and has a basin of 512 state(s): [...] Number of occurrences of the original attractors in 1000 perturbed copies of the network: Attractor 1: 622 Attractor 2: 589 \end{verbatim} \end{samepage} We see that the steady-state attractor is slightly more robust to perturbations than the simple attractor with 7 states, as it can be identified in a higher number of perturbed copies. \subsection{Identifying specific properties of biological networks} The described robustness measures could also be used to identify specific properties of real-world networks in comparison to arbitrary (random) networks. For example, one could assume that attractors in biological networks are more robust to perturbations than attractors in random networks with a similar structure, as they should be capable of compensating for small dysfunctions of their components. Similarly to the above code, one could execute a number of random perturbations on the biological network and measure the percentage of original attractors found in the perturbed copies. Afterwards, one could repeat this process on a number of randomly generated networks -- i.e., generate perturbed copies from each of the random networks, and measure the percentage of attractors in the copies. If the percentage of the biological network is higher than most of the percentages of the random network, this suggests that the biological network exhibits a higher robustness. This is a kind of computer-intensive test. \texttt{BoolNet} comprises a generic facility for such computer-intensive tests. This facility already includes several tests (mainly for synchronous Boolean networks) and can be extended by custom test functions. The outlined example of attractor robustness is one of the integrated functions: <<eval=FALSE>>= data(cellcycle) res <- testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testAttractorRobustness", testFunctionParams = list(copies=100, perturb="functions")) @ creates a set of 100 random networks (each with the same number of input genes for the functions as the cell cycle network) and creates 100 perturbed copies for each of these networks and for the cell cycle network by applying \texttt{perturbNetwork()} with \texttt{perturb="functions"}. For each network, it then calculates the percentage of attractors that can still be found in the perturbed copies. The function plots a histogram of this robustness measures of the random networks (see Figure~\ref{fig:robustness}, top panel). The corresponding value of the original cell cycle network is plotted as a red line, and the 95\% quantile is plotted as a blue line. \begin{figure}[p] \centering \includegraphics[width=0.6\linewidth]{attractor_robustness} \includegraphics[width=0.6\linewidth]{transition_robustness} \caption{Top: Attractor robustness of randomly generated networks (histogram) in comparison to the mammalian cell cycle network (red line).\newline Bottom: Normalized Hamming distance of randomly generated networks (histogram) in comparison to the mammalian cell cycle network (red line). } \label{fig:robustness} \end{figure} We can see that the average percentage of found attractors is significantly higher in the biological network with a $p$-value of 0.01. \begin{sloppypar} It is also possible to perturb the states instead of the networks themselves by setting \texttt{perturb} to \texttt{"trajectories"}. In this case, the function applies \texttt{perturbTrajectories()} with \texttt{measure="attractor"} to the biological network and the randomly generated networks. It then tests whether the fraction of state pairs that yield the same attractor is higher in the biological network than in the randomly generated networks. The second built-in test function also tests the robustness of the network behaviour by perturbing the network states: \texttt{testTransitionRobustness()} applies \texttt{perturbTrajectories()} with \texttt{measure="hamming"} to each network. It then checks whether random bit flips yield a higher Hamming distance of the successor states in randomly generated networks than in the biological model, i.e. whether noise in the states influences the randomly generated networks stronger than the biological model. In contrast to the previous measures for which a greater value was assumed in the biological model, the Hamming distance is assumed to be smaller. Hence, we must specify the test alternative as \texttt{alternative="less"}. \end{sloppypar} <<eval=FALSE>>= testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testTransitionRobustness", testFunctionParams=list(numSamples=100), alternative="less") @ The results are shown in the bottom panel of Figure~\ref{fig:robustness}. Again, the result is highly significant (indeed, the Hamming distances are \emph{always} lower in the biological network), which means that the biological network is considerably more robust to noise in the states than the randomly generated models. Another network property can also be tested using a built-in function: When looking at the state graph of a biological network (which can be generated using \texttt{plotStateGraph()}), it can often be observed that many state transitions lead to the same successor states, which means that the dynamics of the network quickly concentrate on a few states after a number of state transitions. We call the number of states whose synchronous state transitions lead to a state $s$ the {\em in-degree} of state $s$. We expect the biological network to have a few states with a high in-degree and many states with a low in-degree. A characteristic to summarize the in-degrees is the Gini index, which is a measure of inhomogeneity. If all states have an in-degree of 1, the Gini index is 0; if all state transitions lead to only one state, the Gini index is 1. <<eval=FALSE>>= testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testIndegree") @ plots an histogram of Gini indices in 100 random networks and draws the Gini index of the cell cycle network as a red line, as depicted in the top panel of Figure~\ref{fig:indegree}. \begin{figure}[p] \centering \includegraphics[width=0.6\linewidth]{indegree} \includegraphics[width=0.6\linewidth]{indegree_kl} \caption{Top: Gini indices of state in-degrees of randomly generated networks (histogram) in comparison to the mammalian cell cycle network (red line)\newline Bottom: Kullback-Leibler distances of in-degrees of the mammalian cell cycle network and 100 random networks.} \label{fig:indegree} \end{figure} The histogram shows that the Gini index of the in-degrees is always higher in the biological network. This is probably due to the special structure of functions in biological networks. Instead of accumulating the in-degrees using the Gini index, it is also possible to compare the distributions of the in-degrees across the networks. For this purpose, the Kullback-Leibler distances of the in-degrees of the supplied network and each of the random networks are calculated and plotted in a histogram. The Kullback-Leibler distance (also called relative entropy) is an asymetric measure of similarity of two distributions \cite{cover91}. If the distributions are equal, the Kullback-Leibler distance is 0, otherwise it is greater than 0. <<eval=FALSE>>= testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testIndegree", accumulation="kullback_leibler") @ results in the plot displayed in the bottom panel of Figure~\ref{fig:indegree}. It is possible to switch between the histogram of an accumulated characteristic (e.g. the Gini index) and the histogram of the Kullback-Leibler distances for all tests. \begin{sloppypar} You can also easily implement your own tests. To do this, the only thing you have to do is implement a custom testing function that replaces \texttt{testIndegree()} or \texttt{testAttractorRobustness()}. Testing functions have the following signature: \end{sloppypar} \begin{verbatim} function(network, accumulate=TRUE, params) \end{verbatim} The first parameter is the network that should be tested. The parameter \texttt{accumulate} specifies whether a single characteristic value (e.g., the Gini index of the in-degrees) should be calculated, or whether a distribution of values (e.g., a vector of all in-degrees) should be returned. The third parameter is a list of further arguments needed by your function. If, for example, we would like to compare the sizes of the basins of attractions of synchronous attractors in biological and random networks, we would write a function like this: \begin{samepage} <<>>= testBasinSizes <- function(network, accumulate=TRUE, params) { attr <- getAttractors(network) basinSizes <- sapply(attr$attractors, function(a) { a$basinSize }) if (accumulate) return(mean(basinSizes)) else return(basinSizes) } @ \end{samepage} This function calculates the mean basin size as a characteristic value if accumulation is required, or returns the sizes of all basins of attraction in a vector otherwise. It does not need any further parameters in \texttt{params}. Now, we can start a test using <<eval=FALSE>>= testNetworkProperties(cellcycle, numRandomNets=100, testFunction="testBasinSizes", xlab="Average size of basins of attraction") @ to produce the plot shown in Figure~\ref{fig:basinsize}. Apparently, the average basin sizes do not differ as much as the built-in test characteristics between the random networks and the cell cycle network. \begin{figure}[h] \centering \includegraphics[width=0.6\linewidth]{basinsize} \caption{A custom test statistic measuring the basin sizes on randomly generated networks (histogram) and the mammalian cell cycle network (red line).} \label{fig:basinsize} \end{figure} \begin{sloppypar} By writing custom test functions, you can extend the test facility to perform a wide variety computer-intensive test. Of course, it is also possible to plot the Kullback-Leibler distances with such new methods by using \verb+accumulation="kullback_leibler"+. \texttt{testNetworkProperties()} accepts most of the parameters of \texttt{generateRandomNKNetwork()}. If necessary, you can generate more specialized kinds of random networks which resemble the original network in certain aspects, for example by specifying a generation function or by setting a proportion of 0 and 1 in the function outputs similar to the original network using \verb+functionGeneration="biased"+. \end{sloppypar} \clearpage \section{Import and export}\label{sec:importexport} \subsection{Saving networks in the \texttt{BoolNet} file format} Corresponding to the \texttt{loadNetwork()} command, a network can be saved using \texttt{saveNetwork()}. This stores the network in the network file format described in Section~\ref{sec:appendix} and can be applied to all types of networks supported by \texttt{BoolNet}. For example, the cell cycle network can be saved using <<eval=FALSE>>= saveNetwork(cellcycle, file="cellcycle.txt") @ \begin{sloppypar} The function stores the expressions that describe the transition functions. In some cases, there may not always be a valid symbolic description of the networks (e.g. for networks returned by \texttt{generateRandomNKNetwork()} when the \texttt{readableFunctions} parameter was not set). In this case, \texttt{saveNetwork()} can generate symbolic representations of the transition functions in Disjunctive Normal Form (DNF): \end{sloppypar} <<>>= net <- generateRandomNKNetwork(n=10, k=3, readableFunctions=FALSE) saveNetwork(net, file="randomnet.txt", generateDNF=TRUE) @ The \texttt{generateDNF} parameter can also be used to detail which type of DNF formulae should be exported: \texttt{generateDNF="canonical"} exports canonical DNF formulae. \texttt{generateDNF="short"} minimizes the canonical functions by joining terms. By simply setting \texttt{generateDNF=TRUE}, formulae with up to 12 inputs are minimized, and formulae with more than 12 inputs are exported in a canonical form, as a minization is very time-consuming in this case. \subsection{Import from and export to SBML} \begin{sloppypar} \texttt{BoolNet} provides an interface to the widely used Systems Biology Markup Language (SBML) via the import function \texttt{loadSBML()} and the export function \texttt{saveSBML()}. As the core SBML does not fully support Boolean models, import and export of SBML models is based on the \texttt{sbml-qual} package which extends SBML by several qualitative modeling approaches, such as general logical models and Petri nets. For a full description of \texttt{sbml-qual}, refer to \href{http://sbml.org/Documents/Specifications/SBML_Level_3/Packages/Qualitative_Models_(qual)}{http://sbml.org/Documents/Specifications/SBML\_Level\_3/Packages/Qualitative\_Models\_(qual)}. \end{sloppypar} \texttt{BoolNet} only supports a subset of \texttt{sbml-qual}. It can read and write logical models with two possible values for each state, which are equivalent to Boolean networks. Logical models with more than two values for a gene or Petri nets cannot currently be handled by \texttt{BoolNet}. An export to SBML is usually not associated with any loss of information. For example, we can write the cell cycle network to a file and re-import it into \texttt{BoolNet}: \begin{footnotesize} <<eval=FALSE>>= toSBML(cellcycle, file="cellcycle.sbml") sbml_cellcycle <- loadSBML("cellcycle.sbml") sbml_cellcycle @ \end{footnotesize} Apart from some additional brackets, the re-imported network coincides with the original network. Similar to the \texttt{saveNetwork()} function, \texttt{toSBML()} exports a symbolic representation of the network transition functionss, which may not always be available. As for \texttt{saveNetwork()}, there is a parameter \texttt{generateDNF} that can be set to generate a symbolic representation in Disjunctive Normal Form from the truth tables. \subsection{Importing networks from BioTapestry} BioTapestry is a widely-used application for visual modeling of gene-regulatory networks \cite{longabaugh05}. It can be freely accessed at \url{http://www.biotapestry.org}. Although its primary purpose is visualization, the software supports specifying logical functions for the genes. \texttt{BoolNet} can read in the top-level (``Full genome'') plot of a BioTapestry file (*.btp) and convert it into a Boolean network. As an example, we assume the following BioTapestry model with 5 genes (2~inputs and 3~dependent genes): \begin{center} \includegraphics[width=0.8\linewidth]{biotap_model} \end{center} The corresponding BioTapestry file is included in \texttt{BoolNet}. You can determine its path using <<eval=FALSE>>= system.file("doc/example.btp", package="BoolNet") @ \label{cmd:example.btp} to access it in BioTapestry or \texttt{BoolNet}. For the import, \texttt{BoolNet} needs to know the type of influence a gene has on another gene. Therefore, imported networks should only use links that are either enhancers or repressors. Neutral links are ignored in the import. We now set further simulation parameters for the model. These parameters are imported by \texttt{BoolNet} to construct the functions of the Boolean network. First, we want to change the function of Gene~2 to \texttt{OR}. Right-click on Gene~2 and choose \texttt{Simulation Properties...}. \begin{center} \includegraphics[width=0.8\linewidth]{biotap_sim_properties} \end{center} In the properties dialog, choose the \texttt{Logic} tab, and select \texttt{OR} for the logical function. \begin{center} \includegraphics[width=0.8\linewidth]{biotap_logic} \end{center} Now set the function of Gene~1 to \texttt{XOR} (exclusive or) in the same way. \begin{samepage} You can also specify initial values for constant genes, i.e., genes with no input links. Choose the simulation properties of Input~1, and change to the \texttt{Parameters} tab. Choose \texttt{initVal} and set it to 1. \begin{center} \includegraphics[width=0.8\linewidth]{biotap_initval} \end{center} \end{samepage} Press Return to store the result, and exit the dialog with \texttt{OK}. This will create a fixed gene with value 1 (i.e., an over-expressed gene) in the \texttt{BoolNet} import. Note that values other than 0 and 1 are ignored by the import, as well as initialization values for non-constant genes. We assume that you save the network to a file ``example.btp'' in your working directory. In \texttt{R}, type <<echo=FALSE>>= net <- loadBioTapestry(system.file("doc/example.btp", package="BoolNet")) @ <<eval=FALSE>>= net <- loadBioTapestry("example.btp") @ to import the network. Alternatively, replace the file name by the command on page~\pageref{cmd:example.btp} to use the file in the package if you do not want to create the file yourself. The imported network looks like this: <<eval=FALSE>>= net @ \begin{verbatim} Boolean network with 5 genes Involved genes: Input 1 Input 2 Gene 1 Gene 2 Gene 3 \end{verbatim} \pagebreak[4] \begin{verbatim} Transition functions: Input 1 = 1 Input 2 = Input 2 Gene 1 = (!Gene 1 & !Input 1 & Input 2) | (!Gene 1 & Input 1 & !Input 2) | (Gene 1 & !Input 1 & !Input 2) | (Gene 1 & Input 1 & Input 2) Gene 2 = Gene 1 & Gene 3 & !Input 2 Gene 3 = Gene 1 | Gene 2 Knocked-out and over-expressed genes: Input 1 = 1 \end{verbatim} We can see that Input~1 is specified as an over-expressed constant gene. Input~2 is modeled as depending only on itself, i.e. it keeps its initial value. Gene~1 is a representation of the XOR function in Disjunctive Normal Form (DNF), using only logical ANDs, logical ORs, and negations. Gene~2 and Gene~3 consist of conjunctions and disjunctions of their inputs respectively. In addition to this textual description, we can visually verify the network by plotting its wiring: <<eval=FALSE>>= plotNetworkWiring(net) @ The resulting plot is shown in Figure~\ref{fig:wiring_biotap}. \begin{figure}[h] \centering \includegraphics[width=0.6\linewidth]{wiring_biotap} \caption{The wiring graph of the imported network specified in BioTapestry.} \label{fig:wiring_biotap} \end{figure} You can now use the imported network just like any other network in \texttt{BoolNet}. \clearpage \subsection{Exporting network simulations to Pajek} For further analysis, network simulations can be exported to Pajek, a Windows application that provides visualization and analysis methods for graph structures \cite{batagelij98}. For more information on Pajek, please refer to \url{http://pajek.imfm.si/doku.php}. The export function writes the state transition graph to a Pajek file (*.net). This requires a synchronous exhaustive attractor search in \texttt{BoolNet} to build the full transition table. To export the mammalian cell cycle network to Pajek, call <<eval=FALSE>>= data(cellcycle) attr <- getAttractors(cellcycle) toPajek(attr, file="cellcycle.net") @ This will export the graph of the state transitions, which is usually sufficient for plotting. If you want to include the state information (i.e., the gene assignment vectors), call <<eval=FALSE>>= toPajek(attr, file="cellcycle.net", includeLabels=TRUE) @ Now, start Pajek, load the network with \texttt{File | Network | Read}, and check out the tools provided by this application. For example, visualizations can be accessed using the menu item \texttt{Draw | Draw}. Figure~\ref{fig:pajek} shows a plot of the cell cycle network with the Kamada-Kawai layout (Menu entry \texttt{Layout | Energy | Kamada-Kawai | Separate Components}). \begin{figure}[h] \centering \includegraphics[width=0.75\linewidth]{pajek} \caption{A visualization of the mammalian cell cycle network in Pajek.} \label{fig:pajek} \end{figure} \clearpage \bibliographystyle{plain} \bibliography{BoolNet_package_vignette} \section{Appendix}\label{sec:appendix} \subsection{Network file format} This section provides a full language description for the network file format of \texttt{BoolNet}. The language is described in Extended Backus-Naur Form (EBNF). For synchronous, asynchronous and probabilistic Boolean networks, the supported format is as follows: \begin{verbatim} Network = Header Newline {Rule Newline | Comment Newline}; Header = "targets" Separator "factors"; Rule = GeneName Separator BooleanExpression [Separator Probability]; Comment = "#" String; BooleanExpression = GeneName | "!" BooleanExpression | "(" BooleanExpression ")" | BooleanExpression " & " BooleanExpression | BooleanExpression " | " BooleanExpression; | "all(" BooleanExpression {"," BooleanExpression} ")" | "any(" BooleanExpression {"," BooleanExpression} ")" | "maj(" BooleanExpression {"," BooleanExpression} ")" | "sumgt(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "sumlt(" BooleanExpression {"," BooleanExpression} "," Integer ")"; GeneName = ? A gene name from the list of involved genes ?; Separator = ","; Integer = ? An integer value?; Probability = ? A floating-point number ?; String = ? Any sequence of characters (except a line break) ?; Newline = ? A line break character ?; \end{verbatim} \pagebreak[4] The extended format for temporal networks includes additional time specifications and temporal predicates is defined as follows: \begin{verbatim} Network = Header Newline {Function Newline | Comment Newline}; Header = "targets" Separator "factors"; Function = GeneName Separator BooleanExpression; Comment = "#" String; BooleanExpression = GeneName | GeneName TemporalSpecification | BooleanOperator | TemporalOperator BooleanOperator = BooleanExpression | "!" BooleanExpression | "(" BooleanExpression ")" | BooleanExpression " & " BooleanExpression | BooleanExpression " | " BooleanExpression; TemporalOperator = "all" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "any" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "maj" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} ")" | "sumgt" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "sumlt" [TemporalIteratorDef] "(" BooleanExpression {"," BooleanExpression} "," Integer ")" | "timeis" "(" Integer ")" | "timegt" "(" Integer ")" | "timelt" "(" Integer ")"; TemporalIteratorDef = "[" TemporalIterator "=" Integer ".." Integer "]"; TemporalSpecification = "[" TemporalOperand {"+" TemporalOperand | "-" TemporalOperand} "]"; TemporalOperand = TemporalIterator | Integer TemporalIterator = ? An alphanumeric string ?; GeneName = ? A gene name from the list of involved genes ?; Separator = ","; Integer = ? An integer value?; String = ? Any sequence of characters (except a line break) ?; Newline = ? A line break character ?; \end{verbatim} \end{document} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/inst/doc/example.btp������������������������������������������������������������������������0000644�0001762�0000144�00000026164�13277247010�015514� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<BioTapestry version="3.1" > <workspace x="1" y="0" w="12000" h="9000" /> <startupView/> <fonts> <font name="small" type="serif" isBold="true" isItalic="false" size="20" /> <font name="medium" type="serif" isBold="true" isItalic="false" size="28" /> <font name="cisRegName" type="serif" isBold="true" isItalic="false" size="28" /> <font name="geneName" type="serif" isBold="true" isItalic="false" size="28" /> <font name="link" type="serif" isBold="true" isItalic="false" size="28" /> <font name="mediumLarge" type="sanSerif" isBold="true" isItalic="false" size="30" /> <font name="netModule" type="sanSerif" isBold="true" isItalic="false" size="34" /> <font name="large" type="sanSerif" isBold="true" isItalic="false" size="34" /> <font name="notes" type="sanSerif" isBold="true" isItalic="false" size="34" /> <font name="date" type="sanSerif" isBold="false" isItalic="false" size="25" /> <font name="title" type="sanSerif" isBold="true" isItalic="false" size="32" /> </fonts> <displayOptions /> <colors> <color color="EX-dark-cyan" name="Dark Steel Blue" r="0" g="101" b="128" /> <color color="EX-cyan" name="Cyan" r="0" g="255" b="255" /> <color color="EX-yellow-orange" name="Tangerine" r="255" g="153" b="0" /> <color color="EX-pale-green" name="Pale Green" r="133" g="204" b="102" /> <color color="lightOrange" name="Light Orange" r="244" g="211" b="170" /> <color color="EX-dark-green" name="Dark Green" r="39" g="128" b="0" /> <color color="lightGray" name="Light Gray" r="240" g="240" b="240" /> <color color="EX-pale-red-orange" name="Dark Salmon" r="230" g="156" b="138" /> <color color="lightBlue" name="Light Blue" r="220" g="220" b="240" /> <color color="EX-yellow-green" name="Lime" r="154" g="255" b="0" /> <color color="EX-yellow" name="Gold" r="255" g="203" b="0" /> <color color="EX-dark-gray-purple" name="Dark Blue" r="0" g="25" b="128" /> <color color="yellowGreen" name="Yellow Green" r="246" g="249" b="170" /> <color color="EX-dark-red" name="Deep Ochre" r="140" g="56" b="56" /> <color color="EX-pale-magenta" name="Light Plum" r="211" g="138" b="230" /> <color color="EX-purple" name="Indigo" r="102" g="51" b="255" /> <color color="EX-pale-purple" name="Cornflower Blue" r="149" g="165" b="230" /> <color color="EX-red" name="Bright Red" r="255" g="0" b="0" /> <color color="EX-pale-yellow-green" name="Pale Goldenrod" r="221" g="230" b="138" /> <color color="EX-dark-purple" name="Slate Blue" r="77" g="56" b="140" /> <color color="EX-pale-cyan" name="Aquamarine" r="138" g="230" b="182" /> <color color="EX-pure-blue" name="Blue" r="1" g="0" b="255" /> <color color="inactiveLightBlue" name="Very Light Blue" r="235" g="235" b="250" /> <color color="lightPurple" name="Light Purple" r="235" g="219" b="229" /> <color color="black" name="Black" r="0" g="0" b="0" /> <color color="EX-dark-yellow-green" name="Olive Green" r="115" g="128" b="0" /> <color color="EX-dark-tan" name="Dark Tan" r="166" g="133" b="83" /> <color color="EX-magenta" name="Fuchsia" r="254" g="0" b="255" /> <color color="EX-pale-blue" name="Powder Blue" r="102" g="183" b="204" /> <color color="white" name="White" r="255" g="255" b="255" /> <color color="lightGreen" name="Light Green" r="214" g="239" b="209" /> <color color="inactiveLightGreen" name="Very Light Green" r="230" g="255" b="220" /> <color color="inactiveLightPurple" name="Very Light Purple" r="245" g="229" b="240" /> <color color="EX-orange" name="Pumpkin Orange" r="255" g="103" b="0" /> <color color="inactiveYellowGreen" name="Light Yellow Green" r="255" g="255" b="220" /> <color color="inactiveLightOrange" name="Very Light Orange" r="255" g="230" b="200" /> <color color="EX-medium-magenta" name="Mauve" r="166" g="83" b="166" /> <color color="EX-blue-magenta" name="Bright Purple" r="154" g="0" b="255" /> <color color="EX-green" name="Bright Green" r="1" g="255" b="0" /> <color color="EX-dark-magenta" name="Violet" r="102" g="0" b="128" /> <color color="inactiveLightGray" name="Very Light Gray" r="245" g="245" b="245" /> <color color="EX-pale-blue-magenta" name="Lilac" r="146" g="102" b="204" /> <color color="darkGray" name="Dark Gray" r="150" g="150" b="150" /> <color color="EX-pale-yellow orange" name="Dark Wheat" r="204" g="175" b="102" /> <color color="EX-dark-orange" name="Sienna" r="128" g="92" b="0" /> <color color="EX-blue" name="Sky Blue" r="0" g="152" b="255" /> <color color="EX-pale-red" name="Rose" r="204" g="102" b="153" /> </colors> <images> </images> <userTreePaths> </userTreePaths> <genome name="Full Genome" id="bioTapA" > <rootLongName /> <rootDescription /> <nodes> <boxes> <box name="Input 1" id="3" > <simulationLogic type="AND" > <simParameters> <simParameter name="initVal" value="1" /> </simParameters> </simulationLogic> </box> <box name="Input 2" id="4" > <simulationLogic type="AND" /> </box> </boxes> <genes> <gene name="Gene 1" id="0" > <simulationLogic type="XOR" /> </gene> <gene name="Gene 2" id="1" > <simulationLogic type="AND" /> </gene> <gene name="Gene 3" id="2" > <simulationLogic type="OR" /> </gene> </genes> </nodes> <links> <link label="" src="0" targ="0" sign="-" id="13" targPad="5" /> <link label="" src="0" targ="1" sign="+" id="10" targPad="1" /> <link label="" src="0" targ="2" sign="+" id="12" targPad="2" /> <link label="" src="1" targ="2" sign="+" id="11" targPad="1" /> <link label="" src="2" targ="1" sign="+" id="9" targPad="3" /> <link label="" src="3" targ="0" sign="+" id="6" targPad="0" launchPad="1" /> <link label="" src="4" targ="0" sign="-" id="8" targPad="2" launchPad="1" /> <link label="" src="4" targ="1" sign="-" id="7" targPad="2" launchPad="1" /> </links> <netOverlays> </netOverlays> <notes> </notes> </genome> <genomeInstances> </genomeInstances> <layouts> <layout name="bioTapB" genome="bioTapA" type="free" > <layoutMetadata /> <props> <nprops> <nprop id="0" color="EX-orange" x="5870.0" y="4680.0" orient="right" /> <nprop id="1" color="EX-dark-cyan" x="6440.0" y="4640.0" orient="right" /> <nprop id="2" color="EX-blue" x="6160.0" y="4160.0" orient="right" /> <nprop id="3" color="darkGray" x="5770.0" y="4620.0" orient="right" /> <nprop id="4" color="darkGray" x="5450.0" y="4250.0" orient="right" /> </nprops> <lprops> <linkBus labelX="5200.0" labelY="4280.0" labelDir="" src="0" > <drawStyle color="EX-orange" style="solid" thick="regular" /> <segments> <linkSegment id="3" parent="0" strtX="6000.0" strtY="4690.0" endX="6080.0" endY="4690.0" /> <linkSegment id="2" parent="1" strtX="6000.0" strtY="4640.0" endX="5930.0" endY="4640.0" /> <linkSegment id="1" parent="0" strtX="6000.0" strtY="4690.0" endX="6000.0" endY="4640.0" /> <linkSegment id="0" strtX="6000.0" strtY="4690.0" /> <linkSegment id="7" parent="4" strtX="6080.0" strtY="4390.0" endX="6340.0" endY="4390.0" /> <linkSegment id="6" parent="5" strtX="6080.0" strtY="4130.0" endX="6190.0" endY="4130.0" /> <linkSegment id="5" parent="4" strtX="6080.0" strtY="4390.0" endX="6080.0" endY="4130.0" /> <linkSegment id="4" parent="3" strtX="6080.0" strtY="4690.0" endX="6080.0" endY="4390.0" /> <linkSegment id="9" parent="8" strtX="6340.0" strtY="4630.0" endX="6460.0" endY="4630.0" /> <linkSegment id="8" parent="7" strtX="6340.0" strtY="4390.0" endX="6340.0" endY="4630.0" /> </segments> <drops> <drop ref="*" connectStart="0" /> <drop ref="10" connectEnd="9" /> <drop ref="13" connectEnd="2" /> <drop ref="12" connectEnd="6" /> </drops> </linkBus> <linkBus labelX="4820.0" labelY="4280.0" labelDir="" src="1" > <drawStyle color="EX-dark-cyan" style="solid" thick="regular" /> <segments> <linkSegment id="3" parent="2" strtX="6600.0" strtY="4870.0" endX="6100.0" endY="4870.0" /> <linkSegment id="2" parent="0" strtX="6600.0" strtY="4650.0" endX="6600.0" endY="4870.0" /> <linkSegment id="0" strtX="6600.0" strtY="4650.0" /> <linkSegment id="5" parent="4" strtX="6100.0" strtY="4150.0" endX="6180.0" endY="4150.0" /> <linkSegment id="4" parent="3" strtX="6100.0" strtY="4870.0" endX="6100.0" endY="4150.0" /> </segments> <drops> <drop ref="*" connectStart="0" /> <drop ref="11" connectEnd="5" /> </drops> </linkBus> <linkBus labelX="3220.0" labelY="3790.0" labelDir="" src="3" > <drawStyle color="black" style="solid" thick="regular" /> <segments> <linkSegment id="0" strtX="5880.0" strtY="4620.0" /> </segments> <drops> <drop ref="*" connectStart="0" /> <drop ref="6" connectStart="0" /> </drops> </linkBus> <linkBus labelX="3310.0" labelY="3940.0" labelDir="" src="4" > <drawStyle color="black" style="solid" thick="regular" /> <segments> <linkSegment id="3" parent="0" strtX="5620.0" strtY="4250.0" endX="5620.0" endY="4560.0" /> <linkSegment id="0" strtX="5620.0" strtY="4250.0" /> <linkSegment id="7" parent="6" strtX="6360.0" strtY="4250.0" endX="6360.0" endY="4610.0" /> <linkSegment id="6" parent="0" strtX="5620.0" strtY="4250.0" endX="6360.0" endY="4250.0" /> <linkSegment id="4" parent="3" strtX="5620.0" strtY="4560.0" endX="5900.0" endY="4560.0" /> <linkSegment id="8" parent="7" strtX="6360.0" strtY="4610.0" endX="6470.0" endY="4610.0" /> </segments> <drops> <drop ref="*" connectStart="0" /> <drop ref="7" connectEnd="8" /> <drop ref="8" connectEnd="4" /> </drops> </linkBus> <linkBus labelX="4440.0" labelY="4280.0" labelDir="" src="2" > <drawStyle color="EX-blue" style="solid" thick="regular" /> <segments> <linkSegment id="2" parent="0" strtX="6380.0" strtY="4170.0" endX="6380.0" endY="4590.0" /> <linkSegment id="0" strtX="6380.0" strtY="4170.0" /> <linkSegment id="4" parent="2" strtX="6380.0" strtY="4590.0" endX="6480.0" endY="4590.0" /> </segments> <drops> <drop ref="*" connectStart="0" /> <drop ref="9" connectEnd="4" /> </drops> </linkBus> </lprops> </props> </layout> </layouts> <QPCR threshold="1.6" > </QPCR> <TimeCourseData> </TimeCourseData> <TemporalInputRangeData> </TemporalInputRangeData> </BioTapestry> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/inst/doc/BoolNet_package_vignette.R���������������������������������������������������������0000644�0001762�0000144�00000072370�14506502645�020423� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������### R code from vignette source 'BoolNet_package_vignette.Snw' ################################################### ### code chunk number 1: BoolNet_package_vignette.Snw:81-82 (eval = FALSE) ################################################### ## install.packages("BoolNet") ################################################### ### code chunk number 2: BoolNet_package_vignette.Snw:86-87 ################################################### library(BoolNet) ################################################### ### code chunk number 3: BoolNet_package_vignette.Snw:166-167 (eval = FALSE) ################################################### ## cellcycle <- loadNetwork("cellcycle.txt") ################################################### ### code chunk number 4: BoolNet_package_vignette.Snw:172-173 ################################################### data(cellcycle) ################################################### ### code chunk number 5: BoolNet_package_vignette.Snw:222-223 ################################################### data(yeastTimeSeries) ################################################### ### code chunk number 6: BoolNet_package_vignette.Snw:230-231 ################################################### binSeries <- binarizeTimeSeries(yeastTimeSeries) ################################################### ### code chunk number 7: BoolNet_package_vignette.Snw:236-239 ################################################### net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4) ################################################### ### code chunk number 8: BoolNet_package_vignette.Snw:245-246 ################################################### net ################################################### ### code chunk number 9: BoolNet_package_vignette.Snw:253-254 (eval = FALSE) ################################################### ## plotNetworkWiring(net) ################################################### ### code chunk number 10: BoolNet_package_vignette.Snw:268-272 ################################################### net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4, excludedDependencies = list("Sic1" = c("Sic1", "Fkh2"))) ################################################### ### code chunk number 11: BoolNet_package_vignette.Snw:281-287 ################################################### net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", maxK=4) functionIndices <- c(1,2,3,2) #select function index for each regulatory component dontCareDefaults <- lapply(seq_along(net$interactions), function(idx) rep(F, sum(net$interactions[[idx]][[functionIndices[idx]]]$func == -1))) #determine number of don't care values for each selected function and set them to 0 names(dontCareDefaults) <- net$genes singleNet <- chooseNetwork(net, functionIndices, dontCareValues = dontCareDefaults) ################################################### ### code chunk number 12: BoolNet_package_vignette.Snw:290-291 ################################################### singleNet ################################################### ### code chunk number 13: BoolNet_package_vignette.Snw:297-298 ################################################### set.seed(3176) ################################################### ### code chunk number 14: BoolNet_package_vignette.Snw:300-304 ################################################### series <- generateTimeSeries(cellcycle, numSeries=100, numMeasurements=10, noiseLevel=0.1) ################################################### ### code chunk number 15: BoolNet_package_vignette.Snw:309-312 ################################################### binSeries <- binarizeTimeSeries(series, method="kmeans") net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit") net ################################################### ### code chunk number 16: BoolNet_package_vignette.Snw:318-319 ################################################### set.seed(4463) ################################################### ### code chunk number 17: BoolNet_package_vignette.Snw:321-326 ################################################### series <- generateTimeSeries(cellcycle, numSeries=10, numMeasurements=10, perturbations=1, noiseLevel=0.1) ################################################### ### code chunk number 18: < ################################################### series$perturbations ################################################### ### code chunk number 19: BoolNet_package_vignette.Snw:337-341 ################################################### perturbations <- series$perturbations series$perturbations <- NULL binSeries <- binarizeTimeSeries(series, method="kmeans") ################################################### ### code chunk number 20: BoolNet_package_vignette.Snw:344-348 ################################################### net <- reconstructNetwork(binSeries$binarizedMeasurements, method="bestfit", perturbations=perturbations) net ################################################### ### code chunk number 21: BoolNet_package_vignette.Snw:357-358 ################################################### net <- generateRandomNKNetwork(n=10, k=3) ################################################### ### code chunk number 22: BoolNet_package_vignette.Snw:361-362 ################################################### net <- generateRandomNKNetwork(n=10, k=c(1,2,3,1,3,2,3,2,1,1)) ################################################### ### code chunk number 23: BoolNet_package_vignette.Snw:367-368 ################################################### net <- generateRandomNKNetwork(n=20, k=20, topology="scale_free") ################################################### ### code chunk number 24: BoolNet_package_vignette.Snw:372-373 ################################################### net <- generateRandomNKNetwork(n=10, k=3, linkage="lattice") ################################################### ### code chunk number 25: BoolNet_package_vignette.Snw:378-382 ################################################### net <- generateRandomNKNetwork(n=10, k=3, functionGeneration="biased", zeroBias=0.75) ################################################### ### code chunk number 26: BoolNet_package_vignette.Snw:389-397 ################################################### net1 <- generateRandomNKNetwork(n=10, k=3, functionGeneration=generateCanalyzing, zeroBias=0.75) net2 <- generateRandomNKNetwork(n=10, k=3, functionGeneration=generateNestedCanalyzing, zeroBias=0.75) ################################################### ### code chunk number 27: BoolNet_package_vignette.Snw:405-418 ################################################### isMonotone <- function(input, func) { for (i in seq_len(ncol(input))) # check each input gene { groupResults <- split(func, input[,i]) if (any(groupResults[[1]] < groupResults[[2]]) && any(groupResults[[1]] > groupResults[[2]])) # the function is not monotone return(FALSE) } return(TRUE) } ################################################### ### code chunk number 28: BoolNet_package_vignette.Snw:427-431 ################################################### net <- generateRandomNKNetwork(n=10, k=3, validationFunction="isMonotone", failureIterations=1000) ################################################### ### code chunk number 29: BoolNet_package_vignette.Snw:442-444 ################################################### data(cellcycle) knockedOut <- fixGenes(cellcycle, "CycD", 0) ################################################### ### code chunk number 30: BoolNet_package_vignette.Snw:447-448 ################################################### knockedOut <- fixGenes(cellcycle, 1, 0) ################################################### ### code chunk number 31: BoolNet_package_vignette.Snw:451-452 ################################################### overExpressed <- fixGenes(cellcycle, "CycD", 1) ################################################### ### code chunk number 32: BoolNet_package_vignette.Snw:455-456 ################################################### originalNet <- fixGenes(knockedOut, "CycD", -1) ################################################### ### code chunk number 33: BoolNet_package_vignette.Snw:461-462 ################################################### newNet <- fixGenes(cellcycle, c("CycD","CycE"), c(0,1)) ################################################### ### code chunk number 34: BoolNet_package_vignette.Snw:473-475 ################################################### data(cellcycle) stateTransition(cellcycle, rep(1,10)) ################################################### ### code chunk number 35: BoolNet_package_vignette.Snw:479-481 ################################################### path <- getPathToAttractor(cellcycle, rep(0,10)) path ################################################### ### code chunk number 36: BoolNet_package_vignette.Snw:486-487 (eval = FALSE) ################################################### ## plotSequence(sequence=path) ################################################### ### code chunk number 37: BoolNet_package_vignette.Snw:500-501 (eval = FALSE) ################################################### ## sequenceToLaTeX(sequence=path, file="sequence.tex") ################################################### ### code chunk number 38: BoolNet_package_vignette.Snw:506-508 ################################################### startState <- generateState(cellcycle, specs=c("CycD"=1,"CycA"=1)) stateTransition(cellcycle,startState) ################################################### ### code chunk number 39: BoolNet_package_vignette.Snw:515-516 ################################################### data(igf) ################################################### ### code chunk number 40: BoolNet_package_vignette.Snw:521-523 ################################################### startState <- generateState(igf, specs=c("IGF"=1)) stateTransition(igf, startState) ################################################### ### code chunk number 41: BoolNet_package_vignette.Snw:526-527 ################################################### getPathToAttractor(network=igf,state=startState) ################################################### ### code chunk number 42: BoolNet_package_vignette.Snw:532-535 ################################################### startState <- generateState(igf, specs=list("IGF"=c(0,0,1))) startState ################################################### ### code chunk number 43: BoolNet_package_vignette.Snw:545-546 (eval = FALSE) ################################################### ## plotSequence(network=igf, startState=startState) ################################################### ### code chunk number 44: BoolNet_package_vignette.Snw:552-553 ################################################### set.seed(54321) ################################################### ### code chunk number 45: BoolNet_package_vignette.Snw:555-556 ################################################### stateTransition(cellcycle, rep(1,10), type="asynchronous") ################################################### ### code chunk number 46: BoolNet_package_vignette.Snw:562-563 ################################################### set.seed(4321) ################################################### ### code chunk number 47: BoolNet_package_vignette.Snw:565-567 ################################################### stateTransition(cellcycle, rep(1,10), type="asynchronous", geneProbabilities=c(0.05,0.05,0.2,0.3,0.05,0.05,0.05,0.05,0.1,0.1)) ################################################### ### code chunk number 48: BoolNet_package_vignette.Snw:574-576 ################################################### stateTransition(cellcycle, rep(1,10), type="asynchronous", chosenGene="CycE") ################################################### ### code chunk number 49: BoolNet_package_vignette.Snw:580-581 ################################################### set.seed(432) ################################################### ### code chunk number 50: BoolNet_package_vignette.Snw:583-585 ################################################### data(examplePBN) stateTransition(examplePBN, c(0,1,1), type="probabilistic") ################################################### ### code chunk number 51: BoolNet_package_vignette.Snw:588-590 ################################################### stateTransition(examplePBN, c(0,1,1), type="probabilistic", chosenFunctions=c(2,1,2)) ################################################### ### code chunk number 52: BoolNet_package_vignette.Snw:608-611 (eval = FALSE) ################################################### ## data(cellcycle) ## attr <- getAttractors(cellcycle) ## attr ################################################### ### code chunk number 53: BoolNet_package_vignette.Snw:614-616 ################################################### attr <- getAttractors(cellcycle) attr ################################################### ### code chunk number 54: BoolNet_package_vignette.Snw:622-623 (eval = FALSE) ################################################### ## print(attr, activeOnly=TRUE) ################################################### ### code chunk number 55: BoolNet_package_vignette.Snw:626-627 ################################################### print(attr, activeOnly=TRUE) ################################################### ### code chunk number 56: BoolNet_package_vignette.Snw:636-637 ################################################### getAttractorSequence(attr, 2) ################################################### ### code chunk number 57: BoolNet_package_vignette.Snw:644-646 (eval = FALSE) ################################################### ## tt <- getTransitionTable(attr) ## tt ################################################### ### code chunk number 58: BoolNet_package_vignette.Snw:660-661 (eval = FALSE) ################################################### ## getBasinOfAttraction(attr, 1) ################################################### ### code chunk number 59: BoolNet_package_vignette.Snw:666-667 (eval = FALSE) ################################################### ## getStateSummary(attr, c(1,1,1,1,1,1,1,1,1,1)) ################################################### ### code chunk number 60: BoolNet_package_vignette.Snw:679-680 (eval = FALSE) ################################################### ## plotStateGraph(attr) ################################################### ### code chunk number 61: BoolNet_package_vignette.Snw:686-687 (eval = FALSE) ################################################### ## plotStateGraph(attr, piecewise=TRUE) ################################################### ### code chunk number 62: BoolNet_package_vignette.Snw:702-703 (eval = FALSE) ################################################### ## attr <- getAttractors(cellcycle, method="random", startStates=100) ################################################### ### code chunk number 63: BoolNet_package_vignette.Snw:707-710 (eval = FALSE) ################################################### ## attr <- getAttractors(cellcycle, ## method="chosen", ## startStates=list(rep(0,10),rep(1,10))) ################################################### ### code chunk number 64: BoolNet_package_vignette.Snw:719-720 (eval = FALSE) ################################################### ## plotAttractors(attr, subset=2) ################################################### ### code chunk number 65: BoolNet_package_vignette.Snw:723-724 (eval = FALSE) ################################################### ## attractorsToLaTeX(attr, subset=2, file="attractors.tex") ################################################### ### code chunk number 66: BoolNet_package_vignette.Snw:738-742 ################################################### attr <- getAttractors(cellcycle, type="asynchronous", method="random", startStates=500) ################################################### ### code chunk number 67: BoolNet_package_vignette.Snw:748-749 (eval = FALSE) ################################################### ## attr ################################################### ### code chunk number 68: BoolNet_package_vignette.Snw:775-780 (eval = FALSE) ################################################### ## attr <- getAttractors(cellcycle, ## type="asynchronous", ## method="random", ## startStates=500, ## avoidSelfLoops=FALSE) ################################################### ### code chunk number 69: BoolNet_package_vignette.Snw:795-796 (eval = FALSE) ################################################### ## plotAttractors(attr, subset=2, mode="graph", drawLabels=FALSE) ################################################### ### code chunk number 70: BoolNet_package_vignette.Snw:804-806 (eval = FALSE) ################################################### ## sim <- simulateSymbolicModel(igf) ## sim ################################################### ### code chunk number 71: BoolNet_package_vignette.Snw:809-811 ################################################### sim <- simulateSymbolicModel(igf) sim ################################################### ### code chunk number 72: BoolNet_package_vignette.Snw:825-826 (eval = FALSE) ################################################### ## plotAttractors(sim, subset=2) ################################################### ### code chunk number 73: BoolNet_package_vignette.Snw:829-830 (eval = FALSE) ################################################### ## plotStateGraph(sim) ################################################### ### code chunk number 74: BoolNet_package_vignette.Snw:844-845 ################################################### set.seed(43851) ################################################### ### code chunk number 75: BoolNet_package_vignette.Snw:847-848 ################################################### sim <- simulateSymbolicModel(igf, method="random", startStates=2) ################################################### ### code chunk number 76: BoolNet_package_vignette.Snw:851-852 ################################################### sim$sequences ################################################### ### code chunk number 77: BoolNet_package_vignette.Snw:867-870 ################################################### data(examplePBN) sim <- markovSimulation(examplePBN) sim ################################################### ### code chunk number 78: BoolNet_package_vignette.Snw:876-877 (eval = FALSE) ################################################### ## plotPBNTransitions(sim) ################################################### ### code chunk number 79: BoolNet_package_vignette.Snw:890-895 ################################################### data(cellcycle) sim <- markovSimulation(cellcycle, numIterations=1024, returnTable=FALSE) sim ################################################### ### code chunk number 80: BoolNet_package_vignette.Snw:904-909 ################################################### sim <- markovSimulation(cellcycle, numIterations=1024, returnTable=FALSE, startStates=list(rep(1,10))) sim ################################################### ### code chunk number 81: BoolNet_package_vignette.Snw:921-922 ################################################### set.seed(3361) ################################################### ### code chunk number 82: BoolNet_package_vignette.Snw:924-929 ################################################### data(cellcycle) r <- perturbTrajectories(cellcycle, measure="hamming", numSamples=100, flipBits=1) ################################################### ### code chunk number 83: BoolNet_package_vignette.Snw:933-934 ################################################### r$value ################################################### ### code chunk number 84: BoolNet_package_vignette.Snw:938-944 ################################################### r <- perturbTrajectories(cellcycle, measure="sensitivity", numSamples=100, flipBits=1, gene="CycE") r$value ################################################### ### code chunk number 85: BoolNet_package_vignette.Snw:949-954 ################################################### r <- perturbTrajectories(cellcycle, measure="attractor", numSamples=100, flipBits=1) r$value ################################################### ### code chunk number 86: BoolNet_package_vignette.Snw:961-964 ################################################### perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="bitflip") ################################################### ### code chunk number 87: BoolNet_package_vignette.Snw:969-972 ################################################### perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="shuffle") ################################################### ### code chunk number 88: BoolNet_package_vignette.Snw:978-982 ################################################### perturbedNet <- perturbNetwork(cellcycle, perturb="transitions", method="bitflip", numStates=10) ################################################### ### code chunk number 89: BoolNet_package_vignette.Snw:990-1046 (eval = FALSE) ################################################### ## # Perform a robustness test on a network ## # by counting the numbers of perturbed networks ## # containing the attractors of the original net ## ## library(BoolNet) ## ## # load mammalian cell cycle network ## data(cellcycle) ## ## # get attractors in original network ## attrs <- getAttractors(cellcycle, canonical=TRUE) ## ## # create 1000 perturbed copies of the network and search for attractors ## perturbationResults <- sapply(1:1000, function(i) ## { ## # perturb network and identify attractors ## perturbedNet <- perturbNetwork(cellcycle, perturb="functions", method="bitflip") ## perturbedAttrs <- getAttractors(perturbedNet, canonical=TRUE) ## ## # check whether the attractors in the original network exist in the perturbed network ## attractorIndices <- sapply(attrs$attractors,function(attractor1) ## { ## index <- which(sapply(perturbedAttrs$attractors, function(attractor2) ## { ## identical(attractor1, attractor2) ## })) ## if (length(index) == 0) ## NA ## else ## index ## }) ## return(attractorIndices) ## }) ## ## # perturbationResults now contains a matrix ## # with the first 2 columns specifying the indices or the ## # original attractors in the perturbed network ## # (or NA if the attractor was not found) and the next 2 ## # columns counting the numbers of states ## # in the basin of attraction (or NA if the attractor was not found) ## ## # measure the total numbers of occurrences of the original attractors in the perturbed copies ## numOccurrences <- apply(perturbationResults[seq_along(attrs$attractors),,drop=FALSE], 1, ## function(row)sum(!is.na(row))) ## ## # print original attractors ## cat("Attractors in original network:\n") ## print(attrs) ## ## # print information ## cat("Number of occurrences of the original attractors", ## "in 1000 perturbed copies of the network:\n") ## for (i in 1:length(attrs$attractors)) ## { ## cat("Attractor ",i,": ",numOccurrences[i],"\n",sep="") ## } ################################################### ### code chunk number 90: BoolNet_package_vignette.Snw:1080-1085 (eval = FALSE) ################################################### ## data(cellcycle) ## res <- testNetworkProperties(cellcycle, ## numRandomNets=100, ## testFunction="testAttractorRobustness", ## testFunctionParams = list(copies=100, perturb="functions")) ################################################### ### code chunk number 91: BoolNet_package_vignette.Snw:1109-1114 (eval = FALSE) ################################################### ## testNetworkProperties(cellcycle, ## numRandomNets=100, ## testFunction="testTransitionRobustness", ## testFunctionParams=list(numSamples=100), ## alternative="less") ################################################### ### code chunk number 92: BoolNet_package_vignette.Snw:1121-1124 (eval = FALSE) ################################################### ## testNetworkProperties(cellcycle, ## numRandomNets=100, ## testFunction="testIndegree") ################################################### ### code chunk number 93: BoolNet_package_vignette.Snw:1142-1146 (eval = FALSE) ################################################### ## testNetworkProperties(cellcycle, ## numRandomNets=100, ## testFunction="testIndegree", ## accumulation="kullback_leibler") ################################################### ### code chunk number 94: BoolNet_package_vignette.Snw:1162-1174 ################################################### testBasinSizes <- function(network, accumulate=TRUE, params) { attr <- getAttractors(network) basinSizes <- sapply(attr$attractors, function(a) { a$basinSize }) if (accumulate) return(mean(basinSizes)) else return(basinSizes) } ################################################### ### code chunk number 95: BoolNet_package_vignette.Snw:1180-1184 (eval = FALSE) ################################################### ## testNetworkProperties(cellcycle, ## numRandomNets=100, ## testFunction="testBasinSizes", ## xlab="Average size of basins of attraction") ################################################### ### code chunk number 96: BoolNet_package_vignette.Snw:1207-1208 (eval = FALSE) ################################################### ## saveNetwork(cellcycle, file="cellcycle.txt") ################################################### ### code chunk number 97: BoolNet_package_vignette.Snw:1213-1215 ################################################### net <- generateRandomNKNetwork(n=10, k=3, readableFunctions=FALSE) saveNetwork(net, file="randomnet.txt", generateDNF=TRUE) ################################################### ### code chunk number 98: BoolNet_package_vignette.Snw:1230-1233 (eval = FALSE) ################################################### ## toSBML(cellcycle, file="cellcycle.sbml") ## sbml_cellcycle <- loadSBML("cellcycle.sbml") ## sbml_cellcycle ################################################### ### code chunk number 99: BoolNet_package_vignette.Snw:1252-1253 (eval = FALSE) ################################################### ## system.file("doc/example.btp", package="BoolNet") ################################################### ### code chunk number 100: BoolNet_package_vignette.Snw:1285-1286 ################################################### net <- loadBioTapestry(system.file("doc/example.btp", package="BoolNet")) ################################################### ### code chunk number 101: BoolNet_package_vignette.Snw:1288-1289 (eval = FALSE) ################################################### ## net <- loadBioTapestry("example.btp") ################################################### ### code chunk number 102: BoolNet_package_vignette.Snw:1294-1295 (eval = FALSE) ################################################### ## net ################################################### ### code chunk number 103: BoolNet_package_vignette.Snw:1318-1319 (eval = FALSE) ################################################### ## plotNetworkWiring(net) ################################################### ### code chunk number 104: BoolNet_package_vignette.Snw:1340-1343 (eval = FALSE) ################################################### ## data(cellcycle) ## attr <- getAttractors(cellcycle) ## toPajek(attr, file="cellcycle.net") ################################################### ### code chunk number 105: BoolNet_package_vignette.Snw:1347-1348 (eval = FALSE) ################################################### ## toPajek(attr, file="cellcycle.net", includeLabels=TRUE) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/inst/CITATION�������������������������������������������������������������������������������0000644�0001762�0000144�00000001057�14377077466�013756� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������citHeader("To cite package 'BoolNet' in publications use:") bibentry(bibtype = "Article", title = "BoolNet - an R package for generation, reconstruction and analysis of Boolean networks", author = c(person("Christoph","Muessel",role= "aut"), person("Martin","Hopfensitz", role="aut"), person(c("Hans", "A."),"Kestler", role="aut", email="hans.kestler@uni-ulm.de")), journal = "Bioinformatics", volume = 26, number = 10, pages = "1378--1380", year = 2010, doi = "10.1093/bioinformatics/btq124" )���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BoolNet/inst/NEWS.Rd��������������������������������������������������������������������������������0000644�0001762�0000144�00000015214�13450340674�013645� 0����������������������������������������������������������������������������������������������������ustar �ligges��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������\name{NEWS} \title{NEWS file for the \pkg{BoolNet} package} \section{Changes in version 2.1.5}{ \itemize{ \item{Fixed vignette compilation errors on Solaris 10.} } } \section{Changes in version 2.1.4}{ \itemize{ \item{\code{getAttractors()} now allows for plotting all attractors inside one plot. Fixed minor bugs.} } } \section{Changes in version 2.1.1}{ \itemize{ \item{Fixed compilation errors on Windows.} } } \section{Changes in version 2.1.0}{ \subsection{Modified functions}{ \itemize{ \item{\code{getAttractors()} and \code{simulateSymbolicModel()} now support the identification of attractors in large networks based on a formulation as a satisfiability (SAT) problem. } \item{\code{plotAttractors()} and \code{plotSequence()} now plot the genes in the order of the network instead of the reverse order by default. This behaviour can be controlled using a new parameter \code{reverse} which is also available in \code{attractorsToLaTeX()} and \code{sequenceToLaTeX()}.} \item{Bugfix regarding negated temporal predicates in \code{simulateSymbolicModel()}.} } } } \section{Changes in version 2.0.2}{ \subsection{Modified functions}{ \itemize{ \item{Fixed undefined behaviour in \code{markovSimulation()}.} } } } \section{Changes in version 2.0.1}{ \subsection{Modified functions}{ \itemize{ \item{Fixed memory misalignment in \code{simulateSymbolicModel()}.} \item{\code{loadSBML()} now accepts nodes that are constant, but have no initial value.} } } } \section{Changes in version 2.0}{ \subsection{New functions}{ \itemize{ \item{Support of temporal networks, and inclusion of a new simulator \code{simulateSymbolicModel()} to simulate these networks. Related functions include \code{truthTableToSymbolic()} and \code{symbolicToTruthTable()} to convert networks between the symbolic representation used by the new simulator and the truth table representation employed by the standard simulator.} \item{New function \code{perturbTrajectories()} to assess the robustness of networks to noise in the states}.} } \subsection{Modified functions}{ \itemize{ \item{\code{loadNetwork()} can now load networks in a symbolic representation and with temporal extensions. \code{loadSBML()} and \code{loadBioTapestry()} can load symbolic networks without temporal extensions. } \item{Most functions of the package have been adapted to work either with the symbolic representation or with the truth table representation of networks.} \item{\code{plotSequence()} and \code{sequenceToLaTeX()} now visualize the attractor.} \item{\code{reconstructNetwork()} now supports the specification of prior knowledge in form of required or excluded dependencies. Furthermore, it can now reconstruct networks from perturbation time series. By default, the function now returns incomplete functions with "don't care" values" instead of enumerating all possible functions. } \item{\code{generateTimeSeries()} can now generate artificial perturbation data with simulated knock-out or overexpression of genes.} \item{\code{generateRandomNKNetwork()} can now be supplied with a user-defined generation function for the transition functions. Generation functions \code{generateCanalyzing()} and \code{generateNestedCanalyzing()} for canalyzing functions and nested canalyzing functions are included in the package.} \item{\code{testNetworkProperties()} supports several new tests that perturb the network states instead of the networks themselves. These are available in the test functions \code{testAttractorRobustness()} and \code{testTransitionRobustness()}. } } } } \section{Changes in version 1.63}{ \subsection{Modified functions}{ \itemize{ \item{Fixed issues preventing the use of \pkg{BoolNet} on Big Endian systems.} \item{Eliminated some bad style code.} \item{Fixed some valgrind notes.} } } } \section{Changes in version 1.62}{ \subsection{Modified functions}{ \itemize{ \item{Minor bugfixes in \code{loadNetwork()}.} \item{Fixed undefined behaviour warnings for GCC 4.9.} } } } \section{Changes in version 1.61}{ \subsection{Modified functions}{ \itemize{ \item{Bugfixes in \code{plotAttractors()} and \code{plotSequence()}.} \item{Fixed compatibility issues with R 3.0 alpha.} } } } \section{Changes in version 1.60}{ \subsection{New functions}{ \itemize{ \item{Support for SBML: \code{loadSBML()} and \code{toSBML()} import from and export to SBML documents with the \code{sbml-qual} extension package.} \item{\code{saveNetwork()} stores networks in the \pkg{BoolNet} file format.} } } \subsection{Modified functions}{ \itemize{ \item{The DNF generator employed by \code{generateRandomNKNetwork()} and \code{simplifyNetwork()} (as well as by the new functions \code{saveNetwork()} and \code{toSBML()}) now supports minimizing the canonical DNFs.} } } } \section{Changes in version 1.51}{ \subsection{Modified functions}{ \itemize{ \item{\pkg{BoolNet} now supports the modified interface of \pkg{igraph} 0.6 in all plotting functions, but is still compatible with older versions of \pkg{igraph}.} \item{\code{loadNetwork()} supports comment lines in the network files.} } } } \section{Changes in version 1.50}{ \subsection{New functions}{ \itemize{ \item{\code{generateTimeSeries()} generates random state sequences from an existing network.} \item{\code{plotSequence()} and \code{sequenceToLaTeX()} plot and export sequences of states similar to \code{plotAttractors()} and \code{attractorsToLaTeX()}.} \item{\code{getAttractorSequence()} extracts the states of a single synchronous attractor from an attractor information structure as a data frame.} \item{\code{generateState()} provides a simple way to specify network states using partial assignments.} } } \subsection{Modified functions}{ \itemize{ \item{\code{getPathToAttractor()} has an additional parameter \code{includeAttractorStates} specifying which attractor states should be included in the path. The default behaviour has been changed to include all attractor states.} \item{\code{generateRandomNKNetwork()} now supports the generation of networks using specific classes of functions. For this purpose, it has two new parameters \code{validationFunction} and \code{failureIterations}.} \item{By default, \code{loadNetwork()} no longer changes gene names to lower case. If this behaviour is desired, it can be reactivated using the new \code{lowercaseGenes} parameter.} \item{\code{stateTransition()} now names the state vector using the gene names.} \item{\code{plotAttractors()} has a new parameter \code{drawLegend} to disable the legend.} \item{The \code{randomChainLength} parameter of \code{getAttractors()} now defaults to 10000.} \item{\code{getAttractors()}, \code{reconstructNetwork()} and \code{markovSimulation()} can now be interrupted by the user.} } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������