diff options
420 files changed, 19069 insertions, 68880 deletions
diff --git a/.gitignore b/.gitignore index 0986bb6e4c..3b0e21bde3 100644 --- a/.gitignore +++ b/.gitignore @@ -86,6 +86,8 @@ lib/os_mon/priv/obj/win32/ lib/runtime_tools/c_src/win32/ lib/runtime_tools/priv/lib/ lib/runtime_tools/priv/obj/ +lib/runtime_tools/doc/src/DTRACE.xml +lib/runtime_tools/doc/src/SYSTEMTAP.xml lib/tools/bin/win32/ lib/tools/c_src/win32/ lib/tools/obj/win32/ @@ -335,6 +337,7 @@ JAVADOC-GENERATED /system/doc/installation_guide/INSTALL.xml /system/doc/installation_guide/INSTALL-CROSS.xml /system/doc/installation_guide/INSTALL-WIN32.xml +/system/doc/installation_guide/MARKDOWN.xml # test_server diff --git a/HOWTO/BENCHMARKS.md b/HOWTO/BENCHMARKS.md new file mode 100644 index 0000000000..b3df4638ea --- /dev/null +++ b/HOWTO/BENCHMARKS.md @@ -0,0 +1,73 @@ +Benchmarking Erlang/OTP +======================= + +The Erlang/OTP source tree contains a number of benchmarks. The same framework +is used to run these benchmarks as is used to run tests. Therefore in order to +run benchmarks you have to [release the tests][] just as you normally would. + +Note that many of these benchmarks were developed to test a specific feature +under a specific setting. We strive to keep the benchmarks up-to-date, but alas +time is not an endless resource so some benchmarks will be outdated and +irrelevant. + +Running the benchmarks +---------------------- + +As with testing, `ts` is used to run the benchmarks. Before running any +benchmarks you have to [install the tests][]. To get a listing of all +benchmarks you have available call `ts:benchmarks()`. + +To run all benchmarks call `ts:bench()`. This will run all benchmarks using +the emulator which is in you `$PATH` (Note that this does not have to be the +same as from which the benchmarks were built from). All the results of the +benchmarks are put in a folder in `$TESTROOT/test_server/` called +`YYYY_MO_DDTHH_MI_SS`. + +Each benchmark is run multiple times and the data for all runs is collected in +the files within the benchmark folder. All benchmarks are written so that a +higher values are better. + +Writing benchmarks +------------------ + +Benchmarks are just normal testcases in Common Test suites. They are marked as +benchmarks by being included in the `AppName_bench.spec` which is located in +`lib/AppName/test/` for the applications which have benchmarks. Note that you +might want to add a skip clause to `AppName.spec` for the benchmarks if you do +not want them to be run in the nightly tests. + +Results of benchmarks are sent using the ct_event mechanism and automatically +collected and formatted by ts. + + ct_event:notify( + #event{name = benchmark_data, + data = [{value,TPS}]}). + +The application, suite and testcase associated with the value is automatically +detected. If you want to supply your own you can include `suite` andor `name` +with the data. i.e. + + ct_event:notify( + #event{name = benchmark_data, + data = [{suite,"erts_bench"}, + {name,"ets_transactions_per_sec"}, + {value,TPS}]}). + +The reason for using the internal ct_event and not ct is because the benchmark +code has to be backwards compatible with at least R14. + +The value which is reported should be as raw as possible. i.e. you should not +do any averaging of the value before reporting. The tools we use to collect the +benchmark data over time will do averages, means, stddev and more with the data. +So the more data which is sent using `ct_event` the better. + +Viewing benchmarks +------------------ + +At the moment of writing this HOWTO the tool for viewing benchmark results is +not available as opensource. This will hopefully change in the near future. + + + [release the tests]: TESTING.md#releasing-tests + [install the tests]: TESTING.md#configuring-the-test-environment + diff --git a/README.bootstrap b/HOWTO/BOOTSTRAP.md index f42bc7aa47..59e31165cf 100644 --- a/README.bootstrap +++ b/HOWTO/BOOTSTRAP.md @@ -1,16 +1,16 @@ Notes about prebuilt beam files under version control ------------------------------------------------------ +===================================================== This information applies mostly to developers, some parts only to developers of the main branch i.e. Ericsson and HiPE personel. There are two types of derived code under version control, namely: -primary bootstrap - Resides in the $ERL_TOP/bootstrap/{lib,bin} directories. -preloaded code - Resides in the $ERL_TOP/erts/preloaded directory. +primary bootstrap - Resides in the `$ERL_TOP/bootstrap/{lib,bin}` directories. +preloaded code - Resides in the `$ERL_TOP/erts/preloaded` directory. Primary bootstrap -................. +----------------- The two types of version controlled code are fundamentally different. The primary bootstrap is code compiled from source files in @@ -19,7 +19,7 @@ lib/orber/include. They are checked in in the version control system to make it possible to build directly from the code base tree without the need for an earlier version of the compiler. When a new version of OTP is released, these files are updated manually (or rather, by using -the $ERL_TOP/otp_build script) and checked in. The files can also be +the `$ERL_TOP/otp_build` script) and checked in. The files can also be updated due to changes in the compiler during the development process. The primary bootstrap is always updated as a separate deliberate process, never during a normal development build. @@ -27,31 +27,31 @@ deliberate process, never during a normal development build. If a prebuilt open source version of erlang is used, the directory bootstrap initially does not contain any beam files, the directory is instead populated by copying beam files from the -$ERL_TOP/lib/{kernel,stdlib,compiler}/ebin directories. This +`$ERL_TOP/lib/{kernel,stdlib,compiler}/ebin` directories. This construction is to save space in the distribution, but the result would be the same. Open source developers need not provide patches for the precompiled beam files in the primary bootstrap, the bootstrap update is always performed by the main developers. Preloaded code -.............. +-------------- -The directory $ERL_TOP/preloaded contains both src and ebin +The directory `$ERL_TOP/preloaded` contains both src and ebin subdirectories. The preloaded code is compiled into the virtual machine and always present. When compiling the virtual machine, those beam files need to be present and they are considered a part of the virtual machine rather than a part of the kernel application. When preloaded files are to be updated, the source code is built using a -special Makefile in the $ERL_TOP/preloaded/src directory, which +special Makefile in the `$ERL_TOP/preloaded/src` directory, which creates beam files in the same directory. When they seem to compile successfully, they can be used in an emulator build by being copied -to the ebin directory. otp_build update_preloaded can be used to +to the ebin directory. `otp_build update_preloaded` can be used to ease the process (there are also similar targets in the -$ERL_TOP/preloaded/src/Makefile). +`$ERL_TOP/preloaded/src/Makefile`). In prebuilt open source distributions, these beam files are also present, but to update them one might need to change permission on the -$ERL_TOP/preloaded/ebin directory, then build and then manually copy +`$ERL_TOP/preloaded/ebin` directory, then build and then manually copy the beam files from the source directory to ../ebin. If patches are created that involve the source files used to build preloaded code, always note this specially as the preloaded/ebin directory needs diff --git a/README.dtrace.md b/HOWTO/DTRACE.md index 5bc042f9fc..b719c68c59 100644 --- a/README.dtrace.md +++ b/HOWTO/DTRACE.md @@ -5,7 +5,7 @@ History ------- The first implementation of DTrace probes for the Erlang virtual -machine was presented at the [2008 Erlang User Conference] [4]. That +machine was presented at the [2008 Erlang User Conference] [1]. That work, based on the Erlang/OTP R12 release, was discontinued due to what appears to be miscommunication with the original developers. @@ -16,13 +16,13 @@ e.g. `foo_module:dtrace_probe("message goes here!")`. Goals ----- -1. Annotate as much of the Erlang VM as is practical. +* Annotate as much of the Erlang VM as is practical. * The initial goal is to trace file I/O operations. -2. Support all platforms that implement DTrace: OS X, Solaris, - and (I hope) FreeBSD and NetBSD. -3. To the extent that it's practical, support SystemTap on Linux - via DTrace provider compatibility. -4. Allow Erlang code to supply annotations. +* Support all platforms that implement DTrace: OS X, Solaris, + and (I hope) FreeBSD and NetBSD. +* To the extent that it's practical, support SystemTap on Linux + via DTrace provider compatibility. +* Allow Erlang code to supply annotations. Supported platforms ------------------- @@ -33,8 +33,8 @@ Supported platforms OpenIndiana release 151a, and both appear to work. * FreeBSD 9.0, though please see the "FreeBSD 9.0 Release Notes" section below! -* Linux via SystemTap compatibility. Please see the file - `README.systemtap.md` for more details. +* Linux via SystemTap compatibility. Please see + [$ERL_TOP/HOWTO/SYSTEMTAP.md][] for more details. Just add the `--with-dynamic-trace=dtrace` option to your command when you run the `configure` script. If you are using systemtap, the configure option @@ -43,10 +43,10 @@ is `--with-dynamic-trace=systemtap` Status ------ -As of R15B01, the dynamic trace code is included in the main OTP distribution, +As of R15B01, the dynamic trace code is included in the OTP source distribution, although it's considered experimental. The main development of the dtrace code still happens outside of Ericsson, but there is no need to fetch a patched -version of OTP to get the basic funtionality. +version of the OTP source to get the basic funtionality. Implementation summary ---------------------- @@ -66,9 +66,7 @@ following may be executed in a different Pthread: * `efile_drv` command execution (C code) * `efile_drv` status return (C code) -**TODO: keep this description up-to-date.** - -Example output from `lib/dtrace/examples/efile_drv.d` while executing +Example output from `lib/runtime_tools/examples/efile_drv.d` while executing `file:rename("old-name", "new-name")`: efile_drv enter tag={3,84} user tag some-user-tag | RENAME (12) | args: old-name new-name , 0 0 (port #Port<0.59>) @@ -83,7 +81,7 @@ Example output from `lib/dtrace/examples/efile_drv.d` while executing these two numbers form a unique ID for the I/O operation. * `12` is the command number for the rename operation. See the definition for `FILE_RENAME` in the source code file `efile_drv.c` - or the `BEGIN` section of the D script `lib/dtrace/examples/efile_drv.d`. + or the `BEGIN` section of the D script `lib/runtime_tools/examples/efile_drv.d`. * `old-name` and `new-name` are the two string arguments for the source and destination of the `rename(2)` system call. The two integer arguments are unused; the simple formatting code @@ -101,8 +99,8 @@ So, where does the `some-user-tag` string come from? At the moment, the user tag comes from code like the following: - put(dtrace_utag, "some-user-tag"), - file:rename("old-name", "new-name"). + dyntrace:put_tag("some-user-tag"), + file:rename("old-name", "new-name"), This method of tagging I/O at the Erlang level is subject to change. @@ -391,3 +389,4 @@ Guide to efile_drv.c probe arguments probe arg9 = C driver dt_i4 = advise_type; [1]: http://www.erlang.org/euc/08/ + [$ERL_TOP/HOWTO/SYSTEMTAP.md]: SYSTEMTAP.md diff --git a/HOWTO/INSTALL-CROSS.md b/HOWTO/INSTALL-CROSS.md new file mode 100644 index 0000000000..95264a82eb --- /dev/null +++ b/HOWTO/INSTALL-CROSS.md @@ -0,0 +1,556 @@ +Cross Compiling Erlang/OTP +========================== + +Introduction +------------ + +This document describes how to cross compile Erlang/OTP-%OTP-REL%. Note that +the support for cross compiling Erlang/OTP should be considered as +experimental. As far as we know, the %OTP-REL% release should cross compile +fine, but since we currently have a very limited set of cross compilation +environments to test with we cannot be sure. The cross compilation support +will remain in an experimental state until we get a lot more cross compilation +environments to test with. + +You are advised to read the whole document before attempting to cross +compile Erlang/OTP. However, before reading this document, you should read +the [$ERL_TOP/HOWTO/INSTALL.md][] document which describes building and installing +Erlang/OTP in general. `$ERL_TOP` is the top directory in the source tree. + +### otp\_build Versus configure/make ### + +Building Erlang/OTP can be done either by using the `$ERL_TOP/otp_build` +script, or by invoking `$ERL_TOP/configure` and `make` directly. Building using +`otp_build` is easier since it involves fewer steps, but the `otp_build` build +procedure is not as flexible as the `configure`/`make` build procedure. Note +that `otp_build configure` will produce a default configuration that differs +from what `configure` will produce by default. For example, currently +`--disable-dynamic-ssl-lib` is added to the `configure` command line arguments +unless `--enable-dynamic-ssl-lib` has been explicitly passed. The binary +releases that we deliver are built using `otp_build`. The defaults used by +`otp_build configure` may change at any time without prior notice. + +### Cross Configuration ### + +The `$ERL_TOP/xcomp/erl-xcomp.conf.template` file contains all available cross +configuration variables and can be used as a template when creating a cross +compilation configuration. All [cross configuration variables][] are also +listed at the end of this document. For examples of working cross +configurations see the `$ERL_TOP/xcomp/erl-xcomp-TileraMDE2.0-tilepro.conf` +file and the `$ERL_TOP/xcomp/erl-xcomp-x86_64-saf-linux-gnu.conf` file. If the +default behavior of a variable is satisfactory, the variable does not need to +be set. However, the `configure` script will issue a warning when a default +value is used. When a variable has been set, no warning will be issued. + +A cross configuration file can be passed to `otp_build configure` using the +`--xcomp-conf` command line argument. Note that `configure` does not accept +this command line argument. When using the `configure` script directly, pass +the configuration variables as arguments to `configure` using a +`<VARIABLE>=<VALUE>` syntax. Variables can also be passed as environment +variables to `configure`. However, if you pass the configuration in the +environment, make sure to unset all of these environment variables before +invoking `make`; otherwise, the environment variables might set make variables +in some applications, or parts of some applications, and you may end up with +an erroneously configured build. + +### What can be Cross Compiled? ### + +All Erlang/OTP applications except the `wx` application can be cross compiled. +The build of the `wx` driver will currently be automatically disabled when +cross compiling. + +### Compatibility ### + +The build system, including cross compilation configuration variables used, +may be subject to non backward compatible changes without prior notice. +Current cross build system has been tested when cross compiling some Linux/GNU +systems, but has only been partly tested for more esoteric platforms. The +VxWorks example file is highly dependent on our environment and is here more +or less only for internal use. + +### Patches ### + +Please submit any patches for cross compiling in a way consistent with this +system. All input is welcome as we have a very limited set of cross compiling +environments to test with. If a new configuration variable is needed, add it +to `$ERL_TOP/xcomp/erl-xcomp.conf.template`, and use it in `configure.in`. +Other files that might need to be updated are: + +- `$ERL_TOP/xcomp/erl-xcomp-vars.sh` +- `$ERL_TOP/erl-build-tool-vars.sh` +- `$ERL_TOP/erts/aclocal.m4` +- `$ERL_TOP/xcomp/README.md` +- `$ERL_TOP/xcomp/erl-xcomp-*.conf` + +Note that this might be an incomplete list of files that need to be updated. + +General information on how to submit patches can be found at: + <http://wiki.github.com/erlang/otp/submitting-patches> + +Build and Install Procedure +--------------------------- + +If you are building in Git, you want to read the [Building in Git][] section +of [$ERL_TOP/HOWTO/INSTALL.md][] before proceeding. + +We will first go through the `configure`/`make` build procedure which people +probably are most familiar with. + +### Building With configure/make Directly ### + + (1) + +Change directory into the top directory of the Erlang/OTP source tree. + + $ cd $ERL_TOP + +In order to compile Erlang code, a small Erlang bootstrap system has to be +built, or an Erlang/OTP system of the same release as the one being built +has to be provided in the `$PATH`. The Erlang/OTP for the target system will +be built using this Erlang system, together with the cross compilation tools +provided. + +If you want to build the documentation out of the same source tree as you are +cross compiling in, you currently need a full Erlang/OTP system of the same +release as the one being built for the build machine. If this is the case, +build and install one for the build machine (or use one already built) and add +it to the `$PATH` before cross building, and building the documentation. See +the [How to Build the Documentation][] section in the [$ERL_TOP/HOWTO/INSTALL.md][] +document for information on how to build the documentation. + +If you want to build using a compatible Erlang/OTP system in the `$PATH`, +jump to (3). + +#### Building a Bootstrap System #### + + (2) + + $ ./configure --enable-bootstrap-only + $ make + +The `--enable-bootstrap-only` argument to `configure` isn't strictly necessary, +but will speed things up. It will only run `configure` in applications +necessary for the bootstrap, and will disable a lot of things not needed by +the bootstrap system. If you run `configure` without `--enable-boostrap-only` +you also have to run make as `make bootstrap`; otherwise, the whole system will +be built. + +#### Cross Building the System #### + + (3) + + $ ./configure --host=<HOST> --build=<BUILD> [Other Config Args] + $ make + +`<HOST>` is the host/target system that you build for. It does not have to be +a full `CPU-VENDOR-OS` triplet, but can be. The full `CPU-VENDOR-OS` triplet +will be created by executing `$ERL_TOP/erts/autoconf/config.sub <HOST>`. If +`config.sub` fails, you need to be more specific. + +`<BUILD>` should equal the `CPU-VENDOR-OS` triplet of the system that you +build on. If you execute `$ERL_TOP/erts/autoconf/config.guess`, it will in +most cases print the triplet you want to use for this. + +Pass the cross compilation variables as command line arguments to `configure` +using a `<VARIABLE>=<VALUE>` syntax. + +> *NOTE*: You can *not* pass a configuration file using the `--xcomp-conf` +> argument when you invoke `configure` directly. The `--xcomp-conf` argument +> can only be passed to `otp_build configure`. + +`make` will verify that the Erlang/OTP system used when building is of the +same release as the system being built, and will fail if this is not the case. +It is possible, however not recommended, to force the cross compilation even +though the wrong Erlang/OTP system is used. This by invoking `make` like this: +`make ERL_XCOMP_FORCE_DIFFERENT_OTP=yes`. + +> *WARNING*: Invoking `make ERL_XCOMP_FORCE_DIFFERENT_OTP=yes` might fail, +> silently produce suboptimal code, or silently produce erroneous code. + +#### Installing #### + +You can either install using the installation paths determined by `configure` +(4), or install manually using (5). + +##### Installing Using Paths Determined by configure ##### + + (4) + + $ make install DESTDIR=<TEMPORARY_PREFIX> + +`make install` will install at a location specified when doing `configure`. +`configure` arguments specifying where the installation should reside are for +example: `--prefix`, `--exec-prefix`, `--libdir`, `--bindir`, etc. By default +it will install under `/usr/local`. You typically do not want to install your +cross build under `/usr/local` on your build machine. Using [DESTDIR][] +will cause the installation paths to be prefixed by `$DESTDIR`. This makes it +possible to install and package the installation on the build machine without +having to place the installation in the same directory on the build machine as +it should be executed from on the target machine. + +When `make install` has finished, change directory into `$DESTDIR`, package +the system, move it to the target machine, and unpack it. Note that the +installation will only be working on the target machine at the location +determined by `configure`. + +##### Installing Manually ##### + + (5) + + $ make release RELEASE_ROOT=<RELEASE_DIR> + +`make release` will copy what you have built for the target machine to +`<RELEASE_DIR>`. The `Install` script will not be run. The content of +`<RELEASE_DIR>` is what by default ends up in `/usr/local/lib/erlang`. + +The `Install` script used when installing Erlang/OTP requires common Unix +tools such as `sed` to be present in your `$PATH`. If your target system +does not have such tools, you need to run the `Install` script on your +build machine before packaging Erlang/OTP. The `Install` script should +currently be invoked as follows in the directory where it resides +(the top directory): + + $ ./Install [-cross] [-minimal|-sasl] <ERL_ROOT> + +where: + +* `-minimal` Creates an installation that starts up a minimal amount + of applications, i.e., only `kernel` and `stdlib` are started. The + minimal system is normally enough, and is what `make install` uses. +* `-sasl` Creates an installation that also starts up the `sasl` + application. +* `-cross` For cross compilation. Informs the install script that it + is run on the build machine. +* `<ERL_ROOT>` - The absolute path to the Erlang installation to use + at run time. This is often the same as the current working directory, + but does not have to be. It can follow any other path through the file + system to the same directory. + +If neither `-minimal`, nor `-sasl` is passed as argument you will be +prompted. + +You can now either do: + + (6) + +* Decide where the installation should be located on the target machine, + run the `Install` script on the build machine, and package the installed + installation. The installation just need to be unpacked at the right + location on the target machine: + + $ cd <RELEASE_DIR> + $ ./Install -cross [-minimal|-sasl] <ABSOLUTE_INSTALL_DIR_ON_TARGET> + +or: + + (7) + +* Package the installation in `<RELEASE_DIR>`, place it wherever you want + on your target machine, and run the `Install` script on your target + machine: + + $ cd <ABSOLUTE_INSTALL_DIR_ON_TARGET> + $ ./Install [-minimal|-sasl] <ABSOLUTE_INSTALL_DIR_ON_TARGET> + +### Building With the otp\_build Script ### + + (8) + + $ cd $ERL_TOP + + (9) + + $ ./otp_build configure --xcomp-conf=<FILE> [Other Config Args] + +alternatively: + + $ ./otp_build configure --host=<HOST> --build=<BUILD> [Other Config Args] + +If you have your cross compilation configuration in a file, pass it using the +`--xcomp-conf=<FILE>` command line argument. If not, pass `--host=<HOST>`, +`--build=<BUILD>`, and the configuration variables using a `<VARIABLE>=<VALUE>` +syntax on the command line (same as in (3)). Note that `<HOST>` and `<BUILD>` +have to be passed one way or the other; either by using `erl_xcomp_host=<HOST>` +and `erl_xcomp_build=<BUILD>` in the configuration file, or by using the +`--host=<HOST>`, and `--build=<BUILD>` command line arguments. + +`otp_build configure` will configure both for the boostrap system on the +build machine and the cross host system. + + (10) + + $ ./otp_build boot -a + +`otp_build boot -a` will first build a bootstrap system for the build machine +and then do the cross build of the system. + + (11) + + $ ./otp_build release -a <RELEASE_DIR> + +`otp_build release -a` will do the same as (5), and you will after this have +to do a manual install either by doing (6), or (7). + +Testing the cross compiled system +--------------------------------- +Some of the tests that come with erlang use native code to test. This means +that when cross compiling erlang you also have to cross compile test suites +in order to run tests on the target host. To do this you first have to release +the tests as usual. + + $ make release_tests + +or + + $ ./otp_build tests + +The tests will be released into `$ERL_TOP/release/tests`. After releasing the +tests you have to install the tests on the build machine. You supply the same +xcomp file as to `./otp_build` in (9). + + $ cd $ERL_TOP/release/tests/test_server/ + $ $ERL_TOP/bootstrap/bin/erl -eval 'ts:install([{xcomp,"<FILE>"}])' -s ts compile_testcases -s init stop + +You should get a lot of printouts as the testcases are compiled. Once done you +should copy the entire `$ERL_TOP/release/tests` folder to the cross host system. + +Then go to the cross host system and setup the erlang installed in (4) or (5) +to be in your `$PATH`. Then go to what previously was +`$ERL_TOP/release/tests/test_server` and issue the following command. + + $ erl -s ts install -s ts run all_tests -s init stop + +The configure should be skipped and all tests should hopefully pass. For more +details about how to use ts run `erl -s ts help -s init stop` + +Currently Used Configuration Variables +-------------------------------------- + +Note that you cannot define arbitrary variables in a cross compilation +configuration file. Only the ones listed below will be guaranteed to be +visible throughout the whole execution of all `configure` scripts. Other +variables needs to be defined as arguments to `configure` or exported in +the environment. + +### Variables for otp\_build Only ### + +Variables in this section are only used, when configuring Erlang/OTP for +cross compilation using `$ERL_TOP/otp_build configure`. + +> *NOTE*: These variables currently have *no* effect if you configure using +> the `configure` script directly. + +* `erl_xcomp_build` - The build system used. This value will be passed as + `--build=$erl_xcomp_build` argument to the `configure` script. It does + not have to be a full `CPU-VENDOR-OS` triplet, but can be. The full + `CPU-VENDOR-OS` triplet will be created by + `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_build`. If set to `guess`, + the build system will be guessed using + `$ERL_TOP/erts/autoconf/config.guess`. + +* `erl_xcomp_host` - Cross host/target system to build for. This value will + be passed as `--host=$erl_xcomp_host` argument to the `configure` script. + It does not have to be a full `CPU-VENDOR-OS` triplet, but can be. The + full `CPU-VENDOR-OS` triplet will be created by + `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_host`. + +* `erl_xcomp_configure_flags` - Extra configure flags to pass to the + `configure` script. + +### Cross Compiler and Other Tools ### + +If the cross compilation tools are prefixed by `<HOST>-` you probably do +not need to set these variables (where `<HOST>` is what has been passed as +`--host=<HOST>` argument to `configure`). + +All variables in this section can also be used when native compiling. + +* `CC` - C compiler. + +* `CFLAGS` - C compiler flags. + +* `STATIC_CFLAGS` - Static C compiler flags. + +* `CFLAG_RUNTIME_LIBRARY_PATH` - This flag should set runtime library + search path for the shared libraries. Note that this actually is a + linker flag, but it needs to be passed via the compiler. + +* `CPP` - C pre-processor. + +* `CPPFLAGS` - C pre-processor flags. + +* `CXX` - C++ compiler. + +* `CXXFLAGS` - C++ compiler flags. + +* `LD` - Linker. + +* `LDFLAGS` - Linker flags. + +* `LIBS` - Libraries. + +#### Dynamic Erlang Driver Linking #### + +> *NOTE*: Either set all or none of the `DED_LD*` variables. + +* `DED_LD` - Linker for Dynamically loaded Erlang Drivers. + +* `DED_LDFLAGS` - Linker flags to use with `DED_LD`. + +* `DED_LD_FLAG_RUNTIME_LIBRARY_PATH` - This flag should set runtime library + search path for shared libraries when linking with `DED_LD`. + +#### Large File Support #### + +> *NOTE*: Either set all or none of the `LFS_*` variables. + +* `LFS_CFLAGS` - Large file support C compiler flags. + +* `LFS_LDFLAGS` - Large file support linker flags. + +* `LFS_LIBS` - Large file support libraries. + +#### Other Tools #### + +* `RANLIB` - `ranlib` archive index tool. + +* `AR` - `ar` archiving tool. + +* `GETCONF` - `getconf` system configuration inspection tool. `getconf` is + currently used for finding out large file support flags to use, and + on Linux systems for finding out if we have an NPTL thread library or + not. + +### Cross System Root Locations ### + +* `erl_xcomp_sysroot` - The absolute path to the system root of the cross + compilation environment. Currently, the `crypto`, `odbc`, `ssh` and + `ssl` applications need the system root. These applications will be + skipped if the system root has not been set. The system root might be + needed for other things too. If this is the case and the system root + has not been set, `configure` will fail and request you to set it. + +* `erl_xcomp_isysroot` - The absolute path to the system root for includes + of the cross compilation environment. If not set, this value defaults + to `$erl_xcomp_sysroot`, i.e., only set this value if the include system + root path is not the same as the system root path. + +### Optional Feature, and Bug Tests ### + +These tests cannot (always) be done automatically when cross compiling. You +usually do not need to set these variables. + +> *WARNING*: Setting these variables wrong may cause hard to detect +> runtime errors. If you need to change these values, *really* make sure +> that the values are correct. + +> *NOTE*: Some of these values will override results of tests performed +> by `configure`, and some will not be used until `configure` is sure that +> it cannot figure the result out. + +The `configure` script will issue a warning when a default value is used. +When a variable has been set, no warning will be issued. + +* `erl_xcomp_after_morecore_hook` - `yes|no`. Defaults to `no`. If `yes`, + the target system must have a working `__after_morecore_hook` that can be + used for tracking used `malloc()` implementations core memory usage. + This is currently only used by unsupported features. + +* `erl_xcomp_bigendian` - `yes|no`. No default. If `yes`, the target system + must be big endian. If `no`, little endian. This can often be + automatically detected, but not always. If not automatically detected, + `configure` will fail unless this variable is set. Since no default + value is used, `configure` will try to figure this out automatically. + +* `erl_xcomp_clock_gettime_cpu_time` - `yes|no`. Defaults to `no`. If `yes`, + the target system must have a working `clock_gettime()` implementation + that can be used for retrieving process CPU time. + +* `erl_xcomp_getaddrinfo` - `yes|no`. Defaults to `no`. If `yes`, the target + system must have a working `getaddrinfo()` implementation that can + handle both IPv4 and IPv6. + +* `erl_xcomp_gethrvtime_procfs_ioctl` - `yes|no`. Defaults to `no`. If `yes`, + the target system must have a working `gethrvtime()` implementation and + is used with procfs `ioctl()`. + +* `erl_xcomp_dlsym_brk_wrappers` - `yes|no`. Defaults to `no`. If `yes`, the + target system must have a working `dlsym(RTLD_NEXT, <S>)` implementation + that can be used on `brk` and `sbrk` symbols used by the `malloc()` + implementation in use, and by this track the `malloc()` implementations + core memory usage. This is currently only used by unsupported features. + +* `erl_xcomp_kqueue` - `yes|no`. Defaults to `no`. If `yes`, the target + system must have a working `kqueue()` implementation that returns a file + descriptor which can be used by `poll()` and/or `select()`. If `no` and + the target system has not got `epoll()` or `/dev/poll`, the kernel-poll + feature will be disabled. + +* `erl_xcomp_linux_clock_gettime_correction` - `yes|no`. Defaults to `yes` on + Linux; otherwise, `no`. If `yes`, `clock_gettime(CLOCK_MONOTONIC, _)` on + the target system must work. This variable is recommended to be set to + `no` on Linux systems with kernel versions less than 2.6. + +* `erl_xcomp_linux_nptl` - `yes|no`. Defaults to `yes` on Linux; otherwise, + `no`. If `yes`, the target system must have NPTL (Native POSIX Thread + Library). Older Linux systems have LinuxThreads instead of NPTL (Linux + kernel versions typically less than 2.6). + +* `erl_xcomp_linux_usable_sigaltstack` - `yes|no`. Defaults to `yes` on Linux; + otherwise, `no`. If `yes`, `sigaltstack()` must be usable on the target + system. `sigaltstack()` on Linux kernel versions less than 2.4 are + broken. + +* `erl_xcomp_linux_usable_sigusrx` - `yes|no`. Defaults to `yes`. If `yes`, + the `SIGUSR1` and `SIGUSR2` signals must be usable by the ERTS. Old + LinuxThreads thread libraries (Linux kernel versions typically less than + 2.2) used these signals and made them unusable by the ERTS. + +* `erl_xcomp_poll` - `yes|no`. Defaults to `no` on Darwin/MacOSX; otherwise, + `yes`. If `yes`, the target system must have a working `poll()` + implementation that also can handle devices. If `no`, `select()` will be + used instead of `poll()`. + +* `erl_xcomp_putenv_copy` - `yes|no`. Defaults to `no`. If `yes`, the target + system must have a `putenv()` implementation that stores a copy of the + key/value pair. + +* `erl_xcomp_reliable_fpe` - `yes|no`. Defaults to `no`. If `yes`, the target + system must have reliable floating point exceptions. + +Copyright and License +--------------------- + +%CopyrightBegin% + +Copyright Ericsson AB 2009-2010. All Rights Reserved. + +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +%CopyrightEnd% + +Modifying This Document +----------------------- + +Before modifying this document you need to have a look at the +[$ERL_TOP/HOWTO/MARKDOWN.md][] document. + + + + [$ERL_TOP/HOWTO/INSTALL.md]: INSTALL.md + [Building in Git]: INSTALL.md#How-to-Build-and-Install-ErlangOTP_Building-in-Git + [How to Build the Documentation]: INSTALL.md#The-ErlangOTP-Documentation_How-to-Build-the-Documentation + [cross configuration variables]: #Currently-Used-Configuration-Variables + [DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html + [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md + + [?TOC]: true diff --git a/INSTALL-WIN32.md b/HOWTO/INSTALL-WIN32.md index ff253d3dfa..94d3688f23 100644 --- a/INSTALL-WIN32.md +++ b/HOWTO/INSTALL-WIN32.md @@ -1037,10 +1037,11 @@ Modifying This Document ----------------------- Before modifying this document you need to have a look at the -`$ERL_TOP/README.md.txt` document. +[$ERL_TOP/HOWTO/MARKDOWN.md][] document. [1]: http://www.erlang.org/faq.html "mailing lists" + [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md [?TOC]: true diff --git a/INSTALL.md b/HOWTO/INSTALL.md index 34dd9fed8e..4f7c317a47 100644 --- a/INSTALL.md +++ b/HOWTO/INSTALL.md @@ -18,10 +18,10 @@ Erlang/OTP should be possible to build from source on any Unix system, including Mac OS X. This document describes how to native compile Erlang/OTP on Unix. For detailed instructions on how to -* cross compile Erlang/OTP, see the [$ERL_TOP/INSTALL-CROSS.md][] +* cross compile Erlang/OTP, see the [$ERL_TOP/HOWTO/INSTALL-CROSS.md][] document. -* build Erlang/OTP on Windows, see the [$ERL_TOP/INSTALL-WIN32.md][] +* build Erlang/OTP on Windows, see the [$ERL_TOP/HOWTO/INSTALL-WIN32.md][] document. Binary releases for Windows can be found at @@ -825,12 +825,12 @@ Modifying This Document ----------------------- Before modifying this document you need to have a look at the -`$ERL_TOP/README.md.txt` document. +[$ERL_TOP/HOWTO/MARKDOWN.md][] document. - [$ERL_TOP/INSTALL-CROSS.md]: INSTALL-CROSS - [$ERL_TOP/INSTALL-WIN32.md]: INSTALL-WIN32 + [$ERL_TOP/HOWTO/INSTALL-CROSS.md]: INSTALL-CROSS.md + [$ERL_TOP/HOWTO/INSTALL-WIN32.md]: INSTALL-WIN32.md [DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html [Building in Git]: #How-to-Build-and-Install-ErlangOTP_Building-in-Git [Pre-built Source Release]: #How-to-Build-and-Install-ErlangOTP_Prebuilt-Source-Release @@ -838,5 +838,6 @@ Before modifying this document you need to have a look at the [html documentation]: http://www.erlang.org/download/otp_doc_html_%OTP-REL%.tar.gz [man pages]: http://www.erlang.org/download/otp_doc_man_%OTP-REL%.tar.gz [the released source tar ball]: http://www.erlang.org/download/otp_src_%OTP-REL%.tar.gz + [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md [?TOC]: true diff --git a/README.md.txt b/HOWTO/MARKDOWN.md index a5a1bf4b7d..42045fb10c 100644 --- a/README.md.txt +++ b/HOWTO/MARKDOWN.md @@ -5,7 +5,7 @@ Introduction ------------ If you are looking for information on how to build and install Erlang/OTP you -want to read the [$ERL_TOP/INSTALL.md][] document instead of this document +want to read the [$ERL_TOP/HOWTO/INSTALL.md][] document instead of this document (where `$ERL_TOP` is the top source directory in the source tree). All files with the `.md` suffix (as well as this file) are ordinary text files @@ -258,7 +258,7 @@ under the License. - [$ERL_TOP/INSTALL.md]: doc/installation_guide:INSTALL + [$ERL_TOP/HOWTO/INSTALL.md]: INSTALL.md [github]: http://github.com [our github repository]: http://github.com/erlang/otp diff --git a/HOWTO/SYSTEMTAP.md b/HOWTO/SYSTEMTAP.md new file mode 100644 index 0000000000..ce9c0b2f0c --- /dev/null +++ b/HOWTO/SYSTEMTAP.md @@ -0,0 +1,75 @@ +SystemTap and Erlang/OTP +======================== + +Introduction +------------ + +SystemTap is DTrace for Linux. In fact Erlang's SystemTap support +is build using SystemTap's DTrace compatibility's layer. For an +introduction to Erlang DTrace support read [$ERL_TOP/HOWTO/DTRACE.md][]. + +Requisites +---------- + +* Linux Kernel with UTRACE support + + check for UTRACE support in your current kernel: + + # grep CONFIG_UTRACE /boot/config-`uname -r` + CONFIG_UTRACE=y + + Fedora 16 is known to contain UTRACE, for most other Linux distributions + a custom build kernel will be required. + Check Fedora's SystemTap documentation for additional required packages + (e.g. Kernel Debug Symbols) + +* SystemTap > 1.6 + + A the time of writing this, the latest released version of SystemTap is + version 1.6. Erlang's DTrace support requires a MACRO that was introduced + after that release. So either get a newer release or build SystemTap from + git yourself (see: http://sourceware.org/systemtap/getinvolved.html) + +Building Erlang +--------------- + +Configure and build Erlang with SystemTap support: + + # ./configure --with-dynamic-trace=systemtap + whatever args you need + # make + +Testing +------- + +SystemTap, unlike DTrace, needs to know what binary it is tracing and has to +be able to read that binary before it starts tracing. Your probe script +therefor has to reference the correct beam emulator and stap needs to be able +to find that binary. +The examples are written for "beam", but other versions such as "beam.smp" or +"beam.debug.smp" might exist (depending on your configuration). Make sure you +either specify the full the path of the binary in the probe or your "beam" +binary is in the search path. + +All available probes can be listed like this: + + # stap -L 'process("beam").mark("*")' + +or: + + # PATH=/path/to/beam:$PATH stap -L 'process("beam").mark("*")' + + +Probes in the dtrace.so NIF library like this: + + # PATH=/path/to/dtrace/priv/lib:$PATH stap -L 'process("dtrace.so").mark("*")' + +Running SystemTap scripts +------------------------- + +Adjust the process("beam") reference to your beam version and attach the script +to a running "beam" instance: + + # stap /path/to/probe/script/port1.systemtap -x <pid of beam> + + + [$ERL_TOP/HOWTO/DTRACE.md]: DTRACE.md diff --git a/HOWTO/TESTING.md b/HOWTO/TESTING.md new file mode 100644 index 0000000000..34eaa68df8 --- /dev/null +++ b/HOWTO/TESTING.md @@ -0,0 +1,150 @@ +Testing Erlang/OTP +================== + +Before you start testing you need to have the Erlang release which you +are going to test in your path. See [$ERL_TOP/HOWTO/INSTALL.md][] for +instructions on how to build an Erlang release. + +Short version +------------- +Move to the top directory of the Erlang release you want to test, i.e. +cd /ldisk/work/otp + + export ERL_TOP=`pwd` + ./otp_build setup -a + export PATH=`pwd`/bin:$PATH + ./otp_build tests + cd release/tests/test_server + erl -s ts install -s ts run all_tests -s init stop + +Where are the tests +------------------- + +There are a lot of tests which test Erlang/OTP (as of 2012 about 12000) and +they are located in different places throughout the source tree. Below is a list +of the places where you can expect to find tests: + +* $ERL_TOP/lib/AppName/test/ +* $ERL_TOP/erts/test/ +* $ERL_TOP/erts/emulator/test/ +* $ERL_TOP/erts/epmd/test/ + +Writing tests +------------- + +All tests are [common_test][] suites and follow the same pattern as all +[common_test][] suites. However, a couple of corner cases are +handled by a test wrapper called `ts`. `ts` allows the test writer to put +`Makefile.src` and `Makefile.first` files in the [data_dir][] and a special +directory called `all_SUITE_data`. + +`Makefile.first` is run before any other Makefile and is typically used to +generate .hrl files which are needed by other test suites. At the moment only +the erl_interface tests use this feature and it should remain that way. + +`Makefile.src` is configured to a `Makefile` using the `variables` created when +[configuring the tests][]. These `Makefile`s are later run by the test suite +to compile whatever platform specific code the tests need to run. + +Releasing tests +--------------- + +If you cannot use [ct_run][] in the source tree you have to release the tests +into a common test directory. The easiest way to do this is to use `otp_build` +like this: + + export ERL_TOP=`pwd`; ./otp_build tests + +This will release all tests in Erlang/OTP to `$ERL_TOP/release/tests/`. If you +want to change the directory where the tests are released to use the `TESTROOT` +environmental variable. + +In the `$TESTROOT` you should now see *_test folders. These folders contain +everything needed to test Erlang/OTP and are platform independent; if you are +testing Erlang on multiple platforms you just have to release on one and copy +the tests to all other platforms. + +### Releasing cross tests + +For releasing tests in a cross compilation environment see [$ERL_TOP/HOWTO/INSTALL-CROSS.md][]. + +Configuring and Running tests +----------------------------- + +Running tests is done by first navigating to the `$TESTROOT/test_server` folder +created when you released the tests and then start `erl` in that directory. The +emulator flags specified will be used in the test runs. For example, if you want +to test using async threads you have to supply `+A 10` to `erl` when you start it. + +To configure and run the tests `ts` is used. `ts` is a wrapper module to +[common_test][] which takes care of configuration and build issues before +[common_test][] is started. + +`ts` has a lot of special options and functions which can be usefull when +testing Erlang/OTP. For a full listing issue `ts:help()` in the erlang shell. + +### Configuring the test environment + +Before running released tests you have to install them on the target system. +Installing the tests is done by calling `ts:install().` in the Erlang shell +which you intend to test from. `ts:install()` is basically a wrapper to a +configure script and some Erlang code which figures out what your system looks +like and what kind of emulator you are testing with. `ts:install()` can also +take some arguments if necessary, see `ts:help()` for details. + +All variables created by `ts:install()` are found in +`$TESTROOT/test_server/variables`. + +### Running the tests + +To run all test suites go to `$TESTROOT/test_server` fire up an Erlang shell and type: + + ts:run(). + +Note that running all tests will require several hours, so you may want to run +the test cases for a single application + + ts:run(Application, [batch]). + +or even part of the test suite for an application, for example + + ts:run(emulator, bs, [batch]). + +to run all test suite modules starting with `bs` (i.e. all modules that test +the bit syntax). + +To run a specific test case in a module, the full name of the module and test +case must be specified: + + ts:run(emulator, bs_bincomp_SUITE, byte_aligned, [batch]). + +Run `ts:help().` for more information. + +As of R14B02 it is also possibly to start all tests but the erl_interface tests +by invoking Common Test directly from the released applications test directory, +i.e. + + cd $TESTROOT/test_server + $ERL_TOP/bin/ct_run -suite ../compiler_test/andor_SUITE -case t_orelse + +Running [ct_run][] from the command line still requires you to do the +`ts:install()` step above. + +Examining the results +--------------------- + +Open the file `release/tests/test_server/index.html` in a web browser. Or open +`release/tests/test_server/last_test.html` when a test suite is running to +examine the results so far for the currently executing test suite (in R14B02 and +later you want to open the `release/tests/test_server/all_runs.html` file to +get to the currently running test) + + [ct_run]: http://www.erlang.org/doc/man/ct_run.html + [ct hook]: http://www.erlang.org/doc/apps/common_test/ct_hooks_chapter.html + [$ERL_TOP/HOWTO/INSTALL.md]: INSTALL.md + [$ERL_TOP/HOWTO/INSTALL-CROSS.md]: INSTALL-CROSS.md#testing-the-cross-compiled-system + [common_test]: http://www.erlang.org/doc/man/ct.html + [data_dir]: http://www.erlang.org/doc/apps/common_test/write_test_chapter.html#data_priv_dir + [configuring the tests]: #configuring-the-test-environment + + [?TOC]: true diff --git a/INSTALL-CROSS.md b/INSTALL-CROSS.md deleted file mode 120000 index 9e7743b9de..0000000000 --- a/INSTALL-CROSS.md +++ /dev/null @@ -1 +0,0 @@ -xcomp/README.md
\ No newline at end of file @@ -18,7 +18,7 @@ Building and Installing ----------------------- Information on building and installing Erlang/OTP can be found -in the `INSTALL.md` document. +in the [$ERL_TOP/HOWTO/INSTALL.md] [5] document. Contributing to Erlang/OTP -------------------------- @@ -46,7 +46,7 @@ In short: may suggest improvements that are needed before the change can be accepted and merged. -* Once or twice a week, a status email called "What's cooking in Erlang/OTP" +* Once or twice a week, a status email called ["What's cooking in Erlang/OTP"] [4] will be sent to the [`erlang-patches`] [3] mailing list. Copyright and License @@ -73,4 +73,6 @@ Copyright and License [1]: http://www.erlang.org [2]: http://wiki.github.com/erlang/otp/submitting-patches - [3]: http://www.erlang.org/faq.html + [3]: http://www.erlang.org/faq/faq.html + [4]: http://erlang.github.com/otp/ + [5]: HOWTO/INSTALL.md diff --git a/README.systemtap.md b/README.systemtap.md deleted file mode 100644 index c190bcc893..0000000000 --- a/README.systemtap.md +++ /dev/null @@ -1,72 +0,0 @@ -SystemTap and Erlang/OTP -======================== - -Introduction ------------- - -SystemTap is DTrace for Linux. In fact Erlang's SystemTap support -is build using SystemTap's DTrace compatibility's layer. For an -introduction to Erlang DTrace support read README.dtrace.md. - -Requisites ----------- - -* Linux Kernel with UTRACE support - - check for UTRACE support in your current kernel: - - # grep CONFIG_UTRACE /boot/config-`uname -r` - CONFIG_UTRACE=y - - Fedora 16 is known to contain UTRACE, for most other Linux distributions - a custom build kernel will be required. - Check Fedora's SystemTap documentation for additional required packages - (e.g. Kernel Debug Symbols) - -* SystemTap > 1.6 - - A the time of writing this, the latest released version of SystemTap is - version 1.6. Erlang's DTrace support requires a MACRO that was introduced - after that release. So either get a newer release or build SystemTap from - git yourself (see: http://sourceware.org/systemtap/getinvolved.html) - -Building Erlang ---------------- - -Configure and build Erlang with SystemTap support: - - # ./configure --with-dynamic-trace=systemtap + whatever args you need - # make - -Testing -------- - -SystemTap, unlike DTrace, needs to know what binary it is tracing and has to -be able to read that binary before it starts tracing. Your probe script -therefor has to reference the correct beam emulator and stap needs to be able -to find that binary. -The examples are written for "beam", but other versions such as "beam.smp" or -"beam.debug.smp" might exist (depending on your configuration). Make sure you -either specify the full the path of the binary in the probe or your "beam" -binary is in the search path. - -All available probes can be listed like this: - - # stap -L 'process("beam").mark("*")' - -or: - - # PATH=/path/to/beam:$PATH stap -L 'process("beam").mark("*")' - - -Probes in the dtrace.so NIF library like this: - - # PATH=/path/to/dtrace/priv/lib:$PATH stap -L 'process("dtrace.so").mark("*")' - -Running SystemTap scripts -------------------------- - -Adjust the process("beam") reference to your beam version and attach the script -to a running "beam" instance: - - # stap /path/to/probe/script/port1.systemtap -x <pid of beam> diff --git a/TAR.include b/TAR.include index 5146458eea..87854d24c7 100644 --- a/TAR.include +++ b/TAR.include @@ -2,10 +2,10 @@ AUTHORS EPLICENCE Makefile.in README.md -README.md.txt -INSTALL.md -INSTALL-CROSS.md -INSTALL-WIN32.md +HOWTO/MARKDOWN.md +HOWTO/INSTALL.md +HOWTO/INSTALL-CROSS.md +HOWTO/INSTALL-WIN32.md configure.in aclocal.m4 otp_build diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot Binary files differindex 3d2153e66d..c6ebc852a2 100644 --- a/bootstrap/bin/start.boot +++ b/bootstrap/bin/start.boot diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot Binary files differindex 3d2153e66d..c6ebc852a2 100644 --- a/bootstrap/bin/start_clean.boot +++ b/bootstrap/bin/start_clean.boot diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app new file mode 100644 index 0000000000..5170231c59 --- /dev/null +++ b/bootstrap/lib/compiler/ebin/compiler.app @@ -0,0 +1,69 @@ +% This is an -*- erlang -*- file. +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +{application, compiler, + [{description, "ERTS CXC 138 10"}, + {vsn, "4.8.1"}, + {modules, [ + beam_asm, + beam_block, + beam_bool, + beam_bsm, + beam_clean, + beam_dead, + beam_dict, + beam_disasm, + beam_except, + beam_flatten, + beam_jump, + beam_listing, + beam_opcodes, + beam_peep, + beam_receive, + beam_split, + beam_trim, + beam_type, + beam_utils, + beam_validator, + cerl, + cerl_clauses, + cerl_inline, + cerl_trees, + compile, + core_scan, + core_lint, + core_parse, + core_pp, + core_lib, + erl_bifs, + rec_env, + sys_core_dsetel, + sys_core_fold, + sys_core_inline, + sys_expand_pmod, + sys_pre_attributes, + sys_pre_expand, + v3_codegen, + v3_core, + v3_kernel, + v3_kernel_pp, + v3_life + ]}, + {registered, []}, + {applications, [kernel, stdlib]}, + {env, []}]}. diff --git a/bootstrap/lib/compiler/ebin/compiler.appup b/bootstrap/lib/compiler/ebin/compiler.appup new file mode 100644 index 0000000000..887d074b16 --- /dev/null +++ b/bootstrap/lib/compiler/ebin/compiler.appup @@ -0,0 +1 @@ +{"4.8.1",[],[]}. diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam Binary files differindex b7e4a46066..f1fd519f50 100644 --- a/bootstrap/lib/kernel/ebin/code.beam +++ b/bootstrap/lib/kernel/ebin/code.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam Binary files differindex 5e286cdd48..1deb5ad05e 100644 --- a/bootstrap/lib/kernel/ebin/disk_log_1.beam +++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam diff --git a/bootstrap/lib/kernel/ebin/erl_ddll.beam b/bootstrap/lib/kernel/ebin/erl_ddll.beam Binary files differindex b909dd2786..4fdec24b11 100644 --- a/bootstrap/lib/kernel/ebin/erl_ddll.beam +++ b/bootstrap/lib/kernel/ebin/erl_ddll.beam diff --git a/bootstrap/lib/kernel/ebin/error_logger.beam b/bootstrap/lib/kernel/ebin/error_logger.beam Binary files differindex e07bef5657..bad3d6211f 100644 --- a/bootstrap/lib/kernel/ebin/error_logger.beam +++ b/bootstrap/lib/kernel/ebin/error_logger.beam diff --git a/bootstrap/lib/kernel/ebin/erts_debug.beam b/bootstrap/lib/kernel/ebin/erts_debug.beam Binary files differindex 83a981cb1d..5c6483e368 100644 --- a/bootstrap/lib/kernel/ebin/erts_debug.beam +++ b/bootstrap/lib/kernel/ebin/erts_debug.beam diff --git a/bootstrap/lib/kernel/ebin/file.beam b/bootstrap/lib/kernel/ebin/file.beam Binary files differindex aa7dcf388d..243be75c43 100644 --- a/bootstrap/lib/kernel/ebin/file.beam +++ b/bootstrap/lib/kernel/ebin/file.beam diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex 028b5215a2..1574686ba6 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam Binary files differindex 65f517ed39..fe2d597723 100644 --- a/bootstrap/lib/kernel/ebin/inet.beam +++ b/bootstrap/lib/kernel/ebin/inet.beam diff --git a/bootstrap/lib/kernel/ebin/inet_config.beam b/bootstrap/lib/kernel/ebin/inet_config.beam Binary files differindex fc1e2c8387..9479212ed0 100644 --- a/bootstrap/lib/kernel/ebin/inet_config.beam +++ b/bootstrap/lib/kernel/ebin/inet_config.beam diff --git a/bootstrap/lib/kernel/ebin/inet_parse.beam b/bootstrap/lib/kernel/ebin/inet_parse.beam Binary files differindex 14ca272933..b74c0ee730 100644 --- a/bootstrap/lib/kernel/ebin/inet_parse.beam +++ b/bootstrap/lib/kernel/ebin/inet_parse.beam diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app new file mode 100644 index 0000000000..48f6250828 --- /dev/null +++ b/bootstrap/lib/kernel/ebin/kernel.app @@ -0,0 +1,120 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% This is an -*- erlang -*- file. +%% +{application, kernel, + [ + {description, "ERTS CXC 138 10"}, + {vsn, "2.16"}, + {modules, [application, + application_controller, + application_master, + application_starter, + auth, + code, + packages, + code_server, + dist_util, + erl_boot_server, + erl_distribution, + erl_reply, + error_handler, + error_logger, + file, + file_server, + file_io_server, + global, + global_group, + global_search, + group, + heart, + hipe_unified_loader, + inet6_tcp, + inet6_tcp_dist, + inet6_udp, + inet6_sctp, + inet_config, + inet_hosts, + inet_gethost_native, + inet_tcp_dist, + kernel, + kernel_config, + net, + net_adm, + net_kernel, + os, + ram_file, + rpc, + user, + user_drv, + user_sup, + disk_log, + disk_log_1, + disk_log_server, + disk_log_sup, + dist_ac, + erl_ddll, + erl_epmd, + erts_debug, + gen_tcp, + gen_udp, + gen_sctp, + inet, + inet_db, + inet_dns, + inet_parse, + inet_res, + inet_tcp, + inet_udp, + inet_sctp, + pg2, + seq_trace, + standard_error, + wrap_log_reader]}, + {registered, [application_controller, + erl_reply, + auth, + boot_server, + code_server, + disk_log_server, + disk_log_sup, + erl_prim_loader, + error_logger, + file_server_2, + fixtable_server, + global_group, + global_name_server, + heart, + init, + kernel_config, + kernel_sup, + net_kernel, + net_sup, + rex, + user, + os_server, + ddll_server, + erl_epmd, + inet_db, + pg2]}, + {applications, []}, + {env, [{error_logger, tty}]}, + {mod, {kernel, []}} + ] +}. diff --git a/erts/test/autoimport_SUITE_data/dummy.txt b/bootstrap/lib/kernel/ebin/kernel.appup index 972643e527..b534b736be 100644 --- a/erts/test/autoimport_SUITE_data/dummy.txt +++ b/bootstrap/lib/kernel/ebin/kernel.appup @@ -1,7 +1,7 @@ -%% +%% -*- erlang -*- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -15,5 +15,13 @@ %% under the License. %% %% %CopyrightEnd% -%% -%% Purpouse: Dummy +{"2.16", + %% Up from - max two major revisions back + [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14 + %% Down to - max two major revisions back + [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14 +}. diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam Binary files differindex a81f3e47d5..9eebd72403 100644 --- a/bootstrap/lib/kernel/ebin/net_kernel.beam +++ b/bootstrap/lib/kernel/ebin/net_kernel.beam diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam Binary files differindex 1291f1cdfa..ea33408b31 100644 --- a/bootstrap/lib/kernel/ebin/os.beam +++ b/bootstrap/lib/kernel/ebin/os.beam diff --git a/bootstrap/lib/stdlib/ebin/binary.beam b/bootstrap/lib/stdlib/ebin/binary.beam Binary files differindex 0cc6c6fce9..255c50aa01 100644 --- a/bootstrap/lib/stdlib/ebin/binary.beam +++ b/bootstrap/lib/stdlib/ebin/binary.beam diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam Binary files differindex 642689d749..cc6521891b 100644 --- a/bootstrap/lib/stdlib/ebin/ets.beam +++ b/bootstrap/lib/stdlib/ebin/ets.beam diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam Binary files differindex 5e23551fb3..dfd689aa5a 100644 --- a/bootstrap/lib/stdlib/ebin/lists.beam +++ b/bootstrap/lib/stdlib/ebin/lists.beam diff --git a/bootstrap/lib/stdlib/ebin/math.beam b/bootstrap/lib/stdlib/ebin/math.beam Binary files differindex e97284ca1e..9b662405ea 100644 --- a/bootstrap/lib/stdlib/ebin/math.beam +++ b/bootstrap/lib/stdlib/ebin/math.beam diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam Binary files differindex 1a9a55dc24..270d35ef33 100644 --- a/bootstrap/lib/stdlib/ebin/otp_internal.beam +++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam Binary files differindex f51bc3ccbd..8a25d95384 100644 --- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam +++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam Binary files differindex 4b9cbb7cfc..e20546d45d 100644 --- a/bootstrap/lib/stdlib/ebin/re.beam +++ b/bootstrap/lib/stdlib/ebin/re.beam diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app new file mode 100644 index 0000000000..461531e1df --- /dev/null +++ b/bootstrap/lib/stdlib/ebin/stdlib.app @@ -0,0 +1,105 @@ +%% This is an -*- erlang -*- file. +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +{application, stdlib, + [{description, "ERTS CXC 138 10"}, + {vsn, "1.19"}, + {modules, [array, + base64, + beam_lib, + binary, + c, + calendar, + dets, + dets_server, + dets_sup, + dets_utils, + dets_v8, + dets_v9, + dict, + digraph, + digraph_utils, + edlin, + edlin_expand, + epp, + eval_bits, + erl_bits, + erl_compile, + erl_eval, + erl_expand_records, + erl_internal, + erl_lint, + erl_parse, + erl_posix_msg, + erl_pp, + erl_scan, + erl_tar, + error_logger_file_h, + error_logger_tty_h, + escript, + ets, + file_sorter, + filelib, + filename, + gb_trees, + gb_sets, + gen, + gen_event, + gen_fsm, + gen_server, + io, + io_lib, + io_lib_format, + io_lib_fread, + io_lib_pretty, + lib, + lists, + log_mf_h, + math, + ms_transform, + orddict, + ordsets, + otp_internal, + pg, + pool, + proc_lib, + proplists, + qlc, + qlc_pt, + queue, + random, + re, + sets, + shell, + shell_default, + slave, + sofs, + string, + supervisor, + supervisor_bridge, + sys, + timer, + unicode, + win32reg, + zip]}, + {registered,[timer_server,rsh_starter,take_over_monitor,pool_master, + dets]}, + {applications, [kernel]}, + {env, []}]}. + diff --git a/bootstrap/lib/stdlib/ebin/stdlib.appup b/bootstrap/lib/stdlib/ebin/stdlib.appup new file mode 100644 index 0000000000..ff9b5387c9 --- /dev/null +++ b/bootstrap/lib/stdlib/ebin/stdlib.appup @@ -0,0 +1,27 @@ +%% -*- erlang -*- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +{"1.19", + %% Up from - max two major revisions back + [{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14 + %% Down to - max two major revisions back + [{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14 +}. diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam Binary files differindex 3ace8184d0..e014257a58 100644 --- a/bootstrap/lib/stdlib/ebin/string.beam +++ b/bootstrap/lib/stdlib/ebin/string.beam diff --git a/bootstrap/lib/stdlib/ebin/unicode.beam b/bootstrap/lib/stdlib/ebin/unicode.beam Binary files differindex 7dcf140730..074fe0534d 100644 --- a/bootstrap/lib/stdlib/ebin/unicode.beam +++ b/bootstrap/lib/stdlib/ebin/unicode.beam diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile index 13cf003aad..e4ccc330b5 100644 --- a/erts/doc/src/Makefile +++ b/erts/doc/src/Makefile @@ -55,7 +55,6 @@ XML_REF3_EFILES = \ XML_REF3_FILES = \ driver_entry.xml \ erl_nif.xml \ - erl_set_memory_block.xml \ erl_driver.xml \ erl_prim_loader.xml \ erlang.xml \ @@ -158,9 +157,6 @@ $(SPECDIR)/specs_driver_entry.xml: $(SPECDIR)/specs_erl_nif.xml: escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module erl_nif -$(SPECDIR)/specs_erl_set_memory_block.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ - -o$(dir $@) -module erl_set_memory_block $(SPECDIR)/specs_erl_driver.xml: escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module erl_driver diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index f8a92e1ec4..6221a239fa 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -586,7 +586,9 @@ <item> <p>Sets the maximum number of concurrent processes for this system. <c><![CDATA[Number]]></c> must be in the range 16..134217727. - Default is 32768.</p> + Default is 32768.</p> + <p><em>NOTE</em>: It is possible to choose any value in the range + but powers of 2 perform best.</p> </item> <tag><marker id="compat_rel"><c><![CDATA[+R ReleaseNumber]]></c></marker></tag> <item> diff --git a/erts/doc/src/erl_set_memory_block.xml b/erts/doc/src/erl_set_memory_block.xml deleted file mode 100644 index d77da56d95..0000000000 --- a/erts/doc/src/erl_set_memory_block.xml +++ /dev/null @@ -1,172 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE cref SYSTEM "cref.dtd"> - -<cref> - <header> - <copyright> - <year>1998</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>erl_set_memory_block</title> - <prepared>Patrik Nyblom</prepared> - <responsible></responsible> - <docno></docno> - <approved></approved> - <checked></checked> - <date>98-08-05</date> - <rev>A</rev> - <file>erl_set_memory_block.xml</file> - </header> - <lib>erl_set_memory_block</lib> - <libsummary>Custom memory allocation for Erlang on VxWorks®</libsummary> - <description> - <p>This documentation is specific to VxWorks.</p> - <p>The <c><![CDATA[erl_set_memory_block]]></c> function/command initiates custom - memory allocation for the Erlang emulator. It has to be called - before the Erlang emulator is started and makes Erlang use one - single large memory block for all memory allocation.</p> - <p>The memory within the block can be utilized by other tasks than - Erlang. This is accomplished by calling the functions - <c><![CDATA[sys_alloc]]></c>, <c><![CDATA[sys_realloc]]></c> and <c><![CDATA[sys_free]]></c> instead - of <c><![CDATA[malloc]]></c>, <c><![CDATA[realloc]]></c> and <c><![CDATA[free]]></c> respectively.</p> - <p>The purpose of this is to avoid problems inherent in the - VxWorks systems <c><![CDATA[malloc]]></c> library. The memory allocation within the - large memory block avoids fragmentation by using an "address - order first fit" algorithm. Another advantage of using a - separate memory block is that resource reclamation can be made - more easily when Erlang is stopped.</p> - <p>The <c><![CDATA[erl_set_memory_block]]></c> function is callable from any C - program as an ordinary 10 argument function as well as - from the commandline.</p> - </description> - <funcs> - <func> - <name><ret>int</ret><nametext>erl_set_memory_block(size_t size, void *ptr, int warn_mixed_malloc, int realloc_always_moves, int use_reclaim, ...)</nametext></name> - <fsummary>Specify parameters for Erlang internal memory allocation.</fsummary> - <desc> - <p>The function is called before Erlang is - started to specify a large memory block where Erlang can - maintain memory internally.</p> - <p>Parameters:</p> - <taglist> - <tag>size_t size</tag> - <item>The size in bytes of Erlang's internal memory block. Has to - be specified. Note that the VxWorks system uses dynamic - memory allocation heavily, so leave some memory to the system.</item> - <tag>void *ptr</tag> - <item> - <p>A pointer to the actual memory block of size - <c><![CDATA[size]]></c>. If this is specified as 0 (NULL), Erlang will - allocate the memory when starting and will reclaim the - memory block (as a whole) when stopped.</p> - <p>If a memory block is allocated and provided here, the - <c><![CDATA[sys_alloc]]></c> etc routines can still be used after - the Erlang emulator is stopped. The Erlang emulator can - also be restarted while other tasks using the memory - block are running without destroying the memory. If - Erlang is to be restarted, also set the - <c><![CDATA[use_reclaim]]></c> flag.</p> - <p>If 0 is specified here, the Erlang system should not - be stopped while some other task uses the memory block - (has called <c><![CDATA[sys_alloc]]></c>).</p> - </item> - <tag>int warn_mixed_malloc</tag> - <item> - <p>If this flag is set to true (anything else than 0), the - system will write a warning message on the console if a - program is mixing normal <c><![CDATA[malloc]]></c> with - <c><![CDATA[sys_realloc]]></c> or <c><![CDATA[sys_free]]></c>.</p> - </item> - <tag>int realloc_always_moves</tag> - <item> - <p>If this flag is set to true (anything else than 0), all - calls to <c><![CDATA[sys_realloc]]></c> result in a moved memory - block. This can in certain conditions give less - fragmentation. This flag may be removed in future releases.</p> - </item> - <tag>int use_reclaim</tag> - <item> - <p>If this flag is set to true (anything else than 0), all - memory allocated with <c><![CDATA[sys_alloc]]></c> is automatically - reclaimed as soon as a task exits. This is very useful - to make writing port programs (and other programs as - well) easier. Combine this with using the routines - <c><![CDATA[save_open]]></c> etc. specified in the reclaim.h - file delivered in the Erlang distribution.</p> - </item> - </taglist> - <p>Return Value:</p> - <p>Returns 0 (OK) on success, otherwise a value <> 0.</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>erl_memory_show(...)</nametext></name> - <fsummary>A utility similar to VxWorks <c><![CDATA[memShow]]></c>, but for the Erlang memory area.</fsummary> - <desc> - <p>Return Value:</p> - <p>Returns 0 (OK) on success, otherwise a value <> 0.</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>erl_mem_info_get(MEM_PART_STATS *stats)</nametext></name> - <fsummary>A utility similar to VxWorks <c><![CDATA[memPartInfoGet]]></c>, but for the Erlang memory area.</fsummary> - <desc> - <p>Parameter:</p> - <taglist> - <tag>MEM_PART_STATS *stats</tag> - <item>A pointer to a MEM_PART_STATS structure as defined in - <c><![CDATA[<memLib.h>]]></c>. A successful call will fill in all - fields of the structure, on error all fields are left untouched. </item> - </taglist> - <p>Return Value:</p> - <p>Returns 0 (OK) on success, otherwise a value <> 0</p> - </desc> - </func> - </funcs> - - <section> - <title>NOTES</title> - <p>The memory block used by Erlang actually does not need to be - inside the area known to ordinary <c><![CDATA[malloc]]></c>. It is possible - to set the <c><![CDATA[USER_RESERVED_MEM]]></c> preprocessor symbol when compiling - the wind kernel and then use user reserved memory for - Erlang. Erlang can therefor utilize memory above the 32 Mb limit - of VxWorks on the PowerPC architecture.</p> - <p>Example:</p> - <p>In config.h for the wind kernel:</p> - <code type="none"><![CDATA[ - #undef LOCAL_MEM_AUTOSIZE - #undef LOCAL_MEM_SIZE - #undef USER_RESERVED_MEM - - #define LOCAL_MEM_SIZE 0x05000000 - #define USER_RESERVED_MEM 0x03000000 - ]]></code> - <p>In the start-up script/code for the VxWorks node:</p> - <code type="none"><![CDATA[ -erl_set_memory_block(sysPhysMemTop()-sysMemTop(),sysMemTop(),0,0,1); - ]]></code> - <p>Setting the <c><![CDATA[use_reclaim]]></c> flag decreases performance of the - system, but makes programming much easier. Other similar - facilities are present in the Erlang system even without using a - separate memory block. The routines called <c><![CDATA[save_malloc]]></c>, - <c><![CDATA[save_realloc]]></c> and <c><![CDATA[save_free]]></c> provide the same - facilities by using VxWorks own <c><![CDATA[malloc]]></c>. Similar routines - exist for files, see the file <c><![CDATA[reclaim.h]]></c> in the distribution.</p> - </section> -</cref> - diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index e69f223897..35ae44f018 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -65,14 +65,14 @@ <funcs> <func> - <name>abs(Number) -> integer() | float()</name> + <name name="abs" arity="1" clause_i="1"/> + <name name="abs" arity="1" clause_i="2"/> + <type variable="Float" name_i="1"/> + <type variable="Int" name_i="2"/> <fsummary>Arithmetical absolute value</fsummary> - <type> - <v>Number = number()</v> - </type> <desc> <p>Returns an integer or float which is the arithmetical - absolute value of <c>Number</c>.</p> + absolute value of <c><anno>Float</anno></c> or <c><anno>Int</anno></c>.</p> <pre> > <input>abs(-3.33).</input> 3.33 @@ -82,26 +82,19 @@ </desc> </func> <func> - <name>erlang:adler32(Data) -> integer()</name> + <name name="adler32" arity="1"/> <fsummary>Compute adler32 checksum</fsummary> - <type> - <v>Data = iodata()</v> - </type> <desc> - <p>Computes and returns the adler32 checksum for <c>Data</c>.</p> + <p>Computes and returns the adler32 checksum for <c><anno>Data</anno></c>.</p> </desc> </func> <func> - <name>erlang:adler32(OldAdler, Data) -> integer()</name> + <name name="adler32" arity="2"/> <fsummary>Compute adler32 checksum</fsummary> - <type> - <v>OldAdler = integer()</v> - <v>Data = iodata()</v> - </type> <desc> <p>Continue computing the adler32 checksum by combining - the previous checksum, <c>OldAdler</c>, with the checksum of - <c>Data</c>.</p> + the previous checksum, <c><anno>OldAdler</anno></c>, with the checksum of + <c><anno>Data</anno></c>.</p> <p>The following code:</p> <code> X = erlang:adler32(Data1), @@ -114,12 +107,8 @@ </desc> </func> <func> - <name>erlang:adler32_combine(FirstAdler, SecondAdler, SecondSize) -> integer()</name> + <name name="adler32_combine" arity="3"/> <fsummary>Combine two adler32 checksums</fsummary> - <type> - <v>FirstAdler = SecondAdler = integer()</v> - <v>SecondSize = integer()</v> - </type> <desc> <p>Combines two previously computed adler32 checksums. This computation requires the size of the data object for @@ -138,18 +127,14 @@ </desc> </func> <func> - <name>erlang:append_element(Tuple1, Term) -> Tuple2</name> + <name name="append_element" arity="2"/> <fsummary>Append an extra element to a tuple</fsummary> - <type> - <v>Tuple1 = Tuple2 = tuple()</v> - <v>Term = term()</v> - </type> <desc> <p>Returns a new tuple which has one element more than - <c>Tuple1</c>, and contains the elements in <c>Tuple1</c> - followed by <c>Term</c> as the last element. Semantically + <c><anno>Tuple1</anno></c>, and contains the elements in <c><anno>Tuple1</anno></c> + followed by <c><anno>Term</anno></c> as the last element. Semantically equivalent to - <c>list_to_tuple(tuple_to_list(Tuple) ++ [Term])</c>, but much + <c>list_to_tuple(tuple_to_list(<anno>Tuple1</anno>) ++ [<anno>Term</anno>])</c>, but much faster.</p> <pre> > <input>erlang:append_element({one, two}, three).</input> @@ -204,27 +189,24 @@ </desc> </func> <func> - <name>atom_to_binary(Atom, Encoding) -> binary()</name> + <name name="atom_to_binary" arity="2"/> <fsummary>Return the binary representation of an atom</fsummary> - <type> - <v>Atom = atom()</v> - <v>Encoding = latin1 | utf8 | unicode</v> - </type> <desc> <p>Returns a binary which corresponds to the text - representation of <c>Atom</c>. If <c>Encoding</c> + representation of <c><anno>Atom</anno></c>. If <c><anno>Encoding</anno></c> is <c>latin1</c>, there will be one byte for each character - in the text representation. If <c>Encoding</c> is <c>utf8</c> or + in the text representation. If <c><anno>Encoding</anno></c> is + <c>utf8</c> or <c>unicode</c>, the characters will be encoded using UTF-8 (meaning that characters from 16#80 up to 0xFF will be encoded in two bytes).</p> - <note><p>Currently, <c>atom_to_binary(Atom, latin1)</c> can + <note><p>Currently, <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> can never fail because the text representation of an atom can only contain characters from 0 to 16#FF. In a future release, the text representation of atoms might be allowed to contain any Unicode character - and <c>atom_to_binary(Atom, latin1)</c> will fail if the - text representation for the <c>Atom</c> contains a Unicode + and <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> will fail if the + text representation for the <c><anno>Atom</anno></c> contains a Unicode character greater than 16#FF.</p></note> <pre> @@ -233,30 +215,21 @@ </desc> </func> <func> - <name>atom_to_list(Atom) -> string()</name> + <name name="atom_to_list" arity="1"/> <fsummary>Text representation of an atom</fsummary> - <type> - <v>Atom = atom()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Atom</c>.</p> + representation of <c><anno>Atom</anno></c>.</p> <pre> > <input>atom_to_list('Erlang').</input> "Erlang"</pre> </desc> </func> <func> - <name>binary_part(Subject, PosLen) -> binary()</name> + <name name="binary_part" arity="2"/> <fsummary>Extracts a part of a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>PosLen = {Start,Length}</v> - <v>Start = integer() >= 0</v> - <v>Length = integer() >= 0</v> - </type> - <desc> - <p>Extracts the part of the binary described by <c>PosLen</c>.</p> + <desc> + <p>Extracts the part of the binary described by <c><anno>PosLen</anno></c>.</p> <p>Negative length can be used to extract bytes at the end of a binary:</p> @@ -266,53 +239,44 @@ <<6,7,8,9,10>> </code> - <p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> + <p>If <c><anno>PosLen</anno></c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> - <p><c>Start</c> is zero-based, i.e.:</p> + <p><c><anno>Start</anno></c> is zero-based, i.e.:</p> <code> 1> Bin = <<1,2,3>> 2> binary_part(Bin,{0,2}). <<1,2>> </code> - <p>See the STDLIB module <c>binary</c> for details about the <c>PosLen</c> semantics.</p> + <p>See the STDLIB module <c>binary</c> for details about the <c><anno>PosLen</anno></c> semantics.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>binary_part(Subject, Start, Length) -> binary()</name> + <name name="binary_part" arity="3"/> <fsummary>Extracts a part of a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Start = integer() >= 0</v> - <v>Length = integer() >= 0</v> - </type> <desc> - <p>The same as <c>binary_part(Subject, {Pos, Len})</c>.</p> + <p>The same as <c>binary_part(<anno>Subject</anno>, {<anno>Start</anno>, <anno>Length</anno>})</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>binary_to_atom(Binary, Encoding) -> atom()</name> + <name name="binary_to_atom" arity="2"/> <fsummary>Convert from text representation to an atom</fsummary> - <type> - <v>Binary = binary()</v> - <v>Encoding = latin1 | utf8 | unicode</v> - </type> <desc> <p>Returns the atom whose text representation is - <c>Binary</c>. If <c>Encoding</c> is <c>latin1</c>, no - translation of bytes in the binary is done. If <c>Encoding</c> + <c><anno>Binary</anno></c>. If <c><anno>Encoding</anno></c> is <c>latin1</c>, no + translation of bytes in the binary is done. If <c><anno>Encoding</anno></c> is <c>utf8</c> or <c>unicode</c>, the binary must contain valid UTF-8 sequences; furthermore, only Unicode characters up to 0xFF are allowed.</p> - <note><p><c>binary_to_atom(Binary, utf8)</c> will fail if + <note><p><c>binary_to_atom(<anno>Binary</anno>, utf8)</c> will fail if the binary contains Unicode characters greater than 16#FF. In a future release, such Unicode characters might be allowed - and <c>binary_to_atom(Binary, utf8)</c> + and <c>binary_to_atom(<anno>Binary</anno>, utf8)</c> will not fail in that case.</p></note> <pre> @@ -325,12 +289,8 @@ </desc> </func> <func> - <name>binary_to_existing_atom(Binary, Encoding) -> atom()</name> + <name name="binary_to_existing_atom" arity="2"/> <fsummary>Convert from text representation to an atom</fsummary> - <type> - <v>Binary = binary()</v> - <v>Encoding = latin1 | utf8 | unicode</v> - </type> <desc> <p>Works like <seealso marker="#binary_to_atom/2">binary_to_atom/2</seealso>, but the atom must already exist.</p> @@ -338,27 +298,21 @@ </desc> </func> <func> - <name>binary_to_list(Binary) -> [char()]</name> + <name name="binary_to_list" arity="1"/> <fsummary>Convert a binary to a list</fsummary> - <type> - <v>Binary = binary()</v> - </type> <desc> <p>Returns a list of integers which correspond to the bytes of - <c>Binary</c>.</p> + <c><anno>Binary</anno></c>.</p> </desc> </func> <func> - <name>binary_to_list(Binary, Start, Stop) -> [char()]</name> + <name name="binary_to_list" arity="3"/> <fsummary>Convert part of a binary to a list</fsummary> - <type> - <v>Binary = binary()</v> - <v>Start = Stop = 1..byte_size(Binary)</v> - </type> + <type_desc variable="Start">1..byte_size(<anno>Binary</anno>)</type_desc> <desc> <p>As <c>binary_to_list/1</c>, but returns a list of integers - corresponding to the bytes from position <c>Start</c> to - position <c>Stop</c> in <c>Binary</c>. Positions in the + corresponding to the bytes from position <c><anno>Start</anno></c> to + position <c><anno>Stop</anno></c> in <c><anno>Binary</anno></c>. Positions in the binary are numbered starting from 1.</p> <note><p>This function's indexing style of using one-based indices for @@ -368,27 +322,21 @@ </desc> </func> <func> - <name>bitstring_to_list(Bitstring) -> [char()|bitstring()]</name> + <name name="bitstring_to_list" arity="1"/> <fsummary>Convert a bitstring to a list</fsummary> - <type> - <v>Bitstring = bitstring()</v> - </type> <desc> <p>Returns a list of integers which correspond to the bytes of - <c>Bitstring</c>. If the number of bits in the binary is not + <c><anno>Bitstring</anno></c>. If the number of bits in the binary is not divisible by 8, the last element of the list will be a bitstring containing the remaining bits (1 up to 7 bits).</p> </desc> </func> <func> - <name>binary_to_term(Binary) -> term()</name> + <name name="binary_to_term" arity="1"/> <fsummary>Decode an Erlang external term format binary</fsummary> - <type> - <v>Binary = <seealso marker="#type-ext_binary">ext_binary()</seealso></v> - </type> <desc> <p>Returns an Erlang term which is the result of decoding - the binary object <c>Binary</c>, which must be encoded + the binary object <c><anno>Binary</anno></c>, which must be encoded according to the Erlang external term format.</p> <warning> <p>When decoding binaries from untrusted sources, consider using @@ -401,12 +349,8 @@ </desc> </func> <func> - <name>binary_to_term(Binary, Opts) -> term()</name> + <name name="binary_to_term" arity="2"/> <fsummary>Decode an Erlang external term format binary</fsummary> - <type> - <v>Opts = [safe]</v> - <v>Binary = <seealso marker="#type-ext_binary">ext_binary()</seealso></v> - </type> <desc> <p>As <c>binary_to_term/1</c>, but takes options that affect decoding of the binary.</p> @@ -436,13 +380,10 @@ </desc> </func> <func> - <name>bit_size(Bitstring) -> integer() >= 0</name> + <name name="bit_size" arity="1"/> <fsummary>Return the size of a bitstring</fsummary> - <type> - <v>Bitstring = bitstring()</v> - </type> <desc> - <p>Returns an integer which is the size in bits of <c>Bitstring</c>.</p> + <p>Returns an integer which is the size in bits of <c><anno>Bitstring</anno></c>.</p> <pre> > <input>bit_size(<<433:16,3:3>>).</input> 19 @@ -452,11 +393,8 @@ </desc> </func> <func> - <name>erlang:bump_reductions(Reductions) -> void()</name> + <name name="bump_reductions" arity="1"/> <fsummary>Increment the reduction counter</fsummary> - <type> - <v>Reductions = integer() >= 0</v> - </type> <desc> <p>This implementation-dependent function increments the reduction counter for the calling process. In the Beam @@ -472,14 +410,11 @@ </desc> </func> <func> - <name>byte_size(Bitstring) -> integer() >= 0</name> + <name name="byte_size" arity="1"/> <fsummary>Return the size of a bitstring (or binary)</fsummary> - <type> - <v>Bitstring = bitstring()</v> - </type> <desc> <p>Returns an integer which is the number of bytes needed to contain - <c>Bitstring</c>. (That is, if the number of bits in <c>Bitstring</c> is not + <c><anno>Bitstring</anno></c>. (That is, if the number of bits in <c><anno>Bitstring</anno></c> is not divisible by 8, the resulting number of bytes will be rounded <em>up</em>.)</p> <pre> > <input>byte_size(<<433:16,3:3>>).</input> @@ -490,21 +425,17 @@ </desc> </func> <func> - <name>erlang:cancel_timer(TimerRef) -> Time | false</name> + <name name="cancel_timer" arity="1"/> <fsummary>Cancel a timer</fsummary> - <type> - <v>TimerRef = reference()</v> - <v>Time = integer() >= 0</v> - </type> <desc> - <p>Cancels a timer, where <c>TimerRef</c> was returned by + <p>Cancels a timer, where <c><anno>TimerRef</anno></c> was returned by either <seealso marker="#send_after/3">erlang:send_after/3</seealso> or <seealso marker="#start_timer/3">erlang:start_timer/3</seealso>. If the timer is there to be removed, the function returns the time in milliseconds left until the timer would have expired, - otherwise <c>false</c> (which means that <c>TimerRef</c> was + otherwise <c>false</c> (which means that <c><anno>TimerRef</anno></c> was never a timer, that it has already been cancelled, or that it has already delivered its message).</p> <p>See also @@ -518,27 +449,20 @@ </func> <func> - <name>check_old_code(Module) -> boolean()</name> + <name name="check_old_code" arity="1"/> <fsummary>Check if a module has old code</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Returns <c>true</c> if the <c>Module</c> has old code, + <p>Returns <c>true</c> if the <c><anno>Module</anno></c> has old code, and <c>false</c> otherwise.</p> <p>See also <seealso marker="kernel:code">code(3)</seealso>.</p> </desc> </func> <func> - <name>check_process_code(Pid, Module) -> boolean()</name> + <name name="check_process_code" arity="2"/> <fsummary>Check if a process is executing old code for a module</fsummary> - <type> - <v>Pid = pid()</v> - <v>Module = atom()</v> - </type> <desc> - <p>Returns <c>true</c> if the process <c>Pid</c> is executing - old code for <c>Module</c>. That is, if the current call of + <p>Returns <c>true</c> if the process <c><anno>Pid</anno></c> is executing + old code for <c><anno>Module</anno></c>. That is, if the current call of the process executes old code for this module, or if the process has references to old code for this module, or if the process contains funs that references old code for this @@ -550,26 +474,19 @@ false</pre> </desc> </func> <func> - <name>erlang:crc32(Data) -> integer() >= 0</name> + <name name="crc32" arity="1"/> <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> - <type> - <v>Data = iodata()</v> - </type> <desc> - <p>Computes and returns the crc32 (IEEE 802.3 style) checksum for <c>Data</c>.</p> + <p>Computes and returns the crc32 (IEEE 802.3 style) checksum for <c><anno>Data</anno></c>.</p> </desc> </func> <func> - <name>erlang:crc32(OldCrc, Data) -> integer() >= 0</name> + <name name="crc32" arity="2"/> <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> - <type> - <v>OldCrc = integer() >= 0</v> - <v>Data = iodata()</v> - </type> <desc> <p>Continue computing the crc32 checksum by combining - the previous checksum, <c>OldCrc</c>, with the checksum of - <c>Data</c>.</p> + the previous checksum, <c><anno>OldCrc</anno></c>, with the checksum of + <c><anno>Data</anno></c>.</p> <p>The following code:</p> <code> X = erlang:crc32(Data1), @@ -582,12 +499,8 @@ false</pre> </desc> </func> <func> - <name>erlang:crc32_combine(FirstCrc, SecondCrc, SecondSize) -> integer() >= 0</name> + <name name="crc32_combine" arity="3"/> <fsummary>Combine two crc32 (IEEE 802.3) checksums</fsummary> - <type> - <v>FirstCrc = SecondCrc = integer() >= 0</v> - <v>SecondSize = integer() >= 0</v> - </type> <desc> <p>Combines two previously computed crc32 checksums. This computation requires the size of the data object for @@ -606,11 +519,8 @@ false</pre> </desc> </func> <func> - <name>date() -> Date</name> + <name name="date" arity="0"/> <fsummary>Current date</fsummary> - <type> - <v>Date = <seealso marker="calendar#type-date">calendar:date()</seealso></v> - </type> <desc> <p>Returns the current date as <c>{Year, Month, Day}</c>.</p> <p>The time zone and daylight saving time correction depend on @@ -621,47 +531,24 @@ false</pre> </desc> </func> <func> - <name>erlang:decode_packet(Type,Bin,Options) -> {ok,Packet,Rest} | {more,Length} | {error,Reason}</name> + <name name="decode_packet" arity="3"/> <fsummary>Extracts a protocol packet from a binary</fsummary> - <type> - <v>Bin = binary()</v> - <v>Options = [Opt]</v> - <v>Packet = binary() | HttpPacket</v> - <v>Rest = binary()</v> - <v>Length = integer() > 0 | undefined</v> - <v>Reason = term()</v> - <v> Type, Opt -- see below</v> - <v></v> - <v>HttpPacket = HttpRequest | HttpResponse | HttpHeader | http_eoh | HttpError</v> - <v>HttpRequest = {http_request, HttpMethod, HttpUri, HttpVersion}</v> - <v>HttpResponse = {http_response, HttpVersion, integer(), HttpString}</v> - <v>HttpHeader = {http_header, integer(), HttpField, Reserved=term(), Value=HttpString}</v> - <v>HttpError = {http_error, HttpString}</v> - <v>HttpMethod = HttpMethodAtom | HttpString</v> - <v>HttpMethodAtom = 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE'</v> - <v>HttpUri = '*' | {absoluteURI, http|https, Host=HttpString, Port=integer()|undefined, Path=HttpString} | - {scheme, Scheme=HttpString, HttpString} | {abs_path, HttpString} | HttpString</v> - <v>HttpVersion = {Major=integer(), Minor=integer()}</v> - <v>HttpString = string() | binary()</v> - <v>HttpField = HttpFieldAtom | HttpString</v> - <v>HttpFieldAtom = 'Cache-Control' | 'Connection' | 'Date' | 'Pragma' | 'Transfer-Encoding' | 'Upgrade' | 'Via' | 'Accept' | 'Accept-Charset' | 'Accept-Encoding' | 'Accept-Language' | 'Authorization' | 'From' | 'Host' | 'If-Modified-Since' | 'If-Match' | 'If-None-Match' | 'If-Range' | 'If-Unmodified-Since' | 'Max-Forwards' | 'Proxy-Authorization' | 'Range' | 'Referer' | 'User-Agent' | 'Age' | 'Location' | 'Proxy-Authenticate' | 'Public' | 'Retry-After' | 'Server' | 'Vary' | 'Warning' | 'Www-Authenticate' | 'Allow' | 'Content-Base' | 'Content-Encoding' | 'Content-Language' | 'Content-Length' | 'Content-Location' | 'Content-Md5' | 'Content-Range' | 'Content-Type' | 'Etag' | 'Expires' | 'Last-Modified' | 'Accept-Ranges' | 'Set-Cookie' | 'Set-Cookie2' | 'X-Forwarded-For' | 'Cookie' | 'Keep-Alive' | 'Proxy-Connection'</v> - <v></v> - </type> - <desc> - <p>Decodes the binary <c>Bin</c> according to the packet - protocol specified by <c>Type</c>. Very similar to the packet - handling done by sockets with the option {packet,Type}.</p> - <p>If an entire packet is contained in <c>Bin</c> it is + <desc> + + <p>Decodes the binary <c><anno>Bin</anno></c> according to the packet + protocol specified by <c><anno>Type</anno></c>. Very similar to the packet + handling done by sockets with the option {packet,<anno>Type</anno>}.</p> + <p>If an entire packet is contained in <c><anno>Bin</anno></c> it is returned together with the remainder of the binary as - <c>{ok,Packet,Rest}</c>.</p> - <p>If <c>Bin</c> does not contain the entire packet, - <c>{more,Length}</c> is returned. <c>Length</c> is either the + <c>{ok,<anno>Packet</anno>,<anno>Rest</anno>}</c>.</p> + <p>If <c><anno>Bin</anno></c> does not contain the entire packet, + <c>{more,<anno>Length</anno>}</c> is returned. <c><anno>Length</anno></c> is either the expected <em>total size</em> of the packet or <c>undefined</c> if the expected packet size is not known. <c>decode_packet</c> can then be called again with more data added.</p> <p>If the packet does not conform to the protocol format - <c>{error,Reason}</c> is returned.</p> - <p>The following values of <c>Type</c> are valid:</p> + <c>{error,<anno>Reason</anno>}</c> is returned.</p> + <p>The following values of <c><anno>Type</anno></c> are valid:</p> <taglist> <tag><c>raw | 0</c></tag> <item> @@ -699,15 +586,15 @@ false</pre> <item> <p>The Hypertext Transfer Protocol. The packets are returned with the format according to - <c>HttpPacket</c> described above. A packet is either a + <c><anno>HttpPacket</anno></c> described above. A packet is either a request, a response, a header or an end of header - mark. Invalid lines are returned as <c>HttpError</c>.</p> + mark. Invalid lines are returned as <c><anno>HttpError</anno></c>.</p> <p>Recognized request methods and header fields are returned as atoms. Others are returned as strings.</p> <p>The protocol type <c>http</c> should only be used for - the first line when a <c>HttpRequest</c> or a - <c>HttpResponse</c> is expected. The following calls - should use <c>httph</c> to get <c>HttpHeader</c>'s until + the first line when a <c><anno>HttpRequest</anno></c> or a + <c><anno>HttpResponse</anno></c> is expected. The following calls + should use <c>httph</c> to get <c><anno>HttpHeader</anno></c>'s until <c>http_eoh</c> is returned that marks the end of the headers and the beginning of any following message body.</p> <p>The variants <c>http_bin</c> and <c>httph_bin</c> will return @@ -716,14 +603,14 @@ false</pre> </taglist> <p>The following options are available:</p> <taglist> - <tag><c>{packet_size, integer()}</c></tag> + <tag><c>{packet_size, integer() >= 0}</c></tag> <item><p>Sets the max allowed size of the packet body. If the packet header indicates that the length of the packet is longer than the max allowed length, the packet is considered invalid. Default is 0 which means no size limit.</p> </item> - <tag><c>{line_length, integer()}</c></tag> + <tag><c>{line_length, integer() >= 0}</c></tag> <item><p>For packet type <c>line</c>, truncate lines longer than the indicated length.</p> <p>Option <c>line_length</c> also applies to <c>http*</c> @@ -740,13 +627,10 @@ false</pre> </desc> </func> <func> - <name>delete_module(Module) -> true | undefined</name> + <name name="delete_module" arity="1"/> <fsummary>Make the current code for a module old</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Makes the current code for <c>Module</c> become old code, and + <p>Makes the current code for <c><anno>Module</anno></c> become old code, and deletes all references for this module from the export table. Returns <c>undefined</c> if the module does not exist, otherwise <c>true</c>.</p> @@ -760,27 +644,24 @@ false</pre> </desc> </func> <func> - <name>demonitor(MonitorRef) -> true</name> + <name name="demonitor" arity="1"/> <fsummary>Stop monitoring</fsummary> - <type> - <v>MonitorRef = reference()</v> - </type> <desc> - <p>If <c>MonitorRef</c> is a reference which the calling process + <p>If <c><anno>MonitorRef</anno></c> is a reference which the calling process obtained by calling <seealso marker="#monitor/2">monitor/2</seealso>, this monitoring is turned off. If the monitoring is already turned off, nothing happens.</p> - <p>Once <c>demonitor(MonitorRef)</c> has returned it is - guaranteed that no <c>{'DOWN', MonitorRef, _, _, _}</c> message + <p>Once <c>demonitor(<anno>MonitorRef</anno>)</c> has returned it is + guaranteed that no <c>{'DOWN', <anno>MonitorRef</anno>, _, _, _}</c> message due to the monitor will be placed in the caller's message queue - in the future. A <c>{'DOWN', MonitorRef, _, _, _}</c> message + in the future. A <c>{'DOWN', <anno>MonitorRef</anno>, _, _, _}</c> message might have been placed in the caller's message queue prior to the call, though. Therefore, in most cases, it is advisable to remove such a <c>'DOWN'</c> message from the message queue after monitoring has been stopped. - <seealso marker="#demonitor/2">demonitor(MonitorRef, [flush])</seealso> can be used instead of - <c>demonitor(MonitorRef)</c> if this cleanup is wanted.</p> + <seealso marker="#demonitor/2">demonitor(<anno>MonitorRef</anno>, [flush])</seealso> can be used instead of + <c>demonitor(<anno>MonitorRef</anno>)</c> if this cleanup is wanted.</p> <note> <p>Prior to OTP release R11B (erts version 5.5) <c>demonitor/1</c> behaved completely asynchronous, i.e., the monitor was active @@ -792,35 +673,30 @@ false</pre> asynchronously send a "demonitor signal" to the monitored entity and ignore any future results of the monitor. </p> </note> - <p>Failure: It is an error if <c>MonitorRef</c> refers to a + <p>Failure: It is an error if <c><anno>MonitorRef</anno></c> refers to a monitoring started by another process. Not all such cases are cheap to check; if checking is cheap, the call fails with - <c>badarg</c> (for example if <c>MonitorRef</c> is a remote + <c>badarg</c> (for example if <c><anno>MonitorRef</anno></c> is a remote reference).</p> </desc> </func> <func> - <name>demonitor(MonitorRef, OptionList) -> boolean()</name> + <name name="demonitor" arity="2"/> <fsummary>Stop monitoring</fsummary> - <type> - <v>MonitorRef = reference()</v> - <v>OptionList = [Option]</v> - <v> Option = flush | info</v> - </type> <desc> <p>The returned value is <c>true</c> unless <c>info</c> is part - of <c>OptionList</c>. + of <c><anno>OptionList</anno></c>. </p> - <p><c>demonitor(MonitorRef, [])</c> is equivalent to - <seealso marker="#demonitor/1">demonitor(MonitorRef)</seealso>.</p> - <p>Currently the following <c>Option</c>s are valid:</p> + <p><c>demonitor(<anno>MonitorRef</anno>, [])</c> is equivalent to + <seealso marker="#demonitor/1">demonitor(<anno>MonitorRef</anno>)</seealso>.</p> + <p>Currently the following <c><anno>Option</anno></c>s are valid:</p> <taglist> <tag><c>flush</c></tag> <item> - <p>Remove (one) <c>{_, MonitorRef, _, _, _}</c> message, + <p>Remove (one) <c>{_, <anno>MonitorRef</anno>, _, _, _}</c> message, if there is one, from the caller's message queue after monitoring has been stopped.</p> - <p>Calling <c>demonitor(MonitorRef, [flush])</c> + <p>Calling <c>demonitor(<anno>MonitorRef</anno>, [flush])</c> is equivalent to the following, but more efficient:</p> <code type="none"> @@ -860,8 +736,8 @@ false</pre> <note> <p>More options may be added in the future.</p> </note> - <p>Failure: <c>badarg</c> if <c>OptionList</c> is not a list, or - if <c>Option</c> is not a valid option, or the same failure as for + <p>Failure: <c>badarg</c> if <c><anno>OptionList</anno></c> is not a list, or + if <c><anno>Option</anno></c> is not a valid option, or the same failure as for <seealso marker="#demonitor/1">demonitor/1</seealso></p> </desc> </func> @@ -878,13 +754,10 @@ false</pre> </desc> </func> <func> - <name>erlang:display(Term) -> true</name> + <name name="display" arity="1"/> <fsummary>Print a term on standard output</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Prints a text representation of <c>Term</c> on the standard + <p>Prints a text representation of <c><anno>Term</anno></c> on the standard output.</p> <warning> <p>This BIF is intended for debugging only.</p> @@ -892,15 +765,12 @@ false</pre> </desc> </func> <func> - <name>element(N, Tuple) -> term()</name> + <name name="element" arity="2"/> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Get Nth element of a tuple</fsummary> - <type> - <v>N = 1..tuple_size(Tuple)</v> - <v>Tuple = tuple()</v> - </type> <desc> - <p>Returns the <c>N</c>th element (numbering from 1) of - <c>Tuple</c>.</p> + <p>Returns the <c><anno>N</anno></c>th element (numbering from 1) of + <c><anno>Tuple</anno></c>.</p> <pre> > <input>element(2, {a, b, c}).</input> b</pre> @@ -908,11 +778,8 @@ b</pre> </desc> </func> <func> - <name>erase() -> [{Key, Val}]</name> + <name name="erase" arity="0"/> <fsummary>Return and delete the process dictionary</fsummary> - <type> - <v>Key = Val = term()</v> - </type> <desc> <p>Returns the process dictionary and deletes it.</p> <pre> @@ -923,15 +790,12 @@ b</pre> </desc> </func> <func> - <name>erase(Key) -> Val | undefined</name> + <name name="erase" arity="1"/> <fsummary>Return and delete a value from the process dictionary</fsummary> - <type> - <v>Key = Val = term()</v> - </type> <desc> - <p>Returns the value <c>Val</c> associated with <c>Key</c> and + <p>Returns the value <c><anno>Val</anno></c> associated with <c><anno>Key</anno></c> and deletes it from the process dictionary. Returns - <c>undefined</c> if no value is associated with <c>Key</c>.</p> + <c>undefined</c> if no value is associated with <c><anno>Key</anno></c>.</p> <pre> > <input>put(key1, {merry, lambs, are, playing}),</input> <input>X = erase(key1),</input> @@ -940,15 +804,12 @@ b</pre> </desc> </func> <func> - <name>error(Reason)</name> + <name name="error" arity="1"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - </type> <desc> <p>Stops the execution of the calling process with the reason - <c>Reason</c>, where <c>Reason</c> is any term. The actual - exit reason will be <c>{Reason, Where}</c>, where <c>Where</c> + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. The actual + exit reason will be <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> is a list of the functions most recently called (the current function first). Since evaluating this function causes the process to terminate, it has no return value.</p> @@ -962,18 +823,14 @@ b</pre> </desc> </func> <func> - <name>error(Reason, Args)</name> + <name name="error" arity="2"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Stops the execution of the calling process with the reason - <c>Reason</c>, where <c>Reason</c> is any term. The actual - exit reason will be <c>{Reason, Where}</c>, where <c>Where</c> + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. The actual + exit reason will be <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> is a list of the functions most recently called (the current - function first). <c>Args</c> is expected to be the list of + function first). <c><anno>Args</anno></c> is expected to be the list of arguments for the current function; in Beam it will be used to provide the actual arguments for the current function in the <c>Where</c> term. Since evaluating this function causes @@ -981,14 +838,11 @@ b</pre> </desc> </func> <func> - <name>exit(Reason)</name> + <name name="exit" arity="1"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - </type> <desc> <p>Stops the execution of the calling process with the exit - reason <c>Reason</c>, where <c>Reason</c> is any term. Since + reason <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. Since evaluating this function causes the process to terminate, it has no return value.</p> <pre> @@ -999,78 +853,67 @@ b</pre> </desc> </func> <func> - <name>exit(Pid, Reason) -> true</name> + <name name="exit" arity="2"/> <fsummary>Send an exit signal to a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Reason = term()</v> - </type> - <desc> - <p>Sends an exit signal with exit reason <c>Reason</c> to - the process <c>Pid</c>.</p> - <p>The following behavior apply if <c>Reason</c> is any term + <desc> + <p>Sends an exit signal with exit reason <c><anno>Reason</anno></c> to + the process <c><anno>Pid</anno></c>.</p> + <p>The following behavior apply if <c><anno>Reason</anno></c> is any term except <c>normal</c> or <c>kill</c>:</p> - <p>If <c>Pid</c> is not trapping exits, <c>Pid</c> itself will - exit with exit reason <c>Reason</c>. If <c>Pid</c> is trapping + <p>If <c><anno>Pid</anno></c> is not trapping exits, <c><anno>Pid</anno></c> itself will + exit with exit reason <c><anno>Reason</anno></c>. If <c><anno>Pid</anno></c> is trapping exits, the exit signal is transformed into a message - <c>{'EXIT', From, Reason}</c> and delivered to the message - queue of <c>Pid</c>. <c>From</c> is the pid of the process + <c>{'EXIT', From, <anno>Reason</anno>}</c> and delivered to the message + queue of <c><anno>Pid</anno></c>. <c>From</c> is the pid of the process which sent the exit signal. See also <seealso marker="#process_flag/2">process_flag/2</seealso>.</p> - <p>If <c>Reason</c> is the atom <c>normal</c>, <c>Pid</c> will + <p>If <c><anno>Reason</anno></c> is the atom <c>normal</c>, <c><anno>Pid</anno></c> will not exit. If it is trapping exits, the exit signal is transformed into a message <c>{'EXIT', From, normal}</c> and delivered to its message queue.</p> - <p>If <c>Reason</c> is the atom <c>kill</c>, that is if - <c>exit(Pid, kill)</c> is called, an untrappable exit signal - is sent to <c>Pid</c> which will unconditionally exit with + <p>If <c><anno>Reason</anno></c> is the atom <c>kill</c>, that is if + <c>exit(<anno>Pid</anno>, kill)</c> is called, an untrappable exit signal + is sent to <c><anno>Pid</anno></c> which will unconditionally exit with exit reason <c>killed</c>.</p> </desc> </func> <func> - <name>erlang:external_size(Term) -> integer() >= 0</name> + <name name="external_size" arity="1"/> <fsummary>Calculate the maximum size for a term encoded in the Erlang external term format</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> <p>Calculates, without doing the encoding, the maximum byte size for a term encoded in the Erlang external term format. The following condition applies always:</p> <p> <pre> -> <input>Size1 = byte_size(term_to_binary(Term)),</input> -> <input>Size2 = erlang:external_size(Term),</input> +> <input>Size1 = byte_size(term_to_binary(<anno>Term</anno>)),</input> +> <input>Size2 = erlang:external_size(<anno>Term</anno>),</input> > <input>true = Size1 =< Size2.</input> true </pre> </p> - <p>This is equivalent to a call to: <code>erlang:external_size(Term, []) + <p>This is equivalent to a call to: <code>erlang:external_size(<anno>Term</anno>, []) </code></p> </desc> </func> <func> - <name>erlang:external_size(Term, [Option]) -> integer() >= 0</name> + <name name="external_size" arity="2"/> <fsummary>Calculate the maximum size for a term encoded in the Erlang external term format</fsummary> - <type> - <v>Term = term()</v> - <v>Option = {minor_version, Version}</v> - </type> <desc> <p>Calculates, without doing the encoding, the maximum byte size for a term encoded in the Erlang external term format. The following condition applies always:</p> <p> <pre> -> <input>Size1 = byte_size(term_to_binary(Term, Options)),</input> -> <input>Size2 = erlang:external_size(Term, Options),</input> +> <input>Size1 = byte_size(term_to_binary(<anno>Term</anno>, <anno>Options</anno>)),</input> +> <input>Size2 = erlang:external_size(<anno>Term</anno>, <anno>Options</anno>),</input> > <input>true = Size1 =< Size2.</input> true </pre> </p> - <p>The option <c>{minor_version, Version}</c> specifies how floats + <p>The option <c>{minor_version, <anno>Version</anno>}</c> specifies how floats are encoded. See <seealso marker="#term_to_binary/2">term_to_binary/2</seealso> for a more detailed description. @@ -1078,13 +921,10 @@ true </desc> </func> <func> - <name>float(Number) -> float()</name> + <name name="float" arity="1"/> <fsummary>Convert a number to a float</fsummary> - <type> - <v>Number = number()</v> - </type> <desc> - <p>Returns a float by converting <c>Number</c> to a float.</p> + <p>Returns a float by converting <c><anno>Number</anno></c> to a float.</p> <pre> > <input>float(55).</input> 55.0</pre> @@ -1101,14 +941,11 @@ true </desc> </func> <func> - <name>float_to_list(Float) -> string()</name> + <name name="float_to_list" arity="1"/> <fsummary>Text representation of a float</fsummary> - <type> - <v>Float = float()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Float</c>.</p> + representation of <c><anno>Float</anno></c>.</p> <pre> > <input>float_to_list(7.0).</input> "7.00000000000000000000e+00"</pre> @@ -1213,18 +1050,15 @@ true </desc> </func> <func> - <name>erlang:fun_info(Fun, Item) -> {Item, Info}</name> + <name name="fun_info" arity="2"/> + <type name="fun_info_item"/> <fsummary>Information about a fun</fsummary> - <type> - <v>Fun = fun()</v> - <v>Item, Info -- see below</v> - </type> - <desc> - <p>Returns information about <c>Fun</c> as specified by - <c>Item</c>, in the form <c>{Item,Info}</c>.</p> - <p>For any fun, <c>Item</c> can be any of the atoms + <desc> + <p>Returns information about <c><anno>Fun</anno></c> as specified by + <c><anno>Item</anno></c>, in the form <c>{<anno>Item</anno>,<anno>Info</anno>}</c>.</p> + <p>For any fun, <c><anno>Item</anno></c> can be any of the atoms <c>module</c>, <c>name</c>, <c>arity</c>, <c>env</c>, or <c>type</c>.</p> - <p>For a local fun, <c>Item</c> can also be any of the atoms + <p>For a local fun, <c><anno>Item</anno></c> can also be any of the atoms <c>index</c>, <c>new_index</c>, <c>new_uniq</c>, <c>uniq</c>, and <c>pid</c>. For an external fun, the value of any of these items is always the atom <c>undefined</c>.</p> @@ -1233,33 +1067,26 @@ true </desc> </func> <func> - <name>erlang:fun_to_list(Fun) -> string()</name> + <name name="fun_to_list" arity="1"/> <fsummary>Text representation of a fun</fsummary> - <type> - <v>Fun = fun()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Fun</c>.</p> + representation of <c><anno>Fun</anno></c>.</p> </desc> </func> <func> - <name>erlang:function_exported(Module, Function, Arity) -> boolean()</name> + <name name="function_exported" arity="3"/> <fsummary>Check if a function is exported and loaded</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Arity = arity()</v> - </type> <desc> - <p>Returns <c>true</c> if the module <c>Module</c> is loaded - and contains an exported function <c>Function/Arity</c>; + <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is loaded + and contains an exported function <c><anno>Function</anno>/<anno>Arity</anno></c>; otherwise <c>false</c>.</p> <p>Returns <c>false</c> for any BIF (functions implemented in C rather than in Erlang).</p> </desc> </func> <func> - <name>garbage_collect() -> true</name> + <name name="garbage_collect" arity="0"/> <fsummary>Force an immediate garbage collection of the calling process</fsummary> <desc> <p>Forces an immediate garbage collection of the currently @@ -1276,26 +1103,20 @@ true </desc> </func> <func> - <name>garbage_collect(Pid) -> boolean()</name> + <name name="garbage_collect" arity="1"/> <fsummary>Force an immediate garbage collection of a process</fsummary> - <type> - <v>Pid = pid()</v> - </type> <desc> <p>Works like <c>erlang:garbage_collect()</c> but on any process. The same caveats apply. Returns <c>false</c> if - <c>Pid</c> refers to a dead process; <c>true</c> otherwise.</p> + <c><anno>Pid</anno></c> refers to a dead process; <c>true</c> otherwise.</p> </desc> </func> <func> - <name>get() -> [{Key, Val}]</name> + <name name="get" arity="0"/> <fsummary>Return the process dictionary</fsummary> - <type> - <v>Key = Val = term()</v> - </type> <desc> <p>Returns the process dictionary as a list of - <c>{Key, Val}</c> tuples.</p> + <c>{<anno>Key</anno>, <anno>Val</anno>}</c> tuples.</p> <pre> > <input>put(key1, merry),</input> <input>put(key2, lambs),</input> @@ -1305,14 +1126,11 @@ true </desc> </func> <func> - <name>get(Key) -> Val | undefined</name> + <name name="get" arity="1"/> <fsummary>Return a value from the process dictionary</fsummary> - <type> - <v>Key = Val = term()</v> - </type> <desc> - <p>Returns the value <c>Val</c>associated with <c>Key</c> in - the process dictionary, or <c>undefined</c> if <c>Key</c> + <p>Returns the value <c><anno>Val</anno></c>associated with <c><anno>Key</anno></c> in + the process dictionary, or <c>undefined</c> if <c><anno>Key</anno></c> does not exist.</p> <pre> > <input>put(key1, merry),</input> @@ -1331,14 +1149,11 @@ true </desc> </func> <func> - <name>get_keys(Val) -> [Key]</name> + <name name="get_keys" arity="1"/> <fsummary>Return a list of keys from the process dictionary</fsummary> - <type> - <v>Val = Key = term()</v> - </type> <desc> <p>Returns a list of keys which are associated with the value - <c>Val</c> in the process dictionary.</p> + <c><anno>Val</anno></c> in the process dictionary.</p> <pre> > <input>put(mary, {1, 2}),</input> <input>put(had, {1, 2}),</input> @@ -1351,28 +1166,23 @@ true </desc> </func> <func> - <name>erlang:get_stacktrace() -> [{Module, Function, Arity | Args, Location}]</name> + <name name="get_stacktrace" arity="0"/> <fsummary>Get the call stack back-trace of the last exception</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Arity = arity()</v> - <v>Args = [term()]</v> - <v>Location = [{atom(),term()}]</v> - </type> + <type name="stack_item"/> <desc> <p>Get the call stack back-trace (<em>stacktrace</em>) of the last exception in the calling process as a list of - <c>{Module,Function,Arity,Location}</c> tuples. - The <c>Arity</c> field in the first tuple may be the argument + <c>{<anno>Module</anno>,<anno>Function</anno>,<anno>Arity</anno>,<anno>Location</anno>}</c> tuples. + The <c><anno>Arity</anno></c> field in the first tuple may be the argument list of that function call instead of an arity integer, depending on the exception.</p> <p>If there has not been any exceptions in a process, the - stacktrace is []. After a code change for the process, + stacktrace is <c>[]</c>. After a code change for the process, the stacktrace may also be reset to [].</p> <p>The stacktrace is the same data as the <c>catch</c> operator returns, for example:</p> <p><c>{'EXIT',{badarg,Stacktrace}} = catch abs(x)</c></p> - <p><c>Location</c> is a (possibly empty) list of two-tuples that + <p><c><anno>Location</anno></c> is a (possibly empty) list of two-tuples that may indicate the location in the source code of the function. The first element is an atom that describes the type of information in the second element. Currently the following @@ -1397,11 +1207,8 @@ true </desc> </func> <func> - <name>group_leader() -> GroupLeader</name> + <name name="group_leader" arity="0"/> <fsummary>Get the group leader for the calling process</fsummary> - <type> - <v>GroupLeader = pid()</v> - </type> <desc> <p>Returns the pid of the group leader for the process which evaluates the function.</p> @@ -1414,13 +1221,10 @@ true </desc> </func> <func> - <name>group_leader(GroupLeader, Pid) -> true</name> + <name name="group_leader" arity="2"/> <fsummary>Set the group leader for a process</fsummary> - <type> - <v>GroupLeader = Pid = pid()</v> - </type> <desc> - <p>Sets the group leader of <c>Pid</c> to <c>GroupLeader</c>. + <p>Sets the group leader of <c><anno>Pid</anno></c> to <c><anno>GroupLeader</anno></c>. Typically, this is used when a processes started from a certain shell should have another group leader than <c>init</c>.</p> @@ -1429,7 +1233,7 @@ true </desc> </func> <func> - <name>halt()</name> + <name name="halt" arity="0"/> <fsummary>Halt the Erlang runtime system and indicate normal exit to the calling environment</fsummary> <desc> <p>The same as @@ -1440,14 +1244,11 @@ os_prompt% </pre> </desc> </func> <func> - <name>halt(Status)</name> + <name name="halt" arity="1"/> <fsummary>Halt the Erlang runtime system</fsummary> - <type> - <v>Status = integer() >= 0 | string() | abort</v> - </type> <desc> <p>The same as - <seealso marker="#halt/2"><c>halt(Status, [])</c></seealso>.</p> + <seealso marker="#halt/2"><c>halt(<anno>Status</anno>, [])</c></seealso>.</p> <pre> > <input>halt(17).</input> os_prompt% <input>echo $?</input> @@ -1456,26 +1257,21 @@ os_prompt% </pre> </desc> </func> <func> - <name>halt(Status, Options)</name> + <name name="halt" arity="2"/> <fsummary>Halt the Erlang runtime system</fsummary> - <type> - <v>Status = integer() >= 0 | string() | abort</v> - <v>Options = [Option]</v> - <v>Option = {flush,boolean()} | term()</v> - </type> <desc> - <p><c>Status</c> must be a non-negative integer, a string, + <p><c><anno>Status</anno></c> must be a non-negative integer, a string, or the atom <c>abort</c>. Halts the Erlang runtime system. Has no return value. - Depending on <c>Status</c>: + Depending on <c><anno>Status</anno></c>: </p> <taglist> <tag>integer()</tag> - <item>The runtime system exits with the integer value <c>Status</c> + <item>The runtime system exits with the integer value <c><anno>Status</anno></c> as status code to the calling environment (operating system). </item> <tag>string()</tag> - <item>An erlang crash dump is produced with <c>Status</c> as slogan, + <item>An erlang crash dump is produced with <c><anno>Status</anno></c> as slogan, and then the runtime system exits with status code <c>1</c>. </item> <tag><c>abort</c></tag> @@ -1487,10 +1283,10 @@ os_prompt% </pre> <p>Note that on many platforms, only the status codes 0-255 are supported by the operating system. </p> - <p>For integer <c>Status</c> the Erlang runtime system closes all ports + <p>For integer <c><anno>Status</anno></c> the Erlang runtime system closes all ports and allows async threads to finish their operations before exiting. To exit without such flushing use - <c>Option</c> as <c>{flush,false}</c>. + <c><anno>Option</anno></c> as <c>{flush,false}</c>. </p> <p>For statuses <c>string()</c> and <c>abort</c> the <c>flush</c> option is ignored and flushing is <em>not</em> done. @@ -1498,11 +1294,11 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:hash(Term, Range) -> Hash</name> + <name name="hash" arity="2"/> <fsummary>Hash function (deprecated)</fsummary> <desc> - <p>Returns a hash value for <c>Term</c> within the range - <c>1..Range</c>. The allowed range is 1..2^27-1.</p> + <p>Returns a hash value for <c><anno>Term</anno></c> within the range + <c>1..<anno>Range</anno></c>. The allowed range is 1..2^27-1.</p> <warning> <p>This BIF is deprecated as the hash value may differ on different architectures. Also the hash values for integer @@ -1515,35 +1311,28 @@ os_prompt% </pre> </desc> </func> <func> - <name>hd(List) -> term()</name> + <name name="hd" arity="1"/> <fsummary>Head of a list</fsummary> - <type> - <v>List = [term()]</v> - </type> <desc> - <p>Returns the head of <c>List</c>, that is, the first element.</p> + <p>Returns the head of <c><anno>List</anno></c>, that is, the first element.</p> <pre> > <input>hd([1,2,3,4,5]).</input> 1</pre> <p>Allowed in guard tests.</p> - <p>Failure: <c>badarg</c> if <c>List</c> is the empty list [].</p> + <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty list [].</p> </desc> </func> <func> - <name>erlang:hibernate(Module, Function, Args)</name> + <name name="hibernate" arity="3"/> <fsummary>Hibernate a process until a message is sent to it</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Puts the calling process into a wait state where its memory allocation has been reduced as much as possible, which is useful if the process does not expect to receive any messages in the near future.</p> <p>The process will be awaken when a message is sent to it, and - control will resume in <c>Module:Function</c> with - the arguments given by <c>Args</c> with the call stack + control will resume in <c><anno>Module</anno>:<anno>Function</anno></c> with + the arguments given by <c><anno>Args</anno></c> with the call stack emptied, meaning that the process will terminate when that function returns. Thus <c>erlang:hibernate/3</c> will never return to its caller.</p> @@ -1573,14 +1362,11 @@ os_prompt% </pre> </desc> </func> <func> - <name>integer_to_list(Integer) -> string()</name> + <name name="integer_to_list" arity="1"/> <fsummary>Text representation of an integer</fsummary> - <type> - <v>Integer = integer()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Integer</c>.</p> + representation of <c><anno>Integer</anno></c>.</p> <pre> > <input>integer_to_list(77).</input> "77"</pre> @@ -1598,14 +1384,11 @@ os_prompt% </pre> </desc> </func> <func> - <name>iolist_to_binary(IoListOrBinary) -> binary()</name> + <name name="iolist_to_binary" arity="1"/> <fsummary>Convert an iolist to a binary</fsummary> - <type> - <v>IoListOrBinary = iolist() | binary()</v> - </type> <desc> <p>Returns a binary which is made from the integers and - binaries in <c>IoListOrBinary</c>.</p> + binaries in <c><anno>IoListOrBinary</anno></c>.</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> @@ -1618,22 +1401,19 @@ os_prompt% </pre> </desc> </func> <func> - <name>iolist_size(Item) -> integer() >= 0</name> + <name name="iolist_size" arity="1"/> <fsummary>Size of an iolist</fsummary> - <type> - <v>Item = iolist() | binary()</v> - </type> <desc> <p>Returns an integer which is the size in bytes of the binary that would be the result of - <c>iolist_to_binary(Item)</c>.</p> + <c>iolist_to_binary(<anno>Item</anno>)</c>.</p> <pre> > <input>iolist_size([1,2|<<3,4>>]).</input> 4</pre> </desc> </func> <func> - <name>is_alive() -> boolean()</name> + <name name="is_alive" arity="0"/> <fsummary>Check whether the local node is alive</fsummary> <desc> <p>Returns <c>true</c> if the local node is alive; that is, if @@ -1642,25 +1422,19 @@ os_prompt% </pre> </desc> </func> <func> - <name>is_atom(Term) -> boolean()</name> + <name name="is_atom" arity="1"/> <fsummary>Check whether a term is an atom</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is an atom; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an atom; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_binary(Term) -> boolean()</name> + <name name="is_binary" arity="1"/> <fsummary>Check whether a term is a binary</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a binary; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a binary; otherwise returns <c>false</c>.</p> <p>A binary always contains a complete number of bytes.</p> @@ -1669,78 +1443,58 @@ os_prompt% </pre> </desc> </func> <func> - <name>is_bitstring(Term) -> boolean()</name> + <name name="is_bitstring" arity="1"/> <fsummary>Check whether a term is a bitstring</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a bitstring (including a binary); + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a bitstring (including a binary); otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_boolean(Term) -> boolean()</name> + <name name="is_boolean" arity="1"/> <fsummary>Check whether a term is a boolean</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is either the atom <c>true</c> or the atom <c>false</c> (i.e. a boolean); otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>erlang:is_builtin(Module, Function, Arity) -> boolean()</name> + <name name="is_builtin" arity="3"/> <fsummary>Check if a function is a BIF implemented in C</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Arity = arity()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Module:Function/Arity</c> is + <p>Returns <c>true</c> if <c><anno>Module</anno>:<anno>Function</anno>/<anno>Arity</anno></c> is a BIF implemented in C; otherwise returns <c>false</c>. This BIF is useful for builders of cross reference tools.</p> </desc> </func> <func> - <name>is_float(Term) -> boolean()</name> + <name name="is_float" arity="1"/> <fsummary>Check whether a term is a float</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a floating point + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a floating point number; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_function(Term) -> boolean()</name> + <name name="is_function" arity="1"/> <fsummary>Check whether a term is a fun</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a fun; otherwise + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_function(Term, Arity) -> boolean()</name> + <name name="is_function" arity="2"/> <fsummary>Check whether a term is a fun with a given arity</fsummary> - <type> - <v>Term = term()</v> - <v>Arity = arity()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a fun that can be - applied with <c>Arity</c> number of arguments; otherwise + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun that can be + applied with <c><anno>Arity</anno></c> number of arguments; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> <warning> @@ -1753,74 +1507,56 @@ os_prompt% </pre> </desc> </func> <func> - <name>is_integer(Term) -> boolean()</name> + <name name="is_integer" arity="1"/> <fsummary>Check whether a term is an integer</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is an integer; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_list(Term) -> boolean()</name> + <name name="is_list" arity="1"/> <fsummary>Check whether a term is a list</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a list with + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a list with zero or more elements; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_number(Term) -> boolean()</name> + <name name="is_number" arity="1"/> <fsummary>Check whether a term is a number</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is either an integer or a + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is either an integer or a floating point number; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_pid(Term) -> boolean()</name> + <name name="is_pid" arity="1"/> <fsummary>Check whether a term is a pid</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a pid (process + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a pid (process identifier); otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_port(Term) -> boolean()</name> + <name name="is_port" arity="1"/> <fsummary>Check whether a term is a port</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a port identifier; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a port identifier; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_process_alive(Pid) -> boolean()</name> + <name name="is_process_alive" arity="1"/> <fsummary>Check whether a process is alive</fsummary> - <type> - <v>Pid = pid()</v> - </type> <desc> <p> - <c>Pid</c> must refer to a process at the local node. + <c><anno>Pid</anno></c> must refer to a process at the local node. Returns <c>true</c> if the process exists and is alive, that is, is not exiting and has not exited. Otherwise, returns <c>false</c>. @@ -1828,41 +1564,32 @@ os_prompt% </pre> </desc> </func> <func> - <name>is_record(Term, RecordTag) -> boolean()</name> + <name name="is_record" arity="2"/> <fsummary>Check whether a term appears to be a record</fsummary> - <type> - <v>Term = term()</v> - <v>RecordTag = atom()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a tuple and its first - element is <c>RecordTag</c>. Otherwise, returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple and its first + element is <c><anno>RecordTag</anno></c>. Otherwise, returns <c>false</c>.</p> <note> <p>Normally the compiler treats calls to <c>is_record/2</c> - specially. It emits code to verify that <c>Term</c> is a - tuple, that its first element is <c>RecordTag</c>, and that - the size is correct. However, if the <c>RecordTag</c> is + specially. It emits code to verify that <c><anno>Term</anno></c> is a + tuple, that its first element is <c><anno>RecordTag</anno></c>, and that + the size is correct. However, if the <c><anno>RecordTag</anno></c> is not a literal atom, the <c>is_record/2</c> BIF will be called instead and the size of the tuple will not be verified.</p> </note> - <p>Allowed in guard tests, if <c>RecordTag</c> is a literal + <p>Allowed in guard tests, if <c><anno>RecordTag</anno></c> is a literal atom.</p> </desc> </func> <func> - <name>is_record(Term, RecordTag, Size) -> boolean()</name> + <name name="is_record" arity="3"/> <fsummary>Check whether a term appears to be a record</fsummary> - <type> - <v>Term = term()</v> - <v>RecordTag = atom()</v> - <v>Size = integer()</v> - </type> - <desc> - <p><c>RecordTag</c> must be an atom. Returns <c>true</c> if - <c>Term</c> is a tuple, its first element is <c>RecordTag</c>, - and its size is <c>Size</c>. Otherwise, returns <c>false</c>.</p> - <p>Allowed in guard tests, provided that <c>RecordTag</c> is + <desc> + <p><c><anno>RecordTag</anno></c> must be an atom. Returns <c>true</c> if + <c><anno>Term</anno></c> is a tuple, its first element is <c><anno>RecordTag</anno></c>, + and its size is <c><anno>Size</anno></c>. Otherwise, returns <c>false</c>.</p> + <p>Allowed in guard tests, provided that <c><anno>RecordTag</anno></c> is a literal atom and <c>Size</c> is a literal integer.</p> <note> <p>This BIF is documented for completeness. In most cases @@ -1871,37 +1598,28 @@ os_prompt% </pre> </desc> </func> <func> - <name>is_reference(Term) -> boolean()</name> + <name name="is_reference" arity="1"/> <fsummary>Check whether a term is a reference</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a reference; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a reference; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_tuple(Term) -> boolean()</name> + <name name="is_tuple" arity="1"/> <fsummary>Check whether a term is a tuple</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a tuple; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>length(List) -> integer() >= 0</name> + <name name="length" arity="1"/> <fsummary>Length of a list</fsummary> - <type> - <v>List = [term()]</v> - </type> <desc> - <p>Returns the length of <c>List</c>.</p> + <p>Returns the length of <c><anno>List</anno></c>.</p> <pre> > <input>length([1,2,3,4,5,6,7,8,9]).</input> 9</pre> @@ -1909,52 +1627,47 @@ os_prompt% </pre> </desc> </func> <func> - <name>link(Pid) -> true</name> + <name name="link" arity="1"/> <fsummary>Create a link to another process (or port)</fsummary> - <type> - <v>Pid = pid() | port()</v> - </type> <desc> <p>Creates a link between the calling process and another - process (or port) <c>Pid</c>, if there is not such a link + process (or port) <c><anno>PidOrPort</anno></c>, if there is not such a link already. If a process attempts to create a link to itself, nothing is done. Returns <c>true</c>.</p> - <p>If <c>Pid</c> does not exist, the behavior of the BIF depends + <p>If <c><anno>PidOrPort</anno></c> does not exist, the behavior of the BIF depends on if the calling process is trapping exits or not (see <seealso marker="#process_flag/2">process_flag/2</seealso>):</p> <list type="bulleted"> <item>If the calling process is not trapping exits, and - checking <c>Pid</c> is cheap -- that is, if <c>Pid</c> is + checking <c><anno>PidOrPort</anno></c> is cheap -- that is, if <c><anno>PidOrPort</anno></c> is local -- <c>link/1</c> fails with reason <c>noproc</c>.</item> <item>Otherwise, if the calling process is trapping exits, - and/or <c>Pid</c> is remote, <c>link/1</c> returns + and/or <c><anno>PidOrPort</anno></c> is remote, <c>link/1</c> returns <c>true</c>, but an exit signal with reason <c>noproc</c> is sent to the calling process.</item> </list> </desc> </func> <func> - <name>list_to_atom(String) -> atom()</name> + <name name="list_to_atom" arity="1"/> <fsummary>Convert from text representation to an atom</fsummary> - <type> - <v>String = string()</v> - </type> <desc> - <p>Returns the atom whose text representation is <c>String</c>.</p> + <p>Returns the atom whose text representation is <c><anno>String</anno></c>.</p> + <p><c><anno>String</anno></c> may only contain ISO-latin-1 + characterns (i.e. numbers below 256) as the current + implementation does not allow unicode characters >= 256 in + atoms.</p> <pre> > <input>list_to_atom("Erlang").</input> 'Erlang'</pre> </desc> </func> <func> - <name>list_to_binary(IoList) -> binary()</name> + <name name="list_to_binary" arity="1"/> <fsummary>Convert a list to a binary</fsummary> - <type> - <v>IoList = iolist()</v> - </type> <desc> <p>Returns a binary which is made from the integers and - binaries in <c>IoList</c>.</p> + binaries in <c><anno>IoList</anno></c>.</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> @@ -1967,14 +1680,12 @@ os_prompt% </pre> </desc> </func> <func> - <name>list_to_bitstring(BitstringList) -> bitstring()</name> + <name name="list_to_bitstring" arity="1"/> + <type name="bitstring_list"/> <fsummary>Convert a list to a bitstring</fsummary> - <type> - <v>BitstringList = [BitstringList | bitstring() | char()]</v> - </type> <desc> <p>Returns a bitstring which is made from the integers and - bitstrings in <c>BitstringList</c>. (The last tail in <c>BitstringList</c> + bitstrings in <c><anno>BitstringList</anno></c>. (The last tail in <c><anno>BitstringList</anno></c> is allowed to be a bitstring.)</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> @@ -1983,51 +1694,42 @@ os_prompt% </pre> <<4,5>> > <input>Bin3 = <<6,7:4,>>.</input> <<6>> -> <input>list_to_binary([Bin1,1,[2,3,Bin2],4|Bin3]).</input> +> <input>list_to_bitstring([Bin1,1,[2,3,Bin2],4|Bin3]).</input> <<1,2,3,1,2,3,4,5,4,6,7:46>></pre> </desc> </func> <func> - <name>list_to_existing_atom(String) -> atom()</name> + <name name="list_to_existing_atom" arity="1"/> <fsummary>Convert from text representation to an atom</fsummary> - <type> - <v>String = string()</v> - </type> <desc> - <p>Returns the atom whose text representation is <c>String</c>, + <p>Returns the atom whose text representation is <c><anno>String</anno></c>, but only if there already exists such atom.</p> <p>Failure: <c>badarg</c> if there does not already exist an atom - whose text representation is <c>String</c>.</p> + whose text representation is <c><anno>String</anno></c>.</p> </desc> </func> <func> - <name>list_to_float(String) -> float()</name> + <name name="list_to_float" arity="1"/> <fsummary>Convert from text representation to a float</fsummary> - <type> - <v>String = string()</v> - </type> <desc> - <p>Returns the float whose text representation is <c>String</c>.</p> + <p>Returns the float whose text representation is <c><anno>String</anno></c>.</p> <pre> > <input>list_to_float("2.2017764e+0").</input> 2.2017764</pre> - <p>Failure: <c>badarg</c> if <c>String</c> contains a bad + <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad representation of a float.</p> </desc> </func> <func> - <name>list_to_integer(String) -> integer()</name> + <name name="list_to_integer" arity="1"/> <fsummary>Convert from text representation to an integer</fsummary> - <type> - <v>String = string()</v> - </type> <desc> <p>Returns an integer whose text representation is - <c>String</c>.</p> + <c><anno>String</anno></c>.</p> <pre> > <input>list_to_integer("123").</input> 123</pre> - <p>Failure: <c>badarg</c> if <c>String</c> contains a bad + <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad representation of an integer.</p> </desc> </func> @@ -2045,13 +1747,10 @@ os_prompt% </pre> </desc> </func> <func> - <name>list_to_pid(String) -> pid()</name> + <name name="list_to_pid" arity="1"/> <fsummary>Convert from text representation to a pid</fsummary> - <type> - <v>String = string()</v> - </type> <desc> - <p>Returns a pid whose text representation is <c>String</c>.</p> + <p>Returns a pid whose text representation is <c><anno>String</anno></c>.</p> <warning> <p>This BIF is intended for debugging and for use in the Erlang operating system. It should not be used in @@ -2060,18 +1759,15 @@ os_prompt% </pre> <pre> > <input>list_to_pid("<0.4.1>").</input> <0.4.1></pre> - <p>Failure: <c>badarg</c> if <c>String</c> contains a bad + <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad representation of a pid.</p> </desc> </func> <func> - <name>list_to_tuple(List) -> tuple()</name> + <name name="list_to_tuple" arity="1"/> <fsummary>Convert a list to a tuple</fsummary> - <type> - <v>List = [term()]</v> - </type> <desc> - <p>Returns a tuple which corresponds to <c>List</c>. <c>List</c> + <p>Returns a tuple which corresponds to <c><anno>List</anno></c>. <c><anno>List</anno></c> can contain any Erlang terms.</p> <pre> > <input>list_to_tuple([share, ['Ericsson_B', 163]]).</input> @@ -2079,38 +1775,30 @@ os_prompt% </pre> </desc> </func> <func> - <name>load_module(Module, Binary) -> {module, Module} | {error, Reason}</name> + <name name="load_module" arity="2"/> <fsummary>Load object code for a module</fsummary> - <type> - <v>Module = atom()</v> - <v>Binary = binary()</v> - <v>Reason = badfile | not_purged | badfile</v> - </type> - <desc> - <p>If <c>Binary</c> contains the object code for the module - <c>Module</c>, this BIF loads that object code. Also, if - the code for the module <c>Module</c> already exists, all + <desc> + <p>If <c><anno>Binary</anno></c> contains the object code for the module + <c><anno>Module</anno></c>, this BIF loads that object code. Also, if + the code for the module <c><anno>Module</anno></c> already exists, all export references are replaced so they point to the newly loaded code. The previously loaded code is kept in the system as old code, as there may still be processes which are executing that code. It returns either - <c>{module, Module}</c>, or <c>{error, Reason}</c> if loading - fails. <c>Reason</c> is one of the following:</p> + <c>{module, <anno>Module</anno>}</c>, or <c>{error, <anno>Reason</anno>}</c> if loading + fails. <c><anno>Reason</anno></c> is one of the following:</p> <taglist> <tag><c>badfile</c></tag> <item> - <p>The object code in <c>Binary</c> has an incorrect format.</p> + <p>The object code in <c><anno>Binary</anno></c> has an + incorrect format <em>or</em> the object code contains code + for another module than <c><anno>Module</anno></c>.</p> </item> <tag><c>not_purged</c></tag> <item> - <p><c>Binary</c> contains a module which cannot be loaded + <p><c><anno>Binary</anno></c> contains a module which cannot be loaded because old code for this module already exists.</p> </item> - <tag><c>badfile</c></tag> - <item> - <p>The object code contains code for another module than - <c>Module</c></p> - </item> </taglist> <warning> <p>This BIF is intended for the code server (see @@ -2120,15 +1808,8 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:load_nif(Path, LoadInfo) -> ok | {error, {Reason, Text}}</name> + <name name="load_nif" arity="2"/> <fsummary>Load NIF library</fsummary> - <type> - <v>Path = string()</v> - <v>LoadInfo = term()</v> - <v>Reason = load_failed | bad_lib | load | reload | - upgrade | old_code</v> - <v>Text = string()</v> - </type> <desc> <note> <p>In releases older than OTP R14B, NIFs were an @@ -2139,21 +1820,21 @@ os_prompt% </pre> <c>{error,Reason,Text}</c>.</p> </note> <p>Loads and links a dynamic library containing native - implemented functions (NIFs) for a module. <c>Path</c> is a + implemented functions (NIFs) for a module. <c><anno>Path</anno></c> is a file path to the sharable object/dynamic library file minus the OS-dependent file extension (.so for Unix and .dll for Windows). See <seealso marker="erl_nif">erl_nif</seealso> on how to implement a NIF library.</p> - <p><c>LoadInfo</c> can be any term. It will be passed on to + <p><c><anno>LoadInfo</anno></c> can be any term. It will be passed on to the library as part of the initialization. A good practice is to include a module version number to support future code upgrade scenarios.</p> <p>The call to <c>load_nif/2</c> must be made <em>directly</em> from the Erlang code of the module that the NIF library belongs to.</p> - <p>It returns either <c>ok</c>, or <c>{error,{Reason,Text}}</c> - if loading fails. <c>Reason</c> is one of the atoms below, - while <c>Text</c> is a human readable string that may give + <p>It returns either <c>ok</c>, or <c>{error,{<anno>Reason</anno>,Text}}</c> + if loading fails. <c><anno>Reason</anno></c> is one of the atoms below, + while <c><anno>Text</anno></c> is a human readable string that may give some more information about the failure.</p> <taglist> <tag><c>load_failed</c></tag> @@ -2179,11 +1860,8 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:loaded() -> [Module]</name> + <name name="loaded" arity="0"/> <fsummary>List of all loaded modules</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> <p>Returns a list of all loaded Erlang modules (current and/or old code), including preloaded modules.</p> @@ -2191,11 +1869,8 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:localtime() -> DateTime</name> + <name name="localtime" arity="0"/> <fsummary>Current local date and time</fsummary> - <type> - <v>DateTime = <seealso marker="calendar#type-datetime">calendar:datetime()</seealso></v> - </type> <desc> <p>Returns the current local date and time <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c>.</p> @@ -2212,32 +1887,27 @@ os_prompt% </pre> <desc> <p>Converts local date and time to Universal Time Coordinated (UTC), if this is supported by the underlying OS. Otherwise, - no conversion is done and <c>{<anno>Date1</anno>, <anno>Time1</anno>}</c> is returned.</p> + no conversion is done and <c><anno>Localtime</anno></c> is returned.</p> <pre> > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}).</input> {{1996,11,6},{13,45,17}}</pre> - <p>Failure: <c>badarg</c> if <c>Date1</c> or <c>Time1</c> do - not denote a valid date or time.</p> + <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> does not denote + a valid date and time.</p> </desc> </func> <func> - <name>erlang:localtime_to_universaltime({Date1, Time1}, IsDst) -> {Date2, Time2}</name> + <name name="localtime_to_universaltime" arity="2"/> <fsummary>Convert from local to Universal Time Coordinated (UTC) date and time</fsummary> - <type> - <v>Date1 = Date2 = <seealso marker="calendar#type-date">calendar:date()</seealso></v> - <v>Time1 = Time2 = <seealso marker="calendar#type-time">calendar:time()</seealso></v> - <v>IsDst = true | false | undefined</v> - </type> <desc> <p>Converts local date and time to Universal Time Coordinated (UTC) just like <c>erlang:localtime_to_universaltime/1</c>, but the caller decides if daylight saving time is active or not.</p> - <p>If <c>IsDst == true</c> the <c>{Date1, Time1}</c> is during - daylight saving time, if <c>IsDst == false</c> it is not, - and if <c>IsDst == undefined</c> the underlying OS may + <p>If <c><anno>IsDst</anno> == true</c> the <c><anno>Localtime</anno></c> is during + daylight saving time, if <c><anno>IsDst</anno> == false</c> it is not, + and if <c><anno>IsDst</anno> == undefined</c> the underlying OS may guess, which is the same as calling - <c>erlang:localtime_to_universaltime({Date1, Time1})</c>.</p> + <c>erlang:localtime_to_universaltime(<anno>Localtime</anno>)</c>.</p> <pre> > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}, true).</input> {{1996,11,6},{12,45,17}} @@ -2245,12 +1915,12 @@ os_prompt% </pre> {{1996,11,6},{13,45,17}} > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}, undefined).</input> {{1996,11,6},{13,45,17}}</pre> - <p>Failure: <c>badarg</c> if <c>Date1</c> or <c>Time1</c> do - not denote a valid date or time.</p> + <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> does not denote + a valid date and time.</p> </desc> </func> <func> - <name>make_ref() -> reference()</name> + <name name="make_ref" arity="0"/> <fsummary>Return an almost unique reference</fsummary> <desc> <p>Returns an almost unique reference.</p> @@ -2262,33 +1932,23 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:make_tuple(Arity, InitialValue) -> tuple()</name> + <name name="make_tuple" arity="2"/> <fsummary>Create a new tuple of a given arity</fsummary> - <type> - <v>Arity = arity()</v> - <v>InitialValue = term()</v> - </type> <desc> - <p>Returns a new tuple of the given <c>Arity</c>, where all - elements are <c>InitialValue</c>.</p> + <p>Returns a new tuple of the given <c><anno>Arity</anno></c>, where all + elements are <c><anno>InitialValue</anno></c>.</p> <pre> > <input>erlang:make_tuple(4, []).</input> {[],[],[],[]}</pre> </desc> </func> <func> - <name>erlang:make_tuple(Arity, Default, InitList) -> tuple()</name> + <name name="make_tuple" arity="3"/> <fsummary>Create a new tuple with given arity and contents</fsummary> - <type> - <v>Arity = arity()</v> - <v>Default = term()</v> - <v>InitList = [{Position,term()}]</v> - <v>Position = integer()</v> - </type> - <desc> - <p><c>erlang:make_tuple</c> first creates a tuple of size <c>Arity</c> - where each element has the value <c>Default</c>. It then fills - in values from <c>InitList</c>. Each list element in <c>InitList</c> + <desc> + <p><c>erlang:make_tuple</c> first creates a tuple of size <c><anno>Arity</anno></c> + where each element has the value <c><anno>DefaultValue</anno></c>. It then fills + in values from <c><anno>InitList</anno></c>. Each list element in <c><anno>InitList</anno></c> must be a two-tuple where the first element is a position in the newly created tuple and the second element is any term. If a position occurs more than once in the list, the term corresponding to @@ -2307,15 +1967,11 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:md5(Data) -> Digest</name> + <name name="md5" arity="1"/> <fsummary>Compute an MD5 message digest</fsummary> - <type> - <v>Data = iodata()</v> - <v>Digest = binary()</v> - </type> <desc> - <p>Computes an <c>MD5</c> message digest from <c>Data</c>, where - the length of the digest is 128 bits (16 bytes). <c>Data</c> + <p>Computes an <c>MD5</c> message digest from <c><anno>Data</anno></c>, where + the length of the digest is 128 bits (16 bytes). <c><anno>Data</anno></c> is a binary or a list of small integers and binaries.</p> <p>See The MD5 Message Digest Algorithm (RFC 1321) for more information about MD5.</p> @@ -2324,51 +1980,39 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:md5_final(Context) -> Digest</name> + <name name="md5_final" arity="1"/> <fsummary>Finish the update of an MD5 context and return the computed MD5 message digest</fsummary> - <type> - <v>Context = Digest = binary()</v> - </type> <desc> - <p>Finishes the update of an MD5 <c>Context</c> and returns + <p>Finishes the update of an MD5 <c><anno>Context</anno></c> and returns the computed <c>MD5</c> message digest.</p> </desc> </func> <func> - <name>erlang:md5_init() -> Context</name> + <name name="md5_init" arity="0"/> <fsummary>Create an MD5 context</fsummary> - <type> - <v>Context = binary()</v> - </type> <desc> <p>Creates an MD5 context, to be used in subsequent calls to <c>md5_update/2</c>.</p> </desc> </func> <func> - <name>erlang:md5_update(Context, Data) -> NewContext</name> + <name name="md5_update" arity="2"/> <fsummary>Update an MD5 context with data, and return a new context</fsummary> - <type> - <v>Data = iodata()</v> - <v>Context = NewContext = binary()</v> - </type> <desc> - <p>Updates an MD5 <c>Context</c> with <c>Data</c>, and returns - a <c>NewContext</c>.</p> + <p>Updates an MD5 <c><anno>Context</anno></c> with <c><anno>Data</anno></c>, and returns + a <c><anno>NewContext</anno></c>.</p> </desc> </func> <func> - <name>erlang:memory() -> [{Type, Size}]</name> + <name name="memory" arity="0"/> + <type name="memory_type"/> <fsummary>Information about dynamically allocated memory</fsummary> - <type> - <v>Type, Size -- see below</v> - </type> <desc> <p>Returns a list containing information about memory dynamically allocated by the Erlang emulator. Each element of the list is a tuple <c>{Type, Size}</c>. The first element - <c>Type</c>is an atom describing memory type. The second - element <c>Size</c>is memory size in bytes. A description of + <c><anno>Type</anno></c>is an atom describing memory type. The second + element <c><anno>Size</anno></c>is memory size in bytes. A description of each memory type follows:</p> <taglist> <tag><c>total</c></tag> @@ -2430,6 +2074,14 @@ os_prompt% </pre> <p>This memory is part of the memory presented as <c>system</c> memory.</p> </item> + <tag><c>low</c></tag> + <item> + <p>Only on 64-bit halfword emulator.</p> + <p>The total amount of memory allocated in low memory areas + that are restricted to less than 4 Gb even though + the system may have more physical memory.</p> + <p>May be removed in future releases of halfword emulator.</p> + </item> <tag><c>maximum</c></tag> <item> <p>The maximum total amount of memory allocated since @@ -2441,14 +2093,6 @@ os_prompt% </pre> <seealso marker="tools:instrument">instrument(3)</seealso> and/or <seealso marker="erts:erl">erl(1)</seealso>.</p> </item> - <tag><c>low</c></tag> - <item> - <p>Only on 64-bit halfword emulator.</p> - <p>The total amount of memory allocated in low memory areas - that are restricted to less than 4 Gb even though - the system may have more physical memory.</p> - <p>May be removed in future releases of halfword emulator.</p> - </item> </taglist> <note> <p>The <c>system</c> value is not complete. Some allocated @@ -2512,16 +2156,15 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:memory(Type | [Type]) -> Size | [{Type, Size}]</name> + <name name="memory" arity="1" clause_i="1"/> + <name name="memory" arity="1" clause_i="2"/> + <type name="memory_type"/> <fsummary>Information about dynamically allocated memory</fsummary> - <type> - <v>Type, Size -- see below</v> - </type> <desc> <p>Returns the memory size in bytes allocated for memory of - type <c>Type</c>. The argument can also be given as a list - of <c>Type</c> atoms, in which case a corresponding list of - <c>{Type, Size}</c> tuples is returned.</p> + type <c><anno>Type</anno></c>. The argument can also be given as a list + of <c>memory_type()</c> atoms, in which case a corresponding list of + <c>{memory_type(), Size :: integer >= 0}</c> tuples is returned.</p> <note> <p> Since erts version 5.6.4 <c>erlang:memory/1</c> requires that @@ -2533,13 +2176,13 @@ os_prompt% </pre> <taglist> <tag><c>badarg</c></tag> <item> - If <c>Type</c> is not one of the memory types listed in the + If <c><anno>Type</anno></c> is not one of the memory types listed in the documentation of <seealso marker="#memory/0">erlang:memory/0</seealso>. </item> <tag><c>badarg</c></tag> <item> - If <c>maximum</c> is passed as <c>Type</c> and the emulator + If <c>maximum</c> is passed as <c><anno>Type</anno></c> and the emulator is not run in instrumented mode. </item> <tag><c>notsup</c></tag> @@ -2561,13 +2204,10 @@ os_prompt% </pre> </desc> </func> <func> - <name>module_loaded(Module) -> boolean()</name> + <name name="module_loaded" arity="1"/> <fsummary>Check if a module is loaded</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Returns <c>true</c> if the module <c>Module</c> is loaded, + <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is loaded, otherwise returns <c>false</c>. It does not attempt to load the module.</p> <warning> @@ -2578,22 +2218,15 @@ os_prompt% </pre> </desc> </func> <func> - <name>monitor(Type, Item) -> MonitorRef</name> + <name name="monitor" arity="2"/> <fsummary>Start monitoring</fsummary> - <type> - <v>Type = process</v> - <v>Item = pid() | {RegName, Node} | RegName</v> - <v> RegName = atom()</v> - <v> Node = node()</v> - <v>MonitorRef = reference()</v> - </type> - <desc> - <p>The calling process starts monitoring <c>Item</c> which is - an object of type <c>Type</c>.</p> + <desc> + <p>The calling process starts monitoring <c><anno>Item</anno></c> which is + an object of type <c><anno>Type</anno></c>.</p> <p>Currently only processes can be monitored, i.e. the only - allowed <c>Type</c> is <c>process</c>, but other types may be + allowed <c><anno>Type</anno></c> is <c>process</c>, but other types may be allowed in the future.</p> - <p><c>Item</c> can be:</p> + <p><c><anno>Item</anno></c> can be:</p> <taglist> <tag><c>pid()</c></tag> <item> @@ -2619,8 +2252,8 @@ os_prompt% </pre> unregistered.</p> </note> <p>A <c>'DOWN'</c> message will be sent to the monitoring - process if <c>Item</c> dies, if <c>Item</c> does not exist, - or if the connection is lost to the node which <c>Item</c> + process if <c><anno>Item</anno></c> dies, if <c><anno>Item</anno></c> does not exist, + or if the connection is lost to the node which <c><anno>Item</anno></c> resides on. A <c>'DOWN'</c> message has the following pattern:</p> <code type="none"> {'DOWN', MonitorRef, Type, Object, Info}</code> @@ -2631,11 +2264,11 @@ os_prompt% </pre> <item> <p>A reference to the monitored object:</p> <list type="bulleted"> - <item>the pid of the monitored process, if <c>Item</c> was + <item>the pid of the monitored process, if <c><anno>Item</anno></c> was specified as a pid.</item> - <item><c>{RegName, Node}</c>, if <c>Item</c> was specified as + <item><c>{RegName, Node}</c>, if <c><anno>Item</anno></c> was specified as <c>{RegName, Node}</c>.</item> - <item><c>{RegName, Node}</c>, if <c>Item</c> was specified as + <item><c>{RegName, Node}</c>, if <c><anno>Item</anno></c> was specified as <c>RegName</c>. <c>Node</c> will in this case be the name of the local node (<c>node()</c>).</item> </list> @@ -2644,7 +2277,7 @@ os_prompt% </pre> <item> <p>Either the exit reason of the process, <c>noproc</c> (non-existing process), or <c>noconnection</c> (no - connection to <c>Node</c>).</p> + connection to <c><anno>Node</anno></c>).</p> </item> </taglist> <note> @@ -2662,7 +2295,7 @@ os_prompt% </pre> where remote process monitoring by registered name is not implemented), the call fails with <c>badarg</c>.</p> <p>Making several calls to <c>monitor/2</c> for the same - <c>Item</c> is not an error; it results in as many, completely + <c><anno>Item</anno></c> is not an error; it results in as many, completely independent, monitorings.</p> <note> <p>The format of the <c>'DOWN'</c> message changed in the 5.2 @@ -2680,25 +2313,21 @@ os_prompt% </pre> </desc> </func> <func> - <name>monitor_node(Node, Flag) -> true</name> + <name name="monitor_node" arity="2"/> <fsummary>Monitor the status of a node</fsummary> - <type> - <v>Node = node()</v> - <v>Flag = boolean()</v> - </type> <desc> - <p>Monitors the status of the node <c>Node</c>. If <c>Flag</c> - is <c>true</c>, monitoring is turned on; if <c>Flag</c> is + <p>Monitors the status of the node <c><anno>Node</anno></c>. If <c><anno>Flag</anno></c> + is <c>true</c>, monitoring is turned on; if <c><anno>Flag</anno></c> is <c>false</c>, monitoring is turned off.</p> <p>Making several calls to <c>monitor_node(Node, true)</c> for - the same <c>Node</c> is not an error; it results in as many, + the same <c><anno>Node</anno></c> is not an error; it results in as many, completely independent, monitorings.</p> - <p>If <c>Node</c> fails or does not exist, the message + <p>If <c><anno>Node</anno></c> fails or does not exist, the message <c>{nodedown, Node}</c> is delivered to the process. If a process has made two calls to <c>monitor_node(Node, true)</c> - and <c>Node</c> terminates, two <c>nodedown</c> messages are + and <c><anno>Node</anno></c> terminates, two <c>nodedown</c> messages are delivered to the process. If there is no connection to - <c>Node</c>, there will be an attempt to create one. If this + <c><anno>Node</anno></c>, there will be an attempt to create one. If this fails, a <c>nodedown</c> message is delivered.</p> <p>Nodes connected through hidden connections can be monitored as any other node.</p> @@ -2706,14 +2335,8 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:monitor_node(Node, Flag, Options) -> true</name> + <name name="monitor_node" arity="3"/> <fsummary>Monitor the status of a node</fsummary> - <type> - <v>Node = node()</v> - <v>Flag = boolean()</v> - <v>Options = [Option]</v> - <v>Option = allow_passive_connect</v> - </type> <desc> <p>Behaves as <c>monitor_node/2</c> except that it allows an extra option to be given, namely <c>allow_passive_connect</c>. @@ -2736,11 +2359,8 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:nif_error(Reason)</name> + <name name="nif_error" arity="1"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - </type> <desc> <p>Works exactly like <seealso marker="#error/1">erlang:error/1</seealso>, @@ -2751,12 +2371,8 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:nif_error(Reason, Args)</name> + <name name="nif_error" arity="2"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Works exactly like <seealso marker="#error/2">erlang:error/2</seealso>, @@ -2767,11 +2383,8 @@ os_prompt% </pre> </desc> </func> <func> - <name>node() -> Node</name> + <name name="node" arity="0"/> <fsummary>Name of the local node</fsummary> - <type> - <v>Node = node()</v> - </type> <desc> <p>Returns the name of the local node. If the node is not alive, <c>nonode@nohost</c> is returned instead.</p> @@ -2779,14 +2392,10 @@ os_prompt% </pre> </desc> </func> <func> - <name>node(Arg) -> Node</name> + <name name="node" arity="1"/> <fsummary>At which node is a pid, port or reference located</fsummary> - <type> - <v>Arg = pid() | port() | reference()</v> - <v>Node = node()</v> - </type> <desc> - <p>Returns the node where <c>Arg</c> is located. <c>Arg</c> can + <p>Returns the node where <c><anno>Arg</anno></c> is located. <c><anno>Arg</anno></c> can be a pid, a reference, or a port. If the local node is not alive, <c>nonode@nohost</c> is returned.</p> <p>Allowed in guard tests.</p> @@ -2801,17 +2410,13 @@ os_prompt% </pre> </desc> </func> <func> - <name>nodes(Arg | [Arg]) -> Nodes</name> + <name name="nodes" arity="1"/> <fsummary>All nodes of a certain type in the system</fsummary> - <type> - <v>Arg = visible | hidden | connected | this | known</v> - <v>Nodes = [node()]</v> - </type> <desc> <p>Returns a list of nodes according to argument given. The result returned when the argument is a list, is the list of nodes satisfying the disjunction(s) of the list elements.</p> - <p><c>Arg</c> can be any of the following:</p> + <p><c><anno>NodeType</anno></c> can be any of the following:</p> <taglist> <tag><c>visible</c></tag> <item> @@ -2840,15 +2445,12 @@ os_prompt% </pre> <c>nodes() = nodes(visible)</c>.</p> <p>If the local node is not alive, <c>nodes(this) == nodes(known) == [nonode@nohost]</c>, for - any other <c>Arg</c> the empty list [] is returned.</p> + any other <c><anno>Arg</anno></c> the empty list [] is returned.</p> </desc> </func> <func> - <name>now() -> timestamp()</name> - <type> - <v>timestamp() = {MegaSecs, Secs, MicroSecs}</v> - <v>MegaSecs = Secs = MicroSecs = integer() >= 0</v> - </type> + <name name="now" arity="0"/> + <type name="timestamp"/> <fsummary>Elapsed time since 00:00 GMT</fsummary> <desc> <p>Returns the tuple <c>{MegaSecs, Secs, MicroSecs}</c> which is @@ -2870,35 +2472,19 @@ os_prompt% </pre> </desc> </func> <func> - <name>open_port(PortName, PortSettings) -> port()</name> + <name name="open_port" arity="2"/> <fsummary>Open a port</fsummary> - <type> - <v>PortName = {spawn, Command} | {spawn_driver, Command} | {spawn_executable, FileName} | {fd, In, Out}</v> - <v> Command = string()</v> - <v> FileName = [ FileNameChar ] | binary()</v> - <v> FileNameChar = integer() (1..255 or any Unicode codepoint, see description)</v> - <v> In = Out = integer()</v> - <v>PortSettings = [Opt]</v> - <v> Opt = {packet, N} | stream | {line, L} | {cd, Dir} | {env, Env} | {args, [ ArgString ]} | {arg0, ArgString} | exit_status | use_stdio | nouse_stdio | stderr_to_stdout | in | out | binary | eof</v> - <v> N = 1 | 2 | 4</v> - <v> L = integer()</v> - <v> Dir = string()</v> - <v> ArgString = [ FileNameChar ] | binary()</v> - <v> Env = [{Name, Val}]</v> - <v> Name = string()</v> - <v> Val = string() | false</v> - </type> <desc> <p>Returns a port identifier as the result of opening a new Erlang port. A port can be seen as an external Erlang - process. <c>PortName</c> is one of the following:</p> + process. <c><anno>PortName</anno></c> is one of the following:</p> <taglist> - <tag><c>{spawn, Command}</c></tag> + <tag><c>{spawn, <anno>Command</anno>}</c></tag> <item> - <p>Starts an external program. <c>Command</c> is the name - of the external program which will be run. <c>Command</c> + <p>Starts an external program. <c><anno>Command</anno></c> is the name + of the external program which will be run. <c><anno>Command</anno></c> runs outside the Erlang work space unless an Erlang - driver with the name <c>Command</c> is found. If found, + driver with the name <c><anno>Command</anno></c> is found. If found, that driver will be started. A driver runs in the Erlang workspace, which means that it is linked with the Erlang runtime system.</p> @@ -2918,24 +2504,24 @@ os_prompt% </pre> name of the executable (or driver). This (among other things) makes this option unsuitable for running programs having spaces in file or directory names. Use - {spawn_executable, Command} instead if spaces in executable + {spawn_executable, <anno>Command</anno>} instead if spaces in executable file names is desired.</p> </item> - <tag><c>{spawn_driver, Command}</c></tag> + <tag><c>{spawn_driver, <anno>Command</anno>}</c></tag> <item> - <p>Works like <c>{spawn, Command}</c>, but demands the + <p>Works like <c>{spawn, <anno>Command</anno>}</c>, but demands the first (space separated) token of the command to be the name of a loaded driver. If no driver with that name is loaded, a <c>badarg</c> error is raised.</p> </item> - <tag><c>{spawn_executable, Command}</c></tag> + <tag><c>{spawn_executable, <anno>FileName</anno>}</c></tag> <item> - <p>Works like <c>{spawn, Command}</c>, but only runs - external executables. The <c>Command</c> in its whole + <p>Works like <c>{spawn, <anno>FileName</anno>}</c>, but only runs + external executables. The <c><anno>FileName</anno></c> in its whole is used as the name of the executable, including any spaces. If arguments are to be passed, the - <c>args</c> and <c>arg0</c> <c>PortSettings</c> can be used.</p> + <c>args</c> and <c>arg0</c> <c><anno>PortSettings</anno></c> can be used.</p> <p>The shell is not usually invoked to start the program, it's executed directly. Neither is the @@ -2966,7 +2552,7 @@ os_prompt% </pre> of the executable is limited to the ISO-latin-1 character set.</p></note> - <p>If the <c>Command</c> cannot be run, an error + <p>If the <c><anno>FileName</anno></c> cannot be run, an error exception, with the posix error code as the reason, is raised. The error reason may differ between operating systems. Typically the error <c>enoent</c> is raised @@ -2974,23 +2560,23 @@ os_prompt% </pre> <c>eaccess</c> is raised when the given file is not executable.</p> </item> - <tag><c>{fd, In, Out}</c></tag> + <tag><c>{fd, <anno>In</anno>, <anno>Out</anno>}</c></tag> <item> <p>Allows an Erlang process to access any currently opened file descriptors used by Erlang. The file descriptor - <c>In</c> can be used for standard input, and the file - descriptor <c>Out</c> for standard output. It is only + <c><anno>In</anno></c> can be used for standard input, and the file + descriptor <c><anno>Out</anno></c> for standard output. It is only used for various servers in the Erlang operating system (<c>shell</c> and <c>user</c>). Hence, its use is very limited.</p> </item> </taglist> - <p><c>PortSettings</c> is a list of settings for the port. + <p><c><anno>PortSettings</anno></c> is a list of settings for the port. Valid settings are:</p> <taglist> - <tag><c>{packet, N}</c></tag> + <tag><c>{packet, <anno>N</anno>}</c></tag> <item> - <p>Messages are preceded by their length, sent in <c>N</c> + <p>Messages are preceded by their length, sent in <c><anno>N</anno></c> bytes, with the most significant byte first. Valid values for <c>N</c> are 1, 2, or 4.</p> </item> @@ -3000,7 +2586,7 @@ os_prompt% </pre> user-defined protocol must be used between the Erlang process and the external object.</p> </item> - <tag><c>{line, L}</c></tag> + <tag><c>{line, <anno>L</anno>}</c></tag> <item> <p>Messages are delivered on a per line basis. Each line (delimited by the OS-dependent newline sequence) is @@ -3008,7 +2594,7 @@ os_prompt% </pre> is <c>{Flag, Line}</c>, where <c>Flag</c> is either <c>eol</c> or <c>noeol</c> and <c>Line</c> is the actual data delivered (without the newline sequence).</p> - <p><c>L</c> specifies the maximum line length in bytes. + <p><c><anno>L</anno></c> specifies the maximum line length in bytes. Lines longer than this will be delivered in more than one message, with the <c>Flag</c> set to <c>noeol</c> for all but the last message. If end of file is encountered @@ -3016,36 +2602,36 @@ os_prompt% </pre> sequence, the last line will also be delivered with the <c>Flag</c> set to <c>noeol</c>. In all other cases, lines are delivered with <c>Flag</c> set to <c>eol</c>.</p> - <p>The <c>{packet, N}</c> and <c>{line, L}</c> settings are + <p>The <c>{packet, <anno>N</anno>}</c> and <c>{line, <anno>L</anno>}</c> settings are mutually exclusive.</p> </item> - <tag><c>{cd, Dir}</c></tag> + <tag><c>{cd, <anno>Dir</anno>}</c></tag> <item> - <p>This is only valid for <c>{spawn, Command}</c> and - <c>{spawn_executable, Command}</c>. - The external program starts using <c>Dir</c> as its - working directory. <c>Dir</c> must be a string. Not - available on VxWorks.</p> + <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <c>{spawn_executable, <anno>FileName</anno>}</c>. + The external program starts using <c><anno>Dir</anno></c> as its + working directory. <c><anno>Dir</anno></c> must be a string. + </p> </item> - <tag><c>{env, Env}</c></tag> + <tag><c>{env, <anno>Env</anno>}</c></tag> <item> - <p>This is only valid for <c>{spawn, Command}</c> and - <c>{spawn_executable, Command}</c>. + <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <c>{spawn_executable, <anno>FileName</anno>}</c>. The environment of the started process is extended using - the environment specifications in <c>Env</c>.</p> - <p><c>Env</c> should be a list of tuples <c>{Name, Val}</c>, - where <c>Name</c> is the name of an environment variable, - and <c>Val</c> is the value it is to have in the spawned - port process. Both <c>Name</c> and <c>Val</c> must be - strings. The one exception is <c>Val</c> being the atom + the environment specifications in <c><anno>Env</anno></c>.</p> + <p><c><anno>Env</anno></c> should be a list of tuples <c>{<anno>Name</anno>, <anno>Val</anno>}</c>, + where <c><anno>Name</anno></c> is the name of an environment variable, + and <c><anno>Val</anno></c> is the value it is to have in the spawned + port process. Both <c><anno>Name</anno></c> and <c><anno>Val</anno></c> must be + strings. The one exception is <c><anno>Val</anno></c> being the atom <c>false</c> (in analogy with <c>os:getenv/1</c>), which - removes the environment variable. Not available on - VxWorks.</p> + removes the environment variable. + </p> </item> - <tag><c>{args, [ string() ]}</c></tag> + <tag><c>{args, [ string() | binary() ]}</c></tag> <item> - <p>This option is only valid for <c>{spawn_executable, Command}</c> + <p>This option is only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> and specifies arguments to the executable. Each argument is given as a separate string and (on Unix) eventually ends up as one element each in the argument vector. On @@ -3088,10 +2674,10 @@ os_prompt% </pre> option can be used.</p> </item> - <tag><c>{arg0, string()}</c></tag> + <tag><c>{arg0, string() | binary()}</c></tag> <item> - <p>This option is only valid for <c>{spawn_executable, Command}</c> + <p>This option is only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> and explicitly specifies the program name argument when running an executable. This might in some circumstances, on some operating systems, be desirable. How the program @@ -3105,9 +2691,9 @@ os_prompt% </pre> <tag><c>exit_status</c></tag> <item> - <p>This is only valid for <c>{spawn, Command}</c> where - <c>Command</c> refers to an external program, and for - <c>{spawn_executable, Command}</c>.</p> + <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> where + <c><anno>Command</anno></c> refers to an external program, and for + <c>{spawn_executable, <anno>FileName</anno>}</c>.</p> <p>When the external process connected to the port exits, a message of the form <c>{Port,{exit_status,Status}}</c> is sent to the connected process, where <c>Status</c> is the @@ -3122,8 +2708,8 @@ os_prompt% </pre> </item> <tag><c>use_stdio</c></tag> <item> - <p>This is only valid for <c>{spawn, Command}</c> and - <c>{spawn_executable, Command}</c>. It + <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <c>{spawn_executable, <anno>FileName</anno>}</c>. It allows the standard input and output (file descriptors 0 and 1) of the spawned (UNIX) process for communication with Erlang.</p> @@ -3220,7 +2806,7 @@ os_prompt% </pre> </item> <tag><c>enoent</c></tag> <item> - <p>The <c>Command</c> given in <c>{spawn_executable, Command}</c> does not point out an existing file.</p> + <p>The <c><anno>FileName</anno></c> given in <c>{spawn_executable, <anno>FileName</anno>}</c> does not point out an existing file.</p> </item> </taglist> <p>During use of a port opened using <c>{spawn, Name}</c>, @@ -3236,56 +2822,47 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:phash(Term, Range) -> Hash</name> + <name name="phash" arity="2"/> + <type_desc variable="Range">Range = 1..2^32, Hash = 1..Range</type_desc> <fsummary>Portable hash function</fsummary> - <type> - <v>Term = term()</v> - <v>Range = 1..2^32</v> - <v>Hash = 1..Range</v> - </type> <desc> <p>Portable hash function that will give the same hash for the same Erlang term regardless of machine architecture and ERTS version (the BIF was introduced in ERTS 4.9.1.1). Range can be between 1 and 2^32, the function returns a hash value - for <c>Term</c> within the range <c>1..Range</c>.</p> + for <c><anno>Term</anno></c> within the range <c>1..<anno>Range</anno></c>.</p> <p>This BIF could be used instead of the old deprecated <c>erlang:hash/2</c> BIF, as it calculates better hashes for all data-types, but consider using <c>phash2/1,2</c> instead.</p> </desc> </func> <func> - <name>erlang:phash2(Term [, Range]) -> Hash</name> + <name name="phash2" arity="1"/> + <name name="phash2" arity="2"/> + <type_desc variable="Range">1..2^32</type_desc> + <type_desc variable="Hash">0..Range-1</type_desc> <fsummary>Portable hash function</fsummary> - <type> - <v>Term = term()</v> - <v>Range = 1..2^32</v> - <v>Hash = 0..Range-1</v> - </type> <desc> <p>Portable hash function that will give the same hash for the same Erlang term regardless of machine architecture and ERTS version (the BIF was introduced in ERTS 5.2). Range can be between 1 and 2^32, the function returns a hash value for - <c>Term</c> within the range <c>0..Range-1</c>. When called - without the <c>Range</c> argument, a value in the range + <c><anno>Term</anno></c> within the range <c>0..<anno>Range</anno>-1</c>. When called + without the <c><anno>Range</anno></c> argument, a value in the range <c>0..2^27-1</c> is returned.</p> <p>This BIF should always be used for hashing terms. It distributes small integers better than <c>phash/2</c>, and it is faster for bignums and binaries.</p> - <p>Note that the range <c>0..Range-1</c> is different from - the range of <c>phash/2</c> (<c>1..Range</c>).</p> + <p>Note that the range <c>0..<anno>Range</anno>-1</c> is different from + the range of <c>phash/2</c> (<c>1..<anno>Range</anno></c>).</p> </desc> </func> <func> - <name>pid_to_list(Pid) -> string()</name> + <name name="pid_to_list" arity="1"/> <fsummary>Text representation of a pid</fsummary> - <type> - <v>Pid = pid()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Pid</c>.</p> + representation of <c><anno>Pid</anno></c>.</p> <warning> <p>This BIF is intended for debugging and for use in the Erlang operating system. It should not be used in @@ -3294,88 +2871,74 @@ os_prompt% </pre> </desc> </func> <func> - <name>port_close(Port) -> true</name> + <name name="port_close" arity="1"/> <fsummary>Close an open port</fsummary> - <type> - <v>Port = port() | atom()</v> - </type> <desc> <p>Closes an open port. Roughly the same as - <c>Port ! {self(), close}</c> except for the error behaviour + <c><anno>Port</anno> ! {self(), close}</c> except for the error behaviour (see below), and that the port does <em>not</em> reply with <c>{Port, closed}</c>. Any process may close a port with <c>port_close/1</c>, not only the port owner (the connected process).</p> - <p>For comparison: <c>Port ! {self(), close}</c> fails with - <c>badarg</c> if <c>Port</c> cannot be sent to (i.e., - <c>Port</c> refers neither to a port nor to a process). If - <c>Port</c> is a closed port nothing happens. If <c>Port</c> + <p>For comparison: <c><anno>Port</anno> ! {self(), close}</c> fails with + <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e., + <c><anno>Port</anno></c> refers neither to a port nor to a process). If + <c><anno>Port</anno></c> is a closed port nothing happens. If <c><anno>Port</anno></c> is an open port and the calling process is the port owner, the port replies with <c>{Port, closed}</c> when all buffers have been flushed and the port really closes, but if the calling process is not the port owner the <em>port owner</em> fails with <c>badsig</c>.</p> <p>Note that any process can close a port using - <c>Port ! {PortOwner, close}</c> just as if it itself was + <c><anno>Port</anno> ! {PortOwner, close}</c> just as if it itself was the port owner, but the reply always goes to the port owner.</p> <p>In short: <c>port_close(Port)</c> has a cleaner and more - logical behaviour than <c>Port ! {self(), close}</c>.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not an open port or + logical behaviour than <c><anno>Port</anno> ! {self(), close}</c>.</p> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or the registered name of an open port.</p> </desc> </func> <func> - <name>port_command(Port, Data) -> true</name> + <name name="port_command" arity="2"/> <fsummary>Send data to a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Data = iodata()</v> - </type> <desc> <p>Sends data to a port. Same as - <c>Port ! {self(), {command, Data}}</c> except for the error + <c><anno>Port</anno> ! {self(), {command, Data}}</c> except for the error behaviour (see below). Any process may send data to a port with <c>port_command/2</c>, not only the port owner (the connected process).</p> - <p>For comparison: <c>Port ! {self(), {command, Data}}</c> - fails with <c>badarg</c> if <c>Port</c> cannot be sent to - (i.e., <c>Port</c> refers neither to a port nor to a process). - If <c>Port</c> is a closed port the data message disappears - without a sound. If <c>Port</c> is open and the calling + <p>For comparison: <c><anno>Port</anno> ! {self(), {command, Data}}</c> + fails with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to + (i.e., <c><anno>Port</anno></c> refers neither to a port nor to a process). + If <c><anno>Port</anno></c> is a closed port the data message disappears + without a sound. If <c><anno>Port</anno></c> is open and the calling process is not the port owner, the <em>port owner</em> fails with <c>badsig</c>. The port owner fails with <c>badsig</c> - also if <c>Data</c> is not a valid IO list.</p> + also if <c><anno>Data</anno></c> is not a valid IO list.</p> <p>Note that any process can send to a port using - <c>Port ! {PortOwner, {command, Data}}</c> just as if it + <c><anno>Port</anno> ! {PortOwner, {command, <anno>Data</anno>}}</c> just as if it itself was the port owner.</p> - <p>In short: <c>port_command(Port, Data)</c> has a cleaner and + <p>In short: <c>port_command(<anno>Port</anno>, <anno>Data</anno>)</c> has a cleaner and more logical behaviour than - <c>Port ! {self(), {command, Data}}</c>.</p> + <c><anno>Port</anno> ! {self(), {command, Data}}</c>.</p> <p>If the port is busy, the calling process will be suspended until the port is not busy anymore.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> - If <c>Port</c> is not an open port or the registered name + If <c><anno>Port</anno></c> is not an open port or the registered name of an open port. </item> <tag><c>badarg</c></tag> <item> - If <c>Data</c> is not a valid io list. + If <c><anno>Data</anno></c> is not a valid io list. </item> </taglist> </desc> </func> <func> - <name>port_command(Port, Data, OptionList) -> boolean()</name> + <name name="port_command" arity="3"/> <fsummary>Send data to a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Data = iodata()</v> - <v>OptionList = [Option]</v> - <v>Option = force</v> - <v>Option = nosuspend</v> - </type> <desc> <p>Sends data to a port. <c>port_command(Port, Data, [])</c> equals <c>port_command(Port, Data)</c>.</p> @@ -3383,7 +2946,7 @@ os_prompt% </pre> otherwise, <c>true</c> is returned.</p> <p>If the port is busy, the calling process will be suspended until the port is not busy anymore.</p> - <p>Currently the following <c>Option</c>s are valid:</p> + <p>Currently the following <c><anno>Option</anno></c>s are valid:</p> <taglist> <tag><c>force</c></tag> <item>The calling process will not be suspended if the port is @@ -3407,16 +2970,16 @@ os_prompt% </pre> <taglist> <tag><c>badarg</c></tag> <item> - If <c>Port</c> is not an open port or the registered name + If <c><anno>Port</anno></c> is not an open port or the registered name of an open port. </item> <tag><c>badarg</c></tag> <item> - If <c>Data</c> is not a valid io list. + If <c><anno>Data</anno></c> is not a valid io list. </item> <tag><c>badarg</c></tag> <item> - If <c>OptionList</c> is not a valid option list. + If <c><anno>OptionList</anno></c> is not a valid option list. </item> <tag><c>notsup</c></tag> <item> @@ -3428,15 +2991,11 @@ os_prompt% </pre> </desc> </func> <func> - <name>port_connect(Port, Pid) -> true</name> + <name name="port_connect" arity="2"/> <fsummary>Set the owner of a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Pid = pid()</v> - </type> <desc> - <p>Sets the port owner (the connected port) to <c>Pid</c>. - Roughly the same as <c>Port ! {self(), {connect, Pid}}</c> + <p>Sets the port owner (the connected port) to <c><anno>Pid</anno></c>. + Roughly the same as <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c> except for the following:</p> <list type="bulleted"> <item> @@ -3454,164 +3013,146 @@ os_prompt% </pre> <c>unlink(Port)</c> if this is not desired. Any process may set the port owner to be any process with <c>port_connect/2</c>.</p> - <p>For comparison: <c>Port ! {self(), {connect, Pid}}</c> fails - with <c>badarg</c> if <c>Port</c> cannot be sent to (i.e., - <c>Port</c> refers neither to a port nor to a process). If - <c>Port</c> is a closed port nothing happens. If <c>Port</c> + <p>For comparison: <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c> fails + with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e., + <c><anno>Port</anno></c> refers neither to a port nor to a process). If + <c><anno>Port</anno></c> is a closed port nothing happens. If <c><anno>Port</anno></c> is an open port and the calling process is the port owner, the port replies with <c>{Port, connected}</c> to the old port owner. Note that the old port owner is still linked to - the port, and that the new is not. If <c>Port</c> is an open + the port, and that the new is not. If <c><anno>Port</anno></c> is an open port and the calling process is not the port owner, the <em>port owner</em> fails with <c>badsig</c>. The port - owner fails with <c>badsig</c> also if <c>Pid</c> is not an + owner fails with <c>badsig</c> also if <c><anno>Pid</anno></c> is not an existing local pid.</p> <p>Note that any process can set the port owner using - <c>Port ! {PortOwner, {connect, Pid}}</c> just as if it + <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> just as if it itself was the port owner, but the reply always goes to the port owner.</p> - <p>In short: <c>port_connect(Port, Pid)</c> has a cleaner and + <p>In short: <c>port_connect(<anno>Port</anno>, <anno>Pid</anno>)</c> has a cleaner and more logical behaviour than - <c>Port ! {self(),{connect,Pid}}</c>.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not an open port - or the registered name of an open port, or if <c>Pid</c> is + <c><anno>Port</anno> ! {self(),{connect,<anno>Pid</anno>}}</c>.</p> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port + or the registered name of an open port, or if <c><anno>Pid</anno></c> is not an existing local pid.</p> </desc> </func> <func> - <name>port_control(Port, Operation, Data) -> Res</name> + <name name="port_control" arity="3"/> <fsummary>Perform a synchronous control operation on a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Operation = integer()</v> - <v>Data = Res = iodata()</v> - </type> <desc> <p>Performs a synchronous control operation on a port. - The meaning of <c>Operation</c> and <c>Data</c> depends on + The meaning of <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> depends on the port, i.e., on the port driver. Not all port drivers support this control feature.</p> <p>Returns: a list of integers in the range 0 through 255, or a binary, depending on the port driver. The meaning of the returned data also depends on the port driver.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not an open port or - the registered name of an open port, if <c>Operation</c> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or + the registered name of an open port, if <c><anno>Operation</anno></c> cannot fit in a 32-bit integer, if the port driver does not support synchronous control operations, or if the port driver so decides for any reason (probably something wrong with - <c>Operation</c> or <c>Data</c>).</p> + <c><anno>Operation</anno></c> or <c><anno>Data</anno></c>).</p> </desc> </func> <func> - <name>erlang:port_call(Port, Operation, Data) -> term()</name> + <name name="port_call" arity="3"/> <fsummary>Synchronous call to a port with term data</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Operation = integer()</v> - <v>Data = term()</v> - </type> <desc> <p>Performs a synchronous call to a port. The meaning of - <c>Operation</c> and <c>Data</c> depends on the port, i.e., + <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> depends on the port, i.e., on the port driver. Not all port drivers support this feature.</p> - <p><c>Port</c> is a port identifier, referring to a driver.</p> - <p><c>Operation</c> is an integer, which is passed on to + <p><c><anno>Port</anno></c> is a port identifier, referring to a driver.</p> + <p><c><anno>Operation</anno></c> is an integer, which is passed on to the driver.</p> - <p><c>Data</c> is any Erlang term. This data is converted to + <p><c><anno>Data</anno></c> is any Erlang term. This data is converted to binary term format and sent to the port.</p> <p>Returns: a term from the driver. The meaning of the returned data also depends on the port driver.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not an open port or - the registered name of an open port, if <c>Operation</c> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or + the registered name of an open port, if <c><anno>Operation</anno></c> cannot fit in a 32-bit integer, if the port driver does not support synchronous control operations, or if the port driver so decides for any reason (probably something wrong with - <c>Operation</c> or <c>Data</c>).</p> + <c><anno>Operation</anno></c> or <c><anno>Data</anno></c>).</p> </desc> </func> <func> - <name>erlang:port_info(Port) -> [{Item, Info}] | undefined</name> + <name name="port_info" arity="1"/> + <type name="port_info_result_item"/> <fsummary>Information about a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Item, Info -- see below</v> - </type> <desc> <p>Returns a list containing tuples with information about - the <c>Port</c>, or <c>undefined</c> if the port is not open. + the <c><anno>Port</anno></c>, or <c>undefined</c> if the port is not open. The order of the tuples is not defined, nor are all the tuples mandatory.</p> <taglist> - <tag><c>{registered_name, RegName}</c></tag> + <tag><c>{registered_name, <anno>RegName</anno>}</c></tag> <item> - <p><c>RegName</c> (an atom) is the registered name of + <p><c><anno>RegName</anno></c> (an atom) is the registered name of the port. If the port has no registered name, this tuple is not present in the list.</p> </item> - <tag><c>{id, Index}</c></tag> + <tag><c>{id, <anno>Index</anno>}</c></tag> <item> - <p><c>Index</c> (an integer) is the internal index of the + <p><c><anno>Index</anno></c> (an integer) is the internal index of the port. This index may be used to separate ports.</p> </item> - <tag><c>{connected, Pid}</c></tag> + <tag><c>{connected, <anno>Pid</anno>}</c></tag> <item> - <p><c>Pid</c> is the process connected to the port.</p> + <p><c><anno>Pid</anno></c> is the process connected to the port.</p> </item> - <tag><c>{links, Pids}</c></tag> + <tag><c>{links, <anno>Pids</anno>}</c></tag> <item> - <p><c>Pids</c> is a list of pids to which processes the + <p><c><anno>Pids</anno></c> is a list of pids to which processes the port is linked.</p> </item> - <tag><c>{name, String}</c></tag> + <tag><c>{name, <anno>String</anno>}</c></tag> <item> - <p><c>String</c> is the command name set by + <p><c><anno>String</anno></c> is the command name set by <c>open_port</c>.</p> </item> - <tag><c>{input, Bytes}</c></tag> + <tag><c>{input, <anno>Bytes</anno>}</c></tag> <item> - <p><c>Bytes</c> is the total number of bytes read from + <p><c><anno>Bytes</anno></c> is the total number of bytes read from the port.</p> </item> - <tag><c>{output, Bytes}</c></tag> + <tag><c>{output, <anno>Bytes</anno>}</c></tag> <item> - <p><c>Bytes</c> is the total number of bytes written to + <p><c><anno>Bytes</anno></c> is the total number of bytes written to the port.</p> </item> - <tag><c>{os_pid, Integer | undefined}</c></tag> + <tag><c>{os_pid, <anno>OsPid</anno> | undefined}</c></tag> <item> - <p><c>Integer</c> is the process identifier (or equivalent) of an OS process created with <c>open_port({spawn | spawn_executable, Command}, Options)</c>. If the port is not the result of spawning an OS process, the value is <c>undefined</c>.</p> + <p><c> <anno>OsPid</anno></c> is the process identifier (or equivalent) of an OS process created with <c>open_port({spawn | spawn_executable, Command}, Options)</c>. If the port is not the result of spawning an OS process, the value is <c>undefined</c>.</p> </item> </taglist> - <p>Failure: <c>badarg</c> if <c>Port</c> is not a local port.</p> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port.</p> </desc> </func> <func> - <name>erlang:port_info(Port, Item) -> {Item, Info} | undefined | []</name> + <name name="port_info" arity="2"/> + <type name="port_info_item"/> + <type name="port_info_result_item"/> <fsummary>Information about a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Item, Info -- see below</v> - </type> - <desc> - <p>Returns information about <c>Port</c> as specified - by <c>Item</c>, or <c>undefined</c> if the port is not open. - Also, if <c>Item == registered_name</c> and the port has no - registered name, [] is returned.</p> - <p>For valid values of <c>Item</c>, and corresponding - values of <c>Info</c>, see + <desc> + <p>Returns information about <c><anno>Port</anno></c> as specified + by <c><anno>Item</anno></c>, or <c>undefined</c> if the port is not open. + Also, if <c>Item =:= registered_name</c> and the port has no + registered name, <c>[]</c> is returned.</p> + <p>For valid values of <c><anno>Item</anno></c>, and corresponding + values of <c><anno>Result</anno></c>, see <seealso marker="#port_info/1">erlang:port_info/1</seealso>.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not a local port.</p> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port.</p> </desc> </func> <func> - <name>erlang:port_to_list(Port) -> string()</name> + <name name="port_to_list" arity="1"/> <fsummary>Text representation of a port identifier</fsummary> - <type> - <v>Port = port()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of the port identifier <c>Port</c>.</p> + representation of the port identifier <c><anno>Port</anno></c>.</p> <warning> <p>This BIF is intended for debugging and for use in the Erlang operating system. It should not be used in @@ -3620,18 +3161,15 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:ports() -> [port()]</name> + <name name="ports" arity="0"/> <fsummary>All open ports</fsummary> <desc> <p>Returns a list of all ports on the local node.</p> </desc> </func> <func> - <name>pre_loaded() -> [Module]</name> + <name name="pre_loaded" arity="0"/> <fsummary>List of all pre-loaded modules</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> <p>Returns a list of Erlang modules which are pre-loaded in the system. As all loading of code is done through the file @@ -3640,220 +3178,222 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:process_display(Pid, Type) -> void()</name> + <name name="process_display" arity="2"/> <fsummary>Write information about a local process on standard error</fsummary> - <type> - <v>Pid = pid()</v> - <v>Type = backtrace</v> - </type> <desc> - <p>Writes information about the local process <c>Pid</c> on + <p>Writes information about the local process <c><anno>Pid</anno></c> on standard error. The currently allowed value for the atom - <c>Type</c> is <c>backtrace</c>, which shows the contents of + <c><anno>Type</anno></c> is <c>backtrace</c>, which shows the contents of the call stack, including information about the call chain, with the current function printed first. The format of the output is not further defined.</p> </desc> </func> <func> - <name>process_flag(Flag, Value) -> OldValue</name> - <fsummary>Set process flags for the calling process</fsummary> - <type> - <v>Flag, Value, OldValue -- see below</v> - </type> + <name name="process_flag" arity="2" clause_i="1"/> + <fsummary>Set process flag trap_exit for the calling process</fsummary> <desc> - <p>Sets certain flags for the process which calls this - function. Returns the old value of the flag.</p> - <taglist> - <tag><c>process_flag(trap_exit, Boolean)</c></tag> - <item> - <p>When <c>trap_exit</c> is set to <c>true</c>, exit signals - arriving to a process are converted to <c>{'EXIT', From, Reason}</c> messages, which can be received as ordinary - messages. If <c>trap_exit</c> is set to <c>false</c>, the - process exits if it receives an exit signal other than - <c>normal</c> and the exit signal is propagated to its - linked processes. Application processes should normally - not trap exits.</p> - <p>See also <seealso marker="#exit/2">exit/2</seealso>.</p> - </item> - <tag><c>process_flag(error_handler, Module)</c></tag> - <item> - <p>This is used by a process to redefine the error handler - for undefined function calls and undefined registered - processes. Inexperienced users should not use this flag - since code auto-loading is dependent on the correct - operation of the error handling module.</p> - </item> - <tag><c>process_flag(min_heap_size, MinHeapSize)</c></tag> - <item> - <p>This changes the minimum heap size for the calling - process.</p> - </item> - <tag><c>process_flag(min_bin_vheap_size, MinBinVHeapSize)</c></tag> - <item> - <p>This changes the minimum binary virtual heap size for the calling - process.</p> - </item> - <tag><marker id="process_flag_priority"><c>process_flag(priority, Level)</c></marker></tag> - <item> - <p>This sets the process priority. <c>Level</c> is an atom. - There are currently four priority levels: <c>low</c>, - <c>normal</c>, <c>high</c>, and <c>max</c>. The default - priority level is <c>normal</c>. <em>NOTE</em>: The - <c>max</c> priority level is reserved for internal use in - the Erlang runtime system, and should <em>not</em> be used - by others. - </p> - <p>Internally in each priority level processes are scheduled - in a round robin fashion. - </p> - <p>Execution of processes on priority <c>normal</c> and - priority <c>low</c> will be interleaved. Processes on - priority <c>low</c> will be selected for execution less - frequently than processes on priority <c>normal</c>. - </p> - <p>When there are runnable processes on priority <c>high</c> - no processes on priority <c>low</c>, or <c>normal</c> will - be selected for execution. Note, however, that this does - <em>not</em> mean that no processes on priority <c>low</c>, - or <c>normal</c> will be able to run when there are - processes on priority <c>high</c> running. On the runtime - system with SMP support there might be more processes running - in parallel than processes on priority <c>high</c>, i.e., - a <c>low</c>, and a <c>high</c> priority process might - execute at the same time. - </p> - <p>When there are runnable processes on priority <c>max</c> - no processes on priority <c>low</c>, <c>normal</c>, or - <c>high</c> will be selected for execution. As with the - <c>high</c> priority, processes on lower priorities might - execute in parallel with processes on priority <c>max</c>. - </p> - <p>Scheduling is preemptive. Regardless of priority, a process - is preempted when it has consumed more than a certain amount - of reductions since the last time it was selected for - execution. - </p> - <p><em>NOTE</em>: You should not depend on the scheduling - to remain exactly as it is today. Scheduling, at least on - the runtime system with SMP support, is very likely to be - modified in the future in order to better utilize available - processor cores. - </p> - <p>There is currently <em>no</em> automatic mechanism for - avoiding priority inversion, such as priority inheritance, - or priority ceilings. When using priorities you have - to take this into account and handle such scenarios by - yourself. - </p> - <p>Making calls from a <c>high</c> priority process into code - that you don't have control over may cause the <c>high</c> - priority process to wait for a processes with lower - priority, i.e., effectively decreasing the priority of the - <c>high</c> priority process during the call. Even if this - isn't the case with one version of the code that you don't - have under your control, it might be the case in a future - version of it. This might, for example, happen if a - <c>high</c> priority process triggers code loading, since - the code server runs on priority <c>normal</c>. - </p> - <p>Other priorities than <c>normal</c> are normally not needed. - When other priorities are used, they need to be used - with care, especially the <c>high</c> priority <em>must</em> - be used with care. A process on <c>high</c> priority should - only perform work for short periods of time. Busy looping for - long periods of time in a <c>high</c> priority process will - most likely cause problems, since there are important servers - in OTP running on priority <c>normal</c>. - </p> - </item> - - <tag><c>process_flag(save_calls, N)</c></tag> - <item> - <p><c>N</c> must be an integer in the interval 0..10000. - If <c>N</c> > 0, call saving is made active for the - process, which means that information about the <c>N</c> - most recent global function calls, BIF calls, sends and - receives made by the process are saved in a list, which - can be retrieved with - <c>process_info(Pid, last_calls)</c>. A global function - call is one in which the module of the function is - explicitly mentioned. Only a fixed amount of information - is saved: a tuple <c>{Module, Function, Arity}</c> for - function calls, and the mere atoms <c>send</c>, - <c>'receive'</c> and <c>timeout</c> for sends and receives - (<c>'receive'</c> when a message is received and - <c>timeout</c> when a receive times out). If <c>N</c> = 0, - call saving is disabled for the process, which is the - default. Whenever the size of the call saving list is set, - its contents are reset.</p> - </item> - <tag><c>process_flag(sensitive, Boolean)</c></tag> - <item> - <p>Set or clear the <c>sensitive</c> flag for the current process. - When a process has been marked as sensitive by calling - <c>process_flag(sensitive, true)</c>, features in the run-time - system that can be used for examining the data and/or inner working - of the process are silently disabled.</p> - <p>Features that are disabled include (but are not limited to) - the following:</p> - <p>Tracing: Trace flags can still be set for the process, but no - trace messages of any kind will be generated. - (If the <c>sensitive</c> flag is turned off, trace messages will - again be generated if there are any trace flags set.)</p> - <p>Sequential tracing: The sequential trace token will be propagated - as usual, but no sequential trace messages will be generated.</p> - <p><c>process_info/1,2</c> cannot be used to read out the message - queue or the process dictionary (both will be returned as empty lists).</p> - <p>Stack back-traces cannot be displayed for the process.</p> - <p>In crash dumps, the stack, messages, and the process dictionary - will be omitted.</p> - <p>If <c>{save_calls,N}</c> has been set for the process, no - function calls will be saved to the call saving list. - (The call saving list will not be cleared; furthermore, send, receive, - and timeout events will still be added to the list.)</p> - </item> - </taglist> + <p>When <c>trap_exit</c> is set to <c>true</c>, exit signals + arriving to a process are converted to <c>{'EXIT', From, Reason}</c> messages, which can be received as ordinary + messages. If <c>trap_exit</c> is set to <c>false</c>, the + process exits if it receives an exit signal other than + <c>normal</c> and the exit signal is propagated to its + linked processes. Application processes should normally + not trap exits.</p> + <p>Returns the old value of the flag.</p> + <p>See also <seealso marker="#exit/2">exit/2</seealso>.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="2"/> + <fsummary>Set process flag error_handler for the calling process</fsummary> + <desc> + <p>This is used by a process to redefine the error handler + for undefined function calls and undefined registered + processes. Inexperienced users should not use this flag + since code auto-loading is dependent on the correct + operation of the error handling module.</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="3"/> + <fsummary>Set process flag min_heap_size for the calling process</fsummary> + <desc> + <p>This changes the minimum heap size for the calling + process.</p> + <p>Returns the old value of the flag.</p> </desc> </func> <func> - <name>process_flag(Pid, Flag, Value) -> OldValue</name> + <name name="process_flag" arity="2" clause_i="4"/> + <fsummary>Set process flag min_bin_vheap_size for the calling process</fsummary> + <desc> + <p>This changes the minimum binary virtual heap size for the calling + process.</p> + <p>Returns the old value of the flag.</p> </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="5"/> + <type name="priority_level"/> + <fsummary>Set process flag priority for the calling process</fsummary> + <desc> + <p><marker id="process_flag_priority"></marker> + This sets the process priority. <c><anno>Level</anno></c> is an atom. + There are currently four priority levels: <c>low</c>, + <c>normal</c>, <c>high</c>, and <c>max</c>. The default + priority level is <c>normal</c>. <em>NOTE</em>: The + <c>max</c> priority level is reserved for internal use in + the Erlang runtime system, and should <em>not</em> be used + by others. + </p> + <p>Internally in each priority level processes are scheduled + in a round robin fashion. + </p> + <p>Execution of processes on priority <c>normal</c> and + priority <c>low</c> will be interleaved. Processes on + priority <c>low</c> will be selected for execution less + frequently than processes on priority <c>normal</c>. + </p> + <p>When there are runnable processes on priority <c>high</c> + no processes on priority <c>low</c>, or <c>normal</c> will + be selected for execution. Note, however, that this does + <em>not</em> mean that no processes on priority <c>low</c>, + or <c>normal</c> will be able to run when there are + processes on priority <c>high</c> running. On the runtime + system with SMP support there might be more processes running + in parallel than processes on priority <c>high</c>, i.e., + a <c>low</c>, and a <c>high</c> priority process might + execute at the same time. + </p> + <p>When there are runnable processes on priority <c>max</c> + no processes on priority <c>low</c>, <c>normal</c>, or + <c>high</c> will be selected for execution. As with the + <c>high</c> priority, processes on lower priorities might + execute in parallel with processes on priority <c>max</c>. + </p> + <p>Scheduling is preemptive. Regardless of priority, a process + is preempted when it has consumed more than a certain amount + of reductions since the last time it was selected for + execution. + </p> + <p><em>NOTE</em>: You should not depend on the scheduling + to remain exactly as it is today. Scheduling, at least on + the runtime system with SMP support, is very likely to be + modified in the future in order to better utilize available + processor cores. + </p> + <p>There is currently <em>no</em> automatic mechanism for + avoiding priority inversion, such as priority inheritance, + or priority ceilings. When using priorities you have + to take this into account and handle such scenarios by + yourself. + </p> + <p>Making calls from a <c>high</c> priority process into code + that you don't have control over may cause the <c>high</c> + priority process to wait for a processes with lower + priority, i.e., effectively decreasing the priority of the + <c>high</c> priority process during the call. Even if this + isn't the case with one version of the code that you don't + have under your control, it might be the case in a future + version of it. This might, for example, happen if a + <c>high</c> priority process triggers code loading, since + the code server runs on priority <c>normal</c>. + </p> + <p>Other priorities than <c>normal</c> are normally not needed. + When other priorities are used, they need to be used + with care, especially the <c>high</c> priority <em>must</em> + be used with care. A process on <c>high</c> priority should + only perform work for short periods of time. Busy looping for + long periods of time in a <c>high</c> priority process will + most likely cause problems, since there are important servers + in OTP running on priority <c>normal</c>. + </p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="6"/> + <fsummary>Set process flag save_calls for the calling process</fsummary> + <desc> + <p><c><anno>N</anno></c> must be an integer in the interval 0..10000. + If <c><anno>N</anno></c> > 0, call saving is made active for the + process, which means that information about the <c><anno>N</anno></c> + most recent global function calls, BIF calls, sends and + receives made by the process are saved in a list, which + can be retrieved with + <c>process_info(Pid, last_calls)</c>. A global function + call is one in which the module of the function is + explicitly mentioned. Only a fixed amount of information + is saved: a tuple <c>{Module, Function, Arity}</c> for + function calls, and the mere atoms <c>send</c>, + <c>'receive'</c> and <c>timeout</c> for sends and receives + (<c>'receive'</c> when a message is received and + <c>timeout</c> when a receive times out). If <c>N</c> = 0, + call saving is disabled for the process, which is the + default. Whenever the size of the call saving list is set, + its contents are reset.</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="7"/> + <fsummary>Set process flag sensitive for the calling process</fsummary> + <desc> + <p>Set or clear the <c>sensitive</c> flag for the current process. + When a process has been marked as sensitive by calling + <c>process_flag(sensitive, true)</c>, features in the run-time + system that can be used for examining the data and/or inner working + of the process are silently disabled.</p> + <p>Features that are disabled include (but are not limited to) + the following:</p> + <p>Tracing: Trace flags can still be set for the process, but no + trace messages of any kind will be generated. + (If the <c>sensitive</c> flag is turned off, trace messages will + again be generated if there are any trace flags set.)</p> + <p>Sequential tracing: The sequential trace token will be propagated + as usual, but no sequential trace messages will be generated.</p> + <p><c>process_info/1,2</c> cannot be used to read out the message + queue or the process dictionary (both will be returned as empty lists).</p> + <p>Stack back-traces cannot be displayed for the process.</p> + <p>In crash dumps, the stack, messages, and the process dictionary + will be omitted.</p> + <p>If <c>{save_calls,N}</c> has been set for the process, no + function calls will be saved to the call saving list. + (The call saving list will not be cleared; furthermore, send, receive, + and timeout events will still be added to the list.)</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="3"/> <fsummary>Set process flags for a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Flag, Value, OldValue -- see below</v> - </type> <desc> - <p>Sets certain flags for the process <c>Pid</c>, in the same + <p>Sets certain flags for the process <c><anno>Pid</anno></c>, in the same manner as <seealso marker="#process_flag/2">process_flag/2</seealso>. Returns the old value of the flag. The allowed values for - <c>Flag</c> are only a subset of those allowed in + <c><anno>Flag</anno></c> are only a subset of those allowed in <c>process_flag/2</c>, namely: <c>save_calls</c>.</p> - <p>Failure: <c>badarg</c> if <c>Pid</c> is not a local process.</p> + <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a local process.</p> </desc> </func> <func> - <name>process_info(Pid) -> InfoResult</name> + <name name="process_info" arity="1"/> + <type name="process_info_result_item"/> + <type name="priority_level"/> + <type name="stack_item"/> <fsummary>Information about a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Item = atom()</v> - <v>Info = term()</v> - <v>InfoTuple = {Item, Info}</v> - <v>InfoTupleList = [InfoTuple]</v> - <v>InfoResult = InfoTupleList | undefined</v> - </type> - <desc> - <p>Returns a list containing <c>InfoTuple</c>s with + <desc> + <p>Returns a list containing <c><anno>InfoTuple</anno></c>s with miscellaneous information about the process identified by <c>Pid</c>, or <c>undefined</c> if the process is not alive. </p> <p> - The order of the <c>InfoTuple</c>s is not defined, nor - are all the <c>InfoTuple</c>s mandatory. The <c>InfoTuple</c>s + The order of the <c><anno>InfoTuple</anno></c>s is not defined, nor + are all the <c><anno>InfoTuple</anno></c>s mandatory. The <c><anno>InfoTuple</anno></c>s part of the result may be changed without prior notice. - Currently <c>InfoTuple</c>s with the following <c>Item</c>s + Currently <c><anno>InfoTuple</anno></c>s with the following items are part of the result: <c>current_function</c>, <c>initial_call</c>, <c>status</c>, <c>message_queue_len</c>, <c>messages</c>, <c>links</c>, @@ -3861,12 +3401,12 @@ os_prompt% </pre> <c>priority</c>, <c>group_leader</c>, <c>total_heap_size</c>, <c>heap_size</c>, <c>stack_size</c>, <c>reductions</c>, and <c>garbage_collection</c>. - If the process identified by <c>Pid</c> has a registered name - also an <c>InfoTuple</c> with <c>Item == registered_name</c> + If the process identified by <c><anno>Pid</anno></c> has a registered name + also an <c><anno>InfoTuple</anno></c> with the item <c>registered_name</c> will appear. </p> <p>See <seealso marker="#process_info/2">process_info/2</seealso> - for information about specific <c>InfoTuple</c>s.</p> + for information about specific <c><anno>InfoTuple</anno></c>s.</p> <warning> <p>This BIF is intended for <em>debugging only</em>, use <seealso marker="#process_info/2">process_info/2</seealso> @@ -3877,113 +3417,108 @@ os_prompt% </pre> </desc> </func> <func> - <name>process_info(Pid, ItemSpec) -> InfoResult</name> + <name name="process_info" arity="2" clause_i="1"/> + <name name="process_info" arity="2" clause_i="2"/> + <type name="process_info_item"/> + <type name="process_info_result_item"/> + <type name="stack_item"/> + <type name="priority_level"/> <fsummary>Information about a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Item = atom()</v> - <v>Info = term()</v> - <v>ItemList = [Item]</v> - <v>ItemSpec = Item | ItemList</v> - <v>InfoTuple = {Item, Info}</v> - <v>InfoTupleList = [InfoTuple]</v> - <v>InfoResult = InfoTuple | InfoTupleList | undefined | []</v> - </type> - <desc> - <p>Returns information about the process identified by <c>Pid</c> - as specified by the <c>ItemSpec</c>, or <c>undefined</c> if the + <desc> + <p>Returns information about the process identified by <c><anno>Pid</anno></c> + as specified by the <c><anno>Item</anno></c> or the <c><anno>ItemList</anno></c>, or <c>undefined</c> if the process is not alive. </p> - <p>If the process is alive and <c>ItemSpec</c> is a single - <c>Item</c>, the returned value is the corresponding - <c>InfoTuple</c> unless <c>ItemSpec == registered_name</c> + <p>If the process is alive and a single <c><anno>Item</anno></c> is given, + the returned value is the corresponding + <c><anno>InfoTuple</anno></c> unless <c>Item =:= registered_name</c> and the process has no registered name. In this case <c>[]</c> is returned. This strange behavior is due to historical reasons, and is kept for backward compatibility. </p> - <p>If <c>ItemSpec</c> is an <c>ItemList</c>, the result is an - <c>InfoTupleList</c>. The <c>InfoTuple</c>s in the - <c>InfoTupleList</c> will appear with the corresponding - <c>Item</c>s in the same order as the <c>Item</c>s appeared - in the <c>ItemList</c>. Valid <c>Item</c>s may appear multiple - times in the <c>ItemList</c>. + <p>If an <c>ItemList</c> is given, the result is an + <c><anno>InfoTupleList</anno></c>. The <c><anno>InfoTuple</anno></c>s in the + <c><anno>InfoTupleList</anno></c> will appear with the corresponding + <c><anno>Item</anno></c>s in the same order as the <c><anno>Item</anno></c>s appeared + in the <c><anno>ItemList</anno></c>. Valid <c><anno>Item</anno></c>s may appear multiple + times in the <c><anno>ItemList</anno></c>. </p> - <note><p>If <c>registered_name</c> is part of an <c>ItemList</c> + <note><p>If <c>registered_name</c> is part of an <c><anno>ItemList</anno></c> and the process has no name registered a - <c>{registered_name, []}</c> <c>InfoTuple</c> <em>will</em> - appear in the resulting <c>InfoTupleList</c>. This - behavior is different than when - <c>ItemSpec == registered_name</c>, and than when + <c>{registered_name, []}</c> <c><anno>InfoTuple</anno></c> <em>will</em> + appear in the resulting <c><anno>InfoTupleList</anno></c>. This + behavior is different than when a single + <c>Item =:= registered_name</c> is given, and than when <c>process_info/1</c> is used. </p></note> - <p>Currently the following <c>InfoTuple</c>s with corresponding - <c>Item</c>s are valid:</p> + <p>Currently the following <c><anno>InfoTuple</anno></c>s with corresponding + <c><anno>Item</anno></c>s are valid:</p> <taglist> - <tag><c>{backtrace, Bin}</c></tag> + <tag><c>{backtrace, <anno>Bin</anno>}</c></tag> <item> - <p>The binary <c>Bin</c> contains the same information as + <p>The binary <c><anno>Bin</anno></c> contains the same information as the output from - <c>erlang:process_display(Pid, backtrace)</c>. Use + <c>erlang:process_display(<anno>Pid</anno>, backtrace)</c>. Use <c>binary_to_list/1</c> to obtain the string of characters from the binary.</p> </item> - <tag><c>{binary, BinInfo}</c></tag> + <tag><c>{binary, <anno>BinInfo</anno>}</c></tag> <item> - <p><c>BinInfo</c> is a list containing miscellaneous information + <p><c><anno>BinInfo</anno></c> is a list containing miscellaneous information about binaries currently being referred to by this process. - This <c>InfoTuple</c> may be changed or removed without prior + This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{catchlevel, CatchLevel}</c></tag> + <tag><c>{catchlevel, <anno>CatchLevel</anno>}</c></tag> <item> - <p><c>CatchLevel</c> is the number of currently active - catches in this process. This <c>InfoTuple</c> may be + <p><c><anno>CatchLevel</anno></c> is the number of currently active + catches in this process. This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{current_function, {Module, Function, Arity}}</c></tag> + <tag><c>{current_function, {<anno>Module</anno>, <anno>Function</anno>, <anno>Arity</anno>}}</c></tag> <item> - <p><c>Module</c>, <c>Function</c>, <c>Arity</c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, <c><anno>Arity</anno></c> is the current function call of the process.</p> </item> - <tag><c>{current_location, {Module, Function, Arity, Location}}</c></tag> + <tag><c>{current_location, {<anno>Module</anno>, <anno>Function</anno>, <anno>Arity</anno>, <anno>Location</anno>}}</c></tag> <item> - <p><c>Module</c>, <c>Function</c>, <c>Arity</c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, <c><anno>Arity</anno></c> is the current function call of the process. - <c>Location</c> is a list of two-tuples that describes the + <c><anno>Location</anno></c> is a list of two-tuples that describes the location in the source code. </p> </item> - <tag><c>{current_stacktrace, Stack}</c></tag> + <tag><c>{current_stacktrace, <anno>Stack</anno>}</c></tag> <item> <p>Return the current call stack back-trace (<em>stacktrace</em>) of the process. The stack has the same format as returned by <seealso marker="#get_stacktrace/0">erlang:get_stacktrace/0</seealso>. </p> </item> - <tag><c>{dictionary, Dictionary}</c></tag> + <tag><c>{dictionary, <anno>Dictionary</anno>}</c></tag> <item> - <p><c>Dictionary</c> is the dictionary of the process.</p> + <p><c><anno>Dictionary</anno></c> is the dictionary of the process.</p> </item> - <tag><c>{error_handler, Module}</c></tag> + <tag><c>{error_handler, <anno>Module</anno>}</c></tag> <item> - <p><c>Module</c> is the error handler module used by + <p><c><anno>Module</anno></c> is the error handler module used by the process (for undefined function calls, for example).</p> </item> - <tag><c>{garbage_collection, GCInfo}</c></tag> + <tag><c>{garbage_collection, <anno>GCInfo</anno>}</c></tag> <item> - <p><c>GCInfo</c> is a list which contains miscellaneous + <p><c><anno>GCInfo</anno></c> is a list which contains miscellaneous information about garbage collection for this process. - The content of <c>GCInfo</c> may be changed without + The content of <c><anno>GCInfo</anno></c> may be changed without prior notice.</p> </item> - <tag><c>{group_leader, GroupLeader}</c></tag> + <tag><c>{group_leader, <anno>GroupLeader</anno>}</c></tag> <item> - <p><c>GroupLeader</c> is group leader for the IO of + <p><c><anno>GroupLeader</anno></c> is group leader for the IO of the process.</p> </item> - <tag><c>{heap_size, Size}</c></tag> + <tag><c>{heap_size, <anno>Size</anno>}</c></tag> <item> - <p><c>Size</c> is the size in words of youngest heap generation + <p><c><anno>Size</anno></c> is the size in words of youngest heap generation of the process. This generation currently include the stack of the process. This information is highly implementation dependent, and may change if the implementation change. @@ -3995,9 +3530,9 @@ os_prompt% </pre> the initial function call with which the process was spawned.</p> </item> - <tag><c>{links, Pids}</c></tag> + <tag><c>{links, <anno>Pids</anno>}</c></tag> <item> - <p><c>Pids</c> is a list of pids, with processes to + <p><c><anno>Pids</anno></c> is a list of pids, with processes to which the process has a link.</p> </item> <tag><c>{last_calls, false|Calls}</c></tag> @@ -4008,131 +3543,131 @@ os_prompt% </pre> If call saving is active, a list is returned, in which the last element is the most recent called.</p> </item> - <tag><c>{memory, Size}</c></tag> + <tag><c>{memory, <anno>Size</anno>}</c></tag> <item> - <p><c>Size</c> is the size in bytes of the process. This + <p><c><anno>Size</anno></c> is the size in bytes of the process. This includes call stack, heap and internal structures.</p> </item> - <tag><c>{message_queue_len, MessageQueueLen}</c></tag> + <tag><c>{message_queue_len, <anno>MessageQueueLen</anno>}</c></tag> <item> - <p><c>MessageQueueLen</c> is the number of messages + <p><c><anno>MessageQueueLen</anno></c> is the number of messages currently in the message queue of the process. This is - the length of the list <c>MessageQueue</c> returned as + the length of the list <c><anno>MessageQueue</anno></c> returned as the info item <c>messages</c> (see below).</p> </item> - <tag><c>{messages, MessageQueue}</c></tag> + <tag><c>{messages, <anno>MessageQueue</anno>}</c></tag> <item> - <p><c>MessageQueue</c> is a list of the messages to + <p><c><anno>MessageQueue</anno></c> is a list of the messages to the process, which have not yet been processed.</p> </item> - <tag><c>{min_heap_size, MinHeapSize}</c></tag> + <tag><c>{min_heap_size, <anno>MinHeapSize</anno>}</c></tag> <item> - <p><c>MinHeapSize</c> is the minimum heap size for the process.</p> + <p><c><anno>MinHeapSize</anno></c> is the minimum heap size for the process.</p> </item> - <tag><c>{min_bin_vheap_size, MinBinVHeapSize}</c></tag> + <tag><c>{min_bin_vheap_size, <anno>MinBinVHeapSize</anno>}</c></tag> <item> - <p><c>MinBinVHeapSize</c> is the minimum binary virtual heap size for the process.</p> + <p><c><anno>MinBinVHeapSize</anno></c> is the minimum binary virtual heap size for the process.</p> </item> - <tag><c>{monitored_by, Pids}</c></tag> + <tag><c>{monitored_by, <anno>Pids</anno>}</c></tag> <item> <p>A list of pids that are monitoring the process (with <c>monitor/2</c>).</p> </item> - <tag><c>{monitors, Monitors}</c></tag> + <tag><c>{monitors, <anno>Monitors</anno>}</c></tag> <item> <p>A list of monitors (started by <c>monitor/2</c>) that are active for the process. For a local process monitor or a remote process monitor by pid, the list item - is <c>{process, Pid}</c>, and for a remote process + is <c>{process, <anno>Pid</anno>}</c>, and for a remote process monitor by name, the list item is - <c>{process, {RegName, Node}}</c>.</p> + <c>{process, {<anno>RegName</anno>, <anno>Node</anno>}}</c>.</p> </item> <tag><c>{priority, Level}</c></tag> <item> - <p><c>Level</c> is the current priority level for + <p><c><anno>Level</anno></c> is the current priority level for the process. For more information on priorities see <seealso marker="#process_flag_priority">process_flag(priority, Level)</seealso>.</p> </item> - <tag><c>{reductions, Number}</c></tag> + <tag><c>{reductions, <anno>Number</anno>}</c></tag> <item> - <p><c>Number</c> is the number of reductions executed by + <p><c><anno>Number</anno></c> is the number of reductions executed by the process.</p> </item> - <tag><c>{registered_name, Atom}</c></tag> + <tag><c>{registered_name, <anno>Atom</anno>}</c></tag> <item> - <p><c>Atom</c> is the registered name of the process. If + <p><c><anno>Atom</anno></c> is the registered name of the process. If the process has no registered name, this tuple is not present in the list.</p> </item> - <tag><c>{sequential_trace_token, [] | SequentialTraceToken}</c></tag> + <tag><c>{sequential_trace_token, [] | <anno>SequentialTraceToken</anno>}</c></tag> <item> - <p><c>SequentialTraceToken</c> the sequential trace token for - the process. This <c>InfoTuple</c> may be changed or removed + <p><c><anno>SequentialTraceToken</anno></c> the sequential trace token for + the process. This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{stack_size, Size}</c></tag> + <tag><c>{stack_size, <anno>Size</anno>}</c></tag> <item> - <p><c>Size</c> is the stack size of the process in words.</p> + <p><c><anno>Size</anno></c> is the stack size of the process in words.</p> </item> - <tag><c>{status, Status}</c></tag> + <tag><c>{status, <anno>Status</anno>}</c></tag> <item> - <p><c>Status</c> is the status of the process. <c>Status</c> + <p><c><anno>Status</anno></c> is the status of the process. <c><anno>Status</anno></c> is <c>exiting</c>, <c>garbage_collecting</c>, <c>waiting</c> (for a message), <c>running</c>, <c>runnable</c> (ready to run, but another process is running), or <c>suspended</c> (suspended on a "busy" port or by the <c>erlang:suspend_process/[1,2]</c> BIF).</p> </item> - <tag><c>{suspending, SuspendeeList}</c></tag> + <tag><c>{suspending, <anno>SuspendeeList</anno>}</c></tag> <item> - <p><c>SuspendeeList</c> is a list of <c>{Suspendee, - ActiveSuspendCount, OutstandingSuspendCount}</c> tuples. - <c>Suspendee</c> is the pid of a process that have been or is to - be suspended by the process identified by <c>Pid</c> via the + <p><c><anno>SuspendeeList</anno></c> is a list of <c>{<anno>Suspendee</anno>, + <anno>ActiveSuspendCount</anno>, <anno>OutstandingSuspendCount</anno>}</c> tuples. + <c><anno>Suspendee</anno></c> is the pid of a process that have been or is to + be suspended by the process identified by <c><anno>Pid</anno></c> via the <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso> BIF, or the <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> - BIF. <c>ActiveSuspendCount</c> is the number of times the - <c>Suspendee</c> has been suspended by <c>Pid</c>. - <c>OutstandingSuspendCount</c> is the number of not yet - completed suspend requests sent by <c>Pid</c>. That is, - if <c>ActiveSuspendCount /= 0</c>, <c>Suspendee</c> is + BIF. <c><anno>ActiveSuspendCount</anno></c> is the number of times the + <c><anno>Suspendee</anno></c> has been suspended by <c><anno>Pid</anno></c>. + <c><anno>OutstandingSuspendCount</anno></c> is the number of not yet + completed suspend requests sent by <c><anno>Pid</anno></c>. That is, + if <c><anno>ActiveSuspendCount</anno> =/= 0</c>, <c><anno>Suspendee</anno></c> is currently in the suspended state, and if - <c>OutstandingSuspendCount /= 0</c> the <c>asynchronous</c> + <c><anno>OutstandingSuspendCount</anno> =/= 0</c> the <c>asynchronous</c> option of <c>erlang:suspend_process/2</c> has been used and - the suspendee has not yet been suspended by <c>Pid</c>. - Note that the <c>ActiveSuspendCount</c> and - <c>OutstandingSuspendCount</c> are not the total suspend count - on <c>Suspendee</c>, only the parts contributed by <c>Pid</c>. + the suspendee has not yet been suspended by <c><anno>Pid</anno></c>. + Note that the <c><anno>ActiveSuspendCount</anno></c> and + <c><anno>OutstandingSuspendCount</anno></c> are not the total suspend count + on <c><anno>Suspendee</anno></c>, only the parts contributed by <c>Pid</c>. </p> </item> - <tag><c>{total_heap_size, Size}</c></tag> + <tag><c>{total_heap_size, <anno>Size</anno>}</c></tag> <item> - <p><c>Size</c> is the total size in words of all heap + <p><c><anno>Size</anno></c> is the total size in words of all heap fragments of the process. This currently include the stack of the process. </p> </item> - <tag><c>{trace, InternalTraceFlags}</c></tag> + <tag><c>{trace, <anno>InternalTraceFlags</anno>}</c></tag> <item> - <p><c>InternalTraceFlags</c> is an integer representing - internal trace flag for this process. This <c>InfoTuple</c> + <p><c><anno>InternalTraceFlags</anno></c> is an integer representing + internal trace flag for this process. This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{trap_exit, Boolean}</c></tag> + <tag><c>{trap_exit, <anno>Boolean</anno>}</c></tag> <item> - <p><c>Boolean</c> is <c>true</c> if the process is trapping + <p><c><anno>Boolean</anno></c> is <c>true</c> if the process is trapping exits, otherwise it is <c>false</c>.</p> </item> </taglist> <p>Note however, that not all implementations support every one - of the above <c>Items</c>.</p> - <p>Failure: <c>badarg</c> if <c>Pid</c> is not a local process, - or if <c>Item</c> is not a valid <c>Item</c>.</p> + of the above <c><anno>Item</anno></c>s.</p> + <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a local process, + or if <c><anno>Item</anno></c> is not a valid <c><anno>Item</anno></c>.</p> </desc> </func> <func> - <name>processes() -> [pid()]</name> + <name name="processes" arity="0"/> <fsummary>All processes</fsummary> <desc> <p>Returns a list of process identifiers corresponding to @@ -4149,13 +3684,10 @@ os_prompt% </pre> </desc> </func> <func> - <name>purge_module(Module) -> void()</name> + <name name="purge_module" arity="1"/> <fsummary>Remove old code for a module</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Removes old code for <c>Module</c>. Before this BIF is used, + <p>Removes old code for <c><anno>Module</anno></c>. Before this BIF is used, <c>erlang:check_process_code/2</c> should be called to check that no processes are executing old code in the module.</p> <warning> @@ -4164,20 +3696,17 @@ os_prompt% </pre> used elsewhere.</p> </warning> <p>Failure: <c>badarg</c> if there is no old code for - <c>Module</c>.</p> + <c><anno>Module</anno></c>.</p> </desc> </func> <func> - <name>put(Key, Val) -> OldVal | undefined</name> + <name name="put" arity="2"/> <fsummary>Add a new value to the process dictionary</fsummary> - <type> - <v>Key = Val = OldVal = term()</v> - </type> - <desc> - <p>Adds a new <c>Key</c> to the process dictionary, associated - with the value <c>Val</c>, and returns <c>undefined</c>. If - <c>Key</c> already exists, the old value is deleted and - replaced by <c>Val</c> and the function returns the old value.</p> + <desc> + <p>Adds a new <c><anno>Key</anno></c> to the process dictionary, associated + with the value <c><anno>Val</anno></c>, and returns <c>undefined</c>. If + <c><anno>Key</anno></c> already exists, the old value is deleted and + replaced by <c><anno>Val</anno></c> and the function returns the old value.</p> <note> <p>The values stored when <c>put</c> is evaluated within the scope of a <c>catch</c> will not be retracted if a @@ -4191,17 +3720,9 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:raise(Class, Reason, Stacktrace)</name> + <name name="raise" arity="3"/> + <type name="raise_stacktrace"/> <fsummary>Stop execution with an exception of given class, reason and call stack backtrace</fsummary> - <type> - <v>Class = error | exit | throw</v> - <v>Reason = term()</v> - <v>Stacktrace = [{Module, Function, Arity | Args} | {Fun, Args}]</v> - <v> Module = Function = atom()</v> - <v> Arity = arity()</v> - <v> Args = [term()]</v> - <v> Fun = [fun()]</v> - </type> <desc> <p>Stops the execution of the calling process with an exception of given class, reason and call stack backtrace @@ -4212,11 +3733,11 @@ os_prompt% </pre> be avoided in applications, unless you know very well what you are doing.</p> </warning> - <p><c>Class</c> is one of <c>error</c>, <c>exit</c> or + <p><c><anno>Class</anno></c> is one of <c>error</c>, <c>exit</c> or <c>throw</c>, so if it were not for the stacktrace - <c>erlang:raise(Class, Reason, Stacktrace)</c> is - equivalent to <c>erlang:Class(Reason)</c>. - <c>Reason</c> is any term and <c>Stacktrace</c> is a list as + <c>erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, <anno>Stacktrace</anno>)</c> is + equivalent to <c>erlang:<anno>Class</anno>(<anno>Reason</anno>)</c>. + <c><anno>Reason</anno></c> is any term and <c><anno>Stacktrace</anno></c> is a list as returned from <c>get_stacktrace()</c>, that is a list of 4-tuples <c>{Module, Function, Arity | Args, Location}</c> where <c>Module</c> and <c>Function</c> @@ -4233,24 +3754,21 @@ os_prompt% </pre> terminate, it has no return value - unless the arguments are invalid, in which case the function <em>returns the error reason</em>, that is <c>badarg</c>. If you want to be really sure not to return you can call - <c>error(erlang:raise(Class, Reason, Stacktrace))</c> + <c>error(erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, <anno>Stacktrace</anno>))</c> and hope to distinguish exceptions later.</p> </desc> </func> <func> - <name>erlang:read_timer(TimerRef) -> integer() >= 0 | false</name> + <name name="read_timer" arity="1"/> <fsummary>Number of milliseconds remaining for a timer</fsummary> - <type> - <v>TimerRef = reference()</v> - </type> <desc> - <p><c>TimerRef</c> is a timer reference returned by + <p><c><anno>TimerRef</anno></c> is a timer reference returned by <seealso marker="#send_after/3">erlang:send_after/3</seealso> or <seealso marker="#start_timer/3">erlang:start_timer/3</seealso>. If the timer is active, the function returns the time in milliseconds left until the timer will expire, otherwise - <c>false</c> (which means that <c>TimerRef</c> was never a + <c>false</c> (which means that <c><anno>TimerRef</anno></c> was never a timer, that it has been cancelled, or that it has already delivered its message).</p> <p>See also @@ -4261,14 +3779,11 @@ os_prompt% </pre> </desc> </func> <func> - <name>erlang:ref_to_list(Ref) -> string()</name> + <name name="ref_to_list" arity="1"/> <fsummary>Text representation of a reference</fsummary> - <type> - <v>Ref = reference()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Ref</c>.</p> + representation of <c><anno>Ref</anno></c>.</p> <warning> <p>This BIF is intended for debugging and for use in the Erlang operating system. It should not be used in @@ -4277,33 +3792,25 @@ os_prompt% </pre> </desc> </func> <func> - <name>register(RegName, Pid | Port) -> true</name> + <name name="register" arity="2"/> <fsummary>Register a name for a pid (or port)</fsummary> - <type> - <v>RegName = atom()</v> - <v>Pid = pid()</v> - <v>Port = port()</v> - </type> - <desc> - <p>Associates the name <c>RegName</c> with a pid or a port - identifier. <c>RegName</c>, which must be an atom, can be used + <desc> + <p>Associates the name <c><anno>RegName</anno></c> with a pid or a port + identifier. <c><anno>RegName</anno></c>, which must be an atom, can be used instead of the pid / port identifier in the send operator - (<c>RegName ! Message</c>).</p> + (<c><anno>RegName</anno> ! Message</c>).</p> <pre> > <input>register(db, Pid).</input> true</pre> - <p>Failure: <c>badarg</c> if <c>Pid</c> is not an existing, - local process or port, if <c>RegName</c> is already in use, + <p>Failure: <c>badarg</c> if <c><anno>PidOrPort</anno></c> is not an existing, + local process or port, if <c><anno>RegName</anno></c> is already in use, if the process or port is already registered (already has a - name), or if <c>RegName</c> is the atom <c>undefined</c>.</p> + name), or if <c><anno>RegName</anno></c> is the atom <c>undefined</c>.</p> </desc> </func> <func> - <name>registered() -> [RegName]</name> + <name name="registered" arity="0"/> <fsummary>All registered names</fsummary> - <type> - <v>RegName = atom()</v> - </type> <desc> <p>Returns a list of names which have been registered using <seealso marker="#register/2">register/2</seealso>.</p> @@ -4313,22 +3820,19 @@ true</pre> </desc> </func> <func> - <name>erlang:resume_process(Suspendee) -> true</name> + <name name="resume_process" arity="1"/> <fsummary>Resume a suspended process</fsummary> - <type> - <v>Suspendee = pid()</v> - </type> <desc> <p>Decreases the suspend count on the process identified by - <c>Suspendee</c>. <c>Suspendee</c> should previously have been + <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> should previously have been suspended via <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso>, or <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> - by the process calling <c>erlang:resume_process(Suspendee)</c>. When - the suspend count on <c>Suspendee</c> reach zero, <c>Suspendee</c> + by the process calling <c>erlang:resume_process(<anno>Suspendee</anno>)</c>. When + the suspend count on <c><anno>Suspendee</anno></c> reach zero, <c><anno>Suspendee</anno></c> will be resumed, i.e., the state of the <c>Suspendee</c> is changed - from suspended into the state <c>Suspendee</c> was in before it was + from suspended into the state <c><anno>Suspendee</anno></c> was in before it was suspended. </p> <warning> @@ -4338,29 +3842,26 @@ true</pre> <taglist> <tag><c>badarg</c></tag> <item> - If <c>Suspendee</c> isn't a process identifier. + If <c><anno>Suspendee</anno></c> isn't a process identifier. </item> <tag><c>badarg</c></tag> <item> If the process calling <c>erlang:resume_process/1</c> had not previously increased the suspend count on the process - identified by <c>Suspendee</c>. + identified by <c><anno>Suspendee</anno></c>. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c>Suspendee</c> is not alive. + If the process identified by <c><anno>Suspendee</anno></c> is not alive. </item> </taglist> </desc> </func> <func> - <name>round(Number) -> integer()</name> + <name name="round" arity="1"/> <fsummary>Return an integer by rounding a number</fsummary> - <type> - <v>Number = number()</v> - </type> <desc> - <p>Returns an integer by rounding <c>Number</c>.</p> + <p>Returns an integer by rounding <c><anno>Number</anno></c>.</p> <pre> > <input>round(5.5).</input> 6</pre> @@ -4368,7 +3869,7 @@ true</pre> </desc> </func> <func> - <name>self() -> pid()</name> + <name name="self" arity="0"/> <fsummary>Pid of the calling process</fsummary> <desc> <p>Returns the pid (process identifier) of the calling process.</p> @@ -4379,33 +3880,21 @@ true</pre> </desc> </func> <func> - <name>erlang:send(Dest, Msg) -> Msg</name> + <name name="send" arity="2"/> <fsummary>Send a message</fsummary> - <type> - <v>Dest = pid() | port() | RegName | {RegName, Node}</v> - <v>Msg = term()</v> - <v> RegName = atom()</v> - <v> Node = node()</v> - </type> - <desc> - <p>Sends a message and returns <c>Msg</c>. This is the same as - <c>Dest ! Msg</c>.</p> - <p><c>Dest</c> may be a remote or local pid, a (local) port, a - locally registered name, or a tuple <c>{RegName, Node}</c> + <type name="dst"/> + <desc> + <p>Sends a message and returns <c><anno>Msg</anno></c>. This is the same as + <c><anno>Dest</anno> ! <anno>Msg</anno></c>.</p> + <p><c><anno>Dest</anno></c> may be a remote or local pid, a (local) port, a + locally registered name, or a tuple <c>{<anno>RegName</anno>, <anno>Node</anno>}</c> for a registered name at another node.</p> </desc> </func> <func> - <name>erlang:send(Dest, Msg, [Option]) -> Res</name> + <name name="send" arity="3"/> + <type name="dst"/> <fsummary>Send a message conditionally</fsummary> - <type> - <v>Dest = pid() | port() | RegName | {RegName, Node}</v> - <v> RegName = atom()</v> - <v> Node = node()</v> - <v>Msg = term()</v> - <v>Option = nosuspend | noconnect</v> - <v>Res = ok | nosuspend | noconnect</v> - </type> <desc> <p>Sends a message and returns <c>ok</c>, or does not send the message but returns something else (see below). Otherwise @@ -4435,28 +3924,24 @@ true</pre> </desc> </func> <func> - <name>erlang:send_after(Time, Dest, Msg) -> TimerRef</name> + <name name="send_after" arity="3"/> + <type_desc variable="Time">0 <= Time <= 4294967295</type_desc> <fsummary>Start a timer</fsummary> - <type> - <v>Time = integer() >= 0</v> - <v> 0 <= Time <= 4294967295</v> - <v>Dest = pid() | RegName </v> - <v> LocalPid = pid() (of a process, alive or dead, on the local node)</v> - <v>Msg = term()</v> - <v>TimerRef = reference()</v> - </type> <desc> <p>Starts a timer which will send the message <c>Msg</c> - to <c>Dest</c> after <c>Time</c> milliseconds.</p> - <p>If <c>Dest</c> is an atom, it is supposed to be the name of + to <c><anno>Dest</anno></c> after <c><anno>Time</anno></c> milliseconds.</p> + <p>If <c><anno>Dest</anno></c> is a <c>pid()</c> it has to be a <c>pid()</c> of a local process, dead or alive.</p> + <p>The <c><anno>Time</anno></c> value can, in the current implementation, not be greater than 4294967295.</p> + <p>If <c><anno>Dest</anno></c> is an <c>atom()</c>, it is supposed to be the name of a registered process. The process referred to by the name is looked up at the time of delivery. No error is given if the name does not refer to a process.</p> - <p>If <c>Dest</c> is a pid, the timer will be automatically - canceled if the process referred to by the pid is not alive, + + <p>If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will be automatically + canceled if the process referred to by the <c>pid()</c> is not alive, or when the process exits. This feature was introduced in erts version 5.4.11. Note that timers will not be - automatically canceled when <c>Dest</c> is an atom.</p> + automatically canceled when <c><anno>Dest</anno></c> is an <c>atom</c>.</p> <p>See also <seealso marker="#start_timer/3">erlang:start_timer/3</seealso>, <seealso marker="#cancel_timer/1">erlang:cancel_timer/1</seealso>, @@ -4556,32 +4041,25 @@ true</pre> </desc> </func> <func> - <name>setelement(Index, Tuple1, Value) -> Tuple2</name> + <name name="setelement" arity="3"/> + <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>)</type_desc> <fsummary>Set Nth element of a tuple</fsummary> - <type> - <v>Index = 1..tuple_size(Tuple1)</v> - <v>Tuple1 = Tuple2 = tuple()</v> - <v>Value = term()</v> - </type> - <desc> - <p>Returns a tuple which is a copy of the argument <c>Tuple1</c> - with the element given by the integer argument <c>Index</c> + <desc> + <p>Returns a tuple which is a copy of the argument <c><anno>Tuple1</anno></c> + with the element given by the integer argument <c><anno>Index</anno></c> (the first element is the element with index 1) replaced by - the argument <c>Value</c>.</p> + the argument <c><anno>Value</anno></c>.</p> <pre> > <input>setelement(2, {10, green, bottles}, red).</input> {10,red,bottles}</pre> </desc> </func> <func> - <name>size(Item) -> integer() >= 0</name> + <name name="size" arity="1"/> <fsummary>Size of a tuple or binary</fsummary> - <type> - <v>Item = tuple() | binary()</v> - </type> <desc> <p>Returns an integer which is the size of the argument - <c>Item</c>, which must be either a tuple or a binary.</p> + <c><anno>Item</anno></c>, which must be either a tuple or a binary.</p> <pre> > <input>size({morni, mulle, bwange}).</input> 3</pre> @@ -4609,20 +4087,16 @@ true</pre> </desc> </func> <func> - <name>spawn(Module, Function, Args) -> pid()</name> + <name name="spawn" arity="3"/> <fsummary>Create a new process with a function as entry point</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Returns the pid of a new process started by the application - of <c>Module:Function</c> to <c>Args</c>. The new process + of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>. The new process created will be placed in the system scheduler queue and be run some time later.</p> - <p><c>error_handler:undefined_function(Module, Function, Args)</c> is evaluated by the new process if - <c>Module:Function/Arity</c> does not exist (where - <c>Arity</c> is the length of <c>Args</c>). The error handler + <p><c>error_handler:undefined_function(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> is evaluated by the new process if + <c><anno>Module</anno>:<anno>Function</anno>/Arity</c> does not exist (where + <c>Arity</c> is the length of <c><anno>Args</anno></c>). The error handler can be redefined (see <seealso marker="#process_flag/2">process_flag/2</seealso>). If <c>error_handler</c> is undefined, or the user has @@ -4669,15 +4143,11 @@ true</pre> </desc> </func> <func> - <name>spawn_link(Module, Function, Args) -> pid()</name> + <name name="spawn_link" arity="3"/> <fsummary>Create and link to a new process with a function as entry point</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Returns the pid of a new process started by the application - of <c>Module:Function</c> to <c>Args</c>. A link is created + of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>. A link is created between the calling process and the new process, atomically. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> @@ -4856,15 +4326,12 @@ true</pre> </desc> </func> <func> - <name>split_binary(Bin, Pos) -> {Bin1, Bin2}</name> + <name name="split_binary" arity="2"/> + <type_desc variable="Pos">0..byte_size(Bin)</type_desc> <fsummary>Split a binary into two</fsummary> - <type> - <v>Bin = Bin1 = Bin2 = binary()</v> - <v>Pos = 0..byte_size(Bin)</v> - </type> <desc> <p>Returns a tuple containing the binaries which are the result - of splitting <c>Bin</c> into two parts at position <c>Pos</c>. + of splitting <c><anno>Bin</anno></c> into two parts at position <c><anno>Pos</anno></c>. This is not a destructive operation. After the operation, there will be three binaries altogether.</p> <pre> @@ -4881,30 +4348,24 @@ true</pre> </desc> </func> <func> - <name>erlang:start_timer(Time, Dest, Msg) -> TimerRef</name> + <name name="start_timer" arity="3"/> + <type_desc variable="Time">0 <= Time <= 4294967295</type_desc> <fsummary>Start a timer</fsummary> - <type> - <v>Time = integer() >= 0</v> - <v> 0 <= Time <= 4294967295</v> - <v>Dest = LocalPid | RegName </v> - <v> LocalPid = pid() (of a process, alive or dead, on the local node)</v> - <v> RegName = atom()</v> - <v>Msg = term()</v> - <v>TimerRef = reference()</v> - </type> <desc> <p>Starts a timer which will send the message - <c>{timeout, TimerRef, Msg}</c> to <c>Dest</c> - after <c>Time</c> milliseconds.</p> - <p>If <c>Dest</c> is an atom, it is supposed to be the name of + <c>{timeout, <anno>TimerRef</anno>, <anno>Msg</anno>}</c> to <c><anno>Dest</anno></c> + after <c><anno>Time</anno></c> milliseconds.</p> + <p>If <c><anno>Dest</anno></c> is a <c>pid()</c> it has to be a <c>pid()</c> of a local process, dead or alive.</p> + <p>The <c><anno>Time</anno></c> value can, in the current implementation, not be greater than 4294967295.</p> + <p>If <c><anno>Dest</anno></c> is an <c>atom()</c>, it is supposed to be the name of a registered process. The process referred to by the name is looked up at the time of delivery. No error is given if the name does not refer to a process.</p> - <p>If <c>Dest</c> is a pid, the timer will be automatically - canceled if the process referred to by the pid is not alive, + <p>If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will be automatically + canceled if the process referred to by the <c>pid()</c> is not alive, or when the process exits. This feature was introduced in erts version 5.4.11. Note that timers will not be - automatically canceled when <c>Dest</c> is an atom.</p> + automatically canceled when <c><anno>Dest</anno></c> is an <c>atom()</c>.</p> <p>See also <seealso marker="#send_after/3">erlang:send_after/3</seealso>, <seealso marker="#cancel_timer/1">erlang:cancel_timer/1</seealso>, @@ -4915,54 +4376,52 @@ true</pre> </desc> </func> <func> - <name>statistics(Type) -> Res</name> - <fsummary>Information about the system</fsummary> - <type> - <v>Type, Res -- see below</v> - </type> + <name name="statistics" arity="1" clause_i="1"/> + <fsummary>Information about context switches</fsummary> <desc> - <p>All times are in milliseconds unless otherwise specified.</p> - <p>Returns information about the system as specified by - <c>Type</c>:</p> - <taglist> - <tag><c>context_switches</c></tag> - <item> - <p>Returns <c>{ContextSwitches, 0}</c>, where - <c>ContextSwitches</c> is the total number of context - switches since the system started.</p> - </item> - <tag><marker id="statistics_exact_reductions"><c>exact_reductions</c></marker></tag> - <item> - <p>Returns - <c>{Total_Exact_Reductions, Exact_Reductions_Since_Last_Call}</c>.</p> - <note><p><c>statistics(exact_reductions)</c> is - a more expensive operation than - <seealso marker="#statistics_reductions">statistics(reductions)</seealso> - especially on an Erlang machine with SMP support.</p> - </note> - </item> - <tag><c>garbage_collection</c></tag> - <item> - <p>Returns <c>{Number_of_GCs, Words_Reclaimed, 0}</c>. This - information may not be valid for all implementations.</p> - <pre> + <p><c><anno>ContextSwitches</anno></c> is the total number of context + switches since the system started.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="2"/> + <fsummary>Information about exact reductions</fsummary> + <desc> + <marker id="statistics_exact_reductions"></marker> + <note><p><c>statistics(exact_reductions)</c> is + a more expensive operation than + <seealso marker="#statistics_reductions">statistics(reductions)</seealso> + especially on an Erlang machine with SMP support.</p> + </note> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="3"/> + <fsummary>Information about garbage collection</fsummary> + <desc> + <p>This information may not be valid for all implementations.</p> + <pre> > <input>statistics(garbage_collection).</input> {85,23961,0} </pre> - </item> - <tag><c>io</c></tag> - <item> - <p>Returns <c>{{input, Input}, {output, Output}}</c>, - where <c>Input</c> is the total number of bytes received - through ports, and <c>Output</c> is the total number of - bytes output to ports.</p> - </item> - <tag><marker id="statistics_reductions"><c>reductions</c></marker></tag> - <item> - <p>Returns - <c>{Total_Reductions, Reductions_Since_Last_Call}</c>.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="4"/> + <fsummary>Information about io</fsummary> + <desc> + <p><c><anno>Input</anno></c> is the total number of bytes received + through ports, and <c><anno>Output</anno></c> is the total number of + bytes output to ports.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="5"/> + <fsummary>Information about reductions</fsummary> + <desc> + <marker id="statistics_reductions"></marker> <note> - <p>From erts version 5.5 (OTP release R11B) + <p>Since erts-5.5 (OTP release R11B) this value does not include reductions performed in current time slices of currently scheduled processes. If an exact value is wanted, use @@ -4972,53 +4431,65 @@ true</pre> > <input>statistics(reductions).</input> {2046,11} </pre> - </item> - <tag><c>run_queue</c></tag> - <item> - <p>Returns the length of the run queue, that is, the number - of processes that are ready to run.</p> - </item> - <tag><c>runtime</c></tag> - <item> - <p>Returns <c>{Total_Run_Time, Time_Since_Last_Call}</c>. - Note that the run-time is the sum of the run-time for all - threads in the Erlang run-time system and may therefore be greater - than the wall-clock time.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="6"/> + <fsummary>Information about the run-queue</fsummary> + <desc> + <p>Returns the length of the run queue, that is, the number + of processes that are ready to run.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="7"/> + <fsummary>Information about run-time</fsummary> + <desc> + <p>Note that the run-time is the sum of the run-time for all + threads in the Erlang run-time system and may therefore be greater + than the wall-clock time.</p> <pre> > <input>statistics(runtime).</input> {1690,1620} </pre> - </item> - <tag><marker id="statistics_scheduler_wall_time"><c>scheduler_wall_time</c></marker></tag> - <item> - <p>Returns a list of tuples with - <c>{SchedulerId, ActiveTime, TotalTime}</c>, where <c>SchedulerId</c> is an integer id of the scheduler, <c>ActiveTime</c> is - the duration the scheduler has been busy, <c>TotalTime</c> is the total time duration since - <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> - activation. The time unit is not defined and may be subject to change - between releases, operating systems and system restarts. - <c>scheduler_wall_time</c> should only be used to calculate relative - values for scheduler-utilization. <c>ActiveTime</c> can never exceed <c>TotalTime</c>. - </p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="8"/> + <fsummary>Information about each schedulers work time</fsummary> + <desc> + <marker id="statistics_scheduler_wall_time"></marker> + <p> + Returns a list of tuples with <c>{<anno>SchedulerId</anno>, + <anno>ActiveTime</anno>, <anno>TotalTime</anno>}</c>, where + <c>SchedulerId</c> is an integer id of the scheduler, <c>ActiveTime</c> is + the duration the scheduler has been busy, <c>TotalTime</c> is the total time duration since + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + activation. The time unit is not defined and may be subject to change + between releases, operating systems and system restarts. + <c>scheduler_wall_time</c> should only be used to calculate relative + values for scheduler-utilization. <c>ActiveTime</c> can never exceed <c>TotalTime</c>. + </p> - <p>The definition of a busy scheduler is when it is not idle or not - scheduling (selecting) a process or port, meaning; executing process - code, executing linked-in-driver or NIF code, executing - built-in-functions or any other runtime handling, garbage collecting - or handling any other memory management. Note, a scheduler may also be - busy even if the operating system has scheduled out the scheduler - thread. - </p> + <p>The definition of a busy scheduler is when it is not idle or not + scheduling (selecting) a process or port, meaning; executing process + code, executing linked-in-driver or NIF code, executing + built-in-functions or any other runtime handling, garbage collecting + or handling any other memory management. Note, a scheduler may also be + busy even if the operating system has scheduled out the scheduler + thread. + </p> - <p> - Returns <c>undefined</c> if the system flag <seealso marker="#system_flag_scheduler_wall_time"> - scheduler_wall_time</seealso> is turned off. - </p> + <p> + Returns <c>undefined</c> if the system flag + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + is turned off. + </p> - <p>The list of scheduler information is unsorted and may appear in different order - between calls. - </p> - <p>Using <c>scheduler_wall_time</c> to calculate scheduler utilization.</p> + <p>The list of scheduler information is unsorted and may appear in different order + between calls. + </p> + <p>Using <c>scheduler_wall_time</c> to calculate scheduler utilization.</p> <pre> > <input>erlang:system_flag(scheduler_wall_time, true).</input> false @@ -5046,34 +4517,26 @@ ok {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0,Ts1)), A/T.</input> 0.9769136803764825 </pre> - <note> <p><c>scheduler_wall_time</c> is by default disabled. Use <c>erlang:system_flag(scheduler_wall_time, true)</c> to enable it. </p> </note> - </item> - - <tag><c>wall_clock</c></tag> - <item> - <p>Returns - <c>{Total_Wallclock_Time, Wallclock_Time_Since_Last_Call}</c>. - <c>wall_clock</c> can be used in the same manner as - <c>runtime</c>, except that real time is measured as - opposed to runtime or CPU time.</p> - </item> - </taglist> </desc> </func> <func> - <name>erlang:suspend_process(Suspendee, OptList) -> boolean()</name> + <name name="statistics" arity="1" clause_i="9"/> + <fsummary>Information about wall-clock</fsummary> + <desc> + <p><c>wall_clock</c> can be used in the same manner as + <c>runtime</c>, except that real time is measured as + opposed to runtime or CPU time.</p> + </desc> + </func> + <func> + <name name="suspend_process" arity="2"/> <fsummary>Suspend a process</fsummary> - <type> - <v>Suspendee = pid()</v> - <v>OptList = [Opt]</v> - <v>Opt = atom()</v> - </type> <desc> <p>Increases the suspend count on the process identified by - <c>Suspendee</c> and puts it in the suspended state if it isn't + <c><anno>Suspendee</anno></c> and puts it in the suspended state if it isn't already in the suspended state. A suspended process will not be scheduled for execution until the process has been resumed. </p> @@ -5081,49 +4544,49 @@ ok <p>A process can be suspended by multiple processes and can be suspended multiple times by a single process. A suspended process will not leave the suspended state until its suspend - count reach zero. The suspend count of <c>Suspendee</c> is - decreased when - <seealso marker="#resume_process/1">erlang:resume_process(Suspendee)</seealso> + count reach zero. The suspend count of <c><anno>Suspendee</anno></c> + is decreased when + <seealso marker="#resume_process/1">erlang:resume_process(<anno>Suspendee</anno>)</seealso> is called by the same process that called - <c>erlang:suspend_process(Suspendee)</c>. All increased suspend + <c>erlang:suspend_process(<anno>Suspendee</anno>)</c>. All increased suspend counts on other processes acquired by a process will automatically be decreased when the process terminates.</p> - <p>Currently the following options (<c>Opt</c>s) are available:</p> + <p>Currently the following options (<c><anno>Opt</anno></c>s) are available:</p> <taglist> <tag><c>asynchronous</c></tag> <item> A suspend request is sent to the process identified by - <c>Suspendee</c>. <c>Suspendee</c> will eventually suspend + <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> will eventually suspend unless it is resumed before it was able to suspend. The caller of <c>erlang:suspend_process/2</c> will return immediately, - regardless of whether the <c>Suspendee</c> has suspended yet - or not. Note that the point in time when the <c>Suspendee</c> + regardless of whether the <c><anno>Suspendee</anno></c> has suspended yet + or not. Note that the point in time when the <c><anno>Suspendee</anno></c> will actually suspend cannot be deduced from other events in the system. The only guarantee given is that the - <c>Suspendee</c> will <em>eventually</em> suspend (unless it + <c><anno>Suspendee</anno></c> will <em>eventually</em> suspend (unless it is resumed). If the <c>asynchronous</c> option has <em>not</em> been passed, the caller of <c>erlang:suspend_process/2</c> will - be blocked until the <c>Suspendee</c> has actually suspended. + be blocked until the <c><anno>Suspendee</anno></c> has actually suspended. </item> <tag><c>unless_suspending</c></tag> <item> - The process identified by <c>Suspendee</c> will be suspended + The process identified by <c><anno>Suspendee</anno></c> will be suspended unless the calling process already is suspending the - <c>Suspendee</c>. If <c>unless_suspending</c> is combined + <c><anno>Suspendee</anno></c>. If <c>unless_suspending</c> is combined with the <c>asynchronous</c> option, a suspend request will be sent unless the calling process already is suspending the - <c>Suspendee</c> or if a suspend request already has been sent + <c><anno>Suspendee</anno></c> or if a suspend request already has been sent and is in transit. If the calling process already is suspending - the <c>Suspendee</c>, or if combined with the <c>asynchronous</c> + the <c><anno>Suspendee</anno></c>, or if combined with the <c>asynchronous</c> option and a send request already is in transit, - <c>false</c> is returned and the suspend count on <c>Suspendee</c> + <c>false</c> is returned and the suspend count on <c><anno>Suspendee</anno></c> will remain unchanged. </item> </taglist> <p>If the suspend count on the process identified by - <c>Suspendee</c> was increased, <c>true</c> is returned; otherwise, + <c><anno>Suspendee</anno></c> was increased, <c>true</c> is returned; otherwise, <c>false</c> is returned.</p> <warning> @@ -5133,28 +4596,28 @@ ok <taglist> <tag><c>badarg</c></tag> <item> - If <c>Suspendee</c> isn't a process identifier. + If <c><anno>Suspendee</anno></c> isn't a process identifier. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c>Suspendee</c> is same the process as + If the process identified by <c><anno>Suspendee</anno></c> is same the process as the process calling <c>erlang:suspend_process/2</c>. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c>Suspendee</c> is not alive. + If the process identified by <c><anno>Suspendee</anno></c> is not alive. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c>Suspendee</c> resides on another node. + If the process identified by <c><anno>Suspendee</anno></c> resides on another node. </item> <tag><c>badarg</c></tag> <item> - If <c>OptList</c> isn't a proper list of valid <c>Opt</c>s. + If <c><anno>OptList</anno></c> isn't a proper list of valid <c><anno>Opt</anno></c>s. </item> <tag><c>system_limit</c></tag> <item> - If the process identified by <c>Suspendee</c> has been suspended more + If the process identified by <c><anno>Suspendee</anno></c> has been suspended more times by the calling process than can be represented by the currently used internal data structures. The current system limit is larger than 2 000 000 000 suspends, and it will never be less @@ -5177,292 +4640,322 @@ ok </desc> </func> <func> - <name>erlang:system_flag(Flag, Value) -> OldValue</name> - <fsummary>Set system flags</fsummary> - <type> - <v>Flag, Value, OldValue -- see below</v> - </type> + <name name="system_flag" arity="2" clause_i="1"/> + <fsummary>Set system flag backtrace_depth</fsummary> + <desc> + <p>Sets the maximum depth of call stack back-traces in the + exit reason element of <c>'EXIT'</c> tuples.</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="2"/> + <type name="cpu_topology"/> + <type name="level_entry"/> + <type name="level_tag"/> + <type name="sub_level"/> + <type name="info_list"/> + <fsummary>Set system flag cpu_topology</fsummary> + <desc> + <warning> + <p><marker id="system_flag_cpu_topology"></marker> + This argument is <em>deprecated</em> and + scheduled for removal in erts-5.10/OTP-R16. Instead of using + this argument you are advised to use the <c>erl</c> command + line argument <seealso marker="erts:erl#+sct">+sct</seealso>. + When this argument has been removed a final CPU topology to use + will be determined at emulator boot time.</p> + </warning> + <p>Sets the user defined <c><anno>CpuTopology</anno></c>. The user defined + CPU topology will override any automatically detected + CPU topology. By passing <c>undefined</c> as <c><anno>CpuTopology</anno></c> + the system will revert back to the CPU topology automatically + detected. The returned value equals the value returned + from <c>erlang:system_info(cpu_topology)</c> before the + change was made. + </p> + <p>Returns the old value of the flag.</p> + <p>The CPU topology is used when binding schedulers to logical + processors. If schedulers are already bound when the CPU + topology is changed, the schedulers will be sent a request + to rebind according to the new CPU topology. + </p> + <p>The user defined CPU topology can also be set by passing + the <seealso marker="erts:erl#+sct">+sct</seealso> command + line argument to <c>erl</c>. + </p> + <p>For information on the <c><anno>CpuTopology</anno></c> type + and more, see the documentation of + <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>, + and the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> + and <seealso marker="erts:erl#+sbt">+sbt</seealso> + command line flags. + </p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="3"/> + <fsummary>Set system flag fullsweep_after</fsummary> + <desc> + <p><c><anno>Number</anno></c> is a non-negative integer which indicates + how many times generational garbage collections can be + done without forcing a fullsweep collection. The value + applies to new processes; processes already running are + not affected.</p> + <p>Returns the old value of the flag.</p> + <p>In low-memory systems (especially without virtual + memory), setting the value to 0 can help to conserve + memory.</p> + <p>An alternative way to set this value is through the + (operating system) environment variable + <c>ERL_FULLSWEEP_AFTER</c>.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="4"/> + <fsummary>Set system flag min_heap_size</fsummary> + <desc> + <p>Sets the default minimum heap size for processes. The + size is given in words. The new <c>min_heap_size</c> only + effects processes spawned after the change of + <c>min_heap_size</c> has been made. + The <c>min_heap_size</c> can be set for individual + processes by use of + <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or + <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="5"/> + <fsummary>Set system flag min_bin_vheap_size</fsummary> + <desc> + <p>Sets the default minimum binary virtual heap size for processes. The + size is given in words. The new <c>min_bin_vhheap_size</c> only + effects processes spawned after the change of + <c>min_bin_vhheap_size</c> has been made. + The <c>min_bin_vheap_size</c> can be set for individual + processes by use of + <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or + <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="6"/> + <fsummary>Set system flag multi_scheduling</fsummary> + <desc> + <p><marker id="system_flag_multi_scheduling"></marker> + If multi-scheduling is enabled, more than one scheduler + thread is used by the emulator. Multi-scheduling can be + blocked. When multi-scheduling has been blocked, only + one scheduler thread will schedule Erlang processes.</p> + <p>If <c><anno>BlockState</anno> =:= block</c>, multi-scheduling will + be blocked. If <c><anno>BlockState</anno> =:= unblock</c> and no-one + else is blocking multi-scheduling and this process has + only blocked one time, multi-scheduling will be unblocked. + One process can block multi-scheduling multiple times. + If a process has blocked multiple times, it has to + unblock exactly as many times as it has blocked before it + has released its multi-scheduling block. If a process that + has blocked multi-scheduling exits, it will release its + blocking of multi-scheduling.</p> + <p>The return values are <c>disabled</c>, <c>blocked</c>, + or <c>enabled</c>. The returned value describes the + state just after the call to + <c>erlang:system_flag(multi_scheduling, <anno>BlockState</anno>)</c> + has been made. The return values are described in the + documentation of <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>.</p> + <p><em>NOTE</em>: Blocking of multi-scheduling should normally + not be needed. If you feel that you need to + block multi-scheduling, think through the + problem at least a couple of times again. + Blocking multi-scheduling should only be used + as a last resort since it will most likely be + a <em>very inefficient</em> way to solve the + problem.</p> + <p>See also <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, + <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, and + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="7"/> + <type name="scheduler_bind_type"/> + <fsummary>Set system flag scheduler_bind_type</fsummary> <desc> <warning> - <p>The - <seealso marker="#system_flag_cpu_topology">cpu_topology</seealso>, - and - <seealso marker="#system_flag_scheduler_bind_type">scheduler_bind_type</seealso> - <c>Flag</c>s are <em>deprecated</em> and have been scheduled for - removal in erts-5.10/OTP-R16.</p> + <p><marker id="system_flag_scheduler_bind_type"></marker> + This argument is <em>deprecated</em> and + scheduled for removal in erts-5.10/OTP-R16. Instead of using + this argument you are advised to use the <c>erl</c> command + line argument <seealso marker="erts:erl#+sbt">+sbt</seealso>. + When this argument has been removed a final scheduler bind type + to use will be determined at emulator boot time.</p> </warning> - <p>Sets various system properties of the Erlang node. Returns - the old value of the flag.</p> + <p>Controls if and how schedulers are bound to logical + processors.</p> + <p>When <c>erlang:system_flag(scheduler_bind_type, <anno>How</anno>)</c> is + called, an asynchronous signal is sent to all schedulers + online which causes them to try to bind or unbind as requested. + <em>NOTE:</em> If a scheduler fails to bind, this + will often be silently ignored. This since it isn't always + possible to verify valid logical processor identifiers. If + an error is reported, it will be reported to the + <c>error_logger</c>. If you want to verify that the + schedulers actually have bound as requested, call + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. + </p> + <p>Schedulers can currently only be bound on newer Linux, + Solaris, FreeBSD, and Windows systems, but more systems will be + supported in the future. + </p> + <p>In order for the runtime system to be able to bind schedulers, + the CPU topology needs to be known. If the runtime system fails + to automatically detect the CPU topology, it can be defined. + For more information on how to define the CPU topology, see + the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command + line flag. + </p> + <p>The runtime system will by default <em>not</em> bind schedulers + to logical processors. + </p> + <p><em>NOTE:</em> If the Erlang runtime system is the only + operating system process that binds threads to logical processors, + this improves the performance of the runtime system. However, + if other operating system processes (as for example another Erlang + runtime system) also bind threads to logical processors, there + might be a performance penalty instead. In some cases this + performance penalty might be severe. If this is the case, you + are advised to not bind the schedulers.</p> + <p>Schedulers can be bound in different ways. The <c><anno>How</anno></c> + argument determines how schedulers are bound. <c><anno>How</anno></c> can + currently be one of:</p> <taglist> - <tag><c>erlang:system_flag(backtrace_depth, Depth)</c></tag> - <item> - <p>Sets the maximum depth of call stack back-traces in the - exit reason element of <c>'EXIT'</c> tuples.</p> - </item> - <tag><marker id="system_flag_cpu_topology"><c>erlang:system_flag(cpu_topology, CpuTopology)</c></marker></tag> - <item> - <p><em>NOTE:</em> This argument is <em>deprecated</em> and - scheduled for removal in erts-5.10/OTP-R16. Instead of using - this argument you are advised to use the <c>erl</c> command - line argument <seealso marker="erts:erl#+sct">+sct</seealso>. - When this argument has been removed a final CPU topology to use - will be determined at emulator boot time.</p> - <p>Sets the user defined <c>CpuTopology</c>. The user defined - CPU topology will override any automatically detected - CPU topology. By passing <c>undefined</c> as <c>CpuTopology</c> - the system will revert back to the CPU topology automatically - detected. The returned value equals the value returned - from <c>erlang:system_info(cpu_topology)</c> before the - change was made. - </p> - <p>The CPU topology is used when binding schedulers to logical - processors. If schedulers are already bound when the CPU - topology is changed, the schedulers will be sent a request - to rebind according to the new CPU topology. - </p> - <p>The user defined CPU topology can also be set by passing - the <seealso marker="erts:erl#+sct">+sct</seealso> command - line argument to <c>erl</c>. - </p> - <p>For information on the <c>CpuTopology</c> type - and more, see the documentation of - <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>, - and the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> - and <seealso marker="erts:erl#+sbt">+sbt</seealso> - command line flags. - </p> - </item> - <tag><c>erlang:system_flag(fullsweep_after, Number)</c></tag> - <item> - <p><c>Number</c> is a non-negative integer which indicates - how many times generational garbage collections can be - done without forcing a fullsweep collection. The value - applies to new processes; processes already running are - not affected.</p> - <p>In low-memory systems (especially without virtual - memory), setting the value to 0 can help to conserve - memory.</p> - <p>An alternative way to set this value is through the - (operating system) environment variable - <c>ERL_FULLSWEEP_AFTER</c>.</p> - </item> - <tag><c>erlang:system_flag(min_heap_size, MinHeapSize)</c></tag> - <item> - <p>Sets the default minimum heap size for processes. The - size is given in words. The new <c>min_heap_size</c> only - effects processes spawned after the change of - <c>min_heap_size</c> has been made. - The <c>min_heap_size</c> can be set for individual - processes by use of - <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or - <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> - </item> - <tag><c>erlang:system_flag(min_bin_vheap_size, MinBinVHeapSize)</c></tag> - <item> - <p>Sets the default minimum binary virtual heap size for processes. The - size is given in words. The new <c>min_bin_vhheap_size</c> only - effects processes spawned after the change of - <c>min_bin_vhheap_size</c> has been made. - The <c>min_bin_vheap_size</c> can be set for individual - processes by use of - <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or - <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> - </item> - <tag><marker id="system_flag_multi_scheduling"><c>erlang:system_flag(multi_scheduling, BlockState)</c></marker></tag> - <item> - <p><c>BlockState = block | unblock</c></p> - <p>If multi-scheduling is enabled, more than one scheduler - thread is used by the emulator. Multi-scheduling can be - blocked. When multi-scheduling has been blocked, only - one scheduler thread will schedule Erlang processes.</p> - <p>If <c>BlockState =:= block</c>, multi-scheduling will - be blocked. If <c>BlockState =:= unblock</c> and no-one - else is blocking multi-scheduling and this process has - only blocked one time, multi-scheduling will be unblocked. - One process can block multi-scheduling multiple times. - If a process has blocked multiple times, it has to - unblock exactly as many times as it has blocked before it - has released its multi-scheduling block. If a process that - has blocked multi-scheduling exits, it will release its - blocking of multi-scheduling.</p> - <p>The return values are <c>disabled</c>, <c>blocked</c>, - or <c>enabled</c>. The returned value describes the - state just after the call to - <c>erlang:system_flag(multi_scheduling, BlockState)</c> - has been made. The return values are described in the - documentation of <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>.</p> - <p><em>NOTE</em>: Blocking of multi-scheduling should normally - not be needed. If you feel that you need to - block multi-scheduling, think through the - problem at least a couple of times again. - Blocking multi-scheduling should only be used - as a last resort since it will most likely be - a <em>very inefficient</em> way to solve the - problem.</p> - <p>See also <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, - <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, and - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> - </item> - <tag><marker id="system_flag_scheduler_bind_type"><c>erlang:system_flag(scheduler_bind_type, How)</c></marker></tag> - <item> - <p><em>NOTE:</em> This argument is <em>deprecated</em> and - scheduled for removal in erts-5.10/OTP-R16. Instead of using - this argument you are advised to use the <c>erl</c> command - line argument <seealso marker="erts:erl#+sbt">+sbt</seealso>. - When this argument has been removed a final scheduler bind type - to use will be determined at emulator boot time.</p> - <p>Controls if and how schedulers are bound to logical - processors.</p> - <p>When <c>erlang:system_flag(scheduler_bind_type, How)</c> is - called, an asynchronous signal is sent to all schedulers - online which causes them to try to bind or unbind as requested. - <em>NOTE:</em> If a scheduler fails to bind, this - will often be silently ignored. This since it isn't always - possible to verify valid logical processor identifiers. If - an error is reported, it will be reported to the - <c>error_logger</c>. If you want to verify that the - schedulers actually have bound as requested, call - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. - </p> - <p>Schedulers can currently only be bound on newer Linux, - Solaris, FreeBSD, and Windows systems, but more systems will be - supported in the future. - </p> - <p>In order for the runtime system to be able to bind schedulers, - the CPU topology needs to be known. If the runtime system fails - to automatically detect the CPU topology, it can be defined. - For more information on how to define the CPU topology, see - the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command - line flag. - </p> - <p>The runtime system will by default <em>not</em> bind schedulers - to logical processors. - </p> - <p><em>NOTE:</em> If the Erlang runtime system is the only - operating system process that binds threads to logical processors, - this improves the performance of the runtime system. However, - if other operating system processes (as for example another Erlang - runtime system) also bind threads to logical processors, there - might be a performance penalty instead. In some cases this - performance penalty might be severe. If this is the case, you - are advised to not bind the schedulers.</p> - <p>Schedulers can be bound in different ways. The <c>How</c> - argument determines how schedulers are bound. <c>How</c> can - currently be one of:</p> - <taglist> - <tag><c>unbound</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt u</seealso>. - </p></item> - <tag><c>no_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ns</seealso>. - </p></item> - <tag><c>thread_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ts</seealso>. - </p></item> - <tag><c>processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ps</seealso>. - </p></item> - <tag><c>spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt s</seealso>. - </p></item> - <tag><c>no_node_thread_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt nnts</seealso>. - </p></item> - <tag><c>no_node_processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt nnps</seealso>. - </p></item> - <tag><c>thread_no_node_processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso>. - </p></item> - <tag><c>default_bind</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt db</seealso>. - </p></item> - </taglist> - <p>The value returned equals <c>How</c> before the - <c>scheduler_bind_type</c> flag was changed.</p> - <p>Failure:</p> - <taglist> - <tag><c>notsup</c></tag> - <item> - <p>If binding of schedulers is not supported.</p> - </item> - <tag><c>badarg</c></tag> - <item> - <p>If <c>How</c> isn't one of the documented alternatives.</p> - </item> - <tag><c>badarg</c></tag> - <item> - <p>If no CPU topology information is available.</p> - </item> - </taglist> - <p>The scheduler bind type can also be set by passing - the <seealso marker="erts:erl#+sbt">+sbt</seealso> command - line argument to <c>erl</c>. - </p> - <p>For more information, see - <seealso marker="#system_info_scheduler_bind_type">erlang:system_info(scheduler_bind_type)</seealso>, - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>, - the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> - and <seealso marker="erts:erl#+sct">+sct</seealso> command line - flags. - </p> - </item> - <tag><marker id="system_flag_scheduler_wall_time"><c>erlang:system_flag(scheduler_wall_time, Boolean)</c></marker></tag> + <tag><c>unbound</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt u</seealso>. + </p></item> + <tag><c>no_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ns</seealso>. + </p></item> + <tag><c>thread_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ts</seealso>. + </p></item> + <tag><c>processor_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ps</seealso>. + </p></item> + <tag><c>spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt s</seealso>. + </p></item> + <tag><c>no_node_thread_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt nnts</seealso>. + </p></item> + <tag><c>no_node_processor_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt nnps</seealso>. + </p></item> + <tag><c>thread_no_node_processor_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso>. + </p></item> + <tag><c>default_bind</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt db</seealso>. + </p></item> + </taglist> + <p>The value returned equals <c><anno>How</anno></c> before the + <c>scheduler_bind_type</c> flag was changed.</p> + <p>Failure:</p> + <taglist> + <tag><c>notsup</c></tag> <item> - <p>Turns on/off scheduler wall time measurements. </p> - <p>For more information see, - <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>. - </p> + <p>If binding of schedulers is not supported.</p> </item> - - <tag><marker id="system_flag_schedulers_online"><c>erlang:system_flag(schedulers_online, SchedulersOnline)</c></marker></tag> + <tag><c>badarg</c></tag> <item> - <p>Sets the amount of schedulers online. Valid range is - <![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers)]]>. - </p> - <p>For more information see, - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, - and - <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. - </p> + <p>If <c>How</c> isn't one of the documented alternatives.</p> </item> - - <tag><c>erlang:system_flag(trace_control_word, TCW)</c></tag> + <tag><c>badarg</c></tag> <item> - <p>Sets the value of the node's trace control word to - <c>TCW</c>. <c>TCW</c> should be an unsigned integer. For - more information see documentation of the - <seealso marker="erts:match_spec#set_tcw">set_tcw</seealso> - function in the match specification documentation in the - ERTS User's Guide.</p> + <p>If no CPU topology information is available.</p> </item> </taglist> - <note> - <p>The <c>schedulers</c> option has been removed as - of erts version 5.5.3. The number of scheduler - threads is determined at emulator boot time, and - cannot be changed after that.</p> - </note> + <p>The scheduler bind type can also be set by passing + the <seealso marker="erts:erl#+sbt">+sbt</seealso> command + line argument to <c>erl</c>. + </p> + <p>For more information, see + <seealso marker="#system_info_scheduler_bind_type">erlang:system_info(scheduler_bind_type)</seealso>, + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>, + the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> + and <seealso marker="erts:erl#+sct">+sct</seealso> command line + flags. + </p> </desc> </func> <func> - <name>erlang:system_info(Type) -> Res</name> - <fsummary>Information about the system</fsummary> - <type> - <v>Type, Res -- see below</v> - </type> + <name name="system_flag" arity="2" clause_i="8"/> + <fsummary>Set system flag scheduler_wall_time</fsummary> + <desc><p><marker id="system_flag_scheduler_wall_time"></marker> + Turns on/off scheduler wall time measurements. </p> + <p>For more information see, + <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>. + </p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="9"/> + <fsummary>Set system flag schedulers_online</fsummary> <desc> - <p>Returns various information about the current system - (emulator) as specified by <c>Type</c>:</p> + <p><marker id="system_flag_schedulers_online"></marker> + Sets the amount of schedulers online. Valid range is + <![CDATA[1 <= SchedulersOnline <= erlang:system_info(schedulers)]]>. + </p> + <p>Returns the old value of the flag.</p> + <p>For more information see, + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, + and + <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. + </p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="10"/> + <fsummary>Set system flag trace_control_word</fsummary> + <desc> + <p>Sets the value of the node's trace control word to + <c><anno>TCW</anno></c>. <c><anno>TCW</anno></c> should be an unsigned integer. For + more information see documentation of the + <seealso marker="erts:match_spec#set_tcw">set_tcw</seealso> + function in the match specification documentation in the + ERTS User's Guide.</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="system_info" arity="1" clause_i="1"/> + <name name="system_info" arity="1" clause_i="2"/> + <name name="system_info" arity="1" clause_i="3"/> + <name name="system_info" arity="1" clause_i="4"/> + <name name="system_info" arity="1" clause_i="5"/> + <type variable="Allocator" name_i="2"/> + <type variable="Version" name_i="2"/> + <type variable="Features" name_i="2"/> + <type variable="Settings" name_i="2"/> + <type variable="Alloc" name_i="3"/> + <fsummary>Information about the allocators of the system</fsummary> + <desc> + <p> + Returns various information about the + <marker id="system_info_allocator_tags">allocators</marker> of the + current system (emulator) as specified by + <c><anno>Item</anno></c>:</p> <taglist> <tag><marker id="system_info_allocated_areas"><c>allocated_areas</c></marker></tag> <item> @@ -5487,37 +4980,27 @@ ok </item> <tag><marker id="system_info_allocator"><c>allocator</c></marker></tag> <item> - <p>Returns <c>{Allocator, Version, Features, Settings}.</c></p> - <p>Types:</p> - <list type="bulleted"> - <item><c>Allocator = undefined | glibc</c></item> - <item><c>Version = [integer()]</c></item> - <item><c>Features = [atom()]</c></item> - <item><c>Settings = [{Subsystem, [{Parameter, Value}]}]</c></item> - <item><c>Subsystem = atom()</c></item> - <item><c>Parameter = atom()</c></item> - <item><c>Value = term()</c></item> - </list> + <p>Returns <c>{<anno>Allocator</anno>, <anno>Version</anno>, <anno>Features</anno>, <anno>Settings</anno>}.</c></p> <p>Explanation:</p> <list type="bulleted"> <item> - <p><c>Allocator</c> corresponds to the <c>malloc()</c> - implementation used. If <c>Allocator</c> equals + <p><c><anno>Allocator</anno></c> corresponds to the <c>malloc()</c> + implementation used. If <c><anno>Allocator</anno></c> equals <c>undefined</c>, the <c>malloc()</c> implementation used could not be identified. Currently <c>glibc</c> can be identified.</p> </item> <item> - <p><c>Version</c> is a list of integers (but not a + <p><c><anno>Version</anno></c> is a list of integers (but not a string) representing the version of the <c>malloc()</c> implementation used.</p> </item> <item> - <p><c>Features</c> is a list of atoms representing + <p><c><anno>Features</anno></c> is a list of atoms representing allocation features used.</p> </item> <item> - <p><c>Settings</c> is a list of subsystems, their + <p><c><anno>Settings</anno></c> is a list of subsystems, their configurable parameters, and used values. Settings may differ between different combinations of platforms, allocators, and allocation features. @@ -5537,15 +5020,15 @@ ok erts_alloc(3)</seealso> documentation. </p> </item> - <tag><marker id="system_info_allocator_tuple"><c>{allocator, Alloc}</c></marker></tag> + <tag><marker id="system_info_allocator_tuple"><c>{allocator, <anno>Alloc</anno>}</c></marker></tag> <item> <p>Returns information about the specified allocator. As of erts version 5.6.1 the return value is a list of <c>{instance, InstanceNo, InstanceInfo}</c> tuples where <c>InstanceInfo</c> contains information about a specific instance of the allocator. - If <c>Alloc</c> is not a recognized allocator, - <c>undefined</c> is returned. If <c>Alloc</c> is disabled, + If <c><anno>Alloc</anno></c> is not a recognized allocator, + <c>undefined</c> is returned. If <c><anno>Alloc</anno></c> is disabled, <c>false</c> is returned.</p> <p><em>Note:</em> The information returned is highly implementation dependent and may be changed, or removed @@ -5574,54 +5057,51 @@ ok values. The first value is memory pool size and the second value used memory size.</p> </item> - <tag><marker id="system_info_allocator_sizes"><c>{allocator_sizes, Alloc}</c></marker></tag> + <tag><marker id="system_info_allocator_sizes"><c>{allocator_sizes, <anno>Alloc</anno>}</c></marker></tag> <item> <p>Returns various size information for the specified allocator. The information returned is a subset of the information returned by - <seealso marker="#system_info_allocator_tuple">erlang:system_info({allocator, Alloc})</seealso>. + <seealso marker="#system_info_allocator_tuple">erlang:system_info({allocator, <anno>Alloc</anno>})</seealso>. </p> </item> - <tag><c>build_type</c></tag> - <item> - <p>Returns an atom describing the build type of the runtime - system. This is normally the atom <c>opt</c> for optimized. - Other possible return values are <c>debug</c>, <c>purify</c>, - <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>, - <c>gprof</c>, and <c>lcnt</c>. Possible return values - may be added and/or removed at any time without prior notice. - </p> - </item> - <tag><c>c_compiler_used</c></tag> - <item> - <p>Returns a two-tuple describing the C compiler used when - compiling the runtime system. The first element is an - atom describing the name of the compiler, or <c>undefined</c> - if unknown. The second element is a term describing the - version of the compiler, or <c>undefined</c> if unknown. - </p> - </item> - <tag><c>check_io</c></tag> - <item> - <p>Returns a list containing miscellaneous information - regarding the emulators internal I/O checking. Note, - the content of the returned list may vary between - platforms and over time. The only thing guaranteed is - that a list is returned.</p> - </item> - <tag><c>compat_rel</c></tag> - <item> - <p>Returns the compatibility mode of the local node as - an integer. The integer returned represents the - Erlang/OTP release which the current emulator has been - set to be backward compatible with. The compatibility - mode can be configured at startup by using the command - line flag <c>+R</c>, see - <seealso marker="erts:erl#compat_rel">erl(1)</seealso>.</p> - </item> - <tag><marker id="system_info_cpu_topology"><c>cpu_topology</c></marker></tag> + </taglist> + </desc> + </func> + <func> + <name name="system_info" arity="1" clause_i="10"/> + <name name="system_info" arity="1" clause_i="11"/> + <type name="cpu_topology"/> + <type name="level_entry"/> + <type_desc name="cpu_topology"> + <marker id="system_info_cpu_topology"></marker> + All <c><anno>LevelEntry</anno></c>s of a list + must contain the same <c><anno>LevelTag</anno></c>, except + on the top level where both <c>node</c> and + <c>processor</c> <c><anno>LevelTag</anno></c>s may co-exist. + </type_desc> + <type_desc name="level_entry"> + <c>{<anno>LevelTag</anno>, <anno>SubLevel</anno>} == {<anno>LevelTag</anno>, [], <anno>SubLevel</anno>}</c> + </type_desc> + <type name="level_tag"/> + <type_desc name="level_tag"> + More <c><anno>LevelTag</anno></c>s may be introduced in the future. + </type_desc> + <type name="sub_level"/> + <type name="info_list"/> + <type_desc name="info_list"> + The <c>info_list()</c> may be extended in the future. + </type_desc> + <fsummary>Information about the CPU topology of the system</fsummary> + <desc> + <p>Returns various information about the + <marker id="system_info_cpu_topology_tags">CPU topology</marker> + of the current system + (emulator) as specified by <c><anno>Item</anno></c>:</p> + <taglist> + <tag><c>cpu_topology</c></tag> <item> - <p>Returns the <c>CpuTopology</c> which currently is used by the + <p>Returns the <c><anno>CpuTopology</anno></c> which currently is used by the emulator. The CPU topology is used when binding schedulers to logical processors. The CPU topology used is the <seealso marker="erlang#system_info_cpu_topology_defined">user @@ -5629,31 +5109,11 @@ ok <seealso marker="erlang#system_info_cpu_topology_detected">automatically detected CPU topology</seealso> if such exists. If no CPU topology exists, <c>undefined</c> is returned.</p> - <p>Types:</p> - <list type="bulleted"> - <item><c>CpuTopology = LevelEntryList | undefined</c></item> - <item><c>LevelEntryList = [LevelEntry]</c> (all - <c>LevelEntry</c>s of a <c>LevelEntryList</c> - must contain the same <c>LevelTag</c>, except - on the top level where both <c>node</c> and - <c>processor</c> <c>LevelTag</c>s may co-exist)</item> - <item><c>LevelEntry = {LevelTag, SubLevel} - | {LevelTag, InfoList, SubLevel}</c> - (<c>{LevelTag, SubLevel} - == {LevelTag, [], SubLevel}</c>)</item> - <item><c>LevelTag = node|processor|core|thread</c> - (more <c>LevelTag</c>s may be introduced in - the future)</item> - <item><c>SubLevel = [LevelEntry] | LogicalCpuId</c></item> - <item><c>LogicalCpuId = {logical, integer()}</c></item> - <item><c>InfoList = []</c> (the <c>InfoList</c> - may be extended in the future)</item> - </list> <p><c>node</c> refers to NUMA (non-uniform memory access) nodes, and <c>thread</c> refers to hardware threads (e.g. Intels hyper-threads).</p> - <p>A level in the <c>CpuTopology</c> term can be omitted if - only one entry exists and the <c>InfoList</c> is empty. + <p>A level in the <c><anno>CpuTopology</anno></c> term can be omitted if + only one entry exists and the <c><anno>InfoList</anno></c> is empty. </p> <p><c>thread</c> can only be a sub level to <c>core</c>. <c>core</c> can be a sub level to either <c>processor</c> @@ -5665,15 +5125,15 @@ ok consist of a mix of processor internal and external NUMA nodes, as long as each logical CPU belongs to one and only one NUMA node. Cache hierarchy is not part of - the <c>CpuTopology</c> type yet, but will be in the + the <c><anno>CpuTopology</anno></c> type yet, but will be in the future. Other things may also make it into the CPU topology in the future. In other words, expect the - <c>CpuTopology</c> type to change. + <c><anno>CpuTopology</anno></c> type to change. </p> </item> <tag><marker id="system_info_cpu_topology_defined"><c>{cpu_topology, defined}</c></marker></tag> <item> - <p>Returns the user defined <c>CpuTopology</c>. For more + <p>Returns the user defined <c><anno>CpuTopology</anno></c>. For more information see the documentation of the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command line flag, and the documentation of the @@ -5683,7 +5143,7 @@ ok </item> <tag><marker id="system_info_cpu_topology_detected"><c>{cpu_topology, detected}</c></marker></tag> <item> - <p>Returns the automatically detected <c>CpuTopology</c>. The + <p>Returns the automatically detected <c><anno>CpuTopology</anno></c>. The emulator currently only detects the CPU topology on some newer Linux, Solaris, FreeBSD, and Windows systems. On Windows system with more than 32 logical processors the CPU topology is not detected. @@ -5695,13 +5155,112 @@ ok </item> <tag><c>{cpu_topology, used}</c></tag> <item> - <p>Returns the <c>CpuTopology</c> which is used by the + <p>Returns the <c><anno>CpuTopology</anno></c> which is used by the emulator. For more information see the documentation of the <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> argument. </p> </item> + </taglist> + </desc> + </func> + <func> + <name name="system_info" arity="1" clause_i="6"/> + <name name="system_info" arity="1" clause_i="7"/> + <name name="system_info" arity="1" clause_i="8"/> + <name name="system_info" arity="1" clause_i="9"/> + <name name="system_info" arity="1" clause_i="12"/> + <name name="system_info" arity="1" clause_i="13"/> + <name name="system_info" arity="1" clause_i="14"/> + <name name="system_info" arity="1" clause_i="15"/> + <name name="system_info" arity="1" clause_i="16"/> + <name name="system_info" arity="1" clause_i="17"/> + <name name="system_info" arity="1" clause_i="18"/> + <name name="system_info" arity="1" clause_i="19"/> + <name name="system_info" arity="1" clause_i="20"/> + <name name="system_info" arity="1" clause_i="21"/> + <name name="system_info" arity="1" clause_i="22"/> + <name name="system_info" arity="1" clause_i="23"/> + <name name="system_info" arity="1" clause_i="24"/> + <name name="system_info" arity="1" clause_i="25"/> + <name name="system_info" arity="1" clause_i="26"/> + <name name="system_info" arity="1" clause_i="27"/> + <name name="system_info" arity="1" clause_i="28"/> + <name name="system_info" arity="1" clause_i="29"/> + <name name="system_info" arity="1" clause_i="30"/> + <name name="system_info" arity="1" clause_i="31"/> + <name name="system_info" arity="1" clause_i="32"/> + <name name="system_info" arity="1" clause_i="33"/> + <name name="system_info" arity="1" clause_i="34"/> + <name name="system_info" arity="1" clause_i="35"/> + <name name="system_info" arity="1" clause_i="36"/> + <name name="system_info" arity="1" clause_i="37"/> + <name name="system_info" arity="1" clause_i="38"/> + <name name="system_info" arity="1" clause_i="39"/> + <name name="system_info" arity="1" clause_i="40"/> + <name name="system_info" arity="1" clause_i="41"/> + <name name="system_info" arity="1" clause_i="42"/> + <name name="system_info" arity="1" clause_i="43"/> + <name name="system_info" arity="1" clause_i="44"/> + <name name="system_info" arity="1" clause_i="45"/> + <name name="system_info" arity="1" clause_i="46"/> + <name name="system_info" arity="1" clause_i="47"/> + <name name="system_info" arity="1" clause_i="48"/> + <name name="system_info" arity="1" clause_i="49"/> + <name name="system_info" arity="1" clause_i="50"/> + <name name="system_info" arity="1" clause_i="51"/> + <fsummary>Information about the system</fsummary> + <desc> + <p>Returns various information about the current system + (emulator) as specified by <c><anno>Item</anno></c>:</p> + <taglist> + <tag><c>allocated_areas</c>, <c>allocator</c>, + <c>alloc_util_allocators</c>, <c>allocator_sizes</c></tag> + <item> + <p>See <seealso marker="#system_info_allocator_tags">above</seealso>.</p> + </item> + <tag><c>build_type</c></tag> + <item> + <p>Returns an atom describing the build type of the runtime + system. This is normally the atom <c>opt</c> for optimized. + Other possible return values are <c>debug</c>, <c>purify</c>, + <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>, + <c>gprof</c>, and <c>lcnt</c>. Possible return values + may be added and/or removed at any time without prior notice. + </p> + </item> + <tag><c>c_compiler_used</c></tag> + <item> + <p>Returns a two-tuple describing the C compiler used when + compiling the runtime system. The first element is an + atom describing the name of the compiler, or <c>undefined</c> + if unknown. The second element is a term describing the + version of the compiler, or <c>undefined</c> if unknown. + </p> + </item> + <tag><c>check_io</c></tag> + <item> + <p>Returns a list containing miscellaneous information + regarding the emulators internal I/O checking. Note, + the content of the returned list may vary between + platforms and over time. The only thing guaranteed is + that a list is returned.</p> + </item> + <tag><c>compat_rel</c></tag> + <item> + <p>Returns the compatibility mode of the local node as + an integer. The integer returned represents the + Erlang/OTP release which the current emulator has been + set to be backward compatible with. The compatibility + mode can be configured at startup by using the command + line flag <c>+R</c>, see + <seealso marker="erts:erl#compat_rel">erl(1)</seealso>.</p> + </item> + <tag><c>cpu_topology</c></tag> + <item> + <p>See <seealso marker="#system_info_cpu_topology_tags">above</seealso>.</p> + </item> <tag><c>creation</c></tag> <item> <p>Returns the creation of the local node as an integer. @@ -5731,10 +5290,10 @@ ok <item> <p>Returns a list of tuples <c>{Node, ControllingEntity}</c>, one entry for each - connected remote node. The <c>Node</c> is the name of the - node and the <c>ControllingEntity</c> is the port or pid + connected remote node. The <c><anno>Node</anno></c> is the name of the + node and the <c><anno>ControllingEntity</anno></c> is the port or pid responsible for the communication to that node. More - specifically, the <c>ControllingEntity</c> for nodes + specifically, the <c><anno>ControllingEntity</anno></c> for nodes connected via TCP/IP (the normal case) is the socket actually used in communication with the specific node.</p> </item> @@ -5782,7 +5341,7 @@ ok </item> <tag><c>fullsweep_after</c></tag> <item> - <p>Returns <c>{fullsweep_after, integer()}</c> which is the + <p>Returns <c>{fullsweep_after, integer() >= 0}</c> which is the <c>fullsweep_after</c> garbage collection setting used by default. For more information see <c>garbage_collection</c> described below.</p> @@ -5875,12 +5434,12 @@ ok </item> <tag><c>min_heap_size</c></tag> <item> - <p>Returns <c>{min_heap_size, MinHeapSize}</c> where <c>MinHeapSize</c> is the current system wide + <p>Returns <c>{min_heap_size, <anno>MinHeapSize</anno>}</c> where <c><anno>MinHeapSize</anno></c> is the current system wide minimum heap size for spawned processes.</p> </item> <tag><c>min_bin_vheap_size</c></tag> <item> - <p>Returns <c>{min_bin_vheap_size, MinBinVHeapSize}</c> where <c>MinBinVHeapSize</c> is the current system wide + <p>Returns <c>{min_bin_vheap_size, <anno>MinBinVHeapSize</anno>}</c> where <c><anno>MinBinVHeapSize</anno></c> is the current system wide minimum binary virtual heap size for spawned processes.</p> </item> <tag><c>modified_timing_level</c></tag> @@ -5924,10 +5483,10 @@ ok </item> <tag><marker id="system_info_multi_scheduling_blockers"><c>multi_scheduling_blockers</c></marker></tag> <item> - <p>Returns a list of <c>PID</c>s when multi-scheduling - is blocked; otherwise, the empty list. The <c>PID</c>s - in the list is <c>PID</c>s of the processes currently - blocking multi-scheduling. A <c>PID</c> will only be + <p>Returns a list of <c><anno>PID</anno></c>s when multi-scheduling + is blocked; otherwise, the empty list. The <c><anno>PID</anno></c>s + in the list is <c><anno>PID</anno></c>s of the processes currently + blocking multi-scheduling. A <c><anno>PID</anno></c> will only be present once in the list, even if the corresponding process has blocked multiple times.</p> <p>See also <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, @@ -6002,7 +5561,7 @@ ok <item> <p>Returns the scheduler id (<c>SchedulerId</c>) of the scheduler thread that the calling process is executing - on. <c>SchedulerId</c> is a positive integer; where + on. <c><anno>SchedulerId</anno></c> is a positive integer; where <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers)]]></c>. See also <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </item> @@ -6034,7 +5593,8 @@ ok <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, and <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>. - </p> + </p> <name name="system_info" arity="1" clause_i="49"/> + </item> <tag><c>smp_support</c></tag> <item> @@ -6128,53 +5688,39 @@ ok </func> <func> - <name>erlang:system_monitor() -> MonSettings</name> + <name name="system_monitor" arity="0"/> + <type name="system_monitor_option"/> <fsummary>Current system performance monitoring settings</fsummary> - <type> - <v>MonSettings -> {MonitorPid, Options} | undefined</v> - <v> MonitorPid = pid()</v> - <v> Options = [Option]</v> - <v> Option = {long_gc, Time} | {large_heap, Size} | busy_port | busy_dist_port</v> - <v> Time = Size = integer()</v> - </type> <desc> <p>Returns the current system monitoring settings set by <seealso marker="#system_monitor/2">erlang:system_monitor/2</seealso> - as <c>{MonitorPid, Options}</c>, or <c>undefined</c> if there + as <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c>, or <c>undefined</c> if there are no settings. The order of the options may be different from the one that was set.</p> </desc> </func> <func> - <name>erlang:system_monitor(undefined | {MonitorPid, Options}) -> MonSettings</name> + <name name="system_monitor" arity="1"/> + <type name="system_monitor_option"/> <fsummary>Set or clear system performance monitoring options</fsummary> - <type> - <v>MonitorPid, Options, MonSettings -- see below</v> - </type> <desc> <p>When called with the argument <c>undefined</c>, all system performance monitoring settings are cleared.</p> - <p>Calling the function with <c>{MonitorPid, Options}</c> as + <p>Calling the function with <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c> as argument, is the same as calling - <seealso marker="#system_monitor/2">erlang:system_monitor(MonitorPid, Options)</seealso>.</p> + <seealso marker="#system_monitor/2">erlang:system_monitor(<anno>MonitorPid</anno>, <anno>Options</anno>)</seealso>.</p> <p>Returns the previous system monitor settings just like <seealso marker="#system_monitor/0">erlang:system_monitor/0</seealso>.</p> </desc> </func> <func> - <name>erlang:system_monitor(MonitorPid, [Option]) -> MonSettings</name> + <name name="system_monitor" arity="2"/> + <type name="system_monitor_option"/> <fsummary>Set system performance monitoring options</fsummary> - <type> - <v>MonitorPid = pid()</v> - <v>Option = {long_gc, Time} | {large_heap, Size} | busy_port | busy_dist_port</v> - <v> Time = Size = integer()</v> - <v>MonSettings = {OldMonitorPid, [Option]}</v> - <v> OldMonitorPid = pid()</v> - </type> - <desc> - <p>Sets system performance monitoring options. <c>MonitorPid</c> + <desc> + <p>Sets system performance monitoring options. <c><anno>MonitorPid</anno></c> is a local pid that will receive system monitor messages, and the second argument is a list of monitoring options:</p> <taglist> @@ -6183,7 +5729,7 @@ ok <p>If a garbage collection in the system takes at least <c>Time</c> wallclock milliseconds, a message <c>{monitor, GcPid, long_gc, Info}</c> is sent to - <c>MonitorPid</c>. <c>GcPid</c> is the pid that was + <c><anno>MonitorPid</anno></c>. <c>GcPid</c> is the pid that was garbage collected and <c>Info</c> is a list of two-element tuples describing the result of the garbage collection. One of the tuples is <c>{timeout, GcTime}</c> where @@ -6206,7 +5752,7 @@ ok <p>If a garbage collection in the system results in the allocated size of a heap being at least <c>Size</c> words, a message <c>{monitor, GcPid, large_heap, Info}</c> - is sent to <c>MonitorPid</c>. <c>GcPid</c> and <c>Info</c> + is sent to <c><anno>MonitorPid</anno></c>. <c>GcPid</c> and <c>Info</c> are the same as for <c>long_gc</c> above, except that the tuple tagged with <c>timeout</c> is not present. <em>Note</em>: As of erts version 5.6 the monitor message @@ -6222,7 +5768,7 @@ ok <p>If a process in the system gets suspended because it sends to a busy port, a message <c>{monitor, SusPid, busy_port, Port}</c> is sent to - <c>MonitorPid</c>. <c>SusPid</c> is the pid that got + <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid that got suspended when sending to <c>Port</c>.</p> </item> <tag><c>busy_dist_port</c></tag> @@ -6231,7 +5777,7 @@ ok sends to a process on a remote node whose inter-node communication was handled by a busy port, a message <c>{monitor, SusPid, busy_dist_port, Port}</c> is sent to - <c>MonitorPid</c>. <c>SusPid</c> is the pid that got + <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid that got suspended when sending through the inter-node communication port <c>Port</c>.</p> </item> @@ -6246,48 +5792,48 @@ ok <p>Keep the monitoring process neat and do not set the system monitor limits too tight.</p> </note> - <p>Failure: <c>badarg</c> if <c>MonitorPid</c> does not exist.</p> + <p>Failure: <c>badarg</c> if <c><anno>MonitorPid</anno></c> does not exist or is not a local process.</p> </desc> </func> <func> - <name>erlang:system_profile() -> ProfilerSettings</name> + <name name="system_profile" arity="0"/> + <type name="system_profile_option"/> <fsummary>Current system profiling settings</fsummary> - <type> - <v>ProfilerSettings -> {ProfilerPid, Options} | undefined</v> - <v> ProfilerPid = pid() | port()</v> - <v> Options = [Option]</v> - <v> Option = runnable_procs | runnable_ports | scheduler | exclusive</v> - </type> <desc> <p>Returns the current system profiling settings set by <seealso marker="#system_profile/2">erlang:system_profile/2</seealso> - as <c>{ProfilerPid, Options}</c>, or <c>undefined</c> if there + as <c>{<anno>ProfilerPid</anno>, <anno>Options</anno>}</c>, or <c>undefined</c> if there are no settings. The order of the options may be different from the one that was set.</p> </desc> </func> <func> - <name>erlang:system_profile(ProfilerPid, Options) -> ProfilerSettings</name> + <name name="system_profile" arity="2"/> + <type name="system_profile_option"/> <fsummary>Current system profiling settings</fsummary> - <type> - <v>ProfilerSettings -> {ProfilerPid, Options} | undefined</v> - <v> ProfilerPid = pid() | port()</v> - <v> Options = [Option]</v> - <v> Option = runnable_procs | runnable_ports | scheduler | exclusive</v> - </type> - <desc> - <p>Sets system profiler options. <c>ProfilerPid</c> + <desc> + <p>Sets system profiler options. <c><anno>ProfilerPid</anno></c> is a local pid or port that will receive profiling messages. The receiver is excluded from all profiling. The second argument is a list of profiling options:</p> <taglist> + <tag><c>exclusive</c></tag> + <item> + <p> + If a synchronous call to a port from a process is done, the + calling process is considered not runnable during the call + runtime to the port. The calling process is notified as + <c>inactive</c> and subsequently <c>active</c> when the port + callback returns. + </p> + </item> <tag><c>runnable_procs</c></tag> <item> <p>If a process is put into or removed from the run queue a message, <c>{profile, Pid, State, Mfa, Ts}</c>, is sent to - <c>ProfilerPid</c>. Running processes that is reinserted into the + <c><anno>ProfilerPid</anno></c>. Running processes that is reinserted into the run queue after having been preemptively scheduled out will not trigger this message. </p> @@ -6296,24 +5842,14 @@ ok <item> <p>If a port is put into or removed from the run queue a message, <c>{profile, Port, State, 0, Ts}</c>, is sent to - <c>ProfilerPid</c>. + <c><anno>ProfilerPid</anno></c>. </p> </item> <tag><c>scheduler</c></tag> <item> <p>If a scheduler is put to sleep or awoken a message, <c>{profile, scheduler, Id, State, NoScheds, Ts}</c>, is sent - to <c>ProfilerPid</c>. - </p> - </item> - <tag><c>exclusive</c></tag> - <item> - <p> - If a synchronous call to a port from a process is done, the - calling process is considered not runnable during the call - runtime to the port. The calling process is notified as - <c>inactive</c> and subsequently <c>active</c> when the port - callback returns. + to <c><anno>ProfilerPid</anno></c>. </p> </item> </taglist> @@ -6324,14 +5860,11 @@ ok </func> <func> - <name>term_to_binary(Term) -> ext_binary()</name> + <name name="term_to_binary" arity="1"/> <fsummary>Encode a term to an Erlang external term format binary</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> <p>Returns a binary data object which is the result of encoding - <c>Term</c> according to the Erlang external term format.</p> + <c><anno>Term</anno></c> according to the Erlang external term format.</p> <p>This can be used for a variety of purposes, for example writing a term to a file in an efficient way, or sending an Erlang term to some type of communications channel not @@ -6341,20 +5874,16 @@ ok </desc> </func> <func> - <name>term_to_binary(Term, [Option]) -> ext_binary()</name> + <name name="term_to_binary" arity="2"/> <fsummary>Encode a term to en Erlang external term format binary</fsummary> - <type> - <v>Term = term()</v> - <v>Option = compressed | {compressed,Level} | {minor_version,Version}</v> - </type> <desc> <p>Returns a binary data object which is the result of encoding - <c>Term</c> according to the Erlang external term format.</p> + <c><anno>Term</anno></c> according to the Erlang external term format.</p> <p>If the option <c>compressed</c> is provided, the external term format will be compressed. The compressed format is automatically recognized by <c>binary_to_term/1</c> in R7B and later.</p> <p>It is also possible to specify a compression level by giving - the option <c>{compressed,Level}</c>, where <c>Level</c> is an + the option <c>{compressed, <anno>Level</anno>}</c>, where <c><anno>Level</anno></c> is an integer from 0 through 9. <c>0</c> means that no compression will be done (it is the same as not giving any <c>compressed</c> option); <c>1</c> will take the least time but may not compress as well as @@ -6363,16 +5892,16 @@ ok on the input term, level 9 compression may or may not produce a smaller result than level 1 compression.</p> <p>Currently, <c>compressed</c> gives the same result as - <c>{compressed,6}</c>.</p> - <p>The option <c>{minor_version,Version}</c> can be use to control + <c>{compressed, 6}</c>.</p> + <p>The option <c>{minor_version, <anno>Version</anno>}</c> can be use to control some details of the encoding. This option was - introduced in R11B-4. Currently, the allowed values for <c>Version</c> + introduced in R11B-4. Currently, the allowed values for <c><anno>Version</anno></c> are <c>0</c> and <c>1</c>.</p> - <p><c>{minor_version,1}</c> forces any floats in the term to be encoded + <p><c>{minor_version, 1}</c> forces any floats in the term to be encoded in a more space-efficient and exact way (namely in the 64-bit IEEE format, rather than converted to a textual representation). <c>binary_to_term/1</c> in R11B-4 and later is able decode the new representation.</p> - <p><c>{minor_version,0}</c> is currently the default, meaning that floats + <p><c>{minor_version, 0}</c> is currently the default, meaning that floats will be encoded using a textual representation; this option is useful if you want to ensure that releases prior to R11B-4 can decode resulting binary.</p> @@ -6381,14 +5910,11 @@ ok </desc> </func> <func> - <name>throw(Any)</name> + <name name="throw" arity="1"/> <fsummary>Throw an exception</fsummary> - <type> - <v>Any = term()</v> - </type> <desc> <p>A non-local return from a function. If evaluated within a - <c>catch</c>, <c>catch</c> will return the value <c>Any</c>.</p> + <c>catch</c>, <c>catch</c> will return the value <c><anno>Any</anno></c>.</p> <pre> > <input>catch throw({hello, there}).</input> {hello,there}</pre> @@ -6396,11 +5922,8 @@ ok </desc> </func> <func> - <name>time() -> {Hour, Minute, Second}</name> + <name name="time" arity="0"/> <fsummary>Current time</fsummary> - <type> - <v>Hour = Minute = Second = integer() >= 0</v> - </type> <desc> <p>Returns the current time as <c>{Hour, Minute, Second}</c>.</p> <p>The time zone and daylight saving time correction depend on @@ -6411,35 +5934,27 @@ ok </desc> </func> <func> - <name>tl(List1) -> List2</name> + <name name="tl" arity="1"/> <fsummary>Tail of a list</fsummary> - <type> - <v>List1 = List2 = [term()]</v> - </type> <desc> - <p>Returns the tail of <c>List1</c>, that is, the list minus + <p>Returns the tail of <c><anno>List</anno></c>, that is, the list minus the first element.</p> <pre> > <input>tl([geesties, guilies, beasties]).</input> [guilies, beasties]</pre> <p>Allowed in guard tests.</p> - <p>Failure: <c>badarg</c> if <c>List</c> is the empty list [].</p> + <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty list [].</p> </desc> </func> <func> - <name>erlang:trace(PidSpec, How, FlagList) -> integer() >= 0</name> + <name name="trace" arity="3"/> + <type name="trace_flag"/> <fsummary>Set trace flags for a process or processes</fsummary> - <type> - <v>PidSpec = pid() | existing | new | all</v> - <v>How = boolean()</v> - <v>FlagList = [Flag]</v> - <v> Flag -- see below</v> - </type> - <desc> - <p>Turns on (if <c>How == true</c>) or off (if - <c>How == false</c>) the trace flags in <c>FlagList</c> for - the process or processes represented by <c>PidSpec</c>.</p> - <p><c>PidSpec</c> is either a pid for a local process, or one of + <desc> + <p>Turns on (if <c><anno>How</anno> == true</c>) or off (if + <c><anno>How</anno> == false</c>) the trace flags in <c><anno>FlagList</anno></c> for + the process or processes represented by <c><anno>PidSpec</anno></c>.</p> + <p><c><anno>PidSpec</anno></c> is either a pid for a local process, or one of the following atoms:</p> <taglist> <tag><c>existing</c></tag> @@ -6456,7 +5971,7 @@ ok will be created in the future.</p> </item> </taglist> - <p><c>FlagList</c> can contain any number of the following + <p><c><anno>FlagList</anno></c> can contain any number of the following flags (the "message tags" refers to the list of messages following below):</p> <taglist> @@ -6771,11 +6286,11 @@ ok <p>Only one process can trace a particular process. For this reason, attempts to trace an already traced process will fail.</p> <p>Returns: A number indicating the number of processes that - matched <c>PidSpec</c>. If <c>PidSpec</c> is a pid, - the return value will be <c>1</c>. If <c>PidSpec</c> is + matched <c><anno>PidSpec</anno></c>. If <c><anno>PidSpec</anno></c> is a pid, + the return value will be <c>1</c>. If <c><anno>PidSpec</anno></c> is <c>all</c> or <c>existing</c> the return value will be the number of processes running, excluding tracer processes. - If <c>PidSpec</c> is <c>new</c>, the return value will be + If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value will be <c>0</c>.</p> <p>Failure: If specified arguments are not supported. For example <c>cpu_timestamp</c> is not supported on all @@ -6783,64 +6298,58 @@ ok </desc> </func> <func> - <name>erlang:trace_delivered(Tracee) -> Ref</name> + <name name="trace_delivered" arity="1"/> <fsummary>Notification when trace has been delivered</fsummary> - <type> - <v>Tracee = pid() | all</v> - <v>Ref = reference()</v> - </type> <desc> <p>The delivery of trace messages is dislocated on the time-line compared to other events in the system. If you know that the - <c>Tracee</c> has passed some specific point in its execution, + <c><anno>Tracee</anno></c> has passed some specific point in its execution, and you want to know when at least all trace messages corresponding to events up to this point have reached the tracer - you can use <c>erlang:trace_delivered(Tracee)</c>. A - <c>{trace_delivered, Tracee, Ref}</c> message is sent to - the caller of <c>erlang:trace_delivered(Tracee)</c> when it + you can use <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>. A + <c>{trace_delivered, <anno>Tracee</anno>, <anno>Ref</anno>}</c> message is sent to + the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> when it is guaranteed that all trace messages have been delivered to - the tracer up to the point that the <c>Tracee</c> had reached + the tracer up to the point that the <c><anno>Tracee</anno></c> had reached at the time of the call to - <c>erlang:trace_delivered(Tracee)</c>.</p> + <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>.</p> <p>Note that the <c>trace_delivered</c> message does <em>not</em> imply that trace messages have been delivered; instead, it implies that all trace messages that <em>should</em> be delivered have - been delivered. It is not an error if <c>Tracee</c> isn't, and + been delivered. It is not an error if <c><anno>Tracee</anno></c> isn't, and hasn't been traced by someone, but if this is the case, <em>no</em> trace messages will have been delivered when the <c>trace_delivered</c> message arrives.</p> - <p>Note that <c>Tracee</c> has to refer to a process currently, + <p>Note that <c><anno>Tracee</anno></c> has to refer to a process currently, or previously existing on the same node as the caller of - <c>erlang:trace_delivered(Tracee)</c> resides on. - The special <c>Tracee</c> atom <c>all</c> denotes all processes + <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on. + The special <c><anno>Tracee</anno></c> atom <c>all</c> denotes all processes that currently are traced in the node.</p> - <p>An example: Process <c>A</c> is tracee, port <c>B</c> is + <p>An example: Process <c>A</c> is <c><anno>Tracee</anno></c>, port <c>B</c> is tracer, and process <c>C</c> is the port owner of <c>B</c>. <c>C</c> wants to close <c>B</c> when <c>A</c> exits. <c>C</c> can ensure that the trace isn't truncated by calling <c>erlang:trace_delivered(A)</c> when <c>A</c> exits and wait - for the <c>{trace_delivered, A, Ref}</c> message before closing + for the <c>{trace_delivered, A, <anno>Ref</anno>}</c> message before closing <c>B</c>.</p> - <p>Failure: <c>badarg</c> if <c>Tracee</c> does not refer to a + <p>Failure: <c>badarg</c> if <c><anno>Tracee</anno></c> does not refer to a process (dead or alive) on the same node as the caller of - <c>erlang:trace_delivered(Tracee)</c> resides on.</p> + <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on.</p> </desc> </func> <func> - <name>erlang:trace_info(PidOrFunc, Item) -> Res</name> + <name name="trace_info" arity="2"/> + <type name="trace_info_return"/> + <type name="trace_info_item_result"/> + <type name="trace_info_flag"/> + <type name="trace_match_spec"/> <fsummary>Trace information about a process or function</fsummary> - <type> - <v>PidOrFunc = pid() | new | {Module, Function, Arity} | on_load</v> - <v> Module = Function = atom()</v> - <v> Arity = arity()</v> - <v>Item, Res -- see below</v> - </type> <desc> <p>Returns trace information about a process or function.</p> - <p>To get information about a process, <c>PidOrFunc</c> should + <p>To get information about a process, <c><anno>PidOrFunc</anno></c> should be a pid or the atom <c>new</c>. The atom <c>new</c> means that the default trace state for processes to be created will - be returned. <c>Item</c> must have one of the following + be returned. <c><anno>Item</anno></c> must have one of the following values:</p> <taglist> <tag><c>flags</c></tag> @@ -6920,22 +6429,24 @@ ok <tag><c>all</c></tag> <item> - <p>Return a list containing the <c>{Item, Value}</c> tuples + <p>Return a list containing the <c>{<anno>Item</anno>, Value}</c> tuples for all other items, or return <c>false</c> if no tracing is active for this function.</p> </item> </taglist> - <p>The actual return value will be <c>{Item, Value}</c>, where + <p>The actual return value will be <c>{<anno>Item</anno>, Value}</c>, where <c>Value</c> is the requested information as described above. If a pid for a dead process was given, or the name of a non-existing function, <c>Value</c> will be <c>undefined</c>.</p> - <p>If <c>PidOrFunc</c> is the <c>on_load</c>, the information + <p>If <c><anno>PidOrFunc</anno></c> is the <c>on_load</c>, the information returned refers to the default value for code that will be loaded.</p> </desc> </func> <func> - <name>erlang:trace_pattern(MFA, MatchSpec) -> integer() >= 0</name> + <name name="trace_pattern" arity="2" clause_i="1"/> + <type name="trace_pattern_mfa"/> + <type name="trace_match_spec"/> <fsummary>Set trace patterns for global call tracing</fsummary> <desc> <p>The same as @@ -6944,11 +6455,11 @@ ok </desc> </func> <func> - <name>erlang:trace_pattern(MFA, MatchSpec, FlagList) -> integer() >= 0</name> + <name name="trace_pattern" arity="3"/> + <type name="trace_pattern_mfa"/> + <type name="trace_match_spec"/> + <type name="trace_pattern_flag"/> <fsummary>Set trace patterns for tracing of function calls</fsummary> - <type> - <v>MFA, MatchSpec, FlagList -- see below</v> - </type> <desc> <p>This BIF is used to enable or disable call tracing for exported functions. It must be combined with @@ -6973,7 +6484,7 @@ ok and an action to be performed. The default action is to send a trace message. If the pattern does not match or the guard fails, the action will not be executed.</p> - <p>The <c>MFA</c> argument should be a tuple like + <p>The <c><anno>MFA</anno></c> argument should be a tuple like <c>{Module, Function, Arity}</c> or the atom <c>on_load</c> (described below). It can be the module, function, and arity for an exported function (or a BIF in any module). @@ -6996,11 +6507,11 @@ ok </taglist> <p>Other combinations, such as <c>{Module,'_',Arity}</c>, are not allowed. Local functions will match wildcards only if - the <c>local</c> option is in the <c>FlagList</c>.</p> - <p>If the <c>MFA</c> argument is the atom <c>on_load</c>, + the <c>local</c> option is in the <c><anno>FlagList</anno></c>.</p> + <p>If the <c><anno>MFA</anno></c> argument is the atom <c>on_load</c>, the match specification and flag list will be used on all modules that are newly loaded.</p> - <p>The <c>MatchSpec</c> argument can take any of the following + <p>The <c><anno>MatchSpec</anno></c> argument can take any of the following forms:</p> <taglist> <tag><c>false</c></tag> @@ -7012,7 +6523,7 @@ ok <item> <p>Enable tracing for the matching function(s).</p> </item> - <tag><c>MatchSpecList</c></tag> + <tag><c><anno>MatchSpecList</anno></c></tag> <item> <p>A list of match specifications. An empty list is equivalent to <c>true</c>. See the ERTS User's Guide @@ -7020,18 +6531,18 @@ ok </item> <tag><c>restart</c></tag> <item> - <p>For the <c>FlagList</c> option <c>call_count</c> and <c>call_time</c>: + <p>For the <c><anno>FlagList</anno></c> option <c>call_count</c> and <c>call_time</c>: restart the existing counters. The behaviour is undefined - for other <c>FlagList</c> options.</p> + for other <c><anno>FlagList</anno></c> options.</p> </item> <tag><c>pause</c></tag> <item> - <p>For the <c>FlagList</c> option <c>call_count</c> and <c>call_time</c>: pause + <p>For the <c><anno>FlagList</anno></c> option <c>call_count</c> and <c>call_time</c>: pause the existing counters. The behaviour is undefined for other <c>FlagList</c> options.</p> </item> </taglist> - <p>The <c>FlagList</c> parameter is a list of options. + <p>The <c><anno>FlagList</anno></c> parameter is a list of options. The following options are allowed:</p> <taglist> <tag><c>global</c></tag> @@ -7050,13 +6561,13 @@ ok the process, a <c>return_to</c> message will also be sent when this function returns to its caller.</p> </item> - <tag><c>meta | {meta, Pid}</c></tag> + <tag><c>meta | {meta, <anno>Pid</anno>}</c></tag> <item> <p>Turn on or off meta tracing for all types of function calls. Trace messages will be sent to the tracer process - or port <c>Pid</c> whenever any of the specified + or port <c><anno>Pid</anno></c> whenever any of the specified functions are called, regardless of how they are called. - If no <c>Pid</c> is specified, <c>self()</c> is used as a + If no <c><anno>Pid</anno></c> is specified, <c>self()</c> is used as a default tracer process.</p> <p>Meta tracing traces all processes and does not care about the process trace flags set by <c>trace/3</c>, @@ -7068,32 +6579,32 @@ ok </item> <tag><c>call_count</c></tag> <item> - <p>Starts (<c>MatchSpec == true</c>) or stops - (<c>MatchSpec == false</c>) call count tracing for all + <p>Starts (<c><anno>MatchSpec</anno> == true</c>) or stops + (<c><anno>MatchSpec</anno> == false</c>) call count tracing for all types of function calls. For every function a counter is incremented when the function is called, in any process. No process trace flags need to be activated.</p> <p>If call count tracing is started while already running, the count is restarted from zero. Running counters can be - paused with <c>MatchSpec == pause</c>. Paused and running + paused with <c><anno>MatchSpec</anno> == pause</c>. Paused and running counters can be restarted from zero with - <c>MatchSpec == restart</c>.</p> + <c><anno>MatchSpec</anno> == restart</c>.</p> <p>The counter value can be read with <seealso marker="#trace_info/2">erlang:trace_info/2</seealso>.</p> </item> <tag><c>call_time</c></tag> <item> - <p>Starts (<c>MatchSpec == true</c>) or stops - (<c>MatchSpec == false</c>) call time tracing for all + <p>Starts (<c><anno>MatchSpec</anno> == true</c>) or stops + (<c><anno>MatchSpec</anno> == false</c>) call time tracing for all types of function calls. For every function a counter is incremented when the function is called. Time spent in the function is accumulated in two other counters, seconds and micro-seconds. The counters are stored for each call traced process.</p> <p>If call time tracing is started while already running, the count and time is restarted from zero. Running counters can be - paused with <c>MatchSpec == pause</c>. Paused and running + paused with <c><anno>MatchSpec</anno> == pause</c>. Paused and running counters can be restarted from zero with - <c>MatchSpec == restart</c>.</p> + <c><anno>MatchSpec</anno> == restart</c>.</p> <p>The counter value can be read with <seealso marker="#trace_info/2">erlang:trace_info/2</seealso>.</p> </item> @@ -7119,18 +6630,15 @@ ok <seealso marker="#trace_info/2">erlang:trace_info/2</seealso> BIF to retrieve the existing match specification.</p> <p>Returns the number of exported functions that matched - the <c>MFA</c> argument. This will be zero if none matched at + the <c><anno>MFA</anno></c> argument. This will be zero if none matched at all.</p> </desc> </func> <func> - <name>trunc(Number) -> integer()</name> + <name name="trunc" arity="1"/> <fsummary>Return an integer by the truncating a number</fsummary> - <type> - <v>Number = number()</v> - </type> <desc> - <p>Returns an integer by the truncating <c>Number</c>.</p> + <p>Returns an integer by the truncating <c><anno>Number</anno></c>.</p> <pre> > <input>trunc(5.5).</input> 5</pre> @@ -7138,13 +6646,10 @@ ok </desc> </func> <func> - <name>tuple_size(Tuple) -> integer() >= 0</name> + <name name="tuple_size" arity="1"/> <fsummary>Return the size of a tuple</fsummary> - <type> - <v>Tuple = tuple()</v> - </type> <desc> - <p>Returns an integer which is the number of elements in <c>Tuple</c>.</p> + <p>Returns an integer which is the number of elements in <c><anno>Tuple</anno></c>.</p> <pre> > <input>tuple_size({morni, mulle, bwange}).</input> 3</pre> @@ -7152,25 +6657,19 @@ ok </desc> </func> <func> - <name>tuple_to_list(Tuple) -> [term()]</name> + <name name="tuple_to_list" arity="1"/> <fsummary>Convert a tuple to a list</fsummary> - <type> - <v>Tuple = tuple()</v> - </type> <desc> - <p>Returns a list which corresponds to <c>Tuple</c>. - <c>Tuple</c> may contain any Erlang terms.</p> + <p>Returns a list which corresponds to <c><anno>Tuple</anno></c>. + <c><anno>Tuple</anno></c> may contain any Erlang terms.</p> <pre> > <input>tuple_to_list({share, {'Ericsson_B', 163}}).</input> [share,{'Ericsson_B',163}]</pre> </desc> </func> <func> - <name>erlang:universaltime() -> DateTime</name> + <name name="universaltime" arity="0"/> <fsummary>Current date and time according to Universal Time Coordinated (UTC)</fsummary> - <type> - <v>DateTime = <seealso marker="calendar#type-datetime">calendar:datetime()</seealso></v> - </type> <desc> <p>Returns the current date and time according to Universal Time Coordinated (UTC), also called GMT, in the form @@ -7184,46 +6683,39 @@ ok </desc> </func> <func> - <name>erlang:universaltime_to_localtime({Date1, Time1}) -> {Date2, Time2}</name> + <name name="universaltime_to_localtime" arity="1"/> <fsummary>Convert from Universal Time Coordinated (UTC) to local date and time</fsummary> - <type> - <v>Date1 = Date2 = <seealso marker="calendar#type-date">calendar:date()</seealso></v> - <v>Time1 = Time2 = <seealso marker="calendar#type-time">calendar:time()</seealso></v> - </type> <desc> <p>Converts Universal Time Coordinated (UTC) date and time to local date and time, if this is supported by the underlying OS. Otherwise, no conversion is done, and - <c>{Date1, Time1}</c> is returned.</p> + <c><anno>Universaltime</anno></c> is returned.</p> <pre> > <input>erlang:universaltime_to_localtime({{1996,11,6},{14,18,43}}).</input> {{1996,11,7},{15,18,43}}</pre> - <p>Failure: <c>badarg</c> if <c>Date1</c> or <c>Time1</c> do - not denote a valid date or time.</p> + <p>Failure: <c>badarg</c> if <c>Universaltime</c> does not denote + a valid date and time.</p> </desc> </func> <func> - <name>unlink(Id) -> true</name> + <name name="unlink" arity="1"/> <fsummary>Remove a link, if there is one, to another process or port</fsummary> - <type> - <v>Id = pid() | port()</v> - </type> <desc> <p>Removes the link, if there is one, between the calling - process and the process or port referred to by <c>Id</c>.</p> + process and the process or port referred to by <c><anno>Id</anno></c>.</p> <p>Returns <c>true</c> and does not fail, even if there is no - link to <c>Id</c>, or if <c>Id</c> does not exist.</p> - <p>Once <c>unlink(Id)</c> has returned it is guaranteed that + link to <c><anno>Id</anno></c>, or if <c><anno>Id</anno></c> does not exist.</p> + <p>Once <c>unlink(<anno>Id</anno>)</c> has returned it is guaranteed that the link between the caller and the entity referred to by - <c>Id</c> has no effect on the caller in the future (unless + <c><anno>Id</anno></c> has no effect on the caller in the future (unless the link is setup again). If caller is trapping exits, an - <c>{'EXIT', Id, _}</c> message due to the link might have + <c>{'EXIT', <anno>Id</anno>, _}</c> message due to the link might have been placed in the caller's message queue prior to the call, - though. Note, the <c>{'EXIT', Id, _}</c> message can be the - result of the link, but can also be the result of <c>Id</c> + though. Note, the <c>{'EXIT', <anno>Id</anno>, _}</c> message can be the + result of the link, but can also be the result of <c><anno>Id</anno></c> calling <c>exit/2</c>. Therefore, it <em>may</em> be appropriate to cleanup the message queue when trapping exits - after the call to <c>unlink(Id)</c>, as follow:</p> + after the call to <c>unlink(<anno>Id</anno>)</c>, as follow:</p> <code type="none"> unlink(Id), @@ -7246,13 +6738,10 @@ ok </desc> </func> <func> - <name>unregister(RegName) -> true</name> + <name name="unregister" arity="1"/> <fsummary>Remove the registered name for a process (or port)</fsummary> - <type> - <v>RegName = atom()</v> - </type> <desc> - <p>Removes the registered name <c>RegName</c>, associated with a + <p>Removes the registered name <c><anno>RegName</anno></c>, associated with a pid or a port identifier.</p> <pre> > <input>unregister(db).</input> @@ -7263,7 +6752,7 @@ true</pre> </desc> </func> <func> - <name>whereis(RegName) -> pid() | port() | undefined</name> + <name name="whereis" arity="1"/> <fsummary>Get the pid (or port) with a given registered name</fsummary> <desc> <p>Returns the pid or port identifier with the registered name diff --git a/erts/doc/src/ref_man.xml b/erts/doc/src/ref_man.xml index 2042cf28bd..5c9938075c 100644 --- a/erts/doc/src/ref_man.xml +++ b/erts/doc/src/ref_man.xml @@ -49,7 +49,6 @@ <xi:include href="escript.xml"/> <xi:include href="erlsrv.xml"/> <xi:include href="start_erl.xml"/> - <xi:include href="erl_set_memory_block.xml"/> <xi:include href="run_erl.xml"/> <xi:include href="start.xml"/> <xi:include href="erl_driver.xml"/> diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 985ef72517..7e966c81bb 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -332,15 +332,11 @@ LIBS += $(THR_LIBS) ifneq ($(findstring erts_internal_r, $(THR_LIBS)),erts_internal_r) -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -ERTS_INTERNAL_LIB=erts_internal -else ifneq ($(strip $(THR_LIB_NAME)),) ERTS_INTERNAL_LIB=erts_internal_r else ERTS_INTERNAL_LIB=erts_internal endif -endif LIBS += -l$(ERTS_INTERNAL_LIB)$(TYPEMARKER) @@ -463,8 +459,6 @@ _create_dirs := $(shell mkdir -p $(CREATE_DIRS)) GENERATE = HIPE_ASM = -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -else ifdef HIPE_ENABLED HIPE_ASM += $(TTF_DIR)/hipe_x86_asm.h \ $(TTF_DIR)/hipe_amd64_asm.h \ @@ -476,7 +470,6 @@ GENERATE += $(HIPE_ASM) \ $(TTF_DIR)/hipe_literals.h \ $(BINDIR)/hipe_mkliterals$(TF_MARKER) endif -endif ifdef DTRACE_ENABLED # global.h causes problems by including dtrace-wrapper.h which includes @@ -616,11 +609,6 @@ ifdef PERFCTR_PATH INCLUDES += -I$(PERFCTR_PATH)/usr.lib -I$(PERFCTR_PATH)/linux/include endif -# Need to include etc dir on VxWorks -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -INCLUDES += -I$(ERL_TOP)/erts/etc/vxworks -endif - ifeq ($(TARGET),win32) $(OBJDIR)/dll_sys.o: sys/$(ERLANG_OSTYPE)/sys.c $(CC) $(CFLAGS) -DERL_RUN_SHARED_LIB=1 $(INCLUDES) -c $< -o $@ @@ -663,12 +651,6 @@ $(OBJDIR)/%.o: drivers/common/%.c $(OBJDIR)/%.o: drivers/$(ERLANG_OSTYPE)/%.c $(CC) $(CFLAGS) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) -I../etc/$(ERLANG_OSTYPE) -c $< -o $@ -# VxWorks uses unix drivers too... -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -$(OBJDIR)/%.o: drivers/unix/%.c - $(CC) $(CFLAGS) $(INCLUDES) -Idrivers/common -c $< -o $@ -endif - # ---------------------------------------------------------------------- # Specials # @@ -709,7 +691,9 @@ EMU_OBJS = \ $(OBJDIR)/beam_emu.o $(OBJDIR)/beam_opcodes.o \ $(OBJDIR)/beam_load.o $(OBJDIR)/beam_bif_load.o \ $(OBJDIR)/beam_debug.o $(OBJDIR)/beam_bp.o \ - $(OBJDIR)/beam_catches.o + $(OBJDIR)/beam_catches.o \ + $(OBJDIR)/code_ix.o \ + $(OBJDIR)/beam_ranges.o RUN_OBJS = \ $(OBJDIR)/erl_pbifs.o $(OBJDIR)/benchmark.o \ @@ -779,12 +763,8 @@ OS_OBJS = \ $(OBJDIR)/gzio.o \ $(OBJDIR)/elib_memmove.o -ifeq ($(findstring vxworks,$(TARGET)),vxworks) - OS_OBJS += $(OBJDIR)/int64.o -else OS_OBJS += $(OBJDIR)/sys_float.o \ $(OBJDIR)/sys_time.o -endif DRV_OBJS = \ $(OBJDIR)/efile_drv.o \ $(OBJDIR)/inet_drv.o \ @@ -792,9 +772,7 @@ DRV_OBJS = \ $(OBJDIR)/ram_file_drv.o endif -ifneq ($(findstring vxworks,$(TARGET)),vxworks) DRV_OBJS += $(OBJDIR)/ttsl_drv.o -endif ifeq ($(ERTS_ENABLE_KERNEL_POLL),yes) OS_OBJS += $(OBJDIR)/erl_poll.kp.o \ @@ -932,31 +910,6 @@ $(OBJDIR)/hipe_arm.o: hipe/hipe_arm.c # end of HiPE section ######################################## -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -######################################## -# Extract what we need from libgcc.a -######################################## -GCCLIBFLAGS=@GCCLIBFLAGS@ -STRIP=@STRIP@ -SYMPREFIX=@SYMPREFIX@ - -NEEDFUNCTIONS=__divdi3 __moddi3 __udivdi3 -KEEPSYMS=$(NEEDFUNCTIONS:%=-K $(SYMPREFIX)%) - -$(OBJDIR)/int64.o: $(TARGET)/int64.c - $(CC) -o $(OBJDIR)/int64tmp.o -c $(TARGET)/int64.c - $(LD) -o $(OBJDIR)/int64.o $(OBJDIR)/int64tmp.o $(LDFLAGS) $(GCCLIBFLAGS) - $(STRIP) $(KEEPSYMS) $(OBJDIR)/int64.o - -$(TARGET)/int64.c: - echo 'void dummy(void); void dummy(void) {' > $(TARGET)/int64.c - for x in $(NEEDFUNCTIONS); do echo 'extern void '$$x'();' \ - >> $(TARGET)/int64.c; done - for x in $(NEEDFUNCTIONS); do echo $$x'();' >> $(TARGET)/int64.c; done - echo '}' >> $(TARGET)/int64.c - -endif - # ---------------------------------------------------------------------- # The emulator itself diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index ada2d152b7..94f8edf165 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -37,25 +37,83 @@ static void set_default_trace_pattern(Eterm module); static Eterm check_process_code(Process* rp, Module* modp); -static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp); -static void delete_export_references(Eterm module); -static int purge_module(int module); +static void delete_code(Module* modp); static void decrement_refc(BeamInstr* code); static int is_native(BeamInstr* code); static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); static int any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); -static void remove_from_address_table(BeamInstr* code); -Eterm -load_module_2(BIF_ALIST_2) + + +BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) { - Eterm reason; - Eterm* hp; - int sz; - byte* code; + Module* modp; Eterm res; + ErtsCodeIndex code_ix; + + if (is_not_atom(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); + } + code_ix = erts_active_code_ix(); + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) == NULL) { + return am_undefined; + } + erts_rlock_old_code(code_ix); + res = ((modp->curr.code && is_native(modp->curr.code)) || + (modp->old.code != 0 && is_native(modp->old.code))) ? + am_true : am_false; + erts_runlock_old_code(code_ix); + return res; +} + +BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) +{ + Module* modp; + Eterm res; + + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD3(bif_export[BIF_code_make_stub_module_3], + BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + } + + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + + modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); + + if (modp && modp->curr.num_breakpoints > 0) { + ASSERT(modp->curr.code != NULL); + erts_clear_module_break(modp); + ASSERT(modp->curr.num_breakpoints == 0); + } + + erts_start_staging_code_ix(); + + res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + + if (res == BIF_ARG_1) { + erts_end_staging_code_ix(); + erts_commit_staging_code_ix(); + } + else { + erts_abort_staging_code_ix(); + } + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_release_code_write_permission(); + return res; +} + +BIF_RETTYPE +prepare_loading_2(BIF_ALIST_2) +{ byte* temp_alloc = NULL; - struct LoaderState* stp; + byte* code; + Uint sz; + Binary* magic; + Eterm reason; + Eterm* hp; + Eterm res; if (is_not_atom(BIF_ARG_1)) { error: @@ -65,108 +123,277 @@ load_module_2(BIF_ALIST_2) if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) { goto error; } - hp = HAlloc(BIF_P, 3); - /* - * Read the BEAM file and prepare the module for loading. - */ - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); sz = binary_size(BIF_ARG_2); - reason = erts_prepare_loading(stp, BIF_P, BIF_P->group_leader, + reason = erts_prepare_loading(magic, BIF_P, BIF_P->group_leader, &BIF_ARG_1, code, sz); erts_free_aligned_binary_bytes(temp_alloc); if (reason != NIL) { + hp = HAlloc(BIF_P, 3); res = TUPLE2(hp, am_error, reason); BIF_RET(res); } + hp = HAlloc(BIF_P, PROC_BIN_SIZE); + res = erts_mk_magic_binary_term(&hp, &MSO(BIF_P), magic); + erts_refc_dec(&magic->refc, 1); + BIF_RET(res); +} - /* - * Stop all other processes and finish the loading of the module. - */ - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); +struct m { + Binary* code; + Eterm module; + Module* modp; + Uint exception; +}; - reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); - if (reason != NIL) { - res = TUPLE2(hp, am_error, reason); - } else { - set_default_trace_pattern(BIF_ARG_1); - res = TUPLE2(hp, am_module, BIF_ARG_1); - } +static Eterm staging_epilogue(Process* c_p, int, Eterm res, int, struct m*, int); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); +static Eterm +exception_list(Process* p, Eterm tag, struct m* mp, Sint exceptions) +{ + Eterm* hp = HAlloc(p, 3 + 2*exceptions); + Eterm res = NIL; + + mp += exceptions - 1; + while (exceptions > 0) { + if (mp->exception) { + res = CONS(hp, mp->module, res); + hp += 2; + exceptions--; + } + mp--; + } + return TUPLE2(hp, tag, res); } -BIF_RETTYPE purge_module_1(BIF_ALIST_1) + +BIF_RETTYPE +finish_loading_1(BIF_ALIST_1) { - int purge_res; + int i; + int n; + struct m* p = NULL; + Uint exceptions; + Eterm res; + int is_blocking = 0; + int do_commit = 0; - if (is_not_atom(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_finish_loading_1], BIF_P, BIF_ARG_1); } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + /* + * Validate the argument before we start loading; it must be a + * proper list where each element is a magic binary containing + * prepared (not previously loaded) code. + * + * First count the number of elements and allocate an array + * to keep the elements in. + */ - erts_export_consolidate(); - purge_res = purge_module(atom_val(BIF_ARG_1)); + n = list_length(BIF_ARG_1); + if (n == -1) { + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; + } + p = erts_alloc(ERTS_ALC_T_LOADER_TMP, n*sizeof(struct m)); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + /* + * We now know that the argument is a proper list. Validate + * and collect the binaries into the array. + */ - if (purge_res < 0) { - BIF_ERROR(BIF_P, BADARG); + for (i = 0; i < n; i++) { + Eterm* cons = list_val(BIF_ARG_1); + Eterm term = CAR(cons); + ProcBin* pb; + + if (!ERTS_TERM_IS_MAGIC_BINARY(term)) { + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; + } + pb = (ProcBin*) binary_val(term); + p[i].code = pb->val; + p[i].module = erts_module_for_prepared_code(p[i].code); + if (p[i].module == NIL) { + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; + } + BIF_ARG_1 = CDR(cons); } - BIF_RET(am_true); -} -BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) -{ - Module* modp; + /* + * Since we cannot handle atomic loading of a group of modules + * if one or more of them uses on_load, we will only allow one + * element in the list. This limitation is intended to be + * lifted in the future. + */ - if (is_not_atom(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); + if (n > 1) { + ERTS_BIF_PREP_ERROR(res, BIF_P, SYSTEM_LIMIT); + goto done; } - if ((modp = erts_get_module(BIF_ARG_1)) == NULL) { - return am_undefined; + + /* + * All types are correct. There cannot be a BADARG from now on. + * Before we can start loading, we must check whether any of + * the modules already has old code. To avoid a race, we must + * not allow other process to initiate a code loading operation + * from now on. + */ + + res = am_ok; + erts_start_staging_code_ix(); + + for (i = 0; i < n; i++) { + p[i].modp = erts_put_module(p[i].module); + } + for (i = 0; i < n; i++) { + if (p[i].modp->curr.num_breakpoints > 0 || + p[i].modp->curr.num_traced_exports > 0 || + erts_is_default_trace_enabled()) { + /* tracing involved, fallback with thread blocking */ + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + break; + } } - return ((modp->code && is_native(modp->code)) || - (modp->old_code != 0 && is_native(modp->old_code))) ? - am_true : am_false; -} -BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) -{ - Eterm res; + if (is_blocking) { + for (i = 0; i < n; i++) { + if (p[i].modp->curr.num_breakpoints) { + erts_clear_module_break(p[i].modp); + ASSERT(p[i].modp->curr.num_breakpoints == 0); + } + } + } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + exceptions = 0; + for (i = 0; i < n; i++) { + p[i].exception = 0; + if (p[i].modp->curr.code && p[i].modp->old.code) { + p[i].exception = 1; + exceptions++; + } + } - erts_export_consolidate(); - res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + if (exceptions) { + res = exception_list(BIF_P, am_not_purged, p, exceptions); + } else { + /* + * Now we can load all code. This can't fail. + */ - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - return res; + exceptions = 0; + for (i = 0; i < n; i++) { + Eterm mod; + Eterm retval; + + erts_refc_inc(&p[i].code->refc, 1); + retval = erts_finish_loading(p[i].code, BIF_P, 0, &mod); + ASSERT(retval == NIL || retval == am_on_load); + if (retval == am_on_load) { + p[i].exception = 1; + exceptions++; + } + } + + /* + * Check whether any module has an on_load_handler. + */ + + if (exceptions) { + res = exception_list(BIF_P, am_on_load, p, exceptions); + } + do_commit = 1; + } + +done: + return staging_epilogue(BIF_P, do_commit, res, is_blocking, p, n); +} + +static Eterm +staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking, + struct m* loaded, int nloaded) +{ +#ifdef ERTS_SMP + if (is_blocking || !commit) +#endif + { + if (commit) { + erts_end_staging_code_ix(); + erts_commit_staging_code_ix(); + if (loaded) { + int i; + for (i=0; i < nloaded; i++) { + set_default_trace_pattern(loaded[i].module); + } + } + } + else { + erts_abort_staging_code_ix(); + } + if (loaded) { + erts_free(ERTS_ALC_T_LOADER_TMP, loaded); + } + if (is_blocking) { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); + } + erts_release_code_write_permission(); + return res; + } +#ifdef ERTS_SMP + else { + ErtsThrPrgrVal later; + ASSERT(is_value(res)); + + if (loaded) { + erts_free(ERTS_ALC_T_LOADER_TMP, loaded); + } + erts_end_staging_code_ix(); + /* + * Now we must wait for all schedulers to do a memory barrier before + * we can activate and let them access the new staged code. This allows + * schedulers to read active code_ix in a safe way while executing + * without any memory barriers at all. + */ + + later = erts_thr_progress_later(c_p->scheduler_data); + erts_thr_progress_wakeup(c_p->scheduler_data, later); + erts_notify_code_ix_activation(c_p, later); + erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); + /* + * handle_code_ix_activation() will do the rest "later" + * and resume this process to return 'res'. + */ + ERTS_BIF_YIELD_RETURN(c_p, res); + } +#endif } BIF_RETTYPE check_old_code_1(BIF_ALIST_1) { + ErtsCodeIndex code_ix; Module* modp; + Eterm res = am_false; if (is_not_atom(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } - modp = erts_get_module(BIF_ARG_1); - if (modp == NULL) { /* Doesn't exist. */ - BIF_RET(am_false); - } else if (modp->old_code == NULL) { /* No old code. */ - BIF_RET(am_false); + code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); + if (modp != NULL) { + erts_rlock_old_code(code_ix); + if (modp->old.code != NULL) { + res = am_true; + } + erts_runlock_old_code(code_ix); } - BIF_RET(am_true); + BIF_RET(res); } Eterm @@ -180,14 +407,20 @@ check_process_code_2(BIF_ALIST_2) } if (is_internal_pid(BIF_ARG_1)) { Eterm res; + ErtsCodeIndex code_ix; if (internal_pid_index(BIF_ARG_1) >= erts_max_processes) goto error; - modp = erts_get_module(BIF_ARG_2); + code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_2, code_ix); if (modp == NULL) { /* Doesn't exist. */ return am_false; - } else if (modp->old_code == NULL) { /* No old code. */ + } + erts_rlock_old_code(code_ix); + if (modp->old.code == NULL) { /* No old code. */ + erts_runlock_old_code(code_ix); return am_false; } + erts_runlock_old_code(code_ix); #ifdef ERTS_SMP rp = erts_pid2proc_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, @@ -202,7 +435,14 @@ check_process_code_2(BIF_ALIST_2) ERTS_BIF_YIELD2(bif_export[BIF_check_process_code_2], BIF_P, BIF_ARG_1, BIF_ARG_2); } - res = check_process_code(rp, modp); + erts_rlock_old_code(code_ix); + if (modp->old.code != NULL) { /* must check again */ + res = check_process_code(rp, modp); + } + else { + res = am_false; + } + erts_runlock_old_code(code_ix); #ifdef ERTS_SMP if (BIF_P != rp) { erts_resume(rp, ERTS_PROC_LOCK_MAIN); @@ -223,56 +463,71 @@ check_process_code_2(BIF_ALIST_2) BIF_RETTYPE delete_module_1(BIF_ALIST_1) { - int res; + ErtsCodeIndex code_ix; + Module* modp; + int is_blocking = 0; + int success = 0; + Eterm res = NIL; - if (is_not_atom(BIF_ARG_1)) - goto badarg; + if (is_not_atom(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); + } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_delete_module_1], BIF_P, BIF_ARG_1); + } { - Module *modp = erts_get_module(BIF_ARG_1); + erts_start_staging_code_ix(); + code_ix = erts_staging_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp) { res = am_undefined; } - else if (modp->old_code != 0) { + else if (modp->old.code != 0) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, "Module %T must be purged before loading\n", BIF_ARG_1); erts_send_error_to_logger(BIF_P->group_leader, dsbufp); - res = am_badarg; + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); } else { - delete_export_references(BIF_ARG_1); - delete_code(BIF_P, 0, modp); + if (modp->curr.num_breakpoints > 0 || + modp->curr.num_traced_exports > 0) { + /* we have tracing, retry single threaded */ + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + if (modp->curr.num_breakpoints) { + erts_clear_module_break(modp); + ASSERT(modp->curr.num_breakpoints == 0); + } + } + delete_code(modp); res = am_true; + success = 1; } } - - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - - if (res == am_badarg) { - badarg: - BIF_ERROR(BIF_P, BADARG); - } - BIF_RET(res); + return staging_epilogue(BIF_P, success, res, is_blocking, NULL, 0); } BIF_RETTYPE module_loaded_1(BIF_ALIST_1) { Module* modp; + ErtsCodeIndex code_ix; + Eterm res = am_false; if (is_not_atom(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } - if ((modp = erts_get_module(BIF_ARG_1)) == NULL || - modp->code == NULL || - modp->code[MI_ON_LOAD_FUNCTION_PTR] != 0) { - BIF_RET(am_false); + code_ix = erts_active_code_ix(); + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) != NULL) { + if (modp->curr.code != NULL + && modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] == 0) { + res = am_true; + } } - BIF_RET(am_true); + BIF_RET(res); } BIF_RETTYPE pre_loaded_0(BIF_ALIST_0) @@ -282,27 +537,28 @@ BIF_RETTYPE pre_loaded_0(BIF_ALIST_0) BIF_RETTYPE loaded_0(BIF_ALIST_0) { + ErtsCodeIndex code_ix = erts_active_code_ix(); + Module* modp; Eterm previous = NIL; Eterm* hp; int i; int j = 0; - - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { + + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp = module_code(i, code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { j++; } } if (j > 0) { hp = HAlloc(BIF_P, j*2); - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { - previous = CONS(hp, make_atom(module_code(i)->module), - previous); + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp=module_code(i,code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + previous = CONS(hp, make_atom(modp->module), previous); hp += 2; } } @@ -312,54 +568,65 @@ BIF_RETTYPE loaded_0(BIF_ALIST_0) BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) { - Module* modp = erts_get_module(BIF_ARG_1); - Eterm on_load; + Module* modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); - if (!modp || modp->code == 0) { - error: - BIF_ERROR(BIF_P, BADARG); + if (modp && modp->curr.code) { + BIF_TRAP_CODE_PTR_0(BIF_P, modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]); } - if ((on_load = modp->code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { - goto error; + else { + BIF_ERROR(BIF_P, BADARG); } - BIF_TRAP_CODE_PTR_0(BIF_P, on_load); } BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) { - Module* modp = erts_get_module(BIF_ARG_1); + ErtsCodeIndex code_ix; + Module* modp; Eterm on_load; - if (!modp || modp->code == 0) { + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD2(bif_export[BIF_finish_after_on_load_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } + + /* ToDo: Use code_ix staging instead of thread blocking */ + + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + + code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); + + if (!modp || modp->curr.code == 0) { error: + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_release_code_write_permission(); BIF_ERROR(BIF_P, BADARG); } - if ((on_load = modp->code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { + if ((on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { goto error; } if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) { goto error; } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - if (BIF_ARG_2 == am_true) { int i; /* * The on_load function succeded. Fix up export entries. */ - for (i = 0; i < export_list_size(); i++) { - Export *ep = export_list(i); + for (i = 0; i < export_list_size(code_ix); i++) { + Export *ep = export_list(i,code_ix); if (ep != NULL && ep->code[0] == BIF_ARG_1 && ep->code[4] != 0) { - ep->address = (void *) ep->code[4]; + ep->addressv[code_ix] = (void *) ep->code[4]; ep->code[4] = 0; } } - modp->code[MI_ON_LOAD_FUNCTION_PTR] = 0; + modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] = 0; set_default_trace_pattern(BIF_ARG_1); } else if (BIF_ARG_2 == am_false) { BeamInstr* code; @@ -370,19 +637,21 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) * This is an combination of delete and purge. We purge * the current code; the old code is not touched. */ - erts_total_code_size -= modp->code_length; - code = modp->code; - end = (BeamInstr *)((char *)code + modp->code_length); + erts_total_code_size -= modp->curr.code_length; + code = modp->curr.code; + end = (BeamInstr *)((char *)code + modp->curr.code_length); erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->catches, code, modp->code_length); + beam_catches_delmod(modp->curr.catches, code, modp->curr.code_length, + erts_active_code_ix()); erts_free(ERTS_ALC_T_CODE, (void *) code); - modp->code = NULL; - modp->code_length = 0; - modp->catches = BEAM_CATCHES_NIL; - remove_from_address_table(code); + modp->curr.code = NULL; + modp->curr.code_length = 0; + modp->curr.catches = BEAM_CATCHES_NIL; + erts_remove_from_ranges(code); } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_release_code_write_permission(); BIF_RET(am_true); } @@ -403,11 +672,11 @@ set_default_trace_pattern(Eterm module) if (trace_pattern_is_on) { Eterm mfa[1]; mfa[0] = module; - (void) erts_set_trace_pattern(mfa, 1, + (void) erts_set_trace_pattern(0, mfa, 1, match_spec, meta_match_spec, 1, trace_pattern_flags, - meta_tracer_pid); + meta_tracer_pid, 1); } } @@ -427,10 +696,10 @@ check_process_code(Process* rp, Module* modp) /* * Pick up limits for the module. */ - start = modp->old_code; - end = (BeamInstr *)((char *)start + modp->old_code_length); + start = modp->old.code; + end = (BeamInstr *)((char *)start + modp->old.code_length); mod_start = (char *) start; - mod_size = modp->old_code_length; + mod_size = modp->old.code_length; /* * Check if current instruction or continuation pointer points into module. @@ -562,10 +831,10 @@ check_process_code(Process* rp, Module* modp) done_gc = 1; FLAGS(rp) |= F_NEED_FULLSWEEP; (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity); - literals = (Eterm *) modp->old_code[MI_LITERALS_START]; - lit_size = (Eterm *) modp->old_code[MI_LITERALS_END] - literals; + literals = (Eterm *) modp->old.code[MI_LITERALS_START]; + lit_size = (Eterm *) modp->old.code[MI_LITERALS_END] - literals; oh = (struct erl_off_heap_header *) - modp->old_code[MI_LITERALS_OFF_HEAP]; + modp->old.code[MI_LITERALS_OFF_HEAP]; erts_garbage_collect_literals(rp, literals, lit_size, oh); } } @@ -624,53 +893,82 @@ any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) #undef in_area - -static int -purge_module(int module) +BIF_RETTYPE purge_module_1(BIF_ALIST_1) { + ErtsCodeIndex code_ix; BeamInstr* code; BeamInstr* end; Module* modp; + int is_blocking = 0; + Eterm ret; - /* - * Correct module? - */ - - if ((modp = erts_get_module(make_atom(module))) == NULL) { - return -2; + if (is_not_atom(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); } - /* - * Any code to purge? - */ - if (modp->old_code == 0) { - return -1; + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_purge_module_1], BIF_P, BIF_ARG_1); } + code_ix = erts_active_code_ix(); + /* - * Unload any NIF library + * Correct module? */ - if (modp->old_nif != NULL) { - erts_unload_nif(modp->old_nif); - modp->old_nif = NULL; + + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) == NULL) { + ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG); } + else { + erts_rwlock_old_code(code_ix); - /* - * Remove the old code. - */ - ASSERT(erts_total_code_size >= modp->old_code_length); - erts_total_code_size -= modp->old_code_length; - code = modp->old_code; - end = (BeamInstr *)((char *)code + modp->old_code_length); - erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->old_catches, code, modp->old_code_length); - decrement_refc(code); - erts_free(ERTS_ALC_T_CODE, (void *) code); - modp->old_code = NULL; - modp->old_code_length = 0; - modp->old_catches = BEAM_CATCHES_NIL; - remove_from_address_table(code); - return 0; + /* + * Any code to purge? + */ + if (modp->old.code == 0) { + ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG); + } + else { + /* + * Unload any NIF library + */ + if (modp->old.nif != NULL) { + /* ToDo: Do unload nif without blocking */ + erts_rwunlock_old_code(code_ix); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + erts_rwlock_old_code(code_ix); + erts_unload_nif(modp->old.nif); + modp->old.nif = NULL; + } + + /* + * Remove the old code. + */ + ASSERT(erts_total_code_size >= modp->old.code_length); + erts_total_code_size -= modp->old.code_length; + code = modp->old.code; + end = (BeamInstr *)((char *)code + modp->old.code_length); + erts_cleanup_funs_on_purge(code, end); + beam_catches_delmod(modp->old.catches, code, modp->old.code_length, + code_ix); + decrement_refc(code); + erts_free(ERTS_ALC_T_CODE, (void *) code); + modp->old.code = NULL; + modp->old.code_length = 0; + modp->old.catches = BEAM_CATCHES_NIL; + erts_remove_from_ranges(code); + ERTS_BIF_PREP_RET(ret, am_true); + } + erts_rwunlock_old_code(code_ix); + } + if (is_blocking) { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + } + erts_release_code_write_permission(); + return ret; } static void @@ -690,92 +988,48 @@ decrement_refc(BeamInstr* code) } } -static void -remove_from_address_table(BeamInstr* code) -{ - int i; - - for (i = 0; i < num_loaded_modules; i++) { - if (modules[i].start == code) { - num_loaded_modules--; - while (i < num_loaded_modules) { - modules[i] = modules[i+1]; - i++; - } - mid_module = &modules[num_loaded_modules/2]; - return; - } - } - ASSERT(0); /* Not found? */ -} - - /* - * Move code from current to old. + * Move code from current to old and null all export entries for the module */ -static void -delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) -{ -#ifdef ERTS_ENABLE_LOCK_CHECK -#ifdef ERTS_SMP - if (c_p && c_p_locks) - erts_proc_lc_chk_only_proc_main(c_p); - else -#endif - erts_lc_check_exact(NULL, 0); -#endif - - /* - * Clear breakpoints if any - */ - if (modp->code != NULL && modp->code[MI_NUM_BREAKPOINTS] > 0) { - if (c_p && c_p_locks) - erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - erts_clear_module_break(modp); - modp->code[MI_NUM_BREAKPOINTS] = 0; - erts_smp_thr_progress_unblock(); - if (c_p && c_p_locks) - erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); - } - modp->old_code = modp->code; - modp->old_code_length = modp->code_length; - modp->old_catches = modp->catches; - modp->old_nif = modp->nif; - modp->code = NULL; - modp->code_length = 0; - modp->catches = BEAM_CATCHES_NIL; - modp->nif = NULL; -} - - -/* null all references on the export table for the module called with the - atom index below */ - static void -delete_export_references(Eterm module) +delete_code(Module* modp) { + ErtsCodeIndex code_ix = erts_staging_code_ix(); + Eterm module = make_atom(modp->module); int i; - ASSERT(is_atom(module)); - - for (i = 0; i < export_list_size(); i++) { - Export *ep = export_list(i); + for (i = 0; i < export_list_size(code_ix); i++) { + Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->code[0] == module)) { - if (ep->address == ep->code+3 && - (ep->code[3] == (BeamInstr) em_apply_bif)) { - continue; + if (ep->addressv[code_ix] == ep->code+3) { + if (ep->code[3] == (BeamInstr) em_apply_bif) { + continue; + } + else if (ep->code[3] == + (BeamInstr) BeamOp(op_i_generic_breakpoint)) { + ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); + ASSERT(modp->curr.num_traced_exports > 0); + erts_clear_export_break(modp, ep->code+3); + } + else ASSERT(ep->code[3] == (BeamInstr) em_call_error_handler + || !erts_initialized); } - ep->address = ep->code+3; + ep->addressv[code_ix] = ep->code+3; ep->code[3] = (BeamInstr) em_call_error_handler; ep->code[4] = 0; - MatchSetUnref(ep->match_prog_set); - ep->match_prog_set = NULL; } } + + ASSERT(modp->curr.num_breakpoints == 0); + ASSERT(modp->curr.num_traced_exports == 0); + modp->old = modp->curr; + modp->curr.code = NULL; + modp->curr.code_length = 0; + modp->curr.catches = BEAM_CATCHES_NIL; + modp->curr.nif = NULL; } - + Eterm beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) @@ -787,11 +1041,10 @@ beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) * if not, delete old code; error if old code already exists. */ - if (modp->code != NULL && modp->old_code != NULL) { + if (modp->curr.code != NULL && modp->old.code != NULL) { return am_not_purged; - } else if (modp->old_code == NULL) { /* Make the current version old. */ - delete_code(c_p, c_p_locks, modp); - delete_export_references(module); + } else if (modp->old.code == NULL) { /* Make the current version old. */ + delete_code(modp); } return NIL; } diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index d772bea02f..50d18b0347 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -44,67 +44,34 @@ #define ReAlloc(P, SIZ) erts_realloc(ERTS_ALC_T_BPD, (P), (SZ)) #define Free(P) erts_free(ERTS_ALC_T_BPD, (P)) -/* -** Doubly linked ring macros -*/ - -#define BpInit(a,i) \ -do { \ - (a)->orig_instr = (i); \ - (a)->next = (a); \ - (a)->prev = (a); \ -} while (0) - -#define BpSpliceNext(a,b) \ -do { \ - register BpData *c = (a), *d = (b), *e; \ - e = c->next->prev; \ - c->next->prev = d->next->prev; \ - d->next->prev = e; \ - e = c->next; \ - c->next = d->next; \ - d->next = e; \ -} while (0) - -#define BpSplicePrev(a,b) \ -do { \ - register BpData *c = (a), *d = (b), *e; \ - e = c->prev->next; \ - c->prev->next = d->prev->next; \ - d->prev->next = e; \ - e = c->prev; \ - c->prev = d->prev; \ - d->prev = e; \ -} while (0) - -#ifdef DEBUG -# define BpSingleton(a) ((a)->next == (a) && (a)->prev == (a)) +#if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP) +# define ERTS_SMP_REQ_PROC_MAIN_LOCK(P) \ + if ((P)) erts_proc_lc_require_lock((P), ERTS_PROC_LOCK_MAIN) +# define ERTS_SMP_UNREQ_PROC_MAIN_LOCK(P) \ + if ((P)) erts_proc_lc_unrequire_lock((P), ERTS_PROC_LOCK_MAIN) #else -# define BpSingleton(a) ((a)->next == (a)) +# define ERTS_SMP_REQ_PROC_MAIN_LOCK(P) +# define ERTS_SMP_UNREQ_PROC_MAIN_LOCK(P) #endif -#define BpInitAndSpliceNext(a,i,b) \ -do { \ - (a)->orig_instr = (i); \ - (a)->prev = (b); \ - (b)->next->prev = (a); \ - (a)->next = (b)->next; \ - (b)->next = (a); \ -} while (0) +#define ERTS_BPF_LOCAL_TRACE 0x01 +#define ERTS_BPF_META_TRACE 0x02 +#define ERTS_BPF_COUNT 0x04 +#define ERTS_BPF_COUNT_ACTIVE 0x08 +#define ERTS_BPF_DEBUG 0x10 +#define ERTS_BPF_TIME_TRACE 0x20 +#define ERTS_BPF_TIME_TRACE_ACTIVE 0x40 +#define ERTS_BPF_GLOBAL_TRACE 0x80 -#define BpInitAndSplicePrev(a,i,b) \ -do { \ - (a)->orig_instr = (i); \ - (a)->next = (b); \ - (b)->prev->next = (a); \ - (a)->prev = (b)->prev; \ - (b)->prev = (a); \ -} while (0) +#define ERTS_BPF_ALL 0xFF +extern Eterm beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */ +extern Eterm beam_return_trace[1]; /* OpCode(i_return_trace) */ +extern Eterm beam_exception_trace[1]; /* OpCode(i_exception_trace) */ +extern Eterm beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */ -#define BREAK_IS_BIF (1) -#define BREAK_IS_ERL (0) - +erts_smp_atomic32_t erts_active_bp_index; +erts_smp_atomic32_t erts_staging_bp_index; /* ************************************************************************* ** Local prototypes @@ -113,26 +80,30 @@ do { \ /* ** Helpers */ - -static int set_break(Eterm mfa[3], int specified, - Binary *match_spec, BeamInstr break_op, - enum erts_break_op count_op, Eterm tracer_pid); -static int set_module_break(Module *modp, Eterm mfa[3], int specified, - Binary *match_spec, BeamInstr break_op, - enum erts_break_op count_op, Eterm tracer_pid); -static int set_function_break(Module *modp, BeamInstr *pc, int bif, - Binary *match_spec, BeamInstr break_op, - enum erts_break_op count_op, Eterm tracer_pid); - -static int clear_break(Eterm mfa[3], int specified, - BeamInstr break_op); -static int clear_module_break(Module *modp, Eterm mfa[3], int specified, - BeamInstr break_op); -static int clear_function_break(Module *modp, BeamInstr *pc, int bif, - BeamInstr break_op); - -static BpData *is_break(BeamInstr *pc, BeamInstr break_op); -static BpData *get_break(Process *p, BeamInstr *pc, BeamInstr break_op); +static Eterm do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg, + int local, Binary* ms, Eterm tracer_pid); +static void set_break(BpFunctions* f, Binary *match_spec, Uint break_flags, + enum erts_break_op count_op, Eterm tracer_pid); +static void set_function_break(BeamInstr *pc, + Binary *match_spec, + Uint break_flags, + enum erts_break_op count_op, + Eterm tracer_pid); + +static void clear_break(BpFunctions* f, Uint break_flags); +static int clear_function_break(BeamInstr *pc, Uint break_flags); + +static BpDataTime* get_time_break(BeamInstr *pc); +static GenericBpData* check_break(BeamInstr *pc, Uint break_flags); +static void bp_time_diff(bp_data_time_item_t *item, + process_breakpoint_time_t *pbt, + Uint ms, Uint s, Uint us); + +static void bp_meta_unref(BpMetaPid* bmp); +static void bp_count_unref(BpCount* bcp); +static void bp_time_unref(BpDataTime* bdt); +static void consolidate_bp_data(Module* modp, BeamInstr* pc, int local); +static void uninstall_breakpoint(BeamInstr* pc); /* bp_hash */ #define BP_TIME_ADD(pi0, pi1) \ @@ -152,240 +123,996 @@ static ERTS_INLINE bp_data_time_item_t * bp_hash_get(bp_time_hash_t *hash, bp_da static ERTS_INLINE bp_data_time_item_t * bp_hash_put(bp_time_hash_t *hash, bp_data_time_item_t *sitem); static void bp_hash_delete(bp_time_hash_t *hash); - /* ************************************************************************* ** External interfaces */ -erts_smp_spinlock_t erts_bp_lock; - void erts_bp_init(void) { - erts_smp_spinlock_init(&erts_bp_lock, "breakpoints"); + erts_smp_atomic32_init_nob(&erts_active_bp_index, 0); + erts_smp_atomic32_init_nob(&erts_staging_bp_index, 1); } -int -erts_set_trace_break(Eterm mfa[3], int specified, Binary *match_spec, - Eterm tracer_pid) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return set_break(mfa, specified, match_spec, - (BeamInstr) BeamOp(op_i_trace_breakpoint), 0, tracer_pid); + +void +erts_bp_match_functions(BpFunctions* f, Eterm mfa[3], int specified) +{ + ErtsCodeIndex code_ix = erts_active_code_ix(); + Uint max_funcs = 0; + int current; + int max_modules = module_code_size(code_ix); + int num_modules = 0; + Module* modp; + Module** module; + Uint i; + + module = (Module **) Alloc(max_modules*sizeof(Module *)); + num_modules = 0; + for (current = 0; current < max_modules; current++) { + modp = module_code(current, code_ix); + if (modp->curr.code) { + max_funcs += modp->curr.code[MI_NUM_FUNCTIONS]; + module[num_modules++] = modp; + } + } + + f->matching = (BpFunction *) Alloc(max_funcs*sizeof(BpFunction)); + i = 0; + for (current = 0; current < num_modules; current++) { + BeamInstr** code_base = (BeamInstr **) module[current]->curr.code; + BeamInstr* code; + Uint num_functions = (Uint) code_base[MI_NUM_FUNCTIONS]; + Uint fi; + + if (specified > 0) { + if (mfa[0] != make_atom(module[current]->module)) { + /* Wrong module name */ + continue; + } + } + + for (fi = 0; fi < num_functions; fi++) { + Eterm* pc; + int wi; + + code = code_base[MI_FUNCTIONS+fi]; + ASSERT(code[0] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); + pc = code+5; + if (erts_is_native_break(pc)) { + continue; + } + if (is_nil(code[3])) { /* Ignore BIF stub */ + continue; + } + for (wi = 0; + wi < specified && (Eterm) code[2+wi] == mfa[wi]; + wi++) { + /* Empty loop body */ + } + if (wi == specified) { + /* Store match */ + f->matching[i].pc = pc; + f->matching[i].mod = module[current]; + i++; + } + } + } + f->matched = i; + Free(module); } -int -erts_set_mtrace_break(Eterm mfa[3], int specified, Binary *match_spec, - Eterm tracer_pid) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return set_break(mfa, specified, match_spec, - (BeamInstr) BeamOp(op_i_mtrace_breakpoint), 0, tracer_pid); +void +erts_bp_match_export(BpFunctions* f, Eterm mfa[3], int specified) +{ + ErtsCodeIndex code_ix = erts_active_code_ix(); + int i; + int num_exps = export_list_size(code_ix); + int ne; + + f->matching = (BpFunction *) Alloc(num_exps*sizeof(BpFunction)); + ne = 0; + for (i = 0; i < num_exps; i++) { + Export* ep = export_list(i, code_ix); + BeamInstr* pc; + int j; + + for (j = 0; j < specified && mfa[j] == ep->code[j]; j++) { + /* Empty loop body */ + } + if (j < specified) { + continue; + } + pc = ep->code+3; + if (ep->addressv[code_ix] == pc) { + if ((*pc == (BeamInstr) em_apply_bif || + *pc == (BeamInstr) em_call_error_handler)) { + continue; + } + ASSERT(*pc == (BeamInstr) BeamOp(op_i_generic_breakpoint)); + } else if (erts_is_native_break(ep->addressv[code_ix])) { + continue; + } + + f->matching[ne].pc = pc; + f->matching[ne].mod = erts_get_module(ep->code[0], code_ix); + ne++; + + } + f->matched = ne; } -/* set breakpoint data for on exported bif entry */ +void +erts_bp_free_matched_functions(BpFunctions* f) +{ + Free(f->matching); +} void -erts_set_mtrace_bif(BeamInstr *pc, Binary *match_spec, Eterm tracer_pid) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - set_function_break(NULL, pc, BREAK_IS_BIF, match_spec, (BeamInstr) BeamOp(op_i_mtrace_breakpoint), 0, tracer_pid); +erts_consolidate_bp_data(BpFunctions* f, int local) +{ + BpFunction* fs = f->matching; + Uint i; + Uint n = f->matched; + + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked()); + + for (i = 0; i < n; i++) { + consolidate_bp_data(fs[i].mod, fs[i].pc, local); + } } -void erts_set_time_trace_bif(BeamInstr *pc, enum erts_break_op count_op) { - set_function_break(NULL, pc, BREAK_IS_BIF, NULL, (BeamInstr) BeamOp(op_i_time_breakpoint), count_op, NIL); +void +erts_consolidate_bif_bp_data(void) +{ + int i; + + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked()); + for (i = 0; i < BIF_SIZE; i++) { + Export *ep = bif_export[i]; + consolidate_bp_data(0, ep->code+3, 0); + } } -void erts_clear_time_trace_bif(BeamInstr *pc) { - clear_function_break(NULL, pc, BREAK_IS_BIF, (BeamInstr) BeamOp(op_i_time_breakpoint)); +static void +consolidate_bp_data(Module* modp, BeamInstr* pc, int local) +{ + GenericBp* g = (GenericBp *) pc[-4]; + GenericBpData* src; + GenericBpData* dst; + Uint flags; + + if (g == 0) { + return; + } + + src = &g->data[erts_active_bp_ix()]; + dst = &g->data[erts_staging_bp_ix()]; + + /* + * The contents of the staging area may be out of date. + * Decrement all reference pointers. + */ + + flags = dst->flags; + if (flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { + MatchSetUnref(dst->local_ms); + } + if (flags & ERTS_BPF_META_TRACE) { + bp_meta_unref(dst->meta_pid); + MatchSetUnref(dst->meta_ms); + } + if (flags & ERTS_BPF_COUNT) { + bp_count_unref(dst->count); + } + if (flags & ERTS_BPF_TIME_TRACE) { + bp_time_unref(dst->time); + } + + /* + * If all flags are zero, deallocate all breakpoint data. + */ + + flags = dst->flags = src->flags; + if (flags == 0) { + if (modp) { + if (local) { + modp->curr.num_breakpoints--; + } else { + modp->curr.num_traced_exports--; + } + ASSERT(modp->curr.num_breakpoints >= 0); + ASSERT(modp->curr.num_traced_exports >= 0); + ASSERT(*pc != (BeamInstr) BeamOp(op_i_generic_breakpoint)); + } + pc[-4] = 0; + Free(g); + return; + } + + /* + * Copy the active data to the staging area (making it ready + * for the next time it will be used). + */ + + if (flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { + dst->local_ms = src->local_ms; + MatchSetRef(dst->local_ms); + } + if (flags & ERTS_BPF_META_TRACE) { + dst->meta_pid = src->meta_pid; + erts_refc_inc(&dst->meta_pid->refc, 1); + dst->meta_ms = src->meta_ms; + MatchSetRef(dst->meta_ms); + } + if (flags & ERTS_BPF_COUNT) { + dst->count = src->count; + erts_refc_inc(&dst->count->refc, 1); + } + if (flags & ERTS_BPF_TIME_TRACE) { + dst->time = src->time; + erts_refc_inc(&dst->time->refc, 1); + ASSERT(dst->time->hash); + } } -int -erts_set_debug_break(Eterm mfa[3], int specified) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return set_break(mfa, specified, NULL, - (BeamInstr) BeamOp(op_i_debug_breakpoint), 0, NIL); +void +erts_commit_staged_bp(void) +{ + ErtsBpIndex staging = erts_staging_bp_ix(); + ErtsBpIndex active = erts_active_bp_ix(); + + erts_smp_atomic32_set_nob(&erts_active_bp_index, staging); + erts_smp_atomic32_set_nob(&erts_staging_bp_index, active); } -int -erts_set_count_break(Eterm mfa[3], int specified, enum erts_break_op count_op) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return set_break(mfa, specified, NULL, - (BeamInstr) BeamOp(op_i_count_breakpoint), count_op, NIL); +void +erts_install_breakpoints(BpFunctions* f) +{ + Uint i; + Uint n = f->matched; + BeamInstr br = (BeamInstr) BeamOp(op_i_generic_breakpoint); + + for (i = 0; i < n; i++) { + BeamInstr* pc = f->matching[i].pc; + GenericBp* g = (GenericBp *) pc[-4]; + if (*pc != br && g) { + Module* modp = f->matching[i].mod; + + /* + * The breakpoint must be disabled in the active data + * (it will enabled later by switching bp indices), + * and enabled in the staging data. + */ + ASSERT(g->data[erts_active_bp_ix()].flags == 0); + ASSERT(g->data[erts_staging_bp_ix()].flags != 0); + + /* + * The following write is not protected by any lock. We + * assume that the hardware guarantees that a write of an + * aligned word-size (or half-word) writes is atomic + * (i.e. that other processes executing this code will not + * see a half pointer). + */ + *pc = br; + modp->curr.num_breakpoints++; + } + } } -int -erts_set_time_break(Eterm mfa[3], int specified, enum erts_break_op count_op) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return set_break(mfa, specified, NULL, - (BeamInstr) BeamOp(op_i_time_breakpoint), count_op, NIL); +void +erts_uninstall_breakpoints(BpFunctions* f) +{ + Uint i; + Uint n = f->matched; + + for (i = 0; i < n; i++) { + BeamInstr* pc = f->matching[i].pc; + uninstall_breakpoint(pc); + } } -int -erts_clear_trace_break(Eterm mfa[3], int specified) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return clear_break(mfa, specified, - (BeamInstr) BeamOp(op_i_trace_breakpoint)); +static void +uninstall_breakpoint(BeamInstr* pc) +{ + if (*pc == (BeamInstr) BeamOp(op_i_generic_breakpoint)) { + GenericBp* g = (GenericBp *) pc[-4]; + if (g->data[erts_active_bp_ix()].flags == 0) { + /* + * The following write is not protected by any lock. We + * assume that the hardware guarantees that a write of an + * aligned word-size (or half-word) writes is atomic + * (i.e. that other processes executing this code will not + * see a half pointer). + */ + *pc = g->orig_instr; + } + } } -int -erts_clear_mtrace_break(Eterm mfa[3], int specified) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return clear_break(mfa, specified, - (BeamInstr) BeamOp(op_i_mtrace_breakpoint)); +void +erts_set_trace_break(BpFunctions* f, Binary *match_spec) +{ + set_break(f, match_spec, ERTS_BPF_LOCAL_TRACE, 0, am_true); } void -erts_clear_mtrace_bif(BeamInstr *pc) { - clear_function_break(NULL, pc, BREAK_IS_BIF, (BeamInstr) BeamOp(op_i_mtrace_breakpoint)); +erts_set_mtrace_break(BpFunctions* f, Binary *match_spec, Eterm tracer_pid) +{ + set_break(f, match_spec, ERTS_BPF_META_TRACE, 0, tracer_pid); } -int -erts_clear_debug_break(Eterm mfa[3], int specified) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return clear_break(mfa, specified, - (BeamInstr) BeamOp(op_i_debug_breakpoint)); +void +erts_set_call_trace_bif(BeamInstr *pc, Binary *match_spec, int local) +{ + Uint flags = local ? ERTS_BPF_LOCAL_TRACE : ERTS_BPF_GLOBAL_TRACE; + + set_function_break(pc, match_spec, flags, 0, NIL); } -int -erts_clear_count_break(Eterm mfa[3], int specified) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return clear_break(mfa, specified, - (BeamInstr) BeamOp(op_i_count_breakpoint)); +void +erts_set_mtrace_bif(BeamInstr *pc, Binary *match_spec, Eterm tracer_pid) +{ + set_function_break(pc, match_spec, ERTS_BPF_META_TRACE, 0, tracer_pid); } -int -erts_clear_time_break(Eterm mfa[3], int specified) { - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return clear_break(mfa, specified, - (BeamInstr) BeamOp(op_i_time_breakpoint)); +void +erts_set_time_trace_bif(BeamInstr *pc, enum erts_break_op count_op) +{ + set_function_break(pc, NULL, + ERTS_BPF_TIME_TRACE|ERTS_BPF_TIME_TRACE_ACTIVE, + count_op, NIL); } -int -erts_clear_break(Eterm mfa[3], int specified) { +void +erts_clear_time_trace_bif(BeamInstr *pc) { + clear_function_break(pc, ERTS_BPF_TIME_TRACE|ERTS_BPF_TIME_TRACE_ACTIVE); +} + +void +erts_set_debug_break(BpFunctions* f) { + set_break(f, NULL, ERTS_BPF_DEBUG, 0, NIL); +} + +void +erts_set_count_break(BpFunctions* f, enum erts_break_op count_op) +{ + set_break(f, 0, ERTS_BPF_COUNT|ERTS_BPF_COUNT_ACTIVE, + count_op, NIL); +} + +void +erts_set_time_break(BpFunctions* f, enum erts_break_op count_op) +{ + set_break(f, 0, ERTS_BPF_TIME_TRACE|ERTS_BPF_TIME_TRACE_ACTIVE, + count_op, NIL); +} + +void +erts_clear_trace_break(BpFunctions* f) +{ + clear_break(f, ERTS_BPF_LOCAL_TRACE); +} + +void +erts_clear_call_trace_bif(BeamInstr *pc, int local) +{ + GenericBp* g = (GenericBp *) pc[-4]; + + if (g) { + Uint flags = local ? ERTS_BPF_LOCAL_TRACE : ERTS_BPF_GLOBAL_TRACE; + if (g->data[erts_staging_bp_ix()].flags & flags) { + clear_function_break(pc, flags); + } + } +} + +void +erts_clear_mtrace_break(BpFunctions* f) +{ + clear_break(f, ERTS_BPF_META_TRACE); +} + +void +erts_clear_mtrace_bif(BeamInstr *pc) +{ + clear_function_break(pc, ERTS_BPF_META_TRACE); +} + +void +erts_clear_debug_break(BpFunctions* f) +{ ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - return clear_break(mfa, specified, 0); + clear_break(f, ERTS_BPF_DEBUG); +} + +void +erts_clear_count_break(BpFunctions* f) +{ + clear_break(f, ERTS_BPF_COUNT|ERTS_BPF_COUNT_ACTIVE); +} + +void +erts_clear_time_break(BpFunctions* f) +{ + clear_break(f, ERTS_BPF_TIME_TRACE|ERTS_BPF_TIME_TRACE_ACTIVE); +} + +void +erts_clear_all_breaks(BpFunctions* f) +{ + clear_break(f, ERTS_BPF_ALL); } int erts_clear_module_break(Module *modp) { + BeamInstr** code_base; + Uint n; + Uint i; + ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); ASSERT(modp); - return clear_module_break(modp, NULL, 0, 0); + code_base = (BeamInstr **) modp->curr.code; + if (code_base == NULL) { + return 0; + } + n = (Uint) code_base[MI_NUM_FUNCTIONS]; + for (i = 0; i < n; ++i) { + BeamInstr* pc; + + pc = code_base[MI_FUNCTIONS+i] + 5; + if (erts_is_native_break(pc)) { + continue; + } + clear_function_break(pc, ERTS_BPF_ALL); + } + + erts_commit_staged_bp(); + + for (i = 0; i < n; ++i) { + BeamInstr* pc; + + pc = code_base[MI_FUNCTIONS+i] + 5; + if (erts_is_native_break(pc)) { + continue; + } + uninstall_breakpoint(pc); + consolidate_bp_data(modp, pc, 1); + ASSERT(pc[-4] == 0); + } + return n; } -int -erts_clear_function_break(Module *modp, BeamInstr *pc) { +void +erts_clear_export_break(Module* modp, BeamInstr* pc) +{ ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - ASSERT(modp); - return clear_function_break(modp, pc, BREAK_IS_ERL, 0); + + clear_function_break(pc, ERTS_BPF_ALL); + erts_commit_staged_bp(); + *pc = (BeamInstr) 0; + consolidate_bp_data(modp, pc, 0); + ASSERT(pc[-4] == 0); } +BeamInstr +erts_generic_breakpoint(Process* c_p, BeamInstr* I, Eterm* reg) +{ + GenericBp* g; + GenericBpData* bp; + Uint bp_flags; + ErtsBpIndex ix = erts_active_bp_ix(); + + g = (GenericBp *) I[-4]; + bp = &g->data[ix]; + bp_flags = bp->flags; + ASSERT((bp_flags & ~ERTS_BPF_ALL) == 0); + if (bp_flags & (ERTS_BPF_LOCAL_TRACE| + ERTS_BPF_GLOBAL_TRACE| + ERTS_BPF_TIME_TRACE_ACTIVE) && + !IS_TRACED_FL(c_p, F_TRACE_CALLS)) { + bp_flags &= ~(ERTS_BPF_LOCAL_TRACE| + ERTS_BPF_GLOBAL_TRACE| + ERTS_BPF_TIME_TRACE| + ERTS_BPF_TIME_TRACE_ACTIVE); + if (bp_flags == 0) { /* Quick exit */ + return g->orig_instr; + } + } + + if (bp_flags & ERTS_BPF_LOCAL_TRACE) { + ASSERT((bp_flags & ERTS_BPF_GLOBAL_TRACE) == 0); + (void) do_call_trace(c_p, I, reg, 1, bp->local_ms, am_true); + } else if (bp_flags & ERTS_BPF_GLOBAL_TRACE) { + (void) do_call_trace(c_p, I, reg, 0, bp->local_ms, am_true); + } + + if (bp_flags & ERTS_BPF_META_TRACE) { + Eterm old_pid; + Eterm new_pid; + + old_pid = (Eterm) erts_smp_atomic_read_nob(&bp->meta_pid->pid); + new_pid = do_call_trace(c_p, I, reg, 1, bp->meta_ms, old_pid); + if (new_pid != old_pid) { + erts_smp_atomic_set_nob(&bp->meta_pid->pid, new_pid); + } + } + + if (bp_flags & ERTS_BPF_COUNT_ACTIVE) { + erts_smp_atomic_inc_nob(&bp->count->acount); + } + + if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE) { + Eterm w; + erts_trace_time_call(c_p, I, bp->time); + w = (BeamInstr) *c_p->cp; + if (! (w == (BeamInstr) BeamOp(op_i_return_time_trace) || + w == (BeamInstr) BeamOp(op_return_trace) || + w == (BeamInstr) BeamOp(op_i_return_to_trace)) ) { + Eterm* E = c_p->stop; + ASSERT(c_p->htop <= E && E <= c_p->hend); + if (E - 2 < c_p->htop) { + (void) erts_garbage_collect(c_p, 2, reg, I[-1]); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + } + E = c_p->stop; + ASSERT(c_p->htop <= E && E <= c_p->hend); + + E -= 2; + E[0] = make_cp(I); + E[1] = make_cp(c_p->cp); /* original return address */ + c_p->cp = beam_return_time_trace; + c_p->stop = E; + } + } + + if (bp_flags & ERTS_BPF_DEBUG) { + return (BeamInstr) BeamOp(op_i_debug_breakpoint); + } else { + return g->orig_instr; + } +} /* - * SMP NOTE: Process p may have become exiting on return! + * Entry point called by the trace wrap functions in erl_bif_wrap.c + * + * The trace wrap functions are themselves called through the export + * entries instead of the original BIF functions. */ -BeamInstr -erts_trace_break(Process *p, BeamInstr *pc, Eterm *args, - Uint32 *ret_flags, Eterm *tracer_pid) { - Eterm tpid1, tpid2; - BpData **bds = (BpData **) (pc)[-4]; - BpDataTrace *bdt = NULL; +Eterm +erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I) +{ + Eterm result; + Eterm (*func)(Process*, Eterm*, BeamInstr*); + Export* ep = bif_export[bif_index]; + Uint32 flags = 0, flags_meta = 0; + Eterm meta_tracer_pid = NIL; + int applying = (I == &(ep->code[3])); /* Yup, the apply code for a bif + * is actually in the + * export entry */ + BeamInstr *cp = p->cp; + GenericBp* g; + GenericBpData* bp; + Uint bp_flags = 0; + + ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); + + g = (GenericBp *) ep->fake_op_func_info_for_hipe[1]; + if (g) { + bp = &g->data[erts_active_bp_ix()]; + bp_flags = bp->flags; + } - ASSERT(bds); - ASSERT(pc[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); - bdt = (BpDataTrace *) bds[bp_sched2ix_proc(p)]; - ASSERT(bdt); - bdt = (BpDataTrace *) bdt->next; - ASSERT(bdt); - ASSERT(ret_flags); - ASSERT(tracer_pid); - - ErtsSmpBPLock(bdt); - tpid1 = tpid2 = bdt->tracer_pid; - ErtsSmpBPUnlock(bdt); - - *ret_flags = erts_call_trace(p, pc-3/*mfa*/, bdt->match_spec, args, - 1, &tpid2); - *tracer_pid = tpid2; - if (tpid1 != tpid2) { - ErtsSmpBPLock(bdt); - bdt->tracer_pid = tpid2; - ErtsSmpBPUnlock(bdt); - } - bds[bp_sched2ix_proc(p)] = (BpData *) bdt; - return bdt->orig_instr; + /* + * Make continuation pointer OK, it is not during direct BIF calls, + * but it is correct during apply of bif. + */ + if (!applying) { + p->cp = I; + } + if (bp_flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE) && + IS_TRACED_FL(p, F_TRACE_CALLS)) { + int local = !!(bp_flags & ERTS_BPF_LOCAL_TRACE); + flags = erts_call_trace(p, ep->code, bp->local_ms, args, + local, &p->tracer_proc); + } + if (bp_flags & ERTS_BPF_META_TRACE) { + Eterm tpid1, tpid2; + + tpid1 = tpid2 = + (Eterm) erts_smp_atomic_read_nob(&bp->meta_pid->pid); + flags_meta = erts_call_trace(p, ep->code, bp->meta_ms, args, + 0, &tpid2); + meta_tracer_pid = tpid2; + if (tpid1 != tpid2) { + erts_smp_atomic_set_nob(&bp->meta_pid->pid, tpid2); + } + } + if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE && + IS_TRACED_FL(p, F_TRACE_CALLS)) { + BeamInstr *pc = (BeamInstr *)ep->code+3; + erts_trace_time_call(p, pc, bp->time); + } + + /* Restore original continuation pointer (if changed). */ + p->cp = cp; + + func = bif_table[bif_index].f; + + result = func(p, args, I); + + if (applying && (flags & MATCH_SET_RETURN_TO_TRACE)) { + BeamInstr i_return_trace = beam_return_trace[0]; + BeamInstr i_return_to_trace = beam_return_to_trace[0]; + BeamInstr i_return_time_trace = beam_return_time_trace[0]; + Eterm *cpp; + /* Maybe advance cp to skip trace stack frames */ + for (cpp = p->stop; ; cp = cp_val(*cpp++)) { + if (*cp == i_return_trace) { + /* Skip stack frame variables */ + while (is_not_CP(*cpp)) cpp++; + cpp += 2; /* Skip return_trace parameters */ + } else if (*cp == i_return_time_trace) { + /* Skip stack frame variables */ + while (is_not_CP(*cpp)) cpp++; + cpp += 1; /* Skip return_time_trace parameters */ + } else if (*cp == i_return_to_trace) { + /* A return_to trace message is going to be generated + * by normal means, so we do not have to. + */ + cp = NULL; + break; + } else break; + } + } + + /* Try to get these in the order + * they usually appear in normal code... */ + if (is_non_value(result)) { + Uint reason = p->freason; + if (reason != TRAP) { + Eterm class; + Eterm value = p->fvalue; + DeclareTmpHeapNoproc(nocatch,3); + UseTmpHeapNoproc(3); + /* Expand error value like in handle_error() */ + if (reason & EXF_ARGLIST) { + Eterm *tp; + ASSERT(is_tuple(value)); + tp = tuple_val(value); + value = tp[1]; + } + if ((reason & EXF_THROWN) && (p->catches <= 0)) { + value = TUPLE2(nocatch, am_nocatch, value); + reason = EXC_ERROR; + } + /* Note: expand_error_value() could theoretically + * allocate on the heap, but not for any error + * returned by a BIF, and it would do no harm, + * just be annoying. + */ + value = expand_error_value(p, reason, value); + class = exception_tag[GET_EXC_CLASS(reason)]; + + if (flags_meta & MATCH_SET_EXCEPTION_TRACE) { + erts_trace_exception(p, ep->code, class, value, + &meta_tracer_pid); + } + if (flags & MATCH_SET_EXCEPTION_TRACE) { + erts_trace_exception(p, ep->code, class, value, + &p->tracer_proc); + } + if ((flags & MATCH_SET_RETURN_TO_TRACE) && p->catches > 0) { + /* can only happen if(local)*/ + Eterm *ptr = p->stop; + ASSERT(is_CP(*ptr)); + ASSERT(ptr <= STACK_START(p)); + /* Search the nearest stack frame for a catch */ + while (++ptr < STACK_START(p)) { + if (is_CP(*ptr)) break; + if (is_catch(*ptr)) { + if (applying) { + /* Apply of BIF, cp is in calling function */ + if (cp) erts_trace_return_to(p, cp); + } else { + /* Direct bif call, I points into + * calling function */ + erts_trace_return_to(p, I); + } + } + } + } + UnUseTmpHeapNoproc(3); + if ((flags_meta|flags) & MATCH_SET_EXCEPTION_TRACE) { + erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR); + p->trace_flags |= F_EXCEPTION_TRACE; + erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR); + } + } + } else { + if (flags_meta & MATCH_SET_RX_TRACE) { + erts_trace_return(p, ep->code, result, &meta_tracer_pid); + } + /* MATCH_SET_RETURN_TO_TRACE cannot occur if(meta) */ + if (flags & MATCH_SET_RX_TRACE) { + erts_trace_return(p, ep->code, result, &p->tracer_proc); + } + if (flags & MATCH_SET_RETURN_TO_TRACE) { + /* can only happen if(local)*/ + if (applying) { + /* Apply of BIF, cp is in calling function */ + if (cp) erts_trace_return_to(p, cp); + } else { + /* Direct bif call, I points into calling function */ + erts_trace_return_to(p, I); + } + } + } + ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); + return result; +} + +static Eterm +do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg, + int local, Binary* ms, Eterm tracer_pid) +{ + Eterm* cpp; + int return_to_trace = 0; + BeamInstr w; + BeamInstr *cp_save; + Uint32 flags; + Uint need = 0; + Eterm* E = c_p->stop; + + w = *c_p->cp; + if (w == (BeamInstr) BeamOp(op_return_trace)) { + cpp = &E[2]; + } else if (w == (BeamInstr) BeamOp(op_i_return_to_trace)) { + return_to_trace = 1; + cpp = &E[0]; + } else if (w == (BeamInstr) BeamOp(op_i_return_time_trace)) { + cpp = &E[0]; + } else { + cpp = NULL; + } + if (cpp) { + for (;;) { + BeamInstr w = *cp_val(*cpp); + if (w == (BeamInstr) BeamOp(op_return_trace)) { + cpp += 3; + } else if (w == (BeamInstr) BeamOp(op_i_return_to_trace)) { + return_to_trace = 1; + cpp += 1; + } else if (w == (BeamInstr) BeamOp(op_i_return_time_trace)) { + cpp += 2; + } else { + break; + } + } + cp_save = c_p->cp; + c_p->cp = (BeamInstr *) cp_val(*cpp); + ASSERT(is_CP(*cpp)); + } + ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); + flags = erts_call_trace(c_p, I-3, ms, reg, local, &tracer_pid); + ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); + if (cpp) { + c_p->cp = cp_save; + } + + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) { + need += 1; + } + if (flags & MATCH_SET_RX_TRACE) { + need += 3; + } + if (need) { + ASSERT(c_p->htop <= E && E <= c_p->hend); + if (E - need < c_p->htop) { + (void) erts_garbage_collect(c_p, need, reg, I[-1]); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + E = c_p->stop; + } + } + if (flags & MATCH_SET_RETURN_TO_TRACE && !return_to_trace) { + E -= 1; + ASSERT(c_p->htop <= E && E <= c_p->hend); + E[0] = make_cp(c_p->cp); + c_p->cp = (BeamInstr *) beam_return_to_trace; + } + if (flags & MATCH_SET_RX_TRACE) { + E -= 3; + ASSERT(c_p->htop <= E && E <= c_p->hend); + ASSERT(is_CP((Eterm) (UWord) (I - 3))); + ASSERT(am_true == tracer_pid || + is_internal_pid(tracer_pid) || is_internal_port(tracer_pid)); + E[2] = make_cp(c_p->cp); + E[1] = tracer_pid; + E[0] = make_cp(I - 3); /* We ARE at the beginning of an + instruction, + the funcinfo is above i. */ + c_p->cp = (flags & MATCH_SET_EXCEPTION_TRACE) ? + beam_exception_trace : beam_return_trace; + erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); + c_p->trace_flags |= F_EXCEPTION_TRACE; + erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); + } + c_p->stop = E; + return tracer_pid; } +void +erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt) +{ + Uint ms,s,us; + process_breakpoint_time_t *pbt = NULL; + bp_data_time_item_t sitem, *item = NULL; + bp_time_hash_t *h = NULL; + BpDataTime *pbdt = NULL; + ASSERT(c_p); + ASSERT(erts_smp_atomic32_read_acqb(&c_p->state) & ERTS_PSFLG_RUNNING); -/* - * SMP NOTE: Process p may have become exiting on return! - */ -Uint32 -erts_bif_mtrace(Process *p, BeamInstr *pc, Eterm *args, int local, - Eterm *tracer_pid) { - BpData **bds = (BpData **) (pc)[-4]; - BpDataTrace *bdt = NULL; + /* get previous timestamp and breakpoint + * from the process psd */ + pbt = ERTS_PROC_GET_CALL_TIME(c_p); + get_sys_now(&ms, &s, &us); - ASSERT(tracer_pid); - if (bds) { - Eterm tpid1, tpid2; - Uint32 flags; - bdt = (BpDataTrace *)bds[bp_sched2ix_proc(p)]; + /* get pbt + * timestamp = t0 + * lookup bdt from code + * set ts0 to pbt + * add call count here? + */ + if (pbt == 0) { + /* First call of process to instrumented function */ + pbt = Alloc(sizeof(process_breakpoint_time_t)); + (void *) ERTS_PROC_SET_CALL_TIME(c_p, ERTS_PROC_LOCK_MAIN, pbt); + } else { + ASSERT(pbt->pc); + /* add time to previous code */ + bp_time_diff(&sitem, pbt, ms, s, us); + sitem.pid = c_p->id; + sitem.count = 0; - ErtsSmpBPLock(bdt); - tpid1 = tpid2 = bdt->tracer_pid; - ErtsSmpBPUnlock(bdt); + /* previous breakpoint */ + pbdt = get_time_break(pbt->pc); - flags = erts_call_trace(p, pc-3/*mfa*/, bdt->match_spec, args, - local, &tpid2); - *tracer_pid = tpid2; - if (tpid1 != tpid2) { - ErtsSmpBPLock(bdt); - bdt->tracer_pid = tpid2; - ErtsSmpBPUnlock(bdt); + /* if null then the breakpoint was removed */ + if (pbdt) { + h = &(pbdt->hash[bp_sched2ix_proc(c_p)]); + + ASSERT(h); + ASSERT(h->item); + + item = bp_hash_get(h, &sitem); + if (!item) { + item = bp_hash_put(h, &sitem); + } else { + BP_TIME_ADD(item, &sitem); + } } - return flags; } - *tracer_pid = NIL; - return 0; + + /* Add count to this code */ + sitem.pid = c_p->id; + sitem.count = 1; + sitem.s_time = 0; + sitem.us_time = 0; + + /* this breakpoint */ + ASSERT(bdt); + h = &(bdt->hash[bp_sched2ix_proc(c_p)]); + + ASSERT(h); + ASSERT(h->item); + + item = bp_hash_get(h, &sitem); + if (!item) { + item = bp_hash_put(h, &sitem); + } else { + BP_TIME_ADD(item, &sitem); + } + + pbt->pc = I; + pbt->ms = ms; + pbt->s = s; + pbt->us = us; } +void +erts_trace_time_return(Process *p, BeamInstr *pc) +{ + Uint ms,s,us; + process_breakpoint_time_t *pbt = NULL; + bp_data_time_item_t sitem, *item = NULL; + bp_time_hash_t *h = NULL; + BpDataTime *pbdt = NULL; + + ASSERT(p); + ASSERT(erts_smp_atomic32_read_acqb(&p->state) & ERTS_PSFLG_RUNNING); + /* get previous timestamp and breakpoint + * from the process psd */ + + pbt = ERTS_PROC_GET_CALL_TIME(p); + get_sys_now(&ms,&s,&us); + + /* get pbt + * lookup bdt from code + * timestamp = t1 + * get ts0 from pbt + * get item from bdt->hash[bp_hash(p->id)] + * ack diff (t1, t0) to item + */ + + if (pbt) { + /* might have been removed due to + * trace_pattern(false) + */ + ASSERT(pbt->pc); + + bp_time_diff(&sitem, pbt, ms, s, us); + sitem.pid = p->id; + sitem.count = 0; + + /* previous breakpoint */ + pbdt = get_time_break(pbt->pc); + + /* beware, the trace_pattern might have been removed */ + if (pbdt) { + h = &(pbdt->hash[bp_sched2ix_proc(p)]); + + ASSERT(h); + ASSERT(h->item); + + item = bp_hash_get(h, &sitem); + if (!item) { + item = bp_hash_put(h, &sitem); + } else { + BP_TIME_ADD(item, &sitem); + } + } + + pbt->pc = pc; + pbt->ms = ms; + pbt->s = s; + pbt->us = us; + } +} int -erts_is_trace_break(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_ret) { - BpDataTrace *bdt = - (BpDataTrace *) is_break(pc, (BeamInstr) BeamOp(op_i_trace_breakpoint)); - - if (bdt) { +erts_is_trace_break(BeamInstr *pc, Binary **match_spec_ret, int local) +{ + Uint flags = local ? ERTS_BPF_LOCAL_TRACE : ERTS_BPF_GLOBAL_TRACE; + GenericBpData* bp = check_break(pc, flags); + + if (bp) { if (match_spec_ret) { - *match_spec_ret = bdt->match_spec; + *match_spec_ret = bp->local_ms; } - if (tracer_pid_ret) { - ErtsSmpBPLock(bdt); - *tracer_pid_ret = bdt->tracer_pid; - ErtsSmpBPUnlock(bdt); - } - return !0; + return 1; } return 0; } int -erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_ret) { - BpDataTrace *bdt = - (BpDataTrace *) is_break(pc, (BeamInstr) BeamOp(op_i_mtrace_breakpoint)); +erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret, + Eterm *tracer_pid_ret) +{ + GenericBpData* bp = check_break(pc, ERTS_BPF_META_TRACE); - if (bdt) { + if (bp) { if (match_spec_ret) { - *match_spec_ret = bdt->match_spec; + *match_spec_ret = bp->meta_ms; } if (tracer_pid_ret) { - ErtsSmpBPLock(bdt); - *tracer_pid_ret = bdt->tracer_pid; - ErtsSmpBPUnlock(bdt); + *tracer_pid_ret = + (Eterm) erts_smp_atomic_read_nob(&bp->meta_pid->pid); } - return !0; + return 1; } return 0; } @@ -402,15 +1129,15 @@ erts_is_native_break(BeamInstr *pc) { } int -erts_is_count_break(BeamInstr *pc, Sint *count_ret) { - BpDataCount *bdc = - (BpDataCount *) is_break(pc, (BeamInstr) BeamOp(op_i_count_breakpoint)); +erts_is_count_break(BeamInstr *pc, Uint *count_ret) +{ + GenericBpData* bp = check_break(pc, ERTS_BPF_COUNT); - if (bdc) { + if (bp) { if (count_ret) { - *count_ret = (Sint) erts_smp_atomic_read_nob(&bdc->acount); + *count_ret = (Uint) erts_smp_atomic_read_nob(&bp->count->acount); } - return !0; + return 1; } return 0; } @@ -421,7 +1148,7 @@ int erts_is_time_break(Process *p, BeamInstr *pc, Eterm *retval) { Uint size; Eterm *hp, t; bp_data_time_item_t *item = NULL; - BpDataTime *bdt = (BpDataTime *) is_break(pc, (BeamInstr) BeamOp(op_i_time_breakpoint)); + BpDataTime *bdt = get_time_break(pc); if (bdt) { if (retval) { @@ -464,7 +1191,7 @@ int erts_is_time_break(Process *p, BeamInstr *pc, Eterm *retval) { } bp_hash_delete(&hash); } - return !0; + return 1; } return 0; @@ -478,15 +1205,16 @@ erts_find_local_func(Eterm mfa[3]) { BeamInstr* code_ptr; Uint i,n; - if ((modp = erts_get_module(mfa[0])) == NULL) + if ((modp = erts_get_module(mfa[0], erts_active_code_ix())) == NULL) return NULL; - if ((code_base = (BeamInstr **) modp->code) == NULL) + if ((code_base = (BeamInstr **) modp->curr.code) == NULL) return NULL; n = (BeamInstr) code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { code_ptr = code_base[MI_FUNCTIONS+i]; ASSERT(((BeamInstr) BeamOp(op_i_func_info_IaaI)) == code_ptr[0]); - ASSERT(mfa[0] == ((Eterm) code_ptr[2])); + ASSERT(mfa[0] == ((Eterm) code_ptr[2]) || + is_nil((Eterm) code_ptr[2])); if (mfa[1] == ((Eterm) code_ptr[3]) && ((BeamInstr) mfa[2]) == code_ptr[4]) { return code_ptr + 5; @@ -654,7 +1382,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) { * the previous breakpoint. */ - pbdt = (BpDataTime *) get_break(p, pbt->pc, (BeamInstr) BeamOp(op_i_time_breakpoint)); + pbdt = get_time_break(pbt->pc); if (pbdt) { get_sys_now(&ms,&s,&us); bp_time_diff(&sitem, pbt, ms, s, us); @@ -692,669 +1420,259 @@ void erts_schedule_time_break(Process *p, Uint schedule) { } /* pbt */ } -/* call_time breakpoint - * Accumulated times are added to the previous bp, - * not the current one. The current one is saved - * for future reference. - * The previous breakpoint is stored in the process it self, the psd. - * We do not need to store in a stack frame. - * There is no need for locking, each thread has its own - * area in each bp to save data. - * Since we need to diffrentiate between processes for each bp, - * every bp has a hash (per thread) to process-bp statistics. - * - egil - */ - -void erts_trace_time_break(Process *p, BeamInstr *pc, BpDataTime *bdt, Uint type) { - Uint ms,s,us; - process_breakpoint_time_t *pbt = NULL; - bp_data_time_item_t sitem, *item = NULL; - bp_time_hash_t *h = NULL; - BpDataTime *pbdt = NULL; - - ASSERT(p); - ASSERT(p->status == P_RUNNING); - - /* get previous timestamp and breakpoint - * from the process psd */ - - pbt = ERTS_PROC_GET_CALL_TIME(p); - get_sys_now(&ms,&s,&us); - - switch(type) { - /* get pbt - * timestamp = t0 - * lookup bdt from code - * set ts0 to pbt - * add call count here? - */ - case ERTS_BP_CALL_TIME_CALL: - case ERTS_BP_CALL_TIME_TAIL_CALL: - - if (pbt) { - ASSERT(pbt->pc); - /* add time to previous code */ - bp_time_diff(&sitem, pbt, ms, s, us); - sitem.pid = p->id; - sitem.count = 0; - - /* previous breakpoint */ - pbdt = (BpDataTime *) get_break(p, pbt->pc, (BeamInstr) BeamOp(op_i_time_breakpoint)); - - /* if null then the breakpoint was removed */ - if (pbdt) { - h = &(pbdt->hash[bp_sched2ix_proc(p)]); - - ASSERT(h); - ASSERT(h->item); - - item = bp_hash_get(h, &sitem); - if (!item) { - item = bp_hash_put(h, &sitem); - } else { - BP_TIME_ADD(item, &sitem); - } - } - - } else { - /* first call of process to instrumented function */ - pbt = Alloc(sizeof(process_breakpoint_time_t)); - (void *) ERTS_PROC_SET_CALL_TIME(p, ERTS_PROC_LOCK_MAIN, pbt); - } - /* add count to this code */ - sitem.pid = p->id; - sitem.count = 1; - sitem.s_time = 0; - sitem.us_time = 0; - - /* this breakpoint */ - ASSERT(bdt); - h = &(bdt->hash[bp_sched2ix_proc(p)]); - - ASSERT(h); - ASSERT(h->item); - - item = bp_hash_get(h, &sitem); - if (!item) { - item = bp_hash_put(h, &sitem); - } else { - BP_TIME_ADD(item, &sitem); - } - - pbt->pc = pc; - pbt->ms = ms; - pbt->s = s; - pbt->us = us; - break; - - case ERTS_BP_CALL_TIME_RETURN: - /* get pbt - * lookup bdt from code - * timestamp = t1 - * get ts0 from pbt - * get item from bdt->hash[bp_hash(p->id)] - * ack diff (t1, t0) to item - */ - - if(pbt) { - /* might have been removed due to - * trace_pattern(false) - */ - ASSERT(pbt->pc); - - bp_time_diff(&sitem, pbt, ms, s, us); - sitem.pid = p->id; - sitem.count = 0; - - /* previous breakpoint */ - pbdt = (BpDataTime *) get_break(p, pbt->pc, (BeamInstr) BeamOp(op_i_time_breakpoint)); - - /* beware, the trace_pattern might have been removed */ - if (pbdt) { - h = &(pbdt->hash[bp_sched2ix_proc(p)]); - - ASSERT(h); - ASSERT(h->item); - - item = bp_hash_get(h, &sitem); - if (!item) { - item = bp_hash_put(h, &sitem); - } else { - BP_TIME_ADD(item, &sitem); - } - } - - pbt->pc = pc; - pbt->ms = ms; - pbt->s = s; - pbt->us = us; - } - break; - default : - ASSERT(0); - /* will never happen */ - break; - } -} - - /* ************************************************************************* ** Local helpers */ -static int set_break(Eterm mfa[3], int specified, - Binary *match_spec, BeamInstr break_op, - enum erts_break_op count_op, Eterm tracer_pid) +static void +set_break(BpFunctions* f, Binary *match_spec, Uint break_flags, + enum erts_break_op count_op, Eterm tracer_pid) { - Module *modp; - int num_processed = 0; - if (!specified) { - /* Find and process all modules in the system... */ - int current; - int last = module_code_size(); - for (current = 0; current < last; current++) { - modp = module_code(current); - ASSERT(modp != NULL); - num_processed += - set_module_break(modp, mfa, specified, - match_spec, break_op, count_op, - tracer_pid); - } - } else { - /* Process a single module */ - if ((modp = erts_get_module(mfa[0])) != NULL) { - num_processed += - set_module_break(modp, mfa, specified, - match_spec, break_op, count_op, - tracer_pid); - } - } - return num_processed; -} - -static int set_module_break(Module *modp, Eterm mfa[3], int specified, - Binary *match_spec, BeamInstr break_op, - enum erts_break_op count_op, Eterm tracer_pid) { - BeamInstr** code_base; - BeamInstr* code_ptr; - int num_processed = 0; - Uint i,n; + Uint i; + Uint n; - ASSERT(break_op); - ASSERT(modp); - code_base = (BeamInstr **) modp->code; - if (code_base == NULL) { - return 0; + n = f->matched; + for (i = 0; i < n; i++) { + BeamInstr* pc = f->matching[i].pc; + set_function_break(pc, match_spec, break_flags, + count_op, tracer_pid); } - n = (BeamInstr) code_base[MI_NUM_FUNCTIONS]; - for (i = 0; i < n; ++i) { - code_ptr = code_base[MI_FUNCTIONS+i]; - ASSERT(code_ptr[0] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); - if ((specified < 2 || mfa[1] == ((Eterm) code_ptr[3])) && - (specified < 3 || ((int) mfa[2]) == ((int) code_ptr[4]))) { - BeamInstr *pc = code_ptr+5; - - num_processed += - set_function_break(modp, pc, BREAK_IS_ERL, match_spec, - break_op, count_op, tracer_pid); - } - } - return num_processed; } -static int set_function_break(Module *modp, BeamInstr *pc, int bif, - Binary *match_spec, BeamInstr break_op, - enum erts_break_op count_op, Eterm tracer_pid) { - - BeamInstr **code_base = NULL; - BpData *bd, **r, ***rs; - size_t size; - Uint ix = 0; - - if (bif == BREAK_IS_ERL) { - code_base = (BeamInstr **)modp->code; - ASSERT(code_base); - ASSERT(code_base <= (BeamInstr **)pc); - ASSERT((BeamInstr **)pc < code_base + (modp->code_length/sizeof(BeamInstr *))); - } else { - ASSERT(*pc == (BeamInstr) em_apply_bif); - ASSERT(modp == NULL); +static void +set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags, + enum erts_break_op count_op, Eterm tracer_pid) +{ + GenericBp* g; + GenericBpData* bp; + Uint common; + ErtsBpIndex ix = erts_staging_bp_ix(); + + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked()); + g = (GenericBp *) pc[-4]; + if (g == 0) { + int i; + if (count_op == erts_break_reset || count_op == erts_break_stop) { + /* Do not insert a new breakpoint */ + return; + } + g = Alloc(sizeof(GenericBp)); + g->orig_instr = *pc; + for (i = 0; i < ERTS_NUM_BP_IX; i++) { + g->data[i].flags = 0; + } + pc[-4] = (BeamInstr) g; } + bp = &g->data[ix]; /* - * Currently no trace support for native code. + * If we are changing an existing breakpoint, clean up old data. */ - if (erts_is_native_break(pc)) { - return 0; - } - /* Do not allow two breakpoints of the same kind */ - if ( (bd = is_break(pc, break_op))) { - if (break_op == (BeamInstr) BeamOp(op_i_trace_breakpoint) - || break_op == (BeamInstr) BeamOp(op_i_mtrace_breakpoint)) { - - BpDataTrace *bdt = (BpDataTrace *) bd; - Binary *old_match_spec; - - /* Update match spec and tracer */ - MatchSetRef(match_spec); - ErtsSmpBPLock(bdt); - old_match_spec = bdt->match_spec; - bdt->match_spec = match_spec; - bdt->tracer_pid = tracer_pid; - ErtsSmpBPUnlock(bdt); - MatchSetUnref(old_match_spec); - } else { - BpDataCount *bdc = (BpDataCount *) bd; - erts_aint_t count = 0; - erts_aint_t res = 0; - - ASSERT(! match_spec); - ASSERT(is_nil(tracer_pid)); - - if (break_op == (BeamInstr) BeamOp(op_i_count_breakpoint)) { - if (count_op == erts_break_stop) { - count = erts_smp_atomic_read_nob(&bdc->acount); - if (count >= 0) { - while(1) { - res = erts_smp_atomic_cmpxchg_nob(&bdc->acount, -count - 1, count); - if ((res == count) || count < 0) break; - count = res; - } - } - } else { - /* Reset call counter */ - erts_smp_atomic_set_nob(&bdc->acount, 0); - } - - } else if (break_op == (BeamInstr) BeamOp(op_i_time_breakpoint)) { - BpDataTime *bdt = (BpDataTime *) bd; - Uint i = 0; - - ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); - - if (count_op == erts_break_stop) { - bdt->pause = 1; - } else { - bdt->pause = 0; - for (i = 0; i < bdt->n; i++) { - bp_hash_delete(&(bdt->hash[i])); - bp_hash_init(&(bdt->hash[i]), 32); - } - } - } else { - ASSERT (! count_op); - } - } - return 1; - } - if (break_op == (BeamInstr) BeamOp(op_i_trace_breakpoint) || - break_op == (BeamInstr) BeamOp(op_i_mtrace_breakpoint)) { - size = sizeof(BpDataTrace); - } else { - ASSERT(! match_spec); - ASSERT(is_nil(tracer_pid)); - if (break_op == (BeamInstr) BeamOp(op_i_count_breakpoint)) { - if (count_op == erts_break_reset || count_op == erts_break_stop) { - /* Do not insert a new breakpoint */ - return 1; - } - size = sizeof(BpDataCount); - } else if (break_op == (BeamInstr) BeamOp(op_i_time_breakpoint)) { - if (count_op == erts_break_reset || count_op == erts_break_stop) { - /* Do not insert a new breakpoint */ - return 1; - } - size = sizeof(BpDataTime); + common = break_flags & bp->flags; + if (common & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { + MatchSetUnref(bp->local_ms); + } else if (common & ERTS_BPF_META_TRACE) { + MatchSetUnref(bp->meta_ms); + bp_meta_unref(bp->meta_pid); + } else if (common & ERTS_BPF_COUNT) { + if (count_op == erts_break_stop) { + bp->flags &= ~ERTS_BPF_COUNT_ACTIVE; } else { - ASSERT(! count_op); - ASSERT(break_op == (BeamInstr) BeamOp(op_i_debug_breakpoint)); - size = sizeof(BpDataDebug); + bp->flags |= ERTS_BPF_COUNT_ACTIVE; + erts_smp_atomic_set_nob(&bp->count->acount, 0); } - } - rs = (BpData ***) (pc-4); - if (! *rs) { - size_t ssize = sizeof(BeamInstr) * erts_no_schedulers; - *rs = (BpData **) Alloc(ssize); - sys_memzero(*rs, ssize); - } - - r = &((*rs)[0]); - - if (! *r) { - ASSERT(*pc != (BeamInstr) BeamOp(op_i_trace_breakpoint)); - ASSERT(*pc != (BeamInstr) BeamOp(op_i_mtrace_breakpoint)); - ASSERT(*pc != (BeamInstr) BeamOp(op_i_debug_breakpoint)); - ASSERT(*pc != (BeamInstr) BeamOp(op_i_count_breakpoint)); - ASSERT(*pc != (BeamInstr) BeamOp(op_i_time_breakpoint)); - /* First breakpoint; create singleton ring */ - bd = Alloc(size); - BpInit(bd, *pc); - *r = bd; - if (bif == BREAK_IS_ERL) { - *pc = break_op; - } - } else { - ASSERT(*pc == (BeamInstr) BeamOp(op_i_trace_breakpoint) || - *pc == (BeamInstr) BeamOp(op_i_mtrace_breakpoint) || - *pc == (BeamInstr) BeamOp(op_i_debug_breakpoint) || - *pc == (BeamInstr) BeamOp(op_i_time_breakpoint) || - *pc == (BeamInstr) BeamOp(op_i_count_breakpoint) || - *pc == (BeamInstr) em_apply_bif); - if (*pc == (BeamInstr) BeamOp(op_i_debug_breakpoint)) { - /* Debug bp must be last, so if it is also first; - * it must be singleton. */ - ASSERT(BpSingleton(*r)); - /* Insert new bp first in the ring, i.e second to last. */ - bd = Alloc(size); - BpInitAndSpliceNext(bd, *pc, *r); - if (bif == BREAK_IS_ERL) { - *pc = break_op; - } - } else if ((*r)->prev->orig_instr - == (BeamInstr) BeamOp(op_i_debug_breakpoint)) { - /* Debug bp last in the ring; insert new second to last. */ - bd = Alloc(size); - BpInitAndSplicePrev(bd, (*r)->prev->orig_instr, *r); - (*r)->prev->orig_instr = break_op; + ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); + return; + } else if (common & ERTS_BPF_TIME_TRACE) { + BpDataTime* bdt = bp->time; + Uint i = 0; + + if (count_op == erts_break_stop) { + bp->flags &= ~ERTS_BPF_TIME_TRACE_ACTIVE; } else { - /* Just insert last in the ring */ - bd = Alloc(size); - BpInitAndSpliceNext(bd, (*r)->orig_instr, *r); - (*r)->orig_instr = break_op; - *r = bd; + bp->flags |= ERTS_BPF_TIME_TRACE_ACTIVE; + for (i = 0; i < bdt->n; i++) { + bp_hash_delete(&(bdt->hash[i])); + bp_hash_init(&(bdt->hash[i]), 32); + } } - } - for (ix = 1; ix < erts_no_schedulers; ++ix) { - (*rs)[ix] = (*rs)[0]; + ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); + return; } - bd->this_instr = break_op; - /* Init the bp type specific data */ - if (break_op == (BeamInstr) BeamOp(op_i_trace_breakpoint) || - break_op == (BeamInstr) BeamOp(op_i_mtrace_breakpoint)) { - - BpDataTrace *bdt = (BpDataTrace *) bd; - - MatchSetRef(match_spec); - bdt->match_spec = match_spec; - bdt->tracer_pid = tracer_pid; - } else if (break_op == (BeamInstr) BeamOp(op_i_time_breakpoint)) { - BpDataTime *bdt = (BpDataTime *) bd; - Uint i = 0; - - bdt->pause = 0; - bdt->n = erts_no_schedulers; - bdt->hash = Alloc(sizeof(bp_time_hash_t)*(bdt->n)); + /* + * Initialize the new breakpoint data. + */ + if (break_flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { + MatchSetRef(match_spec); + bp->local_ms = match_spec; + } else if (break_flags & ERTS_BPF_META_TRACE) { + BpMetaPid* bmp; + MatchSetRef(match_spec); + bp->meta_ms = match_spec; + bmp = Alloc(sizeof(BpMetaPid)); + erts_refc_init(&bmp->refc, 1); + erts_smp_atomic_init_nob(&bmp->pid, tracer_pid); + bp->meta_pid = bmp; + } else if (break_flags & ERTS_BPF_COUNT) { + BpCount* bcp; + + ASSERT((bp->flags & ERTS_BPF_COUNT) == 0); + bcp = Alloc(sizeof(BpCount)); + erts_refc_init(&bcp->refc, 1); + erts_smp_atomic_init_nob(&bcp->acount, 0); + bp->count = bcp; + } else if (break_flags & ERTS_BPF_TIME_TRACE) { + BpDataTime* bdt; + int i; + + ASSERT((bp->flags & ERTS_BPF_TIME_TRACE) == 0); + bdt = Alloc(sizeof(BpDataTime)); + erts_refc_init(&bdt->refc, 1); + bdt->n = erts_no_schedulers; + bdt->hash = Alloc(sizeof(bp_time_hash_t)*(bdt->n)); for (i = 0; i < bdt->n; i++) { bp_hash_init(&(bdt->hash[i]), 32); } - } else if (break_op == (BeamInstr) BeamOp(op_i_count_breakpoint)) { - BpDataCount *bdc = (BpDataCount *) bd; - erts_smp_atomic_init_nob(&bdc->acount, 0); + bp->time = bdt; } - if (bif == BREAK_IS_ERL) { - ++(*(BeamInstr*)&code_base[MI_NUM_BREAKPOINTS]); + bp->flags |= break_flags; + ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); +} + +static void +clear_break(BpFunctions* f, Uint break_flags) +{ + Uint i; + Uint n; + + n = f->matched; + for (i = 0; i < n; i++) { + BeamInstr* pc = f->matching[i].pc; + clear_function_break(pc, break_flags); } - return 1; } -static int clear_break(Eterm mfa[3], int specified, BeamInstr break_op) +static int +clear_function_break(BeamInstr *pc, Uint break_flags) { - int num_processed = 0; - Module *modp; + GenericBp* g; + GenericBpData* bp; + Uint common; + ErtsBpIndex ix = erts_staging_bp_ix(); - if (!specified) { - /* Iterate over all modules */ - int current; - int last = module_code_size(); + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked()); - for (current = 0; current < last; current++) { - modp = module_code(current); - ASSERT(modp != NULL); - num_processed += clear_module_break(modp, mfa, specified, break_op); - } - } else { - /* Process a single module */ - if ((modp = erts_get_module(mfa[0])) != NULL) { - num_processed += - clear_module_break(modp, mfa, specified, break_op); - } + if ((g = (GenericBp *) pc[-4]) == 0) { + return 1; } - return num_processed; -} -static int clear_module_break(Module *m, Eterm mfa[3], int specified, - BeamInstr break_op) { - BeamInstr** code_base; - BeamInstr* code_ptr; - int num_processed = 0; - Uint i; - BeamInstr n; - - ASSERT(m); - code_base = (BeamInstr **) m->code; - if (code_base == NULL) { - return 0; + bp = &g->data[ix]; + ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); + common = bp->flags & break_flags; + bp->flags &= ~break_flags; + if (common & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { + MatchSetUnref(bp->local_ms); } - n = (BeamInstr) code_base[MI_NUM_FUNCTIONS]; - for (i = 0; i < n; ++i) { - code_ptr = code_base[MI_FUNCTIONS+i]; - if ((specified < 2 || mfa[1] == ((Eterm) code_ptr[3])) && - (specified < 3 || ((int) mfa[2]) == ((int) code_ptr[4]))) { - BeamInstr *pc = code_ptr + 5; - - num_processed += - clear_function_break(m, pc, BREAK_IS_ERL, break_op); - } + if (common & ERTS_BPF_META_TRACE) { + MatchSetUnref(bp->meta_ms); + } + if (common & ERTS_BPF_COUNT) { + ASSERT((bp->flags & ERTS_BPF_COUNT_ACTIVE) == 0); + bp_count_unref(bp->count); + } + if (common & ERTS_BPF_TIME_TRACE) { + ASSERT((bp->flags & ERTS_BPF_TIME_TRACE_ACTIVE) == 0); + bp_time_unref(bp->time); } - return num_processed; -} -static int clear_function_break(Module *m, BeamInstr *pc, int bif, BeamInstr break_op) { - BpData *bd; - Uint ix = 0; - BeamInstr **code_base = NULL; + ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); + return 1; +} - if (bif == BREAK_IS_ERL) { - code_base = (BeamInstr **)m->code; - ASSERT(code_base); - ASSERT(code_base <= (BeamInstr **)pc); - ASSERT((BeamInstr **)pc < code_base + (m->code_length/sizeof(BeamInstr *))); - } else { - ASSERT(*pc == (BeamInstr) em_apply_bif); - ASSERT(m == NULL); +static void +bp_meta_unref(BpMetaPid* bmp) +{ + if (erts_refc_dectest(&bmp->refc, 0) <= 0) { + Free(bmp); } +} - /* - * Currently no trace support for native code. - */ - if (erts_is_native_break(pc)) { - return 0; +static void +bp_count_unref(BpCount* bcp) +{ + if (erts_refc_dectest(&bcp->refc, 0) <= 0) { + Free(bcp); } +} - while ( (bd = is_break(pc, break_op))) { - /* Remove all breakpoints of this type. - * There should be only one of each type, - * but break_op may be 0 which matches any type. +static void +bp_time_unref(BpDataTime* bdt) +{ + if (erts_refc_dectest(&bdt->refc, 0) <= 0) { + Uint i = 0; + Uint j = 0; + Process *h_p = NULL; + bp_data_time_item_t* item = NULL; + process_breakpoint_time_t* pbt = NULL; + + /* remove all psd associated with the hash + * and then delete the hash. + * ... sigh ... */ - BeamInstr op; - BpData ***rs = (BpData ***) (pc - 4); - BpData **r = NULL; - -#ifdef DEBUG - for (ix = 1; ix < erts_no_schedulers; ++ix) { - ASSERT((*rs)[ix] == (*rs)[0]); - } -#endif - - r = &((*rs)[0]); - - ASSERT(*r); - /* Find opcode for this breakpoint */ - if (break_op) { - op = break_op; - } else { - if (bd == (*r)->next) { - /* First breakpoint in ring */ - op = *pc; - } else { - op = bd->prev->orig_instr; - } - } - if (BpSingleton(bd)) { - ASSERT(*r == bd); - /* Only one breakpoint to remove */ - if (bif == BREAK_IS_ERL) { - *pc = bd->orig_instr; - } - Free(*rs); - *rs = NULL; - } else { - BpData *bd_prev = bd->prev; - - BpSpliceNext(bd, bd_prev); - ASSERT(BpSingleton(bd)); - if (bd == *r) { - /* We removed the last breakpoint in the ring */ - *r = bd_prev; - bd_prev->orig_instr = bd->orig_instr; - } else if (bd_prev == *r) { - /* We removed the first breakpoint in the ring */ - if (bif == BREAK_IS_ERL) { - *pc = bd->orig_instr; - } - } else { - bd_prev->orig_instr = bd->orig_instr; - } - } - if (op == (BeamInstr) BeamOp(op_i_trace_breakpoint) || - op == (BeamInstr) BeamOp(op_i_mtrace_breakpoint)) { - - BpDataTrace *bdt = (BpDataTrace *) bd; - MatchSetUnref(bdt->match_spec); - } - if (op == (BeamInstr) BeamOp(op_i_time_breakpoint)) { - BpDataTime *bdt = (BpDataTime *) bd; - Uint i = 0; - Uint j = 0; - Process *h_p = NULL; - bp_data_time_item_t *item = NULL; - process_breakpoint_time_t *pbt = NULL; - - /* remove all psd associated with the hash - * and then delete the hash. - * ... sigh ... - */ - for( i = 0; i < bdt->n; ++i) { - if (bdt->hash[i].used) { - for (j = 0; j < bdt->hash[i].n; ++j) { - item = &(bdt->hash[i].item[j]); - if (item->pid != NIL) { - h_p = process_tab[internal_pid_index(item->pid)]; - if (h_p) { - pbt = ERTS_PROC_SET_CALL_TIME(h_p, ERTS_PROC_LOCK_MAIN, NULL); - if (pbt) { - Free(pbt); - } + for (i = 0; i < bdt->n; ++i) { + if (bdt->hash[i].used) { + for (j = 0; j < bdt->hash[i].n; ++j) { + item = &(bdt->hash[i].item[j]); + if (item->pid != NIL) { + h_p = erts_pid2proc(NULL, 0, item->pid, + ERTS_PROC_LOCK_MAIN); + if (h_p) { + pbt = ERTS_PROC_SET_CALL_TIME(h_p, + ERTS_PROC_LOCK_MAIN, + NULL); + if (pbt) { + Free(pbt); } + erts_smp_proc_unlock(h_p, ERTS_PROC_LOCK_MAIN); } } } - bp_hash_delete(&(bdt->hash[i])); } - Free(bdt->hash); - bdt->hash = NULL; - bdt->n = 0; + bp_hash_delete(&(bdt->hash[i])); } - Free(bd); - if (bif == BREAK_IS_ERL) { - ASSERT(((BeamInstr) code_base[MI_NUM_BREAKPOINTS]) > 0); - --(*(BeamInstr*)&code_base[MI_NUM_BREAKPOINTS]); - } - if (*rs) { - for (ix = 1; ix < erts_no_schedulers; ++ix) { - (*rs)[ix] = (*rs)[0]; - } - } - } /* while bd != NULL */ - return 1; + Free(bdt->hash); + Free(bdt); + } } - - -/* -** Searches (linear forward) the breakpoint ring for a specified opcode -** and returns a pointer to the breakpoint data structure or NULL if -** not found. If the specified opcode is 0, the last breakpoint is -** returned. The program counter must point to the first executable -** (breakpoint) instruction of the function. -*/ - -BpData *erts_get_time_break(Process *p, BeamInstr *pc) { - return get_break(p, pc, (BeamInstr) BeamOp(op_i_time_breakpoint)); +static BpDataTime* +get_time_break(BeamInstr *pc) +{ + GenericBpData* bp = check_break(pc, ERTS_BPF_TIME_TRACE); + return bp ? bp->time : 0; } -static BpData *get_break(Process *p, BeamInstr *pc, BeamInstr break_op) { - ASSERT(pc[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); - if (! erts_is_native_break(pc)) { - BpData **rs = (BpData **) pc[-4]; - BpData *bd = NULL, *ebd = NULL; - - if (! rs) { - return NULL; - } - - bd = ebd = rs[bp_sched2ix_proc(p)]; - ASSERT(bd); - if (bd->this_instr == break_op) { - return bd; - } - - bd = bd->next; - while (bd != ebd) { - ASSERT(bd); - if (bd->this_instr == break_op) { - ASSERT(bd); - return bd; - } - bd = bd->next; - } - } - return NULL; -} +static GenericBpData* +check_break(BeamInstr *pc, Uint break_flags) +{ + GenericBp* g = (GenericBp *) pc[-4]; -static BpData *is_break(BeamInstr *pc, BeamInstr break_op) { - BpData **rs; - BpData *bd = NULL, *ebd = NULL; ASSERT(pc[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); - if (erts_is_native_break(pc)) { - return NULL; - } - rs = (BpData **) pc[-4]; - if (! rs) { - return NULL; - } - - bd = ebd = rs[erts_bp_sched2ix()]; - ASSERT(bd); - if ( (break_op == 0) || (bd->this_instr == break_op)) { - return bd; + return 0; } - - bd = bd->next; - while (bd != ebd) { - ASSERT(bd); - if (bd->this_instr == break_op) { - ASSERT(bd); - return bd; + if (g) { + GenericBpData* bp = &g->data[erts_active_bp_ix()]; + ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); + if (bp->flags & break_flags) { + return bp; } - bd = bd->next; } - return NULL; + return 0; } diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h index 167069552f..28aaaa462a 100644 --- a/erts/emulator/beam/beam_bp.h +++ b/erts/emulator/beam/beam_bp.h @@ -25,77 +25,6 @@ #include "erl_vm.h" #include "global.h" - - -/* A couple of gotchas: - * - * The breakpoint structure from BeamInstr, - * In beam_emu where the instruction counter pointer, I (or pc), - * points to the *current* instruction. At that time, if the instruction - * is a breakpoint instruction the pc looks like the following, - * - * I[-5] | op_i_func_info_IaaI | scheduler specific entries - * I[-4] | BpData** bpa | --> | BpData * bdas1 | ... | BpData * bdasN | - * I[-3] | Tagged Module | | | - * I[-2] | Tagged Function | V V - * I[-1] | Arity | BpData -> BpData -> BpData -> BpData - * I[0] | The bp instruction | ^ * the bp wheel * | - * |------------------------------ - * - * Common struct to all bp_data_* - * - * 1) The type of bp_data structure in the ring is deduced from the - * orig_instr field of the structure _before_ in the ring, except for - * the first structure in the ring that has its instruction in - * pc[0] of the code to execute. - * This is valid as long as you don't search for the function while it is - * being executed by something else. Or is in the middle of its rotation for - * any other reason. - * A key, the bp beam instruction, is included for this reason. - * - * 2) pc[-4][sched_id - 1] points to the _last_ structure in the ring before the - * breakpoints are being executed. - * - * So, as an example, when a breakpointed function starts to execute, - * the first instruction that is a breakpoint instruction at pc[0] finds - * its data at ((BpData **) pc[-4][sched_id - 1])->next and has to cast that pointer - * to the correct bp_data type. -*/ - -typedef struct bp_data { - struct bp_data *next; /* Doubly linked ring pointers */ - struct bp_data *prev; /* -"- */ - BeamInstr orig_instr; /* The original instruction to execute */ - BeamInstr this_instr; /* key */ -} BpData; -/* -** All the following bp_data_.. structs must begin the same way -*/ - -typedef struct bp_data_trace { - struct bp_data *next; - struct bp_data *prev; - BeamInstr orig_instr; - BeamInstr this_instr; /* key */ - Binary *match_spec; - Eterm tracer_pid; -} BpDataTrace; - -typedef struct bp_data_debug { - struct bp_data *next; - struct bp_data *prev; - BeamInstr orig_instr; - BeamInstr this_instr; /* key */ -} BpDataDebug; - -typedef struct bp_data_count { /* Call count */ - struct bp_data *next; - struct bp_data *prev; - BeamInstr orig_instr; - BeamInstr this_instr; /* key */ - erts_smp_atomic_t acount; -} BpDataCount; - typedef struct { Eterm pid; Sint count; @@ -110,13 +39,9 @@ typedef struct { } bp_time_hash_t; typedef struct bp_data_time { /* Call time */ - struct bp_data *next; - struct bp_data *prev; - BeamInstr orig_instr; - BeamInstr this_instr; /* key */ - Uint pause; - Uint n; - bp_time_hash_t *hash; + Uint n; + bp_time_hash_t *hash; + erts_refc_t refc; } BpDataTime; typedef struct { @@ -126,64 +51,42 @@ typedef struct { BeamInstr *pc; } process_breakpoint_time_t; /* used within psd */ -extern erts_smp_spinlock_t erts_bp_lock; +typedef struct { + erts_smp_atomic_t acount; + erts_refc_t refc; +} BpCount; + +typedef struct { + erts_smp_atomic_t pid; + erts_refc_t refc; +} BpMetaPid; + +typedef struct generic_bp_data { + Uint flags; + Binary* local_ms; /* Match spec for local call trace */ + Binary* meta_ms; /* Match spec for meta trace */ + BpMetaPid* meta_pid; /* Meta trace pid */ + BpCount* count; /* For call count */ + BpDataTime* time; /* For time trace */ +} GenericBpData; + +#define ERTS_NUM_BP_IX 2 + +typedef struct generic_bp { + BeamInstr orig_instr; + GenericBpData data[ERTS_NUM_BP_IX]; +} GenericBp; #define ERTS_BP_CALL_TIME_SCHEDULE_IN (0) #define ERTS_BP_CALL_TIME_SCHEDULE_OUT (1) #define ERTS_BP_CALL_TIME_SCHEDULE_EXITING (2) -#define ERTS_BP_CALL_TIME_CALL (0) -#define ERTS_BP_CALL_TIME_RETURN (1) -#define ERTS_BP_CALL_TIME_TAIL_CALL (2) - -#ifdef ERTS_SMP -#define ErtsSmpBPLock(BDC) erts_smp_spin_lock(&erts_bp_lock) -#define ErtsSmpBPUnlock(BDC) erts_smp_spin_unlock(&erts_bp_lock) -#else -#define ErtsSmpBPLock(BDC) -#define ErtsSmpBPUnlock(BDC) -#endif - #ifdef ERTS_SMP #define bp_sched2ix_proc(p) ((p)->scheduler_data->no - 1) #else #define bp_sched2ix_proc(p) (0) #endif -#define ErtsCountBreak(p, pc,instr_result) \ -do { \ - BpData **bds = (BpData **) (pc)[-4]; \ - BpDataCount *bdc = NULL; \ - Uint ix = bp_sched2ix_proc( (p) ); \ - erts_aint_t count = 0; \ - \ - ASSERT((pc)[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); \ - ASSERT(bds); \ - bdc = (BpDataCount *) bds[ix]; \ - bdc = (BpDataCount *) bdc->next; \ - ASSERT(bdc); \ - bds[ix] = (BpData *) bdc; \ - count = erts_smp_atomic_read_nob(&bdc->acount); \ - if (count >= 0) erts_smp_atomic_inc_nob(&bdc->acount); \ - *(instr_result) = bdc->orig_instr; \ -} while (0) - -#define ErtsBreakSkip(p, pc,instr_result) \ -do { \ - BpData **bds = (BpData **) (pc)[-4]; \ - BpData *bd = NULL; \ - Uint ix = bp_sched2ix_proc( (p) ); \ - \ - ASSERT((pc)[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); \ - ASSERT(bds); \ - bd = bds[ix]; \ - ASSERT(bd); \ - bd = bd->next; \ - ASSERT(bd); \ - bds[ix] = bd; \ - *(instr_result) = bd->orig_instr; \ -} while (0) - enum erts_break_op{ erts_break_nop = 0, /* Must be false */ erts_break_set = !0, /* Must be true */ @@ -191,7 +94,17 @@ enum erts_break_op{ erts_break_stop }; +typedef Uint32 ErtsBpIndex; +typedef struct { + BeamInstr* pc; + Module* mod; +} BpFunction; + +typedef struct { + Uint matched; /* Number matched */ + BpFunction* matching; /* Matching functions */ +} BpFunctions; /* ** Function interface exported from beam_bp.c @@ -199,49 +112,66 @@ enum erts_break_op{ void erts_bp_init(void); -int erts_set_trace_break(Eterm mfa[3], int specified, Binary *match_spec, - Eterm tracer_pid); -int erts_clear_trace_break(Eterm mfa[3], int specified); -int erts_set_mtrace_break(Eterm mfa[3], int specified, Binary *match_spec, +void erts_prepare_bp_staging(void); +void erts_commit_staged_bp(void); + +ERTS_GLB_INLINE ErtsBpIndex erts_active_bp_ix(void); +ERTS_GLB_INLINE ErtsBpIndex erts_staging_bp_ix(void); + +void erts_bp_match_functions(BpFunctions* f, Eterm mfa[3], int specified); +void erts_bp_match_export(BpFunctions* f, Eterm mfa[3], int specified); +void erts_bp_free_matched_functions(BpFunctions* f); + +void erts_install_breakpoints(BpFunctions* f); +void erts_uninstall_breakpoints(BpFunctions* f); +void erts_consolidate_bp_data(BpFunctions* f, int local); +void erts_consolidate_bif_bp_data(void); + +void erts_set_trace_break(BpFunctions *f, Binary *match_spec); +void erts_clear_trace_break(BpFunctions *f); + +void erts_set_call_trace_bif(BeamInstr *pc, Binary *match_spec, int local); +void erts_clear_call_trace_bif(BeamInstr *pc, int local); + +void erts_set_mtrace_break(BpFunctions *f, Binary *match_spec, Eterm tracer_pid); -int erts_clear_mtrace_break(Eterm mfa[3], int specified); +void erts_clear_mtrace_break(BpFunctions *f); void erts_set_mtrace_bif(BeamInstr *pc, Binary *match_spec, Eterm tracer_pid); void erts_clear_mtrace_bif(BeamInstr *pc); -int erts_set_debug_break(Eterm mfa[3], int specified); -int erts_clear_debug_break(Eterm mfa[3], int specified); -int erts_set_count_break(Eterm mfa[3], int specified, enum erts_break_op); -int erts_clear_count_break(Eterm mfa[3], int specified); +void erts_set_debug_break(BpFunctions *f); +void erts_clear_debug_break(BpFunctions *f); +void erts_set_count_break(BpFunctions *f, enum erts_break_op); +void erts_clear_count_break(BpFunctions *f); -int erts_clear_break(Eterm mfa[3], int specified); + +void erts_clear_all_breaks(BpFunctions* f); int erts_clear_module_break(Module *modp); -int erts_clear_function_break(Module *modp, BeamInstr *pc); +void erts_clear_export_break(Module *modp, BeamInstr* pc); +BeamInstr erts_generic_breakpoint(Process* c_p, BeamInstr* I, Eterm* reg); BeamInstr erts_trace_break(Process *p, BeamInstr *pc, Eterm *args, Uint32 *ret_flags, Eterm *tracer_pid); -Uint32 erts_bif_mtrace(Process *p, BeamInstr *pc, Eterm *args, - int local, Eterm *tracer_pid); -int erts_is_trace_break(BeamInstr *pc, Binary **match_spec_ret, - Eterm *tracer_pid_ret); +int erts_is_trace_break(BeamInstr *pc, Binary **match_spec_ret, int local); int erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_rte); int erts_is_mtrace_bif(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_ret); int erts_is_native_break(BeamInstr *pc); -int erts_is_count_break(BeamInstr *pc, Sint *count_ret); +int erts_is_count_break(BeamInstr *pc, Uint *count_ret); int erts_is_time_break(Process *p, BeamInstr *pc, Eterm *call_time); -void erts_trace_time_break(Process *p, BeamInstr *pc, BpDataTime *bdt, Uint type); +void erts_trace_time_call(Process* c_p, BeamInstr* pc, BpDataTime* bdt); +void erts_trace_time_return(Process* c_p, BeamInstr* pc); void erts_schedule_time_break(Process *p, Uint out); -int erts_set_time_break(Eterm mfa[3], int specified, enum erts_break_op); -int erts_clear_time_break(Eterm mfa[3], int specified); +void erts_set_time_break(BpFunctions *f, enum erts_break_op); +void erts_clear_time_break(BpFunctions *f); int erts_is_time_trace_bif(Process *p, BeamInstr *pc, Eterm *call_time); void erts_set_time_trace_bif(BeamInstr *pc, enum erts_break_op); void erts_clear_time_trace_bif(BeamInstr *pc); -BpData *erts_get_time_break(Process *p, BeamInstr *pc); BeamInstr *erts_find_local_func(Eterm mfa[3]); @@ -258,6 +188,19 @@ ERTS_GLB_INLINE Uint erts_bp_sched2ix(void) return 0; #endif } + +extern erts_smp_atomic32_t erts_active_bp_index; +extern erts_smp_atomic32_t erts_staging_bp_index; + +ERTS_GLB_INLINE ErtsBpIndex erts_active_bp_ix(void) +{ + return erts_smp_atomic32_read_nob(&erts_active_bp_index); +} + +ERTS_GLB_INLINE ErtsBpIndex erts_staging_bp_ix(void) +{ + return erts_smp_atomic32_read_nob(&erts_staging_bp_index); +} #endif #endif /* _BEAM_BP_H */ diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index 406ef1db5f..92f7ffe5a2 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -31,78 +31,144 @@ typedef struct { unsigned cdr; } beam_catch_t; -static int free_list; -static unsigned high_mark; -static unsigned tabsize; -static beam_catch_t *beam_catches; +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + +struct bc_pool { + int free_list; + unsigned high_mark; + unsigned tabsize; + beam_catch_t *beam_catches; + /* + * Note that the 'beam_catches' area is shared by pools. Used slots + * are readonly as long as the module is not purgable. The free-list is + * protected by the code_ix lock. + */ + + IF_DEBUG(int is_staging;) +}; + +static struct bc_pool bccix[ERTS_NUM_CODE_IX]; void beam_catches_init(void) { - tabsize = DEFAULT_TABSIZE; - free_list = -1; - high_mark = 0; + int i; + + bccix[0].tabsize = DEFAULT_TABSIZE; + bccix[0].free_list = -1; + bccix[0].high_mark = 0; + bccix[0].beam_catches = erts_alloc(ERTS_ALC_T_CODE, + sizeof(beam_catch_t)*DEFAULT_TABSIZE); + IF_DEBUG(bccix[0].is_staging = 0); + for (i=1; i<ERTS_NUM_CODE_IX; i++) { + bccix[i] = bccix[i-1]; + } + /* For initial load: */ + IF_DEBUG(bccix[erts_staging_code_ix()].is_staging = 1); +} - beam_catches = erts_alloc(ERTS_ALC_T_CODE, sizeof(beam_catch_t)*DEFAULT_TABSIZE); + +static void gc_old_vec(beam_catch_t* vec) +{ + int i; + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + if (bccix[i].beam_catches == vec) { + return; + } + } + erts_free(ERTS_ALC_T_CODE, vec); +} + + +void beam_catches_start_staging(void) +{ + ErtsCodeIndex dst = erts_staging_code_ix(); + ErtsCodeIndex src = erts_active_code_ix(); + beam_catch_t* prev_vec = bccix[dst].beam_catches; + + ASSERT(!bccix[src].is_staging && !bccix[dst].is_staging); + + bccix[dst] = bccix[src]; + gc_old_vec(prev_vec); + IF_DEBUG(bccix[dst].is_staging = 1); +} + +void beam_catches_end_staging(int commit) +{ + IF_DEBUG(bccix[erts_staging_code_ix()].is_staging = 0); } unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr) { int i; + struct bc_pool* p = &bccix[erts_staging_code_ix()]; + ASSERT(p->is_staging); /* * Allocate from free_list while it is non-empty. * If free_list is empty, allocate at high_mark. - * - * This avoids the need to initialise the free list in - * beam_catches_init(), which would cost O(TABSIZ) time. */ - if( free_list >= 0 ) { - i = free_list; - free_list = beam_catches[i].cdr; - } else if( high_mark < tabsize ) { - i = high_mark; - high_mark++; - } else { - /* No free slots and table is full: realloc table */ - tabsize = 2*tabsize; - beam_catches = erts_realloc(ERTS_ALC_T_CODE, beam_catches, sizeof(beam_catch_t)*tabsize); - i = high_mark; - high_mark++; + if (p->free_list >= 0) { + i = p->free_list; + p->free_list = p->beam_catches[i].cdr; + } + else { + if (p->high_mark >= p->tabsize) { + /* No free slots and table is full: realloc table */ + beam_catch_t* prev_vec = p->beam_catches; + unsigned newsize = p->tabsize*2; + + p->beam_catches = erts_alloc(ERTS_ALC_T_CODE, + newsize*sizeof(beam_catch_t)); + sys_memcpy(p->beam_catches, prev_vec, + p->tabsize*sizeof(beam_catch_t)); + gc_old_vec(prev_vec); + p->tabsize = newsize; + } + i = p->high_mark++; } - beam_catches[i].cp = cp; - beam_catches[i].cdr = cdr; + p->beam_catches[i].cp = cp; + p->beam_catches[i].cdr = cdr; return i; } BeamInstr *beam_catches_car(unsigned i) { - if( i >= tabsize ) { + struct bc_pool* p = &bccix[erts_active_code_ix()]; + + if (i >= p->tabsize ) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); } - return beam_catches[i].cp; + return p->beam_catches[i].cp; } -void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes) +void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, + ErtsCodeIndex code_ix) { + struct bc_pool* p = &bccix[code_ix]; unsigned i, cdr; + ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_staging_code_ix()].is_staging); for(i = head; i != (unsigned)-1;) { - if( i >= tabsize ) { + if (i >= p->tabsize) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); } - if( (char*)beam_catches[i].cp - (char*)code >= code_bytes ) { + if( (char*)p->beam_catches[i].cp - (char*)code >= code_bytes ) { erl_exit(1, "beam_catches_delmod: item %#x has cp %#lx which is not " "in module's range [%#lx,%#lx[\r\n", - i, (long)beam_catches[i].cp, + i, (long)p->beam_catches[i].cp, (long)code, (long)((char*)code + code_bytes)); } - beam_catches[i].cp = 0; - cdr = beam_catches[i].cdr; - beam_catches[i].cdr = free_list; - free_list = i; + p->beam_catches[i].cp = 0; + cdr = p->beam_catches[i].cdr; + p->beam_catches[i].cdr = p->free_list; + p->free_list = i; i = cdr; } } diff --git a/erts/emulator/beam/beam_catches.h b/erts/emulator/beam/beam_catches.h index 6223427f0d..b2bd2351a5 100644 --- a/erts/emulator/beam/beam_catches.h +++ b/erts/emulator/beam/beam_catches.h @@ -20,12 +20,21 @@ #ifndef __BEAM_CATCHES_H #define __BEAM_CATCHES_H +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include "sys.h" +#include "code_ix.h" + #define BEAM_CATCHES_NIL (-1) void beam_catches_init(void); +void beam_catches_start_staging(void); +void beam_catches_end_staging(int commit); unsigned beam_catches_cons(BeamInstr* cp, unsigned cdr); BeamInstr *beam_catches_car(unsigned i); -void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes); +void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes, + ErtsCodeIndex); #define catch_pc(x) beam_catches_car(catch_val((x))) diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index 8041c92162..a609ed8c71 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -84,6 +84,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) int i; int specified = 0; Eterm res; + BpFunctions f; if (bool != am_true && bool != am_false) goto error; @@ -114,18 +115,30 @@ erts_debug_breakpoint_2(BIF_ALIST_2) mfa[2] = signed_val(mfa[2]); } + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD2(bif_export[BIF_erts_debug_breakpoint_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); + erts_bp_match_functions(&f, mfa, specified); if (bool == am_true) { - res = make_small(erts_set_debug_break(mfa, specified)); + erts_set_debug_break(&f); + erts_install_breakpoints(&f); + erts_commit_staged_bp(); } else { - res = make_small(erts_clear_debug_break(mfa, specified)); + erts_clear_debug_break(&f); + erts_commit_staged_bp(); + erts_uninstall_breakpoints(&f); } + erts_consolidate_bp_data(&f, 1); + res = make_small(f.matched); + erts_bp_free_matched_functions(&f); erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - + erts_release_code_write_permission(); return res; error: @@ -207,6 +220,7 @@ erts_debug_disassemble_1(BIF_ALIST_1) BIF_RET(am_false); } } else if (is_tuple(addr)) { + ErtsCodeIndex code_ix; Module* modp; Eterm mod; Eterm name; @@ -225,14 +239,14 @@ erts_debug_disassemble_1(BIF_ALIST_1) goto error; } arity = signed_val(tp[3]); - modp = erts_get_module(mod); + code_ix = erts_active_code_ix(); + modp = erts_get_module(mod, code_ix); /* * Try the export entry first to allow disassembly of special functions * such as erts_debug:apply/4. Then search for it in the module. */ - - if ((ep = erts_find_function(mod, name, arity)) != NULL) { + if ((ep = erts_find_function(mod, name, arity, code_ix)) != NULL) { /* XXX: add "&& ep->address != ep->code+3" condition? * Consider a traced function. * Its ep will have ep->address == ep->code+3. @@ -241,9 +255,9 @@ erts_debug_disassemble_1(BIF_ALIST_1) * But this code_ptr will point to the start of the Export, * not the function's func_info instruction. BOOM !? */ - code_ptr = ((BeamInstr *) ep->address) - 5; + code_ptr = ((BeamInstr *) ep->addressv[code_ix]) - 5; funcinfo = code_ptr+2; - } else if (modp == NULL || (code_base = modp->code) == NULL) { + } else if (modp == NULL || (code_base = modp->curr.code) == NULL) { BIF_RET(am_undef); } else { n = code_base[MI_NUM_FUNCTIONS]; diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 6d3b15cd46..5dc5aa1e03 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -63,11 +63,7 @@ # define PROCESS_MAIN_CHK_LOCKS(P) \ do { \ if ((P)) { \ - erts_pix_lock_t *pix_lock__ = ERTS_PIX2PIXLOCK(internal_pid_index((P)->id));\ erts_proc_lc_chk_only_proc_main((P)); \ - erts_pix_lock(pix_lock__); \ - ASSERT(0 < (P)->lock.refc && (P)->lock.refc < erts_no_schedulers*5);\ - erts_pix_unlock(pix_lock__); \ } \ else \ erts_lc_check_exact(NULL, 0); \ @@ -221,7 +217,6 @@ BeamInstr beam_continue_exit[1]; BeamInstr* em_call_error_handler; BeamInstr* em_apply_bif; -BeamInstr* em_call_traced_function; /* NOTE These should be the only variables containing trace instructions. @@ -495,7 +490,7 @@ extern int count_instructions; do { \ if (FCALLS > 0) { \ Eterm* dis_next; \ - SET_I(((Export *) Arg(0))->address); \ + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); \ dis_next = (Eterm *) *I; \ FCALLS--; \ CHECK_ARGS(I); \ @@ -504,7 +499,7 @@ extern int count_instructions; && FCALLS > neg_o_reds) { \ goto save_calls1; \ } else { \ - SET_I(((Export *) Arg(0))->address); \ + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); \ CHECK_ARGS(I); \ goto context_switch; \ } \ @@ -965,16 +960,9 @@ static void save_stacktrace(Process* c_p, BeamInstr* pc, Eterm* reg, static struct StackTrace * get_trace_from_exc(Eterm exc); static Eterm make_arglist(Process* c_p, Eterm* reg, int a); -#if defined(VXWORKS) -static int init_done; -#endif - void init_emulator(void) { -#if defined(VXWORKS) - init_done = 0; -#endif erts_smp_atomic_init_nob(&warned_for_tuple_funs, (erts_aint_t) 0); process_main(); } @@ -1107,9 +1095,7 @@ dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) */ void process_main(void) { -#if !defined(VXWORKS) static int init_done = 0; -#endif Process* c_p = NULL; int reds_used; #ifdef DEBUG @@ -1507,7 +1493,7 @@ void process_main(void) */ #ifdef USE_VM_CALL_PROBES if (DTRACE_ENABLED(global_function_entry)) { - BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); + BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->addressv[erts_active_code_ix()]); DTRACE_GLOBAL_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); } #endif @@ -1522,7 +1508,7 @@ void process_main(void) SET_CP(c_p, I+2); #ifdef USE_VM_CALL_PROBES if (DTRACE_ENABLED(global_function_entry)) { - BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); + BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->addressv[erts_active_code_ix()]); DTRACE_GLOBAL_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); } #endif @@ -1535,7 +1521,7 @@ void process_main(void) OpCase(i_call_ext_only_e): #ifdef USE_VM_CALL_PROBES if (DTRACE_ENABLED(global_function_entry)) { - BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); + BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->addressv[erts_active_code_ix()]); DTRACE_GLOBAL_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); } #endif @@ -1826,13 +1812,12 @@ void process_main(void) msgp = PEEK_MESSAGE(c_p); if (msgp) erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); - else { + else #endif + { SET_I((BeamInstr *) Arg(0)); Goto(*I); /* Jump to a wait or wait_timeout instruction */ -#ifdef ERTS_SMP } -#endif } ErtsMoveMsgAttachmentIntoProc(msgp, c_p, E, HTOP, FCALLS, { @@ -2061,11 +2046,11 @@ void process_main(void) OpCase(wait_f): wait2: { - ASSERT(!ERTS_PROC_IS_EXITING(c_p)); c_p->i = (BeamInstr *) Arg(0); /* L1 */ SWAPOUT; c_p->arity = 0; - c_p->status = P_WAITING; + erts_smp_atomic32_read_band_relb(&c_p->state, ~ERTS_PSFLG_ACTIVE); + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); c_p->current = NULL; goto do_schedule; @@ -3144,10 +3129,6 @@ void process_main(void) c_p->arg_reg[0] = r(0); SWAPOUT; c_p->i = I; - erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS); - if (c_p->status != P_SUSPENDED) - erts_add_to_runq(c_p); - erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS); goto do_schedule1; } @@ -4580,64 +4561,6 @@ void process_main(void) * Trace and debugging support. */ - /* - * At this point, I points to the code[3] in the export entry for - * a trace-enabled function. - * - * code[0]: Module - * code[1]: Function - * code[2]: Arity - * code[3]: &&call_traced_function - * code[4]: Address of function. - */ - OpCase(call_traced_function): { - if (IS_TRACED_FL(c_p, F_TRACE_CALLS)) { - unsigned offset = offsetof(Export, code) + 3*sizeof(BeamInstr); - Export* ep = (Export *) (((char *)I)-offset); - Uint32 flags; - - SWAPOUT; - reg[0] = r(0); - PROCESS_MAIN_CHK_LOCKS(c_p); - ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); - flags = erts_call_trace(c_p, ep->code, ep->match_prog_set, reg, - 0, &c_p->tracer_proc); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); - PROCESS_MAIN_CHK_LOCKS(c_p); - ASSERT(!ERTS_PROC_IS_EXITING(c_p)); - SWAPIN; - - if (flags & MATCH_SET_RX_TRACE) { - ASSERT(c_p->htop <= E && E <= c_p->hend); - if (E - 3 < HTOP) { - /* SWAPOUT, SWAPIN was done and r(0) was saved above */ - PROCESS_MAIN_CHK_LOCKS(c_p); - FCALLS -= erts_garbage_collect(c_p, 3, reg, ep->code[2]); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - PROCESS_MAIN_CHK_LOCKS(c_p); - r(0) = reg[0]; - SWAPIN; - } - E -= 3; - ASSERT(c_p->htop <= E && E <= c_p->hend); - ASSERT(is_CP((BeamInstr)(ep->code))); - ASSERT(is_internal_pid(c_p->tracer_proc) || - is_internal_port(c_p->tracer_proc)); - E[2] = make_cp(c_p->cp); /* Code in lower range on halfword */ - E[1] = am_true; /* Process tracer */ - E[0] = make_cp(ep->code); - c_p->cp = (flags & MATCH_SET_EXCEPTION_TRACE) - ? beam_exception_trace : beam_return_trace; - erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); - c_p->trace_flags |= F_EXCEPTION_TRACE; - erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); - } - } - SET_I((BeamInstr *)Arg(0)); - Dispatch(); - } - OpCase(return_trace): { BeamInstr* code = (BeamInstr *) (UWord) E[0]; @@ -4652,80 +4575,22 @@ void process_main(void) Goto(*I); } - OpCase(i_count_breakpoint): { - BeamInstr real_I; - - ErtsCountBreak(c_p, (BeamInstr *) I, &real_I); - ASSERT(VALID_INSTR(real_I)); - Goto(real_I); - } - - /* need to send mfa instead of bdt pointer - * the pointer might be deallocated. - */ - - OpCase(i_time_breakpoint): { + OpCase(i_generic_breakpoint): { BeamInstr real_I; - BpData **bds = (BpData **) (I)[-4]; - BpDataTime *bdt = NULL; - Uint ix = 0; -#ifdef ERTS_SMP - ix = c_p->scheduler_data->no - 1; -#else - ix = 0; -#endif - bdt = (BpDataTime *)bds[ix]; - - ASSERT((I)[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); - ASSERT(bdt); - bdt = (BpDataTime *) bdt->next; - ASSERT(bdt); - bds[ix] = (BpData *) bdt; - real_I = bdt->orig_instr; + ASSERT(I[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); + SWAPOUT; + reg[0] = r(0); + real_I = erts_generic_breakpoint(c_p, I, reg); + r(0) = reg[0]; + SWAPIN; ASSERT(VALID_INSTR(real_I)); - - if (IS_TRACED_FL(c_p, F_TRACE_CALLS) && !(bdt->pause)) { - if ( (*(c_p->cp) == (BeamInstr) OpCode(i_return_time_trace)) || - (*(c_p->cp) == (BeamInstr) OpCode(return_trace)) || - (*(c_p->cp) == (BeamInstr) OpCode(i_return_to_trace))) { - /* This _IS_ a tail recursive call */ - SWAPOUT; - erts_trace_time_break(c_p, I, bdt, ERTS_BP_CALL_TIME_TAIL_CALL); - SWAPIN; - } else { - SWAPOUT; - erts_trace_time_break(c_p, I, bdt, ERTS_BP_CALL_TIME_CALL); - - /* r register needs to be copied to the array - * for the garbage collector - */ - ASSERT(c_p->htop <= E && E <= c_p->hend); - if (E - 2 < HTOP) { - reg[0] = r(0); - PROCESS_MAIN_CHK_LOCKS(c_p); - FCALLS -= erts_garbage_collect(c_p, 2, reg, I[-1]); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - PROCESS_MAIN_CHK_LOCKS(c_p); - r(0) = reg[0]; - } - SWAPIN; - - ASSERT(c_p->htop <= E && E <= c_p->hend); - - E -= 2; - E[0] = make_cp(I); - E[1] = make_cp(c_p->cp); /* original return address */ - c_p->cp = beam_return_time_trace; - } - } - Goto(real_I); } OpCase(i_return_time_trace): { BeamInstr *pc = (BeamInstr *) (UWord) E[0]; SWAPOUT; - erts_trace_time_break(c_p, pc, NULL, ERTS_BP_CALL_TIME_RETURN); + erts_trace_time_return(c_p, pc); SWAPIN; c_p->cp = NULL; SET_I((BeamInstr *) cp_val(E[1])); @@ -4733,114 +4598,6 @@ void process_main(void) Goto(*I); } - OpCase(i_trace_breakpoint): - if (! IS_TRACED_FL(c_p, F_TRACE_CALLS)) { - BeamInstr real_I; - - ErtsBreakSkip(c_p, (BeamInstr *) I, &real_I); - Goto(real_I); - } - /* Fall through to next case */ - OpCase(i_mtrace_breakpoint): { - BeamInstr real_I; - Uint32 flags; - Eterm tracer_pid; - Uint* cpp; - int return_to_trace = 0, need = 0; - flags = 0; - SWAPOUT; - reg[0] = r(0); - - if (*(c_p->cp) == (BeamInstr) OpCode(return_trace)) { - cpp = &E[2]; - } else if (*(c_p->cp) == (BeamInstr) OpCode(i_return_to_trace)) { - return_to_trace = !0; - cpp = &E[0]; - } else if (*(c_p->cp) == (BeamInstr) OpCode(i_return_time_trace)) { - return_to_trace = !0; - cpp = &E[0]; - } else { - cpp = NULL; - } - if (cpp) { - /* This _IS_ a tail recursive call, if there are - * return_trace and/or i_return_to_trace stackframes - * on the stack, they are not intermixed with y registers - */ - BeamInstr *cp_save = c_p->cp; - for (;;) { - ASSERT(is_CP(*cpp)); - if (*cp_val(*cpp) == (BeamInstr) OpCode(return_trace)) { - cpp += 3; - } else if (*cp_val(*cpp) == (BeamInstr) OpCode(i_return_to_trace)) { - return_to_trace = !0; - cpp += 1; - } else if (*cp_val(*cpp) == (BeamInstr) OpCode(i_return_time_trace)) { - cpp += 2; - } else - break; - } - c_p->cp = (BeamInstr *) cp_val(*cpp); - ASSERT(is_CP(*cpp)); - ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); - real_I = erts_trace_break(c_p, I, reg, &flags, &tracer_pid); - ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); - SWAPIN; /* Needed by shared heap. */ - c_p->cp = cp_save; - } else { - ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); - real_I = erts_trace_break(c_p, I, reg, &flags, &tracer_pid); - ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); - SWAPIN; /* Needed by shared heap. */ - } - - ASSERT(!ERTS_PROC_IS_EXITING(c_p)); - - if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) { - need += 1; - } - if (flags & MATCH_SET_RX_TRACE) { - need += 3; - } - if (need) { - ASSERT(c_p->htop <= E && E <= c_p->hend); - if (E - need < HTOP) { - /* SWAPOUT was done and r(0) was saved above */ - PROCESS_MAIN_CHK_LOCKS(c_p); - FCALLS -= erts_garbage_collect(c_p, need, reg, I[-1]); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - PROCESS_MAIN_CHK_LOCKS(c_p); - r(0) = reg[0]; - SWAPIN; - } - } - if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) { - E -= 1; - ASSERT(c_p->htop <= E && E <= c_p->hend); - E[0] = make_cp(c_p->cp); - c_p->cp = (BeamInstr *) beam_return_to_trace; - } - if (flags & MATCH_SET_RX_TRACE) { - E -= 3; - ASSERT(c_p->htop <= E && E <= c_p->hend); - ASSERT(is_CP((Eterm) (UWord) (I - 3))); - ASSERT(am_true == tracer_pid || - is_internal_pid(tracer_pid) || is_internal_port(tracer_pid)); - E[2] = make_cp(c_p->cp); - E[1] = tracer_pid; - E[0] = make_cp(I - 3); /* We ARE at the beginning of an - instruction, - the funcinfo is above i. */ - c_p->cp = - (flags & MATCH_SET_EXCEPTION_TRACE) - ? beam_exception_trace : beam_return_trace; - erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); - c_p->trace_flags |= F_EXCEPTION_TRACE; - erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); - } - Goto(real_I); - } - OpCase(i_return_to_trace): { if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO)) { Uint *cpp = (Uint*) E; @@ -5110,9 +4867,6 @@ void process_main(void) c_p->arity = 1; /* One living register (the 'true' return value) */ SWAPOUT; c_p->i = I + 1; /* Next instruction */ - erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS); - erts_add_to_runq(c_p); - erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS); c_p->current = NULL; goto do_schedule; } @@ -5193,7 +4947,6 @@ void process_main(void) #endif /* NO_JUMP_TABLE */ em_call_error_handler = OpCode(call_error_handler); - em_call_traced_function = OpCode(call_traced_function); em_apply_bif = OpCode(apply_bif); beam_apply[0] = (BeamInstr) OpCode(i_apply); @@ -5234,7 +4987,7 @@ void process_main(void) save_calls(c_p, (Export *) Arg(0)); - SET_I(((Export *) Arg(0))->address); + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); dis_next = (Eterm *) *I; FCALLS--; @@ -5911,7 +5664,8 @@ call_error_handler(Process* p, BeamInstr* fi, Eterm* reg, Eterm func) /* * Search for the error_handler module. */ - ep = erts_find_function(erts_proc_get_error_handler(p), func, 3); + ep = erts_find_function(erts_proc_get_error_handler(p), func, 3, + erts_active_code_ix()); if (ep == NULL) { /* No error handler */ p->current = fi; p->freason = EXC_UNDEF; @@ -5941,7 +5695,7 @@ call_error_handler(Process* p, BeamInstr* fi, Eterm* reg, Eterm func) reg[0] = fi[0]; reg[1] = fi[1]; reg[2] = args; - return ep->address; + return ep->addressv[erts_active_code_ix()]; } @@ -5955,7 +5709,7 @@ apply_setup_error_handler(Process* p, Eterm module, Eterm function, Uint arity, * there is no error handler module. */ - if ((ep = erts_find_export_entry(erts_proc_get_error_handler(p), + if ((ep = erts_active_export_entry(erts_proc_get_error_handler(p), am_undefined_function, 3)) == NULL) { return NULL; } else { @@ -6062,7 +5816,7 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) * Note: All BIFs have export entries; thus, no special case is needed. */ - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { if ((ep = apply_setup_error_handler(p, module, function, arity, reg)) == NULL) goto error; } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) { save_calls(p, ep); @@ -6070,11 +5824,11 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) #ifdef USE_VM_CALL_PROBES if (DTRACE_ENABLED(global_function_entry)) { - BeamInstr *fptr = (BeamInstr *) ep->address; + BeamInstr *fptr = (BeamInstr *) ep->addressv[erts_active_code_ix()]; DTRACE_GLOBAL_CALL(p, (Eterm)fptr[-3], (Eterm)fptr[-2], (Uint)fptr[-1]); } #endif - return ep->address; + return ep->addressv[erts_active_code_ix()]; } static BeamInstr* @@ -6116,7 +5870,7 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) * Note: All BIFs have export entries; thus, no special case is needed. */ - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { if ((ep = apply_setup_error_handler(p, module, function, arity, reg)) == NULL) goto error; } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) { @@ -6125,11 +5879,11 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) #ifdef USE_VM_CALL_PROBES if (DTRACE_ENABLED(global_function_entry)) { - BeamInstr *fptr = (BeamInstr *) ep->address; + BeamInstr *fptr = (BeamInstr *) ep->addressv[erts_active_code_ix()]; DTRACE_GLOBAL_CALL(p, (Eterm)fptr[-3], (Eterm)fptr[-2], (Uint)fptr[-1]); } #endif - return ep->address; + return ep->addressv[erts_active_code_ix()]; } int @@ -6206,9 +5960,7 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re */ erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p); - if (c_p->msg.len > 0) { - erts_add_to_runq(c_p); - } else { + if (!c_p->msg.len) { erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); c_p->fvalue = NIL; PROCESS_MAIN_CHK_LOCKS(c_p); @@ -6216,14 +5968,12 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); - ASSERT(!ERTS_PROC_IS_EXITING(c_p)); #ifdef ERTS_SMP ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p); - if (c_p->msg.len > 0) - erts_add_to_runq(c_p); - else + if (!c_p->msg.len) #endif - c_p->status = P_WAITING; + erts_smp_atomic32_read_band_relb(&c_p->state, ~ERTS_PSFLG_ACTIVE); + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); } erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); c_p->current = bif_export[BIF_hibernate_3]->code; @@ -6311,7 +6061,7 @@ call_fun(Process* p, /* Current process. */ Export* ep; Module* modp; Eterm module; - + ErtsCodeIndex code_ix = erts_active_code_ix(); /* * No arity. There is no module loaded that defines the fun, @@ -6319,9 +6069,9 @@ call_fun(Process* p, /* Current process. */ * representation (the module has never been loaded), * or the module defining the fun has been unloaded. */ - module = fe->module; - if ((modp = erts_get_module(module)) != NULL && modp->code != NULL) { + if ((modp = erts_get_module(module, code_ix)) != NULL + && modp->curr.code != NULL) { /* * There is a module loaded, but obviously the fun is not * defined in it. We must not call the error_handler @@ -6336,7 +6086,7 @@ call_fun(Process* p, /* Current process. */ */ ep = erts_find_function(erts_proc_get_error_handler(p), - am_undefined_lambda, 3); + am_undefined_lambda, 3, code_ix); if (ep == NULL) { /* No error handler */ p->current = NULL; p->freason = EXC_UNDEF; @@ -6346,7 +6096,7 @@ call_fun(Process* p, /* Current process. */ reg[1] = fun; reg[2] = args; reg[3] = NIL; - return ep->address; + return ep->addressv[erts_active_code_ix()]; } } } else if (is_export_header(hdr)) { @@ -6358,7 +6108,7 @@ call_fun(Process* p, /* Current process. */ if (arity == actual_arity) { DTRACE_GLOBAL_CALL(p, ep->code[0], ep->code[1], (Uint)ep->code[2]); - return ep->address; + return ep->addressv[erts_active_code_ix()]; } else { /* * Wrong arity. First build a list of the arguments. @@ -6409,8 +6159,8 @@ call_fun(Process* p, /* Current process. */ erts_send_warning_to_logger(p->group_leader, dsbufp); } - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { - ep = erts_find_export_entry(erts_proc_get_error_handler(p), + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { + ep = erts_active_export_entry(erts_proc_get_error_handler(p), am_undefined_function, 3); if (ep == NULL) { p->freason = EXC_UNDEF; @@ -6434,7 +6184,7 @@ call_fun(Process* p, /* Current process. */ reg[2] = args; } DTRACE_GLOBAL_CALL(p, module, function, arity); - return ep->address; + return ep->addressv[erts_active_code_ix()]; } else { badfun: p->current = NULL; @@ -6537,7 +6287,8 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity) if ((ep = export_get(&e)) == NULL) { return 0; } - return ep->address == ep->code+3 && (ep->code[3] == (BeamInstr) em_apply_bif); + return ep->addressv[erts_active_code_ix()] == ep->code+3 + && (ep->code[3] == (BeamInstr) em_apply_bif); } diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index dd788df6e4..d3f55a2ba4 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -352,27 +352,6 @@ typedef struct LoaderState { int loc_size; /* Size of location info in bytes (2/4) */ } LoaderState; -/* - * Layout of the line table. - */ - -#define MI_LINE_FNAME_PTR 0 -#define MI_LINE_LOC_TAB 1 -#define MI_LINE_LOC_SIZE 2 -#define MI_LINE_FUNC_TAB 3 - -#define LINE_INVALID_LOCATION (0) - -/* - * Macros for manipulating locations. - */ - -#define IS_VALID_LOCATION(File, Line) \ - ((unsigned) (File) < 255 && (unsigned) (Line) < ((1 << 24) - 1)) -#define MAKE_LOCATION(File, Line) (((File) << 24) | (Line)) -#define LOC_FILE(Loc) ((Loc) >> 24) -#define LOC_LINE(Loc) ((Loc) & ((1 << 24)-1)) - #define GetTagAndValue(Stp, Tag, Val) \ do { \ BeamInstr __w; \ @@ -496,7 +475,8 @@ typedef struct LoaderState { } while (0) -static void free_state(LoaderState* stp); +static void free_loader_state(Binary* magic); +static void loader_state_dtor(Binary* magic); static Eterm insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, Eterm module, BeamInstr* code, Uint size); @@ -507,6 +487,7 @@ static int verify_chunks(LoaderState* stp); static int load_atom_table(LoaderState* stp); static int load_import_table(LoaderState* stp); static int read_export_table(LoaderState* stp); +static int is_bif(Eterm mod, Eterm func, unsigned arity); static int read_lambda_table(LoaderState* stp); static int read_literal_table(LoaderState* stp); static int read_line_table(LoaderState* stp); @@ -548,22 +529,9 @@ static Eterm native_addresses(Process* p, Eterm mod); int patch_funentries(Eterm Patchlist); int patch(Eterm Addresses, Uint fe); static int safe_mul(UWord a, UWord b, UWord* resp); -static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, - BeamInstr* modp, int idx); - static int must_swap_floats; -/* - * The following variables keep a sorted list of address ranges for - * each module. It allows us to quickly find a function given an - * instruction pointer. - */ -Range* modules = NULL; /* Sorted lists of module addresses. */ -int num_loaded_modules; /* Number of loaded modules. */ -int allocated_modules; /* Number of slots allocated. */ -Range* mid_module = NULL; /* Cached search start point */ - Uint erts_total_code_size; /**********************************************************************/ @@ -579,11 +547,7 @@ void init_load(void) f.fd = 1.0; must_swap_floats = (f.fw[0] == 0); - allocated_modules = 128; - modules = (Range *) erts_alloc(ERTS_ALC_T_MODULE_REFS, - allocated_modules*sizeof(Range)); - mid_module = modules; - num_loaded_modules = 0; + erts_init_ranges(); } static void @@ -595,7 +559,7 @@ define_file(LoaderState* stp, char* name, int idx) } Eterm -erts_load_module(Process *c_p, +erts_preload_module(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, /* Group leader or NIL if none. */ Eterm* modp, /* @@ -605,15 +569,16 @@ erts_load_module(Process *c_p, byte* code, /* Points to the code to load */ Uint size) /* Size of code to load. */ { - LoaderState* stp = erts_alloc_loader_state(); + Binary* magic = erts_alloc_loader_state(); Eterm retval; - retval = erts_prepare_loading(stp, c_p, group_leader, modp, + ASSERT(!erts_initialized); + retval = erts_prepare_loading(magic, c_p, group_leader, modp, code, size); if (retval != NIL) { return retval; } - return erts_finish_loading(stp, c_p, c_p_locks, modp); + return erts_finish_loading(magic, c_p, c_p_locks, modp); } /* #define LOAD_MEMORY_HARD_DEBUG 1*/ @@ -629,11 +594,13 @@ extern void check_allocated_block(Uint type, void *blk); #endif Eterm -erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, +erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint unloaded_size) { Eterm retval = am_badfile; + LoaderState* stp; + stp = ERTS_MAGIC_BIN_DATA(magic); stp->module = *modp; stp->group_leader = group_leader; @@ -666,7 +633,7 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, /* * Initialize code area. */ - stp->code_buffer_size = erts_next_heap_size(2048 + stp->num_functions, 0); + stp->code_buffer_size = 2048 + stp->num_functions; stp->code = (BeamInstr *) erts_alloc(ERTS_ALC_T_CODE, sizeof(BeamInstr) * stp->code_buffer_size); @@ -679,8 +646,6 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, stp->code[MI_COMPILE_PTR] = 0; stp->code[MI_COMPILE_SIZE] = 0; stp->code[MI_COMPILE_SIZE_ON_HEAP] = 0; - stp->code[MI_NUM_BREAKPOINTS] = 0; - /* * Read the atom table. @@ -774,23 +739,24 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, load_error: if (retval != NIL) { - free_state(stp); + free_loader_state(magic); } return retval; } Eterm -erts_finish_loading(LoaderState* stp, Process* c_p, +erts_finish_loading(Binary* magic, Process* c_p, ErtsProcLocks c_p_locks, Eterm* modp) { Eterm retval; + LoaderState* stp = ERTS_MAGIC_BIN_DATA(magic); /* * No other process may run since we will update the export * table which is not protected by any locks. */ - ERTS_SMP_LC_ASSERT(erts_initialized == 0 || + ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_is_code_ix_locked() || erts_smp_thr_progress_is_blocking()); /* @@ -811,7 +777,6 @@ erts_finish_loading(LoaderState* stp, Process* c_p, * exported and imported functions. This can't fail. */ - erts_export_consolidate(); CHKBLK(ERTS_ALC_T_CODE,stp->code); final_touch(stp); @@ -837,16 +802,20 @@ erts_finish_loading(LoaderState* stp, Process* c_p, } load_error: - free_state(stp); + free_loader_state(magic); return retval; } -LoaderState* +Binary* erts_alloc_loader_state(void) { LoaderState* stp; + Binary* magic; - stp = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(LoaderState)); + magic = erts_create_magic_binary(sizeof(LoaderState), + loader_state_dtor); + erts_refc_inc(&magic->refc, 1); + stp = ERTS_MAGIC_BIN_DATA(magic); stp->bin = NULL; stp->function = THE_NON_VALUE; /* Function not known yet */ stp->arity = 0; @@ -875,76 +844,123 @@ erts_alloc_loader_state(void) stp->line_instr = 0; stp->func_line = 0; stp->fname = 0; - return stp; + return magic; +} + +/* + * Return the module name (a tagged atom) for the prepared code + * in the magic binary, or NIL if the binary does not contain + * prepared code. + */ +Eterm +erts_module_for_prepared_code(Binary* magic) +{ + LoaderState* stp; + + if (ERTS_MAGIC_BIN_DESTRUCTOR(magic) != loader_state_dtor) { + return NIL; + } + stp = ERTS_MAGIC_BIN_DATA(magic); + if (stp->code != 0) { + return stp->module; + } else { + return NIL; + } } static void -free_state(LoaderState* stp) +free_loader_state(Binary* magic) { + loader_state_dtor(magic); + if (erts_refc_dectest(&magic->refc, 0) == 0) { + erts_bin_free(magic); + } +} + +/* + * This destructor function can safely be called multiple times. + */ +static void +loader_state_dtor(Binary* magic) +{ + LoaderState* stp = ERTS_MAGIC_BIN_DATA(magic); + if (stp->bin != 0) { driver_free_binary(stp->bin); + stp->bin = 0; } if (stp->code != 0) { erts_free(ERTS_ALC_T_CODE, stp->code); + stp->code = 0; } - if (stp->labels != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->labels); + if (stp->labels != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->labels); + stp->labels = 0; } - if (stp->atom != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->atom); + if (stp->atom != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->atom); + stp->atom = 0; } - if (stp->import != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->import); + if (stp->import != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->import); + stp->import = 0; } - if (stp->export != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->export); + if (stp->export != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->export); + stp->export = 0; } if (stp->lambdas != stp->def_lambdas) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->lambdas); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->lambdas); + stp->lambdas = stp->def_lambdas; } - if (stp->literals != NULL) { + if (stp->literals != 0) { int i; for (i = 0; i < stp->num_literals; i++) { - if (stp->literals[i].heap != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, + if (stp->literals[i].heap != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals[i].heap); + stp->literals[i].heap = 0; } } - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->literals); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals); + stp->literals = 0; } - while (stp->literal_patches != NULL) { + while (stp->literal_patches != 0) { LiteralPatch* next = stp->literal_patches->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->literal_patches); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literal_patches); stp->literal_patches = next; } - while (stp->string_patches != NULL) { + while (stp->string_patches != 0) { StringPatch* next = stp->string_patches->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->string_patches); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->string_patches); stp->string_patches = next; } - while (stp->genop_blocks) { - GenOpBlock* next = stp->genop_blocks->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->genop_blocks); - stp->genop_blocks = next; - } if (stp->line_item != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->line_item); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->line_item); + stp->line_item = 0; } if (stp->line_instr != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->line_instr); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->line_instr); + stp->line_instr = 0; } if (stp->func_line != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->func_line); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->func_line); + stp->func_line = 0; } if (stp->fname != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->fname); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->fname); + stp->fname = 0; } - erts_free(ERTS_ALC_T_LOADER_TMP, stp); + /* + * The following data items should have been freed earlier. + */ + + ASSERT(stp->genop_blocks == 0); } static Eterm @@ -954,7 +970,6 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, { Module* modp; Eterm retval; - int i; if ((retval = beam_make_current_old(c_p, c_p_locks, module)) != NIL) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); @@ -971,30 +986,15 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, erts_total_code_size += size; modp = erts_put_module(module); - modp->code = code; - modp->code_length = size; - modp->catches = BEAM_CATCHES_NIL; /* Will be filled in later. */ + modp->curr.code = code; + modp->curr.code_length = size; + modp->curr.catches = BEAM_CATCHES_NIL; /* Will be filled in later. */ /* - * Update address table (used for finding a function from a PC value). + * Update ranges (used for finding a function from a PC value). */ - if (num_loaded_modules == allocated_modules) { - allocated_modules *= 2; - modules = (Range *) erts_realloc(ERTS_ALC_T_MODULE_REFS, - (void *) modules, - allocated_modules * sizeof(Range)); - } - for (i = num_loaded_modules; i > 0; i--) { - if (code > modules[i-1].start) { - break; - } - modules[i] = modules[i-1]; - } - modules[i].start = code; - modules[i].end = (BeamInstr *) (((byte *)code) + size); - num_loaded_modules++; - mid_module = &modules[num_loaded_modules/2]; + erts_update_ranges(code, size); return NIL; } @@ -1217,9 +1217,8 @@ load_atom_table(LoaderState* stp) GetInt(stp, 4, stp->num_atoms); stp->num_atoms++; - stp->atom = erts_alloc(ERTS_ALC_T_LOADER_TMP, - erts_next_heap_size((stp->num_atoms*sizeof(Eterm)), - 0)); + stp->atom = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + stp->num_atoms*sizeof(Eterm)); /* * Read all atoms. @@ -1263,10 +1262,8 @@ load_import_table(LoaderState* stp) int i; GetInt(stp, 4, stp->num_imports); - stp->import = erts_alloc(ERTS_ALC_T_LOADER_TMP, - erts_next_heap_size((stp->num_imports * - sizeof(ImportEntry)), - 0)); + stp->import = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + stp->num_imports * sizeof(ImportEntry)); for (i = 0; i < stp->num_imports; i++) { int n; Eterm mod; @@ -1296,7 +1293,7 @@ load_import_table(LoaderState* stp) * If the export entry refers to a BIF, get the pointer to * the BIF function. */ - if ((e = erts_find_export_entry(mod, func, arity)) != NULL) { + if ((e = erts_active_export_entry(mod, func, arity)) != NULL) { if (e->code[3] == (BeamInstr) em_apply_bif) { stp->import[i].bf = (BifFunction) e->code[4]; if (func == am_load_nif && mod == am_erlang && arity == 2) { @@ -1315,16 +1312,8 @@ load_import_table(LoaderState* stp) static int read_export_table(LoaderState* stp) { - static struct { - Eterm mod; - Eterm func; - int arity; - } allow_redef[] = { - /* The BIFs that are allowed to be redefined by Erlang code */ - {am_erlang,am_apply,2}, - {am_erlang,am_apply,3}, - }; int i; + BeamInstr* address; GetInt(stp, 4, stp->num_exps); if (stp->num_exps > stp->num_functions) { @@ -1332,7 +1321,7 @@ read_export_table(LoaderState* stp) stp->num_exps, stp->num_functions); } stp->export - = (ExportEntry *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + = (ExportEntry *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, (stp->num_exps * sizeof(ExportEntry))); for (i = 0; i < stp->num_exps; i++) { @@ -1340,7 +1329,6 @@ read_export_table(LoaderState* stp) Uint value; Eterm func; Uint arity; - Export* e; GetInt(stp, 4, n); GetAtom(stp, n, func); @@ -1358,29 +1346,34 @@ read_export_table(LoaderState* stp) if (value == 0) { LoadError2(stp, "export table entry %d: label %d not resolved", i, n); } - stp->export[i].address = stp->code + value; + stp->export[i].address = address = stp->code + value; /* - * Check that we are not redefining a BIF (except the ones allowed to - * redefine). + * Find out if there is a BIF with the same name. */ - if ((e = erts_find_export_entry(stp->module, func, arity)) != NULL) { - if (e->code[3] == (BeamInstr) em_apply_bif) { - int j; - for (j = 0; j < sizeof(allow_redef)/sizeof(allow_redef[0]); j++) { - if (stp->module == allow_redef[j].mod && - func == allow_redef[j].func && - arity == allow_redef[j].arity) { - break; - } - } - if (j == sizeof(allow_redef)/sizeof(allow_redef[0])) { - LoadError2(stp, "exported function %T/%d redefines BIF", - func, arity); - } - } + if (!is_bif(stp->module, func, arity)) { + continue; + } + + /* + * This is a stub for a BIF. + * + * It should not be exported, and the information in its + * func_info instruction should be invalidated so that it + * can be filtered out by module_info(functions) and by + * any other functions that walk through all local functions. + */ + + if (stp->labels[n].patches) { + LoadError3(stp, "there are local calls to the stub for " + "the BIF %T:%T/%d", + stp->module, func, arity); } + stp->export[i].address = NULL; + address[-1] = 0; + address[-2] = NIL; + address[-3] = NIL; } return 1; @@ -1388,15 +1381,39 @@ read_export_table(LoaderState* stp) return 0; } + +static int +is_bif(Eterm mod, Eterm func, unsigned arity) +{ + Export* e = erts_active_export_entry(mod, func, arity); + if (e == NULL) { + return 0; + } + if (e->code[3] != (BeamInstr) em_apply_bif) { + return 0; + } + if (mod == am_erlang && func == am_apply && arity == 3) { + /* + * erlang:apply/3 is a special case -- it is implemented + * as an instruction and it is OK to redefine it. + */ + return 0; + } + return 1; +} + static int read_lambda_table(LoaderState* stp) { int i; GetInt(stp, 4, stp->num_lambdas); - stp->lambdas_allocated = stp->num_lambdas; - stp->lambdas = (Lambda *) erts_alloc(ERTS_ALC_T_LOADER_TMP, - stp->num_lambdas * sizeof(Lambda)); + if (stp->num_lambdas > stp->lambdas_allocated) { + ASSERT(stp->lambdas == stp->def_lambdas); + stp->lambdas_allocated = stp->num_lambdas; + stp->lambdas = (Lambda *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, + stp->num_lambdas * sizeof(Lambda)); + } for (i = 0; i < stp->num_lambdas; i++) { Uint n; Uint32 Index; @@ -1446,7 +1463,7 @@ read_literal_table(LoaderState* stp) stp->file_p = uncompressed; stp->file_left = (unsigned) uncompressed_sz; GetInt(stp, 4, stp->num_literals); - stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_literals * sizeof(Literal)); stp->allocated_literals = stp->num_literals; @@ -1466,7 +1483,7 @@ read_literal_table(LoaderState* stp) if ((heap_size = erts_decode_ext_size(p, sz)) < 0) { LoadError1(stp, "literal %d: bad external format", i); } - hp = stp->literals[i].heap = erts_alloc(ERTS_ALC_T_LOADER_TMP, + hp = stp->literals[i].heap = erts_alloc(ERTS_ALC_T_PREPARED_CODE, heap_size*sizeof(Eterm)); stp->literals[i].off_heap.first = 0; stp->literals[i].off_heap.overhead = 0; @@ -1538,7 +1555,7 @@ read_line_table(LoaderState* stp) */ num_line_items++; - lp = (BeamInstr *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + lp = (BeamInstr *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, num_line_items * sizeof(BeamInstr)); stp->line_item = lp; stp->num_line_items = num_line_items; @@ -1594,7 +1611,7 @@ read_line_table(LoaderState* stp) */ if (stp->num_fnames != 0) { - stp->fname = (Eterm *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->fname = (Eterm *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_fnames * sizeof(Eterm)); for (i = 0; i < stp->num_fnames; i++) { @@ -1610,11 +1627,11 @@ read_line_table(LoaderState* stp) /* * Allocate the arrays to be filled while code is being loaded. */ - stp->line_instr = (LineInstr *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->line_instr = (LineInstr *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_line_instrs * sizeof(LineInstr)); stp->current_li = 0; - stp->func_line = (int *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->func_line = (int *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_functions * sizeof(int)); @@ -1677,7 +1694,7 @@ read_code_header(LoaderState* stp) * Initialize label table. */ - stp->labels = (Label *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->labels = (Label *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_labels * sizeof(Label)); for (i = 0; i < stp->num_labels; i++) { stp->labels[i].value = 0; @@ -1703,9 +1720,9 @@ read_code_header(LoaderState* stp) #define CodeNeed(w) do { \ ASSERT(ci <= code_buffer_size); \ if (code_buffer_size < ci+(w)) { \ - code_buffer_size = erts_next_heap_size(ci+(w), 0); \ - stp->code = code \ - = (BeamInstr *) erts_realloc(ERTS_ALC_T_CODE, \ + code_buffer_size = 2*ci+(w); \ + stp->code = code = \ + (BeamInstr *) erts_realloc(ERTS_ALC_T_CODE, \ (void *) code, \ code_buffer_size * sizeof(BeamInstr)); \ } \ @@ -1731,6 +1748,7 @@ load_code(LoaderState* stp) GenOp* last_op = NULL; GenOp** last_op_next = NULL; int arity; + int retval = 1; /* * The size of the loaded func_info instruction is needed @@ -2457,7 +2475,11 @@ load_code(LoaderState* stp) case op_int_code_end: stp->code_buffer_size = code_buffer_size; stp->ci = ci; - return 1; + stp->function = THE_NON_VALUE; + stp->genop = NULL; + stp->specific_op = -1; + retval = 1; + goto cleanup; } /* @@ -2471,9 +2493,20 @@ load_code(LoaderState* stp) } } - load_error: - return 0; + retval = 0; + + cleanup: + /* + * Clean up everything that is not needed any longer. + */ + + while (stp->genop_blocks) { + GenOpBlock* next = stp->genop_blocks->next; + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->genop_blocks); + stp->genop_blocks = next; + } + return retval; } @@ -4265,24 +4298,31 @@ final_touch(LoaderState* stp) index = next; } modp = erts_put_module(stp->module); - modp->catches = catches; + modp->curr.catches = catches; /* * Export functions. */ for (i = 0; i < stp->num_exps; i++) { - Export* ep = erts_export_put(stp->module, stp->export[i].function, - stp->export[i].arity); + Export* ep; + BeamInstr* address = stp->export[i].address; + + if (address == NULL) { + /* Skip stub for a BIF */ + continue; + } + ep = erts_export_put(stp->module, stp->export[i].function, + stp->export[i].arity); if (!on_load) { - ep->address = stp->export[i].address; + ep->addressv[erts_staging_code_ix()] = address; } else { /* * Don't make any of the exported functions * callable yet. */ - ep->address = ep->code+3; - ep->code[4] = (BeamInstr) stp->export[i].address; + ep->addressv[erts_staging_code_ix()] = ep->code+3; + ep->code[4] = (BeamInstr) address; } } @@ -4926,7 +4966,7 @@ new_label(LoaderState* stp) int num = stp->num_labels; stp->num_labels++; - stp->labels = (Label *) erts_realloc(ERTS_ALC_T_LOADER_TMP, + stp->labels = (Label *) erts_realloc(ERTS_ALC_T_PREPARED_CODE, (void *) stp->labels, stp->num_labels * sizeof(Label)); stp->labels[num].value = 0; @@ -4937,7 +4977,8 @@ new_label(LoaderState* stp) static void new_literal_patch(LoaderState* stp, int pos) { - LiteralPatch* p = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(LiteralPatch)); + LiteralPatch* p = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + sizeof(LiteralPatch)); p->pos = pos; p->next = stp->literal_patches; stp->literal_patches = p; @@ -4946,7 +4987,7 @@ new_literal_patch(LoaderState* stp, int pos) static void new_string_patch(LoaderState* stp, int pos) { - StringPatch* p = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(StringPatch)); + StringPatch* p = erts_alloc(ERTS_ALC_T_PREPARED_CODE, sizeof(StringPatch)); p->pos = pos; p->next = stp->string_patches; stp->string_patches = p; @@ -4964,14 +5005,14 @@ new_literal(LoaderState* stp, Eterm** hpp, Uint heap_size) ASSERT(stp->num_literals == 0); stp->allocated_literals = 8; need = stp->allocated_literals * sizeof(Literal); - stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, need); } else if (stp->allocated_literals <= stp->num_literals) { Uint need; stp->allocated_literals *= 2; need = stp->allocated_literals * sizeof(Literal); - stp->literals = (Literal *) erts_realloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_realloc(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals, need); } @@ -4980,7 +5021,7 @@ new_literal(LoaderState* stp, Eterm** hpp, Uint heap_size) lit = stp->literals + stp->num_literals; lit->offset = 0; lit->heap_size = heap_size; - lit->heap = erts_alloc(ERTS_ALC_T_LOADER_TMP, heap_size*sizeof(Eterm)); + lit->heap = erts_alloc(ERTS_ALC_T_PREPARED_CODE, heap_size*sizeof(Eterm)); lit->term = make_boxed(lit->heap); lit->off_heap.first = 0; lit->off_heap.overhead = 0; @@ -4999,7 +5040,7 @@ erts_module_info_0(Process* p, Eterm module) return THE_NON_VALUE; } - if (erts_get_module(module) == NULL) { + if (erts_get_module(module, erts_active_code_ix()) == NULL) { return THE_NON_VALUE; } @@ -5054,32 +5095,43 @@ functions_in_module(Process* p, /* Process whose heap to use. */ BeamInstr* code; int i; Uint num_functions; + Uint need; Eterm* hp; + Eterm* hp_end; Eterm result = NIL; if (is_not_atom(mod)) { return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; num_functions = code[MI_NUM_FUNCTIONS]; - hp = HAlloc(p, 5*num_functions); + need = 5*num_functions; + hp = HAlloc(p, need); + hp_end = hp + need; for (i = num_functions-1; i >= 0 ; i--) { BeamInstr* func_info = (BeamInstr *) code[MI_FUNCTIONS+i]; Eterm name = (Eterm) func_info[3]; int arity = (int) func_info[4]; Eterm tuple; - ASSERT(is_atom(name)); - tuple = TUPLE2(hp, name, make_small(arity)); - hp += 3; - result = CONS(hp, tuple, result); - hp += 2; + /* + * If the function name is [], this entry is a stub for + * a BIF that should be ignored. + */ + ASSERT(is_atom(name) || is_nil(name)); + if (is_atom(name)) { + tuple = TUPLE2(hp, name, make_small(arity)); + hp += 3; + result = CONS(hp, tuple, result); + hp += 2; + } } + HRelease(p, hp_end, hp); return result; } @@ -5106,12 +5158,12 @@ native_addresses(Process* p, Eterm mod) return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; num_functions = code[MI_NUM_FUNCTIONS]; need = (6+BIG_UINT_HEAP_SIZE)*num_functions; hp = HAlloc(p, need); @@ -5122,9 +5174,11 @@ native_addresses(Process* p, Eterm mod) int arity = (int) func_info[4]; Eterm tuple; - ASSERT(is_atom(name)); + ASSERT(is_atom(name) || is_nil(name)); /* [] if BIF stub */ if (func_info[1] != 0) { - Eterm addr = erts_bld_uint(&hp, NULL, func_info[1]); + Eterm addr; + ASSERT(is_atom(name)); + addr = erts_bld_uint(&hp, NULL, func_info[1]); tuple = erts_bld_tuple(&hp, NULL, 3, name, make_small(arity), addr); result = erts_bld_cons(&hp, NULL, tuple, result); } @@ -5149,18 +5203,20 @@ exported_from_module(Process* p, /* Process whose heap to use. */ Eterm* hp = NULL; Eterm* hend = NULL; Eterm result = NIL; + ErtsCodeIndex code_ix; if (is_not_atom(mod)) { return THE_NON_VALUE; } - for (i = 0; i < export_list_size(); i++) { - Export* ep = export_list(i); + code_ix = erts_active_code_ix(); + for (i = 0; i < export_list_size(code_ix); i++) { + Export* ep = export_list(i,code_ix); if (ep->code[0] == mod) { Eterm tuple; - if (ep->address == ep->code+3 && + if (ep->addressv[code_ix] == ep->code+3 && ep->code[3] == (BeamInstr) em_call_error_handler) { /* There is a call to the function, but it does not exist. */ continue; @@ -5204,11 +5260,11 @@ attributes_for_module(Process* p, /* Process whose heap to use. */ return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; ext = (byte *) code[MI_ATTR_PTR]; if (ext != NULL) { hp = HAlloc(p, code[MI_ATTR_SIZE_ON_HEAP]); @@ -5244,11 +5300,11 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; ext = (byte *) code[MI_COMPILE_PTR]; if (ext != NULL) { hp = HAlloc(p, code[MI_COMPILE_SIZE_ON_HEAP]); @@ -5263,113 +5319,6 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ } /* - * Find a function from the given pc and fill information in - * the FunctionInfo struct. If the full_info is non-zero, fill - * in all available information (including location in the - * source code). If no function is found, the 'current' field - * will be set to NULL. - */ - -void -erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info) -{ - Range* low = modules; - Range* high = low + num_loaded_modules; - Range* mid = mid_module; - - fi->current = NULL; - fi->needed = 5; - fi->loc = LINE_INVALID_LOCATION; - while (low < high) { - if (pc < mid->start) { - high = mid; - } else if (pc > mid->end) { - low = mid + 1; - } else { - BeamInstr** low1 = (BeamInstr **) (mid->start + MI_FUNCTIONS); - BeamInstr** high1 = low1 + mid->start[MI_NUM_FUNCTIONS]; - BeamInstr** mid1; - - while (low1 < high1) { - mid1 = low1 + (high1-low1) / 2; - if (pc < mid1[0]) { - high1 = mid1; - } else if (pc < mid1[1]) { - mid_module = mid; - fi->current = mid1[0]+2; - if (full_info) { - BeamInstr** fp = (BeamInstr **) (mid->start + - MI_FUNCTIONS); - int idx = mid1 - fp; - lookup_loc(fi, pc, mid->start, idx); - } - return; - } else { - low1 = mid1 + 1; - } - } - return; - } - mid = low + (high-low) / 2; - } -} - -static void -lookup_loc(FunctionInfo* fi, BeamInstr* orig_pc, BeamInstr* modp, int idx) -{ - Eterm* line = (Eterm *) modp[MI_LINE_TABLE]; - Eterm* low; - Eterm* high; - Eterm* mid; - Eterm pc; - - if (line == 0) { - return; - } - - pc = (Eterm) (BeamInstr) orig_pc; - fi->fname_ptr = (Eterm *) (BeamInstr) line[MI_LINE_FNAME_PTR]; - low = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx]; - high = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx+1]; - while (high > low) { - mid = low + (high-low) / 2; - if (pc < mid[0]) { - high = mid; - } else if (pc < mid[1]) { - int file; - int index = mid - (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB]; - - if (line[MI_LINE_LOC_SIZE] == 2) { - Uint16* loc_table = - (Uint16 *) (BeamInstr) line[MI_LINE_LOC_TAB]; - fi->loc = loc_table[index]; - } else { - Uint32* loc_table = - (Uint32 *) (BeamInstr) line[MI_LINE_LOC_TAB]; - ASSERT(line[MI_LINE_LOC_SIZE] == 4); - fi->loc = loc_table[index]; - } - if (fi->loc == LINE_INVALID_LOCATION) { - return; - } - fi->needed += 3+2+3+2; - file = LOC_FILE(fi->loc); - if (file == 0) { - /* Special case: Module name with ".erl" appended */ - Atom* mod_atom = atom_tab(atom_val(fi->current[0])); - fi->needed += 2*(mod_atom->len+4); - } else { - Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); - fi->needed += 2*ap->len; - } - return; - } else { - low = mid + 1; - } - } -} - -/* * Build a single {M,F,A,Loction} item to be part of * a stack trace. */ @@ -5449,6 +5398,7 @@ code_get_chunk_2(BIF_ALIST_2) Process* p = BIF_P; Eterm Bin = BIF_ARG_1; Eterm Chunk = BIF_ARG_2; + Binary* magic = 0; LoaderState* stp; Uint chunk = 0; ErlSubBin* sb; @@ -5461,12 +5411,13 @@ code_get_chunk_2(BIF_ALIST_2) Eterm real_bin; byte* temp_alloc = NULL; - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if ((start = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { error: erts_free_aligned_binary_bytes(temp_alloc); - if (stp) { - free_state(stp); + if (magic) { + free_loader_state(magic); } BIF_ERROR(p, BADARG); } @@ -5511,7 +5462,7 @@ code_get_chunk_2(BIF_ALIST_2) done: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return res; } @@ -5524,14 +5475,16 @@ code_module_md5_1(BIF_ALIST_1) { Process* p = BIF_P; Eterm Bin = BIF_ARG_1; + Binary* magic; LoaderState* stp; byte* bytes; byte* temp_alloc = NULL; Eterm res; - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if ((bytes = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { - free_state(stp); + free_loader_state(magic); BIF_ERROR(p, BADARG); } stp->module = THE_NON_VALUE; /* Suppress diagnostiscs */ @@ -5545,7 +5498,7 @@ code_module_md5_1(BIF_ALIST_1) done: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return res; } @@ -5601,7 +5554,7 @@ stub_read_export_table(LoaderState* stp) stp->num_exps, stp->num_functions); } stp->export - = (ExportEntry *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + = (ExportEntry *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_exps * sizeof(ExportEntry)); for (i = 0; i < stp->num_exps; i++) { @@ -5627,20 +5580,29 @@ stub_final_touch(LoaderState* stp, BeamInstr* fp) { int i; int n = stp->num_exps; + Eterm mod = fp[2]; Eterm function = fp[3]; int arity = fp[4]; #ifdef HIPE Lambda* lp; #endif + if (is_bif(mod, function, arity)) { + fp[1] = 0; + fp[2] = 0; + fp[3] = 0; + fp[4] = 0; + return; + } + /* * Test if the function should be exported. */ for (i = 0; i < n; i++) { if (stp->export[i].function == function && stp->export[i].arity == arity) { - Export* ep = erts_export_put(fp[2], function, arity); - ep->address = fp+5; + Export* ep = erts_export_put(mod, function, arity); + ep->addressv[erts_staging_code_ix()] = fp+5; return; } } @@ -5819,6 +5781,7 @@ patch_funentries(Eterm Patchlist) Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) { + Binary* magic; LoaderState* stp; BeamInstr Funcs; BeamInstr Patchlist; @@ -5840,7 +5803,8 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) * Must initialize stp->lambdas here because the error handling code * at label 'error' uses it. */ - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if (is_not_atom(Mod)) { goto error; @@ -5920,7 +5884,6 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) code[MI_COMPILE_PTR] = 0; code[MI_COMPILE_SIZE] = 0; code[MI_COMPILE_SIZE_ON_HEAP] = 0; - code[MI_NUM_BREAKPOINTS] = 0; code[MI_LITERALS_START] = 0; code[MI_LITERALS_END] = 0; code[MI_LITERALS_OFF_HEAP] = 0; @@ -6028,13 +5991,13 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) if (patch_funentries(Patchlist)) { erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return Mod; } error: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); BIF_ERROR(p, BADARG); } @@ -6051,3 +6014,4 @@ static int safe_mul(UWord a, UWord b, UWord* resp) return (res / b) == a; } } + diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index 997ba197db..1048f258a5 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -49,11 +49,6 @@ extern void** beam_ops; extern BeamInstr beam_debug_apply[]; extern BeamInstr* em_call_error_handler; extern BeamInstr* em_apply_bif; -extern BeamInstr* em_call_traced_function; -typedef struct { - BeamInstr* start; /* Pointer to start of module. */ - BeamInstr* end; /* Points one word beyond last function in module. */ -} Range; /* * The following variables keep a sorted list of address ranges for @@ -61,11 +56,6 @@ typedef struct { * instruction pointer. */ -extern Range* modules; -extern int num_loaded_modules; -extern int allocated_modules; -extern Range* mid_module; - /* Total code size in bytes */ extern Uint erts_total_code_size; /* @@ -94,27 +84,22 @@ extern Uint erts_total_code_size; #define MI_COMPILE_SIZE_ON_HEAP 6 /* - * Number of breakpoints in module is stored in this word - */ -#define MI_NUM_BREAKPOINTS 7 - -/* * Literal area (constant pool). */ -#define MI_LITERALS_START 8 -#define MI_LITERALS_END 9 -#define MI_LITERALS_OFF_HEAP 10 +#define MI_LITERALS_START 7 +#define MI_LITERALS_END 8 +#define MI_LITERALS_OFF_HEAP 9 /* * Pointer to the on_load function (or NULL if none). */ -#define MI_ON_LOAD_FUNCTION_PTR 11 +#define MI_ON_LOAD_FUNCTION_PTR 10 /* * Pointer to the line table (or NULL if none). */ -#define MI_LINE_TABLE 12 +#define MI_LINE_TABLE 11 /* * Start of function pointer table. This table contains pointers to @@ -125,5 +110,27 @@ extern Uint erts_total_code_size; * this table. */ -#define MI_FUNCTIONS 13 +#define MI_FUNCTIONS 12 + +/* + * Layout of the line table. + */ + +#define MI_LINE_FNAME_PTR 0 +#define MI_LINE_LOC_TAB 1 +#define MI_LINE_LOC_SIZE 2 +#define MI_LINE_FUNC_TAB 3 + +#define LINE_INVALID_LOCATION (0) + +/* + * Macros for manipulating locations. + */ + +#define IS_VALID_LOCATION(File, Line) \ + ((unsigned) (File) < 255 && (unsigned) (Line) < ((1 << 24) - 1)) +#define MAKE_LOCATION(File, Line) (((File) << 24) | (Line)) +#define LOC_FILE(Loc) ((Loc) >> 24) +#define LOC_LINE(Loc) ((Loc) & ((1 << 24)-1)) + #endif /* _BEAM_LOAD_H */ diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c new file mode 100644 index 0000000000..0f2d5d0c2a --- /dev/null +++ b/erts/emulator/beam/beam_ranges.c @@ -0,0 +1,349 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sys.h" +#include "erl_vm.h" +#include "global.h" +#include "beam_load.h" + +typedef struct { + BeamInstr* start; /* Pointer to start of module. */ + erts_smp_atomic_t end; /* (BeamInstr*) Points one word beyond last function in module. */ +} Range; + +/* Range 'end' needs to be atomic as we purge module + by setting end=start in active code_ix */ +#define RANGE_END(R) ((BeamInstr*)erts_smp_atomic_read_nob(&(R)->end)) + +static Range* find_range(BeamInstr* pc); +static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, + BeamInstr* modp, int idx); + +/* + * The following variables keep a sorted list of address ranges for + * each module. It allows us to quickly find a function given an + * instruction pointer. + */ +struct ranges { + Range* modules; /* Sorted lists of module addresses. */ + Sint n; /* Number of range entries. */ + Sint allocated; /* Number of allocated entries. */ + erts_smp_atomic_t mid; /* Cached search start point */ +}; +static struct ranges r[ERTS_NUM_CODE_IX]; +static erts_smp_atomic_t mem_used; + +#ifdef HARD_DEBUG +static void check_consistency(struct ranges* p) +{ + int i; + + ASSERT(p->n <= p->allocated); + ASSERT((Uint)(p->mid - p->modules) < p->n || + (p->mid == p->modules && p->n == 0)); + for (i = 0; i < p->n; i++) { + ASSERT(p->modules[i].start <= RANGE_END(&p->modules[i])); + ASSERT(!i || RANGE_END(&p->modules[i-1]) < p->modules[i].start); + } +} +# define CHECK(r) check_consistency(r) +#else +# define CHECK(r) +#endif /* HARD_DEBUG */ + + +void +erts_init_ranges(void) +{ + Sint i; + + erts_smp_atomic_init_nob(&mem_used, 0); + for (i = 0; i < ERTS_NUM_CODE_IX; i++) { + r[i].modules = 0; + r[i].n = 0; + r[i].allocated = 0; + erts_smp_atomic_init_nob(&r[i].mid, 0); + } +} + +void +erts_start_staging_ranges(void) +{ + ErtsCodeIndex dst = erts_staging_code_ix(); + + if (r[dst].modules) { + erts_smp_atomic_add_nob(&mem_used, -r[dst].allocated); + erts_free(ERTS_ALC_T_MODULE_REFS, r[dst].modules); + r[dst].modules = NULL; + } +} + +void +erts_end_staging_ranges(int commit) +{ + ErtsCodeIndex dst = erts_staging_code_ix(); + + if (commit && r[dst].modules == NULL) { + Sint i; + Sint n; + + /* No modules added, just clone src and remove purged code. */ + ErtsCodeIndex src = erts_active_code_ix(); + + erts_smp_atomic_add_nob(&mem_used, r[src].n); + r[dst].modules = erts_alloc(ERTS_ALC_T_MODULE_REFS, + r[src].n * sizeof(Range)); + r[dst].allocated = r[src].n; + n = 0; + for (i = 0; i < r[src].n; i++) { + Range* rp = r[src].modules+i; + if (rp->start < RANGE_END(rp)) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n] = *rp; + n++; + } + } + r[dst].n = n; + erts_smp_atomic_set_nob(&r[dst].mid, + (erts_aint_t) (r[dst].modules + n / 2)); + } +} + +void +erts_update_ranges(BeamInstr* code, Uint size) +{ + ErtsCodeIndex dst = erts_staging_code_ix(); + ErtsCodeIndex src = erts_active_code_ix(); + Sint i; + Sint n; + Sint need; + + if (src == dst) { + ASSERT(!erts_initialized); + + /* + * During start-up of system, the indices are the same. + * Handle this by faking a source area. + */ + src = (src+1) % ERTS_NUM_CODE_IX; + if (r[src].modules) { + erts_smp_atomic_add_nob(&mem_used, -r[src].allocated); + erts_free(ERTS_ALC_T_MODULE_REFS, r[src].modules); + } + r[src] = r[dst]; + r[dst].modules = 0; + } + + CHECK(&r[src]); + + ASSERT(r[dst].modules == NULL); + need = r[dst].allocated = r[src].n + 1; + erts_smp_atomic_add_nob(&mem_used, need); + r[dst].modules = (Range *) erts_alloc(ERTS_ALC_T_MODULE_REFS, + need * sizeof(Range)); + n = 0; + for (i = 0; i < r[src].n; i++) { + Range* rp = r[src].modules+i; + if (code < rp->start) { + r[dst].modules[n].start = code; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(((byte *)code) + size)); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < code); + n++; + break; + } + if (rp->start < RANGE_END(rp)) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n].start = rp->start; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(RANGE_END(rp))); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < rp->start); + n++; + } + } + + while (i < r[src].n) { + Range* rp = r[src].modules+i; + if (rp->start < RANGE_END(rp)) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n].start = rp->start; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(RANGE_END(rp))); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < rp->start); + n++; + } + i++; + } + + if (n == 0 || code > r[dst].modules[n-1].start) { + r[dst].modules[n].start = code; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(((byte *)code) + size)); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < code); + n++; + } + + ASSERT(n <= r[src].n+1); + r[dst].n = n; + erts_smp_atomic_set_nob(&r[dst].mid, + (erts_aint_t) (r[dst].modules + n / 2)); + + CHECK(&r[dst]); + CHECK(&r[src]); +} + +void +erts_remove_from_ranges(BeamInstr* code) +{ + Range* rp = find_range(code); + erts_smp_atomic_set_nob(&rp->end, (erts_aint_t)rp->start); +} + +UWord +erts_ranges_sz(void) +{ + return erts_smp_atomic_read_nob(&mem_used) * sizeof(Range); +} + +/* + * Find a function from the given pc and fill information in + * the FunctionInfo struct. If the full_info is non-zero, fill + * in all available information (including location in the + * source code). If no function is found, the 'current' field + * will be set to NULL. + */ + +void +erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info) +{ + BeamInstr** low; + BeamInstr** high; + BeamInstr** mid; + Range* rp; + + fi->current = NULL; + fi->needed = 5; + fi->loc = LINE_INVALID_LOCATION; + rp = find_range(pc); + if (rp == 0) { + return; + } + + low = (BeamInstr **) (rp->start + MI_FUNCTIONS); + high = low + rp->start[MI_NUM_FUNCTIONS]; + while (low < high) { + mid = low + (high-low) / 2; + if (pc < mid[0]) { + high = mid; + } else if (pc < mid[1]) { + fi->current = mid[0]+2; + if (full_info) { + BeamInstr** fp = (BeamInstr **) (rp->start + + MI_FUNCTIONS); + int idx = mid - fp; + lookup_loc(fi, pc, rp->start, idx); + } + return; + } else { + low = mid + 1; + } + } +} + +static Range* +find_range(BeamInstr* pc) +{ + ErtsCodeIndex active = erts_active_code_ix(); + Range* low = r[active].modules; + Range* high = low + r[active].n; + Range* mid = (Range *) erts_smp_atomic_read_nob(&r[active].mid); + + CHECK(&r[active]); + while (low < high) { + if (pc < mid->start) { + high = mid; + } else if (pc > RANGE_END(mid)) { + low = mid + 1; + } else { + erts_smp_atomic_set_nob(&r[active].mid, (erts_aint_t) mid); + return mid; + } + mid = low + (high-low) / 2; + } + return 0; +} + +static void +lookup_loc(FunctionInfo* fi, BeamInstr* orig_pc, BeamInstr* modp, int idx) +{ + Eterm* line = (Eterm *) modp[MI_LINE_TABLE]; + Eterm* low; + Eterm* high; + Eterm* mid; + Eterm pc; + + if (line == 0) { + return; + } + + pc = (Eterm) (BeamInstr) orig_pc; + fi->fname_ptr = (Eterm *) (BeamInstr) line[MI_LINE_FNAME_PTR]; + low = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx]; + high = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx+1]; + while (high > low) { + mid = low + (high-low) / 2; + if (pc < mid[0]) { + high = mid; + } else if (pc < mid[1]) { + int file; + int index = mid - (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB]; + + if (line[MI_LINE_LOC_SIZE] == 2) { + Uint16* loc_table = + (Uint16 *) (BeamInstr) line[MI_LINE_LOC_TAB]; + fi->loc = loc_table[index]; + } else { + Uint32* loc_table = + (Uint32 *) (BeamInstr) line[MI_LINE_LOC_TAB]; + ASSERT(line[MI_LINE_LOC_SIZE] == 4); + fi->loc = loc_table[index]; + } + if (fi->loc == LINE_INVALID_LOCATION) { + return; + } + fi->needed += 3+2+3+2; + file = LOC_FILE(fi->loc); + if (file == 0) { + /* Special case: Module name with ".erl" appended */ + Atom* mod_atom = atom_tab(atom_val(fi->current[0])); + fi->needed += 2*(mod_atom->len+4); + } else { + Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); + fi->needed += 2*ap->len; + } + return; + } else { + low = mid + 1; + } + } +} diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index fc00b42454..66f4259d20 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -233,15 +233,17 @@ BIF_RETTYPE link_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); - res_no_proc: - if (BIF_P->flags & F_TRAPEXIT) { - ErtsProcLocks locks = ERTS_PROC_LOCK_MAIN; - erts_deliver_exit_message(BIF_ARG_1, BIF_P, &locks, am_noproc, NIL); - erts_smp_proc_unlock(BIF_P, ~ERTS_PROC_LOCK_MAIN & locks); - BIF_RET(am_true); +res_no_proc: { + erts_aint32_t state = erts_smp_atomic32_read_nob(&BIF_P->state); + if (state & ERTS_PSFLG_TRAP_EXIT) { + ErtsProcLocks locks = ERTS_PROC_LOCK_MAIN; + erts_deliver_exit_message(BIF_ARG_1, BIF_P, &locks, am_noproc, NIL); + erts_smp_proc_unlock(BIF_P, ~ERTS_PROC_LOCK_MAIN & locks); + BIF_RET(am_true); + } + else + BIF_ERROR(BIF_P, EXC_NOPROC); } - else - BIF_ERROR(BIF_P, EXC_NOPROC); } #define ERTS_DEMONITOR_FALSE 2 @@ -1103,8 +1105,9 @@ BIF_RETTYPE hibernate_3(BIF_ALIST_3) if (erts_hibernate(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, reg)) { /* - * If hibernate succeeded, TRAP. The process will be suspended - * if status is P_WAITING or continue (if any message was in the queue). + * If hibernate succeeded, TRAP. The process will be wait in a + * hibernated state if its state is inactive (!ERTS_PSFLG_ACTIVE); + * otherwise, continue executing (if any message was in the queue). */ BIF_TRAP_CODE_PTR_(BIF_P, BIF_P->i); } @@ -1403,9 +1406,8 @@ BIF_RETTYPE exit_2(BIF_ALIST_2) } else { rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; - rp = erts_pid2proc_opt(BIF_P, ERTS_PROC_LOCK_MAIN, - BIF_ARG_1, rp_locks, - ERTS_P2P_FLG_SMP_INC_REFC); + rp = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN, + BIF_ARG_1, rp_locks); if (!rp) { BIF_RET(am_true); } @@ -1427,8 +1429,6 @@ BIF_RETTYPE exit_2(BIF_ALIST_2) rp_locks &= ~ERTS_PROC_LOCK_MAIN; if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); - if (rp != BIF_P) - erts_smp_proc_dec_refc(rp); #endif /* * We may have exited ourselves and may have to take action. @@ -1502,14 +1502,13 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2) BIF_RET(old_value); } else if (BIF_ARG_1 == am_priority) { - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_STATUS); old_value = erts_set_process_priority(BIF_P, BIF_ARG_2); - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_STATUS); if (old_value == THE_NON_VALUE) goto error; BIF_RET(old_value); } else if (BIF_ARG_1 == am_trap_exit) { + erts_aint32_t state; Uint trap_exit; if (BIF_ARG_2 == am_true) { trap_exit = 1; @@ -1524,59 +1523,52 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2) * For more info, see implementation of erts_send_exit_signal(). */ erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_STATUS); + ERTS_SMP_LC_ASSERT((ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS) + & erts_proc_lc_my_proc_locks(BIF_P)); ERTS_SMP_BIF_CHK_PENDING_EXIT(BIF_P, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); - old_value = ERTS_PROC_IS_TRAPPING_EXITS(BIF_P) ? am_true : am_false; - if (trap_exit) { - ERTS_PROC_SET_TRAP_EXIT(BIF_P); - } else { - ERTS_PROC_UNSET_TRAP_EXIT(BIF_P); - } + if (trap_exit) + state = erts_smp_atomic32_read_bor_nob(&BIF_P->state, + ERTS_PSFLG_TRAP_EXIT); + else + state = erts_smp_atomic32_read_band_nob(&BIF_P->state, + ~ERTS_PSFLG_TRAP_EXIT); + old_value = (state & ERTS_PSFLG_TRAP_EXIT) ? am_true : am_false; erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_STATUS); BIF_RET(old_value); } else if (BIF_ARG_1 == am_scheduler) { - int yield; - ErtsRunQueue *old; - ErtsRunQueue *new; + ErtsRunQueue *old, *new, *curr; Sint sched; + erts_aint32_t state; + if (!is_small(BIF_ARG_2)) goto error; sched = signed_val(BIF_ARG_2); if (sched < 0 || erts_no_schedulers < sched) goto error; - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_STATUS); - old = BIF_P->bound_runq; -#ifdef ERTS_SMP - ASSERT(!old || old == BIF_P->run_queue); -#endif - new = !sched ? NULL : erts_schedid2runq(sched); -#ifndef ERTS_SMP - yield = 0; -#else - if (new == old) - yield = 0; + + if (sched == 0) { + new = NULL; + state = erts_smp_atomic32_read_band_mb(&BIF_P->state, + ~ERTS_PSFLG_BOUND); + } else { - ErtsRunQueue *curr = BIF_P->run_queue; - if (!new) - erts_smp_runq_lock(curr); - else - erts_smp_runqs_lock(curr, new); - yield = new && BIF_P->run_queue != new; -#endif - BIF_P->bound_runq = new; + new = erts_schedid2runq(sched); #ifdef ERTS_SMP - if (new) - BIF_P->run_queue = new; - if (!new) - erts_smp_runq_unlock(curr); - else - erts_smp_runqs_unlock(curr, new); - } + erts_atomic_set_nob(&BIF_P->run_queue, (erts_aint_t) new); #endif - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_STATUS); + state = erts_smp_atomic32_read_bor_mb(&BIF_P->state, + ERTS_PSFLG_BOUND); + } + + curr = ERTS_GET_SCHEDULER_DATA_FROM_PROC(BIF_P)->run_queue; + old = (ERTS_PSFLG_BOUND & state) ? curr : NULL; + + ASSERT(!old || old == curr); + old_value = old ? make_small(old->ix+1) : make_small(0); - if (yield) + if (new && new != curr) ERTS_BIF_YIELD_RETURN_X(BIF_P, old_value, am_scheduler); else BIF_RET(old_value); @@ -1826,8 +1818,7 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) { if (internal_pid_index(to) >= erts_max_processes) return SEND_BADARG; - rp = erts_pid2proc_opt(p, ERTS_PROC_LOCK_MAIN, - to, 0, ERTS_P2P_FLG_SMP_INC_REFC); + rp = erts_proc_lookup_raw(to); if (!rp) { ERTS_SMP_ASSERT_IS_NOT_EXITING(p); @@ -1865,7 +1856,7 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) { } erts_whereis_name(p, ERTS_PROC_LOCK_MAIN, to, - &rp, 0, ERTS_P2P_FLG_SMP_INC_REFC, + &rp, 0, 0, &pt); if (pt) { @@ -2017,7 +2008,7 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) { erts_whereis_name(p, ERTS_PROC_LOCK_MAIN, tp[1], - &rp, 0, ERTS_P2P_FLG_SMP_INC_REFC, + &rp, 0, 0, &pt); if (pt) { portid = pt->id; @@ -2060,23 +2051,15 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) { rp_locks |= ERTS_PROC_LOCK_MAIN; #endif /* send to local process */ - erts_send_message(p, rp, &rp_locks, msg, 0); - if (!erts_use_sender_punish) + res = erts_send_message(p, rp, &rp_locks, msg, 0); + if (erts_use_sender_punish) + res *= 4; + else res = 0; - else { -#ifdef ERTS_SMP - res = rp->msg_inq.len*4; - if (ERTS_PROC_LOCK_MAIN & rp_locks) - res += rp->msg.len*4; -#else - res = rp->msg.len*4; -#endif - } erts_smp_proc_unlock(rp, p == rp ? (rp_locks & ~ERTS_PROC_LOCK_MAIN) : rp_locks); - erts_smp_proc_dec_refc(rp); return res; } } @@ -3486,7 +3469,7 @@ BIF_RETTYPE garbage_collect_1(BIF_ALIST_1) if (rp == ERTS_PROC_LOCK_BUSY) ERTS_BIF_YIELD1(bif_export[BIF_garbage_collect_1], BIF_P, BIF_ARG_1); #else - rp = erts_pid2proc(BIF_P, 0, BIF_ARG_1, 0); + rp = erts_proc_lookup(BIF_ARG_1); #endif if (!rp) BIF_RET(am_false); @@ -3780,7 +3763,8 @@ BIF_RETTYPE function_exported_3(BIF_ALIST_3) is_not_small(BIF_ARG_3)) { BIF_ERROR(BIF_P, BADARG); } - if (erts_find_function(BIF_ARG_1, BIF_ARG_2, signed_val(BIF_ARG_3)) == NULL) { + if (erts_find_function(BIF_ARG_1, BIF_ARG_2, signed_val(BIF_ARG_3), + erts_active_code_ix()) == NULL) { BIF_RET(am_false); } BIF_RET(am_true); @@ -4216,8 +4200,8 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) erts_smp_thr_progress_block(); for (i = 0; i < erts_max_processes; i++) { - if (process_tab[i] != (Process*) 0) { - Process* p = process_tab[i]; + Process *p = erts_pix2proc(i); + if (p) { #ifdef USE_VM_PROBES p->seq_trace_token = (p->dt_utag != NIL) ? am_have_dt_utag : NIL; #else @@ -4513,6 +4497,21 @@ erts_bif_prep_await_proc_exit_apply_trap(Process *c_p, Export bif_return_trap_export; +void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a, + Eterm (*bif)(BIF_ALIST_0)) +{ + int i; + sys_memset((void *) ep, 0, sizeof(Export)); + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + ep->addressv[i] = &ep->code[3]; + } + ep->code[0] = m; + ep->code[1] = f; + ep->code[2] = a; + ep->code[3] = (BeamInstr) em_apply_bif; + ep->code[4] = (BeamInstr) bif; +} + void erts_init_bif(void) { reference0 = 0; @@ -4528,17 +4527,13 @@ void erts_init_bif(void) * yield the calling process traps to. The only thing it does: * return the value passed as argument. */ - sys_memset((void *) &bif_return_trap_export, 0, sizeof(Export)); - bif_return_trap_export.address = &bif_return_trap_export.code[3]; - bif_return_trap_export.code[0] = am_erlang; - bif_return_trap_export.code[1] = am_bif_return_trap; + erts_init_trap_export(&bif_return_trap_export, am_erlang, am_bif_return_trap, #ifdef DEBUG - bif_return_trap_export.code[2] = 2; + 2 #else - bif_return_trap_export.code[2] = 1; + 1 #endif - bif_return_trap_export.code[3] = (BeamInstr) em_apply_bif; - bif_return_trap_export.code[4] = (BeamInstr) &bif_return_trap; + , &bif_return_trap); flush_monitor_message_trap = erts_export_put(am_erlang, am_flush_monitor_message, diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h index d20089a9fb..7cb2c78815 100644 --- a/erts/emulator/beam/bif.h +++ b/erts/emulator/beam/bif.h @@ -125,7 +125,7 @@ do { \ #define ERTS_BIF_PREP_TRAP0(Ret, Trap, Proc) \ do { \ (Proc)->arity = 0; \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -135,7 +135,7 @@ do { \ Eterm* reg = ERTS_PROC_GET_SCHDATA((Proc))->x_reg_array; \ (Proc)->arity = 1; \ reg[0] = (Eterm) (A0); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -146,7 +146,7 @@ do { \ (Proc)->arity = 2; \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -158,7 +158,7 @@ do { \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ reg[2] = (Eterm) (A2); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -170,13 +170,13 @@ do { \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ reg[2] = (Eterm) (A2); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ } while (0) #define BIF_TRAP0(p, Trap_) do { \ (p)->arity = 0; \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -185,7 +185,7 @@ do { \ Eterm* reg = ERTS_PROC_GET_SCHDATA((p))->x_reg_array; \ (p)->arity = 1; \ reg[0] = (A0); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -195,7 +195,7 @@ do { \ (p)->arity = 2; \ reg[0] = (A0); \ reg[1] = (A1); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -206,7 +206,7 @@ do { \ reg[0] = (A0); \ reg[1] = (A1); \ reg[2] = (A2); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 797bce43ab..f7dad2767f 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -142,8 +142,6 @@ bif erlang:list_to_pid/1 bif 'erl.lang.proc':string_to_pid/1 ebif_string_to_pid_1 list_to_pid_1 bif erlang:list_to_tuple/1 bif 'erl.lang.tuple':from_list/1 ebif_list_to_tuple_1 -bif erlang:load_module/2 -bif 'erl.system.code':load/2 ebif_load_module_2 bif erlang:loaded/0 bif 'erl.system.code':loaded/0 ebif_loaded_0 bif erlang:localtime/0 @@ -829,6 +827,13 @@ bif erlang:dt_restore_tag/1 bif erlang:dt_prepend_vm_tag_data/1 bif erlang:dt_append_vm_tag_data/1 + +# +# New in R16B. +# +bif erlang:prepare_loading/2 +bif erlang:finish_loading/1 + # # Obsolete # diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 6f5020dc14..0a51e00016 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -71,9 +71,10 @@ process_info(int to, void *to_arg) { int i; for (i = 0; i < erts_max_processes; i++) { - if ((process_tab[i] != NULL) && (process_tab[i]->i != ENULL)) { - if (process_tab[i]->status != P_EXITING) - print_process_info(to, to_arg, process_tab[i]); + Process *p = erts_pix2proc(i); + if (p && p->i != ENULL) { + if (!ERTS_PROC_IS_EXITING(p)) + print_process_info(to, to_arg, p); } } @@ -89,7 +90,8 @@ process_killer(void) erts_printf("\n\nProcess Information\n\n"); erts_printf("--------------------------------------------------\n"); for (i = erts_max_processes-1; i >= 0; i--) { - if (((rp = process_tab[i]) != NULL) && rp->i != ENULL) { + rp = erts_pix2proc(i); + if (rp && rp->i != ENULL) { int br; print_process_info(ERTS_PRINT_STDOUT, NULL, rp); erts_printf("(k)ill (n)ext (r)eturn:\n"); @@ -97,11 +99,20 @@ process_killer(void) if ((j = sys_get_key(0)) <= 0) erl_exit(0, ""); switch(j) { - case 'k': - if (rp->status == P_WAITING) { - ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; - erts_smp_proc_inc_refc(rp); - erts_smp_proc_lock(rp, rp_locks); + case 'k': { + ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; + erts_aint32_t state; + erts_smp_proc_inc_refc(rp); + erts_smp_proc_lock(rp, rp_locks); + state = erts_smp_atomic32_read_acqb(&rp->state); + if (state & (ERTS_PSFLG_FREE + | ERTS_PSFLG_EXITING + | ERTS_PSFLG_ACTIVE + | ERTS_PSFLG_IN_RUNQ + | ERTS_PSFLG_RUNNING)) { + erts_printf("Can only kill WAITING processes this way\n"); + } + else { (void) erts_send_exit_signal(NULL, NIL, rp, @@ -110,12 +121,10 @@ process_killer(void) NIL, NULL, 0); - erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); } - else - erts_printf("Can only kill WAITING processes this way\n"); - + erts_smp_proc_unlock(rp, rp_locks); + erts_smp_proc_dec_refc(rp); + } case 'n': br = 1; break; case 'r': return; default: return; @@ -180,42 +189,38 @@ static void doit_print_monitor(ErtsMonitor *mon, void *vpcontext) void print_process_info(int to, void *to_arg, Process *p) { + time_t approx_started; int garbing = 0; int running = 0; - time_t tmp_t; struct saved_calls *scb; + erts_aint32_t state; /* display the PID */ erts_print(to, to_arg, "=proc:%T\n", p->id); /* Display the state */ erts_print(to, to_arg, "State: "); - switch (p->status) { - case P_FREE: + + state = erts_smp_atomic32_read_acqb(&p->state); + if (state & ERTS_PSFLG_FREE) erts_print(to, to_arg, "Non Existing\n"); /* Should never happen */ - break; - case P_RUNABLE: - erts_print(to, to_arg, "Scheduled\n"); - break; - case P_WAITING: - erts_print(to, to_arg, "Waiting\n"); - break; - case P_SUSPENDED: - erts_print(to, to_arg, "Suspended\n"); - break; - case P_RUNNING: - erts_print(to, to_arg, "Running\n"); - running = 1; - break; - case P_EXITING: + else if (state & ERTS_PSFLG_EXITING) erts_print(to, to_arg, "Exiting\n"); - break; - case P_GARBING: - erts_print(to, to_arg, "Garbing\n"); + else if (state & ERTS_PSFLG_GC) { garbing = 1; running = 1; - break; + erts_print(to, to_arg, "Garbing\n"); + } + else if (state & ERTS_PSFLG_SUSPENDED) + erts_print(to, to_arg, "Suspended\n"); + else if (state & ERTS_PSFLG_RUNNING) { + running = 1; + erts_print(to, to_arg, "Running\n"); } + else if (state & ERTS_PSFLG_ACTIVE) + erts_print(to, to_arg, "Scheduled\n"); + else + erts_print(to, to_arg, "Waiting\n"); /* * If the process is registered as a global process, display the @@ -245,8 +250,8 @@ print_process_info(int to, void *to_arg, Process *p) } erts_print(to, to_arg, "Spawned by: %T\n", p->parent); - tmp_t = p->started.tv_sec; - erts_print(to, to_arg, "Started: %s", ctime(&tmp_t)); + approx_started = (time_t) p->approx_started; + erts_print(to, to_arg, "Started: %s", ctime(&approx_started)); ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p); erts_print(to, to_arg, "Message queue length: %d\n", p->msg.len); @@ -377,17 +382,22 @@ loaded(int to, void *to_arg) int old = 0; int cur = 0; BeamInstr* code; + Module* modp; + ErtsCodeIndex code_ix; + + code_ix = erts_active_code_ix(); + erts_rlock_old_code(code_ix); /* * Calculate and print totals. */ - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { - cur += module_code(i)->code_length; - if (module_code(i)->old_code_length != 0) { - old += module_code(i)->old_code_length; + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp = module_code(i, code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + cur += modp->curr.code_length; + if (modp->old.code_length != 0) { + old += modp->old.code_length; } } } @@ -398,21 +408,22 @@ loaded(int to, void *to_arg) * Print one line per module. */ - for (i = 0; i < module_code_size(); i++) { + for (i = 0; i < module_code_size(code_ix); i++) { + modp = module_code(i, code_ix); if (!ERTS_IS_CRASH_DUMPING) { /* * Interactive dump; keep it brief. */ - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { - erts_print(to, to_arg, "%T", make_atom(module_code(i)->module)); - cur += module_code(i)->code_length; - erts_print(to, to_arg, " %d", module_code(i)->code_length ); - if (module_code(i)->old_code_length != 0) { + if (modp != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + erts_print(to, to_arg, "%T", make_atom(modp->module)); + cur += modp->curr.code_length; + erts_print(to, to_arg, " %d", modp->curr.code_length ); + if (modp->old.code_length != 0) { erts_print(to, to_arg, " (%d old)", - module_code(i)->old_code_length ); - old += module_code(i)->old_code_length; + modp->old.code_length ); + old += modp->old.code_length; } erts_print(to, to_arg, "\n"); } @@ -420,15 +431,15 @@ loaded(int to, void *to_arg) /* * To crash dump; make it parseable. */ - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { + if (modp != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { erts_print(to, to_arg, "=mod:"); - erts_print(to, to_arg, "%T", make_atom(module_code(i)->module)); + erts_print(to, to_arg, "%T", make_atom(modp->module)); erts_print(to, to_arg, "\n"); erts_print(to, to_arg, "Current size: %d\n", - module_code(i)->code_length); - code = module_code(i)->code; + modp->curr.code_length); + code = modp->curr.code; if (code != NULL && code[MI_ATTR_PTR]) { erts_print(to, to_arg, "Current attributes: "); dump_attributes(to, to_arg, (byte *) code[MI_ATTR_PTR], @@ -440,9 +451,9 @@ loaded(int to, void *to_arg) code[MI_COMPILE_SIZE]); } - if (module_code(i)->old_code_length != 0) { - erts_print(to, to_arg, "Old size: %d\n", module_code(i)->old_code_length); - code = module_code(i)->old_code; + if (modp->old.code_length != 0) { + erts_print(to, to_arg, "Old size: %d\n", modp->old.code_length); + code = modp->old.code; if (code[MI_ATTR_PTR]) { erts_print(to, to_arg, "Old attributes: "); dump_attributes(to, to_arg, (byte *) code[MI_ATTR_PTR], @@ -457,6 +468,7 @@ loaded(int to, void *to_arg) } } } + erts_runlock_old_code(code_ix); } @@ -616,7 +628,8 @@ bin_check(void) int i, printed = 0; for (i=0; i < erts_max_processes; i++) { - if ((rp = process_tab[i]) == NULL) + rp = erts_pix2proc(i); + if (!rp) continue; for (hdr = rp->off_heap.first; hdr; hdr = hdr->next) { if (hdr->thing_word == HEADER_PROC_BIN) { @@ -704,7 +717,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) erts_print_nif_taints(fd, NULL); erts_fdprintf(fd, "Atoms: %d\n", atom_table_size()); info(fd, NULL); /* General system info */ - if (process_tab != NULL) /* XXX true at init */ + if (erts_proc.tab) process_info(fd, NULL); /* Info about each process and port */ db_info(fd, NULL, 0); erts_print_bif_timer_info(fd, NULL); diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c new file mode 100644 index 0000000000..8025058ee0 --- /dev/null +++ b/erts/emulator/beam/code_ix.c @@ -0,0 +1,166 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "code_ix.h" +#include "global.h" +#include "beam_catches.h" + + + +#if 0 +# define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_staging_code_ix()) +#else +# define CIX_TRACE(text) +#endif + +erts_smp_atomic32_t the_active_code_index; +erts_smp_atomic32_t the_staging_code_index; + +static int the_code_ix_lock = 0; +struct code_ix_queue_item { + Process *p; + struct code_ix_queue_item* next; +}; +static struct code_ix_queue_item* the_code_ix_queue = NULL; +static erts_smp_mtx_t the_code_ix_queue_lock; + +#ifdef ERTS_ENABLE_LOCK_CHECK +static erts_tsd_key_t has_code_write_permission; +#endif + +void erts_code_ix_init(void) +{ + /* We start emulator by initializing preloaded modules + * single threaded with active and staging set both to zero. + * Preloading is finished by a commit that will set things straight. + */ + erts_smp_atomic32_init_nob(&the_active_code_index, 0); + erts_smp_atomic32_init_nob(&the_staging_code_index, 0); + erts_smp_mtx_init(&the_code_ix_queue_lock, "code_ix_queue"); +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_tsd_key_create(&has_code_write_permission); +#endif + CIX_TRACE("init"); +} + +void erts_start_staging_code_ix(void) +{ + beam_catches_start_staging(); + export_start_staging(); + module_start_staging(); + erts_start_staging_ranges(); + CIX_TRACE("start"); +} + + +void erts_end_staging_code_ix(void) +{ + beam_catches_end_staging(1); + export_end_staging(1); + module_end_staging(1); + erts_end_staging_ranges(1); + CIX_TRACE("end"); +} + +void erts_commit_staging_code_ix(void) +{ + ErtsCodeIndex ix; + /* We need to this lock as we are now making the staging export table active */ + export_staging_lock(); + ix = erts_staging_code_ix(); + erts_smp_atomic32_set_nob(&the_active_code_index, ix); + ix = (ix + 1) % ERTS_NUM_CODE_IX; + erts_smp_atomic32_set_nob(&the_staging_code_index, ix); + export_staging_unlock(); + CIX_TRACE("activate"); +} + +void erts_abort_staging_code_ix(void) +{ + beam_catches_end_staging(0); + export_end_staging(0); + module_end_staging(0); + erts_end_staging_ranges(0); + CIX_TRACE("abort"); +} + + +/* + * Calller _must_ yield if we return 0 + */ +int erts_try_seize_code_write_permission(Process* c_p) +{ + int success; +#ifdef ERTS_SMP + ASSERT(!erts_smp_thr_progress_is_blocking()); /* to avoid deadlock */ +#endif + + erts_smp_mtx_lock(&the_code_ix_queue_lock); + success = !the_code_ix_lock; + if (success) { + the_code_ix_lock = 1; +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_tsd_set(has_code_write_permission, (void *) 1); +#endif + } + else { /* Already locked */ + struct code_ix_queue_item* qitem; + qitem = erts_alloc(ERTS_ALC_T_CODE_IX_LOCK_Q, sizeof(*qitem)); + qitem->p = c_p; + erts_smp_proc_inc_refc(c_p); + qitem->next = the_code_ix_queue; + the_code_ix_queue = qitem; + erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); + } + erts_smp_mtx_unlock(&the_code_ix_queue_lock); + return success; +} + +void erts_release_code_write_permission(void) +{ + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked()); + erts_smp_mtx_lock(&the_code_ix_queue_lock); + while (the_code_ix_queue != NULL) { /* unleash the entire herd */ + struct code_ix_queue_item* qitem = the_code_ix_queue; + erts_smp_proc_lock(qitem->p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(qitem->p)) { + erts_resume(qitem->p, ERTS_PROC_LOCK_STATUS); + } + erts_smp_proc_unlock(qitem->p, ERTS_PROC_LOCK_STATUS); + the_code_ix_queue = qitem->next; + erts_smp_proc_dec_refc(qitem->p); + erts_free(ERTS_ALC_T_CODE_IX_LOCK_Q, qitem); + } + the_code_ix_lock = 0; +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_tsd_set(has_code_write_permission, (void *) 0); +#endif + erts_smp_mtx_unlock(&the_code_ix_queue_lock); +} + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_code_ix_locked(void) +{ + return the_code_ix_lock && erts_tsd_get(has_code_write_permission); +} +#endif diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h new file mode 100644 index 0000000000..6b2680044e --- /dev/null +++ b/erts/emulator/beam/code_ix.h @@ -0,0 +1,141 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* Description: + * This is the interface that facilitate changing the beam code + * (load,upgrade,delete) while allowing executing Erlang processes to + * access the code without any locks or other expensive memory barriers. + * + * The basic idea is to maintain several "logical copies" of the code. These + * copies are identified by a global 'code index', an integer of 0, 1 or 2. + * The code index is used as argument to code access structures like + * export, module, beam_catches, beam_ranges. + * + * The current 'active' code index is used to access the current running + * code. The 'staging' code index is used by the process that performs + * a code change operation. When a code change operation completes + * succesfully, the staging code index becomes the new active code index. + * + * The third code index is not explicitly used. It can be thought of as + * the "previous active" or the "next staging" index. It is needed to make + * sure that we do not reuse a code index for staging until we are sure + * that no executing BIFs are still referring it. + * We could get by with only two (0 and 1), but that would require that we + * must wait for all schedulers to re-schedule before each code change + * operation can start staging. + * + * Note that the 'code index' is very loosely coupled to the concept of + * 'current' and 'old' module versions. You can almost say that they are + * orthogonal to each other. Code index is an emulator global concept while + * 'current' and 'old' is specific for each module. + */ + +#ifndef __CODE_IX_H__ +#define __CODE_IX_H__ + +#ifndef __SYS_H__ +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +# include "sys.h" +#endif +struct process; + + +#define ERTS_NUM_CODE_IX 3 +typedef unsigned ErtsCodeIndex; + + +/* Called once at emulator initialization. + */ +void erts_code_ix_init(void); + +/* Return active code index. + * Is guaranteed to be valid until the calling BIF returns. + * To get a consistent view of the code, only one call to erts_active_code_ix() + * should be made and the returned ix reused within the same BIF call. + */ +ERTS_GLB_INLINE +ErtsCodeIndex erts_active_code_ix(void); + +/* Return staging code ix. + * Only used by a process performing code loading/upgrading/deleting/purging. + * code_ix must be locked. + */ +ERTS_GLB_INLINE +ErtsCodeIndex erts_staging_code_ix(void); + +/* Try seize exclusive code write permission. Needed for code staging. + * Main process lock (only) must be held. + * System thread progress must not be blocked. + * Caller is suspended and *must* yield if 0 is returned. + */ +int erts_try_seize_code_write_permission(struct process*); + +/* Release code write permission. + * Will resume any suspended waiters. + */ +void erts_release_code_write_permission(void); + +/* Prepare the "staging area" to be a complete copy of the active code. + * Code write permission must have been seized. + * Must be followed by calls to either "end" and "commit" or "abort" before + * code write permission can be released. + */ +void erts_start_staging_code_ix(void); + +/* End the staging. + * Preceded by "start" and must be followed by "commit". + */ +void erts_end_staging_code_ix(void); + +/* Set staging code index as new active code index. + * Preceded by "end". + */ +void erts_commit_staging_code_ix(void); + +/* Abort the staging. + * Preceded by "start". + */ +void erts_abort_staging_code_ix(void); + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_code_ix_locked(void); +#endif + + + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +extern erts_smp_atomic32_t the_active_code_index; +extern erts_smp_atomic32_t the_staging_code_index; + +ERTS_GLB_INLINE ErtsCodeIndex erts_active_code_ix(void) +{ + return erts_smp_atomic32_read_nob(&the_active_code_index); +} +ERTS_GLB_INLINE ErtsCodeIndex erts_staging_code_ix(void) +{ + return erts_smp_atomic32_read_nob(&the_staging_code_index); +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + +#endif /* !__CODE_IX_H__ */ + diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 01fd63d5d9..5db68f6d45 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -1312,7 +1312,7 @@ int erts_net_message(Port *prt, if (is_not_pid(from) || is_not_atom(to)){ goto invalid_message; } - rp = erts_whereis_process(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC); + rp = erts_whereis_process(NULL, 0, to, 0, 0); if (rp) { Uint xsize = (type == DOP_REG_SEND ? 0 @@ -1338,7 +1338,6 @@ int erts_net_message(Port *prt, erts_queue_dist_message(rp, &locks, ede_copy, token); if (locks) erts_smp_proc_unlock(rp, locks); - erts_smp_proc_dec_refc(rp); } break; @@ -1364,7 +1363,7 @@ int erts_net_message(Port *prt, if (is_not_pid(to)) { goto invalid_message; } - rp = erts_pid2proc_opt(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC); + rp = erts_proc_lookup(to); if (rp) { Uint xsize = type == DOP_SEND ? 0 : ERTS_HEAP_FRAG_SIZE(token_size); ErtsProcLocks locks = 0; @@ -1388,7 +1387,6 @@ int erts_net_message(Port *prt, erts_queue_dist_message(rp, &locks, ede_copy, token); if (locks) erts_smp_proc_unlock(rp, locks); - erts_smp_proc_dec_refc(rp); } break; @@ -1544,8 +1542,7 @@ int erts_net_message(Port *prt, if (is_not_pid(from) || is_not_internal_pid(to)) { goto invalid_message; } - rp = erts_pid2proc_opt(NULL, 0, to, rp_locks, - ERTS_P2P_FLG_SMP_INC_REFC); + rp = erts_pid2proc(NULL, 0, to, rp_locks); if (rp) { (void) erts_send_exit_signal(NULL, from, @@ -1556,7 +1553,6 @@ int erts_net_message(Port *prt, NULL, 0); erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); } break; } @@ -1973,6 +1969,7 @@ erts_dist_command(Port *prt, int reds_limit) bw(foq.first->extp, size); #endif reds += ERTS_PORT_REDS_DIST_CMD_DATA(size); + erts_smp_atomic_add_nob(&erts_bytes_out, size); fob = foq.first; obufsize += size_obuf(fob); foq.first = foq.first->next; @@ -2056,6 +2053,7 @@ erts_dist_command(Port *prt, int reds_limit) bw(oq.first->extp, size); #endif reds += ERTS_PORT_REDS_DIST_CMD_DATA(size); + erts_smp_atomic_add_nob(&erts_bytes_out, size); fob = oq.first; obufsize += size_obuf(fob); oq.first = oq.first->next; @@ -2242,7 +2240,7 @@ static void doit_print_monitor_info(ErtsMonitor *mon, void *vptdp) void *arg = ((struct print_to_data *) vptdp)->arg; Process *rp; ErtsMonitor *rmon; - rp = erts_pid2proc_unlocked(mon->pid); + rp = erts_proc_lookup(mon->pid); if (!rp || (rmon = erts_lookup_monitor(rp->monitors, mon->ref)) == NULL) { erts_print(to, arg, "Warning, stray monitor for: %T\n", mon->pid); } else if (mon->type == MON_ORIGIN) { @@ -2281,7 +2279,7 @@ static void doit_print_link_info2(ErtsLink *lnk, void *vpplc) static void doit_print_link_info(ErtsLink *lnk, void *vptdp) { - if (is_internal_pid(lnk->pid) && erts_pid2proc_unlocked(lnk->pid)) { + if (is_internal_pid(lnk->pid) && erts_proc_lookup(lnk->pid)) { PrintLinkContext plc = {(struct print_to_data *) vptdp, lnk->pid}; erts_doforall_links(ERTS_LINK_ROOT(lnk), &doit_print_link_info2, &plc); } @@ -2303,7 +2301,7 @@ static void doit_print_nodelink_info(ErtsLink *lnk, void *vpcontext) { PrintNodeLinkContext *pcontext = vpcontext; - if (is_internal_pid(lnk->pid) && erts_pid2proc_unlocked(lnk->pid)) + if (is_internal_pid(lnk->pid) && erts_proc_lookup(lnk->pid)) erts_print(pcontext->ptd.to, pcontext->ptd.arg, "Remote monitoring: %T %T\n", lnk->pid, pcontext->sysname); } @@ -2451,15 +2449,15 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) goto error; /* Check that all trap functions are defined !! */ - if (dsend2_trap->address == NULL || - dsend3_trap->address == NULL || + if (dsend2_trap->addressv[0] == NULL || + dsend3_trap->addressv[0] == NULL || /* dsend_nosuspend_trap->address == NULL ||*/ - dlink_trap->address == NULL || - dunlink_trap->address == NULL || - dmonitor_node_trap->address == NULL || - dgroup_leader_trap->address == NULL || - dmonitor_p_trap->address == NULL || - dexit_trap->address == NULL) { + dlink_trap->addressv[0] == NULL || + dunlink_trap->addressv[0] == NULL || + dmonitor_node_trap->addressv[0] == NULL || + dgroup_leader_trap->addressv[0] == NULL || + dmonitor_p_trap->addressv[0] == NULL || + dexit_trap->addressv[0] == NULL) { goto error; } @@ -2706,9 +2704,8 @@ BIF_RETTYPE dist_exit_3(BIF_ALIST_3) } else { lp_locks = ERTS_PROC_LOCKS_XSIG_SEND; - lp = erts_pid2proc_opt(BIF_P, ERTS_PROC_LOCK_MAIN, - local, lp_locks, - ERTS_P2P_FLG_SMP_INC_REFC); + lp = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN, + local, lp_locks); if (!lp) { BIF_RET(am_true); /* ignore */ } @@ -2727,9 +2724,7 @@ BIF_RETTYPE dist_exit_3(BIF_ALIST_3) lp_locks &= ~ERTS_PROC_LOCK_MAIN; #endif erts_smp_proc_unlock(lp, lp_locks); - if (lp != BIF_P) - erts_smp_proc_dec_refc(lp); - else { + if (lp == BIF_P) { /* * We may have exited current process and may have to take action. */ diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 6fce032f9d..ba73ca6da7 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -2182,9 +2182,9 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) if (want.code) { size.code = module_table_sz(); size.code += export_table_sz(); - size.code += export_list_size() * sizeof(Export); + size.code += export_entries_sz(); size.code += erts_fun_table_sz(); - size.code += allocated_modules*sizeof(Range); + size.code += erts_ranges_sz(); size.code += erts_total_code_size; } @@ -2300,11 +2300,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) values[i].name = "static"; values[i].ui[0] = erts_max_ports*sizeof(Port) /* Port table */ - + erts_timer_wheel_memory_size() /* Timer wheel */ -#ifdef SYS_TMP_BUF_SIZE - + SYS_TMP_BUF_SIZE /* tmp_buf in sys on vxworks & ose */ -#endif - ; + + erts_timer_wheel_memory_size(); /* Timer wheel */ i++; erts_atom_get_text_space_sizes(&reserved_atom_space, &atom_space); @@ -2332,7 +2328,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) values[i].arity = 2; values[i].name = "export_list"; - values[i].ui[0] = export_list_size() * sizeof(Export); + values[i].ui[0] = export_entries_sz(); i++; values[i].arity = 2; @@ -2347,7 +2343,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) values[i].arity = 2; values[i].name = "module_refs"; - values[i].ui[0] = allocated_modules*sizeof(Range); + values[i].ui[0] = erts_ranges_sz(); i++; values[i].arity = 2; diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 4aa8fa82fb..0a4407f009 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -164,6 +164,7 @@ type MSG_REF FIXED_SIZE PROCESSES msg_ref type MSG_ROOTS TEMPORARY PROCESSES msg_roots type ROOTSET TEMPORARY PROCESSES root_set type LOADER_TMP TEMPORARY CODE loader_tmp +type PREPARED_CODE SHORT_LIVED CODE prepared_code type BIF_TIMER_TABLE LONG_LIVED SYSTEM bif_timer_table type SL_BIF_TIMER SHORT_LIVED PROCESSES bif_timer_sl type LL_BIF_TIMER STANDARD PROCESSES bif_timer_ll @@ -263,6 +264,8 @@ type ZLIB STANDARD SYSTEM zlib type CPU_GRPS_MAP LONG_LIVED SYSTEM cpu_groups_map type AUX_WORK_TMO LONG_LIVED SYSTEM aux_work_timeouts type MISC_AUX_WORK_Q LONG_LIVED SYSTEM misc_aux_work_q +type CODE_IX_LOCK_Q SHORT_LIVED SYSTEM code_ix_lock_q +type PROC_INTERVAL LONG_LIVED SYSTEM process_interval +if threads_no_smp # Need thread safe allocs, but std_alloc and fix_alloc are not; @@ -321,6 +324,8 @@ type SL_PTIMER SHORT_LIVED SYSTEM ptimer_sl type LL_PTIMER STANDARD SYSTEM ptimer_ll type SYS_MSG_Q SHORT_LIVED PROCESSES system_messages_queue type FP_EXCEPTION LONG_LIVED SYSTEM fp_exception +type LL_MPATHS LONG_LIVED SYSTEM ll_migration_paths +type SL_MPATHS SHORT_LIVED SYSTEM sl_migration_paths +endif +if hipe @@ -414,28 +419,4 @@ type CON_VPRINTF_BUF TEMPORARY SYSTEM con_vprintf_buf +endif -+if vxworks - -type SYS_TMP_BUF LONG_LIVED SYSTEM sys_tmp_buf -type PEND_DATA SYSTEM SYSTEM pending_data -type FD_TAB LONG_LIVED SYSTEM fd_tab -type FD_ENTRY_BUF SYSTEM SYSTEM fd_entry_buf - -+endif - -+if ose - -type SYS_TMP_BUF LONG_LIVED SYSTEM sys_tmp_buf -type PUTENV_STR SYSTEM SYSTEM putenv_string -type GETENV_STR SYSTEM SYSTEM getenv_string -type GETENV_STATE SYSTEM SYSTEM getenv_state -type SIG_ENTRY SYSTEM SYSTEM sig_entry -type DRIVER_DATA SYSTEM SYSTEM driver_data -type PGM_TAB SYSTEM SYSTEM pgm_tab -type PGM_ENTRY SYSTEM SYSTEM pgm_entry -type PRT_TAB SYSTEM SYSTEM prt_tab -type PRT_ENTRY SYSTEM SYSTEM prt_entry - -+endif - # ---------------------------------------------------------------------------- diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index cb975d64b0..d85c6feba7 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -122,6 +122,8 @@ typedef struct { #endif } ErtsAsyncData; +#if defined(USE_THREADS) && defined(USE_VM_PROBES) + /* * Some compilers, e.g. GCC 4.2.1 and -O3, will optimize away DTrace * calls if they're the last thing in the function. :-( @@ -129,6 +131,7 @@ typedef struct { * https://github.com/memcached/memcached/commit/6298b3978687530bc9d219b6ac707a1b681b2a46 */ static unsigned gcc_optimizer_hack = 0; +#endif int erts_async_max_threads; /* Initialized by erl_init.c */ int erts_async_thread_suggested_stack_size; /* Initialized by erl_init.c */ @@ -281,8 +284,8 @@ static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) len = -1; DTRACE2(aio_pool_add, port_str, len); } -#endif gcc_optimizer_hack++; +#endif } static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index cc4f2be8eb..474151d454 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -72,52 +72,29 @@ binary_matches(Process *p, Eterm arg1, Eterm arg2, Eterm arg3); void erts_init_bif_binary(void) { - sys_memset((void *) &binary_match_trap_export, 0, sizeof(Export)); - binary_match_trap_export.address = &binary_match_trap_export.code[3]; - binary_match_trap_export.code[0] = am_erlang; - binary_match_trap_export.code[1] = am_binary_match_trap; - binary_match_trap_export.code[2] = 3; - binary_match_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_match_trap_export.code[4] = (BeamInstr) &binary_match_trap; - - sys_memset((void *) &binary_matches_trap_export, 0, sizeof(Export)); - binary_matches_trap_export.address = &binary_matches_trap_export.code[3]; - binary_matches_trap_export.code[0] = am_erlang; - binary_matches_trap_export.code[1] = am_binary_matches_trap; - binary_matches_trap_export.code[2] = 3; - binary_matches_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_matches_trap_export.code[4] = (BeamInstr) &binary_matches_trap; - - sys_memset((void *) &binary_longest_prefix_trap_export, 0, sizeof(Export)); - binary_longest_prefix_trap_export.address = &binary_longest_prefix_trap_export.code[3]; - binary_longest_prefix_trap_export.code[0] = am_erlang; - binary_longest_prefix_trap_export.code[1] = am_binary_longest_prefix_trap; - binary_longest_prefix_trap_export.code[2] = 3; - binary_longest_prefix_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_longest_prefix_trap_export.code[4] = (BeamInstr) &binary_longest_prefix_trap; - - sys_memset((void *) &binary_longest_suffix_trap_export, 0, sizeof(Export)); - binary_longest_suffix_trap_export.address = &binary_longest_suffix_trap_export.code[3]; - binary_longest_suffix_trap_export.code[0] = am_erlang; - binary_longest_suffix_trap_export.code[1] = am_binary_longest_suffix_trap; - binary_longest_suffix_trap_export.code[2] = 3; - binary_longest_suffix_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_longest_suffix_trap_export.code[4] = (BeamInstr) &binary_longest_suffix_trap; - - sys_memset((void *) &binary_bin_to_list_trap_export, 0, sizeof(Export)); - binary_bin_to_list_trap_export.address = &binary_bin_to_list_trap_export.code[3]; - binary_bin_to_list_trap_export.code[0] = am_erlang; - binary_bin_to_list_trap_export.code[1] = am_binary_bin_to_list_trap; - binary_bin_to_list_trap_export.code[2] = 3; - binary_bin_to_list_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_bin_to_list_trap_export.code[4] = (BeamInstr) &binary_bin_to_list_trap; - sys_memset((void *) &binary_copy_trap_export, 0, sizeof(Export)); - binary_copy_trap_export.address = &binary_copy_trap_export.code[3]; - binary_copy_trap_export.code[0] = am_erlang; - binary_copy_trap_export.code[1] = am_binary_copy_trap; - binary_copy_trap_export.code[2] = 2; - binary_copy_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_copy_trap_export.code[4] = (BeamInstr) &binary_copy_trap; + erts_init_trap_export(&binary_match_trap_export, + am_erlang, am_binary_match_trap, 3, + &binary_match_trap); + + erts_init_trap_export(&binary_matches_trap_export, + am_erlang, am_binary_matches_trap, 3, + &binary_matches_trap); + + erts_init_trap_export(&binary_longest_prefix_trap_export, + am_erlang, am_binary_longest_prefix_trap, 3, + &binary_longest_prefix_trap); + + erts_init_trap_export(&binary_longest_suffix_trap_export, + am_erlang, am_binary_longest_suffix_trap, 3, + &binary_longest_suffix_trap); + + erts_init_trap_export(&binary_bin_to_list_trap_export, + am_erlang, am_binary_bin_to_list_trap, 3, + &binary_bin_to_list_trap); + + erts_init_trap_export(&binary_copy_trap_export, + am_erlang, am_binary_copy_trap, 2, + &binary_copy_trap); max_loop_limit = 0; return; diff --git a/erts/emulator/beam/erl_bif_chksum.c b/erts/emulator/beam/erl_bif_chksum.c index 06b7ffdf32..ff5ce3cc7a 100644 --- a/erts/emulator/beam/erl_bif_chksum.c +++ b/erts/emulator/beam/erl_bif_chksum.c @@ -42,16 +42,9 @@ static Export chksum_md5_2_exp; void erts_init_bif_chksum(void) { /* Non visual BIF to trap to. */ - memset(&chksum_md5_2_exp, 0, sizeof(Export)); - chksum_md5_2_exp.address = - &chksum_md5_2_exp.code[3]; - chksum_md5_2_exp.code[0] = am_erlang; - chksum_md5_2_exp.code[1] = am_atom_put("md5_trap",8); - chksum_md5_2_exp.code[2] = 2; - chksum_md5_2_exp.code[3] = - (BeamInstr) em_apply_bif; - chksum_md5_2_exp.code[4] = - (BeamInstr) &md5_2; + erts_init_trap_export(&chksum_md5_2_exp, + am_erlang, am_atom_put("md5_trap",8), 2, + &md5_2); } diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index c338ee1c4b..7f7c975e78 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -368,13 +368,11 @@ BIF_RETTYPE erl_ddll_try_load_3(BIF_ALIST_3) #endif for (j = 0; j < erts_max_ports; j++) { Port* prt = &erts_port[j]; -#ifdef DDLL_SMP erts_smp_port_state_lock(prt); -#endif if (!(prt->status & FREE_PORT_FLAGS) && prt->drv_ptr->handle == dh) { -#if DDLL_SMP erts_smp_atomic_inc_nob(&prt->refc); +#if DDLL_SMP /* Extremely rare spinlock */ while(prt->status & ERTS_PORT_SFLG_INITIALIZING) { erts_smp_port_state_unlock(prt); @@ -598,13 +596,11 @@ done: #endif for (j = 0; j < erts_max_ports; j++) { Port* prt = &erts_port[j]; -#if DDLL_SMP erts_smp_port_state_lock(prt); -#endif if (!(prt->status & FREE_PORT_FLAGS) && prt->drv_ptr->handle == dh) { -#if DDLL_SMP erts_smp_atomic_inc_nob(&prt->refc); +#if DDLL_SMP /* Extremely rare spinlock */ while(prt->status & ERTS_PORT_SFLG_INITIALIZING) { erts_smp_port_state_unlock(prt); @@ -1060,13 +1056,11 @@ void erts_ddll_proc_dead(Process *p, ErtsProcLocks plocks) #endif for (j = 0; j < erts_max_ports; j++) { Port* prt = &erts_port[j]; -#if DDLL_SMP erts_smp_port_state_lock(prt); -#endif if (!(prt->status & FREE_PORT_FLAGS) && prt->drv_ptr->handle == dh) { -#if DDLL_SMP erts_smp_atomic_inc_nob(&prt->refc); +#if DDLL_SMP while(prt->status & ERTS_PORT_SFLG_INITIALIZING) { erts_smp_port_state_unlock(prt); erts_smp_port_state_lock(prt); diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index f56b00287f..e2f7c8673f 100755 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -1338,13 +1338,15 @@ process_info_aux(Process *BIF_P, hp = HAlloc(BIF_P, 3); break; - case am_trap_exit: + case am_trap_exit: { + erts_aint32_t state = erts_smp_atomic32_read_nob(&rp->state); hp = HAlloc(BIF_P, 3); - if (rp->flags & F_TRAPEXIT) + if (state & ERTS_PSFLG_TRAP_EXIT) res = am_true; else res = am_false; break; + } case am_error_handler: hp = HAlloc(BIF_P, 3); @@ -3098,15 +3100,13 @@ BIF_RETTYPE is_process_alive_1(BIF_ALIST_1) if(internal_pid_index(BIF_ARG_1) >= erts_max_processes) BIF_ERROR(BIF_P, BADARG); - rp = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN, - BIF_ARG_1, ERTS_PROC_LOCK_STATUS); + rp = erts_proc_lookup(BIF_ARG_1); if (!rp) { BIF_RET(am_false); } else { - int have_pending_exit = ERTS_PROC_PENDING_EXIT(rp); - erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); - if (have_pending_exit) + if (erts_smp_atomic32_read_acqb(&rp->state) + & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) ERTS_BIF_AWAIT_X_DATA_TRAP(BIF_P, BIF_ARG_1, am_false); else BIF_RET(am_true); @@ -3710,9 +3710,8 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) && is_internal_pid(tp[2])) { int xres; ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; - Process *rp = erts_pid2proc_opt(BIF_P, ERTS_PROC_LOCK_MAIN, - tp[2], rp_locks, - ERTS_P2P_FLG_SMP_INC_REFC); + Process *rp = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN, + tp[2], rp_locks); if (!rp) { DECL_AM(dead); BIF_RET(AM_dead); @@ -3738,7 +3737,6 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) rp_locks &= ~ERTS_PROC_LOCK_MAIN; #endif erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); if (xres > 1) { DECL_AM(message); BIF_RET(AM_message); @@ -3949,7 +3947,7 @@ static Eterm lcnt_build_lock_term(Eterm **hpp, Uint *szp, erts_lcnt_lock_t *lock id = am_atom_put(ltype, strlen(ltype)); } else if (lock->flag & ERTS_LCNT_LT_PROCLOCK) { /* use registered names as id's for process locks if available */ - proc = erts_pid2proc_unlocked(lock->id); + proc = erts_proc_lookup(lock->id); if (proc && proc->reg) { id = proc->reg->name; } else { diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c index 6b843d2e08..b036c5ef5c 100644 --- a/erts/emulator/beam/erl_bif_re.c +++ b/erts/emulator/beam/erl_bif_re.c @@ -71,14 +71,9 @@ void erts_init_bif_re(void) erts_pcre_stack_free = &erts_erts_pcre_stack_free; default_table = NULL; /* ISO8859-1 default, forced into pcre */ max_loop_limit = CONTEXT_REDS * LOOP_FACTOR; - - sys_memset((void *) &re_exec_trap_export, 0, sizeof(Export)); - re_exec_trap_export.address = &re_exec_trap_export.code[3]; - re_exec_trap_export.code[0] = am_erlang; - re_exec_trap_export.code[1] = am_re_run_trap; - re_exec_trap_export.code[2] = 3; - re_exec_trap_export.code[3] = (BeamInstr) em_apply_bif; - re_exec_trap_export.code[4] = (BeamInstr) &re_exec_trap; + + erts_init_trap_export(&re_exec_trap_export, am_erlang, am_re_run_trap, 3, + &re_exec_trap); grun_trap_exportp = erts_export_put(am_re,am_grun,3); urun_trap_exportp = erts_export_put(am_re,am_urun,3); diff --git a/erts/emulator/beam/erl_bif_timer.c b/erts/emulator/beam/erl_bif_timer.c index d806be0704..525b11f61c 100644 --- a/erts/emulator/beam/erl_bif_timer.c +++ b/erts/emulator/beam/erl_bif_timer.c @@ -324,10 +324,9 @@ bif_timer_timeout(ErtsBifTimer* btm) ASSERT(!erts_get_current_process()); if (btm->flags & BTM_FLG_BYNAME) - rp = erts_whereis_process(NULL,0,btm->receiver.name,0,ERTS_P2P_FLG_SMP_INC_REFC); + rp = erts_whereis_process(NULL, 0, btm->receiver.name, 0, 0); else { rp = btm->receiver.proc.ess; - erts_smp_proc_inc_refc(rp); unlink_proc(btm); } @@ -379,7 +378,6 @@ bif_timer_timeout(ErtsBifTimer* btm) #endif ); erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); } } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 80f774523c..e88fb8c9f4 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -42,12 +42,24 @@ #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1) const struct trace_pattern_flags erts_trace_pattern_flags_off = {0, 0, 0, 0, 0}; + +/* + * The following variables are protected by code write permission. + */ static int erts_default_trace_pattern_is_on; static Binary *erts_default_match_spec; static Binary *erts_default_meta_match_spec; static struct trace_pattern_flags erts_default_trace_pattern_flags; static Eterm erts_default_meta_tracer_pid; +static struct { /* Protected by code write permission */ + int current; + int install; + int local; + BpFunctions f; /* Local functions */ + BpFunctions e; /* Export entries */ +} finish_bp; + static Eterm trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist); static BIF_RETTYPE @@ -60,12 +72,11 @@ static Eterm trace_info_pid(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_func(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_on_load(Process* p, Eterm key); -static int setup_func_trace(Export* ep, void* match_prog); -static int reset_func_trace(Export* ep); -static void reset_bif_trace(int bif_index); -static void setup_bif_trace(int bif_index); -static void set_trace_bif(int bif_index, void* match_prog); -static void clear_trace_bif(int bif_index); +static void reset_bif_trace(void); +static void setup_bif_trace(void); +static void install_exp_breakpoints(BpFunctions* f); +static void uninstall_exp_breakpoints(BpFunctions* f); +static void clean_export_entries(BpFunctions* f); void erts_bif_trace_init(void) @@ -98,7 +109,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) { DeclareTmpHeap(mfa,3,p); /* Not really heap here, but might be when setting pattern */ int i; - int matches = 0; + int matches = -1; int specified = 0; enum erts_break_op on; Binary* match_prog_set; @@ -107,9 +118,12 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) int is_global; Process *meta_tracer_proc = p; Eterm meta_tracer_pid = p->id; + int is_blocking = 0; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + if (!erts_try_seize_code_write_permission(p)) { + ERTS_BIF_YIELD3(bif_export[BIF_trace_pattern_3], p, MFA, Pattern, flaglist); + } + finish_bp.current = -1; UseTmpHeap(3,p); /* @@ -241,7 +255,6 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) erts_default_meta_match_spec = NULL; erts_default_meta_tracer_pid = NIL; } - MatchSetUnref(match_prog_set); if (erts_default_trace_pattern_flags.breakpoint && flags.breakpoint) { /* Breakpoint trace -> breakpoint trace */ @@ -297,8 +310,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) erts_default_trace_pattern_is_on = !!flags.breakpoint; } } - - goto done; + matches = 0; } else if (is_tuple(MFA)) { Eterm *tp = tuple_val(MFA); if (tp[0] != make_arityval(3)) { @@ -322,35 +334,37 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) if (is_small(mfa[2])) { mfa[2] = signed_val(mfa[2]); } - } else { - goto error; - } - if (meta_tracer_proc) { - meta_tracer_proc->trace_flags |= F_TRACER; - } + if (meta_tracer_proc) { + meta_tracer_proc->trace_flags |= F_TRACER; + } + matches = erts_set_trace_pattern(p, mfa, specified, + match_prog_set, match_prog_set, + on, flags, meta_tracer_pid, 0); + } - matches = erts_set_trace_pattern(mfa, specified, - match_prog_set, match_prog_set, - on, flags, meta_tracer_pid); + error: MatchSetUnref(match_prog_set); - - done: UnUseTmpHeap(3,p); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - - return make_small(matches); - error: +#ifdef ERTS_SMP + if (finish_bp.current >= 0) { + ASSERT(matches >= 0); + erts_notify_finish_breakpointing(p); + erts_suspend(p, ERTS_PROC_LOCK_MAIN, NULL); + ERTS_BIF_YIELD_RETURN(p, make_small(matches)); + } +#endif - MatchSetUnref(match_prog_set); + erts_release_code_write_permission(); - UnUseTmpHeap(3,p); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - BIF_ERROR(p, BADARG); + if (matches >= 0) { + return make_small(matches); + } + else { + BIF_ERROR(p, BADARG); + } } void @@ -360,6 +374,8 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on, struct trace_pattern_flags *trace_pattern_flags, Eterm *meta_tracer_pid) { + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked() || + erts_smp_thr_progress_is_blocking()); if (trace_pattern_is_on) *trace_pattern_is_on = erts_default_trace_pattern_is_on; if (match_spec) @@ -372,7 +388,12 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on, *meta_tracer_pid = erts_default_meta_tracer_pid; } - +int erts_is_default_trace_enabled(void) +{ + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked() || + erts_smp_thr_progress_is_blocking()); + return erts_default_trace_pattern_is_on; +} Uint erts_trace_flag2bit(Eterm flag) @@ -466,6 +487,10 @@ Eterm trace_3(BIF_ALIST_3) BIF_ERROR(p, BADARG); } + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD3(bif_export[BIF_trace_3], BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + } + if (is_nil(tracer) || is_internal_pid(tracer)) { Process *tracer_proc = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, @@ -653,8 +678,7 @@ Eterm trace_3(BIF_ALIST_3) if (procs || mods) { /* tracing of processes */ for (i = 0; i < erts_max_processes; i++) { - Process* tracee_p = process_tab[i]; - + Process* tracee_p = erts_pix2proc(i); if (! tracee_p) continue; if (tracer != NIL) { @@ -730,6 +754,7 @@ Eterm trace_3(BIF_ALIST_3) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); } #endif + erts_release_code_write_permission(); BIF_RET(make_small(matches)); @@ -745,6 +770,7 @@ Eterm trace_3(BIF_ALIST_3) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); } #endif + erts_release_code_write_permission(); BIF_ERROR(p, BADARG); } @@ -772,8 +798,7 @@ static int port_already_traced(Process *c_p, Port *tracee_port, Eterm tracer) return 1; } else if(is_internal_pid(tracee_port->tracer_proc)) { - Process *tracer_p = erts_pid2proc(c_p, ERTS_PROC_LOCK_MAIN, - tracee_port->tracer_proc, 0); + Process *tracer_p = erts_proc_lookup(tracee_port->tracer_proc); if (!tracer_p) { /* Current trace process now invalid * - discard it and approve the new. */ @@ -813,8 +838,7 @@ static int already_traced(Process *c_p, Process *tracee_p, Eterm tracer) return 1; } else if(is_internal_pid(tracee_p->tracer_proc)) { - Process *tracer_p = erts_pid2proc(c_p, ERTS_PROC_LOCK_MAIN, - tracee_p->tracer_proc, 0); + Process *tracer_p = erts_proc_lookup(tracee_p->tracer_proc); if (!tracer_p) { /* Current trace process now invalid * - discard it and approve the new. */ @@ -841,6 +865,11 @@ Eterm trace_info_2(BIF_ALIST_2) Eterm What = BIF_ARG_1; Eterm Key = BIF_ARG_2; Eterm res; + + if (!erts_try_seize_code_write_permission(p)) { + ERTS_BIF_YIELD2(bif_export[BIF_trace_info_2], p, What, Key); + } + if (What == am_on_load) { res = trace_info_on_load(p, Key); } else if (is_atom(What) || is_pid(What)) { @@ -848,8 +877,10 @@ Eterm trace_info_2(BIF_ALIST_2) } else if (is_tuple(What)) { res = trace_info_func(p, What, Key); } else { + erts_release_code_write_permission(); BIF_ERROR(p, BADARG); } + erts_release_code_write_permission(); BIF_RET(res); } @@ -876,7 +907,7 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key) } if (is_internal_pid(tracer)) { - if (!erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, tracer, 0)) { + if (!erts_proc_lookup(tracer)) { reset_tracer: tracee->trace_flags &= ~TRACEE_FLAGS; trace_flags = tracee->trace_flags; @@ -977,64 +1008,54 @@ static int function_is_traced(Process *p, Binary **ms, /* out */ Binary **ms_meta, /* out */ Eterm *tracer_pid_meta, /* out */ - Sint *count, /* out */ + Uint *count, /* out */ Eterm *call_time) /* out */ { Export e; Export* ep; - int i; - BeamInstr *code; + BeamInstr* pc; /* First look for an export entry */ e.code[0] = mfa[0]; e.code[1] = mfa[1]; e.code[2] = mfa[2]; if ((ep = export_get(&e)) != NULL) { - if (ep->address == ep->code+3 && - ep->code[3] != (BeamInstr) em_call_error_handler) { - if (ep->code[3] == (BeamInstr) em_call_traced_function) { - *ms = ep->match_prog_set; + pc = ep->code+3; + if (ep->addressv[erts_active_code_ix()] == pc && + *pc != (BeamInstr) em_call_error_handler) { + + int r = 0; + + ASSERT(*pc == (BeamInstr) em_apply_bif || + *pc == (BeamInstr) BeamOp(op_i_generic_breakpoint)); + + if (erts_is_trace_break(pc, ms, 0)) { return FUNC_TRACE_GLOBAL_TRACE; } - if (ep->code[3] == (BeamInstr) em_apply_bif) { - for (i = 0; i < BIF_SIZE; ++i) { - if (bif_export[i] == ep) { - int r = 0; - - if (erts_bif_trace_flags[i] & BIF_TRACE_AS_GLOBAL) { - *ms = ep->match_prog_set; - return FUNC_TRACE_GLOBAL_TRACE; - } else { - if (erts_bif_trace_flags[i] & BIF_TRACE_AS_LOCAL) { - r |= FUNC_TRACE_LOCAL_TRACE; - *ms = ep->match_prog_set; - } - if (erts_is_mtrace_break(ep->code+3, ms_meta, - tracer_pid_meta)) { - r |= FUNC_TRACE_META_TRACE; - } - if (erts_is_time_break(p, ep->code+3, call_time)) { - r |= FUNC_TRACE_TIME_TRACE; - } - } - return r ? r : FUNC_TRACE_UNTRACED; - } - } - erl_exit(1,"Impossible ghost bif encountered in trace_info."); + + if (erts_is_trace_break(pc, ms, 1)) { + r |= FUNC_TRACE_LOCAL_TRACE; + } + if (erts_is_mtrace_break(pc, ms_meta, tracer_pid_meta)) { + r |= FUNC_TRACE_META_TRACE; } + if (erts_is_time_break(p, pc, call_time)) { + r |= FUNC_TRACE_TIME_TRACE; + } + return r ? r : FUNC_TRACE_UNTRACED; } } /* OK, now look for breakpoint tracing */ - if ((code = erts_find_local_func(mfa)) != NULL) { + if ((pc = erts_find_local_func(mfa)) != NULL) { int r = - (erts_is_trace_break(code, ms, NULL) + (erts_is_trace_break(pc, ms, 1) ? FUNC_TRACE_LOCAL_TRACE : 0) - | (erts_is_mtrace_break(code, ms_meta, tracer_pid_meta) + | (erts_is_mtrace_break(pc, ms_meta, tracer_pid_meta) ? FUNC_TRACE_META_TRACE : 0) - | (erts_is_count_break(code, count) + | (erts_is_count_break(pc, count) ? FUNC_TRACE_COUNT_TRACE : 0) - | (erts_is_time_break(p, code, call_time) + | (erts_is_time_break(p, pc, call_time) ? FUNC_TRACE_TIME_TRACE : 0); return r ? r : FUNC_TRACE_UNTRACED; @@ -1049,7 +1070,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key) Eterm* hp; DeclareTmpHeap(mfa,3,p); /* Not really heap here, but might be when setting pattern */ Binary *ms = NULL, *ms_meta = NULL; - Sint count = 0; + Uint count = 0; Eterm traced = am_false; Eterm match_spec = am_false; Eterm retval = am_false; @@ -1137,9 +1158,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key) break; case am_call_count: if (r & FUNC_TRACE_COUNT_TRACE) { - retval = count < 0 ? - erts_make_integer(-count-1, p) : - erts_make_integer(count, p); + retval = erts_make_integer(count, p); } break; case am_call_time: @@ -1328,38 +1347,46 @@ trace_info_on_load(Process* p, Eterm key) #undef FUNC_TRACE_LOCAL_TRACE int -erts_set_trace_pattern(Eterm* mfa, int specified, +erts_set_trace_pattern(Process*p, Eterm* mfa, int specified, Binary* match_prog_set, Binary *meta_match_prog_set, int on, struct trace_pattern_flags flags, - Eterm meta_tracer_pid) + Eterm meta_tracer_pid, int is_blocking) { + const ErtsCodeIndex code_ix = erts_active_code_ix(); int matches = 0; int i; + int n; + BpFunction* fp; /* * First work on normal functions (not real BIFs). */ - - for (i = 0; i < export_list_size(); i++) { - Export* ep = export_list(i); - int j; - - if (ExportIsBuiltIn(ep)) { - continue; - } - - for (j = 0; j < specified && mfa[j] == ep->code[j]; j++) { - /* Empty loop body */ - } - if (j == specified) { - if (on) { - if (! flags.breakpoint) - matches += setup_func_trace(ep, match_prog_set); - else - reset_func_trace(ep); - } else if (! flags.breakpoint) { - matches += reset_func_trace(ep); + erts_bp_match_export(&finish_bp.e, mfa, specified); + fp = finish_bp.e.matching; + n = finish_bp.e.matched; + + for (i = 0; i < n; i++) { + BeamInstr* pc = fp[i].pc; + Export* ep = (Export *)(((char *)(pc-3)) - offsetof(Export, code)); + + if (!on || flags.breakpoint) { + erts_clear_call_trace_bif(pc, 0); + if (pc[0] == (BeamInstr) BeamOp(op_i_generic_breakpoint)) { + pc[0] = (BeamInstr) BeamOp(op_jump_f); + } + } else { + if (ep->addressv[code_ix] != pc) { + fp[i].mod->curr.num_traced_exports++; +#ifdef DEBUG + pc[-5] = (BeamInstr) BeamOp(op_i_func_info_IaaI); +#endif + pc[0] = (BeamInstr) BeamOp(op_jump_f); + pc[1] = (BeamInstr) ep->addressv[code_ix]; + } + erts_set_call_trace_bif(pc, match_prog_set, 0); + if (ep->addressv[code_ix] != pc) { + pc[0] = (BeamInstr) BeamOp(op_i_generic_breakpoint); } } } @@ -1384,26 +1411,15 @@ erts_set_trace_pattern(Eterm* mfa, int specified, /* Empty loop body */ } if (j == specified) { + BeamInstr* pc = (BeamInstr *)bif_export[i]->code + 3; + if (! flags.breakpoint) { /* Export entry call trace */ if (on) { - if (erts_bif_trace_flags[i] & BIF_TRACE_AS_META) { - ASSERT(ExportIsBuiltIn(bif_export[i])); - erts_clear_mtrace_bif - ((BeamInstr *)bif_export[i]->code + 3); - erts_bif_trace_flags[i] &= ~BIF_TRACE_AS_META; - } - set_trace_bif(i, match_prog_set); - erts_bif_trace_flags[i] &= ~BIF_TRACE_AS_LOCAL; - erts_bif_trace_flags[i] |= BIF_TRACE_AS_GLOBAL; - setup_bif_trace(i); + erts_clear_call_trace_bif(pc, 1); + erts_clear_mtrace_bif(pc); + erts_set_call_trace_bif(pc, match_prog_set, 0); } else { /* off */ - if (erts_bif_trace_flags[i] & BIF_TRACE_AS_GLOBAL) { - clear_trace_bif(i); - erts_bif_trace_flags[i] &= ~BIF_TRACE_AS_GLOBAL; - } - if (! erts_bif_trace_flags[i]) { - reset_bif_trace(i); - } + erts_clear_call_trace_bif(pc, 0); } matches++; } else { /* Breakpoint call trace */ @@ -1411,52 +1427,33 @@ erts_set_trace_pattern(Eterm* mfa, int specified, if (on) { if (flags.local) { - set_trace_bif(i, match_prog_set); - erts_bif_trace_flags[i] |= BIF_TRACE_AS_LOCAL; - erts_bif_trace_flags[i] &= ~BIF_TRACE_AS_GLOBAL; + erts_clear_call_trace_bif(pc, 0); + erts_set_call_trace_bif(pc, match_prog_set, 1); m = 1; } if (flags.meta) { - erts_set_mtrace_bif - ((BeamInstr *)bif_export[i]->code + 3, - meta_match_prog_set, meta_tracer_pid); - erts_bif_trace_flags[i] |= BIF_TRACE_AS_META; - erts_bif_trace_flags[i] &= ~BIF_TRACE_AS_GLOBAL; + erts_set_mtrace_bif(pc, meta_match_prog_set, + meta_tracer_pid); m = 1; } if (flags.call_time) { - erts_set_time_trace_bif(bif_export[i]->code + 3, on); + erts_set_time_trace_bif(pc, on); /* I don't want to remove any other tracers */ - erts_bif_trace_flags[i] |= BIF_TRACE_AS_CALL_TIME; m = 1; } - if (erts_bif_trace_flags[i]) { - setup_bif_trace(i); - } } else { /* off */ if (flags.local) { - if (erts_bif_trace_flags[i] & BIF_TRACE_AS_LOCAL) { - clear_trace_bif(i); - erts_bif_trace_flags[i] &= ~BIF_TRACE_AS_LOCAL; - } + erts_clear_call_trace_bif(pc, 1); m = 1; } if (flags.meta) { - if (erts_bif_trace_flags[i] & BIF_TRACE_AS_META) { - erts_clear_mtrace_bif - ((BeamInstr *)bif_export[i]->code + 3); - erts_bif_trace_flags[i] &= ~BIF_TRACE_AS_META; - } + erts_clear_mtrace_bif(pc); m = 1; } if (flags.call_time) { - erts_clear_time_trace_bif(bif_export[i]->code + 3); - erts_bif_trace_flags[i] &= ~BIF_TRACE_AS_CALL_TIME; + erts_clear_time_trace_bif(pc); m = 1; } - if (! erts_bif_trace_flags[i]) { - reset_bif_trace(i); - } } matches += m; } @@ -1466,176 +1463,242 @@ erts_set_trace_pattern(Eterm* mfa, int specified, /* ** So, now for breakpoint tracing */ + erts_bp_match_functions(&finish_bp.f, mfa, specified); if (on) { if (! flags.breakpoint) { - erts_clear_trace_break(mfa, specified); - erts_clear_mtrace_break(mfa, specified); - erts_clear_count_break(mfa, specified); - erts_clear_time_break(mfa, specified); + erts_clear_all_breaks(&finish_bp.f); } else { - int m = 0; if (flags.local) { - m = erts_set_trace_break(mfa, specified, match_prog_set, - am_true); + erts_set_trace_break(&finish_bp.f, match_prog_set); } if (flags.meta) { - m = erts_set_mtrace_break(mfa, specified, meta_match_prog_set, - meta_tracer_pid); + erts_set_mtrace_break(&finish_bp.f, meta_match_prog_set, + meta_tracer_pid); } if (flags.call_count) { - m = erts_set_count_break(mfa, specified, on); + erts_set_count_break(&finish_bp.f, on); } if (flags.call_time) { - m = erts_set_time_break(mfa, specified, on); + erts_set_time_break(&finish_bp.f, on); } - /* All assignments to 'm' above should give the same value, - * so just use the last */ - matches += m; } } else { - int m = 0; if (flags.local) { - m = erts_clear_trace_break(mfa, specified); + erts_clear_trace_break(&finish_bp.f); } if (flags.meta) { - m = erts_clear_mtrace_break(mfa, specified); + erts_clear_mtrace_break(&finish_bp.f); } if (flags.call_count) { - m = erts_clear_count_break(mfa, specified); + erts_clear_count_break(&finish_bp.f); } if (flags.call_time) { - m = erts_clear_time_break(mfa, specified); + erts_clear_time_break(&finish_bp.f); + } + } + + finish_bp.current = 0; + finish_bp.install = on; + finish_bp.local = flags.breakpoint; + +#ifdef ERTS_SMP + if (is_blocking) { + ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); +#endif + while (erts_finish_breakpointing()) { + /* Empty loop body */ } - /* All assignments to 'm' above should give the same value, - * so just use the last */ - matches += m; +#ifdef ERTS_SMP + finish_bp.current = -1; } +#endif + if (flags.breakpoint) { + matches += finish_bp.f.matched; + } else { + matches += finish_bp.e.matched; + } return matches; } -/* - * Setup function tracing for the given exported function. - * - * Return Value: 1 if entry refers to a BIF or loaded function, - * 0 if the entry refers to a function not loaded. - */ - -static int -setup_func_trace(Export* ep, void* match_prog) +int +erts_finish_breakpointing(void) { - if (ep->address == ep->code+3) { - if (ep->code[3] == (BeamInstr) em_call_error_handler) { - return 0; - } else if (ep->code[3] == (BeamInstr) em_call_traced_function) { - MatchSetUnref(ep->match_prog_set); - ep->match_prog_set = match_prog; - MatchSetRef(ep->match_prog_set); - return 1; - } else { - /* - * We ignore apply/3 and anything else. - */ - return 0; - } - } - + ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked()); + /* - * Currently no trace support for native code. + * Memory barriers will be issued for all processes *before* + * each of the stages below. (Unless the other schedulers + * are blocked, in which case memory barriers will be issued + * when they are awaken.) */ - if (erts_is_native_break(ep->address)) { + + switch (finish_bp.current++) { + case 0: + /* + * At this point, in all functions that are to be breakpointed, + * a pointer to a GenericBp struct has already been added, + * + * Insert the new breakpoints (if any) into the + * code. Different schedulers may see breakpoint instruction + * at different times, but it does not matter since the newly + * added breakpoints are disabled. + */ + if (finish_bp.install) { + if (finish_bp.local) { + erts_install_breakpoints(&finish_bp.f); + } else { + install_exp_breakpoints(&finish_bp.e); + } + } + setup_bif_trace(); + return 1; + case 1: + /* + * Switch index for the breakpoint data, activating the staged + * data. (Depending on the changes in the breakpoint data, + * that could either activate breakpoints or disable + * breakpoints.) + */ + erts_commit_staged_bp(); + return 1; + case 2: + /* + * Remove breakpoints instructions for disabled breakpoints + * (if any). + */ + if (finish_bp.install) { + if (finish_bp.local) { + uninstall_exp_breakpoints(&finish_bp.e); + } else { + erts_uninstall_breakpoints(&finish_bp.f); + } + } else { + if (finish_bp.local) { + erts_uninstall_breakpoints(&finish_bp.f); + } else { + uninstall_exp_breakpoints(&finish_bp.e); + } + } + reset_bif_trace(); + return 1; + case 3: + /* + * Now all breakpoints have either been inserted or removed. + * For all updated breakpoints, copy the active breakpoint + * data to the staged breakpoint data to make them equal + * (simplifying for the next time breakpoints are to be + * updated). If any breakpoints have been totally disabled, + * deallocate the GenericBp structs for them. + */ + erts_consolidate_bif_bp_data(); + clean_export_entries(&finish_bp.e); + erts_consolidate_bp_data(&finish_bp.e, 0); + erts_consolidate_bp_data(&finish_bp.f, 1); + erts_bp_free_matched_functions(&finish_bp.e); + erts_bp_free_matched_functions(&finish_bp.f); return 0; + default: + ASSERT(0); } - - ep->code[3] = (BeamInstr) em_call_traced_function; - ep->code[4] = (BeamInstr) ep->address; - ep->address = ep->code+3; - ep->match_prog_set = match_prog; - MatchSetRef(ep->match_prog_set); - return 1; + return 0; } -static void setup_bif_trace(int bif_index) { - Export *ep = bif_export[bif_index]; - - ASSERT(ExportIsBuiltIn(ep)); - ASSERT(ep->code[4]); - ep->code[4] = (BeamInstr) bif_table[bif_index].traced; -} +static void +install_exp_breakpoints(BpFunctions* f) +{ + const ErtsCodeIndex code_ix = erts_active_code_ix(); + BpFunction* fp = f->matching; + Uint ne = f->matched; + Uint i; + Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr); -static void set_trace_bif(int bif_index, void* match_prog) { - Export *ep = bif_export[bif_index]; - -#ifdef HARDDEBUG - erts_fprintf(stderr, "set_trace_bif: %T:%T/%bpu\n", - ep->code[0], ep->code[1], ep->code[2]); -#endif - ASSERT(ExportIsBuiltIn(ep)); - MatchSetUnref(ep->match_prog_set); - ep->match_prog_set = match_prog; - MatchSetRef(ep->match_prog_set); -} + for (i = 0; i < ne; i++) { + BeamInstr* pc = fp[i].pc; + Export* ep = (Export *) (((char *)pc)-offset); -/* - * Reset function tracing for the given exported function. - * - * Return Value: 1 if entry refers to a BIF or loaded function, - * 0 if the entry refers to a function not loaded. - */ + ep->addressv[code_ix] = pc; + } +} -static int -reset_func_trace(Export* ep) +static void +uninstall_exp_breakpoints(BpFunctions* f) { - if (ep->address == ep->code+3) { - if (ep->code[3] == (BeamInstr) em_call_error_handler) { - return 0; - } else if (ep->code[3] == (BeamInstr) em_call_traced_function) { - ep->address = (Uint *) ep->code[4]; - MatchSetUnref(ep->match_prog_set); - ep->match_prog_set = NULL; - return 1; - } else { - /* - * We ignore apply/3 and anything else. - */ - return 0; + const ErtsCodeIndex code_ix = erts_active_code_ix(); + BpFunction* fp = f->matching; + Uint ne = f->matched; + Uint i; + Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr); + + for (i = 0; i < ne; i++) { + BeamInstr* pc = fp[i].pc; + Export* ep = (Export *) (((char *)pc)-offset); + + if (ep->addressv[code_ix] != pc) { + continue; } + ASSERT(*pc == (BeamInstr) BeamOp(op_jump_f)); + ep->addressv[code_ix] = (BeamInstr *) ep->code[4]; } - - /* - * Currently no trace support for native code. - */ - if (erts_is_native_break(ep->address)) { - return 0; - } - - /* - * Nothing to do, but the export entry matches. - */ +} + +static void +clean_export_entries(BpFunctions* f) +{ + const ErtsCodeIndex code_ix = erts_active_code_ix(); + BpFunction* fp = f->matching; + Uint ne = f->matched; + Uint i; + Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr); - return 1; + for (i = 0; i < ne; i++) { + BeamInstr* pc = fp[i].pc; + Export* ep = (Export *) (((char *)pc)-offset); + + if (ep->addressv[code_ix] == pc) { + continue; + } + if (*pc == (BeamInstr) BeamOp(op_jump_f)) { + ep->code[3] = (BeamInstr) 0; + ep->code[4] = (BeamInstr) 0; + } + } } -static void reset_bif_trace(int bif_index) { - Export *ep = bif_export[bif_index]; - - ASSERT(ExportIsBuiltIn(ep)); - ASSERT(ep->code[4]); - ASSERT(! ep->match_prog_set); - ASSERT(! erts_is_mtrace_break((BeamInstr *)ep->code+3, NULL, NULL)); - ep->code[4] = (BeamInstr) bif_table[bif_index].f; +static void +setup_bif_trace(void) +{ + int i; + + for (i = 0; i < BIF_SIZE; ++i) { + Export *ep = bif_export[i]; + GenericBp* g = (GenericBp *) ep->fake_op_func_info_for_hipe[1]; + if (g) { + if (ExportIsBuiltIn(ep)) { + ASSERT(ep->code[4]); + ep->code[4] = (BeamInstr) bif_table[i].traced; + } + } + } } -static void clear_trace_bif(int bif_index) { - Export *ep = bif_export[bif_index]; - -#ifdef HARDDEBUG - erts_fprintf(stderr, "clear_trace_bif: %T:%T/%bpu\n", - ep->code[0], ep->code[1], ep->code[2]); -#endif - ASSERT(ExportIsBuiltIn(ep)); - MatchSetUnref(ep->match_prog_set); - ep->match_prog_set = NULL; +static void +reset_bif_trace(void) +{ + int i; + ErtsBpIndex active = erts_active_bp_ix(); + + for (i = 0; i < BIF_SIZE; ++i) { + Export *ep = bif_export[i]; + BeamInstr* pc = ep->code+3; + GenericBp* g = (GenericBp *) pc[-4]; + if (g && g->data[active].flags == 0) { + if (ExportIsBuiltIn(ep)) { + ASSERT(ep->code[4]); + ep->code[4] = (BeamInstr) bif_table[i].f; + } + } + } } /* @@ -2142,9 +2205,9 @@ BIF_RETTYPE system_profile_2(BIF_ALIST_2) /* Check if valid process, no locks are taken */ if (is_internal_pid(profiler)) { - if (internal_pid_index(profiler) >= erts_max_processes) goto error; - profiler_p = process_tab[internal_pid_index(profiler)]; - if (INVALID_PID(profiler_p, profiler)) goto error; + profiler_p = erts_proc_lookup(profiler); + if (!profiler_p) + goto error; } else if (is_internal_port(profiler)) { if (internal_port_index(profiler) >= erts_max_ports) goto error; profiler_port = &erts_port[internal_port_index(profiler)]; diff --git a/erts/emulator/beam/erl_cpu_topology.c b/erts/emulator/beam/erl_cpu_topology.c index fe3693d0ca..3f90f34736 100644 --- a/erts/emulator/beam/erl_cpu_topology.c +++ b/erts/emulator/beam/erl_cpu_topology.c @@ -486,7 +486,7 @@ erts_sched_check_cpu_bind_post_suspend(ErtsSchedulerData *esdp) erts_thr_set_main_status(1, (int) esdp->no); /* Make sure we check if we should bind to a cpu or not... */ - esdp->run_queue->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND; + (void) ERTS_RUNQ_FLGS_SET(esdp->run_queue, ERTS_RUNQ_FLG_CHK_CPU_BIND); } #endif @@ -498,9 +498,6 @@ erts_sched_check_cpu_bind(ErtsSchedulerData *esdp) erts_cpu_groups_map_t *cgm; erts_cpu_groups_callback_list_t *cgcl; erts_cpu_groups_callback_call_t *cgcc; -#ifdef ERTS_SMP - esdp->run_queue->flags &= ~ERTS_RUNQ_FLG_CHK_CPU_BIND; -#endif erts_smp_runq_unlock(esdp->run_queue); erts_smp_rwmtx_rwlock(&cpuinfo_rwmtx); cpu_id = scheduler2cpu_map[esdp->no].bind_id; diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 51bdf53823..4c30905495 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -224,8 +224,9 @@ Export ets_select_continue_exp; static Export ets_delete_continue_exp; static void -free_dbtable(DbTable* tb) +free_dbtable(void *vtb) { + DbTable *tb = (DbTable *) vtb; #ifdef HARDDEBUG if (erts_smp_atomic_read_nob(&tb->common.memory_size) != sizeof(DbTable)) { erts_fprintf(stderr, "ets: free_dbtable memory remain=%ld fix=%x\n", @@ -251,20 +252,8 @@ free_dbtable(DbTable* tb) ASSERT(is_immed(tb->common.heir_data)); erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable)); ERTS_ETS_MISC_MEM_ADD(-sizeof(DbTable)); - ERTS_SMP_MEMORY_BARRIER; } -#ifdef ERTS_SMP -static void -chk_free_dbtable(void *vtb) -{ - DbTable * tb = (DbTable *) vtb; - ERTS_THR_MEMORY_BARRIER; - if (erts_refc_dectest(&tb->common.ref, 0) == 0) - free_dbtable(tb); -} -#endif - static void schedule_free_dbtable(DbTable* tb) { /* @@ -275,15 +264,10 @@ static void schedule_free_dbtable(DbTable* tb) * need to unlock the table lock after this * function has returned). */ -#ifdef ERTS_SMP - int scheds = erts_get_max_no_executing_schedulers(); - ASSERT(scheds >= 1); ASSERT(erts_refc_read(&tb->common.ref, 0) == 0); - erts_refc_init(&tb->common.ref, scheds); - erts_schedule_multi_misc_aux_work(0, scheds, chk_free_dbtable, tb); -#else - free_dbtable(tb); -#endif + erts_schedule_thr_prgr_later_op(free_dbtable, + (void *) tb, + &tb->release.data); } static ERTS_INLINE void db_init_lock(DbTable* tb, int use_frequent_read_lock, @@ -542,10 +526,6 @@ static int remove_named_tab(DbTable *tb, int have_lock) &rwlock); #ifdef ERTS_SMP if (!have_lock && erts_smp_rwmtx_tryrwlock(rwlock) == EBUSY) { - /* - * We keep our increased refc over this op in order to - * prevent the table from disapearing. - */ db_unlock(tb, LCK_WRITE); erts_smp_rwmtx_rwlock(rwlock); db_lock(tb, LCK_WRITE); @@ -1481,7 +1461,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) "** Too many db tables **\n"); free_heir_data(tb); tb->common.meth->db_free_table(tb); - free_dbtable(tb); + free_dbtable((void *) tb); BIF_ERROR(BIF_P, SYSTEM_LIMIT); } @@ -2816,7 +2796,6 @@ void init_db(void) { DbTable init_tb; int i; - extern BeamInstr* em_apply_bif; Eterm *hp; unsigned bits; size_t size; @@ -2850,7 +2829,7 @@ void init_db(void) else db_max_tabs = user_requested_db_max_tabs; - bits = erts_fit_in_bits(db_max_tabs-1); + bits = erts_fit_in_bits_int32(db_max_tabs-1); if (bits > SMALL_BITS) { erl_exit(1,"Max limit for ets tabled too high %u (max %u).", db_max_tabs, ((Uint)1)<<SMALL_BITS); @@ -2949,49 +2928,24 @@ void init_db(void) } /* Non visual BIF to trap to. */ - memset(&ets_select_delete_continue_exp, 0, sizeof(Export)); - ets_select_delete_continue_exp.address = - &ets_select_delete_continue_exp.code[3]; - ets_select_delete_continue_exp.code[0] = am_ets; - ets_select_delete_continue_exp.code[1] = am_atom_put("delete_trap",11); - ets_select_delete_continue_exp.code[2] = 1; - ets_select_delete_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_delete_continue_exp.code[4] = - (BeamInstr) &ets_select_delete_1; + erts_init_trap_export(&ets_select_delete_continue_exp, + am_ets, am_atom_put("delete_trap",11), 1, + &ets_select_delete_1); /* Non visual BIF to trap to. */ - memset(&ets_select_count_continue_exp, 0, sizeof(Export)); - ets_select_count_continue_exp.address = - &ets_select_count_continue_exp.code[3]; - ets_select_count_continue_exp.code[0] = am_ets; - ets_select_count_continue_exp.code[1] = am_atom_put("count_trap",11); - ets_select_count_continue_exp.code[2] = 1; - ets_select_count_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_count_continue_exp.code[4] = - (BeamInstr) &ets_select_count_1; + erts_init_trap_export(&ets_select_count_continue_exp, + am_ets, am_atom_put("count_trap",11), 1, + &ets_select_count_1); /* Non visual BIF to trap to. */ - memset(&ets_select_continue_exp, 0, sizeof(Export)); - ets_select_continue_exp.address = - &ets_select_continue_exp.code[3]; - ets_select_continue_exp.code[0] = am_ets; - ets_select_continue_exp.code[1] = am_atom_put("select_trap",11); - ets_select_continue_exp.code[2] = 1; - ets_select_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_continue_exp.code[4] = - (BeamInstr) &ets_select_trap_1; + erts_init_trap_export(&ets_select_continue_exp, + am_ets, am_atom_put("select_trap",11), 1, + &ets_select_trap_1); /* Non visual BIF to trap to. */ - memset(&ets_delete_continue_exp, 0, sizeof(Export)); - ets_delete_continue_exp.address = &ets_delete_continue_exp.code[3]; - ets_delete_continue_exp.code[0] = am_ets; - ets_delete_continue_exp.code[1] = am_atom_put("delete_trap",11); - ets_delete_continue_exp.code[2] = 1; - ets_delete_continue_exp.code[3] = (BeamInstr) em_apply_bif; - ets_delete_continue_exp.code[4] = (BeamInstr) &ets_delete_trap; + erts_init_trap_export(&ets_delete_continue_exp, + am_ets, am_atom_put("delete_trap",11), 1, + &ets_delete_trap); hp = ms_delete_all_buff; ms_delete_all = CONS(hp, am_true, NIL); @@ -3124,7 +3078,7 @@ retry: if (to_proc == NULL) { return 0; /* heir not alive, table still mine */ } - if (erts_cmp_timeval(&to_proc->started, &tb->common.heir_started) != 0) { + if (to_proc->started_interval != tb->common.heir_started_interval) { erts_smp_proc_unlock(to_proc, to_locks); return 0; /* heir dead and pid reused, table still mine */ } @@ -3520,14 +3474,14 @@ static void set_heir(Process* me, DbTable* tb, Eterm heir, UWord heir_data) return; } if (heir == me->id) { - tb->common.heir_started = me->started; + erts_ensure_later_proc_interval(me->started_interval); + tb->common.heir_started_interval = me->started_interval; } else { - Process* heir_proc= erts_pid2proc_opt(me, ERTS_PROC_LOCK_MAIN, heir, - 0, ERTS_P2P_FLG_SMP_INC_REFC); + Process* heir_proc= erts_proc_lookup(heir); if (heir_proc != NULL) { - tb->common.heir_started = heir_proc->started; - erts_smp_proc_dec_refc(heir_proc); + erts_ensure_later_proc_interval(heir_proc->started_interval); + tb->common.heir_started_interval = heir_proc->started_interval; } else { tb->common.heir = am_none; } diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h index 2e5deaf338..e9a661efbc 100644 --- a/erts/emulator/beam/erl_db.h +++ b/erts/emulator/beam/erl_db.h @@ -27,6 +27,10 @@ #define __DB_H__ #include "sys.h" +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY +#define ERL_THR_PROGRESS_TSD_TYPE_ONLY +#include "erl_thr_progress.h" +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY #include "bif.h" #include "erl_db_util.h" /* Flags */ @@ -36,6 +40,11 @@ Uint erts_get_ets_misc_mem_size(void); +typedef struct { + DbTableCommon common; + ErtsThrPrgrLaterOp data; +} DbTableRelease; + /* * So, the structure for a database table, NB this is only * interesting in db.c. @@ -44,6 +53,7 @@ union db_table { DbTableCommon common; /* Any type of db table */ DbTableHash hash; /* Linear hash array specific data */ DbTableTree tree; /* AVL tree specific data */ + DbTableRelease release; /*TT*/ }; diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 312050b931..faa7f31d99 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -452,16 +452,8 @@ DbTableMethod db_tree = void db_initialize_tree(void) { - memset(&ets_select_reverse_exp, 0, sizeof(Export)); - ets_select_reverse_exp.address = - &ets_select_reverse_exp.code[3]; - ets_select_reverse_exp.code[0] = am_ets; - ets_select_reverse_exp.code[1] = am_reverse; - ets_select_reverse_exp.code[2] = 3; - ets_select_reverse_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_reverse_exp.code[4] = - (BeamInstr) &ets_select_reverse; + erts_init_trap_export(&ets_select_reverse_exp, am_ets, am_reverse, 3, + &ets_select_reverse); return; }; diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h index 6a96e174e1..dcecc4251a 100644 --- a/erts/emulator/beam/erl_db_util.h +++ b/erts/emulator/beam/erl_db_util.h @@ -209,7 +209,7 @@ typedef struct db_fixation { */ typedef struct db_table_common { - erts_refc_t ref; /* fixation counter and delete counter */ + erts_refc_t ref; /* fixation counter */ #ifdef ERTS_SMP erts_smp_rwmtx_t rwlock; /* rw lock on table */ erts_smp_mtx_t fixlock; /* Protects fixations,megasec,sec,microsec */ @@ -219,7 +219,7 @@ typedef struct db_table_common { Eterm owner; /* Pid of the creator */ Eterm heir; /* Pid of the heir */ UWord heir_data; /* To send in ETS-TRANSFER (is_immed or (DbTerm*) */ - SysTimeval heir_started; /* To further identify the heir */ + Uint64 heir_started_interval; /* To further identify the heir */ Eterm the_name; /* an atom */ Eterm id; /* atom | integer */ DbTableMethod* meth; /* table methods */ diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index 1ae9a211d7..771ee46d2b 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -87,10 +87,7 @@ #include <stdlib.h> #include <string.h> /* ssize_t on Mac OS X */ -#if defined(VXWORKS) -# include <ioLib.h> -typedef struct iovec SysIOVec; -#elif defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_) +#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_) #ifndef STATIC_ERLANG_DRIVER /* Windows dynamic drivers, everything is different... */ #define ERL_DRIVER_TYPES_ONLY @@ -370,11 +367,7 @@ typedef struct erl_drv_entry { /* For windows dynamic drivers */ #ifndef ERL_DRIVER_TYPES_ONLY -#if defined(VXWORKS) -# define DRIVER_INIT(DRIVER_NAME) \ - ErlDrvEntry* DRIVER_NAME ## _init(void); \ - ErlDrvEntry* DRIVER_NAME ## _init(void) -#elif defined(__WIN32__) +#if defined(__WIN32__) # define DRIVER_INIT(DRIVER_NAME) \ __declspec(dllexport) ErlDrvEntry* driver_init(void); \ __declspec(dllexport) ErlDrvEntry* driver_init(void) diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h index 54cfd6aa83..217066ab11 100644 --- a/erts/emulator/beam/erl_fun.h +++ b/erts/emulator/beam/erl_fun.h @@ -77,8 +77,6 @@ ErlFunEntry* erts_get_fun_entry(Eterm mod, int uniq, int index); ErlFunEntry* erts_put_fun_entry2(Eterm mod, int old_uniq, int old_index, byte* uniq, int index, int arity); -ErlFunEntry* erts_get_fun_entry2(Eterm mod, int old_uniq, int old_index, - byte* uniq, int index, int arity); void erts_erase_fun_entry(ErlFunEntry* fe); void erts_cleanup_funs(ErlFunThing* funp); diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 52a6e52e6c..6075a527c3 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -357,11 +357,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) trace_gc(p, am_gc_start); } - erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - p->gcstatus = p->status; - p->status = P_GARBING; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); - + erts_smp_atomic32_read_bor_nob(&p->state, ERTS_PSFLG_GC); if (erts_system_monitor_long_gc != 0) { get_now(&ms1, &s1, &us1); } @@ -404,9 +400,8 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) ErtsGcQuickSanityCheck(p); - erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - p->status = p->gcstatus; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC); + if (IS_TRACED_FL(p, F_TRACE_GC)) { trace_gc(p, am_gc_end); } @@ -490,10 +485,7 @@ erts_garbage_collect_hibernate(Process* p) /* * Preliminaries. */ - erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - p->gcstatus = p->status; - p->status = P_GARBING; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_smp_atomic32_read_bor_nob(&p->state, ERTS_PSFLG_GC); ErtsGcQuickSanityCheck(p); ASSERT(p->mbuf_sz == 0); ASSERT(p->mbuf == 0); @@ -604,9 +596,7 @@ erts_garbage_collect_hibernate(Process* p) ErtsGcQuickSanityCheck(p); - erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - p->status = p->gcstatus; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC); } @@ -630,10 +620,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, /* * Set GC state. */ - erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - p->gcstatus = p->status; - p->status = P_GARBING; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_smp_atomic32_read_bor_nob(&p->state, ERTS_PSFLG_GC); /* * We assume that the caller has already done a major collection @@ -775,9 +762,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, /* * Restore status. */ - erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - p->status = p->gcstatus; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC); } static int diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 02164728fe..d382e421e6 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -55,6 +55,61 @@ #endif /* + * The variables below (prefixed with etp_) are for erts/etc/unix/etp-commands + * only. Do not remove even though they aren't used elsewhere in the emulator! + */ +#ifdef ERTS_SMP +const int etp_smp_compiled = 1; +#else +const int etp_smp_compiled = 0; +#endif +#ifdef USE_THREADS +const int etp_thread_compiled = 1; +#else +const int etp_thread_compiled = 0; +#endif +const char etp_erts_version[] = ERLANG_VERSION; +const char etp_otp_release[] = ERLANG_OTP_RELEASE; +const char etp_compile_date[] = ERLANG_COMPILE_DATE; +const char etp_arch[] = ERLANG_ARCHITECTURE; +#ifdef ERTS_ENABLE_KERNEL_POLL +const int etp_kernel_poll_support = 1; +#else +const int etp_kernel_poll_support = 0; +#endif +#if defined(ARCH_64) +const int etp_arch_bits = 64; +#elif defined(ARCH_32) +const int etp_arch_bits = 32; +#else +# error "Not 64-bit, nor 32-bit arch" +#endif +#if HALFWORD_HEAP +const int etp_halfword = 1; +#else +const int etp_halfword = 0; +#endif +#ifdef HIPE +const int etp_hipe = 1; +#else +const int etp_hipe = 0; +#endif +#ifdef DEBUG +const int etp_debug_compiled = 1; +#else +const int etp_debug_compiled = 0; +#endif +#ifdef ERTS_ENABLE_LOCK_COUNT +const int etp_lock_count = 1; +#else +const int etp_lock_count = 0; +#endif +#ifdef ERTS_ENABLE_LOCK_CHECK +const int etp_lock_check = 1; +#else +const int etp_lock_check = 0; +#endif +/* * Note about VxWorks: All variables must be initialized by executable code, * not by an initializer. Otherwise a new instance of the emulator will * inherit previous values. @@ -241,6 +296,7 @@ erl_init(int ncpu) erts_init_trace(); erts_init_binary(); erts_init_bits(); + erts_code_ix_init(); erts_init_fun_table(); init_atom_table(); init_export_table(); @@ -289,7 +345,8 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** Eterm env; start_mod = am_atom_put(modname, sys_strlen(modname)); - if (erts_find_function(start_mod, am_start, 2) == NULL) { + if (erts_find_function(start_mod, am_start, 2, + erts_active_code_ix()) == NULL) { erl_exit(5, "No function %s:start/2\n", modname); } @@ -388,7 +445,7 @@ load_preloaded(void) if ((code = sys_preload_begin(&preload_p[i])) == 0) erl_exit(1, "Failed to find preloaded code for module %s\n", name); - res = erts_load_module(NULL, 0, NIL, &module_name, code, length); + res = erts_preload_module(NULL, 0, NIL, &module_name, code, length); sys_preload_end(&preload_p[i]); if (res != NIL) erl_exit(1,"Failed loading preloaded module %s (%T)\n", @@ -555,6 +612,7 @@ early_init(int *argc, char **argv) /* erts_printf_eterm_func = erts_printf_term; erts_disable_tolerant_timeofday = 0; display_items = 200; + erts_proc.max = ERTS_DEFAULT_MAX_PROCESSES; erts_backtrace_depth = DEFAULT_BACKTRACE_SIZE; erts_async_max_threads = 0; erts_async_thread_suggested_stack_size = ERTS_ASYNC_THREAD_MIN_STACK_SIZE; @@ -1097,7 +1155,7 @@ erl_start(int argc, char **argv) case 'P': /* set maximum number of processes */ Parg = get_arg(argv[i]+2, argv[i+1], &i); - erts_max_processes = atoi(Parg); + erts_proc.max = atoi(Parg); /* Check of result is delayed until later. This is because +R may be given after +P. */ break; @@ -1396,10 +1454,10 @@ erl_start(int argc, char **argv) } /* Delayed check of +P flag */ - if (erts_max_processes < ERTS_MIN_PROCESSES - || erts_max_processes > ERTS_MAX_PROCESSES + if (erts_proc.max < ERTS_MIN_PROCESSES + || erts_proc.max > ERTS_MAX_PROCESSES || (erts_use_r9_pids_ports - && erts_max_processes > ERTS_MAX_R9_PROCESSES)) { + && erts_proc.max > ERTS_MAX_R9_PROCESSES)) { erts_fprintf(stderr, "bad number of processes %s\n", Parg); erts_usage(); } @@ -1427,6 +1485,8 @@ erl_start(int argc, char **argv) erl_init(ncpu); load_preloaded(); + erts_end_staging_code_ix(); + erts_commit_staging_code_ix(); erts_initialized = 1; diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index b545ec07c0..11fed4079d 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -82,8 +82,8 @@ static erts_lc_lock_order_t erts_lock_order[] = { #ifdef ERTS_SMP { "bif_timers", NULL }, { "reg_tab", NULL }, - { "migration_info_update", NULL }, { "proc_main", "pid" }, + { "old_code", "address" }, #ifdef HIPE { "hipe_mfait_lock", NULL }, #endif @@ -93,6 +93,7 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "proc_msgq", "pid" }, { "dist_entry", "address" }, { "dist_entry_links", "address" }, + { "code_ix_queue", NULL }, { "proc_status", "pid" }, { "proc_tab", NULL }, { "ports_snapshot", NULL }, @@ -124,6 +125,7 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "removed_fd_pre_alloc_lock", "address" }, { "state_prealloc", NULL }, { "schdlr_sspnd", NULL }, + { "migration_info_update", NULL }, { "run_queue", "address" }, { "cpu_info", NULL }, { "pollset", "address" }, @@ -443,7 +445,7 @@ print_lock2(char *prefix, Sint16 id, Wterm extra, Uint16 flags, char *suffix) "%s'%s:%p%s'%s%s", prefix, lname, - boxed_val(extra), + _unchecked_boxed_val(extra), lock_type(flags), rw_op_str(flags), suffix); diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 919567ab27..e397f075d1 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -296,36 +296,6 @@ erts_msg_distext2heap(Process *pp, return THE_NON_VALUE; } -static ERTS_INLINE void -notify_new_message(Process *receiver) -{ - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS - & erts_proc_lc_my_proc_locks(receiver)); - - switch (receiver->status) { - case P_GARBING: - switch (receiver->gcstatus) { - case P_SUSPENDED: - goto suspended; - case P_WAITING: - goto waiting; - default: - break; - } - break; - case P_SUSPENDED: - suspended: - receiver->rstatus = P_RUNABLE; - break; - case P_WAITING: - waiting: - erts_add_to_runq(receiver); - break; - default: - break; - } -} - void erts_queue_dist_message(Process *rcvr, ErtsProcLocks *rcvr_locks, @@ -339,7 +309,7 @@ erts_queue_dist_message(Process *rcvr, Sint tok_serial = 0; #endif #ifdef ERTS_SMP - ErtsProcLocks need_locks; + erts_aint_t state; #endif ERTS_SMP_LC_ASSERT(*rcvr_locks == erts_proc_lc_my_proc_locks(rcvr)); @@ -347,20 +317,21 @@ erts_queue_dist_message(Process *rcvr, mp = message_alloc(); #ifdef ERTS_SMP - need_locks = ~(*rcvr_locks) & (ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); - if (need_locks) { - *rcvr_locks |= need_locks; - if (erts_smp_proc_trylock(rcvr, need_locks) == EBUSY) { - if (need_locks == ERTS_PROC_LOCK_MSGQ) { + if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) { + if (erts_smp_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) { + ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ; + if (*rcvr_locks & ERTS_PROC_LOCK_STATUS) { erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_STATUS); - need_locks = (ERTS_PROC_LOCK_MSGQ - | ERTS_PROC_LOCK_STATUS); + need_locks |= ERTS_PROC_LOCK_STATUS; } erts_smp_proc_lock(rcvr, need_locks); } } - if (rcvr->is_exiting || ERTS_PROC_PENDING_EXIT(rcvr)) { + state = erts_smp_atomic32_read_acqb(&rcvr->state); + if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) { + if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) + erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); /* Drop message if receiver is exiting or has a pending exit ... */ if (is_not_nil(token)) { ErlHeapFragment *heap_frag; @@ -376,6 +347,8 @@ erts_queue_dist_message(Process *rcvr, /* Ahh... need to decode it in order to trace it... */ ErlHeapFragment *mbuf; Eterm msg; + if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) + erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); message_free(mp); msg = erts_msg_distext2heap(rcvr, rcvr_locks, &mbuf, &token, dist_ext); if (is_value(msg)) @@ -437,26 +410,33 @@ erts_queue_dist_message(Process *rcvr, mp->data.dist_ext = dist_ext; LINK_MESSAGE(rcvr, mp); - notify_new_message(rcvr); + if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) + erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); + + erts_proc_notify_new_message(rcvr); } } /* Add a message last in message queue */ -void -erts_queue_message(Process* receiver, - ErtsProcLocks *receiver_locks, - ErlHeapFragment* bp, - Eterm message, - Eterm seq_trace_token +static Sint +queue_message(Process *c_p, + Process* receiver, + ErtsProcLocks *receiver_locks, + erts_aint32_t *receiver_state, + ErlHeapFragment* bp, + Eterm message, + Eterm seq_trace_token #ifdef USE_VM_PROBES , Eterm dt_utag #endif -) + ) { + Sint res; ErlMessage* mp; -#ifdef ERTS_SMP - ErtsProcLocks need_locks; -#else + int locked_msgq = 0; + erts_aint_t state; + +#ifndef ERTS_SMP ASSERT(bp != NULL || receiver->mbuf == NULL); #endif @@ -464,31 +444,45 @@ erts_queue_message(Process* receiver, mp = message_alloc(); + if (receiver_state) + state = *receiver_state; + else + state = erts_smp_atomic32_read_acqb(&receiver->state); + #ifdef ERTS_SMP - need_locks = ~(*receiver_locks) & (ERTS_PROC_LOCK_MSGQ - | ERTS_PROC_LOCK_STATUS); - if (need_locks) { - *receiver_locks |= need_locks; - if (erts_smp_proc_trylock(receiver, need_locks) == EBUSY) { - if (need_locks == ERTS_PROC_LOCK_MSGQ) { + + if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) + goto exiting; + + if (!(*receiver_locks & ERTS_PROC_LOCK_MSGQ)) { + if (erts_smp_proc_trylock(receiver, ERTS_PROC_LOCK_MSGQ) == EBUSY) { + ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ; + if (*receiver_locks & ERTS_PROC_LOCK_STATUS) { erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_STATUS); - need_locks = (ERTS_PROC_LOCK_MSGQ - | ERTS_PROC_LOCK_STATUS); + need_locks |= ERTS_PROC_LOCK_STATUS; } erts_smp_proc_lock(receiver, need_locks); } + locked_msgq = 1; + state = erts_smp_atomic32_read_nob(&receiver->state); + if (receiver_state) + *receiver_state = state; } - if (receiver->is_exiting || ERTS_PROC_PENDING_EXIT(receiver)) { - /* Drop message if receiver is exiting or has a pending - * exit ... - */ +#endif + + if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) { +#ifdef ERTS_SMP + exiting: +#endif + /* Drop message if receiver is exiting or has a pending exit... */ + if (locked_msgq) + erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ); if (bp) free_message_buffer(bp); message_free(mp); - return; + return 0; } -#endif ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = seq_trace_token; @@ -498,7 +492,10 @@ erts_queue_message(Process* receiver, mp->next = NULL; mp->data.heap_frag = bp; -#ifdef ERTS_SMP +#ifndef ERTS_SMP + res = receiver->msg.len; +#else + res = receiver->u.alive.msg_inq.len; if (*receiver_locks & ERTS_PROC_LOCK_MAIN) { /* * We move 'in queue' to 'private queue' and place @@ -508,15 +505,15 @@ erts_queue_message(Process* receiver, * we don't need to include the 'in queue' in * the root set when garbage collecting. */ + res += receiver->msg.len; ERTS_SMP_MSGQ_MV_INQ2PRIVQ(receiver); LINK_MESSAGE_PRIVQ(receiver, mp); } - else { + else +#endif + { LINK_MESSAGE(receiver, mp); } -#else - LINK_MESSAGE(receiver, mp); -#endif #ifdef USE_VM_PROBES if (DTRACE_ENABLED(message_queued)) { @@ -536,15 +533,43 @@ erts_queue_message(Process* receiver, tok_label, tok_lastcnt, tok_serial); } #endif - notify_new_message(receiver); - if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) { + if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) trace_receive(receiver, message); - } + + if (locked_msgq) + erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ); + + erts_proc_notify_new_message(receiver); #ifndef ERTS_SMP ERTS_HOLE_CHECK(receiver); #endif + return res; +} + +void +erts_queue_message(Process* receiver, + ErtsProcLocks *receiver_locks, + ErlHeapFragment* bp, + Eterm message, + Eterm seq_trace_token +#ifdef USE_VM_PROBES + , Eterm dt_utag +#endif + ) +{ + queue_message(NULL, + receiver, + receiver_locks, + NULL, + bp, + message, + seq_trace_token +#ifdef USE_VM_PROBES + , dt_utag +#endif + ); } void @@ -576,9 +601,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) #endif #ifdef HARD_DEBUG - ProcBin *dbg_mso_start = off_heap->mso; - ErlFunThing *dbg_fun_start = off_heap->funs; - ExternalThing *dbg_external_start = off_heap->externals; + struct erl_off_heap_header* dbg_oh_start = off_heap->first; Eterm dbg_term, dbg_token; ErlHeapFragment *dbg_bp; Uint *dbg_hp, *dbg_thp_start; @@ -752,48 +775,16 @@ copy_done: int i, j; ErlHeapFragment* frag; { - ProcBin *mso = off_heap->mso; - i = j = 0; - while (mso != dbg_mso_start) { - mso = mso->next; - i++; - } - for (frag=bp; frag; frag=frag->next) { - mso = frag->off_heap.mso; - while (mso) { - mso = mso->next; - j++; - } - } - ASSERT(i == j); - } - { - ErlFunThing *fun = off_heap->funs; + struct erl_off_heap_header* dbg_oh = off_heap->first; i = j = 0; - while (fun != dbg_fun_start) { - fun = fun->next; + while (dbg_oh != dbg_oh_start) { + dbg_oh = dbg_oh->next; i++; } for (frag=bp; frag; frag=frag->next) { - fun = frag->off_heap.funs; - while (fun) { - fun = fun->next; - j++; - } - } - ASSERT(i == j); - } - { - ExternalThing *external = off_heap->externals; - i = j = 0; - while (external != dbg_external_start) { - external = external->next; - i++; - } - for (frag=bp; frag; frag=frag->next) { - external = frag->off_heap.externals; - while (external) { - external = external->next; + dbg_oh = frag->off_heap.first; + while (dbg_oh) { + dbg_oh = dbg_oh->next; j++; } } @@ -878,7 +869,7 @@ erts_move_msg_attached_data_to_heap(Eterm **hpp, ErlOffHeap *ohp, ErlMessage *ms * Send a local message when sender & receiver processes are known. */ -void +Sint erts_send_message(Process* sender, Process* receiver, ErtsProcLocks *receiver_locks, @@ -888,6 +879,7 @@ erts_send_message(Process* sender, Uint msize; ErlHeapFragment* bp = NULL; Eterm token = NIL; + Sint res = 0; #ifdef USE_VM_PROBES DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(receiver_name, 64); @@ -974,15 +966,17 @@ erts_send_message(Process* sender, msize, tok_label, tok_lastcnt, tok_serial); } #endif - erts_queue_message(receiver, - receiver_locks, - bp, - message, - token + res = queue_message(NULL, + receiver, + receiver_locks, + NULL, + bp, + message, + token #ifdef USE_VM_PROBES - , utag + , utag #endif - ); + ); BM_SWAP_TIMER(send,system); } else if (sender == receiver) { /* Drop message if receiver has a pending exit ... */ @@ -1026,31 +1020,45 @@ erts_send_message(Process* sender, ERTS_SMP_MSGQ_MV_INQ2PRIVQ(receiver); LINK_MESSAGE_PRIVQ(receiver, mp); + res = receiver->msg.len; + if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) { trace_receive(receiver, message); } } BM_SWAP_TIMER(send,system); - return; } else { #ifdef ERTS_SMP ErlOffHeap *ohp; Eterm *hp; + erts_aint32_t state; + BM_SWAP_TIMER(send,size); msize = size_object(message); BM_SWAP_TIMER(size,send); - hp = erts_alloc_message_heap(msize,&bp,&ohp,receiver,receiver_locks); + hp = erts_alloc_message_heap_state(msize, + &bp, + &ohp, + receiver, + receiver_locks, + &state); BM_SWAP_TIMER(send,copy); message = copy_struct(message, msize, &hp, ohp); BM_MESSAGE_COPIED(msz); BM_SWAP_TIMER(copy,send); DTRACE6(message_send, sender_name, receiver_name, msize, tok_label, tok_lastcnt, tok_serial); - erts_queue_message(receiver, receiver_locks, bp, message, token + res = queue_message(sender, + receiver, + receiver_locks, + &state, + bp, + message, + token #ifdef USE_VM_PROBES - , NIL + , NIL #endif - ); + ); BM_SWAP_TIMER(send,system); #else ErlMessage* mp = message_alloc(); @@ -1080,12 +1088,9 @@ erts_send_message(Process* sender, mp->next = NULL; mp->data.attached = NULL; LINK_MESSAGE(receiver, mp); + res = receiver->msg.len; + erts_proc_notify_new_message(receiver); - if (receiver->status == P_WAITING) { - erts_add_to_runq(receiver); - } else if (receiver->status == P_SUSPENDED) { - receiver->rstatus = P_RUNABLE; - } if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) { trace_receive(receiver, message); } @@ -1093,6 +1098,7 @@ erts_send_message(Process* sender, #endif /* #ifndef ERTS_SMP */ return; } + return res; } /* diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index 3e9a24ee81..2ae94965b1 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -90,7 +90,7 @@ typedef struct { ErlMessage* first; ErlMessage** last; /* point to the last next pointer */ ErlMessage** save; - int len; /* queue length */ + Sint len; /* queue length */ /* * The following two fields are used by the recv_mark/1 and @@ -105,7 +105,7 @@ typedef struct { typedef struct { ErlMessage* first; ErlMessage** last; /* point to the last next pointer */ - int len; /* queue length */ + Sint len; /* queue length */ } ErlMessageInQueue; #endif @@ -125,23 +125,23 @@ typedef struct { #ifdef ERTS_SMP /* Move in message queue to end of private message queue */ -#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(P) \ -do { \ - if ((P)->msg_inq.first) { \ - *(P)->msg.last = (P)->msg_inq.first; \ - (P)->msg.last = (P)->msg_inq.last; \ - (P)->msg.len += (P)->msg_inq.len; \ - (P)->msg_inq.first = NULL; \ - (P)->msg_inq.last = &(P)->msg_inq.first; \ - (P)->msg_inq.len = 0; \ - } \ +#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(P) \ +do { \ + if ((P)->u.alive.msg_inq.first) { \ + *(P)->msg.last = (P)->u.alive.msg_inq.first; \ + (P)->msg.last = (P)->u.alive.msg_inq.last; \ + (P)->msg.len += (P)->u.alive.msg_inq.len; \ + (P)->u.alive.msg_inq.first = NULL; \ + (P)->u.alive.msg_inq.last = &(P)->u.alive.msg_inq.first; \ + (P)->u.alive.msg_inq.len = 0; \ + } \ } while (0) /* Add message last in message queue */ #define LINK_MESSAGE(p, mp) do { \ - *(p)->msg_inq.last = (mp); \ - (p)->msg_inq.last = &(mp)->next; \ - (p)->msg_inq.len++; \ + *(p)->u.alive.msg_inq.last = (mp); \ + (p)->u.alive.msg_inq.last = &(mp)->next; \ + (p)->u.alive.msg_inq.len++; \ } while(0) #else @@ -234,7 +234,7 @@ void erts_queue_message(Process*, ErtsProcLocks*, ErlHeapFragment*, Eterm, Eterm #endif ); void erts_deliver_exit_message(Eterm, Process*, ErtsProcLocks *, Eterm, Eterm); -void erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm, unsigned); +Sint erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm, unsigned); void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp); void erts_move_msg_mbuf_to_heap(Eterm**, ErlOffHeap*, ErlMessage *); diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index b323bc7f69..594c51a5db 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -311,6 +311,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, #endif Eterm receiver = to_pid->pid; int flush_me = 0; + int scheduler = erts_get_scheduler_id() != 0; if (env != NULL) { c_p = env->proc; @@ -330,8 +331,11 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, #if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP) rp_had_locks = rp_locks; #endif - rp = erts_pid2proc_opt(c_p, ERTS_PROC_LOCK_MAIN, - receiver, rp_locks, ERTS_P2P_FLG_SMP_INC_REFC); + + rp = (scheduler + ? erts_proc_lookup(receiver) + : erts_pid2proc_opt(c_p, ERTS_PROC_LOCK_MAIN, + receiver, rp_locks, ERTS_P2P_FLG_SMP_INC_REFC)); if (rp == NULL) { ASSERT(env == NULL || receiver != c_p->id); return 0; @@ -358,12 +362,12 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, , NIL #endif ); - if (rp_locks) { - ERTS_SMP_LC_ASSERT(rp_locks == (rp_had_locks | (ERTS_PROC_LOCK_MSGQ | - ERTS_PROC_LOCK_STATUS))); - erts_smp_proc_unlock(rp, (ERTS_PROC_LOCK_MSGQ | ERTS_PROC_LOCK_STATUS)); - } - erts_smp_proc_dec_refc(rp); + if (c_p == rp) + rp_locks &= ~ERTS_PROC_LOCK_MAIN; + if (rp_locks) + erts_smp_proc_unlock(rp, rp_locks); + if (!scheduler) + erts_smp_proc_dec_refc(rp); if (flush_me) { cache_env(env); } @@ -1520,6 +1524,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) if (len < 0) { BIF_ERROR(BIF_P, BADARG); } + lib_name = (char *) erts_alloc(ERTS_ALC_T_TMP, len + 1); if (intlist_to_buf(BIF_ARG_1, lib_name, len) != len) { @@ -1528,6 +1533,12 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) } lib_name[len] = '\0'; + if (!erts_try_seize_code_write_permission(BIF_P)) { + erts_free(ERTS_ALC_T_TMP, lib_name); + ERTS_BIF_YIELD2(bif_export[BIF_load_nif_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } + /* Block system (is this the right place to do it?) */ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -1541,11 +1552,11 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ASSERT(caller != NULL); mod_atom = caller[0]; ASSERT(is_atom(mod_atom)); - mod=erts_get_module(mod_atom); + mod=erts_get_module(mod_atom, erts_active_code_ix()); ASSERT(mod != NULL); - if (!in_area(caller, mod->code, mod->code_length)) { - ASSERT(in_area(caller, mod->old_code, mod->old_code_length)); + if (!in_area(caller, mod->curr.code, mod->curr.code_length)) { + ASSERT(in_area(caller, mod->old.code, mod->old.code_length)); ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old " "module '%T' not allowed", mod_atom); @@ -1591,7 +1602,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) BeamInstr** code_pp; ErlNifFunc* f = &entry->funcs[i]; if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom) - || (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) { + || (code_pp = get_func_pp(mod->curr.code, f_atom, f->arity))==NULL) { ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u", mod_atom, f->name, f->arity); } @@ -1620,18 +1631,18 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) erts_refc_init(&lib->rt_dtor_cnt, 0); lib->mod = mod; env.mod_nif = lib; - if (mod->nif != NULL) { /* Reload */ + if (mod->curr.nif != NULL) { /* Reload */ int k; - lib->priv_data = mod->nif->priv_data; + lib->priv_data = mod->curr.nif->priv_data; - ASSERT(mod->nif->entry != NULL); + ASSERT(mod->curr.nif->entry != NULL); if (entry->reload == NULL) { ret = load_nif_error(BIF_P,reload,"Reload not supported by this NIF library."); goto error; } /* Check that no NIF is removed */ - for (k=0; k < mod->nif->entry->num_of_funcs; k++) { - ErlNifFunc* old_func = &mod->nif->entry->funcs[k]; + for (k=0; k < mod->curr.nif->entry->num_of_funcs; k++) { + ErlNifFunc* old_func = &mod->curr.nif->entry->funcs[k]; for (i=0; i < entry->num_of_funcs; i++) { if (old_func->arity == entry->funcs[i].arity && sys_strcmp(old_func->name, entry->funcs[i].name) == 0) { @@ -1652,24 +1663,24 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ret = load_nif_error(BIF_P, reload, "Library reload-call unsuccessful."); } else { - mod->nif->entry = NULL; /* to prevent 'unload' callback */ - erts_unload_nif(mod->nif); + mod->curr.nif->entry = NULL; /* to prevent 'unload' callback */ + erts_unload_nif(mod->curr.nif); reload_warning = 1; } } else { lib->priv_data = NULL; - if (mod->old_nif != NULL) { /* Upgrade */ - void* prev_old_data = mod->old_nif->priv_data; + if (mod->old.nif != NULL) { /* Upgrade */ + void* prev_old_data = mod->old.nif->priv_data; if (entry->upgrade == NULL) { ret = load_nif_error(BIF_P, upgrade, "Upgrade not supported by this NIF library."); goto error; } erts_pre_nif(&env, BIF_P, lib); - veto = entry->upgrade(&env, &lib->priv_data, &mod->old_nif->priv_data, BIF_ARG_2); + veto = entry->upgrade(&env, &lib->priv_data, &mod->old.nif->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { - mod->old_nif->priv_data = prev_old_data; + mod->old.nif->priv_data = prev_old_data; ret = load_nif_error(BIF_P, upgrade, "Library upgrade-call unsuccessful."); } /*else if (mod->old_nif->priv_data != prev_old_data) { @@ -1689,20 +1700,21 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) /* ** Everything ok, patch the beam code with op_call_nif */ - mod->nif = lib; + mod->curr.nif = lib; for (i=0; i < entry->num_of_funcs; i++) { BeamInstr* code_ptr; erts_atom_get(entry->funcs[i].name, sys_strlen(entry->funcs[i].name), &f_atom); - code_ptr = *get_func_pp(mod->code, f_atom, entry->funcs[i].arity); + code_ptr = *get_func_pp(mod->curr.code, f_atom, entry->funcs[i].arity); if (code_ptr[1] == 0) { code_ptr[5+0] = (BeamInstr) BeamOp(op_call_nif); } else { /* Function traced, patch the original instruction word */ - BpData** bps = (BpData**) code_ptr[1]; - BpData* bp = (BpData*) bps[erts_bp_sched2ix()]; - bp->orig_instr = (BeamInstr) BeamOp(op_call_nif); + GenericBp* g = (GenericBp *) code_ptr[1]; + ASSERT(code_ptr[5+0] == + (BeamInstr) BeamOp(op_i_generic_breakpoint)); + g->orig_instr = (BeamInstr) BeamOp(op_call_nif); } code_ptr[5+1] = (BeamInstr) entry->funcs[i].fptr; code_ptr[5+2] = (BeamInstr) lib; @@ -1722,6 +1734,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_release_code_write_permission(); erts_free(ERTS_ALC_T_TMP, lib_name); if (reload_warning) { diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index e5d99dc4f1..3fc7b2c9c2 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -187,11 +187,7 @@ extern TWinDynNifCallbacks WinDynNifCallbacks; #else # define ERL_NIF_INIT_GLOB # define ERL_NIF_INIT_BODY -# if defined(VXWORKS) -# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* MODNAME ## _init(void) -# else -# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* nif_init(void) -# endif +# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* nif_init(void) #endif diff --git a/erts/emulator/beam/erl_node_container_utils.h b/erts/emulator/beam/erl_node_container_utils.h index 329a2204cc..7b4cb7b042 100644 --- a/erts/emulator/beam/erl_node_container_utils.h +++ b/erts/emulator/beam/erl_node_container_utils.h @@ -128,8 +128,47 @@ extern int erts_use_r9_pids_ports; * Pids * \* */ -#define internal_pid_index(x) (internal_pid_data((x)) \ - & erts_process_tab_index_mask) +#define erts_max_processes erts_proc.max + +typedef struct { + erts_smp_atomic_t *tab; + int max; + int tab_cache_lines; + int pix_per_cache_line; + int pix_cl_mask; + int pix_cl_shift; + int pix_cli_mask; + int pix_cli_shift; +} ErtsProcTab; + +extern ErtsProcTab erts_proc; + +ERTS_GLB_INLINE int erts_pid_data2ix(Eterm pid_data); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE int erts_pid_data2ix(Eterm pid_data) +{ + int n, pix; + + n = (int) pid_data; + if (erts_proc.pix_cl_mask) { + pix = ((n & erts_proc.pix_cl_mask) << erts_proc.pix_cl_shift); + pix += ((n >> erts_proc.pix_cli_shift) & erts_proc.pix_cli_mask); + } + else { + n %= erts_proc.max; + pix = n % erts_proc.tab_cache_lines; + pix *= erts_proc.pix_per_cache_line; + pix += n / erts_proc.tab_cache_lines; + } + ASSERT(0 <= pix && pix < erts_proc.max); + return pix; +} + +#endif + +#define internal_pid_index(x) erts_pid_data2ix(internal_pid_data((x))) #define internal_pid_node_name(x) (internal_pid_node((x))->sysname) #define external_pid_node_name(x) (external_pid_node((x))->sysname) diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index c7fd379367..606a0accf4 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -1298,21 +1298,22 @@ setup_reference_table(void) UnUseTmpHeapNoproc(3); /* Insert all processes */ - for (i = 0; i < erts_max_processes; i++) - if (process_tab[i]) { + for (i = 0; i < erts_max_processes; i++) { + Process *proc = erts_pix2proc(i); + if (proc) { ErlMessage *msg; /* Insert Heap */ - insert_offheap(&(process_tab[i]->off_heap), + insert_offheap(&(proc->off_heap), HEAP_REF, - process_tab[i]->id); + proc->id); /* Insert message buffers */ - for(hfp = process_tab[i]->mbuf; hfp; hfp = hfp->next) + for(hfp = proc->mbuf; hfp; hfp = hfp->next) insert_offheap(&(hfp->off_heap), HEAP_REF, - process_tab[i]->id); + proc->id); /* Insert msg msg buffers */ - for (msg = process_tab[i]->msg.first; msg; msg = msg->next) { + for (msg = proc->msg.first; msg; msg = msg->next) { ErlHeapFragment *heap_frag = NULL; if (msg->data.attached) { if (is_value(ERL_MESSAGE_TERM(msg))) @@ -1320,7 +1321,7 @@ setup_reference_table(void) else { if (msg->data.dist_ext->dep) insert_dist_entry(msg->data.dist_ext->dep, - HEAP_REF, process_tab[i]->id, 0); + HEAP_REF, proc->id, 0); if (is_not_nil(ERL_MESSAGE_TOKEN(msg))) heap_frag = erts_dist_ext_trailer(msg->data.dist_ext); } @@ -1328,10 +1329,10 @@ setup_reference_table(void) if (heap_frag) insert_offheap(&(heap_frag->off_heap), HEAP_REF, - process_tab[i]->id); + proc->id); } #ifdef ERTS_SMP - for (msg = process_tab[i]->msg_inq.first; msg; msg = msg->next) { + for (msg = proc->u.alive.msg_inq.first; msg; msg = msg->next) { ErlHeapFragment *heap_frag = NULL; if (msg->data.attached) { if (is_value(ERL_MESSAGE_TERM(msg))) @@ -1339,7 +1340,7 @@ setup_reference_table(void) else { if (msg->data.dist_ext->dep) insert_dist_entry(msg->data.dist_ext->dep, - HEAP_REF, process_tab[i]->id, 0); + HEAP_REF, proc->id, 0); if (is_not_nil(ERL_MESSAGE_TOKEN(msg))) heap_frag = erts_dist_ext_trailer(msg->data.dist_ext); } @@ -1347,21 +1348,22 @@ setup_reference_table(void) if (heap_frag) insert_offheap(&(heap_frag->off_heap), HEAP_REF, - process_tab[i]->id); + proc->id); } #endif /* Insert links */ - if(process_tab[i]->nlinks) - insert_links(process_tab[i]->nlinks, process_tab[i]->id); - if(process_tab[i]->monitors) - insert_monitors(process_tab[i]->monitors, process_tab[i]->id); + if(proc->nlinks) + insert_links(proc->nlinks, proc->id); + if(proc->monitors) + insert_monitors(proc->monitors, proc->id); /* Insert controller */ { - DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(process_tab[i]); + DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(proc); if (dep) - insert_dist_entry(dep, CTRL_REF, process_tab[i]->id, 0); + insert_dist_entry(dep, CTRL_REF, proc->id, 0); } } + } #ifdef ERTS_SMP erts_foreach_sys_msg_in_q(insert_sys_msg); diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 0f1a0d441a..86454fe1fa 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -56,12 +56,6 @@ #define ERTS_PORT_IS_IN_RUNQ(RQ, P) \ ((P)->sched.next || (P)->sched.prev || (RQ)->ports.start == (P)) -#define ERTS_PORT_NOT_IN_RUNQ(P) \ -do { \ - (P)->sched.prev = NULL; \ - (P)->sched.next = NULL; \ -} while (0) - #ifdef USE_VM_PROBES #define DTRACE_DRIVER(PROBE_NAME, PP) \ if (DTRACE_ENABLED(driver_ready_input)) { \ @@ -167,7 +161,7 @@ enqueue_port(ErtsRunQueue *runq, Port *pp) { ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); pp->sched.next = NULL; - pp->sched.prev = runq->ports.end; + pp->sched.in_runq = 1; if (runq->ports.end) { ASSERT(runq->ports.start); runq->ports.end->sched.next = pp; @@ -177,39 +171,10 @@ enqueue_port(ErtsRunQueue *runq, Port *pp) runq->ports.start = pp; } - runq->ports.info.len++; - if (runq->ports.info.max_len < runq->ports.info.len) - runq->ports.info.max_len = runq->ports.info.len; - runq->len++; - if (runq->max_len < runq->len) - runq->max_len = runq->len; runq->ports.end = pp; ASSERT(runq->ports.start && runq->ports.end); -} -static ERTS_INLINE void -dequeue_port(ErtsRunQueue *runq, Port *pp) -{ - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); - if (pp->sched.next) - pp->sched.next->sched.prev = pp->sched.prev; - else { - ASSERT(runq->ports.end == pp); - runq->ports.end = pp->sched.prev; - } - if (pp->sched.prev) - pp->sched.prev->sched.next = pp->sched.next; - else { - ASSERT(runq->ports.start == pp); - runq->ports.start = pp->sched.next; - } - - ASSERT(runq->ports.info.len > 0); - runq->ports.info.len--; - ASSERT(runq->len > 0); - runq->len--; - ASSERT(runq->ports.start || !runq->ports.end); - ASSERT(runq->ports.end || !runq->ports.start); + erts_smp_inc_runq_len(runq, &runq->ports.info, ERTS_PORT_PRIO_LEVEL); } static ERTS_INLINE Port * @@ -222,16 +187,11 @@ pop_port(ErtsRunQueue *runq) } else { runq->ports.start = runq->ports.start->sched.next; - if (runq->ports.start) - runq->ports.start->sched.prev = NULL; - else { + if (!runq->ports.start) { ASSERT(runq->ports.end == pp); runq->ports.end = NULL; } - ASSERT(runq->ports.info.len > 0); - runq->ports.info.len--; - ASSERT(runq->len > 0); - runq->len--; + erts_smp_dec_runq_len(runq, &runq->ports.info, ERTS_PORT_PRIO_LEVEL); } ASSERT(runq->ports.start || !runq->ports.end); @@ -285,7 +245,7 @@ check_port_queue(ErtsRunQueue *runq, Port *chk_pp, int inq) } ASSERT(no_forward == no_backward); } - ASSERT(no_forward == runq->ports.info.len); + ASSERT(no_forward == RUNQ_READ_LEN(&runq->ports.info.len)); if (chk_pp) { if (chk_pp->sched.taskq || chk_pp->sched.exe_taskq) { ASSERT(chk_pp->sched.taskq != chk_pp->sched.exe_taskq); @@ -467,10 +427,11 @@ erts_port_task_abort(Eterm id, ErtsPortTaskHandle *pthp) ErtsPortTaskQueue *ptqp; ErtsPortTask *ptp; Port *pp; - int port_is_dequeued = 0; pp = &erts_port[internal_port_index(id)]; runq = erts_port_runq(pp); + if (!runq) + return 1; ptp = handle2task(pthp); @@ -505,22 +466,12 @@ erts_port_task_abort(Eterm id, ErtsPortTaskHandle *pthp) if (ptqp->first || pp->sched.taskq != ptqp) ptqp = NULL; - else { + else pp->sched.taskq = NULL; - if (!pp->sched.exe_taskq) { - dequeue_port(runq, pp); - ERTS_PORT_NOT_IN_RUNQ(pp); - port_is_dequeued = 1; - } - } ERTS_PT_CHK_PRES_PORTQ(runq, pp); erts_smp_runq_unlock(runq); - - if (erts_system_profile_flags.runnable_ports && port_is_dequeued) { - profile_runnable_port(pp, am_inactive); - } port_task_free(ptp); if (ptqp) @@ -575,7 +526,7 @@ erts_port_task_schedule(Eterm id, if (!pp->sched.taskq) { pp->sched.taskq = port_taskq_init(port_taskq_alloc(), pp); - enq_port = !pp->sched.exe_taskq; + enq_port = !pp->sched.in_runq && !pp->sched.exe_taskq; } #ifdef ERTS_SMP @@ -585,13 +536,13 @@ erts_port_task_schedule(Eterm id, /* Port emigrated ... */ erts_smp_atomic_set_nob(&pp->run_queue, (erts_aint_t) xrunq); erts_smp_runq_unlock(runq); - runq = xrunq; + runq = erts_port_runq(pp); + if (!runq) + return -1; } } #endif - ASSERT(!enq_port || !(runq->flags & ERTS_RUNQ_FLG_SUSPENDED)); - ASSERT(pp->sched.taskq); ASSERT(ptp); @@ -633,7 +584,7 @@ erts_port_task_schedule(Eterm id, #elif defined(DEBUG) if (!enq_port && !pp->sched.exe_taskq) { /* We should be in port run q */ - ASSERT(pp->sched.prev || runq->ports.start == pp); + ASSERT(pp->sched.in_runq); } #endif #endif @@ -661,63 +612,54 @@ void erts_port_task_free_port(Port *pp) { ErtsRunQueue *runq; - int port_is_dequeued = 0; + ErtsPortTaskQueue *ptqp; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp)); ASSERT(!(pp->status & ERTS_PORT_SFLGS_DEAD)); runq = erts_port_runq(pp); ASSERT(runq); ERTS_PT_CHK_PRES_PORTQ(runq, pp); - if (pp->sched.exe_taskq) { + ptqp = pp->sched.exe_taskq; + if (ptqp) { /* I (this thread) am currently executing this port, free it when scheduled out... */ - ErtsPortTask *ptp = port_task_alloc(); + ErtsPortTask *ptp; + enqueue_free: + ptp = port_task_alloc(); erts_smp_port_state_lock(pp); pp->status &= ~ERTS_PORT_SFLG_CLOSING; pp->status |= ERTS_PORT_SFLG_FREE_SCHEDULED; erts_may_save_closed_port(pp); erts_smp_port_state_unlock(pp); - ERTS_SMP_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 1); + ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 1); ptp->type = ERTS_PORT_TASK_FREE; ptp->event = (ErlDrvEvent) -1; ptp->event_data = NULL; set_handle(ptp, NULL); - push_task(pp->sched.exe_taskq, ptp); + push_task(ptqp, ptp); ERTS_PT_CHK_PRES_PORTQ(runq, pp); erts_smp_runq_unlock(runq); } else { - ErtsPortTaskQueue *ptqp = pp->sched.taskq; - if (ptqp) { - dequeue_port(runq, pp); - ERTS_PORT_NOT_IN_RUNQ(pp); - port_is_dequeued = 1; + if (pp->sched.in_runq) { + ptqp = pp->sched.taskq; + if (!ptqp) + pp->sched.taskq = ptqp = port_taskq_init(port_taskq_alloc(), pp); + goto enqueue_free; } + ASSERT(!pp->sched.taskq); erts_smp_port_state_lock(pp); pp->status &= ~ERTS_PORT_SFLG_CLOSING; pp->status |= ERTS_PORT_SFLG_FREE_SCHEDULED; erts_may_save_closed_port(pp); erts_smp_port_state_unlock(pp); -#ifdef ERTS_SMP erts_smp_atomic_dec_nob(&pp->refc); /* Not alive */ -#endif - ERTS_SMP_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 0); /* Lock */ + ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 0); /* Lock */ handle_remaining_tasks(runq, pp); /* May release runq lock */ ASSERT(!pp->sched.exe_taskq && (!ptqp || !ptqp->first)); pp->sched.taskq = NULL; ERTS_PT_CHK_PRES_PORTQ(runq, pp); -#ifndef ERTS_SMP - ASSERT(pp->status & ERTS_PORT_SFLG_PORT_DEBUG); - erts_port_status_set(pp, ERTS_PORT_SFLG_FREE); -#endif erts_smp_runq_unlock(runq); - - if (erts_system_profile_flags.runnable_ports && port_is_dequeued) { - profile_runnable_port(pp, am_inactive); - } - - if (ptqp) - port_taskq_free(ptqp); } } @@ -738,7 +680,6 @@ typedef struct { int erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) { - int port_was_enqueued = 0; Port *pp; ErtsPortTaskQueue *ptqp; ErtsPortTask *ptp; @@ -757,11 +698,18 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) goto done; } - ERTS_PORT_NOT_IN_RUNQ(pp); + ASSERT(pp->sched.in_runq); + pp->sched.in_runq = 0; + if (!pp->sched.taskq) { + if (erts_system_profile_flags.runnable_ports) + profile_runnable_port(pp, am_inactive); + res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks) + != (erts_aint_t) 0); + goto done; + } *curr_port_pp = pp; - ASSERT(pp->sched.taskq); ASSERT(pp->sched.taskq->first); ptqp = pp->sched.taskq; pp->sched.taskq = NULL; @@ -823,12 +771,8 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) handle_remaining_tasks(runq, pp); ASSERT(!ptqp->first && (!pp->sched.taskq || !pp->sched.taskq->first)); -#ifdef ERTS_SMP erts_smp_atomic_dec_nob(&pp->refc); /* Not alive */ - ERTS_SMP_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 0); /* Lock */ -#else - erts_port_status_bor_set(pp, ERTS_PORT_SFLG_FREE); -#endif + ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 0); /* Lock */ port_task_free(ptp); if (pp->sched.taskq) @@ -918,6 +862,8 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) if (!pp->sched.taskq) { ASSERT(pp->sched.exe_taskq); pp->sched.exe_taskq = NULL; + if (erts_system_profile_flags.runnable_ports) + profile_runnable_port(pp, am_inactive); } else { #ifdef ERTS_SMP @@ -940,14 +886,20 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) else { /* Port emigrated ... */ erts_smp_atomic_set_nob(&pp->run_queue, (erts_aint_t) xrunq); - enqueue_port(xrunq, pp); - ASSERT(pp->sched.exe_taskq); - pp->sched.exe_taskq = NULL; - erts_smp_runq_unlock(xrunq); - erts_smp_notify_inc_runq(xrunq); + erts_smp_runq_unlock(runq); + + xrunq = erts_port_runq(pp); + if (xrunq) { + enqueue_port(xrunq, pp); + ASSERT(pp->sched.exe_taskq); + pp->sched.exe_taskq = NULL; + erts_smp_runq_unlock(xrunq); + erts_smp_notify_inc_runq(xrunq); + } + + erts_smp_runq_lock(runq); } #endif - port_was_enqueued = 1; } res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks) @@ -957,10 +909,6 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) port_taskq_free(ptqp); - if (erts_system_profile_flags.runnable_ports && (port_was_enqueued != 1)) { - profile_runnable_port(pp, am_inactive); - } - /* trace port scheduling, out */ if (IS_TRACED_FL(pp, F_TRACE_SCHED_PORTS)) { trace_sched_ports(pp, am_out); @@ -1049,63 +997,33 @@ erts_port_is_scheduled(Port *pp) { int res; ErtsRunQueue *runq = erts_port_runq(pp); + if (!runq) + return 0; res = pp->sched.taskq || pp->sched.exe_taskq; erts_smp_runq_unlock(runq); return res; } #ifdef ERTS_SMP +void +erts_enqueue_port(ErtsRunQueue *rq, Port *pp) +{ + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); + ASSERT(rq == (ErtsRunQueue *) erts_smp_atomic_read_nob(&pp->run_queue)); + ASSERT(pp->sched.in_runq); + enqueue_port(rq, pp); +} -ErtsMigrateResult -erts_port_migrate(Port *prt, int *prt_locked, - ErtsRunQueue *from_rq, int *from_locked, - ErtsRunQueue *to_rq, int *to_locked) +Port * +erts_dequeue_port(ErtsRunQueue *rq) { - ERTS_SMP_LC_ASSERT(*from_locked); - ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked); - ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked); - - if (!*from_locked || !*to_locked) { - if (from_rq < to_rq) { - if (!*to_locked) { - if (!*from_locked) - erts_smp_runq_lock(from_rq); - erts_smp_runq_lock(to_rq); - } - else if (erts_smp_runq_trylock(from_rq) == EBUSY) { - erts_smp_runq_unlock(to_rq); - erts_smp_runq_lock(from_rq); - erts_smp_runq_lock(to_rq); - } - } - else { - if (!*from_locked) { - if (!*to_locked) - erts_smp_runq_lock(to_rq); - erts_smp_runq_lock(from_rq); - } - else if (erts_smp_runq_trylock(to_rq) == EBUSY) { - erts_smp_runq_unlock(from_rq); - erts_smp_runq_lock(to_rq); - erts_smp_runq_lock(from_rq); - } - } - *to_locked = *from_locked = 1; - } - ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked); - ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked); - - /* Refuse to migrate to a suspended run queue */ - if (to_rq->flags & ERTS_RUNQ_FLG_SUSPENDED) - return ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED; - if (from_rq != (ErtsRunQueue *) erts_smp_atomic_read_nob(&prt->run_queue)) - return ERTS_MIGRATE_FAILED_RUNQ_CHANGED; - if (!ERTS_PORT_IS_IN_RUNQ(from_rq, prt)) - return ERTS_MIGRATE_FAILED_NOT_IN_RUNQ; - dequeue_port(from_rq, prt); - erts_smp_atomic_set_nob(&prt->run_queue, (erts_aint_t) to_rq); - enqueue_port(to_rq, prt); - return ERTS_MIGRATE_SUCCESS; + Port *pp; + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); + pp = pop_port(rq); + ASSERT(!pp + || rq == (ErtsRunQueue *) erts_smp_atomic_read_nob(&pp->run_queue)); + ASSERT(!pp || pp->sched.in_runq); + return pp; } #endif diff --git a/erts/emulator/beam/erl_port_task.h b/erts/emulator/beam/erl_port_task.h index d7104e1143..fd88b1c1ff 100644 --- a/erts/emulator/beam/erl_port_task.h +++ b/erts/emulator/beam/erl_port_task.h @@ -62,7 +62,7 @@ typedef struct ErtsPortTaskQueue_ ErtsPortTaskQueue; typedef struct { Port *next; - Port *prev; + int in_runq; ErtsPortTaskQueue *taskq; ErtsPortTaskQueue *exe_taskq; } ErtsPortTaskSched; @@ -92,7 +92,7 @@ ERTS_GLB_INLINE void erts_port_task_init_sched(ErtsPortTaskSched *ptsp) { ptsp->next = NULL; - ptsp->prev = NULL; + ptsp->in_runq = 0; ptsp->taskq = NULL; ptsp->exe_taskq = NULL; } @@ -123,13 +123,10 @@ int erts_port_task_schedule(Eterm, ErlDrvEventData); void erts_port_task_free_port(Port *); int erts_port_is_scheduled(Port *); + #ifdef ERTS_SMP -ErtsMigrateResult erts_port_migrate(Port *, - int *, - ErtsRunQueue *, - int *, - ErtsRunQueue *, - int *); +void erts_enqueue_port(ErtsRunQueue *rq, Port *pp); +Port *erts_dequeue_port(ErtsRunQueue *rq); #endif #undef ERTS_INCLUDE_SCHEDULER_INTERNALS #endif /* ERL_PORT_TASK_H__ */ diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index 34da9cab84..2320b64295 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -437,7 +437,10 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, } break; case BINARY_DEF: - { + if (header_is_bin_matchstate(*boxed_val(wobj))) { + PRINT_STRING(res, fn, arg, "#MatchState"); + } + else { ProcBin* pb = (ProcBin *) binary_val(wobj); if (pb->size == 1) PRINT_STRING(res, fn, arg, "<<1 byte>>"); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 0fa2def5af..c58bf40435 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -94,34 +94,194 @@ #define HIGH_BIT (1 << PRIORITY_HIGH) #define NORMAL_BIT (1 << PRIORITY_NORMAL) #define LOW_BIT (1 << PRIORITY_LOW) +#define PORT_BIT (1 << ERTS_PORT_PRIO_LEVEL) -#define ERTS_MAYBE_SAVE_TERMINATING_PROCESS(P) \ -do { \ - ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx)); \ - if (saved_term_procs.end) \ - save_terminating_process((P)); \ -} while (0) +#define ERTS_EMPTY_RUNQ(RQ) \ + ((ERTS_RUNQ_FLGS_GET_NOB((RQ)) & ERTS_RUNQ_FLGS_QMASK) == 0 \ + && (RQ)->misc.start == NULL) -#define ERTS_EMPTY_RUNQ(RQ) \ - ((RQ)->len == 0 && (RQ)->misc.start == NULL) +#undef RUNQ_READ_RQ +#undef RUNQ_SET_RQ +#define RUNQ_READ_RQ(X) ((ErtsRunQueue *) erts_smp_atomic_read_nob((X))) +#define RUNQ_SET_RQ(X, RQ) erts_smp_atomic_set_nob((X), (erts_aint_t) (RQ)) + +#ifdef DEBUG +# if defined(ARCH_64) && !HALFWORD_HEAP +# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) \ + (RUNQ_SET_RQ((RQP), (0xdeadbeefdead0003LL | ((N) << 4))) +# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) \ +do { \ + ASSERT((RQP) != NULL); \ + ASSERT(((((Uint) (RQP)) & ((Uint) 0x3))) == ((Uint) 0)); \ + ASSERT((((Uint) (RQP)) & ~((Uint) 0xffff)) != ((Uint) 0xdeadbeefdead0000LL));\ +} while (0) +# else +# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) \ + (RUNQ_SET_RQ((RQP), (0xdead0003 | ((N) << 4)))) +# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) \ +do { \ + ASSERT((RQP) != NULL); \ + ASSERT(((((UWord) (RQP)) & ((UWord) 1))) == ((UWord) 0)); \ + ASSERT((((UWord) (RQP)) & ~((UWord) 0xffff)) != ((UWord) 0xdead0000)); \ +} while (0) +# endif +#else +# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) +# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) +#endif #define ERTS_EMPTY_RUNQ_PORTS(RQ) \ - ((RQ)->ports.info.len == 0 && (RQ)->misc.start == NULL) + (RUNQ_READ_LEN(&(RQ)->ports.info.len) == 0 && (RQ)->misc.start == NULL) extern BeamInstr beam_apply[]; extern BeamInstr beam_exit[]; extern BeamInstr beam_continue_exit[]; -static Sint p_last; -static Sint p_next; -static Sint p_serial; -static Uint p_serial_mask; -static Uint p_serial_shift; +#ifdef ARCH_32 + +union { + erts_smp_dw_atomic_t pid_data; + char align[ERTS_CACHE_LINE_SIZE]; +} last erts_align_attribute(ERTS_CACHE_LINE_SIZE); + + +static ERTS_INLINE Uint64 +dw_aint_to_uint64(erts_dw_aint_t *dw) +{ +#ifdef ETHR_SU_DW_NAINT_T__ + return (Uint64) dw->dw_sint; +#else + Uint64 res; + res = (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_HIGH_WORD]); + res <<= 32; + res |= (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_LOW_WORD]); + return res; +#endif +} + +static void +unint64_to_dw_aint(erts_dw_aint_t *dw, Uint64 val) +{ +#ifdef ETHR_SU_DW_NAINT_T__ + dw->dw_sint = (ETHR_SU_DW_NAINT_T__) val; +#else + dw->sint[ERTS_DW_AINT_LOW_WORD] = (erts_aint_t) (val & 0xffffffff); + dw->sint[ERTS_DW_AINT_HIGH_WORD] = (erts_aint_t) ((val >> 32) & 0xffffffff); +#endif +} + +static ERTS_INLINE void +last_pid_data_init_nob(Uint64 val) +{ + erts_dw_aint_t dw; + unint64_to_dw_aint(&dw, val); + erts_smp_dw_atomic_init_nob(&last.pid_data, &dw); +} + +static ERTS_INLINE void +last_pid_data_set_relb(Uint64 val) +{ + erts_dw_aint_t dw; + unint64_to_dw_aint(&dw, val); + erts_smp_dw_atomic_set_relb(&last.pid_data, &dw); +} + +static ERTS_INLINE Uint64 +last_pid_data_read_nob(void) +{ + erts_dw_aint_t dw; + erts_smp_dw_atomic_read_nob(&last.pid_data, &dw); + return dw_aint_to_uint64(&dw); +} + +static ERTS_INLINE Uint64 +last_pid_data_read_acqb(void) +{ + erts_dw_aint_t dw; + erts_smp_dw_atomic_read_acqb(&last.pid_data, &dw); + return dw_aint_to_uint64(&dw); +} + +static ERTS_INLINE Uint64 +last_pid_data_cmpxchg_relb(Uint64 new, Uint64 exp) +{ + erts_dw_aint_t dw_new, dw_xchg; + + unint64_to_dw_aint(&dw_new, new); + unint64_to_dw_aint(&dw_xchg, exp); + + if (erts_smp_dw_atomic_cmpxchg_relb(&last.pid_data, &dw_new, &dw_xchg)) + return exp; + else + return dw_aint_to_uint64(&dw_xchg); +} + +#elif defined(ARCH_64) + +union { + erts_smp_atomic_t pid_data; + char align[ERTS_CACHE_LINE_SIZE]; +} last erts_align_attribute(ERTS_CACHE_LINE_SIZE); + +static ERTS_INLINE void +last_pid_data_init_nob(Uint64 val) +{ + erts_smp_atomic_init_nob(&last.pid_data, (erts_aint_t) val); +} + +static ERTS_INLINE void +last_pid_data_set_relb(Uint64 val) +{ + erts_smp_atomic_set_relb(&last.pid_data, (erts_aint_t) val); +} + +static ERTS_INLINE Uint64 +last_pid_data_read_nob(void) +{ + return (Uint64) erts_smp_atomic_read_nob(&last.pid_data); +} + +static ERTS_INLINE Uint64 +last_pid_data_read_acqb(void) +{ + return (Uint64) erts_smp_atomic_read_acqb(&last.pid_data); +} + +static ERTS_INLINE Uint64 +last_pid_data_cmpxchg_relb(Uint64 new, Uint64 exp) +{ + return (Uint64) erts_smp_atomic_cmpxchg_relb(&last.pid_data, + (erts_aint_t) new, + (erts_aint_t) exp); +} + +#else +# error "Not 64-bit, nor 32-bit architecture..." +#endif + +static ERTS_INLINE int +last_pid_data_cmp(Uint64 lpd1, Uint64 lpd2) +{ + Uint64 lpd1_wrap; + + if (lpd1 == lpd2) + return 0; + + lpd1_wrap = lpd1 + (((Uint64) 1) << 63); + + if (lpd1 < lpd1_wrap) + return (lpd1 < lpd2 && lpd2 < lpd1_wrap) ? -1 : 1; + else + return (lpd1_wrap <= lpd2 && lpd2 < lpd1) ? 1 : -1; +} + + +#define ERTS_PID_DATA_MASK__ ((1 << _PID_DATA_SIZE) - 1) int erts_sched_compact_load; Uint erts_no_schedulers; -Uint erts_max_processes = ERTS_DEFAULT_MAX_PROCESSES; -Uint erts_process_tab_index_mask; + +ErtsProcTab erts_proc erts_align_attribute(ERTS_CACHE_LINE_SIZE); int erts_sched_thread_suggested_stack_size = -1; @@ -188,7 +348,7 @@ static struct { struct { int active_runqs; int reds; - int max_len; + erts_aint32_t max_len; } prev_rise; Uint n; } balance_info; @@ -208,7 +368,7 @@ erts_sched_stat_t erts_sched_stat; static erts_tsd_key_t sched_data_key; #endif -static erts_smp_mtx_t proc_tab_mtx; +erts_smp_rwmtx_t erts_proc_tab_rwmtx; static erts_smp_atomic32_t function_calls; @@ -231,7 +391,6 @@ typedef union { static ErtsAlignedSchedulerSleepInfo *aligned_sched_sleep_info; -Process** process_tab; static Uint last_reductions; static Uint last_exact_reductions; Uint erts_default_process_flags; @@ -257,11 +416,11 @@ struct ErtsTermProcElement_ { union { struct { Eterm pid; - SysTimeval spawned; - SysTimeval exited; + Uint64 spawned; + Uint64 exited; } process; struct { - SysTimeval time; + Uint64 interval; } bif_invocation; } u; }; @@ -363,6 +522,7 @@ dbg_chk_aux_work_val(erts_aint32_t value) valid |= ERTS_SSI_AUX_WORK_MISC_THR_PRGR; valid |= ERTS_SSI_AUX_WORK_DD; valid |= ERTS_SSI_AUX_WORK_DD_THR_PRGR; + valid |= ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP; #endif #if HAVE_ERTS_MSEG valid |= ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK; @@ -370,6 +530,10 @@ dbg_chk_aux_work_val(erts_aint32_t value) #ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN valid |= ERTS_SSI_AUX_WORK_CHECK_CHILDREN; #endif +#ifdef ERTS_SMP + valid |= ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; + valid |= ERTS_SSI_AUX_WORK_FINISH_BP; +#endif #ifdef ERTS_SSI_AUX_WORK_REAP_PORTS valid |= ERTS_SSI_AUX_WORK_REAP_PORTS; #endif @@ -399,6 +563,53 @@ erts_smp_lc_runq_is_locked(ErtsRunQueue *runq) } #endif +static erts_interval_t *proc_interval; + +static void +proc_interval_init(void) +{ + proc_interval = erts_alloc_permanent_cache_aligned( + ERTS_ALC_T_PROC_INTERVAL, + sizeof(erts_interval_t)); + erts_smp_interval_init(proc_interval); +} + +static ERTS_INLINE Uint64 +get_proc_interval(void) +{ + return erts_smp_current_interval_nob(proc_interval); +} + +static ERTS_INLINE Uint64 +ensure_later_proc_interval(Uint64 interval) +{ + return erts_smp_ensure_later_interval_nob(proc_interval, interval); +} + +static ERTS_INLINE Uint64 +step_proc_interval(void) +{ + return erts_smp_step_interval_nob(proc_interval); +} + +Uint64 +erts_get_proc_interval(void) +{ + return get_proc_interval(); +} + +Uint64 +erts_ensure_later_proc_interval(Uint64 interval) +{ + return ensure_later_proc_interval(interval); +} + +Uint64 +erts_step_proc_interval(void) +{ + return step_proc_interval(); +} + void erts_pre_init_process(void) { @@ -448,7 +659,16 @@ erts_pre_init_process(void) void erts_init_process(int ncpu) { - Uint proc_bits = ERTS_PROC_BITS; + int proc_tab_sz; + int max_proc_bits; + int proc_bits = ERTS_PROC_BITS; + erts_smp_atomic_t *proc_entry; + char *proc_tab_end; + erts_smp_rwmtx_opt_t proc_tab_rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; + proc_tab_rwmtx_opts.type = ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ; + proc_tab_rwmtx_opts.lived = ERTS_SMP_RWMTX_LONG_LIVED; + + proc_interval_init(); #ifdef ERTS_SMP erts_disable_proc_not_running_opt = 0; @@ -459,23 +679,51 @@ erts_init_process(int ncpu) erts_smp_atomic32_init_nob(&process_count, 0); - if (erts_use_r9_pids_ports) { + if (erts_use_r9_pids_ports) proc_bits = ERTS_R9_PROC_BITS; - ASSERT(erts_max_processes <= (1 << ERTS_R9_PROC_BITS)); + + if (erts_proc.max > (1 << proc_bits)) + erts_proc.max = 1 << proc_bits; + + proc_tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(erts_proc.max + * sizeof(erts_smp_atomic_t)); + erts_proc.tab = erts_alloc(ERTS_ALC_T_PROC_TABLE, proc_tab_sz); + proc_tab_end = ((char *) erts_proc.tab) + proc_tab_sz; + proc_entry = erts_proc.tab; + while (proc_tab_end > ((char *) proc_entry)) { + erts_smp_atomic_init_nob(proc_entry, ERTS_AINT_NULL); + proc_entry++; } - process_tab = (Process**) erts_alloc(ERTS_ALC_T_PROC_TABLE, - erts_max_processes*sizeof(Process*)); - sys_memzero(process_tab, erts_max_processes * sizeof(Process*)); + erts_smp_rwmtx_init_opt(&erts_proc_tab_rwmtx, + &proc_tab_rwmtx_opts, + "proc_tab"); + last_pid_data_init_nob(~((Uint64) 0)); - erts_smp_mtx_init(&proc_tab_mtx, "proc_tab"); - p_last = -1; - p_next = 0; - p_serial = 0; + max_proc_bits = erts_fit_in_bits_int32((Sint32) erts_proc.max - 1); + + erts_proc.tab_cache_lines = proc_tab_sz/ERTS_CACHE_LINE_SIZE; + erts_proc.pix_per_cache_line = ERTS_CACHE_LINE_SIZE/sizeof(erts_smp_atomic_t); + if ((erts_proc.max & (erts_proc.max - 1)) + | (erts_proc.pix_per_cache_line & (erts_proc.pix_per_cache_line - 1))) { + /* + * erts_proc.max or erts_proc.pix_per_cache_line + * not a power of 2 :( + */ + erts_proc.pix_cl_mask = 0; + erts_proc.pix_cl_shift = 0; + erts_proc.pix_cli_mask = 0; + erts_proc.pix_cli_shift = 0; + } + else { + ASSERT((erts_proc.tab_cache_lines + & (erts_proc.tab_cache_lines - 1)) == 0); + erts_proc.pix_cl_mask = erts_proc.tab_cache_lines-1; + erts_proc.pix_cl_shift = erts_fit_in_bits_int32(erts_proc.pix_per_cache_line-1); + erts_proc.pix_cli_shift = erts_fit_in_bits_int32(erts_proc.pix_cl_mask); + erts_proc.pix_cli_mask = (1 << (max_proc_bits - erts_proc.pix_cli_shift)) - 1; + } - p_serial_shift = erts_fit_in_bits(erts_max_processes - 1); - p_serial_mask = ((~(~((Uint) 0) << proc_bits)) >> p_serial_shift); - erts_process_tab_index_mask = ~(~((Uint) 0) << p_serial_shift); last_reductions = 0; last_exact_reductions = 0; erts_default_process_flags = 0; @@ -733,8 +981,9 @@ static ERTS_INLINE ErtsProcList * proclist_create(Process *p) { ErtsProcList *plp = proclist_alloc(); + ensure_later_proc_interval(p->started_interval); plp->pid = p->id; - plp->started = p->started; + plp->started_interval = p->started_interval; return plp; } @@ -747,8 +996,7 @@ proclist_destroy(ErtsProcList *plp) static ERTS_INLINE int proclist_same(ErtsProcList *plp, Process *p) { - return (plp->pid == p->id - && erts_cmp_timeval(&plp->started, &p->started) == 0); + return plp->pid == p->id && plp->started_interval == p->started_interval; } ErtsProcList * @@ -1200,7 +1448,94 @@ handle_async_ready_clean(ErtsAuxWorkData *awdp, } } +#endif /* ERTS_USE_ASYNC_READY_Q */ + +#ifdef ERTS_SMP +void +erts_notify_code_ix_activation(Process* p, ErtsThrPrgrVal later) +{ + ErtsAuxWorkData* awdp = &p->scheduler_data->aux_work_data; + ASSERT(awdp->code_ix_activation.code_stager == NULL); + awdp->code_ix_activation.code_stager = p; + awdp->code_ix_activation.thr_prgr = later; + erts_smp_proc_inc_refc(p); + set_aux_work_flags_wakeup_relb(p->scheduler_data->ssi, + ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION); +} + +static erts_aint32_t +handle_code_ix_activation(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +{ + Process* p; + if (!erts_thr_progress_has_reached(awdp->code_ix_activation.thr_prgr)) { + return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; + } + unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION); + p = awdp->code_ix_activation.code_stager; + ASSERT(p); +#ifdef DEBUG + awdp->code_ix_activation.code_stager = NULL; +#endif + erts_commit_staging_code_ix(); + erts_release_code_write_permission(); + erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(p)) { + erts_resume(p, ERTS_PROC_LOCK_STATUS); + } + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_smp_proc_dec_refc(p); + return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; +} +#endif /* ERTS_SMP */ + +#ifdef ERTS_SMP +void +erts_notify_finish_breakpointing(Process* p) +{ + ErtsAuxWorkData* awdp = &p->scheduler_data->aux_work_data; + + ASSERT(awdp->bp_ix_activation.stager == NULL); + awdp->bp_ix_activation.stager = p; + awdp->bp_ix_activation.thr_prgr = erts_thr_progress_later(awdp->esdp); + erts_thr_progress_wakeup(awdp->esdp, awdp->bp_ix_activation.thr_prgr); + erts_smp_proc_inc_refc(p); + set_aux_work_flags_wakeup_relb(p->scheduler_data->ssi, + ERTS_SSI_AUX_WORK_FINISH_BP); +} + +static erts_aint32_t +handle_finish_bp(ErtsAuxWorkData* awdp, erts_aint32_t aux_work) +{ + ErtsThrPrgrVal current = haw_thr_prgr_current(awdp); + + if (!erts_thr_progress_has_reached_this(current, + awdp->bp_ix_activation.thr_prgr)) { + return aux_work & ~ERTS_SSI_AUX_WORK_FINISH_BP; + } + if (erts_finish_breakpointing()) { /* Not done */ + /* Arrange for being called again */ + awdp->bp_ix_activation.thr_prgr = + erts_thr_progress_later(awdp->esdp); + erts_thr_progress_wakeup(awdp->esdp, awdp->bp_ix_activation.thr_prgr); + } else { /* Done */ + Process* p; + + unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_FINISH_BP); + p = awdp->bp_ix_activation.stager; +#ifdef DEBUG + awdp->bp_ix_activation.stager = NULL; #endif + erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(p)) { + erts_resume(p, ERTS_PROC_LOCK_STATUS); + } + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_smp_proc_dec_refc(p); + erts_release_code_write_permission(); + } + return aux_work & ~ERTS_SSI_AUX_WORK_FINISH_BP; +} +#endif /* ERTS_SMP */ static ERTS_INLINE erts_aint32_t handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) @@ -1319,6 +1654,74 @@ handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) return aux_work & ~ERTS_SSI_AUX_WORK_DD_THR_PRGR; } +/* + * Handle scheduled thread progress later operations. + */ +#define ERTS_MAX_THR_PRGR_LATER_OPS 50 + +static ERTS_INLINE erts_aint32_t +handle_thr_prgr_later_op(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +{ + int lops; + ErtsThrPrgrVal current = haw_thr_prgr_current(awdp); + + for (lops = 0; lops < ERTS_MAX_THR_PRGR_LATER_OPS; lops++) { + ErtsThrPrgrLaterOp *lop = awdp->later_op.first; + if (!erts_thr_progress_has_reached_this(current, lop->later)) + return aux_work & ~ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP; + awdp->later_op.first = lop->next; + lop->func(lop->data); + if (!awdp->later_op.first) { + awdp->later_op.last = NULL; + unset_aux_work_flags(awdp->ssi, + ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP); + return aux_work & ~ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP; + } + } + + return aux_work; +} + +#endif /* ERTS_SMP */ + +void +erts_schedule_thr_prgr_later_op(void (*later_func)(void *), + void *later_data, + ErtsThrPrgrLaterOp *lop) +{ +#ifndef ERTS_SMP + later_func(later_data); +#else + ErtsSchedulerData *esdp; + ErtsAuxWorkData *awdp; + int request_wakeup = 1; + + esdp = erts_get_scheduler_data(); + ASSERT(esdp); + awdp = &esdp->aux_work_data; + + lop->func = later_func; + lop->data = later_data; + lop->later = erts_thr_progress_later(esdp); + lop->next = NULL; + if (!awdp->later_op.last) + awdp->later_op.first = lop; + else { + ErtsThrPrgrLaterOp *last = awdp->later_op.last; + last->next = lop; + if (erts_thr_progress_equal(last->later, lop->later)) + request_wakeup = 0; + } + awdp->later_op.last = lop; + set_aux_work_flags_wakeup_nob(awdp->ssi, + ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP); + if (request_wakeup) + erts_thr_progress_wakeup(esdp, lop->later); +#endif +} + +#ifdef ERTS_SMP + static erts_atomic32_t completed_dealloc_count; static void @@ -1544,6 +1947,11 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work, int waiting) | ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC), handle_fix_alloc); +#ifdef ERTS_SMP + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP, + handle_thr_prgr_later_op); +#endif + #if ERTS_USE_ASYNC_READY_Q HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_ASYNC_READY, handle_async_ready); @@ -1573,9 +1981,19 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work, int waiting) handle_mseg_cache_check); #endif +#ifdef ERTS_SMP + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION, + handle_code_ix_activation); +#endif + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_REAP_PORTS, handle_reap_ports); +#ifdef ERTS_SMP + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_FINISH_BP, + handle_finish_bp); +#endif + ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); #ifdef ERTS_SMP @@ -1734,8 +2152,8 @@ sched_waiting_sys(Uint no, ErtsRunQueue *rq) { ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); ASSERT(rq->waiting >= 0); - rq->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK - | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK); + (void) ERTS_RUNQ_FLGS_SET(rq, (ERTS_RUNQ_FLG_OUT_OF_WORK + | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK)); rq->waiting++; rq->waiting *= -1; rq->woken = 0; @@ -1811,8 +2229,8 @@ static ERTS_INLINE void sched_waiting(Uint no, ErtsRunQueue *rq) { ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - rq->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK - | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK); + (void) ERTS_RUNQ_FLGS_SET(rq, (ERTS_RUNQ_FLG_OUT_OF_WORK + | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK)); if (rq->waiting < 0) rq->waiting--; else @@ -1844,9 +2262,8 @@ ongoing_multi_scheduling_block(void) static ERTS_INLINE void empty_runq(ErtsRunQueue *rq) { - erts_aint32_t oifls = erts_smp_atomic32_read_band_nob(&rq->info_flags, - ~ERTS_RUNQ_IFLG_NONEMPTY); - if (oifls & ERTS_RUNQ_IFLG_NONEMPTY) { + Uint32 old_flags = ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_NONEMPTY|ERTS_RUNQ_FLG_PROTECTED); + if (old_flags & ERTS_RUNQ_FLG_NONEMPTY) { #ifdef DEBUG erts_aint32_t empty = erts_smp_atomic32_read_nob(&no_empty_run_queues); /* @@ -1862,9 +2279,8 @@ empty_runq(ErtsRunQueue *rq) static ERTS_INLINE void non_empty_runq(ErtsRunQueue *rq) { - erts_aint32_t oifls = erts_smp_atomic32_read_bor_nob(&rq->info_flags, - ERTS_RUNQ_IFLG_NONEMPTY); - if (!(oifls & ERTS_RUNQ_IFLG_NONEMPTY)) { + Uint32 old_flags = ERTS_RUNQ_FLGS_SET(rq, ERTS_RUNQ_FLG_NONEMPTY); + if (!(old_flags & ERTS_RUNQ_FLG_NONEMPTY)) { #ifdef DEBUG erts_aint32_t empty = erts_smp_atomic32_read_nob(&no_empty_run_queues); /* @@ -2479,19 +2895,16 @@ try_inc_no_active_runqs(int active) static ERTS_INLINE int chk_wake_sched(ErtsRunQueue *crq, int ix, int activate) { - erts_aint32_t iflgs; + Uint32 flags; ErtsRunQueue *wrq; if (crq->ix == ix) return 0; wrq = ERTS_RUNQ_IX(ix); - iflgs = erts_smp_atomic32_read_nob(&wrq->info_flags); - if (!(iflgs & (ERTS_RUNQ_IFLG_SUSPENDED|ERTS_RUNQ_IFLG_NONEMPTY))) { + flags = ERTS_RUNQ_FLGS_GET(wrq); + if (!(flags & (ERTS_RUNQ_FLG_SUSPENDED|ERTS_RUNQ_FLG_NONEMPTY))) { if (activate) { - if (try_inc_no_active_runqs(ix+1)) { - erts_smp_xrunq_lock(crq, wrq); - wrq->flags &= ~ERTS_RUNQ_FLG_INACTIVE; - erts_smp_xrunq_unlock(crq, wrq); - } + if (try_inc_no_active_runqs(ix+1)) + (void) ERTS_RUNQ_FLGS_UNSET(wrq, ERTS_RUNQ_FLG_INACTIVE); } wake_scheduler(wrq, 0); return 1; @@ -2558,9 +2971,7 @@ erts_sched_notify_check_cpu_bind(void) int ix; for (ix = 0; ix < erts_no_run_queues; ix++) { ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - erts_smp_runq_lock(rq); - rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND; - erts_smp_runq_unlock(rq); + (void) ERTS_RUNQ_FLGS_SET(rq, ERTS_RUNQ_FLG_CHK_CPU_BIND); wake_scheduler(rq, 0); } #else @@ -2569,409 +2980,547 @@ erts_sched_notify_check_cpu_bind(void) } -#ifdef ERTS_SMP +static ERTS_INLINE void +enqueue_process(ErtsRunQueue *runq, int prio, Process *p) +{ + ErtsRunPrioQueue *rpq; -ErtsRunQueue * -erts_prepare_emigrate(ErtsRunQueue *c_rq, ErtsRunQueueInfo *c_rqi, int prio) + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); + + erts_smp_inc_runq_len(runq, &runq->procs.prio_info[prio], prio); + + if (prio == PRIORITY_LOW) { + p->schedule_count = RESCHEDULE_LOW; + rpq = &runq->procs.prio[PRIORITY_NORMAL]; + } + else { + p->schedule_count = 1; + rpq = &runq->procs.prio[prio]; + } + + p->next = NULL; + if (rpq->last) + rpq->last->next = p; + else + rpq->first = p; + rpq->last = p; +} + + +static ERTS_INLINE void +unqueue_process(ErtsRunQueue *runq, + ErtsRunPrioQueue *rpq, + ErtsRunQueueInfo *rqi, + int prio, + Process *prev_proc, + Process *proc) { - ASSERT(ERTS_CHK_RUNQ_FLG_EMIGRATE(c_rq->flags, prio)); - ASSERT(ERTS_CHK_RUNQ_FLG_EVACUATE(c_rq->flags, prio) - || c_rqi->len >= c_rqi->migrate.limit.this); + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); - while (1) { - ErtsRunQueue *n_rq = c_rqi->migrate.runq; - ERTS_DBG_VERIFY_VALID_RUNQP(n_rq); - erts_smp_xrunq_lock(c_rq, n_rq); - - /* - * erts_smp_xrunq_lock() may release lock on c_rq! We have - * to check that we still want to emigrate and emigrate - * to the same run queue as before. - */ + if (prev_proc) + prev_proc->next = proc->next; + else + rpq->first = proc->next; + if (!proc->next) + rpq->last = prev_proc; - if (ERTS_CHK_RUNQ_FLG_EMIGRATE(c_rq->flags, prio)) { - Uint32 force = (ERTS_CHK_RUNQ_FLG_EVACUATE(c_rq->flags, prio) - | (c_rq->flags & ERTS_RUNQ_FLG_INACTIVE)); - if (force || c_rqi->len > c_rqi->migrate.limit.this) { - ErtsRunQueueInfo *n_rqi; - /* We still want to emigrate */ - - if (n_rq != c_rqi->migrate.runq) { - /* Ahh... run queue changed; need to do it all over again... */ - erts_smp_runq_unlock(n_rq); - continue; - } - else { + if (!rpq->first) + rpq->last = NULL; - if (prio == ERTS_PORT_PRIO_LEVEL) - n_rqi = &n_rq->ports.info; - else - n_rqi = &n_rq->procs.prio_info[prio]; + erts_smp_dec_runq_len(runq, rqi, prio); +} - if (force || (n_rqi->len < c_rqi->migrate.limit.other)) { - /* emigrate ... */ - return n_rq; - } - } - } - } - ASSERT(n_rq != c_rq); - erts_smp_runq_unlock(n_rq); - if (!(c_rq->flags & ERTS_RUNQ_FLG_INACTIVE)) { - /* No more emigrations to this runq */ - ERTS_UNSET_RUNQ_FLG_EMIGRATE(c_rq->flags, prio); - ERTS_DBG_SET_INVALID_RUNQP(c_rqi->migrate.runq, 0x3); - } +static ERTS_INLINE Process * +dequeue_process(ErtsRunQueue *runq, int prio_q, erts_aint32_t *statep) +{ + erts_aint32_t state; + int prio; + ErtsRunPrioQueue *rpq; + ErtsRunQueueInfo *rqi; + Process *p; + + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); + + ASSERT(PRIORITY_NORMAL == prio_q + || PRIORITY_HIGH == prio_q + || PRIORITY_MAX == prio_q); + rpq = &runq->procs.prio[prio_q]; + p = rpq->first; + if (!p) return NULL; + + ERTS_SMP_DATA_DEPENDENCY_READ_MEMORY_BARRIER; + + state = erts_smp_atomic32_read_nob(&p->state); + if (statep) + *statep = state; + + prio = (int) (ERTS_PSFLG_PRIO_MASK & state); + + rqi = &runq->procs.prio_info[prio]; + + if (p) + unqueue_process(runq, rpq, rqi, prio, NULL, p); + + return p; +} + +static ERTS_INLINE int +check_requeue_process(ErtsRunQueue *rq, int prio_q) +{ + ErtsRunPrioQueue *rpq = &rq->procs.prio[prio_q]; + Process *p = rpq->first; + if (--p->schedule_count > 0 && p != rpq->last) { + /* reschedule */ + rpq->first = p->next; + rpq->last->next = p; + rpq->last = p; + p->next = NULL; + return 1; } + return 0; +} + +#ifdef ERTS_SMP + +static ErtsRunQueue * +check_immigration_need(ErtsRunQueue *c_rq, ErtsMigrationPath *mp, int prio) +{ + int len; + Uint32 f_flags, f_rq_flags; + ErtsRunQueue *f_rq; + + f_flags = mp->prio[prio].flags; + + ASSERT(ERTS_CHK_RUNQ_FLG_IMMIGRATE(mp->flags, prio)); + + f_rq = mp->prio[prio].runq; + if (!f_rq) + return NULL; + + f_rq_flags = ERTS_RUNQ_FLGS_GET(f_rq); + if (f_rq_flags & ERTS_RUNQ_FLG_PROTECTED) + return NULL; + + if (ERTS_CHK_RUNQ_FLG_EVACUATE(f_flags, prio)) + return f_rq; + + if (f_rq_flags & ERTS_RUNQ_FLG_INACTIVE) + return f_rq; + + if (prio == ERTS_PORT_PRIO_LEVEL) + len = RUNQ_READ_LEN(&c_rq->ports.info.len); + else + len = RUNQ_READ_LEN(&c_rq->procs.prio_info[prio].len); + + if (len < mp->prio[prio].limit.this) { + if (prio == ERTS_PORT_PRIO_LEVEL) + len = RUNQ_READ_LEN(&f_rq->ports.info.len); + else + len = RUNQ_READ_LEN(&f_rq->procs.prio_info[prio].len); + + if (len > mp->prio[prio].limit.other) + return f_rq; + } + return NULL; } static void -immigrate(ErtsRunQueue *rq) +immigrate(ErtsRunQueue *c_rq, ErtsMigrationPath *mp) { - int prio; + Uint32 iflags, iflag; + erts_smp_runq_unlock(c_rq); - ASSERT(rq->flags & ERTS_RUNQ_FLGS_IMMIGRATE_QMASK); + ASSERT(erts_thr_progress_is_managed_thread()); - for (prio = 0; prio < ERTS_NO_PRIO_LEVELS; prio++) { - if (ERTS_CHK_RUNQ_FLG_IMMIGRATE(rq->flags, prio)) { - ErtsRunQueueInfo *rqi = (prio == ERTS_PORT_PRIO_LEVEL - ? &rq->ports.info - : &rq->procs.prio_info[prio]); - ErtsRunQueue *from_rq = rqi->migrate.runq; - int rq_locked, from_rq_locked; + iflags = mp->flags & ERTS_RUNQ_FLGS_IMMIGRATE_QMASK; - ERTS_DBG_VERIFY_VALID_RUNQP(from_rq); + iflag = iflags & -iflags; - rq_locked = 1; - from_rq_locked = 1; - erts_smp_xrunq_lock(rq, from_rq); - /* - * erts_smp_xrunq_lock() may release lock on rq! We have - * to check that we still want to immigrate from the same - * run queue as before. - */ - if (ERTS_CHK_RUNQ_FLG_IMMIGRATE(rq->flags, prio) - && from_rq == rqi->migrate.runq) { - ErtsRunQueueInfo *from_rqi = (prio == ERTS_PORT_PRIO_LEVEL - ? &from_rq->ports.info - : &from_rq->procs.prio_info[prio]); - if ((ERTS_CHK_RUNQ_FLG_EVACUATE(rq->flags, prio) - && ERTS_CHK_RUNQ_FLG_EVACUATE(from_rq->flags, prio) - && from_rqi->len) - || (from_rqi->len > rqi->migrate.limit.other - && rqi->len < rqi->migrate.limit.this)) { - if (prio == ERTS_PORT_PRIO_LEVEL) { - Port *prt = from_rq->ports.start; - if (prt) { - int prt_locked = 0; - (void) erts_port_migrate(prt, &prt_locked, - from_rq, &from_rq_locked, - rq, &rq_locked); - if (prt_locked) - erts_smp_port_unlock(prt); - } - } - else { - Process *proc; - ErtsRunPrioQueue *from_rpq; - from_rpq = (prio == PRIORITY_LOW - ? &from_rq->procs.prio[PRIORITY_NORMAL] - : &from_rq->procs.prio[prio]); - for (proc = from_rpq->first; proc; proc = proc->next) - if (proc->prio == prio && !proc->bound_runq) - break; - if (proc) { - ErtsProcLocks proc_locks = 0; - (void) erts_proc_migrate(proc, &proc_locks, - from_rq, &from_rq_locked, - rq, &rq_locked); - if (proc_locks) - erts_smp_proc_unlock(proc, proc_locks); - } + while (iflag) { + ErtsRunQueue *rq; + int prio; + + switch (iflag) { + case (MAX_BIT << ERTS_RUNQ_FLGS_IMMIGRATE_SHFT): + prio = PRIORITY_MAX; + break; + case (HIGH_BIT << ERTS_RUNQ_FLGS_IMMIGRATE_SHFT): + prio = PRIORITY_HIGH; + break; + case (NORMAL_BIT << ERTS_RUNQ_FLGS_IMMIGRATE_SHFT): + prio = PRIORITY_NORMAL; + break; + case (LOW_BIT << ERTS_RUNQ_FLGS_IMMIGRATE_SHFT): + prio = PRIORITY_LOW; + break; + case (PORT_BIT << ERTS_RUNQ_FLGS_IMMIGRATE_SHFT): + prio = ERTS_PORT_PRIO_LEVEL; + break; + default: + erl_exit(ERTS_ABORT_EXIT, + "%s:%d:%s(): Invalid immigrate queue mask", + __FILE__, __LINE__, __func__); + prio = 0; + break; + } + + iflags &= ~iflag; + iflag = iflags & -iflags; + + rq = check_immigration_need(c_rq, mp, prio); + if (rq) { + erts_smp_runq_lock(rq); + if (prio == ERTS_PORT_PRIO_LEVEL) { + Port *prt; + prt = erts_dequeue_port(rq); + if (prt) + RUNQ_SET_RQ(&prt->run_queue, c_rq); + erts_smp_runq_unlock(rq); + if (prt) { + /* port might terminate while we have no lock... */ + rq = erts_port_runq(prt); + if (rq) { + if (rq != c_rq) + erl_exit(ERTS_ABORT_EXIT, + "%s:%d:%s(): Internal error", + __FILE__, __LINE__, __func__); + erts_enqueue_port(c_rq, prt); + if (!iflag) + return; /* done */ + erts_smp_runq_unlock(c_rq); } } - else { - ERTS_UNSET_RUNQ_FLG_IMMIGRATE(rq->flags, prio); - ERTS_DBG_SET_INVALID_RUNQP(rqi->migrate.runq, 0x1); + } + else { + ErtsRunPrioQueue *rpq = &rq->procs.prio[prio == PRIORITY_LOW + ? PRIORITY_NORMAL + : prio]; + Process *prev_proc = NULL; + Process *proc = rpq->first; + int rq_locked = 1; + + while (proc) { + erts_aint32_t state; + state = erts_smp_atomic32_read_acqb(&proc->state); + if (!(ERTS_PSFLG_BOUND & state) + && (prio == (int) (ERTS_PSFLG_PRIO_MASK & state))) { + ErtsRunQueueInfo *rqi = &rq->procs.prio_info[prio]; + unqueue_process(rq, rpq, rqi, prio, prev_proc, proc); + erts_smp_runq_unlock(rq); + RUNQ_SET_RQ(&proc->run_queue, c_rq); + rq_locked = 0; + + erts_smp_runq_lock(c_rq); + enqueue_process(c_rq, prio, proc); + if (!iflag) + return; /* done */ + erts_smp_runq_unlock(c_rq); + break; + } + prev_proc = proc; + proc = proc->next; } + if (rq_locked) + erts_smp_runq_unlock(rq); } - if (from_rq_locked) - erts_smp_runq_unlock(from_rq); - if (!rq_locked) - erts_smp_runq_lock(rq); } } + + erts_smp_runq_lock(c_rq); } +static ERTS_INLINE void +suspend_run_queue(ErtsRunQueue *rq) +{ + erts_smp_atomic32_read_bor_nob(&rq->scheduler->ssi->flags, + ERTS_SSI_FLG_SUSPENDED); + (void) ERTS_RUNQ_FLGS_SET(rq, ERTS_RUNQ_FLG_SUSPENDED); + + wake_scheduler(rq, 0); +} + +static void scheduler_ix_resume_wake(Uint ix); + +static ERTS_INLINE void +resume_run_queue(ErtsRunQueue *rq) +{ + int pix; + + erts_smp_runq_lock(rq); + + (void) ERTS_RUNQ_FLGS_MASK_SET(rq, + (ERTS_RUNQ_FLG_OUT_OF_WORK + | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK + | ERTS_RUNQ_FLG_SUSPENDED), + (ERTS_RUNQ_FLG_OUT_OF_WORK + | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK)); + + rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS; + for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) { + rq->procs.prio_info[pix].max_len = 0; + rq->procs.prio_info[pix].reds = 0; + } + rq->ports.info.max_len = 0; + rq->ports.info.reds = 0; + rq->max_len = 0; + + erts_smp_runq_unlock(rq); + + scheduler_ix_resume_wake(rq->ix); +} + +typedef struct { + Process *first; + Process *last; +} ErtsStuckBoundProcesses; + static void -evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq) +schedule_bound_processes(ErtsRunQueue *rq, + ErtsStuckBoundProcesses *sbpp) { - Port *prt; - int notify_to_rq = 0; - int prio; - int prt_locked = 0; - int rq_locked = 0; - int evac_rq_locked = 1; - ErtsMigrateResult mres; + Process *proc, *next; + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - erts_smp_runq_lock(evac_rq); + proc = sbpp->first; + while (proc) { + erts_aint32_t state = erts_smp_atomic32_read_acqb(&proc->state); + next = proc->next; + enqueue_process(rq, (int) (ERTS_PSFLG_PRIO_MASK & state), proc); + proc = next; + } +} - erts_smp_atomic32_read_bor_nob(&evac_rq->scheduler->ssi->flags, - ERTS_SSI_FLG_SUSPENDED); +static void +evacuate_run_queue(ErtsRunQueue *rq, + ErtsStuckBoundProcesses *sbpp) +{ + int prio_q; + ErtsRunQueue *to_rq; + ErtsMigrationPaths *mps; + ErtsMigrationPath *mp; - evac_rq->flags &= ~ERTS_RUNQ_FLGS_IMMIGRATE_QMASK; - evac_rq->flags |= (ERTS_RUNQ_FLGS_EMIGRATE_QMASK - | ERTS_RUNQ_FLGS_EVACUATE_QMASK - | ERTS_RUNQ_FLG_SUSPENDED); + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - erts_smp_atomic32_read_bor_nob(&evac_rq->info_flags, ERTS_RUNQ_IFLG_SUSPENDED); - /* - * Need to set up evacuation paths first since we - * may release the run queue lock on evac_rq - * when evacuating. - */ - evac_rq->misc.evac_runq = rq; - evac_rq->ports.info.migrate.runq = rq; - for (prio = 0; prio < ERTS_NO_PROC_PRIO_LEVELS; prio++) - evac_rq->procs.prio_info[prio].migrate.runq = rq; + (void) ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_PROTECTED); + + mps = erts_get_migration_paths_managed(); + mp = &mps->mpath[rq->ix]; /* Evacuate scheduled misc ops */ - if (evac_rq->misc.start) { - rq_locked = 1; - erts_smp_xrunq_lock(evac_rq, rq); - if (rq->misc.end) - rq->misc.end->next = evac_rq->misc.start; + if (rq->misc.start) { + ErtsMiscOpList *start, *end; + + to_rq = mp->misc_evac_runq; + if (!to_rq) + return; + + start = rq->misc.start; + end = rq->misc.end; + rq->misc.start = NULL; + rq->misc.end = NULL; + erts_smp_runq_unlock(rq); + + erts_smp_runq_lock(to_rq); + if (to_rq->misc.end) + to_rq->misc.end->next = start; else - rq->misc.start = evac_rq->misc.start; - rq->misc.end = evac_rq->misc.end; - evac_rq->misc.start = NULL; - evac_rq->misc.end = NULL; + to_rq->misc.start = start; + + to_rq->misc.end = end; + erts_smp_runq_unlock(to_rq); + smp_notify_inc_runq(to_rq); + erts_smp_runq_lock(to_rq); } - /* Evacuate scheduled ports */ - prt = evac_rq->ports.start; - while (prt) { - mres = erts_port_migrate(prt, &prt_locked, - evac_rq, &evac_rq_locked, - rq, &rq_locked); - if (mres == ERTS_MIGRATE_SUCCESS) - notify_to_rq = 1; - if (prt_locked) - erts_smp_port_unlock(prt); - if (!evac_rq_locked) { - evac_rq_locked = 1; - erts_smp_runq_lock(evac_rq); + if (rq->ports.start) { + Port *prt; + + to_rq = mp->prio[ERTS_PORT_PRIO_LEVEL].runq; + if (!to_rq) + return; + + /* Evacuate scheduled ports */ + prt = rq->ports.start; + while (prt) { + ErtsRunQueue *prt_rq; + prt = erts_dequeue_port(rq); + RUNQ_SET_RQ(&prt->run_queue, to_rq); + erts_smp_runq_unlock(rq); + /* + * The port might terminate while + * we have no lock on it... + */ + prt_rq = erts_port_runq(prt); + if (prt_rq) { + if (prt_rq != to_rq) + erl_exit(ERTS_ABORT_EXIT, + "%s:%d:%s() internal error\n", + __FILE__, __LINE__, __func__); + erts_enqueue_port(to_rq, prt); + erts_smp_runq_unlock(to_rq); + } + erts_smp_runq_lock(rq); + prt = rq->ports.start; } - prt = evac_rq->ports.start; + smp_notify_inc_runq(to_rq); } /* Evacuate scheduled processes */ - for (prio = 0; prio < ERTS_NO_PROC_PRIO_LEVELS; prio++) { + for (prio_q = 0; prio_q < ERTS_NO_PROC_PRIO_QUEUES; prio_q++) { + erts_aint32_t state; Process *proc; + int notify = 0; + to_rq = NULL; - switch (prio) { - case PRIORITY_MAX: - case PRIORITY_HIGH: - case PRIORITY_NORMAL: - proc = evac_rq->procs.prio[prio].first; - while (proc) { - ErtsProcLocks proc_locks = 0; - - /* Bound processes are stuck... */ - while (proc->bound_runq) { - proc = proc->next; - if (!proc) - goto end_of_proc; - } - - mres = erts_proc_migrate(proc, &proc_locks, - evac_rq, &evac_rq_locked, - rq, &rq_locked); - if (mres == ERTS_MIGRATE_SUCCESS) - notify_to_rq = 1; - if (proc_locks) - erts_smp_proc_unlock(proc, proc_locks); - if (!evac_rq_locked) { - erts_smp_runq_lock(evac_rq); - evac_rq_locked = 1; - } + if (!mp->prio[prio_q].runq) + return; + if (prio_q == PRIORITY_NORMAL && !mp->prio[PRIORITY_LOW].runq) + return; - proc = evac_rq->procs.prio[prio].first; + proc = dequeue_process(rq, prio_q, &state); + while (proc) { + if (ERTS_PSFLG_BOUND & state) { + /* Bound processes get stuck here... */ + proc->next = NULL; + if (sbpp->last) + sbpp->last->next = proc; + else + sbpp->first = proc; + sbpp->last = proc; } + else { + int prio = (int) (ERTS_PSFLG_PRIO_MASK & state); + erts_smp_runq_unlock(rq); - end_of_proc: + to_rq = mp->prio[prio].runq; + RUNQ_SET_RQ(&proc->run_queue, to_rq); -#ifdef DEBUG - for (proc = evac_rq->procs.prio[prio].first; - proc; - proc = proc->next) { - ASSERT(proc->bound_runq); + erts_smp_runq_lock(to_rq); + enqueue_process(to_rq, prio, proc); + erts_smp_runq_unlock(to_rq); + notify = 1; + + erts_smp_runq_lock(rq); } -#endif - break; - case PRIORITY_LOW: - break; - default: - ASSERT(!"Invalid process priority"); - break; + proc = dequeue_process(rq, prio_q, &state); } + if (notify) + smp_notify_inc_runq(to_rq); } - if (rq_locked) - erts_smp_runq_unlock(rq); - - if (evac_rq_locked) - erts_smp_runq_unlock(evac_rq); - - if (notify_to_rq) - smp_notify_inc_runq(rq); - - wake_scheduler(evac_rq, 0); + if (ERTS_EMPTY_RUNQ(rq)) + empty_runq(rq); } static int -try_steal_task_from_victim(ErtsRunQueue *rq, int *rq_lockedp, ErtsRunQueue *vrq) +try_steal_task_from_victim(ErtsRunQueue *rq, int *rq_lockedp, ErtsRunQueue *vrq, Uint32 flags) { - Process *proc; - int vrq_locked; + Uint32 procs_qmask = flags & ERTS_RUNQ_FLGS_PROCS_QMASK; + int max_prio_bit; + ErtsRunPrioQueue *rpq; - if (*rq_lockedp) - erts_smp_xrunq_lock(rq, vrq); - else - erts_smp_runq_lock(vrq); - vrq_locked = 1; + if (*rq_lockedp) { + erts_smp_runq_unlock(rq); + *rq_lockedp = 0; + } + + ERTS_SMP_LC_ASSERT(!erts_smp_lc_runq_is_locked(rq)); - ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp); - ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked); + erts_smp_runq_lock(vrq); if (rq->halt_in_progress) - goto try_steal_port; + goto no_procs; /* * Check for a runnable process to steal... */ - switch (vrq->flags & ERTS_RUNQ_FLGS_PROCS_QMASK) { - case MAX_BIT: - case MAX_BIT|HIGH_BIT: - case MAX_BIT|NORMAL_BIT: - case MAX_BIT|LOW_BIT: - case MAX_BIT|HIGH_BIT|NORMAL_BIT: - case MAX_BIT|HIGH_BIT|LOW_BIT: - case MAX_BIT|NORMAL_BIT|LOW_BIT: - case MAX_BIT|HIGH_BIT|NORMAL_BIT|LOW_BIT: - for (proc = vrq->procs.prio[PRIORITY_MAX].last; - proc; - proc = proc->prev) { - if (!proc->bound_runq) - break; - } - if (proc) + while (procs_qmask) { + Process *prev_proc; + Process *proc; + + max_prio_bit = procs_qmask & -procs_qmask; + switch (max_prio_bit) { + case MAX_BIT: + rpq = &vrq->procs.prio[PRIORITY_MAX]; break; - case HIGH_BIT: - case HIGH_BIT|NORMAL_BIT: - case HIGH_BIT|LOW_BIT: - case HIGH_BIT|NORMAL_BIT|LOW_BIT: - for (proc = vrq->procs.prio[PRIORITY_HIGH].last; - proc; - proc = proc->prev) { - if (!proc->bound_runq) - break; - } - if (proc) + case HIGH_BIT: + rpq = &vrq->procs.prio[PRIORITY_HIGH]; break; - case NORMAL_BIT: - case LOW_BIT: - case NORMAL_BIT|LOW_BIT: - for (proc = vrq->procs.prio[PRIORITY_NORMAL].last; - proc; - proc = proc->prev) { - if (!proc->bound_runq) - break; - } - if (proc) + case NORMAL_BIT: + case LOW_BIT: + rpq = &vrq->procs.prio[PRIORITY_NORMAL]; break; - case 0: - proc = NULL; - break; - default: - ASSERT(!"Invalid queue mask"); - proc = NULL; - break; - } + case 0: + goto no_procs; + default: + ASSERT(!"Invalid queue mask"); + goto no_procs; + } + + prev_proc = NULL; + proc = rpq->first; - if (proc) { - ErtsProcLocks proc_locks = 0; - int res; - ErtsMigrateResult mres; - mres = erts_proc_migrate(proc, &proc_locks, - vrq, &vrq_locked, - rq, rq_lockedp); - if (proc_locks) - erts_smp_proc_unlock(proc, proc_locks); - res = !0; - switch (mres) { - case ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED: - res = 0; - case ERTS_MIGRATE_SUCCESS: - if (vrq_locked) + while (proc) { + erts_aint32_t state = erts_smp_atomic32_read_acqb(&proc->state); + if (!(ERTS_PSFLG_BOUND & state)) { + /* Steal process */ + int prio = (int) (ERTS_PSFLG_PRIO_MASK & state); + ErtsRunQueueInfo *rqi = &vrq->procs.prio_info[prio]; + unqueue_process(vrq, rpq, rqi, prio, prev_proc, proc); erts_smp_runq_unlock(vrq); - return res; - default: /* Other failures */ - break; - } - } + RUNQ_SET_RQ(&proc->run_queue, rq); - ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp); - ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked); + erts_smp_runq_lock(rq); + *rq_lockedp = 1; + enqueue_process(rq, prio, proc); + return !0; + } + prev_proc = proc; + proc = proc->next; + } - if (!vrq_locked) { - if (*rq_lockedp) - erts_smp_xrunq_lock(rq, vrq); - else - erts_smp_runq_lock(vrq); - vrq_locked = 1; + procs_qmask &= ~max_prio_bit; } - try_steal_port: +no_procs: - ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp); - ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked); + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(vrq)); /* * Check for a runnable port to steal... */ - if (vrq->ports.info.len) { - Port *prt = vrq->ports.end; - int prt_locked = 0; - int res; - ErtsMigrateResult mres; - - mres = erts_port_migrate(prt, &prt_locked, - vrq, &vrq_locked, - rq, rq_lockedp); - if (prt_locked) - erts_smp_port_unlock(prt); - res = !0; - switch (mres) { - case ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED: - res = 0; - case ERTS_MIGRATE_SUCCESS: - if (vrq_locked) - erts_smp_runq_unlock(vrq); - return res; - default: /* Other failures */ - break; + if (vrq->ports.start) { + ErtsRunQueue *prt_rq; + Port *prt = erts_dequeue_port(vrq); + RUNQ_SET_RQ(&prt->run_queue, rq); + erts_smp_runq_unlock(vrq); + + /* + * The port might terminate while + * we have no lock on it... + */ + + prt_rq = erts_port_runq(prt); + if (!prt_rq) + return 0; + else { + if (prt_rq != rq) + erl_exit(ERTS_ABORT_EXIT, + "%s:%d:%s() internal error\n", + __FILE__, __LINE__, __func__); + *rq_lockedp = 1; + erts_enqueue_port(rq, prt); + return !0; } } - if (vrq_locked) - erts_smp_runq_unlock(vrq); + erts_smp_runq_unlock(vrq); return 0; } @@ -2981,9 +3530,10 @@ static ERTS_INLINE int check_possible_steal_victim(ErtsRunQueue *rq, int *rq_lockedp, int vix) { ErtsRunQueue *vrq = ERTS_RUNQ_IX(vix); - erts_aint32_t iflgs = erts_smp_atomic32_read_nob(&vrq->info_flags); - if (iflgs & ERTS_RUNQ_IFLG_NONEMPTY) - return try_steal_task_from_victim(rq, rq_lockedp, vrq); + Uint32 flags = ERTS_RUNQ_FLGS_GET(vrq); + if ((flags & (ERTS_RUNQ_FLG_NONEMPTY + | ERTS_RUNQ_FLG_PROTECTED)) == ERTS_RUNQ_FLG_NONEMPTY) + return try_steal_task_from_victim(rq, rq_lockedp, vrq, flags); else return 0; } @@ -2993,15 +3543,12 @@ static int try_steal_task(ErtsRunQueue *rq) { int res, rq_locked, vix, active_rqs, blnc_rqs; + Uint32 flags; - /* - * We are not allowed to steal jobs to this run queue - * if it is suspended. Note that it might get suspended - * at any time when we don't have the lock on the run - * queue. - */ - if (rq->flags & ERTS_RUNQ_FLG_SUSPENDED) - return 0; + /* Protect jobs we steal from getting stolen from us... */ + flags = ERTS_RUNQ_FLGS_SET(rq, ERTS_RUNQ_FLG_PROTECTED); + if (flags & ERTS_RUNQ_FLG_SUSPENDED) + return 0; /* go suspend instead... */ res = 0; rq_locked = 1; @@ -3120,12 +3667,123 @@ do { \ ASSERT(sum__ == (RQ)->full_reds_history_sum); \ } while (0); +#define ERTS_PRE_ALLOCED_MPATHS 8 + +erts_atomic_t erts_migration_paths; + +static struct { + size_t size; + ErtsMigrationPaths *freelist; + struct { + ErtsMigrationPaths *first; + ErtsMigrationPaths *last; + } retired; +} mpaths; + +static void +init_migration_paths(void) +{ + int qix, i; + char *p; + ErtsMigrationPaths *mps; + + mpaths.size = sizeof(ErtsMigrationPaths); + mpaths.size += sizeof(ErtsMigrationPath)*(erts_no_schedulers-1); + mpaths.size = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(mpaths.size); + + p = erts_alloc_permanent_cache_aligned(ERTS_ALC_T_LL_MPATHS, + (mpaths.size + * ERTS_PRE_ALLOCED_MPATHS)); + mpaths.freelist = NULL; + for (i = 0; i < ERTS_PRE_ALLOCED_MPATHS-1; i++) { + mps = (ErtsMigrationPaths *) p; + mps->next = mpaths.freelist; + mpaths.freelist = mps; + p += mpaths.size; + } + + mps = (ErtsMigrationPaths *) p; + mps->block = NULL; + for (qix = 0; qix < erts_no_run_queues; qix++) { + int pix; + mps->mpath[qix].flags = 0; + mps->mpath[qix].misc_evac_runq = NULL; + for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) { + mps->mpath[qix].prio[pix].limit.this = -1; + mps->mpath[qix].prio[pix].limit.other = -1; + mps->mpath[qix].prio[pix].runq = NULL; + mps->mpath[qix].prio[pix].flags = 0; + } + } + erts_atomic_init_wb(&erts_migration_paths, (erts_aint_t) mps); +} + +static ERTS_INLINE ErtsMigrationPaths * +alloc_mpaths(void) +{ + void *block; + ErtsMigrationPaths *res; + ERTS_SMP_LC_ASSERT(erts_smp_lc_mtx_is_locked(&balance_info.update_mtx)); + + res = mpaths.freelist; + if (res) { + mpaths.freelist = res->next; + res->block = NULL; + return res; + } + res = erts_alloc(ERTS_ALC_T_SL_MPATHS, + mpaths.size+ERTS_CACHE_LINE_SIZE); + block = (void *) res; + if (((UWord) res) & ERTS_CACHE_LINE_MASK) + res = (ErtsMigrationPaths *) ((((UWord) res) & ~ERTS_CACHE_LINE_MASK) + + ERTS_CACHE_LINE_SIZE); + res->block = block; + return res; +} + +static ERTS_INLINE void +retire_mpaths(ErtsMigrationPaths *mps) +{ + ErtsThrPrgrVal current; + + ERTS_SMP_LC_ASSERT(erts_smp_lc_mtx_is_locked(&balance_info.update_mtx)); + + current = erts_thr_progress_current(); + + while (mpaths.retired.first) { + ErtsMigrationPaths *tmp = mpaths.retired.first; + if (!erts_thr_progress_has_reached_this(current, tmp->thr_prgr)) + break; + mpaths.retired.first = tmp->next; + if (tmp->block) { + erts_free(ERTS_ALC_T_SL_MPATHS, tmp->block); + } + else { + tmp->next = mpaths.freelist; + mpaths.freelist = tmp; + } + } + + if (!mpaths.retired.first) + mpaths.retired.last = NULL; + + mps->thr_prgr = erts_thr_progress_later(NULL); + mps->next = NULL; + + if (mpaths.retired.last) + mpaths.retired.last->next = mps; + else + mpaths.retired.first = mps; + mpaths.retired.last = mps; +} + static void check_balance(ErtsRunQueue *c_rq) { #if ERTS_MAX_PROCESSES >= (1 << 27) # error check_balance() assumes ERTS_MAX_PROCESS < (1 << 27) #endif + ErtsMigrationPaths *new_mpaths, *old_mpaths; ErtsRunQueueBalance avg = {0}; Sint64 scheds_reds, full_scheds_reds; int forced, active, current_active, oowc, half_full_scheds, full_scheds, @@ -3151,9 +3809,9 @@ check_balance(ErtsRunQueue *c_rq) ERTS_FOREACH_RUNQ(rq, { if (rq->waiting) - rq->flags |= ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK; + (void) ERTS_RUNQ_FLGS_SET(rq, ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK); else - rq->flags &= ~ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK; + (void) ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK); rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS; }); @@ -3195,7 +3853,7 @@ check_balance(ErtsRunQueue *c_rq) ErtsRunQueue *rq = ERTS_RUNQ_IX(qix); erts_smp_runq_lock(rq); - run_queue_info[qix].flags = rq->flags; + run_queue_info[qix].flags = ERTS_RUNQ_FLGS_GET_NOB(rq); for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) { run_queue_info[qix].prio[pix].max_len = rq->procs.prio_info[pix].max_len; @@ -3529,47 +4187,27 @@ erts_fprintf(stderr, "--------------------------------\n"); set_no_active_runqs(active); balance_info.halftime = 1; - erts_smp_atomic32_set_nob(&balance_info.checking_balance, 0); + new_mpaths = alloc_mpaths(); + + /* Write migration paths */ - /* Write migration paths and reset balance statistics in all queues */ for (qix = 0; qix < blnc_no_rqs; qix++) { int mqix; - Uint32 flags; - ErtsRunQueue *rq = ERTS_RUNQ_IX(qix); - ErtsRunQueueInfo *rqi; - flags = run_queue_info[qix].flags; - erts_smp_runq_lock(rq); - flags |= (rq->flags & ~ERTS_RUNQ_FLGS_MIGRATION_INFO); - ASSERT(!(flags & ERTS_RUNQ_FLG_OUT_OF_WORK)); - if (rq->waiting) - flags |= ERTS_RUNQ_FLG_OUT_OF_WORK; - - rq->full_reds_history_sum - = run_queue_info[qix].full_reds_history_sum; - rq->full_reds_history[freds_hist_ix] - = run_queue_info[qix].full_reds_history_change; + Uint32 flags = run_queue_info[qix].flags; + ErtsMigrationPath *mp = &new_mpaths->mpath[qix]; - ERTS_DBG_CHK_FULL_REDS_HISTORY(rq); + mp->flags = flags; + mp->misc_evac_runq = NULL; - rq->out_of_work_count = 0; - rq->flags = flags; - rq->max_len = rq->len; for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) { - rqi = (pix == ERTS_PORT_PRIO_LEVEL - ? &rq->ports.info - : &rq->procs.prio_info[pix]); - rqi->max_len = rqi->len; - rqi->reds = 0; if (!(ERTS_CHK_RUNQ_FLG_EMIGRATE(flags, pix) | ERTS_CHK_RUNQ_FLG_IMMIGRATE(flags, pix))) { ASSERT(run_queue_info[qix].prio[pix].immigrate_from < 0); ASSERT(run_queue_info[qix].prio[pix].emigrate_to < 0); -#ifdef DEBUG - rqi->migrate.limit.this = -1; - rqi->migrate.limit.other = -1; - ERTS_DBG_SET_INVALID_RUNQP(rqi->migrate.runq, 0x2); -#endif - + mp->prio[pix].limit.this = -1; + mp->prio[pix].limit.other = -1; + mp->prio[pix].runq = NULL; + mp->prio[pix].flags = 0; } else if (ERTS_CHK_RUNQ_FLG_EMIGRATE(flags, pix)) { ASSERT(!ERTS_CHK_RUNQ_FLG_IMMIGRATE(flags, pix)); @@ -3577,11 +4215,12 @@ erts_fprintf(stderr, "--------------------------------\n"); ASSERT(run_queue_info[qix].prio[pix].emigrate_to >= 0); mqix = run_queue_info[qix].prio[pix].emigrate_to; - rqi->migrate.limit.this + mp->prio[pix].limit.this = run_queue_info[qix].prio[pix].migration_limit; - rqi->migrate.limit.other + mp->prio[pix].limit.other = run_queue_info[mqix].prio[pix].migration_limit; - rqi->migrate.runq = ERTS_RUNQ_IX(mqix); + mp->prio[pix].runq = ERTS_RUNQ_IX(mqix); + mp->prio[pix].flags = run_queue_info[mqix].flags; } else { ASSERT(ERTS_CHK_RUNQ_FLG_IMMIGRATE(flags, pix)); @@ -3589,24 +4228,142 @@ erts_fprintf(stderr, "--------------------------------\n"); ASSERT(run_queue_info[qix].prio[pix].immigrate_from >= 0); mqix = run_queue_info[qix].prio[pix].immigrate_from; - rqi->migrate.limit.this + mp->prio[pix].limit.this = run_queue_info[qix].prio[pix].migration_limit; - rqi->migrate.limit.other + mp->prio[pix].limit.other = run_queue_info[mqix].prio[pix].migration_limit; - rqi->migrate.runq = ERTS_RUNQ_IX(mqix); + mp->prio[pix].runq = ERTS_RUNQ_IX(mqix); + mp->prio[pix].flags = run_queue_info[mqix].flags; } } + } + + old_mpaths = erts_get_migration_paths_managed(); + + /* Keep offline run-queues as is */ + for (qix = blnc_no_rqs; qix < erts_no_schedulers; qix++) { + ErtsMigrationPath *nmp = &new_mpaths->mpath[qix]; + ErtsMigrationPath *omp = &old_mpaths->mpath[qix]; + + nmp->flags = omp->flags; + nmp->misc_evac_runq = omp->misc_evac_runq; + + for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) { + nmp->prio[pix].limit.this = omp->prio[pix].limit.this; + nmp->prio[pix].limit.other = omp->prio[pix].limit.other; + nmp->prio[pix].runq = omp->prio[pix].runq; + nmp->prio[pix].flags = omp->prio[pix].flags; + } + } + + + /* Publish new migration paths... */ + erts_atomic_set_wb(&erts_migration_paths, (erts_aint_t) new_mpaths); + + /* Reset balance statistics in all online queues */ + for (qix = 0; qix < blnc_no_rqs; qix++) { + Uint32 flags = run_queue_info[qix].flags; + ErtsRunQueue *rq = ERTS_RUNQ_IX(qix); + + erts_smp_runq_lock(rq); + ASSERT(!(flags & ERTS_RUNQ_FLG_OUT_OF_WORK)); + if (rq->waiting) + flags |= ERTS_RUNQ_FLG_OUT_OF_WORK; + + rq->full_reds_history_sum + = run_queue_info[qix].full_reds_history_sum; + rq->full_reds_history[freds_hist_ix] + = run_queue_info[qix].full_reds_history_change; + + ERTS_DBG_CHK_FULL_REDS_HISTORY(rq); + + rq->out_of_work_count = 0; + (void) ERTS_RUNQ_FLGS_MASK_SET(rq, ERTS_RUNQ_FLGS_MIGRATION_INFO, flags); + + rq->max_len = rq->len; + for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) { + ErtsRunQueueInfo *rqi; + rqi = (pix == ERTS_PORT_PRIO_LEVEL + ? &rq->ports.info + : &rq->procs.prio_info[pix]); + erts_smp_reset_max_len(rq, rqi); + rqi->reds = 0; + } rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS; erts_smp_runq_unlock(rq); } + erts_smp_atomic32_set_nob(&balance_info.checking_balance, 0); + balance_info.n++; + retire_mpaths(old_mpaths); erts_smp_mtx_unlock(&balance_info.update_mtx); erts_smp_runq_lock(c_rq); } +static void +change_no_used_runqs(int used) +{ + ErtsMigrationPaths *new_mpaths, *old_mpaths; + int active, qix; + erts_smp_mtx_lock(&balance_info.update_mtx); + get_no_runqs(&active, NULL); + set_no_used_runqs(used); + + old_mpaths = erts_get_migration_paths_managed(); + new_mpaths = alloc_mpaths(); + + /* Write migration paths... */ + + for (qix = 0; qix < used; qix++) { + int pix; + ErtsMigrationPath *omp = &old_mpaths->mpath[qix]; + ErtsMigrationPath *nmp = &new_mpaths->mpath[qix]; + + nmp->flags = omp->flags & ~ERTS_RUNQ_FLGS_MIGRATION_QMASKS; + nmp->misc_evac_runq = NULL; + + for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) { + nmp->prio[pix].limit.this = -1; + nmp->prio[pix].limit.other = -1; + nmp->prio[pix].runq = NULL; + nmp->prio[pix].flags = 0; + } + } + for (qix = used; qix < erts_no_run_queues; qix++) { + int pix; + ErtsRunQueue *to_rq = ERTS_RUNQ_IX(qix % used); + ErtsMigrationPath *nmp = &new_mpaths->mpath[qix]; + + nmp->flags = (ERTS_RUNQ_FLGS_EMIGRATE_QMASK + | ERTS_RUNQ_FLGS_EVACUATE_QMASK); + nmp->misc_evac_runq = to_rq; + for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) { + nmp->prio[pix].limit.this = -1; + nmp->prio[pix].limit.other = -1; + nmp->prio[pix].runq = to_rq; + nmp->prio[pix].flags = 0; + } + } + + /* ... and publish them. */ + erts_atomic_set_wb(&erts_migration_paths, (erts_aint_t) new_mpaths); + + retire_mpaths(old_mpaths); + + /* Make sure that we balance soon... */ + balance_info.forced_check_balance = 1; + + erts_smp_mtx_unlock(&balance_info.update_mtx); + + erts_smp_runq_lock(ERTS_RUNQ_IX(0)); + ERTS_RUNQ_IX(0)->check_balance_reds = 0; + erts_smp_runq_unlock(ERTS_RUNQ_IX(0)); +} + + #endif /* #ifdef ERTS_SMP */ Uint @@ -3674,11 +4431,11 @@ static struct { int limit; int dec_shift; int dec_mask; - void (*check)(ErtsRunQueue *rq); + void (*check)(ErtsRunQueue *rq, Uint32 flags); } wakeup_other; static void -wakeup_other_check(ErtsRunQueue *rq) +wakeup_other_check(ErtsRunQueue *rq, Uint32 flags) { int wo_reds = rq->wakeup_other_reds; if (wo_reds) { @@ -3696,6 +4453,8 @@ wakeup_other_check(ErtsRunQueue *rq) if (rq->wakeup_other > wakeup_other.limit) { int empty_rqs = erts_smp_atomic32_read_acqb(&no_empty_run_queues); + if (flags & ERTS_RUNQ_FLG_PROTECTED) + (void) ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_PROTECTED); if (empty_rqs != 0) wake_scheduler_on_empty_runq(rq); rq->wakeup_other = 0; @@ -3740,18 +4499,21 @@ wakeup_other_set_limit(void) } static void -wakeup_other_check_legacy(ErtsRunQueue *rq) +wakeup_other_check_legacy(ErtsRunQueue *rq, Uint32 flags) { int wo_reds = rq->wakeup_other_reds; if (wo_reds) { - if (rq->len < 2) { + erts_aint32_t len = rq->len; + if (len < 2) { rq->wakeup_other -= ERTS_WAKEUP_OTHER_DEC_LEGACY*wo_reds; if (rq->wakeup_other < 0) rq->wakeup_other = 0; } else if (rq->wakeup_other < wakeup_other.limit) - rq->wakeup_other += rq->len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC_LEGACY; + rq->wakeup_other += len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC_LEGACY; else { + if (flags & ERTS_RUNQ_FLG_PROTECTED) + (void) ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_PROTECTED); if (erts_smp_atomic32_read_acqb(&no_empty_run_queues) != 0) { wake_scheduler_on_empty_runq(rq); rq->wakeup_other = 0; @@ -3908,6 +4670,8 @@ init_aux_work_data(ErtsAuxWorkData *awdp, ErtsSchedulerData *esdp, char *dawwp) awdp->dd.thr_prgr = ERTS_THR_PRGR_VAL_WAITING; awdp->dd.completed_callback = NULL; awdp->dd.completed_arg = NULL; + awdp->later_op.first = NULL; + awdp->later_op.last = NULL; #endif #ifdef ERTS_USE_ASYNC_READY_Q #ifdef ERTS_SMP @@ -3971,7 +4735,6 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online) ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); rq->ix = ix; - erts_smp_atomic32_init_nob(&rq->info_flags, ERTS_RUNQ_IFLG_NONEMPTY); /* make sure that the "extra" id correponds to the schedulers * id if the esdp->no <-> ix+1 mapping change. @@ -3982,7 +4745,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online) rq->waiting = 0; rq->woken = 0; - rq->flags = 0; + ERTS_RUNQ_FLGS_INIT(rq, ERTS_RUNQ_FLG_NONEMPTY); rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS; rq->full_reds_history_sum = 0; for (rix = 0; rix < ERTS_FULL_REDS_HISTORY_SIZE; rix++) { @@ -3996,19 +4759,14 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online) rq->wakeup_other_reds = 0; rq->halt_in_progress = 0; - rq->procs.len = 0; rq->procs.pending_exiters = NULL; rq->procs.context_switches = 0; rq->procs.reductions = 0; for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) { - rq->procs.prio_info[pix].len = 0; + erts_smp_atomic32_init_nob(&rq->procs.prio_info[pix].len, 0); rq->procs.prio_info[pix].max_len = 0; rq->procs.prio_info[pix].reds = 0; - rq->procs.prio_info[pix].migrate.limit.this = 0; - rq->procs.prio_info[pix].migrate.limit.other = 0; - ERTS_DBG_SET_INVALID_RUNQP(rq->procs.prio_info[pix].migrate.runq, - 0x0); if (pix < ERTS_NO_PROC_PRIO_LEVELS - 1) { rq->procs.prio[pix].first = NULL; rq->procs.prio[pix].last = NULL; @@ -4017,14 +4775,10 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online) rq->misc.start = NULL; rq->misc.end = NULL; - rq->misc.evac_runq = NULL; - rq->ports.info.len = 0; + erts_smp_atomic32_init_nob(&rq->ports.info.len, 0); rq->ports.info.max_len = 0; rq->ports.info.reds = 0; - rq->ports.info.migrate.limit.this = 0; - rq->ports.info.migrate.limit.other = 0; - rq->ports.info.migrate.runq = NULL; rq->ports.start = NULL; rq->ports.end = NULL; } @@ -4159,10 +4913,12 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online) balance_info.prev_rise.reds = 0; balance_info.n = 0; + init_migration_paths(); + if (no_schedulers_online < no_schedulers) { + change_no_used_runqs(no_schedulers_online); for (ix = no_schedulers_online; ix < erts_no_run_queues; ix++) - evacuate_run_queue(ERTS_RUNQ_IX(ix), - ERTS_RUNQ_IX(ix % no_schedulers_online)); + suspend_run_queue(ERTS_RUNQ_IX(ix)); } schdlr_sspnd.wait_curr_online = no_schedulers_online; @@ -4225,91 +4981,197 @@ erts_get_scheduler_data(void) #endif -static int remove_proc_from_runq(ErtsRunQueue *rq, Process *p, int to_inactive); +/* + * scheduler_out_process() return with c_rq locked. + */ +static ERTS_INLINE int +schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p) +{ + erts_aint32_t a, e, n; + int res = 0; + + a = state; + + while (1) { + n = e = a; + + ASSERT(a & ERTS_PSFLG_RUNNING); + ASSERT(!(a & ERTS_PSFLG_IN_RUNQ)); + + n &= ~ERTS_PSFLG_RUNNING; + if ((a & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED)) == ERTS_PSFLG_ACTIVE) + n |= ERTS_PSFLG_IN_RUNQ; + a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e); + if (a == e) + break; + } + + if (!(n & ERTS_PSFLG_IN_RUNQ)) { + if (erts_system_profile_flags.runnable_procs) + profile_runnable_proc(p, am_inactive); + } + else { + int prio = (int) (ERTS_PSFLG_PRIO_MASK & n); + ErtsRunQueue *runq = erts_get_runq_proc(p); + + ASSERT(!(n & ERTS_PSFLG_SUSPENDED)); + +#ifdef ERTS_SMP + if (!(ERTS_PSFLG_BOUND & n)) { + ErtsRunQueue *new_runq = erts_check_emigration_need(runq, prio); + if (new_runq) { + RUNQ_SET_RQ(&p->run_queue, new_runq); + runq = new_runq; + } + } +#endif + ASSERT(runq); + res = 1; + + erts_smp_runq_lock(runq); + + /* Enqueue the process */ + enqueue_process(runq, prio, p); + + if (runq == c_rq) + return res; + erts_smp_runq_unlock(runq); + smp_notify_inc_runq(runq); + } + erts_smp_runq_lock(c_rq); + return res; +} static ERTS_INLINE void -suspend_process(ErtsRunQueue *rq, Process *p) +add2runq(Process *p, erts_aint32_t state) { - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - p->rcount++; /* count number of suspend */ -#ifdef ERTS_SMP - ASSERT(!(p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) - || p == erts_get_current_process()); - ASSERT(p->status != P_RUNNING - || p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING); - if (p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) - goto runable; -#endif - switch(p->status) { - case P_SUSPENDED: - break; - case P_RUNABLE: + int prio = (int) (ERTS_PSFLG_PRIO_MASK & state); + ErtsRunQueue *runq = erts_get_runq_proc(p); + #ifdef ERTS_SMP - runable: - if (!ERTS_PROC_PENDING_EXIT(p)) + if (!(ERTS_PSFLG_BOUND & state)) { + ErtsRunQueue *new_runq = erts_check_emigration_need(runq, prio); + if (new_runq) { + RUNQ_SET_RQ(&p->run_queue, new_runq); + runq = new_runq; + } + } #endif - remove_proc_from_runq(rq, p, 1); - /* else: - * leave process in schedq so it will discover the pending exit - */ - p->rstatus = P_RUNABLE; /* wakeup as runnable */ - break; - case P_RUNNING: - p->rstatus = P_RUNABLE; /* wakeup as runnable */ - break; - case P_WAITING: - p->rstatus = P_WAITING; /* wakeup as waiting */ - break; - case P_EXITING: - return; /* ignore this */ - case P_GARBING: - case P_FREE: - erl_exit(1, "bad state in suspend_process()\n"); + ASSERT(runq); + + erts_smp_runq_lock(runq); + + /* Enqueue the process */ + enqueue_process(runq, prio, p); + + erts_smp_runq_unlock(runq); + smp_notify_inc_runq(runq); + +} + +static ERTS_INLINE void +schedule_process(Process *p, erts_aint32_t state, int active_enq) +{ + erts_aint32_t a = state, n; + + while (1) { + erts_aint32_t e; + n = e = a; + + if (a & ERTS_PSFLG_FREE) + return; /* We don't want to schedule free processes... */ + n |= ERTS_PSFLG_ACTIVE; + if (!(a & (ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_RUNNING))) + n |= ERTS_PSFLG_IN_RUNQ; + a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e); + if (a == e) + break; + if (!active_enq && (a & ERTS_PSFLG_ACTIVE)) + return; /* Someone else activated process ... */ } - if ((erts_system_profile_flags.runnable_procs) && (p->rcount == 1) && (p->status != P_WAITING)) { - profile_runnable_proc(p, am_inactive); + if (erts_system_profile_flags.runnable_procs + && !(a & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED))) { + profile_runnable_proc(p, am_active); } - p->status = P_SUSPENDED; - + if ((n & ERTS_PSFLG_IN_RUNQ) && !(a & ERTS_PSFLG_IN_RUNQ)) + add2runq(p, n); } -static ERTS_INLINE void -resume_process(Process *p) +void +erts_schedule_process(Process *p, erts_aint32_t state) +{ + schedule_process(p, state, 0); +} + +static ERTS_INLINE int +suspend_process(Process *c_p, Process *p) { - Uint32 *statusp; + erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state); + int suspended = 0; ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - switch (p->status) { - case P_SUSPENDED: - statusp = &p->status; - break; - case P_GARBING: - if (p->gcstatus == P_SUSPENDED) { - statusp = &p->gcstatus; - break; + + if ((state & ERTS_PSFLG_SUSPENDED)) + suspended = -1; + else { + if (c_p == p) { + state = erts_smp_atomic32_read_bor_relb(&p->state, + ERTS_PSFLG_SUSPENDED); + state |= ERTS_PSFLG_SUSPENDED; + ASSERT(state & ERTS_PSFLG_RUNNING); + suspended = 1; } - /* Fall through */ - default: - return; + else { + while (!(state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_EXITING))) { + erts_aint32_t e, n; + n = e = state; + n |= ERTS_PSFLG_SUSPENDED; + state = erts_smp_atomic32_cmpxchg_relb(&p->state, n, e); + if (state == e) { + state = n; + suspended = 1; + break; + } + } + } + } + + if (state & ERTS_PSFLG_SUSPENDED) { + + ASSERT(!(ERTS_PSFLG_RUNNING & state) + || p == erts_get_current_process()); + + if (erts_system_profile_flags.runnable_procs + && (p->rcount == 0) + && (state & ERTS_PSFLG_ACTIVE)) { + profile_runnable_proc(p, am_inactive); + } + + p->rcount++; /* count number of suspend */ } + return suspended; +} + +static ERTS_INLINE void +resume_process(Process *p) +{ + erts_aint32_t state; + ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); ASSERT(p->rcount > 0); if (--p->rcount > 0) /* multiple suspend */ return; - switch(p->rstatus) { - case P_RUNABLE: - erts_add_to_runq(p); - break; - case P_WAITING: - *statusp = P_WAITING; - break; - default: - erl_exit(1, "bad state in resume_process()\n"); + + state = erts_smp_atomic32_read_band_mb(&p->state, ~ERTS_PSFLG_SUSPENDED); + state &= ~ERTS_PSFLG_SUSPENDED; + if ((state & (ERTS_PSFLG_EXITING + | ERTS_PSFLG_ACTIVE + | ERTS_PSFLG_IN_RUNQ + | ERTS_PSFLG_RUNNING)) == ERTS_PSFLG_ACTIVE) { + schedule_process(p, state, 1); } - p->rstatus = P_FREE; } int @@ -4433,6 +5295,7 @@ suspend_scheduler(ErtsSchedulerData *esdp) int wake = 0; erts_aint32_t aux_work; int thr_prgr_active = 1; + ErtsStuckBoundProcesses sbp = {NULL, NULL}; /* * Schedulers may be suspended in two different ways: @@ -4447,6 +5310,8 @@ suspend_scheduler(ErtsSchedulerData *esdp) ASSERT(no != 1); + evacuate_run_queue(esdp->run_queue, &sbp); + erts_smp_runq_unlock(esdp->run_queue); erts_sched_check_cpu_bind_prep_suspend(esdp); @@ -4510,19 +5375,28 @@ suspend_scheduler(ErtsSchedulerData *esdp) erts_smp_mtx_unlock(&schdlr_sspnd.mtx); while (1) { + erts_aint32_t qmask; erts_aint32_t flgs; + qmask = (ERTS_RUNQ_FLGS_GET(esdp->run_queue) + & ERTS_RUNQ_FLGS_QMASK); aux_work = erts_atomic32_read_acqb(&ssi->aux_work); - if (aux_work) { + if (aux_work|qmask) { if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); sched_wall_time_change(esdp, 1); } - aux_work = handle_aux_work(&esdp->aux_work_data, - aux_work, - 1); + if (aux_work) + aux_work = handle_aux_work(&esdp->aux_work_data, + aux_work, + 1); if (aux_work && erts_thr_progress_update(esdp)) erts_thr_progress_leader_update(esdp); + if (qmask) { + erts_smp_runq_lock(esdp->run_queue); + evacuate_run_queue(esdp->run_queue, &sbp); + erts_smp_runq_unlock(esdp->run_queue); + } } if (!aux_work) { @@ -4592,56 +5466,11 @@ suspend_scheduler(ErtsSchedulerData *esdp) erts_smp_runq_lock(esdp->run_queue); non_empty_runq(esdp->run_queue); + schedule_bound_processes(esdp->run_queue, &sbp); + erts_sched_check_cpu_bind_post_suspend(esdp); } -#define ERTS_RUNQ_RESET_SUSPEND_INFO(RQ, DBG_ID) \ -do { \ - int pix__; \ - (RQ)->misc.evac_runq = NULL; \ - (RQ)->ports.info.migrate.runq = NULL; \ - (RQ)->flags &= ~(ERTS_RUNQ_FLGS_IMMIGRATE_QMASK \ - | ERTS_RUNQ_FLGS_EMIGRATE_QMASK \ - | ERTS_RUNQ_FLGS_EVACUATE_QMASK \ - | ERTS_RUNQ_FLG_SUSPENDED); \ - (RQ)->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK \ - | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK); \ - (RQ)->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS; \ - erts_smp_atomic32_read_band_nob(&(RQ)->info_flags, ~ERTS_RUNQ_IFLG_SUSPENDED);\ - for (pix__ = 0; pix__ < ERTS_NO_PROC_PRIO_LEVELS; pix__++) { \ - (RQ)->procs.prio_info[pix__].max_len = 0; \ - (RQ)->procs.prio_info[pix__].reds = 0; \ - ERTS_DBG_SET_INVALID_RUNQP((RQ)->procs.prio_info[pix__].migrate.runq,\ - (DBG_ID)); \ - } \ - (RQ)->ports.info.max_len = 0; \ - (RQ)->ports.info.reds = 0; \ -} while (0) - -#define ERTS_RUNQ_RESET_MIGRATION_PATHS__(RQ) \ -do { \ - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked((RQ))); \ - (RQ)->misc.evac_runq = NULL; \ - (RQ)->ports.info.migrate.runq = NULL; \ - (RQ)->flags &= ~(ERTS_RUNQ_FLGS_IMMIGRATE_QMASK \ - | ERTS_RUNQ_FLGS_EMIGRATE_QMASK \ - | ERTS_RUNQ_FLGS_EVACUATE_QMASK); \ -} while (0) - -#ifdef DEBUG -#define ERTS_RUNQ_RESET_MIGRATION_PATHS(RQ, DBG_ID) \ -do { \ - int pix__; \ - ERTS_RUNQ_RESET_MIGRATION_PATHS__((RQ)); \ - for (pix__ = 0; pix__ < ERTS_NO_PROC_PRIO_LEVELS; pix__++) \ - ERTS_DBG_SET_INVALID_RUNQP((RQ)->procs.prio_info[pix__].migrate.runq,\ - (DBG_ID)); \ -} while (0) -#else -#define ERTS_RUNQ_RESET_MIGRATION_PATHS(RQ, DBG_ID) \ - ERTS_RUNQ_RESET_MIGRATION_PATHS__((RQ)) -#endif - ErtsSchedSuspendResult erts_schedulers_state(Uint *total, Uint *online, @@ -4711,27 +5540,13 @@ erts_set_schedulers_online(Process *p, have_unlocked_plocks = 1; erts_smp_proc_unlock(p, plocks); } - erts_smp_mtx_unlock(&schdlr_sspnd.mtx); - erts_smp_mtx_lock(&balance_info.update_mtx); - for (ix = online; ix < no; ix++) { - ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - erts_smp_runq_lock(rq); - ERTS_RUNQ_RESET_SUSPEND_INFO(rq, 0x5); - erts_smp_runq_unlock(rq); - scheduler_ix_resume_wake(ix); - } - /* - * Spread evacuation paths among all online - * run queues. - */ - for (ix = no; ix < erts_no_run_queues; ix++) { - ErtsRunQueue *from_rq = ERTS_RUNQ_IX(ix); - ErtsRunQueue *to_rq = ERTS_RUNQ_IX(ix % no); - evacuate_run_queue(from_rq, to_rq); - } - set_no_used_runqs(no); - erts_smp_mtx_unlock(&balance_info.update_mtx); - erts_smp_mtx_lock(&schdlr_sspnd.mtx); + change_no_used_runqs(no); + + for (ix = online; ix < no; ix++) + resume_run_queue(ERTS_RUNQ_IX(ix)); + + for (ix = no; ix < erts_no_run_queues; ix++) + suspend_run_queue(ERTS_RUNQ_IX(ix)); } res = ERTS_SCHDLR_SSPND_DONE; } @@ -4758,25 +5573,11 @@ erts_set_schedulers_online(Process *p, have_unlocked_plocks = 1; erts_smp_proc_unlock(p, plocks); } - erts_smp_mtx_unlock(&schdlr_sspnd.mtx); - erts_smp_mtx_lock(&balance_info.update_mtx); - - for (ix = 0; ix < online; ix++) { - ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - erts_smp_runq_lock(rq); - ERTS_RUNQ_RESET_MIGRATION_PATHS(rq, 0x6); - erts_smp_runq_unlock(rq); - } - /* - * Evacutation order important! Newly suspended run queues - * has to be evacuated last. - */ - for (ix = erts_no_run_queues-1; ix >= no; ix--) - evacuate_run_queue(ERTS_RUNQ_IX(ix), - ERTS_RUNQ_IX(ix % no)); - set_no_used_runqs(no); - erts_smp_mtx_unlock(&balance_info.update_mtx); - erts_smp_mtx_lock(&schdlr_sspnd.mtx); + + change_no_used_runqs(no); + for (ix = no; ix < erts_no_run_queues; ix++) + suspend_run_queue(ERTS_RUNQ_IX(ix)); + for (ix = no; ix < online; ix++) { ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); wake_scheduler(rq, 0); @@ -4873,25 +5674,14 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) schdlr_sspnd.msb.wait_active = 2; } - erts_smp_mtx_unlock(&schdlr_sspnd.mtx); - erts_smp_mtx_lock(&balance_info.update_mtx); - set_no_used_runqs(1); - for (ix = 0; ix < online; ix++) { + change_no_used_runqs(1); + for (ix = 1; ix < erts_no_run_queues; ix++) + suspend_run_queue(ERTS_RUNQ_IX(ix)); + + for (ix = 1; ix < online; ix++) { ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - erts_smp_runq_lock(rq); - ASSERT(!(rq->flags & ERTS_RUNQ_FLG_SUSPENDED)); - ERTS_RUNQ_RESET_MIGRATION_PATHS(rq, 0x7); - erts_smp_runq_unlock(rq); + wake_scheduler(rq, 0); } - /* - * Evacuate all activities in all other run queues - * into the first run queue. Note order is important, - * online run queues has to be evacuated last. - */ - for (ix = erts_no_run_queues-1; ix >= 1; ix--) - evacuate_run_queue(ERTS_RUNQ_IX(ix), ERTS_RUNQ_IX(0)); - erts_smp_mtx_unlock(&balance_info.update_mtx); - erts_smp_mtx_lock(&schdlr_sspnd.mtx); if (erts_smp_atomic32_read_nob(&schdlr_sspnd.active) != schdlr_sspnd.msb.wait_active) { @@ -4935,15 +5725,6 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) plp = proclist_create(p); plp->next = schdlr_sspnd.msb.procs; schdlr_sspnd.msb.procs = plp; -#ifdef DEBUG - ERTS_FOREACH_RUNQ(srq, - { - if (srq != ERTS_RUNQ_IX(0)) { - ASSERT(ERTS_EMPTY_RUNQ(srq)); - ASSERT(srq->flags & ERTS_RUNQ_FLG_SUSPENDED); - } - }); -#endif ASSERT(p->scheduler_data); } } @@ -4975,27 +5756,6 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED; else { ERTS_SCHDLR_SSPND_CHNG_SET(ERTS_SCHDLR_SSPND_CHNG_MSB, 0); -#ifdef DEBUG - ERTS_FOREACH_RUNQ(rq, - { - if (rq != p->scheduler_data->run_queue) { - if (!ERTS_EMPTY_RUNQ(rq)) { - Process *rp; - int pix; - ASSERT(rq->ports.info.len == 0); - for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) { - for (rp = rq->procs.prio[pix].first; - rp; - rp = rp->next) { - ASSERT(rp->bound_runq); - } - } - } - - ASSERT(rq->flags & ERTS_RUNQ_FLG_SUSPENDED); - } - }); -#endif p->flags &= ~F_HAVE_BLCKD_MSCHED; schdlr_sspnd.msb.ongoing = 0; if (schdlr_sspnd.online == 1) { @@ -5005,35 +5765,19 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) } else { int online = schdlr_sspnd.online; - erts_smp_mtx_unlock(&schdlr_sspnd.mtx); if (plocks) { have_unlocked_plocks = 1; erts_smp_proc_unlock(p, plocks); } - erts_smp_mtx_lock(&balance_info.update_mtx); + + change_no_used_runqs(online); /* Resume all online run queues */ - for (ix = 1; ix < online; ix++) { - ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - erts_smp_runq_lock(rq); - ERTS_RUNQ_RESET_SUSPEND_INFO(rq, 0x4); - erts_smp_runq_unlock(rq); - scheduler_ix_resume_wake(ix); - } + for (ix = 1; ix < online; ix++) + resume_run_queue(ERTS_RUNQ_IX(ix)); - /* Spread evacuation paths among all online run queues */ for (ix = online; ix < erts_no_run_queues; ix++) - evacuate_run_queue(ERTS_RUNQ_IX(ix), - ERTS_RUNQ_IX(ix % online)); - - set_no_used_runqs(online); - /* Make sure that we balance soon... */ - balance_info.forced_check_balance = 1; - erts_smp_runq_lock(ERTS_RUNQ_IX(0)); - ERTS_RUNQ_IX(0)->check_balance_reds = 0; - erts_smp_runq_unlock(ERTS_RUNQ_IX(0)); - erts_smp_mtx_unlock(&balance_info.update_mtx); - erts_smp_mtx_lock(&schdlr_sspnd.mtx); + suspend_run_queue(ERTS_RUNQ_IX(ix)); } res = ERTS_SCHDLR_SSPND_DONE; } @@ -5340,10 +6084,7 @@ handle_pend_sync_suspend(Process *suspendee, if (suspender) { ASSERT(is_nil(suspender->suspendee)); if (suspendee_alive) { - ErtsRunQueue *rq = erts_get_runq_proc(suspendee); - erts_smp_runq_lock(rq); - suspend_process(rq, suspendee); - erts_smp_runq_unlock(rq); + erts_suspend(suspendee, suspendee_locks, NULL); suspender->suspendee = suspendee->id; } /* suspender is suspended waiting for suspendee to suspend; @@ -5386,10 +6127,9 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks, resume_process(rp); } else { - ErtsRunQueue *cp_rq, *rp_rq; rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS, - pid, ERTS_PROC_LOCK_STATUS); + pid, pid_locks|ERTS_PROC_LOCK_STATUS); if (!rp) { c_p->flags &= ~F_P2PNR_RESCHED; @@ -5398,58 +6138,36 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks, ASSERT(!(c_p->flags & F_P2PNR_RESCHED)); - cp_rq = erts_get_runq_proc(c_p); - rp_rq = erts_get_runq_proc(rp); - erts_smp_runqs_lock(cp_rq, rp_rq); - if (rp->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) { - running: - /* Phiu... */ - - /* - * If we got pending suspenders and suspend ourselves waiting - * to suspend another process we might deadlock. - * In this case we have to yield, be suspended by - * someone else and then do it all over again. - */ - if (!c_p->pending_suspenders) { - /* Mark rp pending for suspend by c_p */ - add_pend_suspend(rp, c_p->id, handle_pend_sync_suspend); - ASSERT(is_nil(c_p->suspendee)); - - /* Suspend c_p; when rp is suspended c_p will be resumed. */ - suspend_process(cp_rq, c_p); - c_p->flags |= F_P2PNR_RESCHED; - } - /* Yield (caller is assumed to yield immediately in bif). */ - erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); - rp = ERTS_PROC_LOCK_BUSY; + if (suspend) { + if (suspend_process(c_p, rp)) + goto done; } else { - ErtsProcLocks need_locks = pid_locks & ~ERTS_PROC_LOCK_STATUS; - if (need_locks && erts_smp_proc_trylock(rp, need_locks) == EBUSY) { - erts_smp_runqs_unlock(cp_rq, rp_rq); - erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); - rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS, - pid, pid_locks|ERTS_PROC_LOCK_STATUS); - if (!rp) - goto done; - /* run-queues may have changed */ - cp_rq = erts_get_runq_proc(c_p); - rp_rq = erts_get_runq_proc(rp); - erts_smp_runqs_lock(cp_rq, rp_rq); - if (rp->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) { - /* Ahh... */ - erts_smp_proc_unlock(rp, - pid_locks & ~ERTS_PROC_LOCK_STATUS); - goto running; - } - } + if (!(ERTS_PSFLG_RUNNING & erts_smp_atomic32_read_acqb(&rp->state))) + goto done; + + } + + /* Other process running */ - /* rp is not running and we got the locks we want... */ - if (suspend) - suspend_process(rp_rq, rp); + /* + * If we got pending suspenders and suspend ourselves waiting + * to suspend another process we might deadlock. + * In this case we have to yield, be suspended by + * someone else and then do it all over again. + */ + if (!c_p->pending_suspenders) { + /* Mark rp pending for suspend by c_p */ + add_pend_suspend(rp, c_p->id, handle_pend_sync_suspend); + ASSERT(is_nil(c_p->suspendee)); + + /* Suspend c_p; when rp is suspended c_p will be resumed. */ + suspend_process(c_p, c_p); + c_p->flags |= F_P2PNR_RESCHED; } - erts_smp_runqs_unlock(cp_rq, rp_rq); + /* Yield (caller is assumed to yield immediately in bif). */ + erts_smp_proc_unlock(rp, pid_locks|ERTS_PROC_LOCK_STATUS); + rp = ERTS_PROC_LOCK_BUSY; } done: @@ -5506,36 +6224,26 @@ erts_pid2proc_nropt(Process *c_p, ErtsProcLocks c_p_locks, return erts_pid2proc_not_running(c_p, c_p_locks, pid, pid_locks); } -static ERTS_INLINE void -do_bif_suspend_process(ErtsSuspendMonitor *smon, - Process *suspendee, - ErtsRunQueue *locked_runq) +static ERTS_INLINE int +do_bif_suspend_process(Process *c_p, + ErtsSuspendMonitor *smon, + Process *suspendee) { ASSERT(suspendee); - ASSERT(!suspendee->is_exiting); + ASSERT(!ERTS_PROC_IS_EXITING(suspendee)); ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(suspendee)); if (smon) { if (!smon->active) { - ErtsRunQueue *rq; - - if (locked_runq) - rq = locked_runq; - else { - rq = erts_get_runq_proc(suspendee); - erts_smp_runq_lock(rq); - } - - suspend_process(rq, suspendee); - - if (!locked_runq) - erts_smp_runq_unlock(rq); + if (!suspend_process(c_p, suspendee)) + return 0; } smon->active += smon->pending; ASSERT(smon->active); smon->pending = 0; + return 1; } - + return 0; } static void @@ -5558,10 +6266,17 @@ handle_pend_bif_sync_suspend(Process *suspendee, erts_delete_suspend_monitor(&suspender->suspend_monitors, suspendee->id); else { +#ifdef DEBUG + int res; +#endif ErtsSuspendMonitor *smon; smon = erts_lookup_suspend_monitor(suspender->suspend_monitors, suspendee->id); - do_bif_suspend_process(smon, suspendee, NULL); +#ifdef DEBUG + res = +#endif + do_bif_suspend_process(suspendee, smon, suspendee); + ASSERT(!smon || res != 0); suspender->suspendee = suspendee->id; } /* suspender is suspended waiting for suspendee to suspend; @@ -5593,10 +6308,17 @@ handle_pend_bif_async_suspend(Process *suspendee, erts_delete_suspend_monitor(&suspender->suspend_monitors, suspendee->id); else { +#ifdef DEBUG + int res; +#endif ErtsSuspendMonitor *smon; smon = erts_lookup_suspend_monitor(suspender->suspend_monitors, suspendee->id); - do_bif_suspend_process(smon, suspendee, NULL); +#ifdef DEBUG + res = +#endif + do_bif_suspend_process(suspendee, smon, suspendee); + ASSERT(!smon || res != 0); } erts_smp_proc_unlock(suspender, ERTS_PROC_LOCK_LINK); } @@ -5681,7 +6403,8 @@ suspend_process_2(BIF_ALIST_2) /* This is really a piece of cake without SMP support... */ if (!smon->active) { - suspend_process(ERTS_RUNQ_IX(0), suspendee); + erts_smp_atomic32_read_bor_nob(&suspendee->state, ERTS_PSFLG_SUSPENDED); + suspend_process(BIF_P, suspendee); smon->active++; res = am_true; } @@ -5724,21 +6447,15 @@ suspend_process_2(BIF_ALIST_2) if (smon->pending && unless_suspending) res = am_false; else { - ErtsRunQueue *rq; if (smon->pending == INT_MAX) goto system_limit; smon->pending++; - rq = erts_get_runq_proc(suspendee); - erts_smp_runq_lock(rq); - if (suspendee->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) + if (!do_bif_suspend_process(BIF_P, smon, suspendee)) add_pend_suspend(suspendee, BIF_P->id, handle_pend_bif_async_suspend); - else - do_bif_suspend_process(smon, suspendee, rq); - erts_smp_runq_unlock(rq); res = am_true; } @@ -5775,7 +6492,6 @@ suspend_process_2(BIF_ALIST_2) /* done */ } else { - ErtsRunQueue *cp_rq, *s_rq; /* We haven't got any active suspends on the suspendee */ /* @@ -5792,12 +6508,7 @@ suspend_process_2(BIF_ALIST_2) if (!unless_suspending || smon->pending == 0) smon->pending++; - cp_rq = erts_get_runq_proc(BIF_P); - s_rq = erts_get_runq_proc(suspendee); - erts_smp_runqs_lock(cp_rq, s_rq); - if (!(suspendee->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING)) { - do_bif_suspend_process(smon, suspendee, s_rq); - erts_smp_runqs_unlock(cp_rq, s_rq); + if (do_bif_suspend_process(BIF_P, smon, suspendee)) { res = (!unless_suspending || smon->active == 1 ? am_true : am_false); @@ -5817,8 +6528,7 @@ suspend_process_2(BIF_ALIST_2) * This time with BIF_P->suspendee == BIF_ARG_1 (see * above). */ - suspend_process(cp_rq, BIF_P); - erts_smp_runqs_unlock(cp_rq, s_rq); + suspend_process(BIF_P, BIF_P); goto yield; } } @@ -5826,9 +6536,15 @@ suspend_process_2(BIF_ALIST_2) } #endif /* ERTS_SMP */ - - ASSERT(suspendee->status == P_SUSPENDED || (asynchronous && smon->pending)); - ASSERT(suspendee->status == P_SUSPENDED || !smon->active); +#ifdef DEBUG + { + erts_aint32_t state = erts_smp_atomic32_read_acqb(&suspendee->state); + ASSERT((state & ERTS_PSFLG_SUSPENDED) + || (asynchronous && smon->pending)); + ASSERT((state & ERTS_PSFLG_SUSPENDED) + || !smon->active); + } +#endif erts_smp_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS); erts_smp_proc_unlock(BIF_P, xlocks); @@ -5923,9 +6639,8 @@ resume_process_1(BIF_ALIST_1) if (!suspendee) goto no_suspendee; - ASSERT(suspendee->status == P_SUSPENDED - || (suspendee->status == P_GARBING - && suspendee->gcstatus == P_SUSPENDED)); + ASSERT(ERTS_PSFLG_SUSPENDED + & erts_smp_atomic32_read_nob(&suspendee->state)); resume_process(suspendee); erts_smp_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS); @@ -5954,449 +6669,46 @@ erts_run_queues_len(Uint *qlen) Uint len = 0; ERTS_ATOMIC_FOREACH_RUNQ(rq, { - if (qlen) - qlen[i++] = rq->procs.len; - len += rq->procs.len; + Sint pqlen = 0; + int pix; + for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) + pqlen += RUNQ_READ_LEN(&rq->procs.prio_info[pix].len); + + if (pqlen < 0) + pqlen = 0; + if (qlen) + qlen[i++] = pqlen; + len += pqlen; } ); return len; } -#ifdef HARDDEBUG_RUNQS -static void -check_procs_runq(ErtsRunQueue *runq, Process *p_in_q, Process *p_not_in_q) -{ - int len[ERTS_NO_PROC_PRIO_LEVELS] = {0}; - int tot_len; - int prioq, prio; - int found_p_in_q; - Process *p, *prevp; - - found_p_in_q = 0; - for (prioq = 0; prioq < ERTS_NO_PROC_PRIO_LEVELS - 1; prioq++) { - prevp = NULL; - for (p = runq->procs.prio[prioq].first; p; p = p->next) { - ASSERT(p != p_not_in_q); - if (p == p_in_q) - found_p_in_q = 1; - switch (p->prio) { - case PRIORITY_MAX: - case PRIORITY_HIGH: - case PRIORITY_NORMAL: - ASSERT(prioq == p->prio); - break; - case PRIORITY_LOW: - ASSERT(prioq == PRIORITY_NORMAL); - break; - default: - ASSERT(!"Bad prio on process"); - } - len[p->prio]++; - ASSERT(prevp == p->prev); - if (p->prev) { - ASSERT(p->prev->next == p); - } - else { - ASSERT(runq->procs.prio[prioq].first == p); - } - if (p->next) { - ASSERT(p->next->prev == p); - } - else { - ASSERT(runq->procs.prio[prioq].last == p); - } - ASSERT(p->run_queue == runq); - prevp = p; - } - } - - ASSERT(!p_in_q || found_p_in_q); - - tot_len = 0; - for (prio = 0; prio < ERTS_NO_PROC_PRIO_LEVELS; prio++) { - ASSERT(len[prio] == runq->procs.prio_info[prio].len); - if (len[prio]) { - ASSERT(runq->flags & (1 << prio)); - } - else { - ASSERT(!(runq->flags & (1 << prio))); - } - tot_len += len[prio]; - } - ASSERT(runq->procs.len == tot_len); -} -# define ERTS_DBG_CHK_PROCS_RUNQ(RQ) check_procs_runq((RQ), NULL, NULL) -# define ERTS_DBG_CHK_PROCS_RUNQ_PROC(RQ, P) check_procs_runq((RQ), (P), NULL) -# define ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(RQ, P) check_procs_runq((RQ), NULL, (P)) -#else -# define ERTS_DBG_CHK_PROCS_RUNQ(RQ) -# define ERTS_DBG_CHK_PROCS_RUNQ_PROC(RQ, P) -# define ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(RQ, P) -#endif - - -static ERTS_INLINE void -enqueue_process(ErtsRunQueue *runq, Process *p) -{ - ErtsRunPrioQueue *rpq; - ErtsRunQueueInfo *rqi; - - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - - ASSERT(p->bound_runq || !(runq->flags & ERTS_RUNQ_FLG_SUSPENDED)); - - rqi = &runq->procs.prio_info[p->prio]; - rqi->len++; - if (rqi->max_len < rqi->len) - rqi->max_len = rqi->len; - - runq->procs.len++; - runq->len++; - if (runq->max_len < runq->len) - runq->max_len = runq->len; - - runq->flags |= (1 << p->prio); - - rpq = (p->prio == PRIORITY_LOW - ? &runq->procs.prio[PRIORITY_NORMAL] - : &runq->procs.prio[p->prio]); - - p->next = NULL; - p->prev = rpq->last; - if (rpq->last) - rpq->last->next = p; - else - rpq->first = p; - rpq->last = p; - - switch (p->status) { - case P_EXITING: - break; - case P_GARBING: - p->gcstatus = P_RUNABLE; - break; - default: - p->status = P_RUNABLE; - break; - } - -#ifdef ERTS_SMP - p->status_flags |= ERTS_PROC_SFLG_INRUNQ; -#endif - - ERTS_DBG_CHK_PROCS_RUNQ_PROC(runq, p); -} - - -static ERTS_INLINE int -dequeue_process(ErtsRunQueue *runq, Process *p) -{ - ErtsRunPrioQueue *rpq; - int res = 1; - - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - - ERTS_DBG_CHK_PROCS_RUNQ(runq); - - rpq = &runq->procs.prio[p->prio == PRIORITY_LOW ? PRIORITY_NORMAL : p->prio]; - if (p->prev) { - p->prev->next = p->next; - } - else if (rpq->first == p) { - rpq->first = p->next; - } - else { - res = 0; - } - if (p->next) { - p->next->prev = p->prev; - } - else if (rpq->last == p) { - rpq->last = p->prev; - } - else { - ASSERT(res == 0); - } - - if (res) { - - if (--runq->procs.prio_info[p->prio].len == 0) - runq->flags &= ~(1 << p->prio); - runq->procs.len--; - runq->len--; - -#ifdef ERTS_SMP - p->status_flags &= ~ERTS_PROC_SFLG_INRUNQ; -#endif - } - - ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p); - return res; -} - -/* schedule a process */ -static ERTS_INLINE ErtsRunQueue * -internal_add_to_runq(ErtsRunQueue *runq, Process *p) -{ - Uint32 prev_status = p->status; - ErtsRunQueue *add_runq; -#ifdef ERTS_SMP - - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); - - if (p->status_flags & ERTS_PROC_SFLG_INRUNQ) - return NULL; - else if (p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) { - ASSERT(ERTS_PROC_IS_EXITING(p) || p->rcount == 0); - ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p); - p->status_flags |= ERTS_PROC_SFLG_PENDADD2SCHEDQ; - return NULL; - } - ASSERT(!p->scheduler_data); -#endif - - ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p); -#ifndef ERTS_SMP - /* Never schedule a suspended process (ok in smp case) */ - ASSERT(ERTS_PROC_IS_EXITING(p) || p->rcount == 0); - add_runq = runq; -#else - ASSERT(!p->bound_runq || p->bound_runq == p->run_queue); - if (p->bound_runq) { - if (p->bound_runq == runq) - add_runq = runq; - else { - add_runq = p->bound_runq; - erts_smp_xrunq_lock(runq, add_runq); - } - } - else { - add_runq = erts_check_emigration_need(runq, p->prio); - if (!add_runq) - add_runq = runq; - else /* Process emigrated */ - p->run_queue = add_runq; - } -#endif - - /* Enqueue the process */ - enqueue_process(add_runq, p); - - if ((erts_system_profile_flags.runnable_procs) - && (prev_status == P_WAITING - || prev_status == P_SUSPENDED)) { - profile_runnable_proc(p, am_active); - } - - if (add_runq != runq) - erts_smp_runq_unlock(add_runq); - - return add_runq; -} - - -void -erts_add_to_runq(Process *p) -{ - ErtsRunQueue *notify_runq; - ErtsRunQueue *runq = erts_get_runq_proc(p); - erts_smp_runq_lock(runq); - notify_runq = internal_add_to_runq(runq, p); - erts_smp_runq_unlock(runq); - smp_notify_inc_runq(notify_runq); - -} - -/* Possibly remove a scheduled process we need to suspend */ - -static int -remove_proc_from_runq(ErtsRunQueue *rq, Process *p, int to_inactive) -{ - int res; - - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - -#ifdef ERTS_SMP - if (p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) { - p->status_flags &= ~ERTS_PROC_SFLG_PENDADD2SCHEDQ; - ASSERT(!remove_proc_from_runq(rq, p, 0)); - return 1; - } -#endif - - res = dequeue_process(rq, p); - - if (res && erts_system_profile_flags.runnable_procs && to_inactive) - profile_runnable_proc(p, am_inactive); - -#ifdef ERTS_SMP - ASSERT(!(p->status_flags & ERTS_PROC_SFLG_INRUNQ)); -#endif - - return res; -} - -#ifdef ERTS_SMP - -ErtsMigrateResult -erts_proc_migrate(Process *p, ErtsProcLocks *plcks, - ErtsRunQueue *from_rq, int *from_locked, - ErtsRunQueue *to_rq, int *to_locked) -{ - ERTS_SMP_LC_ASSERT(*plcks == erts_proc_lc_my_proc_locks(p)); - ERTS_SMP_LC_ASSERT((ERTS_PROC_LOCK_STATUS & *plcks) - || from_locked); - ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked); - ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked); - - /* - * If we have the lock on the run queue to migrate to, - * check that it isn't suspended. If it is suspended, - * we will refuse to migrate to it anyway. - */ - if (*to_locked && (to_rq->flags & ERTS_RUNQ_FLG_SUSPENDED)) - return ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED; - - /* We need status lock on process and locks on both run queues */ - - if (!(ERTS_PROC_LOCK_STATUS & *plcks)) { - if (erts_smp_proc_trylock(p, ERTS_PROC_LOCK_STATUS) == EBUSY) { - ErtsProcLocks lcks = *plcks; - Eterm pid = p->id; - Process *proc = *plcks ? p : NULL; - - if (*from_locked) { - *from_locked = 0; - erts_smp_runq_unlock(from_rq); - } - if (*to_locked) { - *to_locked = 0; - erts_smp_runq_unlock(to_rq); - } - - proc = erts_pid2proc_opt(proc, - lcks, - pid, - lcks|ERTS_PROC_LOCK_STATUS, - ERTS_P2P_FLG_ALLOW_OTHER_X); - if (!proc) { - *plcks = 0; - return ERTS_MIGRATE_FAILED_NOT_IN_RUNQ; - } - ASSERT(proc == p); - } - *plcks |= ERTS_PROC_LOCK_STATUS; - } - - ASSERT(!p->bound_runq); - - ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked); - ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked); - - if (p->run_queue != from_rq) - return ERTS_MIGRATE_FAILED_RUNQ_CHANGED; - - if (!*from_locked || !*to_locked) { - if (from_rq < to_rq) { - if (!*to_locked) { - if (!*from_locked) - erts_smp_runq_lock(from_rq); - erts_smp_runq_lock(to_rq); - } - else if (erts_smp_runq_trylock(from_rq) == EBUSY) { - erts_smp_runq_unlock(to_rq); - erts_smp_runq_lock(from_rq); - erts_smp_runq_lock(to_rq); - } - } - else { - if (!*from_locked) { - if (!*to_locked) - erts_smp_runq_lock(to_rq); - erts_smp_runq_lock(from_rq); - } - else if (erts_smp_runq_trylock(to_rq) == EBUSY) { - erts_smp_runq_unlock(from_rq); - erts_smp_runq_lock(to_rq); - erts_smp_runq_lock(from_rq); - } - } - *to_locked = *from_locked = 1; - } - - ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked); - ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked); - - /* Ok we now got all locks we need; do it... */ - - /* Refuse to migrate to a suspended run queue */ - if (to_rq->flags & ERTS_RUNQ_FLG_SUSPENDED) - return ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED; - - if ((p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) - || !(p->status_flags & ERTS_PROC_SFLG_INRUNQ)) - return ERTS_MIGRATE_FAILED_NOT_IN_RUNQ; - - dequeue_process(from_rq, p); - p->run_queue = to_rq; - enqueue_process(to_rq, p); - - return ERTS_MIGRATE_SUCCESS; -} -#endif /* ERTS_SMP */ - Eterm erts_process_status(Process *c_p, ErtsProcLocks c_p_locks, Process *rp, Eterm rpid) { Eterm res = am_undefined; - Process *p; - - if (rp) { - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS - & erts_proc_lc_my_proc_locks(rp)); - p = rp; - } - else { - p = erts_pid2proc_opt(c_p, c_p_locks, - rpid, ERTS_PROC_LOCK_STATUS, - ERTS_P2P_FLG_ALLOW_OTHER_X); - } + Process *p = rp ? rp : erts_proc_lookup_raw(rpid); if (p) { - switch (p->status) { - case P_RUNABLE: - res = am_runnable; - break; - case P_WAITING: - res = am_waiting; - break; - case P_RUNNING: - res = am_running; - break; - case P_EXITING: + erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state); + if (state & ERTS_PSFLG_FREE) + res = am_free; + else if (state & ERTS_PSFLG_EXITING) res = am_exiting; - break; - case P_GARBING: + else if (state & ERTS_PSFLG_GC) res = am_garbage_collecting; - break; - case P_SUSPENDED: + else if (state & ERTS_PSFLG_SUSPENDED) res = am_suspended; - break; - case P_FREE: /* We cannot look up a process in P_FREE... */ - default: /* Not a valid status... */ - erl_exit(1, "Bad status (%b32u) found for process %T\n", - p->status, p->id); - break; - } - -#ifdef ERTS_SMP - if (!rp && (p != c_p || !(ERTS_PROC_LOCK_STATUS & c_p_locks))) - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + else if (state & ERTS_PSFLG_RUNNING) + res = am_running; + else if (state & ERTS_PSFLG_ACTIVE) + res = am_runnable; + else + res = am_waiting; } +#ifdef ERTS_SMP else { int i; ErtsSchedulerData *esdp; @@ -6411,42 +6723,40 @@ erts_process_status(Process *c_p, ErtsProcLocks c_p_locks, } erts_smp_runq_unlock(esdp->run_queue); } - -#endif - } - +#endif return res; } /* -** Suspend a process +** Suspend a currently executing process ** If we are to suspend on a port the busy_port is the thing ** otherwise busy_port is NIL */ void -erts_suspend(Process* process, ErtsProcLocks process_locks, Port *busy_port) +erts_suspend(Process* c_p, ErtsProcLocks c_p_locks, Port *busy_port) { - ErtsRunQueue *rq; - - ERTS_SMP_LC_ASSERT(process_locks == erts_proc_lc_my_proc_locks(process)); - if (!(process_locks & ERTS_PROC_LOCK_STATUS)) - erts_smp_proc_lock(process, ERTS_PROC_LOCK_STATUS); - - rq = erts_get_runq_proc(process); - - erts_smp_runq_lock(rq); +#ifdef DEBUG + int res; +#endif + ASSERT(c_p == erts_get_current_process()); + ERTS_SMP_LC_ASSERT(c_p_locks == erts_proc_lc_my_proc_locks(c_p)); + if (!(c_p_locks & ERTS_PROC_LOCK_STATUS)) + erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS); - suspend_process(rq, process); +#ifdef DEBUG + res = +#endif + suspend_process(c_p, c_p); - erts_smp_runq_unlock(rq); + ASSERT(res); if (busy_port) - erts_wake_process_later(busy_port, process); + erts_wake_process_later(busy_port, c_p); - if (!(process_locks & ERTS_PROC_LOCK_STATUS)) - erts_smp_proc_unlock(process, ERTS_PROC_LOCK_STATUS); + if (!(c_p_locks & ERTS_PROC_LOCK_STATUS)) + erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS); } @@ -6487,57 +6797,54 @@ erts_resume_processes(ErtsProcList *plp) Eterm erts_get_process_priority(Process *p) { - ErtsRunQueue *rq; - Eterm value; - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - rq = erts_get_runq_proc(p); - erts_smp_runq_lock(rq); - switch(p->prio) { - case PRIORITY_MAX: value = am_max; break; - case PRIORITY_HIGH: value = am_high; break; - case PRIORITY_NORMAL: value = am_normal; break; - case PRIORITY_LOW: value = am_low; break; - default: ASSERT(0); value = am_undefined; break; + erts_aint32_t state = erts_smp_atomic32_read_nob(&p->state); + switch (state & ERTS_PSFLG_PRIO_MASK) { + case PRIORITY_MAX: return am_max; + case PRIORITY_HIGH: return am_high; + case PRIORITY_NORMAL: return am_normal; + case PRIORITY_LOW: return am_low; + default: ASSERT(0); return am_undefined; } - erts_smp_runq_unlock(rq); - return value; } Eterm -erts_set_process_priority(Process *p, Eterm new_value) +erts_set_process_priority(Process *p, Eterm value) { - ErtsRunQueue *rq; - Eterm old_value; - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - rq = erts_get_runq_proc(p); -#ifdef ERTS_SMP - ASSERT(!(p->status_flags & ERTS_PROC_SFLG_INRUNQ)); -#endif - erts_smp_runq_lock(rq); - switch(p->prio) { - case PRIORITY_MAX: old_value = am_max; break; - case PRIORITY_HIGH: old_value = am_high; break; - case PRIORITY_NORMAL: old_value = am_normal; break; - case PRIORITY_LOW: old_value = am_low; break; - default: ASSERT(0); old_value = am_undefined; break; - } - switch (new_value) { - case am_max: p->prio = PRIORITY_MAX; break; - case am_high: p->prio = PRIORITY_HIGH; break; - case am_normal: p->prio = PRIORITY_NORMAL; break; - case am_low: p->prio = PRIORITY_LOW; break; - default: old_value = THE_NON_VALUE; break; + erts_aint32_t a, oprio, nprio; + + switch (value) { + case am_max: nprio = (erts_aint32_t) PRIORITY_MAX; break; + case am_high: nprio = (erts_aint32_t) PRIORITY_HIGH; break; + case am_normal: nprio = (erts_aint32_t) PRIORITY_NORMAL; break; + case am_low: nprio = (erts_aint32_t) PRIORITY_LOW; break; + default: return THE_NON_VALUE; break; } - erts_smp_runq_unlock(rq); - return old_value; -} -/* note that P_RUNNING is only set so that we don't try to remove -** running processes from the schedule queue if they exit - a running -** process not being in the schedule queue!! -** Schedule for up to INPUT_REDUCTIONS context switches, -** return 1 if more to do. -*/ + a = erts_smp_atomic32_read_nob(&p->state); + if (nprio == (a & ERTS_PSFLG_PRIO_MASK)) + oprio = nprio; + else { + erts_aint32_t e, n; + do { + oprio = a & ERTS_PSFLG_PRIO_MASK; + n = e = a; + + ASSERT(!(a & ERTS_PSFLG_IN_RUNQ)); + + n &= ~ERTS_PSFLG_PRIO_MASK; + n |= nprio; + a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e); + } while (a != e); + } + + switch (oprio) { + case PRIORITY_MAX: return am_max; + case PRIORITY_HIGH: return am_high; + case PRIORITY_NORMAL: return am_normal; + case PRIORITY_LOW: return am_low; + default: ASSERT(0); return am_undefined; + } +} /* * schedule() is called from BEAM (process_main()) or HiPE @@ -6560,7 +6867,6 @@ erts_set_process_priority(Process *p, Eterm new_value) Process *schedule(Process *p, int calls) { ErtsRunQueue *rq; - ErtsRunPrioQueue *rpq; erts_aint_t dt; ErtsSchedulerData *esdp; int context_reds; @@ -6568,6 +6874,8 @@ Process *schedule(Process *p, int calls) int input_reductions; int actual_reds; int reds; + Uint32 flags; + erts_aint32_t state = 0; /* Supress warning... */ #ifdef USE_VM_PROBES if (p != NULL && DTRACE_ENABLED(process_unscheduled)) { @@ -6623,92 +6931,60 @@ Process *schedule(Process *p, int calls) erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - if ((erts_system_profile_flags.runnable_procs) - && (p->status == P_WAITING)) { - profile_runnable_proc(p, am_inactive); - } + state = erts_smp_atomic32_read_acqb(&p->state); if (IS_TRACED(p)) { - if (IS_TRACED_FL(p, F_TRACE_CALLS) && p->status != P_FREE) { + if (IS_TRACED_FL(p, F_TRACE_CALLS) && !(state & ERTS_PSFLG_FREE)) { erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_OUT); } - switch (p->status) { - case P_EXITING: + if (state & (ERTS_PSFLG_FREE|ERTS_PSFLG_EXITING)) { if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT)) - trace_sched(p, am_out_exiting); - break; - case P_FREE: - if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT)) - trace_sched(p, am_out_exited); - break; - default: + trace_sched(p, ((state & ERTS_PSFLG_FREE) + ? am_out_exited + : am_out_exiting)); + } + else { if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED)) trace_sched(p, am_out); else if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS)) trace_virtual_sched(p, am_out); - break; } } #ifdef ERTS_SMP - if (ERTS_PROC_PENDING_EXIT(p)) { - erts_handle_pending_exit(p, - ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); - p->status_flags |= ERTS_PROC_SFLG_PENDADD2SCHEDQ; - } - - if (p->pending_suspenders) { - handle_pending_suspend(p, - ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); - ASSERT(!(p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) - || p->rcount == 0); - } + if (state & ERTS_PSFLG_PENDING_EXIT) + erts_handle_pending_exit(p, (ERTS_PROC_LOCK_MAIN + | ERTS_PROC_LOCK_STATUS)); + if (p->pending_suspenders) + handle_pending_suspend(p, (ERTS_PROC_LOCK_MAIN + | ERTS_PROC_LOCK_STATUS)); #endif - erts_smp_runq_lock(rq); - ERTS_PROC_REDUCTIONS_EXECUTED(rq, p->prio, reds, actual_reds); + schedule_out_process(rq, state, p); /* Returns with rq locked! */ + + ERTS_PROC_REDUCTIONS_EXECUTED(rq, + (int) (state & ERTS_PSFLG_PRIO_MASK), + reds, + actual_reds); esdp->current_process = NULL; #ifdef ERTS_SMP p->scheduler_data = NULL; - p->runq_flags &= ~ERTS_PROC_RUNQ_FLG_RUNNING; - p->status_flags &= ~ERTS_PROC_SFLG_RUNNING; - - if (p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) { - ErtsRunQueue *notify_runq; - p->status_flags &= ~ERTS_PROC_SFLG_PENDADD2SCHEDQ; - notify_runq = internal_add_to_runq(rq, p); - if (notify_runq != rq) - smp_notify_inc_runq(notify_runq); - } #endif - if (p->status == P_FREE) { + if (state & ERTS_PSFLG_FREE) { #ifdef ERTS_SMP ASSERT(esdp->free_process == p); esdp->free_process = NULL; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); - erts_smp_proc_dec_refc(p); #else erts_free_proc(p); #endif - } else { - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); } -#ifdef ERTS_SMP - { - ErtsProcList *pnd_xtrs = rq->procs.pending_exiters; - rq->procs.pending_exiters = NULL; + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); - if (pnd_xtrs) { - erts_smp_runq_unlock(rq); - handle_pending_exiters(pnd_xtrs); - erts_smp_runq_lock(rq); - } - - } +#ifdef ERTS_SMP ASSERT(!esdp->free_process); #endif ASSERT(!esdp->current_process); @@ -6728,8 +7004,23 @@ Process *schedule(Process *p, int calls) ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking()); check_activities_to_run: { +#ifdef ERTS_SMP + ErtsMigrationPaths *mps; + ErtsMigrationPath *mp; #ifdef ERTS_SMP + { + ErtsProcList *pnd_xtrs = rq->procs.pending_exiters; + rq->procs.pending_exiters = NULL; + + if (pnd_xtrs) { + erts_smp_runq_unlock(rq); + handle_pending_exiters(pnd_xtrs); + erts_smp_runq_lock(rq); + } + + } +#endif if (rq->check_balance_reds <= 0) check_balance(rq); @@ -6737,20 +7028,28 @@ Process *schedule(Process *p, int calls) ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking()); ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - if (rq->flags & ERTS_RUNQ_FLGS_IMMIGRATE_QMASK) - immigrate(rq); + mps = erts_get_migration_paths_managed(); + mp = &mps->mpath[rq->ix]; + + if (mp->flags & ERTS_RUNQ_FLGS_IMMIGRATE_QMASK) + immigrate(rq, mp); - continue_check_activities_to_run: + continue_check_activities_to_run: + flags = ERTS_RUNQ_FLGS_GET_NOB(rq); + continue_check_activities_to_run_known_flags: - if (rq->flags & (ERTS_RUNQ_FLG_CHK_CPU_BIND - | ERTS_RUNQ_FLG_SUSPENDED)) { - if (rq->flags & ERTS_RUNQ_FLG_SUSPENDED) { - ASSERT(erts_smp_atomic32_read_nob(&esdp->ssi->flags) - & ERTS_SSI_FLG_SUSPENDED); + + if (flags & (ERTS_RUNQ_FLG_CHK_CPU_BIND|ERTS_RUNQ_FLG_SUSPENDED)) { + + if (flags & ERTS_RUNQ_FLG_SUSPENDED) { suspend_scheduler(esdp); + flags = ERTS_RUNQ_FLGS_GET_NOB(rq); } - if (rq->flags & ERTS_RUNQ_FLG_CHK_CPU_BIND) + if (flags & ERTS_RUNQ_FLG_CHK_CPU_BIND) { + flags = ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_CHK_CPU_BIND); + flags &= ~ ERTS_RUNQ_FLG_CHK_CPU_BIND; erts_sched_check_cpu_bind(esdp); + } } { @@ -6779,14 +7078,12 @@ Process *schedule(Process *p, int calls) } #endif /* ERTS_SMP */ - ASSERT(rq->len == rq->procs.len + rq->ports.info.len); - - if ((rq->len == 0 && !rq->misc.start) - || (rq->halt_in_progress - && rq->ports.info.len == 0 && !rq->misc.start)) { + flags = ERTS_RUNQ_FLGS_GET_NOB(rq); + if ((!(flags & ERTS_RUNQ_FLGS_QMASK) && !rq->misc.start) + || (rq->halt_in_progress && ERTS_EMPTY_RUNQ_PORTS(rq))) { + /* Prepare for scheduler wait */ #ifdef ERTS_SMP - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); rq->wakeup_other = 0; @@ -6794,21 +7091,27 @@ Process *schedule(Process *p, int calls) empty_runq(rq); - if (rq->flags & ERTS_RUNQ_FLG_SUSPENDED) { - ASSERT(erts_smp_atomic32_read_nob(&esdp->ssi->flags) - & ERTS_SSI_FLG_SUSPENDED); + flags = ERTS_RUNQ_FLGS_GET_NOB(rq); + if (flags & ERTS_RUNQ_FLG_SUSPENDED) { non_empty_runq(rq); - goto continue_check_activities_to_run; + goto continue_check_activities_to_run_known_flags; } - else if (!(rq->flags & ERTS_RUNQ_FLG_INACTIVE)) { + else if (!(flags & ERTS_RUNQ_FLG_INACTIVE)) { + if (try_steal_task(rq)) { + non_empty_runq(rq); + goto continue_check_activities_to_run; + } + + (void) ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_PROTECTED); + /* * Check for ERTS_RUNQ_FLG_SUSPENDED has to be done * after trying to steal a task. */ - if (try_steal_task(rq) - || (rq->flags & ERTS_RUNQ_FLG_SUSPENDED)) { + flags = ERTS_RUNQ_FLGS_GET_NOB(rq); + if (flags & ERTS_RUNQ_FLG_SUSPENDED) { non_empty_runq(rq); - goto continue_check_activities_to_run; + goto continue_check_activities_to_run_known_flags; } } @@ -6839,6 +7142,7 @@ Process *schedule(Process *p, int calls) erl_sys_schedule(1); dt = erts_do_time_read_and_reset(); if (dt) erts_bump_timer(dt); + #ifdef ERTS_SMP erts_smp_runq_lock(rq); clear_sys_scheduling(); @@ -6852,14 +7156,14 @@ Process *schedule(Process *p, int calls) exec_misc_ops(rq); #ifdef ERTS_SMP - wakeup_other.check(rq); + wakeup_other.check(rq, flags); #endif /* * Find a new port to run. */ - if (rq->ports.info.len) { + if (RUNQ_READ_LEN(&rq->ports.info.len)) { int have_outstanding_io; have_outstanding_io = erts_port_task_execute(rq, &esdp->current_port); if ((have_outstanding_io && fcalls > 2*input_reductions) @@ -6886,159 +7190,122 @@ Process *schedule(Process *p, int calls) /* * Find a new process to run. */ - pick_next_process: - - ERTS_DBG_CHK_PROCS_RUNQ(rq); - - switch (rq->flags & ERTS_RUNQ_FLGS_PROCS_QMASK) { - case MAX_BIT: - case MAX_BIT|HIGH_BIT: - case MAX_BIT|NORMAL_BIT: - case MAX_BIT|LOW_BIT: - case MAX_BIT|HIGH_BIT|NORMAL_BIT: - case MAX_BIT|HIGH_BIT|LOW_BIT: - case MAX_BIT|NORMAL_BIT|LOW_BIT: - case MAX_BIT|HIGH_BIT|NORMAL_BIT|LOW_BIT: - rpq = &rq->procs.prio[PRIORITY_MAX]; - break; - case HIGH_BIT: - case HIGH_BIT|NORMAL_BIT: - case HIGH_BIT|LOW_BIT: - case HIGH_BIT|NORMAL_BIT|LOW_BIT: - rpq = &rq->procs.prio[PRIORITY_HIGH]; - break; - case NORMAL_BIT: - rpq = &rq->procs.prio[PRIORITY_NORMAL]; - break; - case LOW_BIT: - rpq = &rq->procs.prio[PRIORITY_NORMAL]; - break; - case NORMAL_BIT|LOW_BIT: - rpq = &rq->procs.prio[PRIORITY_NORMAL]; - ASSERT(rpq->first != NULL); - p = rpq->first; - if (p->prio == PRIORITY_LOW) { - if (p == rpq->last || p->skipped >= RESCHEDULE_LOW-1) - p->skipped = 0; - else { - /* skip it */ - p->skipped++; - rpq->first = p->next; - rpq->first->prev = NULL; - rpq->last->next = p; - p->prev = rpq->last; - p->next = NULL; - rpq->last = p; + pick_next_process: { + int prio_q; + int qmask; + + flags = ERTS_RUNQ_FLGS_GET_NOB(rq); + qmask = (int) (flags & ERTS_RUNQ_FLGS_PROCS_QMASK); + switch (qmask & -qmask) { + case MAX_BIT: + prio_q = PRIORITY_MAX; + break; + case HIGH_BIT: + prio_q = PRIORITY_HIGH; + break; + case NORMAL_BIT: + case LOW_BIT: + prio_q = PRIORITY_NORMAL; + if (check_requeue_process(rq, PRIORITY_NORMAL)) goto pick_next_process; - } + break; + case 0: /* No process at all */ + default: + ASSERT(qmask == 0); + goto check_activities_to_run; } - break; - case 0: /* No process at all */ - default: - ASSERT((rq->flags & ERTS_RUNQ_FLGS_PROCS_QMASK) == 0); - ASSERT(rq->procs.len == 0); - goto check_activities_to_run; - } - - BM_START_TIMER(system); - - /* - * Take the chosen process out of the queue. - */ - ASSERT(rpq->first); /* Wrong qmask in rq->flags? */ - p = rpq->first; -#ifdef ERTS_SMP - ERTS_SMP_LC_ASSERT(rq == p->run_queue); -#endif - rpq->first = p->next; - if (!rpq->first) - rpq->last = NULL; - else - rpq->first->prev = NULL; - p->next = p->prev = NULL; + BM_START_TIMER(system); - if (--rq->procs.prio_info[p->prio].len == 0) - rq->flags &= ~(1 << p->prio); - ASSERT(rq->procs.len > 0); - rq->procs.len--; - ASSERT(rq->len > 0); - rq->len--; + /* + * Take the chosen process out of the queue. + */ + p = dequeue_process(rq, prio_q, &state); - { - Uint32 ee_flgs = (ERTS_RUNQ_FLG_EVACUATE(p->prio) - | ERTS_RUNQ_FLG_EMIGRATE(p->prio)); + ASSERT(p); /* Wrong qmask in rq->flags? */ - if ((rq->flags & (ERTS_RUNQ_FLG_SUSPENDED|ee_flgs)) == ee_flgs) - ERTS_UNSET_RUNQ_FLG_EVACUATE(rq->flags, p->prio); - } + while (1) { + erts_aint32_t exp, new, tmp; + tmp = new = exp = state; + new &= ~ERTS_PSFLG_IN_RUNQ; + tmp = state & (ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_PENDING_EXIT); + if (tmp != ERTS_PSFLG_SUSPENDED) + new |= ERTS_PSFLG_RUNNING; + state = erts_smp_atomic32_cmpxchg_relb(&p->state, new, exp); + if (state == exp) { + tmp = state & (ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_PENDING_EXIT); + if (tmp == ERTS_PSFLG_SUSPENDED) + goto pick_next_process; + state = new; + break; + } + } - ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(rq, p); + rq->procs.context_switches++; - rq->procs.context_switches++; + esdp->current_process = p; - esdp->current_process = p; + } #ifdef ERTS_SMP - p->runq_flags |= ERTS_PROC_RUNQ_FLG_RUNNING; erts_smp_runq_unlock(rq); + if (flags & ERTS_RUNQ_FLG_PROTECTED) + (void) ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_PROTECTED); + ERTS_SMP_CHK_NO_PROC_LOCKS; erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); if (erts_sched_stat.enabled) { + int prio; UWord old = ERTS_PROC_SCHED_ID(p, (ERTS_PROC_LOCK_MAIN | ERTS_PROC_LOCK_STATUS), (UWord) esdp->no); int migrated = old && old != esdp->no; + prio = (int) (state & ERTS_PSFLG_PRIO_MASK); + erts_smp_spin_lock(&erts_sched_stat.lock); - erts_sched_stat.prio[p->prio].total_executed++; - erts_sched_stat.prio[p->prio].executed++; + erts_sched_stat.prio[prio].total_executed++; + erts_sched_stat.prio[prio].executed++; if (migrated) { - erts_sched_stat.prio[p->prio].total_migrated++; - erts_sched_stat.prio[p->prio].migrated++; + erts_sched_stat.prio[prio].total_migrated++; + erts_sched_stat.prio[prio].migrated++; } erts_smp_spin_unlock(&erts_sched_stat.lock); } - p->status_flags |= ERTS_PROC_SFLG_RUNNING; - p->status_flags &= ~ERTS_PROC_SFLG_INRUNQ; if (ERTS_PROC_PENDING_EXIT(p)) { erts_handle_pending_exit(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); + state = erts_smp_atomic32_read_nob(&p->state); } ASSERT(!p->scheduler_data); p->scheduler_data = esdp; - #endif - ASSERT(p->status != P_SUSPENDED); /* Never run a suspended process */ + /* Never run a suspended process */ + ASSERT(!(ERTS_PSFLG_SUSPENDED & erts_smp_atomic32_read_nob(&p->state))); reds = context_reds; if (IS_TRACED(p)) { - switch (p->status) { - case P_EXITING: + if (state & ERTS_PSFLG_EXITING) { if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT)) trace_sched(p, am_in_exiting); - break; - default: + } + else { if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED)) trace_sched(p, am_in); else if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS)) trace_virtual_sched(p, am_in); - break; } if (IS_TRACED_FL(p, F_TRACE_CALLS)) { erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_IN); } } - if (p->status != P_EXITING) - p->status = P_RUNNING; - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); #ifdef ERTS_SMP @@ -7046,7 +7313,7 @@ Process *schedule(Process *p, int calls) erts_check_my_tracer_proc(p); #endif - if (!ERTS_PROC_IS_EXITING(p) + if (!(state & ERTS_PSFLG_EXITING) && ((FLAGS(p) & F_FORCE_GC) || (MSO(p).overhead > BIN_VHEAP_SZ(p)))) { reds -= erts_garbage_collect(p, 0, p->arg_reg, p->arity); @@ -7137,17 +7404,19 @@ erts_schedule_misc_op(void (*func)(void *), void *arg) ErtsSchedulerData *esdp = erts_get_scheduler_data(); ErtsRunQueue *rq = esdp ? esdp->run_queue : ERTS_RUNQ_IX(0); ErtsMiscOpList *molp = misc_op_list_alloc(); +#ifdef ERTS_SMP + ErtsMigrationPaths *mpaths = erts_get_migration_paths(); - erts_smp_runq_lock(rq); - - while (rq->misc.evac_runq) { - ErtsRunQueue *tmp_rq = rq->misc.evac_runq; - erts_smp_runq_unlock(rq); - rq = tmp_rq; - erts_smp_runq_lock(rq); + if (!mpaths) + rq = ERTS_RUNQ_IX(0); + else { + ErtsRunQueue *erq = mpaths->mpath[rq->ix].misc_evac_runq; + if (erq) + rq = erq; } +#endif - ASSERT(!(rq->flags & ERTS_RUNQ_FLG_SUSPENDED)); + erts_smp_runq_lock(rq); molp->next = NULL; molp->func = func; @@ -7157,7 +7426,9 @@ erts_schedule_misc_op(void (*func)(void *), void *arg) else rq->misc.start = molp; rq->misc.end = molp; + erts_smp_runq_unlock(rq); + smp_notify_inc_runq(rq); } @@ -7247,44 +7518,50 @@ erts_get_exact_total_reductions(Process *c_p, Uint *redsp, Uint *diffp) Sint erts_test_next_pid(int set, Uint next) { + Uint64 lpd; Sint res; - Sint p_prev; + Eterm pid_data; + int first_pix = -1; + erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx); - erts_smp_mtx_lock(&proc_tab_mtx); - - if (!set) { - res = p_next < 0 ? -1 : (p_serial << p_serial_shift | p_next); - } + if (!set) + lpd = last_pid_data_read_nob(); else { - p_serial = (Sint) ((next >> p_serial_shift) & p_serial_mask); - p_next = (Sint) (erts_process_tab_index_mask & next); - - if (p_next >= erts_max_processes) { - p_next = 0; - p_serial++; - p_serial &= p_serial_mask; + lpd = (Uint64) next; + pid_data = (Eterm) (lpd & ERTS_PID_DATA_MASK__); + if (ERTS_INVALID_PID == make_internal_pid(pid_data)) { + lpd += erts_proc.max; + ASSERT(erts_pid_data2ix(pid_data) + == erts_pid_data2ix(lpd & ERTS_PID_DATA_MASK__)); } + last_pid_data_set_relb(lpd); + } - p_prev = p_next; - - do { - if (!process_tab[p_next]) - break; - p_next++; - if(p_next >= erts_max_processes) { - p_next = 0; - p_serial++; - p_serial &= p_serial_mask; + while (1) { + int pix; + lpd++; + pix = (int) (lpd % erts_proc.max); + if (first_pix < 0) + first_pix = pix; + else if (pix == first_pix) { + res = -1; + break; + } + if (ERTS_AINT_NULL == erts_smp_atomic_read_nob(&erts_proc.tab[pix])) { + pid_data = (Eterm) (lpd & ERTS_PID_DATA_MASK__); + if (ERTS_INVALID_PID == make_internal_pid(pid_data)) { + lpd += erts_proc.max; + ASSERT(erts_pid_data2ix(pid_data) + == erts_pid_data2ix(lpd & ERTS_PID_DATA_MASK__)); } - } while (p_prev != p_next); - - res = process_tab[p_next] ? -1 : (p_serial << p_serial_shift | p_next); - + res = lpd & ERTS_PID_DATA_MASK__; + break; + } } - erts_smp_mtx_unlock(&proc_tab_mtx); + erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx); return res; @@ -7293,6 +7570,8 @@ erts_test_next_pid(int set, Uint next) Uint erts_process_count(void) { erts_aint32_t res = erts_smp_atomic32_read_nob(&process_count); + if (res > erts_proc.max) + return erts_proc.max; ASSERT(res >= 0); return (Uint) res; } @@ -7300,97 +7579,138 @@ Uint erts_process_count(void) void erts_free_proc(Process *p) { -#if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP) - erts_lcnt_proc_lock_destroy(p); +#ifdef ERTS_SMP + erts_proc_lock_fin(p); #endif erts_free(ERTS_ALC_T_PROC, (void *) p); } - /* ** Allocate process and find out where to place next process. */ static Process* -alloc_process(void) +alloc_process(ErtsRunQueue *rq, erts_aint32_t state) { -#ifdef ERTS_SMP - erts_pix_lock_t *pix_lock; -#endif + int pix; Process* p; - int p_prev; + Uint64 lpd, exp_lpd; + Eterm pid_data; + erts_aint32_t proc_count; +#ifdef DEBUG + Eterm pid; +#endif - erts_smp_mtx_lock(&proc_tab_mtx); + erts_smp_rwmtx_rlock(&erts_proc_tab_rwmtx); - if (p_next == -1) { - p = NULL; - goto error; /* Process table full! */ + proc_count = erts_smp_atomic32_inc_read_acqb(&process_count); + if (proc_count > erts_proc.max) { + while (1) { + erts_aint32_t act_proc_count; + + act_proc_count = erts_smp_atomic32_cmpxchg_relb(&process_count, + proc_count-1, + proc_count); + if (act_proc_count == proc_count) + goto system_limit; + proc_count = act_proc_count; + if (proc_count <= erts_proc.max) + break; + } } p = (Process*) erts_alloc_fnf(ERTS_ALC_T_PROC, sizeof(Process)); if (!p) - goto error; /* ENOMEM */ + goto enomem; - p_last = p_next; + p->approx_started = erts_get_approx_time(); + p->started_interval = get_proc_interval(); - erts_get_emu_time(&p->started); + lpd = last_pid_data_read_acqb(); -#ifdef ERTS_SMP - pix_lock = ERTS_PIX2PIXLOCK(p_next); - erts_pix_lock(pix_lock); -#endif - ASSERT(!process_tab[p_next]); + /* Reserve slot */ + while (1) { + lpd++; + pix = erts_pid_data2ix((Eterm) (lpd & ERTS_PID_DATA_MASK__)); + if (erts_smp_atomic_read_nob(&erts_proc.tab[pix]) == ERTS_AINT_NULL) { + erts_aint_t val; + val = erts_smp_atomic_cmpxchg_relb(&erts_proc.tab[pix], + ((erts_aint_t) + ERTS_PROC_LOCK_BUSY), + ERTS_AINT_NULL); + + if (ERTS_AINT_NULL == val) + break; + } + } + + pid_data = (Eterm) lpd & ERTS_PID_DATA_MASK__; - process_tab[p_next] = p; - erts_smp_atomic32_inc_nob(&process_count); - p->id = make_internal_pid(p_serial << p_serial_shift | p_next); + p->id = make_internal_pid(pid_data); if (p->id == ERTS_INVALID_PID) { /* Do not use the invalid pid; change serial */ - p_serial++; - p_serial &= p_serial_mask; - p->id = make_internal_pid(p_serial << p_serial_shift | p_next); + lpd += erts_proc.max; + ASSERT(pix == erts_pid_data2ix((Eterm) (lpd & ERTS_PID_DATA_MASK__))); + pid_data = (Eterm) lpd & ERTS_PID_DATA_MASK__; + p->id = make_internal_pid(pid_data); ASSERT(p->id != ERTS_INVALID_PID); } - ASSERT(internal_pid_serial(p->id) <= (erts_use_r9_pids_ports - ? ERTS_MAX_PID_R9_SERIAL - : ERTS_MAX_PID_SERIAL)); + + exp_lpd = last_pid_data_read_nob(); + + /* Move last pid data forward */ + while (1) { + Uint64 act_lpd; + if (last_pid_data_cmp(lpd, exp_lpd) < 0) + break; + act_lpd = last_pid_data_cmpxchg_relb(lpd, exp_lpd); + if (act_lpd == exp_lpd) + break; + exp_lpd = act_lpd; + } #ifdef ERTS_SMP - erts_proc_lock_init(p); /* All locks locked */ - erts_pix_unlock(pix_lock); + RUNQ_SET_RQ(&p->run_queue, rq); #endif - p->rstatus = P_FREE; - p->rcount = 0; + erts_smp_atomic32_init_relb(&p->state, state); - /* - * set p_next to the next available slot - */ +#ifdef DEBUG + pid = p->id; +#endif - p_prev = p_next; +#ifdef ERTS_SMP + erts_proc_lock_init(p); /* All locks locked */ +#endif - while (1) { - p_next++; - if(p_next >= erts_max_processes) { - p_serial++; - p_serial &= p_serial_mask; - p_next = 0; - } + /* Move into slot reserved */ +#ifdef DEBUG + ASSERT(ERTS_PROC_LOCK_BUSY + == (Process *) erts_smp_atomic_xchg_relb(&erts_proc.tab[pix], + (erts_aint_t) p)); +#else + erts_smp_atomic_set_relb(&erts_proc.tab[pix], (erts_aint_t) p); +#endif - if (p_prev == p_next) { - p_next = -1; - break; /* Table full! */ - } + ASSERT(internal_pid_serial(p->id) <= (erts_use_r9_pids_ports + ? ERTS_MAX_PID_R9_SERIAL + : ERTS_MAX_PID_SERIAL)); - if (!process_tab[p_next]) - break; /* found a free slot */ - } + erts_smp_rwmtx_runlock(&erts_proc_tab_rwmtx); - error: + p->rcount = 0; - erts_smp_mtx_unlock(&proc_tab_mtx); + ASSERT(p == (Process *) + erts_smp_atomic_read_nob( + &erts_proc.tab[internal_pid_index(pid)])); return p; +enomem: +system_limit: + + erts_smp_rwmtx_runlock(&erts_proc_tab_rwmtx); + return NULL; + } Eterm @@ -7400,13 +7720,15 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). Eterm args, /* Arguments for function (must be well-formed list). */ ErlSpawnOpts* so) /* Options for spawn. */ { - ErtsRunQueue *rq, *notify_runq; + ErtsRunQueue *rq = NULL; Process *p; Sint arity; /* Number of arguments. */ Uint arg_size; /* Size of arguments. */ Uint sz; /* Needed words on heap. */ Uint heap_need; /* Size needed on heap. */ Eterm res = THE_NON_VALUE; + erts_aint32_t state = 0; + erts_aint32_t prio = (erts_aint32_t) PRIORITY_NORMAL; #ifdef ERTS_SMP erts_smp_proc_lock(parent, ERTS_PROC_LOCKS_ALL_MINOR); @@ -7420,8 +7742,24 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). so->error_code = BADARG; goto error; } - p = alloc_process(); /* All proc locks are locked by this thread - on success */ + + if (so->flags & SPO_USE_ARGS) { + if (so->scheduler) { + int ix = so->scheduler-1; + ASSERT(0 <= ix && ix < erts_no_run_queues); + rq = ERTS_RUNQ_IX(ix); + state |= ERTS_PSFLG_BOUND; + } + prio = (erts_aint32_t) so->priority; + } + + state |= (prio & ERTS_PSFLG_PRIO_MASK); + + if (!rq) + rq = erts_get_runq_proc(parent); + + p = alloc_process(rq, state); /* All proc locks are locked by this thread + on success */ if (!p) { erts_send_error_to_logger_str(parent->group_leader, "Too many processes\n"); @@ -7441,22 +7779,16 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->flags = erts_default_process_flags; - /* Scheduler queue mutex should be locked when changeing - * prio. In this case we don't have to lock it, since - * noone except us has access to the process. - */ if (so->flags & SPO_USE_ARGS) { p->min_heap_size = so->min_heap_size; p->min_vheap_size = so->min_vheap_size; - p->prio = so->priority; p->max_gen_gcs = so->max_gen_gcs; } else { p->min_heap_size = H_MIN_SIZE; p->min_vheap_size = BIN_VH_MIN_SIZE; - p->prio = PRIORITY_NORMAL; p->max_gen_gcs = (Uint16) erts_smp_atomic32_read_nob(&erts_max_gen_gcs); } - p->skipped = 0; + p->schedule_count = 0; ASSERT(p->min_heap_size == erts_next_heap_size(p->min_heap_size, 0)); p->initial[INITIAL_MOD] = mod; @@ -7525,9 +7857,9 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->reds = 0; #ifdef ERTS_SMP - p->u.ptimer = NULL; + p->u.alive.ptimer = NULL; #else - sys_memset(&p->u.tm, 0, sizeof(ErlTimer)); + sys_memset(&p->u.alive.tm, 0, sizeof(ErlTimer)); #endif p->reg = NULL; @@ -7555,10 +7887,9 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->msg.save = &p->msg.first; p->msg.len = 0; #ifdef ERTS_SMP - p->msg_inq.first = NULL; - p->msg_inq.last = &p->msg_inq.first; - p->msg_inq.len = 0; - p->bound_runq = NULL; + p->u.alive.msg_inq.first = NULL; + p->u.alive.msg_inq.last = &p->u.alive.msg_inq.first; + p->u.alive.msg_inq.len = 0; #endif p->bif_timers = NULL; p->mbuf = NULL; @@ -7644,47 +7975,25 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). #ifdef ERTS_SMP p->scheduler_data = NULL; - p->is_exiting = 0; - p->status_flags = 0; - p->runq_flags = 0; p->suspendee = NIL; p->pending_suspenders = NULL; - p->pending_exit.reason = THE_NON_VALUE; - p->pending_exit.bp = NULL; + p->u.alive.pending_exit.reason = THE_NON_VALUE; + p->u.alive.pending_exit.bp = NULL; #endif #if !defined(NO_FPE_SIGNALS) || defined(HIPE) p->fp_exception = 0; #endif + erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL); + + res = p->id; + /* * Schedule process for execution. */ - if (!((so->flags & SPO_USE_ARGS) && so->scheduler)) - rq = erts_get_runq_proc(parent); - else { - int ix = so->scheduler-1; - ASSERT(0 <= ix && ix < erts_no_run_queues); - rq = ERTS_RUNQ_IX(ix); - p->bound_runq = rq; - } - - erts_smp_runq_lock(rq); - -#ifdef ERTS_SMP - p->run_queue = rq; -#endif - - p->status = P_WAITING; - notify_runq = internal_add_to_runq(rq, p); - - erts_smp_runq_unlock(rq); - - smp_notify_inc_runq(notify_runq); - - res = p->id; - erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL); + schedule_process(p, state, 0); VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->id)); @@ -7720,12 +8029,8 @@ void erts_init_empty_process(Process *p) p->max_gen_gcs = 0; p->min_heap_size = 0; p->min_vheap_size = 0; - p->status = P_RUNABLE; - p->gcstatus = P_RUNABLE; - p->rstatus = P_RUNABLE; p->rcount = 0; p->id = ERTS_INVALID_PID; - p->prio = PRIORITY_NORMAL; p->reds = 0; p->tracer_proc = NIL; p->trace_flags = F_INITIAL_TRACE_FLAGS; @@ -7741,10 +8046,9 @@ void erts_init_empty_process(Process *p) p->bin_old_vheap = 0; p->bin_vheap_mature = 0; #ifdef ERTS_SMP - p->u.ptimer = NULL; - p->bound_runq = NULL; + p->u.alive.ptimer = NULL; #else - memset(&(p->u.tm), 0, sizeof(ErlTimer)); + memset(&(p->u.alive.tm), 0, sizeof(ErlTimer)); #endif p->next = NULL; p->off_heap.first = NULL; @@ -7793,8 +8097,8 @@ void erts_init_empty_process(Process *p) p->def_arg_reg[5] = 0; p->parent = NIL; - p->started.tv_sec = 0; - p->started.tv_usec = 0; + p->approx_started = 0; + p->started_interval = 0; #ifdef HIPE hipe_init_process(&p->hipe); @@ -7808,22 +8112,20 @@ void erts_init_empty_process(Process *p) p->last_old_htop = NULL; #endif + erts_smp_atomic32_init_nob(&p->state, (erts_aint32_t) PRIORITY_NORMAL); #ifdef ERTS_SMP p->scheduler_data = NULL; - p->is_exiting = 0; - p->status_flags = 0; - p->runq_flags = 0; - p->msg_inq.first = NULL; - p->msg_inq.last = &p->msg_inq.first; - p->msg_inq.len = 0; + p->u.alive.msg_inq.first = NULL; + p->u.alive.msg_inq.last = &p->u.alive.msg_inq.first; + p->u.alive.msg_inq.len = 0; p->suspendee = NIL; p->pending_suspenders = NULL; - p->pending_exit.reason = THE_NON_VALUE; - p->pending_exit.bp = NULL; + p->u.alive.pending_exit.reason = THE_NON_VALUE; + p->u.alive.pending_exit.bp = NULL; erts_proc_lock_init(p); erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL); - p->run_queue = ERTS_RUNQ_IX(0); + RUNQ_SET_RQ(&p->run_queue, ERTS_RUNQ_IX(0)); #endif #if !defined(NO_FPE_SIGNALS) || defined(HIPE) @@ -7870,12 +8172,12 @@ erts_debug_verify_clean_empty_process(Process* p) ASSERT(p->parent == NIL); #ifdef ERTS_SMP - ASSERT(p->msg_inq.first == NULL); - ASSERT(p->msg_inq.len == 0); + ASSERT(p->u.alive.msg_inq.first == NULL); + ASSERT(p->u.alive.msg_inq.len == 0); ASSERT(p->suspendee == NIL); ASSERT(p->pending_suspenders == NULL); - ASSERT(p->pending_exit.reason == THE_NON_VALUE); - ASSERT(p->pending_exit.bp == NULL); + ASSERT(p->u.alive.pending_exit.reason == THE_NON_VALUE); + ASSERT(p->u.alive.pending_exit.bp == NULL); #endif /* Thing that erts_cleanup_empty_process() cleans up */ @@ -7901,8 +8203,8 @@ erts_cleanup_empty_process(Process* p) free_message_buffer(p->mbuf); p->mbuf = NULL; } -#if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP) - erts_lcnt_proc_lock_destroy(p); +#ifdef ERTS_SMP + erts_proc_lock_fin(p); #endif #ifdef DEBUG erts_debug_verify_clean_empty_process(p); @@ -7999,26 +8301,34 @@ delete_process(Process* p) p->fvalue = NIL; } +static ERTS_INLINE erts_aint32_t +set_proc_exiting_state(Process *p, erts_aint32_t state) +{ + erts_aint32_t a, n, e; + a = state; + while (1) { + n = e = a; + n &= ~(ERTS_PSFLG_SUSPENDED|ERTS_PSFLG_PENDING_EXIT); + n |= ERTS_PSFLG_EXITING|ERTS_PSFLG_ACTIVE; + if (!(a & (ERTS_PSFLG_IN_RUNQ|ERTS_PSFLG_RUNNING))) + n |= ERTS_PSFLG_IN_RUNQ; + a = erts_smp_atomic32_cmpxchg_relb(&p->state, n, e); + if (a == e) + break; + } + return a; +} + static ERTS_INLINE void -set_proc_exiting(Process *p, Eterm reason, ErlHeapFragment *bp) +set_proc_exiting(Process *p, + erts_aint32_t state, + Eterm reason, + ErlHeapFragment *bp) { -#ifdef ERTS_SMP - erts_pix_lock_t *pix_lock = ERTS_PID2PIXLOCK(p->id); ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(p) == ERTS_PROC_LOCKS_ALL); - /* - * You are required to have all proc locks and the pix lock when going - * to status P_EXITING. This makes it is enough to take any lock when - * looking up a process (pid2proc()) to prevent the looked up process - * from exiting until the lock has been released. - */ - erts_pix_lock(pix_lock); - p->is_exiting = 1; -#endif - p->status = P_EXITING; -#ifdef ERTS_SMP - erts_pix_unlock(pix_lock); -#endif + state = set_proc_exiting_state(p, state); + p->fvalue = reason; if (bp) erts_link_mbuf_to_proc(p, bp); @@ -8031,6 +8341,14 @@ set_proc_exiting(Process *p, Eterm reason, ErlHeapFragment *bp) KILL_CATCHES(p); cancel_timer(p); p->i = (BeamInstr *) beam_exit; + + if (erts_system_profile_flags.runnable_procs + && !(state & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED))) { + profile_runnable_proc(p, am_active); + } + + if (!(state & (ERTS_PSFLG_IN_RUNQ|ERTS_PSFLG_RUNNING))) + add2runq(p, state); } @@ -8040,11 +8358,11 @@ void erts_handle_pending_exit(Process *c_p, ErtsProcLocks locks) { ErtsProcLocks xlocks; - ASSERT(is_value(c_p->pending_exit.reason)); + ASSERT(is_value(c_p->u.alive.pending_exit.reason)); ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == locks); ERTS_SMP_LC_ASSERT(locks & ERTS_PROC_LOCK_MAIN); - ERTS_SMP_LC_ASSERT(c_p->status != P_EXITING); - ERTS_SMP_LC_ASSERT(c_p->status != P_FREE); + ERTS_SMP_LC_ASSERT(!((ERTS_PSFLG_EXITING|ERTS_PSFLG_FREE) + & erts_smp_atomic32_read_nob(&c_p->state))); /* Ensure that all locks on c_p are locked before proceeding... */ if (locks == ERTS_PROC_LOCKS_ALL) @@ -8057,9 +8375,12 @@ erts_handle_pending_exit(Process *c_p, ErtsProcLocks locks) } } - set_proc_exiting(c_p, c_p->pending_exit.reason, c_p->pending_exit.bp); - c_p->pending_exit.reason = THE_NON_VALUE; - c_p->pending_exit.bp = NULL; + set_proc_exiting(c_p, + erts_smp_atomic32_read_acqb(&c_p->state), + c_p->u.alive.pending_exit.reason, + c_p->u.alive.pending_exit.bp); + c_p->u.alive.pending_exit.reason = THE_NON_VALUE; + c_p->u.alive.pending_exit.bp = NULL; if (xlocks) erts_smp_proc_unlock(c_p, xlocks); @@ -8073,11 +8394,12 @@ handle_pending_exiters(ErtsProcList *pnd_xtrs) while (plp) { Process *p = erts_pid2proc(NULL, 0, plp->pid, ERTS_PROC_LOCKS_ALL); if (p) { - if (proclist_same(plp, p) - && !(p->status_flags & ERTS_PROC_SFLG_RUNNING)) { - ASSERT(p->status_flags & ERTS_PROC_SFLG_INRUNQ); - ASSERT(ERTS_PROC_PENDING_EXIT(p)); - erts_handle_pending_exit(p, ERTS_PROC_LOCKS_ALL); + if (proclist_same(plp, p)) { + erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state); + if (!(state & ERTS_PSFLG_RUNNING)) { + ASSERT(state & ERTS_PSFLG_PENDING_EXIT); + erts_handle_pending_exit(p, ERTS_PROC_LOCKS_ALL); + } } erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL); } @@ -8105,7 +8427,7 @@ save_pending_exiter(Process *p) rq->procs.pending_exiters = plp; erts_smp_runq_unlock(rq); - + wake_scheduler(rq, 1); } #endif @@ -8167,7 +8489,7 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp, * SMP emulator). When the signal is received the receiver receives an * 'EXIT' message if it is trapping exits; otherwise, it will either * ignore the signal if the exit reason is normal, or go into an - * exiting state (status P_EXITING). When a process has gone into the + * exiting state (ERTS_PSFLG_EXITING). When a process has gone into the * exiting state it will not execute any more Erlang code, but it might * take a while before it actually exits. The exit signal is being * received when the 'EXIT' message is put in the message queue, the @@ -8240,6 +8562,7 @@ send_exit_signal(Process *c_p, /* current process if and only Uint32 flags /* flags */ ) { + erts_aint32_t state = erts_smp_atomic32_read_nob(&rp->state); Eterm rsn = reason == am_kill ? am_killed : reason; ERTS_SMP_LC_ASSERT(*rp_locks == erts_proc_lc_my_proc_locks(rp)); @@ -8261,7 +8584,7 @@ send_exit_signal(Process *c_p, /* current process if and only } #endif - if (ERTS_PROC_IS_TRAPPING_EXITS(rp) + if ((state & ERTS_PSFLG_TRAP_EXIT) && (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) { if (is_not_nil(token) #ifdef USE_VM_PROBES @@ -8277,10 +8600,8 @@ send_exit_signal(Process *c_p, /* current process if and only } else if (reason != am_normal || (flags & ERTS_XSIG_FLG_NO_IGN_NORMAL)) { #ifdef ERTS_SMP - if (!ERTS_PROC_PENDING_EXIT(rp) && !rp->is_exiting) { - ASSERT(rp->status != P_EXITING); - ASSERT(rp->status != P_FREE); - ASSERT(!rp->pending_exit.bp); + if (!(state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT))) { + ASSERT(!rp->u.alive.pending_exit.bp); if (rp == c_p && (*rp_locks & ERTS_PROC_LOCK_MAIN)) { /* Ensure that all locks on c_p are locked before @@ -8295,9 +8616,9 @@ send_exit_signal(Process *c_p, /* current process if and only } *rp_locks = ERTS_PROC_LOCKS_ALL; } - set_proc_exiting(c_p, rsn, NULL); + set_proc_exiting(c_p, state, rsn, NULL); } - else if (!(rp->status_flags & ERTS_PROC_SFLG_RUNNING)) { + else if (!(state & ERTS_PSFLG_RUNNING)) { /* Process not running ... */ ErtsProcLocks need_locks = ~(*rp_locks) & ERTS_PROC_LOCKS_ALL; if (need_locks @@ -8314,6 +8635,7 @@ send_exit_signal(Process *c_p, /* current process if and only /* ...and we have all locks on it... */ *rp_locks = ERTS_PROC_LOCKS_ALL; set_proc_exiting(rp, + state, (is_immed(rsn) ? rsn : copy_object(rsn, rp)), @@ -8329,7 +8651,7 @@ send_exit_signal(Process *c_p, /* current process if and only set_pending_exit: if (is_immed(rsn)) { - rp->pending_exit.reason = rsn; + rp->u.alive.pending_exit.reason = rsn; } else { Eterm *hp; @@ -8337,17 +8659,15 @@ send_exit_signal(Process *c_p, /* current process if and only ErlHeapFragment *bp = new_message_buffer(sz); hp = &bp->mem[0]; - rp->pending_exit.reason = copy_struct(rsn, - sz, - &hp, - &bp->off_heap); - rp->pending_exit.bp = bp; + rp->u.alive.pending_exit.reason = copy_struct(rsn, + sz, + &hp, + &bp->off_heap); + rp->u.alive.pending_exit.bp = bp; } - ASSERT(ERTS_PROC_PENDING_EXIT(rp)); + erts_smp_atomic32_read_bor_relb(&rp->state, + ERTS_PSFLG_PENDING_EXIT); } - if (!(rp->status_flags - & (ERTS_PROC_SFLG_INRUNQ|ERTS_PROC_SFLG_RUNNING))) - erts_add_to_runq(rp); } /* else: * @@ -8359,17 +8679,14 @@ send_exit_signal(Process *c_p, /* current process if and only * exit or by itself before seeing the pending exit. */ #else /* !ERTS_SMP */ - if (c_p == rp) { - rp->status = P_EXITING; - c_p->fvalue = rsn; - } - else if (rp->status != P_EXITING) { /* No recursive process exits /PaN */ - Eterm old_status = rp->status; + erts_aint32_t state = erts_smp_atomic32_read_nob(&rp->state); + if (!(state & ERTS_PSFLG_EXITING)) { set_proc_exiting(rp, - is_immed(rsn) ? rsn : copy_object(rsn, rp), + state, + (is_immed(rsn) || c_p == rp + ? rsn + : copy_object(rsn, rp)), NULL); - if (old_status != P_RUNABLE && old_status != P_RUNNING) - erts_add_to_runq(rp); } #endif return -1; /* Receiver will exit */ @@ -8672,12 +8989,14 @@ resume_suspend_monitor(ErtsSuspendMonitor *smon, void *vc_p) erts_destroy_suspend_monitor(smon); } -static void -continue_exit_process(Process *p #ifdef ERTS_SMP - , erts_pix_lock_t *pix_lock +static void +proc_dec_refc(void *vproc) +{ + erts_smp_proc_dec_refc((Process *) vproc); +} #endif - ); + /* this function fishishes a process and propagates exit messages - called by process_main when a process dies */ @@ -8685,9 +9004,8 @@ void erts_do_exit_process(Process* p, Eterm reason) { #ifdef ERTS_SMP - erts_pix_lock_t *pix_lock = ERTS_PID2PIXLOCK(p->id); + erts_aint32_t state; #endif - p->arity = 0; /* No live registers */ p->fvalue = reason; @@ -8705,32 +9023,22 @@ erts_do_exit_process(Process* p, Eterm reason) #ifdef ERTS_SMP ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); /* By locking all locks (main lock is already locked) when going - to status P_EXITING, it is enough to take any lock when + to exiting state (ERTS_PSFLG_EXITING), it is enough to take any lock when looking up a process (erts_pid2proc()) to prevent the looked up process from exiting until the lock has been released. */ erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR); #endif - - if (erts_system_profile_flags.runnable_procs && (p->status != P_WAITING)) { - profile_runnable_proc(p, am_inactive); - } -#ifdef ERTS_SMP - erts_pix_lock(pix_lock); - p->is_exiting = 1; -#endif - - p->status = P_EXITING; - -#ifdef ERTS_SMP - erts_pix_unlock(pix_lock); - - if (ERTS_PROC_PENDING_EXIT(p)) { +#ifndef ERTS_SMP + set_proc_exiting_state(p, erts_smp_atomic32_read_nob(&p->state)); +#else + state = set_proc_exiting_state(p, erts_smp_atomic32_read_nob(&p->state)); + if (state & ERTS_PSFLG_PENDING_EXIT) { /* Process exited before pending exit was received... */ - p->pending_exit.reason = THE_NON_VALUE; - if (p->pending_exit.bp) { - free_message_buffer(p->pending_exit.bp); - p->pending_exit.bp = NULL; + p->u.alive.pending_exit.reason = THE_NON_VALUE; + if (p->u.alive.pending_exit.bp) { + free_message_buffer(p->u.alive.pending_exit.bp); + p->u.alive.pending_exit.bp = NULL; } } @@ -8764,29 +9072,11 @@ erts_do_exit_process(Process* p, Eterm reason) erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR); -#ifdef ERTS_SMP - continue_exit_process(p, pix_lock); -#else - continue_exit_process(p); -#endif + erts_continue_exit_process(p); } void -erts_continue_exit_process(Process *c_p) -{ -#ifdef ERTS_SMP - continue_exit_process(c_p, ERTS_PID2PIXLOCK(c_p->id)); -#else - continue_exit_process(c_p); -#endif -} - -static void -continue_exit_process(Process *p -#ifdef ERTS_SMP - , erts_pix_lock_t *pix_lock -#endif - ) +erts_continue_exit_process(Process *p) { ErtsLink* lnk; ErtsMonitor *mon; @@ -8802,11 +9092,7 @@ continue_exit_process(Process *p ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(p)); -#ifdef DEBUG - erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - ASSERT(p->status == P_EXITING); - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); -#endif + ASSERT(ERTS_PROC_IS_EXITING(p)); #ifdef ERTS_SMP if (p->flags & F_HAVE_BLCKD_MSCHED) { @@ -8874,48 +9160,47 @@ continue_exit_process(Process *p #endif { + int maybe_save; int pix; /* Do *not* use erts_get_runq_proc() */ ErtsRunQueue *rq; rq = erts_get_runq_current(ERTS_GET_SCHEDULER_DATA_FROM_PROC(p)); - ASSERT(internal_pid_index(p->id) < erts_max_processes); pix = internal_pid_index(p->id); - erts_smp_mtx_lock(&proc_tab_mtx); + erts_smp_rwmtx_rlock(&erts_proc_tab_rwmtx); + maybe_save = saved_term_procs.end != NULL; + if (maybe_save) { + erts_smp_rwmtx_runlock(&erts_proc_tab_rwmtx); + erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx); + } + erts_smp_runq_lock(rq); #ifdef ERTS_SMP - erts_pix_lock(pix_lock); - ASSERT(p->scheduler_data); ASSERT(p->scheduler_data->current_process == p); ASSERT(p->scheduler_data->free_process == NULL); p->scheduler_data->current_process = NULL; p->scheduler_data->free_process = p; - p->status_flags = 0; #endif - process_tab[pix] = NULL; /* Time of death! */ + /* Time of death! */ + erts_smp_atomic_set_relb(&erts_proc.tab[pix], ERTS_AINT_NULL); + ASSERT(erts_smp_atomic32_read_nob(&process_count) > 0); - erts_smp_atomic32_dec_nob(&process_count); + erts_smp_atomic32_dec_relb(&process_count); -#ifdef ERTS_SMP - erts_pix_unlock(pix_lock); -#endif erts_smp_runq_unlock(rq); - if (p_next < 0) { - if (p_last >= p_next) { - p_serial++; - p_serial &= p_serial_mask; - } - p_next = pix; + if (!maybe_save) + erts_smp_rwmtx_runlock(&erts_proc_tab_rwmtx); + else { + if (saved_term_procs.end) + save_terminating_process(p); + erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx); } - ERTS_MAYBE_SAVE_TERMINATING_PROCESS(p); - - erts_smp_mtx_unlock(&proc_tab_mtx); } /* @@ -8930,7 +9215,21 @@ continue_exit_process(Process *p lnk = p->nlinks; p->nlinks = NULL; - p->status = P_FREE; + + { + /* Inactivate and notify free */ + erts_aint32_t n, e, a = erts_smp_atomic32_read_nob(&p->state); + while (1) { + n = e = a; + ASSERT(a & ERTS_PSFLG_EXITING); + n |= ERTS_PSFLG_FREE; + n &= ~ERTS_PSFLG_ACTIVE; + a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e); + if (a == e) + break; + } + } + dep = ((p->flags & F_DISTRIBUTION) ? ERTS_PROC_SET_DIST_ENTRY(p, ERTS_PROC_LOCKS_ALL, NULL) : NULL); @@ -8985,8 +9284,13 @@ continue_exit_process(Process *p delete_process(p); +#ifdef ERTS_SMP + erts_schedule_thr_prgr_later_op(proc_dec_refc, + (void *) p, + &p->u.release_data); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); +#endif return; @@ -8999,8 +9303,6 @@ continue_exit_process(Process *p ERTS_SMP_LC_ASSERT(curr_locks == erts_proc_lc_my_proc_locks(p)); ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & curr_locks); - ASSERT(p->status == P_EXITING); - p->i = (BeamInstr *) beam_continue_exit; if (!(curr_locks & ERTS_PROC_LOCK_STATUS)) { @@ -9008,8 +9310,6 @@ continue_exit_process(Process *p curr_locks |= ERTS_PROC_LOCK_STATUS; } - erts_add_to_runq(p); - if (curr_locks != ERTS_PROC_LOCK_MAIN) erts_smp_proc_unlock(p, ~ERTS_PROC_LOCK_MAIN & curr_locks); @@ -9021,33 +9321,15 @@ continue_exit_process(Process *p static void timeout_proc(Process* p) { + erts_aint32_t state; BeamInstr** pi = (BeamInstr **) p->def_arg_reg; p->i = *pi; p->flags |= F_TIMO; p->flags &= ~F_INSLPQUEUE; - switch (p->status) { - case P_GARBING: - switch (p->gcstatus) { - case P_SUSPENDED: - goto suspended; - case P_WAITING: - goto waiting; - default: - break; - } - break; - case P_WAITING: - waiting: - erts_add_to_runq(p); - break; - case P_SUSPENDED: - suspended: - p->rstatus = P_RUNABLE; /* MUST set resume status to runnable */ - break; - default: - break; - } + state = erts_smp_atomic32_read_acqb(&p->state); + if (!(state & ERTS_PSFLG_ACTIVE)) + schedule_process(p, state, 0); } @@ -9057,9 +9339,9 @@ cancel_timer(Process* p) ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p)); p->flags &= ~(F_INSLPQUEUE|F_TIMO); #ifdef ERTS_SMP - erts_cancel_smp_ptimer(p->u.ptimer); + erts_cancel_smp_ptimer(p->u.alive.ptimer); #else - erts_cancel_timer(&p->u.tm); + erts_cancel_timer(&p->u.alive.tm); #endif } @@ -9080,12 +9362,12 @@ set_timer(Process* p, Uint timeout) p->flags &= ~F_TIMO; #ifdef ERTS_SMP - erts_create_smp_ptimer(&p->u.ptimer, + erts_create_smp_ptimer(&p->u.alive.ptimer, p->id, (ErlTimeoutProc) timeout_proc, timeout); #else - erts_set_timer(&p->u.tm, + erts_set_timer(&p->u.alive.tm, (ErlTimeoutProc) timeout_proc, NULL, (void*) p, @@ -9115,6 +9397,7 @@ erts_stack_dump(int to, void *to_arg, Process *p) void erts_program_counter_info(int to, void *to_arg, Process *p) { + erts_aint32_t state; int i; erts_print(to, to_arg, "Program counter: %p (", p->i); @@ -9123,7 +9406,8 @@ erts_program_counter_info(int to, void *to_arg, Process *p) erts_print(to, to_arg, "CP: %p (", p->cp); print_function_from_pc(to, to_arg, p->cp); erts_print(to, to_arg, ")\n"); - if (!((p->status == P_RUNNING) || (p->status == P_GARBING))) { + state = erts_smp_atomic32_read_acqb(&p->state); + if (!(state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_GC))) { erts_print(to, to_arg, "arity = %d\n",p->arity); if (!ERTS_IS_CRASH_DUMPING) { /* @@ -9296,13 +9580,13 @@ do { \ #endif #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS -# define ERTS_PROCS_DBG_CHK_PID_FOUND(PBDP, PID, TVP) \ - debug_processes_check_found_pid((PBDP), (PID), (TVP), 1) -# define ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(PBDP, PID, TVP) \ - debug_processes_check_found_pid((PBDP), (PID), (TVP), 0) +# define ERTS_PROCS_DBG_CHK_PID_FOUND(PBDP, PID, IC) \ + debug_processes_check_found_pid((PBDP), (PID), (IC), 1) +# define ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(PBDP, PID, IC) \ + debug_processes_check_found_pid((PBDP), (PID), (IC), 0) #else -# define ERTS_PROCS_DBG_CHK_PID_FOUND(PBDP, PID, TVP) -# define ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(PBDP, PID, TVP) +# define ERTS_PROCS_DBG_CHK_PID_FOUND(PBDP, PID, IC) +# define ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(PBDP, PID, IC) #endif #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST @@ -9347,7 +9631,7 @@ static Uint processes_bif_tab_chunks; static Export processes_trap_export; typedef struct { - SysTimeval time; + Uint64 interval; } ErtsProcessesBifChunkInfo; typedef enum { @@ -9372,7 +9656,7 @@ typedef struct { struct { Eterm caller; #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS - SysTimeval *pid_started; + Uint64 *pid_started; #endif #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_HALLOC Eterm *heap; @@ -9401,11 +9685,10 @@ static void debug_processes_verify_all_pids(ErtsProcessesBifData *pbdp); #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS static void debug_processes_check_found_pid(ErtsProcessesBifData *pbdp, Eterm pid, - SysTimeval *started, + Uint64 ic, int pid_should_be_found); #endif #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST -static SysTimeval debug_tv_start; static void debug_processes_check_term_proc_list(void); static void debug_processes_check_term_proc_free_list(ErtsTermProcElement *tpep); #endif @@ -9416,7 +9699,7 @@ save_terminating_process(Process *p) ErtsTermProcElement *tpep = erts_alloc(ERTS_ALC_T_PROCS_TPROC_EL, sizeof(ErtsTermProcElement)); ERTS_PROCS_ASSERT(saved_term_procs.start && saved_term_procs.end); - ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx)); + ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_proc_tab_rwmtx)); ERTS_PROCS_DBG_CHK_TPLIST(); @@ -9424,19 +9707,19 @@ save_terminating_process(Process *p) tpep->next = NULL; tpep->ix = internal_pid_index(p->id); tpep->u.process.pid = p->id; - tpep->u.process.spawned = p->started; - erts_get_emu_time(&tpep->u.process.exited); + tpep->u.process.spawned = p->started_interval; + tpep->u.process.exited = get_proc_interval(); saved_term_procs.end->next = tpep; saved_term_procs.end = tpep; ERTS_PROCS_DBG_CHK_TPLIST(); - ERTS_PROCS_ASSERT((tpep->prev->ix >= 0 - ? erts_cmp_timeval(&tpep->u.process.exited, - &tpep->prev->u.process.exited) - : erts_cmp_timeval(&tpep->u.process.exited, - &tpep->prev->u.bif_invocation.time)) > 0); + ERTS_PROCS_ASSERT(tpep->prev->ix >= 0 + ? (tpep->u.process.exited + >= tpep->prev->u.process.exited) + : (tpep->u.process.exited + >= tpep->prev->u.bif_invocation.interval)); } static void @@ -9467,7 +9750,7 @@ cleanup_processes_bif_data(Binary *bp) if (pbdp->bif_invocation) { ErtsTermProcElement *tpep; - erts_smp_mtx_lock(&proc_tab_mtx); + erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx); ERTS_PROCS_DBG_TRACE(pbdp->debug.caller, cleanup_processes_bif_data, @@ -9521,7 +9804,7 @@ cleanup_processes_bif_data(Binary *bp) ERTS_PROCS_DBG_CHK_TPLIST(); - erts_smp_mtx_unlock(&proc_tab_mtx); + erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx); } } @@ -9549,7 +9832,7 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) pbdp->tix = 0; pbdp->pid_ix = 0; - erts_smp_mtx_lock(&proc_tab_mtx); + erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx); locked = 1; ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, init); @@ -9560,7 +9843,7 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS pbdp->debug.pid_started = erts_alloc(ERTS_ALC_T_PROCS_PIDS, - sizeof(SysTimeval)*pbdp->pid_sz); + sizeof(Uint64)*pbdp->pid_sz); #endif ERTS_PROCS_DBG_SAVE_PIDS(pbdp); @@ -9575,7 +9858,8 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) pbdp->bif_invocation = erts_alloc(ERTS_ALC_T_PROCS_TPROC_EL, sizeof(ErtsTermProcElement)); pbdp->bif_invocation->ix = -1; - erts_get_emu_time(&pbdp->bif_invocation->u.bif_invocation.time); + pbdp->bif_invocation->u.bif_invocation.interval + = step_proc_interval(); ERTS_PROCS_DBG_CHK_TPLIST(); pbdp->bif_invocation->next = NULL; @@ -9602,30 +9886,31 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) int indices = ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE; int cix = ix / ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE; int end_ix = ix + indices; - SysTimeval *invocation_timep; + Uint64 *invocation_interval_p; - invocation_timep = (pbdp->bif_invocation - ? &pbdp->bif_invocation->u.bif_invocation.time - : NULL); + invocation_interval_p + = (pbdp->bif_invocation + ? &pbdp->bif_invocation->u.bif_invocation.interval + : NULL); ERTS_PROCS_ASSERT(is_nil(*res_accp)); if (!locked) { - erts_smp_mtx_lock(&proc_tab_mtx); + erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx); locked = 1; } - ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx)); + ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_proc_tab_rwmtx)); ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, insp_table); if (cix != 0) - erts_get_emu_time(&pbdp->chunk[cix].time); + pbdp->chunk[cix].interval = step_proc_interval(); else if (pbdp->bif_invocation) - pbdp->chunk[0].time = *invocation_timep; - /* else: Time is irrelevant */ + pbdp->chunk[0].interval = *invocation_interval_p; + /* else: interval is irrelevant */ - if (end_ix >= erts_max_processes) { + if (end_ix >= erts_proc.max) { ERTS_PROCS_ASSERT(cix+1 == processes_bif_tab_chunks); - end_ix = erts_max_processes; + end_ix = erts_proc.max; indices = end_ix - ix; /* What to do when done with this chunk */ pbdp->state = (processes_bif_tab_chunks == 1 @@ -9634,16 +9919,15 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) } for (; ix < end_ix; ix++) { - Process *rp = process_tab[ix]; + Process *rp = erts_pix2proc(ix); if (rp - && (!invocation_timep - || erts_cmp_timeval(&rp->started, - invocation_timep) < 0)) { + && (!invocation_interval_p + || rp->started_interval < *invocation_interval_p)) { ERTS_PROCS_ASSERT(is_internal_pid(rp->id)); pbdp->pid[pbdp->pid_ix] = rp->id; #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS - pbdp->debug.pid_started[pbdp->pid_ix] = rp->started; + pbdp->debug.pid_started[pbdp->pid_ix] = rp->started_interval; #endif pbdp->pid_ix++; @@ -9653,7 +9937,7 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) pbdp->tix = end_ix; - erts_smp_mtx_unlock(&proc_tab_mtx); + erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx); locked = 0; reds = indices/ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED; @@ -9665,8 +9949,8 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) ix = pbdp->tix; indices = ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE; end_ix = ix + indices; - if (end_ix > erts_max_processes) { - end_ix = erts_max_processes; + if (end_ix > erts_proc.max) { + end_ix = erts_proc.max; indices = end_ix - ix; } @@ -9685,20 +9969,20 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) int i; int max_reds; int free_term_procs = 0; - SysTimeval *invocation_timep; + Uint64 invocation_interval; ErtsTermProcElement *tpep; ErtsTermProcElement *free_list = NULL; tpep = pbdp->bif_invocation; ERTS_PROCS_ASSERT(tpep); - invocation_timep = &tpep->u.bif_invocation.time; + invocation_interval = tpep->u.bif_invocation.interval; max_reds = have_reds = ERTS_BIF_REDS_LEFT(p); if (max_reds > ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS) max_reds = ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS; reds = 0; - erts_smp_mtx_lock(&proc_tab_mtx); + erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx); ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, insp_term_procs); ERTS_PROCS_DBG_CHK_TPLIST(); @@ -9737,20 +10021,19 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) } else { int cix = tpep->ix/ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE; - SysTimeval *chunk_timep = &pbdp->chunk[cix].time; + Uint64 chunk_interval = pbdp->chunk[cix].interval; Eterm pid = tpep->u.process.pid; ERTS_PROCS_ASSERT(is_internal_pid(pid)); - if (erts_cmp_timeval(&tpep->u.process.spawned, - invocation_timep) < 0) { - if (erts_cmp_timeval(&tpep->u.process.exited, - chunk_timep) < 0) { + if (tpep->u.process.spawned < invocation_interval) { + if (tpep->u.process.exited < chunk_interval) { ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(pbdp, pid, - &tpep->u.process.spawned); + tpep->u.process.spawned); pbdp->pid[pbdp->pid_ix] = pid; #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS - pbdp->debug.pid_started[pbdp->pid_ix] = tpep->u.process.spawned; + pbdp->debug.pid_started[pbdp->pid_ix] + = tpep->u.process.spawned; #endif pbdp->pid_ix++; ERTS_PROCS_ASSERT(pbdp->pid_ix <= pbdp->pid_sz); @@ -9758,13 +10041,13 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) else { ERTS_PROCS_DBG_CHK_PID_FOUND(pbdp, pid, - &tpep->u.process.spawned); + tpep->u.process.spawned); } } else { ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(pbdp, pid, - &tpep->u.process.spawned); + tpep->u.process.spawned); } i++; @@ -9813,7 +10096,7 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) ERTS_PROCS_DBG_CHK_TPLIST(); ERTS_PROCS_DBG_CHK_FREELIST(free_list); - erts_smp_mtx_unlock(&proc_tab_mtx); + erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx); /* * We do the actual free of term proc structures now when we @@ -9873,8 +10156,9 @@ processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp) sizeof(Eterm)*pbdp->pid_sz); #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS pbdp->debug.pid_started = erts_realloc(ERTS_ALC_T_PROCS_PIDS, - pbdp->debug.pid_started, - sizeof(SysTimeval)*pbdp->pid_sz); + pbdp->debug.pid_started, + (sizeof(Uint64) + * pbdp->pid_sz)); #endif } reds = conses/ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED; @@ -9994,22 +10278,13 @@ init_processes_bif(void) { saved_term_procs.start = NULL; saved_term_procs.end = NULL; - processes_bif_tab_chunks = (((erts_max_processes - 1) + processes_bif_tab_chunks = (((erts_proc.max - 1) / ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE) + 1); /* processes_trap/2 is a hidden BIF that the processes/0 BIF traps to. */ - sys_memset((void *) &processes_trap_export, 0, sizeof(Export)); - processes_trap_export.address = &processes_trap_export.code[3]; - processes_trap_export.code[0] = am_erlang; - processes_trap_export.code[1] = am_processes_trap; - processes_trap_export.code[2] = 2; - processes_trap_export.code[3] = (BeamInstr) em_apply_bif; - processes_trap_export.code[4] = (BeamInstr) &processes_trap; - -#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST - erts_get_emu_time(&debug_tv_start); -#endif + erts_init_trap_export(&processes_trap_export, am_erlang, am_processes_trap, 2, + &processes_trap); } @@ -10042,31 +10317,29 @@ erts_debug_processes(Process *c_p) Eterm res; Eterm* hp; Process *p; -#ifdef DEBUG Eterm *hp_end; -#endif - erts_smp_mtx_lock(&proc_tab_mtx); + erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx); res = NIL; need = erts_process_count() * 2; hp = HAlloc(c_p, need); /* we need two heap words for each pid */ -#ifdef DEBUG hp_end = hp + need; -#endif /* make the list by scanning bakward */ - for (i = erts_max_processes-1; i >= 0; i--) { - if ((p = process_tab[i]) != NULL) { - res = CONS(hp, process_tab[i]->id, res); + for (i = erts_proc.max-1; i >= 0; i--) { + p = erts_pix2proc(i); + if (p) { + res = CONS(hp, p->id, res); hp += 2; } } - ASSERT(hp == hp_end); - erts_smp_mtx_unlock(&proc_tab_mtx); + erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx); + + HRelease(c_p, hp_end, hp); return res; } @@ -10098,14 +10371,12 @@ erts_debug_processes_bif_info(Process *c_p) static void debug_processes_check_found_pid(ErtsProcessesBifData *pbdp, Eterm pid, - SysTimeval *tvp, + Uint64 ic, int pid_should_be_found) { int i; for (i = 0; i < pbdp->pid_ix; i++) { - if (pbdp->pid[i] == pid - && pbdp->debug.pid_started[i].tv_sec == tvp->tv_sec - && pbdp->debug.pid_started[i].tv_usec == tvp->tv_usec) { + if (pbdp->pid[i] == pid && pbdp->debug.pid_started[i] == ic) { ERTS_PROCS_ASSERT(pid_should_be_found); return; } @@ -10139,8 +10410,8 @@ debug_processes_save_all_pids(ErtsProcessesBifData *pbdp) pbdp->debug.correct_pids = erts_alloc(ERTS_ALC_T_PROCS_PIDS, sizeof(Eterm)*pbdp->pid_sz); - for (tix = 0, cpix = 0; tix < erts_max_processes; tix++) { - Process *rp = process_tab[tix]; + for (tix = 0, cpix = 0; tix < erts_proc.max; tix++) { + Process *rp = erts_pix2proc(tix); if (rp) { ERTS_PROCS_ASSERT(is_internal_pid(rp->id)); pbdp->debug.correct_pids[cpix++] = rp->id; @@ -10193,14 +10464,13 @@ debug_processes_verify_all_pids(ErtsProcessesBifData *pbdp) static void debug_processes_check_term_proc_list(void) { - ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx)); + ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_proc_tab_rwmtx)); if (!saved_term_procs.start) ERTS_PROCS_ASSERT(!saved_term_procs.end); else { - SysTimeval tv_now; - SysTimeval *prev_xtvp = NULL; + Uint64 curr_interval = get_proc_interval(); + Uint64 *prev_x_interval_p = NULL; ErtsTermProcElement *tpep; - erts_get_emu_time(&tv_now); for (tpep = saved_term_procs.start; tpep; tpep = tpep->next) { if (!tpep->prev) @@ -10212,20 +10482,17 @@ debug_processes_check_term_proc_list(void) else ERTS_PROCS_ASSERT(tpep->next->prev == tpep); if (tpep->ix < 0) { - SysTimeval *tvp = &tpep->u.bif_invocation.time; - ERTS_PROCS_ASSERT(erts_cmp_timeval(&debug_tv_start, tvp) < 0 - && erts_cmp_timeval(tvp, &tv_now) < 0); + Uint64 interval = tpep->u.bif_invocation.interval; + ERTS_PROCS_ASSERT(interval <= curr_interval); } else { - SysTimeval *stvp = &tpep->u.process.spawned; - SysTimeval *xtvp = &tpep->u.process.exited; + Uint64 s_interval = tpep->u.process.spawned; + Uint64 x_interval = tpep->u.process.exited; - ERTS_PROCS_ASSERT(erts_cmp_timeval(&debug_tv_start, - stvp) < 0); - ERTS_PROCS_ASSERT(erts_cmp_timeval(stvp, xtvp) < 0); - if (prev_xtvp) - ERTS_PROCS_ASSERT(erts_cmp_timeval(prev_xtvp, xtvp) < 0); - prev_xtvp = xtvp; + ERTS_PROCS_ASSERT(s_interval <= x_interval); + if (prev_x_interval_p) + ERTS_PROCS_ASSERT(*prev_x_interval_p <= x_interval); + prev_x_interval_p = &tpep->u.process.exited; ERTS_PROCS_ASSERT(is_internal_pid(tpep->u.process.pid)); ERTS_PROCS_ASSERT(tpep->ix == internal_pid_index(tpep->u.process.pid)); diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 9e7a5a5c74..1436e246d6 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -112,28 +112,29 @@ extern int erts_sched_thread_suggested_stack_size; #define PRIORITY_NORMAL 2 #define PRIORITY_LOW 3 #define ERTS_NO_PROC_PRIO_LEVELS 4 +#define ERTS_NO_PROC_PRIO_QUEUES 3 #define ERTS_PORT_PRIO_LEVEL ERTS_NO_PROC_PRIO_LEVELS +#define ERTS_NO_PRIO_LEVELS (ERTS_NO_PROC_PRIO_LEVELS + 1) #define ERTS_RUNQ_FLGS_PROCS_QMASK \ ((((Uint32) 1) << ERTS_NO_PROC_PRIO_LEVELS) - 1) -#define ERTS_NO_PRIO_LEVELS (ERTS_NO_PROC_PRIO_LEVELS + 1) -#define ERTS_RUNQ_FLGS_MIGRATE_QMASK \ +#define ERTS_RUNQ_FLGS_QMASK \ ((((Uint32) 1) << ERTS_NO_PRIO_LEVELS) - 1) #define ERTS_RUNQ_FLGS_EMIGRATE_SHFT \ - ERTS_NO_PROC_PRIO_LEVELS + ERTS_NO_PRIO_LEVELS #define ERTS_RUNQ_FLGS_IMMIGRATE_SHFT \ (ERTS_RUNQ_FLGS_EMIGRATE_SHFT + ERTS_NO_PRIO_LEVELS) #define ERTS_RUNQ_FLGS_EVACUATE_SHFT \ (ERTS_RUNQ_FLGS_IMMIGRATE_SHFT + ERTS_NO_PRIO_LEVELS) #define ERTS_RUNQ_FLGS_EMIGRATE_QMASK \ - (ERTS_RUNQ_FLGS_MIGRATE_QMASK << ERTS_RUNQ_FLGS_EMIGRATE_SHFT) + (ERTS_RUNQ_FLGS_QMASK << ERTS_RUNQ_FLGS_EMIGRATE_SHFT) #define ERTS_RUNQ_FLGS_IMMIGRATE_QMASK \ - (ERTS_RUNQ_FLGS_MIGRATE_QMASK << ERTS_RUNQ_FLGS_IMMIGRATE_SHFT) + (ERTS_RUNQ_FLGS_QMASK << ERTS_RUNQ_FLGS_IMMIGRATE_SHFT) #define ERTS_RUNQ_FLGS_EVACUATE_QMASK \ - (ERTS_RUNQ_FLGS_MIGRATE_QMASK << ERTS_RUNQ_FLGS_EVACUATE_SHFT) + (ERTS_RUNQ_FLGS_QMASK << ERTS_RUNQ_FLGS_EVACUATE_SHFT) #define ERTS_RUNQ_FLG_BASE2 \ (ERTS_RUNQ_FLGS_EVACUATE_SHFT + ERTS_NO_PRIO_LEVELS) @@ -148,14 +149,18 @@ extern int erts_sched_thread_suggested_stack_size; (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 3)) #define ERTS_RUNQ_FLG_INACTIVE \ (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 4)) +#define ERTS_RUNQ_FLG_NONEMPTY \ + (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 5)) +#define ERTS_RUNQ_FLG_PROTECTED \ + (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 6)) #define ERTS_RUNQ_FLGS_MIGRATION_QMASKS \ (ERTS_RUNQ_FLGS_EMIGRATE_QMASK \ | ERTS_RUNQ_FLGS_IMMIGRATE_QMASK \ | ERTS_RUNQ_FLGS_EVACUATE_QMASK) + #define ERTS_RUNQ_FLGS_MIGRATION_INFO \ - (ERTS_RUNQ_FLGS_MIGRATION_QMASKS \ - | ERTS_RUNQ_FLG_INACTIVE \ + (ERTS_RUNQ_FLG_INACTIVE \ | ERTS_RUNQ_FLG_OUT_OF_WORK \ | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK) @@ -186,33 +191,45 @@ extern int erts_sched_thread_suggested_stack_size; #define ERTS_UNSET_RUNQ_FLG_EVACUATE(FLGS, PRIO) \ ((FLGS) &= ~ERTS_RUNQ_FLG_EVACUATE((PRIO))) -#define ERTS_RUNQ_IFLG_SUSPENDED (((erts_aint32_t) 1) << 0) -#define ERTS_RUNQ_IFLG_NONEMPTY (((erts_aint32_t) 1) << 1) - - -#ifdef DEBUG -# if defined(ARCH_64) && !HALFWORD_HEAP -# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) \ - (*((char **) &(RQP)) = (char *) (0xdeadbeefdead0003 | ((N) << 4))) -# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) \ -do { \ - ASSERT((RQP) != NULL); \ - ASSERT(((((Uint) (RQP)) & ((Uint) 0x3))) == ((Uint) 0)); \ - ASSERT((((Uint) (RQP)) & ~((Uint) 0xffff)) != ((Uint) 0xdeadbeefdead0000));\ -} while (0) -# else -# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) \ - (*((char **) &(RQP)) = (char *) (0xdead0003 | ((N) << 4))) -# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) \ -do { \ - ASSERT((RQP) != NULL); \ - ASSERT(((((UWord) (RQP)) & ((UWord) 1))) == ((UWord) 0)); \ - ASSERT((((UWord) (RQP)) & ~((UWord) 0xffff)) != ((UWord) 0xdead0000)); \ -} while (0) -# endif -#else -# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) -# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) +#define ERTS_RUNQ_FLGS_INIT(RQ, INIT) \ + erts_smp_atomic32_init_nob(&(RQ)->flags, (erts_aint32_t) (INIT)) +#define ERTS_RUNQ_FLGS_SET(RQ, FLGS) \ + ((Uint32) erts_smp_atomic32_read_bor_relb(&(RQ)->flags, \ + (erts_aint32_t) (FLGS))) +#define ERTS_RUNQ_FLGS_UNSET(RQ, FLGS) \ + ((Uint32) erts_smp_atomic32_read_band_relb(&(RQ)->flags, \ + (erts_aint32_t) ~(FLGS))) +#define ERTS_RUNQ_FLGS_GET(RQ) \ + ((Uint32) erts_smp_atomic32_read_acqb(&(RQ)->flags)) +#define ERTS_RUNQ_FLGS_GET_NOB(RQ) \ + ((Uint32) erts_smp_atomic32_read_nob(&(RQ)->flags)) +#define ERTS_RUNQ_FLGS_GET_MB(RQ) \ + ((Uint32) erts_smp_atomic32_read_mb(&(RQ)->flags)) +#define ERTS_RUNQ_FLGS_MASK_SET(RQ, MSK, FLGS) \ + ((Uint32) erts_smp_atomic32_mask_set_relb(&(RQ)->flags, \ + (erts_aint32_t) (MSK), \ + (erts_aint32_t) (FLGS))) + +ERTS_GLB_INLINE erts_aint32_t +erts_smp_atomic32_mask_set_relb(erts_smp_atomic32_t *a32p, + erts_aint32_t mask, + erts_aint32_t set); +#if ERTS_GLB_INLINE_INCL_FUNC_DEF +ERTS_GLB_INLINE erts_aint32_t +erts_smp_atomic32_mask_set_relb(erts_smp_atomic32_t *a32p, + erts_aint32_t mask, + erts_aint32_t set) +{ + erts_aint32_t act = erts_smp_atomic32_read_nob(a32p); + while (1) { + erts_aint32_t exp = act; + erts_aint32_t new = exp & ~mask; + new |= (mask & set); + act = erts_smp_atomic32_cmpxchg_relb(a32p, new, exp); + if (act == exp) + return act; + } +} #endif typedef enum { @@ -258,14 +275,17 @@ typedef enum { #define ERTS_SSI_AUX_WORK_DD_THR_PRGR (((erts_aint32_t) 1) << 2) #define ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC (((erts_aint32_t) 1) << 3) #define ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM (((erts_aint32_t) 1) << 4) -#define ERTS_SSI_AUX_WORK_ASYNC_READY (((erts_aint32_t) 1) << 5) -#define ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN (((erts_aint32_t) 1) << 6) -#define ERTS_SSI_AUX_WORK_MISC_THR_PRGR (((erts_aint32_t) 1) << 7) -#define ERTS_SSI_AUX_WORK_MISC (((erts_aint32_t) 1) << 8) -#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 9) -#define ERTS_SSI_AUX_WORK_SET_TMO (((erts_aint32_t) 1) << 10) -#define ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK (((erts_aint32_t) 1) << 11) -#define ERTS_SSI_AUX_WORK_REAP_PORTS (((erts_aint32_t) 1) << 12) +#define ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP (((erts_aint32_t) 1) << 5) +#define ERTS_SSI_AUX_WORK_ASYNC_READY (((erts_aint32_t) 1) << 6) +#define ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN (((erts_aint32_t) 1) << 7) +#define ERTS_SSI_AUX_WORK_MISC_THR_PRGR (((erts_aint32_t) 1) << 8) +#define ERTS_SSI_AUX_WORK_MISC (((erts_aint32_t) 1) << 9) +#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 10) +#define ERTS_SSI_AUX_WORK_SET_TMO (((erts_aint32_t) 1) << 11) +#define ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK (((erts_aint32_t) 1) << 12) +#define ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION (((erts_aint32_t) 1) << 13) +#define ERTS_SSI_AUX_WORK_REAP_PORTS (((erts_aint32_t) 1) << 14) +#define ERTS_SSI_AUX_WORK_FINISH_BP (((erts_aint32_t) 1) << 15) typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo; @@ -291,7 +311,7 @@ struct ErtsSchedulerSleepInfo_ { typedef struct ErtsProcList_ ErtsProcList; struct ErtsProcList_ { Eterm pid; - SysTimeval started; + Uint64 started_interval; ErtsProcList* next; }; @@ -312,21 +332,39 @@ typedef struct ErtsSchedulerData_ ErtsSchedulerData; typedef struct ErtsRunQueue_ ErtsRunQueue; typedef struct { - int len; - int max_len; + erts_smp_atomic32_t len; + erts_aint32_t max_len; int reds; +} ErtsRunQueueInfo; + +#ifdef ERTS_SMP + +typedef struct { + Uint32 flags; + ErtsRunQueue *misc_evac_runq; struct { struct { int this; int other; } limit; ErtsRunQueue *runq; - } migrate; -} ErtsRunQueueInfo; + Uint32 flags; + } prio[ERTS_NO_PRIO_LEVELS]; +} ErtsMigrationPath; + +typedef struct ErtsMigrationPaths_ ErtsMigrationPaths; + +struct ErtsMigrationPaths_ { + void *block; + ErtsMigrationPaths *next; + ErtsThrPrgrVal thr_prgr; + ErtsMigrationPath mpath[1]; +}; + +#endif /* ERTS_SMP */ struct ErtsRunQueue_ { int ix; - erts_smp_atomic32_t info_flags; erts_smp_mtx_t mtx; erts_smp_cnd_t cnd; @@ -334,19 +372,18 @@ struct ErtsRunQueue_ { ErtsSchedulerData *scheduler; int waiting; /* < 0 in sys schedule; > 0 on cnd variable */ int woken; - Uint32 flags; + erts_smp_atomic32_t flags; int check_balance_reds; int full_reds_history_sum; int full_reds_history[ERTS_FULL_REDS_HISTORY_SIZE]; int out_of_work_count; - int max_len; - int len; + erts_aint32_t max_len; + erts_aint32_t len; int wakeup_other; int wakeup_other_reds; int halt_in_progress; struct { - int len; ErtsProcList *pending_exiters; Uint context_switches; Uint reductions; @@ -361,7 +398,7 @@ struct ErtsRunQueue_ { struct { ErtsMiscOpList *start; ErtsMiscOpList *end; - ErtsRunQueue *evac_runq; + erts_smp_atomic_t evac_runq; } misc; struct { @@ -381,7 +418,7 @@ extern ErtsAlignedRunQueue *erts_aligned_run_queues; #define ERTS_PROC_REDUCTIONS_EXECUTED(RQ, PRIO, REDS, AREDS) \ do { \ (RQ)->procs.reductions += (AREDS); \ - (RQ)->procs.prio_info[p->prio].reds += (REDS); \ + (RQ)->procs.prio_info[(PRIO)].reds += (REDS); \ (RQ)->check_balance_reds -= (REDS); \ (RQ)->wakeup_other_reds += (AREDS); \ } while (0) @@ -427,6 +464,10 @@ typedef struct { void (*completed_callback)(void *); void (*completed_arg)(void *); } dd; + struct { + ErtsThrPrgrLaterOp *first; + ErtsThrPrgrLaterOp *last; + } later_op; #endif #ifdef ERTS_USE_ASYNC_READY_Q struct { @@ -439,6 +480,14 @@ typedef struct { #endif #ifdef ERTS_SMP struct { + Process* code_stager; + ErtsThrPrgrVal thr_prgr; + } code_ix_activation; + struct { + Process* stager; + ErtsThrPrgrVal thr_prgr; + } bp_ix_activation; + struct { int *sched2jix; int jix; ErtsDelayedAuxWorkWakeupJob *job; @@ -500,6 +549,90 @@ extern ErtsAlignedSchedulerData *erts_aligned_scheduler_data; extern ErtsSchedulerData *erts_scheduler_data; #endif +#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) +int erts_smp_lc_runq_is_locked(ErtsRunQueue *); +#endif + +#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS + +/* + * Run queue locked during modifications. We use atomic ops since + * other threads peek at values without run queue lock. + */ + +ERTS_GLB_INLINE void erts_smp_inc_runq_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi, int prio); +ERTS_GLB_INLINE void erts_smp_dec_runq_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi, int prio); +ERTS_GLB_INLINE void erts_smp_reset_max_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE void +erts_smp_inc_runq_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi, int prio) +{ + erts_aint32_t len; + + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); + + len = erts_smp_atomic32_read_nob(&rqi->len); + ASSERT(len >= 0); + if (len == 0) { + ASSERT((erts_smp_atomic32_read_nob(&rq->flags) + & ((erts_aint32_t) (1 << prio))) == 0); + erts_smp_atomic32_read_bor_nob(&rq->flags, + (erts_aint32_t) (1 << prio)); + } + len++; + if (rqi->max_len < len) + rqi->max_len = len; + + erts_smp_atomic32_set_relb(&rqi->len, len); + + rq->len++; + if (rq->max_len < rq->len) + rq->max_len = len; + ASSERT(rq->len > 0); +} + +ERTS_GLB_INLINE void +erts_smp_dec_runq_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi, int prio) +{ + erts_aint32_t len; + + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); + + len = erts_smp_atomic32_read_nob(&rqi->len); + len--; + ASSERT(len >= 0); + if (len == 0) { + ASSERT((erts_smp_atomic32_read_nob(&rq->flags) + & ((erts_aint32_t) (1 << prio)))); + erts_smp_atomic32_read_band_nob(&rq->flags, + ~((erts_aint32_t) (1 << prio))); + } + erts_smp_atomic32_set_relb(&rqi->len, len); + + rq->len--; + ASSERT(rq->len >= 0); +} + +ERTS_GLB_INLINE void +erts_smp_reset_max_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi) +{ + erts_aint32_t len; + + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); + + len = erts_smp_atomic32_read_nob(&rqi->len); + ASSERT(rqi->max_len >= len); + rqi->max_len = len; +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + +#define RUNQ_READ_LEN(X) erts_smp_atomic32_read_nob((X)) + +#endif /* ERTS_INCLUDE_SCHEDULER_INTERNALS */ + /* * Process Specific Data. * @@ -612,6 +745,8 @@ struct ErtsPendingSuspend_ { # define BIN_OLD_VHEAP(p) (p)->bin_old_vheap struct process { + Eterm id; /* The pid of this process + (need to be first in struct) */ /* All fields in the PCB that differs between different heap * architectures, have been moved to the end of this struct to * make sure that as few offsets as possible differ. Different @@ -654,13 +789,9 @@ struct process { * Number of reductions left to execute. * Only valid for the current process. */ - Uint32 status; /* process STATE */ - Uint32 gcstatus; /* process gc STATE */ - Uint32 rstatus; /* process resume STATE */ Uint32 rcount; /* suspend count */ - Eterm id; /* The pid of this process */ int prio; /* Priority of process */ - int skipped; /* Times a low prio process has been rescheduled */ + int schedule_count; /* Times left to reschedule a low prio process */ Uint reds; /* No of reductions for this process */ Eterm tracer_proc; /* If proc is traced, this is the tracer (can NOT be boxed) */ @@ -673,7 +804,6 @@ struct process { Eterm ftrace; /* Latest exception stack trace dump */ Process *next; /* Pointer to next process in run queue */ - Process *prev; /* Pointer to prev process in run queue */ struct reg_proc *reg; /* NULL iff not registered */ ErtsLink *nlinks; @@ -711,8 +841,8 @@ struct process { * Information mainly for post-mortem use (erl crash dump). */ Eterm parent; /* Pid of process that created this process. */ - SysTimeval started; /* Time when started. */ - + erts_approx_time_t approx_started; /* Time when started. */ + Uint64 started_interval; /* This is the place, where all fields that differs between memory * architectures, have gone to. @@ -735,27 +865,29 @@ struct process { Uint64 bin_old_vheap; /* Virtual old heap size for binaries */ union { + struct { #ifdef ERTS_SMP - ErtsSmpPTimer *ptimer; + ErtsSmpPTimer *ptimer; + ErlMessageInQueue msg_inq; + ErtsPendExit pending_exit; #else - ErlTimer tm; /* Timer entry */ + ErlTimer tm; /* Timer entry */ +#endif + } alive; /* when process is alive */ +#ifdef ERTS_SMP + ErtsThrPrgrLaterOp release_data; /* when releasing process struct */ #endif void *exit_data; /* Misc data referred during termination */ } u; - ErtsRunQueue *bound_runq; + erts_smp_atomic32_t state; /* Process state flags (see ERTS_PSFLG_*) */ #ifdef ERTS_SMP erts_proc_lock_t lock; ErtsSchedulerData *scheduler_data; - int is_exiting; - Uint32 runq_flags; - Uint32 status_flags; - ErlMessageInQueue msg_inq; Eterm suspendee; ErtsPendingSuspend *pending_suspenders; - ErtsPendExit pending_exit; - ErtsRunQueue *run_queue; + erts_smp_atomic_t run_queue; #ifdef HIPE struct hipe_process_state_smp hipe_smp; #endif @@ -809,6 +941,29 @@ void erts_check_for_holes(Process* p); #define SEQ_TRACE_TOKEN(p) ((p)->seq_trace_token) +#if ERTS_NO_PROC_PRIO_LEVELS > 4 +# error "Need to increase ERTS_PSFLG_PRIO_SHIFT" +#endif + +#define ERTS_PSFLG_PRIO_SHIFT 2 + +#define ERTS_PSFLG_BIT(N) \ + (((erts_aint32_t) 1) << (ERTS_PSFLG_PRIO_SHIFT + (N))) + +#define ERTS_PSFLG_PRIO_MASK (ERTS_PSFLG_BIT(0) - 1) + +#define ERTS_PSFLG_FREE ERTS_PSFLG_BIT(0) +#define ERTS_PSFLG_EXITING ERTS_PSFLG_BIT(1) +#define ERTS_PSFLG_PENDING_EXIT ERTS_PSFLG_BIT(2) +#define ERTS_PSFLG_ACTIVE ERTS_PSFLG_BIT(3) +#define ERTS_PSFLG_IN_RUNQ ERTS_PSFLG_BIT(4) +#define ERTS_PSFLG_RUNNING ERTS_PSFLG_BIT(5) +#define ERTS_PSFLG_SUSPENDED ERTS_PSFLG_BIT(6) +#define ERTS_PSFLG_GC ERTS_PSFLG_BIT(7) +#define ERTS_PSFLG_BOUND ERTS_PSFLG_BIT(8) +#define ERTS_PSFLG_TRAP_EXIT ERTS_PSFLG_BIT(9) + + /* The sequential tracing token is a tuple of size 5: * * {Flags, Label, Serial, Sender} @@ -881,9 +1036,8 @@ Eterm* erts_heap_alloc(Process* p, Uint need, Uint xtra); Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz); #endif -extern Process** process_tab; -extern Uint erts_max_processes; -extern Uint erts_process_tab_index_mask; +extern erts_smp_rwmtx_t erts_proc_tab_rwmtx; +extern erts_smp_atomic_t *erts_proc_tab; extern Uint erts_default_process_flags; extern erts_smp_rwmtx_t erts_cpu_bind_rwmtx; /* If any of the erts_system_monitor_* variables are set (enabled), @@ -911,17 +1065,13 @@ struct erts_system_profile_flags_t { unsigned int exclusive : 1; }; extern struct erts_system_profile_flags_t erts_system_profile_flags; - -#define INVALID_PID(p, pid) ((p) == NULL \ - || (p)->id != (pid) \ - || (p)->status == P_EXITING) #define IS_TRACED(p) ( (p)->tracer_proc != NIL ) #define ARE_TRACE_FLAGS_ON(p,tf) ( ((p)->trace_flags & (tf|F_SENSITIVE)) == (tf) ) #define IS_TRACED_FL(p,tf) ( IS_TRACED(p) && ARE_TRACE_FLAGS_ON(p,tf) ) /* process flags */ -#define F_TRAPEXIT (1 << 0) +#define F_HIBERNATE_SCHED (1 << 0) /* Schedule out after hibernate op */ #define F_INSLPQUEUE (1 << 1) /* Set if in timer queue */ #define F_TIMO (1 << 2) /* Set if timeout */ #define F_HEAP_GROW (1 << 3) @@ -932,7 +1082,6 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; #define F_HAVE_BLCKD_MSCHED (1 << 8) /* Process has blocked multi-scheduling */ #define F_P2PNR_RESCHED (1 << 9) /* Process has been rescheduled via erts_pid2proc_not_running() */ #define F_FORCE_GC (1 << 10) /* Force gc at process in-scheduling */ -#define F_HIBERNATE_SCHED (1 << 11) /* Schedule out after hibernate op */ /* process trace_flags */ #define F_SENSITIVE (1 << 0) @@ -999,67 +1148,10 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; #define DT_UTAG_FLAGS(P) ((P)->dt_utag_flags) #endif - -#ifdef ERTS_SMP -/* Status flags ... */ -#define ERTS_PROC_SFLG_PENDADD2SCHEDQ (((Uint32) 1) << 0) /* Pending - add to - schedule q */ -#define ERTS_PROC_SFLG_INRUNQ (((Uint32) 1) << 1) /* Process is - in run q */ -#define ERTS_PROC_SFLG_TRAPEXIT (((Uint32) 1) << 2) /* Process is - trapping - exit */ -#define ERTS_PROC_SFLG_RUNNING (((Uint32) 1) << 3) /* Process is - running */ -/* Scheduler flags in process struct... */ -#define ERTS_PROC_RUNQ_FLG_RUNNING (((Uint32) 1) << 0) /* Process is - running */ - -#endif - - -#ifdef ERTS_SMP -#define ERTS_PROC_IS_TRAPPING_EXITS(P) \ - (ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks((P)) \ - & ERTS_PROC_LOCK_STATUS), \ - (P)->status_flags & ERTS_PROC_SFLG_TRAPEXIT) - -#define ERTS_PROC_SET_TRAP_EXIT(P) \ - (ERTS_SMP_LC_ASSERT(((ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS) \ - & erts_proc_lc_my_proc_locks((P))) \ - == (ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS)), \ - (P)->status_flags |= ERTS_PROC_SFLG_TRAPEXIT, \ - (P)->flags |= F_TRAPEXIT, \ - 1) - -#define ERTS_PROC_UNSET_TRAP_EXIT(P) \ - (ERTS_SMP_LC_ASSERT(((ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS) \ - & erts_proc_lc_my_proc_locks((P))) \ - == (ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS)), \ - (P)->status_flags &= ~ERTS_PROC_SFLG_TRAPEXIT, \ - (P)->flags &= ~F_TRAPEXIT, \ - 0) -#else -#define ERTS_PROC_IS_TRAPPING_EXITS(P) ((P)->flags & F_TRAPEXIT) -#define ERTS_PROC_SET_TRAP_EXIT(P) ((P)->flags |= F_TRAPEXIT, 1) -#define ERTS_PROC_UNSET_TRAP_EXIT(P) ((P)->flags &= ~F_TRAPEXIT, 0) -#endif - /* Option flags to erts_send_exit_signal() */ #define ERTS_XSIG_FLG_IGN_KILL (((Uint32) 1) << 0) #define ERTS_XSIG_FLG_NO_IGN_NORMAL (((Uint32) 1) << 1) - -/* Process status values */ -#define P_FREE 0 -#define P_RUNABLE 1 -#define P_WAITING 2 -#define P_RUNNING 3 -#define P_EXITING 4 -#define P_GARBING 5 -#define P_SUSPENDED 6 - #define CANCEL_TIMER(p) \ do { \ if ((p)->flags & (F_INSLPQUEUE)) \ @@ -1081,6 +1173,9 @@ void erts_early_init_scheduling(int); void erts_init_scheduling(int, int); Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable); +Uint64 erts_get_proc_interval(void); +Uint64 erts_ensure_later_proc_interval(Uint64); +Uint64 erts_step_proc_interval(void); ErtsProcList *erts_proclist_create(Process *); void erts_proclist_destroy(ErtsProcList *); @@ -1090,6 +1185,10 @@ int erts_sched_set_wakeup_other_thresold(char *str); int erts_sched_set_wakeup_other_type(char *str); int erts_sched_set_busy_wait_threshold(char *str); +void erts_schedule_thr_prgr_later_op(void (*)(void *), + void *, + ErtsThrPrgrLaterOp *); + #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) int erts_dbg_check_halloc_lock(Process *p); #endif @@ -1116,6 +1215,10 @@ void erts_smp_notify_check_children_needed(void); #if ERTS_USE_ASYNC_READY_Q void erts_notify_check_async_ready_queue(void *); #endif +#ifdef ERTS_SMP +void erts_notify_code_ix_activation(Process* p, ErtsThrPrgrVal later); +void erts_notify_finish_breakpointing(Process* p); +#endif void erts_schedule_misc_aux_work(int sched_id, void (*func)(void *), void *arg); @@ -1136,14 +1239,6 @@ Eterm erts_get_schedulers_binds(Process *c_p); Eterm erts_set_cpu_topology(Process *c_p, Eterm term); Eterm erts_bind_schedulers(Process *c_p, Eterm how); ErtsRunQueue *erts_schedid2runq(Uint); -#ifdef ERTS_SMP -ErtsMigrateResult erts_proc_migrate(Process *, - ErtsProcLocks *, - ErtsRunQueue *, - int *, - ErtsRunQueue *, - int *); -#endif Process *schedule(Process*, int); void erts_schedule_misc_op(void (*)(void *), void *); Eterm erl_create_process(Process*, Eterm, Eterm, Eterm, ErlSpawnOpts*); @@ -1192,8 +1287,7 @@ int erts_send_exit_signal(Process *, #ifdef ERTS_SMP void erts_handle_pending_exit(Process *, ErtsProcLocks); #define ERTS_PROC_PENDING_EXIT(P) \ - (ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks((P)) & ERTS_PROC_LOCK_STATUS),\ - (P)->pending_exit.reason != THE_NON_VALUE) + (ERTS_PSFLG_PENDING_EXIT & erts_smp_atomic32_read_acqb(&(P)->state)) #else #define ERTS_PROC_PENDING_EXIT(P) 0 #endif @@ -1245,13 +1339,26 @@ ErtsSchedulerData *erts_get_scheduler_data(void) #endif #endif +void erts_schedule_process(Process *, erts_aint32_t); + +ERTS_GLB_INLINE void erts_proc_notify_new_message(Process *p); +#if ERTS_GLB_INLINE_INCL_FUNC_DEF +ERTS_GLB_INLINE void +erts_proc_notify_new_message(Process *p) +{ + /* No barrier needed, due to msg lock */ + erts_aint32_t state = erts_smp_atomic32_read_nob(&p->state); + if (!(state & ERTS_PSFLG_ACTIVE)) + erts_schedule_process(p, state); +} +#endif + #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) #define ERTS_PROCESS_LOCK_ONLY_LOCK_CHECK_PROTO__ #include "erl_process_lock.h" #undef ERTS_PROCESS_LOCK_ONLY_LOCK_CHECK_PROTO__ -int erts_smp_lc_runq_is_locked(ErtsRunQueue *); #define ERTS_SMP_LC_CHK_RUNQ_LOCK(RQ, L) \ do { \ if ((L)) \ @@ -1377,13 +1484,91 @@ erts_proc_set_error_handler(Process *p, ErtsProcLocks plocks, Eterm handler) #endif +#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS + #ifdef ERTS_SMP -ErtsRunQueue *erts_prepare_emigrate(ErtsRunQueue *c_rq, - ErtsRunQueueInfo *c_rqi, - int prio); +#include "erl_thr_progress.h" + +extern erts_atomic_t erts_migration_paths; + +ERTS_GLB_INLINE ErtsMigrationPaths *erts_get_migration_paths_managed(void); +ERTS_GLB_INLINE ErtsMigrationPaths *erts_get_migration_paths(void); ERTS_GLB_INLINE ErtsRunQueue *erts_check_emigration_need(ErtsRunQueue *c_rq, int prio); +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE ErtsMigrationPaths * +erts_get_migration_paths_managed(void) +{ + return (ErtsMigrationPaths *) erts_atomic_read_ddrb(&erts_migration_paths); +} + +ERTS_GLB_INLINE ErtsMigrationPaths * +erts_get_migration_paths(void) +{ + if (erts_thr_progress_is_managed_thread()) + return erts_get_migration_paths_managed(); + else + return NULL; +} + +ERTS_GLB_INLINE ErtsRunQueue * +erts_check_emigration_need(ErtsRunQueue *c_rq, int prio) +{ + ErtsMigrationPaths *mps = erts_get_migration_paths(); + ErtsMigrationPath *mp; + Uint32 flags; + + if (!mps) + return NULL; + + mp = &mps->mpath[c_rq->ix]; + flags = mp->flags; + + if (ERTS_CHK_RUNQ_FLG_EMIGRATE(flags, prio)) { + int len; + + if (ERTS_CHK_RUNQ_FLG_EVACUATE(flags, prio)) { + /* force emigration */ + return mp->prio[prio].runq; + } + + if (flags & ERTS_RUNQ_FLG_INACTIVE) { + /* + * Run queue was inactive at last balance. Verify that + * it still is before forcing emigration. + */ + if (ERTS_RUNQ_FLGS_GET(c_rq) & ERTS_RUNQ_FLG_INACTIVE) + return mp->prio[prio].runq; + } + + + if (prio == ERTS_PORT_PRIO_LEVEL) + len = RUNQ_READ_LEN(&c_rq->ports.info.len); + else + len = RUNQ_READ_LEN(&c_rq->procs.prio_info[prio].len); + + if (len > mp->prio[prio].limit.this) { + ErtsRunQueue *n_rq = mp->prio[prio].runq; + if (n_rq) { + if (prio == ERTS_PORT_PRIO_LEVEL) + len = RUNQ_READ_LEN(&n_rq->ports.info.len); + else + len = RUNQ_READ_LEN(&n_rq->procs.prio_info[prio].len); + + if (len < mp->prio[prio].limit.other) + return n_rq; + } + } + } + return NULL; +} + +#endif + +#endif + #endif ERTS_GLB_INLINE int erts_is_scheduler_bound(ErtsSchedulerData *esdp); @@ -1406,29 +1591,6 @@ ERTS_GLB_INLINE void erts_smp_runqs_unlock(ErtsRunQueue *rq1, ErtsRunQueue *rq2) #if ERTS_GLB_INLINE_INCL_FUNC_DEF -#ifdef ERTS_SMP -ERTS_GLB_INLINE ErtsRunQueue * -erts_check_emigration_need(ErtsRunQueue *c_rq, int prio) -{ - ErtsRunQueueInfo *c_rqi; - - if (!ERTS_CHK_RUNQ_FLG_EMIGRATE(c_rq->flags, prio)) - return NULL; - - if (prio == ERTS_PORT_PRIO_LEVEL) - c_rqi = &c_rq->ports.info; - else - c_rqi = &c_rq->procs.prio_info[prio]; - - if (!ERTS_CHK_RUNQ_FLG_EVACUATE(c_rq->flags, prio) - && !(c_rq->flags & ERTS_RUNQ_FLG_INACTIVE) - && c_rqi->len <= c_rqi->migrate.limit.this) - return NULL; - - return erts_prepare_emigrate(c_rq, c_rqi, prio); -} -#endif - ERTS_GLB_INLINE int erts_is_scheduler_bound(ErtsSchedulerData *esdp) { @@ -1466,10 +1628,9 @@ Uint erts_get_scheduler_id(void) ERTS_GLB_INLINE ErtsRunQueue * erts_get_runq_proc(Process *p) { - ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); #ifdef ERTS_SMP - ASSERT(p->run_queue); - return p->run_queue; + ASSERT(ERTS_AINT_NULL != erts_atomic_read_nob(&p->run_queue)); + return (ErtsRunQueue *) erts_atomic_read_nob(&p->run_queue); #else return ERTS_RUNQ_IX(0); #endif @@ -1640,25 +1801,13 @@ extern int erts_disable_proc_not_running_opt; #ifdef DEBUG #define ERTS_SMP_ASSERT_IS_NOT_EXITING(P) \ - do { ASSERT(!(P)->is_exiting); } while (0) + do { ASSERT(!ERTS_PROC_IS_EXITING((P))); } while (0) #else #define ERTS_SMP_ASSERT_IS_NOT_EXITING(P) #endif -/* NOTE: At least one process lock has to be held on P! */ -#ifdef ERTS_ENABLE_LOCK_CHECK -#define ERTS_PROC_IS_EXITING(P) \ - (ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks((P)) != 0 \ - || erts_lc_pix_lock_is_locked(ERTS_PID2PIXLOCK((P)->id))),\ - (P)->is_exiting) -#else -#define ERTS_PROC_IS_EXITING(P) ((P)->is_exiting) -#endif - #else /* !ERTS_SMP */ -#define ERTS_PROC_IS_EXITING(P) ((P)->status == P_EXITING) - #define ERTS_SMP_ASSERT_IS_NOT_EXITING(P) #define erts_pid2proc_not_running erts_pid2proc @@ -1666,6 +1815,10 @@ extern int erts_disable_proc_not_running_opt; #endif +#define ERTS_PROC_IS_EXITING(P) \ + (ERTS_PSFLG_EXITING & erts_smp_atomic32_read_acqb(&(P)->state)) + + /* Minimum NUMBER of processes for a small system to start */ #ifdef ERTS_SMP #define ERTS_MIN_PROCESSES ERTS_NO_OF_PIX_LOCKS diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c index 3550f1396c..964dc1ae3e 100644 --- a/erts/emulator/beam/erl_process_dump.c +++ b/erts/emulator/beam/erl_process_dump.c @@ -65,14 +65,11 @@ erts_deep_process_dump(int to, void *to_arg) all_binaries = NULL; for (i = 0; i < erts_max_processes; i++) { - if ((process_tab[i] != NULL) && (process_tab[i]->i != ENULL)) { - if (process_tab[i]->status != P_EXITING) { - Process* p = process_tab[i]; - - if (p->status != P_GARBING) { - dump_process_info(to, to_arg, p); - } - } + Process *p = erts_pix2proc(i); + if (p && p->i != ENULL) { + erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state); + if (!(state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_GC))) + dump_process_info(to, to_arg, p); } } diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c index 34d591df40..aabeeca87a 100644 --- a/erts/emulator/beam/erl_process_lock.c +++ b/erts/emulator/beam/erl_process_lock.c @@ -67,10 +67,12 @@ #include "erl_process.h" -const Process erts_proc_lock_busy; +const Process erts_proc_lock_busy = {ERTS_INVALID_PID}; #ifdef ERTS_SMP +#if ERTS_PROC_LOCK_OWN_IMPL + #define ERTS_PROC_LOCK_SPIN_COUNT_MAX 2000 #define ERTS_PROC_LOCK_SPIN_COUNT_SCHED_INC 32 #define ERTS_PROC_LOCK_SPIN_COUNT_BASE 1000 @@ -90,6 +92,13 @@ static void check_queue(erts_proc_lock_t *lck); #error "The size of the 'uflgs' field of the erts_tse_t type is too small" #endif +static int proc_lock_spin_count; +static int aux_thr_proc_lock_spin_count; + +static void cleanup_tse(void); + +#endif /* ERTS_PROC_LOCK_OWN_IMPL */ + #ifdef ERTS_ENABLE_LOCK_CHECK static struct { Sint16 proc_lock_main; @@ -101,10 +110,6 @@ static struct { erts_pix_lock_t erts_pix_locks[ERTS_NO_OF_PIX_LOCKS]; -static int proc_lock_spin_count; -static int aux_thr_proc_lock_spin_count; - -static void cleanup_tse(void); void erts_init_proc_lock(int cpus) @@ -118,13 +123,8 @@ erts_init_proc_lock(int cpus) erts_mtx_init(&erts_pix_locks[i].u.mtx, "pix_lock"); #endif } +#if ERTS_PROC_LOCK_OWN_IMPL erts_thr_install_exit_handler(cleanup_tse); -#ifdef ERTS_ENABLE_LOCK_CHECK - lc_id.proc_lock_main = erts_lc_get_lock_order_id("proc_main"); - lc_id.proc_lock_link = erts_lc_get_lock_order_id("proc_link"); - lc_id.proc_lock_msgq = erts_lc_get_lock_order_id("proc_msgq"); - lc_id.proc_lock_status = erts_lc_get_lock_order_id("proc_status"); -#endif if (cpus > 1) { proc_lock_spin_count = ERTS_PROC_LOCK_SPIN_COUNT_BASE; proc_lock_spin_count += (ERTS_PROC_LOCK_SPIN_COUNT_SCHED_INC @@ -141,8 +141,17 @@ erts_init_proc_lock(int cpus) } if (proc_lock_spin_count > ERTS_PROC_LOCK_SPIN_COUNT_MAX) proc_lock_spin_count = ERTS_PROC_LOCK_SPIN_COUNT_MAX; +#endif +#ifdef ERTS_ENABLE_LOCK_CHECK + lc_id.proc_lock_main = erts_lc_get_lock_order_id("proc_main"); + lc_id.proc_lock_link = erts_lc_get_lock_order_id("proc_link"); + lc_id.proc_lock_msgq = erts_lc_get_lock_order_id("proc_msgq"); + lc_id.proc_lock_status = erts_lc_get_lock_order_id("proc_status"); +#endif } +#if ERTS_PROC_LOCK_OWN_IMPL + #ifdef ERTS_ENABLE_LOCK_CHECK #define CHECK_UNUSED_TSE(W) ERTS_LC_ASSERT((W)->uflgs == 0) #else @@ -164,13 +173,6 @@ tse_return(erts_tse_t *tse) erts_tse_return(tse); } -void -erts_proc_lock_prepare_proc_lock_waiter(void) -{ - tse_return(tse_fetch(NULL)); -} - - static void cleanup_tse(void) { @@ -560,6 +562,16 @@ erts_proc_unlock_failed(Process *p, transfer_locks(p, wait_locks, pix_lock, 1); /* unlocks pix_lock */ } +#endif /* ERTS_PROC_LOCK_OWN_IMPL */ + +void +erts_proc_lock_prepare_proc_lock_waiter(void) +{ +#if ERTS_PROC_LOCK_OWN_IMPL + tse_return(tse_fetch(NULL)); +#endif +} + /* * proc_safelock() locks process locks on two processes. In order * to avoid a deadlock, proc_safelock() unlocks those locks that @@ -568,12 +580,11 @@ erts_proc_unlock_failed(Process *p, */ static void -proc_safelock(Process *a_proc, - erts_pix_lock_t *a_pix_lck, +proc_safelock(int is_sched, + Process *a_proc, ErtsProcLocks a_have_locks, ErtsProcLocks a_need_locks, Process *b_proc, - erts_pix_lock_t *b_pix_lck, ErtsProcLocks b_have_locks, ErtsProcLocks b_need_locks) { @@ -581,7 +592,6 @@ proc_safelock(Process *a_proc, #ifdef ERTS_ENABLE_LOCK_CHECK Eterm pid1, pid2; #endif - erts_pix_lock_t *pix_lck1, *pix_lck2; ErtsProcLocks need_locks1, have_locks1, need_locks2, have_locks2; ErtsProcLocks unlock_mask; int lock_no, refc1 = 0, refc2 = 0; @@ -598,14 +608,12 @@ proc_safelock(Process *a_proc, #ifdef ERTS_ENABLE_LOCK_CHECK pid1 = a_proc->id; #endif - pix_lck1 = a_pix_lck; need_locks1 = a_need_locks; have_locks1 = a_have_locks; p2 = b_proc; #ifdef ERTS_ENABLE_LOCK_CHECK pid2 = b_proc->id; #endif - pix_lck2 = b_pix_lck; need_locks2 = b_need_locks; have_locks2 = b_have_locks; } @@ -614,14 +622,12 @@ proc_safelock(Process *a_proc, #ifdef ERTS_ENABLE_LOCK_CHECK pid1 = b_proc->id; #endif - pix_lck1 = b_pix_lck; need_locks1 = b_need_locks; have_locks1 = b_have_locks; p2 = a_proc; #ifdef ERTS_ENABLE_LOCK_CHECK pid2 = a_proc->id; #endif - pix_lck2 = a_pix_lck; need_locks2 = a_need_locks; have_locks2 = a_have_locks; } @@ -632,14 +638,12 @@ proc_safelock(Process *a_proc, #ifdef ERTS_ENABLE_LOCK_CHECK pid1 = a_proc->id; #endif - pix_lck1 = a_pix_lck; need_locks1 = a_need_locks | b_need_locks; have_locks1 = a_have_locks | b_have_locks; p2 = NULL; #ifdef ERTS_ENABLE_LOCK_CHECK pid2 = 0; #endif - pix_lck2 = NULL; need_locks2 = 0; have_locks2 = 0; } @@ -649,14 +653,12 @@ proc_safelock(Process *a_proc, #ifdef ERTS_ENABLE_LOCK_CHECK pid1 = b_proc->id; #endif - pix_lck1 = b_pix_lck; need_locks1 = b_need_locks; have_locks1 = b_have_locks; p2 = NULL; #ifdef ERTS_ENABLE_LOCK_CHECK pid2 = 0; #endif - pix_lck2 = NULL; need_locks2 = 0; have_locks2 = 0; #ifdef ERTS_ENABLE_LOCK_CHECK @@ -704,21 +706,21 @@ proc_safelock(Process *a_proc, if (unlock_locks) { have_locks1 &= ~unlock_locks; need_locks1 |= unlock_locks; - if (!have_locks1) { + if (!is_sched && !have_locks1) { refc1 = 1; erts_smp_proc_inc_refc(p1); } - erts_smp_proc_unlock__(p1, pix_lck1, unlock_locks); + erts_smp_proc_unlock(p1, unlock_locks); } unlock_locks = unlock_mask & have_locks2; if (unlock_locks) { have_locks2 &= ~unlock_locks; need_locks2 |= unlock_locks; - if (!have_locks2) { + if (!is_sched && !have_locks2) { refc2 = 1; erts_smp_proc_inc_refc(p2); } - erts_smp_proc_unlock__(p2, pix_lck2, unlock_locks); + erts_smp_proc_unlock(p2, unlock_locks); } } @@ -749,7 +751,7 @@ proc_safelock(Process *a_proc, if (need_locks2 & lock) lock_no--; locks = need_locks1 & lock_mask; - erts_smp_proc_lock__(p1, pix_lck1, locks); + erts_smp_proc_lock(p1, locks); have_locks1 |= locks; need_locks1 &= ~locks; } @@ -760,7 +762,7 @@ proc_safelock(Process *a_proc, lock = (1 << ++lock_no); } locks = need_locks2 & lock_mask; - erts_smp_proc_lock__(p2, pix_lck2, locks); + erts_smp_proc_lock(p2, locks); have_locks2 |= locks; need_locks2 &= ~locks; } @@ -795,10 +797,12 @@ proc_safelock(Process *a_proc, } #endif - if (refc1) - erts_smp_proc_dec_refc(p1); - if (refc2) - erts_smp_proc_dec_refc(p2); + if (!is_sched) { + if (refc1) + erts_smp_proc_dec_refc(p1); + if (refc2) + erts_smp_proc_dec_refc(p2); + } } void @@ -809,77 +813,191 @@ erts_proc_safelock(Process *a_proc, ErtsProcLocks b_have_locks, ErtsProcLocks b_need_locks) { - proc_safelock(a_proc, - a_proc ? ERTS_PID2PIXLOCK(a_proc->id) : NULL, + proc_safelock(erts_get_scheduler_id() != 0, + a_proc, a_have_locks, a_need_locks, b_proc, - b_proc ? ERTS_PID2PIXLOCK(b_proc->id) : NULL, b_have_locks, b_need_locks); } -/* - * erts_pid2proc_safelock() is called from erts_pid2proc_opt() when - * it wasn't possible to trylock all locks needed. - * c_p - current process - * c_p_have_locks - locks held on c_p - * pid - process id of process we are looking up - * proc - process struct of process we are looking - * up (both in and out argument) - * need_locks - all locks we need (including have_locks) - * pix_lock - pix lock for process we are looking up - * flags - option flags - */ -void -erts_pid2proc_safelock(Process *c_p, - ErtsProcLocks c_p_have_locks, - Process **proc, - ErtsProcLocks need_locks, - erts_pix_lock_t *pix_lock, - int flags) +Process * +erts_pid2proc_opt(Process *c_p, + ErtsProcLocks c_p_have_locks, + Eterm pid, + ErtsProcLocks pid_need_locks, + int flags) { - Process *p = *proc; - ERTS_LC_ASSERT(p->lock.refc > 0); - ERTS_LC_ASSERT(process_tab[internal_pid_index(p->id)] == p); - p->lock.refc++; - erts_pix_unlock(pix_lock); - - proc_safelock(c_p, - c_p ? ERTS_PID2PIXLOCK(c_p->id) : NULL, - c_p_have_locks, - c_p_have_locks, - p, - pix_lock, - 0, - need_locks); + Process *dec_refc_proc = NULL; + int need_ptl; + ErtsProcLocks need_locks; + Uint pix; + Process *proc; +#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_ENABLE_LOCK_COUNT) + ErtsProcLocks lcnt_locks; +#endif - erts_pix_lock(pix_lock); +#ifdef ERTS_ENABLE_LOCK_CHECK + if (c_p) { + ErtsProcLocks might_unlock = c_p_have_locks & pid_need_locks; + if (might_unlock) + erts_proc_lc_might_unlock(c_p, might_unlock); + } +#endif - if (!p->is_exiting - || ((flags & ERTS_P2P_FLG_ALLOW_OTHER_X) - && process_tab[internal_pid_index(p->id)] == p)) { - ERTS_LC_ASSERT(p->lock.refc > 1); - p->lock.refc--; + if (is_not_internal_pid(pid)) + return NULL; + pix = internal_pid_index(pid); + + ERTS_LC_ASSERT((pid_need_locks & ERTS_PROC_LOCKS_ALL) == pid_need_locks); + need_locks = pid_need_locks; + + if (c_p && c_p->id == pid) { + ASSERT(c_p->id != ERTS_INVALID_PID); + ASSERT(c_p == erts_pix2proc(pix)); + + if (!(flags & ERTS_P2P_FLG_ALLOW_OTHER_X) + && ERTS_PROC_IS_EXITING(c_p)) + return NULL; + need_locks &= ~c_p_have_locks; + if (!need_locks) { + if (flags & ERTS_P2P_FLG_SMP_INC_REFC) + erts_smp_proc_inc_refc(c_p); + return c_p; + } } - else { - /* No proc. Note, we need to keep refc until after process unlock */ - erts_pix_unlock(pix_lock); - erts_smp_proc_unlock__(p, pix_lock, need_locks); - *proc = NULL; - erts_pix_lock(pix_lock); - ERTS_LC_ASSERT(p->lock.refc > 0); - if (--p->lock.refc == 0) { - erts_pix_unlock(pix_lock); - erts_free_proc(p); - erts_pix_lock(pix_lock); + + need_ptl = !erts_get_scheduler_id(); + + if (need_ptl) + erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx); + + proc = (Process *) erts_smp_atomic_read_ddrb(&erts_proc.tab[pix]); + + if (proc) { + if (proc->id != pid) + proc = NULL; + else if (!need_locks) { + if (flags & ERTS_P2P_FLG_SMP_INC_REFC) + erts_smp_proc_inc_refc(proc); } + else { + int busy; + +#if ERTS_PROC_LOCK_OWN_IMPL +#ifdef ERTS_ENABLE_LOCK_COUNT + lcnt_locks = need_locks; + if (!(flags & ERTS_P2P_FLG_TRY_LOCK)) { + erts_lcnt_proc_lock(&proc->lock, need_locks); + } +#endif + +#ifdef ERTS_ENABLE_LOCK_CHECK + /* Make sure erts_pid2proc_safelock() is enough to handle + a potential lock order violation situation... */ + busy = erts_proc_lc_trylock_force_busy(proc, need_locks); + if (!busy) +#endif +#endif /* ERTS_PROC_LOCK_OWN_IMPL */ + { + /* Try a quick trylock to grab all the locks we need. */ + busy = (int) erts_smp_proc_raw_trylock__(proc, need_locks); + +#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_ENABLE_LOCK_CHECK) + erts_proc_lc_trylock(proc, need_locks, !busy); +#endif +#ifdef ERTS_PROC_LOCK_DEBUG + if (!busy) + erts_proc_lock_op_debug(proc, need_locks, 1); +#endif + } + +#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_ENABLE_LOCK_COUNT) + if (flags & ERTS_P2P_FLG_TRY_LOCK) + erts_lcnt_proc_trylock(&proc->lock, need_locks, + busy ? EBUSY : 0); +#endif + + if (!busy) { + if (flags & ERTS_P2P_FLG_SMP_INC_REFC) + erts_smp_proc_inc_refc(proc); + +#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_ENABLE_LOCK_COUNT) + /* all is great */ + if (!(flags & ERTS_P2P_FLG_TRY_LOCK)) + erts_lcnt_proc_lock_post_x(&proc->lock, lcnt_locks, + __FILE__, __LINE__); +#endif + + } + else { + if (flags & ERTS_P2P_FLG_TRY_LOCK) + proc = ERTS_PROC_LOCK_BUSY; + else { + if (flags & ERTS_P2P_FLG_SMP_INC_REFC) + erts_smp_proc_inc_refc(proc); + +#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_ENABLE_LOCK_COUNT) + erts_lcnt_proc_lock_unaquire(&proc->lock, lcnt_locks); +#endif + + if (need_ptl) { + erts_smp_proc_inc_refc(proc); + dec_refc_proc = proc; + erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx); + need_ptl = 0; + } + + proc_safelock(!need_ptl, + c_p, + c_p_have_locks, + c_p_have_locks, + proc, + 0, + need_locks); + } + } + } } + + if (need_ptl) + erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx); + + if (need_locks + && proc + && proc != ERTS_PROC_LOCK_BUSY + && (!(flags & ERTS_P2P_FLG_ALLOW_OTHER_X) + ? ERTS_PROC_IS_EXITING(proc) + : (proc + != (Process *) erts_smp_atomic_read_nob(&erts_proc.tab[pix])))) { + + erts_smp_proc_unlock(proc, need_locks); + + if (flags & ERTS_P2P_FLG_SMP_INC_REFC) + dec_refc_proc = proc; + proc = NULL; + + } + + if (dec_refc_proc) + erts_smp_proc_dec_refc(dec_refc_proc); + +#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_PROC_LOCK_DEBUG) + ERTS_LC_ASSERT(!proc + || proc == ERTS_PROC_LOCK_BUSY + || (pid_need_locks == + (ERTS_PROC_LOCK_FLGS_READ_(&proc->lock) + & pid_need_locks))); +#endif + + return proc; } void erts_proc_lock_init(Process *p) { +#if ERTS_PROC_LOCK_OWN_IMPL int i; /* We always start with all locks locked */ #if ERTS_PROC_LOCK_ATOMIC_IMPL @@ -890,25 +1008,60 @@ erts_proc_lock_init(Process *p) #endif for (i = 0; i <= ERTS_PROC_LOCK_MAX_BIT; i++) p->lock.queue[i] = NULL; - p->lock.refc = 1; -#ifdef ERTS_ENABLE_LOCK_COUNT - erts_lcnt_proc_lock_init(p); - erts_lcnt_proc_lock(&(p->lock), ERTS_PROC_LOCKS_ALL); - erts_lcnt_proc_lock_post_x(&(p->lock), ERTS_PROC_LOCKS_ALL, __FILE__, __LINE__); -#endif - #ifdef ERTS_ENABLE_LOCK_CHECK erts_proc_lc_trylock(p, ERTS_PROC_LOCKS_ALL, 1); #endif +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + erts_mtx_init_x(&p->lock.main, "proc_main", p->id); + ethr_mutex_lock(&p->lock.main.mtx); +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_lc_trylock(1, &p->lock.main.lc); +#endif + erts_mtx_init_x(&p->lock.link, "proc_link", p->id); + ethr_mutex_lock(&p->lock.link.mtx); +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_lc_trylock(1, &p->lock.link.lc); +#endif + erts_mtx_init_x(&p->lock.msgq, "proc_msgq", p->id); + ethr_mutex_lock(&p->lock.msgq.mtx); +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_lc_trylock(1, &p->lock.msgq.lc); +#endif + erts_mtx_init_x(&p->lock.status, "proc_status", p->id); + ethr_mutex_lock(&p->lock.status.mtx); +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_lc_trylock(1, &p->lock.status.lc); +#endif +#endif + erts_atomic32_init_nob(&p->lock.refc, 1); #ifdef ERTS_PROC_LOCK_DEBUG for (i = 0; i <= ERTS_PROC_LOCK_MAX_BIT; i++) erts_smp_atomic32_init_nob(&p->lock.locked[i], (erts_aint32_t) 1); #endif +#ifdef ERTS_ENABLE_LOCK_COUNT + erts_lcnt_proc_lock_init(p); + erts_lcnt_proc_lock(&(p->lock), ERTS_PROC_LOCKS_ALL); + erts_lcnt_proc_lock_post_x(&(p->lock), ERTS_PROC_LOCKS_ALL, __FILE__, __LINE__); +#endif +} + +void +erts_proc_lock_fin(Process *p) +{ +#if ERTS_PROC_LOCK_RAW_MUTEX_IMPL + erts_mtx_destroy(&p->lock.main); + erts_mtx_destroy(&p->lock.link); + erts_mtx_destroy(&p->lock.msgq); + erts_mtx_destroy(&p->lock.status); +#endif +#if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP) + erts_lcnt_proc_lock_destroy(p); +#endif } /* --- Process lock counting ----------------------------------------------- */ -#ifdef ERTS_ENABLE_LOCK_COUNT +#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_ENABLE_LOCK_COUNT) void erts_lcnt_proc_lock_init(Process *p) { if (erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK) { if (p->id != ERTS_INVALID_PID) { @@ -1027,7 +1180,7 @@ void erts_lcnt_enable_proc_lock_count(int enable) { int i; for (i = 0; i < erts_max_processes; ++i) { - Process* p = process_tab[i]; + Process* p = erts_pix2proc(i); if (p) { if (enable) { if (!ERTS_LCNT_LOCK_TYPE(&(p->lock.lcnt_main))) { @@ -1049,6 +1202,8 @@ void erts_lcnt_enable_proc_lock_count(int enable) { #ifdef ERTS_ENABLE_LOCK_CHECK +#if ERTS_PROC_LOCK_OWN_IMPL + void erts_proc_lc_lock(Process *p, ErtsProcLocks locks) { @@ -1121,9 +1276,12 @@ erts_proc_lc_unlock(Process *p, ErtsProcLocks locks) } } +#endif /* ERTS_PROC_LOCK_OWN_IMPL */ + void erts_proc_lc_might_unlock(Process *p, ErtsProcLocks locks) { +#if ERTS_PROC_LOCK_OWN_IMPL erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1, p->id, ERTS_LC_FLG_LT_PROCLOCK); @@ -1143,11 +1301,22 @@ erts_proc_lc_might_unlock(Process *p, ErtsProcLocks locks) lck.id = lc_id.proc_lock_main; erts_lc_might_unlock(&lck); } +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + if (locks & ERTS_PROC_LOCK_MAIN) + erts_lc_might_unlock(&p->lock.main.lc); + if (locks & ERTS_PROC_LOCK_LINK) + erts_lc_might_unlock(&p->lock.link.lc); + if (locks & ERTS_PROC_LOCK_MSGQ) + erts_lc_might_unlock(&p->lock.msgq.lc); + if (locks & ERTS_PROC_LOCK_STATUS) + erts_lc_might_unlock(&p->lock.status.lc); +#endif } void erts_proc_lc_require_lock(Process *p, ErtsProcLocks locks) { +#if ERTS_PROC_LOCK_OWN_IMPL erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1, p->id, ERTS_LC_FLG_LT_PROCLOCK); @@ -1167,11 +1336,22 @@ erts_proc_lc_require_lock(Process *p, ErtsProcLocks locks) lck.id = lc_id.proc_lock_status; erts_lc_require_lock(&lck); } +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + if (locks & ERTS_PROC_LOCK_MAIN) + erts_lc_require_lock(&p->lock.main.lc); + if (locks & ERTS_PROC_LOCK_LINK) + erts_lc_require_lock(&p->lock.link.lc); + if (locks & ERTS_PROC_LOCK_MSGQ) + erts_lc_require_lock(&p->lock.msgq.lc); + if (locks & ERTS_PROC_LOCK_STATUS) + erts_lc_require_lock(&p->lock.status.lc); +#endif } void erts_proc_lc_unrequire_lock(Process *p, ErtsProcLocks locks) { +#if ERTS_PROC_LOCK_OWN_IMPL erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1, p->id, ERTS_LC_FLG_LT_PROCLOCK); @@ -1191,8 +1371,19 @@ erts_proc_lc_unrequire_lock(Process *p, ErtsProcLocks locks) lck.id = lc_id.proc_lock_main; erts_lc_unrequire_lock(&lck); } +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + if (locks & ERTS_PROC_LOCK_MAIN) + erts_lc_unrequire_lock(&p->lock.main.lc); + if (locks & ERTS_PROC_LOCK_LINK) + erts_lc_unrequire_lock(&p->lock.link.lc); + if (locks & ERTS_PROC_LOCK_MSGQ) + erts_lc_unrequire_lock(&p->lock.msgq.lc); + if (locks & ERTS_PROC_LOCK_STATUS) + erts_lc_unrequire_lock(&p->lock.status.lc); +#endif } +#if ERTS_PROC_LOCK_OWN_IMPL int erts_proc_lc_trylock_force_busy(Process *p, ErtsProcLocks locks) @@ -1218,21 +1409,30 @@ erts_proc_lc_trylock_force_busy(Process *p, ErtsProcLocks locks) return 0; } +#endif /* ERTS_PROC_LOCK_OWN_IMPL */ + void erts_proc_lc_chk_only_proc_main(Process *p) { +#if ERTS_PROC_LOCK_OWN_IMPL erts_lc_lock_t proc_main = ERTS_LC_LOCK_INIT(lc_id.proc_lock_main, p->id, ERTS_LC_FLG_LT_PROCLOCK); erts_lc_check_exact(&proc_main, 1); +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + erts_lc_check_exact(&p->lock.main.lc, 1); +#endif } +#if ERTS_PROC_LOCK_OWN_IMPL #define ERTS_PROC_LC_EMPTY_LOCK_INIT \ ERTS_LC_LOCK_INIT(-1, THE_NON_VALUE, ERTS_LC_FLG_LT_PROCLOCK) +#endif /* ERTS_PROC_LOCK_OWN_IMPL */ void erts_proc_lc_chk_have_proc_locks(Process *p, ErtsProcLocks locks) { int have_locks_len = 0; +#if ERTS_PROC_LOCK_OWN_IMPL erts_lc_lock_t have_locks[4] = {ERTS_PROC_LC_EMPTY_LOCK_INIT, ERTS_PROC_LC_EMPTY_LOCK_INIT, ERTS_PROC_LC_EMPTY_LOCK_INIT, @@ -1253,7 +1453,17 @@ erts_proc_lc_chk_have_proc_locks(Process *p, ErtsProcLocks locks) have_locks[have_locks_len].id = lc_id.proc_lock_status; have_locks[have_locks_len++].extra = p->id; } - +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + erts_lc_lock_t have_locks[4]; + if (locks & ERTS_PROC_LOCK_MAIN) + have_locks[have_locks_len++] = p->lock.main.lc; + if (locks & ERTS_PROC_LOCK_LINK) + have_locks[have_locks_len++] = p->lock.link.lc; + if (locks & ERTS_PROC_LOCK_MSGQ) + have_locks[have_locks_len++] = p->lock.msgq.lc; + if (locks & ERTS_PROC_LOCK_STATUS) + have_locks[have_locks_len++] = p->lock.status.lc; +#endif erts_lc_check(have_locks, have_locks_len, NULL, 0); } @@ -1262,6 +1472,7 @@ erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks) { int have_locks_len = 0; int have_not_locks_len = 0; +#if ERTS_PROC_LOCK_OWN_IMPL erts_lc_lock_t have_locks[4] = {ERTS_PROC_LC_EMPTY_LOCK_INIT, ERTS_PROC_LC_EMPTY_LOCK_INIT, ERTS_PROC_LC_EMPTY_LOCK_INIT, @@ -1303,6 +1514,27 @@ erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks) have_not_locks[have_not_locks_len].id = lc_id.proc_lock_status; have_not_locks[have_not_locks_len++].extra = p->id; } +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + erts_lc_lock_t have_locks[4]; + erts_lc_lock_t have_not_locks[4]; + + if (locks & ERTS_PROC_LOCK_MAIN) + have_locks[have_locks_len++] = p->lock.main.lc; + else + have_not_locks[have_not_locks_len++] = p->lock.main.lc; + if (locks & ERTS_PROC_LOCK_LINK) + have_locks[have_locks_len++] = p->lock.link.lc; + else + have_not_locks[have_not_locks_len++] = p->lock.link.lc; + if (locks & ERTS_PROC_LOCK_MSGQ) + have_locks[have_locks_len++] = p->lock.msgq.lc; + else + have_not_locks[have_not_locks_len++] = p->lock.msgq.lc; + if (locks & ERTS_PROC_LOCK_STATUS) + have_locks[have_locks_len++] = p->lock.status.lc; + else + have_not_locks[have_not_locks_len++] = p->lock.status.lc; +#endif erts_lc_check(have_locks, have_locks_len, have_not_locks, have_not_locks_len); @@ -1312,6 +1544,8 @@ ErtsProcLocks erts_proc_lc_my_proc_locks(Process *p) { int resv[4]; + ErtsProcLocks res = 0; +#if ERTS_PROC_LOCK_OWN_IMPL erts_lc_lock_t locks[4] = {ERTS_LC_LOCK_INIT(lc_id.proc_lock_main, p->id, ERTS_LC_FLG_LT_PROCLOCK), @@ -1324,8 +1558,12 @@ erts_proc_lc_my_proc_locks(Process *p) ERTS_LC_LOCK_INIT(lc_id.proc_lock_status, p->id, ERTS_LC_FLG_LT_PROCLOCK)}; - - ErtsProcLocks res = 0; +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + erts_lc_lock_t locks[4] = {p->lock.main.lc, + p->lock.link.lc, + p->lock.msgq.lc, + p->lock.status.lc}; +#endif erts_lc_have_locks(resv, locks, 4); if (resv[0]) @@ -1358,7 +1596,7 @@ erts_proc_lc_chk_no_proc_locks(char *file, int line) #endif /* #ifdef ERTS_ENABLE_LOCK_CHECK */ -#ifdef ERTS_PROC_LOCK_HARD_DEBUG +#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_PROC_LOCK_HARD_DEBUG) void check_queue(erts_proc_lock_t *lck) { @@ -1391,4 +1629,4 @@ check_queue(erts_proc_lock_t *lck) } #endif -#endif /* ERTS_SMP (the whole file) */ +#endif /* ERTS_SMP */ diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h index 290084d8ca..ca853bf347 100644 --- a/erts/emulator/beam/erl_process_lock.h +++ b/erts/emulator/beam/erl_process_lock.h @@ -37,10 +37,21 @@ #include "erl_smp.h" +#if defined(VALGRIND) || defined(ETHR_DISABLE_NATIVE_IMPLS) +# define ERTS_PROC_LOCK_OWN_IMPL 0 +#else +# define ERTS_PROC_LOCK_OWN_IMPL 1 +#endif + #define ERTS_PROC_LOCK_ATOMIC_IMPL 0 #define ERTS_PROC_LOCK_SPINLOCK_IMPL 0 #define ERTS_PROC_LOCK_MUTEX_IMPL 0 +#if !ERTS_PROC_LOCK_OWN_IMPL +#define ERTS_PROC_LOCK_RAW_MUTEX_IMPL 1 +#else +#define ERTS_PROC_LOCK_RAW_MUTEX_IMPL 0 + #if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) # undef ERTS_PROC_LOCK_ATOMIC_IMPL # define ERTS_PROC_LOCK_ATOMIC_IMPL 1 @@ -52,27 +63,38 @@ # define ERTS_PROC_LOCK_MUTEX_IMPL 1 #endif +#endif + #define ERTS_PROC_LOCK_MAX_BIT 3 typedef erts_aint32_t ErtsProcLocks; typedef struct erts_proc_lock_t_ { +#if ERTS_PROC_LOCK_OWN_IMPL #if ERTS_PROC_LOCK_ATOMIC_IMPL erts_smp_atomic32_t flags; #else ErtsProcLocks flags; #endif erts_tse_t *queue[ERTS_PROC_LOCK_MAX_BIT+1]; - Sint32 refc; -#ifdef ERTS_PROC_LOCK_DEBUG - erts_smp_atomic32_t locked[ERTS_PROC_LOCK_MAX_BIT+1]; -#endif #ifdef ERTS_ENABLE_LOCK_COUNT erts_lcnt_lock_t lcnt_main; erts_lcnt_lock_t lcnt_link; erts_lcnt_lock_t lcnt_msgq; erts_lcnt_lock_t lcnt_status; #endif +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + erts_mtx_t main; + erts_mtx_t link; + erts_mtx_t msgq; + erts_mtx_t status; +#else +# error "no implementation" +#endif + erts_atomic32_t refc; +#ifdef ERTS_PROC_LOCK_DEBUG + erts_smp_atomic32_t locked[ERTS_PROC_LOCK_MAX_BIT+1]; +#endif } erts_proc_lock_t; /* Process lock flags */ @@ -105,11 +127,9 @@ typedef struct erts_proc_lock_t_ { /* * Status lock: * Protects the following fields in the process structure: - * * status - * * rstatus - * * status_flags * * pending_suspenders * * suspendee + * * ... */ #define ERTS_PROC_LOCK_STATUS (((ErtsProcLocks) 1) << ERTS_PROC_LOCK_MAX_BIT) @@ -141,14 +161,11 @@ typedef struct erts_proc_lock_t_ { * Other rules regarding process locking: * * Exiting processes: - * When changing status to P_EXITING on a process, you are required - * to take all process locks (ERTS_PROC_LOCKS_ALL). Thus, by holding - * at least one process lock (whichever one doesn't matter) you - * are guaranteed that the process won't exit until the lock you are - * holding has been released. Appart from all process locks also - * the pix lock corresponding to the process has to be held. - * At the same time as status is changed to P_EXITING, also the - * field 'is_exiting' in the process structure is set to a value != 0. + * When changing state to exiting (ERTS_PSFLG_EXITING) on a process, + * you are required to take all process locks (ERTS_PROC_LOCKS_ALL). + * Thus, by holding at least one process lock (whichever one doesn't + * matter) you are guaranteed that the process won't exit until the + * lock you are holding has been released. * * Lock order: * Process locks with low numeric values has to be locked before @@ -260,12 +277,10 @@ typedef struct { } u; } erts_pix_lock_t; -#define ERTS_PIX2PIXLOCKIX(PIX) \ - ((PIX) & ((1 << ERTS_PIX_LOCKS_BITS) - 1)) -#define ERTS_PIX2PIXLOCK(PIX) \ - (&erts_pix_locks[ERTS_PIX2PIXLOCKIX((PIX))]) #define ERTS_PID2PIXLOCK(PID) \ - ERTS_PIX2PIXLOCK(internal_pid_data((PID))) + (&erts_pix_locks[(internal_pid_data((PID)) & ((1 << ERTS_PIX_LOCKS_BITS) - 1))]) + +#if ERTS_PROC_LOCK_OWN_IMPL #if ERTS_PROC_LOCK_ATOMIC_IMPL @@ -335,11 +350,13 @@ erts_proc_lock_flags_cmpxchg(erts_proc_lock_t *lck, ErtsProcLocks new, #define ERTS_PROC_LOCK_FLGS_READ_(L) ((L)->flags) #endif /* end no opt atomic ops */ +#endif /* ERTS_PROC_LOCK_OWN_IMPL */ extern erts_pix_lock_t erts_pix_locks[ERTS_NO_OF_PIX_LOCKS]; void erts_init_proc_lock(int cpus); void erts_proc_lock_prepare_proc_lock_waiter(void); +#if ERTS_PROC_LOCK_OWN_IMPL void erts_proc_lock_failed(Process *, erts_pix_lock_t *, ErtsProcLocks, @@ -347,6 +364,7 @@ void erts_proc_lock_failed(Process *, void erts_proc_unlock_failed(Process *, erts_pix_lock_t *, ErtsProcLocks); +#endif ERTS_GLB_INLINE void erts_pix_lock(erts_pix_lock_t *); ERTS_GLB_INLINE void erts_pix_unlock(erts_pix_lock_t *); @@ -410,6 +428,7 @@ ERTS_GLB_INLINE int erts_lc_pix_lock_is_locked(erts_pix_lock_t *pixlck) ERTS_GLB_INLINE ErtsProcLocks erts_smp_proc_raw_trylock__(Process *p, ErtsProcLocks locks) { +#if ERTS_PROC_LOCK_OWN_IMPL ErtsProcLocks expct_lflgs = 0; while (1) { @@ -429,8 +448,38 @@ erts_smp_proc_raw_trylock__(Process *p, ErtsProcLocks locks) /* cmpxchg failed, try again (should be rare). */ expct_lflgs = lflgs; } -} +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + + if (locks & ERTS_PROC_LOCK_MAIN) + if (erts_mtx_trylock(&p->lock.main) == EBUSY) + goto busy_main; + if (locks & ERTS_PROC_LOCK_LINK) + if (erts_mtx_trylock(&p->lock.link) == EBUSY) + goto busy_link; + if (locks & ERTS_PROC_LOCK_MSGQ) + if (erts_mtx_trylock(&p->lock.msgq) == EBUSY) + goto busy_msgq; + if (locks & ERTS_PROC_LOCK_STATUS) + if (erts_mtx_trylock(&p->lock.status) == EBUSY) + goto busy_status; + + return 0; + +busy_status: + if (locks & ERTS_PROC_LOCK_MSGQ) + erts_mtx_unlock(&p->lock.msgq); +busy_msgq: + if (locks & ERTS_PROC_LOCK_LINK) + erts_mtx_unlock(&p->lock.link); +busy_link: + if (locks & ERTS_PROC_LOCK_MAIN) + erts_mtx_unlock(&p->lock.main); +busy_main: + + return EBUSY; +#endif +} ERTS_GLB_INLINE void #ifdef ERTS_ENABLE_LOCK_COUNT @@ -444,10 +493,13 @@ erts_smp_proc_lock__(Process *p, ErtsProcLocks locks) #endif { +#if ERTS_PROC_LOCK_OWN_IMPL + ErtsProcLocks old_lflgs; #if !ERTS_PROC_LOCK_ATOMIC_IMPL erts_pix_lock(pix_lck); #endif + #ifdef ERTS_ENABLE_LOCK_COUNT erts_lcnt_proc_lock(&(p->lock), locks); #endif @@ -471,12 +523,14 @@ erts_smp_proc_lock__(Process *p, erts_pix_unlock(pix_lck); } #endif + #ifdef ERTS_ENABLE_LOCK_COUNT erts_lcnt_proc_lock_post_x(&(p->lock), locks, file, line); #endif #ifdef ERTS_ENABLE_LOCK_CHECK erts_proc_lc_lock(p, locks); #endif + #ifdef ERTS_PROC_LOCK_DEBUG erts_proc_lock_op_debug(p, locks, 1); #endif @@ -484,6 +538,22 @@ erts_smp_proc_lock__(Process *p, #if ERTS_PROC_LOCK_ATOMIC_IMPL ETHR_COMPILER_BARRIER; #endif + +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + if (locks & ERTS_PROC_LOCK_MAIN) + erts_mtx_lock(&p->lock.main); + if (locks & ERTS_PROC_LOCK_LINK) + erts_mtx_lock(&p->lock.link); + if (locks & ERTS_PROC_LOCK_MSGQ) + erts_mtx_lock(&p->lock.msgq); + if (locks & ERTS_PROC_LOCK_STATUS) + erts_mtx_lock(&p->lock.status); + +#ifdef ERTS_PROC_LOCK_DEBUG + erts_proc_lock_op_debug(p, locks, 1); +#endif + +#endif } ERTS_GLB_INLINE void @@ -491,6 +561,7 @@ erts_smp_proc_unlock__(Process *p, erts_pix_lock_t *pix_lck, ErtsProcLocks locks) { +#if ERTS_PROC_LOCK_OWN_IMPL ErtsProcLocks old_lflgs; #if ERTS_PROC_LOCK_ATOMIC_IMPL @@ -555,6 +626,23 @@ erts_smp_proc_unlock__(Process *p, break; } + +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + +#ifdef ERTS_PROC_LOCK_DEBUG + erts_proc_lock_op_debug(p, locks, 0); +#endif + + if (locks & ERTS_PROC_LOCK_STATUS) + erts_mtx_unlock(&p->lock.status); + if (locks & ERTS_PROC_LOCK_MSGQ) + erts_mtx_unlock(&p->lock.msgq); + if (locks & ERTS_PROC_LOCK_LINK) + erts_mtx_unlock(&p->lock.link); + if (locks & ERTS_PROC_LOCK_MAIN) + erts_mtx_unlock(&p->lock.main); +#endif + } ERTS_GLB_INLINE int @@ -562,6 +650,7 @@ erts_smp_proc_trylock__(Process *p, erts_pix_lock_t *pix_lck, ErtsProcLocks locks) { +#if ERTS_PROC_LOCK_OWN_IMPL int res; #ifdef ERTS_ENABLE_LOCK_CHECK @@ -573,6 +662,7 @@ erts_smp_proc_trylock__(Process *p, else #endif { + #if !ERTS_PROC_LOCK_ATOMIC_IMPL erts_pix_lock(pix_lck); #endif @@ -611,8 +701,18 @@ erts_smp_proc_trylock__(Process *p, #if ERTS_PROC_LOCK_ATOMIC_IMPL ETHR_COMPILER_BARRIER; #endif - return res; + +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + if (erts_smp_proc_raw_trylock__(p, locks) != 0) + return EBUSY; + else { +#ifdef ERTS_PROC_LOCK_DEBUG + erts_proc_lock_op_debug(p, locks, 1); +#endif + return 0; + } +#endif } #ifdef ERTS_PROC_LOCK_DEBUG @@ -711,44 +811,36 @@ erts_smp_proc_trylock(Process *p, ErtsProcLocks locks) #endif } - ERTS_GLB_INLINE void erts_smp_proc_inc_refc(Process *p) { #ifdef ERTS_SMP - erts_pix_lock_t *pixlck = ERTS_PID2PIXLOCK(p->id); - erts_pix_lock(pixlck); - ERTS_LC_ASSERT(p->lock.refc > 0); - p->lock.refc++; - erts_pix_unlock(pixlck); +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_aint32_t refc = erts_atomic32_inc_read_nob(&p->lock.refc); + ERTS_SMP_LC_ASSERT(refc > 1); +#else + erts_atomic32_inc_nob(&p->lock.refc); +#endif #endif } ERTS_GLB_INLINE void erts_smp_proc_dec_refc(Process *p) { #ifdef ERTS_SMP - Process *fp; - erts_pix_lock_t *pixlck = ERTS_PID2PIXLOCK(p->id); - erts_pix_lock(pixlck); - ERTS_LC_ASSERT(p->lock.refc > 0); - fp = --p->lock.refc == 0 ? p : NULL; - erts_pix_unlock(pixlck); - if (fp) - erts_free_proc(fp); + erts_aint32_t refc = erts_atomic32_dec_read_nob(&p->lock.refc); + ERTS_SMP_LC_ASSERT(refc >= 0); + if (refc == 0) + erts_free_proc(p); #endif } -ERTS_GLB_INLINE void erts_smp_proc_add_refc(Process *p, Sint32 refc) +ERTS_GLB_INLINE void erts_smp_proc_add_refc(Process *p, Sint32 add_refc) { #ifdef ERTS_SMP - Process *fp; - erts_pix_lock_t *pixlck = ERTS_PID2PIXLOCK(p->id); - erts_pix_lock(pixlck); - ERTS_LC_ASSERT(p->lock.refc > 0); - p->lock.refc += refc; - fp = p->lock.refc == 0 ? p : NULL; - erts_pix_unlock(pixlck); - if (fp) - erts_free_proc(fp); + erts_aint32_t refc = erts_atomic32_add_read_nob(&p->lock.refc, + (erts_aint32_t) add_refc); + ERTS_SMP_LC_ASSERT(refc >= 0); + if (refc == 0) + erts_free_proc(p); #endif } @@ -756,6 +848,7 @@ ERTS_GLB_INLINE void erts_smp_proc_add_refc(Process *p, Sint32 refc) #ifdef ERTS_SMP void erts_proc_lock_init(Process *); +void erts_proc_lock_fin(Process *); void erts_proc_safelock(Process *a_proc, ErtsProcLocks a_have_locks, ErtsProcLocks a_need_locks, @@ -788,211 +881,75 @@ extern const Process erts_proc_lock_busy; #define erts_pid2proc(PROC, HL, PID, NL) \ erts_pid2proc_opt((PROC), (HL), (PID), (NL), 0) -ERTS_GLB_INLINE Process * -erts_pid2proc_opt(Process *, ErtsProcLocks, Eterm, ErtsProcLocks, int); -#ifdef ERTS_SMP -void -erts_pid2proc_safelock(Process *c_p, - ErtsProcLocks c_p_have_locks, - Process **proc, - ErtsProcLocks need_locks, - erts_pix_lock_t *pix_lock, - int flags); -ERTS_GLB_INLINE Process *erts_pid2proc_unlocked_opt(Eterm pid, int flags); -#define erts_pid2proc_unlocked(PID) erts_pid2proc_unlocked_opt((PID), 0) -#else -#define erts_pid2proc_unlocked_opt(PID, FLGS) \ - erts_pid2proc_opt(NULL, 0, (PID), 0, FLGS) -#define erts_pid2proc_unlocked(PID) erts_pid2proc_opt(NULL, 0, (PID), 0, 0) +ERTS_GLB_INLINE Process *erts_pix2proc(int ix); +ERTS_GLB_INLINE Process *erts_proc_lookup_raw(Eterm pid); +ERTS_GLB_INLINE Process *erts_proc_lookup(Eterm pid); + +#ifndef ERTS_SMP +ERTS_GLB_INLINE #endif +Process *erts_pid2proc_opt(Process *, ErtsProcLocks, Eterm, ErtsProcLocks, int); #if ERTS_GLB_INLINE_INCL_FUNC_DEF -ERTS_GLB_INLINE Process * -#ifdef ERTS_SMP -erts_pid2proc_unlocked_opt(Eterm pid, int flags) -#else -erts_pid2proc_opt(Process *c_p_unused, - ErtsProcLocks c_p_have_locks_unused, - Eterm pid, - ErtsProcLocks pid_need_locks_unused, - int flags) -#endif +ERTS_GLB_INLINE Process *erts_pix2proc(int ix) { - Uint pix; Process *proc; + ASSERT(0 <= ix && ix < erts_proc.max); + proc = (Process *) erts_smp_atomic_read_nob(&erts_proc.tab[ix]); + return proc == ERTS_PROC_LOCK_BUSY ? NULL : proc; +} + +ERTS_GLB_INLINE Process *erts_proc_lookup_raw(Eterm pid) +{ + Process *proc; + int pix; + + /* + * In SMP case: Only scheduler threads are allowed + * to use this function. Other threads need to + * atomicaly increment refc at lookup, i.e., use + * erts_pid2proc_opt() with ERTS_P2P_FLG_SMP_INC_REFC. + */ + ERTS_SMP_LC_ASSERT(erts_get_scheduler_id()); if (is_not_internal_pid(pid)) return NULL; pix = internal_pid_index(pid); - if(pix >= erts_max_processes) + + proc = (Process *) erts_smp_atomic_read_ddrb(&erts_proc.tab[pix]); + + if (proc && proc->id != pid) return NULL; - proc = process_tab[pix]; - if (proc) { - if (proc->id != pid - || (!(flags & ERTS_P2P_FLG_ALLOW_OTHER_X) - && proc->status == P_EXITING)) - proc = NULL; - } + return proc; } -#ifdef ERTS_SMP +ERTS_GLB_INLINE Process *erts_proc_lookup(Eterm pid) +{ + Process *proc = erts_proc_lookup_raw(pid); + if (proc && ERTS_PROC_IS_EXITING(proc)) + return NULL; + return proc; +} +#ifndef ERTS_SMP ERTS_GLB_INLINE Process * -erts_pid2proc_opt(Process *c_p, - ErtsProcLocks c_p_have_locks, +erts_pid2proc_opt(Process *c_p_unused, + ErtsProcLocks c_p_have_locks_unused, Eterm pid, - ErtsProcLocks pid_need_locks, + ErtsProcLocks pid_need_locks_unused, int flags) { - erts_pix_lock_t *pix_lock; - ErtsProcLocks need_locks; - Uint pix; - Process *proc; -#ifdef ERTS_ENABLE_LOCK_COUNT - ErtsProcLocks lcnt_locks; -#endif - -#ifdef ERTS_ENABLE_LOCK_CHECK - if (c_p) { - ErtsProcLocks might_unlock = c_p_have_locks & pid_need_locks; - if (might_unlock) - erts_proc_lc_might_unlock(c_p, might_unlock); - } -#endif - if (is_not_internal_pid(pid)) { - proc = NULL; - goto done; - } - pix = internal_pid_index(pid); - if(pix >= erts_max_processes) { - proc = NULL; - goto done; - } - - ERTS_LC_ASSERT((pid_need_locks & ERTS_PROC_LOCKS_ALL) == pid_need_locks); - need_locks = pid_need_locks; - - pix_lock = ERTS_PIX2PIXLOCK(pix); - - if (c_p && c_p->id == pid) { - ASSERT(c_p->id != ERTS_INVALID_PID); - ASSERT(c_p == process_tab[pix]); - if (!(flags & ERTS_P2P_FLG_ALLOW_OTHER_X) && c_p->is_exiting) { - proc = NULL; - goto done; - } - need_locks &= ~c_p_have_locks; - if (!need_locks) { - proc = c_p; - erts_pix_lock(pix_lock); - if (flags & ERTS_P2P_FLG_SMP_INC_REFC) - proc->lock.refc++; - erts_pix_unlock(pix_lock); - goto done; - } - } - - erts_pix_lock(pix_lock); - - proc = process_tab[pix]; - if (proc) { - if (proc->id != pid || (!(flags & ERTS_P2P_FLG_ALLOW_OTHER_X) - && ERTS_PROC_IS_EXITING(proc))) { - proc = NULL; - } - else if (!need_locks) { - if (flags & ERTS_P2P_FLG_SMP_INC_REFC) - proc->lock.refc++; - } - else { - int busy; - -#ifdef ERTS_ENABLE_LOCK_COUNT - lcnt_locks = need_locks; - if (!(flags & ERTS_P2P_FLG_TRY_LOCK)) { - erts_lcnt_proc_lock(&proc->lock, need_locks); - } -#endif - -#ifdef ERTS_ENABLE_LOCK_CHECK - /* Make sure erts_pid2proc_safelock() is enough to handle - a potential lock order violation situation... */ - busy = erts_proc_lc_trylock_force_busy(proc, need_locks); - if (!busy) -#endif - { - /* Try a quick trylock to grab all the locks we need. */ - busy = (int) erts_smp_proc_raw_trylock__(proc, need_locks); -#ifdef ERTS_ENABLE_LOCK_CHECK - erts_proc_lc_trylock(proc, need_locks, !busy); -#endif -#ifdef ERTS_PROC_LOCK_DEBUG - if (!busy) - erts_proc_lock_op_debug(proc, need_locks, 1); -#endif - } - -#ifdef ERTS_ENABLE_LOCK_COUNT - if (flags & ERTS_P2P_FLG_TRY_LOCK) { - if (busy) { - erts_lcnt_proc_trylock(&proc->lock, need_locks, EBUSY); - } else { - erts_lcnt_proc_trylock(&proc->lock, need_locks, 0); - } - } -#endif - if (!busy) { - if (flags & ERTS_P2P_FLG_SMP_INC_REFC) - proc->lock.refc++; -#ifdef ERTS_ENABLE_LOCK_COUNT - /* all is great */ - if (!(flags & ERTS_P2P_FLG_TRY_LOCK)) { - erts_lcnt_proc_lock_post_x(&proc->lock, lcnt_locks, __FILE__, __LINE__); - } -#endif - } - else { - if (flags & ERTS_P2P_FLG_TRY_LOCK) - proc = ERTS_PROC_LOCK_BUSY; - else { -#ifdef ERTS_ENABLE_LOCK_COUNT - erts_lcnt_proc_lock_unaquire(&proc->lock, lcnt_locks); -#endif - erts_pid2proc_safelock(c_p, - c_p_have_locks, - &proc, - pid_need_locks, - pix_lock, - flags); - if (proc && (flags & ERTS_P2P_FLG_SMP_INC_REFC)) - proc->lock.refc++; - } - } - } - } - - erts_pix_unlock(pix_lock); -#ifdef ERTS_PROC_LOCK_DEBUG - ERTS_LC_ASSERT(!proc - || proc == ERTS_PROC_LOCK_BUSY - || (pid_need_locks == - (ERTS_PROC_LOCK_FLGS_READ_(&proc->lock) - & pid_need_locks))); -#endif - - - done: - -#if ERTS_PROC_LOCK_ATOMIC_IMPL - ETHR_COMPILER_BARRIER; -#endif - - return proc; + Process *proc = erts_proc_lookup_raw(pid); + return ((!(flags & ERTS_P2P_FLG_ALLOW_OTHER_X) + && proc + && ERTS_PROC_IS_EXITING(proc)) + ? NULL + : proc); } -#endif /* ERTS_SMP */ +#endif /* !ERTS_SMP */ #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ diff --git a/erts/emulator/beam/erl_thr_progress.h b/erts/emulator/beam/erl_thr_progress.h index 89486b065b..e72321cf48 100644 --- a/erts/emulator/beam/erl_thr_progress.h +++ b/erts/emulator/beam/erl_thr_progress.h @@ -78,6 +78,16 @@ void erts_thr_progress_fatal_error_block(SWord timeout, #endif /* ERTS_SMP */ +typedef struct ErtsThrPrgrLaterOp_ ErtsThrPrgrLaterOp; +struct ErtsThrPrgrLaterOp_ { +#ifdef ERTS_SMP + ErtsThrPrgrVal later; +#endif + void (*func)(void *); + void *data; + ErtsThrPrgrLaterOp *next; +}; + #endif #if !defined(ERL_THR_PROGRESS_H__) && !defined(ERL_THR_PROGRESS_TSD_TYPE_ONLY) diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h index ee47c98009..17628286bc 100644 --- a/erts/emulator/beam/erl_threads.h +++ b/erts/emulator/beam/erl_threads.h @@ -258,10 +258,6 @@ #include "sys.h" -typedef struct { SWord sint[2]; } erts_no_dw_atomic_t; -typedef SWord erts_no_atomic_t; -typedef Sint32 erts_no_atomic32_t; - #ifdef USE_THREADS #define ETHR_TRY_INLINE_FUNCS @@ -411,12 +407,15 @@ typedef struct { typedef int erts_rwmtx_t; typedef int erts_tsd_key_t; typedef int erts_tse_t; -#define erts_dw_aint_t erts_no_dw_atomic_t -#define erts_dw_atomic_t erts_no_dw_atomic_t -#define erts_aint_t SWord -#define erts_atomic_t erts_no_atomic_t -#define erts_aint32_t Sint32 -#define erts_atomic32_t erts_no_atomic32_t + +typedef struct { SWord sint[2]; } erts_dw_aint_t; +typedef SWord erts_aint_t; +typedef Sint32 erts_aint32_t; + +#define erts_dw_atomic_t erts_dw_aint_t +#define erts_atomic_t erts_aint_t +#define erts_atomic32_t erts_aint32_t + #if __GNUC__ > 2 typedef struct { } erts_spinlock_t; typedef struct { } erts_rwlock_t; @@ -425,6 +424,14 @@ typedef struct { int gcc_is_buggy; } erts_spinlock_t; typedef struct { int gcc_is_buggy; } erts_rwlock_t; #endif +#ifdef WORDS_BIGENDIAN +#define ERTS_DW_AINT_LOW_WORD 1 +#define ERTS_DW_AINT_HIGH_WORD 0 +#else +#define ERTS_DW_AINT_LOW_WORD 0 +#define ERTS_DW_AINT_HIGH_WORD 1 +#endif + #define ERTS_MTX_INITER 0 #define ERTS_CND_INITER 0 #define ERTS_THR_INIT_DATA_DEF_INITER 0 @@ -433,6 +440,10 @@ typedef struct { int gcc_is_buggy; } erts_rwlock_t; #endif /* #ifdef USE_THREADS */ +#define erts_no_dw_atomic_t erts_dw_aint_t +#define erts_no_atomic_t erts_aint_t +#define erts_no_atomic32_t erts_aint32_t + #define ERTS_AINT_NULL ((erts_aint_t) NULL) #define ERTS_AINT_T_MAX (~(((erts_aint_t) 1) << (sizeof(erts_aint_t)*8-1))) diff --git a/erts/emulator/beam/erl_time.h b/erts/emulator/beam/erl_time.h index 6c6e193818..4bbdcaa3e3 100644 --- a/erts/emulator/beam/erl_time.h +++ b/erts/emulator/beam/erl_time.h @@ -118,9 +118,11 @@ ERTS_GLB_INLINE void erts_do_time_add(erts_short_time_t elapsed) void erts_get_now_cpu(Uint* megasec, Uint* sec, Uint* microsec); #endif +typedef UWord erts_approx_time_t; +erts_approx_time_t erts_get_approx_time(void); + void erts_get_timeval(SysTimeval *tv); erts_time_t erts_get_time(void); -void erts_get_emu_time(SysTimeval *); ERTS_GLB_INLINE int erts_cmp_timeval(SysTimeval *t1p, SysTimeval *t2p); diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 1d0735aa99..c1b4408c06 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -91,6 +91,41 @@ static SysTimeval then; /* Used in get_now */ static SysTimeval last_emu_time; /* Used in erts_get_emu_time() */ SysTimeval erts_first_emu_time; /* Used in erts_get_emu_time() */ +union { + erts_smp_atomic_t time; + char align[ERTS_CACHE_LINE_SIZE]; +} approx erts_align_attribute(ERTS_CACHE_LINE_SIZE); + +static void +init_approx_time(void) +{ + erts_smp_atomic_init_nob(&approx.time, 0); +} + +static ERTS_INLINE erts_approx_time_t +get_approx_time(void) +{ + return (erts_approx_time_t) erts_smp_atomic_read_nob(&approx.time); +} + +static ERTS_INLINE void +update_approx_time(SysTimeval *tv) +{ + erts_approx_time_t new_secs = (erts_approx_time_t) tv->tv_sec; + erts_approx_time_t old_secs = get_approx_time(); + if (old_secs != new_secs) + erts_smp_atomic_set_nob(&approx.time, new_secs); +} + +/* + * erts_get_approx_time() returns an *approximate* time + * in seconds. NOTE that this time may jump backwards!!! + */ +erts_approx_time_t +erts_get_approx_time(void) +{ + return get_approx_time(); +} #ifdef HAVE_GETHRTIME @@ -398,6 +433,8 @@ erts_init_time_sup(void) { erts_smp_mtx_init(&erts_timeofday_mtx, "timeofday"); + init_approx_time(); + last_emu_time.tv_sec = 0; last_emu_time.tv_usec = 0; @@ -417,7 +454,7 @@ erts_init_time_sup(void) gtv = inittv; then.tv_sec = then.tv_usec = 0; - erts_get_emu_time(&erts_first_emu_time); + erts_deliver_time(); return CLOCK_RESOLUTION; } @@ -873,6 +910,8 @@ get_now(Uint* megasec, Uint* sec, Uint* microsec) *megasec = (Uint) (now.tv_sec / 1000000); *sec = (Uint) (now.tv_sec % 1000000); *microsec = (Uint) (now.tv_usec); + + update_approx_time(&now); } void @@ -885,6 +924,8 @@ get_sys_now(Uint* megasec, Uint* sec, Uint* microsec) *megasec = (Uint) (now.tv_sec / 1000000); *sec = (Uint) (now.tv_sec % 1000000); *microsec = (Uint) (now.tv_usec); + + update_approx_time(&now); } @@ -901,6 +942,8 @@ void erts_deliver_time(void) { do_erts_deliver_time(&now); erts_smp_mtx_unlock(&erts_timeofday_mtx); + + update_approx_time(&now); } /* get *real* time (not ticks) remaining until next timeout - if there @@ -949,6 +992,7 @@ void erts_get_timeval(SysTimeval *tv) erts_smp_mtx_lock(&erts_timeofday_mtx); get_tolerant_timeofday(tv); erts_smp_mtx_unlock(&erts_timeofday_mtx); + update_approx_time(tv); } erts_time_t @@ -961,7 +1005,9 @@ erts_get_time(void) get_tolerant_timeofday(&sys_tv); erts_smp_mtx_unlock(&erts_timeofday_mtx); - + + update_approx_time(&sys_tv); + return sys_tv.tv_sec; } @@ -977,38 +1023,3 @@ void erts_get_now_cpu(Uint* megasec, Uint* sec, Uint* microsec) { *sec = (Uint)(tp.tv_sec % 1000000); } #endif - - -/* - * erts_get_emu_time() is similar to get_now(). You will - * always get different times from erts_get_emu_time(), but they - * may equal a time from get_now(). - * - * erts_get_emu_time() is only used internally in the emulator in - * order to order emulator internal events. - */ - -void -erts_get_emu_time(SysTimeval *this_emu_time_p) -{ - erts_smp_mtx_lock(&erts_timeofday_mtx); - - get_tolerant_timeofday(this_emu_time_p); - - /* Make sure time is later than last */ - if (last_emu_time.tv_sec > this_emu_time_p->tv_sec || - (last_emu_time.tv_sec == this_emu_time_p->tv_sec - && last_emu_time.tv_usec >= this_emu_time_p->tv_usec)) { - *this_emu_time_p = last_emu_time; - this_emu_time_p->tv_usec++; - } - /* Check for carry from above + general reasonability */ - if (this_emu_time_p->tv_usec >= 1000000) { - this_emu_time_p->tv_usec = 0; - this_emu_time_p->tv_sec++; - } - - last_emu_time = *this_emu_time_p; - - erts_smp_mtx_unlock(&erts_timeofday_mtx); -} diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 009ca1eb52..d04a91f18c 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -64,7 +64,7 @@ int erts_cpu_timestamp; #endif static erts_smp_mtx_t smq_mtx; -static erts_smp_mtx_t sys_trace_mtx; +static erts_smp_rwmtx_t sys_trace_rwmtx; enum ErtsSysMsgType { SYS_MSG_TYPE_UNDEFINED, @@ -91,7 +91,12 @@ static void init_sys_msg_dispatcher(void); #endif void erts_init_trace(void) { - erts_smp_mtx_init(&sys_trace_mtx, "sys_tracers"); + erts_smp_rwmtx_opt_t rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; + rwmtx_opts.type = ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ; + rwmtx_opts.lived = ERTS_SMP_RWMTX_LONG_LIVED; + + erts_smp_rwmtx_init_opt(&sys_trace_rwmtx, &rwmtx_opts, "sys_tracers"); + #ifdef HAVE_ERTS_NOW_CPU erts_cpu_timestamp = 0; #endif @@ -151,8 +156,8 @@ do { (RES) = (TPID); } while(0) #define ERTS_TRACER_REF_TYPE Process * #define ERTS_GET_TRACER_REF(RES, TPID, TRACEE_FLGS) \ do { \ - (RES) = process_tab[internal_pid_index((TPID))]; \ - if (INVALID_PID((RES), (TPID)) || !((RES)->trace_flags & F_TRACER)) { \ + (RES) = erts_proc_lookup((TPID)); \ + if (!(RES) || !((RES)->trace_flags & F_TRACER)) { \ (TPID) = NIL; \ (TRACEE_FLGS) &= ~TRACEE_FLAGS; \ return; \ @@ -169,10 +174,10 @@ erts_system_profile_setup_active_schedulers(void) active_sched = erts_active_schedulers(); } -void -erts_trace_check_exiting(Eterm exiting) +static void +exiting_reset(Eterm exiting) { - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rwlock(&sys_trace_rwmtx); if (exiting == default_tracer) { default_tracer = NIL; default_trace_flags &= TRACEE_FLAGS; @@ -202,29 +207,49 @@ erts_trace_check_exiting(Eterm exiting) erts_system_profile_clear(NULL); #endif } - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx); +} + +void +erts_trace_check_exiting(Eterm exiting) +{ + int reset = 0; + erts_smp_rwmtx_rlock(&sys_trace_rwmtx); + if (exiting == default_tracer) + reset = 1; + else if (exiting == system_seq_tracer) + reset = 1; + else if (exiting == system_monitor) + reset = 1; + else if (exiting == system_profile) + reset = 1; + erts_smp_rwmtx_runlock(&sys_trace_rwmtx); + if (reset) + exiting_reset(exiting); +} + +static ERTS_INLINE int +is_valid_tracer(Eterm tracer) +{ + return erts_proc_lookup(tracer) || erts_is_valid_tracer_port(tracer); } Eterm erts_set_system_seq_tracer(Process *c_p, ErtsProcLocks c_p_locks, Eterm new) { - Eterm old = THE_NON_VALUE; + Eterm old; - if (new != am_false) { - if (!erts_pid2proc(c_p, c_p_locks, new, 0) - && !erts_is_valid_tracer_port(new)) { - return old; - } - } + if (new != am_false && !is_valid_tracer(new)) + return THE_NON_VALUE; - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rwlock(&sys_trace_rwmtx); old = system_seq_tracer; system_seq_tracer = new; #ifdef DEBUG_PRINTOUTS erts_fprintf(stderr, "set seq tracer new=%T old=%T\n", new, old); #endif - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx); return old; } @@ -232,12 +257,12 @@ Eterm erts_get_system_seq_tracer(void) { Eterm st; - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rlock(&sys_trace_rwmtx); st = system_seq_tracer; #ifdef DEBUG_PRINTOUTS erts_fprintf(stderr, "get seq tracer %T\n", st); #endif - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_runlock(&sys_trace_rwmtx); return st; } @@ -250,7 +275,7 @@ get_default_tracing(Uint *flagsp, Eterm *tracerp) if (is_nil(default_tracer)) { default_trace_flags &= ~TRACEE_FLAGS; } else if (is_internal_pid(default_tracer)) { - if (!erts_pid2proc(NULL, 0, default_tracer, 0)) { + if (!erts_proc_lookup(default_tracer)) { reset_tracer: default_trace_flags &= ~TRACEE_FLAGS; default_tracer = NIL; @@ -270,7 +295,7 @@ get_default_tracing(Uint *flagsp, Eterm *tracerp) void erts_change_default_tracing(int setflags, Uint *flagsp, Eterm *tracerp) { - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rwlock(&sys_trace_rwmtx); if (flagsp) { if (setflags) default_trace_flags |= *flagsp; @@ -280,48 +305,48 @@ erts_change_default_tracing(int setflags, Uint *flagsp, Eterm *tracerp) if (tracerp) default_tracer = *tracerp; get_default_tracing(flagsp, tracerp); - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx); } void erts_get_default_tracing(Uint *flagsp, Eterm *tracerp) { - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rlock(&sys_trace_rwmtx); get_default_tracing(flagsp, tracerp); - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_runlock(&sys_trace_rwmtx); } void erts_set_system_monitor(Eterm monitor) { - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rwlock(&sys_trace_rwmtx); system_monitor = monitor; - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx); } Eterm erts_get_system_monitor(void) { Eterm monitor; - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rlock(&sys_trace_rwmtx); monitor = system_monitor; - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_runlock(&sys_trace_rwmtx); return monitor; } /* Performance monitoring */ void erts_set_system_profile(Eterm profile) { - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rwlock(&sys_trace_rwmtx); system_profile = profile; - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx); } Eterm erts_get_system_profile(void) { Eterm profile; - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rlock(&sys_trace_rwmtx); profile = system_profile; - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_runlock(&sys_trace_rwmtx); return profile; } @@ -384,13 +409,9 @@ WRITE_SYS_MSG_TO_PORT(Eterm unused_to, } #ifndef ERTS_SMP - if (!INVALID_TRACER_PORT(trace_port, trace_port->id)) { + if (!INVALID_TRACER_PORT(trace_port, trace_port->id)) #endif erts_raw_port_command(trace_port, buffer, ptr-buffer); -#ifndef ERTS_SMP - erts_port_release(trace_port); - } -#endif erts_free(ERTS_ALC_T_TMP, (void *) buffer); } @@ -465,13 +486,13 @@ send_to_port(Process *c_p, Eterm message, trace_port = NULL; #else - if (is_not_internal_port(*tracer_pid)) - goto invalid_tracer_port; - trace_port = &erts_port[internal_port_index(*tracer_pid)]; + trace_port = erts_id2port_sflgs(*tracer_pid, + NULL, + 0, + ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP); - if (INVALID_TRACER_PORT(trace_port, *tracer_pid)) { - invalid_tracer_port: + if (!trace_port) { *tracee_flags &= ~TRACEE_FLAGS; *tracer_pid = NIL; return; @@ -491,6 +512,7 @@ send_to_port(Process *c_p, Eterm message, SYS_MSG_TYPE_TRACE, message); #ifndef ERTS_SMP + erts_port_release(trace_port); return; } @@ -537,6 +559,9 @@ send_to_port(Process *c_p, Eterm message, */ do_send_schedfix_to_port(trace_port, c_p->id, ts); } + + erts_port_release(trace_port); + UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #endif @@ -566,23 +591,28 @@ profile_send(Eterm from, Eterm message) { Port *profiler_port = NULL; /* not smp */ - - - profiler_port = &erts_port[internal_port_index(profiler)]; - - do_send_to_port(profiler, - profiler_port, - NIL, /* or current process->id */ - SYS_MSG_TYPE_SYSPROF, - message); + + profiler_port = erts_id2port_sflgs(profiler, + NULL, + 0, + ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP); + if (profiler_port) { + do_send_to_port(profiler, + profiler_port, + NIL, /* or current process->id */ + SYS_MSG_TYPE_SYSPROF, + message); + erts_port_release(profiler_port); + } } else { ASSERT(is_internal_pid(profiler) && internal_pid_index(profiler) < erts_max_processes); - profile_p = process_tab[internal_pid_index(profiler)]; + profile_p = erts_proc_lookup(profiler); - if (INVALID_PID(profile_p, profiler)) return; + if (!profile_p) + return; sz = size_object(message); hp = erts_alloc_message_heap(sz, &bp, &off_heap, profile_p, 0); @@ -626,13 +656,11 @@ seq_trace_send_to_port(Process *c_p, trace_port = NULL; #else - if (is_not_internal_port(seq_tracer)) - goto invalid_tracer_port; - - trace_port = &erts_port[internal_port_index(seq_tracer)]; - - if (INVALID_TRACER_PORT(trace_port, seq_tracer)) { - invalid_tracer_port: + trace_port = erts_id2port_sflgs(seq_tracer, + NULL, + 0, + ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP); + if (!trace_port) { system_seq_tracer = am_false; #ifndef ERTS_SMP UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -650,6 +678,7 @@ seq_trace_send_to_port(Process *c_p, message); #ifndef ERTS_SMP + erts_port_release(trace_port); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); return; } @@ -691,6 +720,9 @@ seq_trace_send_to_port(Process *c_p, */ do_send_schedfix_to_port(trace_port, c_p->id, ts); } + + erts_port_release(trace_port); + UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #endif @@ -789,13 +821,8 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched) ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags); } - if (ERTS_PROC_IS_EXITING(p) -#ifndef ERTS_SMP - || p->status == P_FREE -#endif - ) { + if (ERTS_PROC_IS_EXITING(p)) curr_func = 0; - } else { if (!p->current) p->current = find_function_from_pc(p->i); @@ -874,7 +901,7 @@ trace_send(Process *p, Eterm to, Eterm msg) operation = am_send; if (is_internal_pid(to)) { - if (!erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, to, 0)) + if (!erts_proc_lookup(to)) goto send_to_non_existing_process; } else if(is_external_pid(to) @@ -1116,8 +1143,8 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, #ifndef ERTS_SMP - tracer = process_tab[internal_pid_index(seq_tracer)]; - if (INVALID_PID(tracer, tracer->id)) { + tracer = erts_proc_lookup(seq_tracer); + if (!tracer) { system_seq_tracer = am_false; return; /* no need to send anything */ } @@ -2107,187 +2134,6 @@ void save_calls(Process *p, Export *e) } } -/* - * Entry point called by the trace wrap functions in erl_bif_wrap.c - * - * The trace wrap functions are themselves called through the export - * entries instead of the original BIF functions. - */ -Eterm -erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I) -{ - Eterm result; - int meta = !!(erts_bif_trace_flags[bif_index] & BIF_TRACE_AS_META); - - ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); - - if (!ARE_TRACE_FLAGS_ON(p, F_TRACE_CALLS) && (! meta)) { - /* Warning! This is an Optimization. - * - * If neither meta trace is active nor process trace flags then - * no tracing will occur. Doing the whole else branch will - * also do nothing, only slower. - */ - Eterm (*func)(Process*, Eterm*, BeamInstr*) = bif_table[bif_index].f; - result = func(p, args, I); - } else { - Eterm (*func)(Process*, Eterm*, BeamInstr*); - Export* ep = bif_export[bif_index]; - Uint32 flags = 0, flags_meta = 0; - int global = !!(erts_bif_trace_flags[bif_index] & BIF_TRACE_AS_GLOBAL); - int local = !!(erts_bif_trace_flags[bif_index] & BIF_TRACE_AS_LOCAL); - int time = !!(erts_bif_trace_flags[bif_index] & BIF_TRACE_AS_CALL_TIME); - Eterm meta_tracer_pid = NIL; - int applying = (I == &(ep->code[3])); /* Yup, the apply code for a bif - * is actually in the - * export entry */ - BeamInstr *cp = p->cp; - - /* - * Make continuation pointer OK, it is not during direct BIF calls, - * but it is correct during apply of bif. - */ - if (!applying) { - p->cp = I; - } - if (global || local) { - flags = erts_call_trace(p, ep->code, ep->match_prog_set, args, - local, &p->tracer_proc); - } - if (meta) { - flags_meta = erts_bif_mtrace(p, ep->code+3, args, local, - &meta_tracer_pid); - } - if (time) { - BpDataTime *bdt = NULL; - BeamInstr *pc = (BeamInstr *)ep->code+3; - - bdt = (BpDataTime *) erts_get_time_break(p, pc); - ASSERT(bdt); - - if (!bdt->pause) { - erts_trace_time_break(p, pc, bdt, ERTS_BP_CALL_TIME_CALL); - } - } - /* Restore original continuation pointer (if changed). */ - p->cp = cp; - - func = bif_table[bif_index].f; - - result = func(p, args, I); - - if (applying && (flags & MATCH_SET_RETURN_TO_TRACE)) { - BeamInstr i_return_trace = beam_return_trace[0]; - BeamInstr i_return_to_trace = beam_return_to_trace[0]; - BeamInstr i_return_time_trace = beam_return_time_trace[0]; - Eterm *cpp; - /* Maybe advance cp to skip trace stack frames */ - for (cpp = p->stop; ; cp = cp_val(*cpp++)) { - if (*cp == i_return_trace) { - /* Skip stack frame variables */ - while (is_not_CP(*cpp)) cpp++; - cpp += 2; /* Skip return_trace parameters */ - } else if (*cp == i_return_time_trace) { - /* Skip stack frame variables */ - while (is_not_CP(*cpp)) cpp++; - cpp += 1; /* Skip return_time_trace parameters */ - } else if (*cp == i_return_to_trace) { - /* A return_to trace message is going to be generated - * by normal means, so we do not have to. - */ - cp = NULL; - break; - } else break; - } - } - - /* Try to get these in the order - * they usually appear in normal code... */ - if (is_non_value(result)) { - Uint reason = p->freason; - if (reason != TRAP) { - Eterm class; - Eterm value = p->fvalue; - DeclareTmpHeapNoproc(nocatch,3); - UseTmpHeapNoproc(3); - /* Expand error value like in handle_error() */ - if (reason & EXF_ARGLIST) { - Eterm *tp; - ASSERT(is_tuple(value)); - tp = tuple_val(value); - value = tp[1]; - } - if ((reason & EXF_THROWN) && (p->catches <= 0)) { - value = TUPLE2(nocatch, am_nocatch, value); - reason = EXC_ERROR; - } - /* Note: expand_error_value() could theoretically - * allocate on the heap, but not for any error - * returned by a BIF, and it would do no harm, - * just be annoying. - */ - value = expand_error_value(p, reason, value); - class = exception_tag[GET_EXC_CLASS(reason)]; - - if (flags_meta & MATCH_SET_EXCEPTION_TRACE) { - erts_trace_exception(p, ep->code, class, value, - &meta_tracer_pid); - } - if (flags & MATCH_SET_EXCEPTION_TRACE) { - erts_trace_exception(p, ep->code, class, value, - &p->tracer_proc); - } - if ((flags & MATCH_SET_RETURN_TO_TRACE) && p->catches > 0) { - /* can only happen if(local)*/ - Eterm *ptr = p->stop; - ASSERT(is_CP(*ptr)); - ASSERT(ptr <= STACK_START(p)); - /* Search the nearest stack frame for a catch */ - while (++ptr < STACK_START(p)) { - if (is_CP(*ptr)) break; - if (is_catch(*ptr)) { - if (applying) { - /* Apply of BIF, cp is in calling function */ - if (cp) erts_trace_return_to(p, cp); - } else { - /* Direct bif call, I points into - * calling function */ - erts_trace_return_to(p, I); - } - } - } - } - UnUseTmpHeapNoproc(3); - if ((flags_meta|flags) & MATCH_SET_EXCEPTION_TRACE) { - erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR); - p->trace_flags |= F_EXCEPTION_TRACE; - erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR); - } - } - } else { - if (flags_meta & MATCH_SET_RX_TRACE) { - erts_trace_return(p, ep->code, result, &meta_tracer_pid); - } - /* MATCH_SET_RETURN_TO_TRACE cannot occur if(meta) */ - if (flags & MATCH_SET_RX_TRACE) { - erts_trace_return(p, ep->code, result, &p->tracer_proc); - } - if (flags & MATCH_SET_RETURN_TO_TRACE) { - /* can only happen if(local)*/ - if (applying) { - /* Apply of BIF, cp is in calling function */ - if (cp) erts_trace_return_to(p, cp); - } else { - /* Direct bif call, I points into calling function */ - erts_trace_return_to(p, I); - } - } - } - } - ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); - return result; -} - /* Sends trace message: * {trace_ts, Pid, What, Msg, Timestamp} * or {trace, Pid, What, Msg} @@ -2451,10 +2297,9 @@ monitor_long_gc(Process *p, Uint time) { #ifndef ERTS_SMP ASSERT(is_internal_pid(system_monitor) && internal_pid_index(system_monitor) < erts_max_processes); - monitor_p = process_tab[internal_pid_index(system_monitor)]; - if (INVALID_PID(monitor_p, system_monitor) || p == monitor_p) { + monitor_p = erts_proc_lookup(system_monitor); + if (!monitor_p || p == monitor_p) return; - } #endif hsz = 0; @@ -2527,8 +2372,8 @@ monitor_large_heap(Process *p) { #ifndef ERTS_SMP ASSERT(is_internal_pid(system_monitor) && internal_pid_index(system_monitor) < erts_max_processes); - monitor_p = process_tab[internal_pid_index(system_monitor)]; - if (INVALID_PID(monitor_p, system_monitor) || p == monitor_p) { + monitor_p = erts_proc_lookup(system_monitor); + if (monitor_p || p == monitor_p) { return; } #endif @@ -2582,10 +2427,9 @@ monitor_generic(Process *p, Eterm type, Eterm spec) { #ifndef ERTS_SMP ASSERT(is_internal_pid(system_monitor) && internal_pid_index(system_monitor) < erts_max_processes); - monitor_p = process_tab[internal_pid_index(system_monitor)]; - if (INVALID_PID(monitor_p, system_monitor) || p == monitor_p) { + monitor_p = erts_proc_lookup(system_monitor); + if (!monitor_p || p == monitor_p) return; - } #endif hp = ERTS_ALLOC_SYSMSG_HEAP(5, &bp, &off_heap, monitor_p); @@ -3149,10 +2993,10 @@ sys_msg_disp_failure(ErtsSysMsgQ *smqp, Eterm receiver) break; case SYS_MSG_TYPE_SEQTRACE: /* Reset seq_tracer if it hasn't changed */ - erts_smp_mtx_lock(&sys_trace_mtx); + erts_smp_rwmtx_rwlock(&sys_trace_rwmtx); if (system_seq_tracer == receiver) system_seq_tracer = am_false; - erts_smp_mtx_unlock(&sys_trace_mtx); + erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx); break; case SYS_MSG_TYPE_SYSMON: if (receiver == NIL @@ -3407,12 +3251,12 @@ sys_msg_dispatcher_func(void *unused) goto queue_proc_msg; } else if (is_internal_port(receiver)) { - port = erts_id2port(receiver, NULL, 0); - if (INVALID_TRACER_PORT(port, receiver)) { - if (port) - erts_port_release(port); + port = erts_id2port_sflgs(receiver, + NULL, + 0, + ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP); + if (!port) goto failure; - } else { write_sys_msg_to_port(receiver, port, diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index 6d5eae73b0..049226ab7d 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -77,66 +77,25 @@ void erts_init_unicode(void) { max_loop_limit = CONTEXT_REDS * LOOP_FACTOR; /* Non visual BIFs to trap to. */ - memset(&characters_to_utf8_trap_exp, 0, sizeof(Export)); - characters_to_utf8_trap_exp.address = - &characters_to_utf8_trap_exp.code[3]; - characters_to_utf8_trap_exp.code[0] = am_erlang; - characters_to_utf8_trap_exp.code[1] = - am_atom_put("characters_to_utf8_trap",23); - characters_to_utf8_trap_exp.code[2] = 3; - characters_to_utf8_trap_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_utf8_trap_exp.code[4] = - (BeamInstr) &characters_to_utf8_trap; - - memset(&characters_to_list_trap_1_exp, 0, sizeof(Export)); - characters_to_list_trap_1_exp.address = - &characters_to_list_trap_1_exp.code[3]; - characters_to_list_trap_1_exp.code[0] = am_erlang; - characters_to_list_trap_1_exp.code[1] = - am_atom_put("characters_to_list_trap_1",25); - characters_to_list_trap_1_exp.code[2] = 3; - characters_to_list_trap_1_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_1_exp.code[4] = - (BeamInstr) &characters_to_list_trap_1; - - memset(&characters_to_list_trap_2_exp, 0, sizeof(Export)); - characters_to_list_trap_2_exp.address = - &characters_to_list_trap_2_exp.code[3]; - characters_to_list_trap_2_exp.code[0] = am_erlang; - characters_to_list_trap_2_exp.code[1] = - am_atom_put("characters_to_list_trap_2",25); - characters_to_list_trap_2_exp.code[2] = 3; - characters_to_list_trap_2_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_2_exp.code[4] = - (BeamInstr) &characters_to_list_trap_2; - - - memset(&characters_to_list_trap_3_exp, 0, sizeof(Export)); - characters_to_list_trap_3_exp.address = - &characters_to_list_trap_3_exp.code[3]; - characters_to_list_trap_3_exp.code[0] = am_erlang; - characters_to_list_trap_3_exp.code[1] = - am_atom_put("characters_to_list_trap_3",25); - characters_to_list_trap_3_exp.code[2] = 3; - characters_to_list_trap_3_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_3_exp.code[4] = - (BeamInstr) &characters_to_list_trap_3; - - memset(&characters_to_list_trap_4_exp, 0, sizeof(Export)); - characters_to_list_trap_4_exp.address = - &characters_to_list_trap_4_exp.code[3]; - characters_to_list_trap_4_exp.code[0] = am_erlang; - characters_to_list_trap_4_exp.code[1] = - am_atom_put("characters_to_list_trap_4",25); - characters_to_list_trap_4_exp.code[2] = 1; - characters_to_list_trap_4_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_4_exp.code[4] = - (BeamInstr) &characters_to_list_trap_4; + erts_init_trap_export(&characters_to_utf8_trap_exp, + am_erlang, am_atom_put("characters_to_utf8_trap",23), 3, + &characters_to_utf8_trap); + + erts_init_trap_export(&characters_to_list_trap_1_exp, + am_erlang, am_atom_put("characters_to_list_trap_1",25), 3, + &characters_to_list_trap_1); + + erts_init_trap_export(&characters_to_list_trap_2_exp, + am_erlang, am_atom_put("characters_to_list_trap_2",25), 3, + &characters_to_list_trap_2); + + erts_init_trap_export(&characters_to_list_trap_3_exp, + am_erlang, am_atom_put("characters_to_list_trap_3",25), 3, + &characters_to_list_trap_3); + + erts_init_trap_export(&characters_to_list_trap_4_exp, + am_erlang, am_atom_put("characters_to_list_trap_4",25), 1, + &characters_to_list_trap_4); c_to_b_int_trap_exportp = erts_export_put(am_unicode,am_characters_to_binary_int,2); c_to_l_int_trap_exportp = erts_export_put(am_unicode,am_characters_to_list_int,2); diff --git a/erts/emulator/beam/erlang_dtrace.d b/erts/emulator/beam/erlang_dtrace.d index c1024dafc4..ac9b0052e5 100644 --- a/erts/emulator/beam/erlang_dtrace.d +++ b/erts/emulator/beam/erlang_dtrace.d @@ -639,9 +639,9 @@ provider erlang { * Entry into the efile_drv.c file I/O driver * * For a list of command numbers used by this driver, see the section - * "Guide to probe arguments" in ../../../README.md. That section - * also contains explanation of the various integer and string - * arguments that may be present when any particular probe fires. + * "Guide to efile_drv.c probe arguments" in ../../../HOWTO/DTRACE.md. + * That section also contains explanation of the various integer and + * string arguments that may be present when any particular probe fires. * * NOTE: Not all Linux platforms (using SystemTap) can support * arguments beyond arg9. diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index fb0ee99119..6b5121f917 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -32,98 +32,162 @@ #define EXPORT_HASH(m,f,a) ((m)*(f)+(a)) -static IndexTable export_table; /* Not locked. */ -static Hash secondary_export_table; /* Locked. */ +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif -#include "erl_smp.h" +static IndexTable export_tables[ERTS_NUM_CODE_IX]; /* Active not locked */ -static erts_smp_rwmtx_t export_table_lock; /* Locks the secondary export table. */ +static erts_smp_atomic_t total_entries_bytes; -#define export_read_lock() erts_smp_rwmtx_rlock(&export_table_lock) -#define export_read_unlock() erts_smp_rwmtx_runlock(&export_table_lock) -#define export_write_lock() erts_smp_rwmtx_rwlock(&export_table_lock) -#define export_write_unlock() erts_smp_rwmtx_rwunlock(&export_table_lock) +#include "erl_smp.h" + +/* This lock protects the staging export table from concurrent access + * AND it protects the staging table from becoming active. + */ +erts_smp_mtx_t export_staging_lock; extern BeamInstr* em_call_error_handler; extern BeamInstr* em_call_traced_function; +struct export_entry +{ + IndexSlot slot; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ + Export* ep; +}; + +/* Helper struct that brings things together in one allocation +*/ +struct export_blob +{ + Export exp; + struct export_entry entryv[ERTS_NUM_CODE_IX]; + /* Note that entryv is not indexed by "code_ix". + */ +}; + +/* Helper struct only used as template +*/ +struct export_templ +{ + struct export_entry entry; + Export exp; +}; + +static struct export_blob* entry_to_blob(struct export_entry* ee) +{ + return (struct export_blob*) + ((char*)ee->ep - offsetof(struct export_blob,exp)); +} + void export_info(int to, void *to_arg) { #ifdef ERTS_SMP int lock = !ERTS_IS_CRASH_DUMPING; if (lock) - export_read_lock(); + export_staging_lock(); #endif - index_info(to, to_arg, &export_table); - hash_info(to, to_arg, &secondary_export_table); + index_info(to, to_arg, &export_tables[erts_active_code_ix()]); + hash_info(to, to_arg, &export_tables[erts_staging_code_ix()].htable); #ifdef ERTS_SMP if (lock) - export_read_unlock(); + export_staging_unlock(); #endif } static HashValue -export_hash(Export* x) +export_hash(struct export_entry* ee) { + Export* x = ee->ep; return EXPORT_HASH(x->code[0], x->code[1], x->code[2]); } static int -export_cmp(Export* tmpl, Export* obj) +export_cmp(struct export_entry* tmpl_e, struct export_entry* obj_e) { + Export* tmpl = tmpl_e->ep; + Export* obj = obj_e->ep; return !(tmpl->code[0] == obj->code[0] && tmpl->code[1] == obj->code[1] && tmpl->code[2] == obj->code[2]); } -static Export* -export_alloc(Export* tmpl) +static struct export_entry* +export_alloc(struct export_entry* tmpl_e) { - Export* obj = (Export*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(Export)); - - obj->fake_op_func_info_for_hipe[0] = 0; - obj->fake_op_func_info_for_hipe[1] = 0; - obj->code[0] = tmpl->code[0]; - obj->code[1] = tmpl->code[1]; - obj->code[2] = tmpl->code[2]; - obj->slot.index = -1; - obj->address = obj->code+3; - obj->code[3] = (BeamInstr) em_call_error_handler; - obj->code[4] = 0; - obj->match_prog_set = NULL; - return obj; + struct export_blob* blob; + unsigned ix; + + if (tmpl_e->slot.index == -1) { /* Template, allocate blob */ + Export* tmpl = tmpl_e->ep; + Export* obj; + + blob = (struct export_blob*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(*blob)); + erts_smp_atomic_add_nob(&total_entries_bytes, sizeof(*blob)); + obj = &blob->exp; + obj->fake_op_func_info_for_hipe[0] = 0; + obj->fake_op_func_info_for_hipe[1] = 0; + obj->code[0] = tmpl->code[0]; + obj->code[1] = tmpl->code[1]; + obj->code[2] = tmpl->code[2]; + obj->code[3] = (BeamInstr) em_call_error_handler; + obj->code[4] = 0; + + for (ix=0; ix<ERTS_NUM_CODE_IX; ix++) { + obj->addressv[ix] = obj->code+3; + + blob->entryv[ix].slot.index = -1; + blob->entryv[ix].ep = &blob->exp; + } + ix = 0; + } + else { /* Existing entry in another table, use free entry in blob */ + blob = entry_to_blob(tmpl_e); + for (ix = 0; blob->entryv[ix].slot.index >= 0; ix++) { + ASSERT(ix < ERTS_NUM_CODE_IX); + } + } + return &blob->entryv[ix]; } - -static void -export_free(Export* obj) +static void +export_free(struct export_entry* obj) { - erts_free(ERTS_ALC_T_EXPORT, (void*) obj); + struct export_blob* blob = entry_to_blob(obj); + int i; + obj->slot.index = -1; + for (i=0; i < ERTS_NUM_CODE_IX; i++) { + if (blob->entryv[i].slot.index >= 0) { + return; + } + } + erts_free(ERTS_ALC_T_EXPORT, blob); + erts_smp_atomic_add_nob(&total_entries_bytes, -sizeof(*blob)); } - void init_export_table(void) { HashFunctions f; - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; - rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; - rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; + int i; - erts_smp_rwmtx_init_opt(&export_table_lock, &rwmtx_opt, "export_tab"); + erts_smp_mtx_init(&export_staging_lock, "export_tab"); + erts_smp_atomic_init_nob(&total_entries_bytes, 0); f.hash = (H_FUN) export_hash; f.cmp = (HCMP_FUN) export_cmp; f.alloc = (HALLOC_FUN) export_alloc; f.free = (HFREE_FUN) export_free; - erts_index_init(ERTS_ALC_T_EXPORT_TABLE, &export_table, "export_list", - EXPORT_INITIAL_SIZE, EXPORT_LIMIT, f); - hash_init(ERTS_ALC_T_EXPORT_TABLE, &secondary_export_table, - "secondary_export_table", 50, f); + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + erts_index_init(ERTS_ALC_T_EXPORT_TABLE, &export_tables[i], "export_list", + EXPORT_INITIAL_SIZE, EXPORT_LIMIT, f); + } } /* @@ -138,29 +202,42 @@ init_export_table(void) * called through such an export entry. * 3) This function is suitable for the implementation of erlang:apply/3. */ +extern Export* /* inline-helper */ +erts_find_export_entry(Eterm m, Eterm f, unsigned int a,ErtsCodeIndex code_ix); Export* -erts_find_export_entry(Eterm m, Eterm f, unsigned int a) +erts_find_export_entry(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) { HashValue hval = EXPORT_HASH((BeamInstr) m, (BeamInstr) f, (BeamInstr) a); int ix; HashBucket* b; - ix = hval % export_table.htable.size; - b = export_table.htable.bucket[ix]; + ix = hval % export_tables[code_ix].htable.size; + b = export_tables[code_ix].htable.bucket[ix]; /* * Note: We have inlined the code from hash.c for speed. */ while (b != (HashBucket*) 0) { - Export* ep = (Export *) b; + Export* ep = ((struct export_entry*) b)->ep; if (ep->code[0] == m && ep->code[1] == f && ep->code[2] == a) { - break; + return ep; } b = b->next; } - return (Export*)b; + return NULL; +} + +static struct export_entry* init_template(struct export_templ* templ, + Eterm m, Eterm f, unsigned a) +{ + templ->entry.ep = &templ->exp; + templ->entry.slot.index = -1; + templ->exp.code[0] = m; + templ->exp.code[1] = f; + templ->exp.code[2] = a; + return &templ->entry; } @@ -176,47 +253,42 @@ erts_find_export_entry(Eterm m, Eterm f, unsigned int a) */ Export* -erts_find_function(Eterm m, Eterm f, unsigned int a) +erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) { - Export e; - Export* ep; - - e.code[0] = m; - e.code[1] = f; - e.code[2] = a; - - ep = hash_get(&export_table.htable, (void*) &e); - if (ep != NULL && ep->address == ep->code+3 && - ep->code[3] != (BeamInstr) em_call_traced_function) { - ep = NULL; + struct export_templ templ; + struct export_entry* ee; + + ee = hash_get(&export_tables[code_ix].htable, init_template(&templ, m, f, a)); + if (ee == NULL || + (ee->ep->addressv[code_ix] == ee->ep->code+3 && + ee->ep->code[3] != (BeamInstr) BeamOp(op_i_generic_breakpoint))) { + return NULL; } - return ep; + return ee->ep; } /* * Returns a pointer to an existing export entry for a MFA, * or creates a new one and returns the pointer. * - * This function provides unlocked write access to the main export - * table. It should only be used during start up or when - * all other threads are blocked. + * This function acts on the staging export table. It should only be used + * to load new code. */ Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity) { - Export e; - int ix; + ErtsCodeIndex code_ix = erts_staging_code_ix(); + struct export_templ templ; + struct export_entry* ee; - ERTS_SMP_LC_ASSERT(erts_initialized == 0 - || erts_smp_thr_progress_is_blocking()); ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - e.code[0] = mod; - e.code[1] = func; - e.code[2] = arity; - ix = index_put(&export_table, (void*) &e); - return (Export*) erts_index_lookup(&export_table, ix); + export_staging_lock(); + ee = (struct export_entry*) index_put_entry(&export_tables[code_ix], + init_template(&templ, mod, func, arity)); + export_staging_unlock(); + return ee->ep; } /* @@ -224,77 +296,117 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) * export entry (making a call through it will cause the error_handler to * be called). * - * Stub export entries will be placed in the secondary export table. - * erts_export_consolidate() will move all stub export entries into the - * main export table (will be done the next time code is loaded). + * Stub export entries will be placed in the loader export table. */ Export* erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) { - Export e; + ErtsCodeIndex code_ix; Export* ep; + IF_DEBUG(int retrying = 0;) ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - - e.code[0] = mod; - e.code[1] = func; - e.code[2] = arity; - ep = erts_find_export_entry(mod, func, arity); - if (ep == 0) { - /* - * The code is not loaded (yet). Put the export in the secondary - * export table, to avoid having to lock the main export table. - */ - export_write_lock(); - ep = (Export *) hash_put(&secondary_export_table, (void*) &e); - export_write_unlock(); - } + + do { + code_ix = erts_active_code_ix(); + ep = erts_find_export_entry(mod, func, arity, code_ix); + if (ep == 0) { + /* + * The code is not loaded (yet). Put the export in the staging + * export table, to avoid having to lock the active export table. + */ + export_staging_lock(); + if (erts_active_code_ix() == code_ix) { + struct export_templ templ; + struct export_entry* entry; + + IndexTable* tab = &export_tables[erts_staging_code_ix()]; + init_template(&templ, mod, func, arity); + entry = (struct export_entry *) index_put_entry(tab, &templ.entry); + ep = entry->ep; + ASSERT(ep); + } + else { /* race */ + ASSERT(!retrying); + IF_DEBUG(retrying = 1); + } + export_staging_unlock(); + } + } while (!ep); return ep; } -/* - * To be called before loading code (with other threads blocked). - * This function will move all export entries from the secondary - * export table into the primary. - */ -void -erts_export_consolidate(void) +Export *export_list(int i, ErtsCodeIndex code_ix) { -#ifdef DEBUG - HashInfo hi; -#endif - - ERTS_SMP_LC_ASSERT(erts_initialized == 0 - || erts_smp_thr_progress_is_blocking()); - - export_write_lock(); - erts_index_merge(&secondary_export_table, &export_table); - erts_hash_merge(&secondary_export_table, &export_table.htable); - export_write_unlock(); -#ifdef DEBUG - hash_get_info(&hi, &export_table.htable); - ASSERT(export_table.entries == hi.objs); -#endif + return ((struct export_entry*) erts_index_lookup(&export_tables[code_ix], i))->ep; } -Export *export_list(int i) +int export_list_size(ErtsCodeIndex code_ix) { - return (Export*) erts_index_lookup(&export_table, i); + return export_tables[code_ix].entries; } -int export_list_size(void) +int export_table_sz(void) +{ + int i, bytes = 0; + + export_staging_lock(); + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + bytes += index_table_sz(&export_tables[i]); + } + export_staging_unlock(); + return bytes; +} +int export_entries_sz(void) { - return export_table.entries; + return erts_smp_atomic_read_nob(&total_entries_bytes); } +Export *export_get(Export *e) +{ + struct export_entry ee; + struct export_entry* entry; -int export_table_sz(void) + ee.ep = e; + entry = (struct export_entry*)hash_get(&export_tables[erts_active_code_ix()].htable, &ee); + return entry ? entry->ep : NULL; +} + +IF_DEBUG(static ErtsCodeIndex debug_start_load_ix = 0;) + + +void export_start_staging(void) { - return index_table_sz(&export_table); + ErtsCodeIndex dst_ix = erts_staging_code_ix(); + ErtsCodeIndex src_ix = erts_active_code_ix(); + IndexTable* dst = &export_tables[dst_ix]; + IndexTable* src = &export_tables[src_ix]; + struct export_entry* src_entry; + struct export_entry* dst_entry; + int i; + + ASSERT(dst_ix != src_ix); + ASSERT(debug_start_load_ix == -1); + + export_staging_lock(); + /* + * Insert all entries in src into dst table + */ + for (i = 0; i < src->entries; i++) { + src_entry = (struct export_entry*) erts_index_lookup(src, i); + src_entry->ep->addressv[dst_ix] = src_entry->ep->addressv[src_ix]; + dst_entry = (struct export_entry*) index_put_entry(dst, src_entry); + ASSERT(entry_to_blob(src_entry) == entry_to_blob(dst_entry)); + } + export_staging_unlock(); + + IF_DEBUG(debug_start_load_ix = dst_ix); } -Export *export_get(Export *e) +void export_end_staging(int commit) { - return hash_get(&export_table.htable, e); + ASSERT(debug_start_load_ix == erts_staging_code_ix()); + IF_DEBUG(debug_start_load_ix = -1); } + diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index c604fdf7c3..ee06e69aff 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -28,14 +28,15 @@ #include "index.h" #endif +#include "code_ix.h" + /* ** Export entry */ + typedef struct export { - IndexSlot slot; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ - void* address; /* Pointer to code for function. */ - struct binary* match_prog_set; /* Match program for tracing. */ + void* addressv[ERTS_NUM_CODE_IX]; /* Pointer to code for function. */ BeamInstr fake_op_func_info_for_hipe[2]; /* MUST be just before code[] */ /* @@ -44,12 +45,12 @@ typedef struct export * code[2]: Arity (untagged integer). * code[3]: This entry is 0 unless the 'address' field points to it. * Threaded code instruction to load function - * (em_call_error_handler), execute BIF (em_apply_bif, - * em_apply_apply), or call a traced function - * (em_call_traced_function). - * code[4]: Function pointer to BIF function (for BIFs only) + * (em_call_error_handler), execute BIF (em_apply_bif), + * or a breakpoint instruction (op_i_generic_breakpoint). + * code[4]: Function pointer to BIF function (for BIFs only), * or pointer to threaded code if the module has an - * on_load function that has not been run yet. + * on_load function that has not been run yet, or pointer + * to code for function code[3] is a breakpont instruction. * Otherwise: 0. */ BeamInstr code[5]; @@ -59,21 +60,38 @@ typedef struct export void init_export_table(void); void export_info(int, void *); -Export* erts_find_export_entry(Eterm m, Eterm f, unsigned int a); +ERTS_GLB_INLINE Export* erts_active_export_entry(Eterm m, Eterm f, unsigned a); Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity); - Export* erts_export_get_or_make_stub(Eterm, Eterm, unsigned); -void erts_export_consolidate(void); -Export *export_list(int); -int export_list_size(void); +Export *export_list(int,ErtsCodeIndex); +int export_list_size(ErtsCodeIndex); int export_table_sz(void); +int export_entries_sz(void); Export *export_get(Export*); +void export_start_staging(void); +void export_end_staging(int commit); + +extern erts_smp_mtx_t export_staging_lock; +#define export_staging_lock() erts_smp_mtx_lock(&export_staging_lock) +#define export_staging_unlock() erts_smp_mtx_unlock(&export_staging_lock) #include "beam_load.h" /* For em_* extern declarations */ #define ExportIsBuiltIn(EntryPtr) \ -(((EntryPtr)->address == (EntryPtr)->code + 3) && \ +(((EntryPtr)->addressv[erts_active_code_ix()] == (EntryPtr)->code + 3) && \ ((EntryPtr)->code[3] == (BeamInstr) em_apply_bif)) -#endif +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE Export* +erts_active_export_entry(Eterm m, Eterm f, unsigned int a) +{ + extern Export* erts_find_export_entry(Eterm m, Eterm f, unsigned a, ErtsCodeIndex); + return erts_find_export_entry(m, f, a, erts_active_code_ix()); +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + +#endif /* __EXPORT_H__ */ + diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 52f45b924f..16a987472a 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -2564,7 +2564,7 @@ dec_term_atom_common: goto error; } if (edep && (edep->flags & ERTS_DIST_EXT_BTT_SAFE)) { - if (!erts_find_export_entry(mod, name, arity)) + if (!erts_active_export_entry(mod, name, arity)) goto error; } *objp = make_export(hp); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 1b15c4ac3b..c9be20322d 100755 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -28,6 +28,7 @@ #include "hash.h" #include "index.h" #include "atom.h" +#include "code_ix.h" #include "export.h" #include "module.h" #include "register.h" @@ -143,8 +144,8 @@ typedef struct ErtsXPortsList_ ErtsXPortsList; struct port { ErtsPortTaskSched sched; ErtsPortTaskHandle timeout_task; -#ifdef ERTS_SMP erts_smp_atomic_t refc; +#ifdef ERTS_SMP erts_smp_mtx_t *lock; ErtsXPortsList *xports; erts_smp_atomic_t run_queue; @@ -197,6 +198,8 @@ erts_port_runq(Port *prt) #ifdef ERTS_SMP ErtsRunQueue *rq1, *rq2; rq1 = (ErtsRunQueue *) erts_smp_atomic_read_nob(&prt->run_queue); + if (!rq1) + return NULL; while (1) { erts_smp_runq_lock(rq1); rq2 = (ErtsRunQueue *) erts_smp_atomic_read_nob(&prt->run_queue); @@ -204,6 +207,8 @@ erts_port_runq(Port *prt) return rq1; erts_smp_runq_unlock(rq1); rq1 = rq2; + if (!rq1) + return NULL; } #else return ERTS_RUNQ_IX(0); @@ -764,6 +769,8 @@ void erts_queue_monitor_message(Process *, Eterm, Eterm, Eterm); +void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a, + Eterm (*bif)(Process*,Eterm*)); void erts_init_bif(void); Eterm erl_send(Process *p, Eterm to, Eterm msg); @@ -786,24 +793,33 @@ typedef struct { Eterm* fname_ptr; /* Pointer to fname table */ } FunctionInfo; -struct LoaderState* erts_alloc_loader_state(void); -Eterm erts_prepare_loading(struct LoaderState*, Process *c_p, +Binary* erts_alloc_loader_state(void); +Eterm erts_module_for_prepared_code(Binary* magic); +Eterm erts_prepare_loading(Binary* loader_state, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint size); -Eterm erts_finish_loading(struct LoaderState* stp, Process* c_p, +Eterm erts_finish_loading(Binary* loader_state, Process* c_p, ErtsProcLocks c_p_locks, Eterm* modp); -Eterm erts_load_module(Process *c_p, ErtsProcLocks c_p_locks, - Eterm group_leader, Eterm* mod, byte* code, Uint size); +Eterm erts_preload_module(Process *c_p, ErtsProcLocks c_p_locks, + Eterm group_leader, Eterm* mod, byte* code, Uint size); void init_load(void); BeamInstr* find_function_from_pc(BeamInstr* pc); Eterm* erts_build_mfa_item(FunctionInfo* fi, Eterm* hp, Eterm args, Eterm* mfa_p); -void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info); void erts_set_current_function(FunctionInfo* fi, BeamInstr* current); Eterm erts_module_info_0(Process* p, Eterm module); Eterm erts_module_info_1(Process* p, Eterm module, Eterm what); Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info); +/* beam_ranges.c */ +void erts_init_ranges(void); +void erts_start_staging_ranges(void); +void erts_end_staging_ranges(int commit); +void erts_update_ranges(BeamInstr* code, Uint size); +void erts_remove_from_ranges(BeamInstr* code); +UWord erts_ranges_sz(void); +void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info); + /* break.c */ void init_break_handler(void); void erts_set_ignore_break(void); @@ -1024,28 +1040,29 @@ erts_smp_port_state_unlock(Port *prt) ERTS_GLB_INLINE int erts_smp_port_trylock(Port *prt) { -#ifdef ERTS_SMP int res; ASSERT(erts_smp_atomic_read_nob(&prt->refc) > 0); erts_smp_atomic_inc_nob(&prt->refc); + +#ifdef ERTS_SMP res = erts_smp_mtx_trylock(prt->lock); if (res == EBUSY) { erts_smp_atomic_dec_nob(&prt->refc); } +#else + res = 0; +#endif return res; -#else /* !ERTS_SMP */ - return 0; -#endif } ERTS_GLB_INLINE void erts_smp_port_lock(Port *prt) { -#ifdef ERTS_SMP ASSERT(erts_smp_atomic_read_nob(&prt->refc) > 0); erts_smp_atomic_inc_nob(&prt->refc); +#ifdef ERTS_SMP erts_smp_mtx_lock(prt->lock); #endif } @@ -1053,14 +1070,14 @@ erts_smp_port_lock(Port *prt) ERTS_GLB_INLINE void erts_smp_port_unlock(Port *prt) { -#ifdef ERTS_SMP erts_aint_t refc; +#ifdef ERTS_SMP erts_smp_mtx_unlock(prt->lock); +#endif refc = erts_smp_atomic_dec_read_nob(&prt->refc); ASSERT(refc >= 0); if (refc == 0) erts_port_cleanup(prt); -#endif } #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ @@ -1123,12 +1140,12 @@ erts_id2port_sflgs(Eterm id, Process *c_p, ErtsProcLocks c_p_locks, Uint32 sflgs erts_smp_port_state_unlock(prt); prt = NULL; } -#ifdef ERTS_SMP else { erts_smp_atomic_inc_nob(&prt->refc); erts_smp_port_state_unlock(prt); - if (no_proc_locks) +#ifdef ERTS_SMP + if (no_proc_locks) erts_smp_mtx_lock(prt->lock); else if (erts_smp_mtx_trylock(prt->lock) == EBUSY) { /* Unlock process locks, and acquire locks in lock order... */ @@ -1144,21 +1161,17 @@ erts_id2port_sflgs(Eterm id, Process *c_p, ErtsProcLocks c_p_locks, Uint32 sflgs erts_smp_port_unlock(prt); /* Also decrements refc... */ prt = NULL; } - } #endif + } + return prt; } ERTS_GLB_INLINE void erts_port_release(Port *prt) { -#ifdef ERTS_SMP erts_smp_port_unlock(prt); -#else - if (prt->status & ERTS_PORT_SFLGS_DEAD) - erts_port_cleanup(prt); -#endif } ERTS_GLB_INLINE Port* @@ -1275,6 +1288,122 @@ void erl_drv_thr_init(void); /* utils.c */ +typedef struct { +#ifdef DEBUG + int smp_api; +#endif + union { + Uint64 not_atomic; +#ifdef ARCH_64 + erts_atomic_t atomic; +#else + erts_dw_atomic_t atomic; +#endif + } counter; +} erts_interval_t; + +void erts_interval_init(erts_interval_t *); +void erts_smp_interval_init(erts_interval_t *); +Uint64 erts_step_interval_nob(erts_interval_t *); +Uint64 erts_step_interval_relb(erts_interval_t *); +Uint64 erts_smp_step_interval_nob(erts_interval_t *); +Uint64 erts_smp_step_interval_relb(erts_interval_t *); +Uint64 erts_ensure_later_interval_nob(erts_interval_t *, Uint64); +Uint64 erts_ensure_later_interval_acqb(erts_interval_t *, Uint64); +Uint64 erts_smp_ensure_later_interval_nob(erts_interval_t *, Uint64); +Uint64 erts_smp_ensure_later_interval_acqb(erts_interval_t *, Uint64); +#ifdef ARCH_32 +ERTS_GLB_INLINE Uint64 erts_interval_dw_aint_to_val__(erts_dw_aint_t *); +#endif +ERTS_GLB_INLINE Uint64 erts_current_interval_nob__(erts_interval_t *); +ERTS_GLB_INLINE Uint64 erts_current_interval_acqb__(erts_interval_t *); +ERTS_GLB_INLINE Uint64 erts_current_interval_nob(erts_interval_t *); +ERTS_GLB_INLINE Uint64 erts_current_interval_acqb(erts_interval_t *); +ERTS_GLB_INLINE Uint64 erts_smp_current_interval_nob(erts_interval_t *); +ERTS_GLB_INLINE Uint64 erts_smp_current_interval_acqb(erts_interval_t *); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +#ifdef ARCH_32 + +ERTS_GLB_INLINE Uint64 +erts_interval_dw_aint_to_val__(erts_dw_aint_t *dw) +{ +#ifdef ETHR_SU_DW_NAINT_T__ + return (Uint64) dw->dw_sint; +#else + Uint64 res; + res = (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_HIGH_WORD]); + res <<= 32; + res |= (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_LOW_WORD]); + return res; +#endif +} + +#endif + +ERTS_GLB_INLINE Uint64 +erts_current_interval_nob__(erts_interval_t *icp) +{ +#ifdef ARCH_64 + return (Uint64) erts_atomic_read_nob(&icp->counter.atomic); +#else + erts_dw_aint_t dw; + erts_dw_atomic_read_nob(&icp->counter.atomic, &dw); + return erts_interval_dw_aint_to_val__(&dw); +#endif +} + +ERTS_GLB_INLINE Uint64 +erts_current_interval_acqb__(erts_interval_t *icp) +{ +#ifdef ARCH_64 + return (Uint64) erts_atomic_read_acqb(&icp->counter.atomic); +#else + erts_dw_aint_t dw; + erts_dw_atomic_read_acqb(&icp->counter.atomic, &dw); + return erts_interval_dw_aint_to_val__(&dw); +#endif +} + +ERTS_GLB_INLINE Uint64 +erts_current_interval_nob(erts_interval_t *icp) +{ + ASSERT(!icp->smp_api); + return erts_current_interval_nob__(icp); +} + +ERTS_GLB_INLINE Uint64 +erts_current_interval_acqb(erts_interval_t *icp) +{ + ASSERT(!icp->smp_api); + return erts_current_interval_acqb__(icp); +} + +ERTS_GLB_INLINE Uint64 +erts_smp_current_interval_nob(erts_interval_t *icp) +{ + ASSERT(icp->smp_api); +#ifdef ERTS_SMP + return erts_current_interval_nob__(icp); +#else + return icp->counter.not_atomic; +#endif +} + +ERTS_GLB_INLINE Uint64 +erts_smp_current_interval_acqb(erts_interval_t *icp) +{ + ASSERT(icp->smp_api); +#ifdef ERTS_SMP + return erts_current_interval_acqb__(icp); +#else + return icp->counter.not_atomic; +#endif +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + /* * To be used to silence unused result warnings, but do not abuse it. */ @@ -1282,9 +1411,10 @@ void erts_silence_warn_unused_result(long unused); void erts_cleanup_offheap(ErlOffHeap *offheap); -Uint erts_fit_in_bits(Uint); +int erts_fit_in_bits_int64(Sint64); +int erts_fit_in_bits_int32(Sint32); int list_length(Eterm); -Export* erts_find_function(Eterm, Eterm, unsigned int); +Export* erts_find_function(Eterm, Eterm, unsigned int, ErtsCodeIndex); int erts_is_builtin(Eterm, Eterm, int); Uint32 make_broken_hash(Eterm); Uint32 block_hash(byte *, unsigned, Uint32); @@ -1552,17 +1682,19 @@ struct trace_pattern_flags { }; extern const struct trace_pattern_flags erts_trace_pattern_flags_off; extern int erts_call_time_breakpoint_tracing; -int erts_set_trace_pattern(Eterm* mfa, int specified, +int erts_set_trace_pattern(Process*p, Eterm* mfa, int specified, Binary* match_prog_set, Binary *meta_match_prog_set, int on, struct trace_pattern_flags, - Eterm meta_tracer_pid); + Eterm meta_tracer_pid, int is_blocking); void erts_get_default_trace_pattern(int *trace_pattern_is_on, Binary **match_spec, Binary **meta_match_spec, struct trace_pattern_flags *trace_pattern_flags, Eterm *meta_tracer_pid); +int erts_is_default_trace_enabled(void); void erts_bif_trace_init(void); +int erts_finish_breakpointing(void); /* ** Call_trace uses this API for the parameter matching functions @@ -1608,20 +1740,19 @@ extern void erts_match_prog_foreach_offheap(Binary *b, breakpoint functions */ #define MATCH_SET_EXCEPTION_TRACE (0x4) /* exception trace requested */ #define MATCH_SET_RX_TRACE (MATCH_SET_RETURN_TRACE|MATCH_SET_EXCEPTION_TRACE) -/* - * Flag values when tracing bif - * Future note: flag field is 8 bits - */ -#define BIF_TRACE_AS_LOCAL (0x1) -#define BIF_TRACE_AS_GLOBAL (0x2) -#define BIF_TRACE_AS_META (0x4) -#define BIF_TRACE_AS_CALL_TIME (0x8) extern erts_driver_t vanilla_driver; extern erts_driver_t spawn_driver; extern erts_driver_t fd_driver; /* Should maybe be placed in erl_message.h, but then we get an include mess. */ +ERTS_GLB_INLINE Eterm * +erts_alloc_message_heap_state(Uint size, + ErlHeapFragment **bpp, + ErlOffHeap **ohpp, + Process *receiver, + ErtsProcLocks *receiver_locks, + erts_aint32_t *statep); ERTS_GLB_INLINE Eterm * erts_alloc_message_heap(Uint size, @@ -1644,16 +1775,22 @@ erts_alloc_message_heap(Uint size, */ ERTS_GLB_INLINE Eterm * -erts_alloc_message_heap(Uint size, - ErlHeapFragment **bpp, - ErlOffHeap **ohpp, - Process *receiver, - ErtsProcLocks *receiver_locks) +erts_alloc_message_heap_state(Uint size, + ErlHeapFragment **bpp, + ErlOffHeap **ohpp, + Process *receiver, + ErtsProcLocks *receiver_locks, + erts_aint32_t *statep) { Eterm *hp; + erts_aint32_t state; #ifdef ERTS_SMP int locked_main = 0; - ErtsProcLocks ulocks = *receiver_locks & ERTS_PROC_LOCKS_MSG_SEND; + state = erts_smp_atomic32_read_acqb(&receiver->state); + if (statep) + *statep = state; + if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) + goto allocate_in_mbuf; #endif if (size > (Uint) INT_MAX) @@ -1669,20 +1806,19 @@ erts_alloc_message_heap(Uint size, #ifdef ERTS_SMP try_allocate_on_heap: #endif - if (ERTS_PROC_IS_EXITING(receiver) + state = erts_smp_atomic32_read_nob(&receiver->state); + if (statep) + *statep = state; + if ((state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) || HEAP_LIMIT(receiver) - HEAP_TOP(receiver) <= size) { #ifdef ERTS_SMP - if (locked_main) - ulocks |= ERTS_PROC_LOCK_MAIN; + if (locked_main) { + *receiver_locks &= ~ERTS_PROC_LOCK_MAIN; + erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MAIN); + } #endif goto allocate_in_mbuf; } -#ifdef ERTS_SMP - if (ulocks) { - erts_smp_proc_unlock(receiver, ulocks); - *receiver_locks &= ~ulocks; - } -#endif hp = HEAP_TOP(receiver); HEAP_TOP(receiver) = hp + size; *bpp = NULL; @@ -1698,12 +1834,6 @@ erts_alloc_message_heap(Uint size, else { ErlHeapFragment *bp; allocate_in_mbuf: -#ifdef ERTS_SMP - if (ulocks) { - *receiver_locks &= ~ulocks; - erts_smp_proc_unlock(receiver, ulocks); - } -#endif bp = new_message_buffer(size); hp = bp->mem; *bpp = bp; @@ -1713,6 +1843,17 @@ erts_alloc_message_heap(Uint size, return hp; } +ERTS_GLB_INLINE Eterm * +erts_alloc_message_heap(Uint size, + ErlHeapFragment **bpp, + ErlOffHeap **ohpp, + Process *receiver, + ErtsProcLocks *receiver_locks) +{ + return erts_alloc_message_heap_state(size, bpp, ohpp, receiver, + receiver_locks, NULL); +} + #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ #if !HEAP_ON_C_STACK diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c index a4a3007f93..25d5cce0f3 100644 --- a/erts/emulator/beam/index.c +++ b/erts/emulator/beam/index.c @@ -68,14 +68,14 @@ erts_index_init(ErtsAlcType_t type, IndexTable* t, char* name, return t; } -int -index_put(IndexTable* t, void* tmpl) +IndexSlot* +index_put_entry(IndexTable* t, void* tmpl) { int ix; IndexSlot* p = (IndexSlot*) hash_put(&t->htable, tmpl); if (p->index >= 0) { - return p->index; + return p; } ix = t->entries; @@ -92,7 +92,7 @@ index_put(IndexTable* t, void* tmpl) t->entries++; p->index = ix; t->seg_table[ix>>INDEX_PAGE_SHIFT][ix&INDEX_PAGE_MASK] = p; - return ix; + return p; } int index_get(IndexTable* t, void* tmpl) @@ -135,3 +135,18 @@ void erts_index_merge(Hash* src, IndexTable* dst) } } } + +void index_erase_latest_from(IndexTable* t, Uint from_ix) +{ + if(from_ix < (Uint)t->entries) { + int ix; + for (ix = from_ix; ix < t->entries; ix++) { + IndexSlot* obj = t->seg_table[ix>>INDEX_PAGE_SHIFT][ix&INDEX_PAGE_MASK]; + hash_erase(&t->htable, obj); + } + t->entries = from_ix; + } + else { + ASSERT(from_ix == t->entries); + } +} diff --git a/erts/emulator/beam/index.h b/erts/emulator/beam/index.h index 4eb9b1f992..3afe48d007 100644 --- a/erts/emulator/beam/index.h +++ b/erts/emulator/beam/index.h @@ -55,12 +55,24 @@ void index_info(int, void *, IndexTable*); int index_table_sz(IndexTable *); int index_get(IndexTable*, void*); -int index_put(IndexTable*, void*); + +IndexSlot* index_put_entry(IndexTable*, void*); void erts_index_merge(Hash*, IndexTable*); +/* Erase all entries with index 'ix' and higher +*/ +void index_erase_latest_from(IndexTable*, Uint ix); + +ERTS_GLB_INLINE int index_put(IndexTable*, void*); ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable*, Uint); #if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE int index_put(IndexTable* t, void* tmpl) +{ + return index_put_entry(t, tmpl)->index; +} + ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable* t, Uint ix) { diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 204bff299e..845593d0b2 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -259,10 +259,8 @@ get_free_port(void) } } port->status = ERTS_PORT_SFLG_INITIALIZING; -#ifdef ERTS_SMP - ERTS_SMP_LC_ASSERT(erts_smp_atomic_read_nob(&port->refc) == 0); + ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&port->refc) == 0); erts_smp_atomic_set_nob(&port->refc, 2); /* Port alive + lock */ -#endif erts_smp_port_state_unlock(port); return num & port_num_mask; } @@ -340,10 +338,14 @@ port_cleanup(Port *prt) prt->drv_ptr = NULL; ASSERT(driver); -#ifdef ERTS_SMP - ASSERT(prt->status & ERTS_PORT_SFLG_FREE_SCHEDULED); - ERTS_SMP_LC_ASSERT(erts_smp_atomic_read_nob(&prt->refc) == 0); + ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&prt->refc) == 0); + + ASSERT(prt->status & ERTS_PORT_SFLG_PORT_DEBUG); + ASSERT(!(prt->status & ERTS_PORT_SFLG_FREE)); + prt->status = ERTS_PORT_SFLG_FREE; + +#ifdef ERTS_SMP port_specific = (prt->status & ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK); @@ -352,10 +354,6 @@ port_cleanup(Port *prt) prt->lock = NULL; - ASSERT(prt->status & ERTS_PORT_SFLG_PORT_DEBUG); - ASSERT(!(prt->status & ERTS_PORT_SFLG_FREE)); - prt->status = ERTS_PORT_SFLG_FREE; - erts_smp_port_state_unlock(prt); erts_smp_mtx_unlock(mtx); @@ -606,10 +604,8 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ /* Need to mark the port as free again */ erts_smp_port_state_lock(port); port->status = ERTS_PORT_SFLG_FREE; -#ifdef ERTS_SMP - ERTS_SMP_LC_ASSERT(erts_smp_atomic_read_nob(&port->refc) == 2); + ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&port->refc) == 2); erts_smp_atomic_set_nob(&port->refc, 0); -#endif erts_smp_port_state_unlock(port); return -3; } @@ -1330,7 +1326,7 @@ void init_io(void) erts_max_ports = ERTS_MAX_R9_PORTS; } - port_extra_shift = erts_fit_in_bits(erts_max_ports - 1); + port_extra_shift = erts_fit_in_bits_int32(erts_max_ports - 1); port_num_mask = (1 << ports_bits) - 1; erts_port_tab_index_mask = ~(~((Uint) 0) << port_extra_shift); @@ -1354,8 +1350,8 @@ void init_io(void) for (i = 0; i < erts_max_ports; i++) { erts_port_task_init_sched(&erts_port[i].sched); -#ifdef ERTS_SMP erts_smp_atomic_init_nob(&erts_port[i].refc, 0); +#ifdef ERTS_SMP erts_port[i].lock = NULL; erts_port[i].xports = NULL; erts_smp_spinlock_init_x(&erts_port[i].state_lck, @@ -1594,6 +1590,7 @@ deliver_result(Eterm sender, Eterm pid, Eterm res) { Process *rp; ErtsProcLocks rp_locks = 0; + int scheduler = erts_get_scheduler_id() != 0; ERTS_SMP_CHK_NO_PROC_LOCKS; @@ -1601,7 +1598,9 @@ deliver_result(Eterm sender, Eterm pid, Eterm res) && is_internal_pid(pid) && internal_pid_index(pid) < erts_max_processes); - rp = erts_pid2proc_opt(NULL, 0, pid, 0, ERTS_P2P_FLG_SMP_INC_REFC); + rp = (scheduler + ? erts_proc_lookup(pid) + : erts_pid2proc_opt(NULL, 0, pid, 0, ERTS_P2P_FLG_SMP_INC_REFC)); if (rp) { Eterm tuple; @@ -1619,7 +1618,9 @@ deliver_result(Eterm sender, Eterm pid, Eterm res) #endif ); erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); + if (!scheduler) + erts_smp_proc_dec_refc(rp); + } } @@ -1644,6 +1645,7 @@ static void deliver_read_message(Port* prt, Eterm to, ErlHeapFragment *bp; ErlOffHeap *ohp; ErtsProcLocks rp_locks = 0; + int scheduler = erts_get_scheduler_id() != 0; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); ERTS_SMP_CHK_NO_PROC_LOCKS; @@ -1658,7 +1660,10 @@ static void deliver_read_message(Port* prt, Eterm to, need += 2*len; } - rp = erts_pid2proc_opt(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC); + rp = (scheduler + ? erts_proc_lookup(to) + : erts_pid2proc_opt(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC)); + if (!rp) return; @@ -1711,8 +1716,10 @@ static void deliver_read_message(Port* prt, Eterm to, , NIL #endif ); - erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); + if (rp_locks) + erts_smp_proc_unlock(rp, rp_locks); + if (!scheduler) + erts_smp_proc_dec_refc(rp); } /* @@ -1779,6 +1786,7 @@ deliver_vec_message(Port* prt, /* Port */ ErlHeapFragment *bp; ErlOffHeap *ohp; ErtsProcLocks rp_locks = 0; + int scheduler = erts_get_scheduler_id() != 0; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); ERTS_SMP_CHK_NO_PROC_LOCKS; @@ -1787,7 +1795,10 @@ deliver_vec_message(Port* prt, /* Port */ * Check arguments for validity. */ - rp = erts_pid2proc_opt(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC); + + rp = (scheduler + ? erts_proc_lookup(to) + : erts_pid2proc_opt(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC)); if (!rp) return; @@ -1869,7 +1880,8 @@ deliver_vec_message(Port* prt, /* Port */ #endif ); erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); + if (!scheduler) + erts_smp_proc_dec_refc(rp); } @@ -2277,9 +2289,8 @@ void erts_port_command(Process *proc, { ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; - Process* rp = erts_pid2proc_opt(NULL, 0, - port->connected, rp_locks, - ERTS_P2P_FLG_SMP_INC_REFC); + Process* rp = erts_pid2proc(NULL, 0, + port->connected, rp_locks); if (rp) { (void) erts_send_exit_signal(NULL, port->id, @@ -2290,7 +2301,6 @@ void erts_port_command(Process *proc, NULL, 0); erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); } } @@ -2841,13 +2851,17 @@ void driver_report_exit(int ix, int status) ErlHeapFragment *bp = NULL; ErlOffHeap *ohp; ErtsProcLocks rp_locks = 0; + int scheduler = erts_get_scheduler_id() != 0; ERTS_SMP_CHK_NO_PROC_LOCKS; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); pid = prt->connected; ASSERT(is_internal_pid(pid)); - rp = erts_pid2proc_opt(NULL, 0, pid, 0, ERTS_P2P_FLG_SMP_INC_REFC); + + rp = (scheduler + ? erts_proc_lookup(pid) + : erts_pid2proc_opt(NULL, 0, pid, 0, ERTS_P2P_FLG_SMP_INC_REFC)); if (!rp) return; @@ -2864,7 +2878,8 @@ void driver_report_exit(int ix, int status) ); erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); + if (!scheduler) + erts_smp_proc_dec_refc(rp); } @@ -2995,6 +3010,7 @@ driver_deliver_term(ErlDrvPort port, ErlOffHeap *ohp; ErtsProcLocks rp_locks = 0; struct b2t_states__ b2t; + int scheduler = 1; /* Silence erroneous warning... */ init_b2t_states(&b2t); @@ -3186,7 +3202,13 @@ driver_deliver_term(ErlDrvPort port, if (res <= 0) goto done; - rp = erts_pid2proc_opt(NULL, 0, to, rp_locks, ERTS_P2P_FLG_SMP_INC_REFC); + /* + * Increase refc on proc if done from a non-scheduler thread. + */ + scheduler = erts_get_scheduler_id() != 0; + rp = (scheduler + ? erts_proc_lookup(to) + : erts_pid2proc_opt(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC)); if (!rp) { res = 0; goto done; @@ -3438,7 +3460,8 @@ driver_deliver_term(ErlDrvPort port, if (rp) { if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); - erts_smp_proc_dec_refc(rp); + if (!scheduler) + erts_smp_proc_dec_refc(rp); } #endif cleanup_b2t_states(&b2t); diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index b93b1ad09a..1ef71cda79 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -26,21 +26,32 @@ #include "global.h" #include "module.h" +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + #define MODULE_SIZE 50 #define MODULE_LIMIT (64*1024) -static IndexTable module_table; +static IndexTable module_tables[ERTS_NUM_CODE_IX]; -/* - * SMP note: We don't need to look accesses to the module table because - * there is one only scheduler thread when we update it. +erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; + +static erts_smp_atomic_t tot_module_bytes; + +/* SMP note: Active module table lookup and current module instance can be + * read without any locks. Old module instances are protected by + * "the_old_code_rwlocks" as purging is done on active module table. + * Staging table is protected by the "code_ix lock". */ #include "erl_smp.h" void module_info(int to, void *to_arg) { - index_info(to, to_arg, &module_table); + index_info(to, to_arg, &module_tables[erts_active_code_ix()]); } @@ -59,45 +70,67 @@ static int module_cmp(Module* tmpl, Module* obj) static Module* module_alloc(Module* tmpl) { Module* obj = (Module*) erts_alloc(ERTS_ALC_T_MODULE, sizeof(Module)); + erts_smp_atomic_add_nob(&tot_module_bytes, sizeof(Module)); obj->module = tmpl->module; - obj->code = 0; - obj->old_code = 0; - obj->code_length = 0; - obj->old_code_length = 0; + obj->curr.code = 0; + obj->old.code = 0; + obj->curr.code_length = 0; + obj->old.code_length = 0; obj->slot.index = -1; - obj->nif = NULL; - obj->old_nif = NULL; + obj->curr.nif = NULL; + obj->old.nif = NULL; + obj->curr.num_breakpoints = 0; + obj->old.num_breakpoints = 0; + obj->curr.num_traced_exports = 0; + obj->old.num_traced_exports = 0; return obj; } +static void module_free(Module* mod) +{ + erts_free(ERTS_ALC_T_MODULE, mod); + erts_smp_atomic_add_nob(&tot_module_bytes, -sizeof(Module)); +} void init_module_table(void) { HashFunctions f; + int i; f.hash = (H_FUN) module_hash; f.cmp = (HCMP_FUN) module_cmp; f.alloc = (HALLOC_FUN) module_alloc; - f.free = 0; + f.free = (HFREE_FUN) module_free; + + for (i = 0; i < ERTS_NUM_CODE_IX; i++) { + erts_index_init(ERTS_ALC_T_MODULE_TABLE, &module_tables[i], "module_code", + MODULE_SIZE, MODULE_LIMIT, f); + } - erts_index_init(ERTS_ALC_T_MODULE_TABLE, &module_table, "module_code", - MODULE_SIZE, MODULE_LIMIT, f); + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + erts_smp_rwmtx_init_x(&the_old_code_rwlocks[i], "old_code", make_small(i)); + } + erts_smp_atomic_init_nob(&tot_module_bytes, 0); } Module* -erts_get_module(Eterm mod) +erts_get_module(Eterm mod, ErtsCodeIndex code_ix) { Module e; int index; + IndexTable* mod_tab; ASSERT(is_atom(mod)); + + mod_tab = &module_tables[code_ix]; + e.module = atom_val(mod); - index = index_get(&module_table, (void*) &e); + index = index_get(mod_tab, (void*) &e); if (index == -1) { return NULL; } else { - return (Module*) erts_index_lookup(&module_table, index); + return (Module*) erts_index_lookup(mod_tab, index); } } @@ -105,27 +138,101 @@ Module* erts_put_module(Eterm mod) { Module e; - int index; + IndexTable* mod_tab; + int oldsz, newsz; + Module* res; ASSERT(is_atom(mod)); ERTS_SMP_LC_ASSERT(erts_initialized == 0 - || erts_smp_thr_progress_is_blocking()); + || erts_is_code_ix_locked()); + + mod_tab = &module_tables[erts_staging_code_ix()]; e.module = atom_val(mod); - index = index_put(&module_table, (void*) &e); - return (Module*) erts_index_lookup(&module_table, index); + oldsz = index_table_sz(mod_tab); + res = (Module*) index_put_entry(mod_tab, (void*) &e); + newsz = index_table_sz(mod_tab); + erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); + return res; } -Module *module_code(int i) +Module *module_code(int i, ErtsCodeIndex code_ix) { - return (Module*) erts_index_lookup(&module_table, i); + return (Module*) erts_index_lookup(&module_tables[code_ix], i); } -int module_code_size(void) +int module_code_size(ErtsCodeIndex code_ix) { - return module_table.entries; + return module_tables[code_ix].entries; } int module_table_sz(void) { - return index_table_sz(&module_table); + return erts_smp_atomic_read_nob(&tot_module_bytes); +} + +#ifdef DEBUG +static ErtsCodeIndex dbg_load_code_ix = 0; +#endif + +static int entries_at_start_staging = 0; + +void module_start_staging(void) +{ + IndexTable* src = &module_tables[erts_active_code_ix()]; + IndexTable* dst = &module_tables[erts_staging_code_ix()]; + Module* src_mod; + Module* dst_mod; + int i, oldsz, newsz; + + ASSERT(dbg_load_code_ix == -1); + ASSERT(dst->entries <= src->entries); + + /* + * Make sure our existing modules are up-to-date + */ + for (i = 0; i < dst->entries; i++) { + src_mod = (Module*) erts_index_lookup(src, i); + dst_mod = (Module*) erts_index_lookup(dst, i); + ASSERT(src_mod->module == dst_mod->module); + + dst_mod->curr = src_mod->curr; + dst_mod->old = src_mod->old; + } + + /* + * Copy all new modules from active table + */ + oldsz = index_table_sz(dst); + for (i = dst->entries; i < src->entries; i++) { + src_mod = (Module*) erts_index_lookup(src, i); + dst_mod = (Module*) index_put_entry(dst, src_mod); + ASSERT(dst_mod != src_mod); + + dst_mod->curr = src_mod->curr; + dst_mod->old = src_mod->old; + } + newsz = index_table_sz(dst); + erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); + + entries_at_start_staging = dst->entries; + IF_DEBUG(dbg_load_code_ix = erts_staging_code_ix()); +} + +void module_end_staging(int commit) +{ + ASSERT(dbg_load_code_ix == erts_staging_code_ix()); + + if (!commit) { /* abort */ + IndexTable* tab = &module_tables[erts_staging_code_ix()]; + int oldsz, newsz; + + ASSERT(entries_at_start_staging <= tab->entries); + oldsz = index_table_sz(tab); + index_erase_latest_from(tab, entries_at_start_staging); + newsz = index_table_sz(tab); + erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); + } + + IF_DEBUG(dbg_load_code_ix = -1); } + diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 694e4ab72f..6e123a0ffe 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -24,28 +24,72 @@ #include "index.h" #endif +struct erl_module_instance { + BeamInstr* code; + int code_length; /* Length of loaded code in bytes. */ + unsigned catches; + struct erl_module_nif* nif; + int num_breakpoints; + int num_traced_exports; +}; typedef struct erl_module { IndexSlot slot; /* Must be located at top of struct! */ int module; /* Atom index for module (not tagged). */ - BeamInstr* code; - BeamInstr* old_code; - int code_length; /* Length of loaded code in bytes. */ - int old_code_length; /* Length of old loaded code in bytes */ - unsigned catches, old_catches; - struct erl_module_nif* nif; - struct erl_module_nif* old_nif; + struct erl_module_instance curr; + struct erl_module_instance old; /* protected by "old_code" rwlock */ } Module; -Module* erts_get_module(Eterm mod); +Module* erts_get_module(Eterm mod, ErtsCodeIndex code_ix); Module* erts_put_module(Eterm mod); void init_module_table(void); +void module_start_staging(void); +void module_end_staging(int commit); void module_info(int, void *); -Module *module_code(int); -int module_code_size(void); +Module *module_code(int, ErtsCodeIndex); +int module_code_size(ErtsCodeIndex); int module_table_sz(void); +ERTS_GLB_INLINE void erts_rwlock_old_code(ErtsCodeIndex); +ERTS_GLB_INLINE void erts_rwunlock_old_code(ErtsCodeIndex); +ERTS_GLB_INLINE void erts_rlock_old_code(ErtsCodeIndex); +ERTS_GLB_INLINE void erts_runlock_old_code(ErtsCodeIndex); +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_old_code_rlocked(ErtsCodeIndex); +#endif + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +extern erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; + +ERTS_GLB_INLINE void erts_rwlock_old_code(ErtsCodeIndex code_ix) +{ + erts_smp_rwmtx_rwlock(&the_old_code_rwlocks[code_ix]); +} +ERTS_GLB_INLINE void erts_rwunlock_old_code(ErtsCodeIndex code_ix) +{ + erts_smp_rwmtx_rwunlock(&the_old_code_rwlocks[code_ix]); +} +ERTS_GLB_INLINE void erts_rlock_old_code(ErtsCodeIndex code_ix) +{ + erts_smp_rwmtx_rlock(&the_old_code_rwlocks[code_ix]); +} +ERTS_GLB_INLINE void erts_runlock_old_code(ErtsCodeIndex code_ix) +{ + erts_smp_rwmtx_runlock(&the_old_code_rwlocks[code_ix]); +} + +#ifdef ERTS_ENABLE_LOCK_CHECK +ERTS_GLB_INLINE int erts_is_old_code_rlocked(ErtsCodeIndex code_ix) +{ + return erts_smp_lc_rwmtx_is_rlocked(&the_old_code_rwlocks[code_ix]); +} #endif + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + + +#endif /* !__MODULE_H__ */ diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index 9b168889dd..6764e88c81 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -62,11 +62,8 @@ label L i_func_info I a a I int_code_end -i_trace_breakpoint -i_mtrace_breakpoint +i_generic_breakpoint i_debug_breakpoint -i_count_breakpoint -i_time_breakpoint i_return_time_trace i_return_to_trace i_yield @@ -522,7 +519,6 @@ apply_bif call_nif call_error_handler error_action_code -call_traced_function return_trace # @@ -829,16 +825,20 @@ call_ext_only Ar=u==2 Bif=u$bif:erlang:load_nif/2 => allocate u Ar | i_call_ext # -# The apply/2 and apply/3 BIFs are instructions. +# apply/2 is an instruction, not a BIF. # call_ext u==2 u$func:erlang:apply/2 => i_apply_fun call_ext_last u==2 u$func:erlang:apply/2 D => i_apply_fun_last D call_ext_only u==2 u$func:erlang:apply/2 => i_apply_fun_only -call_ext u==3 u$func:erlang:apply/3 => i_apply -call_ext_last u==3 u$func:erlang:apply/3 D => i_apply_last D -call_ext_only u==3 u$func:erlang:apply/3 => i_apply_only +# +# The apply/3 BIF is an instruction. +# + +call_ext u==3 u$bif:erlang:apply/3 => i_apply +call_ext_last u==3 u$bif:erlang:apply/3 D => i_apply_last D +call_ext_only u==3 u$bif:erlang:apply/3 => i_apply_only # # The exit/1 and throw/1 BIFs never execute the instruction following them; diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c index 26d64887d0..c02872ef80 100644 --- a/erts/emulator/beam/register.c +++ b/erts/emulator/beam/register.c @@ -93,19 +93,14 @@ reg_safe_write_lock(Process *c_p, ErtsProcLocks *c_p_locks) reg_write_lock(); } +#endif + static ERTS_INLINE int is_proc_alive(Process *p) { - int res; - erts_pix_lock_t *pixlck = ERTS_PID2PIXLOCK(p->id); - erts_pix_lock(pixlck); - res = !p->is_exiting; - erts_pix_unlock(pixlck); - return res; + return !ERTS_PROC_IS_EXITING(p); } -#endif - void register_info(int to, void *to_arg) { int lock = !ERTS_IS_CRASH_DUMPING; @@ -389,8 +384,7 @@ erts_whereis_name(Process *c_p, } #else if (rp->p - && ((flags & ERTS_P2P_FLG_ALLOW_OTHER_X) - || rp->p->status != P_EXITING)) + && ((flags & ERTS_P2P_FLG_ALLOW_OTHER_X) || is_proc_alive(rp->p))) *proc = rp->p; else *proc = NULL; @@ -402,7 +396,9 @@ erts_whereis_name(Process *c_p, if (!rp || !rp->pt) *port = NULL; else { -#ifdef ERTS_SMP +#ifndef ERTS_SMP + erts_smp_atomic_inc_nob(&rp->pt->refc); +#else if (pending_port == rp->pt) pending_port = NULL; else { @@ -509,9 +505,11 @@ int erts_unregister_name(Process *c_p, if ((rp = (RegProc*) hash_get(&process_reg, (void*) &r)) != NULL) { if (rp->pt) { if (port != rp->pt) { -#ifdef ERTS_SMP +#ifndef ERTS_SMP + erts_smp_atomic_inc_nob(&rp->pt->refc); +#else if (port) { - ERTS_SMP_LC_ASSERT(port != c_prt); + ASSERT(port != c_prt); erts_smp_port_unlock(port); port = NULL; } diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 7b2bb81f62..1dc6f1d233 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -25,11 +25,6 @@ # define NO_FPE_SIGNALS #endif -/* xxxP __VXWORKS__ */ -#ifdef VXWORKS -#include <vxWorks.h> -#endif - #ifdef DISABLE_CHILD_WAITER_THREAD #undef ENABLE_CHILD_WAITER_THREAD #endif @@ -39,10 +34,10 @@ #define ENABLE_CHILD_WAITER_THREAD 1 #endif +#define ERTS_I64_LITERAL(X) X##LL + #if defined (__WIN32__) # include "erl_win_sys.h" -#elif defined (VXWORKS) -# include "erl_vxworks_sys.h" #else # include "erl_unix_sys.h" #ifndef UNIX @@ -91,14 +86,22 @@ typedef ERTS_SYS_FD_TYPE ErtsSysFdType; # endif #endif -#ifdef __GNUC__ -# if __GNUC__ < 3 && (__GNUC__ != 2 || __GNUC_MINOR__ < 96) -# define ERTS_LIKELY(BOOL) (BOOL) -# define ERTS_UNLIKELY(BOOL) (BOOL) -# else -# define ERTS_LIKELY(BOOL) __builtin_expect((BOOL), !0) -# define ERTS_UNLIKELY(BOOL) __builtin_expect((BOOL), 0) -# endif +#if !defined(__GNUC__) +# define ERTS_AT_LEAST_GCC_VSN__(MAJ, MIN, PL) 0 +#elif !defined(__GNUC_MINOR__) +# define ERTS_AT_LEAST_GCC_VSN__(MAJ, MIN, PL) \ + ((__GNUC__ << 24) >= (((MAJ) << 24) | ((MIN) << 12) | (PL))) +#elif !defined(__GNUC_PATCHLEVEL__) +# define ERTS_AT_LEAST_GCC_VSN__(MAJ, MIN, PL) \ + (((__GNUC__ << 24) | (__GNUC_MINOR__ << 12)) >= (((MAJ) << 24) | ((MIN) << 12) | (PL))) +#else +# define ERTS_AT_LEAST_GCC_VSN__(MAJ, MIN, PL) \ + (((__GNUC__ << 24) | (__GNUC_MINOR__ << 12) | __GNUC_PATCHLEVEL__) >= (((MAJ) << 24) | ((MIN) << 12) | (PL))) +#endif + +#if ERTS_AT_LEAST_GCC_VSN__(2, 96, 0) +# define ERTS_LIKELY(BOOL) __builtin_expect((BOOL), !0) +# define ERTS_UNLIKELY(BOOL) __builtin_expect((BOOL), 0) #else # define ERTS_LIKELY(BOOL) (BOOL) # define ERTS_UNLIKELY(BOOL) (BOOL) @@ -172,10 +175,16 @@ void erl_assert_error(char* expr, char* file, int line); # define const #endif -#ifdef VXWORKS -/* Replace VxWorks' printf with a real one that does fprintf(stdout, ...) */ -int real_printf(const char *fmt, ...); -# define printf real_printf +#undef __deprecated +#if ERTS_AT_LEAST_GCC_VSN__(3, 0, 0) +# define __deprecated __attribute__((deprecated)) +#else +# define __deprecated +#endif +#if ERTS_AT_LEAST_GCC_VSN__(3, 0, 4) +# define erts_align_attribute(SZ) __attribute__ ((aligned (SZ))) +#else +# define erts_align_attribute(SZ) #endif /* In VC++, noreturn is a declspec that has to be before the types, @@ -185,12 +194,6 @@ int real_printf(const char *fmt, ...); #if __GNUC__ # define __decl_noreturn # define __noreturn __attribute__((noreturn)) -# undef __deprecated -# if __GNUC__ >= 3 -# define __deprecated __attribute__((deprecated)) -# else -# define __deprecated -# endif #else # if defined(__WIN32__) && defined(_MSC_VER) # define __noreturn @@ -199,7 +202,6 @@ int real_printf(const char *fmt, ...); # define __noreturn # define __decl_noreturn # endif -# define __deprecated #endif /* @@ -471,38 +473,28 @@ static unsigned long zero_value = 0, one_value = 1; # define SET_NONBLOCKING(fd) ioctlsocket((fd), FIONBIO, &one_value) # else -# ifdef VXWORKS -# include <fcntl.h> /* xxxP added for O_WRONLY etc ... macro:s ... */ -# include <ioLib.h> -static const int zero_value = 0, one_value = 1; -# define SET_BLOCKING(fd) ioctl((fd), FIONBIO, (int)&zero_value) -# define SET_NONBLOCKING(fd) ioctl((fd), FIONBIO, (int)&one_value) -# define ERRNO_BLOCK EWOULDBLOCK - -# else -# ifdef NB_FIONBIO /* Old BSD */ -# include <sys/ioctl.h> +# ifdef NB_FIONBIO /* Old BSD */ +# include <sys/ioctl.h> static const int zero_value = 0, one_value = 1; -# define SET_BLOCKING(fd) ioctl((fd), FIONBIO, &zero_value) -# define SET_NONBLOCKING(fd) ioctl((fd), FIONBIO, &one_value) -# define ERRNO_BLOCK EWOULDBLOCK -# else /* !NB_FIONBIO */ -# include <fcntl.h> -# ifdef NB_O_NDELAY /* Nothing needs this? */ -# define NB_FLAG O_NDELAY -# ifndef ERRNO_BLOCK /* allow override (e.g. EAGAIN) via Makefile */ -# define ERRNO_BLOCK EWOULDBLOCK -# endif -# else /* !NB_O_NDELAY */ /* The True Way - POSIX!:-) */ -# define NB_FLAG O_NONBLOCK -# define ERRNO_BLOCK EAGAIN -# endif /* !NB_O_NDELAY */ -# define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \ - fcntl((fd), F_GETFL, 0) & ~NB_FLAG) -# define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \ - fcntl((fd), F_GETFL, 0) | NB_FLAG) -# endif /* !NB_FIONBIO */ -# endif /* _WXWORKS_ */ +# define SET_BLOCKING(fd) ioctl((fd), FIONBIO, &zero_value) +# define SET_NONBLOCKING(fd) ioctl((fd), FIONBIO, &one_value) +# define ERRNO_BLOCK EWOULDBLOCK +# else /* !NB_FIONBIO */ +# include <fcntl.h> +# ifdef NB_O_NDELAY /* Nothing needs this? */ +# define NB_FLAG O_NDELAY +# ifndef ERRNO_BLOCK /* allow override (e.g. EAGAIN) via Makefile */ +# define ERRNO_BLOCK EWOULDBLOCK +# endif +# else /* !NB_O_NDELAY */ /* The True Way - POSIX!:-) */ +# define NB_FLAG O_NONBLOCK +# define ERRNO_BLOCK EAGAIN +# endif /* !NB_O_NDELAY */ +# define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \ + fcntl((fd), F_GETFL, 0) & ~NB_FLAG) +# define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \ + fcntl((fd), F_GETFL, 0) | NB_FLAG) +# endif /* !NB_FIONBIO */ # endif /* !__WIN32__ */ #endif /* WANT_NONBLOCKING */ @@ -855,13 +847,6 @@ erts_refc_read(erts_refc_t *refcp, erts_aint_t min_val) extern int erts_use_kernel_poll; #endif -#if defined(VXWORKS) -/* NOTE! sys_calloc2 does not exist on other - platforms than VxWorks and OSE */ -void* sys_calloc2(Uint, Uint); -#endif /* VXWORKS || OSE */ - - #define sys_memcpy(s1,s2,n) memcpy(s1,s2,n) #define sys_memmove(s1,s2,n) memmove(s1,s2,n) #define sys_memcmp(s1,s2,n) memcmp(s1,s2,n) @@ -968,43 +953,6 @@ void erl_bin_write(unsigned char *, int, int); # define DEBUGF(x) #endif - -#ifdef VXWORKS -/* This includes redefines of malloc etc - this should be done after sys_alloc, etc, above */ -# include "reclaim.h" -/*********************Malloc and friends************************ - * There is a problem with the naming of malloc and friends, - * malloc is used throughout sys.c and the resolver to mean save_alloc, - * but it should actually mean either sys_alloc or sys_alloc2, - * so the definitions from reclaim_master.h are not any - * good, i redefine the malloc family here, although it's quite - * ugly, actually it would be preferrable to use the - * names sys_alloc and so on throughout the offending code, but - * that will be saved as an later exercise... - * I also add an own calloc, to make the BSD resolver source happy. - ***************************************************************/ -/* Undefine malloc and friends */ -# ifdef malloc -# undef malloc -# endif -# ifdef calloc -# undef calloc -# endif -# ifdef realloc -# undef realloc -# endif -# ifdef free -# undef free -# endif -/* Redefine malloc and friends */ -# define malloc sys_alloc -# define calloc sys_calloc -# define realloc sys_realloc -# define free sys_free - -#endif - #ifdef __WIN32__ #ifdef ARCH_64 #define ERTS_ALLOC_ALIGN_BYTES 16 @@ -1020,23 +968,20 @@ void erl_bin_write(unsigned char *, int, int); #ifdef __WIN32__ - void call_break_handler(void); char* last_error(void); char* win32_errorstr(int); - - #endif /************************************************************************ * Find out the native filename encoding of the process (look at locale of * Unix processes and just do UTF16 on windows ************************************************************************/ -#define ERL_FILENAME_UNKNOWN 0 -#define ERL_FILENAME_LATIN1 1 -#define ERL_FILENAME_UTF8 2 -#define ERL_FILENAME_UTF8_MAC 3 -#define ERL_FILENAME_WIN_WCHAR 4 +#define ERL_FILENAME_UNKNOWN (0) +#define ERL_FILENAME_LATIN1 (1) +#define ERL_FILENAME_UTF8 (2) +#define ERL_FILENAME_UTF8_MAC (3) +#define ERL_FILENAME_WIN_WCHAR (4) int erts_get_native_filename_encoding(void); /* The set function is only to be used by erl_init! */ @@ -1046,4 +991,3 @@ int erts_get_user_requested_filename_encoding(void); void erts_init_sys_common_misc(void); #endif - diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index a36d15204e..db6597dc7c 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -268,16 +268,42 @@ list_length(Eterm list) return i; } -Uint erts_fit_in_bits(Uint n) +static const struct { + Sint64 mask; + int bits; +} fib_data[] = {{ERTS_I64_LITERAL(0x2), 1}, + {ERTS_I64_LITERAL(0xc), 2}, + {ERTS_I64_LITERAL(0xf0), 4}, + {ERTS_I64_LITERAL(0xff00), 8}, + {ERTS_I64_LITERAL(0xffff0000), 16}, + {ERTS_I64_LITERAL(0xffffffff00000000), 32}}; + +static ERTS_INLINE int +fit_in_bits(Sint64 value, int start) { - Uint i; + int bits = 0; + int i; - i = 0; - while (n > 0) { - i++; - n >>= 1; - } - return i; + for (i = start; i >= 0; i--) { + if (value & fib_data[i].mask) { + value >>= fib_data[i].bits; + bits |= fib_data[i].bits; + } + } + + bits++; + + return bits; +} + +int erts_fit_in_bits_int64(Sint64 value) +{ + return fit_in_bits(value, 5); +} + +int erts_fit_in_bits_int32(Sint32 value) +{ + return fit_in_bits((Sint64) (Uint32) value, 4); } int @@ -1640,12 +1666,20 @@ static int do_send_to_logger(Eterm tag, Eterm gleader, char *buf, int len) } #ifndef ERTS_SMP - if ( #ifdef USE_THREADS - !erts_get_scheduler_data() || /* Must be scheduler thread */ + p = NULL; + if (erts_get_scheduler_data()) /* Must be scheduler thread */ #endif - (p = erts_whereis_process(NULL, 0, am_error_logger, 0, 0)) == NULL - || p->status == P_RUNNING) { + { + p = erts_whereis_process(NULL, 0, am_error_logger, 0, 0); + if (p) { + erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state); + if (state & ERTS_PSFLG_RUNNING) + p = NULL; + } + } + + if (!p) { /* buf *always* points to a null terminated string */ erts_fprintf(stderr, "(no error logger present) %T: \"%s\"\n", tag, buf); @@ -3240,7 +3274,7 @@ ptimer_timeout(ErtsSmpPTimer *ptimer) ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS, ERTS_P2P_FLG_ALLOW_OTHER_X); if (p) { - if (!p->is_exiting + if (!ERTS_PROC_IS_EXITING(p) && !(ptimer->timer.flags & ERTS_PTMR_FLG_CANCELLED)) { ASSERT(*ptimer->timer.timer_ref == ptimer); *ptimer->timer.timer_ref = NULL; @@ -3458,6 +3492,254 @@ void erts_silence_warn_unused_result(long unused) } +/* + * Interval counts + */ +void +erts_interval_init(erts_interval_t *icp) +{ +#ifdef ARCH_64 + erts_atomic_init_nob(&icp->counter.atomic, 0); +#else + erts_dw_aint_t dw; +#ifdef ETHR_SU_DW_NAINT_T__ + dw.dw_sint = 0; +#else + dw.sint[ERTS_DW_AINT_HIGH_WORD] = 0; + dw.sint[ERTS_DW_AINT_LOW_WORD] = 0; +#endif + erts_dw_atomic_init_nob(&icp->counter.atomic, &dw); + +#endif +#ifdef DEBUG + icp->smp_api = 0; +#endif +} + +void +erts_smp_interval_init(erts_interval_t *icp) +{ +#ifdef ERTS_SMP + erts_interval_init(icp); +#else + icp->counter.not_atomic = 0; +#endif +#ifdef DEBUG + icp->smp_api = 1; +#endif +} + +static ERTS_INLINE Uint64 +step_interval_nob(erts_interval_t *icp) +{ +#ifdef ARCH_64 + return (Uint64) erts_atomic_inc_read_nob(&icp->counter.atomic); +#else + erts_dw_aint_t exp; + + erts_dw_atomic_read_nob(&icp->counter.atomic, &exp); + while (1) { + erts_dw_aint_t new = exp; + +#ifdef ETHR_SU_DW_NAINT_T__ + new.dw_sint++; +#else + new.sint[ERTS_DW_AINT_LOW_WORD]++; + if (new.sint[ERTS_DW_AINT_LOW_WORD] == 0) + new.sint[ERTS_DW_AINT_HIGH_WORD]++; +#endif + + if (erts_dw_atomic_cmpxchg_nob(&icp->counter.atomic, &new, &exp)) + return erts_interval_dw_aint_to_val__(&new); + + } +#endif +} + +static ERTS_INLINE Uint64 +step_interval_relb(erts_interval_t *icp) +{ +#ifdef ARCH_64 + return (Uint64) erts_atomic_inc_read_relb(&icp->counter.atomic); +#else + erts_dw_aint_t exp; + + erts_dw_atomic_read_nob(&icp->counter.atomic, &exp); + while (1) { + erts_dw_aint_t new = exp; + +#ifdef ETHR_SU_DW_NAINT_T__ + new.dw_sint++; +#else + new.sint[ERTS_DW_AINT_LOW_WORD]++; + if (new.sint[ERTS_DW_AINT_LOW_WORD] == 0) + new.sint[ERTS_DW_AINT_HIGH_WORD]++; +#endif + + if (erts_dw_atomic_cmpxchg_relb(&icp->counter.atomic, &new, &exp)) + return erts_interval_dw_aint_to_val__(&new); + + } +#endif +} + + +static ERTS_INLINE Uint64 +ensure_later_interval_nob(erts_interval_t *icp, Uint64 ic) +{ + Uint64 curr_ic; +#ifdef ARCH_64 + curr_ic = (Uint64) erts_atomic_read_nob(&icp->counter.atomic); + if (curr_ic > ic) + return curr_ic; + return (Uint64) erts_atomic_inc_read_nob(&icp->counter.atomic); +#else + erts_dw_aint_t exp; + + erts_dw_atomic_read_nob(&icp->counter.atomic, &exp); + curr_ic = erts_interval_dw_aint_to_val__(&exp); + if (curr_ic > ic) + return curr_ic; + + while (1) { + erts_dw_aint_t new = exp; + +#ifdef ETHR_SU_DW_NAINT_T__ + new.dw_sint++; +#else + new.sint[ERTS_DW_AINT_LOW_WORD]++; + if (new.sint[ERTS_DW_AINT_LOW_WORD] == 0) + new.sint[ERTS_DW_AINT_HIGH_WORD]++; +#endif + + if (erts_dw_atomic_cmpxchg_nob(&icp->counter.atomic, &new, &exp)) + return erts_interval_dw_aint_to_val__(&new); + + curr_ic = erts_interval_dw_aint_to_val__(&exp); + if (curr_ic > ic) + return curr_ic; + } +#endif +} + + +static ERTS_INLINE Uint64 +ensure_later_interval_acqb(erts_interval_t *icp, Uint64 ic) +{ + Uint64 curr_ic; +#ifdef ARCH_64 + curr_ic = (Uint64) erts_atomic_read_acqb(&icp->counter.atomic); + if (curr_ic > ic) + return curr_ic; + return (Uint64) erts_atomic_inc_read_acqb(&icp->counter.atomic); +#else + erts_dw_aint_t exp; + + erts_dw_atomic_read_acqb(&icp->counter.atomic, &exp); + curr_ic = erts_interval_dw_aint_to_val__(&exp); + if (curr_ic > ic) + return curr_ic; + + while (1) { + erts_dw_aint_t new = exp; + +#ifdef ETHR_SU_DW_NAINT_T__ + new.dw_sint++; +#else + new.sint[ERTS_DW_AINT_LOW_WORD]++; + if (new.sint[ERTS_DW_AINT_LOW_WORD] == 0) + new.sint[ERTS_DW_AINT_HIGH_WORD]++; +#endif + + if (erts_dw_atomic_cmpxchg_acqb(&icp->counter.atomic, &new, &exp)) + return erts_interval_dw_aint_to_val__(&new); + + curr_ic = erts_interval_dw_aint_to_val__(&exp); + if (curr_ic > ic) + return curr_ic; + } +#endif +} + +Uint64 +erts_step_interval_nob(erts_interval_t *icp) +{ + ASSERT(!icp->smp_api); + return step_interval_nob(icp); +} + +Uint64 +erts_step_interval_relb(erts_interval_t *icp) +{ + ASSERT(!icp->smp_api); + return step_interval_relb(icp); +} + +Uint64 +erts_smp_step_interval_nob(erts_interval_t *icp) +{ + ASSERT(icp->smp_api); +#ifdef ERTS_SMP + return step_interval_nob(icp); +#else + return ++icp->counter.not_atomic; +#endif +} + +Uint64 +erts_smp_step_interval_relb(erts_interval_t *icp) +{ + ASSERT(icp->smp_api); +#ifdef ERTS_SMP + return step_interval_relb(icp); +#else + return ++icp->counter.not_atomic; +#endif +} + +Uint64 +erts_ensure_later_interval_nob(erts_interval_t *icp, Uint64 ic) +{ + ASSERT(!icp->smp_api); + return ensure_later_interval_nob(icp, ic); +} + +Uint64 +erts_ensure_later_interval_acqb(erts_interval_t *icp, Uint64 ic) +{ + ASSERT(!icp->smp_api); + return ensure_later_interval_acqb(icp, ic); +} + +Uint64 +erts_smp_ensure_later_interval_nob(erts_interval_t *icp, Uint64 ic) +{ + ASSERT(icp->smp_api); +#ifdef ERTS_SMP + return ensure_later_interval_nob(icp, ic); +#else + if (icp->counter.not_atomic > ic) + return icp->counter.not_atomic; + else + return ++icp->counter.not_atomic; +#endif +} + +Uint64 +erts_smp_ensure_later_interval_acqb(erts_interval_t *icp, Uint64 ic) +{ + ASSERT(icp->smp_api); +#ifdef ERTS_SMP + return ensure_later_interval_acqb(icp, ic); +#else + if (icp->counter.not_atomic > ic) + return icp->counter.not_atomic; + else + return ++icp->counter.not_atomic; +#endif +} + + #ifdef DEBUG /* * Handy functions when using a debugger - don't use in the code! @@ -3490,7 +3772,7 @@ Process *p; void ppi(Eterm pid) { - pp(erts_pid2proc_unlocked(pid)); + pp(erts_proc_lookup(pid)); } void td(Eterm x) diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c index a9303d55bc..ca6d25adb4 100644 --- a/erts/emulator/drivers/common/gzio.c +++ b/erts/emulator/drivers/common/gzio.c @@ -21,11 +21,6 @@ #include "erl_driver.h" #include "sys.h" -#ifdef VXWORKS -/* pull in FOPEN from zutil.h instead */ -#undef F_OPEN -#endif - #ifdef __WIN32__ #ifndef HAVE_CONFLICTING_FREAD_DECLARATION #define HAVE_CONFLICTING_FREAD_DECLARATION diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 76a9b55179..0d6419e50e 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -284,27 +284,15 @@ static unsigned long one_value = 1; #else -#ifdef VXWORKS -#include <sockLib.h> -#include <sys/times.h> -#include <iosLib.h> -#include <taskLib.h> -#include <selectLib.h> -#include <ioLib.h> -#else #include <sys/time.h> #ifdef NETDB_H_NEEDS_IN_H #include <netinet/in.h> #endif #include <netdb.h> -#endif #include <sys/socket.h> #include <netinet/in.h> -#ifdef VXWORKS -#include <rpc/rpctypes.h> -#endif #ifdef DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H #include <rpc/types.h> #endif @@ -312,12 +300,10 @@ static unsigned long one_value = 1; #include <netinet/tcp.h> #include <arpa/inet.h> -#if (!defined(VXWORKS)) #include <sys/param.h> #ifdef HAVE_ARPA_NAMESER_H #include <arpa/nameser.h> #endif -#endif #ifdef HAVE_SYS_SOCKIO_H #include <sys/sockio.h> @@ -331,7 +317,7 @@ static unsigned long one_value = 1; /* SCTP support -- currently for UNIX platforms only: */ #undef HAVE_SCTP -#if (!defined(VXWORKS) && !defined(__WIN32__) && defined(HAVE_SCTP_H)) +#if (!defined(__WIN32__) && defined(HAVE_SCTP_H)) #include <netinet/sctp.h> @@ -478,15 +464,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define sock_connect(s, addr, len) connect((s), (addr), (len)) #define sock_listen(s, b) listen((s), (b)) #define sock_bind(s, addr, len) bind((s), (addr), (len)) -#ifdef VXWORKS -#define sock_getopt(s,t,n,v,l) wrap_sockopt(&getsockopt,\ - s,t,n,v,(unsigned int)(l)) -#define sock_setopt(s,t,n,v,l) wrap_sockopt(&setsockopt,\ - s,t,n,v,(unsigned int)(l)) -#else #define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l)) #define sock_setopt(s,t,n,v,l) setsockopt((s),(t),(n),(v),(l)) -#endif #define sock_name(s, addr, len) getsockname((s), (addr), (len)) #define sock_peer(s, addr, len) getpeername((s), (addr), (len)) #define sock_ntohs(x) ntohs((x)) @@ -535,6 +514,12 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #endif /* __WIN32__ */ +#ifdef HAVE_SOCKLEN_T +# define SOCKLEN_T socklen_t +#else +# define SOCKLEN_T int +#endif + #include "packet_parser.h" #define get_int24(s) ((((unsigned char*) (s))[0] << 16) | \ @@ -685,7 +670,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_LOPT_EXITONCLOSE 26 /* exit port on active close or not ! */ #define INET_LOPT_TCP_HIWTRMRK 27 /* set local high watermark */ #define INET_LOPT_TCP_LOWTRMRK 28 /* set local low watermark */ -#define INET_LOPT_BIT8 29 /* set 8 bit detection */ + /* 29 unused */ #define INET_LOPT_TCP_SEND_TIMEOUT 30 /* set send timeout */ #define INET_LOPT_TCP_DELAY_SEND 31 /* Delay sends until next poll */ #define INET_LOPT_PACKET_SIZE 32 /* Max packet size */ @@ -720,12 +705,6 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_IFOPT_FLAGS 6 #define INET_IFOPT_HWADDR 7 -/* INET_LOPT_BIT8 options */ -#define INET_BIT8_CLEAR 0 -#define INET_BIT8_SET 1 -#define INET_BIT8_ON 2 -#define INET_BIT8_OFF 3 - /* INET_REQ_GETSTAT enumeration */ #define INET_STAT_RECV_CNT 1 #define INET_STAT_RECV_MAX 2 @@ -921,7 +900,6 @@ typedef struct { int mode; /* BINARY | LIST (affect how to interpret hsz) */ int exitf; /* exit port on close or not */ - int bit8f; /* check if data has bit number 7 set */ int deliver; /* Delivery mode, TERM or PORT */ ErlDrvTermData caller; /* recipient of sync reply */ @@ -940,8 +918,6 @@ typedef struct { int sfamily; /* address family */ enum PacketParseType htype; /* header type (TCP only?) */ unsigned int psize; /* max packet size (TCP only?) */ - int bit8; /* set if bit8f==true and data some data - seen had the 7th bit set */ inet_address remote; /* remote address for connected sockets */ inet_address peer_addr; /* fake peer address */ inet_address name_addr; /* fake local address */ @@ -3342,17 +3318,6 @@ static int packet_error_message(udp_descriptor* udesc, int err) } -/* scan buffer for bit 7 */ -static void scanbit8(inet_descriptor* desc, const char* buf, int len) -{ - int c; - - if (!desc->bit8f || desc->bit8) return; - c = 0; - while(len--) c |= *buf++; - desc->bit8 = ((c & 0x80) != 0); -} - /* ** active=TRUE: ** (NOTE! distribution MUST use active=TRUE, deliver=PORT) @@ -3370,8 +3335,6 @@ static int tcp_reply_data(tcp_descriptor* desc, char* buf, int len) packet_get_body(desc->inet.htype, &body, &bodylen); - scanbit8(INETP(desc), body, bodylen); - if (desc->inet.deliver == INET_DELIVER_PORT) { code = inet_port_data(INETP(desc), body, bodylen); } @@ -3403,8 +3366,6 @@ tcp_reply_binary_data(tcp_descriptor* desc, ErlDrvBinary* bin, int offs, int len packet_get_body(desc->inet.htype, &body, &bodylen); offs = body - bin->orig_bytes; /* body offset now */ - scanbit8(INETP(desc), body, bodylen); - if (desc->inet.deliver == INET_DELIVER_PORT) code = inet_port_binary_data(INETP(desc), bin, offs, bodylen); else if ((code=packet_parse(desc->inet.htype, buf, len, &desc->http_state, @@ -3430,8 +3391,6 @@ packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz, { int code; - scanbit8(desc, bin->orig_bytes+offs, len); - if (desc->active == INET_PASSIVE) /* "inet" is actually for both UDP and SCTP, as well as TCP! */ return inet_async_binary_data(desc, hsz, bin, offs, len, extra); @@ -5280,50 +5239,6 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, #endif - - -#ifdef VXWORKS -/* -** THIS is a terrible creature, a bug in the TCP part -** of the old VxWorks stack (non SENS) created a race. -** If (and only if?) a socket got closed from the other -** end and we tried a set/getsockopt on the TCP level, -** the task would generate a bus error... -*/ -static STATUS wrap_sockopt(STATUS (*function)() /* Yep, no parameter - check */, - int s, int level, int optname, - char *optval, unsigned int optlen - /* optlen is a pointer if function - is getsockopt... */) -{ - fd_set rs; - struct timeval timeout; - int to_read; - int ret; - - FD_ZERO(&rs); - FD_SET(s,&rs); - memset(&timeout,0,sizeof(timeout)); - if (level == IPPROTO_TCP) { - taskLock(); - if (select(s+1,&rs,NULL,NULL,&timeout)) { - if (ioctl(s,FIONREAD,(int)&to_read) == ERROR || - to_read == 0) { /* End of file, other end closed? */ - sock_errno() = EBADF; - taskUnlock(); - return ERROR; - } - } - ret = (*function)(s,level,optname,optval,optlen); - taskUnlock(); - } else { - ret = (*function)(s,level,optname,optval,optlen); - } - return ret; -} -#endif - /* Per H @ Tail-f: The original code here had problems that possibly only occur if you abuse it for non-INET sockets, but anyway: a) If the getsockopt for SO_PRIORITY or IP_TOS failed, the actual @@ -5349,13 +5264,8 @@ static int setopt_prio_tos_trick int res; int res_prio; int res_tos; -#ifdef HAVE_SOCKLEN_T - socklen_t -#else - int -#endif - tmp_arg_sz_prio = sizeof(tmp_ival_prio), - tmp_arg_sz_tos = sizeof(tmp_ival_tos); + SOCKLEN_T tmp_arg_sz_prio = sizeof(tmp_ival_prio); + SOCKLEN_T tmp_arg_sz_tos = sizeof(tmp_ival_tos); res_prio = sock_getopt(fd, SOL_SOCKET, SO_PRIORITY, (char *) &tmp_ival_prio, &tmp_arg_sz_prio); @@ -5499,29 +5409,6 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) desc->exitf = ival; continue; - case INET_LOPT_BIT8: - DEBUGF(("inet_set_opts(%ld): s=%d, BIT8=%d\r\n", - (long)desc->port, desc->s, ival)); - switch(ival) { - case INET_BIT8_ON: - desc->bit8f = 1; - desc->bit8 = 0; - break; - case INET_BIT8_OFF: - desc->bit8f = 0; - desc->bit8 = 0; - break; - case INET_BIT8_CLEAR: - desc->bit8f = 1; - desc->bit8 = 0; - break; - case INET_BIT8_SET: - desc->bit8f = 1; - desc->bit8 = 1; - break; - } - continue; - case INET_LOPT_TCP_HIWTRMRK: if (desc->stype == SOCK_STREAM) { tcp_descriptor* tdesc = (tcp_descriptor*) desc; @@ -5603,23 +5490,11 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_OPT_SNDBUF: type = SO_SNDBUF; DEBUGF(("inet_set_opts(%ld): s=%d, SO_SNDBUF=%d\r\n", (long)desc->port, desc->s, ival)); - /* - * Setting buffer sizes in VxWorks gives unexpected results - * our workaround is to leave it at default. - */ -#ifdef VXWORKS - goto skip_os_setopt; -#else break; -#endif case INET_OPT_RCVBUF: type = SO_RCVBUF; DEBUGF(("inet_set_opts(%ld): s=%d, SO_RCVBUF=%d\r\n", (long)desc->port, desc->s, ival)); -#ifdef VXWORKS - goto skip_os_setopt; -#else break; -#endif case INET_OPT_LINGER: type = SO_LINGER; if (len < 4) return -1; @@ -5741,9 +5616,6 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } DEBUGF(("inet_set_opts(%ld): s=%d returned %d\r\n", (long)desc->port, desc->s, res)); -#ifdef VXWORKS -skip_os_setopt: -#endif if (type == SO_RCVBUF) { /* make sure we have desc->bufsz >= SO_RCVBUF */ if (ival > desc->bufsz) @@ -6404,15 +6276,6 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, put_int32(desc->exitf, ptr); continue; - case INET_LOPT_BIT8: - *ptr++ = opt; - if (desc->bit8f) { - put_int32(desc->bit8, ptr); - } else { - put_int32(INET_BIT8_OFF, ptr); - } - continue; - case INET_LOPT_TCP_HIWTRMRK: if (desc->stype == SOCK_STREAM) { *ptr++ = opt; @@ -7471,8 +7334,6 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) desc->mode = INET_MODE_LIST; /* list mode */ desc->exitf = 1; /* exit port when close on active socket */ - desc->bit8f = 0; - desc->bit8 = 0; desc->deliver = INET_DELIVER_TERM; /* standard term format */ desc->active = INET_PASSIVE; /* start passive */ desc->oph = NULL; @@ -7780,8 +7641,8 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, desc->state = INET_STATE_BOUND; if ((port = inet_address_port(&local)) == 0) { - len = sizeof(local); - sock_name(desc->s, (struct sockaddr*) &local, (unsigned int*)&len); + SOCKLEN_T adrlen = sizeof(local); + sock_name(desc->s, &local.sa, &adrlen); port = inet_address_port(&local); } port = sock_ntohs(port); @@ -7816,8 +7677,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } -#ifndef VXWORKS - case INET_REQ_GETSERVBYNAME: { /* L1 Name-String L2 Proto-String */ char namebuf[256]; char protobuf[256]; @@ -7868,8 +7727,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, return ctl_reply(INET_REP_OK, srv->s_name, len, rbuf, rsize); } -#endif /* !VXWORKS */ - default: return ctl_xerror(EXBADPORT, rbuf, rsize); } @@ -8100,7 +7957,6 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, /* Some flags must be inherited at this point */ copy_desc->inet.mode = desc->inet.mode; copy_desc->inet.exitf = desc->inet.exitf; - copy_desc->inet.bit8f = desc->inet.bit8f; copy_desc->inet.deliver = desc->inet.deliver; copy_desc->inet.htype = desc->inet.htype; copy_desc->inet.psize = desc->inet.psize; @@ -9805,7 +9661,6 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err) /* Some flags must be inherited at this point */ copy_desc->inet.mode = desc->inet.mode; copy_desc->inet.exitf = desc->inet.exitf; - copy_desc->inet.bit8f = desc->inet.bit8f; copy_desc->inet.deliver = desc->inet.deliver; copy_desc->inet.htype = desc->inet.htype; copy_desc->inet.psize = desc->inet.psize; diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index b250bac4dc..2aa373aa7d 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -45,23 +45,6 @@ #include <fcntl.h> #endif /* DARWIN */ -#ifdef VXWORKS -#include <ioLib.h> -#include <dosFsLib.h> -#include <nfsLib.h> -#include <sys/stat.h> -/* -** Not nice to include usrLib.h as MANY normal variable names get reported -** as shadowing globals, like 'i' for example. -** Instead we declare the only function we use here -*/ -/* - * #include <usrLib.h> - */ -extern STATUS copy(char *, char *); -#include <errno.h> -#endif - #ifdef SUNOS4 # define getcwd(buf, size) getwd(buf) #endif @@ -93,276 +76,27 @@ extern STATUS copy(char *, char *); #define DIR_MODE 0777 #endif -#ifdef VXWORKS /* Currently only used on vxworks */ - -#define EF_ALLOC(S) driver_alloc((S)) -#define EF_REALLOC(P, S) driver_realloc((P), (S)) -#define EF_SAFE_ALLOC(S) ef_safe_alloc((S)) -#define EF_SAFE_REALLOC(P, S) ef_safe_realloc((P), (S)) -#define EF_FREE(P) do { if((P)) driver_free((P)); } while(0) - -void erl_exit(int n, char *fmt, ...); - -static void *ef_safe_alloc(Uint s) -{ - void *p = EF_ALLOC(s); - if (!p) erl_exit(1, - "unix efile drv: Can't allocate %lu bytes of memory\n", - (unsigned long)s); - return p; -} - -#if 0 /* Currently not used */ - -static void *ef_safe_realloc(void *op, Uint s) -{ - void *p = EF_REALLOC(op, s); - if (!p) erl_exit(1, - "unix efile drv: Can't reallocate %lu bytes of memory\n", - (unsigned long)s); - return p; -} - -#endif /* #if 0 */ -#endif /* #ifdef VXWORKS */ - #define IS_DOT_OR_DOTDOT(s) \ (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) -#ifdef VXWORKS -static int vxworks_to_posix(int vx_errno); -#endif - -/* -** VxWorks (not) strikes again. Too long RESULTING paths -** may give the infamous bus error. Have to check ALL -** filenames and pathnames. No wonder the emulator is slow on -** these cards... -*/ -#ifdef VXWORKS -#define CHECK_PATHLEN(Name, ErrInfo) \ - if (path_size(Name) > PATH_MAX) { \ - errno = ENAMETOOLONG; \ - return check_error(-1, ErrInfo); \ - } -#else -#define CHECK_PATHLEN(X,Y) /* Nothing */ -#endif - static int check_error(int result, Efile_error* errInfo); static int check_error(int result, Efile_error *errInfo) { if (result < 0) { -#ifdef VXWORKS - errInfo->posix_errno = errInfo->os_errno = vxworks_to_posix(errno); -#else errInfo->posix_errno = errInfo->os_errno = errno; -#endif return 0; } return 1; } -#ifdef VXWORKS - -/* - * VxWorks has different error codes for different file systems. - * We map those to POSIX ones. - */ -static int -vxworks_to_posix(int vx_errno) -{ - DEBUGF(("[vxworks_to_posix] vx_errno: %08x\n", vx_errno)); - switch (vx_errno) { - /* dosFsLib mapping */ -#ifdef S_dosFsLib_FILE_ALREADY_EXISTS - case S_dosFsLib_FILE_ALREADY_EXISTS: return EEXIST; -#else - case S_dosFsLib_FILE_EXISTS: return EEXIST; -#endif -#ifdef S_dosFsLib_BAD_DISK - case S_dosFsLib_BAD_DISK: return EIO; -#endif -#ifdef S_dosFsLib_CANT_CHANGE_ROOT - case S_dosFsLib_CANT_CHANGE_ROOT: return EINVAL; -#endif -#ifdef S_dosFsLib_NO_BLOCK_DEVICE - case S_dosFsLib_NO_BLOCK_DEVICE: return ENOTBLK; -#endif -#ifdef S_dosFsLib_BAD_SEEK - case S_dosFsLib_BAD_SEEK: return ESPIPE; -#endif - case S_dosFsLib_VOLUME_NOT_AVAILABLE: return ENXIO; - case S_dosFsLib_DISK_FULL: return ENOSPC; - case S_dosFsLib_FILE_NOT_FOUND: return ENOENT; - case S_dosFsLib_NO_FREE_FILE_DESCRIPTORS: return ENFILE; - case S_dosFsLib_INVALID_NUMBER_OF_BYTES: return EINVAL; - case S_dosFsLib_ILLEGAL_NAME: return EINVAL; - case S_dosFsLib_CANT_DEL_ROOT: return EACCES; - case S_dosFsLib_NOT_FILE: return EISDIR; - case S_dosFsLib_NOT_DIRECTORY: return ENOTDIR; - case S_dosFsLib_NOT_SAME_VOLUME: return EXDEV; - case S_dosFsLib_READ_ONLY: return EACCES; - case S_dosFsLib_ROOT_DIR_FULL: return ENOSPC; - case S_dosFsLib_DIR_NOT_EMPTY: return EEXIST; - case S_dosFsLib_NO_LABEL: return ENXIO; - case S_dosFsLib_INVALID_PARAMETER: return EINVAL; - case S_dosFsLib_NO_CONTIG_SPACE: return ENOSPC; - case S_dosFsLib_FD_OBSOLETE: return EBADF; - case S_dosFsLib_DELETED: return EINVAL; - case S_dosFsLib_INTERNAL_ERROR: return EIO; - case S_dosFsLib_WRITE_ONLY: return EACCES; - /* nfsLib mapping - is needed since Windriver has used */ - /* inconsistent error codes (errno.h/nfsLib.h). */ - case S_nfsLib_NFS_OK: return 0; - case S_nfsLib_NFSERR_PERM: return EPERM; - case S_nfsLib_NFSERR_NOENT: return ENOENT; - case S_nfsLib_NFSERR_IO: return EIO; - case S_nfsLib_NFSERR_NXIO: return ENXIO; -#ifdef S_nfsLib_NFSERR_ACCES - case S_nfsLib_NFSERR_ACCES: return EACCES; -#else - case S_nfsLib_NFSERR_ACCESS: return EACCES; -#endif - case S_nfsLib_NFSERR_EXIST: return EEXIST; - case S_nfsLib_NFSERR_NODEV: return ENODEV; - case S_nfsLib_NFSERR_NOTDIR: return ENOTDIR; - case S_nfsLib_NFSERR_ISDIR: return EISDIR; - case S_nfsLib_NFSERR_FBIG: return EFBIG; - case S_nfsLib_NFSERR_NOSPC: return ENOSPC; - case S_nfsLib_NFSERR_ROFS: return EROFS; - case S_nfsLib_NFSERR_NAMETOOLONG: return ENAMETOOLONG; - case S_nfsLib_NFSERR_NOTEMPTY: return EEXIST; - case S_nfsLib_NFSERR_DQUOT: return ENOSPC; - case S_nfsLib_NFSERR_STALE: return EINVAL; - case S_nfsLib_NFSERR_WFLUSH: return ENXIO; - /* And sometimes (...) the error codes are from ioLib (as in the */ - /* case of the (for nfsLib) unimplemented rename function) */ - case S_ioLib_DISK_NOT_PRESENT: return EIO; -#if S_ioLib_DISK_NOT_PRESENT != S_ioLib_NO_DRIVER - case S_ioLib_NO_DRIVER: return ENXIO; -#endif - case S_ioLib_UNKNOWN_REQUEST: return ENOSYS; - case S_ioLib_DEVICE_TIMEOUT: return EIO; -#ifdef S_ioLib_UNFORMATED - /* Added (VxWorks 5.2 -> 5.3.1) */ - #if S_ioLib_UNFORMATED != S_ioLib_DEVICE_TIMEOUT - case S_ioLib_UNFORMATED: return EIO; - #endif -#endif -#if S_ioLib_DEVICE_TIMEOUT != S_ioLib_DEVICE_ERROR - case S_ioLib_DEVICE_ERROR: return ENXIO; -#endif - case S_ioLib_WRITE_PROTECTED: return EACCES; - case S_ioLib_NO_FILENAME: return EINVAL; - case S_ioLib_CANCELLED: return EINTR; - case S_ioLib_NO_DEVICE_NAME_IN_PATH: return EINVAL; - case S_ioLib_NAME_TOO_LONG: return ENAMETOOLONG; -#ifdef S_objLib_OBJ_UNAVAILABLE - case S_objLib_OBJ_UNAVAILABLE: return ENOENT; -#endif - - /* Temporary workaround for a weird error in passFs - (VxWorks Simsparc only). File operation fails because of - ENOENT, but errno is not set. */ -#ifdef SIMSPARCSOLARIS - case 0: return ENOENT; -#endif - - } - /* If the error code matches none of the above, assume */ - /* it is a POSIX one already. The upper bits (>=16) are */ - /* cleared since VxWorks uses those bits to indicate in */ - /* what module the error occured. */ - return vx_errno & 0xffff; -} - -static int -vxworks_enotsup(Efile_error *errInfo) -{ - errInfo->posix_errno = errInfo->os_errno = ENOTSUP; - return 0; -} - -static int -count_path_length(char *pathname, char *pathname2) -{ - static int stack[PATH_MAX / 2 + 1]; - int sp = 0; - char *tmp; - char *cpy = NULL; - int i; - int sum; - for(i = 0;i < 2;++i) { - if (!i) { - cpy = EF_SAFE_ALLOC(strlen(pathname)+1); - strcpy(cpy, pathname); - } else if (pathname2 != NULL) { - EF_FREE(cpy); - cpy = EF_SAFE_ALLOC(strlen(pathname2)+1); - strcpy(cpy, pathname2); - } else - break; - - for (tmp = strtok(cpy,"/"); tmp != NULL; tmp = strtok(NULL,"/")) { - if (!strcmp(tmp,"..") && sp > 0) - --sp; - else if (strcmp(tmp,".")) - stack[sp++] = strlen(tmp); - } - } - if (cpy != NULL) - EF_FREE(cpy); - sum = 0; - for(i = 0;i < sp; ++i) - sum += stack[i]+1; - return (sum) ? sum : 1; -} - -static int -path_size(char *pathname) -{ - static char currdir[PATH_MAX+2]; - if (*pathname == '/') - return count_path_length(pathname,NULL); - ioDefPathGet(currdir); - strcat(currdir,"/"); - return count_path_length(currdir,pathname); -} - -#endif /* VXWORKS */ - int efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to create. */ { - CHECK_PATHLEN(name,errInfo); #ifdef NO_MKDIR_MODE -#ifdef VXWORKS - /* This is a VxWorks/nfs workaround for erl_tar to create - * non-existant directories. (of some reason (...) VxWorks - * returns, the *non-module-prefixed*, 0xd code when - * trying to create a directory in a directory that doesn't exist). - * (see efile_openfile) - */ - if (mkdir(name) < 0) { - struct stat sb; - if (name[0] == '\0') { - /* Return the correct error code enoent */ - errno = S_nfsLib_NFSERR_NOENT; - } else if (stat(name, &sb) == OK) { - errno = S_nfsLib_NFSERR_EXIST; - } else if((strchr(name, '/') != NULL) && (errno == 0xd)) { - /* Return the correct error code enoent */ - errno = S_nfsLib_NFSERR_NOENT; - } - return check_error(-1, errInfo); - } else return 1; -#else return check_error(mkdir(name), errInfo); -#endif #else return check_error(mkdir(name, DIR_MODE), errInfo); #endif @@ -372,16 +106,9 @@ int efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to delete. */ { - CHECK_PATHLEN(name, errInfo); if (rmdir(name) == 0) { return 1; } -#ifdef VXWORKS - if (name[0] == '\0') { - /* Return the correct error code enoent */ - errno = S_nfsLib_NFSERR_NOENT; - } -#else if (errno == ENOTEMPTY) { errno = EEXIST; } @@ -401,7 +128,6 @@ efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ } errno = saved_errno; } -#endif return check_error(-1, errInfo); } @@ -409,7 +135,6 @@ int efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of file to delete. */ { - CHECK_PATHLEN(name,errInfo); if (unlink(name) == 0) { return 1; } @@ -457,32 +182,13 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */ char* src, /* Original name. */ char* dst) /* New name. */ { - CHECK_PATHLEN(src,errInfo); - CHECK_PATHLEN(dst,errInfo); -#ifdef VXWORKS - - /* First check if src == dst, if so, just return. */ - /* VxWorks dos file system destroys the file otherwise, */ - /* VxWorks nfs file system rename doesn't work at all. */ - if(strcmp(src, dst) == 0) - return 1; -#endif if (rename(src, dst) == 0) { return 1; } -#ifdef VXWORKS - /* nfs for VxWorks doesn't support rename. We try to emulate it */ - /* (by first copying src to dst and then deleting src). */ - if(errno == S_ioLib_UNKNOWN_REQUEST && /* error code returned - by ioLib (!) */ - copy(src, dst) == OK && - unlink(src) == OK) - return 1; -#endif if (errno == ENOTEMPTY) { errno = EEXIST; } -#if defined (sparc) && !defined(VXWORKS) +#if defined (sparc) /* * SunOS 4.1.4 reports overwriting a non-empty directory with a * directory as EINVAL instead of EEXIST (first rule out the correct @@ -543,7 +249,6 @@ int efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to make current. */ { - CHECK_PATHLEN(name, errInfo); return check_error(chdir(name), errInfo); } @@ -600,8 +305,6 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ * If this is the first call, we must open the directory. */ - CHECK_PATHLEN(name, errInfo); - if (*p_dir_handle == NULL) { dp = opendir(name); if (dp == NULL) @@ -641,26 +344,8 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ struct stat statbuf; int fd; int mode; /* Open mode. */ -#ifdef VXWORKS - char pathbuff[PATH_MAX+2]; - char sbuff[PATH_MAX*2]; - char *totbuff = sbuff; - int nameneed; -#endif - - - CHECK_PATHLEN(name, errInfo); - -#ifdef VXWORKS - /* Have to check that it's not a directory. */ - if (stat(name,&statbuf) != ERROR && ISDIR(statbuf)) { - errno = EISDIR; - return check_error(-1, errInfo); - } -#endif if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) { -#if !defined(VXWORKS) && !defined(OSE) /* * For UNIX only, here is some ugly code to allow * /dev/null to be opened as a file. @@ -677,12 +362,9 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ } } if (!(dev_null_ino && statbuf.st_ino == dev_null_ino)) { -#endif errno = EISDIR; return check_error(-1, errInfo); -#if !defined(VXWORKS) && !defined(OSE) } -#endif } switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) { @@ -706,49 +388,14 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ if (flags & EFILE_MODE_APPEND) { mode &= ~O_TRUNC; -#ifndef VXWORKS - mode |= O_APPEND; /* Dont make VxWorks think things it shouldn't */ -#endif + mode |= O_APPEND; } if (flags & EFILE_MODE_EXCL) { mode |= O_EXCL; } -#ifdef VXWORKS - if (*name != '/') { - /* Make sure it is an absolute pathname, because ftruncate needs it */ - ioDefPathGet(pathbuff); - strcat(pathbuff,"/"); - nameneed = strlen(pathbuff) + strlen(name) + 1; - if (nameneed > PATH_MAX*2) - totbuff = EF_SAFE_ALLOC(nameneed); - strcpy(totbuff,pathbuff); - strcat(totbuff,name); - fd = open(totbuff, mode, FILE_MODE); - if (totbuff != sbuff) - EF_FREE(totbuff); - } else { - fd = open(name, mode, FILE_MODE); - } -#else fd = open(name, mode, FILE_MODE); -#endif - -#ifdef VXWORKS - - /* This is a VxWorks/nfs workaround for erl_tar to create - * non-existant directories. (of some reason (...) VxWorks - * returns, the *non-module-prefixed*, 0xd code when - * trying to write a file in a directory that doesn't exist). - * (see efile_mkdir) - */ - if ((fd < 0) && (strchr(name, '/') != NULL) && (errno == 0xd)) { - /* Return the correct error code enoent */ - errno = S_nfsLib_NFSERR_NOENT; - return check_error(-1, errInfo); - } -#endif if (!check_error(fd, errInfo)) return 0; @@ -797,11 +444,7 @@ efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ int fd) /* File descriptor for file to sync. */ { #ifdef NO_FSYNC -#ifdef VXWORKS - return check_error(ioctl(fd, FIOSYNC, 0), errInfo); -#else - undefined fsync -#endif /* VXWORKS */ + undefined fsync /* XXX: Really? */ #else #if defined(DARWIN) && defined(F_FULLFSYNC) return check_error(fcntl(fd, F_FULLFSYNC), errInfo); @@ -818,21 +461,8 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, struct stat statbuf; /* Information about the file */ int result; -#ifdef VXWORKS - if (*name == '\0') { - errInfo->posix_errno = errInfo->os_errno = ENOENT; - return 0; - } -#endif - - CHECK_PATHLEN(name, errInfo); - if (info_for_link) { -#if (defined(VXWORKS)) - result = stat(name, &statbuf); -#else result = lstat(name, &statbuf); -#endif } else { result = stat(name, &statbuf); } @@ -849,19 +479,9 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, #ifdef NO_ACCESS /* Just look at read/write access for owner. */ -#ifdef VXWORKS - - pInfo->access = FA_NONE; - if(statbuf.st_mode & S_IRUSR) - pInfo->access |= FA_READ; - if(statbuf.st_mode & S_IWUSR) - pInfo->access |= FA_WRITE; - -#else pInfo->access = ((statbuf.st_mode >> 6) & 07) >> 1; -#endif /* VXWORKS */ #else pInfo->access = FA_NONE; if (access(name, R_OK) == 0) @@ -902,35 +522,6 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) { struct utimbuf tval; - CHECK_PATHLEN(name, errInfo); - -#ifdef VXWORKS - - if (pInfo->mode != -1) { - int fd; - struct stat statbuf; - - fd = open(name, O_RDONLY, 0); - if (!check_error(fd, errInfo)) - return 0; - if (fstat(fd, &statbuf) < 0) { - close(fd); - return check_error(-1, errInfo); - } - if (pInfo->mode & S_IWUSR) { - /* clear read only bit */ - statbuf.st_attrib &= ~DOS_ATTR_RDONLY; - } else { - /* set read only bit */ - statbuf.st_attrib |= DOS_ATTR_RDONLY; - } - /* This should work for dos files but not for nfs ditos, so don't - * report errors (to avoid problems when running e.g. erl_tar) - */ - ioctl(fd, FIOATTRIBSET, statbuf.st_attrib); - close(fd); - } -#else /* * On some systems chown will always fail for a non-root user unless * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as @@ -952,20 +543,10 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) } } -#endif /* !VXWORKS */ - tval.actime = pInfo->accessTime; tval.modtime = pInfo->modifyTime; -#ifdef VXWORKS - /* VxWorks' utime doesn't work when the file is a nfs mounted - * one, don't report error if utime fails. - */ - utime(name, &tval); - return 1; -#else return check_error(utime(name, &tval), errInfo); -#endif } @@ -979,11 +560,6 @@ efile_write(Efile_error* errInfo, /* Where to return error codes. */ { ssize_t written; /* Bytes written in last operation. */ -#ifdef VXWORKS - if (flags & EFILE_MODE_APPEND) { - lseek(fd, 0, SEEK_END); /* Naive append emulation on VXWORKS */ - } -#endif while (count > 0) { if ((written = write(fd, buf, count)) < 0) { if (errno != EINTR) @@ -1012,12 +588,6 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ ASSERT(iovcnt >= 0); -#ifdef VXWORKS - if (flags & EFILE_MODE_APPEND) { - lseek(fd, 0, SEEK_END); /* Naive append emulation on VXWORKS */ - } -#endif - while (cnt < iovcnt) { if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) { /* Empty buffer - skip */ @@ -1226,118 +796,6 @@ efile_seek(Efile_error* errInfo, /* Where to return error codes. */ int efile_truncate_file(Efile_error* errInfo, int *fd, int flags) { -#ifdef VXWORKS - off_t offset; - char namebuf[PATH_MAX+1]; - char namebuf2[PATH_MAX+10]; - int new; - int dummy; - int i; - int left; - static char buff[1024]; - struct stat st; - Efile_error tmperr; - - if ((offset = lseek(*fd, 0, 1)) < 0) { - return check_error((int) offset,errInfo); - } - if (ftruncate(*fd, offset) < 0) { - if (vxworks_to_posix(errno) != EINVAL) { - return check_error(-1, errInfo); - } - /* - ** Kludge - */ - if(ioctl(*fd,FIOGETNAME,(int) namebuf) < 0) { - return check_error(-1, errInfo); - } - for(i=0;i<1000;++i) { - sprintf(namebuf2,"%s%d",namebuf,i); - CHECK_PATHLEN(namebuf2,errInfo); - if (stat(namebuf2,&st) < 0) { - break; - } - } - if (i > 1000) { - errno = EINVAL; - return check_error(-1, errInfo); - } - if (close(*fd) < 0) { - return check_error(-1, errInfo); - } - if (efile_rename(&tmperr,namebuf,namebuf2) < 0) { - i = check_error(-1,&tmperr); - if (!efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE, - fd,&dummy)) { - *fd = -1; - } else { - *errInfo = tmperr; - } - return i; - } - if ((*fd = open(namebuf2, O_RDONLY, 0)) < 0) { - i = check_error(-1,errInfo); - efile_rename(&tmperr,namebuf2,namebuf); /* at least try */ - if (!efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE, - fd,&dummy)) { - *fd = -1; - } else { - lseek(*fd,offset,SEEK_SET); - } - return i; - } - /* Point of no return... */ - - if ((new = open(namebuf,O_RDWR | O_CREAT, FILE_MODE)) < 0) { - close(*fd); - *fd = -1; - return 0; - } - left = offset; - - while (left) { - if ((i = read(*fd,buff,(left > 1024) ? 1024 : left)) < 0) { - i = check_error(-1,errInfo); - close(new); - close(*fd); - unlink(namebuf); - efile_rename(&tmperr,namebuf2,namebuf); /* at least try */ - if (!efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE, - fd,&dummy)) { - *fd = -1; - } else { - lseek(*fd,offset,SEEK_SET); - } - return i; - } - left -= i; - if (write(new,buff,i) < 0) { - i = check_error(-1,errInfo); - close(new); - close(*fd); - unlink(namebuf); - rename(namebuf2,namebuf); /* at least try */ - if (!efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE, - fd,&dummy)) { - *fd = -1; - } else { - lseek(*fd,offset,SEEK_SET); - } - return i; - } - } - close(*fd); - unlink(namebuf2); - close(new); - i = efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE,fd, - &dummy); - if (i) { - lseek(*fd,offset,SEEK_SET); - } - return i; - } - return 1; -#else #ifndef NO_FTRUNCATE off_t offset; @@ -1347,15 +805,11 @@ efile_truncate_file(Efile_error* errInfo, int *fd, int flags) #else return 1; #endif -#endif } int efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) { -#ifdef VXWORKS - return vxworks_enotsup(errInfo); -#else int len; ASSERT(size > 0); len = readlink(name, buffer, size-1); @@ -1364,7 +818,6 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) } buffer[len] = '\0'; return 1; -#endif } int @@ -1377,21 +830,13 @@ efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) int efile_link(Efile_error* errInfo, char* old, char* new) { -#ifdef VXWORKS - return vxworks_enotsup(errInfo); -#else return check_error(link(old, new), errInfo); -#endif } int efile_symlink(Efile_error* errInfo, char* old, char* new) { -#ifdef VXWORKS - return vxworks_enotsup(errInfo); -#else return check_error(symlink(old, new), errInfo); -#endif } int diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index af593229c0..74868b868c 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -609,8 +609,8 @@ static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity) Uint *code_base; int i, n; - modp = erts_get_module(mod); - if (modp == NULL || (code_base = modp->code) == NULL) + modp = erts_get_module(mod, erts_active_code_ix()); + if (modp == NULL || (code_base = modp->curr.code) == NULL) return NULL; n = code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { @@ -648,7 +648,7 @@ static void *hipe_get_emu_address(Eterm m, Eterm f, unsigned int arity, int is_r /* if not found, stub it via the export entry */ /* no lock needed around erts_export_get_or_make_stub() */ Export *export_entry = erts_export_get_or_make_stub(m, f, arity); - address = export_entry->address; + address = export_entry->addressv[erts_active_code_ix()]; } return address; } @@ -1589,7 +1589,7 @@ BIF_RETTYPE hipe_nonclosure_address(BIF_ALIST_2) f = tp[2]; if (is_not_atom(m) || is_not_atom(f)) goto badfun; - if (!erts_find_export_entry(m, f, BIF_ARG_2)) + if (!erts_active_export_entry(m, f, BIF_ARG_2)) goto badfun; } else goto badfun; diff --git a/erts/emulator/hipe/hipe_bif2.c b/erts/emulator/hipe/hipe_bif2.c index 37a1cc193b..ac0c2e2ffa 100644 --- a/erts/emulator/hipe/hipe_bif2.c +++ b/erts/emulator/hipe/hipe_bif2.c @@ -173,3 +173,10 @@ BIF_RETTYPE hipe_debug_bif_wrapper(BIF_ALIST_1) #endif /* ERTS_ENABLE_LOCK_CHECK && ERTS_SMP */ + +BIF_RETTYPE hipe_bifs_debug_native_called_2(BIF_ALIST_2) +{ + erts_printf("hipe_debug_native_called: %T(%T)\r\n", BIF_ARG_1, BIF_ARG_2); + BIF_RET(am_ok); +} + diff --git a/erts/emulator/hipe/hipe_bif2.tab b/erts/emulator/hipe/hipe_bif2.tab index aac27e8bed..ddbd31f155 100644 --- a/erts/emulator/hipe/hipe_bif2.tab +++ b/erts/emulator/hipe/hipe_bif2.tab @@ -29,3 +29,4 @@ bif hipe_bifs:show_term/1 bif hipe_bifs:in_native/0 bif hipe_bifs:modeswitch_debug_on/0 bif hipe_bifs:modeswitch_debug_off/0 +bif hipe_bifs:debug_native_called/2
\ No newline at end of file diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4 index 942fa0c5cb..d9aa09b79e 100644 --- a/erts/emulator/hipe/hipe_bif_list.m4 +++ b/erts/emulator/hipe/hipe_bif_list.m4 @@ -165,6 +165,7 @@ gc_bif_interface_2(nbif_put_2, put_2) gc_bif_interface_1(nbif_hipe_bifs_show_nstack_1, hipe_show_nstack_1) gc_bif_interface_1(nbif_hipe_bifs_show_pcb_1, hipe_bifs_show_pcb_1) gc_bif_interface_0(nbif_hipe_bifs_nstack_used_size_0, hipe_bifs_nstack_used_size_0) +gc_bif_interface_2(nbif_hipe_bifs_debug_native_called, hipe_bifs_debug_native_called_2) /* * Arithmetic operators called indirectly by the HiPE compiler. diff --git a/erts/emulator/hipe/hipe_debug.c b/erts/emulator/hipe/hipe_debug.c index 7ca11f8c6c..37615bf718 100644 --- a/erts/emulator/hipe/hipe_debug.c +++ b/erts/emulator/hipe/hipe_debug.c @@ -188,8 +188,6 @@ void hipe_print_pcb(Process *p) U("old_htop ", old_htop); U("old_head ", old_heap); U("min_heap_..", min_heap_size); - U("status ", status); - U("rstatus ", rstatus); U("rcount ", rcount); U("id ", id); U("prio ", prio); diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c index 6a3ce5608f..3c782b2f56 100644 --- a/erts/emulator/hipe/hipe_mode_switch.c +++ b/erts/emulator/hipe/hipe_mode_switch.c @@ -360,7 +360,8 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) p->flags &= ~F_HIBERNATE_SCHED; goto do_schedule; } - if (p->status == P_WAITING) { + + if (!(erts_smp_atomic32_read_acqb(&p->state) & ERTS_PSFLG_ACTIVE)) { for (i = 0; i < p->arity; ++i) p->arg_reg[i] = reg[i]; goto do_schedule; @@ -451,10 +452,6 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) case HIPE_MODE_SWITCH_RES_SUSPEND: { p->i = hipe_beam_pc_resume; p->arity = 0; - erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); - if (p->status != P_SUSPENDED) - erts_add_to_runq(p); - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); goto do_schedule; } case HIPE_MODE_SWITCH_RES_WAIT: @@ -470,7 +467,8 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) #endif p->i = hipe_beam_pc_resume; p->arity = 0; - p->status = P_WAITING; + erts_smp_atomic32_read_band_relb(&p->state, + ~ERTS_PSFLG_ACTIVE); erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_MSG_RECEIVE); do_schedule: { diff --git a/erts/emulator/hipe/hipe_native_bif.h b/erts/emulator/hipe/hipe_native_bif.h index 9e3a156fbc..3f460a5a5c 100644 --- a/erts/emulator/hipe/hipe_native_bif.h +++ b/erts/emulator/hipe/hipe_native_bif.h @@ -110,6 +110,9 @@ int hipe_bs_put_big_integer(Eterm, Uint, byte*, unsigned, unsigned); AEXTERN(Eterm,nbif_check_get_msg,(Process*)); Eterm hipe_check_get_msg(Process*); +AEXTERN(BIF_RETTYPE,nbif_hipe_bifs_debug_native_called,(Process*,Eterm,Eterm)); +BIF_RETTYPE hipe_bifs_debug_native_called_2(BIF_ALIST_2); + /* * SMP-specific stuff */ diff --git a/erts/emulator/hipe/hipe_primops.h b/erts/emulator/hipe/hipe_primops.h index 38509c105b..52b4681cfe 100644 --- a/erts/emulator/hipe/hipe_primops.h +++ b/erts/emulator/hipe/hipe_primops.h @@ -80,6 +80,7 @@ PRIMOP_LIST(am_fclearerror_error, &nbif_fclearerror_error) #ifdef NO_FPE_SIGNALS PRIMOP_LIST(am_emulate_fpe, &nbif_emulate_fpe) #endif +PRIMOP_LIST(am_debug_native_called, &nbif_hipe_bifs_debug_native_called) #if defined(__sparc__) #include "hipe_sparc_primops.h" diff --git a/erts/emulator/hipe/hipe_stack.c b/erts/emulator/hipe/hipe_stack.c index da462a64e1..53c316ba52 100644 --- a/erts/emulator/hipe/hipe_stack.c +++ b/erts/emulator/hipe/hipe_stack.c @@ -130,7 +130,7 @@ struct sdesc *hipe_decode_sdesc(Eterm arg) struct sdesc *sdesc; if (is_not_tuple(arg) || - (tuple_val(arg))[0] != make_arityval(5) || + (tuple_val(arg))[0] != make_arityval(6) || term_to_Uint((tuple_val(arg))[1], &ra) == 0 || term_to_Uint((tuple_val(arg))[2], &exnra) == 0 || is_not_small((tuple_val(arg))[3]) || @@ -183,5 +183,13 @@ struct sdesc *hipe_decode_sdesc(Eterm arg) off = unsigned_val(live[i]); sdesc->livebits[off / 32] |= (1 << (off & 31)); } +#ifdef DEBUG + { + Eterm mfa_tpl = tuple_val(arg)[6]; + sdesc->dbg_M = tuple_val(mfa_tpl)[1]; + sdesc->dbg_F = tuple_val(mfa_tpl)[2]; + sdesc->dbg_A = tuple_val(mfa_tpl)[3]; + } +#endif return sdesc; } diff --git a/erts/emulator/hipe/hipe_stack.h b/erts/emulator/hipe/hipe_stack.h index 4e3076caf5..da706ae25e 100644 --- a/erts/emulator/hipe/hipe_stack.h +++ b/erts/emulator/hipe/hipe_stack.h @@ -35,6 +35,10 @@ struct sdesc { struct sdesc *next; /* hash collision chain */ } bucket; unsigned int summary; /* frame size, exn handler presence flag, arity */ +#ifdef DEBUG + Eterm dbg_M, dbg_F; + unsigned dbg_A; +#endif unsigned int livebits[1]; /* size depends on arch & data in summary field */ }; diff --git a/erts/emulator/hipe/hipe_x86_gc.h b/erts/emulator/hipe/hipe_x86_gc.h index e4607ad27d..aa4abb6f59 100644 --- a/erts/emulator/hipe/hipe_x86_gc.h +++ b/erts/emulator/hipe/hipe_x86_gc.h @@ -69,6 +69,11 @@ nstack_walk_init_sdesc(const Process *p, struct nstack_walk_state *state) nstkarity = 0; state->sdesc0[0].summary = (0 << 9) | (0 << 8) | nstkarity; state->sdesc0[0].livebits[0] = 0; +# ifdef DEBUG + state->sdesc0[0].dbg_M = 0; + state->sdesc0[0].dbg_F = am_init; + state->sdesc0[0].dbg_A = 0; +# endif /* XXX: this appears to prevent a gcc-4.1.1 bug on x86 */ __asm__ __volatile__("" : : "m"(*state) : "memory"); return &state->sdesc0[0]; diff --git a/erts/emulator/hipe/hipe_x86_glue.h b/erts/emulator/hipe/hipe_x86_glue.h index b0db93267c..63ad250d60 100644 --- a/erts/emulator/hipe/hipe_x86_glue.h +++ b/erts/emulator/hipe/hipe_x86_glue.h @@ -62,6 +62,9 @@ static __inline__ void hipe_arch_glue_init(void) .sdesc = { .bucket = { .hvalue = (unsigned long)nbif_return }, .summary = (1<<8), + #ifdef DEBUG + .dbg_F = am_return, + #endif }, }; hipe_init_sdesc_table(&nbif_return_sdesc.sdesc); diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index c1336c60d9..ce014c19c2 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -39,7 +39,6 @@ #include "dtrace-wrapper.h" #ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS -# define ERTS_DRV_EV_STATE_EXTRA_SIZE 128 #else # include "safe_hash.h" # define DRV_EV_STATE_HTAB_SIZE 1024 @@ -334,7 +333,9 @@ static void grow_drv_ev_state(int min_ix) { int i; - int new_len = min_ix + 1 + ERTS_DRV_EV_STATE_EXTRA_SIZE; + int new_len; + + new_len = ERTS_POLL_EXPORT(erts_poll_get_table_len)(min_ix + 1); if (new_len > max_fds) new_len = max_fds; diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 26858052c4..b0eaf14d90 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -55,17 +55,12 @@ # ifdef SYS_SELECT_H # include <sys/select.h> # endif -# ifdef VXWORKS -# include <selectLib.h> -# endif #endif -#ifndef VXWORKS -# ifdef NO_SYSCONF -# if ERTS_POLL_USE_SELECT -# include <sys/param.h> -# else -# include <limits.h> -# endif +#ifdef NO_SYSCONF +# if ERTS_POLL_USE_SELECT +# include <sys/param.h> +# else +# include <limits.h> # endif #endif #include "erl_thr_progress.h" @@ -105,8 +100,8 @@ #define ERTS_POLL_COALESCE_KP_RES (ERTS_POLL_USE_KQUEUE || ERTS_POLL_USE_EPOLL) -#define FDS_STATUS_EXTRA_FREE_SIZE 128 -#define POLL_FDS_EXTRA_FREE_SIZE 128 +#define ERTS_EV_TABLE_MIN_LENGTH 1024 +#define ERTS_EV_TABLE_EXP_THRESHOLD (2048*1024) #ifdef ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT # define ERTS_POLL_ASYNC_INTERRUPT_SUPPORT 1 @@ -563,6 +558,28 @@ free_update_requests_block(ErtsPollSet ps, * --- Growing poll set structures ------------------------------------------- */ +int +ERTS_POLL_EXPORT(erts_poll_get_table_len) (int new_len) +{ + if (new_len < ERTS_EV_TABLE_MIN_LENGTH) { + new_len = ERTS_EV_TABLE_MIN_LENGTH; + } else if (new_len < ERTS_EV_TABLE_EXP_THRESHOLD) { + /* find next power of 2 */ + --new_len; + new_len |= new_len >> 1; + new_len |= new_len >> 2; + new_len |= new_len >> 4; + new_len |= new_len >> 8; + new_len |= new_len >> 16; + ++new_len; + } else { + /* grow incrementally */ + new_len += ERTS_EV_TABLE_EXP_THRESHOLD; + } + return new_len; +} + + #if ERTS_POLL_USE_KERNEL_POLL static void grow_res_events(ErtsPollSet ps, int new_len) @@ -575,7 +592,7 @@ grow_res_events(ErtsPollSet ps, int new_len) #elif ERTS_POLL_USE_KQUEUE struct kevent #endif - )*new_len; + ) * ERTS_POLL_EXPORT(erts_poll_get_table_len)(new_len); /* We do not need to save previously stored data */ if (ps->res_events) erts_free(ERTS_ALC_T_POLL_RES_EVS, ps->res_events); @@ -589,7 +606,7 @@ static void grow_poll_fds(ErtsPollSet ps, int min_ix) { int i; - int new_len = min_ix + 1 + POLL_FDS_EXTRA_FREE_SIZE; + int new_len = ERTS_POLL_EXPORT(erts_poll_get_table_len)(min_ix + 1); if (new_len > max_fds) new_len = max_fds; ps->poll_fds = (ps->poll_fds_len @@ -611,7 +628,7 @@ static void grow_fds_status(ErtsPollSet ps, int min_fd) { int i; - int new_len = min_fd + 1 + FDS_STATUS_EXTRA_FREE_SIZE; + int new_len = ERTS_POLL_EXPORT(erts_poll_get_table_len)(min_fd + 1); ASSERT(min_fd < max_fds); if (new_len > max_fds) new_len = max_fds; @@ -2200,10 +2217,6 @@ ERTS_POLL_EXPORT(erts_poll_max_fds)(void) * --- Initialization -------------------------------------------------------- */ -#ifdef VXWORKS -extern int erts_vxworks_max_files; -#endif - void ERTS_POLL_EXPORT(erts_poll_init)(void) { @@ -2212,9 +2225,7 @@ ERTS_POLL_EXPORT(erts_poll_init)(void) errno = 0; -#if defined(VXWORKS) - max_fds = erts_vxworks_max_files; -#elif !defined(NO_SYSCONF) +#if !defined(NO_SYSCONF) max_fds = sysconf(_SC_OPEN_MAX); #elif ERTS_POLL_USE_SELECT max_fds = NOFILE; diff --git a/erts/emulator/sys/common/erl_poll.h b/erts/emulator/sys/common/erl_poll.h index 8dde619105..502290e4bb 100644 --- a/erts/emulator/sys/common/erl_poll.h +++ b/erts/emulator/sys/common/erl_poll.h @@ -246,4 +246,6 @@ void ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet, ErtsPollEvents [], int); +int ERTS_POLL_EXPORT(erts_poll_get_table_len)(int); + #endif /* #ifndef ERL_POLL_H__ */ diff --git a/erts/emulator/sys/vxworks/driver_int.h b/erts/emulator/sys/vxworks/driver_int.h deleted file mode 100644 index f6bc71a799..0000000000 --- a/erts/emulator/sys/vxworks/driver_int.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/*---------------------------------------------------------------------- -** Purpose : System dependant driver declarations -**---------------------------------------------------------------------- */ - -#ifndef __DRIVER_INT_H__ -#define __DRIVER_INT_H__ - -#include <ioLib.h> - -typedef struct iovec SysIOVec; - -#endif diff --git a/erts/emulator/sys/vxworks/erl_main.c b/erts/emulator/sys/vxworks/erl_main.c deleted file mode 100644 index c9b44a635a..0000000000 --- a/erts/emulator/sys/vxworks/erl_main.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2000-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "sys.h" -#include "erl_vm.h" - -#if defined(__GNUC__) -/* - * The generated assembler does the usual trick (relative - * branch-and-link to next instruction) to get a copy of the - * instruction ptr. Instead of branching to an explicit zero offset, - * it branches to the symbol `__eabi' --- which is expected to be - * undefined and thus zero (if it is defined as non-zero, things will - * be interesting --- as in the Chinese curse). To shut up the VxWorks - * linker, we define `__eabi' as zero. - * - * This is just a work around. It's really Wind River's GCC's code - * generator that should be fixed. - */ -__asm__(".equ __eabi, 0"); -#endif - -void -erl_main(int argc, char **argv) -{ - erl_start(argc, argv); -} diff --git a/erts/emulator/sys/vxworks/erl_vxworks_sys.h b/erts/emulator/sys/vxworks/erl_vxworks_sys.h deleted file mode 100644 index 3d53238ea6..0000000000 --- a/erts/emulator/sys/vxworks/erl_vxworks_sys.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -#ifndef __ERL_VXWORKS_SYS_H__ -#define __ERL_VXWORKS_SYS_H__ - -/* stdarg.h don't work without this one... */ -#include <vxWorks.h> - -#include <stdio.h> -#include <math.h> -#include <limits.h> -#include <stdlib.h> -#define index StringIndexFunctionThatIDontWantDeclared -#include <string.h> -#undef index - - - -#include <sys/times.h> -#include <time.h>/* xxxP */ - -#include <dirent.h> -#include <sys/stat.h> - -/* xxxP from unix_sys.h begin */ - -/* - * Make sure that MAXPATHLEN is defined. - */ - -#ifndef MAXPATHLEN -# ifdef PATH_MAX -# define MAXPATHLEN PATH_MAX -# else -# define MAXPATHLEN 2048 -# endif -#endif - -/* xxxP end */ - - -/* Unimplemented math functions */ -#define NO_ASINH -#define NO_ACOSH -#define NO_ATANH -#define NO_ERF -#define NO_ERFC - -/* Stuff that is useful for port programs, drivers, etc */ -#ifndef VXWORKS -#define VXWORKS -#endif - -#define DONT_USE_MAIN -#define NO_FSYNC -#define NO_MKDIR_MODE -#define NO_UMASK -#define NO_SYMBOLIC_LINKS -#define NO_DEVICE_FILES -#define NO_UID -#define NO_ACCESS -#define NO_FCNTL -#define NO_SYSLOG -#define NO_SYSCONF -#define NO_PWD /* XXX Means what? */ -#define NO_DAEMON -/* This chooses ~250 reductions instead of 500 in config.h */ -#if (CPU == CPU32) -#define SLOW_PROCESSOR -#endif - -/* - * Even though we does not always have small memories on VxWorks - * we certainly does not have virtual memory. - */ -#if !defined(LARGE_MEMORY) -#define SMALL_MEMORY -#endif - -/*************** Floating point exception handling ***************/ - -/* There are no known ways to customize the handling of invalid floating - point operations, such as matherr() or ieee_handler(), in VxWorks 5.1. */ - -#if (CPU == MC68040 || CPU == CPU32 || CPU == PPC860 || CPU == PPC32 || \ - CPU == PPC603 || CPU == PPC604 || CPU == SIMSPARCSOLARIS) - -/* VxWorks 5.1 on Motorola 68040 never generates SIGFPE, but sets the - result of invalid floating point ops to Inf and NaN - unfortunately - the way to test for those values is undocumented and hidden in a - "private" include file... */ -/* Haven't found any better way, as of yet, for ppc860 xxxP*/ - -#include <private/mathP.h> -#define NO_FPE_SIGNALS -#define erts_get_current_fp_exception() NULL -#define __ERTS_FP_CHECK_INIT(fpexnp) do {} while (0) -#define __ERTS_FP_ERROR(fpexnp, f, Action) if (isInf(f) || isNan(f)) { Action; } else {} -#define __ERTS_FP_ERROR_THOROUGH(fpexnp, f, Action) __ERTS_FP_ERROR(fpexnp, f, Action) -#define __ERTS_SAVE_FP_EXCEPTION(fpexnp) -#define __ERTS_RESTORE_FP_EXCEPTION(fpexnp) - -#define ERTS_FP_CHECK_INIT(p) __ERTS_FP_CHECK_INIT(&(p)->fp_exception) -#define ERTS_FP_ERROR(p, f, A) __ERTS_FP_ERROR(&(p)->fp_exception, f, A) -#define ERTS_SAVE_FP_EXCEPTION(p) __ERTS_SAVE_FP_EXCEPTION(&(p)->fp_exception) -#define ERTS_RESTORE_FP_EXCEPTION(p) __ERTS_RESTORE_FP_EXCEPTION(&(p)->fp_exception) -#define ERTS_FP_ERROR_THOROUGH(p, f, A) __ERTS_FP_ERROR_THOROUGH(&(p)->fp_exception, f, A) - -#define erts_sys_block_fpe() 0 -#define erts_sys_unblock_fpe(x) do{}while(0) - -#if (CPU == PPC603) -/* Need fppLib to change the Floating point registers - (fix_registers in sys.c)*/ - -#include <fppLib.h> - -#endif /* PPC603 */ - -#else - -Unsupported CPU value ! - -#endif - -typedef void *GETENV_STATE; - -#define HAVE_GETHRTIME - -extern int erts_clock_rate; - -#define SYS_CLK_TCK (erts_clock_rate) - -#define SYS_CLOCK_RESOLUTION 1 - -typedef struct _vxworks_tms { - clock_t tms_utime; - clock_t tms_stime; - clock_t tms_cutime; - clock_t tms_cstime; -} SysTimes; - -typedef long long SysHrTime; - -typedef time_t erts_time_t; -typedef struct timeval SysTimeval; - -extern int sys_init_hrtime(void); -extern SysHrTime sys_gethrtime(void); -extern void sys_gettimeofday(SysTimeval *tvp); -extern clock_t sys_times(SysTimes *t); - -#define SIZEOF_SHORT 2 -#define SIZEOF_INT 4 -#define SIZEOF_LONG 4 -#define SIZEOF_VOID_P 4 -#define SIZEOF_SIZE_T 4 -#define SIZEOF_OFF_T 4 - -/* - * Temporary buffer *only* used in sys code. - */ -#define SYS_TMP_BUF_SIZE 65536 - -/* Need to be able to interrupt erts_poll_wait() from signal handler */ -#define ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT - -#endif /* __ERL_VXWORKS_SYS_H__ */ diff --git a/erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c b/erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c deleted file mode 100644 index c56c633b2f..0000000000 --- a/erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2006-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -/* - * Interface functions to the dynamic linker using dl* functions. - * (As far as I know it works on SunOS 4, 5, Linux and FreeBSD. /Seb) - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include <vxWorks.h> -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <a_out.h> -#include <symLib.h> -#include <loadLib.h> -#include <unldLib.h> -#include <moduleLib.h> -#include <sysSymTbl.h> -#include "sys.h" -#include "global.h" -#include "erl_alloc.h" -#include "erl_driver.h" - -#define EXT_LEN 4 -#define FILE_EXT ".eld" -#define ALT_FILE_EXT ".o" -/* ALT_FILE_EXT must not be longer than FILE_EXT */ -#define DRIVER_INIT_SUFFIX "_init" - -static MODULE_ID get_mid(char *); -static FUNCPTR lookup(char *); - -typedef enum { - NoError, - ModuleNotFound, - ModuleNotUnloadable, - UnknownError -} FakeSytemError; - -static char *errcode_tab[] = { - "No error", - "Module/file not found", - "Module cannot be unloaded", - "Unknown error" -}; - -void erl_sys_ddll_init(void) { - return; -} -/* - * Open a shared object - */ -int erts_sys_ddll_open2(char *full_name, void **handle, ErtsSysDdllError* err) -{ - int len; - - if (erts_sys_ddll_open_noext(full_name, handle, err) == ERL_DE_NO_ERROR) { - return ERL_DE_NO_ERROR; - } - if ((len = sys_strlen(full_name)) > PATH_MAX-EXT_LEN) { - return ERL_DE_LOAD_ERROR_NAME_TO_LONG; - } else { - static char dlname[PATH_MAX + 1]; - - sys_strcpy(dlname, full_name); - sys_strcpy(dlname+len, FILE_EXT); - if (erts_sys_ddll_open_noext(dlname, handle, err) == ERL_DE_NO_ERROR) { - return ERL_DE_NO_ERROR; - } - sys_strcpy(dlname+len, ALT_FILE_EXT); - return erts_sys_ddll_open_noext(dlname, handle, err); - } -} -int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err) -{ - MODULE_ID mid; - - if((mid = get_mid(dlname)) == NULL) { - return ERL_DE_DYNAMIC_ERROR_OFFSET - ((int) ModuleNotFound); - } - *handle = (void *) mid; - return ERL_DE_NO_ERROR; -} - -/* - * Find a symbol in the shared object - */ -#define PREALLOC_BUFFER_SIZE 256 -int erts_sys_ddll_sym2(void *handle, char *func_name, void **function, ErtsSysDdllError* err) -{ - FUNCPTR proc; - static char statbuf[PREALLOC_BUFFER_SIZE]; - char *buf = statbuf; - int need; - - if ((proc = lookup(func_name)) == NULL) { - if ((need = strlen(func_name)+2) > PREALLOC_BUFFER_SIZE) { - buf = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF,need); - } - buf[0] = '_'; - sys_strcpy(buf+1,func_name); - proc = lookup(buf); - if (buf != statbuf) { - erts_free(ERTS_ALC_T_DDLL_TMP_BUF, buf); - } - if (proc == NULL) { - return ERL_DE_LOOKUP_ERROR_NOT_FOUND; - } - } - *function = (void *) proc; - return ERL_DE_NO_ERROR; -} - -/* XXX:PaN These two will be changed with new driver interface! */ - -/* - * Load the driver init function, might appear under different names depending on object arch... - */ - -int erts_sys_ddll_load_driver_init(void *handle, void **function) -{ - MODULE_ID mid = (MODULE_ID) handle; - char *modname; - char *cp; - static char statbuf[PREALLOC_BUFFER_SIZE]; - char *fname = statbuf; - int len; - int res; - void *func; - int need; - - if((modname = moduleNameGet(mid)) == NULL) { - return ERL_DE_DYNAMIC_ERROR_OFFSET - ((int) ModuleNotFound); - } - - if((cp = strrchr(modname, '.')) == NULL) { - len = strlen(modname); - } else { - len = cp - modname; - } - - need = len + strlen(DRIVER_INIT_SUFFIX) + 1; - if (need > PREALLOC_BUFFER_SIZE) { - fname = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, need); /* erts_alloc exits on failure */ - } - sys_strncpy(fname, modname, len); - fname[len] = '\0'; - sys_strcat(fname, DRIVER_INIT_SUFFIX); - res = erts_sys_ddll_sym(handle, fname, &func); - if (fname != statbuf) { - erts_free(ERTS_ALC_T_DDLL_TMP_BUF, fname); - } - if ( res != ERL_DE_NO_ERROR) { - return res; - } - *function = func; - return ERL_DE_NO_ERROR; -} - -int erts_sys_ddll_load_nif_init(void *handle, void **function, ErtsSysDdllError* err) -{ - /* NIFs not implemented for vxworks */ - return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY; -} - -/* - * Call the driver_init function, whatever it's really called, simple on unix... -*/ -void *erts_sys_ddll_call_init(void *function) { - void *(*initfn)(void) = function; - return (*initfn)(); -} -void *erts_sys_ddll_call_nif_init(void *function) { - return erts_sys_ddll_call_init(function); -} - - -/* - * Close a chared object - */ -int erts_sys_ddll_close2(void *handle, ErtsSysDdllError* err) -{ - MODULE_ID mid = (MODULE_ID) handle; - if (unld(mid, 0) < 0) { - return ERL_DE_DYNAMIC_ERROR_OFFSET - ((int) ModuleNotUnloadable); - } - return ERL_DE_NO_ERROR; -} - -/* - * Return string that describes the (current) error - */ -char *erts_sys_ddll_error(int code) -{ - int actual_code; - if (code > ERL_DE_DYNAMIC_ERROR_OFFSET) { - return "Unspecified error"; - } - actual_code = -1*(code - ERL_DE_DYNAMIC_ERROR_OFFSET); - if (actual_code > ((int) UnknownError)) { - actual_code = UnknownError; - } - return errcode_tab[actual_code]; -} - -static FUNCPTR lookup(char *sym) -{ - FUNCPTR entry; - SYM_TYPE type; - - if (symFindByNameAndType(sysSymTbl, sym, (char **)&entry, - &type, N_EXT | N_TEXT, N_EXT | N_TEXT) != OK) { - return NULL ; - } - return entry; -} - -static MODULE_ID get_mid(char* name) -{ - int fd; - MODULE_ID mid = NULL; - - if((fd = open(name, O_RDONLY, 0664)) >= 0) { - mid = loadModule(fd, GLOBAL_SYMBOLS); - close(fd); - } - return mid; -} - -void erts_sys_ddll_free_error(ErtsSysDdllError* err) -{ - /* NYI */ -} - diff --git a/erts/emulator/sys/vxworks/sys.c b/erts/emulator/sys/vxworks/sys.c deleted file mode 100644 index 739b026fb1..0000000000 --- a/erts/emulator/sys/vxworks/sys.c +++ /dev/null @@ -1,2610 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * system-dependent functions - * - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include <vxWorks.h> -#include <version.h> -#include <string.h> -#include <types.h> -#include <sigLib.h> -#include <ioLib.h> -#include <iosLib.h> -#include <envLib.h> -#include <fioLib.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <symLib.h> -#include <sysLib.h> -#include <sysSymTbl.h> -#include <loadLib.h> -#include <taskLib.h> -#include <taskVarLib.h> -#include <taskHookLib.h> -#include <tickLib.h> -#include <time.h> -#include <rngLib.h> -#include <semLib.h> -#include <selectLib.h> -#include <sockLib.h> -#include <a_out.h> -#include <wdLib.h> -#include <timers.h> -#include <ctype.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <stdarg.h> - - -#ifndef WANT_NONBLOCKING -#define WANT_NONBLOCKING -#endif - -#include "sys.h" -#include "erl_alloc.h" - -/* don't need global.h, but bif_table.h (included by bif.h) won't compile otherwise */ -#include "global.h" -#include "bif.h" - -#include "erl_sys_driver.h" - -#include "elib_stat.h" - -#include "reclaim_private.h" /* Some more or less private reclaim facilities */ - -#ifndef RETSIGTYPE -#define RETSIGTYPE void -#endif - -EXTERN_FUNCTION(void, erl_start, (int, char**)); -EXTERN_FUNCTION(void, erl_exit, (int n, char*, _DOTS_)); -EXTERN_FUNCTION(void, erl_error, (char*, va_list)); -EXTERN_FUNCTION(int, driver_interrupt, (int, int)); -EXTERN_FUNCTION(void, increment_time, (int)); -EXTERN_FUNCTION(int, erts_next_time, (_VOID_)); -EXTERN_FUNCTION(void, set_reclaim_free_function, (FreeFunction)); -EXTERN_FUNCTION(int, erl_mem_info_get, (MEM_PART_STATS *)); -EXTERN_FUNCTION(void, erl_crash_dump, (char* file, int line, char* fmt, ...)); - -#define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG) - -/* these are defined in usrLib.c */ -extern int spTaskPriority, spTaskOptions; - -/* forward declarations */ -static FUNCTION(FUNCPTR, lookup, (char*)); -static FUNCTION(int, read_fill, (int, char*, int)); -#if (CPU == SPARC) -static FUNCTION(RETSIGTYPE, fpe_sig_handler, (int)); /*where is this fun? */ -#elif (CPU == PPC603) -static FUNCTION(void, fix_registers, (void)); -#endif -static FUNCTION(void, close_pipes, (int*, int*, int)); -static FUNCTION(void, delete_hook, (void)); -static FUNCTION(void, initialize_allocation, (void)); - -FUNCTION(STATUS, uxPipeDrv, (void)); -FUNCTION(STATUS, pipe, (int*)); -FUNCTION(void, uxPipeShow, (int)); - -void erl_main(int argc, char **argv); -void argcall(char *args); - -/* Malloc-realted functions called from the VxWorks shell */ -EXTERN_FUNCTION(int, erl_set_memory_block, - (int, int, int, int, int, int, int, int, int, int)); -EXTERN_FUNCTION(int, erl_memory_show, - (int, int, int, int, int, int, int, int, int, int)); - -#define DEFAULT_PORT_STACK_SIZE 100000 -static int port_stack_size; - -static int erlang_id = 0; /* Inited at loading, set/reset at each run */ - -/* interval time reported to emulator */ -static int sys_itime; - -/* XXX - This is defined in .../config/all/configAll.h (NUM_FILES), - and not easily accessible at compile or run time - however, - in VxWorks 5.1 it is stored in the (undocumented?) maxFiles variable; - probably shouldn't depend on it, but we try to pick it up... */ -static int max_files = 50; /* default configAll.h */ - -int erts_vxworks_max_files; - -/* - * used by the break handler (set by signal handler on ctl-c) - */ -volatile int erts_break_requested; - -/********************* General functions ****************************/ - -/* - * Reset the terminal to the original settings on exit - * (nothing to do for WxWorks). - */ -void sys_tty_reset(int exit_code) -{ -} - -Uint -erts_sys_misc_mem_sz(void) -{ - Uint res = erts_check_io_size(); - /* res += FIXME */ - return res; -} - -/* - * XXX This declaration should not be here. - */ -void erl_sys_schedule_loop(void); - -#ifdef SOFTDEBUG -static void do_trace(int line, char *file, char *format, ...) -{ - va_list va; - int tid = taskIdSelf(); - char buff[512]; - - va_start(va, format); - sprintf(buff,"Trace: Task: 0x%08x, %s:%d - ", - tid, file, line); - vsprintf(buff + strlen(buff), format, va); - va_end(va); - strcat(buff,"\r\n"); - write(2,buff,strlen(buff)); -} - -#define TRACE() do_trace(__LINE__, __FILE__,"") -#define TRACEF(Args...) do_trace(__LINE__,__FILE__, ## Args) -#endif - -void -erts_sys_pre_init(void) -{ - if (erlang_id != 0) { - /* NOTE: This particular case must *not* call erl_exit() */ - erts_fprintf(stderr, "Sorry, erlang is already running (as task %d)\n", - erlang_id); - exit(1); - } - - /* This must be done as early as possible... */ - if(!reclaim_init()) - fprintf(stderr, "Warning : reclaim facility should be initiated before " - "erlang is started!\n"); - erts_vxworks_max_files = max_files = reclaim_max_files(); - - /* Floating point exceptions */ -#if (CPU == SPARC) - sys_sigset(SIGFPE, fpe_sig_handler); -#elif (CPU == PPC603) - fix_registers(); -#endif - - /* register the private delete hook in reclaim */ - save_delete_hook((FUNCPTR)delete_hook, (caddr_t)0); - erlang_id = taskIdSelf(); -#ifdef DEBUG - printf("emulator task id = 0x%x\n", erlang_id); -#endif -} - -void erts_sys_alloc_init(void) -{ - initialize_allocation(); -} - -void -erl_sys_init(void) -{ - setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ); - /* XXX Bug in VxWorks stdio loses fputch()'ed output after the - setvbuf() but before a *printf(), and possibly worse (malloc - errors, crash?) - so let's give it a *printf().... */ - fprintf(stdout, "%s",""); -} - -void -erl_sys_args(int* argc, char** argv) -{ - erts_init_check_io(); - max_files = erts_check_io_max_files(); - ASSERT(max_files <= erts_vxworks_max_files); -} - -void -erts_sys_schedule_interrupt(int set) -{ - erts_check_io_interrupt(set); -} - -/* - * Called from schedule() when it runs out of runnable processes, - * or when Erlang code has performed INPUT_REDUCTIONS reduction - * steps. runnable == 0 iff there are no runnable Erlang processes. - */ -void -erl_sys_schedule(int runnable) -{ - erts_check_io(!runnable); -} - -void erts_do_break_handling(void) -{ - SET_BLOCKING(0); - /* call the break handling function, reset the flag */ - do_break(); - erts_break_requested = 0; - SET_NONBLOCKING(0); -} - -/* signal handling */ -RETSIGTYPE (*sys_sigset(sig, func))() - int sig; - RETSIGTYPE (*func)(); -{ - struct sigaction act, oact; - - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = func; - sigaction(sig, &act, &oact); - return(oact.sa_handler); -} - -void sys_sigblock(int sig) -{ - sigset_t mask; - - sigemptyset(&mask); - sigaddset(&mask, sig); - sigprocmask(SIG_BLOCK, &mask, (sigset_t *)NULL); -} - -void sys_sigrelease(int sig) -{ - sigset_t mask; - - sigemptyset(&mask); - sigaddset(&mask, sig); - sigprocmask(SIG_UNBLOCK, &mask, (sigset_t *)NULL); -} - -void -erts_sys_prepare_crash_dump(void) -{ - -} - -/* register signal handlers XXX - they don't work, need to find out why... */ -/* set up signal handlers for break and quit */ -static void request_break(void) -{ - /* just set a flag - checked for and handled - * in main thread (not signal handler). - * see check_io() - */ -#ifdef DEBUG - fprintf(stderr,"break!\n"); -#endif - erts_break_requested = 1; - erts_check_io_async_sig_interrupt(1); /* Make sure we don't sleep in erts_poll_wait */ -} - -static void do_quit(void) -{ - halt_0(0); -} - -void erts_set_ignore_break(void) { -} - -void init_break_handler(void) -{ - sys_sigset(SIGINT, request_break); - sys_sigset(SIGQUIT, do_quit); -} - -void erts_replace_intr(void) { -} - -int sys_max_files(void) -{ - return(max_files); -} - -/******************* Routines for time measurement *********************/ - -int sys_init_time(void) -{ - erts_clock_rate = sysClkRateGet(); - /* - ** One could imagine that it would be better returning - ** a resolution more near the clock rate, like in: - ** return 1000 / erts_clock_rate; - ** but tests show that such isn't the case (rounding errors?) - ** Well, we go for the Unix variant of returning 1 - ** as a constant virtual clock rate. - */ - return SYS_CLOCK_RESOLUTION; -} - -int erts_clock_rate; -static volatile int ticks_inuse; -static volatile unsigned long ticks_collected; /* will wrap */ -static WDOG_ID watchdog_id; -static ULONG user_time; -static int this_task_id, sys_itime; -static SysHrTime hrtime_wrap; -static unsigned long last_tick_count; - -static void tolerant_time_clockint(int count) -{ - if (watchdog_id != NULL) { - if (taskIsReady(this_task_id)) - user_time += 1; - ++count; - if (!ticks_inuse) { - ticks_collected += count; - count = 0; - } - wdStart(watchdog_id, 1, (FUNCPTR)tolerant_time_clockint, count); - } -} - -int sys_init_hrtime(void) -{ - this_task_id = taskIdSelf(); /* OK, this only works for one single task - in the system... */ - user_time = 0; - - ticks_inuse = 0; - ticks_collected = 0; - hrtime_wrap = 0; - last_tick_count = 0; - - sys_itime = 1000 / erts_clock_rate; - watchdog_id = wdCreate(); - wdStart(watchdog_id, 1, (FUNCPTR) tolerant_time_clockint, 0); - return 0; -} - -SysHrTime sys_gethrtime(void) -{ - SysHrTime ticks; - - ++ticks_inuse; - ticks = (SysHrTime) (ticks_collected & 0x7FFFFFFF); - ticks_inuse = 0; - if (ticks < (SysHrTime) last_tick_count) { - hrtime_wrap += 1UL << 31; - } - last_tick_count = ticks; - return (ticks + hrtime_wrap) * ((SysHrTime) (1000000000UL / - erts_clock_rate)); -} - -void sys_gettimeofday(SysTimeval *tvp) -{ - struct timespec now; - - clock_gettime(CLOCK_REALTIME, &now); - tvp->tv_sec = now.tv_sec; - tvp->tv_usec = now.tv_nsec / 1000; -} - -clock_t sys_times(SysTimes *t) -{ - t->tms_stime = t->tms_cutime = t->tms_cstime = 0; - ++ticks_inuse; - t->tms_utime = user_time; - ticks_inuse = 0; - return tickGet(); /* The best we can do... */ -} - -/* This is called when *this task* is deleted */ -static void delete_hook(void) -{ - if (watchdog_id != NULL) { - wdDelete(watchdog_id); - watchdog_id = NULL; - } - erlang_id = 0; - this_task_id = 0; -} - -/************************** OS info *******************************/ - -/* Used by erlang:info/1. */ -/* (This code was formerly in drv.XXX/XXX_os_drv.c) */ - -#define MAX_VER_STR 9 /* Number of characters to - consider in version string */ - -static FUNCTION(int, get_number, (char** str_ptr)); - -char os_type[] = "vxworks"; - -static int -get_number(char **str_ptr) -{ - char* s = *str_ptr; /* Pointer to beginning of string. */ - char* dot; /* Pointer to dot in string or NULL. */ - - if (!isdigit(*s)) - return 0; - if ((dot = strchr(s, '.')) == NULL) { - *str_ptr = s+strlen(s); - return atoi(s); - } else { - *dot = '\0'; - *str_ptr = dot+1; - return atoi(s); - } -} - -/* namebuf; Where to return the name. */ -/* size; Size of name buffer. */ -void -os_flavor(char *namebuf, unsigned size) -{ - strcpy(namebuf, "-"); -} - -/* int* pMajor; Pointer to major version. */ -/* int* pMinor; Pointer to minor version. */ -/* int* pBuild; Pointer to build number. */ -void -os_version(int *pMajor, int *pMinor, int *pBuild) -{ - char os_ver[MAX_VER_STR+2]; - char* release; /* Pointer to the release string: - * X.Y or X.Y.Z. - */ - strncpy(os_ver, vxWorksVersion, MAX_VER_STR); - release = os_ver; - *pMajor = get_number(&release); - *pMinor = get_number(&release); - *pBuild = get_number(&release); -} - -void init_getenv_state(GETENV_STATE *state) -{ - *state = NULL; -} - -char *getenv_string(GETENV_STATE *state0) -{ - return NULL; -} - -void fini_getenv_state(GETENV_STATE *state) -{ - *state = NULL; -} - -/************************** Port I/O *******************************/ - - -/* I. Common stuff */ - -#define TMP_BUF_MAX (tmp_buf_size - 1024) -static byte *tmp_buf; -static Uint tmp_buf_size; - -/* II. The spawn/fd/vanilla drivers */ - -/* This data is shared by these drivers - initialized by spawn_init() */ -static struct driver_data { - int port_num, ofd, packet_bytes, report_exit; - int exitcode, exit_reported; /* For returning of exit codes. */ -} *driver_data; /* indexed by fd */ - -/* - * Locking only for exitcodes and exit_reported, one global sem for all - * spawn ports as this is rare. - */ -static SEM_ID driver_data_sem = NULL; -/* - * Also locking when looking up entries in the load table - */ -static SEM_ID entry_data_sem = NULL; - -/* We maintain a linked fifo queue of these structs in order */ -/* to manage unfinnished reads/and writes on differenet fd's */ - -typedef struct pend { - char *cpos; - int fd; - int remain; - struct pend *next; - char buf[1]; /* this is a trick to be able to malloc one chunk */ -} Pend; - -static struct fd_data { - int inport, outport; - char *buf, *cpos; - int sz, remain; /* for input on fd */ - Pend* pending; /* pending outputs */ - -} *fd_data; /* indexed by fd */ - - -/* Driver interfaces */ -static ErlDrvData spawn_start(ErlDrvPort port_num, char *name, SysDriverOpts* opts); -static ErlDrvData fd_start(ErlDrvPort port_num, char *name, SysDriverOpts* opts); -static ErlDrvData vanilla_start(ErlDrvPort port_num, char *name, SysDriverOpts* opts); -static int spawn_init(void); -static void fd_stop(ErlDrvData); -static void stop(ErlDrvData); -static void ready_input(ErlDrvData fd, ErlDrvEvent ready_fd); -static void ready_output(ErlDrvData fd, ErlDrvEvent ready_fd); -static void output(ErlDrvData fd, char *buf, ErlDrvSizeT len); -static void stop_select(ErlDrvEvent, void*); - -struct erl_drv_entry spawn_driver_entry = { - spawn_init, - spawn_start, - stop, - output, - ready_input, - ready_output, - "spawn", - NULL, /* finish */ - NULL, /* handle */ - NULL, /* control */ - NULL, /* timeout */ - NULL, /* outputv */ - NULL, /* ready_async */ - NULL, /* flush */ - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, /* ERL_DRV_FLAGs */ - NULL, /* handle2 */ - NULL, /* process_exit */ - stop_select - -}; -struct erl_drv_entry fd_driver_entry = { - NULL, - fd_start, - fd_stop, - output, - ready_input, - ready_output, - "fd", - NULL, /* finish */ - NULL, /* handle */ - NULL, /* control */ - NULL, /* timeout */ - NULL, /* outputv */ - NULL, /* ready_async */ - NULL, /* flush */ - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, /* ERL_DRV_FLAGs */ - NULL, /* handle2 */ - NULL, /* process_exit */ - stop_select -}; -struct erl_drv_entry vanilla_driver_entry = { - NULL, - vanilla_start, - stop, - output, - ready_input, - ready_output, - "vanilla", - NULL, /* finish */ - NULL, /* handle */ - NULL, /* control */ - NULL, /* timeout */ - NULL, /* outputv */ - NULL, /* ready_async */ - NULL, /* flush */ - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, /* ERL_DRV_FLAGs */ - NULL, /* handle2 */ - NULL, /* process_exit */ - stop_select -}; - -/* -** Set up enough of the driver_data structure to be able to report exit status. -** Some things may be initiated again, but that is no real problem. -*/ -static int pre_set_driver_data(int ifd, int ofd, - int read_write, int report_exit) { - if (read_write & DO_READ) { - driver_data[ifd].report_exit = report_exit; - driver_data[ifd].exitcode = 0; - driver_data[ifd].exit_reported = 0; - if (read_write & DO_WRITE) { - driver_data[ifd].ofd = ofd; - if (ifd != ofd) { - driver_data[ofd] = driver_data[ifd]; - driver_data[ofd].report_exit = 0; - } - } else { /* DO_READ only */ - driver_data[ifd].ofd = -1; - } - return(ifd); - } else { /* DO_WRITE only */ - driver_data[ofd].report_exit = 0; - driver_data[ofd].exitcode = 0; - driver_data[ofd].exit_reported = 0; - driver_data[ofd].ofd = ofd; - return(ofd); - } -} - -/* -** Set up the driver_data structure, it may have been initiated -** partly by the function above, but we dont care. -*/ -static int set_driver_data(int port_num, int ifd, int ofd, - int packet_bytes, int read_write, - int report_exit) -{ - if (read_write & DO_READ) { - driver_data[ifd].packet_bytes = packet_bytes; - driver_data[ifd].port_num = port_num; - driver_data[ifd].report_exit = report_exit; - if (read_write & DO_WRITE) { - driver_data[ifd].ofd = ofd; - if (ifd != ofd) { - driver_data[ofd] = driver_data[ifd]; - driver_data[ofd].report_exit = 0; - } - } else { /* DO_READ only */ - driver_data[ifd].ofd = -1; - } - (void) driver_select(port_num, ifd, ERL_DRV_READ|ERL_DRV_USE, 1); - return(ifd); - } else { /* DO_WRITE only */ - driver_data[ofd].packet_bytes = packet_bytes; - driver_data[ofd].port_num = port_num; - driver_data[ofd].report_exit = 0; - driver_data[ofd].ofd = ofd; - return(ofd); - } -} - -static int need_new_sems = 1; - -static int spawn_init(void) -{ - char *stackenv; - int size; - driver_data = (struct driver_data *) - erts_alloc(ERTS_ALC_T_DRV_TAB, max_files * sizeof(struct driver_data)); - if (need_new_sems) { - driver_data_sem = semMCreate - (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); - entry_data_sem = semMCreate - (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); - } - if (driver_data_sem == NULL || entry_data_sem == NULL) { - erl_exit(1,"Could not allocate driver locking semaphore."); - } - need_new_sems = 0; - - (void)uxPipeDrv(); /* Install pipe driver */ - - if ((stackenv = getenv("ERLPORTSTACKSIZE")) != NULL && - (size = atoi(stackenv)) > 0) - port_stack_size = size; - else - port_stack_size = DEFAULT_PORT_STACK_SIZE; - return 0; -} - -/* Argv has to be built vith the save_xxx routines, not with whathever - sys_xxx2 has in mind... */ -#define argv_alloc save_malloc -#define argv_realloc save_realloc -#define argv_free save_free -/* Build argv, return argc or -1 on failure */ -static int build_argv(char *name, char ***argvp) -{ - int argvsize = 10, argc = 0; - char *args, *arglast = NULL, *argp; - char **argv; - -#ifdef DEBUG - fdprintf(2, "Building argv, %s =>\n", name); -#endif - if ((argv = (char **)argv_alloc(argvsize * sizeof(char *))) == NULL) - return(-1); - if ((args = argv_alloc(strlen(name) + 1)) == NULL) - return(-1); - strcpy(args, name); - argp = strtok_r(args, " \t", &arglast); - while (argp != NULL) { - if (argc + 1 >= argvsize) { - argvsize += 10; - argv = (char **)argv_realloc((char *)argv, argvsize*sizeof(char *)); - if (argv == NULL) { - argv_free(args); - return(-1); - } - } -#ifdef DEBUG - fdprintf(2, "%s\n", argp); -#endif - argv[argc++] = argp; - argp = strtok_r((char *)NULL, " \t", &arglast); - } - argv[argc] = NULL; - *argvp = argv; - return(argc); -} -#undef argv_alloc -#undef argv_realloc -#undef argv_free - - -/* Lookup and return global text symbol or NULL on failure - Symbol name is null-terminated and without the leading '_' */ -static FUNCPTR -lookup(char *sym) -{ - char buf[256]; - char *symname = buf; - int len; - FUNCPTR entry; - SYM_TYPE type; - - len = strlen(sym); - if (len > 254 && (symname = malloc(len+2)) == NULL) - return(NULL); -#if defined _ARCH_PPC || defined SIMSPARCSOLARIS - /* GCC for PPC and SIMSPARC doesn't add a leading _ to symbols */ - strcpy(symname, sym); -#else - sprintf(symname, "_%s", sym); -#endif - if (symFindByNameAndType(sysSymTbl, symname, (char **)&entry, - &type, N_EXT | N_TEXT, N_EXT | N_TEXT) != OK) - entry = NULL; - if (symname != buf) - free(symname); - return(entry); -} - -/* This function is spawned to build argc, argv, lookup the symbol to call, - connect and set up file descriptors, and make the actual call. - N.B. 'name' was allocated by the Erlang task (through plain_malloc) and - is freed by this port program task. - Note: 'name' may be a path containing '/'. */ - -static void call_proc(char *name, int ifd, int ofd, int read_write, - int redir_stderr, int driver_index, - int p6, int p7, int p8, int p9) -{ - int argc; - char **argv, *bname; - FUNCPTR entry; - int ret = -1; - - /* Must consume 'name' */ - argc = build_argv(name, &argv); - plain_free(name); - /* Find basename of path */ - if ((bname = strrchr(argv[0], '/')) != NULL) { - bname++; - } else { - bname = argv[0]; - } -#ifdef DEBUG - fdprintf(2, "Port program name: %s\n", bname); -#endif - semTake(entry_data_sem, WAIT_FOREVER); - - if (argc > 0) { - if ((entry = lookup(bname)) == NULL) { - int fd; - char *fn; - /* NOTE: We don't check the return value of loadModule, - since that was incompatibly changed from 5.0.2b to 5.1, - but rather do a repeated lookup(). */ - if ((fd = open(argv[0], O_RDONLY)) > 0) { - (void) loadModule(fd, GLOBAL_SYMBOLS); - close(fd); - entry = lookup(bname); - } - if (entry == NULL) { - /* filename == func failed, try func.o */ - if ((fn = malloc(strlen(argv[0]) + 3)) != NULL) { /* ".o\0" */ - strcpy(fn, argv[0]); - strcat(fn, ".o"); - if ((fd = open(fn, O_RDONLY)) > 0) { - (void) loadModule(fd, GLOBAL_SYMBOLS); - close(fd); - entry = lookup(bname); - } - free(fn); - } - } - } - } else { - entry = NULL; - } - semGive(entry_data_sem); - - if (read_write & DO_READ) { /* emulator read */ - save_fd(ofd); - ioTaskStdSet(0, 1, ofd); /* stdout for process */ - if(redir_stderr) - ioTaskStdSet(0, 2, ofd);/* stderr for process */ - } - if (read_write & DO_WRITE) { /* emulator write */ - save_fd(ifd); - ioTaskStdSet(0, 0, ifd); /* stdin for process */ - } - if (entry != NULL) { - ret = (*entry)(argc, argv, (char **)NULL); /* NULL for envp */ - } else { - fdprintf(2, "Could not exec \"%s\"\n", argv[0]); - ret = -1; - } - if (driver_data[driver_index].report_exit) { - semTake(driver_data_sem, WAIT_FOREVER); - driver_data[driver_index].exitcode = ret; - driver_data[driver_index].exit_reported = 1; - semGive(driver_data_sem); - } - /* We *don't* want to close the pipes here, but let the delete - hook take care of it - it might want to flush stdout and there'd - better be an open descriptor to flush to... */ - exit(ret); -} - -static void close_pipes(int ifd[2], int ofd[2], int read_write) -{ - if (read_write & DO_READ) { - (void) close(ifd[0]); - (void) close(ifd[1]); - } - if (read_write & DO_WRITE) { - (void) close(ofd[0]); - (void) close(ofd[1]); - } -} - -static void init_fd_data(int fd, int port_unused_argument) -{ - SET_NONBLOCKING(fd); - fd_data[fd].pending = NULL; - fd_data[fd].buf = fd_data[fd].cpos = NULL; - fd_data[fd].remain = fd_data[fd].sz = 0; -} - -static ErlDrvData spawn_start(ErlDrvPort port_num, char *name,SysDriverOpts* opts) -{ - int ifd[2], ofd[2], len, nl, id; - char taskname[11], *progname, *bname; - char *space_in_command; - int packet_bytes = opts->packet_bytes; - int read_write = opts->read_write; - int use_stdio = opts->use_stdio; - int redir_stderr = opts->redir_stderr; - int driver_index; - - if (!use_stdio){ - return (ErlDrvData) -3; - } - - /* Create pipes and set the Erlang task as owner of its - * read and write ends (through save_fd()). - */ - switch (read_write) { - case DO_READ: - if (pipe(ifd) < 0){ - return (ErlDrvData) -2; - } - if (ifd[0] >= max_files) { - close_pipes(ifd, ofd, read_write); - errno = ENFILE; - return (ErlDrvData) -2; - } - save_fd(ifd[0]); - break; - case DO_WRITE: - if (pipe(ofd) < 0) { - return (ErlDrvData) -2; - } - if (ofd[1] >= max_files) { - close_pipes(ifd, ofd, read_write); - errno = ENFILE; - return (ErlDrvData) -2; - } - save_fd(ofd[1]); - break; - case DO_READ|DO_WRITE: - if (pipe(ifd) < 0){ - return (ErlDrvData) -2; - } - if (ifd[0] >= max_files || pipe(ofd) < 0) { - close_pipes(ifd, ofd, DO_READ); - errno = ENFILE; - return (ErlDrvData) -2; - } - if (ofd[1] >= max_files) { - close_pipes(ifd, ofd, read_write); - errno = ENFILE; - return (ErlDrvData) -2; - } - save_fd(ifd[0]); - save_fd(ofd[1]); - break; - default: - return (ErlDrvData) -1; - } - - /* Allocate space for program name to be freed by the - * spawned task. We use plain_malloc so that the allocated - * space is not owned by the Erlang task. - */ - - if ((progname = plain_malloc(strlen(name) + 1)) == NULL) { - close_pipes(ifd, ofd, read_write); - errno = ENOMEM; - return (ErlDrvData) -2; - } - strcpy(progname, name); - - /* Check if name contains a space - * (e.g "port_test -o/home/gandalf/tornado/wind/target/erlang") - */ - if ((space_in_command = strrchr(progname, ' ')) != NULL) { - *space_in_command = '\0'; - } - - /* resulting in "port_test" */ - if ((bname = strrchr(progname, '/')) != NULL) - bname++; - else - bname = progname; - - /* resulting in "port_test" */ - len = strlen(bname); - nl = len > 10 ? 10 : len; - strncpy(taskname, bname, nl); - taskname[nl] = '\0'; - if (space_in_command != NULL) - *space_in_command = ' '; - driver_index = pre_set_driver_data(ifd[0], ofd[1], - read_write, opts->exit_status); - - /* resetting to "port_test -o/home/gandalf/tornado/wind/target/erlang" */ - if ((id = taskSpawn(taskname, spTaskPriority, spTaskOptions, - port_stack_size, (FUNCPTR)call_proc, (int)progname, - ofd[0], ifd[1], read_write, redir_stderr, driver_index, - 0,0,0,0)) - == ERROR) { - close_pipes(ifd, ofd, read_write); - plain_free(progname); /* only when spawn fails */ - errno = ENOMEM; - return (ErlDrvData) -2; - } -#ifdef DEBUG - fdprintf(2, "Spawned %s as %s[0x%x]\n", name, taskname, id); -#endif - if (read_write & DO_READ) - init_fd_data(ifd[0], port_num); - if (read_write & DO_WRITE) - init_fd_data(ofd[1], port_num); - return (ErlDrvData) (set_driver_data(port_num, ifd[0], ofd[1], - packet_bytes,read_write, - opts->exit_status)); -} - -static ErlDrvData fd_start(ErlDrvPort port_num, char *name, SysDriverOpts* opts) -{ - if (((opts->read_write & DO_READ) && opts->ifd >= max_files) || - ((opts->read_write & DO_WRITE) && opts->ofd >= max_files)) { - return (ErlDrvData) -1; - } - - if (opts->read_write & DO_READ) - init_fd_data(opts->ifd, port_num); - if (opts->read_write & DO_WRITE) - init_fd_data(opts->ofd, port_num); - return (ErlDrvData) (set_driver_data(port_num, opts->ifd, opts->ofd, - opts->packet_bytes, opts->read_write, 0)); -} - -static void clear_fd_data(int fd) -{ - - if (fd_data[fd].sz > 0) - erts_free(ERTS_ALC_T_FD_ENTRY_BUF, (void *) fd_data[fd].buf); - fd_data[fd].buf = NULL; - fd_data[fd].sz = 0; - fd_data[fd].remain = 0; - fd_data[fd].cpos = NULL; -} - -static void nbio_stop_fd(int port_num, int fd) -{ - Pend *p, *p1; - - driver_select(port_num, fd, ERL_DRV_READ|ERL_DRV_WRITE, 0); - clear_fd_data(fd); - p = fd_data[fd].pending; - SET_BLOCKING(fd); - while (p) { - p1 = p->next; - free(p); - p = p1; - } - fd_data[fd].pending = NULL; -} - -static void fd_stop(ErlDrvData drv_data) -{ - int ofd; - int fd = (int) drv_data; - - nbio_stop_fd(driver_data[fd].port_num, (int)fd); - ofd = driver_data[fd].ofd; - if (ofd != fd && ofd != -1) - nbio_stop_fd(driver_data[fd].port_num, (int)ofd); /* XXX fd = ofd? */ -} - -static ErlDrvData -vanilla_start(ErlDrvPort port_num, char *name, SysDriverOpts* opts) -{ - int flags, fd; - struct stat statbuf; - - DEBUGF(("vanilla_start, name: %s [r=%1i w=%1i]\n", name, - opts->read_write & DO_READ, - opts->read_write & DO_WRITE)); - - flags = (opts->read_write == DO_READ ? O_RDONLY : - opts->read_write == DO_WRITE ? O_WRONLY|O_CREAT|O_TRUNC : - O_RDWR|O_CREAT); - if ((fd = open(name, flags, 0666)) < 0){ - errno = ENFILE; - return (ErlDrvData) -2; - } - if (fd >= max_files) { - close(fd); - errno = ENFILE; - return (ErlDrvData) -2; - } - if (fstat(fd, &statbuf) < 0) { - close(fd); - errno = ENFILE; - return (ErlDrvData) -2; - } - - /* Return error for reading regular files (doesn't work) */ - if (ISREG(statbuf) && ((opts->read_write) & DO_READ)) { - close(fd); - return (ErlDrvData) -3; - } - init_fd_data(fd, port_num); - return (ErlDrvData) (set_driver_data(port_num, fd, fd, - opts->packet_bytes, opts->read_write, 0)); -} - -/* Note that driver_data[fd].ifd == fd if the port was opened for reading, */ -/* otherwise (i.e. write only) driver_data[fd].ofd = fd. */ - -static void stop(ErlDrvData drv_data) -{ - int port_num, ofd; - int fd = (int) drv_data; - - port_num = driver_data[fd].port_num; - nbio_stop_fd(port_num, fd); - driver_select(port_num, fd, ERL_DRV_USE, 0); /* close(fd) */ - - ofd = driver_data[fd].ofd; - if (ofd != fd && ofd != -1) { - nbio_stop_fd(port_num, ofd); - driver_select(port_num, ofd, ERL_DRV_USE, 0); /* close(fd) */ - } -} - -static int sched_write(int port_num,int fd, char *buf, int len, int pb) -{ - Pend *p, *p2, *p3; - int p_bytes = len; - - p = (Pend*) erts_alloc_fnf(ERTS_ALC_T_PEND_DATA, pb + len + sizeof(Pend)); - if (!p) { - driver_failure(port_num, -1); - return(-1); - } - - switch(pb) { - case 4: put_int32(len, p->buf); break; - case 2: put_int16(len, p->buf); break; - case 1: put_int8(len, p->buf); break; - case 0: break; /* Handles this case too */ - } - sys_memcpy(p->buf + pb, buf, len); - driver_select(port_num, fd, ERL_DRV_WRITE|ERL_DRV_USE, 1); - p->cpos = p->buf; - p->fd = fd; - p->next = NULL; - p->remain = len + pb; - p2 = fd_data[fd].pending; - if (p2 == NULL) - fd_data[fd].pending = p; - else { - p3 = p2->next; - while(p3) { - p_bytes += p2->remain; - p2 = p2->next; - p3 = p3->next; - } - p2->next = p; - } - if (p_bytes > (1 << 13)) /* More than 8 k pending */ - set_busy_port(port_num, 1); - return(0); -} - -/* Fd is the value returned as drv_data by the start func */ -static void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) -{ - int buf_done, port_num, wval, pb, ofd; - byte lb[4]; - struct iovec iv[2]; - int fd = (int) drv_data; - - pb = driver_data[fd].packet_bytes; - port_num = driver_data[fd].port_num; - - if ((ofd = driver_data[fd].ofd) == -1) { - return; - } - - if (fd_data[ofd].pending) { - sched_write(port_num, ofd, buf, len, pb); - return; - } - - if ((pb == 2 && len > 65535) || (pb == 1 && len > 255)) { - driver_failure_posix(port_num, EINVAL); - return; - } - if (pb == 0) { - wval = write(ofd, buf, len); - } else { - lb[0] = (len >> 24) & 255; /* MSB */ - lb[1] = (len >> 16) & 255; - lb[2] = (len >> 8) & 255; - lb[3] = len & 255; /* LSB */ - iv[0].iov_base = (char*) lb + (4 - pb); - iv[0].iov_len = pb; - iv[1].iov_base = buf; - iv[1].iov_len = len; - wval = writev(ofd, iv, 2); - } - if (wval == pb + len ) { - return; - } - if (wval < 0) { - if ((errno == EINTR) || (errno == ERRNO_BLOCK)) { - if (pb) { - sched_write(port_num, ofd, buf ,len, pb); - } else if (pb == 0) { - sched_write(port_num, ofd, buf ,len, 0); - } - return; - } - driver_failure_posix(driver_data[fd].port_num, EINVAL); - return; - } - if (wval < pb) { - sched_write(port_num, ofd, (lb +4 -pb) + wval, pb-wval, 0); - sched_write(port_num, ofd, buf ,len, 0); - return; - } - - /* we now know that wval < (pb + len) */ - buf_done = wval - pb; - sched_write(port_num, ofd, buf + buf_done, len - buf_done,0); -} - -static void stop_select(ErlDrvEvent fd, void* _) -{ - close((int)fd); -} - -static int ensure_header(int fd,char *buf,int packet_size, int sofar) -{ - int res = 0; - int remaining = packet_size - sofar; - - SET_BLOCKING(fd); - if (read_fill(fd, buf+sofar, remaining) != remaining) - return -1; - switch (packet_size) { - case 1: res = get_int8(buf); break; - case 2: res = get_int16(buf); break; - case 4: res = get_int32(buf); break; - } - SET_NONBLOCKING(fd); - return(res); -} - -static int port_inp_failure(int port_num, int ready_fd, int res) -{ - (void) driver_select(port_num, ready_fd, ERL_DRV_READ|ERL_DRV_WRITE, 0); - clear_fd_data(ready_fd); - if (res == 0) { - if (driver_data[ready_fd].report_exit) { - int tmpexit = 0; - int reported; - /* Lock the driver_data structure */ - semTake(driver_data_sem, WAIT_FOREVER); - if ((reported = driver_data[ready_fd].exit_reported)) - tmpexit = driver_data[ready_fd].exitcode; - semGive(driver_data_sem); - if (reported) { - erts_fprintf(stderr,"Exitcode %d reported\r\n", tmpexit); - driver_report_exit(port_num, tmpexit); - } - } - driver_failure_eof(port_num); - } else { - driver_failure(port_num, res); - } - return 0; -} - -/* fd is the drv_data that is returned from the */ -/* initial start routine */ -/* ready_fd is the descriptor that is ready to read */ - -static void ready_input(ErlDrvData drv_data, ErlDrvEvent drv_event) -{ - int port_num, packet_bytes, res; - Uint h = 0; - char *buf; - int fd = (int) drv_data; - int ready_fd = (int) drv_event; - - port_num = driver_data[fd].port_num; - packet_bytes = driver_data[fd].packet_bytes; - - if (packet_bytes == 0) { - if ((res = read(ready_fd, tmp_buf, tmp_buf_size)) > 0) { - driver_output(port_num, (char*)tmp_buf, res); - return; - } - port_inp_failure(port_num, ready_fd, res); - return; - } - - if (fd_data[ready_fd].remain > 0) { /* We try to read the remainder */ - /* space is allocated in buf */ - res = read(ready_fd, fd_data[ready_fd].cpos, - fd_data[ready_fd].remain); - if (res < 0) { - if ((errno == EINTR) || (errno == ERRNO_BLOCK)) { - ; - } else { - port_inp_failure(port_num, ready_fd, res); - } - } else if (res == 0) { - port_inp_failure(port_num, ready_fd, res); - } else if (res == fd_data[ready_fd].remain) { /* we're done */ - driver_output(port_num, fd_data[ready_fd].buf, - fd_data[ready_fd].sz); - clear_fd_data(ready_fd); - } else { /* if (res < fd_data[ready_fd].remain) */ - fd_data[ready_fd].cpos += res; - fd_data[ready_fd].remain -= res; - } - return; - } - - - if (fd_data[ready_fd].remain == 0) { /* clean fd */ - /* We make one read attempt and see what happens */ - res = read(ready_fd, tmp_buf, tmp_buf_size); - if (res < 0) { - if ((errno == EINTR) || (errno == ERRNO_BLOCK)) - return; - port_inp_failure(port_num, ready_fd, res); - return; - } - else if (res == 0) { /* eof */ - port_inp_failure(port_num, ready_fd, res); - return; - } - else if (res < packet_bytes) { /* Ugly case... get at least */ - if ((h = ensure_header(ready_fd, tmp_buf, packet_bytes, res))==-1) { - port_inp_failure(port_num, ready_fd, -1); - return; - } - buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h); - if (!buf) { - port_inp_failure(port_num, ready_fd, -1); - return; - } - fd_data[ready_fd].buf = buf; - fd_data[ready_fd].sz = h; - fd_data[ready_fd].remain = h; - fd_data[ready_fd].cpos = buf; - return; - } - else { /* if (res >= packet_bytes) */ - unsigned char* cpos = tmp_buf; - int bytes_left = res; - while (1) { /* driver_output as many as possible */ - if (bytes_left == 0) { - clear_fd_data(ready_fd); - return; - } - if (bytes_left < packet_bytes) { /* Yet an ugly case */ - if((h=ensure_header(ready_fd, cpos, - packet_bytes, bytes_left))==-1) { - port_inp_failure(port_num, ready_fd, -1); - return; - } - buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h); - if (!buf) - port_inp_failure(port_num, ready_fd, -1); - fd_data[ready_fd].buf = buf; - fd_data[ready_fd].sz = h; - fd_data[ready_fd].remain = h; - fd_data[ready_fd].cpos = buf; - return; - } - switch (packet_bytes) { - case 1: h = get_int8(cpos); cpos += 1; break; - case 2: h = get_int16(cpos); cpos += 2; break; - case 4: h = get_int32(cpos); cpos += 4; break; - } - bytes_left -= packet_bytes; - /* we've got the header, now check if we've got the data */ - if (h <= (bytes_left)) { - driver_output(port_num, (char*) cpos, h); - cpos += h; - bytes_left -= h; - continue; - } - else { /* The last message we got was split */ - buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h); - if (!buf) { - port_inp_failure(port_num, ready_fd, -1); - } - sys_memcpy(buf, cpos, bytes_left); - fd_data[ready_fd].buf = buf; - fd_data[ready_fd].sz = h; - fd_data[ready_fd].remain = h - bytes_left; - fd_data[ready_fd].cpos = buf + bytes_left; - return; - } - } - return; - } - } - fprintf(stderr, "remain %d \n", fd_data[ready_fd].remain); - port_inp_failure(port_num, ready_fd, -1); -} - - -/* fd is the drv_data that is returned from the */ -/* initial start routine */ -/* ready_fd is the descriptor that is ready to read */ - -static void ready_output(ErlDrvData drv_data, ErlDrvEvent drv_event) -{ - Pend *p; - int wval; - - int fd = (int) drv_data; - int ready_fd = (int) drv_event; - - while(1) { - if ((p = fd_data[ready_fd].pending) == NULL) { - driver_select(driver_data[fd].port_num, ready_fd, - ERL_DRV_WRITE, 0); - return; - } - wval = write(p->fd, p->cpos, p->remain); - if (wval == p->remain) { - fd_data[ready_fd].pending = p->next; - erts_free(ERTS_ALC_T_PEND_DATA, p); - if (fd_data[ready_fd].pending == NULL) { - driver_select(driver_data[fd].port_num, ready_fd, - ERL_DRV_WRITE, 0); - set_busy_port(driver_data[fd].port_num, 0); - return; - } - else - continue; - } - else if (wval < 0) { - if (errno == ERRNO_BLOCK || errno == EINTR) - return; - else { - driver_select(driver_data[fd].port_num, ready_fd, - ERL_DRV_WRITE, 0); - driver_failure(driver_data[fd].port_num, -1); - return; - } - } - else if (wval < p->remain) { - p->cpos += wval; - p->remain -= wval; - return; - } - } -} - -/* Fills in the systems representation of the jam/beam process identifier. -** The Pid is put in STRING representation in the supplied buffer, -** no interpretatione of this should be done by the rest of the -** emulator. The buffer should be at least 21 bytes long. -*/ -void sys_get_pid(char *buffer){ - int p = taskIdSelf(); /* Hmm, may be negative??? requires some GB of - memory to make the TCB address convert to a - negative value. */ - sprintf(buffer,"%d", p); -} - -int -erts_sys_putenv(char *buffer, int sep_ix) -{ - return putenv(buffer); -} - -int -erts_sys_getenv(char *key, char *value, size_t *size) -{ - char *orig_value; - int res; - orig_value = getenv(key); - if (!orig_value) - res = -1; - else { - size_t len = sys_strlen(orig_value); - if (len >= *size) { - *size = len + 1; - res = 1; - } - else { - *size = len; - sys_memcpy((void *) value, (void *) orig_value, len+1); - res = 0; - } - } - return res; -} - -int -erts_sys_getenv__(char *key, char *value, size_t *size) -{ - return erts_sys_getenv(key, value, size); -} - -void -sys_init_io(void) -{ - tmp_buf = (byte *) erts_alloc(ERTS_ALC_T_SYS_TMP_BUF, SYS_TMP_BUF_SIZE); - tmp_buf_size = SYS_TMP_BUF_SIZE; - fd_data = (struct fd_data *) - erts_alloc(ERTS_ALC_T_FD_TAB, max_files * sizeof(struct fd_data)); -} - - -/* Fill buffer, return buffer length, 0 for EOF, < 0 for error. */ - -static int read_fill(int fd, char *buf, int len) -{ - int i, got = 0; - do { - if ((i = read(fd, buf+got, len-got)) <= 0) { - return i; - } - got += i; - } while (got < len); - return (len); -} - - -/************************** Misc... *******************************/ - -extern const char pre_loaded_code[]; -extern char* const pre_loaded[]; - - -/* Float conversion */ - -int sys_chars_to_double(char *buf, double *fp) -{ - char *s = buf; - - /* The following check is incorporated from the Vee machine */ - -#define ISDIGIT(d) ((d) >= '0' && (d) <= '9') - - /* Robert says that something like this is what he really wanted: - * - * 7 == sscanf(Tbuf, "%[+-]%[0-9].%[0-9]%[eE]%[+-]%[0-9]%s", ....); - * if (*s2 == 0 || *s3 == 0 || *s4 == 0 || *s6 == 0 || *s7) - * break; - */ - - /* Scan string to check syntax. */ - if (*s == '+' || *s == '-') - s++; - - if (!ISDIGIT(*s)) /* Leading digits. */ - return -1; - while (ISDIGIT(*s)) s++; - if (*s++ != '.') /* Decimal part. */ - return -1; - if (!ISDIGIT(*s)) - return -1; - while (ISDIGIT(*s)) s++; - if (*s == 'e' || *s == 'E') { - /* There is an exponent. */ - s++; - if (*s == '+' || *s == '-') - s++; - if (!ISDIGIT(*s)) - return -1; - while (ISDIGIT(*s)) s++; - } - if (*s) /* That should be it */ - return -1; - - if (sscanf(buf, "%lf", fp) != 1) - return -1; - return 0; -} - -/* - ** Convert a double to ascii format 0.dddde[+|-]ddd - ** return number of characters converted - */ - -int sys_double_to_chars(double fp, char *buf) -{ - (void) sprintf(buf, "%.20e", fp); - return strlen(buf); -} - - -/* Floating point exceptions */ - -#if (CPU == SPARC) -jmp_buf fpe_jmp; - -RETSIGTYPE fpe_sig_handler(int sig) -{ - longjmp(fpe_jmp, 1); -} - -#elif (CPU == PPC603) -static void fix_registers(void){ - FP_CONTEXT fpcontext; - fppSave(&fpcontext); - fpcontext.fpcsr &= ~(_PPC_FPSCR_INIT); - fppRestore(&fpcontext); -} -#endif - - -/* Return a pointer to a vector of names of preloaded modules */ - -Preload* sys_preloaded(void) -{ - return (Preload *) pre_loaded; -} - -/* Return a pointer to preloaded code for module "module" */ -unsigned char* sys_preload_begin(Preload *pp) -{ - return pp->code; -} - -/* Clean up if allocated */ -void sys_preload_end(Preload *pp) -{ - /* Nothing */ -} - -/* Read a key from console (?) */ - -int sys_get_key(int fd) -{ - int c; - unsigned char rbuf[64]; - - fflush(stdout); /* Flush query ??? */ - - if ((c = read(fd,rbuf,64)) <= 0) - return c; - return rbuf[0]; -} - - -/* A real printf that does the equivalent of fprintf(stdout, ...) */ - -/* ARGSUSED */ -static STATUS -stdio_write(char *buf, int nchars, int fp) -{ - if (fwrite(buf, sizeof(char), nchars, (FILE *)fp) == 0) - return(ERROR); - return(OK); -} - -int real_printf(const char *fmt, ...) -{ - va_list ap; - int err; - - va_start(ap, fmt); - err = fioFormatV(fmt, ap, stdio_write, (int)stdout); - va_end(ap); - return(err); -} - - -/* - * Little function to do argc, argv calls from (e.g.) VxWorks shell - * The arguments should be in the form of a single ""-enclosed string - * NOTE: This isn't really part of the emulator, just included here - * so we can use the handy functions and memory reclamation. - */ -void argcall(char *args) -{ - int argc; - char **argv; - FUNCPTR entry; - - if (args != NULL) { - if ((argc = build_argv(args, &argv)) > 0) { - if ((entry = lookup(argv[0])) != NULL) - (*entry)(argc, argv, (char **)NULL); /* NULL for envp */ - else - fprintf(stderr, "Couldn't find %s\n", argv[0]); - } else - fprintf(stderr, "Failed to build argv!\n"); - } else - fprintf(stderr, "No argument list!\n"); -} - - -/* That concludes the Erlang stuff - now we just need to implement an OS... - - Just kidding, but resource reclamation isn't the strength of VxWorks */ -#undef calloc -#undef free -#undef cfree -#undef malloc -#undef realloc -#undef open -#undef creat -#undef socket -#undef accept -#undef close -#undef fopen -#undef fdopen -#undef freopen -#undef fclose - -/********************* Using elib_malloc ****************************/ -/* This gives us yet another level of malloc wrappers. The purpouse */ -/* is to be able to select between different varieties of memory */ -/* allocation without recompiling. */ -/* Maybe the performance is somewhat degraded by this, but */ -/* on the other hand, performance may be much better if the most */ -/* suiting malloc is used (not to mention the much lower */ -/* fragmentation). */ -/* /Patrik N */ -/********************************************************************/ - -/* - * I don't want to include the whole elib header, especially - * as it uses char * for generic pointers. Let's fool ANSI C instead. - */ -extern void *elib_malloc(size_t); -extern void *elib_realloc(void *, size_t); -extern void elib_free(void *); -extern void elib_init(void *, int); -extern void elib_force_init(void *, int); -extern size_t elib_sizeof(void *); - -/* Flags */ -#define USING_ELIB_MALLOC 1 /* We are using the elib_malloc */ -#define WARN_MALLOC_MIX 2 /* Warn if plain malloc or save_malloc - is mixed with sys_free2 or - sys_realloc2 */ -#define REALLOC_MOVES 4 /* Always move on realloc - (less fragmentation) */ -#define USER_POOL 8 /* The user supplied the memory - pool, it was not save_alloced. */ -#define RECLAIM_USER_POOL 16 /* Use the reclaim mechanism in the - user pool. */ -#define NEW_USER_POOL 32 /* The user pool is newly suppllied, - any old pool should be discarded */ - - -#define ELIB_LOCK \ -if(alloc_flags & USING_ELIB_MALLOC) \ - semTake(elib_malloc_sem, WAIT_FOREVER) - -#define ELIB_UNLOCK \ -if(alloc_flags & USING_ELIB_MALLOC) \ - semGive(elib_malloc_sem) - -#define USER_RECLAIM() ((alloc_flags & USING_ELIB_MALLOC) && \ - (alloc_flags & USER_POOL) && \ - (alloc_flags & RECLAIM_USER_POOL)) - -/* - * Global state - * The use of function pointers for the malloc/realloc/free functions - * is actually only useful in the malloc case, we must know what kind of - * realloc/free we are going to use, so we could call elib_xxx directly. - * However, as the overhead is small and this construction makes it - * fairly easy to add another malloc algorithm, the function pointers - * are used in realloc/free to. - */ -static MallocFunction actual_alloc = &save_malloc; -static ReallocFunction actual_realloc = &save_realloc; -static FreeFunction actual_free = &save_free; -static int alloc_flags = 0; -static int alloc_pool_size = 0; -static void *alloc_pool_ptr = NULL; -static SEM_ID elib_malloc_sem = NULL; - -/* - * Descide if we should use the save_free instead of elib_free or, - * in the case of the free used in a delete hook, if we should - * use plain free instead of elib_free. - */ -static int use_save_free(void *ptr){ - register int diff = ((char *) ptr) - ((char *) alloc_pool_ptr); - /* - * Hmmm... should it be save_free even if diff is exactly 0? - * The answer is Yes if the whole area is save_alloced and No if not, - * so reclaim_free_hook is NOT run in the case of one save_alloced area. - */ - return (!(alloc_flags & USING_ELIB_MALLOC) || - (diff < 0 || diff >= alloc_pool_size)); -} - -/* - * A free function used by the task deletion hook for the save_xxx functions. - * Set with the set_reclaim_free_function function. - */ -static void reclaim_free_hook(void *ptr){ - if(use_save_free(ptr)){ - free(ptr); - } else { - ELIB_LOCK; - (*actual_free)(ptr); - ELIB_UNLOCK; - } -} - - -/* - * Initialize, sets the values of pointers based on - * either nothing (the default) or what's set previously by the - * erl_set_memory_block function. - */ -static void initialize_allocation(void){ - set_reclaim_free_function(NULL); - if(alloc_pool_size == 0){ - actual_alloc = (void *(*)(size_t))&save_malloc; - actual_realloc = (void *(*)(void *, size_t))&save_realloc; - actual_free = &save_free; - alloc_flags &= ~(USING_ELIB_MALLOC | USER_POOL | RECLAIM_USER_POOL); - } else { - if(elib_malloc_sem == NULL) - elib_malloc_sem = semMCreate - (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE); - if(elib_malloc_sem == NULL) - erl_exit(1,"Could not create mutex semaphore for elib_malloc"); - if(!(alloc_flags & USER_POOL)){ - if((alloc_pool_ptr = save_malloc(alloc_pool_size)) == NULL) - erl_exit(1,"Erlang set to allocate a %d byte block initially;" - " not enough memory available.", alloc_pool_size); - elib_force_init(alloc_pool_ptr, alloc_pool_size); - } else if(alloc_flags & NEW_USER_POOL){ - elib_force_init(alloc_pool_ptr, alloc_pool_size); - } - actual_alloc=&elib_malloc; - actual_realloc=&elib_realloc; - actual_free=&elib_free; - alloc_flags |= USING_ELIB_MALLOC; - /* We MUST see to that the right free function is used - otherwise we'll get a very nasty crash! */ - if(USER_RECLAIM()) - set_reclaim_free_function(&reclaim_free_hook); - } - alloc_flags &= ~(NEW_USER_POOL); /* It's never new after initialization*/ -} - -/* This does not exist on other platforms, we just use it in sys.c - and the BSD resolver */ -void *sys_calloc2(Uint nelem, Uint elsize){ - void *ptr = erts_alloc_fnf(ERTS_ALC_T_UNDEF, nelem*elsize); - if(ptr != NULL) - memset(ptr,0,nelem*elsize); - return ptr; -} - -/* - * The malloc wrapper - */ -void * -erts_sys_alloc(ErtsAlcType_t type, void *extra, Uint size) -{ - register void *ret; - ELIB_LOCK; - if(USER_RECLAIM()) - ret = save_malloc2((size_t)size,actual_alloc); - else - ret = (*actual_alloc)((size_t)size); - ELIB_UNLOCK; - return ret; -} - -/* - * The realloc wrapper, may respond to the "realloc-always-moves" flag - * if the area is initially allocated with elib_malloc. - */ -void * -erts_sys_realloc(ErtsAlcType_t type, void *extra, void *ptr, Uint size) -{ - register void *ret; - if(use_save_free(ptr)){ - if((alloc_flags & WARN_MALLOC_MIX) && - (alloc_flags & USING_ELIB_MALLOC)) - erts_fprintf(stderr,"Warning, save_malloced data realloced " - "by sys_realloc2\n"); - return save_realloc(ptr, (size_t) size); - } else { - ELIB_LOCK; - if((alloc_flags & REALLOC_MOVES) && - (alloc_flags & USING_ELIB_MALLOC)){ - size_t osz = elib_sizeof(ptr); - if(USER_RECLAIM()) - ret = save_malloc2((size_t) size, actual_alloc); - else - ret = (*actual_alloc)((size_t) size); - if(ret != NULL){ - memcpy(ret,ptr,(((size_t)size) < osz) ? ((size_t)size) : osz); - if(USER_RECLAIM()) - save_free2(ptr,actual_free); - else - (*actual_free)(ptr); - } - } else { - if(USER_RECLAIM()) - ret = save_realloc2(ptr,(size_t)size,actual_realloc); - else - ret = (*actual_realloc)(ptr,(size_t)size); - } - ELIB_UNLOCK; - return ret; - } -} - -/* - * Wrapped free(). - */ -void -erts_sys_free(ErtsAlcType_t type, void *extra, void *ptr) -{ - if(use_save_free(ptr)){ - /* - * This might happen when linked in drivers use save_malloc etc - * directly. - */ - if((alloc_flags & WARN_MALLOC_MIX) && - (alloc_flags & USING_ELIB_MALLOC)) - erts_fprintf(stderr,"Warning, save_malloced data freed by " - "sys_free2\n"); - save_free(ptr); - } else { - ELIB_LOCK; - if(USER_RECLAIM()) - save_free2(ptr,actual_free); - else - (*actual_free)(ptr); - ELIB_UNLOCK; - } -} - -/* - * External interface to be called before erlang is started - * Parameters: - * isize: The size of the memory block where erlang should malloc(). - * iptr: (optional) A pointer to a user supplied memory block of - * size isize. - * warn_save: Instructs sys_free2 and sys_realloc2 to warn if - * memory allocation/reallocation/freeing is mixed between - * pure malloc/save_malloc/sys_alloc2 routines (only - * warns if elib is actually used in the sys_alloc2 routines). - * realloc_moves: Always allocate a fresh memory block on reallocation - * (less fragmentation). - * reclaim_in_supplied: Use memory reclaim mechanisms inside the user - * supplied area, this makes one area reusable between - * starts of erlang and might be nice for drivers etc. - */ - -int erl_set_memory_block(int isize, int iptr, int warn_save, - int realloc_moves, int reclaim_in_supplied, int p5, - int p6, int p7, int p8, int p9){ - if(erlang_id != 0){ - erts_fprintf(stderr,"Error, cannot set erlang memory block while an " - "erlang task is running!\n"); - return 1; - } - if(isize < 8 * 1024 *1024) - erts_fprintf(stderr, - "Warning, the memory pool of %dMb may be to small to " - "run erlang in!\n", isize / (1024 * 1024)); - alloc_pool_size = (size_t) isize; - alloc_pool_ptr = (void *) iptr; - alloc_flags = 0; - /* USING_ELIB_MALLOC gets set by the initialization routine */ - if((void *)iptr != NULL) - alloc_flags |= (USER_POOL | NEW_USER_POOL); - if(realloc_moves) - alloc_flags |= REALLOC_MOVES; - if(warn_save) - alloc_flags |= WARN_MALLOC_MIX; - if((void *)iptr != NULL && reclaim_in_supplied) - alloc_flags |= RECLAIM_USER_POOL; - return 0; -} - -/* External statistics interface */ -int erl_memory_show(int p0, int p1, int p2, int p3, int p4, int p5, - int p6, int p7, int p8, int p9){ - struct elib_stat statistics; - if(!(alloc_flags & USING_ELIB_MALLOC) && erlang_id != 0){ - erts_printf("Using plain save_alloc, use memShow instead.\n"); - return 1; - } - if(erlang_id == 0 && !((alloc_flags & USER_POOL) && - !(alloc_flags & NEW_USER_POOL))){ - erts_printf("Sorry, no allocation statistics until erlang " - "is started.\n"); - return 1; - } - erts_printf("Allocation settings:\n"); - erts_printf("Using elib_malloc with memory pool size of %lu bytes.\n", - (unsigned long) alloc_pool_size); - erts_printf("Realloc-always-moves is %s\n", - (alloc_flags & REALLOC_MOVES) ? "on" : "off"); - erts_printf("Warnings about mixed malloc/free's are %s\n", - (alloc_flags & WARN_MALLOC_MIX) ? "on" : "off"); - if(alloc_flags & USER_POOL){ - erts_printf("The memory block used by elib is user supplied " - "at 0x%08x.\n", (unsigned int) alloc_pool_ptr); - if(alloc_flags & RECLAIM_USER_POOL) - erts_printf("Allocated memory within the user supplied pool\n" - " will be automatically reclaimed at task exit.\n"); - } else { - erts_printf("The memory block used by elib is save_malloc'ed " - "at 0x%08x.\n", (unsigned int) alloc_pool_ptr); - } - erts_printf("Statistics from elib_malloc:\n"); - ELIB_LOCK; - - elib_stat(&statistics); - ELIB_UNLOCK; - erts_printf("Type Size (bytes) Number of blocks\n"); - erts_printf("============= ============ ================\n"); - erts_printf("Total: %12lu %16lu\n", - (unsigned long) statistics.mem_total*4, - (unsigned long) statistics.mem_blocks); - erts_printf("Allocated: %12lu %16lu\n", - (unsigned long) statistics.mem_alloc*4, - (unsigned long) statistics.mem_blocks-statistics.free_blocks); - erts_printf("Free: %12lu %16lu\n", - (unsigned long) statistics.mem_free*4, - (unsigned long) statistics.free_blocks); - erts_printf("Largest free: %12lu -\n\n", - (unsigned long) statistics.max_free*4); - return 0; -} - - -/* -** More programmer friendly (as opposed to user friendly ;-) interface -** to the memory statistics. Resembles the VxWorks memPartInfoGet but -** does not take a partition id as parameter... -*/ -int erl_mem_info_get(MEM_PART_STATS *stats){ - struct elib_stat statistics; - if(!(alloc_flags & USING_ELIB_MALLOC)) - return -1; - ELIB_LOCK; - elib_stat(&statistics); - ELIB_UNLOCK; - stats->numBytesFree = statistics.mem_free*4; - stats->numBlocksFree = statistics.free_blocks; - stats->maxBlockSizeFree = statistics.max_free*4; - stats->numBytesAlloc = statistics.mem_alloc*4; - stats->numBlocksAlloc = statistics.mem_blocks-statistics.free_blocks; - return 0; -} - -/********************* Pipe driver **********************************/ -/* - * Purpose: Pipe driver with Unix (unnamed) pipe semantics. - * Author: Peter Hogfeldt ([email protected]) from an outline - * by Per Hedeland ([email protected]). - * - * Note: This driver must *not* use the reclaim facilities, hence it - * is placed here. (after the #undef's of open,malloc etc) - * - * This driver supports select() and non-blocking I/O via - * ioctl(fd, FIONBIO, val). - * - * 1997-03-21 Peter Hogfeldt - * Added non-blocking I/O. - * - */ - -/* - * SEMAPHORES - * - * Each end of a pipe has two semaphores: semExcl for serialising access to - * the pipe end, and semBlock for blocking I/O. - * - * reader->semBlock is available (full) if and only if the pipe is - * not empty, or the write end is closed. Otherwise - * it is unavailable (empty). It is initially - * unavailable. - * - * writer->semBlock is available (full) if and only if the pipe is - * not full, or if the reader end is closed. - * Otherwise it is unavailable. It is initially - * available. - */ - -#define UXPIPE_SIZE 4096 - -/* Forward declaration */ -typedef struct uxPipeDev UXPIPE_DEV; - -/* - * Pipe descriptor (one for each open pipe). - */ -typedef struct { - int drvNum; - UXPIPE_DEV *reader, *writer; - RING_ID ringId; -} UXPIPE; - -/* - * Device descriptor (one for each of the read and write - * ends of an open pipe). - */ -struct uxPipeDev { - UXPIPE *pipe; - int blocking; - SEL_WAKEUP_LIST wakeupList; - SEM_ID semExcl; - SEM_ID semBlock; -}; - -int uxPipeDrvNum = 0; /* driver number of pipe driver */ - -#define PIPE_NAME "/uxpipe" /* only used internally */ -#define PIPE_READ "/r" /* ditto */ -#define PIPE_WRITE "/w" /* ditto */ - -LOCAL char pipeRead[64], pipeWrite[64]; -LOCAL DEV_HDR devHdr; -LOCAL UXPIPE *newPipe; /* communicate btwn open()s in pipe() */ -LOCAL SEM_ID pipeSem; /* mutual exclusion in pipe() */ - -/* forward declarations */ -LOCAL int uxPipeOpen(DEV_HDR *pDv, char *name, int mode); -LOCAL int uxPipeClose(UXPIPE_DEV *pDev); -LOCAL int uxPipeRead(UXPIPE_DEV *pDev, char *buffer, int maxbytes); -LOCAL int uxPipeWrite(UXPIPE_DEV *pDev, char *buffer, int nbytes); -LOCAL STATUS uxPipeIoctl(FAST UXPIPE_DEV *pDev, FAST int function, int arg); - - -/*************************************************************************** - * - * uxPipeDrv - install Unix pipe driver - * - * This routine initializes the Unix pipe driver. It must be called - * before any other routine in this driver. - * - * RETURNS: - * OK, or ERROR if I/O system is unable to install driver. - */ - -STATUS -uxPipeDrv(void) -{ - if (uxPipeDrvNum > 0) - return (OK); /* driver already installed */ - if ((uxPipeDrvNum = iosDrvInstall((FUNCPTR) NULL, (FUNCPTR) NULL, - uxPipeOpen, uxPipeClose, uxPipeRead, - uxPipeWrite, uxPipeIoctl)) == ERROR) - return (ERROR); - if (iosDevAdd(&devHdr, PIPE_NAME, uxPipeDrvNum) == ERROR) - return (ERROR); - strcpy(pipeRead, PIPE_NAME); - strcat(pipeRead, PIPE_READ); - strcpy(pipeWrite, PIPE_NAME); - strcat(pipeWrite, PIPE_WRITE); - if ((pipeSem = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE)) == NULL) - return (ERROR); - return (OK); -} - -/*************************************************************************** - * - * uxPipeOpen - open a pipe - * - * RETURNS: Pointer to device descriptor, or ERROR if memory cannot be - * allocated (errno = ENOMEM), or invalid argument (errno = EINVAL). - */ - -/* - * DEV_HDR *pDv; pointer to device header (dummy) - * char *name; name of pipe to open ("/r" or "/w") - * int mode; access mode (O_RDONLY or O_WRONLY) - */ -LOCAL int -uxPipeOpen(DEV_HDR *pDv, char *name, int mode) -{ - UXPIPE_DEV *reader, *writer; - - if (mode == O_RDONLY && strcmp(name, PIPE_READ) == 0) { - /* reader open */ - if ((newPipe = (UXPIPE *) malloc(sizeof(UXPIPE))) != NULL) { - if ((newPipe->ringId = rngCreate(UXPIPE_SIZE)) != NULL) { - if ((reader = (UXPIPE_DEV *) malloc(sizeof(UXPIPE_DEV))) != NULL) { - if ((reader->semExcl = semBCreate(SEM_Q_FIFO, SEM_FULL)) != NULL) { - if ((reader->semBlock = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) != NULL) { - reader->pipe = newPipe; - reader->blocking = 1; - selWakeupListInit(&reader->wakeupList); - newPipe->reader = reader; - newPipe->writer = NULL; - newPipe->drvNum = uxPipeDrvNum; - return ((int) reader); - } - semDelete(reader->semExcl); - } - free(reader); - } - rngDelete(newPipe->ringId); - } - free(newPipe); - newPipe = NULL; - errno = ENOMEM; - } - } else if (mode == O_WRONLY && strcmp(name, PIPE_WRITE) == 0) { - /* writer open */ - if (newPipe != NULL && - (writer = (UXPIPE_DEV *) malloc(sizeof(UXPIPE_DEV))) != NULL) { - if ((writer->semExcl = semBCreate(SEM_Q_FIFO, SEM_FULL)) != NULL) { - if ((writer->semBlock = semBCreate(SEM_Q_FIFO, SEM_FULL)) != NULL) { - writer->blocking = 1; - writer->pipe = newPipe; - selWakeupListInit(&writer->wakeupList); - newPipe->writer = writer; - newPipe = NULL; - return ((int) writer); - } - semDelete(writer->semExcl); - } - free(writer); - } - if (newPipe != NULL) - free(newPipe); - newPipe = NULL; - errno = ENOMEM; - } else { - errno = EINVAL; - } - return (ERROR); -} - -/*************************************************************************** - * - * uxPipeClose - close read or write end of a pipe. - * - * RETURNS: - * OK, or ERROR if device descriptor does not refer to an open read or - write end of a pipe (errno = EBADF). - */ - -LOCAL int -uxPipeClose(UXPIPE_DEV *pDev) -{ - UXPIPE *pajp = pDev->pipe; - - taskLock(); - if (pDev == pajp->reader) { - /* Close this end */ - semDelete(pDev->semExcl); - semDelete(pDev->semBlock); - free(pDev); - pajp->reader = NULL; - /* Inform the other end */ - if (pajp->writer != NULL) { - selWakeupAll(&pajp->writer->wakeupList, SELWRITE); - semGive(pajp->writer->semBlock); - } - } else if (pDev == pajp->writer) { - /* Close this end */ - semDelete(pDev->semExcl); - semDelete(pDev->semBlock); - free(pDev); - pajp->writer = NULL; - /* Inform the other end */ - if (pajp->reader != NULL) { - selWakeupAll(&pajp->reader->wakeupList, SELREAD); - semGive(pajp->reader->semBlock); - } - } else { - errno = EBADF; - taskUnlock(); - return (ERROR); - } - if (pajp->reader == NULL && pajp->writer == NULL) { - rngDelete(pajp->ringId); - pajp->drvNum = 0; - free(pajp); - } - taskUnlock(); - return (OK); -} -/*************************************************************************** - * - * uxPipeRead - read from a pipe. - * - * Reads at most maxbytes bytes from the pipe. Blocks if blocking mode is - * set and the pipe is empty. - * - * RETURNS: - * number of bytes read, 0 on EOF, or ERROR if device descriptor does - * not refer to an open read end of a pipe (errno = EBADF), or if - * non-blocking mode is set and the pipe is empty (errno = EWOULDBLOCK). - */ - -LOCAL int -uxPipeRead(UXPIPE_DEV *pDev, char *buffer, int maxbytes) -{ - UXPIPE *pajp = pDev->pipe; - int nbytes = 0; - - if (pDev != pajp->reader) { - errno = EBADF; - return (ERROR); - } - if (maxbytes == 0) - return (0); - semTake(pDev->semExcl, WAIT_FOREVER); - /* - * Note that semBlock may be full, although there is nothing to read. - * This happens e.g. after the following sequence of operations: a - * reader task blocks, a writer task writes two times (the first - * write unblocks the reader task, the second write makes semBlock - * full). - */ - while (nbytes == 0) { - if (pDev->blocking) - semTake(pDev->semBlock, WAIT_FOREVER); - /* - * Reading and updating of the write end must not be interleaved - * with a write from another task - hence we lock this task. - */ - taskLock(); - nbytes = rngBufGet(pajp->ringId, buffer, maxbytes); - if (nbytes > 0) { - /* Give own semaphore if bytes remain or if write end is closed */ - if ((!rngIsEmpty(pajp->ringId) || pajp->writer == NULL) && - pDev->blocking) - semGive(pDev->semBlock); - /* Inform write end */ - if (pajp->writer != NULL) { - if (pajp->writer->blocking) - semGive(pajp->writer->semBlock); - selWakeupAll(&pajp->writer->wakeupList, SELWRITE); - } - } else if (pajp->writer == NULL) { - nbytes = 0; /* EOF */ - /* Give semaphore when write end is closed */ - if (pDev->blocking) - semGive(pDev->semBlock); - taskUnlock(); - semGive(pDev->semExcl); - return (nbytes); - } else if (!pDev->blocking) { - taskUnlock(); - semGive(pDev->semExcl); - errno = EWOULDBLOCK; - return (ERROR); - } - taskUnlock(); - } - semGive(pDev->semExcl); - return (nbytes); -} - -/*************************************************************************** - * - * uxPipeWrite - write to a pipe. - * - * Writes nbytes bytes to the pipe. Blocks if blocking mode is set, and if - * the pipe is full. - * - * RETURNS: - * number of bytes written, or ERROR if the device descriptor does not - * refer to an open write end of a pipe (errno = EBADF); or if the read end - * of the pipe is closed (errno = EPIPE); or if non-blocking mode is set - * and the pipe is full (errno = EWOULDBLOCK). - * - */ - -LOCAL int -uxPipeWrite(UXPIPE_DEV *pDev, char *buffer, int nbytes) -{ - - UXPIPE *pajp = pDev->pipe; - int sofar = 0, written; - - if (pDev != pajp->writer) { - errno = EBADF; - return (ERROR); - } - if (pajp->reader == NULL) { - errno = EPIPE; - return (ERROR); - } - if (nbytes == 0) - return (0); - semTake(pDev->semExcl, WAIT_FOREVER); - while (sofar < nbytes) { - if (pDev->blocking) - semTake(pDev->semBlock, WAIT_FOREVER); - if (pajp->reader == NULL) { - errno = EPIPE; - semGive(pDev->semBlock); - semGive(pDev->semExcl); - return (ERROR); - } - /* Writing and updating of the read end must not be interleaved - * with a read from another task - hence we lock this task. - */ - taskLock(); - written = rngBufPut(pajp->ringId, buffer + sofar, nbytes - sofar); - sofar += written; - /* Inform the read end if we really wrote something */ - if (written > 0 && pajp->reader != NULL) { - selWakeupAll(&pajp->reader->wakeupList, SELREAD); - if (pajp->reader->blocking) - semGive(pajp->reader->semBlock); - } - taskUnlock(); - if (!pDev->blocking) { - if (sofar == 0) { - errno = EWOULDBLOCK; - sofar = ERROR; - } - break; - } - } - /* Give own semaphore if space remains */ - if (!rngIsFull(pajp->ringId) && pDev->blocking) - semGive(pDev->semBlock); - semGive(pDev->semExcl); - return (sofar); -} - -/*************************************************************************** - * - * uxPipeIoctl - do device specific I/O control - * - * RETURNS: - * OK or ERROR. - */ - -LOCAL STATUS -uxPipeIoctl(FAST UXPIPE_DEV *pDev, FAST int function, int arg) - -{ - UXPIPE *pajp = pDev->pipe; - int status = OK; - - switch (function) { - case FIONBIO: - pDev->blocking = (*(int *)arg) ? 0 : 1; - break; - case FIOSELECT: - taskLock(); - selNodeAdd(&pDev->wakeupList, (SEL_WAKEUP_NODE *) arg); - if (selWakeupType((SEL_WAKEUP_NODE *) arg) == SELREAD && - pDev == pajp->reader && - (!rngIsEmpty(pajp->ringId) || pajp->writer == NULL)) - selWakeup((SEL_WAKEUP_NODE *) arg); - if (selWakeupType((SEL_WAKEUP_NODE *) arg) == SELWRITE && - pDev == pajp->writer && - (!rngIsFull(pajp->ringId) || pajp->reader == NULL)) - selWakeup((SEL_WAKEUP_NODE *) arg); - taskUnlock(); - break; - case FIOUNSELECT: - selNodeDelete(&pDev->wakeupList, (SEL_WAKEUP_NODE *) arg); - break; - default: - status = ERROR; - break; - } - return (status); -} - -/*************************************************************************** - * - * pipe - create an intertask channel - * - * Creates a pipe. fd[0] (fd[1]) is the read (write) file descriptor. - * - * RETURNS: - * OK or ERROR, if the pipe could not be created. - */ - -STATUS -pipe(int fd[2]) -{ - semTake(pipeSem, WAIT_FOREVER); - if ((fd[0] = open(pipeRead, O_RDONLY, 0)) != ERROR) { - if ((fd[1] = open(pipeWrite, O_WRONLY, 0)) != ERROR) { - semGive(pipeSem); - return (OK); - } - (void) close(fd[0]); - } - errno &= 0xFFFF; - if((errno & 0xFFFF) == EINTR) /* Why on earth EINTR??? */ - errno = ENFILE; /* It means we are out of file descriptors...*/ - semGive(pipeSem); - return (ERROR); -} - -/*************************************************************************** - * - * uxPipeShow - display pipe information - * - * RETURNS: - * N/A. - */ - -void -uxPipeShow(int fd) -{ - UXPIPE_DEV *pDev; - UXPIPE *pajp; - int drvValue; - - if ((drvValue = iosFdValue(fd)) == ERROR) { - erts_fprintf(stderr, "Error: file descriptor invalid\n"); - return; - } - pDev = (UXPIPE_DEV *)drvValue; - pajp = pDev->pipe; - if (pajp->drvNum != uxPipeDrvNum) { - erts_fprintf(stderr, "Error: Not a ux pipe device\n"); - return; - } - erts_fprintf(stderr, "Device : 0x%x\n", (int) pDev); - erts_fprintf(stderr, "Buffer size : %d\n", UXPIPE_SIZE); - erts_fprintf(stderr, "Bytes in buffer : %d\n\n", rngNBytes(pajp->ringId)); - erts_fprintf(stderr, "READ END\n\n"); - if (pajp->reader != NULL) { - erts_fprintf(stderr, "Mode : "); - erts_fprintf(stderr, "%s\n", - (pajp->reader->blocking) ? "blocking" : "non-blocking"); - } - erts_fprintf(stderr, "Status : "); - if (pajp->reader != NULL) { - erts_fprintf(stderr, "OPEN\n"); - erts_fprintf(stderr, "Wake-up list : %d\n\n", - selWakeupListLen(&pajp->reader->wakeupList)); - erts_fprintf(stderr, "Exclusion Semaphore\n"); - semShow(pajp->reader->semExcl, 1); - erts_fprintf(stderr, "Blocking Semaphore\n"); - semShow(pajp->reader->semBlock, 1); - } else - erts_fprintf(stderr, "CLOSED\n\n"); - erts_fprintf(stderr, "WRITE END\n\n"); - if (pajp->writer != NULL) { - erts_fprintf(stderr, "Mode : "); - erts_fprintf(stderr, "%s\n", - (pajp->writer->blocking) ? "blocking" : "non-blocking"); - } - erts_fprintf(stderr, "Status : "); - if (pajp->writer != NULL) { - erts_fprintf(stderr, "OPEN\n"); - erts_fprintf(stderr, "Wake-up list : %d\n\n", - selWakeupListLen(&pajp->writer->wakeupList)); - erts_fprintf(stderr, "Exclusion Semaphore\n"); - semShow(pajp->writer->semExcl, 1); - erts_fprintf(stderr, "Blocking Semaphore\n"); - semShow(pajp->writer->semBlock, 1); - } else - erts_fprintf(stderr, "CLOSED\n\n"); -} - -#ifdef DEBUG -void -erl_assert_error(char* expr, char* file, int line) -{ - fflush(stdout); - fprintf(stderr, "Assertion failed: %s in %s, line %d\n", - expr, file, line); - fflush(stderr); - erl_crash_dump(file, line, "Assertion failed: %s\n", expr); - abort(); -} -void -erl_debug(char* fmt, ...) -{ - char sbuf[1024]; /* Temporary buffer. */ - va_list va; - - va_start(va, fmt); - vsprintf(sbuf, fmt, va); - va_end(va); - fprintf(stderr, "%s\n", sbuf); -} -#endif diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index 03298a6c54..21c52ca26d 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -90,6 +90,11 @@ #define strncasecmp _strnicmp +#ifndef __GNUC__ +# undef ERTS_I64_LITERAL +# define ERTS_I64_LITERAL(X) X##i64 +#endif + /* * Practial Windows specific macros. */ diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index b5123dc45d..2f2dfc8197 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -26,11 +26,7 @@ #include "sys.h" #include "assert.h" -#ifdef __GNUC__ -#define LL_LITERAL(X) X##LL -#else -#define LL_LITERAL(X) X##i64 -#endif +#define LL_LITERAL(X) ERTS_I64_LITERAL(X) /******************* Routines for time measurement *********************/ diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index 03311423f0..7af7e48bbd 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -47,6 +47,7 @@ MODULES= \ busy_port_SUITE \ call_trace_SUITE \ code_SUITE \ + code_parallel_load_SUITE \ crypto_SUITE \ ddll_SUITE \ decode_packet_SUITE \ @@ -137,10 +138,10 @@ TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) EMAKEFILE=Emakefile -TEST_SPEC_FILES = emulator.spec \ - emulator.spec.win \ - emulator.spec.vxworks \ - emulator.spec.ose +TEST_SPEC_FILES= emulator.spec \ + emulator.spec.win \ + emulator_bench.spec + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index 99ed8f1748..e2442861c7 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -25,7 +25,9 @@ init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, display/1, display_huge/0, - types/1, + erl_bif_types/1,guard_bifs_in_erl_bif_types/1, + shadow_comments/1, + specs/1,improper_bif_stubs/1,auto_imports/1, t_list_to_existing_atom/1,os_env/1,otp_7526/1, binary_to_atom/1,binary_to_existing_atom/1, atom_to_binary/1,min_max/1, erlang_halt/1]). @@ -33,7 +35,9 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [types, t_list_to_existing_atom, os_env, otp_7526, + [erl_bif_types, guard_bifs_in_erl_bif_types, shadow_comments, + specs, improper_bif_stubs, auto_imports, + t_list_to_existing_atom, os_env, otp_7526, display, atom_to_binary, binary_to_atom, binary_to_existing_atom, min_max, erlang_halt]. @@ -86,33 +90,20 @@ deeep(N,Acc) -> deeep(N) -> deeep(N,[hello]). +erl_bif_types(Config) when is_list(Config) -> + ensure_erl_bif_types_compiled(), -types(Config) when is_list(Config) -> - c:l(erl_bif_types), - case erlang:function_exported(erl_bif_types, module_info, 0) of - false -> - %% Fail cleanly. - ?line ?t:fail("erl_bif_types not compiled"); - true -> - types_1() - end. - -types_1() -> - ?line List0 = erlang:system_info(snifs), + List0 = erlang:system_info(snifs), %% Ignore missing type information for hipe BIFs. - ?line List = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs], + List = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs], - case [MFA || MFA <- List, not known_types(MFA)] of - [] -> - types_2(List); - BadTypes -> - io:put_chars("No type information:\n"), - io:format("~p\n", [lists:sort(BadTypes)]), - ?line ?t:fail({length(BadTypes),bifs_without_types}) - end. + KnownTypes = [MFA || MFA <- List, known_types(MFA)], + io:format("There are ~p BIFs with type information in erl_bif_types.", + [length(KnownTypes)]), + erl_bif_types_2(KnownTypes). -types_2(List) -> +erl_bif_types_2(List) -> BadArity = [MFA || {M,F,A}=MFA <- List, begin Types = erl_bif_types:arg_types(M, F, A), @@ -120,14 +111,14 @@ types_2(List) -> end], case BadArity of [] -> - types_3(List); + erl_bif_types_3(List); [_|_] -> io:put_chars("Bifs with bad arity\n"), io:format("~p\n", [BadArity]), ?line ?t:fail({length(BadArity),bad_arity}) end. -types_3(List) -> +erl_bif_types_3(List) -> BadSmokeTest = [MFA || {M,F,A}=MFA <- List, begin try erl_bif_types:type(M, F, A) of @@ -151,9 +142,220 @@ types_3(List) -> ?line ?t:fail({length(BadSmokeTest),bad_smoke_test}) end. +guard_bifs_in_erl_bif_types(_Config) -> + ensure_erl_bif_types_compiled(), + + List0 = erlang:system_info(snifs), + List = [{F,A} || {erlang,F,A} <- List0, + erl_internal:guard_bif(F, A)], + Not = [FA || {F,A}=FA <- List, + not erl_bif_types:is_known(erlang, F, A)], + case Not of + [] -> + ok; + [_|_] -> + io:put_chars( + ["Dialyzer requires that all guard BIFs " + "have type information in erl_bif_types.\n\n" + "The following guard BIFs have no type information " + "in erl_bif_types:\n\n", + [io_lib:format(" ~p/~p\n", [F,A]) || {F,A} <- Not]]), + ?t:fail() + end. + +shadow_comments(_Config) -> + ensure_erl_bif_types_compiled(), + + List0 = erlang:system_info(snifs), + List1 = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs], + List = [MFA || MFA <- List1, not is_operator(MFA)], + HasTypes = [MFA || {M,F,A}=MFA <- List, + erl_bif_types:is_known(M, F, A)], + Path = get_code_path(), + BifRel = sofs:relation(HasTypes, [{m,f,a}]), + BifModules = sofs:to_external(sofs:projection(1, BifRel)), + AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules], + Specs0 = [extract_specs(Mod, Abstr) || + {Mod,Abstr} <- AbstrByModule], + Specs = lists:append(Specs0), + SpecFuns0 = [F || {F,_} <- Specs], + SpecFuns = sofs:relation(SpecFuns0, [{m,f,a}]), + HasTypesAndSpecs = sofs:intersection(BifRel, SpecFuns), + Commented0 = lists:append([extract_comments(Mod, Path) || + Mod <- BifModules]), + Commented = sofs:relation(Commented0, [{m,f,a}]), + {NoComments0,_,NoBifSpecs0} = + sofs:symmetric_partition(HasTypesAndSpecs, Commented), + NoComments = sofs:to_external(NoComments0), + NoBifSpecs = sofs:to_external(NoBifSpecs0), + + case NoComments of + [] -> + ok; + [_|_] -> + io:put_chars( + ["If a BIF stub has both a spec and has type information in " + "erl_bif_types, there *must*\n" + "be a comment in the source file to make that immediately " + "obvious.\n\nThe following comments are missing:\n\n", + [io_lib:format("%% Shadowed by erl_bif_types: ~p:~p/~p\n", + [M,F,A]) || {M,F,A} <- NoComments]]), + ?t:fail() + end, + + case NoBifSpecs of + [] -> + ok; + [_|_] -> + io:put_chars( + ["The following functions have \"shadowed\" comments " + "claiming that there is type information in erl_bif_types,\n" + "but actually there is no such type information.\n\n" + "Therefore, the following comments should be removed:\n\n", + [io_lib:format("%% Shadowed by erl_bif_types: ~p:~p/~p\n", + [M,F,A]) || {M,F,A} <- NoBifSpecs]]), + ?t:fail() + end. + +extract_comments(Mod, Path) -> + Beam = which(Mod, Path), + SrcDir = filename:join(filename:dirname(filename:dirname(Beam)), "src"), + Src = filename:join(SrcDir, atom_to_list(Mod) ++ ".erl"), + {ok,Bin} = file:read_file(Src), + Lines0 = binary:split(Bin, <<"\n">>, [global]), + Lines1 = [T || <<"%% Shadowed by erl_bif_types: ",T/binary>> <- Lines0], + {ok,ReMFA} = re:compile("([^:]*):([^/]*)/(\\d*)"), + Lines = [L || L <- Lines1, re:run(L, ReMFA, [{capture,[]}]) =:= match], + [begin + {match,[M,F,A]} = re:run(L, ReMFA, [{capture,all_but_first,list}]), + {list_to_atom(M),list_to_atom(F),list_to_integer(A)} + end || L <- Lines]. + +ensure_erl_bif_types_compiled() -> + c:l(erl_bif_types), + case erlang:function_exported(erl_bif_types, module_info, 0) of + false -> + %% Fail cleanly. + ?t:fail("erl_bif_types not compiled"); + true -> + ok + end. + known_types({M,F,A}) -> erl_bif_types:is_known(M, F, A). +specs(_) -> + List0 = erlang:system_info(snifs), + + %% Ignore missing type information for hipe BIFs. + List1 = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs], + + %% Ignore all operators. + List = [MFA || MFA <- List1, not is_operator(MFA)], + + %% Extract specs from the abstract code for all BIFs. + Path = get_code_path(), + BifRel = sofs:relation(List, [{m,f,a}]), + BifModules = sofs:to_external(sofs:projection(1, BifRel)), + AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules], + Specs0 = [extract_specs(Mod, Abstr) || + {Mod,Abstr} <- AbstrByModule], + Specs = lists:append(Specs0), + BifSet = sofs:set(List, [function]), + SpecRel0 = sofs:relation(Specs, [{function,spec}]), + SpecRel = sofs:restriction(SpecRel0, BifSet), + + %% Find BIFs without specs. + NoSpecs0 = sofs:difference(BifSet, sofs:domain(SpecRel)), + NoSpecs = sofs:to_external(NoSpecs0), + case NoSpecs of + [] -> + ok; + [_|_] -> + io:put_chars("The following BIFs don't have specs:\n"), + [print_mfa(MFA) || MFA <- NoSpecs], + ?t:fail() + end. + +is_operator({erlang,F,A}) -> + erl_internal:arith_op(F, A) orelse + erl_internal:bool_op(F, A) orelse + erl_internal:comp_op(F, A) orelse + erl_internal:list_op(F, A) orelse + erl_internal:send_op(F, A); +is_operator(_) -> false. + +extract_specs(M, Abstr) -> + [{make_mfa(M, Name),Spec} || {attribute,_,spec,{Name,Spec}} <- Abstr]. + +make_mfa(M, {F,A}) -> {M,F,A}; +make_mfa(M, {M,_,_}=MFA) -> MFA. + +improper_bif_stubs(_) -> + Bifs0 = erlang:system_info(snifs), + Bifs = [MFA || {M,_,_}=MFA <- Bifs0, M =/= hipe_bifs], + Path = get_code_path(), + BifRel = sofs:relation(Bifs, [{m,f,a}]), + BifModules = sofs:to_external(sofs:projection(1, BifRel)), + AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules], + Funcs0 = [extract_functions(Mod, Abstr) || + {Mod,Abstr} <- AbstrByModule], + Funcs = lists:append(Funcs0), + BifSet = sofs:set(Bifs, [function]), + FuncRel0 = sofs:relation(Funcs, [{function,code}]), + FuncRel = sofs:restriction(FuncRel0, BifSet), + [check_stub(MFA, Body) || {MFA,Body} <- sofs:to_external(FuncRel)], + ok. + +auto_imports(_Config) -> + Path = get_code_path(), + {erlang,Abstr} = extract_abstract(erlang, Path), + SpecFuns = [Name || {attribute,_,spec,{Name,_}} <- Abstr], + auto_imports(SpecFuns, 0). + +auto_imports([{F,A}|T], Errors) -> + case erl_internal:bif(F, A) of + false -> + io:format("~p/~p: not auto-imported, but spec claims it " + "is auto-imported", [F,A]), + auto_imports(T, Errors+1); + true -> + auto_imports(T, Errors) + end; +auto_imports([{erlang,F,A}|T], Errors) -> + case erl_internal:bif(F, A) of + false -> + auto_imports(T, Errors); + true -> + io:format("~p/~p: auto-imported, but " + "spec claims it is *not* auto-imported", [F,A]), + auto_imports(T, Errors+1) + end; +auto_imports([], 0) -> + ok; +auto_imports([], Errors) -> + ?t:fail({Errors,inconsistencies}). + +extract_functions(M, Abstr) -> + [{{M,F,A},Body} || {function,_,F,A,Body} <- Abstr]. + +check_stub({erlang,apply,3}, _) -> + ok; +check_stub({_,F,A}, B) -> + try + [{clause,_,Args,[],Body}] = B, + A = length(Args), + [{call,_,{remote,_,{atom,_,erlang},{atom,_,nif_error}},[_]}] = Body + catch + _:_ -> + io:put_chars("Invalid body for the following BIF stub:\n"), + Func = {function,0,F,A,B}, + io:put_chars(erl_pp:function(Func)), + io:nl(), + io:put_chars("The body should be: erlang:nif_error(undef)"), + ?t:fail() + end. + t_list_to_existing_atom(Config) when is_list(Config) -> ?line all = list_to_existing_atom("all"), ?line ?MODULE = list_to_existing_atom(?MODULE_STRING), @@ -483,6 +685,35 @@ erlang_halt(Config) when is_list(Config) -> id(I) -> I. +%% Get code path, including the path for the erts application. +get_code_path() -> + case code:lib_dir(erts) of + {error,bad_name} -> + Erts = filename:join([code:root_dir(),"erts","preloaded","ebin"]), + [Erts|code:get_path()]; + _ -> + code:get_path() + end. + +which(Mod, Path) -> + which_1(atom_to_list(Mod) ++ ".beam", Path). + +which_1(Base, [D|Ds]) -> + Path = filename:join(D, Base), + case filelib:is_regular(Path) of + true -> Path; + false -> which_1(Base, Ds) + end. +print_mfa({M,F,A}) -> + io:format("~p:~p/~p", [M,F,A]). + +extract_abstract(Mod, Path) -> + Beam = which(Mod, Path), + {ok,{Mod,[{abstract_code,{raw_abstract_v1,Abstr}}]}} = + beam_lib:chunks(Beam, [abstract_code]), + {Mod,Abstr}. + + hostname() -> hostname(atom_to_list(node())). diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl index 9d80b01748..eaecd32f95 100644 --- a/erts/emulator/test/call_trace_SUITE.erl +++ b/erts/emulator/test/call_trace_SUITE.erl @@ -25,6 +25,7 @@ init_per_testcase/2,end_per_testcase/2, hipe/1,process_specs/1,basic/1,flags/1,errors/1,pam/1,change_pam/1, return_trace/1,exception_trace/1,on_load/1,deep_exception/1, + upgrade/1, exception_nocatch/1,bit_syntax/1]). %% Helper functions. @@ -46,6 +47,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> Common = [errors, on_load], NotHipe = [process_specs, basic, flags, pam, change_pam, + upgrade, return_trace, exception_trace, deep_exception, exception_nocatch, bit_syntax], Hipe = [hipe], @@ -76,7 +78,13 @@ init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> end_per_testcase(_Func, Config) -> Dog = ?config(watchdog, Config), - ?t:timetrap_cancel(Dog). + ?t:timetrap_cancel(Dog), + + %% Reloading the module will clear all trace patterns, and + %% in a debug-compiled emulator run assertions of the counters + %% for the number of traced exported functions in this module. + + c:l(?MODULE). hipe(Config) when is_list(Config) -> ?line 0 = erlang:trace_pattern({?MODULE,worker_foo,1}, true), @@ -185,8 +193,13 @@ basic() -> %% Trace some functions... ?line trace_func({lists,'_','_'}, []), + + %% Make sure that tracing the same functions more than once + %% does not cause any problems. + ?line 3 = trace_func({?MODULE,foo,'_'}, true), ?line 3 = trace_func({?MODULE,foo,'_'}, true), ?line 1 = trace_func({?MODULE,bar,0}, true), + ?line 1 = trace_func({?MODULE,bar,0}, true), ?line {traced,global} = trace_info({?MODULE,bar,0}, traced), ?line 1 = trace_func({erlang,list_to_integer,1}, true), ?line {traced,global} = trace_info({erlang,list_to_integer,1}, traced), @@ -267,6 +280,118 @@ foo() -> foo0. foo(X) -> X+1. foo(X, Y) -> X+Y. + +%% Note that the semantics that this test case verifies +%% are not explicitly specified in the docs (what I could find in R15B). +%% This test case was written to verify that we do not change +%% any behaviour with the introduction of "block-free" upgrade in R16. +%% In short: Do not refer to this test case as an authority of how it must work. +upgrade(doc) -> + "Test tracing on module being upgraded"; +upgrade(Config) when is_list(Config) -> + V1 = compile_version(my_upgrade_test, 1, Config), + V2 = compile_version(my_upgrade_test, 2, Config), + start_tracer(), + upgrade_do(V1, V2, false), + upgrade_do(V1, V2, true). + +upgrade_do(V1, V2, TraceLocalVersion) -> + {module,my_upgrade_test} = erlang:load_module(my_upgrade_test, V1), + + + %% Test that trace is cleared after load_module + + trace_func({my_upgrade_test,'_','_'}, [], [global]), + case TraceLocalVersion of + true -> trace_func({my_upgrade_test,local_version,0}, [], [local]); + _ -> ok + end, + 1 = my_upgrade_test:version(), + 1 = my_upgrade_test:do_local(), + 1 = my_upgrade_test:do_real_local(), + put('F1_exp', my_upgrade_test:make_fun_exp()), + put('F1_loc', my_upgrade_test:make_fun_local()), + 1 = (get('F1_exp'))(), + 1 = (get('F1_loc'))(), + + Self = self(), + expect({trace,Self,call,{my_upgrade_test,version,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_real_local,[]}}), + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); + _ -> ok + end, + expect({trace,Self,call,{my_upgrade_test,make_fun_exp,[]}}), + expect({trace,Self,call,{my_upgrade_test,make_fun_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,version,[]}}), % F1_exp + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); % F1_loc + _ -> ok + end, + + {module,my_upgrade_test} = erlang:load_module(my_upgrade_test, V2), + 2 = my_upgrade_test:version(), + put('F2_exp', my_upgrade_test:make_fun_exp()), + put('F2_loc', my_upgrade_test:make_fun_local()), + 2 = (get('F1_exp'))(), + 1 = (get('F1_loc'))(), + 2 = (get('F2_exp'))(), + 2 = (get('F2_loc'))(), + expect(), + + put('F1_exp', undefined), + put('F1_loc', undefined), + erlang:garbage_collect(), + erlang:purge_module(my_upgrade_test), + + % Test that trace is cleared after delete_module + + trace_func({my_upgrade_test,'_','_'}, [], [global]), + case TraceLocalVersion of + true -> trace_func({my_upgrade_test,local_version,0}, [], [local]); + _ -> ok + end, + 2 = my_upgrade_test:version(), + 2 = my_upgrade_test:do_local(), + 2 = my_upgrade_test:do_real_local(), + 2 = (get('F2_exp'))(), + 2 = (get('F2_loc'))(), + + expect({trace,Self,call,{my_upgrade_test,version,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_real_local,[]}}), + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); + _ -> ok + end, + expect({trace,Self,call,{my_upgrade_test,version,[]}}), % F2_exp + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); % F2_loc + _ -> ok + end, + + true = erlang:delete_module(my_upgrade_test), + {'EXIT',{undef,_}} = (catch my_upgrade_test:version()), + {'EXIT',{undef,_}} = (catch ((get('F2_exp'))())), + 2 = (get('F2_loc'))(), + expect(), + + put('F2_exp', undefined), + put('F2_loc', undefined), + erlang:garbage_collect(), + erlang:purge_module(my_upgrade_test), + ok. + +compile_version(Module, Version, Config) -> + Data = ?config(data_dir, Config), + File = filename:join(Data, atom_to_list(Module)), + {ok,Module,Bin} = compile:file(File, [{d,'VERSION',Version}, + binary,report]), + Bin. + + + %% Test flags (arity, timestamp) for call_trace/3. %% Also, test the '{tracer,Pid}' option. flags(_Config) -> @@ -1151,11 +1276,13 @@ trace_info(What, Key) -> Res. trace_func(MFA, MatchSpec) -> - get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA, MatchSpec]}}, + trace_func(MFA, MatchSpec, []). +trace_func(MFA, MatchSpec, Flags) -> + get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA, MatchSpec, Flags]}}, Res = receive {apply_result,Result} -> Result end, - ok = io:format("trace_pattern(~p, ~p) -> ~p", [MFA,MatchSpec,Res]), + ok = io:format("trace_pattern(~p, ~p, ~p) -> ~p", [MFA,MatchSpec,Flags,Res]), Res. trace_pid(Pid, On, Flags) -> diff --git a/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl b/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl new file mode 100644 index 0000000000..11b8a95209 --- /dev/null +++ b/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl @@ -0,0 +1,26 @@ +-module(my_upgrade_test). + +-export([version/0]). +-export([do_local/0]). +-export([do_real_local/0]). +-export([make_fun_exp/0]). +-export([make_fun_local/0]). + + +version() -> + ?VERSION. + +do_local() -> + version(). + +do_real_local() -> + local_version(). + +local_version() -> + ?VERSION. + +make_fun_exp() -> + fun() -> ?MODULE:version() end. + +make_fun_local() -> + fun() -> local_version() end. diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl new file mode 100644 index 0000000000..aa9e4c96c6 --- /dev/null +++ b/erts/emulator/test/code_parallel_load_SUITE.erl @@ -0,0 +1,198 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% Author: Björn-Egil Dahlberg + +-module(code_parallel_load_SUITE). +-export([ + all/0, + suite/0, + init_per_suite/1, + end_per_suite/1, + init_per_testcase/2, + end_per_testcase/2 + ]). + +-export([ + multiple_load_check_purge_repeat/1, + many_load_distributed_only_once/1 + ]). + +-define(model, code_parallel_load_SUITE_model). +-define(interval, 50). +-define(number_of_processes, 160). +-define(passes, 4). + + +-include_lib("test_server/include/test_server.hrl"). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [ + multiple_load_check_purge_repeat, + many_load_distributed_only_once + ]. + + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> + Dog=?t:timetrap(?t:minutes(3)), + [{watchdog, Dog}|Config]. + +end_per_testcase(_Func, Config) -> + SConf = ?config(save_config, Config), + Pids = proplists:get_value(purge_pids, SConf), + + case check_old_code(?model) of + true -> check_and_purge_processes_code(Pids, ?model); + _ -> ok + end, + case erlang:delete_module(?model) of + true -> check_and_purge_processes_code(Pids, ?model); + _ -> ok + end, + Dog=?config(watchdog, Config), + ?t:timetrap_cancel(Dog). + + +multiple_load_check_purge_repeat(_Conf) -> + Ts = [v1,v2,v3,v4,v5,v6], + + %% generate code that receives a token, code switches to new code + %% then matches this token against a literal code token + %% should be identical + %% (smoke test for parallel code loading + Codes = [{T, generate(?model, [], [ + format("check(T) -> receive {_Pid, change, T1} -> " + " ~w:check(T1)\n" + " after 0 -> T = f(), check(T) end.\n", [?model]), + format("f() -> ~w.~n", [T]) + ])} || T <- Ts], + + Pids = setup_code_changer(Codes), + {save_config, [{purge_pids,Pids}]}. + +setup_code_changer([{Token,Code}|Cs] = Codes) -> + {module, ?model} = erlang:load_module(?model,Code), + Pids = setup_checkers(Token,?number_of_processes), + code_changer(Cs, Codes, ?interval,Pids,?passes), + Pids. + +code_changer(_, _, _, Pids, 0) -> + [unlink(Pid) || Pid <- Pids], + [exit(Pid, die) || Pid <- Pids], + io:format("done~n"), + ok; +code_changer([], Codes, T, Pids, Ps) -> + code_changer(Codes, Codes, T, Pids, Ps - 1); +code_changer([{Token,Code}|Cs], Codes, T, Pids, Ps) -> + receive after T -> + io:format("load code with token ~4w : pass ~4w~n", [Token, Ps]), + {module, ?model} = erlang:load_module(?model, Code), + % this is second time we call load_module for this module + % so it should have old code + [Pid ! {self(), change, Token} || Pid <- Pids], + % should we wait a moment or just blantantly try to check and purge repeatadly? + receive after 1 -> ok end, + ok = check_and_purge_processes_code(Pids, ?model), + code_changer(Cs, Codes, T, Pids, Ps) + end. + + + +many_load_distributed_only_once(_Conf) -> + Ts = [<<"first version">>, <<"second version">>], + + [{Token1,Code1},{Token2, Code2}] = [{T, generate(?model, [], [ + "check({<<\"second version\">> = V, Pid}) -> V = f(), Pid ! {self(), completed, V}, ok;\n" ++ + format("check(T) -> receive {Pid, change, T1, B} -> " + " Res = erlang:load_module(~w, B), Pid ! {self(), change, Res},\n" + " ~w:check({T1, Pid})\n" + " after 0 -> T = f(), check(T) end.\n", [?model, ?model]), + format("f() -> ~w.~n", [T]) + ])} || T <- Ts], + + + {module, ?model} = erlang:load_module(?model, Code1), + Pids = setup_checkers(Token1,?number_of_processes), + + receive after 1000 -> ok end, % give 'em some time to spin up + [Pid ! {self(), change, Token2, Code2} || Pid <- Pids], + Loads = [receive {Pid, change, Res} -> Res end || Pid <- Pids], + [receive {Pid, completed, Token2} -> ok end || Pid <- Pids], + + ok = ensure_only_one_load(Loads, 0), + {save_config, [{purge_pids,Pids}]}. + +ensure_only_one_load([], 1) -> ok; +ensure_only_one_load([], _) -> too_many_loads; +ensure_only_one_load([{module, ?model}|Loads], N) -> + ensure_only_one_load(Loads, N + 1); +ensure_only_one_load([{error, not_purged}|Loads], N) -> + ensure_only_one_load(Loads, N). +% no other return values are allowed from load_module + + +%% aux + +setup_checkers(_,0) -> []; +setup_checkers(T,N) -> [spawn_link(fun() -> ?model:check(T) end) | setup_checkers(T, N-1)]. + +check_and_purge_processes_code(Pids, M) -> + check_and_purge_processes_code(Pids, M, []). +check_and_purge_processes_code([], M, []) -> + erlang:purge_module(M), + ok; +check_and_purge_processes_code([], M, Pending) -> + io:format("Processes ~w are still executing old code - retrying.~n", [Pending]), + check_and_purge_processes_code(Pending, M, []); +check_and_purge_processes_code([Pid|Pids], M, Pending) -> + case erlang:check_process_code(Pid, M) of + false -> + check_and_purge_processes_code(Pids, M, Pending); + true -> + check_and_purge_processes_code(Pids, M, [Pid|Pending]) + end. + + +generate(Module, Attributes, FunStrings) -> + FunForms = function_forms(FunStrings), + Forms = [ + {attribute,1,module,Module}, + {attribute,2,export,[FA || {FA,_} <- FunForms]} + ] ++ [{attribute, 3, A, V}|| {A, V} <- Attributes] ++ + [ Function || {_, Function} <- FunForms], + {ok, Module, Bin} = compile:forms(Forms), + Bin. + + +function_forms([]) -> []; +function_forms([S|Ss]) -> + {ok, Ts,_} = erl_scan:string(S), + {ok, Form} = erl_parse:parse_form(Ts), + Fun = element(3, Form), + Arity = element(4, Form), + [{{Fun,Arity}, Form}|function_forms(Ss)]. + +format(F,Ts) -> lists:flatten(io_lib:format(F, Ts)). diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index 2ddb4d76d9..c88218c176 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -98,19 +98,6 @@ end_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> Dog=?config(watchdog, Config), ?t:timetrap_cancel(Dog). -%%% Don't be too hard on vxworks, the cross server gets nodedown -%%% cause the card is too busy if we don't sleep a little between pings. -sleep() -> - case os:type() of - vxworks -> - receive - after 10 -> - ok - end; - _ -> - ok - end. - ping(doc) -> ["Tests pinging a node in different ways."]; ping(Config) when is_list(Config) -> @@ -122,23 +109,21 @@ ping(Config) when is_list(Config) -> ?line Host = hostname(), ?line BadName = list_to_atom("__pucko__@" ++ Host), ?line io:format("Pinging ~s (assumed to not exist)", [BadName]), - ?line test_server:do_times(Times, - fun() -> pang = net_adm:ping(BadName), - sleep() + ?line test_server:do_times(Times, fun() -> pang = net_adm:ping(BadName) end), %% Pings another node. ?line {ok, OtherNode} = start_node(distribution_SUITE_other), ?line io:format("Pinging ~s (assumed to exist)", [OtherNode]), - ?line test_server:do_times(Times, fun() -> pong = net_adm:ping(OtherNode),sleep() end), + ?line test_server:do_times(Times, fun() -> pong = net_adm:ping(OtherNode) end), ?line stop_node(OtherNode), %% Pings our own node many times. ?line Node = node(), ?line io:format("Pinging ~s (the same node)", [Node]), - ?line test_server:do_times(Times, fun() -> pong = net_adm:ping(Node),sleep() end), + ?line test_server:do_times(Times, fun() -> pong = net_adm:ping(Node) end), ok. diff --git a/erts/emulator/test/driver_SUITE_data/chkio_drv.c b/erts/emulator/test/driver_SUITE_data/chkio_drv.c index 40f1ad4fea..faf1040276 100644 --- a/erts/emulator/test/driver_SUITE_data/chkio_drv.c +++ b/erts/emulator/test/driver_SUITE_data/chkio_drv.c @@ -17,7 +17,7 @@ */ #ifndef UNIX -#if !defined(__WIN32__) && !defined(VXWORKS) +#if !defined(__WIN32__) #define UNIX 1 #endif #endif diff --git a/erts/emulator/test/driver_SUITE_data/io_ready_exit_drv.c b/erts/emulator/test/driver_SUITE_data/io_ready_exit_drv.c index e6a3edcd74..1e107309df 100644 --- a/erts/emulator/test/driver_SUITE_data/io_ready_exit_drv.c +++ b/erts/emulator/test/driver_SUITE_data/io_ready_exit_drv.c @@ -17,7 +17,7 @@ */ #ifndef UNIX -#if !defined(__WIN32__) && !defined(VXWORKS) +#if !defined(__WIN32__) #define UNIX 1 #endif #endif diff --git a/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c b/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c index b2cc1e785a..d174771629 100644 --- a/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c +++ b/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c @@ -29,7 +29,7 @@ */ #ifndef UNIX -#if !defined(__WIN32__) && !defined(VXWORKS) +#if !defined(__WIN32__) #define UNIX 1 #endif #endif diff --git a/erts/emulator/test/driver_SUITE_data/missing_callback_drv.c b/erts/emulator/test/driver_SUITE_data/missing_callback_drv.c index e7d9a294fa..851f2c745b 100644 --- a/erts/emulator/test/driver_SUITE_data/missing_callback_drv.c +++ b/erts/emulator/test/driver_SUITE_data/missing_callback_drv.c @@ -17,7 +17,7 @@ */ #ifndef UNIX -#if !defined(__WIN32__) && !defined(VXWORKS) +#if !defined(__WIN32__) #define UNIX 1 #endif #endif diff --git a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c index 8e203f74ec..0c86a26604 100644 --- a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c +++ b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c @@ -28,7 +28,7 @@ */ #ifndef UNIX -#if !defined(__WIN32__) && !defined(VXWORKS) +#if !defined(__WIN32__) #define UNIX 1 #endif #endif diff --git a/erts/emulator/test/driver_SUITE_data/timer_drv.c b/erts/emulator/test/driver_SUITE_data/timer_drv.c index 8c3f203a64..57538e0d57 100644 --- a/erts/emulator/test/driver_SUITE_data/timer_drv.c +++ b/erts/emulator/test/driver_SUITE_data/timer_drv.c @@ -1,11 +1,3 @@ -#ifdef VXWORKS -#include <vxWorks.h> -#include <taskVarLib.h> -#include <taskLib.h> -#include <sysLib.h> -#include <string.h> -#include <ioLib.h> -#endif #include <stdio.h> #include "erl_driver.h" @@ -84,12 +76,8 @@ static void timer_read(ErlDrvData p, char *buf, ErlDrvSizeT len) driver_output(port, reply, 1); } else if (buf[0] == DELAY_START_TIMER) { #ifndef __WIN32__ -#ifdef VXWORKS - taskDelay(sysClkRateGet()); -#else sleep(1); #endif -#endif driver_set_timer(port, get_int32(buf + 1)); } } diff --git a/erts/emulator/test/emulator.spec.vxworks b/erts/emulator/test/emulator.spec.vxworks deleted file mode 100644 index 55675bdc29..0000000000 --- a/erts/emulator/test/emulator.spec.vxworks +++ /dev/null @@ -1,26 +0,0 @@ -{topcase, {dir, "../emulator_test"}}. - -% Added since R11 -{skip,{distribution_SUITE,link_to_dead_new_node,"Does not work in distributed test environments"}}. -{skip,{binary_SUITE,terms_float,"Floats, VxWorks, PPC = Floating points never equal..."}}. -{skip,{system_info_SUITE,process_count,"Fix-allocs starving VxWorks cards"}}. -{skip,{monitor_SUITE,mixer,"Fix-allocs starving VxWorks cards"}}. - -{skip,{node_container_SUITE,"Too memory consuming..."}}. - -{skip,{trace_SUITE,system_monitor_long_gc_1,"Too memory consuming..."}}. -{skip,{trace_SUITE,system_monitor_long_gc_2,"Too memory consuming..."}}. -{skip,{trace_SUITE,system_monitor_large_heap_1,"Too memory consuming..."}}. -{skip,{trace_SUITE,system_monitor_large_heap_2,"Too memory consuming..."}}. -% End added since R11 - -{skip, {distribution_SUITE,stop_dist,"Not written to work on VxWorks."}}. -{skip, {distribution_SUITE,dist_auto_connect_never, - "Not written to work on VxWorks."}}. -{skip, {distribution_SUITE,dist_auto_connect_once, - "Not written to work on VxWorks."}}. -{skip, {trace_SUITE,system_monitor_long_gc, - "Too memory consuming for VxWorks cards."}}. -{skip, {trace_meta_SUITE,stack_grow, - "Too memory consuming for VxWorks cards."}}. -{skip, {obsolete_SUITE, "Not on vxworks"}}. diff --git a/erts/emulator/test/emulator_bench.spec b/erts/emulator/test/emulator_bench.spec new file mode 100644 index 0000000000..f709d913b7 --- /dev/null +++ b/erts/emulator/test/emulator_bench.spec @@ -0,0 +1 @@ +{groups,"../emulator_test",estone_SUITE,[estone_bench]}. diff --git a/erts/emulator/test/estone_SUITE.erl b/erts/emulator/test/estone_SUITE.erl index 2417d4bcfe..21834bfa62 100644 --- a/erts/emulator/test/estone_SUITE.erl +++ b/erts/emulator/test/estone_SUITE.erl @@ -19,7 +19,7 @@ -module(estone_SUITE). %% Test functions -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2,estone/1]). + init_per_group/2,end_per_group/2,estone/1,estone_bench/1]). -export([init_per_testcase/2, end_per_testcase/2]). %% Internal exports for EStone tests @@ -46,6 +46,7 @@ -include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct_event.hrl"). %% Test suite defines -define(default_timeout, ?t:minutes(10)). @@ -80,7 +81,7 @@ all() -> [estone]. groups() -> - []. + [{estone_bench, [{repeat,50}],[estone_bench]}]. init_per_suite(Config) -> Config. @@ -108,6 +109,17 @@ estone(Config) when is_list(Config) -> ?line {comment,Mhz ++ " MHz, " ++ integer_to_list(Stones) ++ " ESTONES"}. +estone_bench(Config) -> + DataDir = ?config(data_dir,Config), + L = ?MODULE:macro(?MODULE:micros(),DataDir), + [ct_event:notify( + #event{name = benchmark_data, + data = [{name,proplists:get_value(title,Mark)}, + {value,proplists:get_value(estones,Mark)}]}) + || Mark <- L], + L. + + %% %% Calculate CPU speed %% diff --git a/erts/emulator/test/estone_SUITE_data/estone_cat.c b/erts/emulator/test/estone_SUITE_data/estone_cat.c index 8ed9f8375b..a34bda4384 100644 --- a/erts/emulator/test/estone_SUITE_data/estone_cat.c +++ b/erts/emulator/test/estone_SUITE_data/estone_cat.c @@ -12,11 +12,7 @@ #include <fcntl.h> #include <errno.h> -#ifdef VXWORKS -estone_cat(argc, argv) -#else main(argc, argv) -#endif int argc; char *argv[]; { diff --git a/erts/emulator/test/gc_SUITE.erl b/erts/emulator/test/gc_SUITE.erl index 771d2c9a7a..19fa433a53 100644 --- a/erts/emulator/test/gc_SUITE.erl +++ b/erts/emulator/test/gc_SUITE.erl @@ -54,17 +54,12 @@ grow_heap(doc) -> ["Produce a growing list of elements, ", "for X calls, then drop one item per call", "until the list is empty."]; grow_heap(Config) when is_list(Config) -> - ?line Dog=test_server:timetrap(test_server:minutes(40)), - ?line ok=grow_heap1(256), - case os:type() of - vxworks -> - stop_here; - _ -> - ?line ok=grow_heap1(512), - ?line ok=grow_heap1(1024), - ?line ok=grow_heap1(2048) - end, - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:minutes(40)), + ok = grow_heap1(256), + ok = grow_heap1(512), + ok = grow_heap1(1024), + ok = grow_heap1(2048), + test_server:timetrap_cancel(Dog), ok. grow_heap1(Len) -> @@ -82,10 +77,10 @@ grow_heap1(List, MaxLen, CurLen, up) -> grow_heap1([], _MaxLen, _, down) -> ok; grow_heap1([_|List], MaxLen, CurLen, down) -> - ?line {_,_,C}=erlang:now(), - ?line Num=C rem (length(List))+1, - ?line Elem=lists:nth(Num, List), - ?line NewList=lists:delete(Elem, List), + {_,_,C} = erlang:now(), + Num = C rem (length(List))+1, + Elem = lists:nth(Num, List), + NewList = lists:delete(Elem, List), grow_heap1(NewList, MaxLen, CurLen-1, down). @@ -93,16 +88,11 @@ grow_heap1([_|List], MaxLen, CurLen, down) -> grow_stack(doc) -> ["Increase and decrease stack size, and ", "drop off some garbage from time to time."]; grow_stack(Config) when is_list(Config) -> - ?line Dog=test_server:timetrap(test_server:minutes(80)), + Dog = test_server:timetrap(test_server:minutes(80)), show_heap("before:"), - case os:type() of - vxworks -> - ?line grow_stack1(25, 0); - _ -> - ?line grow_stack1(200, 0) - end, + grow_stack1(200, 0), show_heap("after:"), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. grow_stack1(0, _) -> @@ -123,16 +113,11 @@ grow_stack_heap(doc) -> ["While growing the heap, bounces the size ", "of the stack, and while reducing the heap", "bounces the stack usage."]; grow_stack_heap(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Takes too long to run on VxWorks/cpu32"}; - _ -> - ?line Dog=test_server:timetrap(test_server:minutes(40)), - ?line grow_stack_heap1(16), - ?line grow_stack_heap1(32), - ?line test_server:timetrap_cancel(Dog), - ok - end. + Dog = test_server:timetrap(test_server:minutes(40)), + grow_stack_heap1(16), + grow_stack_heap1(32), + test_server:timetrap_cancel(Dog), + ok. grow_stack_heap1(MaxLen) -> io:format("~ngrow_stack_heap with ~p items.",[MaxLen]), @@ -151,10 +136,10 @@ grow_stack_heap1(List, MaxLen, CurLen, up) -> grow_stack_heap1([], _MaxLen, _, down) -> ok; grow_stack_heap1([_|List], MaxLen, CurLen, down) -> grow_stack1(CurLen*2,0), - ?line {_,_,C}=erlang:now(), - ?line Num=C rem (length(List))+1, - ?line Elem=lists:nth(Num, List), - ?line NewList=lists:delete(Elem, List), + {_,_,C}=erlang:now(), + Num=C rem (length(List))+1, + Elem=lists:nth(Num, List), + NewList=lists:delete(Elem, List), grow_stack_heap1(NewList, MaxLen, CurLen-1, down), ok. diff --git a/erts/emulator/test/mtx_SUITE_data/Makefile.src b/erts/emulator/test/mtx_SUITE_data/Makefile.src index b6c843269c..37eb1daa72 100644 --- a/erts/emulator/test/mtx_SUITE_data/Makefile.src +++ b/erts/emulator/test/mtx_SUITE_data/Makefile.src @@ -27,4 +27,11 @@ LIBS = @ERTS_LIBS@ all: $(NIF_LIBS) +mtx_SUITE.c: force_rebuild + touch mtx_SUITE.c + +force_rebuild: + echo "Force rebuild to compensate for emulator type dependencies" + + @SHLIB_RULES@ diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl index 0b99b3438a..4b555777d7 100644 --- a/erts/emulator/test/port_SUITE.erl +++ b/erts/emulator/test/port_SUITE.erl @@ -157,16 +157,16 @@ win_massive(Config) when is_list(Config) -> end. do_win_massive() -> - ?line Dog = test_server:timetrap(test_server:seconds(360)), - ?line SuiteDir = filename:dirname(code:which(?MODULE)), - ?line Env = " -env ERL_MAX_PORTS 8192", - ?line {ok, Node} = + Dog = test_server:timetrap(test_server:seconds(360)), + SuiteDir = filename:dirname(code:which(?MODULE)), + Env = " -env ERL_MAX_PORTS 8192", + {ok, Node} = test_server:start_node(win_massive, slave, [{args, " -pa " ++ SuiteDir ++ Env}]), - ?line ok = rpc:call(Node,?MODULE,win_massive_client,[3000]), - ?line test_server:stop_node(Node), - ?line test_server:timetrap_cancel(Dog), + ok = rpc:call(Node,?MODULE,win_massive_client,[3000]), + test_server:stop_node(Node), + test_server:timetrap_cancel(Dog), ok. win_massive_client(N) -> @@ -208,11 +208,11 @@ win_massive_loop(P,N) -> %% We will send only a small amount of data, to avoid deadlock. stream_small(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line stream_ping(Config, 512, "", []), - ?line stream_ping(Config, 1777, "", []), - ?line stream_ping(Config, 1777, "-s512", []), - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(10)), + stream_ping(Config, 512, "", []), + stream_ping(Config, 1777, "", []), + stream_ping(Config, 1777, "-s512", []), + test_server:timetrap_cancel(Dog), ok. %% Send big amounts of data (much bigger than the buffer size in port test). @@ -220,30 +220,22 @@ stream_small(Config) when is_list(Config) -> %% non-blocking reads and writes. stream_big(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(180)), - case os:type() of - vxworks -> - %% Don't stress VxWorks too much - ?line stream_ping(Config, 43755, "", []), - ?line stream_ping(Config, 51255, "", []), - ?line stream_ping(Config, 52345, " -s40000", []); - _ -> - ?line stream_ping(Config, 43755, "", []), - ?line stream_ping(Config, 100000, "", []), - ?line stream_ping(Config, 77777, " -s40000", []) - end, - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(180)), + stream_ping(Config, 43755, "", []), + stream_ping(Config, 100000, "", []), + stream_ping(Config, 77777, " -s40000", []), + test_server:timetrap_cancel(Dog), ok. %% Sends packet with header size of 1, 2, and 4, with packets of various %% sizes. basic_ping(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(120)), - ?line ping(Config, sizes(1), 1, "", []), - ?line ping(Config, sizes(2), 2, "", []), - ?line ping(Config, sizes(4), 4, "", []), - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(120)), + ping(Config, sizes(1), 1, "", []), + ping(Config, sizes(2), 2, "", []), + ping(Config, sizes(4), 4, "", []), + test_server:timetrap_cancel(Dog), ok. %% Let the port program insert delays between characters sent back to @@ -251,30 +243,29 @@ basic_ping(Config) when is_list(Config) -> %% small chunks rather than all at once. slow_writes(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(20)), - ?line ping(Config, [8], 4, "-s1", []), - ?line ping(Config, [10], 2, "-s2", []), - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(20)), + ping(Config, [8], 4, "-s1", []), + ping(Config, [10], 2, "-s2", []), + test_server:timetrap_cancel(Dog), ok. bad_packet(doc) -> ["Test that we get {'EXIT', Port, einval} if we try to send a bigger " "packet than the packet header allows."]; bad_packet(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line PortTest = port_test(Config), - ?line process_flag(trap_exit, true), + Dog = test_server:timetrap(test_server:seconds(10)), + PortTest = port_test(Config), + process_flag(trap_exit, true), - ?line bad_packet(PortTest, 1, 256), - ?line bad_packet(PortTest, 1, 257), - ?line bad_packet(PortTest, 2, 65536), - ?line bad_packet(PortTest, 2, 65537), + bad_packet(PortTest, 1, 256), + bad_packet(PortTest, 1, 257), + bad_packet(PortTest, 2, 65536), + bad_packet(PortTest, 2, 65537), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. bad_packet(PortTest, HeaderSize, PacketSize) -> - %% Intentionally no ?line macros. P = open_port({spawn, PortTest}, [{packet, HeaderSize}]), P ! {self(), {command, make_zero_packet(PacketSize)}}, receive @@ -292,16 +283,16 @@ make_zero_packet(N) -> %% Test sending bad messages to a port. bad_port_messages(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line PortTest = port_test(Config), - ?line process_flag(trap_exit, true), + Dog = test_server:timetrap(test_server:seconds(10)), + PortTest = port_test(Config), + process_flag(trap_exit, true), - ?line bad_message(PortTest, {a,b}), - ?line bad_message(PortTest, {a}), - ?line bad_message(PortTest, {self(),{command,bad_command}}), - ?line bad_message(PortTest, {self(),{connect,no_pid}}), + bad_message(PortTest, {a,b}), + bad_message(PortTest, {a}), + bad_message(PortTest, {self(),{command,bad_command}}), + bad_message(PortTest, {self(),{connect,no_pid}}), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. bad_message(PortTest, Message) -> @@ -319,108 +310,97 @@ bad_message(PortTest, Message) -> %% Tests the 'binary' option for a port. t_binary(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(300)), + Dog = test_server:timetrap(test_server:seconds(300)), %% Packet mode. - ?line ping(Config, sizes(1), 1, "", [binary]), - ?line ping(Config, sizes(2), 2, "", [binary]), - ?line ping(Config, sizes(4), 4, "", [binary]), + ping(Config, sizes(1), 1, "", [binary]), + ping(Config, sizes(2), 2, "", [binary]), + ping(Config, sizes(4), 4, "", [binary]), %% Stream mode. - case os:type() of - vxworks -> - %% don't stress VxWorks too much - ?line stream_ping(Config, 435, "", [binary]), - ?line stream_ping(Config, 43755, "", [binary]), - ?line stream_ping(Config, 50000, "", [binary]); - _ -> - ?line stream_ping(Config, 435, "", [binary]), - ?line stream_ping(Config, 43755, "", [binary]), - ?line stream_ping(Config, 100000, "", [binary]) - end, + stream_ping(Config, 435, "", [binary]), + stream_ping(Config, 43755, "", [binary]), + stream_ping(Config, 100000, "", [binary]), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. name1(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(100)), - ?line PortTest = port_test(Config), - ?line Command = lists:concat([PortTest, " "]), - ?line P = open_port({spawn, Command}, []), - ?line register(myport, P), - ?line P = whereis(myport), + Dog = test_server:timetrap(test_server:seconds(100)), + PortTest = port_test(Config), + Command = lists:concat([PortTest, " "]), + P = open_port({spawn, Command}, []), + register(myport, P), + P = whereis(myport), Text = "hej", - ?line myport ! {self(), {command, Text}}, - ?line receive - {P, {data, Text}} -> - ok - end, - ?line myport ! {self(), close}, - ?line receive - {P, closed} -> ok - end, - ?line undefined = whereis(myport), - ?line test_server:timetrap_cancel(Dog), + myport ! {self(), {command, Text}}, + receive + {P, {data, Text}} -> + ok + end, + myport ! {self(), close}, + receive + {P, closed} -> ok + end, + undefined = whereis(myport), + test_server:timetrap_cancel(Dog), ok. %% Test that the 'eof' option works. eof(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(100)), - ?line PortTest = port_test(Config), - ?line Command = lists:concat([PortTest, " -h0 -q"]), - ?line P = open_port({spawn, Command}, [eof]), - ?line receive - {P, eof} -> - ok - end, - ?line P ! {self(), close}, - ?line receive - {P, closed} -> ok - end, - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(100)), + PortTest = port_test(Config), + Command = lists:concat([PortTest, " -h0 -q"]), + P = open_port({spawn, Command}, [eof]), + receive + {P, eof} -> + ok + end, + P ! {self(), close}, + receive + {P, closed} -> ok + end, + test_server:timetrap_cancel(Dog), ok. %% Tests that the 'in' option for a port works. input_only(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(300)), - ?line expect_input(Config, [0, 1, 10, 13, 127, 128, 255], 1, "", [in]), - ?line expect_input(Config, [0, 1, 255, 2048], 2, "", [in]), - ?line expect_input(Config, [0, 1, 255, 2048], 4, "", [in]), - ?line expect_input(Config, [0, 1, 10, 13, 127, 128, 255], - 1, "", [in, binary]), - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(300)), + expect_input(Config, [0, 1, 10, 13, 127, 128, 255], 1, "", [in]), + expect_input(Config, [0, 1, 255, 2048], 2, "", [in]), + expect_input(Config, [0, 1, 255, 2048], 4, "", [in]), + expect_input(Config, [0, 1, 10, 13, 127, 128, 255], + 1, "", [in, binary]), + test_server:timetrap_cancel(Dog), ok. %% Tests that the 'out' option for a port works. output_only(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(100)), - ?line Dir = ?config(priv_dir, Config), - ?line Filename = filename:join(Dir, "output_only_stream"), - ?line output_and_verify(Config, Filename, "-h0", - random_packet(35777, "echo")), - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(100)), + Dir = ?config(priv_dir, Config), + Filename = filename:join(Dir, "output_only_stream"), + output_and_verify(Config, Filename, "-h0", + random_packet(35777, "echo")), + test_server:timetrap_cancel(Dog), ok. output_and_verify(Config, Filename, Options, Data) -> - ?line PortTest = port_test(Config), - ?line Command = lists:concat([PortTest, " ", - Options, " -o", Filename]), - ?line Port = open_port({spawn, Command}, [out]), - ?line Port ! {self(), {command, Data}}, - ?line Port ! {self(), close}, - ?line receive - {Port, closed} -> ok - end, - Wait_time = case os:type() of - vxworks -> 5000; - _ -> 500 - end, - ?line test_server:sleep(Wait_time), - ?line {ok, Written} = file:read_file(Filename), - ?line Data = binary_to_list(Written), + PortTest = port_test(Config), + Command = lists:concat([PortTest, " ", + Options, " -o", Filename]), + Port = open_port({spawn, Command}, [out]), + Port ! {self(), {command, Data}}, + Port ! {self(), close}, + receive + {Port, closed} -> ok + end, + Wait_time = 500, + test_server:sleep(Wait_time), + {ok, Written} = file:read_file(Filename), + Data = binary_to_list(Written), ok. %% Test that receiving several packages written in the same @@ -430,19 +410,11 @@ output_and_verify(Config, Filename, Options, Data) -> %% Basic test of receiving multiple packages, written in %% one operation by the other end. mul_basic(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(600)), - case os:type() of - vxworks -> - %% don't stress vxworks too much - ?line expect_input(Config, [0, 1, 255, 10, 13], 1, "", []), - ?line expect_input(Config, [0, 10, 13, 1600, 8191, 16383], 2, "", []), - ?line expect_input(Config, [10, 35000], 4, "", []); - _ -> - ?line expect_input(Config, [0, 1, 255, 10, 13], 1, "", []), - ?line expect_input(Config, [0, 10, 13, 1600, 32767, 65535], 2, "", []), - ?line expect_input(Config, [10, 70000], 4, "", []) - end, - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(600)), + expect_input(Config, [0, 1, 255, 10, 13], 1, "", []), + expect_input(Config, [0, 10, 13, 1600, 32767, 65535], 2, "", []), + expect_input(Config, [10, 70000], 4, "", []), + test_server:timetrap_cancel(Dog), ok. %% Test reading a buffer consisting of several packets, some @@ -451,9 +423,9 @@ mul_basic(Config) when is_list(Config) -> %% delays in between.) mul_slow_writes(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(250)), - ?line expect_input(Config, [0, 20, 255, 10, 1], 1, "-s64", []), - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(250)), + expect_input(Config, [0, 20, 255, 10, 1], 1, "-s64", []), + test_server:timetrap_cancel(Dog), ok. %% Runs several port tests in parallell. Each individual test @@ -461,27 +433,27 @@ mul_slow_writes(Config) when is_list(Config) -> %% should also finish in about 5 seconds. parallell(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(300)), - ?line Testers = - [fun() -> stream_ping(Config, 1007, "-s100", []) end, - fun() -> stream_ping(Config, 10007, "-s1000", []) end, - fun() -> stream_ping(Config, 10007, "-s1000", []) end, - - fun() -> expect_input(Config, [21, 22, 23, 24, 25], 1, - "-s10", [in]) end, - - fun() -> ping(Config, [10], 1, "-d", []) end, - fun() -> ping(Config, [20000], 2, "-d", []) end, - fun() -> ping(Config, [101], 1, "-s10", []) end, - fun() -> ping(Config, [1001], 2, "-s100", []) end, - fun() -> ping(Config, [10001], 4, "-s1000", []) end, - - fun() -> ping(Config, [501, 501], 2, "-s100", []) end, - fun() -> ping(Config, [11, 12, 13, 14, 11], 1, "-s5", []) end], - ?line process_flag(trap_exit, true), - ?line Pids = lists:map(fun fun_spawn/1, Testers), - ?line wait_for(Pids), - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(300)), + Testers = [ + fun() -> stream_ping(Config, 1007, "-s100", []) end, + fun() -> stream_ping(Config, 10007, "-s1000", []) end, + fun() -> stream_ping(Config, 10007, "-s1000", []) end, + + fun() -> expect_input(Config, [21, 22, 23, 24, 25], 1, + "-s10", [in]) end, + + fun() -> ping(Config, [10], 1, "-d", []) end, + fun() -> ping(Config, [20000], 2, "-d", []) end, + fun() -> ping(Config, [101], 1, "-s10", []) end, + fun() -> ping(Config, [1001], 2, "-s100", []) end, + fun() -> ping(Config, [10001], 4, "-s1000", []) end, + + fun() -> ping(Config, [501, 501], 2, "-s100", []) end, + fun() -> ping(Config, [11, 12, 13, 14, 11], 1, "-s5", []) end], + process_flag(trap_exit, true), + Pids = lists:map(fun fun_spawn/1, Testers), + wait_for(Pids), + test_server:timetrap_cancel(Dog), ok. wait_for([]) -> @@ -500,29 +472,29 @@ wait_for(Pids) -> dying_port(suite) -> []; dying_port(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(150)), - ?line process_flag(trap_exit, true), + Dog = test_server:timetrap(test_server:seconds(150)), + process_flag(trap_exit, true), - ?line P1 = make_dying_port(Config), - ?line P2 = make_dying_port(Config), - ?line P3 = make_dying_port(Config), - ?line P4 = make_dying_port(Config), - ?line P5 = make_dying_port(Config), + P1 = make_dying_port(Config), + P2 = make_dying_port(Config), + P3 = make_dying_port(Config), + P4 = make_dying_port(Config), + P5 = make_dying_port(Config), %% This should be big enough to be sure to block in the write. - ?line Garbage = random_packet(16384), + Garbage = random_packet(16384), - ?line P1 ! {self(), {command, Garbage}}, - ?line P3 ! {self(), {command, Garbage}}, - ?line P5 ! {self(), {command, Garbage}}, + P1 ! {self(), {command, Garbage}}, + P3 ! {self(), {command, Garbage}}, + P5 ! {self(), {command, Garbage}}, - ?line wait_for_port_exit(P1), - ?line wait_for_port_exit(P2), - ?line wait_for_port_exit(P3), - ?line wait_for_port_exit(P4), - ?line wait_for_port_exit(P5), + wait_for_port_exit(P1), + wait_for_port_exit(P2), + wait_for_port_exit(P3), + wait_for_port_exit(P4), + wait_for_port_exit(P5), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. wait_for_port_exit(Port) -> @@ -549,9 +521,9 @@ make_dying_port(Config) when is_list(Config) -> port_program_with_path(suite) -> []; port_program_with_path(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(100)), - ?line DataDir = ?config(data_dir, Config), - ?line PrivDir = ?config(priv_dir, Config), + Dog = test_server:timetrap(test_server:seconds(100)), + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), %% Create a copy of the port test program in a directory not %% included in PATH (i.e. in priv_dir), with the name 'my_port_test.exe'. @@ -560,36 +532,31 @@ port_program_with_path(Config) when is_list(Config) -> %% (On Unix, there will be a single file created, which will be %% a copy of the port program.) - ?line PortTest = os:find_executable("port_test", DataDir), + PortTest = os:find_executable("port_test", DataDir), io:format("os:find_executable(~p, ~p) returned ~p", ["port_test", DataDir, PortTest]), - ?line {ok, PortTestPgm} = file:read_file(PortTest), - ?line NewName = filename:join(PrivDir, filename:basename(PortTest)), - ?line RedHerring = filename:rootname(NewName), - ?line ok = file:write_file(RedHerring, "I'm just here to confuse.\n"), - ?line ok = file:write_file(NewName, PortTestPgm), - ?line ok = file:write_file_info(NewName, #file_info{mode=8#111}), - ?line PgmWithPathAndNoExt = filename:rootname(NewName), + {ok, PortTestPgm} = file:read_file(PortTest), + NewName = filename:join(PrivDir, filename:basename(PortTest)), + RedHerring = filename:rootname(NewName), + ok = file:write_file(RedHerring, "I'm just here to confuse.\n"), + ok = file:write_file(NewName, PortTestPgm), + ok = file:write_file_info(NewName, #file_info{mode=8#111}), + PgmWithPathAndNoExt = filename:rootname(NewName), %% Open the port using the path to the copied port test program, %% but without the .exe extension, and verified that it was started. %% %% If the bug is present the open_port call will fail with badarg. - ?line Command = lists:concat([PgmWithPathAndNoExt, " -h2"]), - %% allow VxWorks time to write file - case os:type() of - vxworks -> test_server:sleep(2500); - _ -> time + Command = lists:concat([PgmWithPathAndNoExt, " -h2"]), + P = open_port({spawn, Command}, [{packet, 2}]), + Message = "echo back to me", + P ! {self(), {command, Message}}, + receive + {P, {data, Message}} -> + ok end, - ?line P = open_port({spawn, Command}, [{packet, 2}]), - ?line Message = "echo back to me", - ?line P ! {self(), {command, Message}}, - ?line receive - {P, {data, Message}} -> - ok - end, - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. @@ -597,56 +564,46 @@ port_program_with_path(Config) when is_list(Config) -> %% This used to fail on Windows. open_input_file_port(suite) -> []; open_input_file_port(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line PrivDir = ?config(priv_dir, Config), + Dog = test_server:timetrap(test_server:seconds(10)), + PrivDir = ?config(priv_dir, Config), %% Create a file with the file driver and read it back using %% open_port/2. - ?line MyFile1 = filename:join(PrivDir, "my_input_file"), - ?line FileData1 = "An input file", - ?line ok = file:write_file(MyFile1, FileData1), - case os:type() of - vxworks -> - %% Can't open input file with vanilla driver on VxWorks - ?line process_flag(trap_exit, true), - ?line case catch open_port(MyFile1, [in]) of - {'EXIT', {badarg, _}} -> - ok - end; - _ -> - ?line case open_port(MyFile1, [in]) of - InputPort when is_port(InputPort) -> - ?line receive - {InputPort, {data, FileData1}} -> - ok - end - end + MyFile1 = filename:join(PrivDir, "my_input_file"), + FileData1 = "An input file", + ok = file:write_file(MyFile1, FileData1), + case open_port(MyFile1, [in]) of + InputPort when is_port(InputPort) -> + receive + {InputPort, {data, FileData1}} -> + ok + end end, - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. %% Tests that files can be written using open_port(Filename, [out]). open_output_file_port(suite) -> []; open_output_file_port(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(100)), - ?line PrivDir = ?config(priv_dir, Config), + Dog = test_server:timetrap(test_server:seconds(100)), + PrivDir = ?config(priv_dir, Config), %% Create a file with open_port/2 and read it back with %% the file driver. - ?line MyFile2 = filename:join(PrivDir, "my_output_file"), - ?line FileData2_0 = "A file created ", - ?line FileData2_1 = "with open_port/2.\n", - ?line FileData2 = FileData2_0 ++ FileData2_1, - ?line OutputPort = open_port(MyFile2, [out]), - ?line OutputPort ! {self(), {command, FileData2_0}}, - ?line OutputPort ! {self(), {command, FileData2_1}}, - ?line OutputPort ! {self(), close}, - ?line {ok, Bin} = file:read_file(MyFile2), - ?line FileData2 = binary_to_list(Bin), - - ?line test_server:timetrap_cancel(Dog), + MyFile2 = filename:join(PrivDir, "my_output_file"), + FileData2_0 = "A file created ", + FileData2_1 = "with open_port/2.\n", + FileData2 = FileData2_0 ++ FileData2_1, + OutputPort = open_port(MyFile2, [out]), + OutputPort ! {self(), {command, FileData2_0}}, + OutputPort ! {self(), {command, FileData2_1}}, + OutputPort ! {self(), close}, + {ok, Bin} = file:read_file(MyFile2), + FileData2 = binary_to_list(Bin), + + test_server:timetrap_cancel(Dog), ok. %% @@ -670,17 +627,17 @@ iter_max_ports(Config) when is_list(Config) -> iter_max_ports_test(Config) -> - ?line Dog = test_server:timetrap(test_server:minutes(20)), - ?line PortTest = port_test(Config), - ?line Command = lists:concat([PortTest, " -h0 -q"]), - ?line Iters = case os:type() of + Dog = test_server:timetrap(test_server:minutes(20)), + PortTest = port_test(Config), + Command = lists:concat([PortTest, " -h0 -q"]), + Iters = case os:type() of {win32,_} -> 4; _ -> 10 end, - ?line L = do_iter_max_ports(Iters, Command), + L = do_iter_max_ports(Iters, Command), io:format("Result: ~p",[L]), - ?line all_equal(L), - ?line test_server:timetrap_cancel(Dog), + all_equal(L), + test_server:timetrap_cancel(Dog), {comment, "Max ports: " ++ integer_to_list(hd(L))}. do_iter_max_ports(N, Command) when N > 0 -> @@ -695,9 +652,9 @@ all_equal([]) -> ok. max_ports(Command) -> test_server:sleep(500), - ?line Ps = open_ports({spawn, Command}, [eof]), - ?line N = length(Ps), - ?line close_ports(Ps), + Ps = open_ports({spawn, Command}, [eof]), + N = length(Ps), + close_ports(Ps), io:format("Got ~p ports\n",[N]), N. @@ -727,105 +684,105 @@ open_ports(Name, Settings) -> enomem -> []; Other -> - ?line test_server:fail({open_ports, Other}) + test_server:fail({open_ports, Other}) end; Other -> - ?line test_server:fail({open_ports, Other}) + test_server:fail({open_ports, Other}) end. %% Tests that exit(Port, Term) works (has been known to crash the emulator). t_exit(suite) -> []; t_exit(Config) when is_list(Config) -> - ?line process_flag(trap_exit, true), - ?line Pid = fun_spawn(fun suicide_port/1, [Config]), - ?line receive - {'EXIT', Pid, die} -> - ok; - Other -> - test_server:fail({bad_message, Other}) - end. + process_flag(trap_exit, true), + Pid = fun_spawn(fun suicide_port/1, [Config]), + receive + {'EXIT', Pid, die} -> + ok; + Other -> + test_server:fail({bad_message, Other}) + end. suicide_port(Config) when is_list(Config) -> - ?line Port = port_expect(Config, [], 0, "", []), - ?line exit(Port, die), - ?line receive after infinity -> ok end. + Port = port_expect(Config, [], 0, "", []), + exit(Port, die), + receive after infinity -> ok end. tps_16_bytes(doc) -> ""; tps_16_bytes(suite) -> []; tps_16_bytes(Config) when is_list(Config) -> - ?line tps(16, Config). + tps(16, Config). tps_1K(doc) -> ""; tps_1K(suite) -> []; tps_1K(Config) when is_list(Config) -> - ?line tps(1024, Config). + tps(1024, Config). tps(Size, Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(300)), - ?line PortTest = port_test(Config), - ?line Packet = list_to_binary(random_packet(Size, "e")), - ?line Port = open_port({spawn, PortTest}, [binary, {packet, 2}]), - ?line Transactions = 10000, - ?line {Elapsed, ok} = test_server:timecall(?MODULE, tps, + Dog = test_server:timetrap(test_server:seconds(300)), + PortTest = port_test(Config), + Packet = list_to_binary(random_packet(Size, "e")), + Port = open_port({spawn, PortTest}, [binary, {packet, 2}]), + Transactions = 10000, + {Elapsed, ok} = test_server:timecall(?MODULE, tps, [Port, Packet, Transactions]), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), {comment, integer_to_list(trunc(Transactions/Elapsed+0.5)) ++ " transactions/s"}. tps(_Port, _Packet, 0) -> ok; tps(Port, Packet, N) -> - ?line port_command(Port, Packet), - ?line receive - {Port, {data, Packet}} -> - ?line tps(Port, Packet, N-1); - Other -> - ?line test_server:fail({bad_message, Other}) - end. + port_command(Port, Packet), + receive + {Port, {data, Packet}} -> + tps(Port, Packet, N-1); + Other -> + test_server:fail({bad_message, Other}) + end. %% Line I/O test line(Config) when is_list(Config) -> - ?line Siz = 110, - ?line Dog = test_server:timetrap(test_server:seconds(300)), - ?line Packet1 = random_packet(Siz), - ?line Packet2 = random_packet(Siz div 2), + Siz = 110, + Dog = test_server:timetrap(test_server:seconds(300)), + Packet1 = random_packet(Siz), + Packet2 = random_packet(Siz div 2), %% Test that packets are split into lines - ?line port_expect(Config,[{lists:append([Packet1, io_lib:nl(), Packet2, + port_expect(Config,[{lists:append([Packet1, io_lib:nl(), Packet2, io_lib:nl()]), [{eol, Packet1}, {eol, Packet2}]}], 0, "", [{line,Siz}]), %% Test the same for binaries - ?line port_expect(Config,[{lists:append([Packet1, io_lib:nl(), Packet2, + port_expect(Config,[{lists:append([Packet1, io_lib:nl(), Packet2, io_lib:nl()]), [{eol, Packet1}, {eol, Packet2}]}], 0, "", [{line,Siz},binary]), %% Test that too long lines get split - ?line port_expect(Config,[{lists:append([Packet1, io_lib:nl(), Packet1, + port_expect(Config,[{lists:append([Packet1, io_lib:nl(), Packet1, Packet2, io_lib:nl()]), [{eol, Packet1}, {noeol, Packet1}, {eol, Packet2}]}], 0, "", [{line,Siz}]), %% Test that last output from closing port program gets received. - ?line L1 = lists:append([Packet1, io_lib:nl(), Packet2]), - ?line S1 = lists:flatten(io_lib:format("-l~w", [length(L1)])), + L1 = lists:append([Packet1, io_lib:nl(), Packet2]), + S1 = lists:flatten(io_lib:format("-l~w", [length(L1)])), io:format("S1 = ~w, L1 = ~w~n", [S1,L1]), - ?line port_expect(Config,[{L1, + port_expect(Config,[{L1, [{eol, Packet1}, {noeol, Packet2}, eof]}], 0, S1, [{line,Siz},eof]), %% Test that lonely <CR> Don't get treated as newlines - ?line port_expect(Config,[{lists:append([Packet1, [13], Packet2, + port_expect(Config,[{lists:append([Packet1, [13], Packet2, io_lib:nl()]), [{noeol, Packet1}, {eol, [13 |Packet2]}]}], 0, "", [{line,Siz}]), %% Test that packets get built up to lines (delayed output from %% port program) - ?line port_expect(Config,[{Packet2,[]}, + port_expect(Config,[{Packet2,[]}, {lists:append([Packet2, io_lib:nl(), Packet1, io_lib:nl()]), [{eol, lists:append(Packet2, Packet2)}, {eol, Packet1}]}], 0, "-d", [{line,Siz}]), %% Test that we get badarg if trying both packet and line - ?line bad_argument(Config, [{packet, 5}, {line, 5}]), - ?line test_server:timetrap_cancel(Dog), + bad_argument(Config, [{packet, 5}, {line, 5}]), + test_server:timetrap_cancel(Dog), ok. %%% Redirection of stderr test @@ -834,15 +791,15 @@ stderr_to_stdout(suite) -> stderr_to_stdout(doc) -> "Test that redirection of standard error to standard output works."; stderr_to_stdout(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(60)), + Dog = test_server:timetrap(test_server:seconds(60)), %% See that it works - ?line Packet = random_packet(10), - ?line port_expect(Config,[{Packet,[Packet]}], 0, "-e -l10", + Packet = random_packet(10), + port_expect(Config,[{Packet,[Packet]}], 0, "-e -l10", [stderr_to_stdout]), - %% ?line stream_ping(Config, 10, "-e", [stderr_to_stdout]), + %% stream_ping(Config, 10, "-e", [stderr_to_stdout]), %% See that it doesn't always happen (will generate garbage on stderr) - ?line port_expect(Config,[{Packet,[eof]}], 0, "-e -l10", [line,eof]), - ?line test_server:timetrap_cancel(Dog), + port_expect(Config,[{Packet,[eof]}], 0, "-e -l10", [line,eof]), + test_server:timetrap_cancel(Dog), ok. @@ -862,47 +819,39 @@ env(suite) -> env(doc) -> ["Test that the 'env' option works"]; env(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skipped,"Environments not implemented on VxWorks (could be...)"}; - _ -> - env2(Config) - end. - -env2(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(60)), - ?line Priv = ?config(priv_dir, Config), - ?line Temp = filename:join(Priv, "env_fun.bin"), + Dog = test_server:timetrap(test_server:seconds(60)), + Priv = ?config(priv_dir, Config), + Temp = filename:join(Priv, "env_fun.bin"), PluppVal = "dirty monkey", - ?line env_slave(Temp, [{"plupp",PluppVal}]), + env_slave(Temp, [{"plupp",PluppVal}]), Long = "LongAndBoringEnvName", - ?line os:putenv(Long, "nisse"), - - ?line env_slave(Temp, [{"plupp",PluppVal}, - {"DIR_PLUPP","###glurfrik"}], - fun() -> - PluppVal = os:getenv("plupp"), - "###glurfrik" = os:getenv("DIR_PLUPP"), - "nisse" = os:getenv(Long) - end), + os:putenv(Long, "nisse"), + + env_slave(Temp, [{"plupp",PluppVal}, + {"DIR_PLUPP","###glurfrik"}], + fun() -> + PluppVal = os:getenv("plupp"), + "###glurfrik" = os:getenv("DIR_PLUPP"), + "nisse" = os:getenv(Long) + end), - - ?line env_slave(Temp, [{"must_define_something","some_value"}, - {"certainly_not_existing",false}, - {"ends_with_equal", "value="}, - {Long,false}, - {"glurf","a glorfy string"}]), + + env_slave(Temp, [{"must_define_something","some_value"}, + {"certainly_not_existing",false}, + {"ends_with_equal", "value="}, + {Long,false}, + {"glurf","a glorfy string"}]), %% A lot of non existing variables (mingled with existing) NotExistingList = [{lists:flatten(io_lib:format("V~p_not_existing",[X])),false} || X <- lists:seq(1,150)], ExistingList = [{lists:flatten(io_lib:format("V~p_existing",[X])),"a_value"} || X <- lists:seq(1,150)], - ?line env_slave(Temp, lists:sort(ExistingList ++ NotExistingList)), + env_slave(Temp, lists:sort(ExistingList ++ NotExistingList)), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. env_slave(File, Env) -> @@ -946,23 +895,15 @@ env_slave_main([File]) -> %% 'env' option %% Test bad environments. bad_env(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skipped,"Environments not implemented on VxWorks"}; - _ -> - bad_env_1() - end. - -bad_env_1() -> - ?line try_bad_env([abbb]), - ?line try_bad_env([{"key","value"}|{"another","value"}]), - ?line try_bad_env([{"key","value","value2"}]), - ?line try_bad_env([{"key",[a,b,c]}]), - ?line try_bad_env([{"key",value}]), - ?line try_bad_env({a,tuple}), - ?line try_bad_env(42), - ?line try_bad_env([a|b]), - ?line try_bad_env(self()), + try_bad_env([abbb]), + try_bad_env([{"key","value"}|{"another","value"}]), + try_bad_env([{"key","value","value2"}]), + try_bad_env([{"key",[a,b,c]}]), + try_bad_env([{"key",value}]), + try_bad_env({a,tuple}), + try_bad_env(42), + try_bad_env([a|b]), + try_bad_env(self()), ok. try_bad_env(Env) -> @@ -979,36 +920,29 @@ cd(suite) -> cd(doc) -> ["Test that the 'cd' option works"]; cd(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skipped,"Task specific directories does not exist on VxWorks"}; - _ -> - cd2(Config) - end. -cd2(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(60)), - - ?line Program = atom_to_list(lib:progname()), - ?line DataDir = ?config(data_dir, Config), - ?line TestDir = filename:join(DataDir, "dir"), - ?line Cmd = Program ++ " -pz " ++ DataDir ++ - " -noshell -s port_test pwd -s erlang halt", - ?line _ = open_port({spawn, Cmd}, - [{cd, TestDir}, - {line, 256}]), - ?line receive - {_, {data, {eol, String}}} -> - case filename_equal(String, TestDir) of - true -> - ok; - false -> - ?line test_server:fail({cd, String}) - end; - Other2 -> - ?line test_server:fail({env, Other2}) - end, + Dog = test_server:timetrap(test_server:seconds(60)), - ?line test_server:timetrap_cancel(Dog), + Program = atom_to_list(lib:progname()), + DataDir = ?config(data_dir, Config), + TestDir = filename:join(DataDir, "dir"), + Cmd = Program ++ " -pz " ++ DataDir ++ + " -noshell -s port_test pwd -s erlang halt", + _ = open_port({spawn, Cmd}, + [{cd, TestDir}, + {line, 256}]), + receive + {_, {data, {eol, String}}} -> + case filename_equal(String, TestDir) of + true -> + ok; + false -> + test_server:fail({cd, String}) + end; + Other2 -> + test_server:fail({env, Other2}) + end, + + test_server:timetrap_cancel(Dog), ok. filename_equal(A, B) -> @@ -1059,8 +993,8 @@ otp_3906(Config) when is_list(Config) -> -define(OTP_3906_MAX_CONC_OSP, 50). otp_3906(Config, OSName) -> - ?line DataDir = filename:dirname(proplists:get_value(data_dir,Config)), - ?line {ok, Variables} = file:consult( + DataDir = filename:dirname(proplists:get_value(data_dir,Config)), + {ok, Variables} = file:consult( filename:join([DataDir,"..","..", "test_server","variables"])), case lists:keysearch('CC', 1, Variables) of @@ -1105,7 +1039,7 @@ otp_3906(Config, OSName) -> succeded -> ok; _ -> - ?line test_server:fail(Result) + test_server:fail(Result) end; _ -> {skipped, "No C compiler found"} @@ -1246,15 +1180,15 @@ otp_4389(doc) -> []; otp_4389(Config) when is_list(Config) -> case os:type() of {unix, _} -> - ?line Dog = test_server:timetrap(test_server:seconds(240)), - ?line TCR = self(), + Dog = test_server:timetrap(test_server:seconds(240)), + TCR = self(), case get_true_cmd() of True when is_list(True) -> - ?line lists:foreach( + lists:foreach( fun (P) -> - ?line receive - {P, ok} -> ?line ok; - {P, Err} -> ?line ?t:fail(Err) + receive + {P, ok} -> ok; + {P, Err} -> ?t:fail(Err) end end, lists:map( @@ -1283,14 +1217,14 @@ otp_4389(Config) when is_list(Config) -> end) end, lists:duplicate(1000,[]))), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), {comment, "This test case doesn't always fail when the bug that " "it tests for is present (it is most likely to fail on" " a multi processor machine). If the test case fails it" " will fail by deadlocking the emulator."}; _ -> - ?line {skipped, "\"true\" command not found"} + {skipped, "\"true\" command not found"} end; _ -> {skip,"Only run on Unix"} @@ -1320,11 +1254,11 @@ exit_status(suite) -> exit_status(doc) -> ["Test that the 'exit_status' option works"]; exit_status(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(60)), - ?line port_expect(Config,[{"x", + Dog = test_server:timetrap(test_server:seconds(60)), + port_expect(Config,[{"x", [{exit_status, 5}]}], 1, "", [exit_status]), - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. spawn_driver(suite) -> @@ -1332,36 +1266,36 @@ spawn_driver(suite) -> spawn_driver(doc) -> ["Test spawning a driver specifically"]; spawn_driver(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line Path = ?config(data_dir, Config), - ?line ok = load_driver(Path, "echo_drv"), - ?line Port = erlang:open_port({spawn_driver, "echo_drv"}, []), - ?line Port ! {self(), {command, "Hello port!"}}, - ?line receive + Dog = test_server:timetrap(test_server:seconds(10)), + Path = ?config(data_dir, Config), + ok = load_driver(Path, "echo_drv"), + Port = erlang:open_port({spawn_driver, "echo_drv"}, []), + Port ! {self(), {command, "Hello port!"}}, + receive {Port, {data, "Hello port!"}} = Msg1 -> io:format("~p~n", [Msg1]), ok; Other -> test_server:fail({unexpected, Other}) end, - ?line Port ! {self(), close}, - ?line receive {Port, closed} -> ok end, + Port ! {self(), close}, + receive {Port, closed} -> ok end, - ?line Port2 = erlang:open_port({spawn_driver, "echo_drv -Hello port?"}, + Port2 = erlang:open_port({spawn_driver, "echo_drv -Hello port?"}, []), - ?line receive + receive {Port2, {data, "Hello port?"}} = Msg2 -> io:format("~p~n", [Msg2]), ok; Other2 -> test_server:fail({unexpected2, Other2}) end, - ?line Port2 ! {self(), close}, - ?line receive {Port2, closed} -> ok end, - ?line {'EXIT',{badarg,_}} = (catch erlang:open_port({spawn_driver, "ls"}, [])), - ?line {'EXIT',{badarg,_}} = (catch erlang:open_port({spawn_driver, "cmd"}, [])), - ?line {'EXIT',{badarg,_}} = (catch erlang:open_port({spawn_driver, os:find_executable("erl")}, [])), - ?line test_server:timetrap_cancel(Dog), + Port2 ! {self(), close}, + receive {Port2, closed} -> ok end, + {'EXIT',{badarg,_}} = (catch erlang:open_port({spawn_driver, "ls"}, [])), + {'EXIT',{badarg,_}} = (catch erlang:open_port({spawn_driver, "cmd"}, [])), + {'EXIT',{badarg,_}} = (catch erlang:open_port({spawn_driver, os:find_executable("erl")}, [])), + test_server:timetrap_cancel(Dog), ok. spawn_executable(suite) -> @@ -1369,48 +1303,48 @@ spawn_executable(suite) -> spawn_executable(doc) -> ["Test spawning an executable specifically"]; spawn_executable(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line DataDir = ?config(data_dir, Config), - ?line EchoArgs1 = filename:join([DataDir,"echo_args"]), - ?line ExactFile1 = filename:nativename(os:find_executable(EchoArgs1)), - ?line [ExactFile1] = run_echo_args(DataDir,[]), - ?line ["echo_args"] = run_echo_args(DataDir,["echo_args"]), - ?line ["echo_arguments"] = run_echo_args(DataDir,["echo_arguments"]), - ?line [ExactFile1,"hello world","dlrow olleh"] = + Dog = test_server:timetrap(test_server:seconds(10)), + DataDir = ?config(data_dir, Config), + EchoArgs1 = filename:join([DataDir,"echo_args"]), + ExactFile1 = filename:nativename(os:find_executable(EchoArgs1)), + [ExactFile1] = run_echo_args(DataDir,[]), + ["echo_args"] = run_echo_args(DataDir,["echo_args"]), + ["echo_arguments"] = run_echo_args(DataDir,["echo_arguments"]), + [ExactFile1,"hello world","dlrow olleh"] = run_echo_args(DataDir,[ExactFile1,"hello world","dlrow olleh"]), - ?line [ExactFile1] = run_echo_args(DataDir,[default]), - ?line [ExactFile1,"hello world","dlrow olleh"] = + [ExactFile1] = run_echo_args(DataDir,[default]), + [ExactFile1,"hello world","dlrow olleh"] = run_echo_args(DataDir,[switch_order,ExactFile1,"hello world", "dlrow olleh"]), - ?line [ExactFile1,"hello world","dlrow olleh"] = + [ExactFile1,"hello world","dlrow olleh"] = run_echo_args(DataDir,[default,"hello world","dlrow olleh"]), - ?line [ExactFile1,"hello world","dlrow olleh"] = + [ExactFile1,"hello world","dlrow olleh"] = run_echo_args_2("\""++ExactFile1++"\" "++"\"hello world\" \"dlrow olleh\""), - ?line PrivDir = ?config(priv_dir, Config), - ?line SpaceDir =filename:join([PrivDir,"With Spaces"]), - ?line file:make_dir(SpaceDir), - ?line Executable = filename:basename(ExactFile1), - ?line file:copy(ExactFile1,filename:join([SpaceDir,Executable])), - ?line ExactFile2 = filename:nativename(filename:join([SpaceDir,Executable])), - ?line chmodplusx(ExactFile2), + PrivDir = ?config(priv_dir, Config), + SpaceDir =filename:join([PrivDir,"With Spaces"]), + file:make_dir(SpaceDir), + Executable = filename:basename(ExactFile1), + file:copy(ExactFile1,filename:join([SpaceDir,Executable])), + ExactFile2 = filename:nativename(filename:join([SpaceDir,Executable])), + chmodplusx(ExactFile2), io:format("|~s|~n",[ExactFile2]), - ?line [ExactFile2] = run_echo_args(SpaceDir,[]), - ?line ["echo_args"] = run_echo_args(SpaceDir,["echo_args"]), - ?line ["echo_arguments"] = run_echo_args(SpaceDir,["echo_arguments"]), - ?line [ExactFile2,"hello world","dlrow olleh"] = + [ExactFile2] = run_echo_args(SpaceDir,[]), + ["echo_args"] = run_echo_args(SpaceDir,["echo_args"]), + ["echo_arguments"] = run_echo_args(SpaceDir,["echo_arguments"]), + [ExactFile2,"hello world","dlrow olleh"] = run_echo_args(SpaceDir,[ExactFile2,"hello world","dlrow olleh"]), - ?line [ExactFile2] = run_echo_args(SpaceDir,[default]), - ?line [ExactFile2,"hello world","dlrow olleh"] = + [ExactFile2] = run_echo_args(SpaceDir,[default]), + [ExactFile2,"hello world","dlrow olleh"] = run_echo_args(SpaceDir,[switch_order,ExactFile2,"hello world", "dlrow olleh"]), - ?line [ExactFile2,"hello world","dlrow olleh"] = + [ExactFile2,"hello world","dlrow olleh"] = run_echo_args(SpaceDir,[default,"hello world","dlrow olleh"]), - ?line [ExactFile2,"hello world","dlrow olleh"] = + [ExactFile2,"hello world","dlrow olleh"] = run_echo_args_2("\""++ExactFile2++"\" "++"\"hello world\" \"dlrow olleh\""), - ?line ExeExt = + ExeExt = case string:to_lower(lists:last(string:tokens(ExactFile2,"."))) of "exe" -> ".exe"; @@ -1418,47 +1352,47 @@ spawn_executable(Config) when is_list(Config) -> "" end, Executable2 = "spoky name"++ExeExt, - ?line file:copy(ExactFile1,filename:join([SpaceDir,Executable2])), - ?line ExactFile3 = filename:nativename(filename:join([SpaceDir,Executable2])), - ?line chmodplusx(ExactFile3), - ?line [ExactFile3] = run_echo_args(SpaceDir,Executable2,[]), - ?line ["echo_args"] = run_echo_args(SpaceDir,Executable2,["echo_args"]), - ?line ["echo_arguments"] = run_echo_args(SpaceDir,Executable2,["echo_arguments"]), - ?line [ExactFile3,"hello world","dlrow olleh"] = + file:copy(ExactFile1,filename:join([SpaceDir,Executable2])), + ExactFile3 = filename:nativename(filename:join([SpaceDir,Executable2])), + chmodplusx(ExactFile3), + [ExactFile3] = run_echo_args(SpaceDir,Executable2,[]), + ["echo_args"] = run_echo_args(SpaceDir,Executable2,["echo_args"]), + ["echo_arguments"] = run_echo_args(SpaceDir,Executable2,["echo_arguments"]), + [ExactFile3,"hello world","dlrow olleh"] = run_echo_args(SpaceDir,Executable2,[ExactFile3,"hello world","dlrow olleh"]), - ?line [ExactFile3] = run_echo_args(SpaceDir,Executable2,[default]), - ?line [ExactFile3,"hello world","dlrow olleh"] = + [ExactFile3] = run_echo_args(SpaceDir,Executable2,[default]), + [ExactFile3,"hello world","dlrow olleh"] = run_echo_args(SpaceDir,Executable2, [switch_order,ExactFile3,"hello world", "dlrow olleh"]), - ?line [ExactFile3,"hello world","dlrow olleh"] = + [ExactFile3,"hello world","dlrow olleh"] = run_echo_args(SpaceDir,Executable2, [default,"hello world","dlrow olleh"]), - ?line [ExactFile3,"hello world","dlrow olleh"] = + [ExactFile3,"hello world","dlrow olleh"] = run_echo_args_2("\""++ExactFile3++"\" "++"\"hello world\" \"dlrow olleh\""), - ?line {'EXIT',{enoent,_}} = (catch run_echo_args(SpaceDir,"fnurflmonfi", + {'EXIT',{enoent,_}} = (catch run_echo_args(SpaceDir,"fnurflmonfi", [default,"hello world", "dlrow olleh"])), NonExec = "kronxfrt"++ExeExt, - ?line file:write_file(filename:join([SpaceDir,NonExec]), + file:write_file(filename:join([SpaceDir,NonExec]), <<"Not an executable">>), - ?line {'EXIT',{eacces,_}} = (catch run_echo_args(SpaceDir,NonExec, + {'EXIT',{eacces,_}} = (catch run_echo_args(SpaceDir,NonExec, [default,"hello world", "dlrow olleh"])), - ?line {'EXIT',{enoent,_}} = (catch open_port({spawn_executable,"cmd"},[])), - ?line {'EXIT',{enoent,_}} = (catch open_port({spawn_executable,"sh"},[])), + {'EXIT',{enoent,_}} = (catch open_port({spawn_executable,"cmd"},[])), + {'EXIT',{enoent,_}} = (catch open_port({spawn_executable,"sh"},[])), case os:type() of {win32,_} -> test_bat_file(SpaceDir); {unix,_} -> test_sh_file(SpaceDir) end, - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. unregister_name(Config) when is_list(Config) -> - ?line true = register(crash, open_port({spawn, "sleep 100"}, [])), - ?line true = unregister(crash). + true = register(crash, open_port({spawn, "sleep 100"}, [])), + true = unregister(crash). test_bat_file(Dir) -> FN = "tf.bat", @@ -1478,16 +1412,16 @@ test_bat_file(Dir) -> <<"\r\n">>, <<":done\r\n">>, <<"\r\n">>], - ?line file:write_file(Full,list_to_binary(D)), - ?line EF = filename:basename(FN), - ?line [DN,"hello","world"] = + file:write_file(Full,list_to_binary(D)), + EF = filename:basename(FN), + [DN,"hello","world"] = run_echo_args(Dir,FN, [default,"hello","world"]), %% The arg0 argumant should be ignored when running batch files - ?line [DN,"hello","world"] = + [DN,"hello","world"] = run_echo_args(Dir,FN, ["knaskurt","hello","world"]), - ?line EF = filename:basename(DN), + EF = filename:basename(DN), ok. test_sh_file(Dir) -> @@ -1501,20 +1435,20 @@ test_sh_file(Dir) -> <<" shift\n">>, <<" i=`expr $i + 1`\n">>, <<"done\n">>], - ?line file:write_file(Full,list_to_binary(D)), - ?line chmodplusx(Full), - ?line [Full,"hello","world"] = + file:write_file(Full,list_to_binary(D)), + chmodplusx(Full), + [Full,"hello","world"] = run_echo_args(Dir,FN, [default,"hello","world"]), - ?line [Full,"hello","world of spaces"] = + [Full,"hello","world of spaces"] = run_echo_args(Dir,FN, [default,"hello","world of spaces"]), - ?line file:write_file(filename:join([Dir,"testfile1"]),<<"testdata1">>), - ?line file:write_file(filename:join([Dir,"testfile2"]),<<"testdata2">>), - ?line Pattern = filename:join([Dir,"testfile*"]), - ?line L = filelib:wildcard(Pattern), - ?line 2 = length(L), - ?line [Full,"hello",Pattern] = + file:write_file(filename:join([Dir,"testfile1"]),<<"testdata1">>), + file:write_file(filename:join([Dir,"testfile2"]),<<"testdata2">>), + Pattern = filename:join([Dir,"testfile*"]), + L = filelib:wildcard(Pattern), + 2 = length(L), + [Full,"hello",Pattern] = run_echo_args(Dir,FN, [default,"hello",Pattern]), ok. @@ -1574,25 +1508,25 @@ mix_up_ports(suite) -> mix_up_ports(doc) -> ["Test that the emulator does not mix up ports when the port table wraps"]; mix_up_ports(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line Path = ?config(data_dir, Config), - ?line ok = load_driver(Path, "echo_drv"), - ?line Port = erlang:open_port({spawn, "echo_drv"}, []), - ?line Port ! {self(), {command, "Hello port!"}}, - ?line receive + Dog = test_server:timetrap(test_server:seconds(10)), + Path = ?config(data_dir, Config), + ok = load_driver(Path, "echo_drv"), + Port = erlang:open_port({spawn, "echo_drv"}, []), + Port ! {self(), {command, "Hello port!"}}, + receive {Port, {data, "Hello port!"}} = Msg1 -> io:format("~p~n", [Msg1]), ok; Other -> test_server:fail({unexpected, Other}) end, - ?line Port ! {self(), close}, - ?line receive {Port, closed} -> ok end, - ?line loop(start, done, + Port ! {self(), close}, + receive {Port, closed} -> ok end, + loop(start, done, fun(P) -> - ?line Q = + Q = (catch erlang:open_port({spawn, "echo_drv"}, [])), -%% ?line io:format("~p ", [Q]), +%% io:format("~p ", [Q]), if is_port(Q) -> Q; true -> @@ -1600,14 +1534,14 @@ mix_up_ports(Config) when is_list(Config) -> done end end), - ?line Port ! {self(), {command, "Hello again port!"}}, - ?line receive + Port ! {self(), {command, "Hello again port!"}}, + receive Msg2 -> test_server:fail({unexpected, Msg2}) after 1000 -> ok end, - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. loop(Stop, Stop, Fun) when is_function(Fun) -> @@ -1622,45 +1556,45 @@ otp_5112(doc) -> ["Test that link to connected process is taken away when port calls", "driver_exit() also when the port index has wrapped"]; otp_5112(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line Path = ?config(data_dir, Config), - ?line ok = load_driver(Path, "exit_drv"), - ?line Port = otp_5112_get_wrapped_port(), - ?line ?t:format("Max ports: ~p~n",[max_ports()]), - ?line ?t:format("Port: ~p~n",[Port]), - ?line {links, Links1} = process_info(self(),links), - ?line ?t:format("Links1: ~p~n",[Links1]), - ?line true = lists:member(Port, Links1), - ?line Port ! {self(), {command, ""}}, - ?line {links, Links2} = process_info(self(),links), - ?line ?t:format("Links2: ~p~n",[Links2]), - ?line false = lists:member(Port, Links2), %% This used to fail - ?line test_server:timetrap_cancel(Dog), + Dog = test_server:timetrap(test_server:seconds(10)), + Path = ?config(data_dir, Config), + ok = load_driver(Path, "exit_drv"), + Port = otp_5112_get_wrapped_port(), + ?t:format("Max ports: ~p~n",[max_ports()]), + ?t:format("Port: ~p~n",[Port]), + {links, Links1} = process_info(self(),links), + ?t:format("Links1: ~p~n",[Links1]), + true = lists:member(Port, Links1), + Port ! {self(), {command, ""}}, + {links, Links2} = process_info(self(),links), + ?t:format("Links2: ~p~n",[Links2]), + false = lists:member(Port, Links2), %% This used to fail + test_server:timetrap_cancel(Dog), ok. otp_5112_get_wrapped_port() -> - ?line P1 = erlang:open_port({spawn, "exit_drv"}, []), - ?line case port_ix(P1) < max_ports() of + P1 = erlang:open_port({spawn, "exit_drv"}, []), + case port_ix(P1) < max_ports() of true -> - ?line ?t:format("Need to wrap port index (~p)~n", [P1]), - ?line otp_5112_wrap_port_ix([P1]), - ?line P2 = erlang:open_port({spawn, "exit_drv"}, []), - ?line false = port_ix(P2) < max_ports(), - ?line P2; + ?t:format("Need to wrap port index (~p)~n", [P1]), + otp_5112_wrap_port_ix([P1]), + P2 = erlang:open_port({spawn, "exit_drv"}, []), + false = port_ix(P2) < max_ports(), + P2; false -> - ?line ?t:format("Port index already wrapped (~p)~n", [P1]), - ?line P1 + ?t:format("Port index already wrapped (~p)~n", [P1]), + P1 end. otp_5112_wrap_port_ix(Ports) -> - ?line case (catch erlang:open_port({spawn, "exit_drv"}, [])) of + case (catch erlang:open_port({spawn, "exit_drv"}, [])) of Port when is_port(Port) -> - ?line otp_5112_wrap_port_ix([Port|Ports]); + otp_5112_wrap_port_ix([Port|Ports]); _ -> %% Port table now full; empty port table - ?line lists:foreach(fun (P) -> P ! {self(), close} end, + lists:foreach(fun (P) -> P ! {self(), close} end, Ports), - ?line ok + ok end. @@ -1669,106 +1603,105 @@ otp_5119(suite) -> otp_5119(doc) -> ["Test that port index is not unnecessarily wrapped"]; otp_5119(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line Path = ?config(data_dir, Config), - ?line ok = load_driver(Path, "exit_drv"), - ?line PI1 = port_ix(otp_5119_fill_empty_port_tab([])), - ?line PI2 = port_ix(erlang:open_port({spawn, "exit_drv"}, [])), - ?line {PortIx1, PortIx2} - = case PI2 > PI1 of - true -> - ?line {PI1, PI2}; - false -> - ?line {port_ix(otp_5119_fill_empty_port_tab([PI2])), - port_ix(erlang:open_port({spawn, "exit_drv"}, []))} - end, - ?line MaxPorts = max_ports(), - ?line ?t:format("PortIx1 = ~p ~p~n", [PI1, PortIx1]), - ?line ?t:format("PortIx2 = ~p ~p~n", [PI2, PortIx2]), - ?line ?t:format("MaxPorts = ~p~n", [MaxPorts]), - ?line true = PortIx2 > PortIx1, - ?line true = PortIx2 =< PortIx1 + MaxPorts, - ?line test_server:timetrap_cancel(Dog), - ?line ok. + Dog = test_server:timetrap(test_server:seconds(10)), + Path = ?config(data_dir, Config), + ok = load_driver(Path, "exit_drv"), + PI1 = port_ix(otp_5119_fill_empty_port_tab([])), + PI2 = port_ix(erlang:open_port({spawn, "exit_drv"}, [])), + {PortIx1, PortIx2} = case PI2 > PI1 of + true -> + {PI1, PI2}; + false -> + {port_ix(otp_5119_fill_empty_port_tab([PI2])), + port_ix(erlang:open_port({spawn, "exit_drv"}, []))} + end, + MaxPorts = max_ports(), + ?t:format("PortIx1 = ~p ~p~n", [PI1, PortIx1]), + ?t:format("PortIx2 = ~p ~p~n", [PI2, PortIx2]), + ?t:format("MaxPorts = ~p~n", [MaxPorts]), + true = PortIx2 > PortIx1, + true = PortIx2 =< PortIx1 + MaxPorts, + test_server:timetrap_cancel(Dog), + ok. otp_5119_fill_empty_port_tab(Ports) -> - ?line case (catch erlang:open_port({spawn, "exit_drv"}, [])) of + case (catch erlang:open_port({spawn, "exit_drv"}, [])) of Port when is_port(Port) -> - ?line otp_5119_fill_empty_port_tab([Port|Ports]); + otp_5119_fill_empty_port_tab([Port|Ports]); _ -> %% Port table now full; empty port table - ?line lists:foreach(fun (P) -> P ! {self(), close} end, + lists:foreach(fun (P) -> P ! {self(), close} end, Ports), - ?line [LastPort|_] = Ports, - ?line LastPort + [LastPort|_] = Ports, + LastPort end. -define(DEF_MAX_PORTS, 1024). max_ports_env() -> - ?line case os:getenv("ERL_MAX_PORTS") of + case os:getenv("ERL_MAX_PORTS") of EMP when is_list(EMP) -> case catch list_to_integer(EMP) of - Int when is_integer(Int) -> ?line Int; - _ -> ?line false + Int when is_integer(Int) -> Int; + _ -> false end; - _ -> ?line false + _ -> false end. max_ports() -> - ?line PreMaxPorts + PreMaxPorts = case max_ports_env() of - Env when is_integer(Env) -> ?line Env; + Env when is_integer(Env) -> Env; _ -> - ?line case os:type() of + case os:type() of {unix, _} -> - ?line UlimStr = string:strip(os:cmd("ulimit -n") + UlimStr = string:strip(os:cmd("ulimit -n") -- "\n"), - ?line case catch list_to_integer(UlimStr) of - Ulim when is_integer(Ulim) -> ?line Ulim; - _ -> ?line ?DEF_MAX_PORTS + case catch list_to_integer(UlimStr) of + Ulim when is_integer(Ulim) -> Ulim; + _ -> ?DEF_MAX_PORTS end; - _ -> ?line ?DEF_MAX_PORTS + _ -> ?DEF_MAX_PORTS end end, - ?line case PreMaxPorts > ?DEF_MAX_PORTS of - true -> ?line PreMaxPorts; - false -> ?line ?DEF_MAX_PORTS + case PreMaxPorts > ?DEF_MAX_PORTS of + true -> PreMaxPorts; + false -> ?DEF_MAX_PORTS end. port_ix(Port) when is_port(Port) -> - ?line ["#Port",_,PortIxStr] = string:tokens(erlang:port_to_list(Port), + ["#Port",_,PortIxStr] = string:tokens(erlang:port_to_list(Port), "<.>"), - ?line list_to_integer(PortIxStr). + list_to_integer(PortIxStr). otp_6224(doc) -> ["Check that port command failure doesn't crash the emulator"]; otp_6224(suite) -> []; otp_6224(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line Path = ?config(data_dir, Config), - ?line ok = load_driver(Path, "failure_drv"), - ?line Go = make_ref(), - ?line Failer = spawn(fun () -> + Dog = test_server:timetrap(test_server:seconds(10)), + Path = ?config(data_dir, Config), + ok = load_driver(Path, "failure_drv"), + Go = make_ref(), + Failer = spawn(fun () -> receive Go -> ok end, - ?line Port = open_port({spawn, "failure_drv"}, + Port = open_port({spawn, "failure_drv"}, []), Port ! {self(), {command, "Fail, please!"}}, otp_6224_loop() end), - ?line Mon = erlang:monitor(process, Failer), - ?line Failer ! Go, - ?line receive + Mon = erlang:monitor(process, Failer), + Failer ! Go, + receive {'DOWN', Mon, process, Failer, Reason} -> - ?line case Reason of - {driver_failed, _} -> ?line ok; - driver_failed -> ?line ok; - _ -> ?line ?t:fail({unexpected_exit_reason, + case Reason of + {driver_failed, _} -> ok; + driver_failed -> ok; + _ -> ?t:fail({unexpected_exit_reason, Reason}) end end, - ?line test_server:timetrap_cancel(Dog), - ?line ok. + test_server:timetrap_cancel(Dog), + ok. otp_6224_loop() -> receive _ -> ok after 0 -> ok end, @@ -1781,11 +1714,11 @@ otp_6224_loop() -> exit_status_multi_scheduling_block(doc) -> []; exit_status_multi_scheduling_block(suite) -> []; exit_status_multi_scheduling_block(Config) when is_list(Config) -> - ?line Repeat = 3, - ?line case ?t:os_type() of + Repeat = 3, + case ?t:os_type() of {unix, _} -> - ?line Dog = ?t:timetrap(test_server:minutes(2*Repeat)), - ?line SleepSecs = 6, + Dog = ?t:timetrap(test_server:minutes(2*Repeat)), + SleepSecs = 6, try lists:foreach(fun (_) -> exit_status_msb_test(Config, @@ -1799,7 +1732,7 @@ exit_status_multi_scheduling_block(Config) when is_list(Config) -> ?t:timetrap_cancel(Dog), receive after SleepSecs+500 -> ok end end; - _ -> ?line {skip, "Not implemented for this OS"} + _ -> {skip, "Not implemented for this OS"} end. exit_status_msb_test(Config, SleepSecs) when is_list(Config) -> @@ -1808,22 +1741,22 @@ exit_status_msb_test(Config, SleepSecs) when is_list(Config) -> %% and we want these port programs to terminate while multi-scheduling %% is blocked. %% - ?line NoSchedsOnln = erlang:system_info(schedulers_online), - ?line Parent = self(), - ?line ?t:format("SleepSecs = ~p~n", [SleepSecs]), - ?line PortProg = "sleep " ++ integer_to_list(SleepSecs), - ?line Start = now(), - ?line NoProcs = case NoSchedsOnln of + NoSchedsOnln = erlang:system_info(schedulers_online), + Parent = self(), + ?t:format("SleepSecs = ~p~n", [SleepSecs]), + PortProg = "sleep " ++ integer_to_list(SleepSecs), + Start = now(), + NoProcs = case NoSchedsOnln of NProcs when NProcs < ?EXIT_STATUS_MSB_MAX_PROCS -> NProcs; _ -> ?EXIT_STATUS_MSB_MAX_PROCS end, - ?line NoPortsPerProc = case 20*NoProcs of + NoPortsPerProc = case 20*NoProcs of TNPorts when TNPorts < ?EXIT_STATUS_MSB_MAX_PORTS -> 20; _ -> ?EXIT_STATUS_MSB_MAX_PORTS div NoProcs end, - ?line ?t:format("NoProcs = ~p~nNoPortsPerProc = ~p~n", + ?t:format("NoProcs = ~p~nNoPortsPerProc = ~p~n", [NoProcs, NoPortsPerProc]), ProcFun = fun () -> @@ -1873,32 +1806,32 @@ exit_status_msb_test(Config, SleepSecs) when is_list(Config) -> PrtSIds), Parent ! {self(), done} end, - ?line Procs = lists:map(fun (N) -> + Procs = lists:map(fun (N) -> spawn_opt(ProcFun, [link, {scheduler, (N rem NoSchedsOnln)+1}]) end, lists:seq(1, NoProcs)), - ?line SIds = lists:map(fun (P) -> + SIds = lists:map(fun (P) -> receive {P, started, SIds} -> SIds end end, Procs), - ?line StartedTime = timer:now_diff(now(), Start)/1000000, - ?line ?t:format("StartedTime = ~p~n", [StartedTime]), - ?line true = StartedTime < SleepSecs, - ?line erlang:system_flag(multi_scheduling, block), - ?line lists:foreach(fun (P) -> receive {P, done} -> ok end end, Procs), - ?line DoneTime = timer:now_diff(now(), Start)/1000000, - ?line ?t:format("DoneTime = ~p~n", [DoneTime]), - ?line true = DoneTime > SleepSecs, - ?line ok = verify_multi_scheduling_blocked(), - ?line erlang:system_flag(multi_scheduling, unblock), - ?line case {length(lists:usort(lists:flatten(SIds))), NoSchedsOnln} of + StartedTime = timer:now_diff(now(), Start)/1000000, + ?t:format("StartedTime = ~p~n", [StartedTime]), + true = StartedTime < SleepSecs, + erlang:system_flag(multi_scheduling, block), + lists:foreach(fun (P) -> receive {P, done} -> ok end end, Procs), + DoneTime = timer:now_diff(now(), Start)/1000000, + ?t:format("DoneTime = ~p~n", [DoneTime]), + true = DoneTime > SleepSecs, + ok = verify_multi_scheduling_blocked(), + erlang:system_flag(multi_scheduling, unblock), + case {length(lists:usort(lists:flatten(SIds))), NoSchedsOnln} of {N, N} -> - ?line ok; + ok; {N, M} -> - ?line ?t:fail("Failed to create ports on all" + ?t:fail("Failed to create ports on all" ++ integer_to_list(M) ++ " available" "schedulers. Only created ports on " ++ integer_to_list(N) ++ " schedulers.") @@ -1921,18 +1854,18 @@ sid_proc(SIds) -> end. verify_multi_scheduling_blocked() -> - ?line Procs = lists:map(fun (_) -> + Procs = lists:map(fun (_) -> spawn_link(fun () -> sid_proc([]) end) end, lists:seq(1, 3*erlang:system_info(schedulers_online))), - ?line receive after 1000 -> ok end, - ?line SIds = lists:map(fun (P) -> + receive after 1000 -> ok end, + SIds = lists:map(fun (P) -> P ! {self(), want_sids}, receive {P, sids, PSIds} -> PSIds end end, Procs), - ?line 1 = length(lists:usort(lists:flatten(SIds))), - ?line ok. + 1 = length(lists:usort(lists:flatten(SIds))), + ok. %%% Pinging functions. @@ -1993,30 +1926,30 @@ build_cmd_line(FixedCmdLine, [], Result) -> port_expect(Config, Actions, HSize, CmdLine, Options0) -> % io:format("port_expect(~p, ~p, ~p, ~p)", % [Actions, HSize, CmdLine, Options0]), - ?line PortTest = port_test(Config), - ?line Cmd = lists:concat([PortTest, " -h", HSize, " ", CmdLine]), - ?line PortType = + PortTest = port_test(Config), + Cmd = lists:concat([PortTest, " -h", HSize, " ", CmdLine]), + PortType = case HSize of 0 -> stream; _ -> {packet, HSize} end, - ?line Options = [PortType|Options0], - ?line io:format("open_port({spawn, ~p}, ~p)", [Cmd, Options]), - ?line Port = open_port({spawn, Cmd}, Options), - ?line port_expect(Port, Actions, Options), + Options = [PortType|Options0], + io:format("open_port({spawn, ~p}, ~p)", [Cmd, Options]), + Port = open_port({spawn, Cmd}, Options), + port_expect(Port, Actions, Options), Port. port_expect(Port, [{Send, Expects}|Rest], Options) when is_list(Expects) -> - ?line port_send(Port, Send), - ?line IsBinaryPort = lists:member(binary, Options), - ?line Receiver = + port_send(Port, Send), + IsBinaryPort = lists:member(binary, Options), + Receiver = case {lists:member(stream, Options), line_option(Options)} of {false, _} -> fun receive_all/2; {true,false} -> fun stream_receive_all/2; {_, true} -> fun receive_all/2 end, - ?line Receiver(Port, maybe_to_binary(Expects, IsBinaryPort)), - ?line port_expect(Port, Rest, Options); + Receiver(Port, maybe_to_binary(Expects, IsBinaryPort)), + port_expect(Port, Rest, Options); port_expect(_, [], _) -> ok. @@ -2068,7 +2001,7 @@ receive_all(Port, [Expect|Rest]) -> _ -> %%% io:format("Unexpected message: ~s", [format(Other)]), io:format("Unexpected message: ~w", [Other]), - ?line test_server:fail(unexpected_message) + test_server:fail(unexpected_message) end end, receive_all(Port, Rest); @@ -2157,15 +2090,8 @@ build_packet(Left, Result, NextChar0) -> build_packet(Left-1, [NextChar0|Result], NextChar). sizes() -> - case os:type() of - vxworks -> - % don't stress VxWorks too much - [10, 13, 64, 127, 128, 255, 256, 1023, 1024, - 8191, 8192, 16383, 16384]; - _ -> - [10, 13, 64, 127, 128, 255, 256, 1023, 1024, - 32767, 32768, 65535, 65536] - end. + [10, 13, 64, 127, 128, 255, 256, 1023, 1024, + 32767, 32768, 65535, 65536]. sizes(Header_Size) -> sizes(Header_Size, sizes(), []). @@ -2203,18 +2129,18 @@ fun_spawn(Fun, Args) -> spawn_link(erlang, apply, [Fun, Args]). port_test(Config) when is_list(Config) -> - ?line filename:join(?config(data_dir, Config), "port_test"). + filename:join(?config(data_dir, Config), "port_test"). ports(doc) -> "Test that erlang:ports/0 returns a consistent snapshot of ports"; ports(suite) -> []; ports(Config) when is_list(Config) -> - ?line Path = ?config(data_dir, Config), - ?line ok = load_driver(Path, "exit_drv"), + Path = ?config(data_dir, Config), + ok = load_driver(Path, "exit_drv"), receive after 1000 -> ok end, % Wait for other ports to stabilize - ?line OtherPorts = erlang:ports(), + OtherPorts = erlang:ports(), io:format("Other ports: ~p\n",[OtherPorts]), MaxPorts = 1024 - length(OtherPorts), @@ -2222,7 +2148,7 @@ ports(Config) when is_list(Config) -> ports_snapshots(100, TrafficPid, OtherPorts), TrafficPid ! {self(),die}, - ?line receive {TrafficPid, dead} -> ok end, + receive {TrafficPid, dead} -> ok end, ok. ports_snapshots(0, _, _) -> @@ -2230,12 +2156,12 @@ ports_snapshots(0, _, _) -> ports_snapshots(Iter, TrafficPid, OtherPorts) -> TrafficPid ! start, - ?line receive after 1 -> ok end, + receive after 1 -> ok end, Snapshot = erlang:ports(), TrafficPid ! {self(), stop}, - ?line receive {TrafficPid, EventList, TrafficPorts} -> ok end, + receive {TrafficPid, EventList, TrafficPorts} -> ok end, %%io:format("Snapshot=~p\n", [Snapshot]), ports_verify(Snapshot, OtherPorts ++ TrafficPorts, EventList), @@ -2252,7 +2178,7 @@ ports_traffic_stopped(MaxPorts, {PortList, PortCnt}) -> %%io:format("Traffic started in ~p\n",[self()]), ports_traffic_started(MaxPorts, {PortList, PortCnt}, []); {Pid,die} -> - ?line lists:foreach(fun(Port)-> erlang:port_close(Port) end, + lists:foreach(fun(Port)-> erlang:port_close(Port) end, PortList), Pid ! {self(),dead} end. @@ -2272,15 +2198,15 @@ ports_traffic_do(MaxPorts, {PortList, PortCnt}, EventList) -> N = uniform(MaxPorts), case N > PortCnt of true -> % Open port - ?line P = open_port({spawn, "exit_drv"}, []), + P = open_port({spawn, "exit_drv"}, []), %%io:format("Created port ~p\n",[P]), ports_traffic_started(MaxPorts, {[P|PortList], PortCnt+1}, [{open,P}|EventList]); false -> % Close port - ?line P = lists:nth(N, PortList), + P = lists:nth(N, PortList), %%io:format("Close port ~p\n",[P]), - ?line true = erlang:port_close(P), + true = erlang:port_close(P), ports_traffic_started(MaxPorts, {lists:delete(P,PortList), PortCnt-1}, [{close,P}|EventList]) end. @@ -2301,7 +2227,7 @@ ports_verify(Ports, PortsAfter, EventList) -> ports_verify(Ports, [P | PortsAfter], Tail); [] -> - ?line test_server:fail("Inconsistent snapshot from erlang:ports()") + test_server:fail("Inconsistent snapshot from erlang:ports()") end end. @@ -2318,27 +2244,27 @@ close_deaf_port(doc) -> ["Send data to port program that does not read it, then "Primary targeting Windows to test threaded_handle_closer in sys.c"]; close_deaf_port(suite) -> []; close_deaf_port(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(100)), - ?line DataDir = ?config(data_dir, Config), - ?line DeadPort = os:find_executable("dead_port", DataDir), - ?line Port = open_port({spawn,DeadPort++" 60"},[]), - ?line erlang:port_command(Port,"Hello, can you hear me!?!?"), - ?line port_close(Port), + Dog = test_server:timetrap(test_server:seconds(100)), + DataDir = ?config(data_dir, Config), + DeadPort = os:find_executable("dead_port", DataDir), + Port = open_port({spawn,DeadPort++" 60"},[]), + erlang:port_command(Port,"Hello, can you hear me!?!?"), + port_close(Port), Res = close_deaf_port_1(0, DeadPort), io:format("Waiting for OS procs to terminate...\n"), receive after 5*1000 -> ok end, - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), Res. close_deaf_port_1(1000, _) -> ok; close_deaf_port_1(N, Cmd) -> Timeout = integer_to_list(random:uniform(5*1000)), - ?line try open_port({spawn_executable,Cmd},[{args,[Timeout]}]) of + try open_port({spawn_executable,Cmd},[{args,[Timeout]}]) of Port -> - ?line erlang:port_command(Port,"Hello, can you hear me!?!?"), - ?line port_close(Port), + erlang:port_command(Port,"Hello, can you hear me!?!?"), + port_close(Port), close_deaf_port_1(N+1, Cmd) catch _:eagain -> diff --git a/erts/emulator/test/port_SUITE_data/dead_port.c b/erts/emulator/test/port_SUITE_data/dead_port.c index 68e96fbf14..4dd9ee4cc2 100644 --- a/erts/emulator/test/port_SUITE_data/dead_port.c +++ b/erts/emulator/test/port_SUITE_data/dead_port.c @@ -17,15 +17,6 @@ * %CopyrightEnd% */ -#ifdef VXWORKS -#include <vxWorks.h> -#include <taskVarLib.h> -#include <taskLib.h> -#include <sysLib.h> -#include <string.h> -#include <ioLib.h> -#endif - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -37,12 +28,7 @@ #ifndef __WIN32__ #include <unistd.h> -#ifdef VXWORKS -#include "reclaim.h" -#include <sys/times.h> -#else #include <sys/time.h> -#endif #define O_BINARY 0 #define _setmode(fd, mode) @@ -53,13 +39,7 @@ #include "winbase.h" #endif - -#ifdef VXWORKS -#define MAIN(argc, argv) port_test(argc, argv) -#else #define MAIN(argc, argv) main(argc, argv) -#endif - extern int errno; @@ -86,9 +66,6 @@ char *argv[]; static void delay(unsigned ms) { -#ifdef VXWORKS - taskDelay((sysClkRateGet() * ms) / 1000); -#else #ifdef __WIN32__ Sleep(ms); #else @@ -98,5 +75,4 @@ delay(unsigned ms) select(0, NULL, NULL, NULL, &t); #endif -#endif } diff --git a/erts/emulator/test/port_SUITE_data/port_test.c b/erts/emulator/test/port_SUITE_data/port_test.c index 7b4e386d87..7abefab2e3 100644 --- a/erts/emulator/test/port_SUITE_data/port_test.c +++ b/erts/emulator/test/port_SUITE_data/port_test.c @@ -3,15 +3,6 @@ * Purpose: A port program to be used for testing the open_port bif. */ -#ifdef VXWORKS -#include <vxWorks.h> -#include <taskVarLib.h> -#include <taskLib.h> -#include <sysLib.h> -#include <string.h> -#include <ioLib.h> -#endif - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -23,12 +14,7 @@ #ifndef __WIN32__ #include <unistd.h> -#ifdef VXWORKS -#include "reclaim.h" -#include <sys/times.h> -#else #include <sys/time.h> -#endif #define O_BINARY 0 #define _setmode(fd, mode) @@ -40,22 +26,13 @@ #endif -#ifdef VXWORKS -#define REDIR_STDOUT(fd) ioTaskStdSet(0, 1, fd); -#else #define REDIR_STDOUT(fd) if (dup2(fd, 1) == -1) { \ fprintf(stderr, "%s: failed to duplicate handle %d to 1: %d\n", \ port_data->progname, fd, errno); \ exit(1); \ } -#endif -#ifdef VXWORKS -#define MAIN(argc, argv) port_test(argc, argv) -#else #define MAIN(argc, argv) main(argc, argv) -#endif - extern int errno; @@ -101,7 +78,6 @@ static void dump(unsigned char* buf, int sz, int max); static void replace_stdout(char* filename); static void generate_reply(char* spec); -#ifndef VXWORKS #ifndef HAVE_STRERROR extern int sys_nerr; #ifndef sys_errlist /* sys_errlist is sometimes defined to @@ -125,7 +101,6 @@ int err; return msgstr; } #endif -#endif MAIN(argc, argv) @@ -133,12 +108,6 @@ int argc; char *argv[]; { int ret; -#ifdef VXWORKS - if(taskVarAdd(0, (int *)&port_data) != OK) { - fprintf(stderr, "Can't do taskVarAdd in port_test\n"); - exit(1); - } -#endif if((port_data = (PORT_TEST_DATA *) malloc(sizeof(PORT_TEST_DATA))) == NULL) { fprintf(stderr, "Couldn't malloc for port_data"); exit(1); @@ -511,9 +480,6 @@ dump(buf, sz, max) static void delay(unsigned ms) { -#ifdef VXWORKS - taskDelay((sysClkRateGet() * ms) / 1000); -#else #ifdef __WIN32__ Sleep(ms); #else @@ -523,7 +489,6 @@ delay(unsigned ms) select(0, NULL, NULL, NULL, &t); #endif -#endif } /* diff --git a/erts/emulator/test/port_SUITE_data/reclaim.h b/erts/emulator/test/port_SUITE_data/reclaim.h deleted file mode 100644 index 1d57dc5b8a..0000000000 --- a/erts/emulator/test/port_SUITE_data/reclaim.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __RECLAIM_H__ -#define __RECLAIM_H__ - - -/* The Erlang release for VxWorks includes a simple mechanism for - "resource reclamation" at task exit - it allows replacement of the - functions that open/close "files" and malloc/free memory with versions - that keep track, to be able to "reclaim" file descriptors and memory - when a task exits (regardless of *how* it exits). - - The interface to this mechanism is made available via this file, - with the following caveats: - - - The interface may change (or perhaps even be removed, though that - isn't likely until VxWorks itself provides similar functionality) - in future releases - i.e. you must always use the version of this - file that comes with the Erlang release you are using. - - - Disaster is guaranteed if you use the mechanism incorrectly (see - below for the correct way), e.g. allocate memory with the "tracking" - version of malloc() and free it with the "standard" version of free(). - - - The mechanism (of course) incurs some performance penalty - thus - for a simple program you may be better off with careful programming, - making sure that you do whatever close()/free()/etc calls that are - appropriate at all exit points (though if you need to guard against - taskDelete() etc, things get messy...). - - To use the mechanism, simply program your application normally, i.e. - use open()/close()/malloc()/free() etc as usual, but #include this - file before any usage of the relevant functions. NOTE: To avoid the - "disaster" mentioned above, you *must* #include it in *all* (or none) - of the files that manipulate a particular file descriptor, allocated - memory area, etc. Finally, note that you can obviously not load your - application before the Erlang system when using this interface. -*/ - -/* Sorry, no ANSI prototypes yet... */ -extern int save_open(),save_creat(),save_socket(),save_accept(),save_close(); -#define open save_open -#define creat save_creat -#define socket save_socket -#define accept save_accept -#define close save_close -extern FILE *save_fopen(), *save_fdopen(), *save_freopen(); -extern int save_fclose(); -#define fopen save_fopen -#define fdopen save_fdopen -#define freopen save_freopen -#define fclose save_fclose -/* XXX Should do opendir/closedir too... */ -extern char *save_malloc(), *save_calloc(), *save_realloc(); -extern void save_free(), save_cfree(); -#define malloc save_malloc -#define calloc save_calloc -#define realloc save_realloc -#define free save_free -#define cfree save_cfree - -#endif diff --git a/erts/emulator/test/port_bif_SUITE_data/port_test.c b/erts/emulator/test/port_bif_SUITE_data/port_test.c index c6b128df66..28324a56a6 100644 --- a/erts/emulator/test/port_bif_SUITE_data/port_test.c +++ b/erts/emulator/test/port_bif_SUITE_data/port_test.c @@ -3,15 +3,6 @@ * Purpose: A port program to be used for testing the open_port bif. */ -#ifdef VXWORKS -#include <vxWorks.h> -#include <taskVarLib.h> -#include <taskLib.h> -#include <sysLib.h> -#include <string.h> -#include <ioLib.h> -#endif - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -23,12 +14,7 @@ #ifndef __WIN32__ #include <unistd.h> -#ifdef VXWORKS -#include "reclaim.h" -#include <sys/times.h> -#else #include <sys/time.h> -#endif #define O_BINARY 0 #define _setmode(fd, mode) @@ -40,22 +26,13 @@ #endif -#ifdef VXWORKS -#define REDIR_STDOUT(fd) ioTaskStdSet(0, 1, fd); -#else #define REDIR_STDOUT(fd) if (dup2(fd, 1) == -1) { \ fprintf(stderr, "%s: failed to duplicate handle %d to 1: %d\n", \ port_data->progname, fd, errno); \ exit(1); \ } -#endif -#ifdef VXWORKS -#define MAIN(argc, argv) port_test(argc, argv) -#else #define MAIN(argc, argv) main(argc, argv) -#endif - extern int errno; @@ -101,7 +78,6 @@ static void dump(unsigned char* buf, int sz, int max); static void replace_stdout(char* filename); static void generate_reply(char* spec); -#ifndef VXWORKS #ifndef HAVE_STRERROR extern int sys_nerr; #ifndef sys_errlist /* sys_errlist is sometimes defined to @@ -125,20 +101,13 @@ int err; return msgstr; } #endif -#endif - MAIN(argc, argv) int argc; char *argv[]; { int ret; -#ifdef VXWORKS - if(taskVarAdd(0, (int *)&port_data) != OK) { - fprintf(stderr, "Can't do taskVarAdd in port_test\n"); - exit(1); - } -#endif + if((port_data = (PORT_TEST_DATA *) malloc(sizeof(PORT_TEST_DATA))) == NULL) { fprintf(stderr, "Couldn't malloc for port_data"); exit(1); @@ -508,9 +477,6 @@ dump(buf, sz, max) static void delay(unsigned ms) { -#ifdef VXWORKS - taskDelay((sysClkRateGet() * ms) / 1000); -#else #ifdef __WIN32__ Sleep(ms); #else @@ -520,7 +486,6 @@ delay(unsigned ms) select(0, NULL, NULL, NULL, &t); #endif -#endif } /* diff --git a/erts/emulator/test/port_bif_SUITE_data/reclaim.h b/erts/emulator/test/port_bif_SUITE_data/reclaim.h deleted file mode 100644 index 1d57dc5b8a..0000000000 --- a/erts/emulator/test/port_bif_SUITE_data/reclaim.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __RECLAIM_H__ -#define __RECLAIM_H__ - - -/* The Erlang release for VxWorks includes a simple mechanism for - "resource reclamation" at task exit - it allows replacement of the - functions that open/close "files" and malloc/free memory with versions - that keep track, to be able to "reclaim" file descriptors and memory - when a task exits (regardless of *how* it exits). - - The interface to this mechanism is made available via this file, - with the following caveats: - - - The interface may change (or perhaps even be removed, though that - isn't likely until VxWorks itself provides similar functionality) - in future releases - i.e. you must always use the version of this - file that comes with the Erlang release you are using. - - - Disaster is guaranteed if you use the mechanism incorrectly (see - below for the correct way), e.g. allocate memory with the "tracking" - version of malloc() and free it with the "standard" version of free(). - - - The mechanism (of course) incurs some performance penalty - thus - for a simple program you may be better off with careful programming, - making sure that you do whatever close()/free()/etc calls that are - appropriate at all exit points (though if you need to guard against - taskDelete() etc, things get messy...). - - To use the mechanism, simply program your application normally, i.e. - use open()/close()/malloc()/free() etc as usual, but #include this - file before any usage of the relevant functions. NOTE: To avoid the - "disaster" mentioned above, you *must* #include it in *all* (or none) - of the files that manipulate a particular file descriptor, allocated - memory area, etc. Finally, note that you can obviously not load your - application before the Erlang system when using this interface. -*/ - -/* Sorry, no ANSI prototypes yet... */ -extern int save_open(),save_creat(),save_socket(),save_accept(),save_close(); -#define open save_open -#define creat save_creat -#define socket save_socket -#define accept save_accept -#define close save_close -extern FILE *save_fopen(), *save_fdopen(), *save_freopen(); -extern int save_fclose(); -#define fopen save_fopen -#define fdopen save_fdopen -#define freopen save_freopen -#define fclose save_fclose -/* XXX Should do opendir/closedir too... */ -extern char *save_malloc(), *save_calloc(), *save_realloc(); -extern void save_free(), save_cfree(); -#define malloc save_malloc -#define calloc save_calloc -#define realloc save_realloc -#define free save_free -#define cfree save_cfree - -#endif diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index fdc55a4cc5..6509871a7d 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -280,15 +280,7 @@ kb_128() -> big_binary()}. eight_kb() -> - %%% This is really much more than eight kb, so vxworks platforms - %%% gets away with 1/8 of the other platforms (due to limited - %%% memory resources). - B64 = case os:type() of - vxworks -> - ?line lists:seq(1, 8); - _ -> - ?line lists:seq(1, 64) - end, + B64 = lists:seq(1, 64), ?line B512 = {<<1>>,B64,<<2,3>>,B64,make_unaligned_sub_binary(<<4,5,6,7,8,9>>), B64,make_sub_binary([1,2,3,4,5,6]), B64,make_sub_binary(lists:seq(1, ?heap_binary_size+1)), diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl index 7ff7449ff5..c9533d0748 100644 --- a/erts/emulator/test/timer_bif_SUITE.erl +++ b/erts/emulator/test/timer_bif_SUITE.erl @@ -71,38 +71,23 @@ end_per_group(_GroupName, Config) -> start_timer_1(doc) -> ["Basic start_timer/3 functionality"]; start_timer_1(Config) when is_list(Config) -> - ?line Ref1 = erlang:start_timer(1000, self(), plopp), - ?line ok = get(1100, {timeout, Ref1, plopp}), - - ?line false = erlang:read_timer(Ref1), - ?line false = erlang:cancel_timer(Ref1), - ?line false = erlang:read_timer(Ref1), - - ?line Ref2 = erlang:start_timer(1000, self(), plapp), - ?line Left2 = erlang:cancel_timer(Ref2), - UpperLimit = case os:type() of - vxworks -> - %% The ticks of vxworks have a far lesser granularity - %% than what is expected in this testcase, in - %% fact the Left2 variable can get a little more than 1000... - 1100; - _ -> - 1000 - end, - ?line RetVal = case os:type() of - vxworks -> - {comment, "VxWorks behaves slightly unexpected, should be fixed,"}; - _ -> - ok - end, - ?line true = (Left2 > 900) and (Left2 =< UpperLimit), - ?line empty = get_msg(), - ?line false = erlang:cancel_timer(Ref2), - - ?line Ref3 = erlang:start_timer(1000, self(), plopp), - ?line no_message = get(900, {timeout, Ref3, plopp}), - - RetVal. + Ref1 = erlang:start_timer(1000, self(), plopp), + ok = get(1100, {timeout, Ref1, plopp}), + + false = erlang:read_timer(Ref1), + false = erlang:cancel_timer(Ref1), + false = erlang:read_timer(Ref1), + + Ref2 = erlang:start_timer(1000, self(), plapp), + Left2 = erlang:cancel_timer(Ref2), + UpperLimit = 1000, + true = (Left2 > 900) and (Left2 =< UpperLimit), + empty = get_msg(), + false = erlang:cancel_timer(Ref2), + + Ref3 = erlang:start_timer(1000, self(), plopp), + no_message = get(900, {timeout, Ref3, plopp}), + ok. send_after_1(doc) -> ["Basic send_after/3 functionality"]; send_after_1(Config) when is_list(Config) -> @@ -153,19 +138,11 @@ send_after_2(Config) when is_list(Config) -> send_after_3(doc) -> ["send_after/3: messages in the right order, worse than send_after_2"]; send_after_3(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skipped, "VxWorks timer granularity and order is not working good, this is subject to change!"}; - _ -> - do_send_after_3() - end. - -do_send_after_3() -> - ?line _ = erlang:send_after(100, self(), b1), - ?line _ = erlang:send_after(101, self(), b2), - ?line _ = erlang:send_after(102, self(), b3), - ?line _ = erlang:send_after(103, self(), last), - ?line [b1, b2, b3, last] = collect(last), + _ = erlang:send_after(100, self(), b1), + _ = erlang:send_after(101, self(), b2), + _ = erlang:send_after(102, self(), b3), + _ = erlang:send_after(103, self(), last), + [b1, b2, b3, last] = collect(last), % This behaviour is not guaranteed: % ?line _ = erlang:send_after(100, self(), c1), diff --git a/erts/emulator/test/trace_local_SUITE.erl b/erts/emulator/test/trace_local_SUITE.erl index 32e2a98e3c..54f8cc3c30 100644 --- a/erts/emulator/test/trace_local_SUITE.erl +++ b/erts/emulator/test/trace_local_SUITE.erl @@ -80,6 +80,7 @@ config(priv_dir,_) -> exception_meta_nocatch/1, exception_meta_nocatch_apply/1, exception_meta_nocatch_function/1, exception_meta_nocatch_apply_function/1, + concurrency/1, init_per_testcase/2, end_per_testcase/2]). init_per_testcase(_Case, Config) -> ?line Dog=test_server:timetrap(test_server:minutes(2)), @@ -89,7 +90,15 @@ end_per_testcase(_Case, Config) -> shutdown(), Dog=?config(watchdog, Config), test_server:timetrap_cancel(Dog), - ok. + + %% Reloading the module will clear all trace patterns, and + %% in a debug-compiled emulator run assertions of the counters + %% for the number of functions with breakpoints. + + c:l(?MODULE). + + + suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -106,7 +115,8 @@ all() -> exception_meta_apply_function, exception_meta_nocatch, exception_meta_nocatch_apply, exception_meta_nocatch_function, - exception_meta_nocatch_apply_function] + exception_meta_nocatch_apply_function, + concurrency] end. groups() -> @@ -350,7 +360,8 @@ same(A, B) -> basic_test() -> ?line setup([call]), - ?line erlang:trace_pattern({?MODULE,'_','_'},[],[local]), + NumMatches = erlang:trace_pattern({?MODULE,'_','_'},[],[local]), + NumMatches = erlang:trace_pattern({?MODULE,'_','_'},[],[local]), ?line erlang:trace_pattern({?MODULE,slave,'_'},false,[local]), ?line [1,1,1,1] = apply_slave(?MODULE,exported_wrap,[1]), ?line ?CT(?MODULE,exported_wrap,[1]), @@ -703,16 +714,10 @@ exception_test(Opts) -> ?line ok. exceptions() -> - ?line Ref = make_ref(), - ?line N = case os:type() of - vxworks -> - ?line 2000; % Limited memory on themachines, not actually - % VxWorks' fault /PaN - _ -> - ?line 200000 - end, - ?line LiL = seq(1, N-1, N), % Long Improper List - ?line LL = seq(1, N, []), % Long List + Ref = make_ref(), + N = 200000, + LiL = seq(1, N-1, N), % Long Improper List + LL = seq(1, N, []), % Long List [{{erlang,exit}, [done]}, {{erlang,error}, [1.0]}, {{erlang,error}, [Ref,[]]}, @@ -813,6 +818,42 @@ clean_location({crash,{Reason,Stk0}}) -> {crash,{Reason,Stk}}; clean_location(Term) -> Term. +concurrency(_Config) -> + N = erlang:system_info(schedulers), + + %% Spawn 2*N processes that spin in a tight infinite loop, + %% and one process that will turn on and off local call + %% trace on the infinite_loop/0 function. We expect the + %% emulator to crash if there is a memory barrier bug or + %% if an aligned word-sized write is not atomic. + + Ps0 = [spawn_monitor(fun() -> infinite_loop() end) || + _ <- lists:seq(1, 2*N)], + OnAndOff = fun() -> concurrency_on_and_off() end, + Ps1 = [spawn_monitor(OnAndOff)|Ps0], + ?t:sleep(1000), + + %% Now spawn off N more processes that turn on off and off + %% a local trace pattern. + Ps = [spawn_monitor(OnAndOff) || _ <- lists:seq(1, N)] ++ Ps1, + ?t:sleep(1000), + + %% Clean up. + [exit(Pid, kill) || {Pid,_} <- Ps], + [receive + {'DOWN',Ref,process,Pid,killed} -> ok + end || {Pid,Ref} <- Ps], + erlang:trace_pattern({?MODULE,infinite_loop,0}, false, [local]), + ok. + +concurrency_on_and_off() -> + 1 = erlang:trace_pattern({?MODULE,infinite_loop,0}, true, [local]), + 1 = erlang:trace_pattern({?MODULE,infinite_loop,0}, false, [local]), + concurrency_on_and_off(). + +infinite_loop() -> + infinite_loop(). + %%% Tracee target functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% diff --git a/erts/emulator/test/trace_port_SUITE.erl b/erts/emulator/test/trace_port_SUITE.erl index f81cab3114..cc2eadafbc 100644 --- a/erts/emulator/test/trace_port_SUITE.erl +++ b/erts/emulator/test/trace_port_SUITE.erl @@ -472,14 +472,9 @@ default_tracer(Config) when is_list(Config) -> ?line M = N, ok. - %%% Help functions. -huge_data() -> - case os:type() of - vxworks -> huge_data(4711); - _ -> huge_data(16384) - end. +huge_data() -> huge_data(16384). huge_data(0) -> []; huge_data(N) when N rem 2 == 0 -> P = huge_data(N div 2), diff --git a/erts/emulator/utils/make_tables b/erts/emulator/utils/make_tables index 91efb4c023..a841f26d6a 100755 --- a/erts/emulator/utils/make_tables +++ b/erts/emulator/utils/make_tables @@ -167,7 +167,6 @@ typedef struct bif_entry { extern BifEntry bif_table[]; extern Export* bif_export[]; -extern unsigned char erts_bif_trace_flags[]; #define BIF_SIZE $bif_size @@ -197,7 +196,6 @@ includes("export.h", "sys.h", "erl_vm.h", "erl_process.h", "bif.h", "erl_bif_table.h", "erl_atom_table.h"); print "\nExport* bif_export[BIF_SIZE];\n"; -print "unsigned char erts_bif_trace_flags[BIF_SIZE];\n\n"; print "BifEntry bif_table[] = {\n"; for ($i = 0; $i < @bif; $i++) { diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in index b10f5d9a87..0e128fda12 100644 --- a/erts/etc/common/Makefile.in +++ b/erts/etc/common/Makefile.in @@ -33,11 +33,7 @@ else ifeq ($(TYPE),purify) PURIFY = purify TYPEMARKER = -ifeq ($(findstring ose,$(TARGET)),ose) -TYPE_FLAGS = -g -XO -DPURIFY -else TYPE_FLAGS = -g -O2 -DPURIFY -endif else override TYPE=opt @@ -77,25 +73,15 @@ EMUDIR = $(ERL_TOP)/erts/emulator/beam EMUOSDIR = $(ERL_TOP)/erts/emulator/@ERLANG_OSTYPE@ SYSDIR = $(ERL_TOP)/erts/emulator/sys/@ERLANG_OSTYPE@ DRVDIR = $(ERL_TOP)/erts/emulator/drivers/@ERLANG_OSTYPE@ -VXETC = ../vxworks UXETC = ../unix OSEETC = ../ose WINETC = ../win32 -ifeq ($(findstring vxworks,$(TARGET)), vxworks) -ERLEXEC = erl.exec -else -ifeq ($(findstring ose,$(TARGET)), ose) -ERLEXEC = -TAR = @TAR@ -else ifeq ($(TARGET), win32) ERLEXEC = erlexec.dll else ERLEXEC = erlexec endif -endif -endif # On windows we always need reentrant libraries. ifeq ($(TARGET),win32) @@ -110,42 +96,6 @@ ERTS_LIB = $(ERL_TOP)/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE # Release directory specification # ---------------------------------------------------- -ifeq ($(findstring vxworks,$(TARGET)), vxworks) -INSTALL_EMBEDDED_PROGS = $(BINDIR)/erl_io $(BINDIR)/rdate $(BINDIR)/vxcall -INSTALL_EMBEDDED_DATA = $(BINDIR)/erl_script.sam $(VXETC)/resolv.conf -INSTALL_INCLUDES = $(VXETC)/reclaim.h -INSTALL_TOP = $(VXETC)/README.VxWorks -INSTALL_MISC = -INSTALL_SRC = heart.c $(VXETC)/heart_config.h $(VXETC)/heart_config.c \ - $(VXETC)/erl.exec.c $(VXETC)/rdate.c $(VXETC)/vxcall.c \ - $(VXETC)/erl_io.c -ERLEXECDIR = $(VXETC) -INSTALL_LIBS = $(OBJDIR)/reclaim.o -INSTALL_OBJS = $(OBJDIR)/heart.o -TEXTFILES = $(BINDIR)/erl_script.sam -ERLSRV_OBJECTS= -MC_OUTPUTS= -ENTRY_LDFLAGS= -ENTRY_OBJ= -INSTALL_PROGS = \ - $(INET_GETHOST) \ - $(BINDIR)/heart \ - $(BINDIR)/$(ERLEXEC) \ - $(INSTALL_EMBEDDED_PROGS) -else -ifeq ($(findstring ose,$(TARGET)), ose) -INSTALL_TOP = $(OSEETC)/README.OSE -INSTALL_ERL_OSE = monolith lm erl_utils drivers port_progs host -INSTALL_SRC = -INSTALL_LIBS = -INSTALL_OBJS = -INSTALL_INCLUDES = -INSTALL_PROGS = -ERLSRV_OBJECTS= -MC_OUTPUTS= -ENTRY_LDFLAGS= -ENTRY_OBJ= -else ifeq ($(TARGET),win32) CFLAGS += -I$(EMUOSDIR) -I$(WINETC) RC=rc.sh @@ -207,7 +157,7 @@ endif PORT_ENTRY_POINT=erl_port_entry ENTRY_LDFLAGS=-entry:$(PORT_ENTRY_POINT) -else +else # UNIX (!win32) ENTRY_LDFLAGS= ENTRY_OBJ= ERLSRV_OBJECTS= @@ -232,8 +182,6 @@ INSTALL_PROGS = \ $(BINDIR)/$(ERLEXEC) \ $(INSTALL_EMBEDDED_PROGS) endif -endif -endif .PHONY: etc etc: $(ENTRY_OBJ) $(INSTALL_PROGS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN) @@ -396,24 +344,6 @@ endif # End of windows specific targets. #--------------------------------------------------------- -ifeq ($(findstring vxworks,$(TARGET)), vxworks) -$(BINDIR)/heart: $(OBJDIR)/heart.o $(OBJDIR)/heart_config.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/heart.o $(OBJDIR)/heart_config.o - -$(OBJDIR)/heart_config.o: $(VXETC)/heart_config.c - $(CC) $(CFLAGS) -o $@ -c $(VXETC)/heart_config.c - -$(OBJDIR)/reclaim.o: $(VXETC)/reclaim.c - $(CC) $(CFLAGS) -o $@ -c $(VXETC)/reclaim.c - -$(OBJDIR)/heart.o: heart.c - $(CC) $(CFLAGS) -I$(VXETC) -o $@ -c heart.c - -$(BINDIR)/erl_script.sam: $(VXETC)/erl_script.sam.in ../../vsn.mk - sed -e 's;%VSN%;$(VSN);' \ - $(VXETC)/erl_script.sam.in > $(BINDIR)/erl_script.sam -else - $(BINDIR)/heart@EXEEXT@: $(OBJDIR)/heart.o $(ENTRY_OBJ) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/heart.o \ $(ENTRY_OBJ) $(WINDSOCK) @@ -421,31 +351,6 @@ $(BINDIR)/heart@EXEEXT@: $(OBJDIR)/heart.o $(ENTRY_OBJ) $(OBJDIR)/heart.o: heart.c $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c heart.c -endif - - -# VxWorks specific executables and objects ... - -$(BINDIR)/erl_io: $(OBJDIR)/erl_io.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erl_io.o - -$(OBJDIR)/erl_io.o: $(VXETC)/erl_io.c - $(CC) $(CFLAGS) -o $@ -c $(VXETC)/erl_io.c - -$(BINDIR)/rdate: $(OBJDIR)/rdate.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/rdate.o - -$(OBJDIR)/rdate.o: $(VXETC)/rdate.c - $(CC) $(CFLAGS) -o $@ -c $(VXETC)/rdate.c - -$(BINDIR)/vxcall: $(OBJDIR)/vxcall.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/vxcall.o - -$(OBJDIR)/vxcall.o: $(VXETC)/vxcall.c - $(CC) $(CFLAGS) -o $@ -c $(VXETC)/vxcall.c - - - # # Objects & executables # diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index 755e308219..6ac77e4e63 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -66,8 +66,7 @@ * input and output file descriptors (0 and 1). These descriptors * (and the standard error descriptor 2) must NOT be closed * explicitely by this program at termination (in UNIX it is - * taken care of by the operating system itself; in VxWorks - * it is taken care of by the spawn driver part of the Emulator). + * taken care of by the operating system itself). * * END OF FILE * @@ -75,12 +74,6 @@ * that there is no process at the other end of the connection * having the connection open for writing (end-of-file). * - * HARDWARE WATCHDOG - * - * When used with VxWorks(with CPU40), the hardware - * watchdog is enabled, making sure that the system reboots - * even if the heart port program malfunctions or the system - * is completely overloaded. */ #ifdef HAVE_CONFIG_H @@ -93,9 +86,6 @@ #include <fcntl.h> #include <process.h> #endif -#ifdef VXWORKS -#include "sys.h" -#endif /* * Implement time correction using times() call even on Linuxes @@ -116,19 +106,7 @@ #include <time.h> #include <errno.h> -#ifdef VXWORKS -# include <vxWorks.h> -# include <ioLib.h> -# include <selectLib.h> -# include <netinet/in.h> -# include <rebootLib.h> -# include <sysLib.h> -# include <taskLib.h> -# include <wdLib.h> -# include <taskHookLib.h> -# include <selectLib.h> -#endif -#if !defined(__WIN32__) && !defined(VXWORKS) +#if !defined(__WIN32__) # include <sys/types.h> # include <netinet/in.h> # include <sys/time.h> @@ -550,8 +528,7 @@ kill_old_erlang(void){ CloseHandle(erlh); } } -#elif !defined(VXWORKS) -/* Unix eh? */ +#else static void kill_old_erlang(void){ pid_t pid; @@ -570,7 +547,7 @@ kill_old_erlang(void){ } } } -#endif /* Not on VxWorks */ +#endif #ifdef __WIN32__ void win_system(char *command) @@ -653,7 +630,7 @@ do_terminate(reason) case R_ERROR: case R_CLOSED: default: -#if defined(__WIN32__) /* Not VxWorks */ +#if defined(__WIN32__) { if(!cmd[0]) { char *command = get_env(HEART_COMMAND_ENV); @@ -1026,59 +1003,6 @@ time_t timestamp(time_t *res) return r; } -#elif defined(VXWORKS) - -static WDOG_ID watchdog_id; -static volatile unsigned elapsed; -static WIND_TCB *this_task; -/* A simple variable is enough to lock the time update, as the - watchdog is run at interrupt level and never preempted. */ -static volatile int lock_time; - -static void my_delete_hook(WIND_TCB *tcb) -{ - if (tcb == this_task) { - wdDelete(watchdog_id); - watchdog_id = NULL; - taskDeleteHookDelete((FUNCPTR) &my_delete_hook); - } -} - -static void my_wd_routine(int count) -{ - if (watchdog_id != NULL) { - ++count; - if (!lock_time) { - elapsed += count; - count = 0; - } - wdStart(watchdog_id, sysClkRateGet(), - (FUNCPTR) &my_wd_routine, count); - } -} - -void init_timestamp(void) -{ - lock_time = 0; - elapsed = 0; - watchdog_id = wdCreate(); - this_task = (WIND_TCB *) taskIdSelf(); - taskDeleteHookAdd((FUNCPTR) &my_delete_hook); - wdStart(watchdog_id, sysClkRateGet(), - (FUNCPTR) &my_wd_routine, 0); -} - -time_t timestamp(time_t *res) -{ - time_t r; - ++lock_time; - r = (time_t) elapsed; - --lock_time; - if (res != NULL) - *res = r; - return r; -} - #elif defined(HAVE_GETHRTIME) void init_timestamp(void) diff --git a/erts/etc/unix/etp-commands b/erts/etc/unix/etp-commands index 1c886620bb..d98505c0ff 100644 --- a/erts/etc/unix/etp-commands +++ b/erts/etc/unix/etp-commands @@ -1022,16 +1022,17 @@ define etp-cp-1 # Non-reentrant # set $etp_cp = (Eterm)($arg0) - set $etp_cp_low = modules - set $etp_cp_high = $etp_cp_low + num_loaded_modules - set $etp_cp_mid = mid_module + set $etp_ranges = &r[(int)the_active_code_index] + set $etp_cp_low = $etp_ranges->modules + set $etp_cp_high = $etp_cp_low + $etp_ranges->n + set $etp_cp_mid = (Range*)$etp_ranges->mid set $etp_cp_p = 0 # while $etp_cp_low < $etp_cp_high if $etp_cp < $etp_cp_mid->start set $etp_cp_high = $etp_cp_mid else - if $etp_cp > $etp_cp_mid->end + if $etp_cp > (BeamInstr*)$etp_cp_mid->end set $etp_cp_low = $etp_cp_mid + 1 else set $etp_cp_p = $etp_cp_low = $etp_cp_high = $etp_cp_mid @@ -1263,7 +1264,684 @@ document etpf-stackdump %--------------------------------------------------------------------------- end +define etp-pix2proc +# Args: Eterm +# + set $proc = (Process *) *((UWord *) &erts_proc.tab[((int) $arg0)]) + printf "(Process *) %p\n", $proc +end + +define etp-pid2proc-1 +# Args: Eterm +# + set $pix = (int) ($arg0 >> 4) + + if (erts_proc.pix_cl_mask != 0) + set $proc = (Process *) *((UWord *) &erts_proc.tab[(((($pix) & erts_proc.pix_cl_mask) << erts_proc.pix_cl_shift) + ((($pix) >> erts_proc.pix_cli_shift) & erts_proc.pix_cli_mask))]) + else + set $proc =(Process *) *((UWord *) &erts_proc.tab[((($pix) % erts_proc.max) % erts_proc.tab_cache_lines + (($pix) % erts_proc.max) / erts_proc.tab_cache_lines)]) + end +end + +define etp-pid2proc +# Args: Eterm +# + etp-pid2proc-1 $arg0 + printf "(Process *) %p\n", $proc +end + +define etp-proc-state-int +# Args: int +# + if ($arg0 & 0xfffff000) + printf "GARBAGE | " + end + if ($arg0 & 0x800) + printf "trapping-exit | " + end + if ($arg0 & 0x400) + printf "bound | " + end + if ($arg0 & 0x200) + printf "garbage-collecting | " + end + if ($arg0 & 0x100) + printf "suspended | " + end + if ($arg0 & 0x80) + printf "running | " + end + if ($arg0 & 0x40) + printf "in-run-queue | " + end + if ($arg0 & 0x20) + printf "active | " + end + if ($arg0 & 0x10) + printf "pending-exit | " + end + if ($arg0 & 0x8) + printf "exiting | " + end + if ($arg0 & 0x4) + printf "free | " + end + if ($arg0 & 0x3) == 0 + printf "prio-max\n" + else + if ($arg0 & 0x3) == 1 + printf "prio-high\n" + else + if ($arg0 & 0x3) == 2 + printf "prio-normal\n" + else + printf "prio-low\n" + end + end + end +end + +document etp-proc-state-int +%--------------------------------------------------------------------------- +% etp-proc-state-int int +% +% Print state of process state value +%--------------------------------------------------------------------------- +end + + +define etp-proc-state +# Args: Process* +# + set $state_int = *(((Uint32 *) &(((Process *) $arg0)->state))) + etp-proc-state-int $state_int +end + +document etp-proc-state +%--------------------------------------------------------------------------- +% etp-proc-state Process* +% +% Print state of process +%--------------------------------------------------------------------------- +end + +define etp-process-info +# Args: Process* +# + printf " Pid: " + etp-1 $arg0->id + printf "\n State: " + etp-proc-state $arg0 + if ($arg0->reg) + printf " Registered name: " + etp-1 $arg0->reg->name + printf "\n" + end + if ($arg0->current) + printf " Current function: " + etp-1 $arg0->current[0] + printf ":" + etp-1 $arg0->current[1] + printf "/%d\n", $arg0->current[2] + end + if ($arg0->cp) + printf " CP: " + etp-cp-1 $arg0->cp + printf "\n" + end + if ($arg0->i) + printf " I: " + etp-cp-1 $arg0->i + printf "\n" + end + printf " Heap size: %ld\n", $arg0->heap_sz + if ($arg0->old_heap) + printf " Old-heap size: %ld\n", $arg0->old_hend - $arg0->old_heap + end + printf " Mbuf size: %ld\n", $arg0->mbuf_sz + if (etp_smp_compiled) + printf " Msgq len: %ld (inner=%ld, outer=%ld)\n", ($arg0->msg.len + $arg0->u.alive.msg_inq.len), $arg0->msg.len, $arg0->u.alive.msg_inq.len + else + printf " Msgq len: %d\n", $arg0->msg.len + end + printf " Parent: " + etp-1 $arg0->parent + printf "\n Pointer: (Process *) %p\n", $arg0 +end + +document etp-process-info +%--------------------------------------------------------------------------- +% etp-process-info Process* +% +% Print info about process +%--------------------------------------------------------------------------- +end + +define etp-processes + if (!erts_initialized) + printf "No processes, since system isn't initialized!\n" + else + set $proc_ix = 0 + while $proc_ix < erts_proc.max + set $proc = (Process *) *((UWord *) &erts_proc.tab[$proc_ix]) + if ($proc != (Process *) 0) + printf "---\n" + printf " Pix: %d\n", $proc_ix + etp-process-info $proc + end + set $proc_ix++ + end + printf "---\n", + end +end + +document etp-processes +%--------------------------------------------------------------------------- +% etp-processes +% +% Print misc info about all processes +%--------------------------------------------------------------------------- +end + + +define etp-port-status-int +# Args: int +# + if ($arg0 & 0x1) + printf " connected" + end + if ($arg0 & 0x2) + printf " exiting" + end + if ($arg0 & 0x4) + printf " distribution" + end + if ($arg0 & 0x8) + printf " binary-io" + end + if ($arg0 & 0x10) + printf " soft-eof" + end + if ($arg0 & 0x20) + printf " port-busy" + end + if ($arg0 & 0x40) + printf " closing" + end + if ($arg0 & 0x80) + printf " send-closed" + end + if ($arg0 & 0x100) + printf " linebuf-io" + end + if ($arg0 & 0x200) + printf " immortal" + end + if ($arg0 & 0x400) + printf " free" + end + if ($arg0 & 0x800) + printf " free-scheduled" + end + if ($arg0 & 0x1000) + printf " initializing" + end + if ($arg0 & 0x2000) + printf " port-specific-lock" + end + if ($arg0 & 0x4000) + printf " invalid" + end + if (etp_debug_compiled) + if ($arg0 & 0x7fff8000) + printf " GARBAGE" + end + else + if ($arg0 & 0xffff8000) + printf " GARBAGE" + end + end + printf "\n" +end + +document etp-port-status-int +%--------------------------------------------------------------------------- +% etp-proc-state-int int +% +% Print port status +%--------------------------------------------------------------------------- +end + + +define etp-port-status +# Args: Port* +# + set $status_int = *(((Uint32 *) &(((Port *) $arg0)->status))) + etp-port-status-int $status_int +end + +document etp-port-status +%--------------------------------------------------------------------------- +% etp-proc-state-int Port * +% +% Print port status +%--------------------------------------------------------------------------- +end + +define etp-port-info +# Args: Port* +# + printf " Port: " + etp-1 $arg0->id + printf "\n Name: %s\n", $arg0->name + printf " Status:" + etp-port-status $arg0 + if ($arg0->reg) + printf " Registered name: " + etp-1 $arg0->reg->name + printf "\n" + end + printf " Connected: " + etp-1 $arg0->connected + printf "\n Pointer: (Port *) %p\n", $arg0 +end + +document etp-port-info +%--------------------------------------------------------------------------- +% etp-port-info Port* +% +% Print info about port +%--------------------------------------------------------------------------- +end + + +define etp-ports + if (!erts_initialized) + printf "No ports, since system isn't initialized!\n" + else + set $port_ix = 0 + while $port_ix < erts_max_ports + set $port = &erts_port[$port_ix] + if ($port->status & 0x400) == 0 + # I.e, not free + printf "---\n" + printf " Pix: %d\n", $port_ix + etp-port-info $port + end + set $port_ix++ + end + printf "---\n", + end +end + +document etp-ports +%--------------------------------------------------------------------------- +% etp-ports +% +% Print misc info about all ports +%--------------------------------------------------------------------------- +end + +define etp-rq-flags-int +# Args: int +# + if ($arg0 & 0x1f) + printf " Queue Mask:" + if ($arg0 & 0x1) + printf " max" + end + if ($arg0 & 0x2) + printf " high" + end + if ($arg0 & 0x4) + printf " normal" + end + if ($arg0 & 0x8) + printf " low" + end + if ($arg0 & 0x10) + printf " ports" + end + printf "\n" + end + + if ($arg0 & 0x3fe0) + printf " Emigrate Mask:" + if ($arg0 & 0x20) + printf " max" + end + if ($arg0 & 0x40) + printf " high" + end + if ($arg0 & 0x80) + printf " normal" + end + if ($arg0 & 0x100) + printf " low" + end + if ($arg0 & 0x200) + printf " ports" + end + printf "\n" + end + + if ($arg0 & 0x7fc00) + printf " Immigrate Mask:" + if ($arg0 & 0x400) + printf " max" + end + if ($arg0 & 0x800) + printf " high" + end + if ($arg0 & 0x1000) + printf " normal" + end + if ($arg0 & 0x2000) + printf " low" + end + if ($arg0 & 0x4000) + printf " ports" + end + printf "\n" + end + + if ($arg0 & 0xf8000) + printf " Evaquate Mask:" + if ($arg0 & 0x8000) + printf " max" + end + if ($arg0 & 0x10000) + printf " high" + end + if ($arg0 & 0x20000) + printf " normal" + end + if ($arg0 & 0x40000) + printf " low" + end + if ($arg0 & 0x80000) + printf " ports" + end + printf "\n" + end + + if ($arg0 & ~0xfffff) + printf " Misc Flags:" + if ($arg0 & 0x100000) + printf " out-of-work" + end + if ($arg0 & 0x200000) + printf " halftime-out-of-work" + end + if ($arg0 & 0x400000) + printf " suspended" + end + if ($arg0 & 0x800000) + printf " check-cpu-bind" + end + if ($arg0 & 0x1000000) + printf " inactive" + end + if ($arg0 & 0x2000000) + printf " non-empty" + end + if ($arg0 & 0x4000000) + printf " protected" + end + if ($arg0 & ~0x7ffffff) + printf " GARBAGE(0x%x)", ($arg0 & ~0x3ffffff) + end + printf "\n" + end +end + +document etp-rq-flags-int +%--------------------------------------------------------------------------- +% etp-rq-flags-int +% +% Print run queue flags +%--------------------------------------------------------------------------- +end + +define etp-ssi-flags +# Args: int +# + if ($arg0 & 0x1) + printf " sleeping" + end + if ($arg0 & 0x2) + printf " poll" + end + if ($arg0 & 0x4) + printf " tse" + end + if ($arg0 & 0x8) + printf " waiting" + end + if ($arg0 & 0x10) + printf " suspended" + end + printf "\n" +end + +document etp-ssi-flags +%--------------------------------------------------------------------------- +% etp-ssi-flags +% Arg int +% +% Print aux work flags +%--------------------------------------------------------------------------- +end + +define etp-aux-work-flags +# Args: int +# + if ($arg0 & 0x1) + printf " delayed-dealloc" + end + if ($arg0 & 0x2) + printf " delayed-dealloc-thr-prgr" + end + if ($arg0 & 0x4) + printf " fix-alloc-dealloc" + end + if ($arg0 & 0x8) + printf " fix-alloc-lower-lim" + end + if ($arg0 & 0x10) + printf " async-ready" + end + if ($arg0 & 0x20) + printf " async-ready-clean" + end + if ($arg0 & 0x40) + printf " misc-work-thr-prgr" + end + if ($arg0 & 0x80) + printf " misc-work" + end + if ($arg0 & 0x100) + printf " check-children" + end + if ($arg0 & 0x200) + printf " set-tmo" + end + if ($arg0 & 0x400) + printf " mseg-cached-check" + end + if ($arg0 & ~0x7ff) + printf " GARBAGE" + end + printf "\n" +end + +document etp-aux-work-flags +%--------------------------------------------------------------------------- +% etp-aux-work-flags +% Arg int +% +% Print aux work flags +%--------------------------------------------------------------------------- +end + +define etp-schedulers + if (!erts_initialized) + printf "No schedulers, since system isn't initialized!\n" + else + set $sched_ix = 0 + while $sched_ix < erts_no_schedulers + printf "--- Scheduler %d ---\n", $sched_ix+1 + printf " IX: %d\n", $sched_ix + if (erts_aligned_scheduler_data[$sched_ix].esd.cpu_id < 0) + printf " CPU Binding: unbound\n" + else + printf " CPU Binding: %d\n", erts_aligned_scheduler_data[$sched_ix].esd.cpu_id + end + printf " Aux work Flags:" + set $aux_work_flags = *((Uint32 *) &erts_aligned_scheduler_data[$sched_ix].esd.ssi->aux_work) + etp-aux-work-flags $aux_work_flags + printf " Sleep Info Flags:" + set $ssi_flags = *((Uint32 *) &erts_aligned_scheduler_data[$sched_ix].esd.ssi->flags) + etp-ssi-flags $ssi_flags + printf " Pointer: (ErtsSchedulerData *) %p\n", &erts_aligned_scheduler_data[$sched_ix].esd + printf " - Run Queue -\n" + if (etp_smp_compiled) + set $runq = erts_aligned_scheduler_data[$sched_ix].esd.run_queue + else + set $runq = &erts_aligned_run_queues[0].runq + end + printf " Length: total=%d", *((Uint32 *) &($runq->len)) + printf ", max=%d", *((Uint32 *) &($runq->procs.prio_info[0].len)) + printf ", high=%d", *((Uint32 *) &($runq->procs.prio_info[1].len)) + printf ", normal=%d", *((Uint32 *) &($runq->procs.prio_info[2].len)) + printf ", low=%d", *((Uint32 *) &($runq->procs.prio_info[3].len)) + printf ", port=%d\n", *((Uint32 *) &($runq->ports.info.len)) + if ($runq->misc.start) + printf " Misc Jobs: yes\n" + else + printf " Misc Jobs: no\n" + end + set $rq_flags = *((Uint32 *) &($runq->flags)) + etp-rq-flags-int $rq_flags + printf " Pointer: (ErtsRunQueue *) %p\n", $runq + + set $sched_ix++ + end + printf "-------------------\n", + end +end + +document etp-schedulers +%--------------------------------------------------------------------------- +% etp-schedulers +% +% Print misc info about all schedulers +%--------------------------------------------------------------------------- +end + +define etp-migration-info + set $minfo = (ErtsMigrationPaths *) *((UWord *) &erts_migration_paths) + set $rq_ix = 0 + while $rq_ix < erts_no_run_queues + if ($minfo->mpath[$rq_ix]) + printf "---\n" + printf "Run Queue Ix: %d\n", $rq_ix + etp-rq-flags-int $minfo->mpath[$rq_ix].flags + end + set $rq_ix++ + end +end +document etp-migration-info +%--------------------------------------------------------------------------- +% etp-migration-info +% +% Print migration information +%--------------------------------------------------------------------------- +end + +define etp-system-info + printf "--------------- System Information ---------------\n" + printf "OTP release: %s\n", etp_otp_release + printf "ERTS version: %s\n", etp_erts_version + printf "Compile date: %s\n", etp_compile_date + printf "Arch: %s\n", etp_arch + printf "Word size: %d-bit\n", etp_arch_bits + printf "Halfword: " + if (etp_halfword) + printf "yes\n" + else + printf "no\n" + end + printf "HiPE support: " + if (etp_hipe) + printf "yes\n" + else + printf "no\n" + end + if (etp_smp_compiled) + printf "SMP support: yes\n" + else + printf "SMP support: no\n" + end + printf "Thread support: " + if (etp_thread_compiled) + printf "yes\n" + else + printf "no\n" + end + printf "Kernel poll: " + if (etp_kernel_poll_support) + if (!erts_initialized) + printf "Supported\n" + else + if (erts_use_kernel_poll) + printf "Supported and used\n" + else + printf "Supported but not used\n" + end + end + else + printf "No support\n" + end + printf "Debug compiled: " + if (etp_debug_compiled) + printf "yes\n" + else + printf "no\n" + end + printf "Lock checking: " + if (etp_lock_check) + printf "yes\n" + else + printf "no\n" + end + printf "Lock counting: " + if (etp_lock_count) + printf "yes\n" + else + printf "no\n" + end + + if (!erts_initialized) + printf "System not initialized\n" + else + printf "Node name: " + etp-1 erts_this_node->sysname + printf "\n" + printf "Number of schedulers: %d\n", erts_no_schedulers + printf "Number of async-threads: %d\n", erts_async_max_threads + end + printf "--------------------------------------------------\n" +end + +document etp-system-info +%--------------------------------------------------------------------------- +% etp-system-info +% +% Print general information about the system +%--------------------------------------------------------------------------- +end define etp-dictdump # Args: ProcDict* @@ -1407,69 +2085,6 @@ document etpf-offheapdump %--------------------------------------------------------------------------- end -define etp-print-procs -# Args: Eterm -# -# Non-reentrant -# - etp-print-procs-1 -end - -define etp-print-procs-1 -# Args: Eterm* -# -# Non-reentrant -# - set $etp_print_procs_q = erts_max_processes / 10 - set $etp_print_procs_r = erts_max_processes % 10 - set $etp_print_procs_t = 10 - set $etp_print_procs_m = $etp_print_procs_q - if $etp_print_procs_r > 0 - set $etp_print_procs_m++ - set $etp_print_procs_r-- - end - set $etp_print_procs_i = 0 - set $etp_print_procs_found = 0 - while $etp_print_procs_i < erts_max_processes - if process_tab[$etp_print_procs_i] - printf "%d: ", $etp_print_procs_i - etp-1 process_tab[$etp_print_procs_i]->id - printf " " - etp-1 ((Eterm)(process_tab[$etp_print_procs_i]->i)) - printf " heap=%d/%d(%d)", process_tab[$etp_print_procs_i]->htop - process_tab[$etp_print_procs_i]->heap, \ - process_tab[$etp_print_procs_i]->hend - process_tab[$etp_print_procs_i]->heap, \ - process_tab[$etp_print_procs_i]->hend - process_tab[$etp_print_procs_i]->stop - printf " old=%d/%d ", process_tab[$etp_print_procs_i]->old_htop - process_tab[$etp_print_procs_i]->old_heap, \ - process_tab[$etp_print_procs_i]->old_hend - process_tab[$etp_print_procs_i]->old_heap - printf " mbuf_sz=%d ", process_tab[$etp_print_procs_i]->mbuf_sz - printf " min=%d ", process_tab[$etp_print_procs_i]->min_heap_size - printf " flags=%x ", process_tab[$etp_print_procs_i]->flags - printf " msgs=%d ", process_tab[$etp_print_procs_i]->msg.len - printf "\n" - end - set $etp_print_procs_i++ - if $etp_print_procs_i > $etp_print_procs_m - printf "%% %d%%...\n", $etp_print_procs_t - set $etp_print_procs_t += 10 - set $etp_print_procs_m += $etp_print_procs_q - if $etp_print_procs_r > 0 - set $etp_print_procs_m++ - set $etp_print_procs_r-- - end - end - end - printf "%% 100%%.\n" -end - -document etp-print-procs -%--------------------------------------------------------------------------- -% etp-print-procs Eterm -% -% Print some information about ALL processes. -%--------------------------------------------------------------------------- -end - - define etp-search-heaps # Args: Eterm # @@ -1498,20 +2113,21 @@ define etp-search-heaps-1 end set $etp_search_heaps_i = 0 set $etp_search_heaps_found = 0 - while $etp_search_heaps_i < erts_max_processes - if process_tab[$etp_search_heaps_i] - if (process_tab[$etp_search_heaps_i]->heap <= ($arg0)) && \ - (($arg0) < process_tab[$etp_search_heaps_i]->hend) + while $etp_search_heaps_i < erts_proc.max + set $proc = (Process *) *((UWord *) &erts_proc.tab[$proc_ix]) + if $proc + if ($proc->heap <= ($arg0)) && \ + (($arg0) < $proc->hend) printf "process_tab[%d]->heap+%d\n", $etp_search_heaps_i, \ - ($arg0)-process_tab[$etp_search_heaps_i]->heap + ($arg0)-$proc->heap end - if (process_tab[$etp_search_heaps_i]->old_heap <= ($arg0)) && \ - (($arg0) <= process_tab[$etp_search_heaps_i]->old_hend) + if ($proc->old_heap <= ($arg0)) && \ + (($arg0) <= $proc->old_hend) printf "process_tab[%d]->old_heap+%d\n", $etp_search_heaps_i, \ - ($arg0)-process_tab[$etp_search_heaps_i]->old_heap + ($arg0)-$proc->old_heap end set $etp_search_heaps_cnt = 0 - set $etp_search_heaps_p = process_tab[$etp_search_heaps_i]->mbuf + set $etp_search_heaps_p = $proc->mbuf while $etp_search_heaps_p && ($etp_search_heaps_cnt < $etp_max_depth) set $etp_search_heaps_cnt++ if (&($etp_search_heaps_p->mem) <= ($arg0)) && \ @@ -1523,7 +2139,7 @@ define etp-search-heaps-1 set $etp_search_heaps_p = $etp_search_heaps_p->next end if $etp_search_heaps_p - printf "process_tab[%d] %% Too many HeapFragments\n", \ + printf "Process ix=%d %% Too many HeapFragments\n", \ $etp_search_heaps_i end end @@ -2070,7 +2686,7 @@ document etp-init %--------------------------------------------------------------------------- end - etp-init help etp-init etp-show +etp-system-info diff --git a/erts/etc/vxworks/README.VxWorks b/erts/etc/vxworks/README.VxWorks deleted file mode 100644 index 299e35b513..0000000000 --- a/erts/etc/vxworks/README.VxWorks +++ /dev/null @@ -1,350 +0,0 @@ - - %CopyrightBegin% - - Copyright Ericsson AB 1997-2009. All Rights Reserved. - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - %CopyrightEnd% - ------------------------------------------------------------------------ -README, Erlang/OTP R11B for VxWorks on PPC860 and PPC603 ------------------------------------------------------------------------ -20060515 -- Patrik Nyblom, [email protected] - -R11B is a libraries only release for VxWorks. Only the libraries of -erl_interface (ei+erl_inteface) and ic are expected to be used. Still -the whole erlang system is distributed, although no support will be -given for anything else but the libraries. The information in this -file still applies to the full erlang distribution and parts of it are -therefore somewhat irrelevant to commercial users. - - -Included OTP applications -------------------------- - -appmon -asn1 -compiler -cosEvent -cosNotification -cosTime -cosTransaction -debugger -erl_interface -erts -eva [1] -ic -inets [2] -jinterface -kernel -mesh -mnemosyne -mnesia [1] -mnesia_session -orber -os_mon -pman -runtime_tools -sasl -snmp -stdlib -tools -tv - -[1] Only ram_copies work, The VxWorks filesystems are not - reliable enough for disk_copies to be fully supported. -[2] CGI scripts do not work on VxWorks. - -Omitted applications --------------------- - -crypto -emacs -etk -gs -odbc -parsetools -toolbar -ssl -megaco -webtools - -As `crypto' and `ssl' provides cryptographic functionality to `inets' -and `snmp', the latter applications will not handle cryptography on -VxWorks. - -Graphical interfaces --------------------- - -For applications using graphical interfaces, only the backend part works. - -Compilers ---------- - -All compilers are expected to be run on a cross host. The VxWorks -systems memory capabilities are too restricting to allow native -compiling. The expected host system is a Sun Solaris machine, although -Erlang compilation may be done on most platforms. - -Supported boards and configuration (only libraries supported) ----------------------------------- -The following boards and configurations are supported: - -* Force PowerCore 603 with Force pcore603 BSP and VxWorks 3.5.1 (no - SENS or SENS 1.1 + SPR23938) and a minimum of 32 Mb memory. - -* Force Powercore 750 with Force pcore750 BSP and VxWorks 3.5.1 (no - SENS or SENS 1.1 + SPR23938) and a minimum of 32 Mb memory. - -* PSS Core PPC860 processors, only erl_interface (too small main memory). - -Most PowerPC boards with FPU are expected to work, but will need to be -tested by OTP to be fully supported. - -The PPC603 build has been compiled with Wind River's `-mlongcall' -flag (SPR25893) to support arbitrary function calls across more -than 32 MB of memory. - -The PPC860 (PowerQuicc) has no FPU and requires a separate build. - -For Erlang to run, the Wind kernel has to be configured with a minimum -of these variables defined in config.h (or by the Tornado -configuration tool): - - INCLUDE_ANSI_ALL - INCLUDE_ENV_VARS - INCLUDE_EXC_HANDLING - INCLUDE_EXC_TASK - INCLUDE_FLOATING_POINT - INCLUDE_FORMATTED_IO - INCLUDE_IO_SYSTEM - INCLUDE_LOADER - INCLUDE_NETWORK - INCLUDE_NET_INIT - INCLUDE_NET_SHOW - INCLUDE_NET_SYM_TBL or INCLUDE_STANDALONE_SYM_TBL - INCLUDE_PIPES - INCLUDE_POSIX_FTRUNC - INCLUDE_RLOGIN or INCLUDE_TELNET (for pty's only) - INCLUDE_SELECT - INCLUDE_SEM_BINARY - INCLUDE_SEM_COUNTING - INCLUDE_SEM_MUTEX - INCLUDE_SHELL (*) - INCLUDE_SHOW_ROUTINES - INCLUDE_SIGNALS - INCLUDE_STARTUP_SCRIPT (*) - INCLUDE_STDIO - INCLUDE_SYM_TBL - INCLUDE_TASK_HOOKS - INCLUDE_TASK_VARS - INCLUDE_TTY_DEV - INCLUDE_UNLOADER - INCLUDE_NFS or INCLUDE_RAMDRV or INCLUDE_DOSFS (i.e. a file system, - possibly read-only) (**) - -(*) Needed for the example startup script, not actually needed in production if - erlang is set up by a c routine called from usrConfig.c. -(**) INCLUDE_NFS usually requires the NFS_USER_ID and NFS_GROUP_ID variables - to be set in config.h - -As an erlang system may open a lot of files, it is recommended to raise the -default NUM_FILES variable to something like 256 in config.h like this: - #ifdef NUM_FILES - #undef NUM_FILES - #endif - #define NUM_FILES 256 - -The SENS stack *has* to be of version 1.1 or higher, 1.0 is *not* -supported and will not work reliably. Upgrades as well as the patch -for SPR23938 can be found at www.wrs.com (i.e. WindSurf). Also, the -following constants in $WIND_BASE/target/h/netBufLib.h has to be -raised to a value of at least four times the default: - - NUM_NET_MBLKS - NUM_64 - NUM_128 - NUM_256 - NUM_512 - NUM_1024 - NUM_2048 - - NUM_SYS_64 - NUM_SYS_128 - NUM_SYS_256 - NUM_SYS_512 - -Use the show routines mbufShow and netStackSysPoolShow to verify that -these pools are not exhausted. - -Installation ------------- - -To install Erlang on a VxWorks card, the following knowledge is -expected: - -* VxWorks installation and configuration. - -* Network (TCP/IP) configuration. - -* Erlang basic operation and configuration. - -There is no specific install script for erlang on the VxWorks -platform. There is however an example VxWorks startup file named -erts-5.0.1/bin/erl_script.sam under the root of an unpacked -release. There may of course be other things to do in the start -script, like using the rdate program in the erlang distribution to get -a correct date and set the TIMEZONE variable. - -Please consult the "Embedded System" documentation for further -information on installation. - -Known Bugs and problems ------------------------ - -We have found the VxWorks/NFS client file system to be unreliable. -Important file operations like rename, ftruncate, cd and unlink -doesn't always work as expected. Therefore more complex file using -parts of OTP, like DETS and disk based mnesia tables cannot be used -reliably with NFS. Lowering the NFS cache size (global variable -nfsCacheSize) to 512 gives a more reliable NFS client, but to disk -base the mnesia tables over NFS is still not a good idea, especially -as disk based mnesia tables are not supported on VxWorks. Another -problem with VxWorks file systems is that the error codes they produce -are not consistent. We have worked around this problem by mapping the -codes to POSIX ones, by doing this we make the VxWorks Erlang platform -behave similarly to the UNIX and Windows implementations. - -The rename and ftruncate operations over NFS are emulated using -copying of files. This is mainly for our own test suites and it is not -recommended to use file:rename and/or file:ftruncate on NFS file -systems in production. - -Floating point operations is somewhat faulty. For instance, testing -floating point numbers for equality should be done with care. This is -actually not a bug, IEEE specifies no equality among floating point -numbers. - -Memory handling ---------------- - -Please read the erl_set_memory_block(3) manual page in the ERTS -documentation for information concerning memory handling in the erlang -emulator. Also please observe that reclaim.o has to be loaded and -reclaim_init() called before any other erlang routines are loaded and -started. If one wish to use the resource reclamation routines in other -programs, refer to the header file in `erts-5.0.1/include/reclaim.h'. -Including that file in your C source makes malloc/realloc/free and -open/fopen/socket/close etc be redefined to routines that makes the -memory and files be free'd/closed when the task exits. Still, -reclaim_init() *has* to be called before any program that uses this is -started. - -Using heart ------------ - -The default behavior of the heart object file that is part of the -distribution is that it reboots the target when the Erlang process -hasn't given it a heart beat in 60 seconds. The normal heart beat rate -is one beat per five seconds. This makes an effective "software -watchdog" but there is really no substitute for the real thing --- a -hardware watchdog. If you want to add a hardware watchdog to the -system please contact us for directions. If you want to disable the -reboot you may set the environment variable HEART_DONT_REBOOT (see the -example erlang start script, erl). Please note that if you DO want the -card to reboot you mustn't define HEART_DONT_REBOOT at all. E.g. to -disable heart reboot you may include the following line in the start -script (as is indeed the case with the example start script). - - putenv "HEART_DONT_REBOOT=1" - -A few words on writing port program and dynamically loaded drivers for VxWorks ------------------------------------------------------------------------------- - -VxWorks has one name-space for all symbols. This makes it harder to -write C programs whose global symbols doesn't interfere with each -other. It is a good rule to avoid all globally visible symbols that -are not absolutely necessary. Due to these facts we use the following -naming rules that are crucial to follow. (there are more issues -involved but the issues described here is a good beginning). - -Port programs must have a function with the same name as the object -file. E.g. if you have an object file named `port_test.o' it must -contain a globally visible function named `port_test'. This is the -function that will be called when you output data from Erlang to the -port. (The object file, in this example, should be named -`port_test.o', but `port_test' will also do). - -Also, in an embedded system, it is recommended to load the port -program into the system before the port program is used. This is to -avoid the real time degradation dynamical linking in runtime would -introduce. Use VxWorks command ld < "port_prg" to accomplish this. - -Dynamically linked drivers must have a function with the same name as -the object file with the added suffix `_init'. We recommend the use of -the macro DRIVER_INIT in `driver.h'. E.g. if you have an object file -named `echo_drv.eld' it must contain a globally visible function -`echo_drv_init'. (The object file, in this example, should be named -`echo_drv.eld' (`eld' is short for Erlang Loadable Driver), but -`echo_drv.o' and `echo_drv' will both also do). It is also very -important to initialize all unused function pointer in the -`driver_entry' struct to NULL (see example below). - -Example of dynamically linked driver ------------------------------------- - -#include <stdio.h> -#include "driver.h" - -static int erlang_port; -static long echo_start(); -static int echo_stop(), echo_read(); - -static struct driver_entry echo_driver_entry = { - null_func, - echo_start, - echo_stop, - echo_read, - null_func, - null_func, - "echo_drv", - null_func -}; - -int DRIVER_INIT(echo_drv)(void *handle) -{ - erlang_port = -1; - - echo_driver_entry.handle = handle; - return (int) &echo_driver_entry; -} - -static long echo_start(long port,char *buf) -{ - if (erlang_port != -1) { - return -1; - } - - erlang_port = port; - return port; -} - -static int echo_read(long port, char *buf, int count) -{ - return driver_output(erlang_port, buf, count); -} - -static int echo_stop() -{ - return erlang_port = -1; -} diff --git a/erts/etc/vxworks/erl.exec.c b/erts/etc/vxworks/erl.exec.c deleted file mode 100644 index 6b45ebaa39..0000000000 --- a/erts/etc/vxworks/erl.exec.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - A simpified version of the 'erl.exec' "startup script". - Called (e.g. from VxWorks shell) with all arguments in a - single string, e.g.: erl "-name thisnode -s mymod myfunc". - These arguments are handled as in 'erl.exec': - -name - -sname - -noshell - -noinput - anything else is just passed on to the emulator. Note that there - is no automatic start of epmd, that -oldshell is implicit, and - that you need to set current directory appropriately if you want - auto-load of port programs -*/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifndef DEFAULT_HOMEDIR /* used if environment HOME isn't set */ -#define DEFAULT_HOMEDIR "/" -#endif - -#define ARGLEN 2048 /* Total length of args passed to erl_main */ -#define ARGMAX 64 /* Max no of "extra" args */ - -static char *erl_cmd = "erl_main -n "; - -static toomuch() -{ - fprintf(stderr, "erl: Too many arguments\n"); - return(-1); -} - -static toolittle(arg) -char *arg; -{ - fprintf(stderr, "erl.exec: Missing argument for %s\n", arg); - return(-1); -} - -erl_exec(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) -int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10; -{ - char *shell = "-oldshell ", *noshell = "", - *home, *rootdir, *bindir, *progname; - char cmd[ARGLEN], eargs[ARGLEN], iargs[ARGLEN]; - char *args[ARGMAX], *arglast = NULL, *argp; - int nargs = 0, len, i; - - if ((rootdir = getenv("ROOTDIR")) == NULL || - (bindir = getenv("BINDIR")) == NULL || - (progname = getenv("PROGNAME")) == NULL) { - fprintf(stderr, "erl.exec: ROOTDIR, BINDIR, and PROGNAME must be set."); - return -1; - } - eargs[0] = '\0'; - iargs[0] = '\0'; - if ((home = getenv("HOME")) == NULL) - home = DEFAULT_HOMEDIR; - argp = strtok_r((char *)arg1, " \t", &arglast); - while (argp != NULL) { - if (strcmp(argp, "-name") == 0) { - if ((argp = strtok_r((char *)NULL, " \t", &arglast)) == NULL) - return(toolittle("-name")); - strcat(iargs, "-name "); - strcat(iargs, argp); - strcat(iargs, " "); - } else if (strcmp(argp, "-sname") == 0) { - if ((argp = strtok_r((char *)NULL, " \t", &arglast)) == NULL) - return(toolittle("-sname")); - strcat(iargs, "-sname "); - strcat(iargs, argp); - strcat(iargs, " "); - } else if (strcmp(argp, "-noshell") == 0) { - strcat(iargs, "-noshell -noinp_shell "); - } else if (strcmp(argp, "-noinput") == 0) { - strcat(iargs, "-noshell -noinput "); - } else { - if (nargs > ARGMAX - 1) - return(toomuch()); - args[nargs++] = argp; - } - argp = strtok_r((char *)NULL, " \t", &arglast); - } - strcpy(cmd, erl_cmd); - strcat(cmd, eargs); - strcat(cmd, " -- -root "); - strcat(cmd, rootdir); - strcat(cmd, " -progname "); - strcat(cmd, progname); - strcat(cmd, " -- "); - strcat(cmd, "-home "); - strcat(cmd, home); - strcat(cmd, " "); - strcat(cmd, iargs); - - len = strlen(cmd); - for (i = 0; i < nargs; i++) { - if (len + strlen(args[i]) + 2 >= ARGLEN) - return(toomuch()); - cmd[len++] = ' '; - strcpy(&cmd[len], args[i]); - len += strlen(args[i]); - } - argcall(cmd); -} - diff --git a/erts/etc/vxworks/erl_io.c b/erts/etc/vxworks/erl_io.c deleted file mode 100644 index 0032b77079..0000000000 --- a/erts/etc/vxworks/erl_io.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* Some stuff to let the Erlang and VxWorks shells coexist peacefully. - Basically, run Erlang as a spawned task with input redirected to - the slave side of a pseudo-tty, and connect explicitly to the master - side of the pseudo-tty to send input to Erlang when desired. */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include <stdio.h> -#include <ioLib.h> -#include <taskLib.h> -#include <ptyDrv.h> - -extern int spTaskPriority, spTaskOptions; - -#define TBUFSIZ 512 - -#define DEFAULT_STACK_SIZE 100000 - -static int slavefd = -1, masterfd = -1; -static run_erl(); - -/* Frontend to the Erlang startup function - callable from VxWorks shell - or script. 'arg' is actually a string passed to the real startup. */ -start_erl(arg) -int arg; -{ - int stacksize; - char *stackenv; - - /* create and open the pty - we want the master side to be open - all the time, since closing it probably generates EOF on the - slave side */ - (void)ptyDevCreate("/pty/erlang.", TBUFSIZ, TBUFSIZ); - if (slavefd != -1) - (void)close(slavefd); - slavefd = open("/pty/erlang.S", O_RDONLY, 0); - if (masterfd != -1) - (void)close(masterfd); - masterfd = open("/pty/erlang.M", O_WRONLY, 0); - - /* flush any old leftover garbage */ - (void) ioctl(masterfd, FIOFLUSH, 0); - if ((stackenv = getenv("ERLSTACKSIZE")) == NULL) - stacksize = DEFAULT_STACK_SIZE; - else - stacksize = atoi(stackenv); - /* spawn Erlang, via stub below */ - return(taskSpawn("erlang", spTaskPriority, spTaskOptions, stacksize, - run_erl, arg, 0,0,0,0,0,0,0,0,0)); -} - -/* Little stub that runs in the spawned task - we need this to redirect - stdin reliably (redirections aren't "inherited" in VxWorks) */ -static -run_erl(arg) -int arg; -{ - ioTaskStdSet(0, 0, slavefd); /* redirect stdin to slave side of pty */ - - /* We don't want to redirect stdout/err since no one will be reading - from the master side (to_erl - and the open()s above - could be - made bidirectional, but still the master side would only be read - when to_erl was running), and output can eventually fill the pty - buffer and cause the Erlang system to block. Not redirecting - stdout/err will have the effect that output from Erlang, e.g. the - shell prompt, will appear on console/rlogin/whatever even when - to_erl isn't running, which may be confusing - can't win 'em all... */ - - erl_exec(arg, 0,0,0,0,0,0,0,0); /* call the real startup */ -} - -/* Function callable from VxWorks shell to talk to Erlang - stop talking - and return to VxWorks shell through ^D (EOF) */ -to_erl() -{ - char buf[TBUFSIZ]; - int cc; - - if (masterfd == -1) { /* sanity check */ - fprintf(stderr, "Must start_erl first!\n"); - return(-1); - } - while ((cc = read(0, buf, TBUFSIZ)) > 0) /* just pass everything through */ - if (write(masterfd, buf, cc) != cc) { - fprintf(stderr, "Write to Erlang failed!\n"); - return(-1); - } - return(cc); -} diff --git a/erts/etc/vxworks/erl_script.sam.in b/erts/etc/vxworks/erl_script.sam.in deleted file mode 100644 index 81c2b0128d..0000000000 --- a/erts/etc/vxworks/erl_script.sam.in +++ /dev/null @@ -1,100 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2009. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# -# erl_script.sam -# Sample VxWorks script to start Erlang -# -# Note! This is not a complete or ready to use VxWorks startup script, -# rather an example of what You should add to Your existing startupscript -# to execute the erlang emulator at boot. -# -# When writing Your own script to start erlang, the paths to -# the binaries have to be changed to reflect your system. -# -# The ROOTDIR variable should not point to a ftp or rcp filesystem unless -# the erlang machine is run in embedded mode. Loading of modules -# is far to slow if the erlang binaries are not placed on a real filesystem -# like NFS or any type of local filesystem. -# - -# -# Load modules -# - -# -# First load and initiate the reclaim facility -# -ld </home/tornado/erlvxworks/erts-%VSN%/bin/reclaim.o -reclaim_init() - -# -# Now load the runtime system -# -ld </home/tornado/erlvxworks/erts-%VSN%/bin/jam -ld </home/tornado/erlvxworks/erts-%VSN%/bin/erl.exec -ld </home/tornado/erlvxworks/erts-%VSN%/bin/erl_io -ld </home/tornado/erlvxworks/erts-%VSN%/bin/vxcall -ld </home/tornado/erlvxworks/erts-%VSN%/bin/heart -ld </home/tornado/erlvxworks/erts-%VSN%/bin/epmd - -# -# Stack sizes -# -putenv "ERLSTACKSIZE=100000" -putenv "ERLPORTSTACKSIZE=100000" - -# -# Activate Round robin scheduling -# -kernelTimeSlice 1 - -# -# Distribution -# The VxWorks machines host name -sethostname "sb001", 5 -# Erlangs internal resolver -putenv "ERLRESCONF=/home/tornado/erlvxworks/erts-%VSN%/bin/resolv.conf" - -# -# Start epmd (for distribution) -# -start_epmd "-daemon" - -# -# Misc environment variables -# -putenv "ROOTDIR=/home/tornado/erlvxworks" -putenv "BINDIR=/home/tornado/erlvxworks/erts-%VSN%/bin" -putenv "PROGNAME=erl" -putenv "HOME=/home/tornado/erlvxworks" - -# -# Set heart no reboot mode (to make heart reboot - -# don't define HEART_DONT_REBOOT at all) -# -putenv "HEART_DONT_REBOOT=1" - -# To get fullsweep garbage collection on systems with -# very limited memory, set ERL_FULLSWEEP_AFTER to "0": -# putenv "ERL_FULLSWEEP_AFTER=0" - -# -# Start Erlang/OTP -# -start_erl "-oldshell -heart -sname vxnode -setcookie switch -boot start_sasl" diff --git a/erts/etc/vxworks/heart_config.c b/erts/etc/vxworks/heart_config.c deleted file mode 100644 index 7e60e61fbb..0000000000 --- a/erts/etc/vxworks/heart_config.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * A basic heart configure module for VxWorks. - * - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include <vxWorks.h> -#include <stdio.h> -#include <stdlib.h> -#include <rebootLib.h> -#include <sysLib.h> - -/* wd_init is executed to initialize a watchdog (if one is used). */ -int wd_init(timeout, prio) - int timeout, prio; -{ - -} - -/* wd_reset should be called every 5th second from heart */ -void wd_reset() -{ - -} - -/* This routine is called when erlang has closed */ -void heart_reboot() -{ - if (getenv("HEART_DONT_REBOOT") != NULL) { - fprintf(stderr, "heart_config: HEART_DONT_REBOOT set, no reboot ...\n"); - } else { - fprintf(stderr, "heart_config: rebooting ...\n"); - taskDelay(sysClkRateGet() * 5); - reboot(BOOT_CLEAR); - } -} - - - - diff --git a/erts/etc/vxworks/heart_config.h b/erts/etc/vxworks/heart_config.h deleted file mode 100644 index 5ffaaa8c3f..0000000000 --- a/erts/etc/vxworks/heart_config.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * This is heart's watchdog interface for VxWorks. - */ - -#ifndef _HW_WATCHDOG_H -#define _HW_WATCHDOG_H - -extern void wd_init(int timeout, int prio); /* wd_init initializes the - watchdog, if one is used. */ -extern void wd_reset(void); /* wd_reset is used by heart to kick - the watchdog, if one is used. */ -extern void heart_reboot(void); /* reboot is called if heart discovers - that the Erlang task has stopped sending - heart beats. It can log system status - and should reboot VxWorks. */ - -#endif diff --git a/erts/etc/vxworks/rdate.c b/erts/etc/vxworks/rdate.c deleted file mode 100644 index 3e8cc644d0..0000000000 --- a/erts/etc/vxworks/rdate.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <vxWorks.h> -#include <timers.h> -#ifdef NETDB -#include <netdb.h> -#endif -#include <sys/socket.h> -#include <netinet/in.h> - -/* - rdate("host") - Set the time from "host". -*/ - -/* No getservbyname() available... */ -#define TIME_PORT 37 - -rdate(host) -char *host; -{ - u_long haddr; -#ifdef NETDB - struct hostent *hp; -#endif - struct sockaddr_in saddr; - int sock; - u_long net_time; - struct timespec t; - - if ((haddr = inet_addr(host)) == ERROR) { -#ifdef NETDB - if ((hp = gethostbyname(host)) == NULL) { -#else - if ((haddr = hostGetByName(host)) == ERROR) { -#endif - printf("Host not found.\n"); - return(-1); - } -#ifdef NETDB - memcpy(&haddr, hp->h_addr, sizeof(haddr)); -#endif - } - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - memcpy(&saddr.sin_addr, &haddr, sizeof(haddr)); - saddr.sin_port = htons(TIME_PORT); - if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { - perror("socket"); - return(-1); - } - if (connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { - perror("connect"); - close(sock); - return(-1); - } - if (read(sock, &net_time, 4) != 4) { - perror("read"); - close(sock); - return(-1); - } - t.tv_sec = ntohl(net_time); - t.tv_sec -= 2208988800; /* seconds 1900-01-01 -- 1970-01-01 */ - t.tv_nsec = 0; - clock_settime(CLOCK_REALTIME, &t); - close(sock); - return(0); -} diff --git a/erts/etc/vxworks/reclaim.c b/erts/etc/vxworks/reclaim.c deleted file mode 100644 index d8676b3750..0000000000 --- a/erts/etc/vxworks/reclaim.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <vxWorks.h> -#include <version.h> -#include <string.h> -#include <types.h> -#include <sigLib.h> -#include <ioLib.h> -#include <iosLib.h> -#include <fioLib.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <symLib.h> -#include <sysLib.h> -#include <sysSymTbl.h> -#include <loadLib.h> -#include <taskLib.h> -#include <taskVarLib.h> -#include <taskHookLib.h> -#include <tickLib.h> -#include <time.h> -#include <rngLib.h> -#include <semLib.h> -#include <selectLib.h> -#include <sockLib.h> -#include <a_out.h> -#include <wdLib.h> -#include <timers.h> -#include <ctype.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <stdarg.h> - -#include <stdio.h> -#include <math.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> - - - -#define RECLAIM_NO_ALIAS /* No #defines for open/malloc/fopen etc */ -#include "reclaim.h" -#include "reclaim_private.h" - -#undef open -#undef creat -#undef socket -#undef accept -#undef close -#undef fopen -#undef fdopen -#undef freopen -#undef fclose -/* XXX Should do opendir/closedir too... */ -#undef malloc -#undef calloc -#undef realloc -#undef free -#undef cfree - -#ifdef _ARCH_PPC -#define MAX_FILES_SYM_NAME "maxFiles" -#else -#define MAX_FILES_SYM_NAME "_maxFiles" -#endif - - -/* - * Use another free() function upon task deletion? - * Note! When changing free function, the new free function will have to - * be able to cope with ALL previously used malloced areas, that is - * it has to be able to find out how things are malloced - * to free them in the right way! - */ -static FreeFunction reclaim_free_function = NULL; - -/* delete hook handling (see below) */ -static int hook_added = 0; /* Initated at first reclaim_init, an extra - non MT-safe check that we only get - initialized once */ - -/* Forward... */ -static void save_reclaim(WIND_TCB *tcbp); - -struct mall_data { - struct mall_data *next; - char *self; -}; - -struct task_data { - FUNCPTR version; /* To recognize when we have reloaded */ - int max_files; /* It may change... */ - struct fd_set open_fds; - struct mall_data *mall_data; - FUNCPTR delete_hook; - caddr_t hook_data; - FILE *open_fps[1]; /* Will be max_files long */ -} *task_data = NULL; - -static int max_files = 50; /* default configAll.h */ - -int reclaim_max_files(void) -{ - return max_files; -} - -#ifdef DEBUG -#define check_hook() \ -((task_data != NULL || \ - fdprintf(2,"check_hook() TID = 0x%08x, Called from line %d\n", \ - (unsigned int)taskIdSelf(),\ - __LINE__)) && \ -(task_data != NULL || \ - (taskVarAdd(0, (int *)&task_data) == OK && \ - (task_data = (struct task_data *)\ - calloc(1, sizeof(struct task_data) + max_files*sizeof(FILE *))) != NULL && \ - (task_data->version = (FUNCPTR)save_reclaim) != NULL && \ - (task_data->max_files = max_files) != 0 && \ - fdprintf(2,"taskVar Added for 0x%08x\n",(unsigned int)taskIdSelf())))) -#else -#define check_hook() \ -(task_data != NULL || \ - (taskVarAdd(0, (int *)&task_data) == OK && \ - (task_data = (struct task_data *)\ - calloc(1, sizeof(struct task_data) + max_files*sizeof(FILE *))) != NULL && \ - (task_data->version = (FUNCPTR)save_reclaim) != NULL && \ - (task_data->max_files = max_files) != 0)) -#endif - -/* - * Global initialization of the reclaim data structures, mainly - * the max_files variable. This HAS to be called by some task before - * the first task that utilizes this exit's, preferrably before any - * task makes the first use of this library. - */ -STATUS reclaim_init(void) -{ - int *mp; - SYM_TYPE type; - struct task_data *tdp; - int i; - - if (!hook_added) { - /* race condition */ - ++hook_added; - /* Try to find the maxFiles value */ - if (symFindByNameAndType(sysSymTbl, MAX_FILES_SYM_NAME, (char **)&mp, - &type, - N_EXT | N_BSS, N_EXT | N_BSS) == OK || - symFindByNameAndType(sysSymTbl, MAX_FILES_SYM_NAME, (char **)&mp, - &type, - N_EXT | N_DATA, N_EXT | N_DATA) == OK) { - -#ifdef DEBUG - fdprintf(2, "Found maxFiles=%d\n", *mp); -#endif - if (*mp <= FD_SETSIZE) - max_files = *mp; - else - max_files = FD_SETSIZE; - } - if (task_data != NULL && task_data->max_files != max_files) { - /* fix our own iff we have one */ - if ((tdp = (struct task_data *) - realloc(task_data, sizeof(struct task_data) + - max_files*sizeof(FILE *))) != NULL) { - task_data = tdp; - for (i = task_data->max_files; i < max_files; i++) - task_data->open_fps[i] = NULL; - task_data->max_files = max_files; - } - } - /* Make sure taskVariables are deleted AFTER our hook is run. */ - taskVarInit(); - if(taskDeleteHookAdd((FUNCPTR)save_reclaim) != OK) { - fprintf(stderr, - "Panic: taskDeleteHook cannot be added for reclaim.\n"); - return ERROR; - } - return OK; - } else - return ERROR; -} - -/* N.B.!! We do *not* execute in the context of the dying task here, - but rather that of tExcTask - we do get a pointer to the task's - TCB though - this pointer is in fact also the task's ID. */ -static void save_reclaim(WIND_TCB *tcbp) -{ - int i, var, oldfd; - struct task_data *tdp; - struct mall_data *mdp, *mdnextp; - - if ((var = taskVarGet((int)tcbp, (int *)&task_data)) != ERROR && - var != 0) { - tdp = (struct task_data *)var; - if (tdp->version == (FUNCPTR)save_reclaim) { /* Only handle our own */ -#ifdef DEBUG - fdprintf(2, "Reclaiming for task id 0x%x:\nFiles: ", (int)tcbp); -#endif - /* Ugh! VxWorks doesn't even flush stdout/err - we need to - get at those (which are task-private of course, i.e. we - can't just do fflush(stdout) here) - we could be really - pedantic and try to redefine stdout/err (which "are" - function calls) too, snarfing the values when they are - used - but besides the overhead this is problematic since - they are actually #defines already... We'll peek in the - TCB instead (no documentation of course). And of course, - we must also meddle with the *file descriptor* indirections, - or we'll just flush out on tExcTask's descriptors... */ - for (i = 1; i <= 2; i++) { - if (tcbp->taskStdFp[i] != NULL) { -#ifdef DEBUG - fdprintf(2, "fflush(%s) ", i == 1 ? "stdout" : "stderr"); -#endif - oldfd = ioTaskStdGet(0, i); - ioTaskStdSet(0, i, tcbp->taskStd[i]); - fflush(tcbp->taskStdFp[i]); - ioTaskStdSet(0, i, oldfd); - } - } - for (i = 3; i < tdp->max_files; i++) { - if (FD_ISSET(i, &tdp->open_fds)) { -#ifdef DEBUG - fdprintf(2, "close(%d) ", i); -#endif - (void) close(i); - } - if (tdp->open_fps[i] != NULL) { -#ifdef DEBUG - fdprintf(2, "fclose(%0x%x) ", (int)tdp->open_fps[i]); -#endif - (void) fclose(tdp->open_fps[i]); - } - } - i = 0; - mdp = tdp->mall_data; - while (mdp != NULL) { - mdnextp = mdp->next; - if(reclaim_free_function != NULL) - (*reclaim_free_function)(mdp->self); - else - free(mdp->self); - i++; - mdp = mdnextp; - } -#ifdef DEBUG - fdprintf(2, "\nFreeing memory: total %d mallocs\n", i); -#endif - - if (tdp->delete_hook != NULL) { -#ifdef DEBUG - fdprintf(2, "Calling delete hook at 0x%08x\n", tdp->delete_hook); -#endif - (*tdp->delete_hook)(tdp->hook_data); -#ifdef DEBUG - fdprintf(2, "Called delete hook at 0x%08x\n", tdp->delete_hook); -#endif - } -#ifdef DEBUG - fdprintf(2, "Freeing own mem at 0x%08x\n", tdp); -#endif - (void) free((char *)tdp); -#ifdef DEBUG - fdprintf(2, "Freed own mem at 0x%08x, done (0x%08x)\n**********\n", tdp, - taskIdSelf()); - checkStack(0); -#endif - } - } -#ifdef DEBUG - else - fdprintf(2, "No task data found for id 0x%x, var = %d\n", (int)tcbp, var); -#endif -} - -/* - * This sets another free function to be used by the task deletion hook. - * The free function HAS to be able to free ANY type of dynamically allocated - * memory that can be in the task data list of allocated memory, that is - * also memory that's allocated before the free function was set. - * A "user-supplied" free function is GLOBAL to the system!!! - * A race condition is present, a task delete hook may be running when this - * function is called, that may not be especially funny... - */ -void set_reclaim_free_function(FreeFunction f){ - reclaim_free_function = f; -} - -void save_delete_hook(FUNCPTR func, caddr_t parm) -{ - if (check_hook()) { - task_data->delete_hook = func; - task_data->hook_data = parm; - } -} - -/* - * plain_malloc is only used by spawn_start; plain_free by call_proc; - * save_fd is used by both. - */ -void *plain_malloc(size_t size){ - return(malloc(size)); -} - -void *plain_realloc(void *ptr, size_t size){ - return(realloc(ptr, size)); -} - -void plain_free(void *ptr){ - free(ptr); -} - -void save_fd(int fd){ - if (fd >= 0 && check_hook() && fd < task_data->max_files) - FD_SET(fd, &task_data->open_fds); -} - -int save_open(char *path, int flags, /*mode_t mode*/ ...){ - int fd; - mode_t mode = 0; - if(flags & O_CREAT){ - va_list pvar; - va_start(pvar,flags); -#ifdef __GNUC__ -#warning save_open() gives three known alignment warnings. -#endif - mode = va_arg(pvar, mode_t); - va_end(pvar); - } - if ((fd = open(path, flags, mode)) >= 0 && check_hook()) - FD_SET(fd, &task_data->open_fds); - return(fd); -} - -int save_creat(char *path, int mode){ - int fd; - if ((fd = creat(path, mode)) >= 0 && check_hook()) - FD_SET(fd, &task_data->open_fds); - return(fd); -} - -int save_socket(int domain, int type, int protocol){ - int fd; - if ((fd = socket(domain, type, protocol)) >= 0 && check_hook()) - FD_SET(fd, &task_data->open_fds); - return(fd); -} - -int save_accept(int s, struct sockaddr *addr, int *addrlen){ - int fd; - if ((fd = accept(s, addr, addrlen)) >= 0 && check_hook()) - FD_SET(fd, &task_data->open_fds); - return(fd); -} - -int save_close(int fd){ - if (fd >= 0 && fd <= FD_SETSIZE && check_hook()) - FD_CLR(fd, &task_data->open_fds); - return(close(fd)); -} - -/* The dealing with FILE *'s below isn't strictly correct, we assume - that one never has several pointing to the same fd - in the unlikely - event that one does, all but the last one opened is forgotten */ -FILE *save_fopen(const char *filename, char *type){ - FILE *fp; - - if ((fp = fopen(filename, type)) != NULL && - check_hook() && fileno(fp) < task_data->max_files) - task_data->open_fps[fileno(fp)] = fp; - return(fp); -} - -FILE *save_fdopen(int fd, char *type){ - FILE *fp; - - if ((fp = fdopen(fd, type)) != NULL && - check_hook() && fileno(fp) < task_data->max_files) { - task_data->open_fps[fileno(fp)] = fp; - FD_CLR(fd, &task_data->open_fds); - } - return(fp); -} - -FILE *save_freopen(char *filename, char *type, FILE *stream){ - FILE *fp; - - if (check_hook()) { - if(fileno(stream) < task_data->max_files && - task_data->open_fps[fileno(stream)] == stream) - task_data->open_fps[fileno(stream)] = NULL; - if ((fp = freopen(filename, type, stream)) != NULL && - fileno(fp) < task_data->max_files) - task_data->open_fps[fileno(fp)] = fp; - } else - fp = freopen(filename, type, stream); - return(fp); -} - -int save_fclose(FILE *stream){ - if (check_hook() && fileno(stream) < task_data->max_files && - task_data->open_fps[fileno(stream)] == stream) - task_data->open_fps[fileno(stream)] = NULL; - return(fclose(stream)); -} - -/* We link all malloc'ed segments by adding a couple of pointers - at the *end* - that way we can return the address malloc gave - (need to make sure we align those pointers) */ - -/* - #define MALL_MARGIN 32 - #define save_mall_size(size) save_mall_size1((size) + 2 * MALL_MARGIN) - #define save_mall_size1(size) \ - (((size) + sizeof(char *) - 1) & (unsigned long)(-sizeof(char*))) - - #define save_mall_enq(ptr, mdp) save_mall_enq1((ptr), (mdp) - MALL_MARGIN) - #define save_mall_enq1(ptr, mdp) \ - (((struct mall_data *)(mdp))->self = (ptr), \ - ((struct mall_data *)(mdp))->next = task_data->mall_data, \ - task_data->mall_data = (struct mall_data *)(mdp)) -*/ -#define save_mall_size(size) \ -(((size) + sizeof(char *) - 1) & (unsigned long)(-sizeof(char*))) -#define save_mall_enq(ptr, mdp) \ -(((struct mall_data *)(mdp))->self = (ptr), \ - ((struct mall_data *)(mdp))->next = task_data->mall_data, \ - task_data->mall_data = (struct mall_data *)(mdp)) - - -#define save_mall_deq(ptr) { \ - struct mall_data *mdp = task_data->mall_data, \ - **prevnext = &task_data->mall_data; \ - while (mdp != NULL && mdp->self != (ptr)) { \ - prevnext = &mdp->next; \ - mdp = mdp->next; \ - } \ - if (mdp != NULL) *prevnext = mdp->next; \ -} - -void *save_malloc2(size_t size, MallocFunction mf){ - unsigned msize = save_mall_size(size); - char *ptr; - - if ((ptr = (*mf)(msize + sizeof(struct mall_data))) != NULL && - check_hook()) - save_mall_enq((void *) ptr, (void *) (ptr + msize)); - return((void *) ptr); -} - -void *save_malloc(size_t size){ - return save_malloc2(size, &malloc); -} - -void *save_calloc2(size_t nelem, size_t elsize, CallocFunction cf){ - unsigned msize = save_mall_size(nelem * elsize); - char *ptr; - - if ((ptr = (*cf)(1, msize + sizeof(struct mall_data))) != NULL && - check_hook()) - save_mall_enq((void *) ptr, (void *) (ptr + msize)); - return((void *) ptr); -} - -void *save_calloc(size_t nelem, size_t elsize){ - return save_calloc2(nelem,elsize,&calloc); -} - -void *save_realloc2(void *optr, size_t size, ReallocFunction rf){ - unsigned msize = save_mall_size(size); - char *ptr; - - /* First we must dequeue the old save block, after that - we try to realloc, if that succeeds we enqueue the new - block, if it fails we have to enqueue the old one anew - so we must deduce the size of that old block first. */ - - struct mall_data *mdp0 = task_data->mall_data, - **prevnext0 = &task_data->mall_data; - while (mdp0 != NULL && mdp0->self != (((char *) optr))) { - prevnext0 = &mdp0->next; - mdp0 = mdp0->next; - } - /* mdp0 == NULL (can) mean that the block that is realloced - have been malloced with an (for example) ordinary malloc - (that is not a save_malloc). This is handled like: no dequeing - is done of that block, the new block is enqueued */ - if (mdp0 != NULL) - save_mall_deq(((char *) optr)); - - if ((ptr = (*rf)(optr, msize + sizeof(struct mall_data))) != NULL && - check_hook()) - save_mall_enq((void *) ptr, (void *) (ptr + msize)); - else if (mdp0 != NULL) - /* re-enqueue the old block that has just been dequeued */ - save_mall_enq(((char *) optr), mdp0); - - return((void *) ptr); -} - -void *save_realloc(void *optr, size_t size){ - return save_realloc2(optr,size,&realloc); -} - -void save_free2(void *ptr, FreeFunction ff) -{ - if (check_hook()) - save_mall_deq(((char *) ptr)); - (*ff)(ptr); -} - -void save_free(void *ptr){ - save_free2(ptr,&free); -} - -void save_cfree2(void *ptr, CfreeFunction cf) -{ - if (check_hook()) - save_mall_deq(((char *)ptr)); - (*cf)(ptr); -} - -void save_cfree(void *ptr){ - save_cfree2(ptr,&cfree); -} - diff --git a/erts/etc/vxworks/reclaim.h b/erts/etc/vxworks/reclaim.h deleted file mode 100644 index ca9aa8f6be..0000000000 --- a/erts/etc/vxworks/reclaim.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -#ifndef _RECLAIM_H -#define _RECLAIM_H - - -/* The Erlang release for VxWorks includes a simple mechanism for - "resource reclamation" at task exit - it allows replacement of the - functions that open/close "files" and malloc/free memory with versions - that keep track, to be able to "reclaim" file descriptors and memory - when a task exits (regardless of *how* it exits). - - The interface to this mechanism is made available via this file, - with the following caveats: - - - The interface may change (or perhaps even be removed, though that - isn't likely until VxWorks itself provides similar functionality) - in future releases - i.e. you must always use the version of this - file that comes with the Erlang release you are using. - - - Disaster is guaranteed if you use the mechanism incorrectly (see - below for the correct way), e.g. allocate memory with the "tracking" - version of malloc() and free it with the "standard" version of free(). - - - The mechanism (of course) incurs some performance penalty - thus - for a simple program you may be better off with careful programming, - making sure that you do whatever close()/free()/etc calls that are - appropriate at all exit points (though if you need to guard against - taskDelete() etc, things get messy...). - - To use the mechanism, simply program your application normally, i.e. - use open()/close()/malloc()/free() etc as usual, but #include this - file before any usage of the relevant functions. NOTE: To avoid the - "disaster" mentioned above, you *must* #include it in *all* (or none) - of the files that manipulate a particular file descriptor, allocated - memory area, etc. - - Before any task that uses this utility is loaded (which includes the - erlang emulator), the reclaim.o object file has to be loaded and - the function reclaim_init() has to be called. reclaim_init should be called - only _ONCE_ in a systems lifetime and has only a primitive guard - against multiple calls (i.e. a global variable is checked). Therefore - the initialization should occur either in the start script of the system - or (even better) in the usrInit() part of system initialization. The - object file itself should be loaded only once, so linking it with the - kernel is a good idea, linking with each application is an extremely bad - dito. Make really sure that it's loaded _before_ any application that - uses it if You want to load it in the startup script. - - If You dont want to have #define's for the posix/stdio names - of the file/memory operations (i.e. no #define malloc save_malloc etc), - #define RECLAIM_NO_ALIAS in Your source before reclaim.h is included. -*/ - -#include <vxWorks.h> /* STATUS, size_t */ -#include <sockLib.h> /* struct sockaddr */ -#include <memLib.h> -#include <stdio.h> /* FILE */ - -#if defined(__STDC__) -#define _RECLAIM_DECL_FUN(RetType, FunName, ParamList) \ -extern RetType FunName ParamList -#define _RECLAIM_VOID_PTR void * -#define _RECLAIM_VOID_PARAM void -#define _RECLAIM_VOID_RETURN void -#elif defined(__cplusplus) -#define _RECLAIM_DECL_FUN(RetType, FunName, ParamList) \ -extern "C" RetType FunName ParamList -#define _RECLAIM_VOID_PTR void * -#define _RECLAIM_VOID_PARAM -#define _RECLAIM_VOID_RETURN void -#else -#define _RECLAIM_DECL_FUN(RetType, FunName, Ignore) extern RetType FunName() -#define DECLARE_FUNCTION_TYPE(RetType, Type, PList) typedef RetType (* Type)() -#define _RECLAIM_VOID_PTR char * -#define _RECLAIM_VOID_PARAM -#define _RECLAIM_VOID_RETURN -#endif /* __STDC__ / __cplusplus */ - -/* Initialize the facility, on a per system basis. */ -_RECLAIM_DECL_FUN(STATUS, reclaim_init, (_RECLAIM_VOID_PARAM)); - -/* File descriptor operations */ -_RECLAIM_DECL_FUN(int,save_open,(char *, int, ...)); -_RECLAIM_DECL_FUN(int,save_creat,(char *, int)); -_RECLAIM_DECL_FUN(int,save_socket,(int, int, int)); -_RECLAIM_DECL_FUN(int,save_accept,(int, struct sockaddr *, int *)); -_RECLAIM_DECL_FUN(int,save_close,(int)); -/* Interface to add an fd to what's reclaimed even though it's not open with - one of the above functions */ -_RECLAIM_DECL_FUN(_RECLAIM_VOID_RETURN, save_fd, (int fd)); -#ifndef RECLAIM_NO_ALIAS -#define open save_open -#define creat save_creat -#define socket save_socket -#define accept save_accept -#define close save_close -#endif -/* Stdio file operations */ -_RECLAIM_DECL_FUN(FILE *, save_fopen, (const char *, char *)); -_RECLAIM_DECL_FUN(FILE *, save_fdopen, (int, char *)); -_RECLAIM_DECL_FUN(FILE *, save_freopen, (char *, char *, FILE *)); -_RECLAIM_DECL_FUN(int, save_fclose, (FILE *)); -/* XXX Should do opendir/closedir too... */ -#ifndef RECLAIM_NO_ALIAS -#define fopen save_fopen -#define fdopen save_fdopen -#define freopen save_freopen -#define fclose save_fclose -#endif -/* Memory allocation */ -_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_malloc, (size_t)); -_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_calloc, (size_t, size_t)); -_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_realloc, - (_RECLAIM_VOID_PTR, size_t)); -_RECLAIM_DECL_FUN(void, save_free, (_RECLAIM_VOID_PTR)); -_RECLAIM_DECL_FUN(void, save_cfree, (_RECLAIM_VOID_PTR)); -#ifndef RECLAIM_NO_ALIAS -#define malloc save_malloc -#define calloc save_calloc -#define realloc save_realloc -#define free save_free -#define cfree save_cfree -#endif -/* Generic interfaces to malloc etc... */ -_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, plain_malloc, (size_t)); -_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, plain_realloc, - (_RECLAIM_VOID_PTR, size_t)); -_RECLAIM_DECL_FUN(void, plain_free, (_RECLAIM_VOID_PTR)); -#endif /* _RECLAIM_H */ - - - - diff --git a/erts/etc/vxworks/reclaim_private.h b/erts/etc/vxworks/reclaim_private.h deleted file mode 100644 index 4ed935bee2..0000000000 --- a/erts/etc/vxworks/reclaim_private.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -#ifndef _RECLAIM_PRIVATE_H -#define _RECLAIM_PRIVATE_H -/* - * Private header for the reclaim facility, also included in the emulator. - */ - -#include "reclaim.h" - -/* Typedefs for ANSI memory allocation function pointers */ -typedef void *(*MallocFunction)(size_t); -typedef void *(*ReallocFunction)(void *, size_t); -typedef void *(*CallocFunction)(size_t, size_t); -typedef void (*FreeFunction)(void *); -typedef STATUS (*CfreeFunction)(char *); - -/* Functions for internal use and use by the emulator */ -extern int reclaim_max_files(void); -extern void set_reclaim_free_function(FreeFunction f); -extern void save_delete_hook(FUNCPTR func, caddr_t parm); -extern void *save_malloc2(size_t size, MallocFunction mf); -extern void *save_calloc2(size_t nelem, size_t elsize, CallocFunction cf); -extern void *save_realloc2(void *optr, size_t size, ReallocFunction rf); -extern void save_free2(void *ptr, FreeFunction ff); -extern void save_cfree2(void *ptr, CfreeFunction ff); - -#endif /* _RECLAIM_PRIVATE_H */ diff --git a/erts/etc/vxworks/resolv.conf b/erts/etc/vxworks/resolv.conf deleted file mode 100644 index 85c89d64c4..0000000000 --- a/erts/etc/vxworks/resolv.conf +++ /dev/null @@ -1,6 +0,0 @@ -domain du.uab.ericsson.se -nameserver 134.138.176.16 -nameserver 136.225.254.224 -nameserver 134.138.128.25 -search du.uab.ericsson.se uab.ericsson.se ericsson.se -lookup bind file diff --git a/erts/etc/vxworks/vxcall.c b/erts/etc/vxworks/vxcall.c deleted file mode 100644 index 3362d05fc5..0000000000 --- a/erts/etc/vxworks/vxcall.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <vxWorks.h> -#include <symLib.h> -#include <sysSymTbl.h> -#include <a_out.h> - -extern char *malloc(); -static STATUS lookup(); - -/* - Little utility to convert from Unix' argv,argv calling conventions to - VxWorks' arg0,arg1,arg2,... - Will do limited argument parsing - no parenthesis around nor commas - between the args, which may be "-enclosed strings (without \ escapes), - '-enclosed characters (also no \ escapes), integers, or symbols. -*/ - -int vxcall(argc, argv) -int argc; -char **argv; -{ - int vxarg[10]; /* Max 10 args can be passed */ - FUNCPTR entry; - SYM_TYPE type; - int i, l; - -#ifdef DEBUG - fdprintf(2, "vxcall:"); - for (i = 1; i < argc; i++) - fdprintf(2, " %s", argv[i]); - fdprintf(2, "\n"); -#endif - if (lookup(argv[1], N_EXT | N_TEXT, (char **)&entry) != OK) - return(ERROR); - /* Do limited "C" parsing of the args */ - for (i = 0; i < 10; i++) { - if (i < argc - 2) { - switch (argv[i+2][0]) { - case '"': - l = strlen(argv[i+2]) - 1; - if (argv[i+2][l] != '"') - return(ERROR); - /* just strip the quotes - should do \escapes within... */ - vxarg[i] = (int)&argv[i+2][1]; - argv[i+2][l] = '\0'; - break; - case '\'': - if (argv[i+2][2] != '\'') - return(ERROR); - vxarg[i] = argv[i+2][1]; /* should do \escapes... */ - break; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - vxarg[i] = atoi(argv[i+2]); /* should do octal, hex, float.. */ - break; - default: - if (lookup(argv[i+2], 0, (char **)&vxarg[i]) != OK) - return(ERROR); - } - } else - vxarg[i] = 0; - } -#ifdef DEBUG - fdprintf(2, "calling 0x%x(0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x)\n", - entry, vxarg[0], vxarg[1], vxarg[2], vxarg[3], vxarg[4], - vxarg[5], vxarg[6], vxarg[7], vxarg[8], vxarg[9]); -#endif - return((*entry)(vxarg[0], vxarg[1], vxarg[2], vxarg[3], vxarg[4], - vxarg[5], vxarg[6], vxarg[7], vxarg[8], vxarg[9])); -} - -/* Entry point for unix:cmd in post-4.1 erlang - uses "sh -c 'cmd...'" */ -int sh(argc, argv) -int argc; -char **argv; -{ - int ll = strlen(argv[argc-1]) - 1; - -#ifdef DEBUG - int i; - fdprintf(2, "sh:"); - for (i = 1; i < argc; i++) - fdprintf(2, " %s", argv[i]); - fdprintf(2, "\n"); -#endif - if (strcmp(argv[1], "-c") != 0 || - argv[2][0] != '\'' || argv[argc-1][ll] != '\'') - return(ERROR); - argv[argc-1][ll] = '\0'; /* delete trailing ' */ - argv[2]++; /* skip leading ' (*after* the above!) */ - return(vxcall(argc-1, argv+1)); -} - -/* Lookup symbol; get address for text symbols, value (assuming int) - otherwise; return OK or ERROR on failure - Symbol name is null-terminated and without the leading '_' */ -STATUS -lookup(sym, stype, value) -char *sym, **value; -int stype; -{ - char buf[256]; - char *symname = buf; - int len, ret; - SYM_TYPE type; - - len = strlen(sym); - if (len > 254 && (symname = malloc(len+2)) == NULL) - return(ERROR); -#if defined _ARCH_PPC || defined SIMSPARCSOLARIS - /* GCC for PPC or SIMSPARC doesn't add a leading _ to symbols */ - strcpy(symname, sym); -#else - sprintf(symname, "_%s", sym); -#endif - ret = (stype != 0) ? - symFindByNameAndType(sysSymTbl, symname, value, &type, stype, stype) : - symFindByName(sysSymTbl, symname, value, &type); - if (symname != buf) - free(symname); - if (ret == OK && (type & N_TEXT) == 0) /* get value */ - *value = (char *)*((int *)*value); - return(ret); -} diff --git a/erts/etc/vxworks/wd_example.c b/erts/etc/vxworks/wd_example.c deleted file mode 100644 index 0e3a6a1cb2..0000000000 --- a/erts/etc/vxworks/wd_example.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * File: frc5te_wd.c - * Purpose: Watchdog NMI handling for FORCE 5TE - * - * Description: - * The watchdog handler routines are system specific. A program that - * wants to utilize a hardware watchdog should call wd_init and test - * the return value. If wd_init returns true (!0); there is a hardware - * watchdog, and that watchdog has been activated. If no watchdog exists, - * wd_init returns false (0). - * - * To keep the watchdog happy, call wd_reset at least every X seconds, - * where X is the number of seconds specified in the call to wd_init. - * - * The watchdog can be disarmed by setting the variable wd_disarmed to 1, - * and armed again by setting the same variable to 0. Watchdog status - * information can be retrieved using the function wd_status. - * - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include <frc5e.h> -#include <logLib.h> -#include <taskLib.h> -#include <sysLib.h> -#include <stdio.h> -#include "hw_watchdog.h" - -/* prototypes */ -extern sysNMIConnect(); -#ifdef __STDC__ -void wd_keeper(int); -void wd_nmi_int(UINT8); -void wd_status(void); -#else -void wd_keeper(); -void wd_nmi_int(); -void wd_status(); -#endif - -#define WD_NMI_MIN_DELAY 0.830 /* Min time before watchdog NMI (in seconds) */ -#define WD_RESET_FREQUENCY (WD_NMI_MIN_DELAY / 2) /* how often the timer is reset */ - -#define WD_KEEPER_STACK_SIZE 10000 - -/* global variables */ -extern int spTaskOptions; -static volatile int wd_count_startval; /* start value set by wd_init */ -static volatile int wd_count; /* counter for wd_keeper */ -volatile int wd_disarmed = 0; /* debug feature */ - -/* wd_init is executed to initialize the watchdog. It spawns the task */ -/* wd_keeper and returns true (non-zero) if a hardware watchdog exists, */ -/* or returns false (zero) otherwise. */ -int wd_init(timeout, prio) - int timeout, prio; -{ - taskSpawn("wd_keeper", prio, spTaskOptions, WD_KEEPER_STACK_SIZE, - (FUNCPTR)wd_keeper, timeout,0,0,0,0,0,0,0,0,0); - return !0; /* watchdog exists */ -} - - -/* wd_reset is called as an alive-signal from the supervisor process. */ -/* If there is no call to this function within a certain time, the */ -/* watchdog will reboot the system. */ -void wd_reset() -{ - wd_count = wd_count_startval; -} - - -/* wd_keeper runs as a separate task and resets the watchdog timer */ -/* before an NMI is generated. This task uses the counter wd_count to */ -/* decide if it should exit or keep resetting the timer. */ -/* Note! This task must run with higher priority than the application! */ -void wd_keeper(timeout) - int timeout; -{ - int wd_delay = sysClkRateGet() * WD_RESET_FREQUENCY; - wd_count_startval = (int)(timeout / WD_RESET_FREQUENCY); - wd_count = wd_count_startval; - - /* Connect and enable level 15 interrupts */ - sysNMIConnect((VOIDFUNCPTR) wd_nmi_int, WD_NMI, WD_NMI); - *(char *)FRC5CE_GEN_PURPOSE2_REG |= FRC5CE_NMI_ENABLE; - - while ((wd_count > 0) || wd_disarmed) { - *(char *)FRC5CE_VME_A32MAP_REG |= FRC5CE_WATCHDOG_ENABLE; - taskDelay(wd_delay); - if (!wd_disarmed) wd_count--; - else wd_count = wd_count_startval; - } - logMsg("Watchdog keeper exits. No alive signal from application in %d seconds.\n",wd_count_startval * WD_RESET_FREQUENCY,0,0,0,0,0); -} - - -/* wd_nmi_int is the function connected to the watchdog interrupt. */ -/* It will report the failure to reset the watchdog timer. */ -void wd_nmi_int(type) - UINT8 type; -{ - switch(type) { - case WD_NMI: - logMsg("Watchdog interrupt! System will reboot.\n",0,0,0,0,0,0); - break; - default: - logMsg("Bad type (%d) in call to watchdog interrupt handler.\n",type,0,0,0,0,0); - break; - } -} - - -/* wd_status displays the current value of the counter. */ -void wd_status() -{ - fprintf(stderr, "Watchdog is %sarmed.\n", wd_disarmed ? "dis" : ""); - fprintf(stderr, "Counter value: %d\n", wd_count); - fprintf(stderr, "Start value is: %d (%d seconds)\n", - wd_count_startval, (int)(wd_count_startval * WD_RESET_FREQUENCY)); -} diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex 80fc79f396..e46795e2b1 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex b78747bc84..66b7a011d6 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex cc170b86b2..fa70defd99 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex 45a409738c..2fa007f683 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 6400cda2b5..19cf856754 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex b2f3ab6c5b..48957a334f 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex 411fc8d524..55697cfe11 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex 7a1f896d36..d2f30fd9cd 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 5ee3d03fef..d36fdeba3f 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1385,14 +1385,7 @@ pathtype(Name) when is_list(Name) -> {unix, _} -> unix_pathtype(Name); {win32, _} -> - win32_pathtype(Name); - {vxworks, _} -> - case vxworks_first(Name) of - {device, _Rest, _Dev} -> - absolute; - _ -> - relative - end + win32_pathtype(Name) end. unix_pathtype(Name) -> @@ -1429,32 +1422,6 @@ win32_pathtype(Name) -> relative end. -vxworks_first(Name) -> - case Name of - [] -> - {not_device, [], []}; - [$/ | T] -> - vxworks_first2(device, T, [$/]); - [H | T] when is_list(H) -> - vxworks_first(H ++ T); - [H | T] -> - vxworks_first2(not_device, T, [H]) - end. - -vxworks_first2(Devicep, Name, FirstComp) -> - case Name of - [] -> - {Devicep, [], FirstComp}; - [$/ |T ] -> - {Devicep, [$/ | T], FirstComp}; - [$: | T]-> - {device, T, [$: | FirstComp]}; - [H | T] when is_list(H) -> - vxworks_first2(Devicep, H ++ T, FirstComp); - [H | T] -> - vxworks_first2(Devicep, T, [H | FirstComp]) - end. - normalize(Name, Acc) -> case Name of [List | Rest] when is_list(List) -> diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 1cbce5b80b..646acf5798 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -48,9 +48,7 @@ -deprecated([hash/2]). -% Get rid of autoimports of spawn to avoid clashes with ourselves. --compile({no_auto_import,[spawn/1]}). --compile({no_auto_import,[spawn/4]}). +%% Get rid of autoimports of spawn to avoid clashes with ourselves. -compile({no_auto_import,[spawn_link/1]}). -compile({no_auto_import,[spawn_link/4]}). -compile({no_auto_import,[spawn_opt/2]}). @@ -59,10 +57,2123 @@ -export_type([timestamp/0]). +-type ext_binary() :: binary(). -type timestamp() :: {MegaSecs :: non_neg_integer(), Secs :: non_neg_integer(), MicroSecs :: non_neg_integer()}. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Native code BIF stubs and their types +%% (BIF's actually implemented in this module goes last in the file) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Exports for all native code stubs +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-export([adler32/1, adler32/2, adler32_combine/3, append_element/2]). +-export([atom_to_binary/2, atom_to_list/1, binary_part/2, binary_part/3]). +-export([binary_to_atom/2, binary_to_existing_atom/2, binary_to_list/1]). +-export([binary_to_list/3, binary_to_term/1, binary_to_term/2]). +-export([bit_size/1, bitsize/1, bitstr_to_list/1, bitstring_to_list/1]). +-export([bump_reductions/1, byte_size/1, call_on_load_function/1]). +-export([cancel_timer/1, check_old_code/1, check_process_code/2, crc32/1]). +-export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). +-export([delete_module/1, demonitor/1, demonitor/2, display/1]). +-export([display_nl/0, display_string/1, dist_exit/3, erase/0, erase/1]). +-export([error/1, error/2, exit/1, exit/2, external_size/1]). +-export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]). +-export([float_to_list/1, fun_info/2, fun_to_list/1, function_exported/3]). +-export([garbage_collect/0, garbage_collect/1]). +-export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]). +-export([get_module_info/1, get_stacktrace/0, group_leader/0]). +-export([group_leader/2, halt/0, halt/1, halt/2, hash/2, hibernate/3]). +-export([integer_to_list/1, iolist_size/1, iolist_to_binary/1]). +-export([is_alive/0, is_builtin/3, is_process_alive/1, length/1, link/1]). +-export([list_to_atom/1, list_to_binary/1, list_to_bitstr/1]). +-export([list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1]). +-export([list_to_integer/1, list_to_pid/1, list_to_tuple/1, loaded/0]). +-export([localtime/0, make_ref/0, match_spec_test/3, md5/1, md5_final/1]). +-export([md5_init/0, md5_update/2, module_loaded/1, monitor/2]). +-export([monitor_node/2, monitor_node/3, nif_error/1, nif_error/2 +]). +-export([node/0, node/1, now/0, phash/2, phash2/1, phash2/2]). +-export([pid_to_list/1, port_close/1, port_command/2, port_command/3]). +-export([port_connect/2, port_control/3, port_get_data/1]). +-export([port_set_data/2, port_to_list/1, ports/0]). +-export([posixtime_to_universaltime/1, pre_loaded/0, prepare_loading/2]). +-export([process_display/2]). +-export([process_flag/3, process_info/1, processes/0, purge_module/1]). +-export([put/2, raise/3, read_timer/1, ref_to_list/1, register/2]). +-export([registered/0, resume_process/1, round/1, self/0, send_after/3]). +-export([seq_trace/2, seq_trace_print/1, seq_trace_print/2, setnode/2]). +-export([setnode/3, size/1, spawn/3, spawn_link/3, split_binary/2]). +-export([start_timer/3, suspend_process/2, system_monitor/0]). +-export([system_monitor/1, system_monitor/2, system_profile/0]). +-export([system_profile/2, throw/1, time/0, trace/3, trace_delivered/1]). +-export([trace_info/2, trunc/1, tuple_size/1, universaltime/0]). +-export([universaltime_to_posixtime/1, unlink/1, unregister/1, whereis/1]). + +-export([abs/1, append/2, element/2, get_module_info/2, hd/1, + is_atom/1, is_binary/1, is_bitstring/1, is_boolean/1, + is_float/1, is_function/1, is_function/2, is_integer/1, + is_list/1, is_number/1, is_pid/1, is_port/1, is_record/2, + is_record/3, is_reference/1, is_tuple/1, load_module/2, + load_nif/2, localtime_to_universaltime/2, make_fun/3, + make_tuple/2, make_tuple/3, nodes/1, open_port/2, + port_call/2, port_call/3, port_info/1, port_info/2, process_flag/2, + process_info/2, send/2, send/3, seq_trace_info/1, + setelement/3, spawn_opt/1, + statistics/1, subtract/2, system_flag/2, + term_to_binary/1, term_to_binary/2, tl/1, trace_pattern/2, + trace_pattern/3, tuple_to_list/1, system_info/1, + universaltime_to_localtime/1]). +-export([dt_get_tag/0, dt_get_tag_data/0, dt_prepend_vm_tag_data/1, dt_append_vm_tag_data/1, + dt_put_tag/1, dt_restore_tag/1, dt_spread_tag/1]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Simple native code BIFs +%%% These are here for the types/specs, the real implementation is in the C code. +%%% The first chunk is originally auto-generated from +%%% $ERL_TOP/lib/hipe/cerl/erl_bif_types.erl as released in R15B. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% types + +-type fun_info_item() :: + arity | + env | + index | + name | + module | + new_index | + new_uniq | + pid | + type | + uniq. + +-type seq_trace_info() :: + 'send' | + 'receive' | + 'print' | + 'timestamp' | + 'label' | + 'serial'. + +-type seq_trace_info_returns() :: + { seq_trace_info(), non_neg_integer() | + boolean() | + { non_neg_integer(), non_neg_integer() } } | + []. + +-type system_profile_option() :: + 'exclusive' | + 'runnable_ports' | + 'runnable_procs' | + 'scheduler'. + +-type system_monitor_option() :: + 'busy_port' | + 'busy_dist_port' | + {'long_gc', non_neg_integer()} | + {'large_heap', non_neg_integer()}. + + +-type raise_stacktrace() :: + [{module(), atom(), arity() | [term()]} | + {function(), [term()]}] | + [{module(), atom(), arity() | [term()], [{atom(),term()}]} | + {function(), [term()], [{atom(),term()}]}]. + +-type bitstring_list() :: + maybe_improper_list(byte() | bitstring() | bitstring_list(), bitstring() | []). + +-type trace_flag() :: + all | + send | + 'receive' | + procs | + call | + silent | + return_to | + running | + exiting | + garbage_collection | + timestamp | + cpu_timestamp | + arity | + set_on_spawn | + set_on_first_spawn | + set_on_link | + set_on_first_link | + {tracer, pid() | port()}. + +-type trace_info_item_result() :: + {traced, global | local | false | undefined} | + {match_spec, trace_match_spec() | false | undefined} | + {meta, pid() | port() | false | undefined | []} | + {meta_match_spec, trace_match_spec() | false | undefined} | + {call_count, non_neg_integer() | boolean() | undefined} | + {call_time, [{pid(), non_neg_integer(), + non_neg_integer(), non_neg_integer()}] | boolean() | undefined}. + +-type trace_info_flag() :: + send | + 'receive' | + set_on_spawn | + call | + return_to | + procs | + set_on_first_spawn | + set_on_link | + running | + garbage_collection | + timestamp | + arity. + +-type trace_info_return() :: + undefined | + {flags, [trace_info_flag()]} | + {tracer, pid() | port() | []} | + trace_info_item_result() | + {all, [ trace_info_item_result() ] | false | undefined}. + +%% Specs and stubs +%% adler32/1 +-spec erlang:adler32(Data) -> non_neg_integer() when + Data :: iodata(). +adler32(_Data) -> + erlang:nif_error(undefined). + +%% adler32/2 +-spec erlang:adler32(OldAdler, Data) -> non_neg_integer() when + OldAdler :: non_neg_integer(), + Data :: iodata(). +adler32(_OldAdler, _Data) -> + erlang:nif_error(undefined). + +%% adler32_combine/3 +-spec erlang:adler32_combine(FirstAdler, SecondAdler, SecondSize) -> non_neg_integer() when + FirstAdler :: non_neg_integer(), + SecondAdler :: non_neg_integer(), + SecondSize :: non_neg_integer(). +adler32_combine(_FirstAdler, _SecondAdler, _SecondSize) -> + erlang:nif_error(undefined). + +%% append_element/2 +-spec erlang:append_element(Tuple1, Term) -> Tuple2 when + Tuple1 :: tuple(), + Tuple2 :: tuple(), + Term :: term(). +append_element(_Tuple1, _Term) -> + erlang:nif_error(undefined). + +%% atom_to_binary/2 +-spec atom_to_binary(Atom, Encoding) -> binary() when + Atom :: atom(), + Encoding :: latin1 | unicode | utf8. +atom_to_binary(_Atom, _Encoding) -> + erlang:nif_error(undefined). + +%% atom_to_list/1 +-spec atom_to_list(Atom) -> string() when + Atom :: atom(). +atom_to_list(_Atom) -> + erlang:nif_error(undefined). + +%% binary_part/2 +%% Shadowed by erl_bif_types: erlang:binary_part/2 +-spec binary_part(Subject, PosLen) -> binary() when + Subject :: binary(), + PosLen :: {Start :: non_neg_integer(), Length :: integer()}. +binary_part(_Subject, _PosLen) -> + erlang:nif_error(undefined). + +%% binary_part/3 +%% Shadowed by erl_bif_types: erlang:binary_part/3 +-spec binary_part(Subject, Start, Length) -> binary() when + Subject :: binary(), + Start :: non_neg_integer(), + Length :: integer(). +binary_part(_Subject, _Start, _Length) -> + erlang:nif_error(undefined). + +%% binary_to_atom/2 +-spec binary_to_atom(Binary, Encoding) -> atom() when + Binary :: binary(), + Encoding :: latin1 | unicode | utf8. +binary_to_atom(_Binary, _Encoding) -> + erlang:nif_error(undefined). + +%% binary_to_existing_atom/2 +-spec binary_to_existing_atom(Binary, Encoding) -> atom() when + Binary :: binary(), + Encoding :: latin1 | unicode | utf8. +binary_to_existing_atom(_Binary, _Encoding) -> + erlang:nif_error(undefined). + +%% binary_to_list/1 +-spec binary_to_list(Binary) -> [byte()] when + Binary :: binary(). +binary_to_list(_Binary) -> + erlang:nif_error(undefined). + +%% binary_to_list/3 +-spec binary_to_list(Binary, Start, Stop) -> [byte()] when + Binary :: binary(), + Start :: pos_integer(), + Stop :: pos_integer(). +binary_to_list(_Binary, _Start, _Stop) -> + erlang:nif_error(undefined). + +%% binary_to_term/1 +-spec binary_to_term(Binary) -> term() when + Binary :: ext_binary(). +binary_to_term(_Binary) -> + erlang:nif_error(undefined). + +%% binary_to_term/2 +-spec binary_to_term(Binary, Opts) -> term() when + Binary :: ext_binary(), + Opts :: [safe]. +binary_to_term(_Binary, _Opts) -> + erlang:nif_error(undefined). + +%% bit_size/1 +%% Shadowed by erl_bif_types: erlang:bit_size/1 +-spec bit_size(Bitstring) -> non_neg_integer() when + Bitstring :: bitstring(). +bit_size(_Bitstring) -> + erlang:nif_error(undefined). + +%% bitsize/1 +-spec bitsize(P1) -> non_neg_integer() when + P1 :: bitstring(). +bitsize(_P1) -> + erlang:nif_error(undefined). + +%% bitstr_to_list/1 +-spec erlang:bitstr_to_list(P1) -> [byte() | bitstring()] when + P1 :: bitstring(). +bitstr_to_list(_P1) -> + erlang:nif_error(undefined). + +%% bitstring_to_list/1 +-spec bitstring_to_list(Bitstring) -> [byte() | bitstring()] when + Bitstring :: bitstring(). +bitstring_to_list(_Bitstring) -> + erlang:nif_error(undefined). + +%% bump_reductions/1 +-spec erlang:bump_reductions(Reductions) -> true when + Reductions :: pos_integer(). +bump_reductions(_Reductions) -> + erlang:nif_error(undefined). + +%% byte_size/1 +%% Shadowed by erl_bif_types: erlang:byte_size/1 +-spec byte_size(Bitstring) -> non_neg_integer() when + Bitstring :: bitstring(). +byte_size(_Bitstring) -> + erlang:nif_error(undefined). + +%% call_on_load_function/1 +-spec erlang:call_on_load_function(P1) -> term() when + P1 :: atom(). +call_on_load_function(_P1) -> + erlang:nif_error(undefined). + +%% cancel_timer/1 +-spec erlang:cancel_timer(TimerRef) -> Time | false when + TimerRef :: reference(), + Time :: non_neg_integer(). +cancel_timer(_TimerRef) -> + erlang:nif_error(undefined). + +%% check_old_code/1 +-spec check_old_code(Module) -> boolean() when + Module :: module(). +check_old_code(_Module) -> + erlang:nif_error(undefined). + +%% check_process_code/2 +-spec check_process_code(Pid, Module) -> boolean() when + Pid :: pid(), + Module :: module(). +check_process_code(_Pid, _Module) -> + erlang:nif_error(undefined). + +%% crc32/1 +-spec erlang:crc32(Data) -> non_neg_integer() when + Data :: iodata(). +crc32(_Data) -> + erlang:nif_error(undefined). + +%% crc32/2 +-spec erlang:crc32(OldCrc, Data) -> non_neg_integer() when + OldCrc :: non_neg_integer(), + Data :: iodata(). +crc32(_OldCrc, _Data) -> + erlang:nif_error(undefined). + +%% crc32_combine/3 +-spec erlang:crc32_combine(FirstCrc, SecondCrc, SecondSize) -> non_neg_integer() when + FirstCrc :: non_neg_integer(), + SecondCrc :: non_neg_integer(), + SecondSize :: non_neg_integer(). +crc32_combine(_FirstCrc, _SecondCrc, _SecondSize) -> + erlang:nif_error(undefined). + +%% date/0 +-spec date() -> Date when + Date :: calendar:date(). +date() -> + erlang:nif_error(undefined). + +%% decode_packet/3 +-spec erlang:decode_packet(Type, Bin, Options) -> + {ok, Packet, Rest} | + {more, Length} | + {error, Reason} when + Type :: 'raw' | 0 | 1 | 2 | 4 | 'asn1' | 'cdr' | 'sunrm' | 'fcgi' + | 'tpkt' | 'line' | 'http' | 'http_bin' | 'httph' | 'httph_bin', + Bin :: binary(), + Options :: [Opt], + Opt :: {packet_size, non_neg_integer()} + | {line_length, non_neg_integer()}, + Packet :: binary() | HttpPacket, + Rest :: binary(), + Length :: non_neg_integer() | undefined, + Reason :: term(), + HttpPacket :: HttpRequest + | HttpResponse + | HttpHeader + | 'http_eoh' + | HttpError, + HttpRequest :: {'http_request', HttpMethod, HttpUri, HttpVersion}, + HttpResponse :: {'http_response', HttpVersion, integer(), HttpString}, + HttpHeader :: {'http_header', + integer(), + HttpField, + Reserved :: term(), + Value :: HttpString}, + HttpError :: {'http_error', HttpString}, + HttpMethod :: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' + | 'TRACE' | HttpString, + HttpUri :: '*' + | { 'absoluteURI', + 'http' | 'https', + Host :: HttpString, + Port :: inet:port_number() | 'undefined', + Path :: HttpString} + | {'scheme', Scheme :: HttpString, HttpString} + | {'abs_path', HttpString} + | HttpString, + HttpVersion :: {Major :: non_neg_integer(), Minor :: non_neg_integer()}, + HttpField :: 'Cache-Control' + | 'Connection' + | 'Date' + | 'Pragma' + | 'Transfer-Encoding' + | 'Upgrade' + | 'Via' + | 'Accept' + | 'Accept-Charset' + | 'Accept-Encoding' + | 'Accept-Language' + | 'Authorization' + | 'From' + | 'Host' + | 'If-Modified-Since' + | 'If-Match' + | 'If-None-Match' + | 'If-Range' + | 'If-Unmodified-Since' + | 'Max-Forwards' + | 'Proxy-Authorization' + | 'Range' + | 'Referer' + | 'User-Agent' + | 'Age' + | 'Location' + | 'Proxy-Authenticate' + | 'Public' + | 'Retry-After' + | 'Server' + | 'Vary' + | 'Warning' + |'Www-Authenticate' + | 'Allow' + | 'Content-Base' + | 'Content-Encoding' + | 'Content-Language' + | 'Content-Length' + | 'Content-Location' + | 'Content-Md5' + | 'Content-Range' + | 'Content-Type' + | 'Etag' + | 'Expires' + | 'Last-Modified' + | 'Accept-Ranges' + | 'Set-Cookie' + | 'Set-Cookie2' + | 'X-Forwarded-For' + | 'Cookie' + | 'Keep-Alive' + | 'Proxy-Connection' + | HttpString, + HttpString :: string() | binary(). +decode_packet(_Type, _Bin, _Options) -> + erlang:nif_error(undefined). + +%% delete_module/1 +-spec delete_module(Module) -> true | undefined when + Module :: module(). +delete_module(_Module) -> + erlang:nif_error(undefined). + +%% demonitor/1 +-spec demonitor(MonitorRef) -> true when + MonitorRef :: reference(). +demonitor(_MonitorRef) -> + erlang:nif_error(undefined). + +%% demonitor/2 +-spec demonitor(MonitorRef, OptionList) -> boolean() when + MonitorRef :: reference(), + OptionList :: [Option], + Option :: flush | info. +demonitor(_MonitorRef, _OptionList) -> + erlang:nif_error(undefined). + +%% display/1 +-spec erlang:display(Term) -> true when + Term :: term(). +display(_Term) -> + erlang:nif_error(undefined). + +%% display_nl/0 +-spec erlang:display_nl() -> true. +display_nl() -> + erlang:nif_error(undefined). + +%% display_string/1 +-spec erlang:display_string(P1) -> true when + P1 :: string(). +display_string(_P1) -> + erlang:nif_error(undefined). + +%% dist_exit/3 +-spec erlang:dist_exit(P1, P2, P3) -> true when + P1 :: pid(), + P2 :: kill | noconnection | normal, + P3 :: pid() | port(). +dist_exit(_P1, _P2, _P3) -> + erlang:nif_error(undefined). + +%% dt_append_vm_tag_data/1 +-spec erlang:dt_append_vm_tag_data(IoData) -> IoDataRet when + IoData :: iodata(), + IoDataRet :: iodata(). +dt_append_vm_tag_data(_IoData) -> + erlang:nif_error(undefined). + +%% dt_get_tag/0 +-spec erlang:dt_get_tag() -> binary() | undefined. +dt_get_tag() -> + erlang:nif_error(undefined). + +%% dt_get_tag_data/0 +-spec erlang:dt_get_tag_data() -> binary() | undefined. +dt_get_tag_data() -> + erlang:nif_error(undefined). + +%% dt_prepend_vm_tag_data/1 +-spec erlang:dt_prepend_vm_tag_data(IoData) -> IoDataRet when + IoData :: iodata(), + IoDataRet :: iodata(). +dt_prepend_vm_tag_data(_IoData) -> + erlang:nif_error(undefined). + +%% dt_put_tag/1 +-spec erlang:dt_put_tag(IoData) -> binary() | undefined when + IoData :: iodata(). +dt_put_tag(_IoData) -> + erlang:nif_error(undefined). + +%% dt_restore_tag/1 +-spec erlang:dt_restore_tag(TagData) -> true when + TagData :: term(). +dt_restore_tag(_TagData) -> + erlang:nif_error(undefined). + +%% dt_spread_tag/1 +-spec erlang:dt_spread_tag(boolean()) -> TagData when + TagData :: term(). +dt_spread_tag(_Bool) -> + erlang:nif_error(undefined). + +%% erase/0 +-spec erase() -> [{Key, Val}] when + Key :: term(), + Val :: term(). +erase() -> + erlang:nif_error(undefined). + +%% erase/1 +-spec erase(Key) -> Val | undefined when + Key :: term(), + Val :: term(). +erase(_Key) -> + erlang:nif_error(undefined). + +%% error/1 +%% Shadowed by erl_bif_types: erlang:error/1 +-spec error(Reason) -> no_return() when + Reason :: term(). +error(_Reason) -> + erlang:nif_error(undefined). + +%% error/2 +%% Shadowed by erl_bif_types: erlang:error/2 +-spec error(Reason, Args) -> no_return() when + Reason :: term(), + Args :: [term()]. +error(_Reason, _Args) -> + erlang:nif_error(undefined). + +%% exit/1 +%% Shadowed by erl_bif_types: erlang:exit/1 +-spec exit(Reason) -> no_return() when + Reason :: term(). +exit(_Reason) -> + erlang:nif_error(undefined). + +%% exit/2 +-spec exit(Pid, Reason) -> true when + Pid :: pid() | port(), + Reason :: term(). +exit(_Pid, _Reason) -> + erlang:nif_error(undefined). + +%% external_size/1 +-spec erlang:external_size(Term) -> non_neg_integer() when + Term :: term(). +external_size(_Term) -> + erlang:nif_error(undefined). + +%% external_size/2 +-spec erlang:external_size(Term, Options) -> non_neg_integer() when + Term :: term(), + Options :: [{minor_version, Version :: non_neg_integer()}]. +external_size(_Term, _Options) -> + erlang:nif_error(undefined). + +%% finish_loading/2 +-spec erlang:finish_loading(PreparedCodeBinaries) -> ok | Error when + PreparedCodeBinaries :: [PreparedCodeBinary], + PreparedCodeBinary :: binary(), + ModuleList :: [module()], + Error :: {not_purged,ModuleList} | {on_load,ModuleList}. +finish_loading(_List) -> + erlang:nif_error(undefined). + +%% finish_after_on_load/2 +-spec erlang:finish_after_on_load(P1, P2) -> true when + P1 :: atom(), + P2 :: boolean(). +finish_after_on_load(_P1, _P2) -> + erlang:nif_error(undefined). + +%% float/1 +%% Shadowed by erl_bif_types: erlang:float/1 +-spec float(Number) -> float() when + Number :: number(). +float(_Number) -> + erlang:nif_error(undefined). + +%% float_to_list/1 +-spec float_to_list(Float) -> string() when + Float :: float(). +float_to_list(_Float) -> + erlang:nif_error(undefined). + +%% fun_info/2 +-spec erlang:fun_info(Fun, Item) -> {Item, Info} when + Fun :: function(), + Item :: fun_info_item(), + Info :: term(). +fun_info(_Fun, _Item) -> + erlang:nif_error(undefined). + +%% fun_to_list/1 +-spec erlang:fun_to_list(Fun) -> string() when + Fun :: function(). +fun_to_list(_Fun) -> + erlang:nif_error(undefined). + +%% function_exported/3 +-spec erlang:function_exported(Module, Function, Arity) -> boolean() when + Module :: module(), + Function :: atom(), + Arity :: arity(). +function_exported(_Module, _Function, _Arity) -> + erlang:nif_error(undefined). + +%% garbage_collect/0 +-spec garbage_collect() -> true. +garbage_collect() -> + erlang:nif_error(undefined). + +%% garbage_collect/1 +-spec garbage_collect(Pid) -> boolean() when + Pid :: pid(). +garbage_collect(_Pid) -> + erlang:nif_error(undefined). + +%% garbage_collect_message_area/0 +-spec erlang:garbage_collect_message_area() -> boolean(). +garbage_collect_message_area() -> + erlang:nif_error(undefined). + +%% get/0 +-spec get() -> [{Key, Val}] when + Key :: term(), + Val :: term(). +get() -> + erlang:nif_error(undefined). + +%% get/1 +-spec get(Key) -> Val | undefined when + Key :: term(), + Val :: term(). +get(_Key) -> + erlang:nif_error(undefined). + +%% get_keys/1 +-spec get_keys(Val) -> [Key] when + Val :: term(), + Key :: term(). +get_keys(_Val) -> + erlang:nif_error(undefined). + +%% get_module_info/1 +-spec erlang:get_module_info(P1) -> [{atom(), [{atom(), term()}]}] when + P1 :: atom(). +get_module_info(_P1) -> + erlang:nif_error(undefined). + +%% get_stacktrace/0 +-spec erlang:get_stacktrace() -> [stack_item()]. +get_stacktrace() -> + erlang:nif_error(undefined). + +%% group_leader/0 +-spec group_leader() -> pid(). +group_leader() -> + erlang:nif_error(undefined). + +%% group_leader/2 +-spec group_leader(GroupLeader, Pid) -> true when + GroupLeader :: pid(), + Pid :: pid(). +group_leader(_GroupLeader, _Pid) -> + erlang:nif_error(undefined). + +%% halt/0 +%% Shadowed by erl_bif_types: erlang:halt/0 +-spec halt() -> no_return(). +halt() -> + erlang:nif_error(undefined). + +%% halt/1 +%% Shadowed by erl_bif_types: erlang:halt/1 +-spec halt(Status) -> no_return() when + Status :: non_neg_integer() | 'abort' | string(). +halt(_Status) -> + erlang:nif_error(undefined). + +%% halt/2 +%% Shadowed by erl_bif_types: erlang:halt/2 +-spec halt(Status, Options) -> no_return() when + Status :: non_neg_integer() | 'abort' | string(), + Options :: [Option], + Option :: {flush, boolean()}. +halt(_Status, _Options) -> + erlang:nif_error(undefined). + +%% hash/2 +-spec erlang:hash(Term, Range) -> pos_integer() when + Term :: term(), + Range :: pos_integer(). +hash(_Term, _Range) -> + erlang:nif_error(undefined). + +%% hibernate/3 +-spec erlang:hibernate(Module, Function, Args) -> no_return() when + Module :: module(), + Function :: atom(), + Args :: [term()]. +hibernate(_Module, _Function, _Args) -> + erlang:nif_error(undefined). + +%% integer_to_list/1 +-spec integer_to_list(Integer) -> string() when + Integer :: integer(). +integer_to_list(_Integer) -> + erlang:nif_error(undefined). + +%% iolist_size/1 +-spec iolist_size(Item) -> non_neg_integer() when + Item :: iolist() | binary(). +iolist_size(_Item) -> + erlang:nif_error(undefined). + +%% iolist_to_binary/1 +-spec iolist_to_binary(IoListOrBinary) -> binary() when + IoListOrBinary :: iolist() | binary(). +iolist_to_binary(_IoListOrBinary) -> + erlang:nif_error(undefined). + +%% is_alive/0 +-spec is_alive() -> boolean(). +is_alive() -> + erlang:nif_error(undefined). + +%% is_builtin/3 +-spec erlang:is_builtin(Module, Function, Arity) -> boolean() when + Module :: module(), + Function :: atom(), + Arity :: arity(). +is_builtin(_Module, _Function, _Arity) -> + erlang:nif_error(undefined). + +%% is_process_alive/1 +-spec is_process_alive(Pid) -> boolean() when + Pid :: pid(). +is_process_alive(_Pid) -> + erlang:nif_error(undefined). + +%% length/1 +%% Shadowed by erl_bif_types: erlang:length/1 +-spec length(List) -> non_neg_integer() when + List :: [term()]. +length(_List) -> + erlang:nif_error(undefined). + +%% link/1 +-spec link(PidOrPort) -> true when + PidOrPort :: pid() | port(). +link(_PidOrPort) -> + erlang:nif_error(undefined). + +%% list_to_atom/1 +-spec list_to_atom(String) -> atom() when + String :: string(). +list_to_atom(_String) -> + erlang:nif_error(undefined). + +%% list_to_binary/1 +-spec list_to_binary(IoList) -> binary() when + IoList :: iolist(). +list_to_binary(_IoList) -> + erlang:nif_error(undefined). + +%% list_to_bitstr/1 +-spec erlang:list_to_bitstr(P1) -> bitstring() when + P1 :: bitstring_list(). +list_to_bitstr(_P1) -> + erlang:nif_error(undefined). + +%% list_to_bitstring/1 +-spec list_to_bitstring(BitstringList) -> bitstring() when + BitstringList :: bitstring_list(). +list_to_bitstring(_BitstringList) -> + erlang:nif_error(undefined). + +%% list_to_existing_atom/1 +-spec list_to_existing_atom(String) -> atom() when + String :: string(). +list_to_existing_atom(_String) -> + erlang:nif_error(undefined). + +%% list_to_float/1 +-spec list_to_float(String) -> float() when + String :: string(). +list_to_float(_String) -> + erlang:nif_error(undefined). + +%% list_to_integer/1 +-spec list_to_integer(String) -> integer() when + String :: string(). +list_to_integer(_String) -> + erlang:nif_error(undefined). + +%% list_to_pid/1 +-spec list_to_pid(String) -> pid() when + String :: string(). +list_to_pid(_String) -> + erlang:nif_error(undefined). + +%% list_to_tuple/1 +-spec list_to_tuple(List) -> tuple() when + List :: [term()]. +list_to_tuple(_List) -> + erlang:nif_error(undefined). + +%% loaded/0 +-spec erlang:loaded() -> [Module] when + Module :: module(). +loaded() -> + erlang:nif_error(undefined). + +%% localtime/0 +-spec erlang:localtime() -> DateTime when + DateTime :: calendar:datetime(). +localtime() -> + erlang:nif_error(undefined). + +%% make_ref/0 +-spec make_ref() -> reference(). +make_ref() -> + erlang:nif_error(undefined). + +%% match_spec_test/3 +-spec erlang:match_spec_test(P1, P2, P3) -> TestResult when + P1 :: [term()] | tuple(), + P2 :: term(), + P3 :: table | trace, + TestResult :: {ok, term(), [return_trace], [ {error | warning, string()} ]} | {error, [ {error | warning, string()} ]}. +match_spec_test(_P1, _P2, _P3) -> + erlang:nif_error(undefined). + +%% md5/1 +-spec erlang:md5(Data) -> Digest when + Data :: iodata(), + Digest :: binary(). +md5(_Data) -> + erlang:nif_error(undefined). + +%% md5_final/1 +-spec erlang:md5_final(Context) -> Digest when + Context :: binary(), + Digest :: binary(). +md5_final(_Context) -> + erlang:nif_error(undefined). + +%% md5_init/0 +-spec erlang:md5_init() -> Context when + Context :: binary(). +md5_init() -> + erlang:nif_error(undefined). + +%% md5_update/2 +-spec erlang:md5_update(Context, Data) -> NewContext when + Context :: binary(), + Data :: iodata(), + NewContext :: binary(). +md5_update(_Context, _Data) -> + erlang:nif_error(undefined). + +%% module_loaded/1 +-spec module_loaded(Module) -> boolean() when + Module :: module(). +module_loaded(_Module) -> + erlang:nif_error(undefined). + +%% monitor/2 +-spec monitor(Type, Item) -> MonitorRef when + Type :: process, + Item :: pid() | Module | {Module, Node}, + Module :: module(), + Node :: node(), + MonitorRef :: reference(). +monitor(_Type, _Item) -> + erlang:nif_error(undefined). + +%% monitor_node/2 +-spec monitor_node(Node, Flag) -> true when + Node :: node(), + Flag :: boolean(). +monitor_node(_Node, _Flag) -> + erlang:nif_error(undefined). + +%% monitor_node/3 +-spec erlang:monitor_node(Node, Flag, Options) -> true when + Node :: node(), + Flag :: boolean(), + Options :: [Option], + Option :: allow_passive_connect. +monitor_node(_Node, _Flag, _Options) -> + erlang:nif_error(undefined). + +%% nif_error/1 +%% Shadowed by erl_bif_types: erlang:nif_error/1 +-spec erlang:nif_error(Reason) -> no_return() when + Reason :: term(). +nif_error(_Reason) -> + erlang:nif_error(undefined). + +%% nif_error/2 +%% Shadowed by erl_bif_types: erlang:nif_error/2 +-spec erlang:nif_error(Reason, Args) -> no_return() when + Reason :: term(), + Args :: [term()]. +nif_error(_Reason, _Args) -> + erlang:nif_error(undefined). + +%% node/0 +%% Shadowed by erl_bif_types: erlang:node/0 +-spec node() -> Node when + Node :: node(). +node() -> + erlang:nif_error(undefined). + +%% node/1 +%% Shadowed by erl_bif_types: erlang:node/1 +-spec node(Arg) -> Node when + Arg :: pid() | port() | reference(), + Node :: node(). +node(_Arg) -> + erlang:nif_error(undefined). + +%% now/0 +-spec now() -> Timestamp when + Timestamp :: timestamp(). +now() -> + erlang:nif_error(undefined). + +%% phash/2 +-spec erlang:phash(Term, Range) -> Hash when + Term :: term(), + Range :: pos_integer(), + Hash :: pos_integer(). +phash(_Term, _Range) -> + erlang:nif_error(undefined). + +%% phash2/1 +-spec erlang:phash2(Term) -> Hash when + Term :: term(), + Hash :: non_neg_integer(). +phash2(_Term) -> + erlang:nif_error(undefined). + +%% phash2/2 +-spec erlang:phash2(Term, Range) -> Hash when + Term :: term(), + Range :: pos_integer(), + Hash :: non_neg_integer(). +phash2(_Term, _Range) -> + erlang:nif_error(undefined). + +%% pid_to_list/1 +-spec pid_to_list(Pid) -> string() when + Pid :: pid(). +pid_to_list(_Pid) -> + erlang:nif_error(undefined). + +%% port_close/1 +-spec port_close(Port) -> true when + Port :: port() | atom(). +port_close(_Port) -> + erlang:nif_error(undefined). + +%% port_command/2 +-spec port_command(Port, Data) -> true when + Port :: port() | atom(), + Data :: iodata(). +port_command(_Port, _Data) -> + erlang:nif_error(undefined). + +%% port_command/3 +-spec port_command(Port, Data, OptionList) -> boolean() when + Port :: port() | atom(), + Data :: iodata(), + OptionList :: [Option], + Option :: force | nosuspend. +port_command(_Port, _Data, _OptionList) -> + erlang:nif_error(undefined). + +%% port_connect/2 +-spec port_connect(Port, Pid) -> true when + Port :: port() | atom(), + Pid :: pid(). +port_connect(_Port, _Pid) -> + erlang:nif_error(undefined). + +%% port_control/3 +-spec port_control(Port, Operation, Data) -> Res when + Port :: port() | atom(), + Operation :: integer(), + Data :: iodata(), + Res :: string() | binary(). +port_control(_Port, _Operation, _Data) -> + erlang:nif_error(undefined). + +%% port_get_data/1 +-spec erlang:port_get_data(P1) -> term() when + P1 :: port() | atom(). +port_get_data(_P1) -> + erlang:nif_error(undefined). + +%% port_set_data/2 +-spec erlang:port_set_data(P1, P2) -> true when + P1 :: port() | atom(), + P2 :: term(). +port_set_data(_P1, _P2) -> + erlang:nif_error(undefined). + +%% port_to_list/1 +-spec erlang:port_to_list(Port) -> string() when + Port :: port(). +port_to_list(_Port) -> + erlang:nif_error(undefined). + +%% ports/0 +-spec erlang:ports() -> [port()]. +ports() -> + erlang:nif_error(undefined). + +%% posixtime_to_universaltime/1 +-spec erlang:posixtime_to_universaltime(P1) -> {calendar:date(), calendar:time()} when + P1 :: integer(). +posixtime_to_universaltime(_P1) -> + erlang:nif_error(undefined). + +%% prepare_loading/2 +-spec erlang:prepare_loading(Module, Code) -> PreparedCode | {error, Reason} when + Module :: module(), + Code :: binary(), + PreparedCode :: binary(), + Reason :: bad_file. +prepare_loading(_Module, _Code) -> + erlang:nif_error(undefined). + +%% pre_loaded/0 +-spec pre_loaded() -> [module()]. +pre_loaded() -> + erlang:nif_error(undefined). + +%% process_display/2 +-spec erlang:process_display(Pid, Type) -> true when + Pid :: pid(), + Type :: backtrace. +process_display(_Pid, _Type) -> + erlang:nif_error(undefined). + +%% process_flag/3 +-spec process_flag(Pid, Flag, Value) -> OldValue when + Pid :: pid(), + Flag :: save_calls, + Value :: non_neg_integer(), + OldValue :: non_neg_integer(). +process_flag(_Pid, _Flag, _Value) -> + erlang:nif_error(undefined). + +%% process_info/1 +-spec process_info(Pid) -> Info when + Pid :: pid(), + Info :: [InfoTuple] | undefined, + InfoTuple :: process_info_result_item(). +process_info(_Pid) -> + erlang:nif_error(undefined). + +%% processes/0 +-spec processes() -> [pid()]. +processes() -> + erlang:nif_error(undefined). + +%% purge_module/1 +-spec purge_module(Module) -> true when + Module :: atom(). +purge_module(_Module) -> + erlang:nif_error(undefined). + +%% put/2 +-spec put(Key, Val) -> term() when + Key :: term(), + Val :: term(). +put(_Key, _Val) -> + erlang:nif_error(undefined). + +%% raise/3 +-spec erlang:raise(Class, Reason, Stacktrace) -> no_return() when + Class :: error | exit | throw, + Reason :: term(), + Stacktrace :: raise_stacktrace(). +raise(_Class, _Reason, _Stacktrace) -> + erlang:nif_error(undefined). + +%% read_timer/1 +-spec erlang:read_timer(TimerRef) -> non_neg_integer() | false when + TimerRef :: reference(). +read_timer(_TimerRef) -> + erlang:nif_error(undefined). + +%% ref_to_list/1 +-spec erlang:ref_to_list(Ref) -> string() when + Ref :: reference(). +ref_to_list(_Ref) -> + erlang:nif_error(undefined). + +%% register/2 +-spec register(RegName, PidOrPort) -> true when + RegName :: atom(), + PidOrPort :: port() | pid(). +register(_RegName, _PidOrPort) -> + erlang:nif_error(undefined). + +%% registered/0 +-spec registered() -> [RegName] when + RegName :: atom(). +registered() -> + erlang:nif_error(undefined). + +%% resume_process/1 +-spec erlang:resume_process(Suspendee) -> true when + Suspendee :: pid(). +resume_process(_Suspendee) -> + erlang:nif_error(undefined). + +%% round/1 +%% Shadowed by erl_bif_types: erlang:round/1 +-spec round(Number) -> integer() when + Number :: number(). +round(_Number) -> + erlang:nif_error(undefined). + +%% self/0 +%% Shadowed by erl_bif_types: erlang:self/0 +-spec self() -> pid(). +self() -> + erlang:nif_error(undefined). + +%% send_after/3 +-spec erlang:send_after(Time, Dest, Msg) -> TimerRef when + Time :: non_neg_integer(), + Dest :: pid() | atom(), + Msg :: term(), + TimerRef :: reference(). +send_after(_Time, _Dest, _Msg) -> + erlang:nif_error(undefined). + +%% seq_trace/2 +-spec erlang:seq_trace(P1, P2) -> seq_trace_info_returns() | {term(), term(), term(), term(), term()} when + P1 :: atom(), + P2 :: boolean() | {integer(), integer()} | integer() | []. +seq_trace(_P1, _P2) -> + erlang:nif_error(undefined). + +%% seq_trace_print/1 +-spec erlang:seq_trace_print(P1) -> boolean() when + P1 :: term(). +seq_trace_print(_P1) -> + erlang:nif_error(undefined). + +%% seq_trace_print/2 +-spec erlang:seq_trace_print(P1, P2) -> boolean() when + P1 :: atom() | integer(), + P2 :: term(). +seq_trace_print(_P1, _P2) -> + erlang:nif_error(undefined). + +%% setnode/2 +-spec erlang:setnode(P1, P2) -> true when + P1 :: atom(), + P2 :: integer(). +setnode(_P1, _P2) -> + erlang:nif_error(undefined). + +%% setnode/3 +-spec erlang:setnode(P1, P2, P3) -> true when + P1 :: atom(), + P2 :: port(), + P3 :: {term(), term(), term(), term()}. +setnode(_P1, _P2, _P3) -> + erlang:nif_error(undefined). + +%% size/1 +%% Shadowed by erl_bif_types: erlang:size/1 +-spec size(Item) -> non_neg_integer() when + Item :: tuple() | binary(). +size(_Item) -> + erlang:nif_error(undefined). + +%% spawn/3 +-spec spawn(Module, Function, Args) -> pid() when + Module :: module(), + Function :: atom(), + Args :: [term()]. +spawn(_Module, _Function, _Args) -> + erlang:nif_error(undefined). + +%% spawn_link/3 +-spec spawn_link(Module, Function, Args) -> pid() when + Module :: module(), + Function :: atom(), + Args :: [term()]. +spawn_link(_Module, _Function, _Args) -> + erlang:nif_error(undefined). + +%% split_binary/2 +-spec split_binary(Bin, Pos) -> {binary(), binary()} when + Bin :: binary(), + Pos :: non_neg_integer(). +split_binary(_Bin, _Pos) -> + erlang:nif_error(undefined). + +%% start_timer/3 +-spec erlang:start_timer(Time, Dest, Msg) -> TimerRef when + Time :: non_neg_integer(), + Dest :: pid() | atom(), + Msg :: term(), + TimerRef :: reference(). +start_timer(_Time, _Dest, _Msg) -> + erlang:nif_error(undefined). + +%% suspend_process/2 +-spec erlang:suspend_process(Suspendee, OptList) -> boolean() when + Suspendee :: pid(), + OptList :: [Opt], + Opt :: unless_suspending | asynchronous. +suspend_process(_Suspendee, _OptList) -> + erlang:nif_error(undefined). + +%% system_monitor/0 +-spec erlang:system_monitor() -> MonSettings when + MonSettings :: undefined | { MonitorPid, Options }, + MonitorPid :: pid(), + Options :: [ system_monitor_option() ]. +system_monitor() -> + erlang:nif_error(undefined). + +%% system_monitor/1 +-spec erlang:system_monitor(Arg) -> MonSettings when + Arg :: undefined | { MonitorPid, Options }, + MonSettings :: undefined | { MonitorPid, Options }, + MonitorPid :: pid(), + Options :: [ system_monitor_option() ]. +system_monitor(_Arg) -> + erlang:nif_error(undefined). + +%% system_monitor/2 +-spec erlang:system_monitor(MonitorPid, Options) -> MonSettings when + MonitorPid :: pid(), + Options :: [ system_monitor_option() ], + MonSettings :: undefined | { OldMonitorPid, OldOptions }, + OldMonitorPid :: pid(), + OldOptions :: [ system_monitor_option() ]. +system_monitor(_MonitorPid, _Options) -> + erlang:nif_error(undefined). + +%% system_profile/0 +-spec erlang:system_profile() -> ProfilerSettings when + ProfilerSettings :: undefined | { ProfilerPid, Options}, + ProfilerPid :: pid() | port(), + Options :: [ system_profile_option() ]. +system_profile() -> + erlang:nif_error(undefined). + +%% system_profile/2 +-spec erlang:system_profile(ProfilerPid, Options) -> ProfilerSettings when + ProfilerPid :: pid() | port() | undefined, + Options :: [ system_profile_option() ], + ProfilerSettings :: undefined | { pid() | port(), [ system_profile_option() ]}. +system_profile(_ProfilerPid, _Options) -> + erlang:nif_error(undefined). + +%% throw/1 +%% Shadowed by erl_bif_types: erlang:throw/1 +-spec throw(Any) -> no_return() when + Any :: term(). +throw(_Any) -> + erlang:nif_error(undefined). + +%% time/0 +-spec time() -> Time when + Time :: calendar:time(). +time() -> + erlang:nif_error(undefined). + +%% trace/3 +-spec erlang:trace(PidSpec, How, FlagList) -> integer() when + PidSpec :: pid() | existing | new | all, + How :: boolean(), + FlagList :: [trace_flag()]. +trace(_PidSpec, _How, _FlagList) -> + erlang:nif_error(undefined). + +%% trace_delivered/1 +-spec erlang:trace_delivered(Tracee) -> Ref when + Tracee :: pid() | all, + Ref :: reference(). +trace_delivered(_Tracee) -> + erlang:nif_error(undefined). + +%% trace_info/2 +-spec erlang:trace_info(PidOrFunc, Item) -> Res when + PidOrFunc :: pid() | new | {Module, Function, Arity} | on_load, + Module :: module(), + Function :: atom(), + Arity :: arity(), + Item :: flags | tracer | traced | match_spec | meta | meta_match_spec | call_count | call_time | all, + Res :: trace_info_return(). +trace_info(_PidOrFunc, _Item) -> + erlang:nif_error(undefined). + +%% trunc/1 +%% Shadowed by erl_bif_types: erlang:trunc/1 +-spec trunc(Number) -> integer() when + Number :: number(). +trunc(_Number) -> + erlang:nif_error(undefined). + +%% tuple_size/1 +%% Shadowed by erl_bif_types: erlang:tuple_size/1 +-spec tuple_size(Tuple) -> non_neg_integer() when + Tuple :: tuple(). +tuple_size(_Tuple) -> + erlang:nif_error(undefined). + +%% universaltime/0 +-spec erlang:universaltime() -> DateTime when + DateTime :: calendar:datetime(). +universaltime() -> + erlang:nif_error(undefined). + +%% universaltime_to_posixtime/1 +-spec erlang:universaltime_to_posixtime(P1) -> integer() when + P1 :: {calendar:date(), calendar:time()}. +universaltime_to_posixtime(_P1) -> + erlang:nif_error(undefined). + +%% unlink/1 +-spec unlink(Id) -> true when + Id :: pid() | port(). +unlink(_Id) -> + erlang:nif_error(undefined). + +%% unregister/1 +-spec unregister(RegName) -> true when + RegName :: atom(). +unregister(_RegName) -> + erlang:nif_error(undefined). + +%% whereis/1 +-spec whereis(RegName) -> pid() | port() | undefined when + RegName :: atom(). +whereis(_RegName) -> + erlang:nif_error(undefined). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% More complicated native code BIFs +%%% These are here for the types/specs, the real implementation is in the C code. +%%% This chunk is handwritten, i.e. contains more complicated specs. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% types and specs + +%% Shadowed by erl_bif_types: erlang:abs/1 +-spec abs(Float) -> float() when + Float :: float(); + (Int) -> non_neg_integer() when + Int :: integer(). +abs(_Number) -> + erlang:nif_error(undefined). + +%% Not documented +%% Shadowed by erl_bif_types: erlang:append/2 +-spec erlang:append(List,Tail) -> maybe_improper_list() when + List :: [term()], + Tail :: term(). +append(_List,_Tail) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:element/2 +-spec element(N, Tuple) -> term() when + N :: pos_integer(), + Tuple :: tuple(). +element(_N, _Tuple) -> + erlang:nif_error(undefined). + +%% Not documented +-spec erlang:get_module_info(Module, Item) -> ModuleInfo when + Module :: atom(), + Item :: module | imports | exports | functions | attributes | compile | native_addresses, + ModuleInfo :: atom() | [] | [{atom(), arity()}] | [{atom(), term()}] | [{atom(), arity(), integer()}]. +get_module_info(_Module, _Item) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:hd/1 +-spec hd(List) -> term() when + List :: [term(), ...]. +hd(_List) -> + erlang:nif_error(undefined). + +%% erlang:info/1 no longer exists! + +%% Shadowed by erl_bif_types: erlang:is_atom/1 +-spec is_atom(Term) -> boolean() when + Term :: term(). +is_atom(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_binary/1 +-spec is_binary(Term) -> boolean() when + Term :: term(). +is_binary(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_bitstring/1 +-spec is_bitstring(Term) -> boolean() when + Term :: term(). +is_bitstring(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_boolean/1 +-spec is_boolean(Term) -> boolean() when + Term :: term(). +is_boolean(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_float/1 +-spec is_float(Term) -> boolean() when + Term :: term(). +is_float(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_function/1 +-spec is_function(Term) -> boolean() when + Term :: term(). +is_function(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_function/2 +-spec is_function(Term, Arity) -> boolean() when + Term :: term(), + Arity :: arity(). +is_function(_Term, _Arity) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_integer/1 +-spec is_integer(Term) -> boolean() when + Term :: term(). +is_integer(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_list/1 +-spec is_list(Term) -> boolean() when + Term :: term(). +is_list(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_number/1 +-spec is_number(Term) -> boolean() when + Term :: term(). +is_number(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_pid/1 +-spec is_pid(Term) -> boolean() when + Term :: term(). +is_pid(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_port/1 +-spec is_port(Term) -> boolean() when + Term :: term(). +is_port(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_record/2 +-spec is_record(Term,RecordTag) -> boolean() when + Term :: term(), + RecordTag :: atom(). +is_record(_Term,_RecordTag) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_record/3 +-spec is_record(Term,RecordTag,Size) -> boolean() when + Term :: term(), + RecordTag :: atom(), + Size :: non_neg_integer(). +is_record(_Term,_RecordTag,_Size) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_reference/1 +-spec is_reference(Term) -> boolean() when + Term :: term(). +is_reference(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_tuple/1 +-spec is_tuple(Term) -> boolean() when + Term :: term(). +is_tuple(_Term) -> + erlang:nif_error(undefined). + +-spec load_module(Module, Binary) -> {module, Module} | {error, Reason} when + Module :: module(), + Binary :: binary(), + Reason :: badfile | not_purged | on_load. +load_module(Mod, Code) -> + case erlang:prepare_loading(Mod, Code) of + {error,_}=Error -> + Error; + Bin when erlang:is_binary(Bin) -> + case erlang:finish_loading([Bin]) of + ok -> + {module,Mod}; + {Error,[Mod]} -> + {error,Error} + end + end. + +-spec erlang:load_nif(Path, LoadInfo) -> ok | Error when + Path :: string(), + LoadInfo :: term(), + Error :: {error, {Reason, Text :: string()}}, + Reason :: load_failed | bad_lib | load | reload | upgrade | old_code. +load_nif(_Path, _LoadInfo) -> + erlang:nif_error(undefined). + +-spec erlang:localtime_to_universaltime(Localtime, IsDst) -> Universaltime when + Localtime :: calendar:datetime(), + Universaltime :: calendar:datetime(), + IsDst :: true | false | undefined. +localtime_to_universaltime(_Localtime, _IsDst) -> + erlang:nif_error(undefined). + +%% CHECK! Why the strange very thorough specification of the error +%% condition with disallowed arity in erl_bif_types? +%% Not documented +-spec erlang:make_fun(Module, Function, Arity) -> function() when + Module :: atom(), + Function :: atom(), + Arity :: arity(). +make_fun(_Module,_Function, _Arity) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:make_tuple/2 +-spec erlang:make_tuple(Arity, InitialValue) -> tuple() when + Arity :: arity(), + InitialValue :: term(). +make_tuple(_Arity,_InitialValue) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:make_tuple/3 +-spec erlang:make_tuple(Arity, DefaultValue, InitList) -> tuple() when + Arity :: arity(), + DefaultValue :: term(), + InitList :: [{Position :: pos_integer(), term()}]. +make_tuple(_Arity,_DefaultValue,_InitList) -> + erlang:nif_error(undefined). + +-spec nodes(Arg) -> Nodes when + Arg :: NodeType | [NodeType], + NodeType :: visible | hidden | connected | this | known, + Nodes :: [node()]. +nodes(_Arg) -> + erlang:nif_error(undefined). + +-spec open_port(PortName, PortSettings) -> port() when + PortName :: {spawn, Command :: string()} | + {spawn_driver, Command :: [byte()]} | + {spawn_executable, FileName :: file:name() } | + {fd, In :: non_neg_integer(), Out :: non_neg_integer()}, + PortSettings :: [Opt], + Opt :: {packet, N :: 1 | 2 | 4} + | stream + | {line, L :: non_neg_integer()} + | {cd, Dir :: string()} + | {env, Env :: [{Name :: string(), Val :: string() | false}]} + | {args, [string() | binary()]} + | {arg0, string() | binary()} + | exit_status + | use_stdio + | nouse_stdio + | stderr_to_stdout + | in + | out + | binary + | eof. +open_port(_PortName,_PortSettings) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:port_call/2 +-spec erlang:port_call(Port, Data) -> term() when + Port :: port() | atom(), + Data :: term(). +port_call(_Port, _Data) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:port_call/3 +-spec erlang:port_call(Port, Operation, Data) -> term() when + Port :: port() | atom(), + Operation :: integer(), + Data :: term(). +port_call(_Port, _Operation, _Data) -> + erlang:nif_error(undefined). + +-type port_info_item() :: + registered_name | + id | + connected | + links | + name | + input | + output | + os_pid. + +-type port_info_result_item() :: + {registered_name, RegName :: atom()} | + {id, Index :: non_neg_integer()} | + {connected, Pid :: pid()} | + {links, Pids :: [pid()]} | + {name, String :: string()} | + {input, Bytes :: non_neg_integer()} | + {output, Bytes :: non_neg_integer()} | + {os_pid, OsPid :: non_neg_integer() | 'undefined'}. + +%% Shadowed by erl_bif_types: erlang:port_info/1 +-spec erlang:port_info(Port) -> Result when + Port :: port() | atom(), + Result :: [port_info_result_item()] | undefined. +port_info(_Result) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:port_info/2 +-spec erlang:port_info(Port, Item) -> Result when + Port :: port() | atom(), + Item :: port_info_item(), + Result :: port_info_result_item() | undefined. +port_info(_Result, _Item) -> + erlang:nif_error(undefined). + +-type priority_level() :: + low | normal | high | max. + +-spec process_flag(trap_exit, Boolean) -> OldBoolean when + Boolean :: boolean(), + OldBoolean :: boolean(); + (error_handler, Module) -> OldModule when + Module :: atom(), + OldModule :: atom(); + (min_heap_size, MinHeapSize) -> OldMinHeapSize when + MinHeapSize :: non_neg_integer(), + OldMinHeapSize :: non_neg_integer(); + (min_bin_vheap_size, MinBinVHeapSize) -> OldMinBinVHeapSize when + MinBinVHeapSize :: non_neg_integer(), + OldMinBinVHeapSize :: non_neg_integer(); + (priority, Level) -> OldLevel when + Level :: priority_level(), + OldLevel :: priority_level(); + (save_calls, N) -> OldN when + N :: 0..10000, + OldN :: 0..10000; + (sensitive, Boolean) -> OldBoolean when + Boolean :: boolean(), + OldBoolean :: boolean(); + %% Deliberately not documented. + ({monitor_nodes, term()}, term()) -> term(); + (monitor_nodes, term()) -> term(). + +process_flag(_Flag, _Value) -> + erlang:nif_error(undefined). + +-type process_info_item() :: + backtrace | + binary | + catchlevel | + current_function | + current_location | + current_stacktrace | + dictionary | + error_handler | + garbage_collection | + group_leader | + heap_size | + initial_call | + links | + last_calls | + memory | + message_que_len | + messages | + min_heap_size | + min_bin_vheap_size | + monitored_by | + monitors | + priority | + reductions | + registered_name | + sequential_trace_token | + stack_size | + status | + suspending | + total_heap_size | + trace | + trap_exit. + +-type process_info_result_item() :: + {backtrace, Bin :: binary()} | + {binary, BinInfo :: [{non_neg_integer(), + non_neg_integer(), + non_neg_integer()}]} | + {catchlevel, CatchLevel :: non_neg_integer()} | + {current_function, + {Module :: module(), Function :: atom(), Arity :: arity()}} | + {current_location, + {Module :: module(), Function :: atom(), Arity :: arity(), + Location :: [{file, Filename :: string()} | % not a stack_item()! + {line, Line :: pos_integer()}]}} | + {current_stacktrace, Stack :: [stack_item()]} | + {dictionary, Dictionary :: [{Key :: term(), Value :: term()}]} | + {error_handler, Module :: module()} | + {garbage_collection, GCInfo :: [{atom(),non_neg_integer()}]} | + {group_leader, GroupLeader :: pid()} | + {heap_size, Size :: non_neg_integer()} | + {initial_call, mfa()} | + {links, Pids :: [pid()]} | + {last_calls, false | (Calls :: [mfa()])} | + {memory, Size :: non_neg_integer()} | + {message_que_len, MessageQueueLen :: non_neg_integer()} | + {messages, MessageQueue :: [term()]} | + {min_heap_size, MinHeapSize :: non_neg_integer()} | + {min_bin_vheap_size, MinBinVHeapSize :: non_neg_integer()} | + {monitored_by, Pids :: [pid()]} | + {monitors, + Monitors :: [{process, Pid :: pid() | + {RegName :: atom(), Node :: node()}}]} | + {priority, Level :: priority_level()} | + {reductions, Number :: non_neg_integer()} | + {registered_name, Atom :: atom()} | + {sequential_trace_token, [] | (SequentialTraceToken :: term())} | + {stack_size, Size :: non_neg_integer()} | + {status, Status :: exiting | garbage_collecting | waiting | running | runnable | suspended} | + {suspending, + SuspendeeList :: [{Suspendee :: pid(), + ActiveSuspendCount :: non_neg_integer(), + OutstandingSuspendCount ::non_neg_integer()}]} | + {total_heap_size, Size :: non_neg_integer()} | + {trace, InternalTraceFlags :: non_neg_integer()} | + {trap_exit, Boolean :: boolean()}. + +-type stack_item() :: + {Module :: module(), + Function :: atom(), + Arity :: arity() | (Args :: [term()]), + Location :: [{file, Filename :: string()} | + {line, Line :: pos_integer()}]}. + +-spec process_info(Pid, Item) -> + InfoTuple | [] | undefined when + Pid :: pid(), + Item :: process_info_item(), + InfoTuple :: process_info_result_item(); + (Pid, ItemList) -> InfoTupleList | [] | undefined when + Pid :: pid(), + ItemList :: [Item], + Item :: process_info_item(), + InfoTupleList :: [InfoTuple], + InfoTuple :: process_info_result_item(). +process_info(_Pid,_ItemSpec) -> + erlang:nif_error(undefined). + +-spec erlang:send(Dest, Msg) -> Msg when + Dest :: dst(), + Msg :: term(). +send(_Dest,_Msg) -> + erlang:nif_error(undefined). + +-spec erlang:send(Dest, Msg, Options) -> Res when + Dest :: dst(), + Msg :: term(), + Options :: [nosuspend | noconnect], + Res :: ok | nosuspend | noconnect. +send(_Dest,_Msg,_Options) -> + erlang:nif_error(undefined). + +%% Not documented +-spec erlang:seq_trace_info(send) -> {send, boolean()}; + ('receive') -> {'receive', boolean()}; + (print) -> {print, boolean()}; + (timestamp) -> {timestamp, boolean()}; + (label) -> [] | {label, non_neg_integer()}; + (serial) -> [] | {serial, {non_neg_integer(), non_neg_integer()}}. +seq_trace_info(_What) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:setelement/3 +-spec setelement(Index, Tuple1, Value) -> Tuple2 when + Index :: pos_integer(), + Tuple1 :: tuple(), + Tuple2 :: tuple(), + Value :: term(). +setelement(_Index, _Tuple1, _Value) -> + erlang:nif_error(undefined). + +-spec erlang:spawn_opt({Module, Function, Args, Options}) -> pid() | {pid(), reference()} when + Module :: module(), + Function :: atom(), + Args :: [term()], + Options :: [Option], + Option :: link | monitor | {priority, Level} + | {fullsweep_after, Number :: non_neg_integer()} + | {min_heap_size, Size :: non_neg_integer()} + | {min_bin_vheap_size, VSize :: non_neg_integer()}, + Level :: low | normal | high. +spawn_opt(_Tuple) -> + erlang:nif_error(undefined). + +-spec statistics(context_switches) -> {ContextSwitches,0} when + ContextSwitches :: non_neg_integer(); + (exact_reductions) -> {Total_Exact_Reductions, + Exact_Reductions_Since_Last_Call} when + Total_Exact_Reductions :: non_neg_integer(), + Exact_Reductions_Since_Last_Call :: non_neg_integer(); + (garbage_collection) -> {Number_of_GCs, Words_Reclaimed, 0} when + Number_of_GCs :: non_neg_integer(), + Words_Reclaimed :: non_neg_integer(); + (io) -> {{input, Input}, {output, Output}} when + Input :: non_neg_integer(), + Output :: non_neg_integer(); + (reductions) -> {Total_Reductions, + Reductions_Since_Last_Call} when + Total_Reductions :: non_neg_integer(), + Reductions_Since_Last_Call :: non_neg_integer(); + (run_queue) -> non_neg_integer(); + (runtime) -> {Total_Run_Time, Time_Since_Last_Call} when + Total_Run_Time :: non_neg_integer(), + Time_Since_Last_Call :: non_neg_integer(); + (scheduler_wall_time) -> [{SchedulerId, ActiveTime, TotalTime}] | undefined when + SchedulerId :: pos_integer(), + ActiveTime :: non_neg_integer(), + TotalTime :: non_neg_integer(); + (wall_clock) -> {Total_Wallclock_Time, + Wallclock_Time_Since_Last_Call} when + Total_Wallclock_Time :: non_neg_integer(), + Wallclock_Time_Since_Last_Call :: non_neg_integer(). +statistics(_Item) -> + erlang:nif_error(undefined). + +%% Not documented +%% Shadowed by erl_bif_types: erlang:subtract/2 +-spec erlang:subtract([term()], [term()]) -> [term()]. +subtract(_,_) -> + erlang:nif_error(undefined). + +-type scheduler_bind_type() :: + 'no_node_processor_spread' | + 'no_node_thread_spread' | + 'no_spread' | + 'processor_spread' | + 'spread' | + 'thread_spread' | + 'thread_no_node_processor_spread' | + 'unbound'. + +-spec erlang:system_flag(backtrace_depth, Depth) -> OldDepth when + Depth :: non_neg_integer(), + OldDepth :: non_neg_integer(); + (cpu_topology, CpuTopology) -> OldCpuTopology when + CpuTopology :: cpu_topology(), + OldCpuTopology :: cpu_topology(); + (fullsweep_after, Number) -> OldNumber when + Number :: non_neg_integer(), + OldNumber :: non_neg_integer(); + (min_heap_size, MinHeapSize) -> OldMinHeapSize when + MinHeapSize :: non_neg_integer(), + OldMinHeapSize :: non_neg_integer(); + (min_bin_vheap_size, MinBinVHeapSize) -> + OldMinBinVHeapSize when + MinBinVHeapSize :: non_neg_integer(), + OldMinBinVHeapSize :: non_neg_integer(); + (multi_scheduling, BlockState) -> OldBlockState when + BlockState :: block | unblock, + OldBlockState :: block | unblock | enabled; + (scheduler_bind_type, How) -> OldBindType when + How :: scheduler_bind_type() | default_bind, + OldBindType :: scheduler_bind_type(); + (scheduler_wall_time, Boolean) -> OldBoolean when + Boolean :: boolean(), + OldBoolean :: boolean(); + (schedulers_online, SchedulersOnline) -> + OldSchedulersOnline when + SchedulersOnline :: pos_integer(), + OldSchedulersOnline :: pos_integer(); + (trace_control_word, TCW) -> OldTCW when + TCW :: non_neg_integer(), + OldTCW :: non_neg_integer(); + %% These are deliberately not documented + (internal_cpu_topology, term()) -> term(); + (sequential_tracer, pid() | port() | false) -> pid() | port() | false; + (1,0) -> true. + +system_flag(_Flag, _Value) -> + erlang:nif_error(undefined). + +-spec term_to_binary(Term) -> ext_binary() when + Term :: term(). +term_to_binary(_Term) -> + erlang:nif_error(undefined). + +-spec term_to_binary(Term, Options) -> ext_binary() when + Term :: term(), + Options :: [compressed | + {compressed, Level :: 0..9} | + {minor_version, Version :: 0..1} ]. +term_to_binary(_Term, _Options) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:tl/1 +-spec tl(List) -> term() when + List :: [term(), ...]. +tl(_List) -> + erlang:nif_error(undefined). + +-type trace_pattern_mfa() :: + {atom(),atom(),arity() | '_'} | on_load. +-type trace_match_spec() :: + [{[term()] | '_' ,[term()],[term()]}]. + +-spec erlang:trace_pattern(MFA, MatchSpec) -> non_neg_integer() when + MFA :: trace_pattern_mfa(), + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean() + | restart + | pause. +trace_pattern(_MFA, _MatchSpec) -> + erlang:nif_error(undefined). + +-type trace_pattern_flag() :: + global | local | + meta | {meta, Pid :: pid()} | + call_count | + call_time. + +-spec erlang:trace_pattern(MFA, MatchSpec, FlagList) -> non_neg_integer() when + MFA :: trace_pattern_mfa(), + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean() + | restart + | pause, + FlagList :: [ trace_pattern_flag() ]. +trace_pattern(_MFA, _MatchSpec, _FlagList) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:tuple_to_list/1 +-spec tuple_to_list(Tuple) -> [term()] when + Tuple :: tuple(). +tuple_to_list(_Tuple) -> + erlang:nif_error(undefined). + +-type cpu_topology() :: + [LevelEntry :: level_entry()] | undefined. +-type level_entry() :: + {LevelTag :: level_tag(), SubLevel :: sub_level()} + | {LevelTag :: level_tag(), + InfoList :: info_list(), + SubLevel :: sub_level()}. +-type level_tag() :: core | node | processor | thread. +-type sub_level() :: [LevelEntry :: level_entry()] + | (LogicalCpuId :: {logical, non_neg_integer()}). +-type info_list() :: []. + +%% Note: changing the ordering number of a clause will change the docs! +%% Shadowed by erl_bif_types: erlang:system_info/1 +-spec erlang:system_info + (allocated_areas) -> [ tuple() ]; + (allocator) -> + {Allocator, Version, Features, Settings} when + Allocator :: undefined | glibc, + Version :: [non_neg_integer()], + Features :: [atom()], + Settings :: [{Subsystem :: atom(), + [{Parameter :: atom(), + Value :: term()}]}]; + (alloc_util_allocators) -> [Alloc] when + Alloc :: atom(); + ({allocator, Alloc}) -> [_] when %% More or less anything + Alloc :: atom(); + ({allocator_sizes, Alloc}) -> [_] when %% More or less anything + Alloc :: atom(); + (build_type) -> opt | debug | purify | quantify | purecov | + gcov | valgrind | gprof | lcnt; + (c_compiler_used) -> {atom(), term()}; + (check_io) -> [_]; + (compat_rel) -> integer(); + (cpu_topology) -> CpuTopology when + CpuTopology :: cpu_topology(); + ({cpu_topology, defined | detected | used}) -> CpuTopology when + CpuTopology :: cpu_topology(); + (creation) -> integer(); + (debug_compiled) -> boolean(); + (dist) -> binary(); + (dist_ctrl) -> {Node :: node(), + ControllingEntity :: port() | pid()}; + (driver_version) -> string(); + (dynamic_trace) -> none | dtrace | systemtap; + (dynamic_trace_probes) -> boolean(); + (elib_malloc) -> false; + (dist_buf_busy_limit) -> non_neg_integer(); + (fullsweep_after) -> {fullsweep_after, non_neg_integer()}; + (garbage_collection) -> [{atom(), integer()}]; + (heap_sizes) -> [non_neg_integer()]; + (heap_type) -> private; + (info) -> binary(); + (kernel_poll) -> boolean(); + (loaded) -> binary(); + (logical_processors | + logical_processors_available | + logical_processors_online) -> unknown | pos_integer(); + (machine) -> string(); + (min_heap_size) -> {min_heap_size, MinHeapSize :: pos_integer()}; + (min_bin_vheap_size) -> {min_bin_vheap_size, + MinBinVHeapSize :: pos_integer()}; + (modified_timing_level) -> integer() | undefined; + (multi_scheduling) -> disabled | blocked | enabled; + (multi_scheduling_blockers) -> [PID :: pid()]; + (otp_release) -> string(); + (process_count) -> pos_integer(); + (process_limit) -> pos_integer(); + (procs) -> binary(); + (scheduler_bind_type) -> spread | + processor_spread | + thread_spread | + thread_no_node_processor_spread | + no_node_processor_spread | + no_node_thread_spread | + no_spread | + unbound; + (scheduler_bindings) -> tuple(); + (scheduler_id) -> SchedulerId :: pos_integer(); + (schedulers | schedulers_online) -> pos_integer(); + (smp_support) -> boolean(); + (system_version) -> string(); + (system_architecture) -> string(); + (threads) -> boolean(); + (thread_pool_size) -> non_neg_integer(); + (trace_control_word) -> non_neg_integer(); + (update_cpu_info) -> changed | unchanged; + (version) -> string(); + (wordsize | {wordsize, internal} | {wordsize, external}) -> 4 | 8. +system_info(_Item) -> + erlang:nif_error(undefined). + +-spec erlang:universaltime_to_localtime(Universaltime) -> Localtime when + Localtime :: calendar:datetime(), + Universaltime :: calendar:datetime(). +universaltime_to_localtime(_Universaltime) -> + erlang:nif_error(undefined). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% End of native code BIFs +%%% Actual Erlang implementation of some BIF's follow +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%-------------------------------------------------------------------------- -spec apply(Fun, Args) -> term() when @@ -71,6 +2182,7 @@ apply(Fun, Args) -> erlang:apply(Fun, Args). +%% Shadowed by erl_bif_types: erlang:apply/3 -spec apply(Module, Function, Args) -> term() when Module :: module(), Function :: atom(), @@ -82,42 +2194,42 @@ apply(Mod, Name, Args) -> -spec spawn(Fun) -> pid() when Fun :: function(). -spawn(F) when is_function(F) -> - spawn(erlang, apply, [F, []]); -spawn({M,F}=MF) when is_atom(M), is_atom(F) -> - spawn(erlang, apply, [MF, []]); +spawn(F) when erlang:is_function(F) -> + erlang:spawn(erlang, apply, [F, []]); +spawn({M,F}=MF) when erlang:is_atom(M), erlang:is_atom(F) -> + erlang:spawn(erlang, apply, [MF, []]); spawn(F) -> erlang:error(badarg, [F]). -spec spawn(Node, Fun) -> pid() when Node :: node(), Fun :: function(). -spawn(N, F) when N =:= node() -> - spawn(F); -spawn(N, F) when is_function(F) -> - spawn(N, erlang, apply, [F, []]); -spawn(N, {M,F}=MF) when is_atom(M), is_atom(F) -> - spawn(N, erlang, apply, [MF, []]); +spawn(N, F) when N =:= erlang:node() -> + erlang:spawn(F); +spawn(N, F) when erlang:is_function(F) -> + erlang:spawn(N, erlang, apply, [F, []]); +spawn(N, {M,F}=MF) when erlang:is_atom(M), erlang:is_atom(F) -> + erlang:spawn(N, erlang, apply, [MF, []]); spawn(N, F) -> erlang:error(badarg, [N, F]). -spec spawn_link(Fun) -> pid() when Fun :: function(). -spawn_link(F) when is_function(F) -> - spawn_link(erlang, apply, [F, []]); -spawn_link({M,F}=MF) when is_atom(M), is_atom(F) -> - spawn_link(erlang, apply, [MF, []]); +spawn_link(F) when erlang:is_function(F) -> + erlang:spawn_link(erlang, apply, [F, []]); +spawn_link({M,F}=MF) when erlang:is_atom(M), erlang:is_atom(F) -> + erlang:spawn_link(erlang, apply, [MF, []]); spawn_link(F) -> erlang:error(badarg, [F]). -spec spawn_link(Node, Fun) -> pid() when Node :: node(), Fun :: function(). -spawn_link(N, F) when N =:= node() -> +spawn_link(N, F) when N =:= erlang:node() -> spawn_link(F); -spawn_link(N, F) when is_function(F) -> +spawn_link(N, F) when erlang:is_function(F) -> spawn_link(N, erlang, apply, [F, []]); -spawn_link(N, {M,F}=MF) when is_atom(M), is_atom(F) -> +spawn_link(N, {M,F}=MF) when erlang:is_atom(M), erlang:is_atom(F) -> spawn_link(N, erlang, apply, [MF, []]); spawn_link(N, F) -> erlang:error(badarg, [N, F]). @@ -126,7 +2238,7 @@ spawn_link(N, F) -> -spec spawn_monitor(Fun) -> {pid(), reference()} when Fun :: function(). -spawn_monitor(F) when is_function(F, 0) -> +spawn_monitor(F) when erlang:is_function(F, 0) -> erlang:spawn_opt({erlang,apply,[F,[]],[monitor]}); spawn_monitor(F) -> erlang:error(badarg, [F]). @@ -135,7 +2247,9 @@ spawn_monitor(F) -> Module :: module(), Function :: atom(), Args :: [term()]. -spawn_monitor(M, F, A) when is_atom(M), is_atom(F), is_list(A) -> +spawn_monitor(M, F, A) when erlang:is_atom(M), + erlang:is_atom(F), + erlang:is_list(A) -> erlang:spawn_opt({M,F,A,[monitor]}); spawn_monitor(M, F, A) -> erlang:error(badarg, [M,F,A]). @@ -148,9 +2262,9 @@ spawn_monitor(M, F, A) -> | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()}, Level :: low | normal | high. -spawn_opt(F, O) when is_function(F) -> +spawn_opt(F, O) when erlang:is_function(F) -> spawn_opt(erlang, apply, [F, []], O); -spawn_opt({M,F}=MF, O) when is_atom(M), is_atom(F) -> +spawn_opt({M,F}=MF, O) when erlang:is_atom(M), erlang:is_atom(F) -> spawn_opt(erlang, apply, [MF, []], O); spawn_opt({M,F,A}, O) -> % For (undocumented) backward compatibility spawn_opt(M, F, A, O); @@ -166,11 +2280,11 @@ spawn_opt(F, O) -> | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()}, Level :: low | normal | high. -spawn_opt(N, F, O) when N =:= node() -> +spawn_opt(N, F, O) when N =:= erlang:node() -> spawn_opt(F, O); -spawn_opt(N, F, O) when is_function(F) -> +spawn_opt(N, F, O) when erlang:is_function(F) -> spawn_opt(N, erlang, apply, [F, []], O); -spawn_opt(N, {M,F}=MF, O) when is_atom(M), is_atom(F) -> +spawn_opt(N, {M,F}=MF, O) when erlang:is_atom(M), erlang:is_atom(F) -> spawn_opt(N, erlang, apply, [MF, []], O); spawn_opt(N, F, O) -> erlang:error(badarg, [N, F, O]). @@ -182,9 +2296,14 @@ spawn_opt(N, F, O) -> Module :: module(), Function :: atom(), Args :: [term()]. -spawn(N,M,F,A) when N =:= node(), is_atom(M), is_atom(F), is_list(A) -> - spawn(M,F,A); -spawn(N,M,F,A) when is_atom(N), is_atom(M), is_atom(F) -> +spawn(N,M,F,A) when N =:= erlang:node(), + erlang:is_atom(M), + erlang:is_atom(F), + erlang:is_list(A) -> + erlang:spawn(M,F,A); +spawn(N,M,F,A) when erlang:is_atom(N), + erlang:is_atom(M), + erlang:is_atom(F) -> case is_well_formed_list(A) of true -> ok; @@ -192,9 +2311,9 @@ spawn(N,M,F,A) when is_atom(N), is_atom(M), is_atom(F) -> erlang:error(badarg, [N, M, F, A]) end, case catch gen_server:call({net_kernel,N}, - {spawn,M,F,A,group_leader()}, + {spawn,M,F,A,erlang:group_leader()}, infinity) of - Pid when is_pid(Pid) -> + Pid when erlang:is_pid(Pid) -> Pid; Error -> case remote_spawn_error(Error, {no_link, N, M, F, A, []}) of @@ -212,9 +2331,14 @@ spawn(N,M,F,A) -> Module :: module(), Function :: atom(), Args :: [term()]. -spawn_link(N,M,F,A) when N =:= node(), is_atom(M), is_atom(F), is_list(A) -> - spawn_link(M,F,A); -spawn_link(N,M,F,A) when is_atom(N), is_atom(M), is_atom(F) -> +spawn_link(N,M,F,A) when N =:= erlang:node(), + erlang:is_atom(M), + erlang:is_atom(F), + erlang:is_list(A) -> + erlang:spawn_link(M,F,A); +spawn_link(N,M,F,A) when erlang:is_atom(N), + erlang:is_atom(M), + erlang:is_atom(F) -> case is_well_formed_list(A) of true -> ok; @@ -222,9 +2346,9 @@ spawn_link(N,M,F,A) when is_atom(N), is_atom(M), is_atom(F) -> erlang:error(badarg, [N, M, F, A]) end, case catch gen_server:call({net_kernel,N}, - {spawn_link,M,F,A,group_leader()}, + {spawn_link,M,F,A,erlang:group_leader()}, infinity) of - Pid when is_pid(Pid) -> + Pid when erlang:is_pid(Pid) -> Pid; Error -> case remote_spawn_error(Error, {link, N, M, F, A, []}) of @@ -268,11 +2392,13 @@ spawn_opt(M, F, A, Opts) -> | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()}, Level :: low | normal | high. -spawn_opt(N, M, F, A, O) when N =:= node(), - is_atom(M), is_atom(F), is_list(A), - is_list(O) -> +spawn_opt(N, M, F, A, O) when N =:= erlang:node(), + erlang:is_atom(M), erlang:is_atom(F), + erlang:is_list(A), erlang:is_list(O) -> spawn_opt(M, F, A, O); -spawn_opt(N, M, F, A, O) when is_atom(N), is_atom(M), is_atom(F) -> +spawn_opt(N, M, F, A, O) when erlang:is_atom(N), + erlang:is_atom(M), + erlang:is_atom(F) -> case {is_well_formed_list(A), is_well_formed_list(O)} of {true, true} -> ok; @@ -291,9 +2417,9 @@ spawn_opt(N, M, F, A, O) when is_atom(N), is_atom(M), is_atom(F) -> {no_link,[]}, O), case catch gen_server:call({net_kernel,N}, - {spawn_opt,M,F,A,NO,L,group_leader()}, + {spawn_opt,M,F,A,NO,L,erlang:group_leader()}, infinity) of - Pid when is_pid(Pid) -> + Pid when erlang:is_pid(Pid) -> Pid; Error -> case remote_spawn_error(Error, {L, N, M, F, A, NO}) of @@ -331,11 +2457,11 @@ is_well_formed_list(_) -> crasher(Node,Mod,Fun,Args,[],Reason) -> error_logger:warning_msg("** Can not start ~w:~w,~w on ~w **~n", [Mod,Fun,Args,Node]), - exit(Reason); + erlang:exit(Reason); crasher(Node,Mod,Fun,Args,Opts,Reason) -> error_logger:warning_msg("** Can not start ~w:~w,~w (~w) on ~w **~n", [Mod,Fun,Args,Opts,Node]), - exit(Reason). + erlang:exit(Reason). -spec erlang:yield() -> 'true'. yield() -> @@ -356,7 +2482,7 @@ disconnect_node(Node) -> Item :: arity | env | index | name | module | new_index | new_uniq | pid | type | uniq, Info :: term(). -fun_info(Fun) when is_function(Fun) -> +fun_info(Fun) when erlang:is_function(Fun) -> Keys = [type,env,arity,name,uniq,index,new_uniq,new_index,module,pid], fun_info_1(Keys, Fun, []). @@ -388,11 +2514,9 @@ send_nosuspend(Pid, Msg, Opts) -> _ -> false end. --spec erlang:localtime_to_universaltime({Date1, Time1}) -> {Date2, Time2} when - Date1 :: calendar:date(), - Date2 :: calendar:date(), - Time1 :: calendar:time(), - Time2 :: calendar:time(). +-spec erlang:localtime_to_universaltime(Localtime) -> Universaltime when + Localtime :: calendar:datetime(), + Universaltime :: calendar:datetime(). localtime_to_universaltime(Localtime) -> erlang:localtime_to_universaltime(Localtime, undefined). @@ -412,25 +2536,25 @@ suspend_process(P) -> %% reactivate the command. %% --spec dlink(pid() | port()) -> 'true'. +-spec erlang:dlink(pid() | port()) -> 'true'. dlink(Pid) -> - case net_kernel:connect(node(Pid)) of - true -> link(Pid); - false -> erlang:dist_exit(self(), noconnection, Pid), true + case net_kernel:connect(erlang:node(Pid)) of + true -> erlang:link(Pid); + false -> erlang:dist_exit(erlang:self(), noconnection, Pid), true end. %% Can this ever happen? --spec dunlink(identifier()) -> 'true'. +-spec erlang:dunlink(identifier()) -> 'true'. dunlink(Pid) -> - case net_kernel:connect(node(Pid)) of - true -> unlink(Pid); + case net_kernel:connect(erlang:node(Pid)) of + true -> erlang:unlink(Pid); false -> true end. dmonitor_node(Node, Flag, []) -> case net_kernel:connect(Node) of true -> erlang:monitor_node(Node, Flag, []); - false -> self() ! {nodedown, Node}, true + false -> erlang:self() ! {nodedown, Node}, true end; dmonitor_node(Node, Flag, Opts) -> @@ -438,31 +2562,31 @@ dmonitor_node(Node, Flag, Opts) -> true -> case net_kernel:passive_cnct(Node) of true -> erlang:monitor_node(Node, Flag, Opts); - false -> self() ! {nodedown, Node}, true + false -> erlang:self() ! {nodedown, Node}, true end; _ -> dmonitor_node(Node,Flag,[]) end. dgroup_leader(Leader, Pid) -> - case net_kernel:connect(node(Pid)) of - true -> group_leader(Leader, Pid); + case net_kernel:connect(erlang:node(Pid)) of + true -> erlang:group_leader(Leader, Pid); false -> true %% bad arg ? end. dexit(Pid, Reason) -> - case net_kernel:connect(node(Pid)) of - true -> exit(Pid, Reason); + case net_kernel:connect(erlang:node(Pid)) of + true -> erlang:exit(Pid, Reason); false -> true end. -dsend(Pid, Msg) when is_pid(Pid) -> - case net_kernel:connect(node(Pid)) of +dsend(Pid, Msg) when erlang:is_pid(Pid) -> + case net_kernel:connect(erlang:node(Pid)) of true -> erlang:send(Pid, Msg); false -> Msg end; -dsend(Port, Msg) when is_port(Port) -> - case net_kernel:connect(node(Port)) of +dsend(Port, Msg) when erlang:is_port(Port) -> + case net_kernel:connect(erlang:node(Port)) of true -> erlang:send(Port, Msg); false -> Msg end; @@ -473,13 +2597,13 @@ dsend({Name, Node}, Msg) -> ignored -> Msg % Not distributed. end. -dsend(Pid, Msg, Opts) when is_pid(Pid) -> - case net_kernel:connect(node(Pid)) of +dsend(Pid, Msg, Opts) when erlang:is_pid(Pid) -> + case net_kernel:connect(erlang:node(Pid)) of true -> erlang:send(Pid, Msg, Opts); false -> ok end; -dsend(Port, Msg, Opts) when is_port(Port) -> - case net_kernel:connect(node(Port)) of +dsend(Port, Msg, Opts) when erlang:is_port(Port) -> + case net_kernel:connect(erlang:node(Port)) of true -> erlang:send(Port, Msg, Opts); false -> ok end; @@ -490,21 +2614,23 @@ dsend({Name, Node}, Msg, Opts) -> ignored -> ok % Not distributed. end. --spec dmonitor_p('process', pid() | {atom(),atom()}) -> reference(). +-spec erlang:dmonitor_p('process', pid() | {atom(),atom()}) -> reference(). dmonitor_p(process, ProcSpec) -> %% ProcSpec = pid() | {atom(),atom()} %% ProcSpec CANNOT be an atom because a locally registered process %% is never handled here. Node = case ProcSpec of - {S,N} when is_atom(S), is_atom(N), N =/= node() -> N; - _ when is_pid(ProcSpec) -> node(ProcSpec) + {S,N} when erlang:is_atom(S), + erlang:is_atom(N), + N =/= erlang:node() -> N; + _ when erlang:is_pid(ProcSpec) -> erlang:node(ProcSpec) end, case net_kernel:connect(Node) of true -> erlang:monitor(process, ProcSpec); false -> - Ref = make_ref(), - self() ! {'DOWN', Ref, process, ProcSpec, noconnection}, + Ref = erlang:make_ref(), + erlang:self() ! {'DOWN', Ref, process, ProcSpec, noconnection}, Ref end. @@ -512,7 +2638,7 @@ dmonitor_p(process, ProcSpec) -> %% Trap function used when modified timing has been enabled. %% --spec delay_trap(Result, timeout()) -> Result. +-spec erlang:delay_trap(Result, timeout()) -> Result. delay_trap(Result, 0) -> erlang:yield(), Result; delay_trap(Result, Timeout) -> receive after Timeout -> Result end. @@ -526,12 +2652,12 @@ delay_trap(Result, Timeout) -> receive after Timeout -> Result end. -spec erlang:set_cookie(Node, Cookie) -> true when Node :: node(), Cookie :: atom(). -set_cookie(Node, C) when Node =/= nonode@nohost, is_atom(Node) -> - case is_atom(C) of +set_cookie(Node, C) when Node =/= nonode@nohost, erlang:is_atom(Node) -> + case erlang:is_atom(C) of true -> auth:set_cookie(Node, C); false -> - error(badarg) + erlang:error(badarg) end. -spec erlang:get_cookie() -> Cookie | nocookie when @@ -545,7 +2671,8 @@ get_cookie() -> integer_to_list(I, 10) -> erlang:integer_to_list(I); integer_to_list(I, Base) - when is_integer(I), is_integer(Base), Base >= 2, Base =< 1+$Z-$A+10 -> + when erlang:is_integer(I), erlang:is_integer(Base), + Base >= 2, Base =< 1+$Z-$A+10 -> if I < 0 -> [$-|integer_to_list(-I, Base, [])]; true -> @@ -575,9 +2702,10 @@ integer_to_list(I0, Base, R0) -> list_to_integer(L, 10) -> erlang:list_to_integer(L); list_to_integer(L, Base) - when is_list(L), is_integer(Base), Base >= 2, Base =< 1+$Z-$A+10 -> + when erlang:is_list(L), erlang:is_integer(Base), + Base >= 2, Base =< 1+$Z-$A+10 -> case list_to_integer_sign(L, Base) of - I when is_integer(I) -> + I when erlang:is_integer(I) -> I; Fault -> erlang:error(Fault, [L,Base]) @@ -587,7 +2715,7 @@ list_to_integer(L, Base) -> list_to_integer_sign([$-|[_|_]=L], Base) -> case list_to_integer(L, Base, 0) of - I when is_integer(I) -> + I when erlang:is_integer(I) -> -I; I -> I @@ -600,13 +2728,13 @@ list_to_integer_sign(_, _) -> badarg. list_to_integer([D|L], Base, I) - when is_integer(D), D >= $0, D =< $9, D < Base+$0 -> + when erlang:is_integer(D), D >= $0, D =< $9, D < Base+$0 -> list_to_integer(L, Base, I*Base + D-$0); list_to_integer([D|L], Base, I) - when is_integer(D), D >= $A, D < Base+$A-10 -> + when erlang:is_integer(D), D >= $A, D < Base+$A-10 -> list_to_integer(L, Base, I*Base + D-$A+10); list_to_integer([D|L], Base, I) - when is_integer(D), D >= $a, D < Base+$a-10 -> + when erlang:is_integer(D), D >= $a, D < Base+$a-10 -> list_to_integer(L, Base, I*Base + D-$a+10); list_to_integer([], _, I) -> I; @@ -618,7 +2746,8 @@ list_to_integer(_, _, _) -> %% erlang:demonitor(Ref, [flush]) traps to %% erlang:flush_monitor_message(Ref, Res) when %% it needs to flush a monitor message. -flush_monitor_message(Ref, Res) when is_reference(Ref), is_atom(Res) -> +flush_monitor_message(Ref, Res) when erlang:is_reference(Ref), + erlang:is_atom(Res) -> receive {_, Ref, _, _, _} -> ok after 0 -> ok end, Res. @@ -644,7 +2773,7 @@ set_cpu_topology(CpuTopology) -> cput_e2i_clvl({logical, _}, _PLvl) -> #cpu.logical; cput_e2i_clvl([E | _], PLvl) -> - case element(1, E) of + case erlang:element(1, E) of node -> case PLvl of 0 -> #cpu.node; #cpu.processor -> #cpu.processor_node @@ -713,7 +2842,7 @@ cput_e2i({thread, TL}, Nid, PId, #cpu{thread = T0} = CPU, PLvl, #cpu.thread, cput_e2i(TL, Nid, PId, CPU#cpu{thread = T0+1}, #cpu.thread, Lvl, Res); cput_e2i({logical, ID}, _Nid, PId, #cpu{processor=P, core=C, thread=T} = CPU, PLvl, #cpu.logical, Res) - when PLvl < #cpu.logical, is_integer(ID), 0 =< ID, ID < 65536 -> + when PLvl < #cpu.logical, erlang:is_integer(ID), 0 =< ID, ID < 65536 -> [CPU#cpu{processor = case P of -1 -> PId+1; _ -> P end, core = case C of -1 -> 0; _ -> C end, thread = case T of -1 -> 0; _ -> T end, @@ -738,9 +2867,9 @@ cput_i2e([], _Frst, _Lvl, _TM) -> cput_i2e([#cpu{logical = LID}| _], _Frst, Lvl, _TM) when Lvl == #cpu.logical -> {logical, LID}; cput_i2e([#cpu{} = I | Is], Frst, Lvl, TM) -> - cput_i2e(element(Lvl, I), Frst, Is, [I], Lvl, TM). + cput_i2e(erlang:element(Lvl, I), Frst, Is, [I], Lvl, TM). -cput_i2e(V, Frst, [I | Is], SameV, Lvl, TM) when V =:= element(Lvl, I) -> +cput_i2e(V, Frst, [I | Is], SameV, Lvl, TM) when V =:= erlang:element(Lvl, I) -> cput_i2e(V, Frst, Is, [I | SameV], Lvl, TM); cput_i2e(-1, true, [], SameV, Lvl, TM) -> cput_i2e(rvrs(SameV), true, Lvl+1, TM); @@ -754,10 +2883,10 @@ cput_i2e(_V, _Frst, Is, SameV, Lvl, TM) -> [{cput_i2e_tag(Lvl, TM), cput_i2e(rvrs(SameV), true, Lvl+1, TM)} | cput_i2e(Is, false, Lvl, TM)]. -cput_i2e_tag_map() -> list_to_tuple([cpu | record_info(fields, cpu)]). +cput_i2e_tag_map() -> erlang:list_to_tuple([cpu | record_info(fields, cpu)]). cput_i2e_tag(Lvl, TM) -> - case element(Lvl, TM) of processor_node -> node; Other -> Other end. + case erlang:element(Lvl, TM) of processor_node -> node; Other -> Other end. rvrs([_] = L) -> L; rvrs(Xs) -> rvrs(Xs, []). @@ -776,7 +2905,7 @@ rvrs([X|Xs],Ys) -> rvrs(Xs, [X|Ys]). %% functions in bif.c. Do not make %% any changes to it without reading %% the comment about them in bif.c! --spec await_proc_exit(dst(), 'apply' | 'data' | 'reason', term()) -> term(). +-spec erlang:await_proc_exit(dst(), 'apply' | 'data' | 'reason', term()) -> term(). await_proc_exit(Proc, Op, Data) -> Mon = erlang:monitor(process, Proc), receive @@ -814,7 +2943,9 @@ max(A, _) -> A. %% erts_memory() in $ERL_TOP/erts/emulator/beam/erl_alloc.c %% --type memory_type() :: 'total' | 'processes' | 'processes_used' | 'system' | 'atom' | 'atom_used' | 'binary' | 'code' | 'ets' | 'low' | 'maximum'. +-type memory_type() :: 'total' | 'processes' | 'processes_used' | 'system' + | 'atom' | 'atom_used' | 'binary' | 'code' | 'ets' + | 'low' | 'maximum'. -define(CARRIER_ALLOCS, [mseg_alloc, sbmbc_alloc, sbmbc_low_alloc]). -define(LOW_ALLOCS, [sbmbc_low_alloc, ll_low_alloc, std_low_alloc]). @@ -833,7 +2964,9 @@ max(A, _) -> A. low = 0, maximum = 0}). --spec memory() -> [{memory_type(), non_neg_integer()}]. +-spec erlang:memory() -> [{Type, Size}] when + Type :: memory_type(), + Size :: non_neg_integer(). memory() -> case aa_mem_data(au_mem_data(?ALL_NEEDED_ALLOCS)) of notsup -> @@ -858,8 +2991,9 @@ memory() -> {ets, Mem#memory.ets} | Tail] end. --spec memory(memory_type()|[memory_type()]) -> non_neg_integer() | [{memory_type(), non_neg_integer()}]. -memory(Type) when is_atom(Type) -> +-spec erlang:memory(Type :: memory_type()) -> non_neg_integer(); + (TypeList :: [memory_type()]) -> [{memory_type(), non_neg_integer()}]. +memory(Type) when erlang:is_atom(Type) -> {AA, ALCU, ChkSup, BadArgZero} = need_mem_info(Type), case get_mem_data(ChkSup, ALCU, AA) of notsup -> @@ -871,7 +3005,7 @@ memory(Type) when is_atom(Type) -> _ -> Value end end; -memory(Types) when is_list(Types) -> +memory(Types) when erlang:is_list(Types) -> {AA, ALCU, ChkSup, BadArgZeroList} = need_mem_info_list(Types), case get_mem_data(ChkSup, ALCU, AA) of notsup -> @@ -1079,7 +3213,7 @@ au_mem_data(EMD, []) -> EMD. au_mem_data(Allocs) -> - Ref = make_ref(), + Ref = erlang:make_ref(), erlang:system_info({allocator_sizes, Ref, Allocs}), receive_emd(Ref). @@ -1165,11 +3299,11 @@ alloc_info(Allocs) -> alloc_sizes(Allocs) -> get_alloc_info(allocator_sizes, Allocs). -get_alloc_info(Type, AAtom) when is_atom(AAtom) -> +get_alloc_info(Type, AAtom) when erlang:is_atom(AAtom) -> [{AAtom, Result}] = get_alloc_info(Type, [AAtom]), Result; -get_alloc_info(Type, AList) when is_list(AList) -> - Ref = make_ref(), +get_alloc_info(Type, AList) when erlang:is_list(AList) -> + Ref = erlang:make_ref(), erlang:system_info({Type, Ref, AList}), receive_allocator(Ref, erlang:system_info(schedulers), @@ -1206,7 +3340,7 @@ receive_allocator(Ref, N, Acc) -> receive_allocator(Ref, N-1, insert_info(InfoList, Acc)) end. --spec await_sched_wall_time_modifications(Ref, Result) -> boolean() when +-spec erlang:await_sched_wall_time_modifications(Ref, Result) -> boolean() when Ref :: reference(), Result :: boolean(). @@ -1214,12 +3348,12 @@ await_sched_wall_time_modifications(Ref, Result) -> sched_wall_time(Ref, erlang:system_info(schedulers)), Result. --spec gather_sched_wall_time_result(Ref) -> [{pos_integer(), - non_neg_integer(), - non_neg_integer()}] when +-spec erlang:gather_sched_wall_time_result(Ref) -> [{pos_integer(), + non_neg_integer(), + non_neg_integer()}] when Ref :: reference(). -gather_sched_wall_time_result(Ref) when is_reference(Ref) -> +gather_sched_wall_time_result(Ref) when erlang:is_reference(Ref) -> sched_wall_time(Ref, erlang:system_info(schedulers), []). sched_wall_time(_Ref, 0) -> diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 0fc56c8c8e..401b5e8611 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -147,6 +147,32 @@ -define(POSIX_FADV_NOREUSE, 5). +%%% BIFs + +-export([internal_name2native/1, + internal_native2name/1, + internal_normalize_utf8/1]). + +-type unicode_string() :: [unicode:unicode_char()]. +-type prim_file_name() :: unicode_string() | unicode:unicode_binary(). + +-spec internal_name2native(prim_file_name()) -> binary(). + +internal_name2native(_) -> + erlang:nif_error(undefined). + +-spec internal_native2name(binary()) -> prim_file_name(). + +internal_native2name(_) -> + erlang:nif_error(undefined). + +-spec internal_normalize_utf8(unicode:unicode_binary()) -> unicode_string(). + +internal_normalize_utf8(_) -> + erlang:nif_error(undefined). + +%%% End of BIFs + %%%----------------------------------------------------------------- %%% Functions operating on a file through a handle. ?FD_DRV. %%% @@ -648,25 +674,7 @@ set_cwd(Dir) -> set_cwd(Port, Dir) when is_port(Port) -> set_cwd_int(Port, Dir). -set_cwd_int(Port, Dir0) -> - Dir = - (catch - case os:type() of - vxworks -> - %% chdir on vxworks doesn't support - %% relative paths - %% must call get_cwd from here and use - %% absname/2, since - %% absname/1 uses file:get_cwd ... - case get_cwd_int(Port, 0) of - {ok, AbsPath} -> - filename:absname(Dir0, AbsPath); - _Badcwd -> - Dir0 - end; - _Else -> - Dir0 - end), +set_cwd_int(Port, Dir) -> %% Dir is now either a string or an EXIT tuple. %% An EXIT tuple will fail in the following catch. drv_command(Port, [?FILE_CHDIR, pathname(Dir)]). diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 846ae97ed2..3c8a059269 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1071,7 +1071,6 @@ enc_opt(deliver) -> ?INET_LOPT_DELIVER; enc_opt(exit_on_close) -> ?INET_LOPT_EXITONCLOSE; enc_opt(high_watermark) -> ?INET_LOPT_TCP_HIWTRMRK; enc_opt(low_watermark) -> ?INET_LOPT_TCP_LOWTRMRK; -enc_opt(bit8) -> ?INET_LOPT_BIT8; enc_opt(send_timeout) -> ?INET_LOPT_TCP_SEND_TIMEOUT; enc_opt(send_timeout_close) -> ?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE; enc_opt(delay_send) -> ?INET_LOPT_TCP_DELAY_SEND; @@ -1125,7 +1124,6 @@ dec_opt(?INET_LOPT_DELIVER) -> deliver; dec_opt(?INET_LOPT_EXITONCLOSE) -> exit_on_close; dec_opt(?INET_LOPT_TCP_HIWTRMRK) -> high_watermark; dec_opt(?INET_LOPT_TCP_LOWTRMRK) -> low_watermark; -dec_opt(?INET_LOPT_BIT8) -> bit8; dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT) -> send_timeout; dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE) -> send_timeout_close; dec_opt(?INET_LOPT_TCP_DELAY_SEND) -> delay_send; @@ -1220,11 +1218,6 @@ type_opt_1(deliver) -> type_opt_1(exit_on_close) -> bool; type_opt_1(low_watermark) -> int; type_opt_1(high_watermark) -> int; -type_opt_1(bit8) -> - {enum,[{clear, ?INET_BIT8_CLEAR}, - {set, ?INET_BIT8_SET}, - {on, ?INET_BIT8_ON}, - {off, ?INET_BIT8_OFF}]}; type_opt_1(send_timeout) -> time; type_opt_1(send_timeout_close) -> bool; type_opt_1(delay_send) -> bool; diff --git a/erts/test/Makefile b/erts/test/Makefile index 79be5497b0..85b78a79d2 100644 --- a/erts/test/Makefile +++ b/erts/test/Makefile @@ -28,7 +28,6 @@ EBIN = . # ---------------------------------------------------- MODULES= \ - autoimport_SUITE \ erlc_SUITE \ install_SUITE \ nt_SUITE \ @@ -39,14 +38,11 @@ MODULES= \ erlexec_SUITE \ z_SUITE -ERL_XML = $(ERL_TOP)/erts/doc/src/erlang.xml -ERL_XML_TARGET = autoimport_SUITE_data/erlang.xml - ERL_FILES= $(MODULES:%=%.erl) TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) -EXTRA_FILES = install_SUITE_data/install_bin $(ERL_XML_TARGET) +EXTRA_FILES = install_SUITE_data/install_bin # ---------------------------------------------------- # Release directory specification @@ -68,10 +64,6 @@ install_SUITE_data/install_bin: ../../make/install_bin rm -f $@ cp -p $< $@ -$(ERL_XML_TARGET): $(ERL_XML) - rm -f $@ - cp -p $< $@ - clean: rm -f $(TARGET_FILES) $(EXTRA_FILES) rm -f core *~ @@ -87,7 +79,7 @@ release_spec: release_tests_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)" - $(INSTALL_DATA) system.spec system.dynspec system.spec.vxworks \ + $(INSTALL_DATA) system.spec system.dynspec \ $(ERL_FILES) $(TARGET_FILES) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" tar cf - *_SUITE_data utils | (cd "$(RELSYSDIR)"; tar xf -) diff --git a/erts/test/autoimport_SUITE.erl b/erts/test/autoimport_SUITE.erl deleted file mode 100644 index 71ed5204b1..0000000000 --- a/erts/test/autoimport_SUITE.erl +++ /dev/null @@ -1,196 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%%% Purpose: Test erlang.xml re autoimports --module(autoimport_SUITE). - --include_lib("test_server/include/test_server.hrl"). --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2,end_per_testcase/2, - autoimports/1]). --define(TEST_TIMEOUT, ?t:seconds(180)). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [autoimports]. - -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_testcase(_Func, Config) -> - Dog = test_server:timetrap(?TEST_TIMEOUT), - [{watchdog, Dog} | Config]. - -end_per_testcase(_Func, Config) -> - Dog = ?config(watchdog, Config), - catch test_server:timetrap_cancel(Dog), - ok. - - -autoimports(suite) -> - []; -autoimports(doc) -> - ["Check that erlang.xml documents autoimports correctly"]; -autoimports(Config) when is_list(Config) -> - ?line XML = filename:join([?config(data_dir,Config),"erlang.xml"]), - ?line case xml(XML) of - [] -> - ok; - List -> - lists:foreach(fun({[],F,A}) -> - io:format("erlang:~s/~p is wrongly " - "documented as ~s/~p~n", - [F,A,F,A]); - ({"erlang",F,A}) -> - io:format("~s/~p is wrongly " - "documented as " - "erlang:~s/~p~n", - [F,A,F,A]) - end,List), - ?t:fail({wrong_autoimports,List}) - end. - -%% -%% Ugly chunk of code to heuristically analyze the erlang.xml -%% documentation file. Don't view this as an example... -%% - -xml(XMLFile) -> - {ok,File} = file:open(XMLFile,[read]), - xskip_to_funcs(file:read_line(File),File), - DocData = xloop(file:read_line(File),File), - true = DocData =/= [], - file:close(File), - analyze(DocData). - -%% Skip lines up to and including the <funcs> tag. -xskip_to_funcs({ok,Line},File) -> - case re:run(Line,"\\<funcs\\>",[{capture,none}]) of - nomatch -> - xskip_to_funcs(file:read_line(File),File); - match -> - ok - end. - -xloop({ok,Line},File) -> - case re:run(Line,"\\<name\\>",[{capture,none}]) of - nomatch -> - xloop(file:read_line(File),File); - match -> - X = re:replace(Line,"\\).*",")",[{return,list}]), - Y = re:replace(X,".*\\>","",[{return,list}]), - Mod = get_module(Y), - Rest1 = fstrip(Mod++":",Y), - Func = get_function(Rest1), - Rest2 = fstrip(Func++"(", Rest1), - Argc = count_args(Rest2,1,0,false), - [{Mod,Func,Argc} | - xloop(file:read_line(File),File)] - end; -xloop(_,_) -> - []. - -analyze([{[],Func,Arity}|T]) -> - case erl_internal:bif(list_to_atom(Func),Arity) of - true -> - analyze(T); - false -> - [{[],Func,Arity} | - analyze(T)] - end; -analyze([{"erlang",Func,Arity}|T]) -> - case erl_internal:bif(list_to_atom(Func),Arity) of - true -> - [{"erlang",Func,Arity}|analyze(T)]; - false -> - analyze(T) - end; -analyze([_|T]) -> - analyze(T); -analyze([]) -> - []. - - -count_args([],_,N,false) -> - N; -count_args([],_,N,true) -> - N+1; -count_args(_,0,N,true) -> - N+1; -count_args(_,0,N,false) -> - N; -count_args([Par|T],Level,N,Got) when (Par =:= 40) or - (Par =:= 123) or (Par =:= 91) -> - count_args(T,Level+1,N,(Level =:= 1) or Got); -count_args([41|T],1,N,true) -> - count_args(T,0,N+1,false); -count_args([Par|T],Level,N, Got) when (Par =:= 41) or - (Par =:= 125) or (Par =:= 93) -> - count_args(T,Level-1,N,Got); -count_args([$,|T],1,N,true) -> - count_args(T,1,N+1,false); -count_args([$ |T],A,B,C) -> - count_args(T,A,B,C); -count_args([_|T],1,N,_) -> - count_args(T,1,N,true); -count_args([_|T],A,B,C) -> - count_args(T,A,B,C). - -fstrip([],X) -> - X; -fstrip(_,[]) -> - []; -fstrip([H|T1],[H|T2]) -> - fstrip(T1,T2); -fstrip(_,L) -> - L. - -get_module(X) -> - get_module(X,[]). -get_module([],_) -> - []; -get_module([$:|_],Acc) -> - lists:reverse(Acc); -get_module([40|_],_) -> %( - []; -get_module([H|T],Acc) -> - get_module(T,[H|Acc]). - -get_function(X) -> - get_function(X,[]). -get_function([],_) -> - []; -get_function([40|_],Acc) -> %( - lists:reverse(Acc); -get_function([H|T],Acc) -> - get_function(T,[H|Acc]). diff --git a/erts/test/system.spec.vxworks b/erts/test/system.spec.vxworks deleted file mode 100644 index 378adf56ac..0000000000 --- a/erts/test/system.spec.vxworks +++ /dev/null @@ -1,2 +0,0 @@ -{topcase, {dir, "../system_test"}}. -{skip,{erlc_SUITE, "Not on VxWorks, erlc is a HOST tool."}} diff --git a/erts/vsn.mk b/erts/vsn.mk index da0f03b24f..a420781e9f 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -17,8 +17,8 @@ # %CopyrightEnd% # -VSN = 5.9.2 -SYSTEM_VSN = R15B02 +VSN = 5.10 +SYSTEM_VSN = R16B # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/Makefile b/lib/Makefile index 3753bd165b..64b17a3cca 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -30,7 +30,7 @@ ifdef BUILD_ALL diameter \ cosTransactions cosEvent cosTime cosNotification \ cosProperty cosFileTransfer cosEventDomain et megaco webtool \ - xmerl edoc eunit ssh inviso typer erl_docgen \ + xmerl edoc eunit ssh typer erl_docgen \ percept eldap dialyzer hipe EXTRA_FILE := $(wildcard EXTRA-APPLICATIONS) EXTRA_APPLICATIONS := $(if $(EXTRA_FILE),$(shell cat $(EXTRA_FILE))) diff --git a/lib/asn1/c_src/Makefile b/lib/asn1/c_src/Makefile index 903cf32838..8cf9cda274 100644 --- a/lib/asn1/c_src/Makefile +++ b/lib/asn1/c_src/Makefile @@ -66,13 +66,8 @@ NIF_SHARED_OBJ_FILE = $(LIBDIR)/asn1_erl_nif.dll CLIB_FLAGS = LN=cp else -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -NIF_SHARED_OBJ_FILE = $(LIBDIR)/asn1_erl_nif.eld -CLIB_FLAGS = -else NIF_SHARED_OBJ_FILE = $(LIBDIR)/asn1_erl_nif.so CLIB_FLAGS = -lc -endif LN= ln -s endif diff --git a/lib/cosFileTransfer/test/fileTransfer_SUITE.erl b/lib/cosFileTransfer/test/fileTransfer_SUITE.erl index 79a234bd28..18a591a7af 100644 --- a/lib/cosFileTransfer/test/fileTransfer_SUITE.erl +++ b/lib/cosFileTransfer/test/fileTransfer_SUITE.erl @@ -292,13 +292,8 @@ fts_ftp_file_api(Config) -> fts_ftp_file_ssl_api(doc) -> ["CosFileTransfer FTP FileTransferSession API tests.", ""]; fts_ftp_file_ssl_api(suite) -> []; fts_ftp_file_ssl_api(Config) -> - case os:type() of - vxworks -> - {skipped, "No SSL-support for VxWorks."}; - _ -> - ?line {ok, Node} = create_node("ftp_file_api_ssl", {4005, 1}, ssl), - file_helper(Config, 'FTP', ?TEST_DIR, Node, 4005, "ftp_file_api_ssl", ssl) - end. + ?line {ok, Node} = create_node("ftp_file_api_ssl", {4005, 1}, ssl), + file_helper(Config, 'FTP', ?TEST_DIR, Node, 4005, "ftp_file_api_ssl", ssl). fts_native_file_api(doc) -> ["CosFileTransfer NATIVE FileTransferSession API tests.", ""]; fts_native_file_api(suite) -> []; @@ -311,15 +306,10 @@ fts_native_file_api(Config) -> fts_native_file_ssl_api(doc) -> ["CosFileTransfer NATIVE FileTransferSession API tests.", ""]; fts_native_file_ssl_api(suite) -> []; fts_native_file_ssl_api(Config) -> - case os:type() of - vxworks -> - {skipped, "No SSL-support for VxWorks."}; - _ -> - ?line {ok, Node} = create_node("native_file_ssl_api", {4007, 1}, ssl), - {ok, Pwd} = file:get_cwd(), - file_helper(Config,{'NATIVE', 'cosFileTransferNATIVE_file'},filename:split(Pwd), - Node, 4007, "native_file_ssl_api", ssl) - end. + ?line {ok, Node} = create_node("native_file_ssl_api", {4007, 1}, ssl), + {ok, Pwd} = file:get_cwd(), + file_helper(Config,{'NATIVE', 'cosFileTransferNATIVE_file'},filename:split(Pwd), + Node, 4007, "native_file_ssl_api", ssl). @@ -817,23 +807,13 @@ create_node(Name, Port, Retries, Type, Args, Options) -> end. starter(Host, Name, Args) -> - case os:type() of - vxworks -> - test_server:start_node(Name, slave, [{args,Args}]); - _ -> - slave:start(Host, Name, Args) - end. + slave:start(Host, Name, Args). slave_sup() -> process_flag(trap_exit, true), receive {'EXIT', _, _} -> - case os:type() of - vxworks -> - erlang:halt(); - _ -> - ignore - end + ignore end. @@ -850,12 +830,7 @@ destroy_node(Node, Type) -> stopper(Node, Type) -> catch stop_orber_remote(Node, Type), - case os:type() of - vxworks -> - test_server:stop_node(Node); - _ -> - slave:stop(Node) - end. + slave:stop(Node). -endif. %%------------------------------------------------------------ diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets index 773525eb7f..d789d8d246 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/results/inets +++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets @@ -31,11 +31,11 @@ httpd_sup.erl:92: The variable Else can never match since previous clauses compl mod_auth.erl:559: The pattern {'error', Reason} can never match the type {_,integer(),maybe_improper_list(),_} mod_auth_dets.erl:120: The call lists:foreach(fun((_) -> 'true' | {'error','no_such_group' | 'no_such_group_member'}),{'ok',[any()]}) will never return since it differs in the 2nd argument from the success typing arguments: (fun((_) -> any()),[any()]) mod_auth_plain.erl:100: The variable _ can never match since previous clauses completely covered the type {'ok',[any()]} -mod_auth_plain.erl:159: The variable _ can never match since previous clauses completely covered the type [any()] -mod_auth_plain.erl:83: The variable O can never match since previous clauses completely covered the type [any()] +mod_auth_plain.erl:159: The variable _ can never match since previous clauses completely covered the type [[any()]] +mod_auth_plain.erl:83: The variable O can never match since previous clauses completely covered the type [[any()]] mod_cgi.erl:372: The pattern {'http_response', NewAccResponse} can never match the type 'ok' mod_dir.erl:101: The call lists:flatten(nonempty_improper_list(atom() | [any()] | char(),atom())) will never return since it differs in the 1st argument from the success typing arguments: ([any()]) -mod_dir.erl:72: The pattern {'error', Reason} can never match the type {'ok',[[[any()] | char()],...]} +mod_dir.erl:72: The pattern {'error', Reason} can never match the type {'ok',[[[any()] | non_neg_integer()],...]} mod_get.erl:135: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]> mod_head.erl:80: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]> mod_htaccess.erl:460: The pattern {'error', BadData} can never match the type {'ok',_} @@ -47,9 +47,9 @@ mod_include.erl:692: The pattern <{'read', Reason}, Info, Path> can never match mod_include.erl:706: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]> mod_include.erl:716: Function read_error/3 will never be called mod_include.erl:719: Function read_error/4 will never be called -mod_security_server.erl:386: The variable O can never match since previous clauses completely covered the type [any()] -mod_security_server.erl:433: The variable Other can never match since previous clauses completely covered the type [any()] -mod_security_server.erl:585: The variable _ can never match since previous clauses completely covered the type [any()] -mod_security_server.erl:608: The variable _ can never match since previous clauses completely covered the type [any()] -mod_security_server.erl:641: The variable _ can never match since previous clauses completely covered the type [any()] +mod_security_server.erl:386: The variable O can never match since previous clauses completely covered the type [tuple()] +mod_security_server.erl:433: The variable Other can never match since previous clauses completely covered the type [tuple()] +mod_security_server.erl:585: The variable _ can never match since previous clauses completely covered the type [tuple()] +mod_security_server.erl:608: The variable _ can never match since previous clauses completely covered the type [tuple()] +mod_security_server.erl:641: The variable _ can never match since previous clauses completely covered the type [tuple()] uri.erl:146: The pattern {'error', Error} can never match since previous clauses completely covered the type {_,{[],[]}} diff --git a/lib/dialyzer/test/user_SUITE_data/results/wsp_pdu b/lib/dialyzer/test/user_SUITE_data/results/wsp_pdu index a47b1f1f2c..d1f8f4caf2 100644 --- a/lib/dialyzer/test/user_SUITE_data/results/wsp_pdu +++ b/lib/dialyzer/test/user_SUITE_data/results/wsp_pdu @@ -6,7 +6,7 @@ wsp_pdu.erl:2403: The call wsp_pdu:d_date(Data1::binary()) will never return sin wsp_pdu.erl:2406: Guard test is_integer(Sec::{[byte()] | byte() | {'long',binary()} | {'short',binary()},binary()}) can never succeed wsp_pdu.erl:2408: The pattern {'short', Data2} can never match the type {[byte()] | byte() | {'long',binary()} | {'short',binary()},binary()} wsp_pdu.erl:2755: Function parse_push_flag/1 has no local return -wsp_pdu.erl:2756: The call erlang:integer_to_list(Value::[any()]) will never return since it differs in the 1st argument from the success typing arguments: (integer()) +wsp_pdu.erl:2756: The call erlang:integer_to_list(Value::[any()]) breaks the contract (Integer) -> string() when is_subtype(Integer,integer()) wsp_pdu.erl:2875: The call wsp_pdu:d_text_string(Data::byte()) will never return since it differs in the 1st argument from the success typing arguments: (binary()) wsp_pdu.erl:2976: The call wsp_pdu:d_q_value(QData::byte()) will never return since it differs in the 1st argument from the success typing arguments: (<<_:8,_:_*8>>) wsp_pdu.erl:3336: The call wsp_pdu:encode_typed_field(Ver::any(),'Q-value',ParamValue::any()) will never return since it differs in the 2nd argument from the success typing arguments: (any(),'Constrained-encoding' | 'Date-value' | 'No-value' | 'Short-integer' | 'Text-string' | 'Text-value' | 'Well-known-charset',any()) diff --git a/lib/diameter/autoconf/configure.vxworks b/lib/diameter/autoconf/configure.vxworks deleted file mode 100755 index 33aa497680..0000000000 --- a/lib/diameter/autoconf/configure.vxworks +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/sh -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: -# Patrik Winroth -# - - -# vxworks_ppc860 vxworks_ppc603 vxworks_ppc603_longcall vxworks_cpu32 vxworks_sparc -# vxworks_ppc750 vxworks_simso - -case $# in -1) host=$1 ;; -*) echo "usage: configure.vxworks host-configuration"; exit 1 ;; -esac - -case $1 in -vxworks_cpu32) ;; -vxworks_ppc750) ;; -vxworks_ppc860) ;; -vxworks_ppc603) ;; -vxworks_ppc603_nolongcall) ;; -vxworks_sparc) ;; -vxworks_simso) ;; -vxworks_simlinux) ;; -vxworks_ppc32) ;; -*) echo "usage: configure.vxworks TARGET"; - echo "where TARGET is one of vxworks_cpu32, vxworks_ppc750, vxworks_ppc860, vxworks_ppc603, vxworks_ppc603_nolongcall, vxworks_sparc, vxworks_simso, vxworks_simlinux, vxworks_ppc32"; exit 1;; -esac - -if [ "x$ERL_TOP" = x ]; then - echo "You need to set ERL_TOP!" - exit 1 -fi - - -target=$host - -# Find out the HOST and WIND_BASE environment -HOST_TYPE=${HOST_TYPE:=sun4-solaris2} -case $1 in -vxworks_ppc750) VXTOP=Tornado2.2 ;; -vxworks_simso) VXTOP=WindRiver ;; -vxworks_simlinux) VXTOP=WindRiver ;; -vxworks_ppc32) VXTOP=WindRiver ;; -*) VXTOP=wind ;; -esac - -WIND_BASE=${WIND_BASE:=`ypmatch tornado passwd | awk -F: '{print $6}'`/$VXTOP} - -# These are created by autoconf. -MKDIRS="${ERL_TOP}/lib/os_mon/priv/bin/$target - ${ERL_TOP}/lib/os_mon/priv/obj/$target - ${ERL_TOP}/lib/orber/priv/obj/$target - ${ERL_TOP}/lib/orber/priv/bin/$target - ${ERL_TOP}/lib/ic/priv/lib/$target - ${ERL_TOP}/lib/ic/priv/obj/$target - ${ERL_TOP}/lib/asn1/priv/lib/$target - ${ERL_TOP}/lib/asn1/priv/obj/$target - ${ERL_TOP}/lib/erl_interface/obj/$target - ${ERL_TOP}/lib/erl_interface/obj.debug/$target - ${ERL_TOP}/lib/erl_interface/bin/$target - ${ERL_TOP}/lib/runtime_tools/priv/lib/$target - ${ERL_TOP}/lib/runtime_tools/priv/obj/$target - ${ERL_TOP}/erts/obj/$target - ${ERL_TOP}/erts/obj.debug/$target - ${ERL_TOP}/bin/$target" - -for dir in $MKDIRS; do - test ! -d "$dir" && mkdir -p "$dir" -done - -# -# Create Makefiles for vxWorks. -# -my_root=${ERL_TOP}/erts/emulator -emu_test=$my_root/test -beam=$my_root/beam -erts_lib_src=${ERL_TOP}/erts/lib_src -erts_incl=${ERL_TOP}/erts/include -erts_incl_intrnl=${ERL_TOP}/erts/include/internal -etcdir=${ERL_TOP}/erts/etc/common -erlint_dir=${ERL_TOP}/lib/erl_interface/src -epmd_dir=${ERL_TOP}/erts/epmd/src -os_mon_dir=${ERL_TOP}/lib/os_mon/c_src -orber_dir=${ERL_TOP}/lib/orber/c_src -ic_dir=${ERL_TOP}/lib/ic/c_src -asn1_dir=${ERL_TOP}/lib/asn1/c_src -internal_tools_dir=${ERL_TOP} -libdir=${ERL_TOP}/lib -tsdir=$libdir/test_server/src -zlibdir=${ERL_TOP}/erts/emulator/zlib -runtime_tools_dir=${ERL_TOP}/lib/runtime_tools/c_src -tools_dir=${ERL_TOP}/lib/tools/c_src - -CONFIG_FILES="${ERL_TOP}/erts/emulator/$host/Makefile - $erts_lib_src/$host/Makefile - $erts_incl/$host/erl_int_sizes_config.h - $erts_incl_intrnl/$host/ethread.mk - $erts_incl_intrnl/$host/ethread_header_config.h - $etcdir/$host/Makefile - $erlint_dir/$host/Makefile - $erlint_dir/$host/eidefs.mk - $epmd_dir/$host/Makefile - $internal_tools_dir/make/$host/otp.mk - $os_mon_dir/$host/Makefile - $zlibdir/$host/Makefile - $ic_dir/$host/Makefile - $asn1_dir/$host/Makefile - $runtime_tools_dir/$host/Makefile - $tools_dir/$host/Makefile - $orber_dir/$host/Makefile" - -for file in $CONFIG_FILES; do - new_name=`echo $file|sed "s%/$host/%/$target/%"` - dir=`echo $new_name|sed 's%/[^/][^/]*$%%'` - if test "$dir" != "$new_name" && test "$dir" != .; then - test ! -d "$dir" && mkdir "$dir" - fi - - sole_name=`echo $file|sed "s%.*$target/%%"` - in_file=`echo $dir|sed "s%/[^/][^/]*$%/$sole_name.in%"` - echo "creating $new_name" - sed -f vxworks/sed.$target -f vxworks/sed.general \ - -e "s,@HOST_TYPE@,$HOST_TYPE,g" \ - -e "s,@WIND_BASE@,$WIND_BASE,g" \ - -e "s,@TARGET@,$target,g" \ - $in_file > $new_name -done - - diff --git a/lib/diameter/autoconf/vxworks/sed.general b/lib/diameter/autoconf/vxworks/sed.general deleted file mode 100644 index 9199983e16..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.general +++ /dev/null @@ -1,124 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles -# for vxworks from the generic Makefile.in that is found in a number -# of directories (see configure.vxworks). -# -# This is the general part that is common for all architectures. -# - -# Size of data types. -s|^#undef SIZEOF_CHAR|#define SIZEOF_CHAR 1| -s|^#undef SIZEOF_SHORT|#define SIZEOF_SHORT 2| -s|^#undef SIZEOF_INT|#define SIZEOF_INT 4| -s|^#undef SIZEOF_LONG_LONG|#define SIZEOF_LONG_LONG 8| -s|^#undef SIZEOF_LONG$|#define SIZEOF_LONG 4| - -# General stuff. -s|@erts_rootdir@|/clearcase/otp/erts| - -s|@LIBOBJS@|$(OBJDIR)/elib_malloc.o| -s|@DLOAD_LIB@|| -s|@LDFLAGS@|| -# FIXME: A bit strange to clear out remaining DED_* -s|@DED_LDFLAGS@|| -s|@DED_CFLAGS@|| -s|@STATIC_CFLAGS@|| -s|@GCCLIB@|libgcc.a| -s|@DEFS@|| -s|@DEXPORT@|| -s|@DCFLAGS@|| -s|@THR_DEFS@|| -s|@THR_LIBS@|| -s|@THR_LIB_NAME@|| -s|@THR_X_LIBS@|| -s|@ETHR_X_LIBS@|| -s|@ETHR_LIBS@|| -s|@ETHR_LIB_NAME@|| -s|@ETHR_DEFS@|| -s|@ETHR_THR_LIB_BASE@|| -s|@EMU_THR_DEFS@|| -s|@EMU_THR_LIBS@|| -s|@EMU_THR_LIB_NAME@|ethread| -s|@ERTS_ENABLE_KERNEL_POLL@|no| -s|@cc_root@|/clearcase/otp/| -# Define VxWorks even though cross-compiling. -s|@HCFLAGS@|-DVXWORKS| -s|@HCLIBS@|| -s|@ENABLE_ALLOC_TYPE_VARS@|| -s|@TERMCAP_LIB@|| -s|@ERTS_BUILD_SMP_EMU@|no| -s|@HAVE_VALGRIND@|no| -s|@EXEEXT@|| -s|@WITH_SCTP@|| - -# HiPE -s|@HIPE_ENABLED@|| -s|@PERFCTR_PATH@|| -s|@USE_PERFCTR@|| - -# m4 -s|@OPSYS@|noopsys| - -# Conditional inclusion of applications -s|@HIPE_APP@|| -s|@SSL_APP@|ssl| -s|@CRYPTO_APP@|crypto| -s|@SSH_APP@|ssh| - -# The target tools prefix, prepended to all cc,ld,as etc commands -s|@TTPREFIX@|GCC_EXEC_PREFIX=@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/host/@HOST_TYPE@/bin/| - -# Install programs etc -s|@PERL@|perl| -s|@INSTALL@|/usr/ucb/install -c| -s|@INSTALL_PROGRAM@|${INSTALL}| -s|@INSTALL_SCRIPT@|${INSTALL}| -s|@INSTALL_DATA@|${INSTALL} -m 644| -s|@INSTALL_DIR@|$(INSTALL) -d| -s|@RM@|/bin/rm| -s|@MKDIR@|/bin/mkdir| -s|@ERLANG_OSTYPE@|vxworks| -s|@vxworks_reclaim@|reclaim.h| -s|@os_mon_programs@|| -s|@erlexec@|erl.exec| -s|@EMU_LIBOBJS@|| - -# General CFLAGS -s|@GENERAL_CFLAGS@|-DHAVE_LOCALTIME_R -DHAVE_GMTIME_R -DENABLE_ELIB_MALLOC -DELIB_HEAP_USER -DELIB_SORTED_BLOCKS -DWORDS_BIGENDIAN -DELIB_DONT_INITIALIZE -DSIZEOF_CHAR=1 -DSIZEOF_SHORT=2 -DSIZEOF_INT=4 -DSIZEOF_LONG=4 -DSIZEOF_LONG_LONG=8 -DSIZEOF_VOID_P=4 -DERTS_USE_PORT_TASKS=1|g -s|@WFLAGS@|| - -# Thread flags for eidefs.mk (erl_interface) -s|@EI_THREADS@|false| - -# Make java code compile although we don't test it on VxWorks (no license) -s|@JAVAC@|javac| - -# What is this anyway? -# Disable it and see what breaks. -#s|@ded_soname@|| - -# Only variable substituted directly -s|$(LDFLAGS)|-r -d| -s|@LIBRT@|| -# XXX What is EFFLAGS? Not used in the emulator Makefile.in anyway. -s|$(EFLAGS)|-DENABLE_ELIB_MALLOC -DELIB_HEAP_USER -DELIB_SORTED_BLOCKS| - diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 b/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 deleted file mode 100644 index 5a1590e786..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 +++ /dev/null @@ -1,45 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_cpu32| -s|@system_type@|vxworks_cpu32| -s|@CC@|@TTPREFIX@cc68k| -s|@HCC@|gcc| -s|@LD@|@TTPREFIX@ld68k| -s|@LIBS@|| -s|@DED_LD@|@TTPREFIX@ld68k| -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_FLAGS@|-g| -s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/m68k-wrs-vxworks/cygnus-2.7.2-960126/m68000/msoft-float/libgcc.a| -s|@RANLIB@|@TTPREFIX@ranlib68k| -s|@AR@|@TTPREFIX@ar68k| -s|@STRIP@|@TTPREFIX@strip68k| -s|@SYMPREFIX@|_| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/m68k-wrs-vxworks/cygnus-2.7.2-960126/m68000/msoft-float -lgcc| - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=CPU32 -mnobitfield -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -fno-builtin -nostdinc -fvolatile -msoft-float| -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=CPU32 -mnobitfield -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -fno-builtin -nostdinc -fvolatile -msoft-float| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 deleted file mode 100644 index 9104b24ed3..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 +++ /dev/null @@ -1,52 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2006-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Peter Andersson -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_ppc32| -s|@system_type@|vxworks_ppc32| -s|@ARCH@|ppc32| -s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccppc -mlongcall| -s|@HCC@|gcc| -s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldppc| -s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/workbench-2.3/@HOST_TYPE@/bin/stripppc| -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/ppc/PPC32/common -lgcc| -s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldppc| -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# generate dwarf debug code on PPC .. -s|@DEBUG_FLAGS@|-gdwarf| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/ppc/PPC32/common/libgcc.a| -s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibppc| -s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arppc| -# -Dasm(X)= is for beam - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC32 -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/powerpc-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | - -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC32 -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -I@WIND_BASE@/vxworks-6.3/target/h -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 deleted file mode 100644 index e1dd7c5afd..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 +++ /dev/null @@ -1,51 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2000-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_ppc603| -s|@system_type@|vxworks_ppc603| -s|@ARCH@|ppc603| -s|@CC@|@TTPREFIX@ccppc -mlongcall| -s|@HCC@|gcc| -s|@LD@|@TTPREFIX@ldppc| -s|@STRIP@|@TTPREFIX@stripppc| -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126 -lgcc| -s|@DED_LD@|@TTPREFIX@ldppc| -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# generate dwarf debug code on PPC .. -s|@DEBUG_FLAGS@|-gdwarf| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/libgcc.a| -s|@RANLIB@|@TTPREFIX@ranlibppc| -s|@AR@|@TTPREFIX@arppc| -# -Dasm(X)= is for beam - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall deleted file mode 100644 index 5d7673d323..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall +++ /dev/null @@ -1,51 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_ppc603| -s|@system_type@|vxworks_ppc603| -s|@ARCH@|ppc603| -s|@CC@|@TTPREFIX@ccppc| -s|@HCC@|gcc| -s|@LD@|@TTPREFIX@ldppc| -s|@STRIP@|@TTPREFIX@stripppc| -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126 -lgcc| -s|@DED_LD@|@TTPREFIX@ldppc| -s|@DED_CFLAGS@|@CFLAGS@| -# generate dwarf debug code on PPC .. -s|@DEBUG_FLAGS@|-gdwarf| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/libgcc.a| -s|@RANLIB@|@TTPREFIX@ranlibppc| -s|@AR@|@TTPREFIX@arppc| -# -Dasm(X)= is for beam - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| - diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 deleted file mode 100644 index 7a3c32df5b..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 +++ /dev/null @@ -1,50 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_ppc860| -s|@system_type@|vxworks_ppc860| -s|@ARCH@|ppc860| -s|@CC@|@TTPREFIX@ccppc -mlongcall| -s|@HCC@|gcc| -s|@LD@|@TTPREFIX@ldppc| -s|@STRIP@|@TTPREFIX@stripppc| -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/soft-float -lgcc| -s|@DED_LD@|@TTPREFIX@ldppc| -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# generate dwarf debug code on PPC .. -s|@DEBUG_FLAGS@|-gdwarf| -# remove -g option (go for dwarf) -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/soft-float/libgcc.a| -s|@RANLIB@|@TTPREFIX@ranlibppc| -s|@AR@|@TTPREFIX@arppc| - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC860 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mcpu=860 -fvolatile -fno-builtin -fno-for-scope -msoft-float -D_GNU_TOOL -nostdinc| -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC860 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mcpu=powerpc -fvolatile -fno-builtin -fno-for-scope -msoft-float -D_GNU_TOOL -nostdinc| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux b/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux deleted file mode 100644 index 56eae6507c..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux +++ /dev/null @@ -1,59 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2008-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Peter Andersson -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_simlinux| -s|@system_type@|vxworks_simlinux| -s|@ARCH@|simlinux| - -s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccpentium| - -s|@HCC@|gcc| - -s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldpentium| - -#s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/strip| -s|@STRIP@|| - -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/simlinux/SIMLINUX/common -lgcc| - -s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldpentium| - -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/simlinux/SIMLINUX/common/libgcc.a| - -s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibpentium| - -s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arpentium| - -# -Dasm(X)= is for beam -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMLINUX -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/i586-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -fvolatile -fno-builtin | -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMLINUX -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_simso b/lib/diameter/autoconf/vxworks/sed.vxworks_simso deleted file mode 100644 index 6b845d31de..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_simso +++ /dev/null @@ -1,64 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2005-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Peter Andersson -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_simso| -s|@system_type@|vxworks_simso| -s|@ARCH@|simso| - -# Tornado2.2: s|@CC@|@TTPREFIX@ccsimso| -s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccsparc| - -s|@HCC@|gcc| - -# Tornado2.2: s|@LD@|@TTPREFIX@ldsimso| -s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldsparc| - -# Tornado2.2: s|@STRIP@|@TTPREFIX@stripsimso| -s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/stripsparc| - -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/simso/SIMSPARCSOLARIS/common -lgcc| - -# Tornado2.2: s|@DED_LD@|@TTPREFIX@ldsimso| -s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldsparc| - -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/simso/SIMSPARCSOLARIS/common/libgcc.a| - -# Tornado2.2: s|@RANLIB@|@TTPREFIX@ranlibsimso| -s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibsparc| - -# Tornado2.2: s|@AR@|arsimso| -s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arsparc| - -# -Dasm(X)= is for beam -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMSPARCSOLARIS -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/sparc-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -fvolatile -fno-builtin | -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMSPARCSOLARIS -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_sparc b/lib/diameter/autoconf/vxworks/sed.vxworks_sparc deleted file mode 100644 index 6f637d8746..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_sparc +++ /dev/null @@ -1,38 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# - -# ccsparc -O2 doesn't work when compiling "rundir"/gc.c - signal 11 is generated when trying -# therefore it is compiled with -O1 instead, which works - get a new ccsparc ! -s/\$(COMPILE\.emu) -o \$@ -c gc\.c/$(CC) @CFLAGS@ @DEFS@ -O1 $(BEAM_MODE) -I$(SYSDIR) -I$(EMUDIR) -I. $(CPPFLAGS) -c -o $@ -c gc.c/ -s/@host@/vxworks_sparc/ -s/@system_type@/vxworks_sparc/ -s/@CC@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/bin\/ccsparc/ -s/@HCC@/gcc/ -s/@LD@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/bin\/ldsparc/ -s/@DEBUG_FLAGS@/-g/ -s/@GCCLIB_PATH@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/lib\/gcc-lib\/sparc-wrs-vxworks\/cygnus-2.2.3.1\/libgcc.a/ -s/@RANLIB@/ranlibsparc/ -s/@AR@/arsparc/ -s/@CFLAGS@/-I\/home\/gandalf\/bsproj\/BS.2\/UOS\/vw\/5.2\/h -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DCPU=SPARC -DVXWORKS -fno-builtin -nostdinc/ - diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 1ef73da1be..260ffeed48 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -45,11 +45,9 @@ t_atom_vals/1, t_binary/0, t_bitstr/0, - t_bitstrlist/0, t_boolean/0, t_byte/0, t_char/0, - t_charlist/0, t_cons/0, t_cons/2, t_cons_hd/1, @@ -72,8 +70,6 @@ t_non_neg_integer/0, t_pos_integer/0, t_integers/1, - t_iodata/0, - t_iolist/0, t_is_any/1, t_is_atom/1, t_is_binary/1, @@ -85,7 +81,6 @@ t_is_fun/1, t_is_integer/1, t_is_integer/1, - t_is_list/1, t_is_nil/1, t_is_none/1, t_is_none_or_unit/1, @@ -118,14 +113,11 @@ t_subtract/2, t_sup/1, t_sup/2, - t_tid/0, - t_timeout/0, t_tuple/0, t_tuple/1, t_tuple_args/1, t_tuple_size/1, - t_tuple_subtypes/1, - t_unicode_string/0 + t_tuple_subtypes/1 ]). -ifdef(DO_ERL_BIF_TYPES_TEST). @@ -144,111 +136,14 @@ type(M, F, A) -> -spec type(atom(), atom(), arity(), [erl_types:erl_type()]) -> erl_types:erl_type(). -%%-- binary ------------------------------------------------------------------- -type(binary, at, 2, Xs) -> - strict(arg_types(binary, at, 2), Xs, fun(_) -> t_integer() end); -type(binary, bin_to_list, Arity, Xs) when 1 =< Arity, Arity =< 3 -> - strict(arg_types(binary, bin_to_list, Arity), Xs, - fun(_) -> t_list(t_integer()) end); -type(binary, compile_pattern, 1, Xs) -> - strict(arg_types(binary, compile_pattern, 1), Xs, - fun(_) -> t_binary_compiled_pattern() end); -type(binary, copy, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> - strict(arg_types(binary, copy, Arity), Xs, - fun(_) -> t_binary() end); -type(binary, decode_unsigned, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> - strict(arg_types(binary, decode_unsigned, Arity), Xs, - fun(_) -> t_non_neg_integer() end); -type(binary, encode_unsigned, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> - strict(arg_types(binary, encode_unsigned, Arity), Xs, - fun(_) -> t_binary() end); -type(binary, first, 1, Xs) -> - strict(arg_types(binary, first, 1), Xs, fun(_) -> t_non_neg_integer() end); -type(binary, last, 1, Xs) -> - strict(arg_types(binary, last, 1), Xs, fun(_) -> t_non_neg_integer() end); -type(binary, list_to_bin, 1, Xs) -> - type(erlang, list_to_binary, 1, Xs); -type(binary, longest_common_prefix, 1, Xs) -> - strict(arg_types(binary, longest_common_prefix, 1), Xs, - fun(_) -> t_integer() end); -type(binary, longest_common_suffix, 1, Xs) -> - strict(arg_types(binary, longest_common_suffix, 1), Xs, - fun(_) -> t_integer() end); -type(binary, match, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> - strict(arg_types(binary, match, Arity), Xs, - fun(_) -> - t_sup(t_atom('nomatch'), t_binary_canonical_part()) - end); -type(binary, matches, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> - strict(arg_types(binary, matches, Arity), Xs, - fun(_) -> t_list(t_binary_canonical_part()) end); -type(binary, part, 2, Xs) -> - type(erlang, binary_part, 2, Xs); -type(binary, part, 3, Xs) -> - type(erlang, binary_part, 3, Xs); -type(binary, referenced_byte_size, 1, Xs) -> - strict(arg_types(binary, referenced_byte_size, 1), Xs, - fun(_) -> t_non_neg_integer() end); -%%-- code --------------------------------------------------------------------- -type(code, get_chunk, 2, Xs) -> - strict(arg_types(code, get_chunk, 2), Xs, - fun (_) -> t_sup(t_binary(), t_atom('undefined')) end); -type(code, is_module_native, 1, Xs) -> - strict(arg_types(code, is_module_native, 1), Xs, - fun (_) -> t_sup(t_boolean(), t_atom('undefined')) end); -type(code, module_md5, 1, Xs) -> - strict(arg_types(code, module_md5, 1), Xs, - fun (_) -> t_sup(t_binary(), t_atom('undefined')) end); -type(code, make_stub_module, 3, Xs) -> - strict(arg_types(code, make_stub_module, 3), Xs, fun ([Mod,_,_]) -> Mod end); -type(code, rehash, 0, _) -> - t_atom('ok'); -%%-- erl_ddll ----------------------------------------------------------------- -type(erl_ddll, demonitor, 1, Xs) -> - type(erlang, demonitor, 1, Xs); -type(erl_ddll, format_error_int, 1, Xs) -> - strict(arg_types(erl_ddll, format_error_int, 1), Xs, - fun (_) -> t_string() end); -type(erl_ddll, info, 2, Xs) -> - strict(arg_types(erl_ddll, info, 2), Xs, fun (_) -> t_atom() end); -type(erl_ddll, loaded_drivers, 0, _) -> - t_tuple([t_atom('ok'), t_list(t_string())]); -type(erl_ddll, monitor, 2, Xs) -> % return type is the same, though args are not - type(erlang, monitor, 2, Xs); -type(erl_ddll, try_load, 3, Xs) -> - strict(arg_types(erl_ddll, try_load, 3), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('ok'), t_atom('already_loaded')]), - t_tuple([t_atom('ok'), t_atom('loaded')]), - t_tuple([t_atom('ok'), - t_atom('pending_driver'), t_reference()]), - t_tuple([t_atom('error'), t_atom('inconsistent')]), - t_tuple([t_atom('error'), t_atom('permanent')])]) - end); -type(erl_ddll, try_unload, 2, Xs) -> - strict(arg_types(erl_ddll, try_unload, 2), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('ok'), t_atom('pending_process')]), - t_tuple([t_atom('ok'), t_atom('unloaded')]), - t_tuple([t_atom('ok'), t_atom('pending_driver')]), - t_tuple([t_atom('ok'), - t_atom('pending_driver'), t_reference()]), - t_tuple([t_atom('error'), t_atom('permanent')]), - t_tuple([t_atom('error'), t_atom('not_loaded')]), - t_tuple([t_atom('error'), - t_atom('not_loaded_by_this_process')])]) - end); %%-- erlang ------------------------------------------------------------------- type(erlang, halt, 0, _) -> t_none(); type(erlang, halt, 1, _) -> t_none(); type(erlang, halt, 2, _) -> t_none(); type(erlang, exit, 1, _) -> t_none(); -%% Note that exit/2 sends an exit signal to another process. -type(erlang, exit, 2, _) -> t_atom('true'); type(erlang, error, 1, _) -> t_none(); type(erlang, error, 2, _) -> t_none(); type(erlang, throw, 1, _) -> t_none(); -type(erlang, hibernate, 3, _) -> t_none(); type(erlang, '==', 2, Xs = [X1, X2]) -> case t_is_atom(X1) andalso t_is_atom(X2) of true -> type(erlang, '=:=', 2, Xs); @@ -600,20 +495,12 @@ type(erlang, 'bnot', 1, Xs) -> {ok, T} -> T end end); -%% This returns (-X)-1, so it often gives a negative result. -%% strict(arg_types(erlang, 'bnot', 1), Xs, fun (_) -> t_integer() end); +%% Guard bif, needs to be here. type(erlang, abs, 1, Xs) -> strict(arg_types(erlang, abs, 1), Xs, fun ([X]) -> X end); -type(erlang, adler32, 1, Xs) -> - strict(arg_types(erlang, adler32, 1), Xs, fun (_) -> t_adler32() end); -type(erlang, adler32, 2, Xs) -> - strict(arg_types(erlang, adler32, 2), Xs, fun (_) -> t_adler32() end); -type(erlang, adler32_combine, 3, Xs) -> - strict(arg_types(erlang, adler32_combine, 3), Xs, - fun (_) -> t_adler32() end); +%% This returns (-X)-1, so it often gives a negative result. +%% strict(arg_types(erlang, 'bnot', 1), Xs, fun (_) -> t_integer() end); type(erlang, append, 2, Xs) -> type(erlang, '++', 2, Xs); % alias -type(erlang, append_element, 2, Xs) -> - strict(arg_types(erlang, append_element, 2), Xs, fun (_) -> t_tuple() end); type(erlang, apply, 2, Xs) -> Fun = fun ([X, _Y]) -> case t_is_fun(X) of @@ -626,111 +513,24 @@ type(erlang, apply, 2, Xs) -> strict(arg_types(erlang, apply, 2), Xs, Fun); type(erlang, apply, 3, Xs) -> strict(arg_types(erlang, apply, 3), Xs, fun (_) -> t_any() end); -type(erlang, atom_to_binary, 2, Xs) -> - strict(arg_types(erlang, atom_to_binary, 2), Xs, fun (_) -> t_binary() end); -type(erlang, atom_to_list, 1, Xs) -> - strict(arg_types(erlang, atom_to_list, 1), Xs, fun (_) -> t_string() end); +%% Guard bif, needs to be here. type(erlang, binary_part, 2, Xs) -> strict(arg_types(erlang, binary_part, 2), Xs, fun (_) -> t_binary() end); +%% Guard bif, needs to be here. type(erlang, binary_part, 3, Xs) -> strict(arg_types(erlang, binary_part, 3), Xs, fun (_) -> t_binary() end); -type(erlang, binary_to_atom, 2, Xs) -> - strict(arg_types(erlang, binary_to_atom, 2), Xs, fun (_) -> t_atom() end); -type(erlang, binary_to_existing_atom, 2, Xs) -> - type(erlang, binary_to_atom, 2, Xs); -type(erlang, binary_to_list, 1, Xs) -> - strict(arg_types(erlang, binary_to_list, 1), Xs, - fun (_) -> t_list(t_byte()) end); -type(erlang, binary_to_list, 3, Xs) -> - strict(arg_types(erlang, binary_to_list, 3), Xs, - fun (_) -> t_list(t_byte()) end); -type(erlang, binary_to_term, 1, Xs) -> - strict(arg_types(erlang, binary_to_term, 1), Xs, fun (_) -> t_any() end); -type(erlang, binary_to_term, 2, Xs) -> - strict(arg_types(erlang, binary_to_term, 2), Xs, fun (_) -> t_any() end); -type(erlang, bitsize, 1, Xs) -> % XXX: TAKE OUT - type(erlang, bit_size, 1, Xs); +%% Guard bif, needs to be here. type(erlang, bit_size, 1, Xs) -> strict(arg_types(erlang, bit_size, 1), Xs, fun (_) -> t_non_neg_integer() end); -type(erlang, bitstr_to_list, 1, Xs) -> % XXX: TAKE OUT - type(erlang, bitstring_to_list, 1, Xs); -type(erlang, bitstring_to_list, 1, Xs) -> - strict(arg_types(erlang, bitstring_to_list, 1), Xs, - fun (_) -> t_list(t_sup(t_byte(), t_bitstr())) end); -type(erlang, bump_reductions, 1, Xs) -> - strict(arg_types(erlang, bump_reductions, 1), Xs, - fun (_) -> t_atom('true') end); +%% Guard bif, needs to be here. type(erlang, byte_size, 1, Xs) -> strict(arg_types(erlang, byte_size, 1), Xs, fun (_) -> t_non_neg_integer() end); -type(erlang, call_on_load_function, 1, Xs) -> - %% Internal BIF used by on_load. - strict(arg_types(erlang, call_on_load_function, 1), Xs, - fun (_) -> t_any() end); -type(erlang, cancel_timer, 1, Xs) -> - strict(arg_types(erlang, cancel_timer, 1), Xs, - fun (_) -> t_sup(t_integer(), t_atom('false')) end); -type(erlang, check_old_code, 1, Xs) -> - strict(arg_types(erlang, check_old_code, 1), Xs, - fun (_) -> t_boolean() end); -type(erlang, check_process_code, 2, Xs) -> - strict(arg_types(erlang, check_process_code, 2), Xs, - fun (_) -> t_boolean() end); -type(erlang, crc32, 1, Xs) -> - strict(arg_types(erlang, crc32, 1), Xs, fun (_) -> t_crc32() end); -type(erlang, crc32, 2, Xs) -> - strict(arg_types(erlang, crc32, 2), Xs, fun (_) -> t_crc32() end); -type(erlang, crc32_combine, 3, Xs) -> - strict(arg_types(erlang, crc32_combine, 3), Xs, fun (_) -> t_crc32() end); -type(erlang, date, 0, _) -> - t_date(); -type(erlang, decode_packet, 3, Xs) -> - strict(arg_types(erlang, decode_packet, 3), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('ok'), t_packet(), t_binary()]), - t_tuple([t_atom('more'), t_sup([t_non_neg_integer(), - t_atom('undefined')])]), - t_tuple([t_atom('error'), t_any()])]) - end); -type(erlang, delete_module, 1, Xs) -> - strict(arg_types(erlang, delete_module, 1), Xs, - fun (_) -> t_sup(t_atom('true'), t_atom('undefined')) end); -type(erlang, demonitor, 1, Xs) -> - strict(arg_types(erlang, demonitor, 1), Xs, fun (_) -> t_atom('true') end); -%% TODO: overapproximation -- boolean only if 'info' is part of arg2 otherwise 'true' -type(erlang, demonitor, 2, Xs) -> - strict(arg_types(erlang, demonitor, 2), Xs, fun (_) -> t_boolean() end); type(erlang, disconnect_node, 1, Xs) -> strict(arg_types(erlang, disconnect_node, 1), Xs, fun (_) -> t_sup([t_boolean(), t_atom('ignored')]) end); -type(erlang, display, 1, _) -> t_atom('true'); -type(erlang, display_string, 1, Xs) -> - strict(arg_types(erlang, display_string, 1), Xs, fun(_) -> t_atom('true') end); -type(erlang, display_nl, 0, _) -> - t_atom('true'); -type(erlang, dist_exit, 3, Xs) -> - strict(arg_types(erlang, dist_exit, 3), Xs, fun (_) -> t_atom('true') end); -type(erlang, dt_append_vm_tag_data, 1, Xs) -> - strict(arg_types(erlang, dt_append_vm_tag_data, 1), - Xs, - fun(_) -> t_iodata() end); -type(erlang, dt_get_tag, 0, _) -> - t_sup(t_binary(), t_atom('undefined')); -type(erlang, dt_get_tag_data, 0, _) -> - t_sup(t_binary(), t_atom('undefined')); -type(erlang, dt_prepend_vm_tag_data, 1, Xs) -> - strict(arg_types(erlang, dt_prepend_vm_tag_data, 1), - Xs, - fun(_) -> t_iodata() end); -type(erlang, dt_put_tag, 1, Xs) -> - strict(arg_types(erlang, dt_put_tag, 1), Xs, - fun(_) -> t_sup(t_binary(), t_atom('undefined')) end); -type(erlang, dt_restore_tag, 1, Xs) -> - strict(arg_types(erlang, dt_restore_tag, 1), Xs, fun(_) -> t_atom('true') end); -type(erlang, dt_spread_tag, 1, Xs) -> - strict(arg_types(erlang, dt_spread_tag, 1), Xs, - fun(_) -> t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), - t_atom('true')) end); +%% Guard bif, needs to be here. +%% Also much more expressive than anything you could write in a spec... type(erlang, element, 2, Xs) -> strict(arg_types(erlang, element, 2), Xs, fun ([X1, X2]) -> @@ -754,95 +554,22 @@ type(erlang, element, 2, Xs) -> t_sup([type(erlang, element, 2, [X1, Y]) || Y <- Ts]) end end); -type(erlang, erase, 0, _) -> t_any(); -type(erlang, erase, 1, _) -> t_any(); -type(erlang, external_size, 1, _) -> t_integer(); -type(erlang, external_size, 2, _) -> t_integer(); -type(erlang, finish_after_on_load, 2, Xs) -> - %% Internal BIF used by on_load. - strict(arg_types(erlang, finish_after_on_load, 2), Xs, - fun (_) -> t_atom('true') end); +%% Guard bif, needs to be here. type(erlang, float, 1, Xs) -> strict(arg_types(erlang, float, 1), Xs, fun (_) -> t_float() end); -type(erlang, float_to_list, 1, Xs) -> - strict(arg_types(erlang, float_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, function_exported, 3, Xs) -> - strict(arg_types(erlang, function_exported, 3), Xs, - fun (_) -> t_boolean() end); type(erlang, fun_info, 1, Xs) -> strict(arg_types(erlang, fun_info, 1), Xs, fun (_) -> t_list(t_tuple([t_atom(), t_any()])) end); -type(erlang, fun_info, 2, Xs) -> - strict(arg_types(erlang, fun_info, 2), Xs, - fun (_) -> t_tuple([t_atom(), t_any()]) end); -type(erlang, fun_to_list, 1, Xs) -> - strict(arg_types(erlang, fun_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, garbage_collect, 0, _) -> t_atom('true'); -type(erlang, garbage_collect, 1, Xs) -> - strict(arg_types(erlang, garbage_collect, 1), Xs, fun (_) -> t_boolean() end); -type(erlang, garbage_collect_message_area, 0, _) -> - t_boolean(); -type(erlang, get, 0, _) -> t_list(t_tuple(2)); -type(erlang, get, 1, _) -> t_any(); % | t_atom('undefined') type(erlang, get_cookie, 0, _) -> t_atom(); % | t_atom('nocookie') -type(erlang, get_keys, 1, _) -> t_list(); -type(erlang, get_module_info, 1, Xs) -> - strict(arg_types(erlang, get_module_info, 1), Xs, - fun (_) -> - t_list(t_tuple([t_atom(), t_list(t_tuple([t_atom(), t_any()]))])) - end); -type(erlang, get_module_info, 2, Xs) -> - T_module_info_2_returns = - t_sup([t_atom(), - t_list(t_tuple([t_atom(), t_any()])), - t_list(t_tuple([t_atom(), t_arity(), t_integer()]))]), - strict(arg_types(erlang, get_module_info, 2), Xs, - fun ([Module, Item]) -> - case t_is_atom(Item) of - true -> - case t_atom_vals(Item) of - ['module'] -> t_inf(t_atom(), Module); - ['imports'] -> t_nil(); - ['exports'] -> t_list(t_tuple([t_atom(), t_arity()])); - ['functions'] -> t_list(t_tuple([t_atom(), t_arity()])); - ['attributes'] -> t_list(t_tuple([t_atom(), t_any()])); - ['compile'] -> t_list(t_tuple([t_atom(), t_any()])); - ['native_addresses'] -> % [{FunName, Arity, Address}] - t_list(t_tuple([t_atom(), t_arity(), t_integer()])); - List when is_list(List) -> - T_module_info_2_returns; - unknown -> - T_module_info_2_returns - end; - false -> - T_module_info_2_returns - end - end); -type(erlang, get_stacktrace, 0, _) -> - t_list(t_tuple([t_atom(), t_atom(), t_sup([t_arity(), t_list()]), - t_list()])); -type(erlang, group_leader, 0, _) -> t_pid(); -type(erlang, group_leader, 2, Xs) -> - strict(arg_types(erlang, group_leader, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, hash, 2, Xs) -> - strict(arg_types(erlang, hash, 2), Xs, fun (_) -> t_integer() end); +%% Guard bif, needs to be here. type(erlang, hd, 1, Xs) -> strict(arg_types(erlang, hd, 1), Xs, fun ([X]) -> t_cons_hd(X) end); -type(erlang, integer_to_list, 1, Xs) -> - strict(arg_types(erlang, integer_to_list, 1), Xs, - fun (_) -> t_string() end); type(erlang, integer_to_list, 2, Xs) -> strict(arg_types(erlang, integer_to_list, 2), Xs, fun (_) -> t_string() end); type(erlang, info, 1, Xs) -> type(erlang, system_info, 1, Xs); % alias -type(erlang, iolist_size, 1, Xs) -> - strict(arg_types(erlang, iolist_size, 1), Xs, - fun (_) -> t_non_neg_integer() end); -type(erlang, iolist_to_binary, 1, Xs) -> - strict(arg_types(erlang, iolist_to_binary, 1), Xs, - fun (_) -> t_binary() end); -type(erlang, is_alive, 0, _) -> t_boolean(); +%% All type tests are guard BIF's and may be implemented in ways that +%% cannot be expressed in a type spec, why they are kept in erl_bif_types. type(erlang, is_atom, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_atom(Y) end, t_atom()) end, strict(arg_types(erlang, is_atom, 1), Xs, Fun); @@ -851,8 +578,6 @@ type(erlang, is_binary, 1, Xs) -> check_guard(X, fun (Y) -> t_is_binary(Y) end, t_binary()) end, strict(arg_types(erlang, is_binary, 1), Xs, Fun); -type(erlang, is_bitstr, 1, Xs) -> % XXX: TAKE OUT - type(erlang, is_bitstring, 1, Xs); type(erlang, is_bitstring, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_bitstr(Y) end, t_bitstr()) @@ -863,8 +588,6 @@ type(erlang, is_boolean, 1, Xs) -> check_guard(X, fun (Y) -> t_is_boolean(Y) end, t_boolean()) end, strict(arg_types(erlang, is_boolean, 1), Xs, Fun); -type(erlang, is_builtin, 3, Xs) -> - strict(arg_types(erlang, is_builtin, 3), Xs, fun (_) -> t_boolean() end); type(erlang, is_float, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_float(Y) end, t_float()) @@ -909,9 +632,6 @@ type(erlang, is_pid, 1, Xs) -> type(erlang, is_port, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_port(Y) end, t_port()) end, strict(arg_types(erlang, is_port, 1), Xs, Fun); -type(erlang, is_process_alive, 1, Xs) -> - strict(arg_types(erlang, is_process_alive, 1), Xs, - fun (_) -> t_boolean() end); type(erlang, is_record, 2, Xs) -> Fun = fun ([X, Y]) -> case t_is_tuple(X) of @@ -1013,68 +733,12 @@ type(erlang, is_tuple, 1, Xs) -> check_guard(X, fun (Y) -> t_is_tuple(Y) end, t_tuple()) end, strict(arg_types(erlang, is_tuple, 1), Xs, Fun); +%% Guard bif, needs to be here. type(erlang, length, 1, Xs) -> strict(arg_types(erlang, length, 1), Xs, fun (_) -> t_non_neg_fixnum() end); -type(erlang, link, 1, Xs) -> - strict(arg_types(erlang, link, 1), Xs, fun (_) -> t_atom('true') end); -type(erlang, list_to_atom, 1, Xs) -> - strict(arg_types(erlang, list_to_atom, 1), Xs, fun (_) -> t_atom() end); -type(erlang, list_to_binary, 1, Xs) -> - strict(arg_types(erlang, list_to_binary, 1), Xs, - fun (_) -> t_binary() end); -type(erlang, list_to_bitstr, 1, Xs) -> - type(erlang, list_to_bitstring, 1, Xs); -type(erlang, list_to_bitstring, 1, Xs) -> - strict(arg_types(erlang, list_to_bitstring, 1), Xs, - fun (_) -> t_bitstr() end); -type(erlang, list_to_existing_atom, 1, Xs) -> - strict(arg_types(erlang, list_to_existing_atom, 1), Xs, - fun (_) -> t_atom() end); -type(erlang, list_to_float, 1, Xs) -> - strict(arg_types(erlang, list_to_float, 1), Xs, fun (_) -> t_float() end); -type(erlang, list_to_integer, 1, Xs) -> - strict(arg_types(erlang, list_to_integer, 1), Xs, - fun (_) -> t_integer() end); type(erlang, list_to_integer, 2, Xs) -> strict(arg_types(erlang, list_to_integer, 2), Xs, fun (_) -> t_integer() end); -type(erlang, list_to_pid, 1, Xs) -> - strict(arg_types(erlang, list_to_pid, 1), Xs, fun (_) -> t_pid() end); -type(erlang, list_to_tuple, 1, Xs) -> - strict(arg_types(erlang, list_to_tuple, 1), Xs, fun (_) -> t_tuple() end); -type(erlang, load_module, 2, Xs) -> - strict(arg_types(erlang, load_module, 2), Xs, - fun ([Mod,_Bin]) -> t_code_load_return(Mod) end); -type(erlang, load_nif, 2, Xs) -> - strict(arg_types(erlang, load_nif, 2), Xs, - fun (_) -> - Reason = t_atoms(['load_failed', 'bad_lib', 'load', - 'reload', 'upgrade', 'old_code']), - RsnPair = t_tuple([Reason, t_string()]), - t_sup(t_atom('ok'), t_tuple([t_atom('error'), RsnPair])) - end); -type(erlang, loaded, 0, _) -> - t_list(t_atom()); -type(erlang, localtime, 0, Xs) -> - type(erlang, universaltime, 0, Xs); % same -type(erlang, localtime_to_universaltime, 1, Xs) -> - type(erlang, universaltime_to_localtime, 1, Xs); % same -type(erlang, localtime_to_universaltime, 2, Xs) -> - strict(arg_types(erlang, localtime_to_universaltime, 2), Xs, % typecheck - fun ([X,_]) -> type(erlang, localtime_to_universaltime, 1, [X]) end); -type(erlang, make_fun, 3, Xs) -> - strict(arg_types(erlang, make_fun, 3), Xs, - fun ([_, _, Arity]) -> - case t_number_vals(Arity) of - [N] -> - case is_integer(N) andalso 0 =< N andalso N =< 255 of - true -> t_fun(N, t_any()); - false -> t_none() - end; - _Other -> t_fun() - end - end); -type(erlang, make_ref, 0, _) -> t_reference(); type(erlang, make_tuple, 2, Xs) -> strict(arg_types(erlang, make_tuple, 2), Xs, fun ([Int, _]) -> @@ -1091,87 +755,19 @@ type(erlang, make_tuple, 3, Xs) -> _Other -> t_tuple() end end); -type(erlang, match_spec_test, 3, Xs) -> - strict(arg_types(erlang, match_spec_test, 3), Xs, - fun (_) -> t_sup(t_tuple([t_atom('ok'), - t_any(), % it can be any term - t_list(t_atom('return_trace')), - t_match_spec_test_errors()]), - t_tuple([t_atom('error'), - t_match_spec_test_errors()])) end); -type(erlang, md5, 1, Xs) -> - strict(arg_types(erlang, md5, 1), Xs, fun (_) -> t_binary() end); -type(erlang, md5_final, 1, Xs) -> - strict(arg_types(erlang, md5_final, 1), Xs, fun (_) -> t_binary() end); -type(erlang, md5_init, 0, _) -> t_binary(); -type(erlang, md5_update, 2, Xs) -> - strict(arg_types(erlang, md5_update, 2), Xs, fun (_) -> t_binary() end); type(erlang, memory, 0, _) -> t_list(t_tuple([t_atom(), t_non_neg_fixnum()])); -type(erlang, memory, 1, Xs) -> - strict(arg_types(erlang, memory, 1), Xs, - fun ([Type]) -> - case t_is_atom(Type) of - true -> t_non_neg_fixnum(); - false -> - case t_is_list(Type) of - true -> t_list(t_tuple([t_atom(), t_non_neg_fixnum()])); - false -> - t_sup(t_non_neg_fixnum(), - t_list(t_tuple([t_atom(), t_non_neg_fixnum()]))) - end - end - end); -type(erlang, module_loaded, 1, Xs) -> - strict(arg_types(erlang, module_loaded, 1), Xs, fun (_) -> t_boolean() end); -type(erlang, monitor, 2, Xs) -> - strict(arg_types(erlang, monitor, 2), Xs, fun (_) -> t_reference() end); -type(erlang, monitor_node, 2, Xs) -> - strict(arg_types(erlang, monitor_node, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, monitor_node, 3, Xs) -> - strict(arg_types(erlang, monitor_node, 3), Xs, - fun (_) -> t_atom('true') end); type(erlang, nif_error, 1, _) -> t_any(); % this BIF and the next one are stubs for NIFs and never return type(erlang, nif_error, 2, Xs) -> strict(arg_types(erlang, nif_error, 2), Xs, fun (_) -> t_any() end); +%% Guard bif, needs to be here. type(erlang, node, 0, _) -> t_node(); +%% Guard bif, needs to be here. type(erlang, node, 1, Xs) -> strict(arg_types(erlang, node, 1), Xs, fun (_) -> t_node() end); type(erlang, nodes, 0, _) -> t_list(t_node()); -type(erlang, nodes, 1, Xs) -> - strict(arg_types(erlang, nodes, 1), Xs, fun (_) -> t_list(t_node()) end); -type(erlang, now, 0, _) -> - t_timestamp(); -type(erlang, open_port, 2, Xs) -> - strict(arg_types(erlang, open_port, 2), Xs, fun (_) -> t_port() end); -type(erlang, phash, 2, Xs) -> - strict(arg_types(erlang, phash, 2), Xs, fun (_) -> t_pos_integer() end); -type(erlang, phash2, 1, Xs) -> - strict(arg_types(erlang, phash2, 1), Xs, fun (_) -> t_non_neg_integer() end); -type(erlang, phash2, 2, Xs) -> - strict(arg_types(erlang, phash2, 2), Xs, fun (_) -> t_non_neg_integer() end); -type(erlang, pid_to_list, 1, Xs) -> - strict(arg_types(erlang, pid_to_list, 1), Xs, fun (_) -> t_string() end); type(erlang, port_call, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> strict(arg_types(erlang, port_call, Arity), Xs, fun (_) -> t_any() end); -type(erlang, port_close, 1, Xs) -> - strict(arg_types(erlang, port_close, 1), Xs, - fun (_) -> t_atom('true') end); -type(erlang, port_command, 2, Xs) -> - strict(arg_types(erlang, port_command, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, port_command, 3, Xs) -> - strict(arg_types(erlang, port_command, 3), Xs, - fun (_) -> t_boolean() end); -type(erlang, port_connect, 2, Xs) -> - strict(arg_types(erlang, port_connect, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, port_control, 3, Xs) -> - strict(arg_types(erlang, port_control, 3), Xs, - fun (_) -> t_sup(t_string(), t_binary()) end); -type(erlang, port_get_data, 1, Xs) -> - strict(arg_types(erlang, port_get_data, 1), Xs, fun (_) -> t_any() end); type(erlang, port_info, 1, Xs) -> strict(arg_types(erlang, port_info, 1), Xs, fun (_) -> t_sup(t_atom('undefined'), t_list()) end); @@ -1201,180 +797,11 @@ type(erlang, port_info, 2, Xs) -> t_string()])]) end) end); -type(erlang, port_to_list, 1, Xs) -> - strict(arg_types(erlang, port_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, ports, 0, _) -> t_list(t_port()); -type(erlang, port_set_data, 2, Xs) -> - strict(arg_types(erlang, port_set_data, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, pre_loaded, 0, _) -> t_list(t_atom()); -type(erlang, process_display, 2, _) -> t_atom('true'); -type(erlang, process_flag, 2, Xs) -> - T_process_flag_returns = t_sup([t_boolean(), t_atom(), t_non_neg_integer()]), - strict(arg_types(erlang, process_flag, 2), Xs, - fun ([Flag, _Option]) -> - case t_is_atom(Flag) of - true -> - case t_atom_vals(Flag) of - ['error_handler'] -> t_atom(); - ['min_heap_size'] -> t_non_neg_integer(); - ['min_bin_vheap_size'] -> t_non_neg_integer(); - ['scheduler'] -> t_non_neg_integer(); - ['monitor_nodes'] -> t_boolean(); - ['priority'] -> t_process_priority_level(); - ['save_calls'] -> t_non_neg_integer(); - ['trap_exit'] -> t_boolean(); - ['sensitive'] -> t_boolean(); - List when is_list(List) -> - T_process_flag_returns; - unknown -> - T_process_flag_returns - end; - false -> % XXX: over-approximation if Flag is tuple - T_process_flag_returns - end - end); -type(erlang, process_flag, 3, Xs) -> - strict(arg_types(erlang, process_flag, 3), Xs, - fun (_) -> t_non_neg_integer() end); -type(erlang, process_info, 1, Xs) -> - strict(arg_types(erlang, process_info, 1), Xs, - fun (_) -> - t_sup(t_list(t_tuple([t_pinfo(), t_any()])), - t_atom('undefined')) - end); -type(erlang, process_info, 2, Xs) -> - %% we define all normal return values: the return when the process exists - %% t_nil() is the return for 'registered_name'; perhaps for more - T_process_info_2_normal_returns = - t_sup([t_tuple([t_pinfo_item(), t_any()]), t_nil()]), - strict(arg_types(erlang, process_info, 2), Xs, - fun ([_Pid, InfoItem]) -> - Ret = case t_is_atom(InfoItem) of - true -> - case t_atom_vals(InfoItem) of - ['backtrace'] -> t_tuple([InfoItem, t_binary()]); - ['current_function'] -> t_tuple([InfoItem, t_mfa()]); - ['dictionary'] -> t_tuple([InfoItem, t_list()]); - ['error_handler'] -> t_tuple([InfoItem, t_atom()]); - ['garbage_collection'] -> - t_tuple([InfoItem, t_list()]); - ['group_leader'] -> t_tuple([InfoItem, t_pid()]); - ['heap_size'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['initial_call'] -> t_tuple([InfoItem, t_mfa()]); - ['last_calls'] -> - t_tuple([InfoItem, - t_sup(t_atom('false'), t_list())]); - ['links'] -> t_tuple([InfoItem, t_list(t_pid())]); - ['memory'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['message_queue_len'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['messages'] -> t_tuple([InfoItem, t_list()]); - ['monitored_by'] -> - t_tuple([InfoItem, t_list(t_pid())]); - ['monitors'] -> - t_tuple([InfoItem, - t_list(t_sup(t_tuple([t_atom('process'), - t_pid()]), - t_tuple([t_atom('process'), - t_tuple([t_atom(), - t_atom()])])))]); - ['priority'] -> - t_tuple([InfoItem, t_process_priority_level()]); - ['reductions'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['registered_name'] -> - t_sup(t_tuple([InfoItem, t_atom()]), t_nil()); - ['sequential_trace_token'] -> - t_tuple([InfoItem, t_any()]); %% Underspecified - ['stack_size'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['status'] -> - t_tuple([InfoItem, t_process_status()]); - ['suspending'] -> - t_tuple([InfoItem, - t_list(t_tuple([t_pid(), - t_non_neg_integer(), - t_non_neg_integer()]))]); - ['total_heap_size'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['trap_exit'] -> - t_tuple([InfoItem, t_boolean()]); - List when is_list(List) -> - T_process_info_2_normal_returns; - unknown -> - T_process_info_2_normal_returns - end; - false -> - case t_is_list(InfoItem) of - true -> - t_list(t_tuple([t_pinfo_item(), t_any()])); - false -> - t_sup(T_process_info_2_normal_returns, - t_list(t_tuple([t_pinfo_item(), t_any()]))) - end - end, - t_sup([Ret, t_atom('undefined')]) - end); -type(erlang, processes, 0, _) -> t_list(t_pid()); -type(erlang, purge_module, 1, Xs) -> - strict(arg_types(erlang, purge_module, 1), Xs, - fun (_) -> t_atom('true') end); -type(erlang, put, 2, Xs) -> - strict(arg_types(erlang, put, 2), Xs, fun (_) -> t_any() end); -type(erlang, raise, 3, _) -> t_none(); -type(erlang, read_timer, 1, Xs) -> - strict(arg_types(erlang, read_timer, 1), Xs, - fun (_) -> t_sup(t_non_neg_integer(), t_atom('false')) end); -type(erlang, ref_to_list, 1, Xs) -> - strict(arg_types(erlang, ref_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, register, 2, Xs) -> - strict(arg_types(erlang, register, 2), Xs, fun (_) -> t_atom('true') end); -type(erlang, registered, 0, _) -> t_list(t_atom()); -type(erlang, resume_process, 1, Xs) -> - strict(arg_types(erlang, resume_process, 1), Xs, - fun (_) -> t_any() end); %% TODO: overapproximation -- fix this +%% Guard bif, needs to be here. type(erlang, round, 1, Xs) -> strict(arg_types(erlang, round, 1), Xs, fun (_) -> t_integer() end); -type(erlang, posixtime_to_universaltime, 1, Xs) -> - strict(arg_types(erlang, posixtime_to_universaltime, 1), Xs, - fun(_) -> t_tuple([t_date(), t_time()]) end); +%% Guard bif, needs to be here. type(erlang, self, 0, _) -> t_pid(); -type(erlang, send, 2, Xs) -> type(erlang, '!', 2, Xs); % alias -type(erlang, send, 3, Xs) -> - strict(arg_types(erlang, send, 3), Xs, - fun (_) -> t_sup(t_atom('ok'), t_sendoptions()) end); -type(erlang, send_after, 3, Xs) -> - strict(arg_types(erlang, send_after, 3), Xs, fun (_) -> t_reference() end); -type(erlang, seq_trace, 2, Xs) -> - strict(arg_types(erlang, seq_trace, 2), Xs, - fun (_) -> t_sup(t_seq_trace_info_returns(), t_tuple(5)) end); -type(erlang, seq_trace_info, 1, Xs) -> - strict(arg_types(erlang, seq_trace_info, 1), Xs, - fun ([Item]) -> - case t_atom_vals(Item) of - ['label'] -> - t_sup(t_tuple([Item, t_non_neg_integer()]), t_nil()); - ['serial'] -> - t_sup(t_tuple([Item, t_tuple([t_non_neg_integer(), - t_non_neg_integer()])]), - t_nil()); - ['send'] -> t_tuple([Item, t_boolean()]); - ['receive'] -> t_tuple([Item, t_boolean()]); - ['print'] -> t_tuple([Item, t_boolean()]); - ['timestamp'] -> t_tuple([Item, t_boolean()]); - List when is_list(List) -> - t_seq_trace_info_returns(); - unknown -> - t_seq_trace_info_returns() - end - end); -type(erlang, seq_trace_print, 1, Xs) -> - strict(arg_types(erlang, seq_trace_print, 1), Xs, fun (_) -> t_boolean() end); -type(erlang, seq_trace_print, 2, Xs) -> - strict(arg_types(erlang, seq_trace_print, 2), Xs, fun (_) -> t_boolean() end); type(erlang, set_cookie, 2, Xs) -> strict(arg_types(erlang, set_cookie, 2), Xs, fun (_) -> t_atom('true') end); type(erlang, setelement, 3, Xs) -> @@ -1408,144 +835,22 @@ type(erlang, setelement, 3, Xs) -> t_sup([type(erlang, setelement, 3, [X1, Y, X3]) || Y <- Ts]) end end); -type(erlang, setnode, 2, Xs) -> - strict(arg_types(erlang, setnode, 2), Xs, fun (_) -> t_atom('true') end); -type(erlang, setnode, 3, Xs) -> - strict(arg_types(erlang, setnode, 3), Xs, fun (_) -> t_atom('true') end); +%% Guard bif, needs to be here. type(erlang, size, 1, Xs) -> strict(arg_types(erlang, size, 1), Xs, fun (_) -> t_non_neg_integer() end); type(erlang, spawn, 1, Xs) -> strict(arg_types(erlang, spawn, 1), Xs, fun (_) -> t_pid() end); type(erlang, spawn, 2, Xs) -> strict(arg_types(erlang, spawn, 2), Xs, fun (_) -> t_pid() end); -type(erlang, spawn, 3, Xs) -> - strict(arg_types(erlang, spawn, 3), Xs, fun (_) -> t_pid() end); type(erlang, spawn, 4, Xs) -> strict(arg_types(erlang, spawn, 4), Xs, fun (_) -> t_pid() end); type(erlang, spawn_link, 1, Xs) -> type(erlang, spawn, 1, Xs); % same type(erlang, spawn_link, 2, Xs) -> type(erlang, spawn, 2, Xs); % same -type(erlang, spawn_link, 3, Xs) -> type(erlang, spawn, 3, Xs); % same type(erlang, spawn_link, 4, Xs) -> type(erlang, spawn, 4, Xs); % same -type(erlang, spawn_opt, 1, Xs) -> - strict(arg_types(erlang, spawn_opt, 1), Xs, - fun ([Tuple]) -> - Fun = fun (TS) -> - [_, _, _, List] = t_tuple_args(TS), - t_spawn_opt_return(List) - end, - t_sup([Fun(TS) || TS <- t_tuple_subtypes(Tuple)]) - end); -type(erlang, spawn_opt, 2, Xs) -> - strict(arg_types(erlang, spawn_opt, 2), Xs, - fun ([_, List]) -> t_spawn_opt_return(List) end); -type(erlang, spawn_opt, 3, Xs) -> - strict(arg_types(erlang, spawn_opt, 3), Xs, - fun ([_, _, List]) -> t_spawn_opt_return(List) end); -type(erlang, spawn_opt, 4, Xs) -> - strict(arg_types(erlang, spawn_opt, 4), Xs, - fun ([_, _, _, List]) -> t_spawn_opt_return(List) end); -type(erlang, split_binary, 2, Xs) -> - strict(arg_types(erlang, split_binary, 2), Xs, - fun (_) -> t_tuple([t_binary(), t_binary()]) end); -type(erlang, start_timer, 3, Xs) -> - strict(arg_types(erlang, start_timer, 3), Xs, fun (_) -> t_reference() end); -type(erlang, statistics, 1, Xs) -> - strict(arg_types(erlang, statistics, 1), Xs, - fun ([Type]) -> - T_statistics_1 = t_sup([t_non_neg_integer(), - t_tuple([t_non_neg_integer(), - t_non_neg_integer()]), - %% When called with the argument 'io'. - t_tuple([t_tuple([t_atom('input'), - t_non_neg_integer()]), - t_tuple([t_atom('output'), - t_non_neg_integer()])]), - t_tuple([t_non_neg_integer(), - t_non_neg_integer(), - t_non_neg_integer()])]), - case t_atom_vals(Type) of - ['context_switches'] -> - t_tuple([t_non_neg_integer(), t_integer(0)]); - ['exact_reductions'] -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]); - ['garbage_collection'] -> - t_tuple([t_non_neg_integer(), - t_non_neg_integer(), - t_integer(0)]); - ['io'] -> - t_tuple([t_tuple([t_atom('input'), t_non_neg_integer()]), - t_tuple([t_atom('output'), t_non_neg_integer()])]); - ['reductions'] -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]); - ['run_queue'] -> - t_non_neg_integer(); - ['runtime'] -> - t_tuple([t_non_neg_integer(), t_integer(0)]); - ['wall_clock'] -> - t_tuple([t_non_neg_integer(), t_integer(0)]); - List when is_list(List) -> - T_statistics_1; - unknown -> - T_statistics_1 - end - end); type(erlang, subtract, 2, Xs) -> type(erlang, '--', 2, Xs); % alias type(erlang, suspend_process, 1, Xs) -> strict(arg_types(erlang, suspend_process, 1), Xs, fun (_) -> t_atom('true') end); -type(erlang, suspend_process, 2, Xs) -> - strict(arg_types(erlang, suspend_process, 2), Xs, - fun (_) -> t_boolean() end); -type(erlang, system_flag, 2, Xs) -> - strict(arg_types(erlang, system_flag, 2), Xs, - fun ([Flag,_Value]) -> - %% this provides an overapproximation of all return values - T_system_flag_2 = t_sup([t_boolean(), - t_integer(), - t_sequential_tracer(), - t_system_cpu_topology(), - t_system_multi_scheduling()]), - case t_is_atom(Flag) of - true -> - case t_atom_vals(Flag) of - ['backtrace_depth'] -> - t_non_neg_fixnum(); - ['cpu_topology'] -> - t_system_cpu_topology(); - ['debug_flags'] -> - t_atom('true'); - ['display_items'] -> - t_non_neg_fixnum(); - ['fullsweep_after'] -> - t_non_neg_fixnum(); - ['min_heap_size'] -> - t_non_neg_fixnum(); - ['min_bin_vheap_size'] -> - t_non_neg_fixnum(); - ['multi_scheduling'] -> - t_system_multi_scheduling(); - ['schedulers_online'] -> - t_pos_fixnum(); - ['scheduler_bind_type'] -> - t_scheduler_bind_type_results(); - ['sequential_tracer'] -> - t_sequential_tracer(); - ['trace_control_word'] -> - t_integer(); - List when is_list(List) -> - T_system_flag_2; - unknown -> - T_system_flag_2 - end; - false -> - case t_is_integer(Flag) of % SHOULD BE: t_is_fixnum - true -> - t_atom('true'); - false -> - T_system_flag_2 - end - end - end); type(erlang, system_info, 1, Xs) -> strict(arg_types(erlang, system_info, 1), Xs, fun ([Type]) -> @@ -1565,12 +870,8 @@ type(erlang, system_info, 1, Xs) -> t_list(t_tuple([t_atom(), t_list(t_tuple([t_atom(), t_any()]))]))]); - ['build_type'] -> - t_system_build_type_return(); ['break_ignored'] -> t_boolean(); - ['c_compiler_used'] -> - t_tuple([t_atom(), t_any()]); ['cpu_topology'] -> t_system_cpu_topology(); ['compat_rel'] -> @@ -1582,9 +883,7 @@ type(erlang, system_info, 1, Xs) -> ['dist'] -> t_binary(); ['dist_ctrl'] -> - t_list(t_tuple([t_atom(), t_sup([t_pid(), t_port])])); - ['driver_version'] -> - t_string(); + t_list(t_tuple([t_atom(), t_sup([t_pid(), t_port()])])); %% elib_malloc is intentionally not included, %% because it scheduled for removal in R15. ['endian'] -> @@ -1604,27 +903,18 @@ type(erlang, system_info, 1, Xs) -> t_binary(); ['internal_cpu_topology'] -> %% Undocumented internal feature t_internal_cpu_topology(); - ['kernel_poll'] -> - t_boolean(); ['loaded'] -> t_binary(); ['logical_processors'] -> t_non_neg_fixnum(); ['machine'] -> t_string(); - ['min_heap_size'] -> - t_tuple([t_atom('min_heap_size'), - t_non_neg_integer()]); - ['min_bin_vheap_size'] -> - t_tuple([t_atom('min_bin_vheap_size'), - t_non_neg_integer()]); ['multi_scheduling'] -> t_system_multi_scheduling(); ['multi_scheduling_blockers'] -> t_list(t_pid()); ['os_type'] -> t_tuple([t_sup([t_atom('unix'), - t_atom('vxworks'), t_atom('win32')]), t_atom()]); ['os_version'] -> @@ -1632,8 +922,6 @@ type(erlang, system_info, 1, Xs) -> t_non_neg_fixnum(), t_non_neg_fixnum()]), t_string()); - ['otp_release'] -> - t_string(); ['process_count'] -> t_non_neg_fixnum(); ['process_limit'] -> @@ -1663,8 +951,6 @@ type(erlang, system_info, 1, Xs) -> t_non_neg_fixnum(); ['trace_control_word'] -> t_integer(); - ['update_cpu_info'] -> - t_sup([t_atom('changed'), t_atom('unchanged')]); ['version'] -> t_string(); ['wordsize'] -> @@ -1678,56 +964,13 @@ type(erlang, system_info, 1, Xs) -> t_any() %% overapproximation as the return value might change end end); -type(erlang, system_monitor, 0, Xs) -> - strict(arg_types(erlang, system_monitor, 0), Xs, - fun (_) -> t_system_monitor_settings() end); -type(erlang, system_monitor, 1, Xs) -> - strict(arg_types(erlang, system_monitor, 1), Xs, - fun (_) -> t_system_monitor_settings() end); -type(erlang, system_monitor, 2, Xs) -> - strict(arg_types(erlang, system_monitor, 2), Xs, - fun (_) -> t_system_monitor_settings() end); -type(erlang, system_profile, 0, _) -> - t_system_profile_return(); -type(erlang, system_profile, 2, Xs) -> - strict(arg_types(erlang, system_profile, 2), Xs, - fun (_) -> t_system_profile_return() end); -type(erlang, term_to_binary, 1, Xs) -> - strict(arg_types(erlang, term_to_binary, 1), Xs, fun (_) -> t_binary() end); -type(erlang, term_to_binary, 2, Xs) -> - strict(arg_types(erlang, term_to_binary, 2), Xs, fun (_) -> t_binary() end); -type(erlang, time, 0, _) -> - t_tuple([t_non_neg_integer(), t_non_neg_integer(), t_non_neg_integer()]); +%% Guard bif, needs to be here. type(erlang, tl, 1, Xs) -> strict(arg_types(erlang, tl, 1), Xs, fun ([X]) -> t_cons_tl(X) end); -type(erlang, trace, 3, Xs) -> - strict(arg_types(erlang, trace, 3), Xs, fun (_) -> t_integer() end); -type(erlang, trace_delivered, 1, Xs) -> - strict(arg_types(erlang, trace_delivered, 1), Xs, - fun (_) -> t_reference() end); -type(erlang, trace_info, 2, Xs) -> - strict(arg_types(erlang, trace_info, 2), Xs, - fun (_) -> - t_tuple([t_atom(), - t_sup([%% the following is info about a PID - t_list(t_atom()), t_pid(), t_port(), - %% the following is info about a func - t_atom('global'), t_atom('local'), - t_atom('false'), t_atom('true'), - t_list(), t_pid(), t_port(), - t_integer(), - t_list(t_tuple([t_atom(), t_any()])), - %% and this is the 'not found' value - t_atom('undefined')])]) - end); -type(erlang, trace_pattern, 2, Xs) -> - strict(arg_types(erlang, trace_pattern, 2), Xs, - fun (_) -> t_non_neg_fixnum() end); %% num of MFAs that match pattern -type(erlang, trace_pattern, 3, Xs) -> - strict(arg_types(erlang, trace_pattern, 3), Xs, - fun (_) -> t_non_neg_fixnum() end); %% num of MFAs that match pattern +%% Guard bif, needs to be here. type(erlang, trunc, 1, Xs) -> strict(arg_types(erlang, trunc, 1), Xs, fun (_) -> t_integer() end); +%% Guard bif, needs to be here. type(erlang, tuple_size, 1, Xs) -> strict(arg_types(erlang, tuple_size, 1), Xs, fun (_) -> t_non_neg_integer() end); type(erlang, tuple_to_list, 1, Xs) -> @@ -1750,266 +993,10 @@ type(erlang, tuple_to_list, 1, Xs) -> end end end); -type(erlang, universaltime, 0, _) -> - t_tuple([t_date(), t_time()]); -type(erlang, universaltime_to_localtime, 1, Xs) -> - strict(arg_types(erlang, universaltime_to_localtime, 1), Xs, - fun ([T]) -> T end); -type(erlang, universaltime_to_posixtime, 1, Xs) -> - strict(arg_types(erlang, universaltime_to_posixtime,1), Xs, - fun(_) -> t_integer() end); -type(erlang, unlink, 1, Xs) -> - strict(arg_types(erlang, unlink, 1), Xs, fun (_) -> t_atom('true') end); -type(erlang, unregister, 1, Xs) -> - strict(arg_types(erlang, unregister, 1), Xs, fun (_) -> t_atom('true') end); -type(erlang, whereis, 1, Xs) -> - strict(arg_types(erlang, whereis, 1), Xs, - fun (_) -> t_sup([t_pid(), t_port(), t_atom('undefined')]) end); type(erlang, yield, 0, _) -> t_atom('true'); -%%-- erl_prim_loader ---------------------------------------------------------- -type(erl_prim_loader, get_file, 1, Xs) -> - strict(arg_types(erl_prim_loader, get_file, 1), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_binary(), t_string()]), - t_atom('error')) - end); -type(erl_prim_loader, get_path, 0, _) -> - t_tuple([t_atom('ok'), t_list(t_string())]); -type(erl_prim_loader, set_path, 1, Xs) -> - strict(arg_types(erl_prim_loader, set_path, 1), Xs, - fun (_) -> t_atom('ok') end); -%%-- error_logger ------------------------------------------------------------- -type(error_logger, warning_map, 0, _) -> - t_sup([t_atom('info'), t_atom('warning'), t_atom('error')]); -%%-- erts_debug --------------------------------------------------------------- -type(erts_debug, breakpoint, 2, Xs) -> - strict(arg_types(erts_debug, breakpoint, 2), Xs, fun (_) -> t_fixnum() end); -type(erts_debug, disassemble, 1, Xs) -> - strict(arg_types(erts_debug, disassemble, 1), Xs, - fun (_) -> t_sup([t_atom('false'), - t_atom('undef'), - t_tuple([t_integer(), t_binary(), t_mfa()])]) end); -type(erts_debug, display, 1, _) -> - t_string(); -type(erts_debug, dist_ext_to_term, 2, Xs) -> - strict(arg_types(erts_debug, dist_ext_to_term, 2), Xs, - fun (_) -> t_any() end); -type(erts_debug, dump_monitors, 1, Xs) -> - strict(arg_types(erts_debug, dump_monitors, 1), Xs, - fun(_) -> t_atom('true') end); -type(erts_debug, dump_links, 1, Xs) -> - strict(arg_types(erts_debug, dump_links, 1), Xs, - fun(_) -> t_atom('true') end); -type(erts_debug, flat_size, 1, Xs) -> - strict(arg_types(erts_debug, flat_size, 1), Xs, fun (_) -> t_integer() end); -type(erts_debug, get_internal_state, 1, _) -> - t_any(); -type(erts_debug, instructions, 0, _) -> - t_list(t_list(t_byte())); -type(erts_debug, lock_counters, 1, Xs) -> - strict(arg_types(erts_debug, lock_counters, 1), Xs, - fun ([Arg]) -> - case t_is_atom(Arg) of - true -> - case t_atom_vals(Arg) of - ['enabled'] -> t_boolean(); - ['info'] -> t_any(); - ['clear'] -> t_atom(ok); - _ -> t_sup([t_boolean(), t_any(), t_atom('ok')]) - end; - false -> - case t_is_tuple(Arg) of - true -> t_boolean(); - false -> t_sup([t_boolean(), t_any(), t_atom('ok')]) - end - end - end); -type(erts_debug, same, 2, Xs) -> - strict(arg_types(erts_debug, same, 2), Xs, fun (_) -> t_boolean() end); -type(erts_debug, set_internal_state, 2, _) -> - t_any(); %%-- ets ---------------------------------------------------------------------- -type(ets, all, 0, _) -> - t_list(t_tab()); -type(ets, delete, 1, Xs) -> - strict(arg_types(ets, delete, 1), Xs, fun (_) -> t_atom('true') end); -type(ets, delete, 2, Xs) -> - strict(arg_types(ets, delete, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, delete_all_objects, 1, Xs) -> - strict(arg_types(ets, delete_all_objects, 1), Xs, - fun (_) -> t_atom('true') end); -type(ets, delete_object, 2, Xs) -> - strict(arg_types(ets, delete_object, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, first, 1, Xs) -> - strict(arg_types(ets, first, 1), Xs, fun (_) -> t_any() end); -type(ets, give_away, 3, Xs) -> - strict(arg_types(ets, give_away, 3), Xs, fun (_) -> t_atom('true') end); -type(ets, info, 1, Xs) -> - strict(arg_types(ets, info, 1), Xs, - fun (_) -> - t_sup(t_list(t_tuple([t_ets_info_items(), t_any()])), - t_atom('undefined')) - end); -type(ets, info, 2, Xs) -> - strict(arg_types(ets, info, 2), Xs, fun (_) -> t_any() end); -type(ets, insert, 2, Xs) -> - strict(arg_types(ets, insert, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, insert_new, 2, Xs) -> - strict(arg_types(ets, insert_new, 2), Xs, fun (_) -> t_boolean() end); -type(ets, is_compiled_ms, 1, Xs) -> - strict(arg_types(ets, is_compiled_ms, 1), Xs, fun (_) -> t_boolean() end); -type(ets, last, 1, Xs) -> - type(ets, first, 1, Xs); -type(ets, lookup, 2, Xs) -> - strict(arg_types(ets, lookup, 2), Xs, fun (_) -> t_list(t_tuple()) end); -type(ets, lookup_element, 3, Xs) -> - strict(arg_types(ets, lookup_element, 3), Xs, fun (_) -> t_any() end); -type(ets, match, 1, Xs) -> - strict(arg_types(ets, match, 1), Xs, fun (_) -> t_matchres() end); -type(ets, match, 2, Xs) -> - strict(arg_types(ets, match, 2), Xs, fun (_) -> t_list() end); -type(ets, match, 3, Xs) -> - strict(arg_types(ets, match, 3), Xs, fun (_) -> t_matchres() end); -type(ets, match_object, 1, Xs) -> type(ets, match, 1, Xs); -type(ets, match_object, 2, Xs) -> type(ets, match, 2, Xs); -type(ets, match_object, 3, Xs) -> type(ets, match, 3, Xs); -type(ets, match_spec_compile, 1, Xs) -> - strict(arg_types(ets, match_spec_compile, 1), Xs, fun (_) -> t_any() end); -type(ets, match_spec_run_r, 3, Xs) -> - strict(arg_types(ets, match_spec_run_r, 3), Xs, fun (_) -> t_list() end); -type(ets, member, 2, Xs) -> - strict(arg_types(ets, member, 2), Xs, fun (_) -> t_boolean() end); -type(ets, new, 2, Xs) -> - strict(arg_types(ets, new, 2), Xs, fun (_) -> t_tab() end); -type(ets, next, 2, Xs) -> - strict(arg_types(ets, next, 2), Xs, - %% t_any below stands for: term() | '$end_of_table' - fun (_) -> t_any() end); -type(ets, prev, 2, Xs) -> type(ets, next, 2, Xs); type(ets, rename, 2, Xs) -> strict(arg_types(ets, rename, 2), Xs, fun ([_, Name]) -> Name end); -type(ets, safe_fixtable, 2, Xs) -> - strict(arg_types(ets, safe_fixtable, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, select, 1, Xs) -> - strict(arg_types(ets, select, 1), Xs, fun (_) -> t_matchres() end); -type(ets, select, 2, Xs) -> - strict(arg_types(ets, select, 2), Xs, fun (_) -> t_list() end); -type(ets, select, 3, Xs) -> - strict(arg_types(ets, select, 3), Xs, fun (_) -> t_matchres() end); -type(ets, select_count, 2, Xs) -> - strict(arg_types(ets, select_count, 2), Xs, - fun (_) -> t_non_neg_fixnum() end); -type(ets, select_delete, 2, Xs) -> - strict(arg_types(ets, select_delete, 2), Xs, - fun (_) -> t_non_neg_fixnum() end); -type(ets, select_reverse, 1, Xs) -> type(ets, select, 1, Xs); -type(ets, select_reverse, 2, Xs) -> type(ets, select, 2, Xs); -type(ets, select_reverse, 3, Xs) -> type(ets, select, 3, Xs); -type(ets, setopts, 2, Xs) -> - strict(arg_types(ets, setopts, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, slot, 2, Xs) -> - strict(arg_types(ets, slot, 2), Xs, - fun (_) -> t_sup(t_list(t_tuple()), t_atom('$end_of_table')) end); -type(ets, update_counter, 3, Xs) -> - strict(arg_types(ets, update_counter, 3), Xs, - fun ([_, _, Op]) -> - case t_is_integer(Op) of - true -> t_integer(); - false -> - case t_is_tuple(Op) of - true -> t_integer(); - false -> - case t_is_list(Op) of - true -> t_list(t_integer()); - false -> - case t_is_nil(Op) of - true -> t_nil(); - false -> t_sup([t_integer(), t_list(t_integer())]) - end - end - end - end - end); -type(ets, update_element, 3, Xs) -> - strict(arg_types(ets, update_element, 3), Xs, fun (_) -> t_boolean() end); -%%-- file --------------------------------------------------------------------- -type(file, native_name_encoding, 0, _) -> - t_file_encoding(); -%%-- prim_file ---------------------------------------------------------------- -type(prim_file, internal_name2native, 1, Xs) -> - strict(arg_types(prim_file, internal_name2native, 1), Xs, - fun (_) -> t_binary() end); -type(prim_file, internal_native2name, 1, Xs) -> - strict(arg_types(prim_file, internal_native2name, 1), Xs, - fun (_) -> t_prim_file_name() end); -type(prim_file, internal_normalize_utf8, 1, Xs) -> - strict(arg_types(prim_file, internal_normalize_utf8, 1), Xs, - fun (_) -> t_unicode_string() end); -%%-- gen_tcp ------------------------------------------------------------------ -%% NOTE: All type information for this module added to avoid loss of precision -type(gen_tcp, accept, 1, Xs) -> - strict(arg_types(gen_tcp, accept, 1), Xs, fun (_) -> t_gen_tcp_accept() end); -type(gen_tcp, accept, 2, Xs) -> - strict(arg_types(gen_tcp, accept, 2), Xs, fun (_) -> t_gen_tcp_accept() end); -type(gen_tcp, connect, 3, Xs) -> - strict(arg_types(gen_tcp, connect, 3), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_tcp, connect, 4, Xs) -> - strict(arg_types(gen_tcp, connect, 4), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_tcp, listen, 2, Xs) -> - strict(arg_types(gen_tcp, listen, 2), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_tcp, recv, 2, Xs) -> - strict(arg_types(gen_tcp, recv, 2), Xs, fun (_) -> t_gen_tcp_recv() end); -type(gen_tcp, recv, 3, Xs) -> - strict(arg_types(gen_tcp, recv, 3), Xs, fun (_) -> t_gen_tcp_recv() end); -type(gen_tcp, send, 2, Xs) -> - strict(arg_types(gen_tcp, send, 2), Xs, - fun (_) -> - t_sup(t_atom('ok'), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_tcp, shutdown, 2, Xs) -> - strict(arg_types(gen_tcp, shutdown, 2), Xs, - fun (_) -> - t_sup(t_atom('ok'), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -%%-- gen_udp ------------------------------------------------------------------ -%% NOTE: All type information for this module added to avoid loss of precision -type(gen_udp, open, 1, Xs) -> - strict(arg_types(gen_udp, open, 1), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_udp, open, 2, Xs) -> - strict(arg_types(gen_udp, open, 2), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_udp, recv, 2, Xs) -> - strict(arg_types(gen_udp, recv, 2), Xs, fun (_) -> t_gen_udp_recv() end); -type(gen_udp, recv, 3, Xs) -> - strict(arg_types(gen_udp, recv, 3), Xs, fun (_) -> t_gen_udp_recv() end); -type(gen_udp, send, 4, Xs) -> - strict(arg_types(gen_udp, send, 4), Xs, - fun (_) -> - t_sup(t_atom('ok'), - t_tuple([t_atom('error'), t_sup(t_atom('not_owner'), - t_inet_posix_error())])) - end); %%-- hipe_bifs ---------------------------------------------------------------- type(hipe_bifs, add_ref, 2, Xs) -> strict(arg_types(hipe_bifs, add_ref, 2), Xs, fun (_) -> t_nil() end); @@ -2132,26 +1119,6 @@ type(hipe_bifs, write_u32, 2, Xs) -> strict(arg_types(hipe_bifs, write_u32, 2), Xs, fun (_) -> t_nil() end); type(hipe_bifs, write_u64, 2, Xs) -> strict(arg_types(hipe_bifs, write_u64, 2), Xs, fun (_) -> t_nil() end); -%%-- io ----------------------------------------------------------------------- -type(io, format, 1, Xs) -> - strict(arg_types(io, format, 1), Xs, fun (_) -> t_atom('ok') end); -type(io, format, 2, Xs) -> - strict(arg_types(io, format, 2), Xs, fun (_) -> t_atom('ok') end); -type(io, format, 3, Xs) -> - strict(arg_types(io, format, 3), Xs, fun (_) -> t_atom('ok') end); -type(io, fwrite, 1, Xs) -> type(io, format, 1, Xs); % same -type(io, fwrite, 2, Xs) -> type(io, format, 2, Xs); % same -type(io, fwrite, 3, Xs) -> type(io, format, 3, Xs); % same -type(io, put_chars, 1, Xs) -> - strict(arg_types(io, put_chars, 1), Xs, fun (_) -> t_atom('ok') end); -type(io, put_chars, 2, Xs) -> - strict(arg_types(io, put_chars, 2), Xs, fun (_) -> t_atom('ok') end); -%%-- io_lib ------------------------------------------------------------------- -type(io_lib, format, 2, Xs) -> - strict(arg_types(io_lib, format, 2), Xs, - %% t_list() because the character list might be arbitrarily nested - fun (_) -> t_list(t_sup(t_char(), t_list())) end); -type(io_lib, fwrite, 2, Xs) -> type(io_lib, format, 2, Xs); % same %%-- lists -------------------------------------------------------------------- type(lists, all, 2, Xs) -> strict(arg_types(lists, all, 2), Xs, @@ -2521,8 +1488,6 @@ type(lists, merge, 2, Xs) -> end end end); -%% type(lists, merge, 3, Xs) -> -%% type(lists, merge3, 3, Xs) -> type(lists, min, 1, Xs) -> strict(arg_types(lists, min, 1), Xs, fun ([L]) -> t_list_elements(L) end); type(lists, nth, 2, Xs) -> @@ -2559,10 +1524,6 @@ type(lists, reverse, 1, Xs) -> strict(arg_types(lists, reverse, 1), Xs, fun ([X]) -> X end); type(lists, reverse, 2, Xs) -> type(erlang, '++', 2, Xs); % reverse-onto is just like append -type(lists, seq, 2, Xs) -> - strict(arg_types(lists, seq, 2), Xs, fun (_) -> t_list(t_integer()) end); -type(lists, seq, 3, Xs) -> - strict(arg_types(lists, seq, 3), Xs, fun (_) -> t_list(t_integer()) end); type(lists, sort, 1, Xs) -> strict(arg_types(lists, sort, 1), Xs, fun ([X]) -> X end); type(lists, sort, 2, Xs) -> @@ -2669,95 +1630,7 @@ type(lists, zipwith, 3, Xs) -> type(lists, zipwith3, 4, Xs) -> strict(arg_types(lists, zipwith3, 4), Xs, fun ([F,_As,_Bs,_Cs]) -> t_sup(t_list(t_fun_range(F)), t_nil()) end); -%%-- math --------------------------------------------------------------------- -type(math, acos, 1, Xs) -> - strict(arg_types(math, acos, 1), Xs, fun (_) -> t_float() end); -type(math, acosh, 1, Xs) -> - strict(arg_types(math, acosh, 1), Xs, fun (_) -> t_float() end); -type(math, asin, 1, Xs) -> - strict(arg_types(math, asin, 1), Xs, fun (_) -> t_float() end); -type(math, asinh, 1, Xs) -> - strict(arg_types(math, asinh, 1), Xs, fun (_) -> t_float() end); -type(math, atan, 1, Xs) -> - strict(arg_types(math, atan, 1), Xs, fun (_) -> t_float() end); -type(math, atan2, 2, Xs) -> - strict(arg_types(math, atan2, 2), Xs, fun (_) -> t_float() end); -type(math, atanh, 1, Xs) -> - strict(arg_types(math, atanh, 1), Xs, fun (_) -> t_float() end); -type(math, cos, 1, Xs) -> - strict(arg_types(math, cos, 1), Xs, fun (_) -> t_float() end); -type(math, cosh, 1, Xs) -> - strict(arg_types(math, cosh, 1), Xs, fun (_) -> t_float() end); -type(math, erf, 1, Xs) -> - strict(arg_types(math, erf, 1), Xs, fun (_) -> t_float() end); -type(math, erfc, 1, Xs) -> - strict(arg_types(math, erfc, 1), Xs, fun (_) -> t_float() end); -type(math, exp, 1, Xs) -> - strict(arg_types(math, exp, 1), Xs, fun (_) -> t_float() end); -type(math, log, 1, Xs) -> - strict(arg_types(math, log, 1), Xs, fun (_) -> t_float() end); -type(math, log10, 1, Xs) -> - strict(arg_types(math, log10, 1), Xs, fun (_) -> t_float() end); -type(math, pi, 0, _) -> t_float(); -type(math, pow, 2, Xs) -> - strict(arg_types(math, pow, 2), Xs, fun (_) -> t_float() end); -type(math, sin, 1, Xs) -> - strict(arg_types(math, sin, 1), Xs, fun (_) -> t_float() end); -type(math, sinh, 1, Xs) -> - strict(arg_types(math, sinh, 1), Xs, fun (_) -> t_float() end); -type(math, sqrt, 1, Xs) -> - strict(arg_types(math, sqrt, 1), Xs, fun (_) -> t_float() end); -type(math, tan, 1, Xs) -> - strict(arg_types(math, tan, 1), Xs, fun (_) -> t_float() end); -type(math, tanh, 1, Xs) -> - strict(arg_types(math, tanh, 1), Xs, fun (_) -> t_float() end); -%%-- net_kernel --------------------------------------------------------------- -type(net_kernel, dflag_unicode_io, 1, Xs) -> - strict(arg_types(net_kernel, dflag_unicode_io, 1), Xs, - fun (_) -> t_boolean() end); -%%-- ordsets ------------------------------------------------------------------ -type(ordsets, filter, 2, Xs) -> - type(lists, filter, 2, Xs); -type(ordsets, fold, 3, Xs) -> - type(lists, foldl, 3, Xs); -%%-- os ----------------------------------------------------------------------- -type(os, getenv, 0, _) -> t_list(t_string()); -type(os, getenv, 1, Xs) -> - strict(arg_types(os, getenv, 1), Xs, - fun (_) -> t_sup(t_string(), t_atom('false')) end); -type(os, getpid, 0, _) -> t_string(); -type(os, putenv, 2, Xs) -> - strict(arg_types(os, putenv, 2), Xs, fun (_) -> t_atom('true') end); -type(os, timestamp, 0, _) -> - t_timestamp(); -%%-- re ----------------------------------------------------------------------- -type(re, compile, 1, Xs) -> - strict(arg_types(re, compile, 1), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_re_MP()]), - t_tuple([t_atom('error'), t_re_ErrorSpec()])) - end); -type(re, compile, 2, Xs) -> - strict(arg_types(re, compile, 2), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_re_MP()]), - t_tuple([t_atom('error'), t_re_ErrorSpec()])) - end); -type(re, run, 2, Xs) -> - strict(arg_types(re, run, 2), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('match'), t_re_Captured()]), - t_atom('nomatch'), - t_tuple([t_atom('error'), t_re_ErrorSpec()])]) - end); -type(re, run, 3, Xs) -> - strict(arg_types(re, run, 3), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('match'), t_re_Captured()]), - t_atom('match'), - t_atom('nomatch'), - t_tuple([t_atom('error'), t_re_ErrorSpec()])]) - end); + %%-- string ------------------------------------------------------------------- type(string, chars, 2, Xs) -> % NOTE: added to avoid loss of information strict(arg_types(string, chars, 2), Xs, fun (_) -> t_string() end); @@ -2776,41 +1649,6 @@ type(string, chars, 3, Xs) -> % NOTE: added to avoid loss of information end end end); -type(string, concat, 2, Xs) -> % NOTE: added to avoid loss of information - strict(arg_types(string, concat, 2), Xs, fun (_) -> t_string() end); -type(string, equal, 2, Xs) -> % NOTE: added to avoid loss of information - strict(arg_types(string, equal, 2), Xs, fun (_) -> t_boolean() end); -type(string, to_float, 1, Xs) -> - strict(arg_types(string, to_float, 1), Xs, - fun (_) -> t_sup(t_tuple([t_float(), t_string()]), - t_tuple([t_atom('error'), - t_sup(t_atom('no_float'), - t_atom('not_a_list'))])) - end); -type(string, to_integer, 1, Xs) -> - strict(arg_types(string, to_integer, 1), Xs, - fun (_) -> t_sup(t_tuple([t_integer(), t_string()]), - t_tuple([t_atom('error'), - t_sup(t_atom('no_integer'), - t_atom('not_a_list'))])) - end); -%%-- unicode ------------------------------------------------------------------ -type(unicode, characters_to_binary, 2, Xs) -> - strict(arg_types(unicode, characters_to_binary, 2), Xs, - fun (_) -> - t_sup([t_binary(), - t_tuple([t_atom('error'), t_binary(), t_ML()]), - t_tuple([t_atom('incomplete'), t_binary(), t_ML()])]) - end); -type(unicode, characters_to_list, 2, Xs) -> - strict(arg_types(unicode, characters_to_list, 2), Xs, - fun (_) -> - t_sup([t_string(), - t_tuple([t_atom('error'), t_string(), t_ML()]), - t_tuple([t_atom('incomplete'), t_string(), t_ML()])]) - end); -type(unicode, bin_is_7bit, 1, Xs) -> - strict(arg_types(unicode, bin_is_7bit, 1), Xs, fun (_) -> t_boolean() end); %%----------------------------------------------------------------------------- type(M, F, A, Xs) when is_atom(M), is_atom(F), @@ -3265,107 +2103,6 @@ key_comparisons_fail(X0, KeyPos, TupleList) -> -spec arg_types(atom(), atom(), arity()) -> [erl_types:erl_type()] | 'unknown'. -%%------- binary -------------------------------------------------------------- -arg_types(binary, at, 2) -> - [t_binary(), t_non_neg_integer()]; -arg_types(binary, bin_to_list, 1) -> - [t_binary()]; -arg_types(binary, bin_to_list, 2) -> - [t_binary(), t_binary_part()]; -arg_types(binary, bin_to_list, 3) -> - [t_binary(), t_integer(), t_non_neg_integer()]; -arg_types(binary, compile_pattern, 1) -> - [t_sup(t_binary(), t_list(t_binary()))]; -arg_types(binary, copy, 1) -> - [t_binary()]; -arg_types(binary, copy, 2) -> - [t_binary(), t_non_neg_integer()]; -arg_types(binary, decode_unsigned, 1) -> - [t_binary()]; -arg_types(binary, decode_unsigned, 2) -> - [t_binary(), t_endian()]; -arg_types(binary, encode_unsigned, 1) -> - [t_non_neg_integer()]; -arg_types(binary, encode_unsigned, 2) -> - [t_non_neg_integer(), t_endian()]; -arg_types(binary, first, 1) -> - [t_binary()]; -arg_types(binary, last, 1) -> - [t_binary()]; -arg_types(binary, list_to_bin, 1) -> - arg_types(erlang, list_to_binary, 1); -arg_types(binary, longest_common_prefix, 1) -> - [t_list(t_binary())]; -arg_types(binary, longest_common_suffix, 1) -> - [t_list(t_binary())]; -arg_types(binary, match, 2) -> - [t_binary(), t_binary_pattern()]; -arg_types(binary, match, 3) -> - [t_binary(), t_binary_pattern(), t_binary_options()]; -arg_types(binary, matches, 2) -> - [t_binary(), t_binary_pattern()]; -arg_types(binary, matches, 3) -> - [t_binary(), t_binary_pattern(), t_binary_options()]; -arg_types(binary, part, 2) -> - arg_types(erlang, binary_part, 2); -arg_types(binary, part, 3) -> - arg_types(erlang, binary_part, 3); -arg_types(binary, referenced_byte_size, 1) -> - [t_binary()]; -%%------- code ---------------------------------------------------------------- -arg_types(code, get_chunk, 2) -> - [t_binary(), t_string()]; -arg_types(code, is_module_native, 1) -> - [t_atom()]; -arg_types(code, module_md5, 1) -> - [t_binary()]; -arg_types(code, make_stub_module, 3) -> - [t_atom(), t_binary(), t_tuple([t_list(), t_list()])]; -arg_types(code, rehash, 0) -> - []; -%%------- erl_ddll ------------------------------------------------------------ -arg_types(erl_ddll, demonitor, 1) -> - arg_types(erlang, demonitor, 1); -arg_types(erl_ddll, format_error_int, 1) -> - [t_sup([t_atom('inconsistent'), - t_atom('linked_in_driver'), - t_atom('permanent'), - t_atom('not_loaded'), - t_atom('not_loaded_by_this_process'), - t_atom('not_pending'), - t_atom('already_loaded'), - t_atom('unloading')])]; -arg_types(erl_ddll, info, 2) -> - [t_sup([t_atom(), t_string()]), - t_sup([t_atom('awaiting_load'), - t_atom('awaiting_unload'), - t_atom('driver_options'), - t_atom('linked_in_driver'), - t_atom('permanent'), - t_atom('port_count'), - t_atom('processes')])]; -arg_types(erl_ddll, loaded_drivers, 0) -> - []; -arg_types(erl_ddll, monitor, 2) -> - [t_atom('driver'), - t_tuple([t_atom(), t_sup([t_atom('loaded'), t_atom('unloaded')])])]; -arg_types(erl_ddll, try_load, 3) -> - [t_sup([t_atom(), t_string(), t_nonempty_list(t_sup([t_atom(), t_string()]))]), - t_sup([t_atom(), t_string()]), - t_list(t_sup([t_tuple([t_atom('driver_options'), - t_list(t_atom('kill_ports'))]), - t_tuple([t_atom('monitor'), - t_sup([t_atom('pending_driver'), - t_atom('pending')])]), - t_tuple([t_atom('reload'), - t_sup([t_atom('pending_driver'), - t_atom('pending')])])]))]; -arg_types(erl_ddll, try_unload, 2) -> - [t_sup([t_atom(), t_string(), t_nonempty_list(t_sup([t_atom(), t_string()]))]), - t_list(t_sup([t_atom('kill_ports'), - t_tuple([t_atom('monitor'), - t_sup([t_atom('pending_driver'), - t_atom('pending')])])]))]; %%------- erlang -------------------------------------------------------------- arg_types(erlang, '!', 2) -> Pid = t_sup([t_pid(), t_port(), t_atom(), @@ -3427,18 +2164,11 @@ arg_types(erlang, 'bsl', 2) -> [t_integer(), t_integer()]; arg_types(erlang, 'bnot', 1) -> [t_integer()]; +%% Guard bif, needs to be here. arg_types(erlang, abs, 1) -> [t_number()]; -arg_types(erlang, adler32, 1) -> - [t_iodata()]; -arg_types(erlang, adler32, 2) -> - [t_adler32(), t_iodata()]; -arg_types(erlang, adler32_combine, 3) -> - [t_adler32(), t_adler32(), t_non_neg_integer()]; arg_types(erlang, append, 2) -> arg_types(erlang, '++', 2); -arg_types(erlang, append_element, 2) -> - [t_tuple(), t_any()]; arg_types(erlang, apply, 2) -> [t_sup(t_tuple([t_module(), t_atom()]), @@ -3446,179 +2176,58 @@ arg_types(erlang, apply, 2) -> t_list()]; arg_types(erlang, apply, 3) -> [t_sup(t_atom(), t_tuple()), t_atom(), t_list()]; -arg_types(erlang, atom_to_binary, 2) -> - [t_atom(), t_encoding_a2b()]; -arg_types(erlang, atom_to_list, 1) -> - [t_atom()]; +%% Guard bif, needs to be here. arg_types(erlang, binary_part, 2) -> [t_binary(), t_tuple([t_non_neg_integer(), t_integer()])]; +%% Guard bif, needs to be here. arg_types(erlang, binary_part, 3) -> [t_binary(), t_non_neg_integer(), t_integer()]; -arg_types(erlang, binary_to_atom, 2) -> - [t_binary(), t_encoding_a2b()]; -arg_types(erlang, binary_to_existing_atom, 2) -> - arg_types(erlang, binary_to_atom, 2); -arg_types(erlang, binary_to_list, 1) -> - [t_binary()]; -arg_types(erlang, binary_to_list, 3) -> - [t_binary(), t_pos_integer(), t_pos_integer()]; % I want fixnum, but cannot -arg_types(erlang, binary_to_term, 1) -> - [t_binary()]; -arg_types(erlang, binary_to_term, 2) -> - [t_binary(), t_list(t_atom('safe'))]; -arg_types(erlang, bitsize, 1) -> % XXX: TAKE OUT - arg_types(erlang, bit_size, 1); +%% Guard bif, needs to be here. arg_types(erlang, bit_size, 1) -> [t_bitstr()]; -arg_types(erlang, bitstr_to_list, 1) -> % XXX: TAKE OUT - arg_types(erlang, bitstring_to_list, 1); -arg_types(erlang, bitstring_to_list, 1) -> - [t_bitstr()]; -arg_types(erlang, bump_reductions, 1) -> - [t_pos_fixnum()]; +%% Guard bif, needs to be here. arg_types(erlang, byte_size, 1) -> [t_binary()]; -arg_types(erlang, call_on_load_function, 1) -> - [t_atom()]; -arg_types(erlang, cancel_timer, 1) -> - [t_reference()]; -arg_types(erlang, check_old_code, 1) -> - [t_atom()]; -arg_types(erlang, check_process_code, 2) -> - [t_pid(), t_atom()]; -arg_types(erlang, crc32, 1) -> - [t_iodata()]; -arg_types(erlang, crc32, 2) -> - [t_crc32(), t_iodata()]; -arg_types(erlang, crc32_combine, 3) -> - [t_crc32(), t_crc32(), t_non_neg_integer()]; -arg_types(erlang, date, 0) -> - []; -arg_types(erlang, decode_packet, 3) -> - [t_decode_packet_type(), t_binary(), t_list(t_decode_packet_option())]; -arg_types(erlang, delete_module, 1) -> - [t_atom()]; -arg_types(erlang, demonitor, 1) -> - [t_reference()]; -arg_types(erlang, demonitor, 2) -> - [t_reference(), t_list(t_atoms(['flush', 'info']))]; arg_types(erlang, disconnect_node, 1) -> [t_node()]; -arg_types(erlang, display, 1) -> - [t_any()]; -arg_types(erlang, display_nl, 0) -> - []; -arg_types(erlang, display_string, 1) -> - [t_string()]; -arg_types(erlang, dist_exit, 3) -> - [t_pid(), t_dist_exit(), t_sup(t_pid(), t_port())]; -arg_types(erlang, dt_append_vm_tag_data, 1) -> - [t_iodata()]; -arg_types(erlang, dt_get_tag, 0) -> - []; -arg_types(erlang, dt_get_tag_data, 0) -> - []; -arg_types(erlang, dt_prepend_vm_tag_data, 1) -> - [t_iodata()]; -arg_types(erlang, dt_put_tag, 1) -> - [t_sup(t_binary(), t_atom('undefined'))]; -arg_types(erlang, dt_restore_tag, 1) -> - [t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), t_atom('true'))]; -arg_types(erlang, dt_spread_tag, 1) -> - [t_boolean()]; -arg_types(erlang, element, 2) -> - [t_pos_fixnum(), t_tuple()]; -arg_types(erlang, erase, 0) -> +arg_types(erlang, halt, 0) -> []; -arg_types(erlang, erase, 1) -> - [t_any()]; +arg_types(erlang, halt, 1) -> + [t_sup([t_non_neg_fixnum(), t_atom('abort'), t_string()])]; +arg_types(erlang, halt, 2) -> + [t_sup([t_non_neg_fixnum(), t_atom('abort'), t_string()]), + t_list(t_tuple([t_atom('flush'), t_boolean()]))]; arg_types(erlang, error, 1) -> [t_any()]; arg_types(erlang, error, 2) -> [t_any(), t_list()]; arg_types(erlang, exit, 1) -> [t_any()]; -arg_types(erlang, exit, 2) -> - [t_sup(t_pid(), t_port()), t_any()]; -arg_types(erlang, external_size, 1) -> - [t_any()]; % takes any term as input -arg_types(erlang, external_size, 2) -> - [t_any(), t_list()]; % takes any term as input and a list of options -arg_types(erlang, finish_after_on_load, 2) -> - [t_atom(), t_boolean()]; +%% Guard bif, needs to be here. +arg_types(erlang, element, 2) -> + [t_pos_fixnum(), t_tuple()]; +%% Guard bif, needs to be here. arg_types(erlang, float, 1) -> [t_number()]; -arg_types(erlang, float_to_list, 1) -> - [t_float()]; -arg_types(erlang, function_exported, 3) -> - [t_atom(), t_atom(), t_arity()]; arg_types(erlang, fun_info, 1) -> [t_fun()]; -arg_types(erlang, fun_info, 2) -> - [t_fun(), t_atom()]; -arg_types(erlang, fun_to_list, 1) -> - [t_fun()]; -arg_types(erlang, garbage_collect, 0) -> - []; -arg_types(erlang, garbage_collect, 1) -> - [t_pid()]; -arg_types(erlang, garbage_collect_message_area, 0) -> - []; -arg_types(erlang, get, 0) -> - []; -arg_types(erlang, get, 1) -> - [t_any()]; arg_types(erlang, get_cookie, 0) -> []; -arg_types(erlang, get_keys, 1) -> - [t_any()]; -arg_types(erlang, get_stacktrace, 0) -> - []; -arg_types(erlang, get_module_info, 1) -> - [t_atom()]; -arg_types(erlang, get_module_info, 2) -> - [t_atom(), t_module_info_2()]; -arg_types(erlang, group_leader, 0) -> - []; -arg_types(erlang, group_leader, 2) -> - [t_pid(), t_pid()]; -arg_types(erlang, halt, 0) -> - []; -arg_types(erlang, halt, 1) -> - [t_sup([t_non_neg_fixnum(), t_atom('abort'), t_string()])]; -arg_types(erlang, halt, 2) -> - [t_sup([t_non_neg_fixnum(), t_atom('abort'), t_string()]), - t_list(t_tuple([t_atom('flush'), t_boolean()]))]; -arg_types(erlang, hash, 2) -> - [t_any(), t_integer()]; +%% Guard bif, needs to be here. arg_types(erlang, hd, 1) -> [t_cons()]; -arg_types(erlang, hibernate, 3) -> - [t_atom(), t_atom(), t_list()]; arg_types(erlang, info, 1) -> arg_types(erlang, system_info, 1); % alias -arg_types(erlang, iolist_to_binary, 1) -> - [t_sup(t_iolist(), t_binary())]; -arg_types(erlang, iolist_size, 1) -> - [t_sup(t_iolist(), t_binary())]; -arg_types(erlang, integer_to_list, 1) -> - [t_integer()]; arg_types(erlang, integer_to_list, 2) -> [t_integer(), t_from_range(2, 36)]; -arg_types(erlang, is_alive, 0) -> - []; arg_types(erlang, is_atom, 1) -> [t_any()]; arg_types(erlang, is_binary, 1) -> [t_any()]; -arg_types(erlang, is_bitstr, 1) -> % XXX: TAKE OUT - arg_types(erlang, is_bitstring, 1); arg_types(erlang, is_bitstring, 1) -> [t_any()]; arg_types(erlang, is_boolean, 1) -> [t_any()]; -arg_types(erlang, is_builtin, 3) -> - [t_atom(), t_atom(), t_arity()]; arg_types(erlang, is_float, 1) -> [t_any()]; arg_types(erlang, is_function, 1) -> @@ -3635,8 +2244,6 @@ arg_types(erlang, is_pid, 1) -> [t_any()]; arg_types(erlang, is_port, 1) -> [t_any()]; -arg_types(erlang, is_process_alive, 1) -> - [t_pid()]; arg_types(erlang, is_record, 2) -> [t_any(), t_atom()]; arg_types(erlang, is_record, 3) -> @@ -3645,548 +2252,91 @@ arg_types(erlang, is_reference, 1) -> [t_any()]; arg_types(erlang, is_tuple, 1) -> [t_any()]; +%% Guard bif, needs to be here. arg_types(erlang, length, 1) -> [t_list()]; -arg_types(erlang, link, 1) -> - [t_sup(t_pid(), t_port())]; -arg_types(erlang, list_to_atom, 1) -> - [t_string()]; -arg_types(erlang, list_to_binary, 1) -> - [t_iolist()]; -arg_types(erlang, list_to_bitstr, 1) -> % XXX: TAKE OUT - arg_types(erlang, list_to_bitstring, 1); -arg_types(erlang, list_to_bitstring, 1) -> - [t_bitstrlist()]; -arg_types(erlang, list_to_existing_atom, 1) -> - [t_string()]; -arg_types(erlang, list_to_float, 1) -> - [t_list(t_byte())]; -arg_types(erlang, list_to_integer, 1) -> - [t_list(t_byte())]; arg_types(erlang, list_to_integer, 2) -> [t_list(t_byte()), t_from_range(2, 36)]; -arg_types(erlang, list_to_pid, 1) -> - [t_string()]; -arg_types(erlang, list_to_tuple, 1) -> - [t_list()]; -arg_types(erlang, load_module, 2) -> - [t_atom(), t_binary()]; -arg_types(erlang, load_nif, 2) -> - [t_string(), t_any()]; -arg_types(erlang, loaded, 0) -> - []; -arg_types(erlang, localtime, 0) -> - []; -arg_types(erlang, localtime_to_universaltime, 1) -> - [t_tuple([t_date(), t_time()])]; -arg_types(erlang, localtime_to_universaltime, 2) -> - arg_types(erlang, localtime_to_universaltime, 1) ++ - [t_sup(t_boolean(), t_atom('undefined'))]; -arg_types(erlang, make_fun, 3) -> - [t_atom(), t_atom(), t_arity()]; -arg_types(erlang, make_ref, 0) -> - []; arg_types(erlang, make_tuple, 2) -> [t_non_neg_fixnum(), t_any()]; % the value 0 is OK as first argument arg_types(erlang, make_tuple, 3) -> [t_non_neg_fixnum(), t_any(), t_list(t_tuple([t_pos_integer(), t_any()]))]; -arg_types(erlang, match_spec_test, 3) -> - [t_sup(t_list(), t_tuple()), - t_any(), - t_sup(t_atom('table'), t_atom('trace'))]; -arg_types(erlang, md5, 1) -> - [t_sup(t_iolist(), t_binary())]; -arg_types(erlang, md5_final, 1) -> - [t_binary()]; -arg_types(erlang, md5_init, 0) -> - []; -arg_types(erlang, md5_update, 2) -> - [t_binary(), t_sup(t_iolist(), t_binary())]; arg_types(erlang, memory, 0) -> []; -arg_types(erlang, memory, 1) -> - Arg = t_atoms(['total', 'processes', 'processes_used', 'system', - 'atom', 'atom_used', 'binary', 'code', 'ets', - 'maximum']), - [t_sup(Arg, t_list(Arg))]; -arg_types(erlang, module_loaded, 1) -> - [t_atom()]; -arg_types(erlang, monitor, 2) -> - [t_atom(), t_sup([t_pid(), t_atom(), t_tuple([t_atom(), t_node()])])]; -arg_types(erlang, monitor_node, 2) -> - [t_node(), t_boolean()]; -arg_types(erlang, monitor_node, 3) -> - [t_node(), t_boolean(), t_list(t_atom('allow_passive_connect'))]; arg_types(erlang, nif_error, 1) -> [t_any()]; arg_types(erlang, nif_error, 2) -> [t_any(), t_list()]; +%% Guard bif, needs to be here. arg_types(erlang, node, 0) -> []; +%% Guard bif, needs to be here. arg_types(erlang, node, 1) -> [t_identifier()]; arg_types(erlang, nodes, 0) -> []; -arg_types(erlang, nodes, 1) -> - NodesArg = t_atoms(['visible', 'hidden', 'connected', 'this', 'known']), - [t_sup(NodesArg, t_list(NodesArg))]; -arg_types(erlang, now, 0) -> - []; -arg_types(erlang, open_port, 2) -> - ArgT = t_sup(t_unicode_string(), t_binary()), - [t_sup(t_atom(), t_sup([t_tuple([t_atom('spawn'), t_string()]), - t_tuple([t_atom('spawn_driver'), t_string()]), - t_tuple([t_atom('spawn_executable'), ArgT]), - t_tuple([t_atom('fd'), t_integer(), t_integer()])])), - t_list(t_sup(t_sup([t_atom('stream'), - t_atom('exit_status'), - t_atom('use_stdio'), - t_atom('nouse_stdio'), - t_atom('stderr_to_stdout'), - t_atom('in'), - t_atom('out'), - t_atom('binary'), - t_atom('eof'), - t_atom('hide')]), - t_sup([t_tuple([t_atom('packet'), t_integer()]), - t_tuple([t_atom('line'), t_integer()]), - t_tuple([t_atom('cd'), t_string()]), - t_tuple([t_atom('env'), t_list(t_tuple(2))]), % XXX: More - t_tuple([t_atom('args'), t_list(ArgT)]), - t_tuple([t_atom('arg0'), ArgT])])))]; -arg_types(erlang, phash, 2) -> - [t_any(), t_pos_integer()]; -arg_types(erlang, phash2, 1) -> - [t_any()]; -arg_types(erlang, phash2, 2) -> - [t_any(), t_pos_integer()]; -arg_types(erlang, pid_to_list, 1) -> - [t_pid()]; arg_types(erlang, port_call, 2) -> [t_sup(t_port(), t_atom()), t_any()]; arg_types(erlang, port_call, 3) -> [t_sup(t_port(), t_atom()), t_integer(), t_any()]; -arg_types(erlang, port_close, 1) -> - [t_sup(t_port(), t_atom())]; -arg_types(erlang, port_command, 2) -> - [t_sup(t_port(), t_atom()), t_sup(t_iolist(), t_binary())]; -arg_types(erlang, port_command, 3) -> - [t_sup(t_port(), t_atom()), - t_sup(t_iolist(), t_binary()), - t_list(t_atoms(['force', 'nosuspend']))]; -arg_types(erlang, port_connect, 2) -> - [t_sup(t_port(), t_atom()), t_pid()]; -arg_types(erlang, port_control, 3) -> - [t_sup(t_port(), t_atom()), t_integer(), t_sup(t_iolist(), t_binary())]; -arg_types(erlang, port_get_data, 1) -> - [t_sup(t_port(), t_atom())]; arg_types(erlang, port_info, 1) -> [t_sup(t_port(), t_atom())]; arg_types(erlang, port_info, 2) -> [t_sup(t_port(), t_atom()), t_atoms(['registered_name', 'id', 'connected', 'links', 'name', 'input', 'output', 'os_pid'])]; -arg_types(erlang, port_to_list, 1) -> - [t_port()]; -arg_types(erlang, ports, 0) -> - []; -arg_types(erlang, port_set_data, 2) -> - [t_sup(t_port(), t_atom()), t_any()]; -arg_types(erlang, pre_loaded, 0) -> - []; -arg_types(erlang, process_display, 2) -> - [t_pid(), t_atom('backtrace')]; -arg_types(erlang, process_flag, 2) -> - [t_sup([t_atom('trap_exit'), - t_atom('error_handler'), - t_atom('min_heap_size'), - t_atom('min_bin_vheap_size'), - t_atom('priority'), - t_atom('save_calls'), - t_atom('sensitive'), - t_atom('scheduler'), % undocumented - t_atom('monitor_nodes'), % undocumented - t_tuple([t_atom('monitor_nodes'), t_list()])]), % undocumented - t_sup([t_boolean(), t_atom(), t_non_neg_integer()])]; -arg_types(erlang, process_flag, 3) -> - [t_pid(), t_atom('save_calls'), t_non_neg_integer()]; -arg_types(erlang, process_info, 1) -> - [t_pid()]; -arg_types(erlang, process_info, 2) -> - [t_pid(), t_pinfo()]; -arg_types(erlang, processes, 0) -> - []; -arg_types(erlang, purge_module, 1) -> - [t_atom()]; -arg_types(erlang, put, 2) -> - [t_any(), t_any()]; -arg_types(erlang, raise, 3) -> - OldStyleType = t_list(t_tuple([t_atom(), t_atom(), - t_sup([t_arity(), t_list()])])), - NewStyleType = type(erlang, get_stacktrace, 0, []), - [t_raise_errorclass(), t_any(), t_sup(OldStyleType, NewStyleType)]; -arg_types(erlang, read_timer, 1) -> - [t_reference()]; -arg_types(erlang, ref_to_list, 1) -> - [t_reference()]; -arg_types(erlang, register, 2) -> - [t_atom(), t_sup(t_port(), t_pid())]; -arg_types(erlang, registered, 0) -> - []; -arg_types(erlang, resume_process, 1) -> - [t_pid()]; % intended for debugging only +%% Guard bif, needs to be here. arg_types(erlang, round, 1) -> [t_number()]; -arg_types(erlang, posixtime_to_universaltime, 1) -> - [t_integer()]; +%% Guard bif, needs to be here. arg_types(erlang, self, 0) -> []; -arg_types(erlang, send, 2) -> - arg_types(erlang, '!', 2); % alias -arg_types(erlang, send, 3) -> - arg_types(erlang, send, 2) ++ [t_list(t_sendoptions())]; -arg_types(erlang, send_after, 3) -> - [t_non_neg_integer(), t_sup(t_pid(), t_atom()), t_any()]; -arg_types(erlang, seq_trace, 2) -> - [t_atom(), t_sup([t_boolean(), t_tuple([t_fixnum(), t_fixnum()]), t_fixnum(), t_nil()])]; -arg_types(erlang, seq_trace_info, 1) -> - [t_seq_trace_info()]; -arg_types(erlang, seq_trace_print, 1) -> - [t_any()]; -arg_types(erlang, seq_trace_print, 2) -> - [t_sup(t_atom(), t_fixnum()), t_any()]; arg_types(erlang, set_cookie, 2) -> [t_node(), t_atom()]; arg_types(erlang, setelement, 3) -> [t_pos_integer(), t_tuple(), t_any()]; -arg_types(erlang, setnode, 2) -> - [t_atom(), t_integer()]; -arg_types(erlang, setnode, 3) -> - [t_atom(), t_port(), t_tuple(4)]; +%% Guard bif, needs to be here. arg_types(erlang, size, 1) -> [t_sup(t_tuple(), t_binary())]; arg_types(erlang, spawn, 1) -> %% TODO: Tuple? [t_fun()]; arg_types(erlang, spawn, 2) -> %% TODO: Tuple? [t_node(), t_fun()]; -arg_types(erlang, spawn, 3) -> %% TODO: Tuple? - [t_atom(), t_atom(), t_list()]; arg_types(erlang, spawn, 4) -> %% TODO: Tuple? [t_node(), t_atom(), t_atom(), t_list()]; arg_types(erlang, spawn_link, 1) -> arg_types(erlang, spawn, 1); % same arg_types(erlang, spawn_link, 2) -> arg_types(erlang, spawn, 2); % same -arg_types(erlang, spawn_link, 3) -> - arg_types(erlang, spawn, 3); % same arg_types(erlang, spawn_link, 4) -> arg_types(erlang, spawn, 4); % same -arg_types(erlang, spawn_opt, 1) -> - [t_tuple([t_atom(), t_atom(), t_list(), t_list(t_spawn_options())])]; -arg_types(erlang, spawn_opt, 2) -> - [t_fun(), t_list(t_spawn_options())]; -arg_types(erlang, spawn_opt, 3) -> - [t_atom(), t_fun(), t_list(t_spawn_options())]; -arg_types(erlang, spawn_opt, 4) -> - [t_node(), t_atom(), t_list(), t_list(t_spawn_options())]; -arg_types(erlang, split_binary, 2) -> - [t_binary(), t_non_neg_integer()]; -arg_types(erlang, start_timer, 3) -> - [t_non_neg_integer(), t_sup(t_pid(), t_atom()), t_any()]; -arg_types(erlang, statistics, 1) -> - [t_sup([t_atom('context_switches'), - t_atom('exact_reductions'), - t_atom('garbage_collection'), - t_atom('io'), - t_atom('reductions'), - t_atom('run_queue'), - t_atom('runtime'), - t_atom('wall_clock')])]; arg_types(erlang, subtract, 2) -> arg_types(erlang, '--', 2); arg_types(erlang, suspend_process, 1) -> [t_pid()]; -arg_types(erlang, suspend_process, 2) -> - [t_pid(), t_list(t_sup([t_atom('unless_suspending'), - t_atom('asynchronous')]))]; -arg_types(erlang, system_flag, 2) -> - [t_sup([t_atom('backtrace_depth'), - t_atom('cpu_topology'), - t_atom('debug_flags'), % undocumented - t_atom('display_items'), % undocumented - t_atom('fullsweep_after'), - t_atom('min_heap_size'), - t_atom('min_bin_vheap_size'), - t_atom('multi_scheduling'), - t_atom('schedulers_online'), - t_atom('scheduler_bind_type'), - %% Undocumented; used to implement (the documented) seq_trace module. - t_atom('sequential_tracer'), - t_atom('trace_control_word'), - %% 'internal_cpu_topology' is an undocumented internal feature. - t_atom('internal_cpu_topology'), - t_integer()]), - t_sup([t_integer(), - %% 'cpu_topology' - t_system_cpu_topology(), - %% 'scheduler_bind_type' - t_scheduler_bind_type_args(), - %% Undocumented: the following is for 'debug_flags' that - %% takes any erlang term as flags and currently ignores it. - %% t_any(), % commented out since it destroys the type signature - %% - %% Again undocumented; the following are for 'sequential_tracer' - t_sequential_tracer(), - %% The following two are for 'multi_scheduling' - t_atom('block'), - t_atom('unblock'), - %% The following is for 'internal_cpu_topology' - t_internal_cpu_topology()])]; arg_types(erlang, system_info, 1) -> [t_sup([t_atom(), % documented t_tuple([t_atom(), t_any()]), % documented t_tuple([t_atom(), t_atom(), t_any()]), t_tuple([t_atom(allocator_sizes), t_reference(), t_any()])])]; -arg_types(erlang, system_monitor, 0) -> - []; -arg_types(erlang, system_monitor, 1) -> - [t_system_monitor_settings()]; -arg_types(erlang, system_monitor, 2) -> - [t_pid(), t_system_monitor_options()]; -arg_types(erlang, system_profile, 0) -> - []; -arg_types(erlang, system_profile, 2) -> - [t_sup([t_pid(), t_port(), t_atom('undefined')]), - t_system_profile_options()]; -arg_types(erlang, term_to_binary, 1) -> - [t_any()]; -arg_types(erlang, term_to_binary, 2) -> - [t_any(), t_list(t_sup([t_atom('compressed'), - t_tuple([t_atom('compressed'), t_from_range(0, 9)]), - t_tuple([t_atom('minor_version'), t_integers([0, 1])])]))]; arg_types(erlang, throw, 1) -> [t_any()]; -arg_types(erlang, time, 0) -> - []; +%% Guard bif, needs to be here. arg_types(erlang, tl, 1) -> [t_cons()]; -arg_types(erlang, trace, 3) -> - [t_sup(t_pid(), t_sup([t_atom('existing'), t_atom('new'), t_atom('all')])), - t_boolean(), - t_list(t_sup(t_atom(), t_tuple(2)))]; -arg_types(erlang, trace_delivered, 1) -> - [t_sup(t_pid(), t_atom('all'))]; -arg_types(erlang, trace_info, 2) -> - [t_sup([%% the following two get info about a PID - t_pid(), t_atom('new'), - %% while the following two get info about a func - t_mfa(), t_atom('on_load')]), - t_sup([%% the following are items about a PID - t_atom('flags'), t_atom('tracer'), - %% while the following are items about a func - t_atom('traced'), t_atom('match_spec'), t_atom('meta'), - t_atom('meta_match_spec'), t_atom('call_count'), - t_atom('call_time'), t_atom('all')])]; -arg_types(erlang, trace_pattern, 2) -> - [t_sup(t_tuple([t_atom(), t_atom(), t_sup(t_arity(), t_atom('_'))]), - t_atom('on_load')), - t_sup([t_boolean(), t_list(), t_atom('restart'), t_atom('pause')])]; -arg_types(erlang, trace_pattern, 3) -> - arg_types(erlang, trace_pattern, 2) ++ - [t_list(t_sup([t_atom('global'), t_atom('local'), - t_atom('meta'), t_tuple([t_atom('meta'), t_pid()]), - t_atom('call_count'), t_atom('call_time')]))]; +%% Guard bif, needs to be here. arg_types(erlang, trunc, 1) -> [t_number()]; +%% Guard bif, needs to be here. arg_types(erlang, tuple_size, 1) -> [t_tuple()]; arg_types(erlang, tuple_to_list, 1) -> [t_tuple()]; -arg_types(erlang, universaltime, 0) -> - []; -arg_types(erlang, universaltime_to_localtime, 1) -> - [t_tuple([t_date(), t_time()])]; -arg_types(erlang, universaltime_to_posixtime, 1) -> - [t_tuple([t_date(), t_time()])]; -arg_types(erlang, unlink, 1) -> - [t_sup(t_pid(), t_port())]; -arg_types(erlang, unregister, 1) -> - [t_atom()]; -arg_types(erlang, whereis, 1) -> - [t_atom()]; arg_types(erlang, yield, 0) -> []; -%%------- erl_prim_loader ----------------------------------------------------- -arg_types(erl_prim_loader, get_file, 1) -> - [t_sup(t_atom(), t_string())]; -arg_types(erl_prim_loader, get_path, 0) -> - []; -arg_types(erl_prim_loader, set_path, 1) -> - [t_list(t_string())]; -%%------- error_logger -------------------------------------------------------- -arg_types(error_logger, warning_map, 0) -> - []; -%%------- erts_debug ---------------------------------------------------------- -arg_types(erts_debug, breakpoint, 2) -> - [t_tuple([t_atom(), t_atom(), t_sup(t_integer(), t_atom('_'))]), t_boolean()]; -arg_types(erts_debug, disassemble, 1) -> - [t_sup(t_mfa(), t_integer())]; -arg_types(erts_debug, display, 1) -> - [t_any()]; -arg_types(erts_debug, dist_ext_to_term, 2) -> - [t_tuple(), t_binary()]; -arg_types(erts_debug, dump_monitors, 1) -> - [t_sup([t_pid(),t_atom()])]; -arg_types(erts_debug, dump_links, 1) -> - [t_sup([t_pid(),t_atom(),t_port()])]; -arg_types(erts_debug, flat_size, 1) -> - [t_any()]; -arg_types(erts_debug, get_internal_state, 1) -> - [t_any()]; -arg_types(erts_debug, instructions, 0) -> - []; -arg_types(erts_debug, lock_counters, 1) -> - [t_sup([t_atom(enabled), - t_atom(info), - t_atom(clear), - t_tuple([t_atom(copy_save), t_boolean()]), - t_tuple([t_atom(process_locks), t_boolean()])])]; -arg_types(erts_debug, same, 2) -> - [t_any(), t_any()]; -arg_types(erts_debug, set_internal_state, 2) -> - [t_any(), t_any()]; %%------- ets ----------------------------------------------------------------- -arg_types(ets, all, 0) -> - []; -arg_types(ets, delete, 1) -> - [t_tab()]; -arg_types(ets, delete, 2) -> - [t_tab(), t_any()]; -arg_types(ets, delete_all_objects, 1) -> - [t_tab()]; -arg_types(ets, delete_object, 2) -> - [t_tab(), t_tuple()]; -arg_types(ets, first, 1) -> - [t_tab()]; -arg_types(ets, give_away, 3) -> - [t_tab(), t_pid(), t_any()]; -arg_types(ets, info, 1) -> - [t_tab()]; -arg_types(ets, info, 2) -> - [t_tab(), t_ets_info_items()]; -arg_types(ets, insert, 2) -> - [t_tab(), t_sup(t_tuple(), t_list(t_tuple()))]; -arg_types(ets, insert_new, 2) -> - [t_tab(), t_sup(t_tuple(), t_list(t_tuple()))]; -arg_types(ets, is_compiled_ms, 1) -> - [t_any()]; -arg_types(ets, last, 1) -> - arg_types(ets, first, 1); -arg_types(ets, lookup, 2) -> - [t_tab(), t_any()]; -arg_types(ets, lookup_element, 3) -> - [t_tab(), t_any(), t_pos_fixnum()]; -arg_types(ets, match, 1) -> - [t_any()]; -arg_types(ets, match, 2) -> - [t_tab(), t_match_pattern()]; -arg_types(ets, match, 3) -> - [t_tab(), t_match_pattern(), t_pos_fixnum()]; -arg_types(ets, match_object, 1) -> - arg_types(ets, match, 1); -arg_types(ets, match_object, 2) -> - arg_types(ets, match, 2); -arg_types(ets, match_object, 3) -> - arg_types(ets, match, 3); -arg_types(ets, match_spec_compile, 1) -> - [t_matchspecs()]; -arg_types(ets, match_spec_run_r, 3) -> - [t_list(t_tuple()),t_matchspecs(), t_list()]; -arg_types(ets, member, 2) -> - [t_tab(), t_any()]; -arg_types(ets, new, 2) -> - [t_atom(), t_ets_new_options()]; -arg_types(ets, next, 2) -> - [t_tab(), t_any()]; -arg_types(ets, prev, 2) -> - [t_tab(), t_any()]; arg_types(ets, rename, 2) -> [t_atom(), t_atom()]; -arg_types(ets, safe_fixtable, 2) -> - [t_tab(), t_boolean()]; -arg_types(ets, select, 1) -> - [t_any()]; -arg_types(ets, select, 2) -> - [t_tab(), t_matchspecs()]; -arg_types(ets, select, 3) -> - [t_tab(), t_matchspecs(), t_pos_fixnum()]; -arg_types(ets, select_count, 2) -> - [t_tab(), t_matchspecs()]; -arg_types(ets, select_delete, 2) -> - [t_tab(), t_matchspecs()]; -arg_types(ets, select_reverse, 1) -> - arg_types(ets, select, 1); -arg_types(ets, select_reverse, 2) -> - arg_types(ets, select, 2); -arg_types(ets, select_reverse, 3) -> - arg_types(ets, select, 3); -arg_types(ets, slot, 2) -> - [t_tab(), t_non_neg_fixnum()]; % 2nd arg can be 0 -arg_types(ets, setopts, 2) -> - Opt = t_sup([t_tuple([t_atom('heir'), t_pid(), t_any()]), - t_tuple([t_atom('heir'), t_atom('none')]), - t_tuple([t_atom('protection'), - t_sup([t_atom('protected'), - t_atom('private'), - t_atom('public')])])]), - [t_tab(), t_sup(Opt, t_list(Opt))]; -arg_types(ets, update_counter, 3) -> - Int = t_integer(), - UpdateOp = t_sup(t_tuple([Int, Int]), t_tuple([Int, Int, Int, Int])), - [t_tab(), t_any(), t_sup([UpdateOp, t_list(UpdateOp), Int])]; -arg_types(ets, update_element, 3) -> - PosValue = t_tuple([t_integer(), t_any()]), - [t_tab(), t_any(), t_sup(PosValue, t_list(PosValue))]; -%%------- file ---------------------------------------------------------------- -arg_types(file, native_name_encoding, 0) -> - []; -%%-- prim_file ---------------------------------------------------------------- -arg_types(prim_file, internal_name2native, 1) -> - [t_prim_file_name()]; -arg_types(prim_file, internal_native2name, 1) -> - [t_binary()]; -arg_types(prim_file, internal_normalize_utf8, 1) -> - [t_binary()]; -%%------- gen_tcp ------------------------------------------------------------- -arg_types(gen_tcp, accept, 1) -> - [t_socket()]; -arg_types(gen_tcp, accept, 2) -> - [t_socket(), t_timeout()]; -arg_types(gen_tcp, connect, 3) -> - [t_gen_tcp_address(), t_gen_tcp_port(), t_list(t_gen_tcp_connect_option())]; -arg_types(gen_tcp, connect, 4) -> - arg_types(gen_tcp, connect, 3) ++ [t_timeout()]; -arg_types(gen_tcp, listen, 2) -> - [t_gen_tcp_port(), t_list(t_gen_tcp_listen_option())]; -arg_types(gen_tcp, recv, 2) -> - [t_socket(), t_non_neg_integer()]; -arg_types(gen_tcp, recv, 3) -> - arg_types(gen_tcp, recv, 2) ++ [t_timeout()]; -arg_types(gen_tcp, send, 2) -> - [t_socket(), t_packet()]; -arg_types(gen_tcp, shutdown, 2) -> - [t_socket(), t_sup([t_atom('read'), t_atom('write'), t_atom('read_write')])]; -%%------- gen_udp ------------------------------------------------------------- -arg_types(gen_udp, open, 1) -> - [t_gen_tcp_port()]; -arg_types(gen_udp, open, 2) -> - [t_gen_tcp_port(), t_list(t_gen_udp_connect_option())]; -arg_types(gen_udp, recv, 2) -> - arg_types(gen_tcp, recv, 2); -arg_types(gen_udp, recv, 3) -> - arg_types(gen_tcp, recv, 3); -arg_types(gen_udp, send, 4) -> - [t_socket(), t_gen_tcp_address(), t_gen_tcp_port(), t_packet()]; %%------- hipe_bifs ----------------------------------------------------------- arg_types(hipe_bifs, add_ref, 2) -> [t_mfa(), t_tuple([t_mfa(), @@ -4233,7 +2383,7 @@ arg_types(hipe_bifs, check_crc, 1) -> arg_types(hipe_bifs, enter_code, 2) -> [t_binary(), t_sup(t_nil(), t_tuple())]; arg_types(hipe_bifs, enter_sdesc, 1) -> - [t_tuple([t_integer(), t_integer(), t_integer(), t_integer(), t_integer()])]; + [t_tuple([t_integer(), t_integer(), t_integer(), t_integer(), t_integer(), t_mfa()])]; arg_types(hipe_bifs, find_na_or_make_stub, 2) -> [t_mfa(), t_boolean()]; arg_types(hipe_bifs, fun_to_address, 1) -> @@ -4284,28 +2434,6 @@ arg_types(hipe_bifs, write_u32, 2) -> [t_integer(), t_integer()]; arg_types(hipe_bifs, write_u64, 2) -> [t_integer(), t_integer()]; -%%------- io ------------------------------------------------------------------ -arg_types(io, format, 1) -> - [t_io_format_string()]; -arg_types(io, format, 2) -> - [t_io_format_string(), t_list()]; -arg_types(io, format, 3) -> - [t_io_device(), t_io_format_string(), t_list()]; -arg_types(io, fwrite, 1) -> - arg_types(io, format, 1); -arg_types(io, fwrite, 2) -> - arg_types(io, format, 2); -arg_types(io, fwrite, 3) -> - arg_types(io, format, 3); -arg_types(io, put_chars, 1) -> - [t_iodata()]; -arg_types(io, put_chars, 2) -> - [t_io_device(), t_iodata()]; -%%------- io_lib -------------------------------------------------------------- -arg_types(io_lib, format, 2) -> - arg_types(io, format, 2); -arg_types(io_lib, fwrite, 2) -> - arg_types(io_lib, format, 2); %%------- lists --------------------------------------------------------------- arg_types(lists, all, 2) -> [t_fun([t_any()], t_boolean()), t_list()]; @@ -4377,10 +2505,6 @@ arg_types(lists, reverse, 1) -> [t_list()]; arg_types(lists, reverse, 2) -> [t_list(), t_any()]; -arg_types(lists, seq, 2) -> - [t_integer(), t_integer()]; -arg_types(lists, seq, 3) -> - [t_integer(), t_integer(), t_integer()]; arg_types(lists, sort, 1) -> [t_list()]; arg_types(lists, sort, 2) -> @@ -4409,97 +2533,12 @@ arg_types(lists, zipwith, 3) -> [t_fun([t_any(), t_any()], t_any()), t_list(), t_list()]; arg_types(lists, zipwith3, 4) -> [t_fun([t_any(), t_any(), t_any()], t_any()), t_list(), t_list(), t_list()]; -%%------- math ---------------------------------------------------------------- -arg_types(math, acos, 1) -> - [t_number()]; -arg_types(math, acosh, 1) -> - [t_number()]; -arg_types(math, asin, 1) -> - [t_number()]; -arg_types(math, asinh, 1) -> - [t_number()]; -arg_types(math, atan, 1) -> - [t_number()]; -arg_types(math, atan2, 2) -> - [t_number(), t_number()]; -arg_types(math, atanh, 1) -> - [t_number()]; -arg_types(math, cos, 1) -> - [t_number()]; -arg_types(math, cosh, 1) -> - [t_number()]; -arg_types(math, erf, 1) -> - [t_number()]; -arg_types(math, erfc, 1) -> - [t_number()]; -arg_types(math, exp, 1) -> - [t_number()]; -arg_types(math, log, 1) -> - [t_number()]; -arg_types(math, log10, 1) -> - [t_number()]; -arg_types(math, pi, 0) -> - []; -arg_types(math, pow, 2) -> - [t_number(), t_number()]; -arg_types(math, sin, 1) -> - [t_number()]; -arg_types(math, sinh, 1) -> - [t_number()]; -arg_types(math, sqrt, 1) -> - [t_number()]; -arg_types(math, tan, 1) -> - [t_number()]; -arg_types(math, tanh, 1) -> - [t_number()]; -%%-- net_kernel --------------------------------------------------------------- -arg_types(net_kernel, dflag_unicode_io, 1) -> - [t_pid()]; -%%------- ordsets ------------------------------------------------------------- -arg_types(ordsets, filter, 2) -> - arg_types(lists, filter, 2); -arg_types(ordsets, fold, 3) -> - arg_types(lists, foldl, 3); -%%------- os ------------------------------------------------------------------ -arg_types(os, getenv, 0) -> - []; -arg_types(os, getenv, 1) -> - [t_string()]; -arg_types(os, getpid, 0) -> - []; -arg_types(os, putenv, 2) -> - [t_string(), t_string()]; -arg_types(os, timestamp, 0) -> - []; -%%-- re ----------------------------------------------------------------------- -arg_types(re, compile, 1) -> - [t_iodata()]; -arg_types(re, compile, 2) -> - [t_sup(t_iodata(), t_charlist()), t_list(t_re_compile_option())]; -arg_types(re, run, 2) -> - [t_sup(t_iodata(), t_charlist()), t_re_RE()]; -arg_types(re, run, 3) -> - [t_sup(t_iodata(), t_charlist()), t_re_RE(), t_list(t_re_run_option())]; + %%------- string -------------------------------------------------------------- arg_types(string, chars, 2) -> [t_char(), t_non_neg_integer()]; arg_types(string, chars, 3) -> [t_char(), t_non_neg_integer(), t_any()]; -arg_types(string, concat, 2) -> - [t_string(), t_string()]; -arg_types(string, equal, 2) -> - [t_string(), t_string()]; -arg_types(string, to_float, 1) -> - [t_string()]; -arg_types(string, to_integer, 1) -> - [t_string()]; -%%------- unicode ------------------------------------------------------------- -arg_types(unicode, characters_to_binary, 2) -> - [t_ML(), t_encoding()]; -arg_types(unicode, characters_to_list, 2) -> - [t_ML(), t_encoding()]; -arg_types(unicode, bin_is_7bit, 1) -> - [t_binary()]; %%----------------------------------------------------------------------------- arg_types(M, F, A) when is_atom(M), is_atom(F), is_integer(A), 0 =< A, A =< 255 -> @@ -4559,244 +2598,22 @@ check_fun_application(Fun, Args) -> %% ===================================================================== -%% These are basic types that should probably be moved to erl_types -%% ===================================================================== - -t_socket() -> t_port(). % alias - -t_ip_address() -> - T_int16 = t_from_range(0, 16#FFFF), - t_sup(t_tuple([t_byte(), t_byte(), t_byte(), t_byte()]), - t_tuple([T_int16, T_int16, T_int16, T_int16, - T_int16, T_int16, T_int16, T_int16])). - -%% ===================================================================== %% Some basic types used in various parts of the system %% ===================================================================== -t_date() -> - t_tuple([t_pos_fixnum(), t_pos_fixnum(), t_pos_fixnum()]). - -t_time() -> - t_tuple([t_non_neg_fixnum(), t_non_neg_fixnum(), t_non_neg_fixnum()]). - -t_timestamp() -> - t_tuple([t_non_neg_fixnum(), t_non_neg_fixnum(), t_non_neg_fixnum()]). - -t_packet() -> - t_sup([t_binary(), t_iolist(), t_httppacket()]). - -t_httppacket() -> - t_sup([t_HttpRequest(), t_HttpResponse(), - t_HttpHeader(), t_atom('http_eoh'), t_HttpError()]). - t_endian() -> t_sup(t_atom('big'), t_atom('little')). %% ===================================================================== -%% HTTP types documented in R12B-4 -%% ===================================================================== - -t_HttpRequest() -> - t_tuple([t_atom('http_request'), t_HttpMethod(), t_HttpUri(), t_HttpVersion()]). - -t_HttpResponse() -> - t_tuple([t_atom('http_response'), t_HttpVersion(), t_integer(), t_HttpString()]). - -t_HttpHeader() -> - t_tuple([t_atom('http_header'), t_integer(), t_HttpField(), t_any(), t_HttpString()]). - -t_HttpError() -> - t_tuple([t_atom('http_error'), t_HttpString()]). - -t_HttpMethod() -> - t_sup(t_HttpMethodAtom(), t_HttpString()). - -t_HttpMethodAtom() -> - t_atoms(['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE']). - -t_HttpUri() -> - t_sup([t_atom('*'), - t_tuple([t_atom('absoluteURI'), - t_sup(t_atom('http'), t_atom('https')), - t_HttpString(), - t_sup(t_non_neg_integer(), t_atom('undefined')), - t_HttpString()]), - t_tuple([t_atom('scheme'), t_HttpString(), t_HttpString()]), - t_tuple([t_atom('abs_path'), t_HttpString()]), - t_HttpString()]). - -t_HttpVersion() -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]). - -t_HttpField() -> - t_sup(t_HttpFieldAtom(), t_HttpString()). - -t_HttpFieldAtom() -> - t_atoms(['Cache-Control', 'Connection', 'Date', 'Pragma', 'Transfer-Encoding', - 'Upgrade', 'Via', 'Accept', 'Accept-Charset', 'Accept-Encoding', - 'Accept-Language', 'Authorization', 'From', 'Host', - 'If-Modified-Since', 'If-Match', 'If-None-Match', 'If-Range', - 'If-Unmodified-Since', 'Max-Forwards', 'Proxy-Authorization', - 'Range', 'Referer', 'User-Agent', 'Age', 'Location', - 'Proxy-Authenticate', 'Public', 'Retry-After', 'Server', 'Vary', - 'Warning', 'Www-Authenticate', 'Allow', 'Content-Base', - 'Content-Encoding', 'Content-Language', 'Content-Length', - 'Content-Location', 'Content-Md5', 'Content-Range', 'Content-Type', - 'Etag', 'Expires', 'Last-Modified', 'Accept-Ranges', - 'Set-Cookie', 'Set-Cookie2', 'X-Forwarded-For', 'Cookie', - 'Keep-Alive', 'Proxy-Connection']). - -t_HttpString() -> - t_sup(t_string(), t_binary()). - -%% ===================================================================== -%% These are used for the built-in functions of 'binary' -%% ===================================================================== - -t_binary_part() -> - t_tuple([t_non_neg_integer(), t_integer()]). - -t_binary_canonical_part() -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]). - -t_binary_pattern() -> - t_sup([t_binary(), - t_list(t_binary()), - t_binary_compiled_pattern()]). - -t_binary_compiled_pattern() -> - t_tuple([t_sup(t_atom('bm'), t_atom('ac')), t_binary()]). - -t_binary_options() -> - t_list(t_tuple([t_atom('scope'), t_binary_part()])). - -%% ===================================================================== -%% These are used for the built-in functions of 'code' -%% ===================================================================== - -t_code_load_return(Mod) -> - t_sup(t_tuple([t_atom('module'), case t_is_atom(Mod) of - true -> Mod; - false -> t_atom() - end]), - t_tuple([t_atom('error'), t_code_load_error_rsn()])). - -t_code_load_error_rsn() -> % also used in erlang:load_module/2 - t_sup([t_atom('badfile'), - t_atom('nofile'), - t_atom('not_purged'), - t_atom('native_code'), - t_atom('on_load'), - t_atom('sticky_directory')]). % only for the 'code' functions - -%% ===================================================================== %% These are used for the built-in functions of 'erlang' %% ===================================================================== -t_adler32() -> - t_non_neg_integer(). - t_crc32() -> t_non_neg_integer(). -t_decode_packet_option() -> - t_sup([t_tuple([t_atom('packet_size'), t_non_neg_integer()]), - t_tuple([t_atom('line_length'), t_non_neg_integer()])]). - -t_decode_packet_type() -> - t_sup([t_inet_setoption_packettype(), t_atom('httph'), t_atom('httph_bin')]). - -t_dist_exit() -> - t_sup([t_atom('kill'), t_atom('noconnection'), t_atom('normal')]). - -t_match_spec_test_errors() -> - t_list(t_sup(t_tuple([t_atom('error'), t_string()]), - t_tuple([t_atom('warning'), t_string()]))). - -t_module_info_2() -> - t_sup([t_atom('module'), - t_atom('imports'), - t_atom('exports'), - t_atom('functions'), - t_atom('attributes'), - t_atom('compile'), - t_atom('native_addresses')]). - -t_pinfo() -> - t_sup([t_pinfo_item(), t_list(t_pinfo_item())]). - -t_pinfo_item() -> - t_sup([t_atom('backtrace'), - t_atom('current_function'), - t_atom('dictionary'), - t_atom('error_handler'), - t_atom('garbage_collection'), - t_atom('group_leader'), - t_atom('heap_size'), - t_atom('initial_call'), - t_atom('last_calls'), - t_atom('links'), - t_atom('memory'), - t_atom('message_queue_len'), - t_atom('messages'), - t_atom('monitored_by'), - t_atom('monitors'), - t_atom('priority'), - t_atom('reductions'), - t_atom('registered_name'), - t_atom('sequential_trace_token'), - t_atom('stack_size'), - t_atom('status'), - t_atom('suspending'), - t_atom('total_heap_size'), - t_atom('trap_exit')]). - -t_process_priority_level() -> - t_sup([t_atom('max'), t_atom('high'), t_atom('normal'), t_atom('low')]). - -t_process_status() -> - t_sup([t_atom('exiting'), t_atom('garbage_collecting'), - t_atom('runnable'), t_atom('running'), - t_atom('suspended'), t_atom('waiting')]). - -t_raise_errorclass() -> - t_sup([t_atom('error'), t_atom('exit'), t_atom('throw')]). - -t_sendoptions() -> - t_sup(t_atom('noconnect'), t_atom('nosuspend')). - -t_seq_trace_info() -> - t_sup([t_atom('send'), - t_atom('receive'), - t_atom('print'), - t_atom('timestamp'), - t_atom('label'), - t_atom('serial')]). - -%% XXX: Better if we also maintain correspondencies between infos and values -t_seq_trace_info_returns() -> - Values = t_sup([t_non_neg_integer(), t_boolean(), - t_tuple([t_non_neg_integer(), t_non_neg_integer()])]), - t_sup(t_tuple([t_seq_trace_info(), Values]), t_nil()). - t_sequential_tracer() -> t_sup([t_atom('false'), t_pid(), t_port()]). -t_spawn_options() -> - t_sup([t_atom('link'), - t_atom('monitor'), - t_tuple([t_atom('priority'), t_process_priority_level()]), - t_tuple([t_atom('min_heap_size'), t_fixnum()]), - t_tuple([t_atom('min_bin_vheap_size'), t_fixnum()]), - t_tuple([t_atom('fullsweep_after'), t_fixnum()])]). - -t_spawn_opt_return(List) -> - case t_is_none(t_inf(t_list(t_atom('monitor')), List)) of - true -> t_pid(); - false -> t_sup(t_pid(), t_tuple([t_pid(), t_reference()])) - end. - t_system_cpu_topology() -> t_sup(t_atom('undefined'), t_system_cpu_topology_level_entry_list()). @@ -4833,17 +2650,6 @@ t_internal_cpu_topology() -> %% Internal undocumented type t_non_neg_fixnum()])), t_atom('undefined')). -t_scheduler_bind_type_args() -> - t_sup([t_atom('default_bind'), - t_atom('no_node_processor_spread'), - t_atom('no_node_thread_spread'), - t_atom('no_spread'), - t_atom('processor_spread'), - t_atom('spread'), - t_atom('thread_spread'), - t_atom('thread_no_node_processor_spread'), - t_atom('unbound')]). - t_scheduler_bind_type_results() -> t_sup([t_atom('no_node_processor_spread'), t_atom('no_node_thread_spread'), @@ -4854,160 +2660,9 @@ t_scheduler_bind_type_results() -> t_atom('thread_no_node_processor_spread'), t_atom('unbound')]). -t_system_monitor_settings() -> - t_sup([t_atom('undefined'), - t_tuple([t_pid(), t_system_monitor_options()])]). - -t_system_monitor_options() -> - t_list(t_sup([t_atom('busy_port'), - t_atom('busy_dist_port'), - t_tuple([t_atom('long_gc'), t_integer()]), - t_tuple([t_atom('large_heap'), t_integer()])])). - t_system_multi_scheduling() -> t_sup([t_atom('blocked'), t_atom('disabled'), t_atom('enabled')]). -t_system_profile_options() -> - t_list(t_sup([t_atom('exclusive'), - t_atom('runnable_ports'), - t_atom('runnable_procs'), - t_atom('scheduler')])). - -t_system_profile_return() -> - t_sup(t_atom('undefined'), - t_tuple([t_sup(t_pid(), t_port()), t_system_profile_options()])). - -t_system_build_type_return() -> - t_sup([t_atom('opt'), - t_atom('debug'), - t_atom('purify'), - t_atom('quantify'), - t_atom('purecov'), - t_atom('gcov'), - t_atom('valgrind'), - t_atom('gprof'), - t_atom('lcnt')]). - -%% ===================================================================== -%% These are used for the built-in functions of 'ets' -%% ===================================================================== - -t_tab() -> - t_sup(t_tid(), t_atom()). - -t_match_pattern() -> - t_sup(t_atom(), t_tuple()). - -t_matchspecs() -> - t_list(t_tuple([t_match_pattern(), t_list(), t_list()])). - -t_matchres() -> - t_sup(t_tuple([t_list(), t_any()]), t_atom('$end_of_table')). - -%% From the 'ets' documentation -%%----------------------------- -%% Option = Type | Access | named_table | {keypos,Pos} -%% | {heir,pid(),HeirData} | {heir,none} | Tweaks -%% Type = set | ordered_set | bag | duplicate_bag -%% Access = public | protected | private -%% Tweaks = {write_concurrency,boolean()} -%% | {read_concurrency,boolean()} | compressed -%% Pos = integer() -%% HeirData = term() -t_ets_new_options() -> - t_list(t_sup([t_atom('set'), - t_atom('ordered_set'), - t_atom('bag'), - t_atom('duplicate_bag'), - t_atom('public'), - t_atom('protected'), - t_atom('private'), - t_atom('named_table'), - t_tuple([t_atom('keypos'), t_integer()]), - t_tuple([t_atom('heir'), t_pid(), t_any()]), - t_tuple([t_atom('heir'), t_atom('none')]), - t_tuple([t_atom('write_concurrency'), t_boolean()]), - t_tuple([t_atom('read_concurrency'), t_boolean()]), - t_atom('compressed')])). - -t_ets_info_items() -> - t_sup([t_atom('fixed'), - t_atom('safe_fixed'), - t_atom('keypos'), - t_atom('memory'), - t_atom('name'), - t_atom('named_table'), - t_atom('node'), - t_atom('owner'), - t_atom('protection'), - t_atom('size'), - t_atom('compressed'), - t_atom('heir'), - t_atom('stats'), - t_atom('type')]). - -%% ===================================================================== -%% These are used for the built-in functions of 'gen_tcp' -%% ===================================================================== - -t_gen_tcp_accept() -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_sup([t_atom('closed'), - t_atom('timeout'), - t_inet_posix_error()])])). - -t_gen_tcp_address() -> - t_sup([t_string(), t_atom(), t_ip_address()]). - -t_gen_tcp_port() -> - t_from_range(0, 16#FFFF). - -t_gen_tcp_connect_option() -> - t_sup([t_atom('list'), - t_atom('binary'), - t_tuple([t_atom('ip'), t_ip_address()]), - t_tuple([t_atom('port'), t_gen_tcp_port()]), - t_tuple([t_atom('fd'), t_integer()]), - t_atom('inet6'), - t_atom('inet'), - t_inet_setoption()]). - -t_gen_tcp_listen_option() -> - t_sup([t_atom('list'), - t_atom('binary'), - t_tuple([t_atom('backlog'), t_non_neg_integer()]), - t_tuple([t_atom('ip'), t_ip_address()]), - t_tuple([t_atom('fd'), t_integer()]), - t_atom('inet6'), - t_atom('inet'), - t_inet_setoption()]). - -t_gen_tcp_recv() -> - t_sup(t_tuple([t_atom('ok'), t_packet()]), - t_tuple([t_atom('error'), t_sup([t_atom('closed'), - t_inet_posix_error()])])). - -%% ===================================================================== -%% These are used for the built-in functions of 'gen_udp' -%% ===================================================================== - -t_gen_udp_connect_option() -> - t_sup([t_atom('list'), - t_atom('binary'), - t_tuple([t_atom('ip'), t_ip_address()]), - t_tuple([t_atom('fd'), t_integer()]), - t_atom('inet6'), - t_atom('inet'), - t_inet_setoption()]). - -t_gen_udp_recv() -> - t_sup(t_tuple([t_atom('ok'), - t_tuple([t_ip_address(), - t_gen_tcp_port(), - t_packet()])]), - t_tuple([t_atom('error'), - t_sup(t_atom('not_owner'), t_inet_posix_error())])). - %% ===================================================================== %% These are used for the built-in functions of 'hipe_bifs' %% ===================================================================== @@ -5040,131 +2695,6 @@ t_insn_type() -> t_atom('closure')]). %% ===================================================================== -%% These are used for the built-in functions of 'inet' -%% ===================================================================== - -t_inet_setoption() -> - t_sup([%% first the 2-tuple options - t_tuple([t_atom('active'), t_sup(t_boolean(), t_atom('once'))]), - t_tuple([t_atom('broadcast'), t_boolean()]), - t_tuple([t_atom('delay_send'), t_boolean()]), - t_tuple([t_atom('dontroute'), t_boolean()]), - t_tuple([t_atom('exit_on_close'), t_boolean()]), - t_tuple([t_atom('header'), t_non_neg_integer()]), - t_tuple([t_atom('keepalive'), t_boolean()]), - t_tuple([t_atom('nodelay'), t_boolean()]), - t_tuple([t_atom('packet'), t_inet_setoption_packettype()]), - t_tuple([t_atom('packet_size'), t_non_neg_integer()]), - t_tuple([t_atom('read_packets'), t_non_neg_integer()]), - t_tuple([t_atom('recbuf'), t_non_neg_integer()]), - t_tuple([t_atom('reuseaddr'), t_boolean()]), - t_tuple([t_atom('send_timeout'), t_non_neg_integer()]), - t_tuple([t_atom('sndbuf'), t_non_neg_integer()]), - t_tuple([t_atom('priority'), t_non_neg_integer()]), - t_tuple([t_atom('tos'), t_non_neg_integer()]), - %% and a 4-tuple option - t_tuple([t_atom('raw'), - t_non_neg_integer(), % protocol level - t_non_neg_integer(), % option number - t_binary()])]). % actual option value - -t_inet_setoption_packettype() -> - t_sup([t_atom('raw'), - t_integers([0,1,2,4]), - t_atom('asn1'), t_atom('cdr'), t_atom('sunrm'), - t_atom('fcgi'), t_atom('tpkt'), t_atom('line'), - t_atom('http'), - t_atom('http_bin')]). %% but t_atom('httph') is not needed - -t_inet_posix_error() -> - t_atom(). %% XXX: Very underspecified - -%% ===================================================================== -%% These are used for the built-in functions of 'io' -%% ===================================================================== - -t_io_device() -> - t_sup(t_atom(), t_pid()). - -%% The documentation in R11B-4 reads -%% Format ::= atom() | string() | binary() -%% but the Format can also be a (deep) list, hence the type below -t_io_format_string() -> - t_sup([t_atom(), t_list(), t_binary()]). - -%% ===================================================================== -%% These are used for the built-in functions of 're'; the functions -%% whose last name component starts with a capital letter are types -%% ===================================================================== - -t_re_MP() -> %% it's supposed to be an opaque data type - t_tuple([t_atom('re_pattern'), t_integer(), t_integer(), t_binary()]). - -t_re_RE() -> - t_sup([t_re_MP(), t_iodata(), t_charlist()]). - -t_re_compile_option() -> - t_sup([t_atoms(['unicode', 'anchored', 'caseless', 'dollar_endonly', - 'dotall', 'extended', 'firstline', 'multiline', - 'no_auto_capture', 'dupnames', 'ungreedy']), - t_tuple([t_atom('newline'), t_re_NLSpec()]), - t_atoms(['bsr_anycrlf', 'bsr_unicode'])]). - -t_re_run_option() -> - t_sup([t_atoms(['anchored', 'global', 'notbol', 'noteol', 'notempty']), - t_tuple([t_atom('offset'), t_integer()]), - t_tuple([t_atom('newline'), t_re_NLSpec()]), - t_tuple([t_atom('capture'), t_re_ValueSpec()]), - t_tuple([t_atom('capture'), t_re_ValueSpec(), t_re_Type()]), - t_re_compile_option()]). - -t_re_ErrorSpec() -> - t_tuple([t_string(), t_non_neg_integer()]). - -t_re_Type() -> - t_atoms(['index', 'list', 'binary']). - -t_re_NLSpec() -> - t_atoms(['cr', 'crlf', 'lf', 'anycrlf', 'any']). - -t_re_ValueSpec() -> - t_sup(t_atoms(['all', 'all_but_first', 'first', 'none']), t_re_ValueList()). - -t_re_ValueList() -> - t_list(t_sup([t_integer(), t_string(), t_atom()])). - -t_re_Captured() -> - t_list(t_sup(t_re_CapturedData(), t_list(t_re_CapturedData()))). - -t_re_CapturedData() -> - t_sup([t_tuple([t_integer(), t_integer()]), t_string(), t_binary()]). - -%% ===================================================================== -%% These are used for the built-in functions of 'prim_file' -%% ===================================================================== - -t_prim_file_name() -> - t_sup(t_unicode_string(), t_binary()). - -%% ===================================================================== -%% These are used for the built-in functions of 'unicode' -%% ===================================================================== - -t_ML() -> % a binary or a possibly deep list of integers or binaries - t_sup(t_list(t_sup([t_integer(), t_binary(), t_list()])), t_binary()). - -t_encoding() -> - t_sup([t_atoms(['latin1', 'unicode', 'utf8', 'utf16', 'utf32']), - t_tuple([t_atom('utf16'), t_endian()]), - t_tuple([t_atom('utf32'), t_endian()])]). - -t_file_encoding() -> - t_atoms(['latin1', 'utf8']). - -t_encoding_a2b() -> % for the 2nd arg of atom_to_binary/2 and binary_to_atom/2 - t_atoms(['latin1', 'unicode', 'utf8']). - -%% ===================================================================== %% Some testing code for ranges below %% ===================================================================== diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl index a44171b2f5..107edf6258 100644 --- a/lib/hipe/icode/hipe_beam_to_icode.erl +++ b/lib/hipe/icode/hipe_beam_to_icode.erl @@ -41,6 +41,9 @@ %% %%-ifndef(DEBUG). %%-define(DEBUG,6). +%% Choose one of two tracing methods +%%-define(DEBUG_BIF_CALL_TRACE,true). +%%-define(IO_FORMAT_CALL_TRACE,true). %%-endif. -include("../main/hipe.hrl"). @@ -51,8 +54,27 @@ -define(no_debug_msg(Str,Xs),ok). %%-define(no_debug_msg(Str,Xs),msg(Str,Xs)). --define(mk_debugcode(MFA, Env, Code), - case MFA of +-ifdef(DEBUG_BIF_CALL_TRACE). + +%% Use BIF hipe_bifs_debug_native_called_2 to trace function calls +mk_debug_calltrace({_M,_F,A}=MFA, Env, Code) -> + MFAVar = mk_var(new), + Ignore = mk_var(new), + MkMfa = hipe_icode:mk_move(MFAVar,hipe_icode:mk_const(MFA)), + Args = [mk_var({x,I-1}) || I <- lists:seq(1,A)], + ArgTup = mk_var(new), + MkArgTup = hipe_icode:mk_primop([ArgTup], mktuple, Args), + Call = hipe_icode:mk_primop([Ignore], debug_native_called, + [MFAVar,ArgTup]), + {[MkMfa,MkArgTup,Call | Code], Env}. + +-endif. + +-ifdef(IO_FORMAT_CALL_TRACE). + +%% Use io:format to trace function calls +mk_debug_calltrace(MFA, Env, Code) -> + case MFA of {io,_,_} -> %% We do not want to loop infinitely if we are compiling %% the module io. @@ -69,7 +91,9 @@ Call = hipe_icode:mk_call([Ignore],io,format,[StringVar,MFAVar],remote), {[MkMfa,MkString,Call | Code], Env} - end). + end. +-endif. + %%----------------------------------------------------------------------- %% Exported types @@ -127,7 +151,7 @@ trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) -> MFA = {M,F,A}, %% Debug code ?IF_DEBUG_LEVEL(5, - {Code3,_Env3} = ?mk_debugcode(MFA, Env2, Code2), + {Code3,_Env3} = mk_debug_calltrace(MFA, Env1, Code2), {Code3,_Env3} = {Code2,Env1}), %% For stack optimization Leafness = leafness(Code3), diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl index a413531c07..b0113fc556 100644 --- a/lib/hipe/icode/hipe_icode_primops.erl +++ b/lib/hipe/icode/hipe_icode_primops.erl @@ -137,7 +137,8 @@ is_safe({hipe_bs_primop, {bs_private_append, _, _}}) -> false; is_safe({hipe_bs_primop, bs_init_writable}) -> true; is_safe(#mkfun{}) -> true; is_safe(#unsafe_element{}) -> true; -is_safe(#unsafe_update_element{}) -> true. +is_safe(#unsafe_update_element{}) -> true; +is_safe(debug_native_called) -> false. -spec fails(icode_funcall()) -> boolean(). @@ -237,6 +238,7 @@ fails({hipe_bs_primop, bs_init_writable}) -> true; fails(#mkfun{}) -> false; fails(#unsafe_element{}) -> false; fails(#unsafe_update_element{}) -> false; +fails(debug_native_called) -> false; %% Apparently, we are calling fails/1 for all MFAs which are compiled. %% This is weird and we should restructure the compiler to avoid %% calling fails/1 for things that are not primops. @@ -721,6 +723,8 @@ type(Primop, Args) -> erl_types:t_any(); redtest -> erl_types:t_any(); + debug_native_called -> + erl_types:t_any(); {M, F, A} -> erl_bif_types:type(M, F, A, Args) end. @@ -893,6 +897,8 @@ type(Primop) -> erl_types:t_any(); redtest -> erl_types:t_any(); + debug_native_called -> + erl_types:t_any(); {M, F, A} -> erl_bif_types:type(M, F, A) end. diff --git a/lib/hipe/rtl/hipe_rtl_primops.erl b/lib/hipe/rtl/hipe_rtl_primops.erl index 5f273d8251..53aaa72aa6 100644 --- a/lib/hipe/rtl/hipe_rtl_primops.erl +++ b/lib/hipe/rtl/hipe_rtl_primops.erl @@ -396,6 +396,8 @@ gen_primop({Op,Dst,Args,Cont,Fail}, IsGuard, ConstTab) -> [Dst1]-> hipe_tagscheme:unsafe_tag_float(Dst1, Arg) end; + debug_native_called -> + [hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)]; %% Only names listed above are accepted! MFA:s are not primops! _ -> diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 41e4188e5f..58f7d4fa25 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -762,14 +762,9 @@ ip_mod_cgi(doc) -> ip_mod_cgi(suite) -> []; ip_mod_cgi(Config) when is_list(Config) -> - case test_server:os_type() of - vxworks -> - {skip, cgi_not_supported_on_vxwoks}; - _ -> - httpd_mod:cgi(ip_comm, ?IP_PORT, - ?config(host, Config), ?config(node, Config)), - ok - end. + httpd_mod:cgi(ip_comm, ?IP_PORT, + ?config(host, Config), ?config(node, Config)), + ok. %%------------------------------------------------------------------------- ip_mod_esi(doc) -> ["Module test: mod_esi"]; @@ -1275,16 +1270,11 @@ essl_mod_cgi(Config) when is_list(Config) -> ssl_mod_cgi(essl, Config). ssl_mod_cgi(Tag, Config) -> - case test_server:os_type() of - vxworks -> - {skip, cgi_not_supported_on_vxwoks}; - _ -> - httpd_mod:cgi(Tag, - ?SSL_PORT, - ?config(host, Config), - ?config(node, Config)), - ok - end. + httpd_mod:cgi(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), + ok. %%------------------------------------------------------------------------- @@ -2698,11 +2688,6 @@ dos_hostname_request(Host) -> get_nof_clients(Mode, Load) -> get_nof_clients(test_server:os_type(), Mode, Load). -get_nof_clients(vxworks, _, light) -> 1; -get_nof_clients(vxworks, ip_comm, medium) -> 3; -get_nof_clients(vxworks, ssl, medium) -> 3; -get_nof_clients(vxworks, ip_comm, heavy) -> 5; -get_nof_clients(vxworks, ssl, heavy) -> 5; get_nof_clients(_, ip_comm, light) -> 5; get_nof_clients(_, ssl, light) -> 2; get_nof_clients(_, ip_comm, medium) -> 10; diff --git a/lib/inets/test/inets.spec.vxworks b/lib/inets/test/inets.spec.vxworks deleted file mode 100644 index 6886299226..0000000000 --- a/lib/inets/test/inets.spec.vxworks +++ /dev/null @@ -1,5 +0,0 @@ -{topcase, {dir, "../inets_test"}}. -{skip, {inets_SUITE, ip_mod_cgi, "Requires processes"}}. -{skip, {inets_SUITE, ip_mod_all_modules, "Requires processes"}}. -{skip, {inets_SUITE, ssl, "Requires SSL"}}. - diff --git a/lib/inets/test/rules.mk b/lib/inets/test/rules.mk index 047c03b267..c4a62a87ed 100644 --- a/lib/inets/test/rules.mk +++ b/lib/inets/test/rules.mk @@ -17,17 +17,12 @@ DEFAULT_TARGETS = opt debug instr release release_docs clean docs # Erlang language section # ---------------------------------------------------- EMULATOR = beam -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -# VxWorks object files should be compressed. -# Other object files should have debug_info. -ERL_COMPILE_FLAGS += +compressed -else + ifdef BOOTSTRAP ERL_COMPILE_FLAGS += +slim else ERL_COMPILE_FLAGS += +debug_info endif -endif ERLC_WFLAGS = -W ERLC = erlc $(ERLC_WFLAGS) $(ERLC_FLAGS) ERL.beam = erl.beam -boot start_clean diff --git a/lib/inviso/AUTHORS b/lib/inviso/AUTHORS deleted file mode 100644 index fc5040fe92..0000000000 --- a/lib/inviso/AUTHORS +++ /dev/null @@ -1,4 +0,0 @@ -Original Authors and Contributors: - -Lennart Ohman - diff --git a/lib/inviso/Makefile b/lib/inviso/Makefile deleted file mode 100644 index be19199151..0000000000 --- a/lib/inviso/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# ``The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# -# Macros -# - -SUB_DIRECTORIES = src doc/src - -include vsn.mk -VSN = $(RUNTIME_TOOLS_VSN) - -SPECIAL_TARGETS = - -# -# Default Subdir Targets -# -include $(ERL_TOP)/make/otp_subdir.mk - - diff --git a/lib/inviso/doc/html/.gitignore b/lib/inviso/doc/html/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/inviso/doc/html/.gitignore +++ /dev/null diff --git a/lib/inviso/doc/man3/.gitignore b/lib/inviso/doc/man3/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/inviso/doc/man3/.gitignore +++ /dev/null diff --git a/lib/inviso/doc/pdf/.gitignore b/lib/inviso/doc/pdf/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/inviso/doc/pdf/.gitignore +++ /dev/null diff --git a/lib/inviso/doc/src/Makefile b/lib/inviso/doc/src/Makefile deleted file mode 100644 index f00b10f29c..0000000000 --- a/lib/inviso/doc/src/Makefile +++ /dev/null @@ -1,122 +0,0 @@ -# ``The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../../vsn.mk -VSN=$(INVISO_VSN) -APPLICATION=inviso - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- -XML_APPLICATION_FILES = ref_man.xml -XML_REF3_FILES = \ - inviso.xml \ - inviso_as_lib.xml \ - inviso_lfm.xml \ - inviso_lfm_tpfreader.xml \ - inviso_rt.xml \ - inviso_rt_meta.xml - -XML_PART_FILES = part.xml part_notes.xml -XML_CHAPTER_FILES = inviso_chapter.xml notes.xml - -BOOK_FILES = book.xml - -XML_FILES = \ - $(BOOK_FILES) $(XML_CHAPTER_FILES) \ - $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) - -GIF_FILES = \ - inviso_users_guide_pic1.gif - -# ---------------------------------------------------- - -HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ - $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) - -INFO_FILE = ../../info - -MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) - -HTML_REF_MAN_FILE = $(HTMLDIR)/index.html - -TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -XML_FLAGS += -DVIPS_FLAGS += - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- -$(HTMLDIR)/%.gif: %.gif - $(INSTALL_DATA) $< $@ - -docs: pdf html man - -$(TOP_PDF_FILE): $(XML_FILES) - -pdf: $(TOP_PDF_FILE) - -html: gifs $(HTML_REF_MAN_FILE) - -man: $(MAN3_FILES) - -gifs: $(GIF_FILES:%=$(HTMLDIR)/%) - -debug opt: - -clean clean_docs: - rm -rf $(HTMLDIR)/* - rm -f $(MAN3DIR)/* - rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) - rm -f errs core *~ - - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_docs_spec: docs - $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf" - $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf" - $(INSTALL_DIR) "$(RELSYSDIR)/doc/html" - $(INSTALL_DATA) $(HTMLDIR)/* \ - "$(RELSYSDIR)/doc/html" - $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)" - $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3" - $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3" - -release_spec: - - - - diff --git a/lib/inviso/doc/src/book.xml b/lib/inviso/doc/src/book.xml deleted file mode 100644 index c258f33ff7..0000000000 --- a/lib/inviso/doc/src/book.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE book SYSTEM "book.dtd"> - -<book xmlns:xi="http://www.w3.org/2001/XInclude"> - <header titlestyle="normal"> - <copyright> - <year>2006</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Inviso</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <insidecover> - </insidecover> - <pagetext>Inviso</pagetext> - <preamble> - <contents level="2"></contents> - </preamble> - <parts lift="no"> - <xi:include href="part.xml"/> - </parts> - <applications> - <xi:include href="ref_man.xml"/> - </applications> - <releasenotes> - <xi:include href="notes.xml"/> - </releasenotes> - <listofterms></listofterms> - <index></index> -</book> - diff --git a/lib/inviso/doc/src/fascicules.xml b/lib/inviso/doc/src/fascicules.xml deleted file mode 100644 index 0678195e07..0000000000 --- a/lib/inviso/doc/src/fascicules.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE fascicules SYSTEM "fascicules.dtd"> - -<fascicules> - <fascicule file="part" href="part_frame.html" entry="no"> - User's Guide - </fascicule> - <fascicule file="ref_man" href="ref_man_frame.html" entry="yes"> - Reference Manual - </fascicule> - <fascicule file="part_notes" href="part_notes_frame.html" entry="no"> - Release Notes - </fascicule> - <fascicule file="" href="../../../../doc/print.html" entry="no"> - Off-Print - </fascicule> -</fascicules> - diff --git a/lib/inviso/doc/src/inviso.xml b/lib/inviso/doc/src/inviso.xml deleted file mode 100644 index c0e2e8f0de..0000000000 --- a/lib/inviso/doc/src/inviso.xml +++ /dev/null @@ -1,693 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>2006</year><year>2011</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>inviso</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <module>inviso</module> - <modulesummary>Main API Module to the Inviso Tracer</modulesummary> - <description> - <warning> - <p>The <c>inviso</c> application is deprecated and will be - removed in the R16 release.</p> - </warning> - <p>With the <c>inviso</c> API runtime components can be started and tracing managed across a network of distributed Erlang nodes, using a control component also started with <c>inviso</c> API functions.</p> - <p>Inviso can be used both in a distributed environment and in a non-distributed. API functions not taking a list of nodes as argument works on all started runtime components. If it is the non-distributed case, that is the local runtime component. The API functions taking a list of nodes as argument, or as part of one of the arguments, can not be used in a non-distributed environment. Return values named <c>NodeResult</c> refers to return values from a single Erlang node, and will therefore be the return in the non-distributed environment.</p> - </description> - <funcs> - <func> - <name>start() -> {ok,pid()} | {error,Reason}</name> - <name>start(Options) -> {ok,pid()} | {error,Reason}</name> - <fsummary>Start a control component at the local node</fsummary> - <type> - <v>Options = [Option]</v> - </type> - <desc> - <p><c>Options</c> may contain both options which will be default options to a runtime component when started, and options to the control component. See <seealso marker="#add_nodes/3">add_nodes/3</seealso> for details on runtime component options. The control component recognizes the following options:</p> - <taglist> - <tag><c>{subscribe,Pid}</c></tag> - <item> - <p>Making the process <c>Pid</c> receive Inviso events from the control component.</p> - <p>Starts a control component process on the local node. A control component must be started before runtime components can be started manually or otherwise accessed through the <c>inviso</c> API.</p> - </item> - </taglist> - </desc> - </func> - <func> - <name>stop() -> shutdown</name> - <fsummary>Stop the control component</fsummary> - <desc> - <p>Stops the control component. Runtime components are left as is. They will behave according to their dependency values.</p> - </desc> - </func> - <func> - <name>add_node(RTtag) -> NodeResult | {error,Reason}</name> - <name>add_node(RTtag,Options) -> NodeResult | {error,Reason}</name> - <fsummary>Starts or adopts a runtime component at the local node</fsummary> - <type> - <v>RTtag = PreviousRTtag = term()</v> - <v>Options = [Option]</v> - <v> Option -- see below</v> - <v> Option = {dependency,Dep}</v> - <v> Dep = int() | infinity</v> - <d>The timeout, in milliseconds, before the runtime component will terminate if abandoned by <em>this</em>control component.</d> - <v> Option = {overload,Overload} | overload</v> - <d>Controls how and how often overload checks shall be performed. Just <c>overload</c>specifies that no loadcheck shall be performed.</d> - <v> Overload = Interval | {LoadMF,Interval,InitMFA,RemoveMFA}</v> - <v> LoadMF = {Mod,Func} | function()/1</v> - <v> Interval = int() | infinity</v> - <d>Interval is the time in milliseconds between overload checks.</d> - <v> InitMFA = RemoveMFA = {Mod,Func,ArgList} | void</v> - <d>When starting up the runtime component or when changing options (see <c>change_options/2</c>) the overload mechanism is initialized with a call to the <c>InitMFA</c>function. It shall return <c>LoadCheckData</c>. Every time a load check is performed, <c>LoadMF</c>is called with <c>LoadCheckData</c>as its only argument. <c>LoadMF</c>shall return <c>ok</c>or <c>{suspend,Reason}</c>. When the runtime component is stopped or made to change options involving changing overload-check, the <c>RemoveMFA</c>function is called. Its return value is discarded.</d> - <v>NodeResult = {ok,NAns} | {error,Reason}</v> - <v> NAns = new | {adopted,State,Status,PreviousRTtag} | already_added</v> - <v> State = new | tracing | idle</v> - <v> Status = running | {suspended,SReason}</v> - </type> - <desc> - <p>Starts or tries to connect to an existing runtime component at the local node, regardless if the system is distributed or not. <c>Options</c> will override any default options specified at start-up of the control component.</p> - <p>The <c>PreviousRTtag</c> can indicate if the incarnation of the runtime component at the node in question was started by "us" and then can be expected to do tracing according to "our" instructions or not.</p> - </desc> - </func> - <func> - <name>add_node_if_ref(RTtag) -> NodeResult | {error,{wrong_reference,OtherTag}} | {error,Reason}</name> - <name>add_node_if_ref(RTtag,Options) -> NodeResult | {error,{wrong_reference,OtherRef}} | {error,Reason}</name> - <fsummary>Start or adopt a runtime component at the local node, provided it has a certain rttag</fsummary> - <type> - <v>OtherRef = term()</v> - <d>rttag of the running incarnation</d> - </type> - <desc> - <p>As <seealso marker="#add_node/1">add_node/1,2</seealso> but will only adopt the runtime component if its rttag is <c>RTtag</c>.</p> - </desc> - </func> - <func> - <name>add_nodes(Nodes,RTtag) -> {ok,NodeResults} | {error,Reason}</name> - <name>add_nodes(Nodes,RTtag,Options) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Start or adopt runtime components at some nodes</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>NodeResults = [{Node,NodeResult}]</v> - </type> - <desc> - <p>As <seealso marker="#add_node/1">add_node/1,2</seealso> but for a distributed environment.</p> - </desc> - </func> - <func> - <name>add_nodes_if_ref(Nodes,RTtag) -> NodeResult | {error,Reason}</name> - <name>add_nodes_if_ref(Nodes,RTtag,Options) -> NodeResult | {error,Reason}</name> - <fsummary>Start or adopt runtime components at some nodes, provided they have a certain rttag</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>NodeResults = [{Node,NodeResult}]</v> - </type> - <desc> - <p>As <seealso marker="#add_node_if_ref/1">add_node_if_ref/1,2</seealso> but for a distributed environment.</p> - </desc> - </func> - <func> - <name>stop_nodes() -> {ok,NodeResults} | NodeResult</name> - <name>stop_nodes(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Stop runtime components</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>Stops runtime component on <c>Nodes</c>. <c>stop_nodes/0</c> will if the control component is running on a distributed node stop all runtime components. And if running on a non distributed node, stop the local and only runtime component.</p> - </desc> - </func> - <func> - <name>stop_all() = {ok,NodeResults} | NodeResult</name> - <fsummary>Stop both control and runtime components</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>A combination of <seealso marker="#stop/0">stop/0</seealso> and <seealso marker="#stop_nodes/0">stop_nodes/0</seealso>.</p> - </desc> - </func> - <func> - <name>change_options(Options) -> NodeResult | {ok,NodeResults} | {error,Reason}</name> - <name>change_options(Nodes,Options) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Change options for runtime components</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>Changes the options for one or several runtime components. If for instance overload is redefined, the previous overload will be stopped and the new started. See <seealso marker="#add_node/1">add_node/1</seealso> for details on <c>Options</c>.</p> - </desc> - </func> - <func> - <name>init_tracing(TracerData) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>init_tracing(TracerList) -> {ok,NodeResults} | {error,Reason}</name> - <name>init_tracing(Nodes,TracerData) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Initiate tracing</fsummary> - <type> - <v>TracerData = [{trace,LogTD} [,{ti,TiTD}] }] | LogTD</v> - <v>LogTD = {HandlerFun,Data1} | collector | {relayer,CollectingNode} | {ip,IPPortParameters} | {file,FilePortParameters}</v> - <v>TiTD = {file,FileName} | {file,FileName,TiSpec} | {relay,Node}</v> - <v> TiSpec = {InitMFA,RemoveMF,CleanMF}</v> - <v> InitMFA = {Mi,Fi,Argsi}</v> - <v> RemoveMF = {Mr,Fr} | void</v> - <v> CleanMF = {Mc,Fc}</v> - <v> Mi = Fi = Mr = Fr = Mc = Fd = atom()</v> - <v> Argsi = [term()]</v> - <v>TracerList = [{Node,TracerData}]</v> - <v>IPPortParameters = Portno | {Portno,Qsize}</v> - <v> Portno = tcp_portno()</v> - <v> Qsize = int()</v> - <v>FilePortParameters = {Filename,wrap,Tail,{time,WrapTime},WrapCnt} | {FileName,wrap,Tail,WrapSize,WrapCnt} | {FileName,wrap,Tail,WrapSize} | {FileName,wrap,Tail} | FileName</v> - <v> FileName = string()</v> - <v> Tail = string() =/= ""</v> - <v> WrapTime = WrapCnt = WrapSize = int() >0</v> - <v>TracerList = [{Node,TracerData}]</v> - <v>Nodes = [Node]</v> - <v>HandlerFun = function()/2;</v> - <v> HandlerFun(TraceMsg,Data1) -> NewData</v> - <v>CollectingNode = pid() | node()</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {ok,LogResults} | {error,NReason}</v> - <v> LogResults = [LogResult]</v> - <v> LogResult = {trace_log,LogRes} | {ti_log,LogRes}</v> - <v> LogRes = ok | {error,Reason}</v> - </type> - <desc> - <p>Starts the tracing at the specified nodes, meaning that the runtime components transits from the state <c>new</c> or <c>idle</c> to <c>tracing</c>. For trace messages to be generated, there must of course also be trace pattern and/or trace flags set. Such can not be set before tracing has been initiated with <c>init_tracing/1,2</c>.</p> - <p><c>TracerData</c> controls how the runtime component will handle generated trace messages. The <c>trace</c> tag controls how regular trace messages are handled. The <c>ti</c> tag controls if and how trace information will be stored and the meta tracer will be activated. That is if <c>ti</c> is omitted, no meta tracer will be started as part of the runtime component. It is possible to have <c>ti</c> without <c>trace</c>, but most likely not useful.</p> - <p>The <c>ip</c> and <c>file</c> trace tracerdata instructions results in using the built in trace ip-port and file-port respectively. <c>relayer</c> will result in that all regular trace messages are forwarded to a runtime component at the specified node. Using a <c>HandlerFun</c> will result in that every incoming regular trace message is applied to the <c>HandlerFun</c>. <c>collector</c> can be used to use this runtime component to receive relayed trace messages and print them to the shell. - </p> - <p>The trace information can be configured to either write trace information to a plain trace information file or to relay it to another inviso meta tracer on another node. The inviso meta tracer is capable of matching function calls with their function returns (only if <c>return_trace</c> is activated in the meta trace match specification for the function in question). This is necessary since it may not be possible to decide what to do, if anything shall be done at all, until the return value of the function call is examined. - </p> - <p>To be able to match calls with returns a state can be saved when detecting a function call in a public loop data structure kept by the inviso meta tracer. The public loop data structure is given as argument to a handler-function called whenever a meta trace message arrives to the inviso meta tracer (both function calls and function returns). The public loop data structure is first initiated by the <c>Mi:Fi</c> function which takes the items in <c>Argsi</c> as arguments. <c>Fi</c> shall return the initial public loop data structure. When meta tracing is stopped, either because tracing is stopped or because tracing is suspended, the <c>Mr:Fr(PublicLoopData)</c> is called to offer a possibility to clean-up. Note that for every function meta-tracing is activated, a public loop data modification function can be specified. That function will prepare the current loop data structure for this particular function. - </p> - <p>Further there is a risk that function call states becomes abandoned inside the public loop data structure. This will happen if a function call is entered into the public loop data structure, but no function return occurs. To prevent the public loop data structure from growing infinitely the clean function <c>Fc</c> will periodically be called with the public loop data structure as argument. Elements entered into the public loop data structure as a result of a function call must contain a timestamp for the <c>Fc</c> to be able to conclude if it is abandoned or not. <c>Fc</c> shall return a new public loop data structure. - </p> - <p>When initiating tracing involving trace information without a <c>TiSpec</c>, a default public loop data structure will be initiated to handle locally registered process aliases. The default public loop data structure is a two-tuple where the first element is used by the meta tracing on the BIF <c>register/2</c>. The second element is left for user usage.</p> - <p>The default public loop data structure may be extended with more element positions. The first position must be left to the implementation of registered-name translations. If the public loop data structure is changed no longer meeting this requirement, the <seealso marker="#tpm_localnames/0">tpm_localnames/0,1</seealso> and <seealso marker="#tpm_globalnames/0">tpm_globalnames/0,1</seealso> can no longer be used.</p> - <p>A wrap files specification is used to limit the disk space consumed by the trace. The trace is written to a limited number of files each with a limited size. The actual filenames are <c>Filename ++ SeqCnt ++ Tail</c>, where <c>SeqCnt</c> counts as a decimal string from 0 to <c>WrapCnt</c> and then around again from 0. When a trace message written to the current file makes it longer than <c>WrapSize</c>, that file is closed, if the number of files in this wrap trace is as many as <c>WrapCnt</c> the oldest file is deleted then a new file is opened to become the current. Thus, when a wrap trace has been stopped, there are at most <c>WrapCnt</c> trace files saved with a size of at least <c>WrapSize</c> (but not much bigger), except for the last file that might even be empty. The default values are <c>WrapSize == 128*1024</c> and <c>WrapCnt == 8</c>.</p> - <p>The <c>SeqCnt</c> values in the filenames are all in the range 0 through <c>WrapCnt</c> with a gap in the circular sequence. The gap is needed to find the end of the trace.</p> - <p>If the <c>WrapSize</c> is specified as <c>{time,WrapTime}</c>, the current file is closed when it has been open more than <c>WrapTime</c> milliseconds, regardless of it being empty or not.</p> - <p>The ip trace driver has a queue of <c>QSize</c> messages waiting to be delivered. If the driver cannot deliver messages as fast as they are produced by the runtime system, they are dropped. The number of dropped messages are indicated in the trace log as separate trace message.</p> - </desc> - </func> - <func> - <name>stop_tracing(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <name>stop_tracing() -> {ok,NodeResults} | NodeResult</name> - <fsummary>Stop tracing</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {ok,State} | {error,Reason}</v> - <v> State = new | idle</v> - </type> - <desc> - <p>Stops tracing on all or specified <c>Nodes</c>. Flushes the trace buffer if a trace-port is used, closes the trace-port and removes all trace flags and meta-patterns. The nodes are called in parallel.</p> - <p>Stopping tracing means going to state <c><![CDATA[idle<c>. If the runtime component was already in state <c>new]]></c>, it will of course remain in state <c>new</c> (then there was no tracing to stop).</p> - </desc> - </func> - <func> - <name>clear() -> {ok,NodeResults} | NodeResult</name> - <name>clear(Nodes,Options) -> {ok,NodeResults} | {error,Reason}</name> - <name>clear(Options) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Stop tracing and remove meta trace patterns</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>Options = [Option]</v> - <v> Option = keep_trace_patterns | keep_log_files</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v> NodeResult = {ok,{new,Status}} | {error,Reason}</v> - <v> Status = running | {suspended,SReason}</v> - </type> - <desc> - <p>Stops all tracing including removing meta-trace patterns. Removes all trace patterns. If the node is <c>tracing</c> or <c>idle</c>, trace-logs belonging to the current tracerdata are removed. Hence the node is returned to state <c>new</c>. Note that the node can still be suspended.</p> - <p>Various options can make the node keep set trace patterns and log-files. The node still enters the <c>new</c> state.</p> - </desc> - </func> - <func> - <name>tp(Nodes,Mod,Func,Arity,MatchSpec,Opts) -> </name> - <name>tp(Nodes,Mod,Func,Arity,MatchSpec) -> {ok,NodeResults} | {error,Reason}</name> - <name>tp(Mod,Func,Arity,MatchSpec,Opts) -> </name> - <name>tp(Mod,Func,Arity,MatchSpec) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>tp(Nodes,PatternList) -> {ok,NodeResults} | {error,Reason}</name> - <name>tp(PatternList) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Set global trace patterns</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>Mod = Func = atom() | '_'</v> - <v>Arity = int() | '_'</v> - <v>MatchSpec = true | false | [] | matchspec()</v> - <v>PatternList = [Pattern],</v> - <v> Pattern = {Mod,Func,Arity,MatchSpec,Opts}</v> - <v>Opts = [Opt]</v> - <v> Opt = only_loaded</v> - <v>NodeResults = [NodeResult]</v> - <v> NodeResult = {ok,[Ans]} | {error,Reason}</v> - <v> Ans = int() | {error,Reason}</v> - </type> - <desc> - <p>Set trace pattern (global) on specified or all nodes. The integer replied if the call was successfully describes the number of matched functions. The functions without a <c>Nodes</c> argument means all nodes, in a non-distributed environment it means the local node. Using wildcards follows the rules for wildcards of <c>erlang:trace_pattern/3</c>. It is for instance illegal to specify <c>M == '_'</c> while <c>F</c> is not <c>'_'</c>.</p> - <p>When calling several nodes, the nodes are called in parallel.</p> - <p>The option <c>only_loaded</c> will prevent modules not loaded (yet) into the runtime system to become loaded just as a result of that a trace pattern is requested to be set on it. Otherwise modules are automatically loaded if not already loaded (since the module must be present for a trace pattern to be set on it). The latter does not apply if the wildcard <c>'_'</c> is used as module specification.</p> - </desc> - </func> - <func> - <name>tpl(Nodes,Mod,Func,Arity,MatchSpec) -> </name> - <name>tpl(Nodes,Mod,Func,Arity,MatchSpec,Opts) -> {ok,NodeResults} | {error,Reason}</name> - <name>tpl(Mod,Func,Arity,MatchSpec) -> </name> - <name>tpl(Mod,Func,Arity,MatchSpec,Opts) -> {ok,NodeResults} | NodeResult| {error,Reason}</name> - <name>tpl(Nodes,PatternList) -> {ok,NodeResults} | {error,Reason}</name> - <name>tpl(PatternList) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Set local trace patterns</fsummary> - <desc> - <p>See <seealso marker="#tp/6">tp/N</seealso> function above for details on arguments and return values.</p> - <p>Set local trace pattern on specified functions. When calling several nodes, the nodes are called in parallel.</p> - </desc> - </func> - <func> - <name>ctp(Nodes,Mod,Func,Arity) -> {ok,NodeResults} | {error,Reason}</name> - <name>ctp(Mod,Func,Arity) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Clear global trace patterns</fsummary> - <desc> - <p>See <seealso marker="#tp/6">tp/N</seealso> for argument descriptions.</p> - <p>Clear global trace patterns. When calling several nodes, the nodes are called in parallel.</p> - </desc> - </func> - <func> - <name>ctpl(Nodes,Mod,Func,Arity) -> {ok,NodeResults} | {error,Reason}</name> - <name>ctpl(Mod,Funct,Arity) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Clear local trace patterns</fsummary> - <desc> - <p>See <seealso marker="#tp/6">tp/N</seealso> for argument description.</p> - <p>Clear local trace patterns. When calling several nodes, the nodes are called in parallel.</p> - </desc> - </func> - <func> - <name>tf(Nodes,PidSpec,FlagList) -> {ok,NodeResults} | {error,Reason}</name> - <name>tf(PidSpec,FlagList) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>tf(Nodes,TraceConfList) -> {ok,NodeResults} | {error,Reason}</name> - <name>tf(NodeTraceConfList) -> {ok,NodeResults} | {error,Reason}</name> - <name>tf(TraceConfList) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Set process trace flags</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>NodeTraceConfList = [{Node,TraceConfList}]</v> - <v>TraceConfList = [{PidSpec,FlagList}]</v> - <v>FlagList = [Flag]</v> - <v>PidSpec = all | new| existing | pid() | locally_registered_name()</v> - <v>Flag -- see erlang:trace/3</v> - <v>NodeResult = {ok,[Ans]} | {error,Reason}</v> - <v>Ans = int() | {error,Reason}</v> - </type> - <desc> - <p>Set process trace flags on processes on all or specified nodes. The integer returned if the call was successful describes the matched number of processes. The functions without a <c>Nodes</c> argument means all nodes, in a non-distributed environment it means the local node. - </p> - <p>There are many combinations which does not make much sense. For instance specifying a certain process identifier at all nodes. Or an empty <c>TraceConfList</c> for all nodes.</p> - <p>When calling several nodes, the nodes are called in parallel.</p> - </desc> - </func> - <func> - <name>ctf(Nodes,PidSpec,FlagList) -> {ok,NodeResults} | {error,Reason}</name> - <name>ctf(PidSpec,FlagList) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>ctf(Nodes,TraceConfList) -> {ok,NodeResults} | {error,Reason}</name> - <name>ctf(TraceConfList) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Clear process trace flags</fsummary> - <desc> - <p>See <seealso marker="#tf/3">tf/N</seealso> for arguments and return value description.</p> - <p>Clear process trace flags on all or specified nodes. When calling several nodes, the nodes are called in parallel.</p> - </desc> - </func> - <func> - <name>ctf_all(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <name>ctf_all() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Clear all process trace flags</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>Clears all trace flags on all or specified nodes. Just for convenience.</p> - </desc> - </func> - <func> - <name>init_tpm(Mod,Func,Arity,CallFunc) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>init_tpm(Nodes,Mod,Func,Arity,CallFunc) -> {ok,NodeResults} | {error,Reason}</name> - <name>init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>init_tpm(Nodes,Mod,Func,Arity, InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Initialize meta tracing</fsummary> - <type> - <v>Mod = Func = atom()</v> - <v>Arity = int()</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - <v>InitFunc,RemoveFunc = {Module,Function} | function()/4 | void</v> - <v>CallFunc = ReturnFunc = {Module,Function} | function()/3 | void</v> - </type> - <desc> - <p>Initializes <c>Mod:Func/Arity</c> for meta tracing without setting any meta trace patterns. This is necessary if the named match specs will be used (see <seealso marker="#tpm_ms/5">tpm_ms/5,6</seealso>). Otherwise initialization of public loop data can be done at the same time as setting meta trace patterns using <seealso marker="#tpm/8">tpm/8,9</seealso>.</p> - <p>Note that we can not use wildcards here (even if it is perfectly legal in Erlang). It also sets the <c>CallFunc</c> and <c>ReturnFunc</c> for the meta traced function. That is the functions which will be called when a function call and a return_trace meta trace message respectively arrives to the inviso meta tracer for <c>Mod:Func/Arity</c>.</p> - <p>This function is also available without <c>InitFunc</c> and <c>RemoveFunc</c>. That means that no initialization of the public loop data structure will be done and that <c>CallFunc</c> and <c>ReturnFunc</c> must either use already existing parts of public loop data structure or not use it at all.</p> - <p>The <c>InitFunc</c> initializes the already existing public loop data structure for use with <c>Mod:Func/Arity. InitFunc(Mod,Func,Arity,PublLD) -> {ok,NewPublLD,Output}</c> where <c>OutPut</c> can be a binary which will then be written to the trace information file. If it is not a binary, no output will be done. <c>RemoveFunc</c> will be called when the meta tracing is cleared with <seealso marker="#ctpm/3">ctpm/3,4</seealso>. <c>RemoveFunc(Mod,Func,Arity,PublLD) -> {ok,NewPublLD}</c>.</p> - <p>See <seealso marker="#tpm/4">tpm/N</seealso> for details on <c>CallFunc</c> and <c>ReturnFunc</c>.</p> - </desc> - </func> - <func> - <name>tpm(Mod,Func,Arity,MS) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>tpm(Nodes,Mod,Func,Arity,MS) -> {ok,NodeResults} | {error,Reason}</name> - <name>tpm(Mod,Func,Arity,MS,CallFunc) -> {ok,NodeResults} | NodeResults | {error,Reason}</name> - <name>tpm(Nodes,Mod,Func,Arity,MS,CallFunc) -> {ok,NodeResults} | {error,Reason}</name> - <name>tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> {ok,NodeResults} | NodeResults | {error,Reason}</name> - <name>tpm(Nodes,Mod,Func,Arity,MS, InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Activate meta tracing</fsummary> - <type> - <v>Mod = Func = atom()</v> - <v>Arity = int()</v> - <v>MS = [match_spec()]</v> - <v>Nodes = [Node]</v> - <v>InitFunc = RemoveFunc = {Module,Function} | function()/4 | void</v> - <v>CallFunc = ReturnFunc = {Module,Function} | function()/3 | void</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {ok,1} | {ok,0} | {error,Reason}1</v> - </type> - <desc> - <p>Activates meta-tracing in the inviso_rt_meta tracer. Except when using <c>tpm/6</c>, <c>tpm/8</c> and <c>tpm/9</c> the <c>Mod:Func/Arity</c> must first have been initiated using <seealso marker="#init_tpm/4">init_tpm/N</seealso>. When calling several nodes, the nodes are called in parallel.</p> - <p><c>CallFunc</c> will be called every time a meta trace message arrives to the inviso meta tracer because of a call to <c>Func</c>. <c>CallFunc(CallingPid,ActualArgList,PublLD) -> {ok,NewPrivLD,Output}</c> where <c>Output</c> can be a binary or <c>void</c>. If it is a binary it will be written to the trace information file.</p> - <p><c>ReturnFunc</c> will be called every time a meta return_trace message arrives to the inviso meta tracer because of a return_trace of a call to <c>Func</c>. <c>ReturnFunc(CallingPid,ReturnValue,PublLD) -> {ok,NewPrivLD,Output}</c>. Further the <c>ReturnFunc</c> must handle the fact that a return_trace message arrives for a call which was never noticed. This because the message queue of the meta tracer may have been emptied.</p> - </desc> - </func> - <func> - <name>tpm_tracer(Mod,Func,Arity,MS) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>tpm_tracer(Nodes,Mod,Func,Arity,MS) -> {ok,NodeResults} | {error,Reason}</name> - <name>tpm_tracer(Mod,Func,Arity,MS,CallFunc) -> {ok,NodeResults} | NodeResults | {error,Reason}</name> - <name>tpm_tracer(Nodes,Mod,Func,Arity,MS,CallFunc) -> {ok,NodeResults} | {error,Reason}</name> - <name>tpm_tracer(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> {ok,NodeResults} | NodeResults | {error,Reason}</name> - <name>tpm_tracer(Nodes,Mod,Func,Arity,MS, InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Activate meta tracing and at the same time append a {tracer,Tracer} process trace flag to the enable list in a match specification <c>trace</c>action term</fsummary> - <desc> - <p>See tpm/X for details on arguments and return values.</p> - <p>Same as tpm/X but all match specs in <c>MS</c> containing a <c>trace</c> action term will have a <c>{tracer,Tracer}</c> appended to its enable-list. <c>Tracer</c> will be the current output for regular trace messages as specified when tracing was initiated. This function is useful when setting a meta trace pattern on a function with the intent that its execution shall turn tracing on for the process executing the match-spec in the meta trace pattern. The reason the <c>tracer</c> process trace flag can not be explicitly written in the action term by the user is that it may be difficult to learn its exact value for a remote node. Further more inviso functions are made to work on several nodes at the same time, requiring different match specs to be set for different nodes.</p> - <p>Simple example: We want any process executing the function <c>mymod:init(1234)</c> (with the argument, exactly the integer 1234) to begin function-call tracing. In the example, if the process is found to be one that shall start call tracing, we also first disable <c>all</c> process trace flags to ensure that we have full control over what the process traces. <c>void</c> in the example specifies that the meta-tracer (inviso_rt_meta) will not call any function when meta trace messages for <c>mymod:init/1</c> arrives. There is no need for a <c>CallFunc</c> since the side-effect (start call-tracing) is achieved immediately with the match-spec.</p> - <code type="none"> - inviso:tpm_tracer(mymod,init,1,[{[1234],[],[{trace,[all],[call]}]}],void). </code> - <p>This will internally, by the meta tracer on each Erlang node, be translated to:</p> - <code type="none"> - erlang:trace_pattern({mymod,init,1},[{[1234],[],[{trace,[all],[call,{{tracer,T}}]}]}],[{meta,P}]). - </code> - <p>Where <c>T</c> is the tracer for regular trace messages (most often a trace-port, but can be the runtime component inviso_rt process), and <c>P</c> is the meta tracer (the inviso_rt_meta process).</p> - </desc> - </func> - <func> - <name>tpm_ms(Mod,Func,Arity,MSname,MS) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>tpm_ms(Nodes,Mod,Func,Arity,MSname,MS) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Add match specifications</fsummary> - <type> - <v>Nodes = [Node]<v> <v>Mod = Func = atom()<v> <v>Arity = int()<v> <v>MSname = term()<v> <v>MS = [match_spec()]<v> <v>NodeResults = [{Node,NodeResult}]<v> <v>NodeResult = {ok,1} | {ok,0} | {error,Reason}<v></v> - </type> - <desc> - <p>This function adds a list of match-specs to the already existing ones. It uses an internal database to keep track of existing match-specs. This set of match specs can hereafter be referred to with the name <c>MSname</c>. If the match-spec does not result in any meta traced functions (for whatever reason), the <c>MS</c> is not saved in the database. The previously known match-specs are not removed. If <c>MSname</c> is already in use as a name referring to a set of match-specs for this particular meta-traced function, the previous set of match-specs are replaced with <c>MS</c>.</p> - <p><c>Mod:Func/Arity</c> must previously have been initiated in order for this function to add a match-spec.</p> - <p>When calling several nodes, the nodes are called in parallel. <c>{ok,1}</c> indicates success.</p> - </desc> - </func> - <func> - <name>tpm_ms_tracer(Mod,Func,Arity,MSname,MS) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>tpm_ms_tracer(Nodes,Mod,Func,Arity,MSname,MS) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Add match specifications and at the same time append a {tracer,Tracer} process trace flag to the enable list in a match specification <c>trace</c>action term</fsummary> - <desc> - <p>See tpm_ms/X for details on arguments and return values, and tpm_tracer/X for explanations about the appending of <c>{tracer,Tracer}</c> process trace flag.</p> - </desc> - </func> - <func> - <name>ctpm_ms(Mod,Func,Arity,MSname) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>ctpm_ms(Nodes,Mod,Func,Arity,MSname) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Remove a match specification</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>Removes a named match-spec from the meta traced function. Note that it never is a fault to remove a match spec. Not even from a function which is non existent.</p> - <p>When calling several nodes, the nodes are called in parallel.</p> - </desc> - </func> - <func> - <name>ctpm(Mod,Func,Arity) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>ctpm(Nodes,Mod,Func,Arity) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Remove a meta trace pattern</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>Removes the meta trace pattern for the function, means stops generating output for this function. The public loop data structure may be cleared by the previously entered <c>RemoveFunc</c>.</p> - <p>When calling several nodes, the nodes are called in parallel.</p> - </desc> - </func> - <func> - <name>tpm_localnames() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>tpm_localnames(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Set meta trace pattern on <c>register/2</c></fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {R1,R2}</v> - <v>R1 = R2 = {ok,0} | {ok,1} | {error,Reason}</v> - </type> - <desc> - <p>Quick version for setting meta-trace patterns on <c>erlang:register/2</c>. It uses a default <c>CallFunc</c> and <c>ReturnFunc</c> in the meta-tracer server. The main purpose of this function is to create ti-log entries for associations between pids and registered name aliases. The implementation uses return_trace to see if the registration was successful or not, before actually making the ti-log alias entry. Further the implementation also meta traces the BIF <c>unregister/1</c>.</p> - <p>If both <c>N1</c> and <c>N2</c> is 1, function call was successful. <c>N1</c> and <c>N2</c> represent setting meta trace pattern on <c>register/2</c> and <c>unregister/1</c>.</p> - </desc> - </func> - <func> - <name>ctpm_localnames() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>ctpm_localnames(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Clear meta trace pattern on <c>register/2</c></fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {R1,R2}</v> - <v>R1 = R2 = ok | {error,Reason}</v> - </type> - <desc> - <p>Function for removing previously set patters by <seealso marker="#tpm_localnames/0">tpm_localnames/0</seealso>. The two results <c>R1</c> and <c>R2</c> represents that meta pattern is removed from both <c>register/2</c> and <c>unregister/1</c>.</p> - </desc> - </func> - <func> - <name>tpm_globalnames() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>tpm_globalnames(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Set meta trace pattern on <c>global:register_name/2</c></fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {R1,R2}</v> - <v>R1 = R2 = {ok,0} | {ok,1} | {error,Reason}</v> - </type> - <desc> - <p>Quick version for setting meta-trace patterns capable of learning the association of a pid with a globally registered name (registered using <c>global:register_name</c>). The implementation meta-traces on <c>global:handle_call({register,'_','_','_'},'_','_')</c> and <c>global:delete_global_name/2</c>. The <c>N1</c> and <c>N2</c> represents the success of the two sub-tmp calls.</p> - </desc> - </func> - <func> - <name>ctpm_globalnames() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>ctpm_globalnames(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Clear meta trace pattern on <c>global:register_name/2</c></fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {R1,R2} | {error,Reason}</v> - <v>R1 = R2 = ok | {error,Reason}</v> - </type> - <desc> - <p>Function for removing previously set meta patters by <seealso marker="#tpm_globalnames/0">tpm_globalnames/0,1</seealso>. The two results <c>R1</c> and <c>R2</c> represents that meta pattern are removed from both <c>global:handle_call/3</c> and <c>global:delete_global_name/1</c>.</p> - </desc> - </func> - <func> - <name>ctp_all() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>ctp_all(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Clear all (global and local) trace patterns</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>Clears all, both global and local trace patterns. Does not clear meta trace patterns. Equivalent to a call to <seealso marker="#ctp/4">ctp/3,4</seealso> and to <seealso marker="#ctpl/4">ctpl/3,4</seealso> with wildcards <c>'_'</c> for all modules, functions and arities.</p> - </desc> - </func> - <func> - <name>suspend(SReason) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>suspend(Nodes,SReason) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Suspend runtime components</fsummary> - <type> - <v>SReason = term()</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>Suspends the runtime components. <c>SReason</c> will become the suspend-reason replied in for instance a <seealso marker="#get_status/0">get_status/0,1</seealso> call. A runtime component that becomes suspended removes all trace flags and all meta trace patterns. In that way trace output is no longer generated. The task of reactivating a suspended runtime component is outside the scoop of inviso. It can for instance be implemented by a higher layer trace-tool "remembering" all trace flags and meta patterns set.</p> - </desc> - </func> - <func> - <name>cancel_suspension() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>cancel_suspend(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Reactivate suspended runtime components</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>Makes the runtime components <c>running</c> again (as opposite to <c>suspended).</c> Since reactivating previous trace flags and meta trace patterns is outside the scoop of inviso, cancelling suspension is simply making it possible to set trace flags and meta trace patterns again.</p> - </desc> - </func> - <func> - <name>get_status() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>get_status(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Get status of runtime components</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {ok,{State,Status}} | {error,Reason}</v> - <v>State = new | idle | tracing</v> - <v>Status = running | {suspended,SReason}</v> - <v>SReason = term()</v> - </type> - <desc> - <p>Finds out the state and status of a runtime component. A runtime component is in state <c>new</c> before it has been initiated to do any tracing the first time. There are clear-functions which can make a runtime component become <c>new</c> again without having to restart. A runtime component becomes <c>idle</c> after tracing is stopped.</p> - </desc> - </func> - <func> - <name>get_tracerdata() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>get_tracerdata(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <fsummary>Get tracerdata of runtime components</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {ok,NResult} | {error,Reason}</v> - <v>NResult = TracerData | no_tracerdata</v> - </type> - <desc> - <p>Returns the current tracerdata of a runtime component. A runtime component in state <c>new</c> can not have tracerdata. An <c>idle</c> runtime component does have tracerdata, the last active tracerdata. <c>TracerData</c> will be a term as specified to <c>init_tracing</c> when tracing was initiated for the runtime component.</p> - </desc> - </func> - <func> - <name>list_logs() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>list_logs(Nodes) -> {ok,NodeResults} | {error,Reason}</name> - <name>list_logs(NodeTracerData) -> {ok,NodeResults} | {error,Reason}</name> - <name>list_logs(TracerData) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Get log file names associated with tracerdata</fsummary> - <type> - <v>TracerData -- see init_tracing/1,2</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {ok,FileList} | {ok,no_log} | {error,Reason}</v> - <v> FileList = [FileType]</v> - <v> FileType = {trace_log,Dir,Files} | {ti_log,Dir,Files}</v> - <v> Files = [FileNameWithOutPath]</v> - </type> - <desc> - <p>Returns the actually existing log files associated with <c>TracerData</c>. If a tracerdata is not specified, current tracerdata is used for that particular runtime component. <c>Files</c> will be a list of one or more files should it be a wrap-set. Otherwise the it is a list of only one filename.</p> - <p>This function is useful to learn the name and path of all files belonging to a trace. This information can later be used to move those files for merging. Note that since it is possible to ask on other tracerdata than the current, it is possible to learn filenames of previously done traces, under the circumstances that they have not been removed.</p> - </desc> - </func> - <func> - <name>fetch_log(LogSpecList,DestDir,Prefix) -> {ok,NodeResults} | {error,not_distributed} | {error,Reason} </name> - <name>fetch_log(DestDir,Prefix) -> {ok,NodeResults} | {error,not_distributed} | {error,Reason}</name> - <fsummary>Fetch log files to control component node</fsummary> - <type> - <v>DestDir = string()</v> - <v>Prefix = string()</v> - <v>LogSpecList = [LogSpec]</v> - <v> LogSpec = {Node,FileSpecList} | Node | {Node,TracerData}</v> - <v>TracerData = see init_tracing/1,/2</v> - <v>FileSpecList = [{trace_log,Dir,FileList},{ti_log,Dir,FileList}] | [{trace_log,Dir,FileList}]</v> - <v> FileList = [RemoteFileName]</v> - <v>NodeResult = {Conclusion,ResultFileSpec} | no_log | {error,NReason}</v> - <v> NReason = own_node | Reason</v> - <v> Conclusion = complete | incomplete</v> - <v> ResultFileSpec = [{trace_log,FileResults},{ti_log,FileResults}]</v> - <v> FileResults = [FileResult]</v> - <v> FileResult = {ok,FileName} | {error,FReason}</v> - <v> FReason = {file_open,{posix(),FileName}} | {file_open,{posix(),RemoteFileName}} | {file_open,{posix(),[DestDir,Prefix,RemoteFileName]}} | {file_write,{posix(),FileName}} | {truncated,FileName} | {truncated,{Reason,FileName}}</v> - <v> posix() = atom()</v> - </type> - <desc> - <p>Copies log files over distributed erlang to the control component node. This function can only be used in a distributed system.</p> - <p>The resulting transferred files will have the prefix <c>Prefix</c> and will be located in <c>DestDir</c>. The source files can either be pointed out using a <c>FileListSpec</c> or tracerdata. If no files are explicitly specified, current tracerdata for that node will be used. Note that if source files have the same name (on several nodes) they will overwrite each other at <c>DestDir</c>.</p> - </desc> - </func> - <func> - <name>delete_log(Nodes,TracerData) -> {ok,NodeResults} | {error,Reason}</name> - <name>delete_log(NodeSpecList) -> {ok,NodeResults} | {error,Reason}</name> - <name>delete_log(Spec) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>delete_log(TracerData) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <name>delete_log() -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Delete log files associated with tracerdata</fsummary> - <type> - <v>Nodes = [Node]</v> - <v>NodeSpecList = [{Node,Spec}]</v> - <v> Spec = [AbsPathFileName] | LogSpecs</v> - <v> LogSpecs = [LogSpec]</v> - <v> LogSpec = {trace_log,Dir,[FileNameWithoutPath]} | {ti_log,Dir,[FileNameWithoutPath]}</v> - <v>TracerData -- see init_tracing/1,/2</v> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = {ok,no_log} | {ok,LogInfos} | {ok,FileInfos}</v> - <v> LogInfos = [LogInfo]</v> - <v> LogInfo = {trace_log,FileInfos} | {ti_log,FileInfos}</v> - <v> FileInfos = [FileInfo]</v> - <v> FileInfo = {ok,FileName} | {error,Reason} </v> - </type> - <desc> - <p>Deletes listed files or files corresponding to tracerdata. If no tracerdata or list of files are specified in the call, current tracerdata at the runtime components will be used to identify files to delete. All filenames shall be strings.</p> - <p><c>FileName</c> can either be an absolute path or just a filename depending on if <c>AbsPathFileName</c> or a <c>LogSpec</c> was used to identify the file.</p> - </desc> - </func> - <func> - <name>subscribe() -> ok | {error,Reason}</name> - <name>subscribe(Pid) -> ok | {error,Reason}</name> - <fsummary>Subscribe to Inviso events</fsummary> - <type> - <v>Pid = pid()</v> - </type> - <desc> - <p>Adds <c>Pid</c> or <c>self()</c> if using <c>subscribe/0</c> to the inviso-event sending list. Note that it is possible to add a pid several times and that the <c>Pid</c> then will receive multiple copies of inviso-event messages.</p> - <p>All events will be sent to all subscribers in the event sending list.</p> - <code type="none"> -Event = {inviso_event,ControllerPid,erlang:localtime(),Msg} - Msg = {connected, Node, {RTtag, {State,Status}}} - | {disconnected, Node, NA} - | {state_change,Node,{State,Status}} - | {port_down,Node,Reason} - Node = node() | local_runtime - </code> - <p>Subscribing to inviso-event may be necessary for a higher layer trace-tool using inviso to follow the runtime components. <c>local_runtime</c> will be used for a runtime component running in a non-distributed environment.</p> - </desc> - </func> - <func> - <name>unsubscribe() -> ok</name> - <name>unsubscribe(Pid) -> ok</name> - <fsummary>Unsubscribe to Inviso events</fsummary> - <desc> - <p>Removes <c>Pid</c> (once) from the subscription list.</p> - </desc> - </func> - </funcs> -</erlref> - diff --git a/lib/inviso/doc/src/inviso_as_lib.xml b/lib/inviso/doc/src/inviso_as_lib.xml deleted file mode 100644 index 1f4961166c..0000000000 --- a/lib/inviso/doc/src/inviso_as_lib.xml +++ /dev/null @@ -1,94 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>2006</year> - <year>2011</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>inviso_as_lib</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <module>inviso_as_lib</module> - <modulesummary>The Inviso Autostart Utility Library</modulesummary> - <description> - <p>The purpose of the Inviso autostart utility library is to facilitate the creation and modification of autostart configuration files used by the standard autostart.</p> - </description> - <funcs> - <func> - <name>setup_autostart(Node, R, Opts, TracerData, CmdFiles, Bindings, Transl, RTtag) -> ok | {error, Reason}</name> - <fsummary>Create an autostart configuration file</fsummary> - <type> - <v>Node = atom()</v> - <v>R = int()</v> - <v>Opts -- see inviso:add_nodes/2,3</v> - <v>TracerData -- see inviso:init_tracing/1,2</v> - <v>CmdFiles = [CmdFile]</v> - <v> CmdFile = string()</v> - <v>Bindings = [{Var,Val}]</v> - <v> Var = atom()</v> - <v> Val = term()</v> - <v>Transl = [{{M1,F1,Arity}, {M2,F2,{Mt,Ft}}}]</v> - <v> M1 = F1 = M2 = F2 = Mt = Ft = atom()</v> - <v> Arity = int()</v> - <v>RTtag = term()</v> - <v>Reason = term()</v> - </type> - <desc> - <p>Creates an autostart configuration file on <c>Node</c>. The name of the file is automatically deducted from consulting the Runtime_Tools configuration parameters at <c>Node</c>.</p> - <p><c>R</c> is the number of allowed autostarts remaining.</p> - <p><c>Opts</c> is the options which shall be given to the runtime component. See <seealso marker="inviso#add_nodes/2">inviso:add_nodes/2,3</seealso>.</p> - <p><c>TracerData</c> is used when initiating tracing on this node. See <seealso marker="inviso#init_tracing/1">inviso:init_tracing/1,2</seealso>.</p> - <p><c>CmdFiles</c> points out files containing instructions understood by the <c>inviso_autostart_server</c> implementation of an autostart initiator.</p> - <p><c>Bindings</c> is a list of <c>{Var, Val}</c> tuples, where <c>Var</c> is the name of a variable and <c>Val</c> the actual value of the variable.</p> - <p><c>Transl</c> means that <c>M1:F1/Arity</c> shall be translated into <c>M2:F2</c>.</p> - <p><c>RTtag</c> is the incarnation tag of the runtime component. See See <seealso marker="inviso#add_nodes/2">inviso:add_nodes/2,3</seealso>.</p> - </desc> - </func> - <func> - <name>set_repeat(Node, R) -> ok | {error, Reason}</name> - <fsummary>Set the repeat parameter in the autostart file</fsummary> - <type> - <v>Node = atom()</v> - <v>R = int()</v> - <v>Reason = term()</v> - </type> - <desc> - <p>Sets the repeat parameter in the autostart file at <c>Node</c> without changing any of its other contents. The autostart configuration file must exist.</p> - <p><c>R</c> is the number of allowed autostarts remaining.</p> - </desc> - </func> - <func> - <name>inhibit_autostart(Node) -> ok | {error, Reason}</name> - <fsummary>Set the repeat parameter in the autostart file to 0</fsummary> - <type> - <v>Node = atom()</v> - <v>Reason = term()</v> - </type> - <desc> - <p>Sets the repeat parameter in the autostart file at <c>Node</c> to 0. Equivalent to <c>set_repeat(Node, 0)</c>.</p> - </desc> - </func> - </funcs> -</erlref> - diff --git a/lib/inviso/doc/src/inviso_chapter.xml b/lib/inviso/doc/src/inviso_chapter.xml deleted file mode 100644 index b69fb97586..0000000000 --- a/lib/inviso/doc/src/inviso_chapter.xml +++ /dev/null @@ -1,362 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>2006</year><year>2011</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Inviso</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - <file>inviso_chapter.xml</file> - </header> - - <section> - <p><em>inviso</em>: (Latin) to go to see, visit, inspect, look at.</p> - <warning> - <p>The <c>inviso</c> application is deprecated and will be - removed in the R16 release.</p> - </warning> - <title>Introduction</title> - <p>The Inviso trace system consists of one or several runtime components supposed to run on each Erlang node doing tracing and one control component which can run on any node with available processor power. Inviso may also be part of a higher layer trace tool. See the inviso-tool as an example. The implementation is spread out over the Runtime_tools and the Inviso Erlang/OTP applications. Erlang modules necessary to run the runtime component are located in Runtime_tools and therefore assumed to be available on any node. Even though Inviso is introduced with Erlang/OTP R11B the runtime component implementation is done with backward compatibility in mind. Meaning that it is possible to compile and run it on older Erlang/OTP releases.</p> - <image file="inviso_users_guide_pic1.gif"> - <icaption>Inviso Trace System Architecture Overview.</icaption> - </image> - <p>This document describes the control and runtime components of the Inviso trace system.</p> - - <section> - <title>Underlying Mechanisms</title> - <p>Inviso is built on Erlang trace BIFs and standard linked in trace-port drivers for efficient trace message logging. This means that Inviso can not co-exist in runtime with any other trace tool using the trace BIFs.</p> - </section> - - <section> - <title>Trace Recepie</title> - <p>This is a short step-by-step description of how tracing using Inviso can be done.</p> - <list type="ordered"> - <item>Start the Inviso control component at any node. Preferably a node that is not participating in the "work" done by your "system". The control component runs independently and normally not linked to any other process. (Prompt 2 in the example below.)</item> - <item>Add all Erlang nodes to the inviso control component where you want to trace. This is starting runtime components on all involved Erlang nodes. Can include the node where the control component runs as well. Note that the Runtime_Tools application must be running on the nodes where runtime components shall be started. (Prompt 1 and 3 in the example below.)</item> - <item>Initiate tracing on the added nodes. Initiating tracing means "opening" the output to where trace-messages will be written. Most commonly this is a file. Note that it is not actually necessary to initiate the same tracing on all nodes. It might for instance be wise to use different filenames on different nodes. In the example below tracing is initiated on two nodes. The same node as where the shell is running (<c>node()</c>) and at <c>node2@hurin</c>. Further both "regular" tracing (<c>trace</c>) as well as trace information (<c>ti</c>) are specified for both nodes. (Prompt 4 in the example below).</item> - <item>If needing pid-to-alias translations, activate meta tracing on the necessary functions. This requires that trace information was specified when initiating tracing. (Prompt 5 in the example below illustrates using pid to locally registered name translations).</item> - <item>Set trace-patterns on the functions that shall be traced. (Prompt 6 in the example below).</item> - <item>Set process trace flags on necessary processes. Do not forget to use the <c>timestamp</c> flag in order to be able to merge log files together in chronological order. (Prompt 7 in the example below).</item> - <item>Run your code. (Prompt 8 in the example below).</item> - <item>Stop tracing (opposite of initiate tracing) and clear trace-patterns on the nodes. It is actually not necessary to stop tracing on all nodes at once. Nodes no longer of interest can be made to stop tracing before others. (Prompt 9 in the example below stops tracing. Prompt 13 removes all trace flags and trace patterns. Removing trace flags are really not necessary since those will be removed when the runtime components are stopped. Removing trace patterns may many times be necessary to "return" the node to a "clean" state from a trace perspective. Trace patterns are never automatically cleared by the runtime system unless the Erlang module in question is reloaded.)</item> - <item>If necessary fetch the log files from the various nodes. (Prompt 10 in the example blow).</item> - <item>Merge and format the log files. (Prompt 12 in the example below).</item> - <item>Stop the runtime components. This is important if the Erlang nodes are real "live" systems, and will not necessarily be stopped just because the tracing is completed. (Prompt 14 in the example below).</item> - </list> - <p>This "recipe" is valid also when tracing in a non-distributed environment. The only difference is that function calls not taking a node-name as argument are used. The runtime component will then of course run on the same node as the control component.</p> - <p>Simple example illustrating the above listed recipe. It traces on two nodes, node1 where the control component also runs. And node2 which is a remote node from the control components perspective. The example uses a mixture of API-calls specifying what nodes to trace on and API functions working on all added nodes. This is in this example interchangeable since all to the control component known nodes are participating in the same way.</p> - <pre> -Eshell V5.5 (abort with ^G) -(node1@hurin)1><input>application:start(runtime_tools).</input> -ok -(node1@hurin)2> <input>inviso:start().</input> -{ok,<0.56.0>} -(node1@hurin)3> <input>inviso:add_nodes([node(),node2@hurin],mytag).</input> -{ok,[{'node1@hurin',{ok,new}}, - {'node2@hurin',{ok,new}}]} -(node1@hurin)4> <input>inviso:init_tracing( [{node(),[{trace,{file,"tracefile_node1.log"}},{ti,{file,"trace_node1.ti"}}]}, {node2@hurin,[{trace,{file,"tracefile_node2.log"}},{ti,{file,"trace_node2.ti"}}]}]).</input> -{ok,[{'node1@hurin',{ok,[{trace_log,ok},{ti_log,ok}]}}, - {'node2@hurin',{ok,[{trace_log,ok},{ti_log,ok}]}}]} -(node1@hurin)5> <input>inviso:tpm_localnames([node(),node2@hurin]).</input> -{ok,[{'node1@hurin',{{ok,1},{ok,1}}}, - {'node2@hurin',{{ok,1},{ok,1}}}]} -(node1@hurin)6> <input>inviso:tpl([node(),node2@hurin],code,which,'_',[]).</input> -{ok,[{'node1@hurin',{ok,[2]}}, - {'node2@hurin',{ok,[2]}}]} -(node1@hurin)7> <input>inviso:tf(all,[call,timestamp]).</input> -{ok,[{'node1@hurin',{ok,"/"}}, - {'node2@hurin',{ok,"-"}}]} -(node1@hurin)8> <input>code:which(ordset).</input> -non_existing -(node1@hurin)9> <input>inviso:stop_tracing().</input> -{ok,[{'node1@hurin',{ok,idle}}, - {'node2@hurin',{ok,idle}}]} -(node1@hurin)10> <input>inviso:fetch_log([node2@hurin],".","aprefix_").</input> -{ok,[{'node2@hurin', - {complete,[{trace_log,[{ok,"aprefix_tracefile_node2.log"}]}, - {ti_log,[{ok,"aprefix_trace_node2.ti"}]}]}}]} -(node1@hurin)11> <input>inviso:list_logs([node()]).</input> -{ok,[{'node1@hurin', - {ok,[{trace_log,".",["tracefile_node1.log"]}, - {ti_log,".",["trace_node1.ti"]}]}}]} -(node1@hurin)12> <input>inviso_lfm:merge( [{node(),[{trace_log,["tracefile_node1.log"]}, {ti_log,["trace_node1.ti"]}]}, {node2@hurin,[{trace_log,["aprefix_tracefile_node2.log"]}, {ti_log,["aprefix_trace_node2.ti"]}]}],"theoutfile.txt").</input> -{ok,15} -(node1@hurin)13> <input>inviso:clear().</input> -{ok,[{'node1@hurin',{ok,{new,running}}}, - {'node2@hurin',{ok,{new,running}}}]} -(node1@hurin)14> <input>inviso:stop_nodes().</input> -{ok,[{'node2@hurin',ok}, - {'node1@hurin',ok}]} -(node1@hurin)15> </pre> - </section> - </section> - - <section> - <title>Incarnation runtime tags</title> - <p>Incarnation runtime tags are used to identify an incarnation of a runtime component. An incarnation is one "start-up" of a runtime component on a specific Erlang node. The reason why it can sometimes be necessary to examine the incarnation runtime tag is that a user wants to connect, adopt, an already running runtime component. This may be the case if the runtime component has autostarted or because the control component terminated without killing the runtime component. While the user has been out of control of the runtime component it may very well have terminated and been restarted. If it was restarted without the user's knowledge, its incarnation runtime tag has most likely changed. The user can therefore, if the current incarnation runtime tag is not what it is supposed to be, conclude that the runtime component is not "doing" what is expected.</p> - <p>The runtime tag is set at runtime component start-up. This is either done when it is started manually by a call to <c>inviso:add_nodes/X</c>, or according to a specification in one of the autostart configuration files.</p> - </section> - - <section> - <title>Runtime component state and status</title> - <p>A runtime component has a state and a status. The possible states are: <c>new</c>, <c>tracing</c> and <c>idle</c>. A runtime component that is <c>tracing</c> has (possibly) open log files. A <c>new</c> runtime component has no current tracer-data. That is it lacks any history of what it has done just recently. An <c>idle</c> runtime component is no longer tracing. It does therefore have current tracer-data that describes what it did do when it was tracing.</p> - <p>The status describes if the runtime component is <c>running</c> or suspended. A suspended runtime component may very well be in state <c>tracing</c>. However the point is that it shall not generate any processor load. It will therefore refrain from generating any trace messages.</p> - </section> - - <section> - <title>The Runtime Meta Tracer</title> - <p>Meta tracing is a trace mechanism separate from the regular tracing. It is normally used by a trace-tool to learn about function calls made anywhere in an Erlang node. A typical example is that there is a possibility in Inviso to get pids translated to registered name in the final formatted trace-log (for processes having registered names). This is done by meta-tracing on the BIF <c>register/2</c> to learn about all name/pid associations made.</p> - <p>Meta tracing in Inviso is done by the <c>inviso_rt_meta</c> process, which is part of the runtime component if trace-information, ti, is initiated. See <seealso marker="inviso#init_tracing/1">inviso:init_tracing/1</seealso> for details. The runtime meta tracer opens and controls the so called trace information file. Translations can then be done off-line using the associations logged in the trace information file. Currently the only type of trace information file available is a straight binary file. A wrap-file makes no sense since pid-to-name associations made in the beginning will most likely be lost.</p> - <p>The runtime meta tracer can also be used to translate pids to own identifiers. The only thing needed is one or several association points in the form of function calls which will only be made if an association is done in the system. The pid and own-identifier must be arguments and/or return values from the same function call.</p> - <p>The runtime meta tracer can further more be used to achieve side-effects during tracing, like turning tracing on or off.</p> - - <section> - <title>Matching function calls with return values</title> - <p>It may sometimes be necessary to wait for a meta traced function to return before it can be decided what to do. This may be due to that one piece of information to make the decision is in the arguments to the function, the other in the return value. This kind of logic can be programmed to be executed by the inviso meta tracer. In order for the inviso meta tracer to "remember" function-call arguments until the function return trace message arrives, a <c>public loop data structure</c> is implemented. The public loop data structure is first created when tracing is initiated (of course only when trace information is specified in the <em>init_tracing</em> call). The public loop data can then later be further initiated each time meta tracing (<c>tpm</c> and <c>tpm_ms</c>) is activated for a certain function.</p> - <p>The default public loop data structure is a tuple of size two. The first element in that tuple is used by the predefined meta tracing for capturing locally registered names. The second element is free to use for any other purpose. The elements of the tuple must in the default implementation be lists of tuples. Where each sub-tuple shall represent one waiting call. The last element of that tuple must be a now-stamp (as returned by the BIF <c>now/0</c>). See below for an explanation of the now-stamp. The size of the outer most tuple may be increased as long as the term residing in the first element is left unchanged, and all other elements follow the above described rules.</p> - <p>The inviso meta tracer "cleans" the public loop data structure approximately once every minute. The reason for this is that entries in the public loop data structure may become abandoned. If for instance a process crashes while executing the body of a meta traced function, no return value will be generated. Or in other words, receiving the call meta trace-message can have caused information to have been written into the public loop data structure. That entry will be used and removed when the return_trace meta trace-message arrives. But if the meta traced function causes an exception, no return_trace message will come. The function which normally removes the entry is then therefore never called.</p> - <p>The default clean-function assumes that every item in the public loop data tuple is a list. Where each list contains tuples where the last element of those tuples are "now-stamps". The default clean-function considers an entry older than 30 seconds to be abandoned.</p> - </section> - - <section> - <title>Making pid/alias entries in the ti-file</title> - <p>When activating meta tracing for a function for the purpose of writing pid-alias associations in the trace information file, a call-func and possibly also a return-func is specified. These functions will be called when a meta trace message arrives to the inviso meta tracer as a result of function calls or returns for this meta traced function. What exactly to write in the trace information file is dictated by the merge mechanism. This since pid-alias translations are done off line when merging log-files. See the chapter on merging and formatting log files for more details.</p> - <p>Simple example where the call to the function <c>connection:assoc_id(Pid,Ref)</c> will associated <c>Pid</c> with the id <c>Ref</c>. We will then in a merged log-file see a translation between <c>Pid</c> and <c>Ref</c>. Actually for all future since there is no unalias function meta traced in this example. The inviso meta tracer will receive a meta trace message every time <c>connection:assoc_id/2</c> is called. When that message arrives the meta tracer will call <c>mytrace:call_assoc_id/3</c> which must return <c>{ok,NewPublicLoopData,OutPutBinary}</c>.</p> - <code type="none"> - -module(mytrace). - - call_assoc_id(_CallingPid,[Pid,Ref],PublLoopData) -> - {ok,PublLoopData,term_to_binary({Pid,Ref,alias,now()})}. - </code> - <pre> - -(node1@hurin)21> <input>inviso:tpm(connection,assoc_id,2,[], {mytrace,call_assoc_id}).</input> -{ok,[{'node1@hurin',{ok,1}}, - {'node2@hurin',{ok,1}}]} -(node1@hurin)22> </pre> - </section> - - <section> - <title>Extending the public loop data structure.</title> - <p>It is of course very likely that the public loop data structure must be extended to host all functions where the meta tracer must delay its action until the function in question returns. What is necessary is to create your own public loop data structure at trace initialization. This is done by using the <c>TiSpec</c>. <c>TiSpec={InitMFA,RemoveMF,CleanMF}</c>, where <c>InitMFA</c> creates the structure, <c>RemoveMF</c> removes it (must often not necessary unless a database, file or similar is used as storage instead of a tuple). <c>CleanMF</c> is the function which will be called each every 60 seconds to go over the public loop data structure. Following the below rules, not much programming will be needed, apart from the <c>InitMFA</c>:</p> - <list type="bulleted"> - <item>Make the public loop data structure a tuple of lists, where each list is a list of tuples where the tuples represents one entry.</item> - <item>Make the <c>CallFunc</c> (the function called each time a call meta trace message arrives for the function in question) add a tuple to the correct list where the last element of that tuple is a now-stamp.</item> - <item>Make sure that the first element in the loop data structure tuple is left alone for the default implementation of the handling of registered names.</item> - <item>Use <c>inviso_rt_meta:clean_std_publld/1</c> (which is exported for this purpose) as <c>CleanMF</c>. This function is normally the default clean function, if not using the possibility to in detail initiate the inner workings of the inviso meta tracer.</item> - </list> - <p>Simple example where tracing is initiated with a public loop data structure having 10 places for nine (the locally registered names is mandatory) different functions to be meta traced. Note that the BIF <c>list_to_tuple/1</c> is used as initialization function. And that the Stdlib function <c>lists:duplicate/2</c> is used to create something for the initialization function to work on.</p> - <pre> -(node1@hurin)4> <input>inviso:init_tracing( [{node2@hurin,[{trace,{file,"tracefile_node2.log"}}, {ti,{file,"trace_node2.ti",{{erlang,list_to_tuple,[lists:duplicate(10,[])]}, void,{inviso_rt_meta,clean_std_publld}}}}]}]).</input> -{ok,[{'node2@hurin',{ok,[{trace_log,ok},{ti_log,ok}]}}]} -(node1@hurin)5> </pre> - </section> - - <section> - <title>Using the inviso meta tracer to achieve side effects</title> - <p>Since meta tracing is independent of regular tracing and catches any function call to a particular function made in any process, it is well suited to be used to turn things on or off during execution. That trick is done by letting the <c>CallFunc</c> and (if used) <c>ReturnFunc</c> do these sideeffects. One must of course remember that the inviso meta tracer is a process amongst all other processes in the system. Meaning that the side effect is not necessarily done exactly when the meta traced function is called. Unless the side effect can be achieved using a match specification action.</p> - </section> - </section> - - <section> - <title>Runtime Component Autostart</title> - <p>In order to trace before any user interaction is possible, an autostart mechanism is implemented. The runtime component is started by the top supervisor of the Runtime_Tools application top supervisor. Hence the Runtime_Tools application must be part of the boot script for autostart tracing to work. The Runtime_Tools applications must of course be started before any application that is to be traced. Do note that application startup is not entirely synchronous. Meaning that just because the application controller has begun starting the next application, Runtime_Tools is not necessarily fully up and running.</p> - <p>The autostart mechanism is configurable. The runtime component comes with a standard autostart configuration, only missing two text-files to be completely operational.</p> - - <section> - <title>Autostart Configuration</title> - <p>The autostart is controlled by the Runtime_Tools application configuration parameter <c>inviso_autostart_mod</c>. It must be the name of a module exporting an <c>autostart/1</c> function. The default value is <c>inviso_autostart</c>, a module which is provided with Runtime_Tools. See <seealso marker="#inviso_autostart">below</seealso> for details.</p> - <p>An <c>autostart/1</c> function must offer the following:</p> - <code type="none"> -autostart(RuntimeToolsArg) = {MFA,Options,Tag} | any() - </code> - <p><c>RuntimeToolsArgs</c> is the argument <c>Arg</c> provided to the Runtime_Tools application through the application resource file <c>{mod,{Module,Arg}}</c> parameter.</p> - <p><c>MFA = {AutoMod,AutoFunc,AutoArgs} | any()</c> controls how tracing will be initiated. Note that initiating tracing is not necessarily the same as starting a runtime component. It is possible to have a runtime component without doing any tracing. The runtime component is started as long as <c>autostart/1</c> returns the proper tuple, and <c>Options</c> does not for instance require a certain non-existing control component. If it is not a proper tuple or there are other faults in the tuple items, the autostart will terminate. Typically will this happen if there is no <c>autostart/1</c> function.</p> - <p>If MFA does not properly point out a function possible to call with <c>spawn(AutoMod,AutoFunc,AutoArg)</c>, there will simply be no initialization. (Initialization is done by a separate process spawned by the runtime component during autostart.) It may be worth reminding that <c>AutoMod</c> must be present at the node where the runtime component is supposed to run. Not necessarily the node where the control component usually runs.</p> - <p><c>Options</c> is the list of options given to the runtime component. See <c>Options</c> in <seealso marker="inviso#add_nodes/2">inviso:add_nodes/2</seealso>.</p> - <p><c>Tag</c> is the runtime component incarnation tag. See <c>Tag</c> in <seealso marker="inviso#add_nodes/2">inviso:add_nodes/2</seealso>.</p> - </section> - - <section> - <title>The Standard Autostart Implementation</title> - <p>As mentioned above, Inviso comes with a complete implementation of autostart sufficient for most situations.</p> - - <section> - <marker id="inviso_autostart"></marker> - <title>inviso_autostart</title> - <p>The default autostart module is <c>inviso_autostart</c>, provided as part of the Runtime_Tools application. Since that name is the default module name, it is not really necessary to set the <c>inviso_autostart_mod</c> configuration parameter for the Runtime_Tools application.</p> - <p>Its <c>autostart/1</c> function reads a configuration file pointed out by the Runtime_Tools application configuration parameter <c>inviso_autostart_conf</c>. If the parameter is not present, a default file, <c>inviso_autostart.config</c> in the current working directory, will be consulted.</p> - <p>The config file must be an ascii text file with one or more tuples ended with a dot. The following parameters are recognized:</p> - <taglist> - <tag><c>{repeat,N}</c></tag> - <item> - <p>Optional parameter where <c>N</c> specifies the maximum remaining autostarts. The autostart functionality will rewrite the configuration decreasing <c>N</c> if present. If <c>N==0</c> the autostart will be terminated.</p> - </item> - <tag><c>{mfa,{M,F,Args}}</c></tag> - <item> - <p>Optional parameter controlling how initialization shall be done. The control component will spawn a separate process to do the initializations by doing <c>spawn(M,F,Args)</c>.</p> - </item> - <tag><c>{options,Options}</c></tag> - <item> - <p>Optional parameter specifying the options for the runtime component itself. See <c>Options</c> in <seealso marker="inviso#add_nodes/2">inviso:add_nodes/2</seealso>.</p> - </item> - <tag><c>{tag,Tag}</c></tag> - <item> - <p>Optional parameter specifying the runtime component tag. If missing the default tag will be <c>default_tag</c>.</p> - </item> - </taglist> - <p>Example:</p> - <code type="none"> -{repeat,1}. -{mfa,{inviso_autostart_server, - init, - [[{tracerdata,{file,"mylogfile"}}, - {cmdfiles,["a_trace_case.txt"]}, - {bindings,[{'M',mymod},{'F','_'},{'Arity','_'}]}, - {translations,[]}]]}}. - </code> - <p>The example file results in the start of a runtime component given no specific options. There will only be one autostart since the repeat parameter is set to 1. Tracing will be initiated by the standard initiator (<seealso marker="#autostart_server">inviso_autostart_server</seealso>). The initiator will initiate tracing opening a plain trace-port logfile (<c>"mylogfile"</c>). It will further read the <c>"a_trace_case.txt"</c> file to get instructions on what patterns and flags to set. If there are variables mentioned in the trace-case file <c>"a_trace_case.txt"</c>, it is parameterized, the variables <c>M</c>, <c>F</c> and <c>Arity</c> will get the values according to <c>bindings</c>. There will be no translations done, hence the trace-case file must be written using <c>inviso_rt</c> function calls directly.</p> - </section> - - <section> - <marker id="autostart_server"></marker> - <title>inviso_autostart_server</title> - <p>To further facilitate the standard autostart implementation a default initiator is implemented. To use it, simply specify it as mfa in the config file read by the standard autostart module.</p> - <p>Its <c>init/1</c> function takes one argument on the form of a list of tuples. The following tuple-parameters are recognized:</p> - <taglist> - <tag><c>{tracerdata,TracerData}</c></tag> - <item> - <p>Specifies how tracing is initiated. See <seealso marker="inviso#init_tracing/1">inviso:init_tracing/1</seealso> for details on <c>TracerData</c>.</p> - </item> - <tag><c>{cmdfiles,ListOfFileNames}</c></tag> - <item> - <p>Specifies trace-case files which shall be executed to set the patterns and flags of the trace. See the <seealso marker="#trace_cases">Trace Cases</seealso> chapter for more details. The files will be executed in the order specified.</p> - </item> - <tag><c>{translations,Translations}</c></tag> - <item> - <p>Optional parameter specifying how functions in trace-case files shall be translated. This is useful since trace-cases can be written for higher-layer Inviso tools, but must during an autostart execute using <c>inviso_rt</c> function calls only.</p> - <code type="none"> -Translations= - [{{Mod1,Func1,Arity}, - {Mod2,Func2,{TranslMod,TranslFunc}}},...] -TranslMod:TranslFunc(ListOfOrigArgs)-> - ListOfTransformedArgs - </code> - <p><c>Mod1:Func1/Arity</c> specifies the function that shall be translated into <c>Mod2:Func2/Arity</c>. The actual arguments will be translated with <c>TranslMod:TranslFunc/1</c>. The translation function shall take a list of the actual arguments, and return a list of new arguments. The return-value list may for instance have certain arguments removed, if such are not relevant to the <c>Func2</c> function. (Such arguments must actually be removed since the return-value list from the translation function must have the correct amount of elements corresponding to the arity of <c>Func2</c>.)</p> - </item> - <tag><c>{bindings,Bindings}</c></tag> - <item> - <p><c>Bindings=[{Var,Val}]</c> <br></br> -<c>Var=atom()</c>, the name of the variable</p> - <p>Optional parameter specifying the actual values of variables used in the trace-cases. <c>Bindings</c> is a bindings structure as used by functions in the <c>erl_eval</c> module.</p> - </item> - </taglist> - </section> - - <section> - <title>The Standard Autostart Utility Library</title> - <p>To facilitate creating the configuration file described above, there are functions in a module named <c>inviso_as_lib</c> which can both create new files according to supplied arguments and update existing configuration files.</p> - <p>The node(s) in question must be running since the functionality in the utility library uses distributed Erlang to access the file system.</p> - </section> - </section> - </section> - - <section> - <title>The Dependency Property</title> - <p>In order to protect real "live" systems from getting a runtime component lingering around without a control component, a dependency property can be specified at runtime component start-up. The property specifies a dependency in milliseconds. Meaning that if the property is set to 0 (zero), the runtime component will terminate immediately if its current control component terminates.</p> - <p>If a control component tries to start a runtime component at an Erlang node where there already is a runtime component, the control component will adopt the already existing runtime component if it has no current control component. Otherwise the control component will experience an error, not being able to start a runtime component at that node.</p> - <p>It must also be noted that an autostart runtime component is running without control component, at least before any control component adopts it.</p> - </section> - - <section> - <title>Overload Protection</title> - <p>Since Inviso is intended to be used on real "live" systems, it is possible to protect the system against overload, having Inviso suspend tracing should an overload situation occur.</p> - <p>What indicates an overload situation must be programmed and configured outside of Inviso. Inviso can initiate an overload protection, call an overload function periodically and clean-up an overload mechanism should it decide to terminate.</p> - <p>Internally inside the runtime component, suspending tracing means removing all process trace flags and meta patterns. Reactivating tracing is outside the scoop of Inviso, but can be implemented in a tool using Inviso.</p> - <p>Simple example adding a runtime component and making it protect its Erlang node from overload.</p> - <pre> -inviso:add_node(my_rt_tag, - [{overload,{{my_ovl,check}, - 15000, - {my_ovl,start,[my_port_pgm]}, - {my_ovl,stop,[my_port_pgm]}}}]). - </pre> - <p>Immediately when the runtime component is started, it will initiate overload protection by calling <c>my_ovl:start(my_port_pgm)</c>. When tracing (not when in state idle or new), the runtime component will every 15000 milliseconds call <c>my_ovl:check/1</c>. Depending on its return value, the runtime component will either do nothing or suspend tracing. When the runtime component is stopped, <c>my_ovl:stop(my_port_pgm)</c> will be called.</p> - </section> - - <section> - <title>Merging and Formatting Logfiles</title> - <p>If logging trace messages to a logfile has been used (decided when tracing is initiated) the various log files will be located on the different Erlang nodes participating in the trace. The log files must be merged and formatted for the following reasons:</p> - <list type="bulleted"> - <item>The various log files from the different nodes must be merged into one logfile in chronological order (where trace messages from different nodes will be mixed). If only one Erlang node participated in the trace, this step is obviously not necessary.</item> - <item>Trace-port log files are on binary format and must in most cases be transformed in some way. This can for instance be to a text-file format or inserted into a database for analysis.</item> - <item>Use trace information data to translate process identifiers to aliases, both standard Erlang ones (as registered names) as well as own invented.</item> - </list> - <p>The first step before any merging can take place is of course to get all log files, including any trace information files to a location where the logfile merger can access them. This can either be done by simply copying the files. However if the file systems on the Erlang nodes are not that easily accessed, there is a <c>fetch_log</c> function implemented in the runtime component. It will transfer log files using distributed Erlang.</p> - <p>Inviso comes with two Erlang modules, <c>inviso_lfm</c> and <c>inviso_lfm_tpfreader</c>, implementing a standard log file merger and formatter. The log file merger (<c>inviso_lfm</c>) uses a file reader process (implemented in <c>inviso_lfm_tpfreader</c>) to access log entries in parallel. It is possible to write your own logfile reader. This is necessary since you may have your own trace-log format and/or own trace information log format. The logfile merger can further more be configured to use your own formatter, customizing what to do with a trace message.</p> - <p>Trace messages in the log files must of course be time-stamped for the logfile merger to be capable of correctly merging them. This means using the <c>timestamp</c> process trace flag.</p> - <p>The standard inviso log-file reader understands the following trace information file entries:</p> - <list type="bulleted"> - <item> - <code type="none"> -{Pid,Alias,alias,NowStamp} </code> - </item> - <item> - <code type="none"> -{Pid,Alias,unalias,NowStamp} </code> - </item> - </list> - <p>The <c>Pid</c> in an <c>alias</c> entry must always be a proper pid. In an <c>unalias</c> entry it may also be the atom <c>undefined</c>. The latter means that all associations involving <c>Alias</c> shall stop to be valid. The standard inviso log file reader uses the now-stamp to make sure that associations are only used during time periods in the log-file when such are valid.</p> - </section> - - <section> - <marker id="trace_cases"></marker> - <title>Trace Cases</title> - <p>The idea behind trace cases is that someone knowledgeable of a certain system component can write a file specifying the trace-patterns and process trace flags necessary to trace on certain items once and for all. Hence a trace case will most likely be a series of calls to functions setting trace patterns and process trace flags.</p> - <p>However, the actual Erlang nodes and values of arguments given in the trace function calls can not be static in order for the trace cases to become useful and reusable. A trace case file must therefore be possible to parameterize. Introducing variables that will get their values at the time of trace case execution. It may also be the case that Inviso is used as a component in a higher layer trace tool. Trace cases may therefore be written calling more complex functions than the low level <c>inviso_rt</c> functions which are available to autostart mechanisms. In a matter of fact, the <c>inviso</c> API itself can be considered a higher layer. It addresses multiple nodes at once where the <c>inviso_rt</c> API can only address the local node.</p> - <p>This results in that for trace cases to be useful there must be a function call translation mechanism and an execution environment capable of handling variable bindings.</p> - <p>A trace-case is a text ascii file consisting of function calls written as they could have been done in the Erlang shell:</p> - <code type="none"> -modulename:functionname(arg1,arg3,...). - </code> - <p>A trace-case may contain any valid function call, including binding new variables which are used later in the trace-case, but:</p> - <list type="bulleted"> - <item>No spawn, send or receive.</item> - <item>No apply or similar (including <c>mod:F(Arg1,Arg2)</c>). This because the variable environment is not available during the translation. Only during execution.</item> - </list> - <p>Example: Trace cases are expected to be written to be executed directly in an Erlang shell (by some utility reading a text file on trace case format) calling <c>inviso</c> functions. The translations must then translate <c>inviso</c> function calls to <c>inviso_rt</c> function calls, since <c>inviso</c> is not available in the Runtime_Tools applications. It can not be assumed that any trace tools outside the Runtime_Tools application is available on the nodes. Luckily (!) the <c>inviso_rt</c> API resembles the <c>inviso</c> API very much, apart from that the <c>inviso_rt</c> API does not take a list of nodes as an argument. Therefore in most situations the only transformation necessary is to change from <c>inviso</c> to <c>inviso_rt</c> and remove the first argument to the function call.</p> - <p>Assume that we have the following trace-case file:</p> - <code type="none"> -inviso:tpl(Nodes,mymod,'_','_',MS). -inviso:tf(Nodes,all,[call,timestamp]). - </code> - <p>For this to work in an autostart the following translation is needed:</p> - <code type="none"> -[{{inviso,tpl,5},{inviso_rt,tpl,{erlang,tl}}}, - {{inviso,tf,3},{inviso_rt,tf,{erlang,tl}}}] - </code> - <p>Since transforming the arguments from <c>inviso</c> calls to <c>inviso_rt</c> calls is simply removing the first argument, there is no need to program any function to do this. The BIF <c>tl/1</c> can be used directly.</p> - <p>Further there must be a variable binding for <c>MS</c> when executing the trace-case. It is not necessary to have one for <c>Nodes</c> since that argument is removed from all function calls by the translation.</p> - </section> -</chapter> - diff --git a/lib/inviso/doc/src/inviso_lfm.xml b/lib/inviso/doc/src/inviso_lfm.xml deleted file mode 100644 index 70207d0b58..0000000000 --- a/lib/inviso/doc/src/inviso_lfm.xml +++ /dev/null @@ -1,93 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>2006</year> - <year>2011</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>inviso_lfm</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <module>inviso_lfm</module> - <modulesummary>An Inviso Off-Line Logfile Merger</modulesummary> - <description> - <p>Implements an off-line logfile merger, merging binary trace-log files from several nodes together in chronological order. The logfile merger can also do pid-to-alias translations.</p> - <p>The logfile merger is supposed to be called from the Erlang shell or a higher layer trace tool. For it to work, all logfiles and trace information files (containing the pid-alias associations) must be located in the file system accessible from this node and organized according to the API description.</p> - <p>The logfile merger starts a process, the output process, which in its turn starts one reader process for every node it shall merge logfiles from. Note that the reason for a process for each node is not remote communication, the logfile merger is an off-line utility, it is to sort the logfile entries in chronological order.</p> - <p>The logfile merger can be customized both when it comes to the implementation of the reader processes and the output the output process shall generate for every logfile entry.</p> - </description> - <funcs> - <func> - <name>merge(Files, OutFile) -></name> - <name>merge(Files, WorkHFun, InitHandlerData) -></name> - <name>merge(Files, BeginHFun, WorkHFun, EndHFun, InitHandlerData) -> {ok, Count} | {error, Reason}</name> - <fsummary>Merge logfiles into one file in chronological order</fsummary> - <type> - <v>Files = [FileDescription]</v> - <v> FileDescription = FileSet | {reader,RMod,RFunc,FileSet}</v> - <v> FileSet = {Node,LogFiles} | {Node,[LogFiles]}</v> - <v> Node = atom()</v> - <v> LogFiles = [{trace_log,[FileName]}] | [{trace_log,[FileName]},{ti_log,TiFileSpec}]</v> - <v> TiFileSpec = [string()] - a list of one string.</v> - <v> FileName = string()</v> - <v> RMod = RFunc = atom()</v> - <v>OutFile = string()</v> - <v>BeginHFun = fun(InitHandlerData) -> {ok, NewHandlerData} | {error, Reason}</v> - <v>WorkHFun = fun(Node, LogEntry, PidMappings, HandlerData) -> {ok, NewHandlerData}</v> - <v> LogEntry = tuple()</v> - <v> PidMappings = term()</v> - <v>EndHFun = fun(HandlerData) -> ok | {error, Reason}</v> - <v>Count = int()</v> - <v>Reason = term()</v> - </type> - <desc> - <p>Merges the logfiles in <c>Files</c> together into one file in chronological order. The logfile merger consists of an output process and one or several reader processes.</p> - <p>Returns <c>{ok, Count}</c> where <c>Count</c> is the total number of log entries processed, if successful.</p> - <p>When specifying <c>LogFiles</c>, currently the standard reader-process only supports:</p> - <list type="bulleted"> - <item>one single file</item> - <item>a list of wraplog files, following the naming convention <c><![CDATA[<Prefix><Nr><Suffix>]]></c>.</item> - </list> - <p>Note that (when using the standard reader process) it is possible to give a list of <c>LogFiles</c>. The list must be sorted starting with the oldest. This will cause several trace-logs (from the same node) to be merged together in the same <c>OutFile</c>. The reader process will simply start reading the next file (or wrapset) when the previous is done.</p> - <p><c>FileDescription == {reader,RMod,RFunc,FileSet}</c> indicates that <c>spawn(RMod, RFunc, [OutputPid,LogFiles])</c> shall create a reader process.</p> - <p>The output process is customized with <c>BeginHFun</c>, <c>WorkHFun</c> and <c>EndHFun</c>. If using <c>merge/2</c> a default output process configuration is used, basically creating a text file and writing the output line by line. <c>BeginHFun</c> is called once before requesting log entries from the reader processes. <c>WorkHFun</c> is called for every log entry (trace message) <c>LogEntry</c>. Here the log entry typically gets written to the output. <c>PidMappings</c> is the translations produced by the reader process. <c>EndHFun</c> is called when all reader processes have terminated.</p> - <p>Currently the standard reader can only handle one ti-file (per <c>LogFiles</c>). The current inviso meta tracer is further not capable of wrapping ti-files. (This also because a wrapped ti-log will most likely be worthless since alias associations done in the beginning are erased but still used in the trace-log).</p> - <p>The standard reader process is implemented in the module <c>inviso_lfm_tpreader</c> (trace port reader). It understands Erlang linked in trace-port driver generated trace-logs and <c>inviso_rt_meta</c> generated trace information files.</p> - </desc> - </func> - </funcs> - - <section> - <title>Writing Your Own Reader Process</title> - <p>Writing a reader process is not that difficult. It must:</p> - <list type="bulleted"> - <item>Export an init-like function accepting two arguments, pid of the output process and the <c>LogFiles</c> component. <c>LogFiles</c> is actually only used by the reader processes, making it possible to redefine <c>LogFiles</c> if implementing an own reader process.</item> - <item>Respond to <c>{get_next_entry, OutputPid}</c> messages with <c>{next_entry, self(), PidMappings, NowTimeStamp, Term}</c> or <c>{next_entry, self(), {error,Reason}}</c>.</item> - <item>Terminate normally when no more log entries are available.</item> - <item>Terminate on an incoming EXIT-signal from <c>OutputPid</c>.</item> - </list> - <p>The reader process must of course understand the format of a logfile written by the runtime component.</p> - </section> -</erlref> - diff --git a/lib/inviso/doc/src/inviso_lfm_tpfreader.xml b/lib/inviso/doc/src/inviso_lfm_tpfreader.xml deleted file mode 100644 index bae40522a3..0000000000 --- a/lib/inviso/doc/src/inviso_lfm_tpfreader.xml +++ /dev/null @@ -1,83 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>2006</year> - <year>2011</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>inviso_lfm_tpfreader</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <module>inviso_lfm_tpfreader</module> - <modulesummary>Inviso Standard Reader Process to Standard Logfile Merger</modulesummary> - <description> - <p>Implements the standard reader process to the standard logfile merger <c>inviso_lfm</c>.</p> - <p>The reader process reads logfiles belonging to the same set (normally one node) in chronological order and delivers logged trace messages one by one to the output process. Before any trace messages are delivered, the <c>inviso_lfm_tpreader</c> implementation reads the entire trace information file (if in use) and builds a database over pid-to-alias associations.</p> - <p>The <c>inviso_lfm_tpreader</c> implementation is capable of considering that an alias may have been used for several processes during different times. An alias may also be in use for several pids at the same time, on purpose. If a process has generated a trace message, all associations between that pid and aliases will be presented as the list <c>PidMappings</c> in the message sent to the output process.</p> - </description> - <funcs> - <func> - <name>handle_logfile_sort_wrapset(LogFiles) -> FileList2</name> - <fsummary>Sort logfiles in chronological order</fsummary> - <type> - <v>LogFiles = [{trace_log, FileList}]</v> - <v>FileList = FileList2 = [FileName]</v> - <v> FileName = string()</v> - </type> - <desc> - <p>Only one <c>{trace_log, FileList}</c> tuple is expected in <c>LogFiles</c>, all other tuples are ignored. <c>FileList</c> must:</p> - <list type="bulleted"> - <item>contain one single file name, or</item> - <item>a list of wraplog files, following the naming convention <c><![CDATA[<Prefix><Nr><Suffix>]]></c>.</item> - </list> - <p>Sorts the files in <c>FileList</c> in chronological order beginning with the oldest. Sorting is only relevant if <c>FileList</c> is a list of wraplogs. The sorting is done on finding the modulo-counter in the filename and not on filesystem timestamps.</p> - <p>This function is exported for convenience should an own reader process be implemented.</p> - </desc> - </func> - </funcs> - - <section> - <title>The Trace Information File Protocol</title> - <p>The format of a trace information file is dictated by the meta tracer process. The <c>inviso_lfm_tpfreader</c> implementation of a reader process understands the following trace information entries. Note that the <c>inviso_rt_meta</c> trace information file is on binary format prefixing every entry with a 4 byte length indicator.</p> - <taglist> - <tag><c>{Pid, Alias, alias, NowStamp}</c></tag> - <item> - <p><c>Pid = pid()</c> <br></br> -<c>Alias = term()</c> <br></br> -<c>NowStamp = term()</c>, but in current implementation as - returned from <c>erlang:now/0</c></p> - <p>This message indicates that from now on shall <c>Pid</c> be associated with <c>Alias</c>.</p> - </item> - <tag><c>{MaybePid, Alias, unalias, NowStamp}</c></tag> - <item> - <p><c>MaybePid = pid() | undefined</c> <br></br> -<c>Alias = term()</c> <br></br> -<c>NowStamp = term()</c>, see above</p> - <p>This message indicates that, if <c>MaybePid</c> is a pid, this pid shall no longer be associated with <c>Alias</c>. If it is <c>undefined</c>, all associations with <c>Alias</c> from now shall be considered invalid.</p> - <p>Also note that there are many situations where <c>unalias</c> entries will be missing. For instance if a process terminates without making explicit function calls removing its associations first. This is seldom a problem unless the pid is reused.</p> - </item> - </taglist> - </section> -</erlref> - diff --git a/lib/inviso/doc/src/inviso_rt.xml b/lib/inviso/doc/src/inviso_rt.xml deleted file mode 100644 index 3a8e77f65c..0000000000 --- a/lib/inviso/doc/src/inviso_rt.xml +++ /dev/null @@ -1,246 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>2006</year> - <year>2011</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>inviso_rt</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <module>inviso_rt</module> - <modulesummary>Direct API to the Inviso Runtime Component</modulesummary> - <description> - <p>The <c>inviso_rt</c> API is normally only used when programming autostart scripts or similar mechanisms. The reason is that the runtime component is part of the Runtime_tools application and will therefore always be available. But the regular inviso API is part of the Inviso application not necessarily available on the node doing an autostart. It is of course possible to runt a "lean" tracer only using the runtime component manually (i.e not through autostart). The runtime component shall otherwise be controlled through the control component, which is accessed with the <c>inviso</c> API.</p> - </description> - <funcs> - <func> - <name>init_tracing(TracerData) -> NodeResult | {error,Reason}</name> - <fsummary>Initiate tracing</fsummary> - <desc> - <p>See <seealso marker="inviso#init_tracing/2">inviso:init_tracing/2</seealso> for details.</p> - </desc> - </func> - <func> - <name>tp(Mod,Func,Arity,MatchSpec,Opts) -></name> - <name>tp(Mod,Func,Arity,MatchSpec) -> NodeResult | {error,Reason}</name> - <name>tp(PatternList) -> NodeResult | {error,Reason}</name> - <fsummary>Set global trace patterns</fsummary> - <type> - <v>Mod,Func = atom() | '_' | ModRegExp | {DirRegExp,ModRegExp}</v> - <v> ModRegExp = regexp_string()</v> - <v> DirRegExp = regexp_string()</v> - <v>Arity = int() | '_'</v> - <v>MatchSpec = true | false | [] | matchspec()</v> - <v>PatternList = [Pattern],</v> - <v> Pattern = {Mod,Func,Arity,MatchSpec,Opts}</v> - <v>Opts = [Opt]</v> - <v> Opt = only_loaded</v> - <v>NodeResult = {ok,[Ans]} | {error,Reason}</v> - <v> Ans = int() | {error,Reason}</v> - </type> - <desc> - <p>Set global trace patterns. The integer replied if the call was successfull describes the number of matched functions. Using wildcards follows the rules for wildcards of <c>erlang:trace_pattern</c>. It is for instance illegal to specify <c>M=='_'</c> while <c>F</c> is not <c>'_'</c>.</p> - <p>Modules can also be specified using Erlang regular expressions as described in the <c>regexp</c> module. If <c>{DirRegExp,ModRegExp}</c> is used, module selection will further be restricted by that the module must be loaded from a location containing <c>DirRegExp</c> somewhere in the path. This can be used to for instance trace on all modules belonging to a certain application.</p> - </desc> - </func> - <func> - <name>tpl(Mod,Func,Arity,MatchSpec) -></name> - <name>tpl(Mod,Func,Arity,MatchSpec,Opts) -> NodeResult | {error,Reason}</name> - <name>tpl(PatternList) -> NodeResult | {error,Reason}</name> - <fsummary>Set local trace patterns</fsummary> - <desc> - <p>See <seealso marker="#tp/5">tp/N</seealso> function above for details on arguments and return values.</p> - <p>Set local trace pattern on specified functions.</p> - </desc> - </func> - <func> - <name>ctp(Mod,Func,Arity) -> NodeResult | {error,Reason}</name> - <fsummary>Clear global trace patterns</fsummary> - <desc> - <p>See <seealso marker="#tp/5">tp/N</seealso> for argument descriptions.</p> - <p>Clear global trace patterns.</p> - </desc> - </func> - <func> - <name>ctpl(Mod,Func,Arity) -> NodeResult | {error,Reason}</name> - <fsummary>Clear local trace patterns</fsummary> - <desc> - <p>See <seealso marker="#tp/5">tp/N</seealso> for argument description.</p> - <p>Clear local trace patterns.</p> - </desc> - </func> - <func> - <name>tf(PidSpec,FlagList) -> NodeResult | {error,Reason}</name> - <name>tf(TraceConfList) -> NodeResult | {error,Reason}</name> - <fsummary>Set process trace flags</fsummary> - <type> - <v>TraceConfList = [{PidSpec,FlagList}]</v> - <v>FlagList = [Flag]</v> - <v>PidSpec = all | new| existing | pid() | locally_registered_name()</v> - <v>Flag = all process trace flags allowed.</v> - <v>NodeResult = {ok,[Ans]} | {error,Reason}</v> - <v>Ans = int() | {error,Reason}</v> - </type> - <desc> - <p>Set process trace flags. The integer returned if the call was successful describes the matched number of processes.</p> - </desc> - </func> - <func> - <name>ctf(PidSpec,FlagList) -> NodeResult | {error,Reason}</name> - <name>ctf(TraceConfList) -> NodeResult | {error,Reason}</name> - <fsummary>Clear process trace flags</fsummary> - <desc> - <p>See <seealso marker="#tf/2">tf/1,2</seealso> for arguments and return value description.</p> - <p>Clear process trace flags.</p> - </desc> - </func> - <func> - <name>init_tpm(Mod,Func,Arity,CallFunc) -> NodeResult | {error,Reason}</name> - <name>init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> NodeResult | {error,Reason}</name> - <fsummary>Initialize meta tracing</fsummary> - <type> - <v>Mod = Func = atom()</v> - <v>Arity = int()</v> - <v>NodeResult = ok | {error,Reason}</v> - <v>InitFunc = RemoveFunc = {Module,Function} | function()/4 | void</v> - </type> - <desc> - <p>See <seealso marker="inviso#init_tpm/4">inviso:init_tpm/5,7</seealso> for details.</p> - </desc> - </func> - <func> - <name>tpm(Mod,Func,Arity,MS) -> NodeResult | {error,Reason}</name> - <name>tpm(Mod,Func,Arity,MS,CallFunc) -> NodeResults | {error,Reason}</name> - <name>tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> NodeResults | {error,Reason}</name> - <fsummary>Activate meta tracing</fsummary> - <type> - <v>Mod = Func = atom() =/= '_'</v> - <v>Arity = int()</v> - <v>MS = match_spec()</v> - <v>InitFunc = CallFunc = ReturnFunc = RemoveFunc = {Module,Function} | function()</v> - <v>NodeResult = {ok,1} | {ok,0} | {error,Reason}</v> - </type> - <desc> - <p>See <seealso marker="inviso#tpm/4">inviso:tpm/4,5,8</seealso> for details.</p> - </desc> - </func> - <func> - <name>tpm_tracer(Mod,Func,Arity,MS) -> NodeResult | {error,Reason}</name> - <name>tpm_tracer(Mod,Func,Arity,MS,CallFunc) -> NodeResults | {error,Reason}</name> - <name>tpm_tracer(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> NodeResults | {error,Reason}</name> - <fsummary>Activate meta tracing</fsummary> - <desc> - <p>See inviso:tpm_tracer/4,5,8 for details.</p> - </desc> - </func> - <func> - <name>tpm_ms(Mod,Func,Arity,MSname,MS) ->d NodeResult | {error,Reason}</name> - <fsummary>Add match specifications</fsummary> - <type> - <v>Mod = Func = atom()</v> - <v>Arity = int()</v> - <v>MSname = term()</v> - <v>MatchSpec = [match_spec()]</v> - <v>NodeResult = {ok,1} | {ok,0} | {error,Reason}</v> - </type> - <desc> - <p>See <seealso marker="inviso#tpm_ms/5">inviso:tpm_ms/5</seealso> for details.</p> - </desc> - </func> - <func> - <name>tpm_ms_tracer(Mod,Func,Arity,MSname,MS) ->d NodeResult | {error,Reason}</name> - <fsummary>Add match specifications</fsummary> - <desc> - <p>See inviso:tpm_ms_tracer/5 for details.</p> - </desc> - </func> - <func> - <name>ctpm_ms(Mod,Func,Arity,MSname) -> NodeResult | {error,Reason}</name> - <fsummary>Remove a match specification</fsummary> - <type> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>See <seealso marker="inviso#ctpm_ms/4">inviso:ctpm_ms/4</seealso> for details.</p> - </desc> - </func> - <func> - <name>ctpm(Mod,Func,Arity) -> {ok,NodeResults} | NodeResult | {error,Reason}</name> - <fsummary>Remove a meta trace pattern</fsummary> - <type> - <v>NodeResults = [{Node,NodeResult}]</v> - <v>NodeResult = ok | {error,Reason}</v> - </type> - <desc> - <p>See <seealso marker="inviso#ctpm/3">inviso:ctpm/3</seealso> for details.</p> - </desc> - </func> - <func> - <name>local_register() ->NodeResult | {error,Reason}</name> - <fsummary>Set meta trace pattern on <c>register/2</c></fsummary> - <type> - <v>NodeResult = {R1,R2}</v> - <v>R1 = R2 = {ok,0} | {ok,1} | {error,Reason}</v> - </type> - <desc> - <p>See <seealso marker="inviso#tpm_localnames/0">inviso:tpm_localnames/0</seealso> for details.</p> - </desc> - </func> - <func> - <name>remove_local_register() ->NodeResult | {error,Reason}</name> - <fsummary>Clear meta trace pattern on <c>register/2</c></fsummary> - <type> - <v>NodeResult = {R1,R2} | {error,Reason}</v> - <v>R1 = R2 = ok | {error,Reason}</v> - </type> - <desc> - <p>See <seealso marker="inviso#ctpm_localnames/0">inviso:ctpm_localnames/0</seealso> for details.</p> - </desc> - </func> - <func> - <name>global_register() ->NodeResult | {error,Reason}</name> - <fsummary>Set meta trace pattern on <c>global:register_name/2</c></fsummary> - <type> - <v>NodeResult = {R1,R2} | {error,Reason}</v> - <v>R1 = R2 = {ok,0} | {ok,1} | {error,Reason}</v> - </type> - <desc> - <p>See <seealso marker="inviso#tpm_globalnames/0">inviso:tpm_globalnames/0</seealso> for details.</p> - </desc> - </func> - <func> - <name>remove_global_register() ->NodeResult | {error,Reason}</name> - <fsummary>Clear meta trace pattern on <c>global:register_name/2</c></fsummary> - <type> - <v>NodeResult = {R1,R2} | {error,Reason}</v> - <v>R1 = R2 = ok | {error,Reason}</v> - </type> - <desc> - <p>See <seealso marker="inviso#ctpm_globalnames/0">inviso:ctpm_globalnames/0</seealso> for details.</p> - </desc> - </func> - </funcs> -</erlref> - diff --git a/lib/inviso/doc/src/inviso_rt_meta.xml b/lib/inviso/doc/src/inviso_rt_meta.xml deleted file mode 100644 index a1e5400ce0..0000000000 --- a/lib/inviso/doc/src/inviso_rt_meta.xml +++ /dev/null @@ -1,78 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>2006</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>inviso_rt_meta</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <module>inviso_rt_meta</module> - <modulesummary>Direct API to the Inviso Runtime Component's meta tracer</modulesummary> - <description> - <p>This module provides a direct API to the inviso meta tracer. These functions are only meant to be used in meta tracing <c>CallFunc</c> and <c>RemoveFunc</c>.</p> - <p>It can sometimes be necessary to manipulate meta match-patterns from <c>CallFunc</c>s and <c>RemoveFunc</c>s. The problem then is that call-funcs and remove-funcs are meta trace call-backs executed inside the inviso meta tracer's context. Hence making calls to the regular API's manipulating meta trace-patterns will hang the inviso meta tracer!.</p> - <p>To remedy this problem, a number of useful tpm-functions are available in this API. It must be understood that their actions are local to the Erlang node where they are called.</p> - </description> - <funcs> - <func> - <name>tpm_ms(Mod,Func,Arity,MSname,MS) -> {ok,0} | {ok,1} | {error,not_initiated}</name> - <fsummary>Adds a list of match-specs, associated with the name <c>MSname</c>, to <c>Mod:Func/Arity</c>.</fsummary> - <desc> - <p>See inviso:tpm_ms/6 for details. Note that this function only effects meta trace-patterns on the Erlang node where the function is called. This also implies that only the local inviso meta tracer's name-database is updated with <c>MSname</c>.</p> - </desc> - </func> - <func> - <name>tpm_ms_tracer(Mod,Func,Arity,MSname,MS) -> {ok,0} | {ok,1} | {error,not_initiated}</name> - <fsummary>As tpm_ms_tracer/5 but also adds a <c>{tracer,Tracer}</c>trace flag to the enable-list of every <c>trace</c>in <c>MS</c>.</fsummary> - <desc> - <p>See inviso:tpm_ms_ms/6 for details. Note that this function only effects meta trace-patterns on the Erlang node where the function is called. This also implies that only the local inviso meta tracer's name-database is updated with <c>MSname</c>.</p> - </desc> - </func> - <func> - <name>list_tpm_ms(Mod,Func,Arity) -> [MSname]</name> - <fsummary>Returns a list of <c>MSname</c>.</fsummary> - <desc> - <p>Returns a list of all <c>MSname</c> in use for <c>Mod:Func/Arity</c>. This can be useful instead of having to have an own-implemented database over currently in use meta match-functions for a particular function.</p> - </desc> - </func> - <func> - <name>ctpm_ms(Mod,Func,Arity,MSname) -> ok</name> - <fsummary>Removes the list of match-specs associated with the <c>MSname</c>from the meta trace-pattern of <c>Mod:Func/Arity</c>.</fsummary> - <desc> - <p>See inviso:ctpm_ms/5 for details. Note that this function only effects meta trace-patterns on the Erlang node where the function is called. This also implies that only the local inviso meta tracer's name-database is updated with <c>MSname</c>.</p> - </desc> - </func> - <func> - <name>get_tracer() -> Tracer</name> - <fsummary>Returns the pid or port acting as regular tracer.</fsummary> - <type> - <v>Tracer = pid() | port()</v> - </type> - <desc> - <p>Returns the pid or port acting as the receiver of regular trace messages. This is useful if it is necessary to manipulate meta trace-patterns by hand (using <c>erlang:trace_pattern/3</c>) and the <c>{tracer,Tracer}</c> must be used in one of the match-function bodies.</p> - </desc> - </func> - </funcs> -</erlref> - diff --git a/lib/inviso/doc/src/inviso_users_guide_pic1.gif b/lib/inviso/doc/src/inviso_users_guide_pic1.gif Binary files differdeleted file mode 100644 index a6da9d37de..0000000000 --- a/lib/inviso/doc/src/inviso_users_guide_pic1.gif +++ /dev/null diff --git a/lib/inviso/doc/src/inviso_users_guide_pic1.ps b/lib/inviso/doc/src/inviso_users_guide_pic1.ps deleted file mode 100644 index fc859cd129..0000000000 --- a/lib/inviso/doc/src/inviso_users_guide_pic1.ps +++ /dev/null @@ -1,24489 +0,0 @@ -%!PS-Adobe-2.0 EPSF-2.0
-%%Title: /clearcase/otp/tools/inviso/doc/src/inviso_users_guide_pic1b.ps
-%%Creator: XV Version 3.10a Rev: 12/29/94 - by John Bradley
-%%BoundingBox: -1 161 615 630
-%%Pages: 1
-%%DocumentFonts:
-%%EndComments
-%%EndProlog
-
-%%Page: 1 1
-
-% remember original state
-/origstate save def
-
-% build a temporary dictionary
-20 dict begin
-
-% define string to hold a scanline's worth of data
-/pix 1848 string def
-
-% define space for color conversions
-/grays 616 string def % space for gray scale line
-/npixls 0 def
-/rgbindx 0 def
-
-% lower left corner
--1 161 translate
-
-% size of image (on paper, in 1/72inch coords)
-616.03200 469.00800 scale
-
-% define 'colorimage' if it isn't defined
-% ('colortogray' and 'mergeprocs' come from xwd2ps
-% via xgrab)
-/colorimage where % do we know about 'colorimage'?
- { pop } % yes: pop off the 'dict' returned
- { % no: define one
- /colortogray { % define an RGB->I function
- /rgbdata exch store % call input 'rgbdata'
- rgbdata length 3 idiv
- /npixls exch store
- /rgbindx 0 store
- 0 1 npixls 1 sub {
- grays exch
- rgbdata rgbindx get 20 mul % Red
- rgbdata rgbindx 1 add get 32 mul % Green
- rgbdata rgbindx 2 add get 12 mul % Blue
- add add 64 idiv % I = .5G + .31R + .18B
- put
- /rgbindx rgbindx 3 add store
- } for
- grays 0 npixls getinterval
- } bind def
-
- % Utility procedure for colorimage operator.
- % This procedure takes two procedures off the
- % stack and merges them into a single procedure.
-
- /mergeprocs { % def
- dup length
- 3 -1 roll
- dup
- length
- dup
- 5 1 roll
- 3 -1 roll
- add
- array cvx
- dup
- 3 -1 roll
- 0 exch
- putinterval
- dup
- 4 2 roll
- putinterval
- } bind def
-
- /colorimage { % def
- pop pop % remove 'false 3' operands
- {colortogray} mergeprocs
- image
- } bind def
- } ifelse % end of 'false' case
-
-
-
-616 469 8 % dimensions of data
-[616 0 0 -469 0 469] % mapping matrix
-{currentfile pix readhexstring pop}
-false 3 colorimage
-
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff000000000000
-000000ffffffccccccffffffffffffffffff000000000000ffffffffffffccccccffffff
-000000ffffff000000000000ffffffffffffcccccc000000000000000000000000ffffff
-000000ffffff000000000000ffffffffffffffffff000000000000ffffffccccccffffff
-ffffffffffff000000ffffffffffffffffffccccccffffffffffffffffff000000000000
-000000ffffffccccccffffffffffffffffff000000000000ffffffffffffccccccffffff
-ffffff000000ffffff000000000000ffffffcccccc000000000000ffffffffffffffffff
-ffffff000000cccccc000000000000ffffffffffffffffffffffffffffffcccccc000000
-000000ffffffffffffffffffffffffffffff000000ffffff000000000000ffffffffffff
-ffffffffffff000000000000000000ffffffffffffffffffffffff000000cccccc000000
-000000ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff000000ffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000
-000000000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
-000000000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-000000000000000000ffffffffffff000000000000ffffffffffff000000ffffffffffff
-000000000000000000ffffffffffff000000ffffffffffffffffffffffff000000ffffff
-ffffff000000ffffffffffffffffff000000000000000000ffffffffffff000000ffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000000000000000ffffff
-ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffff000000000000000000000000000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffffffffffffffff000000ffffffccccccffffffffffff000000ffffffffffff
-000000ffffffccccccffffff000000ffffffffffffffffff000000ffffffccccccffffff
-000000ffffffffffffffffffffffff000000ccccccffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffffffffffffffff000000ffffffccccccffffffffffff000000ffffffffffff
-ffffff000000ccccccffffffffffff000000ffffffffffffffffff000000ccccccffffff
-ffffff000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffff000000ffffffffffffffffffffffffccccccffffffffffff000000ffffffffffff
-ffffff000000ccccccffffff000000ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000ffffff000000000000000000000000ffffffffffff000000000000ccccccffffff
-ffffff000000ffffff000000000000ffffffccccccffffff000000000000000000000000
-ffffffffffff000000ffffffffffffffffff000000ffffff000000000000ccccccffffff
-000000000000ffffffffffffffffffffffffcccccc000000000000000000ffffffffffff
-ffffffffffffccccccffffffffffffffffff000000000000000000ffffffccccccffffff
-ffffffffffff000000000000ffffffffffffccccccffffffffffff000000ffffff000000
-000000ffffffcccccc000000000000ffffffffffffffffff000000ffffff000000000000
-ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
-ffffff000000cccccc000000000000ffffffffffffffffffffffff000000000000000000
-ffffffffffffffffffffffff000000ffffff000000000000ffffffffffffffffff000000
-000000000000000000ffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff000000ffffff
-000000ffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000000000ffffffffffff000000ffffffffffffffffffffffff000000ffffff
-ffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-000000000000000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000000000ffffffffffff000000000000000000ffffffffffff000000000000
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffff000000000000000000ffffff
-ffffff000000000000ffffffffffff000000ffffff000000000000000000ffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-000000000000000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
-000000ffffffffffff000000000000000000ffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
-000000ffffffffffffffffffffffffffffff000000000000ffffffffffffffffff000000
-000000000000ffffff000000000000000000ffffffffffff000000000000ffffff000000
-000000000000ffffffffffffffffffffffffffffff000000000000ffffffffffffffffff
-ffffff000000000000000000ffffffffffffffffffffffffffffffffffff000000000000
-000000ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
-000000000000000000ffffff000000000000000000ffffff000000000000000000ffffff
-ffffff000000ffffff000000000000ffffffffffffffffffffffffffffffffffff000000
-000000ffffffffffffffffffffffff000000000000000000ffffff000000000000000000
-ffffffffffff000000000000000000ffffffffffffffffff000000000000000000ffffff
-000000000000000000ffffff000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffff000000000000000000000000000000ffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000000000000000000000
-000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffff000000ccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-000000ffffffffffffffffffffffff000000ccccccffffffffffff000000ffffffffffff
-ffffff000000ccccccffffffffffff000000ffffffffffffffffff000000ccccccffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff000000ccccccffffffffffffffffffffffffffffff
-000000ffffffccccccffffffffffff000000ffffffffffffffffff000000ccccccffffff
-ffffff000000ffffffffffffffffff000000ccccccffffff000000ffffffffffffffffff
-ffffff000000ccccccffffff000000ffffffffffffffffffffffff000000ccccccffffff
-ffffff000000ffffffffffffffffff000000ccccccffffff000000ffffffffffffffffff
-ffffffffffffccccccffffff000000ffffffffffffffffff000000ffffffccccccffffff
-000000ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffff000000000000000000ffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff000000
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000000000ffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
-000000ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000ffffffffffffffffffffffff000000000000ffffff000000ffffffffffff
-000000000000000000ffffff000000000000000000ffffffffffff000000000000ffffff
-ffffff000000000000000000ffffff000000000000000000ffffff000000000000000000
-ffffff000000000000000000ffffffffffffffffff000000000000000000ffffffffffff
-ffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff
-ffffffffffff000000000000ffffffffffffffffffffffff000000000000000000ffffff
-000000000000000000ffffff000000000000000000ffffff000000ffffff000000000000
-ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
-000000000000000000ffffff000000000000000000ffffffffffff000000000000000000
-ffffffffffffffffff000000000000000000ffffff000000000000000000ffffffffffff
-000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff000000ffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc999999ccccccffffffffffff
-ffffff666666999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-999999ccccccffffffffffffffffff666666999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffcccccc999999ccccccffffffffffffffffff666666999999ffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc999999ccccccffffffffffff
-ffffff666666999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-999999999999ffffffffffffffffff999999999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffcccccc999999999999ffffffffffffffffff999999999999ffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc999999999999ffffffffffff
-ffffff999999999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-666666999999ffffffffffffffffff999999999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffcccccc666666999999ffffffffffffffffff999999999999ffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc666666999999ffffffffffff
-ffffff999999999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-666666999999ffffffffffffffffff999999999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999ccccccffffffffffffffffff666666999999ffffff
-ffffffffffff999999666666ffffffffffffffffffcccccc666666ccccccffffffffffff
-ffffff666666999999ffffffffffffffffff999999666666ffffffffffffffffffcccccc
-666666ccccccffffffffffffffffff666666999999ffffffffffffffffff999999666666
-ffffffffffffffffffcccccc666666ccccccffffffffffffffffff666666999999ffffff
-ffffffffffff999999666666ffffffffffffffffffcccccc666666ccccccffffffffffff
-ffffff666666999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-666666ccccccffffffffffffffffff666666999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffcccccc666666ccccccffffffffffffffffff666666999999ffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc666666ccccccffffffffffff
-ffffff666666999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-666666ccccccffffffffffffffffff666666999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffcccccc999999ccccccffffffffffffffffff666666999999ffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc999999ccccccffffffffffff
-ffffff666666999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-999999ccccccffffffffffffffffff666666999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffcccccc999999ccccccffffffffffffffffff666666999999ffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc999999ccccccffffffffffff
-ffffff666666999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-999999999999ffffffffffffffffff999999999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffcccccc999999999999ffffffffffffffffff999999999999ffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc999999999999ffffffffffff
-ffffff999999999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-666666999999ffffffffffffffffff999999999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffcccccc666666999999ffffffffffffffffff999999999999ffffff
-ffffffffffffcccccc666666ffffffffffffffffffcccccc666666999999ffffffffffff
-ffffff999999999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc
-666666999999ffffffffffffffffff999999999999ffffffffffffffffffcccccc666666
-ffffffffffffffffffffffff
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffff666666000000333333ffffffffffff999999000000000000cccccc
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffff666666000000333333ffffffffffff999999000000000000cccccc
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffff666666000000333333ffffffffffff999999000000000000cccccc
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333000000333333ffffffffffff999999000000000000ffffff
-ffffffffffff000000000000999999ffffffffffff333333000000333333ffffffffffff
-999999000000000000ffffffffffffffffff000000000000666666ffffffffffff333333
-000000333333ffffffffffff999999000000000000ffffffffffffffffff000000000000
-666666ffffffffffff333333000000333333ffffffffffff999999000000000000ffffff
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffff666666000000333333ffffffffffff999999000000000000cccccc
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffff666666000000333333ffffffffffff999999000000000000cccccc
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffff666666000000333333ffffffffffff999999000000000000cccccc
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffff666666000000333333ffffffffffff999999000000000000cccccc
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffff666666000000333333ffffffffffff999999000000000000cccccc
-ffffffffffff000000000000666666ffffffffffff666666000000333333ffffffffffff
-999999000000000000ccccccffffffffffff000000000000666666ffffffffffff666666
-000000333333ffffffffffff999999000000000000ccccccffffffffffff000000000000
-666666ffffffffffffffffff
-ffffffffffff999999333333ccccccffffffffffffcccccc333333999999ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333999999ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffcccccc333333999999ffffffffffffffffff333333666666ffffff
-ffffffffffff999999333333ccccccffffffffffffcccccc333333999999ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333666666ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffcccccc333333666666ffffffffffffffffff333333666666ffffff
-ffffffffffff999999333333ccccccffffffffffffcccccc333333666666ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333666666ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffcccccc333333666666ffffffffffffffffff333333666666ffffff
-ffffffffffff999999333333ccccccffffffffffffcccccc333333666666ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333666666ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333999999ffffffffffffffffff333333666666ffffff
-ffffffffffff666666333333ffffffffffffffffff999999333333999999ffffffffffff
-ffffff333333666666ffffffffffffffffff666666333333ffffffffffffffffff999999
-333333999999ffffffffffffffffff333333666666ffffffffffffffffff666666333333
-ffffffffffffffffff999999333333999999ffffffffffffffffff333333666666ffffff
-ffffffffffff666666333333ffffffffffffffffff999999333333999999ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ffffffffffffffffff999999
-333333999999ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ffffffffffffffffff999999333333999999ffffffffffffffffff333333666666ffffff
-ffffffffffff999999333333ffffffffffffffffff999999333333999999ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ffffffffffffffffff999999
-333333999999ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffcccccc333333999999ffffffffffffffffff333333666666ffffff
-ffffffffffff999999333333ccccccffffffffffffcccccc333333999999ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333999999ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffcccccc333333999999ffffffffffffffffff333333666666ffffff
-ffffffffffff999999333333ccccccffffffffffffcccccc333333999999ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333666666ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffcccccc333333666666ffffffffffffffffff333333666666ffffff
-ffffffffffff999999333333ccccccffffffffffffcccccc333333666666ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333666666ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffcccccc333333666666ffffffffffffffffff333333666666ffffff
-ffffffffffff999999333333ccccccffffffffffffcccccc333333666666ffffffffffff
-ffffff333333666666ffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333666666ffffffffffffffffff333333666666ffffffffffffffffff999999333333
-ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc333333333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc333333333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999cccccc666666999999666666999999666666333333
-333333333333333333333333333333333333333333333333333333999999666666999999
-666666999999999999ccccccccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffff000000ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffcccccc000000ffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff000000ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffff000000ffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999666666
-666666000000000000333333666666333333666666666666999999666666999999cccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccc666666999999666666
-999999666666666666333333333333000000333333333333999999999999cccccccccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000
-000000000000000000ffffffffffff000000000000ffffffffffffffffff000000ffffff
-000000000000ffffffffffffffffff000000000000000000000000ffffffffffff000000
-ffffffffffffffffff000000ffffff000000000000ffffffffffff000000000000ffffff
-ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000000000000000000000ffffffffffffffffff
-000000000000ffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
-ffffffffffffffffff000000ffffffffffffffffffffffff000000000000000000ffffff
-ffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff
-000000ffffff000000000000ffffffffffffffffffffffff000000ffffff000000000000
-ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffffffffff000000000000000000ffffffffffffffffffffffff000000000000000000
-ffffffffffffffffff000000000000000000000000ffffffffffff000000ffffffffffff
-ffffffffffff000000000000ffffffffffffffffffffffffffffff000000ffffff000000
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666666666333333000000000000333333666666999999
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccccccccc666666666666333333333333
-000000333333333333999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000000000000000
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000000000
-ffffffffffff000000000000000000ffffffffffff000000000000ffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
-ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff000000ffffff
-ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff000000
-000000000000ffffffffffff000000ffffffffffff000000000000000000ffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffff000000000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffff000000000000ffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffff000000000000000000ffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999666666333333333333999999999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccccccccc666666333333000000666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000
-ffffffffffffffffff000000000000000000000000000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666000000333333
-666666999999ccccccffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff999999666666000000333333666666999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffcccccc000000
-ffffffffffffffffff000000ffffffffffffcccccc000000ffffffffffffffffff000000
-ffffffffffffcccccc000000ffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffffcccccc000000ffffffffffff000000ffffffffffffffffffcccccc000000
-ffffffffffffffffff000000ffffffffffffccccccffffff000000000000ffffffffffff
-ffffffffffffccccccffffffffffffffffff000000000000ffffff000000ccccccffffff
-000000ffffffffffffffffffffffff000000ccccccffffff000000ffffffffffffffffff
-ffffff000000ccccccffffffffffff000000ffffffffffffffffff000000ccccccffffff
-ffffff000000ffffffffffffffffffffffffccccccffffffffffff000000000000ffffff
-000000ffffffccccccffffff000000ffffffffffffffffffffffff000000ccccccffffff
-000000ffffffffffffffffffffffff000000ccccccffffffffffff000000ffffffffffff
-ffffff000000ccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999666666000000666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999666666
-000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666000000666666999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666333333333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffff000000000000000000ffffffffffff000000ffffff
-ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000ffffff000000ffffffffffff000000
-ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff000000ffffff
-ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff
-ffffffffffffffffffffffffffffff000000ffffffffffff000000000000ffffffffffff
-000000000000ffffffffffff000000ffffffffffffffffff000000000000ffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000
-000000ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333333333999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
-ffffffffffffffffff000000000000ffffff000000ffffffffffff000000000000000000
-ffffff000000000000000000ffffffffffff000000000000ffffffffffff000000000000
-000000ffffff000000000000000000ffffff000000000000000000ffffff000000000000
-000000ffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
-000000000000ffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
-ffffffffffff000000000000000000ffffffffffff000000000000000000ffffffffffff
-ffffffffffffffffffffffffffffff000000000000000000ffffff000000000000ffffff
-000000ffffff000000000000ffffffffffffffffffffffff000000ffffff000000000000
-ffffffffffffffffffffffff000000000000000000ffffff000000000000000000ffffff
-ffffffffffff000000000000000000ffffffffffffffffff000000000000000000ffffff
-000000000000ffffffffffff000000000000ffffffffffff000000000000000000ffffff
-ffffffffffff000000000000ffffffffffffffffffffffff000000000000000000ffffff
-000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333
-666666ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffcccccc666666000000999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000ffffffccccccffffffffffffffffffffffffffffff000000ffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc333333333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999333333666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
-000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000ffffffffffffffffffffffffffffff000000000000000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333ccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff999999333333666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333ccccccffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffcccccc
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccccccccccccccc
-ffffffffffffffffffcccccc999999ccccccffffffffffffffffffcccccccccccccccccc
-ccccccccccccccccccccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff
-ffffff999999333333333333333333000000000000000000000000000000000000333333
-ffffffffffffffffffffffff000000ccccccffffffffffffffffff333333000000000000
-000000000000000000000000000000000000000000333333ffffffffffffffffffffffff
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999ffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-cccccc999999999999333333ffffffffffffffffffcccccc000000ccccccffffffffffff
-ffffff666666666666666666999999666666cccccc999999ccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccccccccccccccccccccc999999ffffffffffffffffffcccccc
-000000ccccccffffffffffffffffff666666666666666666ccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666666666333333333333000000000000
-000000000000333333666666ffffffffffffffffffffffff999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333333333000000000000000000333333
-666666999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999999999ffffffffffffffffff666666333333333333666666666666cccccccccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999666666
-666666000000000000666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc999999666666333333ccccccffffffffffffffffff
-333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffff999999333333ffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000ffffff
-000000000000ffffff000000000000000000ffffff000000000000000000ffffff000000
-000000000000ffffffffffffffffffffffff000000000000000000000000ffffffffffff
-000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999666666333333000000000000000000333333333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffccccccccccccffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333ffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffffffffffffffffffffff000000000000
-ffffffffffff000000ffffff000000ffffffccccccffffff000000ffffffffffffffffff
-ffffff000000ccccccffffffffffff000000ffffffffffffffffffffffffcccccc000000
-ffffffffffffffffff000000ffffffffffffccccccffffffffffffffffffffffffffffff
-000000ffffffccccccffffff000000ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000000000
-000000333333000000999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000333333666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffff
-ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffff000000000000000000ffffffffffff000000
-ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666333333ffffffffffffffffffcccccccccccccccccc
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666333333000000333333666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffff000000
-ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333ffffffffffffffffffcccccc999999666666333333000000
-666666ffffffffffffffffff999999ccccccffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666333333000000333333999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000000000000000000000000000ffffff000000000000000000
-ffffff000000000000000000ffffff000000000000ffffffffffffffffffffffff000000
-000000000000000000000000ffffff000000000000000000000000ffffffffffffffffff
-000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999333333999999333333333333000000000000333333666666999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffcccccc333333666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666ffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff000000000000000000666666666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000000000000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffccccccccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333000000333333ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666000000333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999333333000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999ffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333999999
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff333333999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333666666ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999333333333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666333333999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333666666666666000000000000000000666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333000000666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666333333ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666333333
-ccccccffffffcccccc000000000000000000000000000000666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc000000333333999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333333333
-999999ffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffff999999333333333333999999ffffff
-ffffffffffffffffff000000000000000000000000000000000000666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff333333000000666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-666666000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333666666ccccccffffffffffffffffff
-ffffffffffffffffff666666000000000000000000000000666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666333333333333999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666000000666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffff999999000000000000000000000000ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666333333333333999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-666666000000666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc000000000000999999333333333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccccccccc666666333333000000666666
-999999ffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffcccccc999999666666333333000000666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ccccccffffffffffff333333333333ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666000000333333666666ccccccccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999333333333333666666999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999333333333333000000333333333333999999999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999cccccc666666666666
-333333000000000000666666666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999cccccc666666666666333333
-000000333333666666666666999999666666ccccccccccccccccccccccccccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccccccccc
-cccccc999999999999666666999999333333333333000000666666333333999999999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999999999666666999999333333333333333333333333333333000000
-000000000000000000000000000000000000000000000000000000333333333333333333
-333333666666666666666666666666ccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000000000999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666000000666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333666666
-cccccc000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666333333ffffffffffff
-999999000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333000000
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666333333999999ffffffffffffffffff
-333333000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000999999ffffffffffffffffffffffffcccccc
-333333000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff333333999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999333333666666ffffffffffffffffffffffffffffffffffff999999
-666666000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666ccccccffffffffffffffffffffffffffffffffffffffffff333333
-cccccc000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999000000666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333cccccc
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333ffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666333333999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333000000
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333ccccccffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999333333333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333ffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999000000999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333ccccccffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333000000999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666000000666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333ccccccffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffccccccccccccffffffffffffffffff666666999999666666333333
-333333333333333333333333999999ffffffcccccc333333666666999999666666999999
-666666999999666666ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666ffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999999999666666
-666666333333000000000000666666ffffffffffffffffff999999666666999999cccccc
-ccccccccccccccccccccccccffffffffffffffffffcccccc999999666666999999666666
-999999666666999999666666ffffffffffffffffff333333666666666666cccccccccccc
-ffffffffffffffffffffffffffffffffffff999999666666ffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666ffffffffffffffffff333333666666999999
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666999999333333333333
-000000333333666666ffffffffffffffffff333333ccccccffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-cccccc666666333333000000666666999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffff999999000000999999ffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333333333
-333333999999ccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff999999333333666666000000333333333333cccccc
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc999999999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333ccccccffffffffffffcccccc999999333333
-333333000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000
-666666ccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999333333333333666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffff
-cccccc000000ffffffffffff999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-000000000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffff666666000000666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc000000666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000999999ccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffff333333ccccccccccccffffffffffffffffffffffffffffff
-ffffff000000ccccccffffffffffffffffff666666333333333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc000000666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc000000333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffff999999000000666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc000000666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc000000333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc000000ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999333333999999ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff000000000000000000000000
-000000ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-000000000000ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffccccccffffff
-ffffff000000ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffcccccc000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffcccccc666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-000000000000ffffff000000ffffffffffff000000000000000000ffffffffffffffffff
-000000000000ffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
-000000ffffffffffff000000000000000000ffffffffffff000000000000000000000000
-ffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ccccccffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffff000000ffffffffffff
-ffffff000000000000ffffffffffff000000ffffffffffff000000ffffffcccccc000000
-ffffff000000ffffffffffff000000ffffff000000ccccccccccccffffffffffffffffff
-000000999999000000333333333333000000333333000000ffffffffffff333333333333
-666666666666333333999999666666999999666666ccccccffffffffffffffffffffffff
-ffffff000000ccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff000000999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffcccccc
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffff
-ffffff999999999999000000333333000000000000000000666666ffffffffffffffffff
-999999666666999999ccccccccccccccccccccccccccccccffffffffffffffffffcccccc
-999999666666999999666666999999666666999999666666ffffffffffffffffff333333
-666666000000ccccccccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffff999999
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffff000000999999666666666666ffffff
-ffffff333333666666999999999999ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-666666000000333333333333000000333333666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
-000000ffffffffffffcccccc000000000000333333000000666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffccccccccccccffffffffffffcccccc666666999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff333333999999
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff333333333333333333999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffff000000ffffffffffffffffffffffffccccccffffffffffffffffff999999666666
-000000333333333333ccccccffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666000000666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffff333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999333333333333999999ffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999000000666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffcccccc333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999333333333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffccccccccccccffffffffffff999999666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333333333ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffff000000999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffff000000ccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff666666333333
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000666666ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffff333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333333333
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffff666666333333ffffffffffffffffffffffffffffffffffffffffff333333999999
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffff999999333333999999ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000000000000000000000000000ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffff000000000000ffffffffffffffffffffffffccccccffffff
-ffffff333333ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffcccccc000000999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc000000333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffff000000000000ffffff000000ffffffffffff000000000000
-000000ffffffffffffffffff000000000000ffffffffffffffffff000000000000ffffff
-ffffffffffffffffffffffff000000ffffffffffff000000000000000000ffffffffffff
-000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-333333333333ccccccffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffccccccffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffff000000ffffffffffffffffff000000000000ffffffffffff000000ffffffffffff
-000000ffffffcccccc000000ffffff000000ffffffffffff000000ffffff000000cccccc
-ccccccffffffffffffffffff000000999999000000333333333333000000333333000000
-ffffffffffff333333333333666666999999666666999999666666999999666666cccccc
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff000000999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333000000ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-000000ffffff000000ffffffffffff999999999999000000333333000000000000000000
-666666ffffffffffffffffff999999666666999999cccccccccccccccccccccccccccccc
-ffffffffffffffffffcccccc999999666666999999666666999999666666999999666666
-ffffffffffffffffff333333666666666666ccccccccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999000000999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666000000ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
-999999666666666666ffffffffffff333333666666999999999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666999999333333333333000000333333666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999000000666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666000000ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000ffffffffffff000000ffffffffffffcccccc000000000000333333000000
-666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccccccccffffff
-ffffffcccccc666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666333333ccccccffffffffffffffffffccccccffffff
-ffffffffffff333333999999ffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffff333333333333333333999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff999999666666000000333333333333ccccccffffffffffffffffffffffff
-999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333999999ffffffffffffffffffffffff
-ffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc999999333333333333999999ffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333333333ccccccffffffffffff
-ffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-333333333333666666ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffccccccccccccffffffffffff
-999999666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000666666cccccc
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666000000666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666cccccc
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff000000999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff666666333333333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999000000999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666000000666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc333333333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffff666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333999999ffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-999999333333999999ffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffff000000000000000000000000000000ffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffff000000000000ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffcccccc000000999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333000000
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffff000000ffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffff000000000000ffffff000000
-ffffffffffff000000000000000000ffffffffffffffffff000000000000ffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffff000000ffffffffffff000000
-000000000000ffffffffffff000000000000000000000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff333333333333ccccccffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffccccccffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffffffffffffffff000000000000ffffff
-ffffff000000ffffffffffff000000ffffffcccccc000000ffffff000000ffffffffffff
-000000ffffff000000ffffffffffffffffffffffffffffff000000ffffff000000ffffff
-ffffff000000ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-000000ffffffffffffffffff000000ffffff000000ffffffffffffffffffffffff000000
-000000000000ffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
-ffffff000000ffffff000000000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
-000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff000000
-ffffffffffff000000ffffffffffffffffffffffff000000ffffff000000ffffffffffff
-000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000000000000000ffffffffffff000000ffffffffffffffffff
-000000000000000000000000000000ffffff000000000000000000ffffffffffff000000
-000000000000ffffffffffffffffffffffffffffff000000000000000000000000000000
-ffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666333333ccccccffffff
-ffffffffffffccccccffffffffffffffffff333333999999ffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666000000000000999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333999999
-ffffffffffffffffffffffffffffffffffff333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-333333ccccccffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666333333000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000666666ccccccffffff999999666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999333333000000333333ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666ccccccffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff999999666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666ffffffffffffffffffcccccc999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333ccccccffffffcccccc333333333333
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000000000ffffff000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000000000000000
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333000000000000000000
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffff666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff333333999999ffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff000000ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999000000000000666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc000000000000000000000000000000
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000000000ffffffffffffffffff000000000000000000
-ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000000000ffffff
-ffffff000000000000ffffff000000000000000000ffffffffffff000000000000000000
-ffffff000000000000ffffff000000ffffff000000000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333000000000000
-666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333000000000000000000000000000000
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000
-ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff000000ffffff
-000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff000000
-ffffffffffff000000000000ffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffccccccccccccffffffffffffffffff999999666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-000000000000000000999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999333333000000000000000000
-000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff000000
-ffffffffffff000000ffffffffffff000000ffffff000000000000000000ffffff000000
-ffffffffffffffffffffffffffffff000000ffffff000000ffffffffffffffffff000000
-ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333999999999999666666000000000000000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000333333ffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999333333
-000000666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333333333ccccccffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff
-ffffff000000ffffffffffff000000ffffffcccccc000000ffffffffffff000000000000
-ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffff
-ffffff000000ffffffffffffffffff000000cccccc000000ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff000000000000000000000000000000000000000000000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffccccccffffffffffffffffffcccccc999999ffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999cccccc999999999999666666999999666666999999333333333333
-333333000000333333333333333333333333333333333333666666999999666666999999
-666666cccccc999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000000000000000ffffffffffff000000000000000000ffffffffffff
-ffffff000000000000ffffff000000000000ffffff000000000000000000ffffff000000
-000000000000ffffffffffff000000000000ffffff000000000000000000ffffffffffff
-ffffff000000ffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333333333000000000000000000000000000000000000666666666666
-ccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccccccccc999999999999333333
-333333000000666666333333666666666666999999666666999999666666cccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccc999999666666999999666666
-666666333333666666333333000000000000666666666666999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666333333ccccccffffff666666000000000000000000000000333333333333333333
-000000000000000000333333333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc333333999999999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999333333333333000000333333333333666666666666cccccc
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc999999999999666666333333000000000000
-333333666666666666ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333000000999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-333333ffffffffffffffffffffffffcccccc333333000000000000666666ffffffffffff
-ffffffcccccc999999666666999999ffffffffffffffffffcccccc333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666000000000000000000666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666000000333333666666ccccccccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999999999333333333333666666999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffff
-666666333333ccccccffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffcccccc333333
-ccccccffffffffffffffffffffffffffffffcccccc666666000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999ffffffffffff
-ffffffffffff000000333333333333999999999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccccccccc999999333333000000000000333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999666666333333000000666666
-999999ffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffcccccc999999333333333333000000666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000333333ffffff
-ffffff999999333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666666666333333000000000000000000000000666666666666
-ccccccccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffff999999666666333333000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999333333333333666666999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666000000
-666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999999999666666999999666666666666999999ffffffffffffcccccc333333
-666666333333999999666666999999666666ccccccccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000666666ffffff
-ffffffffffffcccccc333333333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc666666666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999999999333333333333
-666666000000000000cccccc999999999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-ffffffffffffffffffffffff333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666333333333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999666666000000666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccccccccc999999ffffffffffff999999
-000000666666666666999999666666999999999999ffffffffffffffffffcccccccccccc
-999999cccccc666666999999666666999999333333333333666666ffffffffffffcccccc
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000ccccccffffff
-ffffffffffffffffffffffff999999000000666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666333333666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc999999666666ffffffffffffffffffcccccc666666666666
-ccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666ffffffffffffffffffffffff999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666333333999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666000000333333333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666333333333333333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ccccccffffff
-ffffffffffffffffffffffffffffffffffff666666ccccccffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffcccccc666666000000666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffcccccc333333333333
-000000000000000000333333666666999999999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333000000000000
-333333999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999000000666666
-ccccccffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffff333333333333666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666000000666666999999ffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999333333000000333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccccccccc666666666666000000000000000000ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666000000000000000000333333666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffff
-ffffff999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999000000666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333
-000000666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccccccccffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccccccccccccccffffffffffffffffff
-000000999999ffffffffffffffffffccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999666666333333000000ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333333333ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666000000000000999999ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333333333ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffff666666000000000000666666666666cccccccccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-666666333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000666666666666999999ffffffffffffccccccffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffcccccccccccc
-333333333333ccccccffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffcccccc999999666666333333000000666666ccccccffffffffffffffffff
-ffffffffffff333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999999999666666333333000000000000
-000000333333666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-ccccccffffffffffffffffff666666333333333333999999999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666333333ccccccffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffcccccc000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc000000333333999999ffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffcccccc333333000000999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000333333ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-000000000000999999ffffffffffffffffffffffffffffff999999000000333333666666
-ccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666000000
-000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-ffffffffffffffffff333333999999ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffff666666000000333333999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999666666666666333333ffffffffffffffffffffffff999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666666666000000000000000000333333666666
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999000000666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000
-000000999999ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-333333333333000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333000000000000333333
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccccccccc999999999999333333333333000000666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333000000333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000ffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999666666333333
-000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666000000ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000000000
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999ffffffffffffffffff333333000000333333666666666666
-999999ccccccccccccffffffffffffcccccc666666000000000000000000999999cccccc
-ffffffffffffffffffffffffffffffffffffcccccccccccccccccccccccccccccc666666
-999999ffffffffffffffffff333333333333666666666666ccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666000000666666ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333000000000000333333333333999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffcccccc000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000000000ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000000000999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999999999
-666666333333333333999999333333000000000000000000000000000000000000000000
-000000000000ccccccffffffffffff333333000000333333333333333333333333999999
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333000000333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccccccccc666666666666000000000000000000333333333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccccccccffffffffffffffffffffffff
-000000000000333333666666999999ccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333ffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffcccccc666666999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333666666
-ccccccffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffff666666666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000000000000000999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccccccccc666666666666999999
-ffffffffffffffffffccccccccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999999999333333333333000000000000333333666666666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999000000000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333000000000000333333666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333ffffffffffffffffffccccccccccccccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc999999999999333333333333666666ffffff
-ffffffffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333000000999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000000000999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666000000
-000000000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000000000000000
-666666999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666ffffffffffffffffffcccccc666666666666999999999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffff000000ffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000000000666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333000000000000000000
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-333333000000000000000000333333999999999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333333333000000000000
-000000000000333333666666666666ccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000ccccccffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffcccccc333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999333333ccccccffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffff000000ffffff000000000000ffffff
-ffffff000000ffffff000000000000000000cccccc000000000000000000ffffffffffff
-000000000000cccccc000000000000000000ffffffffffff000000000000000000ffffff
-000000000000ffffff000000000000000000000000ffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc000000333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc000000000000999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666000000000000000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999666666000000333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-cccccc999999666666333333333333000000ccccccffffffffffffffffffcccccccccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000000000000000000000ffffffffffff000000ffffff
-ffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff
-000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
-ffffff000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666000000666666ffffffffffffffffffffffffffffff
-ffffffffffff999999000000000000999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333000000000000333333666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000333333999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffcccccc000000
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff333333999999
-ffffffffffffffffffcccccc666666999999999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
-ffffff000000ffffffffffff000000000000ffffffffffffffffff000000ffffffffffff
-ffffff000000ffffffffffff000000ffffff000000ffffffffffffffffff000000ffffff
-ffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666000000ccccccffffffffffffffffffffffffffffff
-ffffffcccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000000000000000999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-ffffffffffffffffffffffff666666666666ccccccccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666000000000000000000333333333333666666999999
-ccccccccccccffffffffffff666666999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff
-000000ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000
-ffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000000000ccccccffffffffffffffffffffffffffffff
-999999000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333000000000000000000666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-000000333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666333333000000000000000000666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccccccccc666666666666333333000000
-000000000000cccccccccccc333333ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffff666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff000000000000000000ffffff000000000000000000000000000000000000
-000000000000cccccc000000000000000000000000000000ffffffffffffcccccc000000
-000000ffffffffffff000000000000ffffff000000000000000000000000000000ffffff
-000000ffffffccccccffffff000000000000ffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc000000333333ffffffffffffffffffffffffffffffcccccc
-000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666000000
-000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999333333000000000000
-333333000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffff666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999000000666666ffffffffffffffffffffffff999999000000
-000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333000000000000333333
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999333333000000999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-333333000000000000ccccccffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333000000999999ffffffffffffffffff999999000000000000
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666000000000000000000999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffff666666666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333333333666666000000000000999999ffffffffffff999999000000000000666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333000000000000000000666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccccccccffffffffffffffffff999999
-666666999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999333333ffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000000000000000000000666666999999000000000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffff
-ffffffcccccc666666000000000000000000999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333000000000000333333999999999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000000000000000000000000000000000000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffff999999333333ccccccffffffffffffcccccc
-333333000000000000333333666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666000000000000000000666666999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000000000000000000000000000000000666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000000000999999cccccc666666000000
-000000000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc999999333333000000333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
-000000ffffffffffffffffff000000000000ffffff000000000000ffffff000000000000
-000000ffffff000000000000000000ffffff000000000000000000ffffffffffffffffff
-ffffff000000000000000000000000ffffffffffff000000000000000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000000000ffffff000000000000
-ffffff000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffccccccccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000000000000000000000000000000000000000ccccccffffffffffff
-ffffffffffffffffffffffffcccccc333333000000000000000000000000000000000000
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666000000000000999999ffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666ffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-000000ffffffffffffffffffffffff000000000000ffffffffffff000000ffffff000000
-ffffffffffffcccccc000000ffffffffffffffffffffffff000000ffffffccccccffffff
-000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff000000000000ccccccffffff
-ffffffffffff000000ffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffcccccc000000ffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333000000000000000000000000000000000000000000000000ccccccffffff
-ffffffffffffffffffffffff666666000000000000000000000000000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666000000333333999999ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff000000
-ffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffff000000000000000000ffffffffffff000000ffffffffffffffffff000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000000000000000000000000000333333666666ccccccffffffffffff
-ffffffffffffffffff999999000000000000000000000000000000333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666000000000000999999ffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999000000333333999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-000000ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffff000000ffffff000000ffffffffffffffffff000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000000000ffffff000000000000ffffff000000000000
-ffffff000000000000ffffff000000000000000000000000000000ffffffffffffffffff
-000000000000000000000000000000000000ffffffffffff000000000000000000ffffff
-000000000000ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc000000000000333333999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc000000000000000000000000000000000000000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666000000333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666000000000000333333
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
-000000000000000000ffffff000000000000000000ffffff000000000000000000ffffff
-000000000000ffffffffffffffffffffffff000000000000000000000000000000ffffff
-000000000000000000000000ffffffffffffffffff000000000000000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000ffffff
-ffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffff000000000000ffffff000000
-ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff000000
-ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccccccccc999999999999666666999999666666333333333333333333333333333333
-333333333333000000333333333333333333333333333333333333333333333333666666
-666666999999333333666666666666666666666666666666666666999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-000000000000000000666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333ffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffff666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333999999ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffff000000ffffffffffff000000ffffffcccccc000000
-ffffffffffff000000ffffffffffff000000ccccccffffff000000ffffff000000ffffff
-ffffffffffff000000ffffff000000ffffff000000ffffffffffffffffff000000ffffff
-ffffff000000ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffcccccc000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999999999333333333333000000
-333333333333666666666666999999666666999999cccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc666666
-999999666666666666333333666666000000000000000000666666666666999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999333333333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
-ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
-ffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666333333000000333333666666666666ccccccccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999999999666666333333
-000000333333666666ccccccccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffccccccffffffffffffffffff999999999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000000000ffffff000000ffffffffffff000000000000
-ffffff000000000000ffffff000000000000ffffff000000000000ffffff000000000000
-000000000000000000000000000000ffffff000000000000000000ffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-666666000000666666999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999666666333333666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333333333
-999999ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff999999333333666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffff333333333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffcccccc333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333ccccccffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff999999333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666000000666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000000000333333999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333000000
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000000000333333999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffff999999000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffcccccc
-666666000000333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666000000000000333333
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666333333ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-cccccc666666333333ffffffffffffffffffffffffffffff666666666666000000666666
-ccccccffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffcccccc666666333333666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc333333000000333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffff999999666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666333333999999ffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffcccccc000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff999999
-333333333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666000000999999ffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999333333666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffcccccc666666333333000000666666666666ccccccccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999999999
-333333000000333333666666999999ffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999ffffffffffffffffffccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666000000999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999333333333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffff999999999999333333333333000000333333333333
-666666666666999999999999ccccccccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-cccccccccccccccccc666666999999333333666666333333000000333333666666666666
-ccccccffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc
-999999999999666666666666333333333333333333000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000333333
-333333333333333333999999666666cccccc999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999000000000000
-000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333666666ccccccffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-666666000000000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666000000666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000000000999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666000000333333999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-333333000000333333999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000666666999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999000000333333999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333666666ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666ffffffffffffffffff999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-ccccccffffffffffffcccccc666666999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666000000000000999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333000000999999
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff999999333333333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333000000000000333333
-666666999999999999ffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffcccccc999999999999333333333333000000333333
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999000000666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999666666666666ffffffffffffffffff000000000000000000000000000000000000
-000000000000ffffffffffffffffff333333666666666666ccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666000000666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999333333333333666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffff999999ccccccffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333000000333333999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666000000666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999333333
-333333666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333000000ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333000000000000666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999666666000000333333333333999999
-ccccccffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff999999666666000000333333666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666000000000000000000000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999000000000000333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc666666
-333333333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccccccccc666666333333000000666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000000000000000000000000000333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666000000333333999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666666666000000000000333333666666666666ccccccccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999999999333333333333
-000000333333333333999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666000000000000000000000000000000999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333000000
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999999999333333333333000000
-333333333333999999666666999999999999cccccc999999ccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccccccccc999999
-cccccc666666999999666666666666333333000000333333666666666666cccccccccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666000000000000000000000000ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-cccccc666666333333ffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-000000000000666666ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccccccccc666666999999666666666666333333333333333333333333000000000000
-000000000000000000000000000000000000000000000000333333333333333333333333
-333333999999666666999999999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000000000000000000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999333333000000666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-333333000000000000ffffffcccccc666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999999999000000999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666333333666666cccccc
-ffffff000000000000ffffffffffff999999000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-000000000000666666ffffffffffffcccccc999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-000000333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666000000999999ccccccffffffffffff
-ffffff000000000000ffffffffffffffffffffffff999999333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffff666666999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666000000000000666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999333333333333999999ffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffff999999000000666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333000000666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333000000333333
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000333333666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333000000000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666333333000000666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333000000333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffccccccffffff666666999999ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff666666999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333000000333333999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666333333666666ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666000000000000ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666000000333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666000000999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666000000000000ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000333333999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999333333333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000000000ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffff999999ccccccffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666000000000000999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-333333666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999000000000000999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffccccccffffffffffffffffffffffffffffff666666999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999000000000000333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666000000999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999000000000000999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333000000
-666666ccccccffffffffffffffffffffffffcccccc333333333333999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc333333000000999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666333333000000666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333666666ffffffffffff666666333333666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-000000000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000999999999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333000000666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-cccccc666666333333ffffffffffffffffffffffffffffff666666333333999999ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffff999999000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999000000000000333333999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-333333333333999999ffffffffffff333333333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffff666666333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666ffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc666666000000999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999ccccccffffffffffffffffffffffffffffff999999666666333333666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc999999333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666ffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333333333999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffcccccc999999
-000000666666999999ccccccffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffcccccc999999333333333333666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666000000333333666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666333333666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666000000333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999000000000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666333333333333333333999999999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc666666
-666666000000333333666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666333333000000666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-666666000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666000000000000999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc000000000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc999999666666666666333333000000333333333333
-333333999999666666cccccc999999cccccc999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999cccccc999999999999666666666666333333333333000000333333333333999999
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333000000000000666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999333333333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666000000333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000000000999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-cccccc666666999999333333666666333333666666000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000333333
-666666333333666666666666999999999999ccccccccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffcccccccccccc333333000000000000
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666333333666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc000000000000666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffcccccc999999
-666666ffffffffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666000000999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc000000000000666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333333333999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333000000333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffccccccccccccffffffffffffffffffcccccc999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666333333666666ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000000000333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000000000
-333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666000000
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000333333999999ffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333000000333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-333333000000000000333333666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999333333333333999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666000000000000999999ccccccffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666333333000000333333666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666333333666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000333333666666
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666666666ffffffffffffffffffffffff
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666000000999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333
-000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000
-000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000000000
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ccccccffffffffffffffffffcccccc666666666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333
-666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000000000999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666333333000000333333666666999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666000000999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffff666666333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666666666000000000000
-000000666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999cccccc999999999999666666999999666666999999666666333333333333333333
-333333333333333333333333333333333333000000333333333333999999666666999999
-999999cccccc999999ccccccccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffccccccffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000666666
-ccccccffffffffffffffffffffffffffffffcccccc000000000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999333333000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc999999666666666666333333000000000000
-333333333333333333333333666666666666666666666666999999999999999999999999
-999999999999999999333333333333333333999999666666666666666666666666666666
-666666333333333333333333333333000000333333333333999999999999cccccccccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffff666666333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333666666ffffffffffffffffffcccccc333333000000666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffcccccc000000999999ffffffcccccc999999
-666666666666333333000000000000333333333333666666666666999999999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999999999000000666666999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc666666999999666666666666333333000000
-000000333333333333999999999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffcccccc666666
-000000333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999cccccc
-999999666666000000666666999999333333000000333333333333333333333333333333
-333333ccccccffffffffffff999999999999666666999999666666999999999999cccccc
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666666666333333333333333333
-666666666666999999cccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccc999999999999666666666666000000333333666666ccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666000000333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccccccccffffffffffff999999000000000000333333666666333333
-666666666666cccccc999999333333666666cccccccccccccccccccccccccccccccccccc
-ccccccccccccffffffffffffcccccc666666999999666666999999666666666666333333
-666666000000333333333333999999ffffffffffffccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999666666333333000000333333666666999999999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999666666333333000000000000666666
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666000000333333999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999999999666666333333
-000000000000333333999999ffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccccccccccccccffffffffffff999999000000000000333333666666
-666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999333333333333333333999999999999cccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc999999666666
-666666000000333333666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666000000000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffccccccffffffffffffffffff999999666666666666cccccc999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-999999333333000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999000000333333
-666666999999999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999666666000000333333666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999666666000000000000666666ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff333333333333666666999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333333333666666cccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccc999999666666333333333333999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333000000
-666666666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999333333333333333333
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666000000333333999999999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999666666000000666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffccccccffffffffffffcccccc666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffff999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000999999999999cccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc666666
-333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffccccccccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333333333666666cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999999999000000666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff333333000000333333ccccccffffffffffffffffffffffff
-cccccc666666000000333333999999ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffcccccc333333000000666666ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333
-999999cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccc666666333333666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999666666000000666666ccccccffffff666666
-333333666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999000000666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc666666666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333666666cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999666666000000999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333000000333333666666
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-cccccc000000000000999999ffffff999999666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffff999999999999ffffffffffffffffff999999666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffff999999999999ffffffffffff
-ffffff999999666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-999999999999ffffffffffffffffff999999666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffff999999999999ffffffffffffffffff999999666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffff999999999999ffffffffffff
-ffffff999999666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-999999999999ffffffffffffffffff999999666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffff999999999999ffffffffffffffffff999999666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffff999999999999ffffffffffff
-ffffff999999666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-999999999999ffffffffffffffffff999999666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffff999999999999ffffffffffffffffff999999666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffff999999666666ffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333666666999999cccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccc333333333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666ffffffcccccc666666000000
-333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-cccccc666666333333ffffffcccccc000000000000666666ffffffffffff333333000000
-000000ffffffffffffcccccc000000000000ccccccffffffcccccc000000000000666666
-ffffffffffff333333000000000000ffffffffffffcccccc000000000000ccccccffffff
-cccccc000000000000666666ffffffffffff333333000000000000ffffffffffffcccccc
-000000000000999999ffffffcccccc000000000000666666ffffffffffff333333000000
-000000ffffffffffffcccccc000000000000999999ffffffcccccc000000000000666666
-ffffffffffff333333000000000000ffffffffffffcccccc000000000000999999ffffff
-cccccc000000000000666666ffffffffffff333333000000000000ffffffffffffcccccc
-000000000000999999ffffffffffff333333000000666666ffffffffffff333333000000
-000000ffffffffffffcccccc000000000000999999ffffffffffff333333000000666666
-ffffffffffff333333000000000000ffffffffffffcccccc000000000000999999ffffff
-ffffff333333000000666666ffffffffffff333333000000000000ffffffffffffcccccc
-000000000000999999ffffffffffff333333000000666666ffffffffffff333333000000
-000000ffffffffffffcccccc000000000000999999ffffffffffff333333000000666666
-ffffffffffff333333000000000000ffffffffffffcccccc000000000000999999ffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000999999999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999333333999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999000000666666ccccccffffffcccccccccccc
-666666000000ccccccffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff999999333333666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffff666666333333ccccccffffffffffffcccccc333333
-999999ffffffffffffffffff333333333333ffffffffffffffffff666666333333cccccc
-ffffffffffffcccccc333333999999ffffffffffffffffff333333333333ffffffffffff
-ffffff666666333333ccccccffffffffffffcccccc333333999999ffffffffffffffffff
-333333333333ffffffffffffffffff666666333333ccccccffffffffffffcccccc333333
-999999ffffffffffffffffff333333333333ffffffffffffffffff666666333333cccccc
-ffffffffffffcccccc333333999999ffffffffffffffffff333333333333ffffffffffff
-ffffff666666333333ccccccffffffffffffcccccc333333999999ffffffffffffffffff
-666666333333ffffffffffffffffff666666333333ccccccffffffffffffcccccc333333
-999999ffffffffffffffffff666666333333ffffffffffffffffff666666333333cccccc
-ffffffffffffcccccc333333999999ffffffffffffffffff666666333333ffffffffffff
-ffffff666666333333ccccccffffffffffffcccccc333333999999ffffffffffffffffff
-666666333333ffffffffffffffffff666666333333ccccccffffffffffffcccccc333333
-999999ffffffffffffffffff666666333333ffffffffffffffffff666666333333cccccc
-ffffffffffffcccccc333333999999ffffffffffffffffff666666333333ffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666333333cccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccc999999666666666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc666666333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666666666cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999666666
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333999999cccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-999999333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff333333666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999999999333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff666666999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666999999cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccc999999333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-666666cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999666666333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccc666666999999ffffffffffffffffff666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffccccccccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999333333ccccccffffffcccccc333333999999ffffff
-ffffffffffff666666666666666666ccccccccccccffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffff666666000000999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-666666333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999cccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccc666666999999ffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333333333000000000000000000333333333333999999999999
-cccccc000000000000ffffffffffffffffff999999000000000000666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999333333ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc000000ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccccccccc666666666666333333000000
-000000000000000000ffffffcccccc999999333333000000000000000000333333cccccc
-ffffffffffffffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666cccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccc666666666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffcccccc000000000000000000000000000000000000000000
-999999ffffffffffffffffffffffffffffff666666666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000999999999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffff000000000000000000000000000000000000
-000000999999ffffffffffffffffffffffff666666ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffcccccc333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333cccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccc333333ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffcccccc000000000000000000000000666666999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999333333999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffff999999000000666666999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666cccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccc000000cccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccc000000cccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccc333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000ffffffccccccffffff000000ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-000000ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffff000000
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666666666cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc000000cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999000000
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999666666666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000000000000000000000000000ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffff000000000000ffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffff000000000000
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffcccccc000000
-000000ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffff666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000000000000000ffffff000000ffffff000000000000
-000000ffffffffffffffffff000000000000000000ffffff000000000000ffffffffffff
-ffffff000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff
-000000ffffff000000000000ffffff000000000000ffffff000000000000ffffff000000
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666cccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccc000000000000000000cccccccccccccccccc
-000000000000cccccc000000000000cccccc000000000000000000cccccc000000000000
-000000cccccc000000000000000000cccccccccccccccccccccccc000000000000000000
-000000cccccccccccc000000000000000000cccccccccccccccccccccccccccccccccccc
-cccccccccccccccccc000000000000cccccc000000000000cccccc000000000000000000
-000000000000cccccccccccccccccccccccccccccccccccccccccc000000000000000000
-cccccc000000cccccccccccccccccccccccc000000000000000000cccccc000000000000
-000000000000000000cccccccccccccccccccccccc000000000000000000cccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccc333333999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000000000ffffffffffff000000000000ffffff000000ffffffffffff
-ffffff000000ffffff000000ffffffffffff000000000000ffffffffffff000000ffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffff000000ffffffffffff000000000000ffffff000000ffffff000000
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc000000cccccc999999cccccc
-999999000000000000cccccc999999000000999999000000999999cccccc999999000000
-999999cccccc999999cccccc000000cccccc999999cccccc000000cccccc999999cccccc
-999999cccccc000000cccccc999999cccccc000000cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc000000000000999999cccccc999999cccccc000000cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc000000cccccc
-000000cccccc000000cccccc999999000000999999cccccc999999000000999999000000
-999999cccccc999999cccccc999999cccccc000000cccccc999999cccccc000000cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999333333999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffff000000ffffff000000ffffffffffffffffff000000000000000000000000ffffff
-ffffff000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff
-000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff000000
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333cccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccc000000cccccccccccccccccc
-cccccc000000cccccccccccccccccc000000cccccc000000cccccccccccc000000cccccc
-cccccccccccccccccccccccc000000cccccccccccccccccccccccc000000000000000000
-cccccccccccc000000cccccccccccccccccc000000cccccccccccccccccccccccccccccc
-cccccccccccccccccccccccc000000cccccccccccccccccccccccccccccc000000cccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc000000cccccc
-000000cccccc000000cccccccccccc000000000000000000000000000000cccccc000000
-cccccccccccccccccccccccccccccccccccccccccc000000000000000000000000cccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccc333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffff000000000000ffffff000000ffffffffffff000000000000
-000000ffffffffffffffffff000000000000ffffffffffffffffff000000000000ffffff
-ffffffffffffffffffffffff000000ffffffffffff000000000000000000ffffffffffff
-000000000000000000000000ffffffffffffffffff000000000000000000ffffffffffff
-000000000000ffffff000000000000000000ffffff000000000000ffffffffffff000000
-ffffff000000000000ffffffffffff000000000000ffffff000000000000ffffff000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-000000ffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffff000000cccccc000000ffffffffffffffffff000000ffffffffffffccccccffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
-000000ffffffcccccc000000ffffffffffff000000ffffffffffff000000cccccc000000
-ffffff000000ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc000000cccccc999999cccccc
-999999000000999999cccccc999999000000999999cccccc000000cccccc000000cccccc
-999999cccccc999999cccccc000000cccccc999999cccccc999999cccccc999999cccccc
-000000cccccc000000cccccc999999cccccc000000cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc000000cccccc999999cccccc999999cccccc000000cccccc
-999999cccccc000000cccccc999999cccccc999999cccccc999999cccccc000000cccccc
-000000cccccc000000cccccc999999000000999999cccccc999999cccccc999999000000
-999999cccccc999999000000999999cccccc000000cccccc999999cccccc000000cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666ffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffff000000ffffffffffffffffff000000000000ffffffffffff000000ffffffffffff
-000000ffffffcccccc000000ffffff000000ffffffffffff000000ffffff000000ffffff
-ffffffffffffffffffffffff000000ffffff000000ffffffffffff000000ffffff000000
-ffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffcccccc000000
-ffffff000000ffffffffffff000000ffffff000000ffffff000000ffffffffffff000000
-000000ffffff000000ffffff000000ffffff000000ffffffffffff000000000000ffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffff666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000ffffffffffffffffff000000000000000000ffffffffffff000000000000
-000000ffffffffffffffffff000000000000000000ffffff000000000000000000ffffff
-000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff000000
-000000000000000000000000000000000000000000000000ffffff000000000000000000
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666666666cccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccc000000000000000000000000000000cccccc
-000000000000000000cccccc000000000000000000cccccc000000000000cccccccccccc
-cccccccccccc000000000000000000000000000000cccccc000000000000000000000000
-cccccccccccccccccc000000000000000000cccccccccccccccccccccccccccccccccccc
-cccccccccccccccccc000000000000000000000000cccccccccccccccccccccccc000000
-000000000000cccccccccccccccccccccccccccccccccccccccccc000000000000000000
-000000000000000000000000cccccccccccc000000000000000000000000cccccccccccc
-000000000000000000cccccccccccccccccc000000000000000000000000000000000000
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccc999999666666ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff
-000000ffffff000000ffffffffffffffffffffffff000000000000000000ffffffffffff
-ffffffffffffffffffffffff000000000000ffffffffffffffffff000000ffffff000000
-000000000000ffffffffffffffffffffffffffffffffffff000000ffffff000000000000
-000000ffffffffffffffffff000000000000ffffffffffffffffffffffffffffff000000
-ffffffffffff000000000000000000000000ffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
-ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff
-ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000
-ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffff
-ffffff000000ffffff000000ffffff000000ffffffffffff000000ffffff000000ffffff
-ffffff000000ffffff000000ffffffffffff000000ffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333999999cccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccc999999666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000ffffffffffff000000ffffffffffffffffff000000000000000000000000
-000000ffffff000000000000000000ffffffffffff000000000000000000ffffffffffff
-ffffffffffffffffff000000000000000000000000000000ffffffffffffffffff000000
-000000000000ffffffffffffffffffffffffffffff000000ffffffffffff000000000000
-000000ffffffffffff000000000000000000000000000000ffffffffffff000000ffffff
-ffffff000000000000000000000000000000ffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff333333000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc000000000000000000000000
-000000000000000000cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999000000000000000000000000000000000000000000999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff000000ffffff
-ffffffffffff000000ffffffffffff000000cccccc000000ffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccc666666666666ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
-000000000000ffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999999999333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333999999cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccc333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-999999333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc333333999999cccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccc333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc333333999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999999999
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc333333666666cccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc999999333333
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666333333cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999333333333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc333333999999cccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccc666666333333999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff333333333333999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999999999333333666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff666666ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333666666
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccc999999666666333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999333333999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999000000999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-000000666666999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999999999333333333333999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666000000ccccccffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffff999999333333333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999333333333333999999cccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc999999
-666666000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc000000666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666333333999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999000000333333666666cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999666666333333333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999000000666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666000000666666999999cccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccc999999333333333333666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc000000000000999999ffffffcccccc
-666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000ffffffccccccffffff000000ffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffff000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333000000666666
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999999999333333333333333333999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000000000666666ffffffffffffffffff
-666666333333000000999999ccccccffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffff999999333333000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000000000000000ffffff000000ffffff000000000000
-000000ffffffffffffffffff000000000000000000ffffff000000000000ffffffffffff
-ffffff000000000000ffffffffffff000000000000ffffffffffffffffffffffff000000
-000000ffffff000000000000ffffff000000000000ffffff000000000000000000ffffff
-000000000000ffffff000000000000ffffff000000000000000000000000000000ffffff
-ffffff000000000000000000ffffff000000000000ffffff000000000000000000000000
-000000ffffff000000000000ffffffffffff000000000000000000000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-333333000000666666666666cccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc999999
-999999333333333333333333999999ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000000000666666ffffffffffffffffffffffff
-ffffffffffffcccccc333333333333666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999000000666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000000000ffffffffffff000000000000ffffff000000ffffffffffff
-ffffff000000ffffff000000ffffffffffff000000000000ffffffffffff000000ffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-000000000000ffffff000000000000ffffff000000000000ffffffffffffffffff000000
-ffffff000000000000ffffff000000ffffffffffff000000ffffff000000ffffffffffff
-000000ffffffffffffffffff000000ffffff000000000000ffffffffffff000000ffffff
-000000000000ffffff000000ffffff000000ffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666000000000000333333666666999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999999999666666333333000000333333
-666666999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000000000333333ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc999999333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000333333666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffff000000ffffff000000ffffffffffffffffff000000000000000000000000ffffff
-ffffff000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff
-000000ffffffffffff000000ffffffffffff000000000000ffffffffffffffffff000000
-ffffff000000ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff
-000000ffffffffffffffffff000000ffffff000000ffffffffffffffffff000000ffffff
-000000ffffffffffff000000ffffffffffff000000000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc666666333333000000666666666666
-999999999999cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccc999999999999333333333333333333999999999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff333333000000333333ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333333333
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-000000ffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
-ffffff000000cccccc000000ffffffffffffffffff000000ffffffffffffccccccffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
-000000ffffffcccccc000000ffffffffffff000000000000ffffffffffffcccccc000000
-ffffff000000ffffffffffff000000ffffffcccccc000000ffffff000000ffffffffffff
-000000ffffffccccccffffff000000ffffff000000ffffffffffffffffff000000ffffff
-000000ffffffffffff000000ffffff000000ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-333333000000000000333333333333666666666666999999999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc666666666666333333333333
-333333000000000000333333666666ccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff333333000000333333ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-666666333333000000666666999999ccccccccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffcccccc999999333333000000000000666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000ffffffffffffffffff000000000000000000ffffffffffff000000000000
-000000ffffffffffffffffff000000000000000000ffffff000000000000000000ffffff
-000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff000000
-000000000000ffffff000000000000ffffff000000000000000000000000000000ffffff
-000000000000000000ffffff000000000000000000000000000000000000000000ffffff
-ffffff000000000000000000ffffff000000000000000000ffffff000000000000000000
-000000000000ffffff000000000000000000000000000000000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccccccccc666666666666333333333333000000333333333333
-666666666666666666666666999999999999999999999999cccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccc999999999999999999999999999999
-999999666666666666666666666666333333000000000000666666666666999999999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333000000333333ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff999999666666666666ffffffffffffffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666333333666666ccccccccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999cccccc
-666666999999666666666666333333333333333333333333000000000000000000000000
-000000000000000000000000000000000000000000333333333333333333333333333333
-333333999999666666999999999999ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333000000333333
-333333666666666666999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccccccccc999999999999333333333333000000000000
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666
-000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999999999333333999999ffffffffffff999999666666666666999999999999
-ccccccccccccccccccccccccffffff999999999999ccccccccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccccccccc999999cccccccccccc999999666666
-999999ccccccffffffffffff999999333333666666666666ccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffff999999000000000000000000000000000000000000000000000000000000000000
-999999ffffffffffffffffff333333999999ffffffffffffffffff999999000000000000
-000000000000000000000000000000000000000000000000999999ffffffffffffffffff
-333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000000000333333999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000
-000000ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999999999666666999999
-333333333333333333999999ffffff999999000000000000000000000000000000000000
-000000000000333333ffffffffffffcccccc333333333333333333333333666666999999
-666666ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-ffffffffffffffffffffffffccccccccccccffffffffffffffffffcccccccccccccccccc
-ccccccccccccccccccccccccccccccccccccccccccccccccffffffffffffffffffffffff
-ccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000000000000000000000333333999999999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000000000
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000000000000000000000000000000000
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000000000000000000000000000666666
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999000000000000999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000000000000000000000000000333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999333333000000000000
-000000000000333333666666ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc333333000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666000000000000000000000000000000000000000000333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999
-666666333333000000000000000000000000333333999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc000000000000666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-000000000000000000000000000000999999999999000000000000000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999333333000000000000000000000000333333999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc333333000000666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666000000000000000000
-000000333333999999ccccccffffffffffffffffff333333333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999666666000000000000000000000000
-000000666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc333333000000333333ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000000000000000000000333333999999
-ccccccffffffffffffffffffffffffffffffffffff999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc999999333333
-000000000000000000000000333333666666ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff666666000000333333ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666000000000000000000000000333333999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc999999333333333333000000000000000000000000333333999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffff666666000000333333ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-000000000000000000000000000000999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc666666333333000000000000000000000000333333
-999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff666666000000333333ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666000000000000000000
-000000333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999666666000000000000
-000000000000000000666666999999ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999000000000000999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000000000000000000000333333999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999333333000000000000000000000000333333666666ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666000000000000000000000000333333999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999999999666666999999333333333333333333333333333333333333333333666666
-666666999999666666ccccccccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999333333000000000000000000000000000000333333999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff999999
-000000000000999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-000000000000000000000000000000999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999333333000000000000
-333333666666666666666666999999999999999999999999999999999999999999666666
-666666666666666666333333333333000000666666999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc666666333333000000000000000000
-000000333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffcccccc000000
-000000666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666000000000000000000
-000000333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc999999000000333333333333999999999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999666666000000333333999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-000000000000000000000000000000666666999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffffcccccc000000000000
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000000000000000000000333333999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffff
-ffffffffffffffffffcccccc333333333333999999cccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccc999999666666333333
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc999999333333000000000000000000000000333333666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ffffffffffffffffffffffffffffffffffff000000000000333333
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000000000000000000000333333999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffff999999333333999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999999999
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000ffffffccccccffffff000000ffffffffffffffffffffffffffffffccccccffffff
-ffffff000000ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffcccccc000000
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffff000000ffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffcccccc999999333333000000000000000000000000000000
-333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999
-666666000000000000666666666666999999ffffffffffff000000000000333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-000000000000000000000000000000999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffcccccc333333cccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccc000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666333333000000
-000000000000000000333333666666999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000
-000000000000000000000000000000666666ffffff333333000000333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666000000000000000000
-000000333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffff999999333333cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-ffffffffffffffffffffffffffffff000000ffffff000000000000000000000000ffffff
-000000000000000000ffffff000000000000ffffff000000000000000000ffffffffffff
-000000000000ffffff000000000000ffffff000000000000ffffffffffffffffff000000
-ffffffffffffffffff000000000000000000000000ffffffffffffffffff000000000000
-ffffffffffff000000000000ffffff000000000000ffffff000000000000ffffff000000
-000000ffffffffffff000000000000ffffff000000000000ffffff000000000000ffffff
-ffffff000000000000ffffff000000000000ffffff000000000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999666666000000000000000000000000000000666666666666ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc000000
-000000000000000000000000000000ffffff333333000000000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000000000000000000000333333999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffcccccc333333cccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccc333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-ffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000
-ffffff000000ffffffffffffffffff000000000000ffffffffffffffffff000000ffffff
-ffffff000000000000ffffff000000ffffffffffffffffff000000ffffffffffff000000
-ffffffffffffffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff
-000000ffffffffffff000000000000ffffff000000000000ffffff000000000000ffffff
-000000ffffffffffffffffffffffff000000ffffff000000000000ffffff000000ffffff
-000000ffffffffffff000000ffffff000000000000ffffff000000ffffff000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999333333000000000000000000000000333333666666
-ccccccffffffffffffffffffffffffffffffffffff333333999999ffffffffffff666666
-000000000000000000000000999999666666000000000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000000000000000000000333333999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffff666666666666999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffcccccc000000
-ffffffffffffffffffffffffffffff000000ccccccffffff000000ffffffffffff000000
-ffffff000000ccccccffffffffffff000000000000ffffffffffffffffff000000ffffff
-ffffff000000ffffffffffff000000ffffff000000000000000000ffffffffffff000000
-ffffffffffffccccccffffff000000ffffffffffff000000ffffff000000000000000000
-000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
-000000ffffffcccccc000000000000000000ffffff000000ffffffffffff000000ffffff
-000000000000000000000000ffffff000000ccccccffffff000000ffffff000000ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999333333000000000000000000
-000000000000333333999999ccccccffffffcccccc000000000000999999ffffffffffff
-000000000000000000000000666666000000000000ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-000000000000000000000000000000999999ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffff
-ffffffffffffffffff999999333333666666cccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc999999333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
-ffffff000000ffffffffffffffffff000000000000ffffffffffffffffff000000ffffff
-ffffff000000ffffffffffff000000000000ffffffffffff000000ffffffffffff000000
-ffffffffffffffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff
-ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
-000000ffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff
-000000ffffffffffffffffffffffff000000ffffffffffff000000ffffff000000ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-333333000000000000000000000000000000666666000000000000000000666666ffffff
-999999000000000000333333000000000000ccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc666666000000000000000000
-000000333333999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffcccccc666666000000666666666666cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc999999cccccc
-999999cccccc999999cccccc999999cccccc999999999999333333000000333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000000000ffffffffffffffffffffffff000000000000000000ffffff
-ffffff000000000000ffffff000000000000000000000000000000000000ffffffffffff
-000000000000000000ffffff000000000000000000000000000000000000000000000000
-000000ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000
-000000ffffff000000000000000000000000000000000000ffffff000000000000ffffff
-000000000000ffffff000000000000000000000000000000000000ffffff000000000000
-ffffff000000000000000000000000000000000000ffffff000000000000000000000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999666666000000000000000000000000000000000000000000666666
-cccccc000000000000000000000000999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff999999666666000000000000000000000000333333999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffff999999666666000000333333333333
-666666999999999999999999cccccccccccccccccccccccccccccccccccccccccc999999
-999999999999999999666666666666333333000000333333999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc000000000000000000000000000000000000
-666666333333000000000000999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffcccccc666666000000000000000000000000333333999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999999999
-666666333333333333333333000000000000000000000000000000000000000000333333
-333333333333333333999999999999ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffff000000000000000000ccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffff000000000000000000ccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff999999cccccc666666666666000000000000000000000000000000000000
-000000333333000000333333333333333333333333333333333333333333333333333333
-666666666666000000000000000000666666999999ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc999999666666666666000000
-000000000000666666333333999999333333000000000000666666666666999999999999
-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-999999666666666666666666666666333333333333000000333333333333999999999999
-ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccccccccc666666333333000000333333666666999999999999ffffff
-ffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc999999666666
-333333000000333333666666999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333666666999999ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc999999666666000000666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-333333999999ccccccffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffff999999333333666666ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff999999333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000000000ffffffffffff000000000000ffffff000000000000000000000000
-ffffffffffffffffff000000000000000000ffffffffffff000000000000ffffffffffff
-ffffff000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffff000000ffffffffffff000000000000000000ffffffffffffffffff
-000000ffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000ffffffcccccc000000ffffffffffff000000ffffff000000ffffffccccccffffff
-000000ffffff000000ffffffffffffffffffcccccc000000000000000000000000ffffff
-ffffff000000000000ffffffffffff000000000000ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333333333
-666666ffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffcccccc666666333333666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffffffffff
-000000ffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-999999000000666666999999ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffcccccc999999333333333333999999ffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000ffffffffffff000000000000000000ffffff000000000000000000
-ffffffffffffffffff000000000000000000ffffffffffff000000000000000000ffffff
-000000000000ffffffffffff000000000000ffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffff999999666666333333000000333333999999999999ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc
-666666666666000000333333666666ccccccffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffcccccc666666666666333333000000333333
-666666333333999999666666ccccccccccccccccccccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccccccccccccccc999999999999666666666666333333333333000000333333333333
-999999999999ffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc
-ffffffffffffffffff666666333333333333333333ffffffffffffffffff666666999999
-666666999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffcccccc000000
-000000000000ffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-999999cccccc666666999999333333333333333333333333000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-333333333333333333666666666666999999999999ccccccccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff666666000000333333333333
-ffffffffffffffffff999999ccccccccccccccccccffffffffffffffffff999999666666
-999999666666666666000000000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffff999999ccccccffffffffffff999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffcccccc000000999999ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffff
-ffffffffffffcccccc000000666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffcccccc000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffff000000
-ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffff000000000000ffffffffffff000000
-000000ffffff000000000000ffffff000000000000000000000000000000000000ffffff
-ffffff000000000000000000ffffffffffff000000000000ffffff000000ffffff000000
-000000ffffff000000000000ffffff000000000000ffffff000000000000000000ffffff
-ffffff000000000000000000000000ffffffffffff000000000000ffffff000000000000
-000000000000ffffffffffffffffff000000000000000000ffffffffffff000000000000
-ffffffffffffffffff000000000000ffffffffffff000000000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000cccccc
-ffffff999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
-000000000000ffffff000000000000ffffff000000ffffff000000ffffffffffff000000
-000000ffffffffffffffffff000000ffffffffffff000000000000ffffffffffffffffff
-ffffff000000ffffff000000000000ffffff000000ffffffffffff000000ffffffffffff
-ffffffffffff000000ffffffffffff000000ffffffffffff000000000000000000ffffff
-ffffffffffff000000ffffff000000ffffffffffff000000ffffff000000ffffffffffff
-000000ffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffff666666333333ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffff000000ffffffffffffffffff000000000000000000000000ffffffffffff
-000000ffffffcccccc000000ffffffffffff000000ffffff000000ffffffcccccc000000
-000000ffffffffffffffffff000000ffffffcccccc000000ffffffffffffffffff000000
-000000000000cccccc000000ffffffffffff000000ffffff000000ffffffccccccffffff
-ffffffffffff000000ffffffffffff000000ccccccffffff000000ffffff000000ffffff
-ffffffffffff000000ffffff000000ffffffffffffffffffffffff000000000000000000
-000000ffffffffffff000000000000ffffffcccccc000000000000ffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffff999999000000ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
-000000ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000
-000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
-ffffff000000ffffff000000ffffffffffffffffff000000000000ffffffffffffffffff
-ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff000000ffffff
-ffffffffffff000000ffffff000000ffffffffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffccccccccccccffffffffffffccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000000000ffffffffffffffffff000000000000000000ffffff000000
-000000000000ffffff000000000000ffffff000000000000000000000000000000ffffff
-ffffff000000000000000000ffffffffffff000000000000000000ffffffffffff000000
-000000000000000000000000000000ffffffffffff000000ffffffffffffffffffffffff
-ffffffffffff000000000000000000ffffffffffff000000000000000000ffffff000000
-000000000000ffffffffffffffffff000000000000000000ffffffffffff000000000000
-000000ffffff000000000000ffffffffffff000000000000ffffffffffffffffff000000
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffff333333333333333333666666ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffff999999
-ccccccffffffffffffcccccc666666000000333333999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc666666ffffff
-ffffffffffff333333000000000000000000ffffffffffffffffff000000000000333333
-333333ffffffffffffffffff999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffcccccc000000000000000000ffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
-ffffff000000000000000000ffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffff999999666666ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffff999999666666ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc
-666666999999666666666666333333333333333333333333333333333333333333999999
-666666999999999999ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffff999999666666ffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffcccccc999999333333000000333333333333
-999999666666999999999999cccccccccccccccccccccccccccccccccccccccccc666666
-999999666666666666333333000000333333999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffff999999333333333333999999999999ffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffcccccc666666333333000000999999ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffff
-ffffffffffffcccccc333333666666ccccccffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffcccccc333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333
-999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999000000999999
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffff999999333333666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffff333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333333333ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff333333666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff666666000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccc333333666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-cccccc333333ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-333333ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999666666333333
-999999ccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffff666666333333ccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc666666
-666666ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-000000ffffffffffffffffff000000ffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffff000000ffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-666666333333333333999999ccccccffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffcccccc999999666666000000999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc666666333333ffffff
-ffffffffffff999999333333ccccccffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffff999999333333999999
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffff000000ffffffffffff000000000000ffffff000000000000
-ffffff000000000000000000ffffff000000000000ffffff000000000000ffffff000000
-000000ffffffffffff000000000000ffffff000000000000ffffff000000000000ffffff
-ffffff000000000000ffffff000000000000000000000000000000ffffffffffffffffff
-000000000000000000000000ffffff000000000000ffffff000000ffffff000000000000
-000000ffffffffffff000000000000000000ffffffffffff000000000000ffffffffffff
-ffffff000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffcccccc666666333333000000666666666666ccccccccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999
-999999333333333333333333666666999999ffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffcccccc333333333333666666ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999666666000000666666ccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000000000ffffffffffff000000ffffffffffff000000ffffff000000
-000000ffffffffffff000000000000ffffff000000000000ffffff000000ffffffffffff
-ffffff000000ffffffffffff000000000000ffffff000000000000ffffffffffff000000
-ffffffffffff000000000000ffffff000000ffffff000000ffffffffffffffffffffffff
-ffffff000000ffffffffffff000000ffffff000000000000ffffff000000ffffffffffff
-ffffff000000000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff
-000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffff999999999999333333333333000000333333
-333333666666666666999999999999cccccc999999ccccccffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999cccccc999999999999666666999999333333333333333333000000333333666666
-666666ccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff666666666666ffffff
-ffffffffffffffffffffffffffffffcccccc999999333333333333333333666666666666
-ccccccccccccccccccccccccffffffffffffffffffffffffffffffffffffffffff999999
-cccccccccccc999999666666666666000000666666999999ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000ffffffffffffffffffffffffffffff000000000000000000000000ffffff000000
-ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff000000
-000000000000ffffffffffff000000ffffffffffff000000000000000000000000000000
-ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffffffffffffffff
-ffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff
-ffffff000000000000ffffffffffffffffffffffff000000000000000000000000ffffff
-ffffff000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcccccc
-cccccc999999999999666666666666333333333333333333000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-666666333333666666333333999999666666cccccc999999ccccccffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffcccccccccccc999999999999
-333333333333333333333333000000000000000000000000000000000000000000333333
-333333333333666666999999999999ffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-000000ffffffccccccffffffffffffffffff000000ffffffffffffffffffcccccc000000
-ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000000000ffffff
-ffffff000000ccccccffffff000000ffffffffffff000000000000ffffffccccccffffff
-ffffffffffff000000ffffffffffff000000cccccc000000ffffffffffffffffffffffff
-ffffff000000ccccccffffff000000ffffff000000ffffffffffff000000ccccccffffff
-ffffff000000000000ffffffffffffffffffcccccc000000ffffffffffffffffffffffff
-ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
-000000000000ffffffffffffffffffffffffffffff000000000000000000000000000000
-000000ffffff000000000000000000ffffff000000000000ffffff000000000000000000
-000000000000000000000000000000000000ffffff000000000000000000000000000000
-ffffff000000000000000000ffffff000000000000000000000000ffffffffffffffffff
-ffffff000000000000000000ffffff000000000000000000ffffffffffff000000000000
-000000ffffffffffff000000000000000000ffffffffffff000000000000000000ffffff
-000000000000ffffffffffff000000000000ffffffffffffffffff000000ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccccccccffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff333333333333ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-999999000000000000ccccccffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999999999ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000cccccc
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffccccccffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffff999999666666ffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc000000000000ccccccffffffcccccc666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffff999999666666ffffffffffffffffffcccccc666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffff999999666666ffffffffffff
-ffffffcccccc666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-999999666666ffffffffffffffffffcccccc666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffffcccccc666666ffffffffffffffffffcccccc666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffffcccccc666666ffffffffffff
-ffffffcccccc666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-cccccc666666ffffffffffffffffffcccccc666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffffcccccc666666ffffffffffffffffffcccccc666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffffcccccc666666ffffffffffff
-ffffffcccccc666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-cccccc666666ffffffffffffffffffcccccc666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffffcccccc666666ffffffffffffffffffcccccc666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffffcccccc666666ffffffffffff
-ffffffcccccc666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-cccccc666666ffffffffffffffffffcccccc666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffffcccccc666666ffffffffffffffffffcccccc666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffffcccccc666666ffffffffffff
-ffffffcccccc666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-cccccc666666ffffffffffffffffffcccccc666666ccccccffffffffffffffffff666666
-ccccccffffffffffffffffffcccccc666666ffffffffffffffffffcccccc666666cccccc
-ffffffffffffffffff666666ccccccffffffffffffffffffcccccc666666ffffffffffff
-ffffffcccccc666666ccccccffffffffffffffffff666666ccccccffffffffffffffffff
-cccccc666666ffffffffffffffffffcccccc666666ccccccffffffffffffffffff666666
-999999ffffffffffffffffffcccccc666666ffffffffffffffffffcccccc666666cccccc
-ffffffffffffffffff666666999999ffffffffffffffffffcccccc666666ffffffffffff
-ffffffcccccc666666ccccccffffffffffffffffff666666999999ffffffffffffffffff
-cccccc666666ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-cccccc333333000000ffffffffffff333333000000666666ffffffffffff666666000000
-000000ffffffffffffcccccc000000000000999999ffffffffffff333333000000666666
-ffffffffffff666666000000000000ffffffffffffcccccc000000000000999999ffffff
-ffffff333333000000666666ffffffffffff666666000000000000ffffffffffffcccccc
-000000000000999999ffffffffffff333333000000666666ffffffffffff666666000000
-000000ffffffffffffcccccc000000000000999999ffffffffffff333333000000666666
-ffffffffffff666666000000000000ffffffffffffcccccc000000000000999999ffffff
-ffffff333333000000333333ffffffffffff666666000000000000ffffffffffffcccccc
-000000000000999999ffffffffffff333333000000333333ffffffffffff666666000000
-000000ffffffffffffcccccc000000000000999999ffffffffffff333333000000333333
-ffffffffffff666666000000000000ffffffffffffcccccc000000000000999999ffffff
-ffffff333333000000333333ffffffffffff999999000000000000ffffffffffffcccccc
-000000000000999999ffffffffffff333333000000333333ffffffffffff999999000000
-000000ffffffffffffcccccc000000000000999999ffffffffffff333333000000333333
-ffffffffffff999999000000000000ffffffffffffcccccc000000000000999999ffffff
-ffffff333333000000333333ffffffffffff999999000000000000ffffffffffffcccccc
-000000000000999999ffffffffffff333333000000333333ffffffffffff999999000000
-000000ffffffffffffcccccc000000000000999999ffffffffffff333333000000333333
-ffffffffffff999999000000000000ffffffffffffffffff000000000000999999ffffff
-ffffff333333000000333333ffffffffffff999999000000000000ffffffffffffffffff
-000000000000999999ffffffffffff333333000000333333ffffffffffff999999000000
-000000ffffffffffffffffff000000000000666666ffffffffffff333333000000333333
-ffffffffffff999999000000000000ffffffffffffffffff000000000000666666ffffff
-ffffff333333000000333333ffffffffffff999999000000000000ffffffffffffffffff
-000000000000666666ffffffffffff333333000000333333ffffffffffff999999000000
-000000ffffffffffffffffff000000000000666666ffffffffffff666666000000333333
-ffffffffffff999999000000000000ffffffffffffffffff000000000000666666ffffff
-ffffff666666000000333333ffffffffffff999999000000000000ffffffffffffffffff
-000000000000666666ffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffff999999333333999999ffffffffffffffffff333333
-999999ffffffffffffffffff666666333333ffffffffffffffffff999999333333999999
-ffffffffffffffffff333333999999ffffffffffffffffff666666333333ffffffffffff
-ffffff999999333333999999ffffffffffffffffff333333999999ffffffffffffffffff
-666666333333ffffffffffffffffff999999333333999999ffffffffffffffffff333333
-666666ffffffffffffffffff666666333333ffffffffffffffffff999999333333999999
-ffffffffffffffffff333333666666ffffffffffffffffff666666333333ffffffffffff
-ffffff999999333333999999ffffffffffffffffff333333666666ffffffffffffffffff
-666666333333ffffffffffffffffff999999333333999999ffffffffffffffffff333333
-666666ffffffffffffffffff666666333333ffffffffffffffffff999999333333999999
-ffffffffffffffffff333333666666ffffffffffffffffff666666333333ffffffffffff
-ffffff999999333333999999ffffffffffffffffff333333666666ffffffffffffffffff
-666666333333ffffffffffffffffff999999333333999999ffffffffffffffffff333333
-666666ffffffffffffffffff666666333333ffffffffffffffffff999999333333999999
-ffffffffffffffffff333333666666ffffffffffffffffff666666333333ffffffffffff
-ffffff999999333333999999ffffffffffffffffff333333666666ffffffffffffffffff
-666666333333ffffffffffffffffff999999333333999999ffffffffffffffffff333333
-666666ffffffffffffffffff666666333333ffffffffffffffffff999999333333999999
-ffffffffffffffffff333333666666ffffffffffffffffff666666333333ffffffffffff
-ffffff999999333333999999ffffffffffffffffff333333666666ffffffffffffffffff
-666666333333ffffffffffffffffff999999333333999999ffffffffffffffffff333333
-666666ffffffffffffffffff666666333333ffffffffffffffffff999999333333999999
-ffffffffffffffffff333333666666ffffffffffffffffff666666333333ffffffffffff
-ffffff999999333333999999ffffffffffffffffff333333666666ffffffffffffffffff
-666666333333ffffffffffffffffff999999333333999999ffffffffffffffffff333333
-666666ffffffffffffffffff999999333333ffffffffffffffffff999999333333999999
-ffffffffffffffffff333333666666ffffffffffffffffff999999333333ffffffffffff
-ffffff999999333333999999ffffffffffffffffff333333666666ffffffffffffffffff
-999999333333ffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffccccccffffffffffffffffffffffffffffffffffffffffffccccccffffff
-ffffffffffffffffffffffffffffffffffffccccccffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-ffffffffffffffffffffffff
-
-showpage
-
-% stop using temporary dictionary
-end
-
-% restore original state
-origstate restore
-
-%%Trailer
diff --git a/lib/inviso/doc/src/notes.xml b/lib/inviso/doc/src/notes.xml deleted file mode 100644 index 661284e786..0000000000 --- a/lib/inviso/doc/src/notes.xml +++ /dev/null @@ -1,278 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>2006</year><year>2011</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Inviso Release Notes</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - <file>notes.xml</file> - </header> - <p>This document describes the changes made to the Inviso application.</p> - -
- <section><title>Inviso 0.6.3</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p>The <c>inviso</c> application has been deprecated and - will be removed in the R16 release.</p> - <p> - Own Id: OTP-9798</p> - </item> - <item> - <p> - Eliminate use of deprecated regexp module</p> - <p> - Own Id: OTP-9810</p> - </item> - </list> - </section> - -</section> - -<section><title>Inviso 0.6.2</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - The obsolete guards has now been changed to the new guard - interface.</p> - <p> - Own Id: OTP-8747</p> - </item> - </list> - </section> - -</section> - -<section><title>Inviso 0.6.1</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - The documentation is now built with open source tools - (xsltproc and fop) that exists on most platforms. One - visible change is that the frames are removed.</p> - <p> - Own Id: OTP-8201</p> - </item> - </list> - </section> - -</section> - -<section><title>Inviso 0.6</title>
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- In this release the following has been fixed and
- enhanced: Autostart: It is now possible to configure
- modules that shall be loaded by the autostart mechanism.
- This because it is not certain that all application
- systems make use of the OTP boot script to set up paths
- to all Erlang modules. Runtime_tools/Inviso: A bug in the
- fetch_log functionality has been fixed. Further a bug
- that was (supposedly) fixed in a previous patch
- concerning meta-tracer write_ti has been fixed (again) in
- this patch. A bug in inviso_as_lib making remote
- autostart config file updates fail has been fixed.
- Inviso: inviso_tool has been given a flush API.</p>
- <p>
- Own Id: OTP-6918</p>
- </item>
- </list>
- </section>
-
-</section>
-<section><title>Inviso 0.5</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The following bugs/improvements have been done: Internal
- interworking between inviso_rt and inviso_rt_meta. The
- call function used by inviso_rt to call inviso_rt_meta is
- now protected with a monitor. Inviso_rt_meta now includes
- the timestamp of the incoming meta trace message when
- calling the call-callback. (Makes it possible to add a
- "better" timestamp to the ti-file.) Bug in inviso_tool
- making it not remove trace patterns when terminating. Bug
- in internal function h_start_session making inviso_tool
- crash if there were no active nodes to start the session
- on. The user-inviso_tool and inviso API-inviso control
- component request/response gen_server protocols had
- default time-out. Since many trace operations can be time
- consuming, a longer time-out is necessary. Improved
- overload protection. It is now possible to let the
- overload protection renew itself (e.g after an exit from
- an external overload protector). Inviso_rt_meta now fully
- uses the exception_trace match spec action term. Run
- Trace Case API (as in contrast to activate and deactivate
- trace case APIs) in inviso_tool. Flush trace-port API
- added to inviso. Get_session_data API added to
- inviso_tool. Improved inviso_tool:stop making it possible
- to name nodes which shall not have their trace patterns
- removed when inviso_tool terminates. Bug in handling of
- writing multiple ti-entries if returned from a
- call/return_from call-back in inviso_rt_meta Process
- trace flags are no longer explicitly removed by the
- inviso_tool when it terminates. Not necessary.
- Inviso_tool get_autostart_data adopted to standard
- autostarter.</p>
- <p>
- *** INCOMPATIBILITY with Meta trace call-backs are called
- with different arguments now. ***</p>
- <p>
- Own Id: OTP-6881</p>
- </item>
- </list>
- </section>
-
-</section>
-<section><title>Inviso 0.4</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- A bug in inviso_rt_meta caused an ETS table containing
- information on initiated (init_tpm) functions to be lost
- when suspending tracing. Further an enhancement to
- inviso_rt has been introduced making it possible to
- activate process trace flags based on globally registered
- names. It is then not an error to activate a global name
- on a node where the name does not reside. The process
- count in the return value will simply be set to zero
- (hence exactly one node in the NodeResult part of the
- return value will indicate one matching process found). A
- bug was found in fetch_log API. At the same time the
- fetch_log functionality was enhanced to also offer flow
- control making fetcher processes send chunks of
- transferred file data at a slower pace.</p>
- <p>
- Own Id: OTP-6703</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Minor Makefile changes.</p>
- <p>
- Own Id: OTP-6689 Aux Id: OTP-6742 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-
-<section><title>Inviso 0.3</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- In this release the first working version of the
- inviso_tool is included. Updates and small bugfixes in
- the inviso application.</p>
- <p>
- Own Id: OTP-6677</p>
- </item>
- </list>
- </section>
-
-</section>
-<section><title>Inviso 0.2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc improvements.</p>
- <p>
- Own Id: OTP-6576</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Inviso 0.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- This ticket includes several improvements and bugfixes to
- both runtime_tools and inviso. The overload mechanism can
- now also react to incoming messages. This is useful if
- an external overload watch-dog is used. Some improvements
- of variable bindings has been done to the default
- autostart mechanism - inviso_autostart_server. Autostart
- "jobs" can now be done in parallel, allowing for some
- jobs to hang waiting for some parts of the traced system
- to become ready before proceeding. Previously when using
- named meta-match-specs (tpm_ms) ending up with zero
- match-specs still kept the meta trace pattern active.
- This caused zero match-specs to be equal to unlimited
- meta tracing on that particular function. If the internal
- database becomes empty of meta match specs, meta trace
- pattern is removed for that function. Standard public
- loop data in the inviso runtime meta tracer process is
- now extended to a 2-tuple. The functions ctp/1 and ctpl/1
- are added making it possible to remove trace patterns for
- a list of functions rather than one by one.
- Inviso_rt_meta will now accept a list of binaries to be
- output into the trace information file, in additions to a
- single binary. Further it is also possible to make own
- output to the trace information file using the write_ti/1
- function. An error was discovered in inviso_rt making the
- inviso_rt_meta remain rather than terminate if the
- inviso_rt terminated due to "running alone" (not allowed
- to run without a control component). A new tool,
- inviso_tool, has been added to the inviso application.</p>
- <p>
- Own Id: OTP-6426</p>
- </item>
- </list>
- </section>
-
-</section>
-
- <section> - <title>Inviso 0.1</title> - <p>First version.</p> - </section> - -</chapter> - diff --git a/lib/inviso/doc/src/part_notes.xml b/lib/inviso/doc/src/part_notes.xml deleted file mode 100644 index 1cd8b0f1a7..0000000000 --- a/lib/inviso/doc/src/part_notes.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE part SYSTEM "part.dtd"> - -<part xmlns:xi="http://www.w3.org/2001/XInclude"> - <header> - <copyright> - <year>2006</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Inviso Release Notes</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <description> - <p><em>Inviso</em>, an Erlang trace tool.</p> - </description> - <xi:include href="notes.xml"/> -</part> - diff --git a/lib/inviso/doc/src/ref_man.xml b/lib/inviso/doc/src/ref_man.xml deleted file mode 100644 index c9e75e4029..0000000000 --- a/lib/inviso/doc/src/ref_man.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE application SYSTEM "application.dtd"> - -<application xmlns:xi="http://www.w3.org/2001/XInclude"> - <header> - <copyright> - <year>2006</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Inviso Reference Manual</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <description> - <p><em>Inviso</em>, an Erlang trace tool.</p> - </description> - <xi:include href="inviso.xml"/> - <xi:include href="inviso_as_lib.xml"/> - <xi:include href="inviso_lfm.xml"/> - <xi:include href="inviso_lfm_tpfreader.xml"/> - <xi:include href="inviso_rt.xml"/> - <xi:include href="inviso_rt_meta.xml"/> -</application> - diff --git a/lib/inviso/ebin/.gitignore b/lib/inviso/ebin/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/inviso/ebin/.gitignore +++ /dev/null diff --git a/lib/inviso/include/.gitignore b/lib/inviso/include/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/inviso/include/.gitignore +++ /dev/null diff --git a/lib/inviso/info b/lib/inviso/info deleted file mode 100644 index 3190d6d1cc..0000000000 --- a/lib/inviso/info +++ /dev/null @@ -1,2 +0,0 @@ -group: tools -short: A trace tool for both development and delivered systems. diff --git a/lib/inviso/priv b/lib/inviso/priv deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/inviso/priv +++ /dev/null diff --git a/lib/inviso/src/Makefile b/lib/inviso/src/Makefile deleted file mode 100644 index 292a2bec99..0000000000 --- a/lib/inviso/src/Makefile +++ /dev/null @@ -1,104 +0,0 @@ -# ``The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../vsn.mk -VSN=$(INVISO_VSN) - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/inviso-$(VSN) - -# ---------------------------------------------------- -# Common Macros -# ---------------------------------------------------- - -MODULES= \ - inviso \ - inviso_c \ - inviso_lfm \ - inviso_lfm_tpfreader \ - inviso_tool \ - inviso_tool_lib - - -#HRL_FILES= ../include/ - -ERL_FILES= $(MODULES:%=%.erl) - -TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) - -APP_FILE= inviso.app - -APP_SRC= $(APP_FILE).src -APP_TARGET= $(EBIN)/$(APP_FILE) - -APPUP_FILE= inviso.appup - -APPUP_SRC= $(APPUP_FILE).src -APPUP_TARGET= $(EBIN)/$(APPUP_FILE) - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_COMPILE_FLAGS += +warn_unused_vars -I../include - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug opt: $(TARGET_FILES) - -clean: - rm -f $(TARGET_FILES) - rm -f errs core *~ - -$(APP_TARGET): $(APP_SRC) ../vsn.mk - sed -e 's;%VSN%;$(VSN);' $< > $@ - -$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk - sed -e 's;%VSN%;$(VSN);' $< > $@ - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) "$(RELSYSDIR)/src" - $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src" -# $(INSTALL_DIR) "$(RELSYSDIR)/include" -# $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include" - $(INSTALL_DIR) "$(RELSYSDIR)/ebin" - $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin" - -release_docs_spec: - - - - - - - diff --git a/lib/inviso/src/inviso.app.src b/lib/inviso/src/inviso.app.src deleted file mode 100644 index 91eaa1b9b2..0000000000 --- a/lib/inviso/src/inviso.app.src +++ /dev/null @@ -1,13 +0,0 @@ -{application,inviso, - [{description, "INVISO trace tool"}, - {vsn, "%VSN%"}, - {modules, [inviso_c,inviso, - inviso_lfm,inviso_lfm_tpfreader - ]}, - {registered, [inviso_c]}, - {applications, [kernel, stdlib, runtime_tools]}, - {env, []} - ]}. - - - diff --git a/lib/inviso/src/inviso.appup.src b/lib/inviso/src/inviso.appup.src deleted file mode 100644 index 54a63833e6..0000000000 --- a/lib/inviso/src/inviso.appup.src +++ /dev/null @@ -1 +0,0 @@ -{"%VSN%",[],[]}. diff --git a/lib/inviso/src/inviso.erl b/lib/inviso/src/inviso.erl deleted file mode 100644 index 07bdf3e649..0000000000 --- a/lib/inviso/src/inviso.erl +++ /dev/null @@ -1,1056 +0,0 @@ -%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
-%% Author: Ann-Marie L�f, [email protected]
-%% Lennart �hman, [email protected]
-%%
-%% Description: API module for the inviso system.
-%% Inviso consists of a control component and possibly one or more runtime
-%% components. This module is simply the API to the inviso system. All normal
-%% calls goes through the control component.
-%% ------------------------------------------------------------------------------
-
--module(inviso).
--deprecated(module). -
-%% ------------------------------------------------------------------------------
-%% Exported API functions.
-%% ------------------------------------------------------------------------------
-
--export([start/0, start/1,
- add_node/1, add_node/2, add_node_if_ref/1, add_node_if_ref/2,
- add_nodes/2, add_nodes/3, add_nodes_if_ref/2, add_nodes_if_ref/3,
- change_options/1, change_options/2,
- init_tracing/1, init_tracing/2,
- stop_tracing/0, stop_tracing/1,
- clear/0, clear/1, clear/2,
- flush/0,flush/1,
- stop/0, stop_nodes/0, stop_nodes/1, stop_all/0,
- tp/1,tp/2,tp/4,tp/5,tp/6,
- tpl/1,tpl/2,tpl/4,tpl/5,tpl/6,
- tpm_localnames/0,tpm_localnames/1,tpm_globalnames/0,tpm_globalnames/1,
- init_tpm/4,init_tpm/5,init_tpm/7,init_tpm/8,
- tpm/4,tpm/5,tpm/6,tpm/8,tpm/9,
- tpm_tracer/4,tpm_tracer/5,tpm_tracer/6,tpm_tracer/8,tpm_tracer/9,
- tpm_ms/5,tpm_ms/6,
- tpm_ms_tracer/5,tpm_ms_tracer/6,
- ctpm_ms/4,ctpm_ms/5,ctpm/3,ctpm/4,
- ctpm_localnames/0,ctpm_localnames/1,ctpm_globalnames/0,ctpm_globalnames/1,
- ctp/1,ctp/2,ctp/3,ctp/4,
- ctpl/1,ctpl/2,ctpl/3,ctpl/4,
- tf/1, tf/2, tf/3,
- ctf/1, ctf/2, ctf/3,
- ctp_all/0, ctp_all/1, ctf_all/0, ctf_all/1,
- suspend/1, suspend/2,
- cancel_suspension/0, cancel_suspension/1,
- get_status/0, get_status/1,
- get_tracerdata/0, get_tracerdata/1,
- list_logs/0, list_logs/1,
- fetch_log/2, fetch_log/3, fetch_log/4,
- delete_log/0, delete_log/1, delete_log/2,
- subscribe/0, subscribe/1,
- unsubscribe/0, unsubscribe/1]).
-
-%% debuging inviso
--export([state/0, state/1]).
-
-%% ------------------------------------------------------------------------------
-%% Macros used in this module.
-%% ------------------------------------------------------------------------------
-
--define(CONTROLLER,inviso_c).
-
-%% Some function calls to runtime components may take long time, we must wait
-%% longer than the standard timeout for a reply from the control component.
--define(CALL_TIMEOUT,60000).
-%% ------------------------------------------------------------------------------
-
-
-
-%% =============================================================================
-%% CONTROL COMPONENT API FUNCTIONS.
-%% =============================================================================
-
-%% start()={ok,pid()}|{error,Reason}
-%% start(Options)={ok,pid()}|{error,Reason}
-%% Options=[Option,...], the options will be default options to runtime components
-%% later started. See add_node about available options.
-%% There are also options consumed by the control component:
-%% Option={subscribe,pid()}
-%%
-%% Starts a control component process on the local node. A control component must
-%% be started before runtime components can be started manually.
-start() ->
- gen_server:start({local,?CONTROLLER},?CONTROLLER,{self(),[]},[]).
-
-start(Options) ->
- gen_server:start({local,?CONTROLLER},?CONTROLLER,{self(),Options},[]).
-%% -----------------------------------------------------------------------------
-
-%% add_node(Reference)=NodeResult|{error, Reason}
-%% add_node(Reference,Options)=NodeResult|{error, Reason}
-%% Reference=PreviousReference = term(),
-%% Options=[Option,...],
-%% Option={dependency,Dep}
-%% Dep=integer()|'infinity'; The timeout before the runtime component will
-%% terminate if abandoned by this control component.
-%% Option={overload,Overload}; controls how and how often overload checks shall
-%% be performed. Instead of specifying a tuple, the atom 'overload' can be
-%% specified to state no loadcheck. The result will actually be the same
-%% if 'infinity' is used as intervall. It is sometimes necessary to
-%% initialize the overlaod check. This can be done with InitMFA. The
-%% loadchecker must then also be removed by using a RemoveMFA.
-%% Overload=Iterval (int() in milliseconds) |
-%% {LoadMF,Interval}|{LoadMF,Interval,InitMFA,RemoveMFA}
-%% LoadMF={Mod,Func}
-%% InitMFA,RemoveMFA={Mod,Func,ArgList}|void
-%% If just Interval is used, it means using a default overload check.
-%% NodeResult={ok,NAns}|{error,Reason}
-%% NAns=new|{adopted,State,Status,PreviousReference}|already_added
-%% Status = running | {suspended, SReason}
-%%
-%% Starts or tries to connect to an existing runtime component at the local
-%% node, regardless if the system is distributed or not.
-%% Options will override any default options specified at start-up of the
-%% control component.
-add_node(Reference) ->
- gen_server:call(?CONTROLLER,{add_nodes,[node()],[],Reference,any_ref},?CALL_TIMEOUT).
-
-add_node(Reference,Options) when is_list(Options) -> - gen_server:call(?CONTROLLER,{add_nodes,[node()],Options,Reference,any_ref},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% add_node(Reference)=NodeResult|{error,{wrong_reference,OtherRef}}|{error,Reason}
-%% add_node(Reference,Options)=NodeResult|{error,{wrong_reference,OtherRef}}|
-%% {error,Reason}
-%%
-%% As add_node/1,/2 but will only connect to an already existing runtime component
-%% if its reference is the same as the one given as argument.
-add_node_if_ref(Reference) ->
- gen_server:call(?CONTROLLER,{add_nodes,[node()],[],Reference,if_ref},?CALL_TIMEOUT).
-
-add_node_if_ref(Reference,Options) when is_list(Options) -> - gen_server:call(?CONTROLLER,{add_nodes,[node()],Options,Reference,if_ref},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% add_nodes(Nodes,Reference)={ok,NodeResults}|{error,Reason}
-%% add_nodes(Nodes,Reference,Options)={ok,NodeResults}|{error,Reason}
-%% Nodes=[Node,...],
-%% NodeResults=[{Node,NodeResult},...]
-%%
-%% As add_node/1,/2 but for the nodes specified in Nodes.
-%% It is possible but not intended to use this function in a non-distributed
-%% system. By speicifying node() as the node where the runtime component shall
-%% be started. The return value will then follow the rules of non distributed
-%% returnvalues and not have a node indicator.
-add_nodes(Nodes,Reference) when is_list(Nodes) -> - gen_server:call(?CONTROLLER,{add_nodes,Nodes,[],Reference,any_ref},?CALL_TIMEOUT).
-
-add_nodes(Nodes,Reference,Options) when is_list(Nodes),is_list(Options) -> - gen_server:call(?CONTROLLER,{add_nodes,Nodes,Options,Reference,any_ref},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% add_nodes_if_ref(Nodes,Reference)={ok,NodeResults}|{error,Reason}
-%% add_nodes_if_ref(Nodes,Reference,Options)={ok,NodeResults}|{error,Reason}
-%%
-%% As add_nodes/2,/3 but will only connect to an already existing runtime component
-%% if its reference is the same as the one given as argument.
-add_nodes_if_ref(Nodes,Reference) when is_list(Nodes) -> - gen_server:call(?CONTROLLER,{add_nodes,Nodes,[],Reference,if_ref},?CALL_TIMEOUT).
-
-add_nodes_if_ref(Nodes,Reference,Options) when is_list(Nodes),is_list(Options) -> - gen_server:call(?CONTROLLER,{add_nodes,Nodes,Options,Reference,if_ref},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% change_options(Options)={ok,NodeResults}|NodeResult|{error,Reason}
-%% change_options(Nodes,Options)={ok,NodeResults}|{error,Reason}
-%% Nodes=[Node,...],
-%% Options= see add_node and add_nodes on available options.
-%%
-%% Change options on all or specified Nodes. This may result in for instance
-%% reinitialization of overloadcheck.
-change_options(Options) when is_list(Options) -> - gen_server:call(?CONTROLLER,{change_options,all,Options},?CALL_TIMEOUT).
-change_options(Nodes,Options) when is_list(Nodes),is_list(Options) -> - gen_server:call(?CONTROLLER,{change_options,Nodes,Options},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% init_tracing(TracerData)={ok,[{Node,NodeResult}]} | NodeResult | {error,Reason}
-%% init_tracing(TracerList)={ok,[{Node,NodeResult}]} | {error,Reason}
-%% init_tracing(Nodes,TracerData)={ok,[{Node,NodeResult}]}|{error,Reason}
-%% TracerData = [{trace,LogTD} [,{ti,TiTD}]}] | LogTD
-%% LogTD = {HandlerFun,Data} | collector | {relayer,pid()} |
-%% {relayer,CollectingNode} | {ip,IPPortParameters} |
-%% {file,FilePortParameters}
-%% TiTD = {file,FileName} | {file,FileName,TiMFA}
-%% TiMFA = {Module,Function,ArgumentList} initiating a private loopdata
-%% inside the meta-tracer.
-%% TracerList = [{Node,TracerData}],
-%% IPPortParameters = Portno | {Portno, Qsiz}
-%% Qsiz =
-%% FilePortParameters = {Filename, wrap, Tail, {time, WrapTime}, WrapCnt} |
-%% {FileName, wrap, Tail, WrapSize, WrapCnt} |
-%% {FileName, wrap, Tail, WrapSize} |
-%% {FileName, wrap, Tail} | FileName
-%% Tail =/= ""
-%% HandlerFun is a function taking 2 arguments.
-%% Nodes = [node()],
-%% CollectingNode = pid() | node(),
-%% NodeResult = {ok,LogResults} | {error, NReason}
-%% LogResults=[LogResult,...]
-%% LogResult={trace_log,LogRes} | {ti_log,LogRes}
-%% LogRes=ok|{error,Reason}
-%%
-%% Starts tracing on the nodes specified. If just providing a TracerData tracing
-%% will be initiated on all our nodes. If it is the non distributed case, that
-%% means only on the local non distributed node.
-%%
-%% {HandlerFun,Data}
-%% Will use the runtime components own process as tracer and handle all
-%% incomming trace message using HandlerFun.
-%% {relayer,CollectingNode}
-%% The runtime component addressed will act tracer and relay all incomming trace
-%% messages to Node or Pid, if CollectingNode is not a traced node connected
-%% to the controll component, the init_tracing call will return an error.
-%% Note that {relayer, Node} only is syntactical sugar for
-%% {relayer, rpc:call(Node,erlang,whereis,[inviso_rt])}
-%% collector
-%% The runtime component is used as tracer or collector of relayed
-%% trace messages using the default handler writing them to io.
-%% ip | file - will open a trace-port on Node using PortParameters
-init_tracing(TracerDataList) ->
- gen_server:call(?CONTROLLER,{init_tracing,TracerDataList},?CALL_TIMEOUT).
-
-init_tracing(Nodes,TracerData) when is_list(Nodes) -> - gen_server:call(?CONTROLLER,{init_tracing,Nodes,TracerData},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% stop_tracing(Nodes)={ok,NodeResults}|{error,Reason}
-%% stop_tracing()={ok,NodeResults}|NodeResult
-%% Nodes=[Node,...],
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={ok,State}|{error,Reason}
-%% State=new|idle
-%% Stops tracing on all or specified Nodes. Flushes trace buffert,
-%% closes trace port and removes all trace flags and meta-patterns.
-%% The nodes are called in parallel.
-stop_tracing() ->
- gen_server:call(?CONTROLLER,{stop_tracing,all},?CALL_TIMEOUT).
-
-stop_tracing(Nodes) when is_list(Nodes) ->
- gen_server:call(?CONTROLLER,{stop_tracing,Nodes},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% clear()={ok,NodeResults}|NodeResult
-%% clear(Nodes,Options)={ok,NodeResults}|{error,Reason}
-%% clear(Options)={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node,...],
-%% Options=[Option,...],
-%% Option=keep_trace_patterns|keep_log_files
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={ok,{new,Status}}|{error,Reason}
-%% Status=running|{suspended,SReason}
-%%
-%% Stops all tracing including removing meta-trace patterns. If the node is tracing
-%% or idle, logs belonging to the current tracerdata are removed. Hence the node
-%% is returned to state 'new'. Note that node can still be suspended.
-clear() ->
- gen_server:call(?CONTROLLER,{clear,all,[]},?CALL_TIMEOUT).
-
-clear(Nodes) when is_list(Nodes) -> - gen_server:call(?CONTROLLER,{clear,Nodes,[]},?CALL_TIMEOUT).
-
-clear(Nodes,Options) when is_list(Nodes),is_list(Options) -> - gen_server:call(?CONTROLLER,{clear,Nodes,Options},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% flush()={ok,NodeResults} | NodeResult
-%% flush(Nodes)={ok,NodeResults}
-%% Nodes=[Node,...]
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok | {error,Reason}
-%% Sends a flush request to the trace-port driver on the nodes in Nodes.
-%% There will be an error for nodes that are not tracing. It is not an error to
-%% try to flush runtime components not using a trace-port.
-flush() ->
- gen_server:call(?CONTROLLER,{flush,all},?CALL_TIMEOUT).
-flush(Nodes) when is_list(Nodes) ->
- gen_server:call(?CONTROLLER,{flush,Nodes},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% stop()=shutdown
-%%
-%% Stops the controll component. Runtime components are left as is. They will
-%% behave according to their dependency values.
-stop() ->
- case catch gen_server:call(?CONTROLLER,stop,?CALL_TIMEOUT) of
- shutdown ->
- shutdown;
- {'EXIT',{noproc,_}} ->
- shutdown;
- {'EXIT',Reason} ->
- exit(Reason)
- end.
-%% -----------------------------------------------------------------------------
-
-%% stop_nodes()={ok,NodeResults}|NodeResult
-%% stop_nodes(Nodes)={ok,NodeResults}|{error,Reason}
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason}
-%%
-%% Stops runtime component on Nodes. stop_nodes/0 will if the control component
-%% is running on a distributed node stop all runtime components. And if running
-%% on a non distributed node, stop the local and only runtime component.
-stop_nodes() ->
- gen_server:call(?CONTROLLER,{stop_nodes,all},?CALL_TIMEOUT).
-stop_nodes(Nodes) when is_list(Nodes) ->
- gen_server:call(?CONTROLLER,{stop_nodes,Nodes},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% stop_all()={ok,NodeResults}|NodeResult
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason}
-%%
-%% A combination of stop/0 and stop_nodes/0.
-stop_all() ->
- gen_server:call(?CONTROLLER, stop_all,?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% tp(Nodes,Module,Function,Arity,MatchSpec,Opts)={ok,NodeResults}|{error,Reason}
-%% tp(Nodes,Module,Function,Arity,MatchSpec)={ok,NodeResults}|{error,Reason}
-%% tp(Module,Function,Arity,MatchSpec)={ok,NodeResults}|NodeResult|{error,Reason}
-%% tp(Nodes,PatternList)={ok,NodeResults}|{error,Reason}
-%% tp(PatternList)={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node,...]
-%% Module,Function=atom() | '_'
-%% Arity=integer() | '_'
-%% MatchSpec=true|false|[]| matchspec()
-%% PatternList=[Pattern,...],
-%% Pattern={Module,Function,Arity,MatchSpec,Opts},
-%% Opts=[Opt,...]
-%% Opt='only_loaded'; means that the runtime component shall not try to load
-%% a module should it not already be present in the runtime system.
-%% NodeResults=[NodeResult,...]
-%% NodeResult={ok,[Ans]}|{error,Reason},
-%% Ans=integer()|{error,Reason}
-%%
-%% Set trace pattern (global) on specified or all Nodes. The integer replied
-%% if the call was successfully describes the matched number of functions.
-%% The functions without a Nodes argument means all nodes, in a non-distributed
-%% environment it means the local node.
-%% When calling several nodes, the nodes are called in parallel.
-tp(Nodes,Module,Function,Arity,MatchSpec,Opts) ->
- trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,Opts}],[global]).
-
-tp(Nodes,Module,Function,Arity,MatchSpec) when is_list(Nodes) -> - trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,[]}],[global]);
-tp(Module,Function,Arity,MatchSpec,Opts) when is_atom(Module) -> - trace_pattern(all,[{Module,Function,Arity,MatchSpec,Opts}],[global]).
-
-tp(Module,Function,Arity,MatchSpec) ->
- trace_pattern(all,[{Module,Function,Arity,MatchSpec,[]}],[global]).
-
-tp(Nodes,PatternList) ->
- trace_pattern(Nodes,PatternList,[global]).
-
-tp(PatternList) ->
- trace_pattern(all,PatternList,[global]).
-%% -----------------------------------------------------------------------------
-
-%% tpl(Nodes,Module,Function,Arity,MatchSpec)={ok,NodeResults}|{error,Reason}
-%% tpl(Module,Function,Arity,MatchSpec)={ok,NodeResults}|NodeResult|{error,Reason}
-%% tpl(Nodes,PatternList)={ok,NodeResults}|{error,Reason}
-%% tpl(PatternList)={ok,NodeResults}|NodeResult|{error,Reason}
-%% see tp/X for description.
-%%
-%% Set trace pattern (local) on specified or all Nodes. The integer replied
-%% if the command was successfully describes the matched number of functions.
-%% The functions without a Nodes argument means all nodes, in a non-distributed
-%% environment it means the local node.
-%% When calling several nodes, the nodes are called in parallel.
-tpl(Nodes,Module,Function,Arity,MatchSpec,Opts) ->
- trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,Opts}],[local]).
-
-tpl(Nodes,Module,Function,Arity,MatchSpec) when is_list(Nodes) -> - trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,[]}],[local]);
-tpl(Module,Function,Arity,MatchSpec,Opts) when is_atom(Module) -> - trace_pattern(all,[{Module,Function,Arity,MatchSpec,Opts}],[local]).
-
-tpl(Module,Function,Arity,MatchSpec) ->
- trace_pattern(all,[{Module,Function,Arity,MatchSpec,[]}],[local]).
-
-tpl(Nodes, PatternList) ->
- trace_pattern(Nodes,PatternList,[local]).
-
-tpl(PatternList) ->
- trace_pattern(all,PatternList,[local]).
-%% -----------------------------------------------------------------------------
-
-%% ctp(Nodes,Module,Function,Arity)={ok,NodeResults}|{error,Reason}
-%% ctp(Module,Function,Arity)={ok,NodeResults}|NodeResult|{error,Reason}
-%% ctp(Nodes,PatternList)={ok,NodeResults}|{error,Reason}
-%% ctp(PatternList)={ok,NodeResults}|NodeResult|{error,Reason}
-%% PatternList=[{Mod,Func,Arity},...]
-%% see tp/X for other argument descriptions.
-%%
-%% Clear trace pattern (global) on specified or all Nodes. The integer replied
-%% if the call was successfully describes the matched number of functions.
-%% The functions without a Nodes argument means all nodes, in a non-distributed
-%% environment it means the local node.
-%% When calling several nodes, the nodes are called in parallel.
-ctp(Nodes,Module,Function,Arity) ->
- trace_pattern(Nodes,[{Module,Function,Arity,false,[only_loaded]}],[global]).
-
-ctp(Module,Function,Arity) ->
- trace_pattern(all,[{Module,Function,Arity,false,[only_loaded]}],[global]).
-
-ctp(Nodes,PatternList) when is_list(PatternList) -> - trace_pattern(Nodes,
- lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
- [global]).
-
-ctp(PatternList) when is_list(PatternList) -> - trace_pattern(all,
- lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
- [global]).
-%% -----------------------------------------------------------------------------
-
-%% ctpl(Nodes,Module,Function,Arity)={ok,NodeResults}|{error,Reason}
-%% ctpl(Module,Function,Arity)={ok,NodeResults}|NodeResult|{error,Reason}
-%% ctpl(Nodes,PatternList)={ok,NodeResults}|{error,Reason}
-%% ctpl(PatternList)={ok,NodeResults}|NodeResult|{error,Reason}
-%% see ctp/X for argument description.
-%%
-%% Clear trace pattern (local) on specified or all Nodes. The integer replied
-%% if the call was successfully describes the matched number of functions.
-%% The functions without a Nodes argument means all nodes, in a non-distributed
-%% environment it means the local node.
-%% When calling several nodes, the nodes are called in parallel.
-ctpl(Nodes,Module,Function,Arity) ->
- trace_pattern(Nodes,[{Module,Function,Arity,false,[only_loaded]}],[local]).
-
-ctpl(Module,Function,Arity) ->
- trace_pattern(all,[{Module,Function,Arity,false,[only_loaded]}],[local]).
-
-ctpl(Nodes,PatternList) when is_list(PatternList) -> - trace_pattern(Nodes,
- lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
- [local]).
-
-ctpl(PatternList) when is_list(PatternList) -> - trace_pattern(all,
- lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
- [local]).
-%% -----------------------------------------------------------------------------
-
-%% Help function doing the control component calling for all tp/X, tpl/X, ctp/X
-%% and ctpl/X functions.
-trace_pattern(Nodes,Patterns,FlagList) ->
- gen_server:call(?CONTROLLER, {trace_pattern, Nodes, Patterns, FlagList},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-%% -----------------------------------------------------------------------------
-
-%% tf(Nodes,PidSpec,FlagList)={ok,NodeResults}|{error,Reason}
-%% tf(PidSpec,FlagList)={ok,NodeResults}|NodeResult|{error,Reason}
-%% tf(Nodes,TraceConfList)={ok,NodeResults}|{error,Reason}
-%% tf(NodeTraceConfList)={ok,NodeResults}|{error,Reason}
-%% tf(TraceConfList)={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node,...],
-%% NodeTraceConfList=[{Node,TraceConfList}]
-%% TraceConfList=[{PidSpec,FlagList},...],
-%% FlagList=[Flags],
-%% PidSpec=all|new|existing|pid()|locally_registered_name()
-%% Flags= all process trace flags allowed.
-%% NodeResult={ok,[Ans]}|{error,Reason},
-%% Ans=integer() | {error,Reason}
-%%
-%% Set process trace flags on processes on all or specified Nodes. The integer
-%% return if the call was successfully describes the matched number of processes.
-%% The functions without a Nodes argument means all nodes, in a non-distributed
-%% environment it means the local node.
-%% There are many combinations which does not make musch scense. For instance
-%% specifying a certain pid at all nodes. Or an empty TraceConfList for all
-%% nodes.
-%% When calling several nodes, the nodes are called in parallel.
-tf(Nodes,PidSpec,FlagList) when is_list(Nodes),is_list(FlagList) -> - trace_flags(Nodes,[{PidSpec, FlagList}],true).
-
-tf(Nodes,TraceConfList) when is_list(Nodes),is_list(TraceConfList) -> - trace_flags(Nodes,TraceConfList,true);
-tf(PidSpec,FlagList) when is_list(FlagList) -> - trace_flags(all,[{PidSpec,FlagList}],true).
-
-tf(ArgList) when is_list(ArgList) -> % This one has triple functionality! - case ArgList of
- [{_Process,Flags}|_] when is_list(Flags),is_atom(hd(Flags))-> % A call to all nodes. - trace_flags(all,ArgList,true);
- [{_Node,TraceConfList}|_] when is_list(TraceConfList),is_tuple(hd(TraceConfList)) -> - trace_flags(ArgList,true);
- [{_Node,_TraceConfList,_How}|_] ->
- trace_flags(ArgList);
- [] -> % Stupid but allowed.
- trace_flags(all,ArgList,true) % Actually doesn't matter which we choose.
- end.
-%% -----------------------------------------------------------------------------
-
-%% ctf(Nodes,PidSpec,FlagList)={ok,NodeResults}|{error,Reason}
-%% ctf(PidSpec,FlagList)={ok,NodeResults}|NodeResult|{error,Reason}
-%% ctf(Nodes,TraceConfList)={ok,NodeResults}|{error,Reason}
-%% ctf(TraceConfList)={ok,NodeResults}|NodeResult|{error,Reason}
-%% see tf/X for arguments.
-%%
-%% Clear process trace flags on all or specified Nodes. The integer replied
-%% if the command was successfully describes the matched number of processes.
-%% The functions without a Nodes argument means all nodes, in a non-distributed
-%% environment it means the local node.
-%% When calling several nodes, the nodes are called in parallel.
-ctf(Nodes,PidSpec,FlagList) when is_list(Nodes),is_list(FlagList) -> - trace_flags(Nodes,[{PidSpec,FlagList}],false).
-
-ctf(Nodes,TraceConfList) when is_list(Nodes),is_list(TraceConfList) -> - trace_flags(Nodes,TraceConfList,false);
-ctf(PidSpec,FlagList) when is_list(FlagList) -> - trace_flags(all,[{PidSpec,FlagList}],false).
-
-ctf(TraceConfList) when is_list(TraceConfList) -> - trace_flags(all,TraceConfList,false).
-%% -----------------------------------------------------------------------------
-
-%% ctf_all(Nodes)={ok,NodeResults}|{error,Reason}
-%% ctf_all()={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node,...],
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason},
-%%
-%% Clears all trace flags on all or specified nodes. Just for convenience.
-ctf_all() ->
- gen_server:call(?CONTROLLER,{trace_flags,all,[{all,[all]}],false},?CALL_TIMEOUT).
-
-ctf_all(Nodes) ->
- gen_server:call(?CONTROLLER,{trace_flags,Nodes,[{all,[all]}],false},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% Help function to tf/X and ctf/X making the call to the control component.
-trace_flags(Nodes, TraceConfList, How) ->
- gen_server:call(?CONTROLLER, {trace_flags, Nodes, TraceConfList, How},?CALL_TIMEOUT).
-
-trace_flags(NodeTraceConfList,How) ->
- gen_server:call(?CONTROLLER,{trace_flags,NodeTraceConfList,How},?CALL_TIMEOUT).
-
-trace_flags(NodeTraceConfListHow) ->
- gen_server:call(?CONTROLLER,{trace_flags,NodeTraceConfListHow},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-%% -----------------------------------------------------------------------------
-
-%% tpm_localnames()={ok,NodeResults}|NodeResult|{error,Reason}
-%% tpm_localnames(Nodes)={ok,NodeResults}|{error,Reason}
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={ok,N}|{error,Reason}, Note that N can only be 0 or 1.
-%%
-%% Quick version for setting meta-trace patterns on erlang:register/2. It uses
-%% a default CallFunc and ReturnFunc in the meta-tracer server.
-%% The main purpose of this function is to create ti-log entries for printing
-%% the aliases for process instead of their process identities.
-tpm_localnames() ->
- tpm_localnames(all).
-
-tpm_localnames(Nodes) ->
- gen_server:call(?CONTROLLER,{meta_pattern,Nodes,{local_register,[]}},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% tpm_globalnames()={ok,NodeResults}|NodeResult|{error,Reason}
-%% tpm_globalnames(Nodes)={ok,NodeResults}|{error,Reason}
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={SubResult,SubResult}
-%% SubResult={ok,N}|{error,Reason}, Note that N can only be 0 or 1.
-%% As tpm_locanames/0,/1 but for registering names with global. Note that this
-%% actually involves setting meta trace patterns on two functions in global.
-tpm_globalnames() ->
- tpm_globalnames(all).
-
-tpm_globalnames(Nodes) ->
- gen_server:call(?CONTROLLER,{meta_pattern,Nodes,{global_register,[]}},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% init_tpm(Mod,Func,Arity,CallFunc)={ok,NodeResults}|NodeResult|{error,Reason}
-%% init_tpm(Nodes,Mod,Func,Arity,CallFunc)={ok,NodeResults}|{error,Reason}
-%% init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=
-%% {ok,NodeResults}|NodeResult|{error,Reason}
-%% init_tpm(Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=
-%% {ok,NodeResults}|{error,Reason}
-%%
-%% Mod,Func=Pointing out the function which shall be meta traced, atom().
-%% Arity=As above, integer().
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason}
-%%
-%% InitFunc,RemoveFunc={Module,Function}|fun(), functions being called when
-%% to initialize the public loopdata structure, and to reset it.
-%% InitFunc(Mod,Func,Arity,PublLD)->{ok,NewPublLD,Output}
-%% Supposed to initialize whatever needs to be done before
-%% handling any incoming meta-trace message for the Mod:Func/Arity.
-%% RemoveFunc(Mod,Func,Arity,PublLD)->{ok,NewPublLD}
-%% Called when meta tracing of Mod:Func/Arity is stopped. It is supposed
-%% to clear datastructures away from the PublLD.
-%% Initializes the public loopdata for this function. Note that we can not use wildcards
-%% here (even if it is perfectly legal in Erlang). It also sets the CallFunc and
-%% ReturnFunc for the meta traced function. The function is hence ready to be
-%% meta traced with either tpm/5 or tpm_ms/5.
-%% When calling several nodes, the nodes are called in parallel.
-init_tpm(Mod,Func,Arity,CallFunc) ->
- init_tpm(all,Mod,Func,Arity,CallFunc).
-
-init_tpm(Nodes,Mod,Func,Arity,CallFunc) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,
- Nodes,
- {init_tpm,
- [Mod,Func,Arity,CallFunc]}},
- ?CALL_TIMEOUT).
-
-init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
- init_tpm(all,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc).
-
-init_tpm(Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,
- Nodes,
- {init_tpm,
- [Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}},
- ?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% tpm(Mod,Func,Arity,MS)={ok,NodeResults}|NodeResult|{error,Reason}
-%% tpm(Nodes,Mod,Func,Arity,MS)={ok,NodeResults}|{error,Reason}
-%% tpm(Mod,Func,Arity,MS,CallFunc)={ok,NodeResults}|NodeResults|{error,Reason}
-%% tpm(Nodes,Mod,Func,Arity,MS,CallFunc)={ok,NodeResults}|{error,Reason}
-%% tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=
-%% {ok,NodeResults}|NodeResults|{error,Reason}
-%% tpm(Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=
-%% {ok,NodeResults}|{error,Reason}
-%%
-%% Mod,Func=atom() and not '_'.
-%% Arity=integer()
-%% MS=list(), matchspecification.
-%% Nodes=List of nodenames.
-%% InitFunc,CallFunc,ReturnFunc,RemoveFunc={Module,Function}|fun(),
-%% functions being called when these functions are called by the meta trace
-%% server at certain events.
-%% CallFunc(CallingPid,ActualArgList,PublLD)->{ok,NewPrivLD,Output}
-%% ReturnFunc(CallingPid,ReturnValue,PublLD)->{ok,NewPrivLD,Output}
-%% When a call respectively return_from trace message arrives for the meta
-%% traced function, the corresponding function is called.
-%% The ReturnFunc must handle the fact that a return_from message arrives
-%% for a call which was never noticed. This because the message queue of the
-%% meta tracer may have been emptied.
-%%
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={ok,N}|{error,Reason}, Note that N can only be 0 or 1.
-%%
-%% Activates meta-tracing in the inviso_rt_meta tracer. Except when using tpm/6,/8
-%% and /9 the function must first have been initiated using init_tpm. If running
-%% a non distributed system the variants without Node shall be used. If running
-%% in a distributed environment, without Node means all our nodes.
-%% When calling several nodes, the nodes are called in parallel.
-tpm(Mod,Func,Arity,MS) ->
- tpm(all,Mod,Func,Arity,MS).
-
-tpm(Nodes,Mod,Func,Arity,MS) when is_integer(Arity) -> - gen_server:call(?CONTROLLER,
- {meta_pattern,Nodes,{tpm,[Mod,Func,Arity,MS]}});
-tpm(Mod,Func,Arity,MS,CallFunc) when is_integer(Arity) -> - tpm(all,Mod,Func,Arity,MS,CallFunc).
-
-tpm(Nodes,Mod,Func,Arity,MS,CallFunc) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,Nodes,{tpm,[Mod,Func,Arity,MS,CallFunc]}}).
-
-tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
- tpm(all,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc).
-
-tpm(Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,
- Nodes,
- {tpm,
- [Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}},
- ?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% Same as tpm/X but the meta tracer will append {tracer,Tracer} to any enable
-%% list in a trace body action term.
-tpm_tracer(Mod,Func,Arity,MS) ->
- tpm_tracer(all,Mod,Func,Arity,MS).
-
-tpm_tracer(Nodes,Mod,Func,Arity,MS) when is_integer(Arity) -> - gen_server:call(?CONTROLLER,
- {meta_pattern,Nodes,{tpm_tracer,[Mod,Func,Arity,MS]}},
- ?CALL_TIMEOUT);
-tpm_tracer(Mod,Func,Arity,MS,CallFunc) when is_integer(Arity) -> - tpm_tracer(all,Mod,Func,Arity,MS,CallFunc).
-
-tpm_tracer(Nodes,Mod,Func,Arity,MS,CallFunc) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,Nodes,{tpm_tracer,[Mod,Func,Arity,MS,CallFunc]}}).
-
-tpm_tracer(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
- tpm_tracer(all,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc).
-
-tpm_tracer(Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,
- Nodes,
- {tpm_tracer,
- [Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}},
- ?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% tpm_ms(Mod,Func,Arity,MSname,MS)={ok,NodeResults}|NodeResult|{error,Reason}
-%% tpm_ms(Nodes,Mod,Func,Arity,MSname,MS)={ok,NodeResults}|{error,Reason}
-%% Nodes= List of all nodes where the function shall be carried out.
-%% Mod,Func=Pointing out the function to which we shall add a match-spec., atom().
-%% Arity=As above, integer().
-%% MSname=A name to be used if this MS shall be removed later. term().
-%% MatchSpec=List of match specification, Remember {return_trace}
-%% if expecting return_from messages.
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={ok,1}|{ok,0}|{error,Reason} where {ok,1} indicates that
-%% setting the matchspecification for the function succeeded.
-%%
-%% This function adds a list of match-specs to the already existing ones. It
-%% uses an internal database to keep track of existing match-specs. If the
-%% match-spec does not result in any meta traced functions (for whatever reason),
-%% the MS is not saved in the database. The previously known match-specs are
-%% not removed.
-%% The function must previously have been initiated in order for this function
-%% to add a match-spec.
-%% When calling several nodes, the nodes are called in parallel.
-tpm_ms(Mod,Func,Arity,MSname,MS) ->
- tpm_ms(all,Mod,Func,Arity,MSname,MS).
-
-tpm_ms(Nodes,Mod,Func,Arity,MSname,MS) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,Nodes,{tpm_ms,[Mod,Func,Arity,MSname,MS]}},
- ?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% Same as tpm_ms/5, /6 but the meta tracer will append {tracer,Tracer} to any enable
-%% list in a trace body action term.
-tpm_ms_tracer(Mod,Func,Arity,MSname,MS) ->
- tpm_ms_tracer(all,Mod,Func,Arity,MSname,MS).
-
-tpm_ms_tracer(Nodes,Mod,Func,Arity,MSname,MS) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,Nodes,{tpm_ms_tracer,[Mod,Func,Arity,MSname,MS]}},
- ?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% ctpm_ms(Mod,Func,Arity,MSname)={ok,NodeResults}|NodeResult|{error,Reason}
-%% ctpm_ms(Nodes,Mod,Func,Arity,MSname)={ok,NodeResults}|{error,Reason}
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason}
-%%
-%% Removes a named match-spec from the meta traced function. Note that it never
-%% is a fault to remove an MS. Not even from a function which is non existant.
-%% When calling several nodes, the nodes are called in parallel.
-ctpm_ms(Mod,Func,Arity,MSname) ->
- ctpm_ms(all,Mod,Func,Arity,MSname).
-
-ctpm_ms(Nodes,Mod,Func,Arity,MSname) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,Nodes,{ctpm_ms,[Mod,Func,Arity,MSname]}},
- ?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% ctpm(Mod,Func,Arity)={ok,NodeResults}|NodeResult|{error,Reason}
-%% ctpm(Node,Mod,Func,Arity)={ok,NodeResults}|{error,Reason}
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason}
-%%
-%% Removes the meta trace pattern for the function, means stops generating output
-%% for this function. The public LD may be cleared by the previously entered
-%% RemoveFunc.
-%% When calling several nodes, the nodes are called in parallel.
-ctpm(Mod,Func,Arity) ->
- ctpm(all,Mod,Func,Arity).
-
-ctpm(Nodes,Mod,Func,Arity) ->
- gen_server:call(?CONTROLLER,
- {meta_pattern,Nodes,{ctpm,[Mod,Func,Arity]}},
- ?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% ctpm_localnames()={ok,NodeResults}|NodeResult|{error,Reason}
-%% ctpm_localnames(Nodes)={ok,NodeResults}|{error,Reason}
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason}
-%%
-%% Removes meta-trace pattern for erlang:register/2, previously set by tpm_localnames.
-%% When calling several nodes, the nodes are called in parallel.
-ctpm_localnames() ->
- ctpm_localnames(all).
-
-ctpm_localnames(Nodes) ->
- gen_server:call(?CONTROLLER,{meta_pattern,Nodes,{remove_local_register,[]}},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% ctpm_localnames()={ok,NodeResults}|NodeResult|{error,Reason}
-%% ctpm_localnames(Nodes)={ok,NodeResults}|{error,Reason}
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={SubResult,Subresult}
-%% SubResult=ok|{error,Reason}
-%%
-%% Removes meta-trace pattern for the register functions in global. Note that there
-%% are two of them.
-%% When calling several nodes, the nodes are called in parallel.
-ctpm_globalnames() ->
- ctpm_globalnames(all).
-
-ctpm_globalnames(Nodes) ->
- gen_server:call(?CONTROLLER,{meta_pattern,Nodes,{remove_global_register,[]}},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% ctp_all(Nodes)={ok,NodeResults}|{error,Reason}
-%% ctp_all()={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node,...],
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason},
-%%
-%% Clears all both global and local trace patterns on all or specified nodes.
-%% Does not effect meta patterns.
-ctp_all() ->
- gen_server:call(?CONTROLLER,{ctp_all,all},?CALL_TIMEOUT).
-
-ctp_all(Nodes) ->
- gen_server:call(?CONTROLLER,{ctp_all,Nodes},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% suspend(Nodes,Reason)={ok,NodeResults}|{error,Reason}
-%% suspend(Reason)={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node],
-%% Reason=term(); supposed to describe the reason why suspended.
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason},
-%%
-%% Suspend all or specified Nodes with reason Reason. Suspend means that all
-%% process trace flags are removed and all meta-patterns.
-suspend(Nodes, Reason) ->
- gen_server:call(?CONTROLLER,{suspend,Reason,Nodes},?CALL_TIMEOUT).
-
-suspend(Reason) ->
- gen_server:call(?CONTROLLER,{suspend,Reason,all},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% cancel_suspension(Nodes)={ok,NodeResults}|{error,Reason}
-%% cancel_suspension()={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node,...],
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult=ok|{error,Reason},
-%% Cancel suspension on all or specified Nodes. Note that this does not imply
-%% that "business" is resumed as before. You must reactivate flags and meta-patter
-%% your self.
-cancel_suspension(Nodes) ->
- gen_server:call(?CONTROLLER,{cancel_suspension,Nodes},?CALL_TIMEOUT).
-
-cancel_suspension() ->
- gen_server:call(?CONTROLLER,{cancel_suspension,all},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% get_status(Nodes)={ok,NodeResults}|{error,Reason}
-%% get_status()={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node,...],
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={ok,{State,Status}}|{error,Reason},
-%% State=new|idle|tracing
-%% Status=running|{suspended,SReason}
-%%
-%% Get Status form all or specified runtime components.
-get_status(Nodes) when is_list(Nodes) -> - gen_server:call(?CONTROLLER,{get_status,Nodes},?CALL_TIMEOUT).
-
-get_status() ->
- gen_server:call(?CONTROLLER,{get_status,all},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% get_tracerdata()={ok,NodeResults}|NodeResult|{error,Reason}
-%% get_tracerdata(Nodes)={ok,NodeResults}|{error,Reason}
-%% Nodes=[Node,...],
-%% NodeResult={ok,NResult}|{error,Reason},
-%% NResult=TracerData|no_tracerdata
-%% TracerData will be exactly as it was specified when doing init_tracing.
-%%
-%% Get TracerData form all or specified runtime components.
-get_tracerdata() ->
- gen_server:call(?CONTROLLER,{get_tracerdata,all},?CALL_TIMEOUT).
-
-get_tracerdata(Nodes) when is_list(Nodes) ->
- gen_server:call(?CONTROLLER,{get_tracerdata,Nodes},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% list_logs(TracerData)={ok,NodeResults}|NodeResult|{error,Reason}
-%% list_logs(NodeList)={ok,NodeResults}|{error,Reason}
-%% list_logs()={ok,NodeResults}|NodeResult|{error,Reason}
-%% TracerData see init_tracing/1/2
-%% NodeList=[NodeSpec,...]
-%% NodeSpec=Node|{Node,TracerData}
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={ok,FileList}|{ok,no_log}|{error,Reason}
-%% FileList=[FileType,...], one or more of different types.
-%% FileType={trace_log,Dir,Files}|{ti_log,Dir,Files}
-%% Files=[FileNameWithOutPath,...]
-%%
-%% Ask local or specified runtime components for now existing logs given
-%% TracerData. If TracerData is left out, the runtime components TracerData,
-%% if existing, will be used instead.
-list_logs() ->
- gen_server:call(?CONTROLLER,list_logs,?CALL_TIMEOUT).
-
-list_logs(TracerDataOrNodesList) when is_list(TracerDataOrNodesList) -> - gen_server:call(?CONTROLLER,{list_logs,TracerDataOrNodesList},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-%% fetch_log(LogSpecList,DestDir,Prefix)={ok,NodeResults}|{error,not_distributed}|
-%% {error,Reason}
-%% fetch_log(DestDir,Prefix)={ok,NodeResults}|{error,not_distributed}|
-%% {error,Reason}
-%% fetch_log(ToNode,DestDir,Prefix)=
-%% fetch_log(ToNode,LogSpecList,DestDir,Prefix)=
-%% DestDir=string(), to where the fetched files shall be placed.
-%% Prefix=string(), prefix on locally saved fetched files.
-%% LogSpecList=[LogSpec,...],
-%% LogSpec={Node,FileSpecList}|Node|{Node,TracerData}
-%% TracerData=see init_tracing/1/2
-%% FileSpecList=[{trace_log,Dir,FileList},{ti_log,Dir,FileList}]
-%% where each tuple-item is optional.
-%% FileList=[RemoteFileName,...]
-%% ToNode=atom()
-%% NodeResult={Conclusion,ResultFileSpec}|no_log|{error,NReason}
-%% Conclusion=complete|incomplete
-%% ResultFileSpec=[{trace_log,FileResults},{ti_log,FileResults}]
-%% FileResults=[FileResult,...]
-%% FileResult={ok,FileName}|{error,FReason}
-%% NReason=own_node|Reason
-%% FReason = {file_open,{posix(),FileName}} |
-%% {file_open,{posix(),RemoteFileName}}
-%% {file_open,{posix(),[DestDir,Prefix,RemoteFileName]}}
-%% {file_write,{posix(),FileName}} |
-%% {truncated,FileName}
-%% {truncated,{Reason,FileName}}
-%% posix() - an atom which is named from the Posix error codes used in
-%% Unix, and in the runtime libraries of most C compilers.
-%% See module file in Kernel Reference manual.
-%%
-%% Copies logfiles over distributed erlang to ToNode. This
-%% function can only be used in a distributed system.
-%% The resulting transfered files will have the prefix Prefix and will be
-%% located in DestDir.
-%% Note that the client process using this function will wait until all files
-%% are moved. The job can be cancelled, causing any already copied files to be
-%% removed, by simply terminating the waiting client process.
-fetch_log(DestDir,Prefix) when is_list(DestDir),is_list(Prefix) -> - gen_server:call(?CONTROLLER,{fetch_log,node(),all,DestDir,Prefix},infinity).
-
-fetch_log(ToNode,DestDir,Prefix) when is_atom(ToNode),is_list(DestDir),is_list(Prefix) -> - gen_server:call(?CONTROLLER,{fetch_log,ToNode,all,DestDir,Prefix},infinity);
-
-fetch_log(LogSpecList,DestDir,Prefix) when is_list(LogSpecList),is_list(DestDir),is_list(Prefix) -> - gen_server:call(?CONTROLLER,{fetch_log,node(),LogSpecList,DestDir,Prefix},infinity).
-
-fetch_log(ToNode,LogSpecList,DestDir,Prefix)
- when is_atom(ToNode),is_list(LogSpecList),is_list(DestDir),is_list(Prefix) -> - gen_server:call(?CONTROLLER,{fetch_log,ToNode,LogSpecList,DestDir,Prefix},infinity).
-%% ------------------------------------------------------------------------------
-
-%% delete_log(Nodes,TracerData)={ok,NodeResults}|{error,Reason}
-%% delete_log(NodeSpecList)={ok,NodeResults}|{error,Reason}
-%% delete_log(Spec)={ok,NodeResults}|NodeResult|{error,Reason}
-%% delete_log(TracerData)={ok,NodeResults}|NodeResult|{error,Reason}
-%% delete_log()={ok,NodeResults}|NodeResult|{error,Reason}
-%% Nodes=[Node,...],
-%% NodeSpecList=[{Node,Spec},...]
-%% Spec=[AbsPathFileName,...]|LogSpecs
-%% LogSpecs=[LogSpec,...]
-%% LogSpec={trace_log,Dir,[FileNameWithoutPath,...]}|
-%% {ti_log,Dir,[FileNameWithoutPath,...]}
-%% TracerData = see init_tracing/1/2
-%% NodeResults=[{Node,NodeResult},...]
-%% NodeResult={ok,no_log}|{ok,LogInfos}|{ok,FileInfos}
-%% LogInfos=[LogInfo,...]
-%% LogInfo={trace_log,FileInfos}|{ti_log,FileInfos}
-%% FileInfos=[FileInfo,...]
-%% FileInfo={ok,FileName}|{error,Reason} whether FileName contains
-%% full path or not depends on if AbsPathFileName or LogSpec was
-%% used when specifying the files.
-%%
-%% Deletes listed files or files corresponding to TracerData from specified
-%% or all Nodes. If no TracerData or list of files is specified in the call the
-%% TracerData at Node will be used to identify log files to delete.
-delete_log() ->
- gen_server:call(?CONTROLLER,{delete_log,all},?CALL_TIMEOUT).
-delete_log(What) ->
- gen_server:call(?CONTROLLER,{delete_log,What},?CALL_TIMEOUT).
-delete_log(Nodes,Spec) ->
- gen_server:call(?CONTROLLER,{delete_log,Nodes,Spec},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% subscribe()= same as subscribe(self())
-%% subscribe(Pid)=ok|{error,Reason}
-%% Pid=pid(),
-%% Reason =
-%% Add Pid or self() to event sending list. Note that it is possible to add a
-%% pid several times and that the Pid then will receive several event messages.
-%% All events will be sent to all subscribers in the event sending list.
-%% Event={inviso_event,ControllerPid,erlang:localtime(),Msg},
-%% Msg=
-%% {connected, Node, {Tag, {State, Status}}}
-%% {disconnected, Node, not_applicable}
-%% {state_change, Node, {State, Status}}
-%% {port_down, Node, Reason}
-%% Node = node() | local_runtime (when running in a non-distributed
-%% environment)
-subscribe() ->
- gen_server:call(?CONTROLLER,{subscribe,self()},?CALL_TIMEOUT).
-
-subscribe(Pid) ->
- gen_server:call(?CONTROLLER,{subscribe,Pid},?CALL_TIMEOUT).
-%% -----------------------------------------------------------------------------
-
-%% unsubscribe()= same as unsubscribe(self())
-%% unsubscribe(Pid)=ok
-%% Pid=pid(),
-%%
-%% Remove, if present, first occurrence of Pid or self() from event sending
-%% list. Note that it is not an error to remove a non existing subscription.
-unsubscribe() ->
- gen_server:call(?CONTROLLER,{unsubscribe,self()},?CALL_TIMEOUT).
-
-unsubscribe(Pid) ->
- gen_server:call(?CONTROLLER,{unsubscribe,Pid},?CALL_TIMEOUT).
-%% ------------------------------------------------------------------------------
-
-
-
-%% debuging the controller
-%% ----------------------------------------------------------------------------
-state() ->
- ?CONTROLLER ! state.
-
-%% debuging the runtime component
-state(Node) ->
- ?CONTROLLER ! {state, Node}.
-
-%%% end of file
diff --git a/lib/inviso/src/inviso_c.erl b/lib/inviso/src/inviso_c.erl deleted file mode 100644 index b1597a7f35..0000000000 --- a/lib/inviso/src/inviso_c.erl +++ /dev/null @@ -1,1335 +0,0 @@ -%% ``The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved via the world wide web at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. -%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -%% AB. All Rights Reserved.'' -%% -%% $Id$ -%% -%% Author: Ann-Marie L�f, [email protected] -%% Lennart �hman, [email protected] -%% -%% Description: The controlling part of the trace tool Inviso -%% -%% This code implements the inviso control component meant to be run on an Erlang -%% node doing any tracing. It can also be used in a non distributed system where -%% the control component and the runtime component will run on the same virtual -%% machine. -%% The control component is not meant to be started by a supervisor but rather -%% directly by the user when needed. -%% This module does not provide any APIs to users. Those are found in inviso.erl. -%% This module merly has the gen_server call-backs. -%% ------------------------------------------------------------------------------ - --module(inviso_c). --behavior(gen_server). - - -%% ------------------------------------------------------------------------------ -%% gen_server callbacks. -%% ------------------------------------------------------------------------------ --export([init/1, - handle_call/3,handle_cast/2,handle_info/2, - terminate/2, - code_change/3]). -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Exported internal functions (used in spawn of help process). -%% ------------------------------------------------------------------------------ --export([log_rec_init/4]). - -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Records. -%% ------------------------------------------------------------------------------ - -%% #state -%% Record used in the loopdata. --record(state,{ - nodes=[], % [#node,...] - distributed, % false | true - subscribers=[], % [{pid(),monitor_ref()},...] - rt_options=[{dependency,{infinity,node()}},{overload, default}] - }). -%% ------------------------------------------------------------------------------ - -%% #node -%% Record storing information about a runtime component connected to this control -%% component. --record(node,{ - node, % [atom(),...] - pid, % pid() - vsn, - ref, % monitor_ref() - tag % term() - }). -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Macros used in this module. -%% ------------------------------------------------------------------------------ - --define(RUNTIME,inviso_rt). % The module API name of the runtime. -%% ------------------------------------------------------------------------------ - - - -%% ============================================================================== -%% Controller component implmentation. -%% ============================================================================== - -init({_Parent,Options}) -> - process_flag(trap_exit,true), - case check_options(Options,start) of - {ok,Options2} -> - LoopData=initiate_state(Options2), - {ok,LoopData}; - Error -> - {stop,Error} - end. -%% ------------------------------------------------------------------------------ - -handle_call({subscribe,Pid},_From,LD) when is_pid(Pid) -> - MRef=erlang:monitor(process,Pid), - {reply,ok,LD#state{subscribers=[{Pid,MRef}|LD#state.subscribers]}}; -handle_call({subscribe,Faulty},_From,LD) -> - {reply,{error,{badarg,Faulty}},LD}; -handle_call({unsubscribe,Pid},_From,LD) -> - case lists:keysearch(Pid,1,LD#state.subscribers) of - {value,{_,MRef}} -> - erlang:demonitor(MRef), - {reply,ok,LD#state{subscribers=lists:keydelete(Pid,1,LD#state.subscribers)}}; - false -> - {reply,ok,LD} - end; -handle_call({add_nodes,Nodes,Opts,Tag,Condition},_From,LD) -> - case check_options(Opts,add_node) of - {ok,Opts2} -> - Opts3=merge_options(LD#state.rt_options,Opts2), - {NewLD,Reply}=do_add_nodes(Nodes,LD,Opts3,Tag,Condition), - {reply,adapt_reply(NewLD,Reply),NewLD}; - Error -> - {reply,Error,LD} - end; -handle_call({change_options,Nodes,Opts},_From,LD) -> - case check_options(Opts,add_node) of - {ok,Opts2} -> - {reply,adapt_reply(LD,do_change_option(Nodes,Opts2,LD)),LD}; - Error -> - {reply,Error,LD} - end; -handle_call({init_tracing,TracerDataList},_From,LD) -> - {reply,adapt_reply(LD,do_init_tracing(TracerDataList,LD)),LD}; -handle_call({init_tracing,Nodes,TracerData},_From,LD) when is_list(Nodes) -> - TracerDataList= - lists:map(fun(N)->{N,TracerData} end,started_trace_nodes(Nodes,LD)), - {reply,adapt_reply(LD,do_init_tracing(TracerDataList,LD)),LD}; -handle_call({init_tracing,Nodes,_TracerData},_From,LD) -> - {reply,{error,{badarg,Nodes}},LD}; -handle_call({trace_pattern,Nodes,Patterns,FlagList},_From,LD) -> - {reply,adapt_reply(LD,distribute_tp(Nodes,Patterns,FlagList,LD)),LD}; -handle_call({trace_flags,Nodes,Args,How},_From,LD) -> - {reply,adapt_reply(LD,distribute_tf(Nodes,Args,How,LD)),LD}; -handle_call({trace_flags,NodeArgs,How},_From,LD) -> - {reply,distribute_tf(NodeArgs,How,LD),LD}; % Always distributed here. -handle_call({trace_flags,NodeArgHows},_From,LD) -> - {reply,distribute_tf(NodeArgHows,LD),LD}; % Always distributed here. -handle_call({meta_pattern,Nodes,Args},_From,LD) -> - {reply,adapt_reply(LD,distribute_metapattern(Nodes,Args,LD)),LD}; -handle_call({ctp_all,Nodes},_From,LD) -> - {reply,adapt_reply(LD,do_ctp_all(Nodes,LD)),LD}; -handle_call({suspend,Reason,Nodes},_From,LD) -> - {reply,adapt_reply(LD,do_suspend(Nodes,Reason,LD)),LD}; -handle_call({cancel_suspension,Nodes},_From,LD) -> - {reply,adapt_reply(LD,do_cancel_suspension(Nodes,LD)),LD}; -handle_call({stop_tracing,Nodes},_From,LD) -> - {reply,adapt_reply(LD,do_stop_tracing(Nodes,LD)),LD}; -handle_call({get_status,Nodes},_From,LD) -> - {reply,adapt_reply(LD,do_get_status(Nodes,LD)),LD}; -handle_call({get_tracerdata,Nodes},_From,LD) -> - {reply,adapt_reply(LD,do_get_tracerdata(Nodes,LD)),LD}; -handle_call(list_logs,_From,LD) -> - {reply,adapt_reply(LD,do_list_logs(all,LD)),LD}; -handle_call({list_logs,TracerDataOrNodesList},_From,LD) -> - {reply,adapt_reply(LD,do_list_logs(TracerDataOrNodesList,LD)),LD}; -handle_call({fetch_log,ToNode,Spec,Dest,Prefix},From,LD) -> - case LD#state.distributed of - true -> % It is a distributed system. - do_fetch_log(ToNode,Spec,Dest,Prefix,From,LD), - {noreply,LD}; % Reply will come from collector pid. - false -> % Stupidity! you dont want this! - {reply,{error,not_distributed},LD} - end; -handle_call({delete_log,NodesOrNodeSpecs},_From,LD) -> - {reply,adapt_reply(LD,do_delete_log(NodesOrNodeSpecs,LD)),LD}; -handle_call({delete_log,Nodes,Specs},_From,LD) when is_list(Nodes) -> - Reply=do_delete_log(lists:map(fun(N)->{N,Specs} end,Nodes),LD), - {reply,adapt_reply(LD,Reply),LD}; -handle_call({delete_log,FaultyNodes,_Specs},_From,LD) -> - {reply,{error,{badarg,FaultyNodes}},LD}; -handle_call({clear,Nodes,Options},_From,LD) -> - {reply,adapt_reply(LD,do_clear(Nodes,LD,Options)),LD}; -handle_call({flush,Nodes},_From,LD) -> - {reply,adapt_reply(LD,do_flush(Nodes,LD)),LD}; -handle_call({stop_nodes,Nodes},_From,LD) -> - {NewLD,Reply}=do_stop_nodes(Nodes,LD), - {reply,adapt_reply(NewLD,Reply),NewLD}; -handle_call(stop,_From,LD) -> - {stop,normal,shutdown,LD}; -handle_call(stop_all,_From,LD) -> - {NewLD,Reply}=do_stop_nodes(started_trace_nodes(all,LD),LD), - {stop,normal,adapt_reply(NewLD,Reply),NewLD}; -handle_call(Request,_From,LD) -> %% for debug purpose only - {reply,{error,{invalid_request,Request}},LD}. - -handle_cast(_Request,LD) -> % There are no casts. - {noreply,LD}. - -handle_info({connect,_Node,Pid,_VSN,Tag},LD) -> % From connecting runtime. - {noreply,do_confirm_connection(Pid,Tag,LD)}; -handle_info({trace_event,Event},LD) -> % A runtime component issues an event. - send_to_subscribers(Event,LD), % Relay to our subscribers. - {noreply,LD}; -handle_info({'DOWN',Ref,process,_From,Info},LD) -> % A runtime component died? - {noreply,do_down_msg(Ref,Info,LD)}; -handle_info(state,LD) -> % For debug purposes. - io:format("trace_c state: ~p~n",[LD]), - {noreply,LD}; -handle_info(_Msg,LD) -> - {noreply,LD}. - -terminate(_Reason, _LD) -> - ok. - -code_change(_OldVsn, LoopData, _Extra) -> - {ok, LoopData}. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% Handle call help functions. -%% ----------------------------------------------------------------------------- - -%% Help function which adapts a reply based on if this is a distributed system -%% or not. The first argument indicates distribution (='true'). -%% If we are not running a distributed system, all node references are removed. -adapt_reply(#state{distributed=Distributed},Reply) -> - adapt_reply(Distributed,Reply); -adapt_reply(true,Reply) -> % We are distributed. - Reply; -adapt_reply(false,{ok,[{_Node,LocalReply}]}) -> - LocalReply; -adapt_reply(false,{ok,[]}) -> - {error,not_an_added_node}; % �R DET H�R VERKLIGEN RIKTIGT? -adapt_reply(false,Reply) -> - Reply. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% First level help functions to handler functions. -%% ============================================================================== - -%% Function starting a runtime component at the nodes in Nodes. If doing non -%% distributed, Nodes will be a list of nonode@nohost. -%% Returns {NewLD,{ok,Replies}} or {LD,{error,Reason}}. -do_add_nodes(Nodes,LD,Options,Tag,Condition) -> - do_add_nodes_2(Nodes,LD,Options,Tag,Condition,[]). - -do_add_nodes_2([Node|Tail],LD,Options,Tag,Condition,Replies) -> - case find(fun is_started/2,LD#state.nodes,Node) of - {value,true} -> % Already started by us. - do_add_nodes_2(Tail,LD,Options,Tag,Condition,[{Node,{ok,already_added}}|Replies]); - no_match -> - case ?RUNTIME:start(Node,Options,Tag,Condition) of - {node_info,_Node,Pid,VSN,State,Status,new} -> - NewLD=do_add_nodes_3(Node,LD,Tag,Pid,VSN,State,Status), - do_add_nodes_2(Tail,NewLD,Options,Tag,Condition,[{Node,{ok,new}}|Replies]); - {node_info,_Node,Pid,VSN,State,Status,{tag,Tag2}} -> - NewLD=do_add_nodes_3(Node,LD,Tag,Pid,VSN,State,Status), - do_add_nodes_2(Tail,NewLD,Options,Tag,Condition, - [{Node,{ok,{adopted,State,Status,Tag2}}}|Replies]); - Error -> - do_add_nodes_2(Tail,LD,Options,Tag,Condition,[{Node,Error}|Replies]) - end - end; -do_add_nodes_2([],LD,_,_,_,Replies) -> - {LD,{ok,lists:reverse(Replies)}}; -do_add_nodes_2(Faulty,LD,_,_,_,_) -> % Not a list of nodes. - {LD,{error,{badarg,Faulty}}}. - -do_add_nodes_3(Node,LD,Tag,Pid,VSN,State,Status) -> - MRef=erlang:monitor(process,Pid), - NodeRec=#node{node=Node,pid=Pid,vsn=VSN,ref=MRef,tag=Tag}, - send_to_subscribers({connected,Node,{Tag,{State,Status}}},LD), - _NewLD=set_node_rec(NodeRec,LD). -%% ------------------------------------------------------------------------------ - -%% Function calling change_options sequensially on all nodes in Nodes. -%% Returns {ok,Replies} or {error,Reason}. -do_change_option(Nodes,Options,LD) -> - do_change_option_2(started_trace_nodes(Nodes,LD#state.nodes),Options,LD,[]). - -do_change_option_2([Node|Tail],Options,LD,Replies) -> - case get_node_rec(Node,LD) of - Rec when is_record(Rec,node) -> - Answer=?RUNTIME:change_options(Rec#node.pid,Options), - do_change_option_2(Tail,Options,LD,[{Node,Answer}|Replies]); - Error -> - do_change_option_2(Tail,Options,LD,[{Node,Error}|Replies]) - end; -do_change_option_2([],_Options,_LD,Replies) -> - {ok,Replies}; -do_change_option_2(Faulty,_,_,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function which calls the runtime components in TracerDataList and initiates -%% the tracing. TracerDataList may either be just one tracer data which shall be -%% applied to all runtime components, or a list of nodes and tracerdata. -do_init_tracing(TracerDataList,LD) -> - case inviso_rt_lib:is_tracerdata(TracerDataList) of - true -> % Then we must add all our nodes. - List=lists:map(fun(N)->{N,TracerDataList} end,started_trace_nodes(all,LD)), - do_init_tracing_2(List,LD,[]); - false -> % Assume it is a list of {Node,Tracerdata} - do_init_tracing_2(TracerDataList,LD,[]) - end. - -do_init_tracing_2([{Node,TracerData}|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - Rec when is_record(Rec,node) -> - case check_modify_tracerdata(TracerData,LD) of - {ok,NewTracerData} -> % Tracerdata ok and node->pid. - Reply=?RUNTIME:init_tracing(Rec#node.pid,NewTracerData), - do_init_tracing_2(Tail,LD,[{Node,Reply}|Replies]); - {error,Reason} -> % Unknown tracerdata. - do_init_tracing_2(Tail,LD,[{Node,{error,Reason}}|Replies]) - end; - {error,Reason} -> - do_init_tracing_2(Tail,LD,[{Node,{error,Reason}}|Replies]) - end; -do_init_tracing_2([_|Tail],LD,Replies) -> % Just ignore item we don't understand. - do_init_tracing_2(Tail,LD,Replies); % Will not end up in Replies either. -do_init_tracing_2([],_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_init_tracing_2(What,_LD,_) -> - {error,{badarg,What}}. -%% ----------------------------------------------------------------------------- - -%% Function setting trace patterns on all nodes mentioned in Nodes. Uses a -%% parallel mechanism in the runtime component. -%% Returns {ok,Reply} or {error,Reason}. -distribute_tp(all,Patterns,FlagList,LD) -> - distribute_tp(started_trace_nodes(all,LD),Patterns,FlagList,LD); -distribute_tp(Nodes,Patterns,FlagList,LD) when is_list(Nodes) -> - RTpids=lists:map(fun(N)->case get_node_rec(N,LD) of - #node{pid=Pid} -> - {Pid,N}; - Error -> - {Error,N} - end - end, - Nodes), - {ok,?RUNTIME:trace_patterns_parallel(RTpids,Patterns,FlagList)}; -distribute_tp(Faulty,_,_,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function which in parallel sets trace flags on all nodes in Nodes. Can be -%% either a list of node names or 'all'. Note that in the reply list there will be an -%% error indicating nodes not reachable. Either because such a node disappeared or -%% because it is not one of "our" nodes. -%% Returns {ok,Reply} or {error,Reason}. -distribute_tf(all,Args,How,LD) -> - distribute_tf(started_trace_nodes(all,LD),Args,How,LD); -distribute_tf(Nodes,Args,How,LD) when is_list(Nodes) -> - RTpids=lists:map(fun(Node)-> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - {Pid,Node}; - Error -> % Not an added node then! - {Error,Node} - end - end, - Nodes), - {ok,?RUNTIME:trace_flags_parallel(RTpids,Args,How)}; -distribute_tf(Faulty,_,_,_) -> - {error,{badarg,Faulty}}. - -%% As above but specific args for each node. -distribute_tf(NodeArgs,How,LD) when is_list(NodeArgs) -> - RTpidArgs=lists:map(fun({Node,Args})-> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - {Pid,Node,Args}; - Error -> % Not an added node then! - {Error,Node} - end - end, - NodeArgs), - {ok,?RUNTIME:trace_flags_parallel(RTpidArgs,How)}; -distribute_tf(Faulty,_,_) -> - {error,{badarg,Faulty}}. - -%% As above but both specific args for each node and How (set or remove flag). -distribute_tf(NodeArgHows,LD) when is_list(NodeArgHows) -> - RTpidArgHows= - lists:map(fun({Node,Args,How}) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - {Pid,Node,Args,How}; - Error -> % Not an added node then! - {Error,Node} - end - end, - NodeArgHows), - {ok,?RUNTIME:trace_flags_parallel(RTpidArgHows)}; -distribute_tf(Faulty,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function making a parallel call to all nodes in Nodes, calling the generic -%% meta-tracer function stated in Args. -%% Returns {ok,Reply} or {error,Reason}. -distribute_metapattern(all,Args,LD) -> - distribute_metapattern(started_trace_nodes(all,LD),Args,LD); -distribute_metapattern(Nodes,Args,LD) when is_list(Nodes) -> - RTpids=lists:map(fun(N)->case get_node_rec(N,LD) of - #node{pid=Pid} -> - {Pid,N}; - Error -> - {Error,N} - end - end, - Nodes), - {ok,?RUNTIME:meta_tracer_call_parallel(RTpids,Args)}; -distribute_metapattern(Faulty,_,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function clearing all trace patterns on all node mentioned in Nodes. -%% Returns {ok,Reply} or {error,Reason}. -do_ctp_all(Nodes,LD) -> - do_ctp_all_2(started_trace_nodes(Nodes,LD),LD,[]). - -do_ctp_all_2([Node|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - do_ctp_all_2(Tail,LD,[{Node,?RUNTIME:clear_all_tp(Pid)}|Replies]); - Error -> - do_ctp_all_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_ctp_all_2([],_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_ctp_all_2(Faulty,_,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function suspending all runtime components mentioned in Nodes. -%% Returns {ok,Reply} or {error,Reason}. -do_suspend(Nodes,Reason,LD) -> - do_suspend_2(started_trace_nodes(Nodes,LD),Reason,LD,[]). - -do_suspend_2([Node|Tail],Reason,LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - Answer=?RUNTIME:call_suspend(Pid,Reason), - do_suspend_2(Tail,Reason,LD,[{Node,Answer}|Replies]); - Error -> - do_suspend_2(Tail,Reason,LD,[{Node,Error}|Replies]) - end; -do_suspend_2([],_Reason,_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_suspend_2(Faulty,_,_,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function cancelling a suspension at the runtime components mentioned in Nodes. -%% Returns {ok,Reply} or {error,Reason}. -do_cancel_suspension(Nodes,LD) -> - do_cancel_suspension_2(started_trace_nodes(Nodes,LD),LD,[]). - -do_cancel_suspension_2([Node|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - Answer=?RUNTIME:cancel_suspension(Pid), - do_cancel_suspension_2(Tail,LD,[{Node,Answer}|Replies]); - Error -> - do_cancel_suspension_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_cancel_suspension_2([],_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_cancel_suspension_2(Faulty,_,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function which stops tracing on all nodes in Nodes. The function is performed -%% in parallel over the nodes to get a more precise stop-time. -%% Return {ok,Reply} or {error,Reason}. -do_stop_tracing(all,LD) -> - do_stop_tracing(started_trace_nodes(all,LD),LD); -do_stop_tracing(Nodes,LD) when is_list(Nodes) -> - RTpids=lists:map(fun(N)->case get_node_rec(N,LD) of - #node{pid=Pid} -> - {Pid,N}; - Error -> - {Error,N} - end - end, - Nodes), - {ok,?RUNTIME:stop_tracing_parallel(RTpids)}; -do_stop_tracing(Faulty,_) -> - {error,{badarg,Faulty}}. -%% ----------------------------------------------------------------------------- - -%% Function fetching the current status of the runtime components in Nodes. -%% Returns {ok,Reply} or {error,Reason}. -do_get_status(Nodes,LD) -> - do_get_status_2(started_trace_nodes(Nodes,LD),LD,[]). - -do_get_status_2([Node|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - do_get_status_2(Tail,LD,[{Node,?RUNTIME:get_status(Pid)}|Replies]); - Error -> - do_get_status_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_get_status_2([],_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_get_status_2(Faulty,_,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function retrieving the tracerdata for the nodes in Nodes. -%% Returns {ok,Reply} or {error,Reason}. -do_get_tracerdata(Nodes,LD) -> - do_get_tracerdata_2(started_trace_nodes(Nodes,LD),LD,[]). - -do_get_tracerdata_2([Node|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - do_get_tracerdata_2(Tail,LD,[{Node,?RUNTIME:get_tracerdata(Pid)}|Replies]); - Error -> - do_get_tracerdata_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_get_tracerdata_2([],_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_get_tracerdata_2(Faulty,_,_) -> - {error,{badarg,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Function that lists all logfiles associated with a certain tracerdata -%% or the current tracerdata should no tracerdata be mentioned. -%% Returns {ok,Replies} or {error,Reason}. -do_list_logs(all,LD) -> % When doing all known nodes. - do_list_logs_2(started_trace_nodes(all,LD),LD,[]); -do_list_logs(TracerDataOrNodesList,LD) -> - case inviso_rt_lib:is_tracerdata(TracerDataOrNodesList) of - true -> % It is tracerdata for this node. - do_list_logs_2([{node(),TracerDataOrNodesList}],LD,[]); - false -> - do_list_logs_2(TracerDataOrNodesList,LD,[]) - end. - -do_list_logs_2([{Node,TD}|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - case check_modify_tracerdata(TD,LD) of - {ok,TracerData} -> - Answer=?RUNTIME:list_logs(Pid,TracerData), - do_list_logs_2(Tail,LD,[{Node,Answer}|Replies]); - Error -> - do_list_logs_2(Tail,LD,[{Node,Error}|Replies]) - end; - Error -> - do_list_logs_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_list_logs_2([Node|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - Answer=?RUNTIME:list_logs(Pid), - do_list_logs_2(Tail,LD,[{Node,Answer}|Replies]); - Error -> - do_list_logs_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_list_logs_2([],_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_list_logs_2(Other,_LD,_Replies) -> - {error,{badarg,Other}}. -%% ----------------------------------------------------------------------------- - -%% Function fetching logfiles using distributed erlang. This function does not -%% return anything significant. This since the reply to the client is always -%% sent by the CollectPid unless there is badarg fault detected before the -%% CollectPid is spawned. Note that this function sends a list of fetchers from -%% which the CollectPid shall expect replies. -%% We try to catch some bad arguments like Destination and Prefix not being -%% strings. However the fact that they are lists does not guarantee they are -%% proper strings. -do_fetch_log(ToNode,all,Dest,Prefix,From,LD) -> - do_fetch_log(ToNode,started_trace_nodes(all,LD),Dest,Prefix,From,LD); -do_fetch_log(ToNode,Specs,Dest,Prefix,From,LD) when is_list(Dest),is_list(Prefix) -> - CollectPid=spawn_link(ToNode,?MODULE,log_rec_init,[self(),Dest,Prefix,From]), - do_fetch_log_2(Specs,LD,CollectPid,[],[]); -do_fetch_log(_ToNode,_Specs,Dest,Prefix,From,_LD) -> - gen_server:reply(From,{error,{badarg,[Dest,Prefix]}}). - -do_fetch_log_2([{Node,Spec}|Rest],LD,CollectPid,Fetchers,Replies) -> - if - Node==node() -> % This is plain stupid! - do_fetch_log_2(Rest,LD,CollectPid,Fetchers,[{Node,{error,own_node}}|Replies]); - true -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - {NewFetchers,NewReplies}= - do_fetch_log_3(Fetchers, - Replies, - Node, - ?RUNTIME:fetch_log(Pid,CollectPid,Spec)), - do_fetch_log_2(Rest,LD,CollectPid,NewFetchers,NewReplies); - Error -> % Most likely the node does not exist. - do_fetch_log_2(Rest,LD,CollectPid,Fetchers,[{Node,Error}|Replies]) - end - end; -do_fetch_log_2([Node|Rest],LD,CollectPid,Fetchers,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - {NewFetchers,NewReplies}= - do_fetch_log_3(Fetchers,Replies,Node,?RUNTIME:fetch_log(Pid,CollectPid)), - do_fetch_log_2(Rest,LD,CollectPid,NewFetchers,NewReplies); - Error -> % Most likely the node does not exist. - do_fetch_log_2(Rest,LD,CollectPid,Fetchers,[{Node,Error}|Replies]) - end; -do_fetch_log_2([],_,CollectPid,Fetchers,Replies) -> - CollectPid ! {?MODULE,self(),Fetchers,Replies}; -do_fetch_log_2(FaultySpec,_,CollectPid,_Fetchers,_Replies) -> - CollectPid ! {?MODULE,self(),[],{error,{badarg,FaultySpec}}}. - -do_fetch_log_3(Fetchers,Replies,Node,{ok,Fetcher}) -> - {[{Node,Fetcher}|Fetchers],Replies}; -do_fetch_log_3(Fetchers,Replies,Node,{complete,no_log}) -> - {Fetchers,[{Node,{complete,no_log}}|Replies]}; -do_fetch_log_3(Fetchers,Replies,Node,{error,Reason}) -> - {Fetchers,[{Node,{error,Reason}}|Replies]}. -%% ----------------------------------------------------------------------------- - -%% Function removing files from the runtime components. We can either ask for -%% all files associated with the current tracerdata to be removed, or provide -%% tracerdata or a list of files to be removed. -%% Returns the client reply. -do_delete_log(all,LD) -> - do_delete_log_2(started_trace_nodes(all,LD),LD,[]); -do_delete_log(NodeSpecs,LD) -> - case inviso_rt_lib:is_tracerdata(NodeSpecs) of - true -> % It is tracerdata for all nodes. - do_delete_log_2(lists:map(fun(N)->{N,NodeSpecs} end, - started_trace_nodes(all,LD)), - LD,[]); - false -> - if - is_list(NodeSpecs),is_list(hd(NodeSpecs)) -> % A list of files. - do_delete_log_2(lists:map(fun(N)->{N,NodeSpecs} end, - started_trace_nodes(all,LD)), - LD,[]); - true -> % Then use it as is. - do_delete_log_2(NodeSpecs,LD,[]) - end - end. - -do_delete_log_2([{Node,Spec}|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - do_delete_log_2(Tail,LD,[{Node,?RUNTIME:delete_log(Pid,Spec)}|Replies]); - Error -> - do_delete_log_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_delete_log_2([Node|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - do_delete_log_2(Tail,LD,[{Node,?RUNTIME:delete_log(Pid)}|Replies]); - Error -> - do_delete_log_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_delete_log_2([],_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_delete_log_2(Faulty,_,_) -> - {error,{badarg,Faulty}}. -%% ----------------------------------------------------------------------------- - -%% Function removing files from runtime components. -%% Returns {ok,Replies} or {error,Reason}. -do_clear(Nodes,LD,Options) -> - do_clear_2(started_trace_nodes(Nodes,LD),LD,Options,[]). - -do_clear_2([Node|Tail],LD,Options,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - do_clear_2(Tail,LD,Options,[{Node,?RUNTIME:clear(Pid,Options)}|Replies]); - Error -> - do_clear_2(Tail,LD,Options,[{Node,Error}|Replies]) - end; -do_clear_2([],_LD,_Options,Replies) -> - {ok,lists:reverse(Replies)}; -do_clear_2(FaultyNodes,_LD,_Options,_Replies) -> - {error,{badarg,FaultyNodes}}. -%% ----------------------------------------------------------------------------- - -%% Function doing a flush trace-port. -%% Returns {ok,Replies} or {error,Reason}. -do_flush(Nodes,LD) -> - do_flush_2(started_trace_nodes(Nodes,LD),LD,[]). - -do_flush_2([Node|Rest],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{pid=Pid} -> - do_flush_2(Rest,LD,[{Node,?RUNTIME:flush(Pid)}|Replies]); - Error -> - do_flush_2(Rest,LD,[{Node,Error}|Replies]) - end; -do_flush_2([],_LD,Replies) -> - {ok,lists:reverse(Replies)}; -do_flush_2(FaultyNodes,_LD,_Replies) -> - {error,{badarg,FaultyNodes}}. -%% ----------------------------------------------------------------------------- - -%% Function stopping runtime components. We can only stop runtime components -%% belonging to this control component. -%% Returns {NewLoopdata,Reply}. -do_stop_nodes(Nodes,LD) -> - do_stop_nodes_2(started_trace_nodes(Nodes,LD),LD,[]). - -do_stop_nodes_2([Node|Tail],LD,Replies) -> - case get_node_rec(Node,LD) of - #node{ref=MRef} -> - erlang:demonitor(MRef), - case ?RUNTIME:stop(Node) of - ok -> - NewLD=delete_node_rec(Node,LD), - send_to_subscribers({disconnected,Node,void},LD), - do_stop_nodes_2(Tail,NewLD,[{Node,ok}|Replies]); - Error -> - do_stop_nodes_2(Tail,LD,[{Node,Error}|Replies]) - end; - Error -> - do_stop_nodes_2(Tail,LD,[{Node,Error}|Replies]) - end; -do_stop_nodes_2([],LD,Replies) -> - {LD,{ok,Replies}}; -do_stop_nodes_2(Faulty,LD,_) -> - {LD,{error,{badarg,Faulty}}}. -%% ----------------------------------------------------------------------------- - -%% Function being called when a runtime component sends a connect message to -%% the controlcomponent. The control component then confirms that is has indeed -%% taken on that runtime component. -%% Returns a new loopdata structure. -do_confirm_connection(Pid,Tag,LD) -> - case ?RUNTIME:confirm_connection(Pid,Tag) of - {node_info,Node,_Pid,VSN,State,Status,_Tag} -> - MRef=erlang:monitor(process,Pid), % We must monitor it from now on. - Rec=#node{node=Node,vsn=VSN,tag=Tag,ref=MRef,pid=Pid}, - send_to_subscribers({connected,Node,{Tag,{State,Status}}},LD), - set_node_rec(Rec,LD); % Makes new loopdata. - _Error -> % Strange, it wanted us as control!? - LD - end. -%% ------------------------------------------------------------------------------ - -%% Function handling an incomming DOWN message. This can be one of our runtime -%% components terminating, or a process subscribing to events. Send a trace-event -%% to subscribers if it was a runtime terminating and remove it from -%% our list of runtime components. -%% Note that if a subscriber has subscribed multiple times to events, we will get -%% multiple DOWN messages too, since we have monitored that process multiple -%% times. It is therefore sufficient to remove just one subscription entry here -%% each time (remove on the monitor reference!). -%% Returns a new LoopData structure. -do_down_msg(Ref,Info,LD) -> - case find(fun ref/2,LD#state.nodes,Ref) of - {value,Node} -> % Yes it was one of our nodes. - send_to_subscribers({disconnected,Node,Info},LD), - delete_node_rec(Node,LD); - no_match -> % Not one of our nodes. - case lists:keysearch(Ref,2,LD#state.subscribers) of - {value,{_Pid,_}} -> % It was a subscriber terminating. - LD#state{subscribers=lists:keydelete(Ref,2,LD#state.subscribers)}; - false -> % Not one of our subscribers either. - LD % Do nothing then. - end - end. -%% ------------------------------------------------------------------------------ - - - -%% ============================================================================== -%% Help functions. -%% ============================================================================== - - -%% Help function which inspects options to start and add_node. Returns a new -%% list of options in {ok,Options} or {error,Reason}. -check_options(Options, Context) -> - check_options_2(Options, Context, []). - -check_options_2([],_Context,Result) -> - {ok,Result}; -check_options_2([{subscribe,Pid}|OptionsTail],start,Result) when is_pid(Pid) -> - check_options_2(OptionsTail,start,[{subscribe,Pid}|Result]); -check_options_2([{unsubscribe,Pid}|OptionsTail],start,Result) when is_pid(Pid) -> - check_options_2(OptionsTail,start,[{unsubscribe,Pid}|Result]); -check_options_2([{dependency,How}|OptionsTail],Context,Result) -> - check_options_2(OptionsTail,Context,[{dependency,How}|Result]); -check_options_2([{overload,How}|OptionsTail],Context,Result) -> - check_options_2(OptionsTail,Context,[{overload,How}|Result]); -check_options_2([overload|OptionsTail],Context,Result) -> - check_options_2(OptionsTail,Context,[overload|Result]); -check_options_2([UnKnown|_],_Context,_Result) -> - {error,{unknown_option,UnKnown}}; -check_options_2(UnKnown,_Context,_Result) -> - {error,{unknown_option,UnKnown}}. -%% ------------------------------------------------------------------------------ - -%% Help function initiating the #state structure, i.e the loopdata. Since there -%% are some initial values from the record defaults when creating a new #state, -%% those must be compared with possibly specified Options. Specified Options shall -%% of course override defaults. -%% Note that it is not the control component's responsibility to understand all -%% options later given to a runtime component. It mearly stores them in rt_options -%% so they can be passed to the runtime component at start-up. -%% Returns a loopdata structure. -initiate_state(Options) -> - ResultingOptions=merge_options((#state{})#state.rt_options,Options), - LD1=initiate_state_2(ResultingOptions,#state{rt_options=[]}), - case node() of % Finally set the distribution flag. - nonode@nohost -> - LD1#state{distributed=false}; - _ -> - LD1#state{distributed=true} - end. - -initiate_state_2([{subscribe,Proc}|Tail],LD) when is_pid(Proc);is_atom(Proc)-> - MRef=erlang:monitor(process,Proc), - initiate_state_2(Tail,LD#state{subscribers=[{Proc,MRef}|LD#state.subscribers]}); -initiate_state_2([Opt|Tail],LD) when is_tuple(Opt),size(Opt)>=1 -> - initiate_state_2(Tail,initiate_state_3(element(1,Opt),Opt,LD)); -initiate_state_2([Opt|Tail],LD) when is_atom(Opt) -> - initiate_state_2(Tail,initiate_state_3(Opt,Opt,LD)); -initiate_state_2([_|Tail],LD) -> - initiate_state_2(Tail,LD); -initiate_state_2([],LD) -> - LD. - -initiate_state_3(OptName,Opt,LD) -> - case initiate_state_is_rt_option(OptName) of - true -> % Yes, it shall be part of the rt_options. - LD#state{rt_options=[Opt|LD#state.rt_options]}; - false -> % Ignore the option then. - LD - end. - -%% This is the only place you have to change should there be more rt_options -%% introduced. -initiate_state_is_rt_option(overload) -> true; -initiate_state_is_rt_option(dependency) -> true; -initiate_state_is_rt_option(_) -> false. -%% ------------------------------------------------------------------------------ - -%% Help function which takes a list of default options and a list of overriding -%% options. The function builds a return value consisting of all default options -%% unless they are overridden by a overriding option. -%% An option can be either {Param,.....} or Param. I.e either a tuple with zero -%% or more values associated with the Parameter, or just an atom. -merge_options([], Options) -> - Options; -merge_options([T|DefaultTail],Options) when is_tuple(T),size(T)>=1 -> - merge_options(DefaultTail,merge_options_2(element(1,T),T,Options)); -merge_options([Param|DefaultTail],Options) when is_atom(Param) -> - merge_options(DefaultTail,merge_options_2(Param,Param,Options)); -merge_options([_|DefaultTail],Options) -> % Strange, bad default option! - merge_options(DefaultTail,Options). - -merge_options_2(Param,Opt,Options) -> - case merge_options_find(Param,Options) of - true -> - Options; - false -> - [Opt|Options] - end. - -merge_options_find(Param,[T|_]) when is_tuple(T),element(1,T)==Param -> - true; -merge_options_find(Param,[Param|_]) -> - true; -merge_options_find(Param,[_|Rest]) -> - merge_options_find(Param,Rest); -merge_options_find(_,[]) -> - false. -%% ------------------------------------------------------------------------------ - -%% Help function which transforms certain parts of a tracer data. Those are -%% parts which must be transformed at the controlnode like node to pid mappings. -%% It also checks the formatting of the tracerdata since runtime components -%% does not accept too badly formatted tracerdata. -%% Returns {ok,NewTraceData} or {error,Reason}. -check_modify_tracerdata(TracerData,LoopData) when is_list(TracerData) -> - case lists:keysearch(trace,1,TracerData) of - {value,{_,TraceTD}} -> % Examine the trace part. - case check_modify_tracerdata(TraceTD,LoopData) of - {ok,NewTraceTD} -> - {ok,lists:keyreplace(trace,1,TracerData,{trace,NewTraceTD})}; - {error,Reason} -> % The trace part was faulty. - {error,Reason} % Ruins everything :-) - end; - false -> % Unusual, but no trace part. - {ok,TracerData} % No modifications necessary. - end; -check_modify_tracerdata(collector,_LoopData) -> - {ok, collector}; -check_modify_tracerdata({relayer,Collector},_LoopData) when is_pid(Collector) -> - {ok,{relayer,Collector}}; -check_modify_tracerdata({relayer,Collector},LoopData) when is_atom(Collector) -> - case get_node_rec(Collector,LoopData) of - Rec when is_record(Rec,node) -> % Collector is a known node. - {ok,{relayer,Rec#node.pid}}; - {error,not_an_added_node} -> - {error,{not_an_added_node,Collector}} - end; -check_modify_tracerdata({Type,Data},_LoopData) when Type==ip;Type==file -> - {ok,{Type,Data}}; -check_modify_tracerdata({Handler,Data},_LoopData) when is_function(Handler) -> - {ok,{Handler,Data}}; -check_modify_tracerdata(Data,_LoopData) -> - {error,{bad_tracerdata,Data}}. -%% ----------------------------------------------------------------------------- - -%% Help function sending an event to all processes subscribing to events. -%% Note that the function manipulates the from Node indicator incase we are not -%% running in a distributed system. -%% Returns nothing significant. -send_to_subscribers(Msg={Event,_Node,Data},LD) -> - AdaptedMsg= - case LD#state.distributed of - true -> - Msg; - false -> - {Event,local_runtime,Data} - end, - TraceEvent={inviso_event,self(),erlang:localtime(),AdaptedMsg}, - send_to_subscribers_2(LD#state.subscribers,TraceEvent). - -send_to_subscribers_2([],_) -> - ok; -send_to_subscribers_2([{Subscriber,_}|Tail],TraceEvent) -> - Subscriber ! TraceEvent, - send_to_subscribers_2(Tail,TraceEvent). -%% ----------------------------------------------------------------------------- - -%% Help function converting the Nodes parameter to known nodes. Actually today -%% it only converts the all atom to all known nodes. -%% Returns a list of nodes. -started_trace_nodes(all,LoopData) -> - lists:map(fun(N)->N#node.node end,LoopData#state.nodes); -started_trace_nodes(Nodes,_) -> - Nodes. -%% ------------------------------------------------------------------------------ - -%% Help function searching through a list of elements looking for an element -%% containing Key. How the element shall be interpreted is done by the Fun. -%% Returns {value,Element} or 'no_match'. -%% Fun=fun(Element,Key)={return,Value} | false -find(_,[],_Key) -> - no_match; -find(Fun,[H|T],Key) -> - case Fun(H,Key) of - {return,Value}-> - {value,Value}; - _ -> - find(Fun,T,Key) - end. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% Functions handling the nodes datastructure part of the #state. -%% #state.nodes is a list of #node. -%% ----------------------------------------------------------------------------- - -%% Function used to build find fun, looking for a certain #node with its monitoring -%% reference set to Ref. Useful when finding out if a DOWN message comes from one -%% of our runtime components. -ref(#node{ref=Ref,node=Node},Ref) -> - {return,Node}; -ref(_,_) -> - false. -%% ----------------------------------------------------------------------------- - -%% use in find/3 -%% Function used to build find fun, finding out if we have a node with the node -%% name Node. -is_started(#node{node=Node},Node) -> - {return,true}; -is_started(_,_) -> - false. -%% ----------------------------------------------------------------------------- - -%% Help function replacing or adding an entry for a node. Works on either a list -%% of #node or a loopdata structure. Returns a new list of #node or a loopdata struct. -set_node_rec(Rec,LD=#state{nodes=NodeList}) -> - LD#state{nodes=set_node_rec_2(Rec,NodeList)}. - -set_node_rec_2(Rec,[]) -> - [Rec]; -set_node_rec_2(Rec,[NodeRec|Tail]) when NodeRec#node.node==Rec#node.node -> - [Rec|Tail]; -set_node_rec_2(Rec,[NodeRec|Tail]) -> - [NodeRec|set_node_rec_2(Rec,Tail)]. -%% ------------------------------------------------------------------------------ - -%% Help function finding a node record for Node in a list of #node or in loopdata. -%% Returns the #node in question or {error,not_an_added_node}. -get_node_rec(Node,NodeList) when is_list(NodeList) -> - get_node_rec_2(Node,NodeList); -get_node_rec(Node,#state{nodes=NodeList}) -> - get_node_rec_2(Node,NodeList). - -get_node_rec_2(_Node,[]) -> - {error,not_an_added_node}; -get_node_rec_2(Node,[NodeRec|_]) when NodeRec#node.node==Node -> - NodeRec; -get_node_rec_2(Node,[_NodeRec|Tail]) -> - get_node_rec_2(Node,Tail). -%% ------------------------------------------------------------------------------ - -%% Help function removing a #node from either a list of #node or from a loopdata -%% structure. Returns a new list of #node or a new loopdata structure. -delete_node_rec(Node,LD=#state{nodes=NodeList}) -> - LD#state{nodes=delete_node_rec_2(Node,NodeList)}; -delete_node_rec(Node,NodeList) when is_list(NodeList) -> - delete_node_rec_2(Node,NodeList). - -delete_node_rec_2(_,[]) -> - []; -delete_node_rec_2(#node{node=Node},[#node{node=Node}|Tail]) -> - Tail; -delete_node_rec_2(Node,[#node{node=Node}|Tail]) -> - Tail; -delete_node_rec_2(Node,[NRec|Tail]) -> - [NRec|delete_node_rec_2(Node,Tail)]. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================= -%% Implementation of the help process receiving all logs from the runtime -%% components. This process is referred to as the CollectPid. -%% It is responsible for sending the reply back to the control component -%% client. If a runtime component becomes suspended, the CollectPid is -%% alerted by the DOWN message. -%% Note that it may take some time before this process responds back to the client. -%% Therefore the client must wait for 'infinity'. The job of transferring the -%% files can be costly. Therefore it is a good idea to stop if no one is really -%% interested in the result. This collector process monitors the From client in -%% order to learn if the job can be cancelled. That will also be a possibility -%% for a client to willfully cancel a fetch job. -%% ============================================================================= - -%% Intitial function on which the control component spawns. Note that the start -%% must be done in two steps since the runtime components must be informed of -%% the CollectPid. But the CollectPid must also know from which runtime components -%% it can expect files from. -%% InitialReplies: contains {Node,Result} for nodes from where there will be no -%% files, but which must be part of the final reply. -log_rec_init(Parent,Dest,Prefix,From={ClientPid,_}) -> - receive - {?MODULE,Parent,Fetchers,InitialReplies} -> - RTs=lists:map(fun({N,F})-> - {N,erlang:monitor(process,F),void,void,void} - end, - Fetchers), - CMRef=erlang:monitor(process,ClientPid), % Monitor the client. - case log_rec_loop(Dest,Prefix,RTs,InitialReplies,CMRef) of - Reply when is_list(Reply) -> % It is an ok value. - gen_server:reply(From,{ok,Reply}); - {error,Reason} -> - gen_server:reply(From,{error,Reason}); - false -> % The client terminated, no response. - true % Simply terminate, fetchers will notice. - end - end. - -log_rec_loop(_Dest,_Prefix,[],Replies,_CMRef) -> % All nodes done! - Replies; % This is the final reply. -log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) -> - receive - {Node,open,{FType,RemoteFName}} -> - case lists:keysearch(Node,1,RTs) of - {value,{_,MRef,_,_,_}} -> - {NewRTs,NewReplies}= - log_rec_open(Dest,Prefix,Node,MRef,FType,RemoteFName,RTs,Replies), - log_rec_loop(Dest,Prefix,NewRTs,NewReplies,CMRef); - false -> - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end; - {Node,open_failure,{FType,RemoteFName}} -> - case lists:keysearch(Node,1,RTs) of - {value,{_,MRef,_,_,_}} -> - {NewRTs,NewReplies}= - log_rec_open_failure(Node,MRef,FType,RemoteFName,RTs,Replies), - log_rec_loop(Dest,Prefix,NewRTs,NewReplies,CMRef); - false -> - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end; - {Node,payload,Bin,FPid} -> % A chunk of data from a fetcher. - case lists:keysearch(Node,1,RTs) of - {value,{_,_,_,_,void}} -> % Node has no file open here. - FPid ! {self(),cancel_transmission}, % No use sending more to me. - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef); % Simply ignore payload. - {value,{_Node,MRef,FType,FName,FD}} -> - case log_rec_payload(Node,MRef,FType,FName,FD,Bin,RTs,Replies) of - {ok,{NewRTs,NewReplies}} -> - FPid ! {self(),chunk_ack}, % For flow control. - log_rec_loop(Dest,Prefix,NewRTs,NewReplies,CMRef); - {error,{NewRTs,NewReplies}} -> - FPid ! {self(),cancel_transmission}, % No use sending more to me. - log_rec_loop(Dest,Prefix,NewRTs,NewReplies,CMRef) - end; - false -> % Node is not part of transfere. - FPid ! {self(),cancel_transmission}, % No use sending more to me. - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end; - {Node,end_of_file} -> - case lists:keysearch(Node,1,RTs) of - {value,{_,_,_,_,void}} -> % Node has no file open here. - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef); - {value,{_,MRef,FType,FName,FD}} -> - {NewRTs,NewReplies}= - log_rec_eof(Node,MRef,FType,FName,FD,RTs,Replies), - log_rec_loop(Dest,Prefix,NewRTs,NewReplies,CMRef); - false -> - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end; - {Node,end_of_transmission} -> % This runtime is done! - case lists:keysearch(Node,1,RTs) of - {value,{_Node,MRef,_,_,_}} -> - erlang:demonitor(MRef), - log_rec_loop(Dest,Prefix, - lists:keydelete(Node,1,RTs), - log_rec_mkreply(Node,complete,Replies), - CMRef); - false -> % Strange, not one of our nodes. - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end; - {Node,incomplete} -> % This runtime is done (with errors). - case lists:keysearch(Node,1,RTs) of - {value,{_,MRef,FType,FName,FD}} -> - erlang:demonitor(MRef), - {NewRTs,NewReplies}= - log_rec_incomplete(Node,FType,FName,FD,RTs,Replies), - log_rec_loop(Dest,Prefix,NewRTs,NewReplies,CMRef); - false -> % Not our, or not anylonger. - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end; - {Node,{error,Reason}} -> % Remote file read_error. - case lists:keysearch(Node,1,RTs) of - {value,{_,MRef,FType,FName,FD}} -> - {NewRTs,NewReplies}= - log_rec_error(Node,MRef,FType,FName,FD,RTs,Reason,Replies), - log_rec_loop(Dest,Prefix,NewRTs,NewReplies,CMRef); - false -> - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end; - {'DOWN',CMRef,process,_,_} -> % The client got tired waiting. - log_rec_cancel(Dest,RTs,Replies), % Close and remove all files. - false; % Indicate no response message. - {'DOWN',Ref,process,_P,_Info} -> - case lists:keysearch(Ref,2,RTs) of - {value,{Node,_,FType,FName,FD}} -> - {NewRTs,NewReplies}= - log_rec_incomplete(Node,FType,FName,FD,RTs,Replies), - log_rec_loop(Dest,Prefix,NewRTs,NewReplies,CMRef); - false -> % Not our, or not anylonger. - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end; - _ -> - log_rec_loop(Dest,Prefix,RTs,Replies,CMRef) - end. - -%% Help function opening a new target file on the receiver. It returns -%% {NewRTs,NewReplies}. -%% Note that we must protect us against that some of the strings are not proper -%% strings, but contains garbage. -log_rec_open(Dest,Prefix,Node,MRef,FType,RemoteFName,RTs,Replies) -> - case catch log_rec_open_2(Dest,Prefix,Node,MRef,FType,RemoteFName,RTs,Replies) of - {'EXIT',Reason} -> - NewRTs=lists:keyreplace(Node,1,RTs,{Node,MRef,void,void,void}), - NewReplies= - log_rec_addreply(Node, - FType, - {error,{file_open,{Reason,[Dest,Prefix,RemoteFName]}}},Replies), - {NewRTs,NewReplies}; - Result -> - Result - end. - -log_rec_open_2(Dest,Prefix,Node,MRef,FType,RemoteFName,RTs,Replies) -> - FName=Prefix++RemoteFName, % Our file name. - case file:open(filename:join([Dest,FName]),[write]) of - {ok,FD} -> - NewRTs=lists:keyreplace(Node,1,RTs,{Node,MRef,FType,FName,FD}), - {NewRTs,Replies}; - {error,Reason} -> - NewRTs=lists:keyreplace(Node,1,RTs,{Node,MRef,void,void,void}), - NewReplies= - log_rec_addreply(Node,FType,{error,{file_open,{Reason,FName}}},Replies), - {NewRTs,NewReplies} - end. - -%% Help function adding a file that was unsuccessfully opened as failed. -log_rec_open_failure(Node,MRef,FType,RemoteFName,RTs,Replies) -> - NewRTs=lists:keyreplace(Node,1,RTs,{Node,MRef,void,void,void}), - NewReplies= - log_rec_addreply(Node, - FType, - {error,{remote_open,RemoteFName}},Replies), - {NewRTs,NewReplies}. - -%% Help function whih writes the Bin to the FD file. If writing was unsuccessful, -%% close the file and modify RTs and add a reply to Replies. Note that we can not -%% stop the runtime from sending us more data belonging to this file. But we will -%% simply just inore it from now on. -%% Returns {SuccessCode,{NewRTs,NewReplies}}. -log_rec_payload(Node,MRef,FType,FName,FD,Bin,RTs,Replies) -> - case file:write(FD,Bin) of - ok -> - {ok,{RTs,Replies}}; - {error,Reason} -> - file:close(FD), - NewRTs=lists:keyreplace(Node,1,RTs,{Node,MRef,void,void,void}), - NewReplies= - log_rec_addreply(Node,FType,{error,{file_write,{Reason,FName}}},Replies), - {error,{NewRTs,NewReplies}} - end. - -%% Help function whih shall be used when a file has been successfully transfered. -%% This function closes the output file and updates RTs and the Replies. -%% Returns {NewRTs,NewReplies}. -log_rec_eof(Node,MRef,FType,FName,FD,RTs,Replies) -> - file:close(FD), - NewRTs=lists:keyreplace(Node,1,RTs,{Node,MRef,void,void,void}), - {NewRTs,log_rec_addreply(Node,FType,{ok,FName},Replies)}. - -%% Help function which, if there is an open file, indicates it as truncated in the -%% replies. And finalize the reply for Node assuming that the node is in total incomplete -%% Returns {NewRTs,NewReplies}. -log_rec_incomplete(Node,_FType,_FName,void,RTs,Replies) -> - NewRTs=lists:keydelete(Node,1,RTs), % The node is done. - {NewRTs,log_rec_mkreply(Node,incomplete,Replies)}; -log_rec_incomplete(Node,FType,FName,FD,RTs,Replies) -> - file:close(FD), % Not going to write anymore in this file. - NewRTs=lists:keydelete(Node,1,RTs), % The node is done. - NewReplies=log_rec_addreply(Node,FType,{error,{truncated,FName}},Replies), - {NewRTs,log_rec_mkreply(Node,incomplete,NewReplies)}. - -%% Help function handling the case when runtime component experiences an error -%% transferering the file. That means that there will be no more chunks of this -%% file. Hence it works a bit like EOF. -%% Returns {NewRTs,NewReplies}. -log_rec_error(Node,MRef,FType,FName,FD,RTs,Reason,Replies) -> - file:close(FD), - NewRTs=lists:keyreplace(Node,1,RTs,{Node,MRef,void,void,void}), - {NewRTs,log_rec_addreply(Node,FType,{error,{truncated,{Reason,FName}}},Replies)}. -%% ----------------------------------------------------------------------------- - -%% Help function adding a reply to the list of replies. -%% Replies is a list {Node,FType,Reply} for each file handled, sucessfully or not. -%% The list may also contain finalized nodes, which will be on the format: -%% {Node,{Conclusion,[{trace_log,TraceLogReplies},{ti_log,TiLogReplies}]}}. -log_rec_addreply(Node,FType,Reply,Replies) -> - [{Node,FType,Reply}|Replies]. - -%% Help function which converts the {Node,FType,Reply} tuples in Replies to -%% a finalized reply. -log_rec_mkreply(Node,Conclusion,Replies) -> - {RemainingReplies,TiReplies,TraceReplies}= - log_rec_mkreply_node_ftype(Node,Replies,[],[],[]), - [{Node,{Conclusion,[{trace_log,TraceReplies},{ti_log,TiReplies}]}}| - RemainingReplies]. - -%% Help function taking out the ti_log and trace_log file-types replies for -%% Node. Returns {RemainingReplies,Ti,Trace}. -log_rec_mkreply_node_ftype(Node,[{Node,ti_log,Result}|Rest],Replies,Ti,Trace) -> - log_rec_mkreply_node_ftype(Node,Rest,Replies,[Result|Ti],Trace); -log_rec_mkreply_node_ftype(Node,[{Node,trace_log,Result}|Rest],Replies,Ti,Trace) -> - log_rec_mkreply_node_ftype(Node,Rest,Replies,Ti,[Result|Trace]); -log_rec_mkreply_node_ftype(Node,[Reply|Rest],Replies,Ti,Trace) -> - log_rec_mkreply_node_ftype(Node,Rest,[Reply|Replies],Ti,Trace); -log_rec_mkreply_node_ftype(_,[],Replies,Ti,Trace) -> - {Replies,Ti,Trace}. -%% ----------------------------------------------------------------------------- - -%% If the fetching job shall be cancelled, we must close all open files and -%% remove them including all already closed files. Returns nothing significant. -log_rec_cancel(Dest,RTs,Replies) -> - log_rec_cancel_open(Dest,RTs), % First close and remove all open files. - log_rec_cancel_finished(Dest,Replies). % Remove all already closed files. - -log_rec_cancel_open(Dest,[{_Node,_MRef,_FType,_FName,void}|Rest]) -> - log_rec_cancel_open(Dest,Rest); % There is no open file to close. -log_rec_cancel_open(Dest,[{_Node,_MRef,_FType,FName,FD}|Rest]) -> - file:close(FD), - catch file:delete(filename:join(Dest,FName)), % Will just try to do my best. - log_rec_cancel_open(Dest,Rest); -log_rec_cancel_open(_Dest,[]) -> - true. - -log_rec_cancel_finished(Dest,[{_N,_FT,Reply}|Rest]) -> - [FName]=log_rec_cancel_finished_get_fname([Reply]), - catch file:delete(filename:join(Dest,FName)), - log_rec_cancel_finished(Dest,Rest); -log_rec_cancel_finished(Dest,[{_N,{_Conclusion,[{_,Replies1},{_,Replies2}]}}|Rest]) -> - FNames1=log_rec_cancel_finished_get_fname(Replies1), - lists:foreach(fun(FName)-> - catch file:delete(filename:join(Dest,FName)) - end, - FNames1), - FNames2=log_rec_cancel_finished_get_fname(Replies2), - lists:foreach(fun(FName)-> - catch file:delete(filename:join(Dest,FName)) - end, - FNames2), - log_rec_cancel_finished(Dest,Rest); -log_rec_cancel_finished(_Dest,[]) -> - true. - -%% Help function going through all possible reply values for a file. So -%% consequently there must be a clause here for every possible log_rec_addreply -%% call above. Returns a list of filenames that shall be removed in order to -%% restore the disk since the fetch job is cancelled. -log_rec_cancel_finished_get_fname([{error,{file_open,{_,FName}}}|Rest]) -> - [FName|log_rec_cancel_finished_get_fname(Rest)]; -log_rec_cancel_finished_get_fname([{error,{file_write,{_,FName}}}|Rest]) -> - [FName|log_rec_cancel_finished_get_fname(Rest)]; -log_rec_cancel_finished_get_fname([{ok,FName}|Rest]) -> - [FName|log_rec_cancel_finished_get_fname(Rest)]; -log_rec_cancel_finished_get_fname([{error,{truncated,{_,FName}}}|Rest]) -> - [FName|log_rec_cancel_finished_get_fname(Rest)]; -log_rec_cancel_finished_get_fname([{error,{truncated,FName}}|Rest]) -> - [FName|log_rec_cancel_finished_get_fname(Rest)]; -log_rec_cancel_finished_get_fname([_|Rest]) -> % This shall not happend. - log_rec_cancel_finished_get_fname(Rest); -log_rec_cancel_finished_get_fname([]) -> - []. -%% ----------------------------------------------------------------------------- - -%% EOF diff --git a/lib/inviso/src/inviso_lfm.erl b/lib/inviso/src/inviso_lfm.erl deleted file mode 100644 index 085048518c..0000000000 --- a/lib/inviso/src/inviso_lfm.erl +++ /dev/null @@ -1,431 +0,0 @@ -%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
-%% Author: Lennart �hman, [email protected]
-%%
-%% INVISO LogFile Merger.
-%%
-%% Merges all log-entries in all files in Files in chronological order
-%% into what ever is handled by WorkHandlerFun. Note that Files can contain
-%% several files. Both in the sence that it can be a wrapset. But also because
-%% the log is spread over more than one LogFiles (i.e trace_log + ti_log).
-%% It is further possible to use another reader-process (for the logfiles)
-%% than the default one. This is useful if the logfiles are formatted in
-%% another way than as done by a trace-port.
-
--module(inviso_lfm).
-
-%% -----------------------------------------------------------------------------
-%% API exports.
-%% -----------------------------------------------------------------------------
-
--export([merge/2,merge/3,merge/4,merge/5,merge/6]).
-%% -----------------------------------------------------------------------------
-
-%% -----------------------------------------------------------------------------
-%% Default handler exports.
-%% -----------------------------------------------------------------------------
-
--export([outfile_opener/1,outfile_writer/4,outfile_closer/1]).
-%% -----------------------------------------------------------------------------
-
-%% -----------------------------------------------------------------------------
-%% Formatting functions.
-%% -----------------------------------------------------------------------------
-
--export([format_arguments/3,format_argument_string/2]).
-%% -----------------------------------------------------------------------------
-%% Internal exports.
-%% -----------------------------------------------------------------------------
-
--export([init_receiver/7]).
-%% -----------------------------------------------------------------------------
-
-%% merge(Files,BeginHandlerFun,WorkHandlerFun,EndHandlerFun,HandlerData)=
-%% {ok,Count} | {error,Reason}
-%% merge(Files,OutputFile) =
-%%
-%% Files=[FileDescription,...]
-%% FileDescription=FileSet | {reader,Mod,Func,FileSet}
-%% FileSet={Node,LogFiles} | {Node,[LogFiles,...]}
-%% in the latter case the LogFiles must be sorted, beginning with the oldest.
-%% LogFiles=[{trace_log,Files} [,{ti_log,[FileName]}] ]
-%% either just trace_log or trace_log and ti_log.
-%% Files=[FileName] | [FileName,...]
-%% in the latter case it is a wrapset.
-%% BeginHandlerFun= ( fun(HandlerData)->{ok,NewHandleData} | {error,Reason} )
-%% WorkHandlerFun= ( fun(Node,Term,PidMappings,HandlerData)->
-%% {ok,NewHandlerData} | {error,Reason}
-%% EndHandlerFun= ( fun(HandlerData)->ok | {error,Reason} )
-%% Count=integer(), the total number of handled log entries.
-%%
-%% Merges all logfiles in Files together into one common log file, in chronological
-%% order according to the time-stamps in each log. Each entry is also marked with
-%% the node name in the merged log.
-%% Configuration:
-%% If a non-default reader shall be used, Mod:Func(ReceiverPid,LogFiles) shall
-%% spawn a reader process complying to the receiver/reader message protocoll.
-%% The default reader reads logs generated by a trace-port.
-%% BeginHandler is called before any logentries are processed, typically to open
-%% the out-file, if any.
-%% WorkHandlerFun is called for every log-entry. It typically writes the output.
-%% EndHandlerFun is called when the last reader has finished, typically to
-%% close the outfile.
-%%
-%% Using merge/2 assumes you want to use default handlers writing to a file.
-merge(Files,OutputFile) when is_list(OutputFile) -> - merge(Files,fun outfile_opener/1,fun outfile_writer/4,fun outfile_closer/1,OutputFile,off).
-merge(Files,WorkHandlerFun,HandlerData) when is_function(WorkHandlerFun) -> - merge(Files,void,WorkHandlerFun,void,HandlerData,off);
-merge(Files,OutputFile,Dbg) when is_list(OutputFile) -> - merge(Files,fun outfile_opener/1,fun outfile_writer/4,fun outfile_closer/1,OutputFile,Dbg).
-merge(Files,WorkHandlerFun,HandlerData,Dbg) when is_function(WorkHandlerFun) -> - merge(Files,void,WorkHandlerFun,void,HandlerData,Dbg).
-merge(Files,BeginHandlerFun,WorkHandlerFun,EndHandlerFun,HandlerData) ->
- merge(Files,BeginHandlerFun,WorkHandlerFun,EndHandlerFun,HandlerData,off).
-merge(Files,BeginHandlerFun,WorkHandlerFun,EndHandlerFun,HandlerData,Dbg) ->
- ReceiverPid=spawn_link(?MODULE,
- init_receiver,
- [self(),Files,BeginHandlerFun,WorkHandlerFun,
- EndHandlerFun,HandlerData,Dbg]),
- wait_for_response(ReceiverPid).
-
-wait_for_response(ReceiverPid) ->
- receive
- {reply,ReceiverPid,Reply} ->
- Reply;
- {'EXIT',ReceiverPid,Reason} ->
- {error,Reason}
- end.
-%% -----------------------------------------------------------------------------
-
-%% =============================================================================
-%% Code for the receiver process.
-%% =============================================================================
-
-%% Initial function for the receiver process. This function must be exported.
-init_receiver(From,Files,BeginHandlerFun,WorkHandlerFun,EndHandlerFun,HandlerData,Dbg) ->
- case setup_readers(Files) of % Create the reader processes.
- {ok,Readers} ->
- process_flag(trap_exit,true),
- if
- is_function(BeginHandlerFun) -> - case catch BeginHandlerFun(HandlerData) of
- {ok,NewHandlerData} ->
- init_receiver_2(From,WorkHandlerFun,EndHandlerFun,
- NewHandlerData,Dbg,Readers);
- {error,Reason} -> % Faulty begin-function.
- From ! {reply,self(),{error,{begin_handler,Reason}}};
- {'EXIT',Reason} ->
- From ! {reply,self(),{error,{begin_handler,Reason}}}
- end;
- true -> % There is no begin-handler.
- init_receiver_2(From,WorkHandlerFun,EndHandlerFun,HandlerData,Dbg,Readers)
- end;
- {error,Reason} ->
- From ! {reply,self(),{error,{files,Reason}}}
- end.
-
-init_receiver_2(From,WorkHandlerFun,EndHandlerFun,HandlerData,Dbg,Readers) ->
- {NewReaders,EntryStruct}=mk_entrystruct(Readers,Dbg),
- {Reply,NewHandlerData}=
- loop(From,WorkHandlerFun,HandlerData,NewReaders,EntryStruct,Dbg,0),
- if
- is_function(EndHandlerFun) -> - case EndHandlerFun(NewHandlerData) of
- ok ->
- From ! {reply,self(),Reply};
- {error,_Reason} ->
- From ! {reply,self(),Reply}
- end;
- true -> % Reply directly then, no finish fun.
- From ! {reply,self(),Reply}
- end.
-
-%% Function that spawns a help process for each group of files in the list.
-%% The help process will read entries from the input files in the correct order
-%% and deliver them to the receiver process.
-%% Note that there is a possibility to design your own readers. The default
-%% reader understands trace-port generated logfiles.
-%% Returns a list of {Node,Pid}.
-setup_readers(Files) ->
- setup_readers_2(Files,[]).
-
-setup_readers_2([{reader,Mod,Func,{Node,FileStruct}}|Rest],Acc) ->
- Pid=spawn_link(Mod,Func,[self(),FileStruct]),
- setup_readers_2(Rest,[{Node,Pid}|Acc]);
-setup_readers_2([{Node,FileStruct}|Rest],Acc) ->
- Pid=spawn_link(inviso_lfm_tpfreader,init,[self(),FileStruct]),
- setup_readers_2(Rest,[{Node,Pid}|Acc]);
-setup_readers_2([],Acc) ->
- {ok,Acc};
-setup_readers_2([Faulty|_],_Acc) ->
- {error,{bad_reader_spec,Faulty}}.
-%% -----------------------------------------------------------------------------
-
-%% This is the workloop that polls each reader for messages and writes them
-%% in the correct order.
-loop(From,WorkHFun,HData,Readers,EntryStruct,Dbg,Count) ->
- case find_oldest_entry(EntryStruct) of
- {Pid,Node,PidMappings,Term} ->
- case get_and_insert_new_entry(From,Node,Pid,Readers,EntryStruct,Dbg) of
- {ok,{NewReaders,NewEntryStruct}} ->
- case WorkHFun(Node,Term,PidMappings,HData) of
- {ok,NewHData} ->
- loop(From,WorkHFun,NewHData,NewReaders,NewEntryStruct,Dbg,Count+1);
- {error,Reason} -> % Serious, we cant go on then.
- stop_readers(NewReaders),
- {{error,{writing_output_file,Reason}},HData}
- end;
- {stop,_Reason} -> % The original caller is no longer there!
- stop_readers(Readers),
- {error,HData}
- end;
- done -> % No more readers.
- {{ok,Count},HData}
- end.
-
-%% Help function which finds the oldest entry in the EntryStruct. Note that the
-%% timestamp can actually be the atom 'false'. This happens for instance if it is
-%% a dropped-messages term. But since 'false' is smaller than any tuple, that
-%% term will be consumed immediately as soon as it turns up in EntryList.
-find_oldest_entry(EntryStruct) ->
- case list_all_entries(EntryStruct) of
- [] -> % The we are done!
- done;
- EntryList when is_list(EntryList) -> % Find smallest timestamp in here then. - {Pid,Node,PidMappings,_TS,Term}=
- lists:foldl(fun({P,N,PMap,TS1,T},{_P,_N,_PMap,TS0,_T}) when TS1<TS0 ->
- {P,N,PMap,TS1,T};
- (_,Acc) ->
- Acc
- end,
- hd(EntryList),
- EntryList),
- {Pid,Node,PidMappings,Term}
- end.
-
-%% Help function which signals all reader process to clean-up and terminate.
-%% Returns nothing significant.
-stop_readers([Pid|Rest]) ->
- Pid ! {stop,self()},
- stop_readers(Rest);
-stop_readers([]) ->
- ok.
-%% -----------------------------------------------------------------------------
-
-%% Help function which tries to replace the entry by Pid in EntryStruct with
-%% a new one from that process. If one is returned on request, it replaces
-%% the old one in EntryStruct. If Pid is done or otherwise dissapears, Pid
-%% is simply removed from Readers and the EntryStruct.
-get_and_insert_new_entry(Node,Pid,Readers,EntryStruct,Dbg) ->
- get_and_insert_new_entry(void,Node,Pid,Readers,EntryStruct,Dbg).
-
-get_and_insert_new_entry(From,Node,Pid,Readers,EntryStruct,Dbg) ->
- Pid ! {get_next_entry,self()},
- receive
- {'EXIT',From,Reason} -> % No one is waiting for our reply!
- {stop,Reason}; % No use continuing then.
- {next_entry,Pid,PidMappings,TS,Term} -> % We got a next entry from Pid!
- ets:insert(EntryStruct,{Pid,Node,PidMappings,TS,Term}),
- {ok,{Readers,EntryStruct}};
- {next_entry,Pid,{error,_Reason}} -> % Reading an entry went wrong.
- get_and_insert_new_entry(From,Node,Pid,Readers,EntryStruct,Dbg);
- {'EXIT',Pid,_Reason} -> % The process has terminated.
- ets:delete(EntryStruct,Pid),
- NewReaders=lists:delete(Pid,Readers),
- {ok,{NewReaders,EntryStruct}}
- end.
-%% -----------------------------------------------------------------------------
-
-%% Help function which from a list of reader processes creates the private
-%% storage where the oldest entry from each reader is always kept.
-%% Returns {Readers,EntryStruct}.
-mk_entrystruct(Pids,Dbg) ->
- TId=ets:new(list_to_atom("inviso_lfm_tab_"++pid_to_list(self())),[set]),
- mk_entrystruct_2(Pids,lists:map(fun({_,P})->P end,Pids),Dbg,TId).
-
-mk_entrystruct_2([{Node,Pid}|Rest],Readers,Dbg,EntryStruct) ->
- {ok,{NewReaders,NewEntryStruct}}=
- get_and_insert_new_entry(Node,Pid,Readers,EntryStruct,Dbg),
- mk_entrystruct_2(Rest,NewReaders,Dbg,NewEntryStruct);
-mk_entrystruct_2([],Readers,_Dbg,EntryStruct) ->
- {Readers,EntryStruct}.
-%% -----------------------------------------------------------------------------
-
-%% Help function that returns a list of our oldest entry structure.
-%% [{Pid,Node,PidMappings,TimeStamp,Term},...]
-list_all_entries(EntryStruct) ->
- ets:tab2list(EntryStruct).
-%% -----------------------------------------------------------------------------
-
-%% =============================================================================
-%% Default handlers for the receiver
-%% =============================================================================
-
-%% These functions are also exported in order to make them available when creating
-%% other funs in other modules.
-
-%% Default begin-handler.
-outfile_opener(FileName) ->
- case file:open(FileName,[write]) of
- {ok,FD} ->
- {ok,FD}; % Let the descriptor be handlerdata.
- {error,Reason} ->
- {error,{open,Reason}}
- end.
-
-%% Default work-handler.
-%% DEN H�R �R L�NGT IFR�N F�RDIG!!!
-outfile_writer(Node,Term,PidMappings,FD) ->
- io:format(FD,"~w ~w ~w~n",[Node,PidMappings,Term]),
- {ok,FD}.
-
-%% Default end-handler.
-outfile_closer(FD) ->
- file:close(FD),
- ok.
-%% -----------------------------------------------------------------------------
-
-%% =============================================================================
-%% Formatting functions.
-%% =============================================================================
-
-%% This section contains a useful formatting function formatting an (function)
-%% argument list. It also offers a working example of how to write
-%% own datatype translators (which will be used by the formatting function to
-%% further enhance the output).
-
-%% format_arguments(Args,FOpts,Transaltors)=Args2 | <failure>
-%% Args=list(), list of the argument as usually given in a trace message,
-%% a stack trace or similar.
-%% FOpts=term(), formatting options understood by the translation functions.
-%% Translations=[Translator,...]
-%% Translator=fun(Term,FOpts)=TResult | {M,F}, where M:F(Term,FOpts)=TResult
-%% TResult={ok,TranslationString} | false
-%% Arg2=list(), list of Args where terms may be replaced by own representations.
-%% Note that terms not effected will remain as is, but if an own representation
-%% is choosen, that must be a string in order for any io format function to
-%% print it exactly as formatted here.
-format_arguments([Arg|Rest],FOpts,Translators) -> % More than one argument.
- [format_argument(Arg,FOpts,Translators)|format_arguments(Rest,FOpts,Translators)];
-format_arguments([],_FOpts,_Translators) ->
- []. % The empty list.
-
-%% Help function handling the various Erlang datatypes. There must hence be one
-%% clause here for every existing datatype.
-format_argument(List,FOpts,Translators) when is_list(List) ->
- case format_argument_own_datatype(List,FOpts,Translators) of
- {true,TranslationStr} ->
- TranslationStr;
- false ->
- format_argument_list(List,FOpts,Translators)
- end;
-format_argument(Tuple,FOpts,Translators) when is_tuple(Tuple) ->
- case format_argument_own_datatype(Tuple,FOpts,Translators) of
- {true,TranslationStr} -> % It was one of our special datatypes.
- TranslationStr;
- false -> % Regular tuple.
- format_argument_tuple(Tuple,FOpts,Translators)
- end;
-format_argument(Binary,FOpts,Translators) when is_binary(Binary) ->
- case format_argument_own_datatype(Binary,FOpts,Translators) of
- {true,TranslationStr} -> % It was one of our special datatypes..
- TranslationStr;
- false -> % Regular binary.
- format_argument_binary(Binary,FOpts,Translators)
- end;
-format_argument(Atom,_FOpts,_Translators) when is_atom(Atom) ->
- Atom;
-format_argument(Integer,_FOpts,_Translators) when is_integer(Integer) ->
- Integer;
-format_argument(Float,_FOpts,_Translators) when is_float(Float) ->
- Float;
-format_argument(Pid,_FOpts,_Translators) when is_pid(Pid) ->
- Pid;
-format_argument(Port,_FOpts,_Translators) when is_port(Port) ->
- Port;
-format_argument(Ref,_FOpts,_Translators) when is_reference(Ref) ->
- Ref;
-format_argument(Fun,_FOpts,_Translators) when is_function(Fun) ->
- Fun.
-
-%% Help function handling the case when an element is a list.
-format_argument_list([Element|Rest],FOpts,Translators) ->
- [format_argument(Element,FOpts,Translators)|
- format_argument_list(Rest,FOpts,Translators)];
-format_argument_list([],_FOpts,_Translators) ->
- [].
-
-%% Help function handling the case when an element is a tuple.
-format_argument_tuple(Tuple,FOpts,Translators) ->
- list_to_tuple(format_argument_tuple(Tuple,FOpts,Translators,size(Tuple),[])).
-
-format_argument_tuple(_,_,_,0,List) ->
- List;
-format_argument_tuple(Tuple,FOpts,Translators,Index,List) ->
- E=format_argument(element(Index,Tuple),FOpts,Translators),
- format_argument_tuple(Tuple,FOpts,Translators,Index-1,[E|List]).
-
-%% Help function handling the case when an element is a binary.
-format_argument_binary(Binary,_FOpts,_Translators) ->
- Binary.
-
-%% Help function trying to use the translations.
-format_argument_own_datatype(Term,FOpts,[Fun|Rest]) when is_function(Fun) ->
- case catch Fun(Term,FOpts) of
- {ok,TranslationStr} ->
- {true,TranslationStr};
- _ ->
- format_argument_own_datatype(Term,FOpts,Rest)
- end;
-format_argument_own_datatype(Term,FOpts,[{M,F}|Rest]) ->
- case catch M:F(Term,FOpts) of
- {ok,TranslationStr} ->
- {true,TranslationStr};
- _ ->
- format_argument_own_datatype(Term,FOpts,Rest)
- end;
-format_argument_own_datatype(Term,FOpts,[_|Rest]) ->
- format_argument_own_datatype(Term,FOpts,Rest);
-format_argument_own_datatype(_Term,_FOpts,[]) -> % There is no applicable format.
- false.
-%% -----------------------------------------------------------------------------
-
-%% format_argument_string(String,_FOpts)={ok,QuotedString} | false
-%% String=string() | term()
-%% QuotedString="String"
-%% Example of datatype checker that checks, in this case, that its argument is
-%% a string. If it is, it returns a deep list of the characters to print in order
-%% to make it a quoted string.
-format_argument_string(List=[_|_],_FOpts) -> % Must be at least one element.
- case format_argument_string_2(List) of
- true ->
- {ok,[$",List,$"]};
- false ->
- false
- end;
-format_argument_string(_,_FOpts) ->
- false.
-
-format_argument_string_2([C|Rest]) when (((C<127) and (C>=32)) or ((C>=8) and (C=<13))) ->
- format_argument_string_2(Rest);
-format_argument_string_2([_|_]) ->
- false;
-format_argument_string_2([]) ->
- true.
-%% -----------------------------------------------------------------------------
diff --git a/lib/inviso/src/inviso_lfm_tpfreader.erl b/lib/inviso/src/inviso_lfm_tpfreader.erl deleted file mode 100644 index 6de4d11fe0..0000000000 --- a/lib/inviso/src/inviso_lfm_tpfreader.erl +++ /dev/null @@ -1,388 +0,0 @@ -%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
-%% Author: Lennart �hman, [email protected]
-
-%%
-%% INVISO LogFileMerger TracePort File READER.
-%%
-%% This module implements a reader process capable of reading traceport files
-%% and feeding them according to the logfile merger process message protocoll
-%% to the logfile merger process.
-%% This module can also serve as example for writing file readers for other
-%% file formats.
-%%
-%% A reader process must:
-%% Support the reader-receiver protocoll.
-%% receive next_entry message: {get_next_entry,ReceiverPid}
-%% recieve stop message should the receiver wish to quit: {stop,ReceiverPid}.
-%% send next_entry message, either with entry or fault-code.
-%% next_entry message contains:{next_entry,self(),PidMappings,Timestamp,Term}
-%% {next_entry,self(),Error}
-%% recognize receiver termination (EXIT-signal).
-%% Understand logfile structure, both filename structure and content.
-%% Understand content (log-entry) details to extract the entry and entry
-%% components as timestamp and originating pid (to make pid-mappings).
-%% Understand any trace information files (ti).
-%%
-%% The logfile structure written by inviso_rt_meta is:
-%% {Pid,Alias,Op,TimeStamp} where:
-%% Pid=pid(), if Alias==unalias: pid()|other_than_pid()
-%% Op=alias|unalias,
-%% TimeStamp=now()
-%% -----------------------------------------------------------------------------
--module(inviso_lfm_tpfreader).
-
--export([init/2]).
-%% -----------------------------------------------------------------------------
-
--export([handle_logfile_sort_wrapset/1]). % Exported as a service to other readers.
-%% -----------------------------------------------------------------------------
-
-%% init(RecPid,FileStruct)=N/A
-%% RecPid=pid(), the process id of the log file merger.
-%% FileStruct=LogFiles | [LogFiles,...]
-%% LogFiles=[{trace_log,[File,...]} [,{ti_log,[File]}] ]
-%% File=string()
-%% Spawn on this function to start a reader process for trace-port generated
-%% logfiles, possibly with inviso-generated ti-files.
-init(RecPid,LogFiles=[Tuple|_]) when is_tuple(Tuple) -> % Only one LogFiles. - init(RecPid,[LogFiles]);
-init(RecPid,FileStruct) when is_list(FileStruct) -> - logfiles_loop(RecPid,FileStruct).
-%% -----------------------------------------------------------------------------
-
-logfiles_loop(RecPid,[LogFiles|Rest]) ->
- {TIalias,TIunalias}=handle_ti_file(LogFiles),% If there is a ti-file, read it.
- Files=handle_logfiles(LogFiles), % Returns a sorted list of logfiles.
- case open_next_file(Files) of
- {ok,FileName,FD,NewFiles} ->
- case loop(RecPid,FileName,NewFiles,TIalias,TIunalias,FD) of
- next ->
- logfiles_loop(RecPid,Rest);
- stop ->
- true % Terminate normally.
- end;
- done -> % Hmm, already out of files.
- true; % Then lets terminate normally.
- {error,Reason} -> % Couldn't even open the first file.
- exit(Reason)
- end;
-logfiles_loop(_RecPid,[]) -> % No more files in LogFiles.
- true. % Terminate normally.
-
-%% This workloop reads an entry from the input file upon request from the merger
-%% process and sends it back to the merger process (Parent). If the file ends
-%% there are more files to open and read in Files, the next file will be opened.
-loop(RecPid,FileName,Files,TIalias,TIunalias,FD) ->
- receive
- {get_next_entry,RecPid} -> % The receiver request the next entry.
- case fetch_next(FileName,FD,Files) of
- {ok,Term,NewCurrFile,NewFiles,NewFD} ->
- TS=find_timestamp_in_term(Term),
- PidMappings=make_pid_mappings(Term,TIalias,TIunalias,TS),
- RecPid ! {next_entry,self(),PidMappings,TS,Term},
- loop(RecPid,NewCurrFile,NewFiles,TIalias,TIunalias,NewFD);
- {error,Reason} -> % Not a properly formatted entry.
- RecPid ! {next_entry,self(),{error,Reason}},
- loop(RecPid,FileName,Files,TIalias,TIunalias,FD);
- done -> % No more files to read in this LogFiles.
- next % Are there more Files in FileStruct?
- end;
- {stop,RecPid} -> % The receiver process is done.
- file:close(FD), % Close file and terminate normally.
- stop
- end.
-%% -----------------------------------------------------------------------------
-
-%% Function which reads the next trace-entry from the file handled by FD, or if
-%% that file reaches EOF opens the next file in Files. Files must be sorted in
-%% the correct order.
-%% Returns {ok,Term,NewFileName,NewFiles,NewFD}, {error,Reason} or 'done'.
-fetch_next(FileName,FD,Files) ->
- case read_traceport_file(FileName,FD) of
- {ok,Term} -> % There were more terms in the file.
- {ok,Term,FileName,Files,FD}; % No changes necessary then.
- eof -> % This file is empty, try next file!
- file:close(FD),
- case open_next_file(Files) of
- {ok,NewFileName,NewFD,NewFiles} -> % A new file has been opened.
- fetch_next(NewFileName,NewFD,NewFiles); % Try again.
- done -> % No more files.
- done;
- {error,Reason} -> % Problems opening files.
- {error,Reason}
- end;
- {error,Reason} -> % Problems reading the file.
- {error,Reason}
- end.
-
-read_traceport_file(FileName,FD) ->
- case file:read(FD,5) of % Trace-port file entries start with 5 bytes.
- {ok,<<0,Size:32>>} -> % Each entry in a traceport file begins.
- case file:read(FD,Size) of
- {ok,Bin} when is_binary(Bin),size(Bin)=:=Size -> - try binary_to_term(Bin) of
- Term -> % Bin was a properly formatted term!
- {ok,Term}
- catch
- error:_Reason -> % Not a properly formatted term!
- {error,{binary_to_term,[FileName,Bin]}}
- end;
- {ok,Bin} -> % Incorrect length.
- {error,{faulty_length,[FileName,Size,Bin]}};
- eof -> % This is premature end of file!
- {error,{premature_eof,FileName}}
- end;
- {ok,<<1,DroppedMsgs:32>>} ->
- {ok,{drop,DroppedMsgs}};
- {ok,JunkBin} -> % Don't understand, report it as error.
- {error,{junk,[FileName,JunkBin]}};
- eof -> % A correct end of file!
- eof
- end.
-
-%% Help function which opens a file in raw binary mode and returns
-%% {ok,FileName,FD,Rest} or {error,Reason}.
-open_next_file([]) -> % There are no more files to open.
- done;
-open_next_file([FileName|Rest]) ->
- case file:open(FileName,[read,raw,binary]) of
- {ok,FD} ->
- {ok,FileName,FD,Rest};
- {error,Reason} ->
- {error,{open,[FileName,Reason]}}
- end.
-%% ------------------------------------------------------------------------------
-
-%% ==============================================================================
-%% Help functions.
-%% ==============================================================================
-
-
-%% Help function which extract the originating process id from the log entry
-%% term and returns a list of all associations to the PID found in TIalias.
-make_pid_mappings(_,void,_,_) -> % Trace Information is not used.
- []; % Simply no pid mappings then!
-make_pid_mappings(Term,TIalias,TIunalias,TS)
- when element(1,Term)==trace;element(1,Term)==trace_ts ->
- Pid=element(2,Term), % The pid.
- TempAliases=find_aliases(ets:lookup(TIalias,Pid),TS),
- remove_expired_aliases(TempAliases,TIalias,TIunalias,TS),
- lists:map(fun({_,_,Alias})->Alias end,
- find_aliases(ets:lookup(TIalias,Pid),TS));
-make_pid_mappings(_Term,_TIalias,_TIunalias,_TS) -> % Don't understand Term.
- []. % Simply no translations then!
-
-%% Help function traversing a list of ets-alias-table entries and returning a
-%% list of those old enough to have happend before TS.
-%% Note that it is possible to have an Offset in microseconds. This because an
-%% association may end up in the ti-file a short time after logentries starts
-%% to appear in the log file for the process in question. We therefore like to
-%% allow some slack,
-find_aliases(List,TS) ->
- lists:filter(fun({_,Now,_}) when Now<TS -> true;
- (_) -> false
- end,
- List).
-%% ------------------------------------------------------------------------------
-
-%% Help function which removes aliases that are no longer valid from the
-%% ETS table. It uses unalias entries which are older than TS but younger than
-%% the alias association.
-%% Returns nothing significant.
-remove_expired_aliases([{Pid,Now1,Alias}|Rest],TIalias,TIunalias,TS) ->
- Candidates=ets:lookup(TIunalias,Alias),
- lists:foreach(fun({_,Now2,P})
- when (Now2>Now1) and
- (Now2<TS) and
- ((P==Pid) or (not(is_pid(P)))) ->
- ets:delete_object(TIalias,{Pid,Now1,Alias}),
- true; % This alias is infact no longer.
- (_) ->
- false
- end,
- Candidates),
- remove_expired_aliases(Rest,TIalias,TIunalias,TS);
-remove_expired_aliases([],_,_,_) ->
- true.
-%% ------------------------------------------------------------------------------
-
-find_timestamp_in_term({trace_ts,_,_,_,TS}) ->
- TS;
-find_timestamp_in_term({trace_ts,_,_,_,_,TS}) ->
- TS;
-find_timestamp_in_term(_) -> % Don't know if there is a timestamp.
- false.
-%% -----------------------------------------------------------------------------
-
-
-%% -----------------------------------------------------------------------------
-%% Help function handling a trace-information file and building the TIstruct storage.
-%% -----------------------------------------------------------------------------
-
-%% Help function which opens a standard ti-file, reads its content and
-%% builds two ETS-table where PID is primary index in the one for aliases, and
-%% the alias is primary index in the one for unalias.
-%% Returns a handle to the two ETS tables.
-%%
-%% This function currently handles:
-%% (1) plain straight raw binary files.
-handle_ti_file(FileStruct) ->
- case lists:keysearch(ti_log,1,FileStruct) of
- {value,{_,[FileName]}} when is_list(FileName) -> % There is one ti-file in this set. - case file:open(FileName,[read,raw,binary]) of
- {ok,FD} ->
- TIdAlias=ets:new(list_to_atom("inviso_ti_atab_"++pid_to_list(self())),
- [bag]),
- TIdUnalias=ets:new(list_to_atom("inviso_ti_utab_"++pid_to_list(self())),
- [bag]),
- handle_ti_file_2(FD,TIdAlias,TIdUnalias), % Fill the table.
- file:close(FD),
- {TIdAlias,TIdUnalias};
- {error,_Reason} -> % Hmm, unable to open the file.
- {void,void} % Treat it as no ti-file.
- end;
- {value,_} -> % Some other file-set.
- {void,void}; % Pretend we don't understand.
- false -> % No ti-file in this set.
- {void,void}
- end.
-
-handle_ti_file_2(FD,TIdAlias,TIdUnalias) ->
- case file:read(FD,5) of % First read the header.
- {ok,<<_,Size:32>>} ->
- case file:read(FD,Size) of % Read the actual term.
- {ok,Bin} when size(Bin)=:=Size ->
- try binary_to_term(Bin) of
- {Pid,Alias,alias,NowStamp} -> % Save this association.
- ets:insert(TIdAlias,{Pid,NowStamp,Alias}),
- handle_ti_file_2(FD,TIdAlias,TIdUnalias);
- {Pid,Alias,unalias,NowStamp} ->
- ets:insert(TIdUnalias,{Alias,NowStamp,Pid}),
- handle_ti_file_2(FD,TIdAlias,TIdUnalias);
- _Term -> % Don't understand!
- handle_ti_file_2(FD,TIdAlias,TIdUnalias)
- catch
- error:_Reason -> % Badly formatted term
- handle_ti_file_2(FD,TIdAlias,TIdUnalias)
- end;
- {ok,_JunkBin} -> % To short probably.
- handle_ti_file_2(FD,TIdAlias,TIdUnalias); % Just drop it.
- eof -> % Should not come here, but
- {TIdAlias,TIdUnalias} % not much we can do, drop it and stop.
- end;
- {ok,_} -> % Also an error.
- handle_ti_file_2(FD,TIdAlias,TIdUnalias);
- eof -> % This is the normal eof point.
- {TIdAlias,TIdUnalias}
- end.
-%% -----------------------------------------------------------------------------
-
-
-%% -----------------------------------------------------------------------------
-%% Help functions sorting out what kind of logfiles we have to deal with.
-%% -----------------------------------------------------------------------------
-
-%% Help function which takes the filestruct argument and retrieves the names
-%% of all log-files mentioned there. If there are several logfiles, this function
-%% sorts them beginning with the oldest. That means that this function must
-%% have knowledge of how wrap-sets and so on works.
-%% Today known set-types:
-%% (1) file: One plain file.
-%% (2) wrap_set: List of files belonging to a wrap-set. Must be sorted.
-handle_logfiles(FileStruct) ->
- handle_logfiles_2(lists:keysearch(trace_log,1,FileStruct)).
-
-handle_logfiles_2({value,{_,[FileName]}}) when is_list(FileName)-> % One single plain file. - [FileName];
-handle_logfiles_2({value,{_,Files}}) when is_list(Files) -> % A wrap-set. - handle_logfile_sort_wrapset(Files);
-handle_logfiles_2(_) ->
- []. % Pretend there were no files otherwise.
-
-%% Help function which sorts the files in WrapSet beginning with the oldest.
-%% It assumes that a logfile is Name++SeqNo++Suffix.
-%% First the Name and Suffix must be established. We look at all files to find
-%% that out.
-%% Returns a list of sorted filenames.
-%% This function is exported since it might turn useful in own implemented
-%% readers.
-handle_logfile_sort_wrapset(Set=[_FileName]) -> % Only one file! Done then :-)
- Set;
-handle_logfile_sort_wrapset([]) -> % Also pretty simple :-)
- [];
-handle_logfile_sort_wrapset(FileSet) ->
- Prefix=find_common_prefix(FileSet),
- Suffix=find_common_prefix(lists:map(fun(Str)->lists:reverse(Str) end,FileSet)),
- find_hole_in_wrapset(FileSet,length(Prefix),length(Suffix)).
-
-%% Help function which finds the longest common prefix of all strings in the
-%% argument-list. Returns that string.
-find_common_prefix(Files=[[FirstChar|_]|_]) ->
- find_common_prefix_2(Files,FirstChar,[],[]);
-find_common_prefix([_|_]) -> % Means that prefix is "".
- "".
-
-find_common_prefix_2([[CurrChar|RestString]|Rest],CurrChar,Files,RevPrefix) ->
- find_common_prefix_2(Rest,CurrChar,[RestString|Files],RevPrefix);
-find_common_prefix_2([_String|_],_CurrChar,_Files,RevPrefix) ->
- lists:reverse(RevPrefix); % Found a difference.
-find_common_prefix_2([],CurrChar,Files=[[FirstChar|_]|_],RevPrefix) ->
- find_common_prefix_2(Files,FirstChar,[],[CurrChar|RevPrefix]);
-find_common_prefix_2([],CurrChar,_,RevPrefix) ->
- lists:reverse([CurrChar|RevPrefix]). % Actually, prefix was entire string!
-
-%% Help function which returns a sorted list of FileSet with the oldest first.
-find_hole_in_wrapset(FileSet,PreLen,SufLen) ->
- NumberedFiles=find_hole_in_wrapset_2(FileSet,PreLen,SufLen),
- find_hole_in_wrapset_3(lists:sort(NumberedFiles),0,[]). % Wrap-sets start at 0.
-
-find_hole_in_wrapset_2([FileName|Rest],PreLen,SufLen) ->
- [{list_to_integer(lists:sublist(FileName,PreLen+1,length(FileName)-PreLen-SufLen)),
- FileName}|
- find_hole_in_wrapset_2(Rest,PreLen,SufLen)];
-find_hole_in_wrapset_2([],_,_) ->
- [].
-
-find_hole_in_wrapset_3([{N,FileName}|Rest],N,Acc) ->
- find_hole_in_wrapset_3(Rest,N+1,[FileName|Acc]);
-find_hole_in_wrapset_3([{_,FileName}|Rest],_N,Acc) -> % FileName is the oldest one.
- [FileName|lists:map(fun({_,FN})->FN end,Rest)]++lists:reverse(Acc);
-find_hole_in_wrapset_3([],_,Acc) -> % Means all were in order.
- lists:reverse(Acc).
-%% -----------------------------------------------------------------------------
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/inviso/src/inviso_tool.erl b/lib/inviso/src/inviso_tool.erl deleted file mode 100644 index 7d3cfb9da0..0000000000 --- a/lib/inviso/src/inviso_tool.erl +++ /dev/null @@ -1,3255 +0,0 @@ -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Description: -%% The inviso_tool implementation. A tool that uses inviso. -%% -%% Authors: -%% Lennart Öhman, [email protected] -%% ----------------------------------------------------------------------------- - --module(inviso_tool). - - -%% This is the inviso tool, which is a tool using the inviso trace application. -%% It is developed to make tracing using trace cases possible in an environment -%% of distributed Erlang nodes. -%% A current restriction is that the Erlang nodes are supposed to have the same -%% code. This since inviso tool can at this point not handle subsets of nodes. -%% Instead all participating Erlang nodes are treated the same. -%% -%% The main functionality of the inviso tool are: -%% -%% (1) Handles start and stop of tracing at participating nodes. -%% (2) Interprets trace-case files at a distributed network level. -%% (The inviso runtime component is responsible for interpreting -%% trace cases at a local level, if run in an autostart). -%% (3) Keeps a command history log from which: -%% (a) Sequences easily can be repeated. -%% (b) Autostart configuration files can be created (understood by the -%% default inviso autostart mechanism). -%% (4) Performs reactivation in case tracing is suspended (manually or by -%% an overload mechanism). -%% (5) Can reconnect crashed nodes and by using the history bringing them -%% up to speed. - -%% Distributed Erlang -%% ------------------ -%% Inviso is built to run in a distributed environment. -%% The inviso tool can also be used in a non distributed environment. - -%% Short description -%% ----------------- -%% Start-up of the inviso tool -%% During the start-up of the tool, the tool starts runtime components at -%% all participating nodes. A runtime component can already be running at -%% a particular node and will then simply be adopted. -%% -%% Session -%% A session is said to start when tracing is initiated, and ends when -%% made to stop by the user. When a session is stopped, tracing is stopped -%% at all participating nodes. Note that participating nodes may come and -%% go though the time-frame of a session. That means that if a node is -%% reconnected it may resume its tracing in the current session through -%% a 'restart_session'. A runtime component that is already tracing at the -%% time start-session will simply be part of the session without its -%% ingoing tracing being changed. -%% -%% Reactivation -%% A node that is suspended can be reactivated to resume tracing. Note that -%% tracing has in this situation never been stopped at the node in question. -%% The inviso tool resumes the node and applies the history to it. -%% -%% Reconnect -%% A node that is "down" from the inviso tool's perspective can be -%% reconnected. During reconnection the tool restarts the runtime component -%% at that node but does not (re)initiate tracing. The latter is called -%% restart_session and must be done explicitly, unless the node in question -%% is in fact already tracing. If the node is already tracing (due to an autostart -%% for instance), it automatically becomes part of the ongoing session (if -%% there is an ongoing session). -%% -%% Restart Session -%% A node that has been down and has been reconnected can be made to -%% initialize and resume its tracing. This is done by starting the session -%% at the node in question and redoing the current history. - -%% Trace files within a session -%% Since it is possible to init-tracing (from an inviso perspective) several -%% times within the same session, a session may leave several trace log files -%% behind. This must be resolved by the tracer data generator function -%% (user supplied) by marking filenames in a chronological order but still -%% making them possible to identify as part of the same session - - - -%% ----------------------------------------------------------------------------- -%% API exports. -%% ----------------------------------------------------------------------------- - --export([start/0,start/1,stop/0,stop/1]). --export([reconnect_nodes/0,reconnect_nodes/1, - start_session/0,start_session/1, - reinitiate_session/0,reinitiate_session/1, - restore_session/0,restore_session/1,restore_session/2, - stop_session/0, - reset_nodes/0,reset_nodes/1, - atc/3,sync_atc/3,sync_atc/4, - sync_rtc/2,sync_rtc/3, - dtc/2,sync_dtc/2,sync_dtc/3, - inviso/2]). --export([reactivate/0,reactivate/1, - save_history/1, - get_autostart_data/1,get_autostart_data/2, - get_activities/0,get_node_status/0,get_node_status/1,get_session_data/0]). --export([flush/0,flush/1]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Debug exports. -%% ----------------------------------------------------------------------------- - --export([get_loopdata/0]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% OTP exports and call backs. -%% ----------------------------------------------------------------------------- - --export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Internal exports. -%% ----------------------------------------------------------------------------- - --export([tc_executer/4,reactivator_executer/6]). --export([std_options_generator/1]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Constants. -%% ----------------------------------------------------------------------------- - -%% Defines the inviso function calls that shall be possible to do through the -%% inviso API in this tool. --define(INVISO_CMDS, - [{tp,5},{tp,4},{tp,1},{tpl,5},{tpl,4},{tpl,1}, - {ctp,1},{ctp,2},{ctp,3},{ctpl,1},{ctpl,2},{ctpl,3}, - {tf,2},{tf,1},{ctf,2},{ctf,1},{ctf_all,0}, - {init_tpm,4},{init_tpm,7}, - {tpm,4},{tpm,5},{tpm,8}, - {tpm_tracer,4},{tpm_tracer,5},{init_tpm,8}, - {tpm_ms,5},{tpm_ms_tracer,5}, - {ctpm_ms,4},{ctpm,3}, - {tpm_localnames,0},{ctpm_localnames,0}, - {tpm_globalnames,0},{ctpm_globalnames,0}, - {ctp_all,0}, - {suspend,1},{cancel_suspension,0}]). -%% ----------------------------------------------------------------------------- - -%% These inviso functions shall be included in the command history log. Others -%% are not relevant to be redone during a recactivation, a restart session or -%% exported to an autostart file. --define(INVISO_CMD_HISTORY, - [{tp,5},{tp,4},{tp,1},{tpl,5},{tpl,4},{tpl,1}, - {ctp,1},{ctp,2},{ctp,3},{ctpl,1},{ctpl,2},{ctpl,3}, - {tf,2},{tf,1},{ctf,2},{ctf,1},{ctf_all,0}, - {init_tpm,4},{init_tpm,7}, - {tpm,4},{tpm,5},{tpm,8}, - {tpm_tracer,4},{tpm_tracer,5},{init_tpm,8}, - {tpm_ms,5},{tpm_ms_tracer,5}, - {ctpm_ms,4},{ctpm,3}, - {tpm_localnames,0},{ctpm_localnames,0}, - {tpm_globalnames,0},{ctpm_globalnames,0}, - {ctp_all,0}]). -%% ----------------------------------------------------------------------------- - -%% Since many function calls to inviso may take long time, especially if they -%% involve difficult and many trace patterns to set, the default gen_server:call -%% time out can not be used. We just do not want to get stuck for ever if some -%% error occurs. --define(CALL_TIMEOUT,60000). - -%% Default max time to wait for a trace case called synchronously to return. --define(SYNC_TC_TIMEOUT,10000). - -%% Runtime components shall terminate when the tool terminates. --define(DEFAULT_DEPENDENCY,{dependency,0}). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Record definitions. -%% ----------------------------------------------------------------------------- - -%% The loopdata record. --record(ld,{ - dir=".", % Working dir of the tool. - nodes=down, % The nodesD database, defaults to non-distr. - c_node, % Location of inviso_c. - c_pid, % The inviso control component. - regexp_node, % Node for regexp expansions. - tc_dict, % Trace case definition db. - chl, % Command history log. - session_state=passive, % passive | tracing - tdg={inviso_tool_lib,std_tdg,[]}, % Tracer data generator func. - tracer_data, % Current session nr and TDGargs. - reactivators=[], % Pids of now running reactivators. - tc_def_file, % Trace case definition file. - optg={?MODULE,std_options_generator,[]}, % Generates options to add_nodes/3. - initial_tcs=[], % Initial trace cases. - started_initial_tcs=[], % Cases that must be stopped when stop_tracing. - history_dir, % File path for history file. - keep_nodes=[], % Nodes that shall not be cleared when stopping. - debug=false % Internal debug mode - }). -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% API -%% ============================================================================= - -%% start()={ok,Pid} | {error,{already_started,pid()}} -%% start(Config) -%% Config=[{Opt,Value},...], list of tuple options. -%% Opt=dir|nodes|c_node|regexp_node|tdg|tc_def_file|optg|initial_tcs| -%% history_dir|keep_nodes -%% Starts the inviso_tool process. Options in Config are the same as those -%% which are kept in the #ld structure. -start() -> - start([]). -start(Config) -> - gen_server:start({local,?MODULE},?MODULE,Config,[]). -%% ----------------------------------------------------------------------------- - -%% stop(UntouchedNodes)= -%% stop()={ok,NodeResults} | NodeResult | {error,Reason} -%% UntouchedNodes=list(), nodes where any trace patterns shall not be removed. -%% NodeResults=[{Node,NodeResult},...] -%% NodeResult=ok | {error,Reason} | patterns_untouched -%% Stops the inviso tool and the inviso control component. Runtime components are -%% stopped by them selves depending on their dependcy of the control component. -%% All runtime components that are not marked as to be kept will have their -%% trace patterns cleared before the inviso control component is shutdown. -%% The NodeResults indicates which nodes were successfullt handled. -stop() -> - stop([]). -stop(UntouchedNodes) -> - gen_server:call(?MODULE,{stop,UntouchedNodes},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% reconnect_nodes()=NodeResult; function for the nod-distributed case. -%% reconnect_nodes(Nodes)={ok,NodesResults} -%% NodesResults=[{Node,NodeResult},...] -%% NodeResult={ok,{State,Status}} | {error,NReason} -%% State=tracing | inactive -%% Status=running | suspended -%% NReason=unknown_node | already_connected | down -%% (Re)starts the inviso runtime components at Nodes. Depending on its state -%% (new,idle or tracing) and if the tool is running a session or not, it becomes -%% part of the tool's ongoing session. If the newly reconnected node is not -%% tracing but the tool runs a session, the node must be reinitiated to become -%% tracing. -reconnect_nodes() -> - gen_server:call(?MODULE,{reconnect_nodes,local_runtime},?CALL_TIMEOUT). -reconnect_nodes(Node) when is_atom(Node) -> - reconnect_nodes([Node]); -reconnect_nodes(Nodes) when is_list(Nodes) -> - gen_server:call(?MODULE,{reconnect_nodes,Nodes},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% start_session()={ok,{SessionNr,InvisoReturn}} | {error,Reason} -%% start_session(MoreTDGargs)= -%% MoreTDGargs=list(), prepended to the fixed list of args used when calling the -%% tracer data generator function. -%% SessionNr=integer(), trace sessions are numbered by the tool. -%% InvisoReturn=If successful inviso call, the returnvalue from inviso. -%% Note that individual nodes may be unsuccessful. See inviso:init_tracing/1 -%% Initiates tracing at all participating nodes. -start_session() -> - start_session([]). -start_session(MoreTDGargs) -> - gen_server:call(?MODULE,{start_session,MoreTDGargs},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% reinitiate_session(Nodes)={ok,InvisoReturn} | {error,Reason} -%% InvisoReturn=If successful inviso call, the returnvalue from inviso:init_tracing/1. -%% Note that individual nodes may be unsuccessful. Mentioned nodes not part -%% of the tool or not in state inactive will be marked as failing by the -%% tool in the InvisoReturn. -%% To reinitate a node means to (inviso) init tracing at it according to saved -%% tracer data generator arguments for the current session and then redo the current -%% history to bring it up to speed. Note that the tool must be running a session -%% for reinitiate to work. -reinitiate_session() -> - gen_server:call(?MODULE,{reinitiate_session,local_runtime},?CALL_TIMEOUT). -reinitiate_session(Nodes) -> - gen_server:call(?MODULE,{reinitiate_session,Nodes},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% restore_session()= -%% restore_session(MoreTDGargs)= -%% restore_session(FileName)= -%% restore_session(FileName,MoreTDGargs)={ok,{SessionNr,InvisoReturn}} | {error,Reason} -%% The two first clauses will start a new session using the last history. This -%% implies that there must have been a session running prior. -%% The two last clauses starts a session and reads a history file and executes the -%% tracecases in it at all inactive nodes. -%% In both cases the reused or read history becomes the current histoy, just if the -%% session had been initiated manually. The tool may not -%% have a session ongoing, and nodes already tracing (nodes which were adopted) -%% are not effected. Just like when starting a session manually. -restore_session() -> - restore_session([]). -restore_session([]) -> % This cant be a filename. - gen_server:call(?MODULE,{restore_session,[]},?CALL_TIMEOUT); -restore_session(FileNameOrMoreTDGargs) -> - case is_string(FileNameOrMoreTDGargs) of - true -> % Interpret it as a filename. - restore_session(FileNameOrMoreTDGargs,[]); - false -> % The we want to use last session history! - gen_server:call(?MODULE,{restore_session,FileNameOrMoreTDGargs},?CALL_TIMEOUT) - end. -restore_session(FileName,MoreTDGargs) -> - gen_server:call(?MODULE,{restore_session,{FileName,MoreTDGargs}},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% stop_session()={ok,{SessionNr,Result}} | {error,Reason} -%% SessionNr=integer() -%% Result=[{Node,NodeResult},...] | NonDistributedNodeResult -%% NodeResult=ok | {error,Reason} -%% NonDistributedNodeResult=[ok] | [] -%% Stops inviso tracing at all participating nodes. The inviso runtime components -%% will go to state idle. It is now time to fetch the logfiles. Will most often -%% succeed. Will only return an error if the entire inviso call returned an -%% error. Not if an individual node failed stop tracing successfully. -%% Any running trace case, including reactivator processes will be terminated. -stop_session() -> - gen_server:call(?MODULE,stop_session,?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% reset_nodes()=NodeResult | {error,Reason} -%% reset_nodes(Nodes)={ok,NodeResults} | {error,Reason} -%% NodeResults and NodeResult as returned by inviso:clear/1 and /0. -%% Clear nodes from trace flags, trace patterns and meta trace patterns. The tool -%% must not be having a running session. -reset_nodes() -> - gen_server:call(?MODULE,{reset_nodes,local_runtime},?CALL_TIMEOUT). -reset_nodes(Nodes) -> - gen_server:call(?MODULE,{reset_nodes,Nodes},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% atc(TC,Id,Vars)=ok | {error,Reason} -%% TC=atom(), name of the trace case. -%% Id=term(), given name of this usage of TC. -%% Vars=list(), list of variable bindings [{Var,Value},...], Var=atom(),Value=term(). -%% Function activating a trace case. The trace case must be defined in the -%% trace case dictionary. The 'ok' return value is only a signal that the -%% trace case has started successfully. It may then run for as long as it is -%% programmed to run. An erroneous return value does not necessarily mean that -%% the trace case has not been executed. It rather means that is undetermined -%% what happend. -atc(TC,Id,Vars) -> - gen_server:call(?MODULE,{atc,{TC,Id,Vars}},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% sync_atc(TC,Id,Vars)=Result | {error,Reason} -%% sync_atc(TC,Id,Vars,TimeOut)= -%% Result=term(), what ever is returned be the last expression in the trace case. -%% TimeOut=interger() | infinity, the max wait time for the trace case to finnish. -%% As atc/3 but waits for the trace case to finish. -sync_atc(TC,Id,Vars) -> - gen_server:call(?MODULE,{sync_atc,{TC,Id,Vars,?SYNC_TC_TIMEOUT}},?CALL_TIMEOUT). -sync_atc(TC,Id,Vars,TimeOut) -> - gen_server:call(?MODULE,{sync_atc,{TC,Id,Vars,TimeOut}},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% sync_rtc(TC,Vars)=Result | {error,Reason} -%% sync_rtc(TC,Vars,TimeOut)= -%% Result=term(), what ever is returned be the last expression in the trace case. -%% TimeOut=interger() | infinity, the max wait time for the trace case to finnish. -%% As sync_atc/3 but the trace case is not marked as activated. It is mearly placed -%% in the history. Hence with sync_rtc a trace case can be "activated" multiple time. -sync_rtc(TC,Vars) -> - gen_server:call(?MODULE,{sync_rtc,{TC,Vars,?SYNC_TC_TIMEOUT}},?CALL_TIMEOUT). -sync_rtc(TC,Vars,TimeOut) -> - gen_server:call(?MODULE,{sync_rtc,{TC,Vars,TimeOut}},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% dtc(TC,Id)=ok | {error,Reason} -%% Deactivates a previosly activated trace case. This function can only be used -%% on trace cases that has a deactivation defined in the trace case dictionary. -%% There is of course really no difference between a file containing an activation -%% compared to a deactivation. But to be able cancelling activations out from the -%% history log, a defined deactivation is essential. -%% As with activation, the returned 'ok' simply indicates the start of the trace -%% case. -dtc(TC,Id) -> - gen_server:call(?MODULE,{dtc,{TC,Id}},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% sync_dtc(TC,Id)=Result | {error,Reason} -%% sync_dtc(TC,Id,TimeOut)= -%% Synchronous deactivation of trace case. See dtc/2 and sync_atc/3 for -%% parameters. -sync_dtc(TC,Id) -> - gen_server:call(?MODULE,{sync_dtc,{TC,Id,?SYNC_TC_TIMEOUT}},?CALL_TIMEOUT). -sync_dtc(TC,Id,TimeOut) -> - gen_server:call(?MODULE,{sync_dtc,{TC,Id,TimeOut}},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% inviso(Cmd,Args)=Result -%% Cmd=atom(), the (inviso) function name that shall be called. -%% Args=list(), the arguments to Cmd. -%% Result=term(), the result from the inviso function call. -%% This function executes a Cmd in the inviso tool context. The inviso call will -%% be logged in history log and thereby repeated in case of a reactivation. -%% Note that this function is intended for use with inviso function API without -%% specifying any nodes, since the function call is supposed to be carried out on -%% all nodes. -%% When these functions are written to an autostart config file by the tool there -%% is supposed to be a translation to inviso_rt functions. -inviso(Cmd,Args) -> - gen_server:call(?MODULE,{inviso,{Cmd,Args}},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% reactivate()=ok | {error,Reason} -%% reactivate(Node)=ok | {error,Reason} -%% Moves a runtime component from suspended to the state running. This can be -%% done for both tracing and inactive nodes. The later is necessary since you -%% may have stopped tracing with a node suspended. -%% In case the node is tracing, commands in the command history log are redone at -%% the node in questions. -%% Note that this function returns 'ok' before the node is running. This because the -%% the reactivated history is done by a separate process and there is no guarantee -%% when it will be ready. The reactivated node will not be marked as running in -%% the tool until done reactivating. -%% Further it is important to understand that if there are "ongoing" tracecases -%% (i.e tracecase scripts that are currently executing) and this node was running -%% at the time that tracecase script started to execute, the list of nodes bound -%% to the Nodes variable in that script executer includes this node. Making it -%% no longer suspended makes it start executing inviso commands from where ever -%% such are called. Hence the reactivation may be interferred by that tracecase. -reactivate() -> % Non-distributed API. - reactivate(node()). -reactivate(Node) -> - gen_server:call(?MODULE,{reactivate,Node},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% save_history(FileName)={ok,AbsFileName} | {error,Reason} -%% Saves the currently collected command history log to a file. The file will -%% be a binary-file. If FileName is an absolute path, it will be saved to that -%% file. Otherwise the history dir will be used. If no history dir was specified -%% the tool dir will be used, prepended to FileName. -save_history(FileName) -> - gen_server:call(?MODULE,{save_history,FileName},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% get_autostart_data(Nodes,Dependency)={ok,{AutoStartData,NodeResults} | -%% {ok,{AutoStartData,NodeResult}} | {error,Reason} -%% Dependency=inviso dependency parameter which will be used for every -%% autostarted runtime component (included in Options). -%% NodeResults=[{Node,NodeResult},...] -%% NodeResult={ok,{Options,{tdg,{M,F,CompleteTDGargs}}}} | {error,Reason} -%% Options=add_nodes options to the inviso runtime component. -%% M,F=atom(), the module and function for tracerdata generation. -%% CompleteTDGargs=list(), all arguments as they are given to the tracer -%% data generator function. -%% AutostartData=[CaseSpec,...] -%% CaseSpec={file,{FileName,Bindings}} | {mfa,{M,F,Args}} -%% FileName=string(), pointing out the trace case file. Note that this -%% is the same as the path used by the tool. -%% Bindings=Var bindings used according to the history for the -%% invocation. -%% M,F=atom(), the function that shall be called (normally some inviso). -%% Args=list(), the actual arguments. Note that this may contain things -%% which can not be written to file (ports, pids,...). -%% Function returning information on how to autostart a node to make it trace -%% according to the current history. The inviso_tool does not know how to write -%% the necessary files at the nodes in question. That must be done by the user -%% of the tool, guided by the return value from this function. -%% Note that there will be two types of trace case files. Regular trace case -%% files and binaries returned from this function. The latter contains the -%% inviso commands which have been executed. Note that the order amongst the -%% trace cases and binaries is of importance (otherwise they will be redone in -%% an incorrect order). -get_autostart_data(Dependency) -> - gen_server:call(?MODULE,{get_autostart_data,Dependency},?CALL_TIMEOUT). -get_autostart_data(Nodes,Dependency) -> - gen_server:call(?MODULE,{get_autostart_data,{Nodes,Dependency}},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% get_activities()={ok,Ongoing} | {error,Reason} -%% Ongoing=list(); [ [TraceCases] [,Reactivators] ] -%% TraceCases={tracecases,TraceCaseList} -%% TraceCaseList=[{{TCname,Id},Phase},...] -%% Phase=activating | deactivating -%% Reactivators={reactivating_nodes,ReactivatingNodes} -%% ReactivatingNodes=[Node,...] -%% Returns a list of assynchronous tracecases and nodes doing reactivation at -%% this momement. This can be useful to implement "home brewn" synchronization, -%% waiting for the runtime components to reach a certain state. -get_activities() -> - gen_server:call(?MODULE,get_activities,?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% get_status(Node)={ok,StateStatus} | {error,Reason} -%% StateStatus={State,Status} | reactivating | down -%% State=tracing | inactive | trace_failure -%% Status=running | suspended -get_node_status() -> - get_node_status(local_runtime). -get_node_status(Node) -> - gen_server:call(?MODULE,{get_node_status,Node},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% get_session_data()={ok,{Status,SessionNr,TDGargs}} | {error,Reason} -%% Status=tracing | not_tracing, info about current/last session. -%% SessionNr=integer() -%% TDGargs=list(), list of the arguments that will be given to the tracer data -%% generator function (not including the leading Nodes list). -%% Returns data about the current or last session. -get_session_data() -> - gen_server:call(?MODULE,get_session_data,?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% flush()={ok,NodeResults} | NodeResult | {error,Reason} -%% flush(Nodes)={ok,NodesResults} | {error,Reason} -%% NodeResults=[{Node,NodeResult},...] -%% NodeResult=ok | {error,Reason} -%% Makes runtime components flush their trace ports. -flush() -> - gen_server:call(?MODULE,flush,?CALL_TIMEOUT). -flush(Nodes) -> - gen_server:call(?MODULE,{flush,Nodes},?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% get_loopdata()=#ld -%% Debug API returning the internal loopdata structure. See #ld above for details. -get_loopdata() -> - gen_server:call(?MODULE,get_loopdata,?CALL_TIMEOUT). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Internal APIs. -%% ----------------------------------------------------------------------------- - -%% tc_executer_reply(To,Reply)=nothing significant -%% To=pid() -%% Reply=term() -%% Internal API used by a trace case executer process to signal its completion. -tc_executer_reply(To,Reply) -> - gen_server:cast(To,{tc_executer_reply,Reply}). -%% ----------------------------------------------------------------------------- - -%% Internal API used by a reactivator process indicating it is done with the -%% history log it has got so far. -%% Timeout set to infinity since the tool may be busy, then the reactivator just -%% have to wait. If the tool crashes the reactivator will be go down too automatically. -reactivator_reply(TPid,Counter) -> - gen_server:call(TPid,{reactivator_reply,{Counter,self()}},infinity). -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% gen_server implementation. -%% ============================================================================= - -init(Config) -> - case fetch_configuration(Config) of % From conf-file and Config. - {ok,LD} when is_record(LD,ld) -> - case start_inviso_at_c_node(LD) of - {ok,CPid} -> - LD2=start_runtime_components(LD), - LD3=read_trace_case_definitions(LD2), - process_flag(trap_exit,true), - start_subscribe_inviso_events(LD3#ld.c_node), - {ok,LD3#ld{c_pid=CPid}}; - {error,Reason} -> % Most likely already running. - {stop,{error,Reason}} - end; - {error,Reason} -> - {stop,{error,{start_up,Reason}}} - end. -%% ----------------------------------------------------------------------------- - -%% Help function starting the inviso control component at node c_node, or "here" -%% if it is not a distributed network. -start_inviso_at_c_node(#ld{c_node=undefined}) -> % Non distributed case. - case inviso:start() of - {ok,Pid} -> - {ok,Pid}; - {error,Reason} -> - {error,Reason} - end; -start_inviso_at_c_node(#ld{c_node=CNode}) -> - case rpc:call(CNode,inviso,start,[]) of - {ok,Pid} -> - {ok,Pid}; - {error,{already_started,_}} -> % A control component already started. - {error,{inviso_control_already_running,CNode}}; - {error,Reason} -> - {error,Reason}; - {badrpc,Reason} -> - {error,{inviso_control_node_error,Reason}} - end. -%% ----------------------------------------------------------------------------- - -%% Help function starting the runtime components at all particapting nodes. -%% It also updates the nodes structure in the #ld to indicate which nodes where -%% successfully started. Returns a new #ld. -%% Note that a runtime component may actually be running at one or several nodes. -%% This is supposed to be the result of an (wanted) autostart. Meaning that the -%% inviso tool can not handle the situation if a runtime component is not doing -%% what it is supposed to do. In case a runtime component is already running it -%% will be adopted and therefore marked as running. -start_runtime_components(LD=#ld{c_node=undefined}) -> - start_runtime_components_2(local_runtime,undefined,LD); -start_runtime_components(LD=#ld{c_node=CNode,nodes=NodesD}) -> - start_runtime_components_2(get_all_nodenames_nodes(NodesD),CNode,LD). -start_runtime_components(Nodes,LD=#ld{c_node=CNode}) -> - start_runtime_components_2(Nodes,CNode,LD). - -start_runtime_components_2(local_runtime,CNode,LD=#ld{optg=OptG}) -> - Opts=start_runtime_components_mk_opts(local_runtime,OptG), - case inviso:add_node(mk_rt_tag(),Opts) of - {ok,NAnsw} -> % Should be more clever really! - NewNodesD=update_added_nodes(CNode,{ok,NAnsw},LD#ld.nodes), - LD#ld{nodes=NewNodesD}; - {error,_Reason} -> - LD - end; -start_runtime_components_2([Node|Rest],CNode,LD=#ld{optg=OptG}) -> - Opts=start_runtime_components_mk_opts(Node,OptG), - case rpc:call(CNode,inviso,add_nodes,[[Node],mk_rt_tag(),Opts]) of - {ok,NodeResults} -> - NewNodesD=update_added_nodes(CNode,NodeResults,LD#ld.nodes), - start_runtime_components_2(Rest,CNode,LD#ld{nodes=NewNodesD}); - {error,_Reason} -> - start_runtime_components_2(Rest,CNode,LD); - {badrpc,_Reason} -> - start_runtime_components_2(Rest,CNode,LD) - end; -start_runtime_components_2([],_,LD) -> - LD. - -start_runtime_components_mk_opts(Node,{M,F,Args}) -> - case catch apply(M,F,[Node|Args]) of - {ok,Opts} when is_list(Opts) -> - start_runtime_component_mk_opts_add_dependency(Opts); - _ -> - [?DEFAULT_DEPENDENCY] - end. - -%% The options generator is not supposed to generate the dependency. Hence this -%% function adds and if necessary removes an incorrectly added dependency tag. -start_runtime_component_mk_opts_add_dependency(Opts) -> - case lists:keysearch(dependency,1,Opts) of - {value,_} -> % Not allowed!!! - [?DEFAULT_DEPENDENCY|lists:keydelete(dependecy,1,Opts)]; - false -> - [?DEFAULT_DEPENDENCY|Opts] - end. -%% ----------------------------------------------------------------------------- - -%% Help function subscribing to inviso events from the inviso controller. This -%% will make it possible to follow runtime components going down. -start_subscribe_inviso_events(undefined) -> - inviso:subscribe(); -start_subscribe_inviso_events(CNode) -> - rpc:call(CNode,inviso,subscribe,[self()]). % Don't want the rpc-proc to subscribe! -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% gen_server handle call back functions. -%% ----------------------------------------------------------------------------- - -handle_call({stop,UntouchedNodes},_From,LD=#ld{nodes=NodesD,c_node=CNode,keep_nodes=KeepNodes}) - when is_list(UntouchedNodes) -> - {stop, - normal, - remove_all_trace_patterns(CNode, - UntouchedNodes++KeepNodes, - get_available_nodes(NodesD)), - LD}; -handle_call({stop,BadArg},_From,LD) -> - {reply,{error,{badarg,BadArg}},LD}; - -handle_call({reconnect_nodes,Nodes},_From,LD) -> - case h_reconnect_nodes(Nodes,LD) of - {ok,{Nodes2,NodesErr,NewLD}} -> - if - Nodes==local_runtime -> - {reply, - build_reconnect_nodes_reply(Nodes,Nodes2,NodesErr,NewLD#ld.nodes), - NewLD}; - is_list(Nodes) -> - {reply, - {ok,build_reconnect_nodes_reply(Nodes,Nodes2,NodesErr,NewLD#ld.nodes)}, - NewLD} - end; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - -handle_call({start_session,MoreTDGargs},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of - false -> % No session running. - if - is_list(MoreTDGargs) -> - DateTime=calendar:universal_time(), - {M,F,Args}=LD#ld.tdg, - TDGargs=inviso_tool_lib:mk_tdg_args(DateTime,MoreTDGargs++Args), - case h_start_session(M,F,TDGargs,LD) of - {ok,{SessionNr,ReturnVal,NewLD}} -> % No nodes to initiate. - NewLD2=add_initial_tcs_to_history(NewLD#ld.initial_tcs, - NewLD#ld{chl=mk_chl(LD#ld.chl)}), - {reply, - {ok,{SessionNr,ReturnVal}}, - NewLD2#ld{session_state=tracing_sessionstate()}}; - {ok,{SessionNr,ReturnVal,Nodes2,NewLD}} -> - NewLD2=do_initial_tcs(NewLD#ld.initial_tcs, - Nodes2, - NewLD#ld{chl=mk_chl(LD#ld.chl)}), - {reply, - {ok,{SessionNr,ReturnVal}}, - NewLD2#ld{session_state=tracing_sessionstate()}}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - true -> % Faulty TDGargs. - {reply,{error,{badarg,MoreTDGargs}},LD} - end; - true -> - {reply,{error,session_already_started},LD} - end; - -handle_call({reinitiate_session,Nodes},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of - true -> % The tool must be tracing. - {M,F,_Args}=LD#ld.tdg, - TDGargs=get_latest_tdgargs_tracer_data(LD#ld.tracer_data), - case h_reinitiate_session(Nodes,M,F,TDGargs,LD) of - {ok,{NodesErr,ReturnVal,NewLD}} -> - {reply, - {ok,build_reinitiate_session_reply(Nodes,NodesErr,ReturnVal)}, - NewLD}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - false -> % Must have a running session! - {reply,{error,no_session},LD} - end; - -handle_call({restore_session,{FileName,MoreTDGargs}},_From,LD=#ld{chl=OldCHL}) - when is_list(MoreTDGargs) -> - case is_tracing(LD#ld.session_state) of - false -> - case catch make_absolute_path(FileName,LD#ld.dir) of - AbsFileName when is_list(AbsFileName) -> - case file:read_file(AbsFileName) of - {ok,Bin} -> - if - is_list(MoreTDGargs) -> - case catch replace_history_chl(OldCHL, - binary_to_term(Bin)) of - {ok,CHL} -> % The file was well formatted. - case h_restore_session(MoreTDGargs, - LD#ld{chl=CHL}) of - {ok,{SessionNr,ReturnVal,NewLD}} -> - {reply, - {ok,{SessionNr,ReturnVal}}, - NewLD#ld{session_state= - tracing_sessionstate()}}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - Error -> % Badly formatted file. - {reply, - {error,{bad_file,{AbsFileName,Error}}}, - LD} - end; - true -> - {reply,{error,{badarg,MoreTDGargs}},LD} - end; - {error,Reason} -> - {reply,{error,{read_file,Reason}},LD} - end; - Error -> - {reply,{error,{bad_filename,{FileName,Error}}},LD} - end; - true -> - {reply,{error,session_already_started},LD} - end; -%% This is doing restore session on the current history. -handle_call({restore_session,MoreTDGargs},_From,LD=#ld{chl=CHL}) -> - case is_tracing(LD#ld.session_state) of - false -> - case history_exists_chl(CHL) of - true -> % There is a history to redo. - if - is_list(MoreTDGargs) -> - case h_restore_session(MoreTDGargs,LD) of - {ok,{SessionNr,ReturnVal,NewLD}} -> - {reply, - {ok,{SessionNr,ReturnVal}}, - NewLD#ld{session_state=tracing_sessionstate()}}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - true -> - {reply,{error,{badarg,MoreTDGargs}},LD} - end; - false -> - {reply,{error,no_history},LD} - end; - true -> - {reply,{error,session_already_started},LD} - end; - -%% To stop tracing means stop_tracing through the inviso API. But we must also -%% remove any help processes executing inviso commands (trace case executers -%% and reactivators). -%% Note that to be really sure we should actually wait for EXIT-signals from those -%% processes before returning a successful returnvalue to the caller. In theory -%% those processes could issue an inviso call effecting a new trace session started -%% with init_tracing shortly after the call to stop_tracing. But too complicated! :-) -%% Further, stop-tracing is done on all nodes in our nodes structure. Regardless -%% if the node is tracing or not -handle_call(stop_session,_From,LD=#ld{session_state=SState,chl=CHL,reactivators=ReAct}) -> - case is_tracing(SState) of - true -> - NewCHL=stop_all_tc_executer_chl(CHL), % Stop any running trace case proc. - NewReAct=stop_all_reactivators(ReAct), % Stop any running reactivators. - case h_stop_session(LD) of - {ok,{SessionNr,Result}} -> - NewNodesD=set_inactive_nodes(Result,LD#ld.nodes), - {reply, - {ok,{SessionNr,Result}}, - LD#ld{session_state=passive_sessionstate(), - nodes=NewNodesD, - chl=NewCHL, - reactivators=NewReAct, - started_initial_tcs=[]}}; - {error,Reason} -> % Now we're really in deep shit :-) - {reply,{error,{unrecoverable,Reason}},LD} - end; - false -> - {reply,{error,no_session},LD} - end; - -handle_call({reset_nodes,Nodes},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of - false -> % We can not be in a session. - {reply,h_reset_nodes(Nodes,LD#ld.c_node),LD}; - true -> - {reply,{error,session_active},LD} - end; - -%% Calling a trace-case, or "turning it on". -handle_call({atc,{TC,Id,Vars}},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of % Check that we are tracing now. - true -> - case h_atc(TC,Id,Vars,LD) of - {ok,NewLD} -> % Trace case executed. - {reply,ok,NewLD}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - false -> % Can't activate if not tracing. - {reply,{error,no_session},LD} - end; - -handle_call({sync_atc,{TC,Id,Vars,TimeOut}},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of - true -> - if - is_integer(TimeOut);TimeOut==infinity -> - case h_sync_atc(TC,Id,Vars,TimeOut,LD) of - {ok,NewLD,Result} -> - {reply,Result,NewLD}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - true -> - {reply,{error,{badarg,TimeOut}},LD} - end; - false -> - {reply,{error,no_session},LD} - end; - -handle_call({sync_rtc,{TC,Vars,TimeOut}},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of - true -> - if - is_integer(TimeOut);TimeOut==infinity -> - case h_sync_rtc(TC,Vars,TimeOut,LD) of - {ok,NewLD,Result} -> - {reply,Result,NewLD}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - true -> - {reply,{error,{badarg,TimeOut}},LD} - end; - false -> - {reply,{error,no_session},LD} - end; - - -handle_call({dtc,{TC,Id}},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of % Check that we are tracing now. - true -> - case h_dtc(TC,Id,LD) of - {ok,NewLD} -> - {reply,ok,NewLD}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - false -> % Can't activate if not tracing. - {reply,{error,no_session},LD} - end; - -handle_call({sync_dtc,{TC,Id,TimeOut}},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of % Check that we are tracing now. - true -> - if - is_integer(TimeOut);TimeOut==infinity -> - case h_sync_dtc(TC,Id,TimeOut,LD) of - {ok,NewLD,Result} -> - {reply,Result,NewLD}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - true -> - {reply,{error,{badarg,TimeOut}},LD} - end; - false -> % Can't activate if not tracing. - {reply,{error,no_session},LD} - end; - -handle_call({inviso,{Cmd,Args}},_From,LD=#ld{session_state=SState}) -> - case is_tracing(SState) of - true -> - if - is_list(Args) -> - case h_inviso(Cmd,Args,LD) of - {ok,{Reply,NewLD}} -> - {reply,Reply,NewLD}; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - true -> - {reply,{error,{badarg,Args}},LD} - end; - false -> % Can't do if not tracing. - {reply,{error,no_session},LD} - end; - -handle_call({reactivate,Node},_From,LD=#ld{nodes=NodesD,c_node=CNode}) -> - case get_state_nodes(Node,NodesD) of - {trace_failure,_} -> - {reply,{error,trace_failure},LD}; - {State,suspended} -> % The node is infact suspended. - case h_reactivate(Node,CNode) of - ok -> - case {State,is_tracing(LD#ld.session_state)} of - {tracing,true} -> % Only then shall we redo cmds. - {reply,ok,redo_cmd_history(Node,LD)}; - _ -> % All other just no longer suspended. - {reply,ok,LD#ld{nodes=set_running_nodes(Node,NodesD)}} - end; - {error,Reason} -> - {reply,{error,Reason},LD} - end; - reactivating -> - {reply,{error,reactivating},LD}; - {_,running} -> - {reply,{error,already_running},LD}; - down -> - {reply,{error,not_available},LD}; - false -> - {reply,{error,unknown_node},LD} - end; - -handle_call({save_history,FileName},_From,LD=#ld{chl=CHL,dir=Dir,history_dir=HDir}) -> - case lists:keysort(2,get_loglist_chl(CHL)) of - [] -> % Empty history or no history. - {reply,{error,no_history},LD}; - Log -> - case h_save_history(HDir,Dir,FileName,Log) of - {ok,AbsFileName} -> - {reply,{ok,AbsFileName},LD}; - {error,Reason} -> - {reply,{error,Reason},LD} - end - end; - -handle_call({get_autostart_data,{Nodes,Dependency}},_From,LD=#ld{chl=CHL}) -> - {ok,ASD} = build_autostart_data(lists:keysort(2,get_loglist_chl(CHL)),LD#ld.tc_dict), - TDGargs=get_latest_tdgargs_tracer_data(LD#ld.tracer_data), - {M,F,_}=LD#ld.tdg, - OptsG=LD#ld.optg, % Addnodes options generator. - {reply, - h_get_autostart_data(Nodes,LD#ld.c_node,Dependency,ASD,M,F,TDGargs,OptsG), - LD}; - -handle_call({get_autostart_data,Dependency},From,LD=#ld{c_node=undefined}) -> - handle_call({get_autostart_data,{local_runtime,Dependency}},From,LD); -handle_call({get_autostart_data,Dependency},From,LD=#ld{nodes=NodesD}) -> - Nodes=get_all_nodenames_nodes(NodesD), - handle_call({get_autostart_data,{local_runtime,{Nodes,Dependency}}},From,LD); - -handle_call(get_activities,_From,LD=#ld{chl=CHL,reactivators=Reactivators}) -> - TraceCases=get_ongoing_chl(CHL), - RNodes=get_all_nodes_reactivators(Reactivators), - ReturnList1= - if - TraceCases==[] -> - []; - true -> - [{tracecases,TraceCases}] - end, - ReturnList2= - if - RNodes==[] -> - ReturnList1; - true -> - [{reactivating_nodes,RNodes}|ReturnList1] - end, - {reply,{ok,ReturnList2},LD}; - -handle_call({get_node_status,Node},_Node,LD) -> - case get_state_nodes(Node,LD#ld.nodes) of - false -> - {reply,{error,unknown_node},LD}; - StateStatus -> - {reply,{ok,StateStatus},LD} - end; - -handle_call(get_session_data,_From,LD=#ld{session_state=SState,tracer_data=TD}) -> - case get_latest_session_nr_tracer_data(TD) of - undefined -> - {reply,{error,no_session},LD}; - SessionNr -> - TDGargs=get_latest_tdgargs_tracer_data(TD), - case is_tracing(SState) of - true -> - {reply,{ok,{tracing,SessionNr,TDGargs}},LD}; - false -> - {reply,{ok,{not_tracing,SessionNr,TDGargs}},LD} - end - end; - -handle_call(flush,_From,LD=#ld{c_node=CNode,nodes=NodesD}) -> - Nodes=get_tracing_nodes(NodesD), - {reply,h_flush(CNode,Nodes),LD}; -handle_call({flush,Nodes},_From,LD=#ld{c_node=CNode}) -> - {reply,h_flush(CNode,Nodes),LD}; - -handle_call(get_loopdata,_From,LD) -> - {reply,LD,LD}; - -%% Internal handle_call callbacks. - -handle_call({reactivator_reply,{Counter,RPid}},_From,LD=#ld{chl=CHL}) -> - HighestUsedCounter=get_highest_used_counter_chl(CHL), - if - HighestUsedCounter>Counter -> % There are now more log entries. - NewUnsortedLog=get_loglist_chl(CHL), - {reply,{more,NewUnsortedLog},LD}; - true -> % No Counter is youngest log entry. - NodesD=LD#ld.nodes, - Node=get_node_reactivators(RPid,LD#ld.reactivators), - {reply, - done, - LD#ld{nodes=set_running_nodes(Node,NodesD), - reactivators=del_reactivators(RPid,LD#ld.reactivators)}} - end. -%% ----------------------------------------------------------------------------- - -%% Handling a notification from a trace case execution process. Receiving this -%% indicated that this phase of the trace case is finnished. -handle_cast({tc_executer_reply,{Phase,ProcH,Result}},LD) -> - case Phase of - activating -> % The trace case is running now. - {ok,NewLD}=h_tc_activation_done(ProcH,Result,LD), - {noreply,NewLD}; - stopping -> - {ok,NewLD}=h_tc_stopping_done(ProcH,Result,LD), - {noreply,NewLD}; - _ -> - {noreply,LD} - end; -handle_cast(_,LD) -> - {noreply,LD}. -%% ----------------------------------------------------------------------------- - -%% This is the case when a runtime component goes down. We stop all running -%% reactivators for this node. Note that there can also be tracecases ongoing -%% where this node is part of the Nodes variable. But there is not much we can -%% do about that. Other then informing the user that it is unwise to reconnect -%% this node before those tracecases have stopped being ongoing. -handle_info({inviso_event,_CNode,_Time,{disconnected,Node,_}},LD) -> - {noreply,LD#ld{nodes=set_down_nodes(Node,LD#ld.nodes), - reactivators=stop_node_reactivators(Node,LD#ld.reactivators)}}; - -%% This is the case when a runtime component gets suspended. Much of the same -%% problem as described above applies. -handle_info({inviso_event,_CNode,_Time,{state_change,Node,{_,{suspended,_}}}},LD) -> - {noreply,LD#ld{nodes=set_suspended_nodes(Node,LD#ld.nodes), - reactivators=stop_node_reactivators(Node,LD#ld.reactivators)}}; - -handle_info(_,LD) -> - {noreply,LD}. -%% ----------------------------------------------------------------------------- - -%% Called when the tool server stops. First clause, termination is initiated by -%% our self and therefore controlled another way. In the second case we are -%% stopping for some external reason, and we must then do more here in terminate/2. -terminate(normal,#ld{c_node=CNode}) -> % This is when we are stopping our self. - stop_inviso_at_c_node(CNode); -terminate(_,#ld{c_node=CNode,nodes=NodesD,keep_nodes=KeepNodes}) -> - remove_all_trace_patterns(CNode,KeepNodes,get_all_nodenames_nodes(NodesD)), - stop_inviso_at_c_node(CNode). -%% ----------------------------------------------------------------------------- - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% ============================================================================= -%% Handler first level help functions. -%% ============================================================================= - -%% ----------------------------------------------------------------------------- -%% reconnect_nodes -%% ----------------------------------------------------------------------------- - -%% Help function reconnecting the nodes in Nodes. Listed nodes must be part of -%% the set of nodes handled by the tool. It is not possible to reconnect a node -%% that is not marked as down. This partly because we otherwise risk losing the -%% trace_failure state (which can not be rediscovered). -h_reconnect_nodes(local_runtime,LD=#ld{nodes=NodesD}) -> % Non-distributed. - case get_state_nodes(local_runtime,NodesD) of - down -> - {ok,{local_runtime,[],start_runtime_components(local_runtime,LD)}}; - _ -> % Allready connected! - {ok,{[],{error,already_connected},LD}} - end; -h_reconnect_nodes(Nodes,LD=#ld{nodes=NodesD}) when is_list(Nodes) -> - {Nodes2,NodesErr}= - lists:foldl(fun(N,{Nodes2,NodesErr})-> - case get_state_nodes(N,NodesD) of - down -> % Yes this node can be reconnected. - {[N|Nodes2],NodesErr}; - false -> % Not part of the node-set! - {Nodes2,[{N,{error,unknown_node}}|NodesErr]}; - _ -> % Allready connected! - {Nodes2,[{N,{error,already_connected}}|NodesErr]} - end - end, - {[],[]}, - Nodes), - LD2=start_runtime_components(Nodes2,LD), % Inpect the #ld.nodes for result. - {ok,{Nodes2,NodesErr,LD2}}; -h_reconnect_nodes(Nodes,_LD) -> - {error,{badarg,Nodes}}. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% start_session -%% ----------------------------------------------------------------------------- - -%% Help function starting the tracing at all nodes. Note that the tracer data -%% is calculated using a user defined function. This is how for instance the -%% file names (of the log files) are determined. -%% Before the nodes are initiated their (possibly remaining) trace patterns are -%% cleared, both local and global. -h_start_session(M,F,TDGargs,LD=#ld{c_node=CNode,nodes=NodesD,tracer_data=TDs}) -> - case get_inactive_running_nodes(NodesD) of - [] -> % There are no nodes to initiate! - h_start_session_nonodes(TDGargs,LD,[]); - Nodes -> % List of nodes or 'local_runtime'. - case h_start_session_ctp_all(CNode,Nodes) of - {ok,Errors,[]} -> % Now no nodes to initiate! - h_start_session_nonodes(TDGargs,LD,Errors); - {ok,Errors,Nodes2} -> % Now these nodes are fresh. - case call_tracer_data_generator(CNode,M,F,TDGargs,Nodes2) of - {ok,TracerList} -> % Generated our tracerdata. - case h_start_session_2(CNode,TracerList,Errors) of - {ok,ReturnValue} -> % Some nodes are initialized now. - {NewNodesD,Nodes3}= - set_tracing_running_nodes(CNode,ReturnValue,NodesD), - {SessionNr,NewTDs}=insert_td_tracer_data(TDGargs,TDs), - {ok,{SessionNr, - ReturnValue, - Nodes3, % The nodes that shall get initial tracases. - LD#ld{nodes=NewNodesD,tracer_data=NewTDs}}}; - {error,Reason} -> - {error,Reason} - end; - {error,Reason} -> % Faulty tracer data generator func. - {error,{bad_tdg,Reason}} - end; - {error,Reason} -> % Error clearing patterns. - {error,Reason} - end - end. - -h_start_session_nonodes(TDGargs,LD=#ld{c_node=CNode,tracer_data=TDs},Errors) -> - {SessionNr,NewTDs}=insert_td_tracer_data(TDGargs,TDs), - if - CNode==undefined -> - {ok,{SessionNr,[],LD#ld{tracer_data=NewTDs}}}; - true -> - {ok,{SessionNr,{ok,Errors},LD#ld{tracer_data=NewTDs}}} - end. - -%% Help function clearing all trace patterns on all nodes. -h_start_session_ctp_all(CNode,Nodes) -> - case remove_all_trace_patterns(CNode,[],Nodes) of - ok -> % Non-distributed case1. - {ok,[],local_runtime}; - {error,Reason} -> % Non-distributed case2 and general failure. - {error,Reason}; - {ok,NodeResults} -> - h_start_session_ctp_all_2(NodeResults,[],[]) - end. - -h_start_session_ctp_all_2([{Node,{error,Reason}}|Rest],Errors,Nodes) -> - h_start_session_ctp_all_2(Rest,[{Node,{error,Reason}}|Errors],Nodes); -h_start_session_ctp_all_2([{Node,_OkOrPatternsUntouched}|Rest],Errors,Nodes) -> - h_start_session_ctp_all_2(Rest,Errors,[Node|Nodes]); -h_start_session_ctp_all_2([],Errors,Nodes) -> - {ok,Errors,Nodes}. - -%% Help function doing the actual init_tracing. -h_start_session_2(undefined,TracerData,_Errors) -> % Non distributed case. - case inviso:init_tracing(TracerData) of - {ok,LogResult} when is_list(LogResult) -> - {ok,{ok,LogResult}}; - {error,already_initated} -> % Perhaps adopted!? - {ok,{error,already_initiated}}; % Not necessarily wrong. - {error,Reason} -> - {error,Reason} - end; -h_start_session_2(CNode,TracerList,Errors) -> - case rpc:call(CNode,inviso,init_tracing,[TracerList]) of - {ok,NodeResults} -> - {ok,{ok,Errors++NodeResults}}; - {error,Reason} -> - {error,Reason}; - {badrpc,Reason} -> - {error,{inviso_control_node_error,Reason}} - end. -%% ----------------------------------------------------------------------------- - -%% Help function starting all initial trace cases. They are actually handled -%% the same way as user started trace cases. We actually only start initial -%% tracecases at Nodes (if Nodes is a list of nodes). This because we may have -%% adopted some nodes some already tracing nodes, and such are supposed to have -%% the correct patterns and flags set. -do_initial_tcs([{TC,Vars}|Rest],Nodes,LD) -> - Id=make_ref(), % Trace case ID. - case h_atc(TC,Id,Vars,LD,Nodes) of % Start using regular start methods. - {ok,NewLD} -> % Trace case was successfully started. - NewInitialTcs=add_initial_tcs(TC,Id,NewLD#ld.started_initial_tcs), - do_initial_tcs(Rest,Nodes,NewLD#ld{started_initial_tcs=NewInitialTcs}); - {error,_Reason} -> - do_initial_tcs(Rest,Nodes,LD) - end; -do_initial_tcs([_|Rest],Nodes,LD) -> - do_initial_tcs(Rest,Nodes,LD); -do_initial_tcs([],_Nodes,LD) -> - LD. -%% ----------------------------------------------------------------------------- - -%% This help functio is used instead of do_initial_tcs/3 if there actually are no -%% nodes to do the trace cases on. The reason we must have this function is that -%% the tracecases must still be entered into the history with bindings and all. -%% But we let them be marked as 'running' immediately (no need for the activator -%% process). -add_initial_tcs_to_history([{TC,Vars}|Rest],LD=#ld{tc_dict=TCdict,chl=CHL}) -> - case get_tracecase_tc_dict(TC,TCdict) of - {ok,TraceCase} -> - case check_bindings(Vars,TraceCase) of - {ok,Bindings} -> - Id=make_ref(), % Trace case ID. - FakeProcH=make_ref(), % Need something to enter as activator. - NewCHL=set_activating_chl(TC,Id,CHL,Bindings,FakeProcH), - NewCHL2=set_running_chl(FakeProcH,TC,Id,void,NewCHL), % Result=void. - NewInitialTcs=add_initial_tcs(TC,Id,LD#ld.started_initial_tcs), - add_initial_tcs_to_history(Rest,LD#ld{chl=NewCHL2, - started_initial_tcs=NewInitialTcs}); - {error,_Reason} -> % Not much we can do about that. - add_initial_tcs_to_history(Rest,LD) - end; - false -> - add_initial_tcs_to_history(Rest,LD) - end; -add_initial_tcs_to_history([],LD) -> - LD. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% reinitiate_session -%% ----------------------------------------------------------------------------- - -%% Function doing the reinitiation. That means first do init_tracing at the nodes -%% in question. Then redo the command history to bring them up to speed. -%% But first the runtime component is cleared of all trace patterns. -h_reinitiate_session(Nodes,M,F,TDGargs,LD=#ld{c_node=CNode,nodes=NodesD}) -> - case h_reinitiate_session_2(Nodes,NodesD,CNode) of - {ok,{[],NodesErr}} -> % No nodes to reinitiate. - {ok,{NodesErr,{ok,[]},LD}}; - {ok,{Nodes2,NodesErr}} -> % List of nodes or local_runtime. - case call_tracer_data_generator(CNode,M,F,TDGargs,Nodes2) of - {ok,TracerList} -> - case h_start_session_2(CNode,TracerList,[]) of % Borrow from start_session. - {ok,ReturnValue} -> % Ok, now we must redo cmd history. - {NewNodesD,_Nodes}= - set_tracing_running_nodes(CNode,ReturnValue,NodesD), - NewLD=h_reinitiate_session_chl(Nodes2,LD#ld{nodes=NewNodesD}), - {ok,{NodesErr,ReturnValue,NewLD}}; - {error,Reason} -> - {error,Reason} - end; - {error,Reason} -> - {error,{bad_tdg,Reason}} - end; - {error,Reason} -> - {error,Reason} - end. - -%% Help function finding out which nodes in Nodes actually can be reinitiated. -%% A node must be up, inactive and not suspended in order for this to work. All the -%% rest is just a matter of how detailed error return values we want to generate. -h_reinitiate_session_2(local_runtime,NodesD,undefined) -> % Non distributed case. - case get_state_nodes(local_runtime,NodesD) of - {inactive,running} -> % Only ok case. - case inviso:ctp_all() of - ok -> - {ok,{local_runtime,[]}}; - {error,Reason} -> % This is strange. - {error,Reason} - end; - {_,suspended} -> - {ok,{[],{error,suspended}}}; - down -> - {ok,{[],{error,down}}}; - _ -> - {ok,{[],{error,already_in_session}}} - end; -h_reinitiate_session_2(Nodes,NodesD,CNode) when is_list(Nodes) -> - {ok,lists:foldl(fun(N,{Nodes2,NodesErr})-> - case get_state_nodes(N,NodesD) of - {inactive,running} -> % Only ok case. - case rpc:call(CNode,inviso,ctp_all,[[N]]) of - {ok,[{N,ok}]} -> - {[N|Nodes2],NodesErr}; - {ok,[{N,{error,Reason}}]} -> - {Nodes2,[{N,{error,Reason}}|NodesErr]}; - {error,Reason} -> - {Nodes2,[{N,{error,Reason}}|NodesErr]}; - {badrpc,Reason} -> - {Nodes2,[{N,{error,{badrpc,Reason}}}|NodesErr]} - end; - {_,suspended} -> - {Nodes2,[{N,{error,suspended}}|NodesErr]}; - down -> - {Nodes2,[{N,{error,down}}|NodesErr]}; - false -> - {Nodes2,[{N,{error,unknown_node}}|NodesErr]}; - _ -> - {Nodes2,[{N,{error,already_in_session}}|NodesErr]} - end - end, - {[],[]}, - Nodes)}; -h_reinitiate_session_2(Nodes,_NodesD,_CNode) -> - {error,{badarg7,Nodes}}. - -%% Help function redoing the command history log at all nodes that actually -%% started to trace. Note that we do not modify the return value which will be -%% given to the caller just because we decide not to redo commands. The user -%% must conclude him self from the inviso return value that commands were not -%% redone at a particular node. -h_reinitiate_session_chl(local_runtime,LD) -> - h_reinitiate_session_chl([local_runtime],LD); -h_reinitiate_session_chl([Node|Rest],LD=#ld{nodes=NodesD}) -> - case get_state_nodes(Node,NodesD) of - {tracing,running} -> % Only case when we shall redo! - h_reinitiate_session_chl(Rest,redo_cmd_history(Node,LD)); - _ -> % No redo of chl in other cases. - h_reinitiate_session_chl(Rest,LD) - end; -h_reinitiate_session_chl([],LD) -> - LD. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% restore_session -%% ----------------------------------------------------------------------------- - -%% Help function starting a session (init tracing) and redoes the history -%% found in CHL. -h_restore_session(MoreTDGargs,LD) -> - DateTime=calendar:universal_time(), - {M,F,Args}=LD#ld.tdg, - TDGargs=inviso_tool_lib:mk_tdg_args(DateTime,MoreTDGargs++Args), - case h_start_session(M,F,TDGargs,LD) of - {ok,{SessionNr,ReturnVal,NewLD}} -> % There were no available nodes. - {ok,{SessionNr,ReturnVal,NewLD}}; - {ok,{SessionNr,ReturnVal,Nodes2,NewLD}} -> - NewLD2=h_reinitiate_session_chl(Nodes2,NewLD), - {ok,{SessionNr,ReturnVal,NewLD2}}; - {error,Reason} -> % Risk of out of control. - {error,Reason} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% stop_session -%% ----------------------------------------------------------------------------- - -%% Help function stopping tracing at tracing nodes. -h_stop_session(#ld{c_node=CNode,nodes=NodesD,tracer_data=TDs}) -> - case h_stop_session_2(CNode,NodesD) of - {ok,Result} -> - {ok,{get_latest_session_nr_tracer_data(TDs),Result}}; - {error,Reason} -> - {error,Reason} - end. - -h_stop_session_2(undefined,NodesD) -> % The non distributed case. - case get_tracing_nodes(NodesD) of - {up,{inactive,_}} -> % Already not tracing! - {ok,[]}; - {up,_} -> - case inviso:stop_tracing() of - {ok,_State} -> - {ok,[ok]}; - {error,no_response} -> - {ok,[]}; - {error,Reason} -> - {error,Reason} - end; - down -> - {ok,[]} - end; -h_stop_session_2(CNode,NodesD) -> - Nodes=get_tracing_nodes(NodesD), - case rpc:call(CNode,inviso,stop_tracing,[Nodes]) of - {ok,NodeResults} -> - {ok,lists:map(fun({N,{ok,_}})->{N,ok}; - (NodeError)->NodeError - end, - NodeResults)}; - {error,Reason} -> - {error,Reason}; - {badrpc,Reason} -> - {error,{inviso_control_node_error,Reason}} - end. -%% ----------------------------------------------------------------------------- - -%% Help function removing any trace flags, trace patterns and meta trace patterns -%% at Nodes. This will cause the nodes to become "fresh". -h_reset_nodes(local_runtime,_CNode) -> - inviso:clear([keep_log_files]); -h_reset_nodes(Nodes,CNode) -> - case inviso_tool_lib:inviso_cmd(CNode,clear,[Nodes,[keep_log_files]]) of - {ok,NodeResults} -> - {ok,NodeResults}; - {error,Reason} -> - {error,Reason} - end. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% atc -%% ----------------------------------------------------------------------------- - -%% Function handling ativating a trace case. Trace cases that do not have a -%% particular on/off handling (but just on in some scense) are handled here too. -%% The trace case is entered into the Command History Log. -%% Note that the trace case can not be executed at this node but must be -%% executed where the inviso control component is. -%% Further it is possible to either activated the tracecase for all running and -%% tracing nodes, or just for a specified list of nodes. -%% TC=tracecase_name(), -%% Id=term(), identifiying this usage so we can turn it off later. -%% Vars=list(), list of variable-value bindnings. -h_atc(TC,Id,Vars,LD) -> - h_atc(TC,Id,Vars,LD,void). % For all running-tracing nodes. - -h_atc(TC,Id,Vars,LD=#ld{c_node=CNode,tc_dict=TCdict,chl=CHL},Nodes) -> - case find_id_chl(TC,Id,CHL) of - activating -> % Already started. - {error,activating}; - stopping -> % Not yet stopped. - {error,deactivating}; - false -> - case get_tracecase_tc_dict(TC,TCdict) of - {ok,TraceCase} -> % Such a trace case exists. - case check_bindings(Vars,TraceCase) of - {ok,Bindings} -> % Necessary vars exists in Vars. - if - is_list(Nodes) -> % Nodes predefined. - h_atc_2(TC,Id,CNode,CHL,LD,TraceCase,Bindings,Nodes); - true -> % Use all tracing and running nodes. - Nodes1=get_nodenames_running_nodes(LD#ld.nodes), - h_atc_2(TC,Id,CNode,CHL,LD,TraceCase,Bindings,Nodes1) - end; - {error,Reason} -> % Variable def missing. - {error,Reason} - end; - false -> - {error,unknown_tracecase} - end; - {ok,_Bindings} -> % Already activated and running. - {error,already_started} - end. - -h_atc_2(TC,Id,CNode,CHL,LD,TraceCase,Bindings,Nodes) -> - {ok,ProcH} = exec_trace_case_on(CNode,TraceCase,Bindings,Nodes), - %% Trace cases have no return values. - NewCHL=set_activating_chl(TC,Id,CHL,Bindings,ProcH), - {ok,LD#ld{chl=NewCHL}}. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% sync_atc -%% ----------------------------------------------------------------------------- - -h_sync_atc(TC,Id,Vars,TimeOut,LD=#ld{c_node=CNode,tc_dict=TCdict,chl=CHL}) -> - case find_id_chl(TC,Id,CHL) of - activating -> % Already started. - {error,activating}; - stopping -> % Not yet stopped. - {error,deactivating}; - false -> - case get_tracecase_tc_dict(TC,TCdict) of - {ok,TraceCase} -> % Such a trace case exists. - case check_bindings(Vars,TraceCase) of - {ok,Bindings} -> % Necessary vars exists in Vars. - {ok,TcFName}=get_tc_activate_fname(TraceCase), - Nodes=get_nodenames_running_nodes(LD#ld.nodes), - Bindings2=erl_eval:add_binding('Nodes',Nodes,Bindings), - RpcNode=get_rpc_nodename(CNode), - case rpc:call(RpcNode,file,script,[TcFName,Bindings2],TimeOut) of - {ok,Value} -> - FakeProcH=make_ref(), - NewCHL1=set_activating_chl(TC,Id,CHL,Bindings,FakeProcH), - NewCHL2=set_running_chl(FakeProcH,TC,Id,Value,NewCHL1), - {ok,LD#ld{chl=NewCHL2},Value}; - {error,Reason} -> - {error,{faulty_tracecase,{TcFName,Reason}}}; - {badrpc,Reason} -> - {error,{badrpc,Reason}} - end; - {error,Reason} -> % Variable def missing. - {error,Reason} - end; - false -> - {error,unknown_tracecase} - end; - {ok,_Bindings} -> % Already activated and running. - {error,already_started} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% rtc -%% ----------------------------------------------------------------------------- - -%% Function handling running a trace case without marking it as activated. It -%% is in the history mearly indicated as activated -h_sync_rtc(TC,Vars,TimeOut,LD=#ld{c_node=CNode,tc_dict=TCdict,chl=CHL}) -> - case get_tracecase_tc_dict(TC,TCdict) of - {ok,TraceCase} -> % Such a trace case exists. - case check_bindings(Vars,TraceCase) of - {ok,Bindings} -> % Necessary vars exists in Vars. - {ok,TcFName}=get_tc_activate_fname(TraceCase), - Nodes=get_nodenames_running_nodes(LD#ld.nodes), - Bindings2=erl_eval:add_binding('Nodes',Nodes,Bindings), - RpcNode=get_rpc_nodename(CNode), - case rpc:call(RpcNode,file,script,[TcFName,Bindings2],TimeOut) of - {ok,Value} -> - {ok,LD#ld{chl=add_rtc_chl(TC,Bindings2,CHL)},Value}; - {error,Reason} -> - {error,{faulty_tracecase,{TcFName,Reason}}}; - {badrpc,Reason} -> - {error,{badrpc,Reason}} - end; - {error,Reason} -> % Variable def missing. - {error,Reason} - end; - false -> - {error,unknown_tracecase} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% dtc -%% ----------------------------------------------------------------------------- - -%% Function handling turning a trace case off. The trace case must be registered -%% as having an off mechanism. If it has an off mechanism and was previously entered -%% into the Command History Log and is done with its activation phase, it will be -%% executed and removed from the CHL. -h_dtc(TC,Id,LD=#ld{c_node=CNode,tc_dict=TCdict,chl=CHL}) -> - case find_id_chl(TC,Id,CHL) of - {ok,Bindings} -> % Yes, we have turned it on before. - case get_tracecase_tc_dict(TC,TCdict) of - {ok,TraceCase} -> - Nodes=get_nodenames_running_nodes(LD#ld.nodes), - case exec_trace_case_off(CNode,TraceCase,Bindings,Nodes) of - {ok,ProcH} -> - NewCHL=set_stopping_chl(TC,Id,CHL,ProcH), - {ok,LD#ld{chl=NewCHL}}; - {error,Reason} -> - {error,Reason} - end; - false -> % Strange, Id ok but no such trace case. - {error,unknown_tracecase} - end; - false -> % Not previously turned on. - {error,unknown_id}; - activating -> - {error,activating}; - stopping -> - {error,already_deactivating} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% sync_dtc -%% ----------------------------------------------------------------------------- - -h_sync_dtc(TC,Id,TimeOut,LD=#ld{c_node=CNode,tc_dict=TCdict,chl=CHL}) -> - case find_id_chl(TC,Id,CHL) of - {ok,Bindings} -> % Yes, we have turned it on before. - case get_tracecase_tc_dict(TC,TCdict) of - {ok,TraceCase} -> - case get_tc_deactivate_fname(TraceCase) of - {ok,TcFName} -> - Nodes=get_nodenames_running_nodes(LD#ld.nodes), - Bindings2=erl_eval:add_binding('Nodes',Nodes,Bindings), - RpcNode=get_rpc_nodename(CNode), - case rpc:call(RpcNode,file,script,[TcFName,Bindings2],TimeOut) of - {ok,Value} -> - FakeProcH=make_ref(), - NewCHL1=set_stopping_chl(TC,Id,CHL,FakeProcH), - NewCHL2=nullify_chl(FakeProcH,TC,Id,NewCHL1), - {ok,LD#ld{chl=NewCHL2},Value}; - {error,Reason} -> % Script fault. - {error,{faulty_tracecase,{TcFName,Reason}}}; - {badrpc,Reason} -> - {error,{badrpc,Reason}} - end; - false -> - {error,no_deactivation} - end; - false -> % Strange, Id ok but no such trace case. - {error,unknown_tracecase} - end; - false -> % Not previously turned on. - {error,unknown_id}; - activating -> - {error,activating}; - stopping -> - {error,already_deactivating} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% inviso -%% ----------------------------------------------------------------------------- - -%% Function executing one inviso command. The returnvalue from the inviso -%% function call will be the return value to the client. The command is -%% entered into the history command log. -%% Note that the inviso call may have to be done at another node, dictated -%% by the c_node field. Further, if the module name is not an atom it is -%% most likely a regexp, which must be expanded at the regexp_node. Note -%% this is only relevant for tp and tpl. -h_inviso(Cmd,Args,LD=#ld{c_node=CNode,regexp_node=RegExpNode,chl=CHL}) -> - Arity=length(Args), - case check_proper_inviso_call(Cmd,Arity) of - {true,RegExpFlag} -> % Yes it is an inviso call. - Nodes=get_nodenames_running_nodes(LD#ld.nodes), - case h_inviso_2(Cmd,Args,CNode,RegExpNode,RegExpFlag,Nodes) of - {ok,Result} -> - case check_inviso_call_to_history(Cmd,Arity) of - true -> % This function shall be added to chl. - {ok,{Result,LD#ld{chl=add_inviso_call_chl(Cmd,Args,CHL)}}}; - false -> % Do not add it. - {ok,{Result,LD}} - end; - {error,Reason} -> - {error,Reason} - end; - false -> % Not an inviso function. - {error,invalid_function_name} - end. - -h_inviso_2(Cmd,Args,undefined,_,_,_) -> % A non distributed system. - case catch apply(inviso,Cmd,Args) of % Regexp expansion only relevant when - {'EXIT',Reason} -> % distributed, here let inviso_rt expand. - {error,{'EXIT',Reason}}; - Result -> - {ok,Result} - end; -h_inviso_2(Cmd,Args,CNode,RegExpNode,RegExpFlag,Nodes) -> - case expand_module_regexps(Args,RegExpNode,Nodes,RegExpFlag) of - {ok,NewArgs} -> - case catch inviso_tool_lib:inviso_cmd(CNode,Cmd,[Nodes|NewArgs]) of - {'EXIT',Reason} -> - {error,{'EXIT',Reason}}; - {error,{badrpc,Reason}} -> % Includes runtime failure. - {error,{badrpc,Reason}}; - Result -> - {ok,Result} - end; - {error,Reason} -> - {error,Reason} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% reactivate -%% ----------------------------------------------------------------------------- - -h_reactivate(_Node,undefined) -> % The non-distributed case. - case inviso:cancel_suspension() of - ok -> - ok; - {error,Reason} -> - {error,Reason} - end; -h_reactivate(Node,CNode) -> - case inviso_tool_lib:inviso_cmd(CNode,cancel_suspension,[[Node]]) of - {ok,[{Node,ok}]} -> - ok; - {ok,[{Node,{error,Reason}}]} -> - {error,Reason}; - {error,Reason} -> - {error,Reason} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% save_history -%% ----------------------------------------------------------------------------- - -h_save_history(HDir,Dir,FileName,SortedLog) -> - Dir0= - if - is_list(HDir) -> % There is a history dir specified. - HDir; % Use it then. - true -> - Dir % Else use the tool dir. - end, - case catch make_absolute_path(FileName,Dir0) of - AbsFileName when is_list(AbsFileName) -> - Log2=build_saved_history_data(SortedLog), % Remove stopped tracecases. - case file:write_file(AbsFileName,term_to_binary(Log2)) of - ok -> - {ok,AbsFileName}; - {error,Reason} -> - {error,{write_file,Reason}} - end; - {'EXIT',_Reason} -> - {error,{bad_filename,FileName}} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% get_autostart_data -%% ----------------------------------------------------------------------------- - -%% Help function building the structures used when exporting autostart information -%% from the tool. Note that we remove the tool-dependency and insert the one -%% specify in the get_autostart_data call. -h_get_autostart_data(local_runtime,_,Dependency,ASD,M,F,TDGargs,OptsG) -> - CompleteTDGargs=call_tracer_data_generator_mkargs(local_runtime,TDGargs), - Opts0=start_runtime_components_mk_opts(local_runtime,OptsG), - Opts=[Dependency|lists:keydelete(dependency,1,Opts0)], - {ok,{ASD,{ok,{Opts,{tdg,{M,F,CompleteTDGargs}}}}}}; - -h_get_autostart_data(Nodes,CNode,Dependency,ASD,M,F,TDGargs,OptsG) when is_list(Nodes) -> - {ok,{ASD,h_get_autostart_data_2(Nodes,CNode,Dependency,M,F,TDGargs,OptsG)}}; -h_get_autostart_data(Nodes,_CNode,_Dependency,_ASD,_M,_F,_TDGargs,_OptsG) -> - {error,{badarg,Nodes}}. - -h_get_autostart_data_2([Node|Rest],CNode,Dependency,M,F,TDGargs,OptsG) -> - CompleteTDGargs=call_tracer_data_generator_mkargs(Node,TDGargs), - Opts0=start_runtime_components_mk_opts(Node,OptsG), - Opts=[Dependency|lists:keydelete(dependency,1,Opts0)], - [{Node,{ok,{Opts,{tdg,{M,F,CompleteTDGargs}}}}}| - h_get_autostart_data_2(Rest,CNode,Dependency,M,F,TDGargs,OptsG)]; -h_get_autostart_data_2([],_CNode,_Dependency,_M,_F,_TDGargs,_OptsG) -> - []. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% flush -%% ----------------------------------------------------------------------------- - -h_flush(undefined,_Nodes) -> - inviso:flush(); -h_flush(CNode,Nodes) -> - inviso_tool_lib:inviso_cmd(CNode,flush,[Nodes]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% tc_executer_reply -%% ----------------------------------------------------------------------------- - -%% Function handling that a trace case has completed its activation phase and -%% shall now be marked in the Command History Log as running. -h_tc_activation_done(ProcH,Result,LD=#ld{chl=CHL}) -> - case find_tc_executer_chl(ProcH,CHL) of - {activating,{TC,Id}} -> - case Result of - {ok,Value} -> % The trace case is successful activated. - {ok,LD#ld{chl=set_running_chl(ProcH,TC,Id,Value,CHL)}}; - {error,_} -> % Then pretend it never happend :-) - {ok,LD#ld{chl=del_tc_chl(ProcH,TC,Id,CHL)}} % Remove it. - end; - _ -> % Where did this come from? - {ok,LD} % Well just ignore it then. - end. -%% ----------------------------------------------------------------------------- - -%% Function handling that a trace case has completed its stopping phase and -%% shall now be nulled in the Command History Log (meaning that it will not -%% be repeated in the event of a reactivation). -h_tc_stopping_done(ProcH,Result,LD=#ld{chl=CHL}) -> - case find_tc_executer_chl(ProcH,CHL) of - {stopping,{TC,Id}} -> - case Result of - {ok,_Result} -> % _Result is returned from the tracecase. - {ok,LD#ld{chl=nullify_chl(ProcH,TC,Id,CHL)}}; - {error,_} -> % This is difficult, is it still active? - {ok,LD#ld{chl=nullify_chl(ProcH,TC,Id,CHL)}} - end; - _ -> % Strange. - {ok,LD} - end. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Terminate. -%% ----------------------------------------------------------------------------- - -%% Help function stopping the inviso control component. Does not return -%% anything significant. -stop_inviso_at_c_node(undefined) -> % Non distributed case. - inviso:stop(); -stop_inviso_at_c_node(CNode) -> - rpc:call(CNode,inviso,stop,[]). -%% ----------------------------------------------------------------------------- - -%% Help function that removes all trace patterns from the nodes that are not -%% marked as such were patterns shall be left after stopping of inviso. -%% Returns {ok,NodeResult} or {error,Reason}. In the non-distributed case -%% 'ok' is returned incase of success, ot 'patterns_untouched'. -remove_all_trace_patterns(undefined,KeepNodes,_Nodes) -> - case KeepNodes of - undefined -> % No, remove patterns from localruntime. - inviso:ctp_all(); - _ -> - patterns_untouched - end; -remove_all_trace_patterns(CNode,KeepNodes,Nodes) -> - Nodes2=lists:filter(fun(N)->not(lists:member(N,KeepNodes)) end,Nodes), - case inviso_tool_lib:inviso_cmd(CNode,ctp_all,[Nodes2]) of - {ok,NodeResults} -> - F=fun(N) -> - case lists:member(N,KeepNodes) of - true -> - {N,patterns_untouched}; - false -> - case lists:keysearch(N,1,NodeResults) of - {value,Result} -> - Result; % {Node,ok} - false -> % Extremely strange. - {N,{error,general_error}} - end - end - end, - {ok,lists:map(F,Nodes)}; - {error,{badrpc,Reason}} -> - {error,{inviso_control_node_error,Reason}}; - {error,Reason} -> - {error,Reason} - end. -%% ----------------------------------------------------------------------------- - -%% ============================================================================= -%% Second level help functions. -%% ============================================================================= - -%% Help function building a reply to a reconnection call based on which nodes -%% where asked to be reconnected and which of those are actually now working. -%% We actually make an effort to serve the return value in the same order as the -%% nodes were mentioned in the original call (Nodes). -build_reconnect_nodes_reply(local_runtime,local_runtime,_NodesErr,NodesD) -> - case get_state_nodes(local_runtime,NodesD) of - down -> - {error,down}; - {State,Status} -> - {ok,{State,Status}} - end; -build_reconnect_nodes_reply(local_runtime,_,NodesErr,_NodesD) -> - NodesErr; -build_reconnect_nodes_reply([Node|Rest],Nodes2,NodesErr,NodesD) -> - case lists:member(Node,Nodes2) of - true -> % Ok, look in the #ld.nodes. - case get_state_nodes(Node,NodesD) of - down -> % Somekind of failure, still down. - [{Node,{error,down}}| - build_reconnect_nodes_reply(Rest,Nodes2,NodesErr,NodesD)]; - {State,Status} -> % {State,Status} - [{Node,{ok,{State,Status}}}| - build_reconnect_nodes_reply(Rest,Nodes2,NodesErr,NodesD)] - end; - false -> % Error already from the beginning. - {value,{_,Error}}=lists:keysearch(Node,1,NodesErr), - [{Node,Error}|build_reconnect_nodes_reply(Rest,Nodes2,NodesErr,NodesD)] - end; -build_reconnect_nodes_reply([],_,_,_) -> - []. -%% ----------------------------------------------------------------------------- - -%% Help function building a return value to reinitiate_session. Nodes contains -%% all involved nodes. If the node occurrs in NodesErr, we choose the error in -%% NodesErr. Otherwise the returnvalue in ReturnVal is used. -build_reinitiate_session_reply(Nodes,NodesErr,{ok,NodesResults}) -> - {ok,build_reinitiate_session_reply_2(Nodes,NodesErr,NodesResults)}; -build_reinitiate_session_reply(local_runtime,[],NodeResult) -> - NodeResult; -build_reinitiate_session_reply(local_runtime,NodesErr,_NodeResult) -> - NodesErr. -build_reinitiate_session_reply_2([Node|Rest],NodesErr,NodeResults) -> - case lists:keysearch(Node,1,NodesErr) of - {value,{_,Error}} -> - [{Node,Error}|build_reinitiate_session_reply_2(Rest,NodesErr,NodeResults)]; - false -> - case lists:keysearch(Node,1,NodeResults) of - {value,Value} -> - [Value|build_reinitiate_session_reply_2(Rest,NodesErr,NodeResults)] - end - end; -build_reinitiate_session_reply_2([],_NodesErr,_NodeResults) -> - []. -%% ----------------------------------------------------------------------------- - -%% Help function returning a history log where stop and stopping entries have -%% been removed. Further all tracecase log entries must be set to running since -%% there can not be such a thing as an activating tracecase stored away in a -%% saved historyfile! -%% We must also take away any #Ref. -build_saved_history_data(SortedLog) -> - CleanedLog= - lists:filter(fun({_,_,Stop,_}) when Stop==stop;Stop==stopping -> false; - (_) -> true - end, - SortedLog), - lists:map(fun({{TC,Id},C,activating,B}) -> {{TC,Id},C,running,B}; - ({{TC,Id},C,S,B}) -> {{TC,Id},C,S,B}; - ({{M,F,Args,_Ref},C}) -> {{M,F,Args},C}; - ({{TC,_Ref},C,B}) -> {TC,C,B} % An rtc. - end, - CleanedLog). -%% ----------------------------------------------------------------------------- - -%% This help function builds the AutoStartData structure which is returned from -%% get_austostart_data. An AutoStartData structure is a list of trace-files and -%% inviso commands. The order is significant since it is the idea that doing -%% the trace case files and inviso commands in that order will bring a node to -%% a certain state in a trace perspective. -%% Returns {ok,AutoStartData} or {error,Reason} -build_autostart_data(SortedLog,TCdict) -> - build_autostart_data_2(SortedLog,TCdict,[]). - -build_autostart_data_2([{_,_C,Stop,_B}|Rest],TCdict,Accum) when Stop==stop;Stop==stopping-> - build_autostart_data_2(Rest,TCdict,Accum); % Simply skip deactivated/deativating. -build_autostart_data_2([{{TCname,_},_C,activating,Bindings}|Rest],TCdict,Accum) -> - build_autostart_data_tc(TCname,Bindings,TCdict,Rest,Accum); -build_autostart_data_2([{{TCname,_},_C,running,Bindings}|Rest],TCdict,Accum) -> - build_autostart_data_tc(TCname,Bindings,TCdict,Rest,Accum); -build_autostart_data_2([{{TCname,_Ref},_C,Bindings}|Rest],TCdict,Accum) -> - build_autostart_data_tc(TCname,Bindings,TCdict,Rest,Accum); -build_autostart_data_2([{{M,F,Args,_Ref},_C}|Rest],TCdict,Accum) -> - build_autostart_data_2(Rest,TCdict,[{mfa,{M,F,Args}}|Accum]); -build_autostart_data_2([],_TCdict,Accum) -> - {ok,lists:reverse(Accum)}. - -%% Help function placing the filename in the AutoStartData structure. -build_autostart_data_tc(TCname,Bindings,TCdict,Rest,Accum) -> - {ok,TC}=get_tracecase_tc_dict(TCname,TCdict), - {ok,FName}=get_tc_activate_fname(TC), - build_autostart_data_2(Rest,TCdict,[{file,{FName,Bindings}}|Accum]). -%% ----------------------------------------------------------------------------- - -%% Help function generating tracerdata to init inviso tracing. The generation -%% is done by the TracerDataGenerator, TDG, function. -%% Individual tracerdata is generated for each node in Nodes. -%% Returns {ok,TracerData} or {error,Reason}. -call_tracer_data_generator(undefined,M,F,TDGargs,_Nodes) -> % Non distributed. - case catch call_tracer_data_generator_3(M,F,TDGargs,local_runtime) of - {'EXIT',Reason} -> - {error,{'EXIT',Reason}}; - TracerData -> - {ok,TracerData} - end; -call_tracer_data_generator(_CNode,M,F,TDGargs,Nodes) -> - case catch call_tracer_data_generator_2(M,F,TDGargs,Nodes) of - {'EXIT',Reason} -> - {error,{'EXIT',Reason}}; - TracerList -> - {ok,TracerList} - end. - -call_tracer_data_generator_2(M,F,TDGargs,[Node|Rest]) -> - [{Node,call_tracer_data_generator_3(M,F,TDGargs,Node)}| - call_tracer_data_generator_2(M,F,TDGargs,Rest)]; -call_tracer_data_generator_2(_,_,_,[]) -> - []. - -call_tracer_data_generator_3(M,F,TDGargs,Node) -> - apply(M,F,call_tracer_data_generator_mkargs(Node,TDGargs)). - -%% This function creates the arguments that the tracer data generator function -%% accepts (in an apply call). The reason for making it a sepparate function is -%% that the arguments are constructed in more situations than just when actually -%% doing the apply. By having a function it will become obvious where to change -%% should the arguments change. -call_tracer_data_generator_mkargs(Node,TDGargs) -> - inviso_tool_lib:mk_complete_tdg_args(Node,TDGargs). -%% ----------------------------------------------------------------------------- - -%% This function acts as standard options generator function. That is returning -%% the options argument to inviso:add_node/3. Note that this function must not -%% return the dependency part of that option. -std_options_generator(_Node) -> - []. % No particular options(!) -%% ----------------------------------------------------------------------------- - - -%% Help function checking that Vars contains a binding for every variable -%% listed in the VarNames field in TraceCase. Note that the special variable 'Nodes' -%% is disregarded, since it is always added by the inviso_tool. -%% Returns {ok,Bindings} or {error,Reason}. Where Bindings is a bindngs structure -%% according to file:eval functionality. -check_bindings(Vars,TraceCase) -> - case catch check_bindings_2(Vars, - get_tc_varnames(TraceCase), - erl_eval:new_bindings()) of - {'EXIT',_Reason} -> - {error,variable_error}; - {error,Reason} -> % Missing a bindning. - {error,Reason}; - {ok,Bindings} -> - {ok,Bindings} - end. - -check_bindings_2(Vars,['Nodes'|Rest],Bindings) -> - check_bindings_2(Vars,Rest,Bindings); % Disregard Nodes since it is automatic. -check_bindings_2(Vars,[VarName|Rest],Bindings) -> - case lists:keysearch(VarName,1,Vars) of - {value,{_,Val}} -> - check_bindings_2(Vars,Rest,erl_eval:add_binding(VarName,Val,Bindings)); - false -> % Mandatory variable missing. - {error,{missing_variable,VarName}} % Quite here then. - end; -check_bindings_2(_,[],Bindings) -> - {ok,Bindings}. -%% ----------------------------------------------------------------------------- - -%% This help function checks that the command the user tries to do is amongst -%% the inviso API. It at the same time returns what kind of command it is. -%% {true,RegExpFlag} or 'false' where RegExpFlag indicates if this command -%% needs to have its argument modified by module regexp expansion or not. -check_proper_inviso_call(Cmd,Arity) -> - case lists:member({Cmd,Arity},?INVISO_CMDS) of - true -> % It is part of inviso API. - {true,check_proper_inviso_call_regexp(Cmd,Arity)}; - false -> - false - end. - -%% Returns {Type,Arity,PlaceOfModuleSpec} or 'false'. -check_proper_inviso_call_regexp(tp,5) -> {tp,5,1}; -check_proper_inviso_call_regexp(tp,4) -> {tp,4,1}; -check_proper_inviso_call_regexp(tp,1) -> {tp,1,1}; -check_proper_inviso_call_regexp(tpl,5) -> {tp,5,1}; -check_proper_inviso_call_regexp(tpl,4) -> {tp,4,1}; -check_proper_inviso_call_regexp(tpl,1) -> {tp,1,1}; -check_proper_inviso_call_regexp(ctp,3) -> {ctp,3,1}; -check_proper_inviso_call_regexp(ctp,1) -> {ctp,1,1}; -check_proper_inviso_call_regexp(ctpl,3) -> {ctp,3,1}; -check_proper_inviso_call_regexp(ctpl,1) -> {ctp,1,1}; -check_proper_inviso_call_regexp(_,_) -> % No regexp expansion. - false. -%% ----------------------------------------------------------------------------- - -%% Help function checking if this inviso command shall be added to the command -%% history log. Returns true or false. -check_inviso_call_to_history(Cmd,Arity) -> - case lists:member({Cmd,Arity},?INVISO_CMD_HISTORY) of - true -> - true; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -%% Help function traversing the arguments and expanding module names stated -%% as regular expressions. This means that the resulting arguments may be longer -%% than the orginal ones. -%% When we run this function it has been determined that we are a distributed -%% system. -%% Also note that if there are no regexps in Args, no regexpansion will be -%% made and RegExpNode may be 'undefined' (as it is if not set at start-up). -%% If RegExpNode is unavailable the nodes found in Nodes will be used until -%% one that works is found. -expand_module_regexps(Args,_RegExpNode,_Nodes,false) -> - {ok,Args}; -expand_module_regexps([PatternList],RegExpNode,Nodes,{tp,1,1}) -> - case catch expand_module_regexps_tp(PatternList,RegExpNode,Nodes) of - NewPatternList when is_list(NewPatternList) -> - {ok,[NewPatternList]}; - {error,Reason} -> - {error,Reason} - end; -expand_module_regexps([PatternList],RegExpNode,Nodes,{ctp,1,1}) -> - case catch expand_module_regexps_ctp(PatternList,RegExpNode,Nodes) of - NewPatternList when is_list(NewPatternList) -> - {ok,[NewPatternList]}; - {error,Reason} -> - {error,Reason} - end; -expand_module_regexps([M,F,Arity,MS,Opts],RegExpNode,Nodes,{tp,5,1}) -> - expand_module_regexps([[{M,F,Arity,MS,Opts}]],RegExpNode,Nodes,{tp,1,1}); -expand_module_regexps([M,F,Arity,MS],RegExpNode,Nodes,{tp,4,1}) -> - expand_module_regexps([[{M,F,Arity,MS,[]}]],RegExpNode,Nodes,{tp,1,1}); -expand_module_regexps([M,F,Arity],RegExpNode,Nodes,{ctp,3,1}) -> - expand_module_regexps([[{M,F,Arity}]],RegExpNode,Nodes,{ctp,1,1}). - - -expand_module_regexps_tp([E={M,_,_,_,_}|Rest],RegExpNode,Nodes) when is_atom(M) -> - [E|expand_module_regexps_tp(Rest,RegExpNode,Nodes)]; -expand_module_regexps_tp([{M,F,Arity,MS,Opts}|Rest],RegExpNode,Nodes) when is_list(M);is_tuple(M) -> - case inviso_tool_lib:expand_module_names([RegExpNode], - M, - [{expand_only_at,RegExpNode}]) of - {singlenode_expansion,Modules} -> - expand_module_regexps_tp_2(Modules,F,Arity,MS,Opts,Rest,RegExpNode,Nodes); - {error,{faulty_node,RegExpNode}} -> % RegExpNode probably down. - case Nodes of - [NewRegExpNode|RestNodes] -> % Ok, just choose a node. - expand_module_regexps_tp([{M,F,Arity,MS,Opts}|Rest],NewRegExpNode,RestNodes); - [] -> % No more nodes to choose from. - throw({error,no_available_regexpnode}) - end; - {error,_Reason} -> - expand_module_regexps_tp(Rest,RegExpNode,Nodes) - end; -expand_module_regexps_tp([_|Rest],RegExpNode,Nodes) -> - expand_module_regexps_tp(Rest,RegExpNode,Nodes); % Skip faulty module specification. -expand_module_regexps_tp([],_RegExpNodes,_Nodes) -> - []. - -expand_module_regexps_tp_2([M|MRest],F,Arity,MS,Opts,Rest,RegExpNode,Nodes) -> - [{M,F,Arity,MS,Opts}| - expand_module_regexps_tp_2(MRest,F,Arity,MS,Opts,Rest,RegExpNode,Nodes)]; -expand_module_regexps_tp_2([],_,_,_,_,Rest,RegExpNode,Nodes) -> - expand_module_regexps_tp(Rest,RegExpNode,Nodes). - -expand_module_regexps_ctp([E={M,_,_}|Rest],RegExpNode,Nodes) when is_atom(M) -> - [E|expand_module_regexps_ctp(Rest,RegExpNode,Nodes)]; -expand_module_regexps_ctp([{M,F,Arity}|Rest],RegExpNode,Nodes) when is_list(M);is_tuple(M) -> - case inviso_tool_lib:expand_module_names([RegExpNode], - M, - [{expand_only_at,RegExpNode}]) of - {singlenode_expansion,Modules} -> - expand_module_regexps_ctp_2(Modules,F,Arity,Rest,RegExpNode,Nodes); - {error,_Reason} -> - expand_module_regexps_ctp(Rest,RegExpNode,Nodes) - end; -expand_module_regexps_ctp([_|Rest],RegExpNode,Nodes) -> - expand_module_regexps_tp(Rest,RegExpNode,Nodes); % Skip faulty module specification. -expand_module_regexps_ctp([],_RegExpNodes,_Nodes) -> - []. - -expand_module_regexps_ctp_2([M|MRest],F,Arity,Rest,RegExpNode,Nodes) -> - [{M,F,Arity}|expand_module_regexps_ctp_2(MRest,F,Arity,Rest,RegExpNode,Nodes)]; -expand_module_regexps_ctp_2([],_,_,Rest,RegExpNode,Nodes) -> - expand_module_regexps_ctp(Rest,RegExpNode,Nodes). -%% ----------------------------------------------------------------------------- - - - -%% Help function running the activation of a trace case. Note that this must -%% be done at the inviso control component's Erlang node *and* that it must be -%% done in its own process since there is no telling for how long a trace case -%% may run. -%% Returns {ok,ActivationHandler}. -exec_trace_case_on(CNode,TraceCase,Bindings,Nodes) -> - {ok,TcFName}=get_tc_activate_fname(TraceCase), - {ok,exec_trace_case_2(CNode, - TcFName, - erl_eval:add_binding('Nodes',Nodes,Bindings), - activating)}. - -%% Help function running the deactivation of a trace case. -exec_trace_case_off(CNode,TraceCase,Bindings,Nodes) -> - case get_tc_deactivate_fname(TraceCase) of - {ok,TcFName} -> % There is a deactivation. - {ok,exec_trace_case_2(CNode, - TcFName, - erl_eval:add_binding('Nodes',Nodes,Bindings), - stopping)}; - false -> - {error,no_deactivation} - end. - -exec_trace_case_2(CNode,TcFName,Bindings,Phase) -> - if - CNode==undefined -> % The non distributed case. - spawn_link(?MODULE,tc_executer,[TcFName,Bindings,Phase,self()]); - true -> - spawn_link(CNode,?MODULE,tc_executer,[TcFName,Bindings,Phase,self()]) - end. - -%% This function is run in its own process and is responsible for executing -%% the trace case. -tc_executer(TcFName,Bindings,Phase,Parent) -> - case catch file:script(TcFName,Bindings) of - {ok,Value} -> - tc_executer_reply(Parent,{Phase,self(),{ok,Value}}); - {'EXIT',Reason} -> - tc_executer_reply(Parent,{Phase,self(),{error,{'EXIT',Reason}}}); - Error -> - tc_executer_reply(Parent,{Phase,self(),Error}) - end. -%% ----------------------------------------------------------------------------- - -%% Help function which starts a reactivator process redoing command history at -%% Node. It also updates the loopdata to indicate that Node is now in state -%% reactivating. It is a good idea to only handle one node per reactivator process. -%% This because if the node terminates and comes back up, the reactivator must be -%% stopped. -redo_cmd_history(Node,LD=#ld{c_node=CNode,tc_dict=TCdict,chl=CHL,nodes=NodesD}) -> - P=start_reactivator(Node,CNode,TCdict,CHL), - LD#ld{nodes=set_reactivating_nodes(Node,NodesD), - reactivators=add_reactivators(Node,P,LD#ld.reactivators)}. - -%% Help function starting a reactivator process replaying the command history log. -%% Returns a pid of the reactivator process. -start_reactivator(Node,CNode,TCdict,CHL) -> - UnsortedLog=get_loglist_chl(CHL), % Must fetch here, later on wrong node. - if - CNode==undefined -> % The non-distributed case. - spawn_link(?MODULE, - reactivator_executer, - [Node,TCdict,UnsortedLog,self(),0,[]]); - true -> - spawn_link(CNode, - ?MODULE, - reactivator_executer, - [Node,TCdict,UnsortedLog,self(),0,[]]) - end. - -%% The strategy is to traverse the CHL ETS table in Counter order, redoing the -%% commands one by one. We wait until one command is finished until we do the -%% next. Commands marked as nullified are not performed. In fact when a command -%% is nullified only the stop will be found in the CHL. Its activation will be -%% removed. -reactivator_executer(Node,TCdict,UnsortedLog,TPid,StartCounter,DoneCases) -> - SortedLog=lists:keysort(2,UnsortedLog), % Sort on Counter, oldest first. - Log=reactivator_skip_log_entries(SortedLog,StartCounter), - case reactivator_executer_2(Node,TCdict,TPid,StartCounter,DoneCases,Log) of - done -> - true; % Simply terminate the reactivator then. - {more,{NewStartCounter,NewDoneCases,NewUnsortedLog}} -> - reactivator_executer(Node,TCdict,NewUnsortedLog,TPid,NewStartCounter,NewDoneCases) - end. - -reactivator_executer_2(Node,TCdict,TPid,_Counter,DoneCases, - [{{TCname,Id},NextC,running,Bindings}|Rest]) -> - reactivator_executer_3(Node,TCdict,TPid,DoneCases,Rest,TCname,Id,NextC,Bindings,Rest); -reactivator_executer_2(Node,TCdict,TPid,_Counter,DoneCases, - [{{TCname,_Ref},NextC,Bindings}|Rest]) -> - reactivator_executer_rtc(Node,TCdict,TPid,DoneCases,Rest,TCname,NextC,Bindings,Rest); -reactivator_executer_2(Node,TCdict,TPid,_Counter,DoneCases, - [{{TCname,Id},NextC,activating,Bindings}|Rest]) -> - reactivator_executer_3(Node,TCdict,TPid,DoneCases,Rest,TCname,Id,NextC,Bindings,Rest); -reactivator_executer_2(Node,TCdict,TPid,_Counter,DoneCases, - [{{M,F,Args,_Ref},NextC}|Rest]) -> - reactivator_executer_cmd(Node,M,F,Args), - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest); -reactivator_executer_2(Node,TCdict,TPid,_Counter,DoneCases, - [{{_TCname,_Id},NextC,stopping,_Bindings}|Rest]) -> - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest); -reactivator_executer_2(Node,TCdict,TPid,_Counter,DoneCases, - [{{TCname,Id,_Ref},NextC,stop,Bindings}|Rest]) -> - case lists:member({TCname,Id},DoneCases) of - true -> % We have activated it, must stop then. - case get_tracecase_tc_dict(TCname,TCdict) of - {ok,{_,_,_,_,FNameOff}} -> - reactivator_executer_tc(Node,Bindings,FNameOff), - NewDoneCases=lists:delete({TCname,Id},DoneCases), - reactivator_executer_2(Node,TCdict,TPid,NextC,NewDoneCases,Rest); - {ok,_} -> % No stop-filename, strange! - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest); - false -> % Even stranger, does not exist!? - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest) - end; - false -> % Never activated in the first place. - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest) - end; -%% Done all log entries found this lap. See if there are more entries by now. -reactivator_executer_2(_Node,_TCdict,TPid,Counter,DoneCases,[]) -> - case reactivator_reply(TPid,Counter) of % Ask the tool process for more entries. - done -> % No more entries in the CHL. - done; - {more,NewUnsortedLog} -> % Repeat the procedure - {more,{Counter+1,DoneCases,NewUnsortedLog}} % with log entries from Counter+1. - end. - -%% This help function activates a tracecase. -reactivator_executer_3(Node,TCdict,TPid,DoneCases,Rest,TCname,Id,NextC,Bindings,Rest) -> - case get_tracecase_tc_dict(TCname,TCdict) of - {ok,{_,_,_,FNameOn}} -> % A case with just on functionality. - reactivator_executer_tc(Node,Bindings,FNameOn), - reactivator_executer_2(Node,TCdict,TPid,NextC,[{TCname,Id}|DoneCases],Rest); - {ok,{_,_,_,FNameOn,_}} -> - reactivator_executer_tc(Node,Bindings,FNameOn), - reactivator_executer_2(Node,TCdict,TPid,NextC,[{TCname,Id}|DoneCases],Rest); - false -> % Strange, does not exist anylonger!? - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest) - end. - -%% Help function executing a trace case in the reactivators context. Does not -%% return anything significant. -reactivator_executer_tc(Node,Bindings,FileName) -> - catch file:eval(FileName,erl_eval:add_binding('Nodes',[Node],Bindings)). - -%% Help function handling trace case that are simply executed - rtc. -reactivator_executer_rtc(Node,TCdict,TPid,DoneCases,Rest,TCname,NextC,Bindings,Rest) -> - case get_tracecase_tc_dict(TCname,TCdict) of - {ok,{_,_,_,FNameOn}} -> % A case with just on functionality. - reactivator_executer_tc(Node,Bindings,FNameOn), - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest); - {ok,{_,_,_,FNameOn,_}} -> - reactivator_executer_tc(Node,Bindings,FNameOn), - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest); - false -> % Strange, does not exist anylonger!? - reactivator_executer_2(Node,TCdict,TPid,NextC,DoneCases,Rest) - end. - -reactivator_executer_cmd(nonode@nohost,M,F,Args) -> - catch apply(M,F,Args); % Non-distributed. -reactivator_executer_cmd(Node,M,F,Args) -> - catch apply(M,F,[[Node]|Args]). - -%% Help function returning a list of log entries missing the first entries -%% having a counter less or equal to C1. -reactivator_skip_log_entries([{_,C,_,_}|Rest],C1) when C<C1 -> - reactivator_skip_log_entries(Rest,C1); -reactivator_skip_log_entries([{_,C}|Rest],C1) when C<C1 -> - reactivator_skip_log_entries(Rest,C1); -reactivator_skip_log_entries(Log,_) -> - Log. -%% ----------------------------------------------------------------------------- - -%% Help function returning the node name to use in an rpc call. -get_rpc_nodename(undefined) -> - node(); -get_rpc_nodename(CNode) -> - CNode. -%% ----------------------------------------------------------------------------- - -mk_rt_tag() -> - inviso_tool. -%% ----------------------------------------------------------------------------- - -is_string([C|Rest]) when C>=32, C=<255 -> - is_string(Rest); -is_string([]) -> - true; -is_string(_) -> - false. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% Functions for handling the configuration file. -%% ----------------------------------------------------------------------------- - -%% The inviso tool is configured via start arguments and/or a configuration file. -%% Start arguments will override any definitions in a configuration file. -%% The configuration file is pointed out by either a start argument or the -%% inviso application parameter 'inviso_tool_config_file'. - -%% Help function building the internal configuration structure. Configurations -%% in the start argument will override parameters found in a configuration file. -fetch_configuration(Config) -> - case fetch_config_filename(Config) of - {ok,FName} -> % We are supposed to use a conf-file. - case read_config_file(FName) of - {ok,LD} -> % Managed to open a file. - NewLD=read_config_list(LD,Config), - {ok,NewLD}; - Error = {error,_Reason} -> % Problem finding/opening file. - Error - end; - false -> % No filename specified. - LD=read_config_list(#ld{},Config), - {ok,LD} - end. - -%% Help function determining the name of the file which shall be consulted as -%% the main configuration file. -%% Returns {ok,FileName} or 'false'. The latter if no name could be determined. -fetch_config_filename(Config) -> - case catch lists:keysearch(config_file,1,Config) of - {value,{_,FName}} when is_list(FName) -> - {ok,FName}; - _ -> % No filename in the start argument. - fetch_config_filename_2() - end. - -fetch_config_filename_2() -> - case application:get_env(inviso_tool_config_file) of - {ok,FName} when is_list(FName) -> - {ok,FName}; - _ -> % Application parameter not specified. - false % Means no config file will be used. - end. - -%% Help function reading the configuration file. Returns a #conf or {error,Reason}. -read_config_file(FName) -> - case catch file:consult(FName) of - {ok,Terms} -> - {ok,read_config_list(#ld{},Terms)}; - {error,Reason} -> - {error,{file_consult,Reason}}; - {'EXIT',Reason} -> - {error,{failure,Reason}} - end. - -%% Help function traversing the Terms list entering known tag-values into #ld. -read_config_list(LD,Terms) -> - LD#ld{ - nodes = case mk_nodes(proplists:get_value(nodes,Terms,LD#ld.nodes)) of - {ok,Nodes} -> Nodes; - _ -> LD#ld.nodes - end, - c_node = proplists:get_value(c_node,Terms,LD#ld.c_node), % atom8) - regexp_node = proplists:get_value(regexp_node,Terms,LD#ld.regexp_node), % atom() - tc_def_file = proplists:get_value(tc_def_file,Terms,LD#ld.tc_def_file), - tdg = proplists:get_value(tdg,Terms,LD#ld.tdg), - debug = proplists:get_value(debug,Terms,LD#ld.debug), - initial_tcs = proplists:get_value(initial_tcs,Terms,LD#ld.initial_tcs), - dir = proplists:get_value(dir,Terms,LD#ld.dir), - optg = proplists:get_value(optg,Terms,LD#ld.optg) - }. - -%% ----------------------------------------------------------------------------- - - -%% Help function which, if it exists, consults the trace definition file. The -%% idea behind the trace definition file is to point out which trace cases there -%% are, where to find them and how to turn them on and off. -%% Trace case definitions are: -%% {TCname,Type,VariableNameList,ActivatioFileName} | -%% {TCname,Type,VariableNameList,ActivationFileName,DeactivationFileName} -%% TCname=atom() -%% Type=on | on_off -%% VariableNameList=[atom(),...] -%% ActivationFileName=DeactivationFileName=string() -read_trace_case_definitions(LD) -> - case LD#ld.tc_def_file of - TCfileName when is_list(TCfileName) -> - case catch file:consult(TCfileName) of - {ok,Terms} -> - Dir=LD#ld.dir, % The working directory of the tool. - TCdict=read_trace_case_definitions_2(Terms,Dir,mk_tc_dict()), - LD#ld{tc_dict=TCdict}; - _ -> - LD - end; - _ -> - LD - end. - -read_trace_case_definitions_2([{TCname,on,VarNames,FName}|Rest],Dir,TCdict) -> - FileName=make_absolute_path(FName,Dir), - read_trace_case_definitions_2(Rest, - Dir, - insert_tracecase_tc_dict(TCname, - on, - VarNames, - FileName, - TCdict)); -read_trace_case_definitions_2([{TCname,on_off,VarNames,FNameOn,FNameOff}|Rest],Dir,TCdict) -> - FileNameOn=make_absolute_path(FNameOn,Dir), - FileNameOff=make_absolute_path(FNameOff,Dir), - read_trace_case_definitions_2(Rest, - Dir, - insert_tracecase_tc_dict(TCname, - on_off, - VarNames, - FileNameOn, - FileNameOff, - TCdict)); -read_trace_case_definitions_2([_|Rest],Dir,TCdict) -> - read_trace_case_definitions_2(Rest,Dir,TCdict); -read_trace_case_definitions_2([],_Dir,TCdict) -> - TCdict. - -%% Help function returning an absolute path to FName if FName is not already -%% absolute. Dir is the working dir of the tool and supposed to be absolute. -make_absolute_path(FName,Dir) -> - case filename:pathtype(FName) of - absolute -> % Then do nothing, allready absolute. - FName; - _ -> - filename:join(Dir,FName) - end. -%% ----------------------------------------------------------------------------- - -get_status(undefined,_Node) -> - inviso:get_status(); -get_status(CNode,Nodes) -> - inviso_tool_lib:inviso_cmd(CNode,get_status,[Nodes]). -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% Internal data structure functions. -%% ============================================================================= - -%% ----------------------------------------------------------------------------- -%% The nodes database structure. -%% ----------------------------------------------------------------------------- - -%% The purpose of the nodes database structure is to keep track of what runtime -%% nodes we have, and their current status. -%% Implementation: -%% [{NodeName,AvailableStatus},...] or AvailableStatus in the -%% non-distributed case. -%% AvailableStatus={up,Status1} | down -%% Status1={State,Status} | reactivating -%% State=tracing | inactive | trace_failure -%% Status=running | suspended -%% reactivating=the node is now being brought up to date. -%% inactive=not tracing, can be initiated and then reactivated. -%% The following states can occure. -%% {inactive,running} -%% Mainly when we start the tool, before a session has been started. -%% {tracing,running} -%% When a trace session is on-going. -%% {trace_failure,running} -%% If init_tracing failed for some reason. -%% {tracing,suspended} -%% reactivating -%% The node is tracing (has always been) but was suspended. It is now -%% no longer suspended and the tool is redong commands. -%% {inactive,suspended} -%% We can end up here if a session is stopped with this node suspended. - -%% Returns a nodes database structure filled with the nodes Nodes. -mk_nodes(Nodes) when is_list(Nodes) -> - {ok,lists:map(fun(N) when is_atom(N)->{N,down} end,Nodes)}; -mk_nodes(local_runtime) -> % The non-distributed case. - down; -mk_nodes(_Nodes) -> - error. -%% ----------------------------------------------------------------------------- - -%% Updates the nodes database structure for each node that has been added. -%% This is the case when we start the tool or reactivate a node. Note that a node -%% may have become adopted instead of started. -%% Returns a new nodes database structure. -update_added_nodes(CNode,[{Node,NodeResult}|Rest],NodesD) -> - case update_added_nodes_3(NodeResult) of - already_added -> % Already added to the control component. - case get_status(CNode,[Node]) of % Examine if it is tracing or not. - {ok,[{Node,NodeResult2}]} -> - Result=mk_nodes_state_from_status(NodeResult2), - update_added_nodes_2(CNode,Node,Result,NodesD,Rest); - {error,_Reason} -> % Strange, mark it as down now. - update_added_nodes_2(CNode,Node,down,NodesD,Rest) - end; - Result -> - update_added_nodes_2(CNode,Node,Result,NodesD,Rest) - end; -update_added_nodes(_CNode,[],NodesD) -> - NodesD; -update_added_nodes(_CNode,NodeResult,_NodesD) -> % Non distributed case. - case update_added_nodes_3(NodeResult) of - already_added -> % Already added, most likely autostart. - mk_nodes_state_from_status(inviso:get_status()); - Result -> - Result % Simply replace NodesD. - end. - -update_added_nodes_2(CNode,Node,Result,NodesD,Rest) -> - case lists:keysearch(Node,1,NodesD) of - {value,_} -> % Node already exists, replace! - update_added_nodes(CNode,Rest,lists:keyreplace(Node,1,NodesD,{Node,Result})); - false -> % Strange, unknown node! - update_added_nodes(CNode,Rest,NodesD) - end. - -update_added_nodes_3({ok,{adopted,tracing,running,_Tag}}) -> - {up,{tracing,running}}; -update_added_nodes_3({ok,{adopted,tracing,{suspended,_SReason},_Tag}}) -> - {up,{tracing,suspended}}; -update_added_nodes_3({ok,{adopted,_,running,_Tag}}) -> - {up,{inactive,running}}; -update_added_nodes_3({ok,{adopted,_,{suspended,_SReason},_Tag}}) -> - {up,{inactive,suspended}}; -update_added_nodes_3({ok,new}) -> - {up,{inactive,running}}; -update_added_nodes_3({ok,already_added}) -> - already_added; % This is an error value! -update_added_nodes_3({error,_Reason}) -> - down. -%% ----------------------------------------------------------------------------- - -%% Function marking all nodes that, according to the returnvalue from init_tracing, -%% now are successfully initiated as tracing and running. Note that nodes that -%% does not fully respond 'ok' when init_tracing are marked as 'trace_failure'. -%% Also note that we assume that the nodes must be running to have made it this far. -%% A node can of course have become suspended in the process, but that node will -%% be marked as suspended later when that inviso event message arrives to the tool. -%% Returns {NewNodesD,Nodes} where Nodes are the nodes that actually got initiated -%% as a result of the init_tracing call (judged from the LogResults). -set_tracing_running_nodes(undefined,{ok,_LogResults},_AvailableStatus) -> % Non-distr. case. - {{up,{tracing,running}},local_runtime}; -set_tracing_running_nodes(undefined,{error,already_initiated},_) -> % Non-distributed case. - {mk_nodes_state_from_status(inviso:get_status()),[]}; % Ask it for its status. -set_tracing_running_nodes(undefined,{error,_Reason},_) -> % Non-distributed case. - {down,[]}; % This is questionable! -set_tracing_running_nodes(CNode,{ok,NodeResults},NodesD) -> - set_tracing_running_nodes_2(CNode,NodeResults,NodesD,[]). - -set_tracing_running_nodes_2(CNode,[{Node,{ok,_LogResults}}|Rest],NodesD,Nodes) -> - case lists:keysearch(Node,1,NodesD) of - {value,_} -> - NewNodesD=lists:keyreplace(Node,1,NodesD,{Node,{up,{tracing,running}}}), - set_tracing_running_nodes_2(CNode,Rest,NewNodesD,[Node|Nodes]); - false -> % Strange. - set_tracing_running_nodes_2(CNode,Rest,NodesD,Nodes) - end; -set_tracing_running_nodes_2(CNode,[{Node,{error,already_initiated}}|Rest],NodesD,Nodes) -> - case get_status(CNode,[Node]) of % Then we must ask what it is doing now. - {ok,[{Node,NodeResult}]} -> - Result=mk_nodes_state_from_status(NodeResult), - NewNodesD=lists:keyreplace(Node,1,NodesD,{Node,Result}), - set_tracing_running_nodes_2(CNode,Rest,NewNodesD,Nodes); - {error,_Reason} -> % Strange, mark it as down. - NewNodesD=lists:keyreplace(Node,1,NodesD,{Node,down}), - set_tracing_running_nodes_2(CNode,Rest,NewNodesD,Nodes) - end; -set_tracing_running_nodes_2(CNode,[{Node,{error,_Reason}}|Rest],NodesD,Nodes) -> - NewNodesD=lists:keyreplace(Node,1,NodesD,{Node,{up,{trace_failure,running}}}), - set_tracing_running_nodes_2(CNode,Rest,NewNodesD,Nodes); -set_tracing_running_nodes_2(_CNode,[],NodesD,Nodes) -> - {NodesD,Nodes}. % New NodesD and nodes successfully initiated. - -%% ----------------------------------------------------------------------------- - -%% Function updating Node in the NodesD structure and sets it to 'down'. -%% Returns a new nodes structure. -set_down_nodes(Node,[{Node,_}|Rest]) -> - [{Node,down}|Rest]; -set_down_nodes(Node,[NodeStruct|Rest]) -> - [NodeStruct|set_down_nodes(Node,Rest)]; -set_down_nodes(_,[]) -> - []; -set_down_nodes(_,_) -> % Non-distributed case. - down. % One can argue if this can happend. -%% ----------------------------------------------------------------------------- - -%% Function updating Node in NodesD to now be suspended. Note that if the node is -%% reactivating it must be moved to state tracing because that is what is doing. -set_suspended_nodes(Node,[{Node,{up,reactivating}}|Rest]) -> - [{Node,{up,{tracing,suspended}}}|Rest]; -set_suspended_nodes(Node,[{Node,{up,{State,_}}}|Rest]) -> - [{Node,{up,{State,suspended}}}|Rest]; -set_suspended_nodes(Node,[NodesData|Rest]) -> - [NodesData|set_suspended_nodes(Node,Rest)]; -set_suspended_nodes(_Node,[]) -> % Hmm, strange why did we end up here? - []; -set_suspended_nodes(_,{up,reactivating}) -> % Non-distributed case. - {up,{tracing,suspended}}; -set_suspended_nodes(_,{up,{State,_}}) -> - {up,{State,suspended}}. -%% ----------------------------------------------------------------------------- - -%% This function is called when reactivation is completed. Hence it moves the -%% node to no longer suspended. Note this can mean that the node is either -%% tracing or inactive. Reactivation is not allowed for a node have trace_failure. -set_running_nodes(Node,NodesD) when is_list(NodesD) -> - case lists:keysearch(Node,1,NodesD) of - {value,{_,AvailableStatus}} -> - lists:keyreplace(Node,1,NodesD,{Node,set_running_nodes_2(AvailableStatus)}); - false -> % Very strange! - NodesD - end; -set_running_nodes(_,NodesD) -> % The non-distributed case. - set_running_nodes_2(NodesD). - -set_running_nodes_2({up,reactivating}) -> - {up,{tracing,running}}; -set_running_nodes_2({up,{State,suspended}}) -> - {up,{State,running}}. -%% ----------------------------------------------------------------------------- - -%% Function marking node as now reactivating. That means it is not suspended -%% any longer (and tracing), but still not part of the set of nodes which shall -%% get all commands. Returns a new NodesD. -set_reactivating_nodes(Node,[{Node,_}|Rest]) -> - [{Node,{up,reactivating}}|Rest]; -set_reactivating_nodes(Node,[NodesData|Rest]) -> - [NodesData|set_reactivating_nodes(Node,Rest)]; -set_reactivating_nodes(_,[]) -> - []; -set_reactivating_nodes(_,{up,_}) -> % The non-distributed case. - {up,reactivating}. -%% ----------------------------------------------------------------------------- - -%% Function called when stop-tracing is done. That is all nodes in Nodes shall -%% be inactive now. Note that an inactive node can still be suspended. -%% Returns a new NodesD. -set_inactive_nodes(_,{up,reactivating}) -> % Non-distributed case. - {up,{inactive,running}}; -set_inactive_nodes(_,{up,{_,Status}}) -> % Tracing or trace_failure. - {up,{inactive,Status}}; -set_inactive_nodes(_,down) -> - down; -set_inactive_nodes([{Node,ok}|Rest],NodesD) -> - case lists:keysearch(Node,1,NodesD) of - {value,{_,{up,reactivating}}} -> - set_inactive_nodes(Rest,lists:keyreplace(Node,1,NodesD,{Node,{up,{inactive,running}}})); - {value,{_,{up,{_,Status}}}} -> % Tracing or trace_failure. - set_inactive_nodes(Rest,lists:keyreplace(Node,1,NodesD,{Node,{up,{inactive,Status}}})); - _ -> % This should not happend. - set_inactive_nodes(Rest,NodesD) - end; -set_inactive_nodes([{_Node,_Error}|Rest],NodesD) -> - set_inactive_nodes(Rest,NodesD); -set_inactive_nodes([],NodesD) -> - NodesD. -%% ----------------------------------------------------------------------------- - -%% Returns a list of all node names. Note that it can only be used in the -%% distributed case. -get_all_nodenames_nodes(NodesD) -> - lists:map(fun({Node,_})->Node end,NodesD). -%% ----------------------------------------------------------------------------- - -%% Returns a list of all nodes that are up, tracing and running (not suspended), -%% or 'void' in the non-distributed case. This is the list of nodes that shall get -%% inviso commands. -get_nodenames_running_nodes([{Node,{up,{tracing,running}}}|Rest]) -> - [Node|get_nodenames_running_nodes(Rest)]; -get_nodenames_running_nodes([{_Node,_}|Rest]) -> - get_nodenames_running_nodes(Rest); -get_nodenames_running_nodes([]) -> - []; -get_nodenames_running_nodes(_) -> - void. % When non distributed, N/A. -%% ----------------------------------------------------------------------------- - -%% Returns a list of nodes that can be made to initiate tracing. -get_inactive_running_nodes({up,{inactive,running}}) -> - local_runtime; -get_inactive_running_nodes(NonDistributed) when not(is_list(NonDistributed)) -> - []; -get_inactive_running_nodes([{Node,{up,{inactive,running}}}|Rest]) -> - [Node|get_inactive_running_nodes(Rest)]; -get_inactive_running_nodes([{_Node,_}|Rest]) -> - get_inactive_running_nodes(Rest); -get_inactive_running_nodes([]) -> - []. -%% ----------------------------------------------------------------------------- - -%% Returns a list of nodes that are currently tracing (not necessarily running). -%% In the non-distributed case the status of the runtime component will be -%% returned. -%% Note that nodes showing trace_failure will be included since we like to stop -%% tracing at those nodes too. -get_tracing_nodes([{Node,{up,{tracing,_}}}|Rest]) -> - [Node|get_tracing_nodes(Rest)]; -get_tracing_nodes([{Node,{up,{trace_failure,_}}}|Rest]) -> - [Node|get_tracing_nodes(Rest)]; -get_tracing_nodes([{Node,{up,reactivating}}|Rest]) -> - [Node|get_tracing_nodes(Rest)]; -get_tracing_nodes([_|Rest]) -> - get_tracing_nodes(Rest); -get_tracing_nodes([]) -> - []; -get_tracing_nodes(AvailableStatus) -> - AvailableStatus. -%% ----------------------------------------------------------------------------- - -%% Returns a list of all nodes that are currently up. -get_available_nodes(down) -> - undefined; -get_available_nodes([{_Node,down}|Rest]) -> - get_available_nodes(Rest); -get_available_nodes([{Node,_}|Rest]) -> - [Node|get_available_nodes(Rest)]; -get_available_nodes([]) -> - []. -%% ----------------------------------------------------------------------------- - -%% Function returning the "state" of Node. Mainly used to check if the node is -%% suspended or not. -%% Returns {State,Status} | reactivating | down -%% where -get_state_nodes(Node,NodesD) when is_list(NodesD) -> - case lists:keysearch(Node,1,NodesD) of - {value,{_,AvailableStatus}} -> - get_state_nodes_2(AvailableStatus); - false -> - false - end; -get_state_nodes(_,NodesD) -> % Non distributed case. - get_state_nodes_2(NodesD). - -get_state_nodes_2({up,{trace_failure,Status}}) -> - {trace_failure,Status}; -get_state_nodes_2({up,{State,suspended}}) -> % {tracing|inactive,suspended} - {State,suspended}; -get_state_nodes_2({up,reactivating}) -> - reactivating; -get_state_nodes_2({up,{State,running}}) -> - {State,running}; -get_state_nodes_2(down) -> - down. -%% ----------------------------------------------------------------------------- - -%% Help function in the case we need to consult the state/status of a runtime -%% component. Returns a nodesD value that can be added to the nodes database. -mk_nodes_state_from_status({ok,{tracing,running}}) -> - {up,{tracing,running}}; -mk_nodes_state_from_status({ok,{tracing,{suspended,_SReason}}}) -> - {up,{tracing,suspended}}; -mk_nodes_state_from_status({ok,{_,running}}) -> - {up,{inactive,running}}; -mk_nodes_state_from_status({ok,{_,{suspended,_SReason}}}) -> - {up,{inactive,suspended}}; -mk_nodes_state_from_status({error,_Reason}) -> - down. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% The session_state. -%% ----------------------------------------------------------------------------- - -%% The session state reflects if the inviso_tool is tracing or not. -%% This means that if the tool is tracing a reconnected node can be made to -%% restart_session. - -%% Returns the correct value indicating that we are tracing now. -tracing_sessionstate() -> - tracing. -%% ----------------------------------------------------------------------------- - -%% Returns true or false depending on if we are tracing now or not. -is_tracing(tracing) -> - true; -is_tracing(_) -> - false. -%% ----------------------------------------------------------------------------- - -%% Returns the correct value indicating that the tool is not tracing. -passive_sessionstate() -> - idle. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% The tracer_data datastructure. -%% ----------------------------------------------------------------------------- - -%% The tracer_data structure collects the tracer data arguments used to init tracing -%% by this inviso tool. The args are saved per session. Each session has -%% a number. -%% Implementation: -%% Sessions=[{SessionNr,TDGargs},...] -%% SessionNr=integer() -%% TDGargs=list(), args given to the tracer data generator -%% minus the first argument which is the Node name. - -%% Function taking tracerdata args structure inserting yet another session. -%% Returns {SessionNr,NewTDs}. -insert_td_tracer_data(TDGargs,TDs=[{SNr,_}|_]) -> - {SNr+1,[{SNr+1,TDGargs}|TDs]}; -insert_td_tracer_data(TDGargs,undefined) -> - {1,[{1,TDGargs}]}. -%% ----------------------------------------------------------------------------- - -%% Returns the latest session nr. -get_latest_session_nr_tracer_data(undefined) -> - undefined; -get_latest_session_nr_tracer_data([{SessionNr,_}|_]) -> - SessionNr. -%% ----------------------------------------------------------------------------- - -%% Returns the tracer data arguments used when creating the trace data for the -%% latest session. -get_latest_tdgargs_tracer_data(undefined) -> - undefined; -get_latest_tdgargs_tracer_data([{_,TDGargs}|_]) -> - TDGargs. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% The tc_dict or trace case dictionary datastructure. -%% ----------------------------------------------------------------------------- - -%% The tc_dict stores information about all available trace cases. -%% Implementation: -%% [{TCname,Type,VarNames,FNameOn [,FNameOff]},...] -%% TCname=atom() -%% Type=on | on_off -%% VarNames=[atom(),...] -%% FNameOn=FNameOff=string() - -%% Returns the empty trace case dictionary. -mk_tc_dict() -> - []. -%% ----------------------------------------------------------------------------- - -%% Function inserting a new trace case into the trace case dictionary. -insert_tracecase_tc_dict(TCname,on,VarNames,FNameOn,TCdict) -> - [{TCname,on,VarNames,FNameOn}|TCdict]. -insert_tracecase_tc_dict(TCname,on_off,VarNames,FNameOn,FNameOff,TCdict) -> - [{TCname,on_off,VarNames,FNameOn,FNameOff}|TCdict]. -%% ----------------------------------------------------------------------------- - -%% Function finding a trace case definition in the tc_dict structure. -%% Returns {ok,{TCname,Type,VarNAmes,FNameOn [,FNameOff]}} or 'false'. -get_tracecase_tc_dict(TCname,[Tuple|_]) when element(1,Tuple)==TCname -> - {ok,Tuple}; -get_tracecase_tc_dict(TCname,[_|Rest]) -> - get_tracecase_tc_dict(TCname,Rest); -get_tracecase_tc_dict(_,[]) -> - false; -get_tracecase_tc_dict(_,_) -> % There are no trace cases! - false. -%% ----------------------------------------------------------------------------- - -%% Function working on the trace case definition returned by get_tracecase_tc_dict/2 -%% function. -%% Returning {ok,ActivationFileName}. -get_tc_activate_fname({_TCname,_Type,_VarNames,FNameOn}) -> - {ok,FNameOn}; -get_tc_activate_fname({_TCname,_Type,_VarNames,FNameOn,_FNameOff}) -> - {ok,FNameOn}. - -get_tc_deactivate_fname({_TCname,_Type,_VarNames,_FNameOn,FNameOff}) -> - {ok,FNameOff}; -get_tc_deactivate_fname(_) -> % Not a case with off function. - false. - -get_tc_varnames({_TCname,_Type,VarNames,_FNameOn}) -> - VarNames; -get_tc_varnames({_TCname,_Type,VarNames,_FNameOn,_FNameOff}) -> - VarNames. - -%% ----------------------------------------------------------------------------- - - -%% The Command History Log (CHL) stores commands to make it possible to -%% reactivate suspended nodes, reconnect restarted nodes, and to make -%% autostart files. -%% Each time tracing is initiated (that is started) the CHL is cleared since -%% it would not make scense to repeat commands from an earlier tracing at -%% reactivation for instance. - -%% Implementation: {NextCounter,OnGoingList,ETStable} -%% NextCounter=integer(), next command number - to be able to sort them in order. -%% OnGoingList=[{ProcH,{TCname,ID}},...] -%% ID=term(), instance id for this execution of this trace case. -%% ETStable=tid() -> {{TCname,Id},Counter,State1,Bindings} -%% ETStable=tid() -> {{TCname,Id},Counter,running,Bindings,Result} | -%% {{TCname,Id,#Ref},Counter,stop,Bindings} | -%% {{TCname,#Ref},Counter,Bindings} % An rtc -%% {{M,F,Args,#Ref},Counter} -%% Counter=integer(), the order-counter for this logged entry. -%% State1=activating | stopping -%% Where: -%% activating: the activation file for the tracecase is running. -%% running : activation is completed. -%% stopping : set on the previously running ETS entry when deactivation -%% file is currently executing. -%% stop : entered with own Counter into the ETS table when -%% deactivation file is executing. Remains after too. -%% Result=term(), the result returned from the tr-case or inviso call. - - -%% Returning an initial empty CHL. -mk_chl(undefined) -> - {1,[],ets:new(inviso_tool_chl,[set,protected])}; -mk_chl({_,_,TId}) -> - ets:delete(TId), - mk_chl(undefined). - -%% Help function returning 'true' if there is a current history. -history_exists_chl(undefined) -> - false; -history_exists_chl({_,_,_}) -> - true. - -%% Function looking up the state of this trace case. -find_id_chl(TCname,Id,{_NextCounter,_OnGoingList,TId}) -> - case ets:lookup(TId,{TCname,Id}) of - [{_,_,running,Bindings,_Result}] -> % The trace case is tracing. - {ok,Bindings}; - [{_,_,State,_}] -> % activating or stopping. - State; - [] -> - false - end. - -%% Function finding the Trace case associated with a process handle -%% doing this trace case's activation or stopping. -find_tc_executer_chl(ProcH,{_,OnGoingList,TId}) -> - case lists:keysearch(ProcH,1,OnGoingList) of - {value,{_,{TCname,Id}}} -> - [{_,_,State,_}]=ets:lookup(TId,{TCname,Id}), - {State,{TCname,Id}}; % Should be activating or stopping. - false -> - false - end. - -%% Adds a Trace case to the CHL. This is done when it is turned on. Or when it -%% is called for trace cases that do not have on/off functionality. -set_activating_chl(TCname,Id,{Counter,OnGoingList,TId},Bindings,ProcH) -> - ets:insert(TId,{{TCname,Id},Counter,activating,Bindings}), - {Counter+1,[{ProcH,{TCname,Id}}|OnGoingList],TId}. - -%% Function marking a trace case as now running. That is the activation -%% phase is completed. It is normaly completed when the process executing -%% the trace case signals that it is done. -set_running_chl(ProcH,TCname,Id,Result,{NextCounter,OnGoingList,TId}) -> - [{_,Counter,_,Bindings}]=ets:lookup(TId,{TCname,Id}), - ets:insert(TId,{{TCname,Id},Counter,running,Bindings,Result}), - NewOnGoingList=lists:keydelete(ProcH,1,OnGoingList), - {NextCounter,NewOnGoingList,TId}. - -%% Function marking trace case TCname with identifier Id as now in its stopping -%% state. Where ProcH is the handler to the process running the stopping -%% trace case. -set_stopping_chl(TCname,Id,{NextCounter,OnGoingList,TId},ProcH)-> - [{_,Counter,_,Bindings,_}]=ets:lookup(TId,{TCname,Id}), - ets:insert(TId,{{TCname,Id},Counter,stopping,Bindings}), - ets:insert(TId,{{TCname,Id,make_ref()},NextCounter,stop,Bindings}), - {NextCounter+1,[{ProcH,{TCname,Id}}|OnGoingList],TId}. - -%% Function removing a TCname-Id from the CHL. This is mostly used -%% if activating the trace case failed for some reason. We do not then -%% expect the user to stop the trace case. Hence it must be removed now. -%% A reactivation process may have noticed the activating-entry and started -%% to activate it. But since the general state reached after an unsuccessful -%% activation can not easily be determined, we don't try to do much about it. -del_tc_chl(ProcH,TCname,Id,{NextCounter,OnGoingList,TId}) -> - ets:delete(TId,{TCname,Id}), - NewOnGoingList=lists:keydelete(ProcH,1,OnGoingList), - {NextCounter,NewOnGoingList,TId}. - -%% Function removing the entry TCname+Id from the CHL. This makes it -%% possible to activate a tracecase with this id again. The entry was -%% previously marked as stopping. -nullify_chl(ProcH,TCname,Id,{NextCounter,OnGoingList,TId}) -> - ets:delete(TId,{TCname,Id}), - NewOnGoingList=lists:keydelete(ProcH,1,OnGoingList), - {NextCounter+1,NewOnGoingList,TId}. - -%% Function stopping all processes saved as being now running tc executers. -%% This is useful as cleanup during stop tracing for instance. -%% Returns a new CHL which is not in all parts correct. Entries in the -%% ETS table are for instance not properly state-changed. But the CHL will -%% from now on only be used to create command files and similar. -stop_all_tc_executer_chl({NextCounter,[{ProcH,_}|Rest],TId}) -> - exit(ProcH,kill), - stop_all_tc_executer_chl({NextCounter,Rest,TId}); -stop_all_tc_executer_chl({NextCounter,[],TId}) -> - {NextCounter,[],TId}. - -%% Function adding a "plain" inviso call to the CHL. -add_inviso_call_chl(Cmd,Args,{NextCounter,OnGoingList,TId}) -> - ets:insert(TId,{{inviso,Cmd,Args,make_ref()},NextCounter}), - {NextCounter+1,OnGoingList,TId}. - -%% Function adding a run trace case entry to the chl. -add_rtc_chl(TCname,Bindings,{NextCounter,OnGoingList,TId}) -> - ets:insert(TId,{{TCname,make_ref()},NextCounter,Bindings}), - {NextCounter+1,OnGoingList,TId}. -%% Returns the highest used counter number in the command history log. -get_highest_used_counter_chl({NextCounter,_,_}) -> - NextCounter-1. - -%% Help function returning a list of {{TCname,Id},Phase} for all ongoing -%% assynchronous tracecases. -get_ongoing_chl(undefined) -> - []; -get_ongoing_chl({_,OngoingList,TId}) -> - get_ongoing_chl_2(OngoingList,TId). - -get_ongoing_chl_2([{_ProcH,{TCname,Id}}|Rest],TId) -> - case ets:lookup(TId,{TCname,Id}) of - [{_,_C,activating,_B}] -> - [{{TCname,Id},activating}|get_ongoing_chl_2(Rest,TId)]; - [{_,_C,stopping,_B}] -> - [{{TCname,Id},deactivating}|get_ongoing_chl_2(Rest,TId)] - end; -get_ongoing_chl_2([],_) -> - []. - -%% Function returning a list of log entries. Note that the list is unsorted -%% in respect to Counter. -get_loglist_chl({_,_,TId}) -> - L=ets:tab2list(TId), - lists:map(fun({{TC,Id},C,S,B,_Result}) -> {{TC,Id},C,S,B}; % running - (Tuple={{_TC,_Id},_C,_S,_B}) -> Tuple; % activating | stopping - (Tuple={{_TC,_Id,_Ref},_C,_S,_B}) -> Tuple; % stop - (Tuple={{_M,_F,_Args,_Ref},_C}) -> Tuple; - (Tuple={{_TC,_Ref},_C,_B}) -> Tuple - end, - L); -get_loglist_chl(_) -> % The history is not initiated, ever! - []. - -%% Function returning a list of log entries, but only those which are not -%% cancelled out by deactivations. -% get_loglist_active_chl({_,_,TId}) -> -% L=ets:tab2list(TId), -% lists:zf(fun({{TC,Id},C,S,B,_Result}) -> {true,{{TC,Id},C,S,B}}; % running -% (Tuple={{_TC,_Id},_C,_S,_B}) -> Tuple; % activating | stopping -% (Tuple={{_TC,_Id,_Ref},_C,_S,_B}) -> Tuple; % stop -% (Tuple={{_M,_F,_Args,_Ref},_C}) -> Tuple -% end, -% L); -% get_loglist_chl(_) -> % The history is not initiated, ever! -% []. - - -%% This helpfunction recreates a history from a saved history list. This function -%% is supposed to crash if the log is not well formatted. Note that we must restore -%% the counter in order for the counter to work if new commands are added to the -%% history. -replace_history_chl(OldCHL,SortedLog) -> - {_,Ongoing,TId}=mk_chl(OldCHL), - {NewTId,Counter}=replace_history_chl_2(TId,SortedLog,0), - {ok,{Counter+1,Ongoing,NewTId}}. - -replace_history_chl_2(TId,[{{TC,Id},C,running,B}|Rest],_Counter) -> - ets:insert(TId,{{TC,Id},C,running,B,undefined}), - replace_history_chl_2(TId,Rest,C); -replace_history_chl_2(TId,[{{M,F,Args},C}|Rest],_Counter) -> - ets:insert(TId,{{M,F,Args,make_ref()},C}), - replace_history_chl_2(TId,Rest,C); -replace_history_chl_2(TId,[{TC,C,B}|Rest],_Counter) -> - ets:insert(TId,{{TC,make_ref()},C,B}), - replace_history_chl_2(TId,Rest,C); -replace_history_chl_2(TId,[],Counter) -> - {TId,Counter}. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% Reactivators data structure. -%% ----------------------------------------------------------------------------- - -%% Function adding a new node-reactivatorpid pair to the reactivators structure. -%% In this way we know which reactivators to remove if Node terminates, or when -%% a node is fully updated when a reactivator is done. -add_reactivators(Node,Pid,Reactivators) -> - [{Node,Pid}|Reactivators]. - -%% Function removing a reactivator entry from the reactivators structure. -del_reactivators(RPid,[{_Node,RPid}|Rest]) -> - Rest; -del_reactivators(RPid,[Element|Rest]) -> - [Element|del_reactivators(RPid,Rest)]; -del_reactivators(_,[]) -> % This should not happend. - []. - -get_node_reactivators(RPid,Reactivators) -> - case lists:keysearch(RPid,2,Reactivators) of - {value,{Node,_}} -> - Node; - false -> % This should not happend. - false - end. - -%% Returns a list of list all nodes that are currently reactivating. -get_all_nodes_reactivators([{Nodes,_Pid}|Rest]) -> - [Nodes|get_all_nodes_reactivators(Rest)]; -get_all_nodes_reactivators([]) -> - []. - -%% Function stopping all running reactivator processes. Returns a new empty -%% reactivators structure. Note that this function does not set the state of -%% Nodes. It must most often be set to running. -stop_all_reactivators([{_Nodes,Pid}|Rest]) -> - exit(Pid,kill), - stop_all_reactivators(Rest); -stop_all_reactivators([]) -> - []. % Returns an empty reactivators. - -%% Help function stopping the reactivator (if any) that reactivates Node. -%% Returns a new list of reactivators structure. -stop_node_reactivators(Node,[{Node,Pid}|Rest]) -> - exit(Pid,kill), - Rest; -stop_node_reactivators(Node,[NodePid|Rest]) -> - [NodePid|stop_node_reactivators(Node,Rest)]; -stop_node_reactivators(_,[]) -> - []. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% Started initial trace cases data structure. -%% ----------------------------------------------------------------------------- - -%% This datastructure keeps information about ongoing trace cases started -%% automatically at init_tracing. These must be automatically stopped when calling -%% stop_tracing. - -add_initial_tcs(TCname,Id,StartedInitialTcs) -> - [{TCname,Id}|StartedInitialTcs]. -%% ----------------------------------------------------------------------------- - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/inviso/src/inviso_tool_lib.erl b/lib/inviso/src/inviso_tool_lib.erl deleted file mode 100644 index f221c4b6de..0000000000 --- a/lib/inviso/src/inviso_tool_lib.erl +++ /dev/null @@ -1,379 +0,0 @@ -% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
-%% Description:
-%% Support module to the inviso tool.
-%%
-%% Authors:
-%% Lennart Öhman, [email protected]
-%% -----------------------------------------------------------------------------
-
--module(inviso_tool_lib).
-
-%% -----------------------------------------------------------------------------
-%% Exported library APIs
-%% -----------------------------------------------------------------------------
--export([inviso_cmd/3,expand_module_names/3,make_patterns/7,std_tdg/2]).
--export([mk_tdg_args/2,mk_complete_tdg_args/2,get_datetime_from_tdg_args/1]).
--export([debug/3]).
-
-%% -----------------------------------------------------------------------------
-%% Constants.
-%% -----------------------------------------------------------------------------
--define(DBG_OFF,off). % No internal debug indicator.
-
-
-%% =============================================================================
-%% Functions for inviso_cmd
-%% =============================================================================
-
-%% Help function which executes a trace control call. The reason for having a special
-%% function is that we either want to do rpc if the trace control component is
-%% located on another Erlang node than this one. Or call trace_c directly if
-%% it actually is on this node.
-%% Returns whatever the inviso function returns. In case of badrpc it is wrapped
-%% in an error-tuple.
-inviso_cmd(NodeName,Func,Args) ->
- case node() of
- NodeName -> % Control component on this node.
- apply(inviso,Func,Args);
- _ -> % On other node, must do RPC.
- case rpc:call(NodeName,inviso,Func,Args) of
- {badrpc,Reason} ->
- {error,{badrpc,Reason}};
- Result ->
- Result
- end
- end.
-%% -----------------------------------------------------------------------------
-
-
-%% =============================================================================
-%% Functions for expand_module_names
-%% =============================================================================
-
-%% Help function which expands the module name depending on how it is expressed.
-%% Setting Nodes to 'void' makes it non-distributed, expanding only here.
-%% The following special cases are handled:
-%% '_' =All modules, no expansion into individual module names. Instead
-%% it is intended to use the '_' mechanism in the trace_pattern BIF.
-%% Can therefore not be combined with a directory regexp.
-%% "*" =Is translated into ".*".
-%% "abc"=Means ".*abc.*". Can only be used for module or directory names
-%% containing upper or lowercase, digits and a slash.
-%% Returns {multinode_expansion,NodeModules},
-%% {singlenode_expansion,Modules},
-%% 'module', 'wildcard' or {error,Reason},
-%% To limit the places where expansion is done, the option {expand_only_at,Node}
-%% can be provided in the Opts list.
-%% In the non-distributed case the singlenode_expansion will be returned.
-expand_module_names(_Nodes,Mod={_,'_'},_) ->
- {error,{faulty_regexp_combination,Mod}};
-expand_module_names(Nodes,{DirStr,ModStr},Opts) when is_list(DirStr), is_list(ModStr) -> - case expand_module_names_special_regexp(DirStr) of
- {ok,NewDirStr} ->
- case expand_module_names_special_regexp(ModStr) of
- {ok,NewModStr} ->
- expand_module_names_2(Nodes,NewDirStr,NewModStr,Opts);
- {error,_Reason} ->
- {error,{faulty_regexp,ModStr}}
- end;
- {error,_Reason} ->
- {error,{faulty_regexp,DirStr}}
- end;
-expand_module_names(_,'_',_Opts) -> % If we want to trace all modules
- wildcard; % we shall not expand it.
-expand_module_names(_Nodes,Mod,_Opts) when is_atom(Mod) -> - module; % If it is an atom, no expansion.
-expand_module_names(Nodes,"*",Opts) -> % Treat this as a reg.exp.
- expand_module_names(Nodes,".*",Opts);
-expand_module_names(Nodes,ModStr,Opts) when is_list(ModStr) -> - case expand_module_names_special_regexp(ModStr) of
- {ok,NewModStr} ->
- expand_module_names_2(Nodes,NewModStr,Opts);
- {error,_Reason} ->
- {error,{faulty_regexp,ModStr}}
- end.
-
-expand_module_names_2(void,ModStr,Opts) -> % Non-distributed case.
- {singlenode_expansion,inviso_rt_lib:expand_regexp(ModStr,Opts)};
-expand_module_names_2(Nodes,ModStr,Opts) ->
- case get_expand_regexp_at_opts(Opts) of
- {ok,Node} -> % Expansion only at this node.
- case inviso_rt_lib:expand_regexp([Node],ModStr,Opts) of
- [{Node,Modules}] when is_list(Modules) -> - {singlenode_expansion,Modules};
- [{Node,_}] -> % Most likely badrpc.
- {error,{faulty_node,Node}}
- end;
- false -> % Expand on all nodes.
- Result=inviso_rt_lib:expand_regexp(Nodes,ModStr,Opts),
- {multinode_expansion,Result}
- end.
-expand_module_names_2(void,DirStr,ModStr,Opts) -> % Non-distributed case.
- {singlenode_expansion,inviso_rt_lib:expand_regexp(DirStr,ModStr,Opts)};
-expand_module_names_2(Nodes,DirStr,ModStr,Opts) ->
- case get_expand_regexp_at_opts(Opts) of
- {ok,Node} -> % Expansion only at this node.
- case inviso_rt_lib:expand_regexp([Node],DirStr,ModStr,Opts) of
- [{Node,Modules}] when is_list(Modules) -> - {singlenode_expansion,Modules};
- [{Node,_}] -> % Most likely badrpc.
- {error,{faulty_node,Node}}
- end;
- false -> % Expand on all nodes.
- Result=inviso_rt_lib:expand_regexp(Nodes,DirStr,ModStr,Opts),
- {multinode_expansion,Result}
- end.
-
-%% Help function which converts a special regexp into a proper one. With
-%% special regexps we mean e.g:"abc" which is supposed to mean ".*abc.*".
-%% Always returns a regexp or {error,Reason}.
-expand_module_names_special_regexp(Str) ->
- StrLen=length(Str),
- case re:run(Str,"[0-9a-zA-Z_/]*") of
- {match,[{0,StrLen}]} -> % Ok, it is the special case.
- {ok,".*"++Str++".*"}; % Convert it to a proper regexp.
- {match,_} ->
- {ok,Str}; % Keep it and hope it is a regexp.
- nomatch ->
- {ok,Str}; % Keep it and hope it is a regexp.
- {error,Reason} -> % Can't continue with this!
- {error,Reason}
- end.
-%% -----------------------------------------------------------------------------
-
-
-%% =============================================================================
-%% Functions for make_pattern.
-%% =============================================================================
-
--define(DEPTH,3). % Max recursive safety catch depth.
-
-%% Help function that creates trace-patterns for each module in the list.
-%% It can handle both lists of modules or lists of nodes and modules.
-%% It will also in the process apply safety catches, if such are not disabled,
-%% in order to prevent certain patterns to form.
-%% The safety catch function is supposed to return either 'ok' or {new,NewTracePattern}.
-%% Where the NewTracePattern is a list of zero or more {M,F,Arity,MS}. The
-%% NewTracePatter is then the replacement for the tried trace-pattern.
-%% Note that the new trace-pattern(s) are also tried against all safety catches.
-%% This can possibly result in even replacements of the replacements. There is
-%% a depth meter to prevent the safety catch mechanism from circularly expanding
-%% trace patterns for ever.
-%% Returns a list of [{Node,PatternList},...] or [Pattern,...].
-%% The latter is used when the modules have been expanded on a single node.
-make_patterns(Catches,Opts,Dbg,NodeModsOrMods,F,A,MS) ->
- OwnArg=get_ownarg_opts(Opts),
- case get_disable_safety_opts(Opts) of
- true -> % Do not use the safety catches.
- make_patterns_2(void,OwnArg,Dbg,NodeModsOrMods,F,A,MS);
- false ->
- make_patterns_2(Catches,OwnArg,Dbg,NodeModsOrMods,F,A,MS)
- end.
-
-make_patterns_2(Catches,OwnArg,Dbg,[{Node,Mods}|Rest],F,A,MS) when is_list(Mods) -> - TPs=make_patterns_3(Catches,OwnArg,Dbg,Mods,F,A,MS,[]),
- [{Node,join_patterns(TPs)}|make_patterns_2(Catches,OwnArg,Dbg,Rest,F,A,MS)];
-make_patterns_2(Catches,OwnArg,Dbg,[{_Node,_}|Rest],F,A,MS) -> % badrpc!?
- make_patterns_2(Catches,OwnArg,Dbg,Rest,F,A,MS);
-make_patterns_2(Catches,OwnArg,Dbg,Modules,F,A,MS) when is_list(Modules) -> - TPs=make_patterns_3(Catches,OwnArg,Dbg,Modules,F,A,MS,[]),
- join_patterns(TPs);
-make_patterns_2(_,_,_,[],_,_,_) ->
- [].
-
-make_patterns_3(void,OwnArg,Dbg,[M|Rest],F,A,MS,Result) -> % S-catches not used!
- make_patterns_3(void,OwnArg,Dbg,Rest,F,A,MS,[{M,F,A,MS}|Result]);
-make_patterns_3(Catches,OwnArg,Dbg,[M|Rest],F,A,MS,Result) ->
- NewTPs=try_safety_catches(Catches,OwnArg,[{M,F,A,MS}],Dbg,[],?DEPTH),
- make_patterns_3(Catches,OwnArg,Dbg,Rest,F,A,MS,[NewTPs|Result]);
-make_patterns_3(_,_,_,[],_,_,_,Result) ->
- lists:flatten(Result).
-
-try_safety_catches(_Catches,_OwnArg,TPs,Dbg,_Accum,0) -> % Max depth here!
- debug(max_catch_depth,Dbg,[TPs]),
- TPs; % Just return them unchanged.
-try_safety_catches(Catches,OwnArg,[TP={M,F,A,MS}|Rest],Dbg,Accum,Depth) ->
- case try_safety_catch(Catches,OwnArg,M,F,A,MS,Dbg) of
- ok -> % This pattern is safe!
- try_safety_catches(Catches,OwnArg,Rest,Dbg,[TP|Accum],?DEPTH);
- {new,NewTPs} -> % Then we must try them too!
- NewTPs2=try_safety_catches(Catches,OwnArg,NewTPs,Dbg,[],Depth-1),
- try_safety_catches(Catches,OwnArg,Rest,Dbg,[NewTPs2|Accum],?DEPTH)
- end;
-try_safety_catches(_,_,[],_,Accum,_) ->
- Accum.
-
-try_safety_catch([{SafetyMod,SafetyFunc}|Rest],OwnArg,M,F,A,MS,Dbg) ->
- case (catch apply(SafetyMod,SafetyFunc,[M,F,A,MS,OwnArg])) of
- ok -> % This catch has no oppinion about it.
- try_safety_catch(Rest,OwnArg,M,F,A,MS,Dbg); % Continue with the next.
- {new,NewTPs} -> % Replace it with this or these new.
- debug(safety_catch,Dbg,[new,{SafetyMod,SafetyFunc},M,F,A,MS,NewTPs]),
- {new,NewTPs}; % and stop trying safety cathes.
- {'EXIT',Reason} -> % Something wrong with the safety catch.
- debug(safety_catch,Dbg,['EXIT',{SafetyMod,SafetyFunc},M,F,A,MS,Reason]),
- try_safety_catch(Rest,OwnArg,M,F,A,MS,Dbg) % Skip it and go on.
- end;
-try_safety_catch([],_,_,_,_,_,_) ->
- ok. % Since it passed all, it is safe!
-%% -----------------------------------------------------------------------------
-
-%% Help function that joins patterns together. This is necessary since you can
-%% only set the pattern once for a module-function-arity. This function can not
-%% remove conflicting match-spec "commands". Match-specs will simply be concatenated.
-%% Returns a list of patterns where each mod-func-arity is unique.
-join_patterns(Patterns) ->
- join_patterns_2(Patterns,[]).
-
-join_patterns_2([{M,F,Arity,MS}|Rest],Result) ->
- case join_patterns_is_already_done(M,F,Arity,Result) of
- false -> % No we have not collapsed this one.
- case join_patterns_3(M,F,Arity,Rest) of
- [] -> % No this combination is unique.
- join_patterns_2(Rest,[{M,F,Arity,MS}|Result]);
- MSs -> % We got a list of all other TPs.
- join_patterns_2(Rest,[{M,F,Arity,MS++MSs}|Result])
- end;
- true -> % We already joined this M-F-Arity.
- join_patterns_2(Rest,Result) % Simply skip it, already done.
- end;
-join_patterns_2([],Result) ->
- Result. % Reversed but does not matter!
-
-%% Help function checking if we have already built a trace-pattern for
-%% this M-F-Arity. If so, the found M-F-Arity is already handled.
-join_patterns_is_already_done(M,F,Arity,[{M,F,Arity,_}|_]) ->
- true;
-join_patterns_is_already_done(M,F,Arity,[_|Rest]) ->
- join_patterns_is_already_done(M,F,Arity,Rest);
-join_patterns_is_already_done(_,_,_,[]) ->
- false.
-
-%% Help function which simply concatenates all match-specs for this
-%% M-F-Arity.
-join_patterns_3(M,F,Arity,[{M,F,Arity,MS}|Rest]) ->
- [MS|join_patterns_3(M,F,Arity,Rest)];
-join_patterns_3(M,F,Arity,[_|Rest]) ->
- join_patterns_3(M,F,Arity,Rest);
-join_patterns_3(_,_,_,[]) ->
- [].
-%% -----------------------------------------------------------------------------
-
-
-%% =============================================================================
-%% Function for tracer data creation.
-%% =============================================================================
-
--define(I2L(Arg),integer_to_list(Arg)).
-
-%% The inviso_tool uses a tracer-data generator function to create the tracer_data
-%% specification for each node that shall participate in tracing controlled
-%% through the inviso-tool. If no own tracer data generator function is specified,
-%% this function is used.
-std_tdg(Node,{{Y,Mo,D},{H,Mi,S}}) ->
- NameStr=atom_to_list(Node)++"_"++?I2L(Y)++"-"++?I2L(Mo)++"-"++?I2L(D)++"_"++
- ?I2L(H)++"-"++?I2L(Mi)++"-"++?I2L(S),
- LogTD={file,NameStr++".log"},
- TiTD={file,NameStr++".ti"},
- [{trace,LogTD},{ti,TiTD}].
-%% ------------------------------------------------------------------------------
-
-%% mk_tdg_args(DateTime,Args)=TDGargs
-%% DateTime={Date,Time}
-%% Date=tuple(),
-%% Time=tuple(),
-%% Args=list()
-%% TDGargs=list(),
-%% Creates the TDGargs list used when calling functions making the CompleteTDGargs.
-mk_tdg_args(DateTime,Args) ->
- [DateTime|Args].
-%% ------------------------------------------------------------------------------
-
-%% mk_complete_tdg_args(Node,TDGargs)=CompleteTDGargs
-%% Returns the list of all arguments a tracer data generator function must accept.
-mk_complete_tdg_args(Node,TDGargs) ->
- [Node|TDGargs].
-%% ------------------------------------------------------------------------------
-
-%% get_datetime_from_tdg_args(TDGargs)=DateTime
-%% Function returning the DateTime tuple in a TDGargs list.
-get_datetime_from_tdg_args([DateTime|_]) ->
- DateTime.
-%% ------------------------------------------------------------------------------
-
-
-%% =============================================================================
-%% Various help functions.
-%% =============================================================================
-
-%% -----------------------------------------------------------------------------
-%% Functions handling set trace-pattern options.
-%% -----------------------------------------------------------------------------
-
-%% Gets additional arguments given to various configurable functions.
-%% Returns a list.
-get_ownarg_opts(Opts) ->
- case lists:keysearch(arg,1,Opts) of
- {value,{_,OwnArg}} when is_list(OwnArg) -> - OwnArg;
- {value,{_,OwnArg}} ->
- [OwnArg];
- false ->
- []
- end.
-%% -----------------------------------------------------------------------------
-
-get_disable_safety_opts(Opts) ->
- case lists:member(disable_safety,Opts) of
- true ->
- true;
- false ->
- false
- end.
-%% -----------------------------------------------------------------------------
-
-get_expand_regexp_at_opts(Opts) ->
- case lists:keysearch(expand_only_at,1,Opts) of
- {value,{_,Node}} when is_atom(Node) -> - {ok,Node};
- _ ->
- false
- end.
-%% -----------------------------------------------------------------------------
-
-
-%% =============================================================================
-%% Functions for the internal debugging system.
-%% =============================================================================
-
-%% The debug system is meant to provide tracing of inviso tool at different levels.
-%%
-%% debug(What,Level,Description) -> nothing significant.
-%% What : controls what kind of event. This can both be certain parts of the tool
-%% as well as certain levels (info to catastrophy).
-%% Level: Determines if What shall be printed or not.
-%% Description: this is what happend.
-debug(_What,?DBG_OFF,_Description) ->
- true; % Debug is off, no action.
-debug(What,On,Description) ->
- debug_2(What,On,Description).
-
-debug_2(What,_,Description) ->
- io:format("INVISO DEBUG:~w, ~p~n",[What,Description]).
-%% -----------------------------------------------------------------------------
diff --git a/lib/inviso/src/inviso_tool_sh.erl b/lib/inviso/src/inviso_tool_sh.erl deleted file mode 100644 index b02f498c5b..0000000000 --- a/lib/inviso/src/inviso_tool_sh.erl +++ /dev/null @@ -1,1749 +0,0 @@ -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Description: -%% The runtime component of the trace tool Inviso. -%% -%% Authors: -%% Lennart �hman, [email protected] -%% ----------------------------------------------------------------------------- - --module(inviso_tool_sh). - -%% Inviso Session Handler. -%% This is the code for the session handler process. Its purpose is that we have -%% one session handler process for each trace session started through the -%% start_session inviso tool API. The session handler process is responsible for: -%% -%% -Knowing the state/status of all participating runtime components. -%% -Keeping storage of all tracerdata all our participants have used. This means -%% also to find out the tracerdata of runtime components connecting by them -%% selves. -%% -%% STORAGE STRATEGY -%% ---------------- -%% The local information storage can be changed by two things. Either by executing -%% commands issued through our APIs. Or by receiving trace_event from the control -%% component. When we execute commands, a corresponding event will also follow. -%% Meaning that in those situations we are informed twice. -%% A simple strategy could be to wait for the event even when doing the changes -%% to the runtime components our self (through commands). But that may result in -%% a small time frame where someone might do yet another command and failing -%% because the local information storage is not uptodate as it would have been -%% expected to be. Therefore we always update the local storage when making changes -%% to a runtime component our selves. There will eventually be a double update -%% through an incoming event. But the storage must coop with that, preventing -%% inconsitancies to happend. An example of a strategy is that the tracerdata table -%% is a bag, not allowing for double entries of the same kind. Therefore a double -%% update is harmless there. - -%% ------------------------------------------------------------------------------ -%% Module wide constants. -%% ------------------------------------------------------------------------------ --define(LOCAL_RUNTIME,local_runtime). % Used as node name when non-disitrbuted. --define(TRACING,tracing). % A state defined by the control component. --define(RUNNING,running). % A status according to control componet. - --define(COPY_LOG_FROM,copy_log_from). % Common fileystem option. -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% API exports. -%% ------------------------------------------------------------------------------ --export([start_link/5,start_link/8]). --export([cancel_session/1,stop_session/3]). --export([reactivate/1,reactivate/2]). --export([ctpl/5,tpl/5,tpl/6,tpl/7, - tf/2,tf/3, - tpm_localnames/2,init_tpm/6,init_tpm/9,tpm/6,tpm/7,tpm/10, - tpm_ms/7,ctpm_ms/6,ctpm/5 - ]). -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Internal exports. -%% ------------------------------------------------------------------------------ --export([init/1,handle_call/3,handle_info/2,terminate/2]). - --export([get_loopdata/1]). -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Includes. -%% ------------------------------------------------------------------------------ --include_lib("kernel/include/file.hrl"). % Necessary for file module. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% Exported API functions. -%% ============================================================================== - -%% start_link(From,NodeParams,CtrlNode,CtrlPid,SafetyCatches,NodesIn,NodesNotIn) = -%% {ok,Pid} | {error,Reason} -%% From= pid(), the initial client expecting the reply. -%% NodeParams=[{Node,TracerData},{Node,TracerData,Opts}...] -%% CtrlNode=atom() | 'void', the node where the trace control component is. -%% CtrlPid=pid(), the pid of the trace control component. -%% SafetyCatches= -%% Dir=string(), where to place fetched logs and the merged log. -%% Dbg=debug structure. -%% NodesIn=[Node,...], list of nodes already in another session. -%% NodesNotIn=[Node,...], list of nodes not in another session. -%% -%% Starts a session-handler. It keeps track of the the state and status of all -%% participating runtime components. Note that there is a non-distributed case too. -%% In the non-distributed case there is no things such as CtrlNode. -start_link(From,TracerData,CtrlPid,SafetyCatches,Dbg) -> - gen_server:start_link(?MODULE, - {self(),From,TracerData,CtrlPid,SafetyCatches,Dbg}, - []). - -start_link(From,NodeParams,CtrlNode,CtrlPid,SafetyCatches,Dbg,NodesIn,NodesNotIn) -> - gen_server:start_link(?MODULE, - {self(),From,NodeParams,CtrlNode,CtrlPid, - SafetyCatches,Dbg,NodesIn,NodesNotIn}, - []). -%% ------------------------------------------------------------------------------ - -%% Stops tracing where it is ongoing. Fetches all logfiles. -stop_session(SID,Dir,Prefix) -> - gen_server:call(SID,{stop_session,Dir,Prefix}). -%% ------------------------------------------------------------------------------ - -%% stop_session(SID) = ok -%% -%% Cancels the session brutaly. All runtime components are made to stop tracing, -%% all local log files are removed using the tracerdata we know for them. -cancel_session(SID) -> - gen_server:call(SID,cancel_session). -%% ------------------------------------------------------------------------------ - -%% reactivate(SID) = {ok, -%% reactivate(SID,Nodes) = {ok,NodeResults} | {error,Reason}. -%% SID=session id, pid(). -%% Nodes=[Node,...] -%% NodeResult=[{Node,Result},...] -%% Result={Good,Bad} -%% Good,Bad=integer(), the number of redone activities. -%% -%% Function which reactivates runtime components being suspended. This is done -%% replaying all trace flags (in the correct order) to the corresponding nodes. -%% Note that this may also mean turning flags off. Like first turning them on -%% then off a split second later. -reactivate(SID) -> - gen_server:call(SID,reactivate). %% NOT IMPLEMENTED YET. -reactivate(SID,Nodes) -> - gen_server:call(SID,{reactivate,Nodes}). -%% ------------------------------------------------------------------------------ - - -%% tpl(SessionID,Mod,Func,Arity,MS)= -%% tpl(SessionID,Mod,Func,Arity,MS,Opts)={ok,N}|{error,Reason}. -%% tpl(SessionID,Nodes,Mod,Func,Arity,MS)= -%% tpl(SessionID,Nodes,Mod,Func,Arity,MS,Opts)={ok,Result}|{error,Reason} -%% Mod='_' | ModuleName | ModRegExp | {DirRegExp,ModRegExp} -%% ModRegExp=DirRegExp= string() -%% Func='_' | FunctionName -%% Arity='_' | integer() -%% MS=[] | false | a match specification -%% Opts=[Opts,...] -%% Opt={arg,Arg}, disable_safety, {expand_regexp_at,NodeName}, only_loaded -%% Nodes=[NodeName,...] -tpl(SID,Mod,Func,Arity,MS) -> - gen_server:call(SID,{tp,tpl,Mod,Func,Arity,MS,[]}). -tpl(SID,Mod,Func,Arity,MS,Opts) when list(MS);MS==true;MS==false -> - gen_server:call(SID,{tp,tpl,Mod,Func,Arity,MS,Opts}); -tpl(SID,Nodes,Mod,Func,Arity,MS) when integer(Arity);Arity=='_' -> - gen_server:call(SID,{tp,tpl,Nodes,Mod,Func,Arity,MS,[]}). -tpl(SID,Nodes,Mod,Func,Arity,MS,Opts) -> - gen_server:call(SID,{tp,tpl,Nodes,Mod,Func,Arity,MS,Opts}). -%% ------------------------------------------------------------------------------ - -%% ctpl(SessionID,Nodes,Mod,Func,Arity)= -%% See tpl/X for arguments. -%% -%% Removes local trace-patterns from functions. -ctpl(SID,Nodes,Mod,Func,Arity) -> - gen_server:call(SID,{ctp,ctpl,Nodes,Mod,Func,Arity}). -%% ------------------------------------------------------------------------------ - - -tpm_localnames(SID,Nodes) -> - gen_server:call(SID,{tpm_localnames,Nodes}). - -%% tpm_globalnames(SID,Nodes) -> -%% gen_server:call(SID,{tpm_globalnames,Nodes}). - -init_tpm(SID,Nodes,Mod,Func,Arity,CallFunc) -> - gen_server:call(SID,{init_tpm,Nodes,Mod,Func,Arity,CallFunc}). -init_tpm(SID,Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - gen_server:call(SID, - {init_tpm,Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc}). -tpm(SID,Nodes,Mod,Func,Arity,MS) -> - gen_server:call(SID,{tpm,Nodes,Mod,Func,Arity,MS}). -tpm(SID,Nodes,Mod,Func,Arity,MS,CallFunc) -> - gen_server:call(SID,{tpm,Nodes,Mod,Func,Arity,MS,CallFunc}). -tpm(SID,Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - gen_server:call(SID,{tpm,Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc}). - -tpm_ms(SID,Nodes,Mod,Func,Arity,MSname,MS) -> - gen_server:call(SID,{tpm_ms,Nodes,Mod,Func,Arity,MSname,MS}). - -ctpm_ms(SID,Nodes,Mod,Func,Arity,MSname) -> - gen_server:call(SID,{tpm_ms,Nodes,Mod,Func,Arity,MSname}). - -ctpm(SID,Nodes,Mod,Func,Arity) -> - gen_server:call(SID,{ctpm,Nodes,Mod,Func,Arity}). -%% ------------------------------------------------------------------------------ - - -%% tf(SessionID,Nodes,TraceConfList)= -%% TraceConfList=[{PidSpec,Flags},...] -%% PidSpec=pid()|atom()|all|new|existing -%% Flags=[Flag,...] -tf(SID,TraceConfList) -> - gen_server:call(SID,{tf,TraceConfList}). -tf(SID,Nodes,TraceConfList) -> - gen_server:call(SID,{tf,Nodes,TraceConfList}). -%% ------------------------------------------------------------------------------ - - -get_loopdata(SID) -> - gen_server:call(SID,get_loopdata). -%% ------------------------------------------------------------------------------ - -%% ============================================================================== -%% Genserver call-backs. -%% ============================================================================== - -%% Initial function for the session handler process. The nodes participating in -%% the session must previously have been added to our control component by the tool. -%% The session handler first finds out the state/status of the specified runtime -%% components, then it tries to initiate tracing on those where it is applicable. -%% Note that a reply to the initial (tool)client is done from here instead from -%% the tool-server. -init({Parent,From,TracerData,CtrlPid,SafetyCatches,Dbg}) -> % The non-distributed case. - {ok,StateStatus}=init_rtcomponent_states([],void,CtrlPid,[?LOCAL_RUNTIME]), - case is_tool_internal_tracerdata(TracerData) of - false -> % We shall initiate local runtime. - case inviso:init_tracing(TracerData) of - ok -> - gen_server:reply(From,{ok,{self(),ok}}), - {ok,mk_ld(Parent, - void, - CtrlPid, - to_rtstates([{?LOCAL_RUNTIME,{tracing,?RUNNING},[]}]), - [{?LOCAL_RUNTIME,TracerData}], - [], - SafetyCatches, - Dbg)}; - {error,Reason} -> % It might have become suspended?! - gen_server:reply(From,{error,Reason}), - {ok,mk_ld(Parent, - void, - CtrlPid, - to_rtstates([{?LOCAL_RUNTIME,StateStatus,[]}]), - [{?LOCAL_RUNTIME,TracerData}], - [], - SafetyCatches, - Dbg)} - end; - true -> % We shall not pass this one on. - gen_server:reply(From,{ok,{self(),ok}}), % Then it is ok. - {ok,mk_ld(Parent, - void, - CtrlPid, - to_rtstates([{?LOCAL_RUNTIME,StateStatus,[]}]), - [], - [?LOCAL_RUNTIME], - SafetyCatches, - Dbg)} - end; -init({Parent,From,NodeParams,CtrlNode,CtrlPid,SafetyCatches,Dbg,NodesIn,NodesNotIn}) -> - case init_rtcomponent_states(NodeParams,CtrlNode,CtrlPid,NodesNotIn) of - {ok,States} -> % A list of {Node,{State,Status},Opts}. - {NodeParams2,Nodes2}=remove_nodeparams(NodesIn,NodeParams), - case inviso_tool_lib:inviso_cmd(CtrlNode,init_tracing,[NodeParams2]) of - {ok,Result} -> % Resulted in state changes! - RTStates=set_tracing_rtstates(to_rtstates(States),Result), - ReplyValue=init_fix_resultnodes(NodesIn,Nodes2,Result), - gen_server:reply(From,{ok,{self(),ReplyValue}}), - {ok,mk_ld(Parent,CtrlNode,CtrlPid,RTStates, - NodeParams2,Nodes2,SafetyCatches,Dbg)}; - {error,Reason} -> % Some general failure. - inviso_tool_lib:inviso_cmd(CtrlNode,unsubscribe,[]), - gen_server:reply(From,{error,{init_tracing,Reason}}), - {stop,{init_tracing,Reason}}; - What -> - io:format("GOT:~n~w~n",[What]), - exit(foo) - end; - {error,Reason} -> % Unable to get the state/status. - inviso_tool_lib:inviso_cmd(CtrlNode,unsubscribe,[]), - gen_server:reply(From,{error,Reason}), - {stop,{error,Reason}}; - What -> - io:format("GOT:~n~w~n",[What]), - exit(foo) - end. -%% ------------------------------------------------------------------------------ - -%% To stop a session means stop the tracing and remove all local files on the -%% runtime nodes. We do have a table with all tracer data and that is how we are -%% going to recreate what files to remove. -%% Since runtime components may actually change state when this procedure is -%% on-going, we do not care! It is the state in the session handling process at -%% the time of start of this procedure which is used. -handle_call(cancel_session,_From,LD) -> - CtrlNode=get_ctrlnode_ld(LD), - RTStates=get_rtstates_ld(LD), - Dbg=get_dbg_ld(LD), - TracingNodes=get_all_tracing_nodes_rtstates(RTStates), - case stop_all_tracing(CtrlNode,Dbg,TracingNodes) of - ok-> % Hopefully all nodes are stopped now. - AvailableNodes=get_all_available_nodes_rtstates(RTStates), - TRDstorage=get_trdstorage_ld(LD), - remove_all_local_logs(CtrlNode,TRDstorage,AvailableNodes,Dbg), - {stop,normal,ok,LD}; % LD actually not correct now! - {error,Reason} -> % Some serious error when stop_tracing. - {stop,normal,{error,Reason},LD} - end; -%% ------------------------------------------------------------------------------ - -%% *Stop all tracing on runtime components still tracing. -%% *Copy all local log files to the collection directory. -handle_call({stop_session,Dir,Prefix},_From,LD) -> - case check_directory_exists(Dir) of % Check that this directory exists here. - true -> - RTStates=get_rtstates_ld(LD), - CtrlNode=get_ctrlnode_ld(LD), - Dbg=get_dbg_ld(LD), - TracingNodes=get_all_tracing_nodes_rtstates(RTStates), - case stop_all_tracing(CtrlNode,Dbg,TracingNodes) of - ok -> % Hopefully no node is still tracing now. - TRDstorage=get_trdstorage_ld(LD), - AvailableNodes=get_all_available_nodes_rtstates(RTStates), - {FailedNodes,FetchedFiles}= - transfer_logfiles(RTStates,CtrlNode,Dir,Prefix, - TRDstorage,Dbg,AvailableNodes), - RemoveNodes= % We only delete local logs where fetch ok. - lists:filter(fun(N)-> - case lists:keysearch(N,1,FailedNodes) of - {value,_} -> - false; - false -> - true - end - end, - AvailableNodes), - remove_all_local_logs(CtrlNode,TRDstorage,RemoveNodes,Dbg), - {stop,normal,{ok,{FailedNodes,FetchedFiles}},LD}; - {error,Reason} -> % Some general failure, quit. - {stop,normal,{error,Reason},LD} - end; - false -> % You specified a non-existing directory! - {reply,{error,{faulty_dir,Dir}},LD} - end; -%% ------------------------------------------------------------------------------ - -handle_call({reactivate,Nodes},_From,LD) -> - RTStates=get_rtstates_ld(LD), - {OurNodes,OtherNodes}= - remove_nodes_not_ours(Nodes,get_all_session_nodes_rtstates(RTStates)), - CtrlNode=get_ctrlnode_ld(LD), - ACTstorage=get_actstorage_ld(LD), - case h_reactivate(CtrlNode,OurNodes,ACTstorage) of - {ok,Results} -> % A list of {Node,Result}. - if - OtherNodes==[] -> % Normal case, no non-session nodes. - {reply,{ok,Results},LD}; - true -> % Add error values for non-session nodes. - {reply, - {ok, - lists:map(fun(N)->{N,{error,not_in_session}} end,OtherNodes)++ - Results}, - LD} - end; - {error,Reason} -> % Then this error takes presidence. - {reply,{error,Reason},LD} - end; -%% ------------------------------------------------------------------------------ - -%% Call-back for set trace-pattern for both global and local functions. -handle_call({tp,PatternFunc,Mod,F,A,MS,Opts},_From,LD) -> - Reply=h_tp(all,PatternFunc,Mod,F,A,MS,Opts,LD), % For all active nodes in the session. - {reply,Reply,LD}; -handle_call({tp,PatternFunc,Nodes,Mod,F,A,MS,Opts},_From,LD) -> - RTStates=get_rtstates_ld(LD), - SNodes=get_all_session_nodes_rtstates(RTStates), % Notes belongoing to the session. - {Nodes2,FaultyNodes}=remove_nodes_not_ours(Nodes,SNodes), - Reply=h_tp(Nodes2,PatternFunc,Mod,F,A,MS,Opts,LD), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,FaultyNodes), - {reply,ErrorReply++Reply,LD}; -%% ------------------------------------------------------------------------------ - -%% Call-back handling the removal of both local and global trace-patterns. -%% NOT IMPLEMENTED YET. -handle_call({ctp,PatternFunc,Nodes,Mod,F,A},_From,LD) -> - Reply=h_ctp(Nodes,PatternFunc,Mod,F,A,LD), - {reply,Reply,LD}; -%% ------------------------------------------------------------------------------ - -handle_call({tpm_localnames,Nodes},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_tpm_localnames(get_ctrlnode_ld(LD),Nodes2,RTStates,ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({init_tpm,Nodes,Mod,Func,Arity,CallFunc},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - init_tpm, - [Mod,Func,Arity,CallFunc], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({init_tpm,Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - init_tpm, - [Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({tpm,Nodes,Mod,Func,Arity,MS},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD),Nodes2,tpm,[Mod,Func,Arity,MS],RTStates,ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({tpm,Nodes,Mod,Func,Arity,MS,CallFunc},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - tpm, - [Mod,Func,Arity,MS,CallFunc], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({tpm,Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - tpm, - [Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({tpm_ms,Nodes,Mod,Func,Arity,MSname,MS},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - tpm_ms, - [Mod,Func,Arity,MSname,MS], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({ctpm_ms,Nodes,Mod,Func,Arity,MSname},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD), - Nodes2, - ctpm_ms, - [Mod,Func,Arity,MSname], - RTStates, - ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; - -handle_call({ctpm,Nodes,Mod,Func,Arity},_From,LD) -> - RTStates=get_rtstates_ld(LD), - OurNodes=get_all_session_nodes_rtstates(RTStates), - {Nodes2,NotOurNodes}=remove_nodes_not_ours(Nodes,OurNodes), - ACTstorage=get_actstorage_ld(LD), - {Reply,NewACTstorage}= - h_all_tpm(get_ctrlnode_ld(LD),Nodes2,ctpm,[Mod,Func,Arity],RTStates,ACTstorage), - ErrorReply=lists:map(fun(N)->{N,{error,not_in_session}} end,NotOurNodes), - {reply,ErrorReply++Reply,put_actstorage_ld(NewACTstorage,LD)}; -%% ------------------------------------------------------------------------------ - -%% Call-back for setting process trace-flags. Handles both distributed and non- -%% distributed case. -handle_call({tf,TraceConfList},From,LD) -> - handle_call({tf,all,TraceConfList},From,LD); -handle_call({tf,Nodes,TraceConfList},_From,LD) -> - {Reply,NewACTstorage}=h_tf(get_ctrlnode_ld(LD), - Nodes, - TraceConfList, - get_actstorage_ld(LD), - get_rtstates_ld(LD)), - {reply,Reply,put_actstorage_ld(NewACTstorage,LD)}; -%% ------------------------------------------------------------------------------ - - - -handle_call(get_loopdata,_From,LD) -> - io:format("The loopdata:~n~p~n",[LD]), - {reply,ok,LD}. -%% ------------------------------------------------------------------------------ - - -%% Clause handling an incomming state-change event from the control component. -%% Note that it does not have to be one of our nodes since it is not possible -%% to subscribe to certain node-events. -%% We may very well get state-change events for state-changes we are the source -%% to our selves. Those state-changes are already incorporated into the RTStates. -%% There is however no harm in doing them again since we know that this event -%% message will reach us before a reply to a potentially following state-change -%% request will reach us. Hence we will do all state-changes in the correct order, -%% even if sometimes done twice. -handle_info({trace_event,CtrlPid,_Time,{state_change,Node,{State,Status}}},LD) -> - case get_ctrlpid_ld(LD) of - CtrlPid -> % It is from our control component. - case {State,Status} of - {?TRACING,?RUNNING} -> % This is the only case when new tracerdata! - NewTracerData=add_current_tracerdata_ld(get_ctrlnode_ld(LD), - Node, - get_rtstates_ld(LD), - get_trdstorage_ld(LD)), - NewRTStates=statechange_rtstates(Node,State,Status,get_rtstates_ld(LD)), - {noreply,put_trdstorage_ld(NewTracerData, - put_rtstates_ld(NewRTStates,LD))}; - _ -> % In all other cases, just fix rtstates. - NewRTStates=statechange_rtstates(Node,State,Status,get_rtstates_ld(LD)), - {noreply,put_rtstates_ld(NewRTStates,LD)} - end; - _ -> - {noreply,LD} - end; -%% If a new runtime component connects to our trace control component, and it is -%% in our list of runtime components belonging to this session, we may update its -%% state to now being present. Otherwise it does not belong to this session. -%% Note that we avoid updating an already connected runtime component. This -%% can happend if it connected by itself after we started the session handler, -%% but before we managed to initiate tracing. Doing so or not will not result in -%% any error in the long run, but during a short period of time we might be -%% prevented from doing things with the runtime though it actually is tracing. -handle_info({trace_event,CtrlPid,_Time,{connected,Node,{_Tag,{State,Status}}}},LD) -> - case get_ctrlpid_ld(LD) of - CtrlPid -> % It is from our control component. - case get_statestatus_rtstates(Node,get_rtstates_ld(LD)) of - {ok,unavailable} -> % This is the situation when we update! - NewRTStates=statechange_rtstates(Node,State,Status,get_rtstates_ld(LD)), - {noreply,put_rtstates_ld(NewRTStates,LD)}; - _ -> % In all other cases, let it be. - {noreply,LD} - end; - _ -> % Not from our control component. - {noreply,LD} - end; -%% If a runtime component disconnects we mark it as unavailable. We must also -%% remove all saved trace-flags in order for them to not be accidently reactivated -%% should the runtime component reconnect and then suspend. -handle_info({trace_event,CtrlPid,_Time,{disconnected,Node,_}},LD) -> - case get_ctrlpid_ld(LD) of - CtrlPid -> % It is from our control component. - NewRTStates=set_unavailable_rtstates(Node,get_rtstates_ld(LD)), - NewACTstorage=del_node_actstorage(Node,get_actstorage_ld(LD)), - {noreply,put_actstorage_ld(NewACTstorage,put_rtstates_ld(NewRTStates,LD))}; - _ -> - {noreply,LD} - end; -handle_info(_,LD) -> - {noreply,LD}. -%% ------------------------------------------------------------------------------ - -%% In terminate we cancel our subscription to event from the trace control component. -%% That should actually not be necessary, but lets do it the correct way! -terminate(_,LD) -> - case get_ctrlnode_ld(LD) of - void -> % Non-distributed. - inviso:unsubscribe(); - Node -> - inviso_tool_lib:inviso_cmd(Node,unsubscribe,[]) - end. -%% ------------------------------------------------------------------------------ - - - -%% ============================================================================== -%% First level help functions to call-backs. -%% ============================================================================== - -%% ------------------------------------------------------------------------------ -%% Help functions to init. -%% ------------------------------------------------------------------------------ - -%% Help function which find out the state/status of the runtime components. -%% Note that since we have just started subscribe to state changes we must -%% check our inqueue to see that we have no waiting messages for the nodes -%% we learned the state/status of. If there is a waiting message we don't -%% know whether that was a state change received before or after the state -%% check was done. We will then redo the state-check. -%% Returns {ok,States} or {error,Reason}. -%% Where States is [{Node,{State,Status},Opts},...]. -%% Note that {error,Reason} can not occur in the non-distributed case. -init_rtcomponent_states(NodeParams,void,CtrlPid,Nodes) -> % The non-distributed case. - ok=inviso:subscribe(), - init_rtcomponent_states_2(NodeParams,void,CtrlPid,Nodes,[]); -init_rtcomponent_states(NodeParams,CtrlNode,CtrlPid,Nodes) -> - ok=inviso_tool_lib:inviso_cmd(CtrlNode,subscribe,[]), - init_rtcomponent_states_2(NodeParams,CtrlNode,CtrlPid,Nodes,[]). - -init_rtcomponent_states_2(_,_,_,[],States) -> - {ok,States}; -init_rtcomponent_states_2(NodeParams,void,CtrlPid,_Nodes,States) -> - case inviso:get_status() of - {ok,StateStatus} -> % Got its state/status, now... - {ProblemNodes,NewStates}= - init_rtcomponent_states_3(NodeParams,CtrlPid,[{?LOCAL_RUNTIME,{ok,StateStatus}}], - [],States), - init_rtcomponent_states_2(NodeParams,void,CtrlPid,ProblemNodes,NewStates); - {error,_Reason} -> % The runtime is not available!? - {ok,[{?LOCAL_RUNTIME,unavailable,[]}]} % Create the return value immediately. - end; -init_rtcomponent_states_2(NodeParams,CtrlNode,CtrlPid,Nodes,States) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,get_status,[Nodes]) of - {ok,NodeResult} -> - {ProblemNodes,NewStates}= - init_rtcomponent_states_3(NodeParams,CtrlPid,NodeResult,[],States), - init_rtcomponent_states_2(NodeParams,CtrlNode,CtrlPid,ProblemNodes,NewStates); - {error,Reason} -> % Severe problem, abort the session. - {error,{get_status,Reason}} - end. - -%% Traverses the list of returnvalues and checks that we do not have an event -%% waiting in the message queue. If we do have, it is a problem. That node will -%% be asked about its state again. -%% Note that it is here we construct the RTStatesList. -init_rtcomponent_states_3(NodeParams,CtrlPid,[{Node,{ok,{State,Status}}}|Rest],Problems,States) -> - receive - {trace_event,CtrlPid,_Time,{state_change,Node,_}} -> - init_rtcomponent_states_3(NodeParams,CtrlPid,Rest,[Node|Problems],States) - after - 0 -> % Not in msg queue, then we're safe! - RTState=case lists:keysearch(Node,1,NodeParams) of - {value,{_Node,_TracerData,Opts}} -> - {Node,{State,Status},Opts}; - _ -> % No option available, use []. - {Node,{State,Status},[]} - end, - init_rtcomponent_states_3(NodeParams,CtrlPid,Rest,Problems,[RTState|States]) - end; -init_rtcomponent_states_3(NodeParams,CtrlPid,[{Node,{error,_Reason}}|Rest],Problems,States) -> - RTState=case lists:keysearch(Node,1,NodeParams) of - {value,{_Node,_TracerData,Opts}} -> - {Node,unavailable,Opts}; - _ -> % No option available, use []. - {Node,unavailable,[]} - end, - init_rtcomponent_states_3(NodeParams,CtrlPid,Rest,Problems,[RTState|States]); -init_rtcomponent_states_3(_,_,[],Problems,States) -> - {Problems,States}. -%% ------------------------------------------------------------------------------ - -%% Help function removing nodes from NodeParams. The reason for this can either -%% be that we are using a tool internal tracerdata that shall not be forwarded to -%% the trace control component, or that the node is actually already part of -%% another session. -%% Returns {NewNodeParams,NodesWhichShallNotBeInitiated}. -remove_nodeparams(Nodes,NodesParams) -> - remove_nodeparams_2(Nodes,NodesParams,[],[]). - -remove_nodeparams_2(Nodes,[NodeParam|Rest],NPAcc,NAcc) when % NPAcc=NodeParamsAcc. - (is_tuple(NodeParam) and ((size(NodeParam)==2) or (size(NodeParam)==3))) -> - Node=element(1,NodeParam), - Params=element(2,NodeParam), % This is tracerdata! - case lists:member(Node,Nodes) of - true -> % Remove this one, in another session. - remove_nodeparams_2(Nodes,Rest,NPAcc,NAcc); - false -> % Ok so far... - case is_tool_internal_tracerdata(Params) of - false -> % Then keep it and use it later! - remove_nodeparams_2(Nodes,Rest,[{Node,Params}|NPAcc],NAcc); - true -> % Since it is, remove it from the list. - remove_nodeparams_2(Nodes,Rest,NPAcc,[Node|NAcc]) - end - end; -remove_nodeparams_2(Nodes,[_|Rest],NPAcc,NAcc) -> % Faulty NodeParam, skip it! - remove_nodeparams_2(Nodes,Rest,NPAcc,NAcc); -remove_nodeparams_2(_,[],NPAcc,NAcc) -> - {lists:reverse(NPAcc),NAcc}. -%% ------------------------------------------------------------------------------ - -%% Help function which adds both the nodes which were already part of another -%% session and the nodes that we actually did not issue any init_tracing for. -%% Returns a new Result list of [{Node,NodeResult},...]. -init_fix_resultnodes(NodesOtherSes,NodesNotInit,Result) -> - NewResult=init_fix_resultnodes_2(NodesOtherSes,{error,in_other_session},Result), - init_fix_resultnodes_2(NodesNotInit,ok,NewResult). - -init_fix_resultnodes_2([Node|Rest],NodeResult,Result) -> - [{Node,NodeResult}|init_fix_resultnodes_2(Rest,NodeResult,Result)]; -init_fix_resultnodes_2([],_,Result) -> - Result. % Append Result to the end of the list. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Help functions to reactivate. -%% ------------------------------------------------------------------------------ - -h_reactivate(CtrlNode,Nodes,ACTstorage) -> % Distributed case. - case inviso_tool_lib:inviso_cmd(CtrlNode,cancel_suspension,[Nodes]) of - {ok,CSuspResults} -> - {GoodNodes,BadResults}= % Sort out nodes no longer suspended. - lists:foldl(fun({Node,ok},{GoodNs,BadNs})-> - {[Node|GoodNs],BadNs}; - ({Node,{error,Reason}},{GoodNs,BadNs})-> - {GoodNs,[{Node,{error,{cancel_suspension,Reason}}}|BadNs]} - end, - {[],[]}, - CSuspResults), - Results=h_reactivate_redo_activity(CtrlNode,GoodNodes,ACTstorage,[]), - {ok,BadResults++Results}; - {error,Reason} -> % General failure cancelling suspend. - {error,{cancel_suspension,Reason}} - end. -%% ------------------------------------------------------------------------------ - -%% Help function which traverses the list of nodes known to be ours and have -%% cancelled their suspend. If we fail redoing one of the activities associated -%% with a node, the node will be reported in the return value as failed. From -%% that point on its state must be considered unknown since we do not know how -%% many of the activities were successfully redone. -h_reactivate_redo_activity(CtrlNode,[Node|Rest],ACTstorage,Acc) -> - case get_activities_actstorage(Node,ACTstorage) of - {ok,Activities} -> % The node existed in activity storage. - {Good,Bad}=h_reactivate_redo_activity_2(CtrlNode,Node,Activities,0,0), - h_reactivate_redo_activity(CtrlNode,Rest,ACTstorage,[{Node,{Good,Bad}}|Acc]); - false -> % Node not present in activity storage. - h_reactivate_redo_activity(CtrlNode,Rest,ACTstorage,[{Node,{0,0}}|Acc]) - end; -h_reactivate_redo_activity(_CtrlNode,[],_,Acc) -> - lists:reverse(Acc). - -%% Help function actually redoing the activity. Note that there must be one -%% clause here for every type of activity. -%% Returns {NrGoodCmds,NrBadCmds}. -%% The number of good or bad commands refers to inviso commands done. If any -%% of the subparts of such a command returned an error, the command is concidered -%% no good. -h_reactivate_redo_activity_2(CtrlNode,Node,[{tf,{Op,TraceConfList}}|Rest],Good,Bad) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,Op,[[Node],TraceConfList]) of - {ok,[{_Node,{ok,Answers}}]} -> - case h_reactivate_redo_activity_check_tf(Answers) of - ok -> - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good+1,Bad); - error -> % At least oneReports the first encountered error. - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1) - end; - {ok,[{_Node,{error,_Reason}}]} -> - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1); - {error,_Reason} -> % General error when doing cmd. - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1) - end; -h_reactivate_redo_activity_2(CtrlNode,Node,[{tpm,{Op,InvisoCmdParams}}|Rest],Good,Bad) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,Op,[[Node]|InvisoCmdParams]) of - {ok,[{_Node,ok}]} -> - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good+1,Bad); - {ok,[{_Node,{error,_Reason}}]} -> - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1); - {error,_Reason} -> % General error when doing cmd. - h_reactivate_redo_activity_2(CtrlNode,Node,Rest,Good,Bad+1) - end; -h_reactivate_redo_activity_2(_CtrlNode,_Node,[],Good,Bad) -> - {Good,Bad}. - -%% Help function traversing a list of results from inviso:tf/2 or inviso:ctf/2 -%% to see if there were any errors. -h_reactivate_redo_activity_check_tf([N|Rest]) when integer(N) -> - h_reactivate_redo_activity_check_tf(Rest); -h_reactivate_redo_activity_check_tf([{error,_Reason}|_]) -> - error; -h_reactivate_redo_activity_check_tf([]) -> - ok. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Help functions to tp (setting trace patterns, both local and global). -%% ------------------------------------------------------------------------------ - -%% Help function which handles both tpl and tp. Note that the non-distributed case -%% handled with Nodes='all'. -%% Returns what shall be the reply to the client. -h_tp(all,PatternFunc,Mod,F,A,MS,Opts,LD) -> % All available runtime nodes. - Nodes=get_all_available_nodes_rtstates(get_rtstates_ld(LD)), - h_tp(Nodes,PatternFunc,Mod,F,A,MS,Opts,LD); -h_tp(Nodes,PatternFunc,Mod,F,A,MS,Opts,LD) -> % Only certain nodes in the session. - CtrlNode=get_ctrlnode_ld(LD), - Dbg=get_dbg_ld(LD), - SafetyCatches=get_safetycatches_ld(LD), - case inviso_tool_lib:expand_module_names(Nodes,Mod,Opts) of % Take care of any reg-exps. - {multinode_expansion,NodeMods} -> - NodeTPs=inviso_tool_lib:make_patterns(SafetyCatches,Opts,Dbg,NodeMods,F,A,MS), - h_tp_node_by_node(CtrlNode,PatternFunc,Dbg,NodeTPs,[]); - {singlenode_expansion,Modules} -> - TPs=inviso_tool_lib:make_patterns(SafetyCatches,Opts,Dbg,Modules,F,A,MS), - h_tp_do_tps(CtrlNode,Nodes,TPs,PatternFunc,Dbg); - module -> - TPs=inviso_tool_lib:make_patterns(SafetyCatches,Opts,Dbg,[Mod],F,A,MS), - h_tp_do_tps(CtrlNode,Nodes,TPs,PatternFunc,Dbg); - wildcard -> % Means do for all modules, no safety. - h_tp_do_tps(CtrlNode,Nodes,[{Mod,F,A,MS}],PatternFunc,Dbg); - {error,Reason} -> - {error,Reason} - end. - -%% Note that this function can never be called in the non-distributed case. -h_tp_node_by_node(CtrlNode,PatternFunc,Dbg,[{Node,TPs}|Rest],Accum) -> - case h_tp_do_tps(CtrlNode,[Node],TPs,PatternFunc,Dbg) of - {ok,[{Node,Result}]} -> - h_tp_node_by_node(CtrlNode,PatternFunc,Dbg,Rest,[{Node,Result}|Accum]); - {error,Reason} -> % Failure, but don't stop. - h_tp_node_by_node(CtrlNode,PatternFunc,Dbg,Rest,[{Node,{error,Reason}}|Accum]) - end; -h_tp_node_by_node(_,_,_,[],Accum) -> - {ok,lists:reverse(Accum)}. - -%% Help function which does the actual call to the trace control component. -%% Note that Nodes can be a list of nodes (including a single one) or -%% ?LOCAL_RUNTIME if we are not distributed. The non-distributed case is otherwise -%% detected by the 'void' CtrlNode. -%% Returns {ok,[{Node,{ok,{NrOfFunctions,NrOfErrors}}},{Node,{error,Reason}},...]} or -%% {error,Reason}. In the non-distributed case {ok,{NrOfFunctions,NrOfErros}} or -%% {error,Reason}. -h_tp_do_tps(void,_Nodes,TPs,PatternFunc,Dbg) -> % Non distributed case! - inviso_tool_lib:debug(tp,Dbg,[TPs,PatternFunc]), - case inviso:PatternFunc(TPs) of - {ok,Result} -> % A list of [Nr1,Nr2,error,...]. - {ok, - lists:foldl(fun(N,{AccNr,AccErr}) when integer(N) -> - {AccNr+N,AccErr}; - (error,{AccNr,AccErr}) -> - {AccNr,AccErr+1} - end, - {0,0}, - Result)}; - {error,Reason} -> - {error,{PatternFunc,Reason}} - end; -h_tp_do_tps(CtrlNode,Nodes,TPs,PatternFunc,Dbg) -> - inviso_tool_lib:debug(tp,Dbg,[Nodes,TPs,PatternFunc]), - case inviso_tool_lib:inviso_cmd(CtrlNode,PatternFunc,[Nodes,TPs]) of - {ok,Result} -> % Result is [{Node,Result},...]. - {ok, - lists:map(fun({Node,{ok,Res}})-> - {Node,lists:foldl(fun(N,{ok,{AccNr,AccErr}}) when integer(N) -> - {ok,{AccNr+N,AccErr}}; - (error,{AccNr,AccErr}) -> - {ok,{AccNr,AccErr+1}} - end, - {ok,{0,0}}, - Res)}; - ({_Node,{error,Reason}})-> - {error,Reason} - end, - Result)}; - {error,Reason} -> - {error,{PatternFunc,Reason}} - end. -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Help functions for removing trace-patterns. -%% ------------------------------------------------------------------------------ - -%% NOT IMPLEMENTED YET. -h_ctp(Node,PatternFunc,Mod,F,A,LD) -> - tbd. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Help functions for calling the trace information facility. -%% ------------------------------------------------------------------------------ - - -%% Function handling the meta trace pattern for capturing registration of local -%% process names. -h_tpm_localnames(CtrlNode,Nodes,RTStates,ACTstorage) -> - AvailableNodes=get_all_available_nodes_rtstates(RTStates), - {Nodes3,FaultyNodes}=remove_nodes_not_ours(Nodes,AvailableNodes), - case inviso_tool_lib:inviso_cmd(CtrlNode,tpm_localnames,[Nodes3]) of - {ok,Result} -> % That good we want to modify tpmstorage! - NewACTstorage=add_tpm_actstorage(Result,tpm_localnames,[],ACTstorage), - ErrorResult=lists:map(fun(N)->{N,{error,not_available}} end,FaultyNodes), - {{ok,ErrorResult++Result},NewACTstorage}; - {error,Reason} -> % If general failure, do not modify storage. - {{error,Reason},ACTstorage} - end. -%% ------------------------------------------------------------------------------ - -%% Functions calling meta trace functions for specified nodes. This function is -%% intended for use with all tmp function calls, init_tpm,tpm,tpm_ms,ctpm_ms and -%% ctpm. -%% Note that we must store called meta trace functions and their parameters in the -%% activity storage in order to be able to redo them in case of a reactivate. -h_all_tpm(CtrlNode,Nodes,TpmCmd,InvisoCmdParams,RTStates,ACTstorage) -> - AvailableNodes=get_all_available_nodes_rtstates(RTStates), - {Nodes3,FaultyNodes}=remove_nodes_not_ours(Nodes,AvailableNodes), - case inviso_tool_lib:inviso_cmd(CtrlNode,TpmCmd,[Nodes3|InvisoCmdParams]) of - {ok,Result} -> % That good we want to modify tpmstorage! - NewACTstorage=add_tpm_actstorage(Result,TpmCmd,InvisoCmdParams,ACTstorage), - ErrorResult=lists:map(fun(N)->{N,{error,not_available}} end,FaultyNodes), - {{ok,ErrorResult++Result},NewACTstorage}; - {error,Reason} -> % If general failure, do not modify storage. - {{error,Reason},ACTstorage} - end. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Help functions for set trace flags. -%% ------------------------------------------------------------------------------ - -%% Help function which sets the tracepatterns in TraceConfList for all nodes -%% mentioned in Nodes. Note that non-distributed case is handled with Nodes='all'. -%% Returns {Reply,NewACTstorage} where Reply is whatever shall be returned to caller -%% and NewACTstorage is traceflag storage modified with the flags added to the -%% corresponding nodes. -h_tf(void,_Nodes,TraceConfList,ACTstorage,_RTStates) -> % The non-distributed case. - Reply=inviso:tf(TraceConfList), - NewACTstorage=add_tf_actstorage([{?LOCAL_RUNTIME,Reply}],tf,TraceConfList,ACTstorage), - {Reply,NewACTstorage}; -h_tf(CtrlNode,all,TraceConfList,ACTstorage,RTStates) -> - AllNodes=get_all_session_nodes_rtstates(RTStates), - h_tf(CtrlNode,AllNodes,TraceConfList,ACTstorage,RTStates); -h_tf(CtrlNode,Nodes,TraceConfList,ACTstorage,_RTStates) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,tf,[Nodes,TraceConfList]) of - {ok,Result} -> % That good we want to modify actstorage! - NewACTstorage=add_tf_actstorage(Result,tf,TraceConfList,ACTstorage), - {{ok,Result},NewACTstorage}; - {error,Reason} -> % If general failure, do not modify actstorage. - {{error,Reason},ACTstorage} - end. -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Help functions to stop_session. -%% ------------------------------------------------------------------------------ - -%% This function fetches all local log-files using our stored tracerdata. Note -%% that there are two major ways of tranfering logfiles. Either via distributed -%% Erlang or by common filesystem (like NFS). The default is distributed Erlang. -%% But there may be info in the RTStates structure about a common file-system. -%% Returns {FailedNodes,FetchedFileNames} where FailedNodes is a list of -%% nodenames where problems occurred. Note that problems does not necessarily -%% mean that no files were copied. -%% FetchedFileNames contains one or two of the tuples {trace_log,Files} and/or -%% {ti_log,Files}, listing all files successfully fetched. Note that the -%% list of fetched files contains sublists of filenames. One for each node and -%% tracerdata. -%% In the non-distributed system we always use copy (since the files always -%% resides locally). -transfer_logfiles(RTStates,CtrlNode,Dir,Prefix,TRDstorage,Dbg,AvailableNodes) -> - if - CtrlNode==void -> % When non-distributed, always copy! - fetch_logfiles_copy(CtrlNode,Dir,Prefix,TRDstorage,Dbg,[?LOCAL_RUNTIME]); - true -> % The distributed case. - {FetchNodes,CopyNodes}=find_logfile_transfer_methods(AvailableNodes,RTStates), - {FailedFetchNodes,FetchedFiles}= - case fetch_logfiles_distributed(CtrlNode,Dir,Prefix,TRDstorage,Dbg,FetchNodes) of - {ok,Failed,Files} -> % So far no disasters. - {Failed,Files}; - {error,Reason} -> % Means all fetch-nodes failed! - inviso_tool_lib:debug(transfer_logfiles,Dbg,[FetchNodes,Reason]), - {lists:map(fun(N)->{N,error} end,FetchNodes),[]} - end, - {FailedCopyNodes,CopiedFiles}= - fetch_logfiles_copy(CtrlNode,Dir,Prefix,TRDstorage,Dbg,CopyNodes), - {FailedFetchNodes++FailedCopyNodes,FetchedFiles++CopiedFiles} - end. - -%% Help function which finds out which node we have a common file system with -%% and from which we must make distributed erlang tranfere. -%% Returns {DistributedNodes,CopyNodes} where CopyNode is [{Node,CopyFromDir},...]. -find_logfile_transfer_methods(Nodes,RTStates) -> - find_logfile_transfer_methods_2(Nodes,RTStates,[],[]). - -find_logfile_transfer_methods_2([Node|Rest],RTStates,FetchAcc,CopyAcc) -> - {ok,Opts}=get_opts_rtstates(Node,RTStates), % Node must be in RTStates! - case lists:keysearch(?COPY_LOG_FROM,1,Opts) of - {value,{_,FromDir}} when list(FromDir) -> % Node has common filesystem. - find_logfile_transfer_methods_2(Rest,RTStates,FetchAcc,[{Node,FromDir}|CopyAcc]); - {value,_} -> % Can't understand dir option. - find_logfile_transfer_methods_2(Rest,RTStates,[Node|FetchAcc],CopyAcc); - false -> % Then we want to use fetch instead. - find_logfile_transfer_methods_2(Rest,RTStates,[Node|FetchAcc],CopyAcc) - end; -find_logfile_transfer_methods_2([],_,FetchAcc,CopyAcc) -> - {FetchAcc,CopyAcc}. -%% ------------------------------------------------------------------------------ - -%% Help function which transferes all local logfiles according to the tracerdata -%% stored for the nodes in Nodes. -%% Returns {ok,FailedNodes,FileNodeSpecs} or {error,Reason}. -%% FailedNodes is a list of nodes where fetching logs did not succeed, partially -%% or not at all. -%% FileNames is a list of list of actually fetched files (the name as it is here, including -%% Dir). The sublists are files which belong together. -fetch_logfiles_distributed(CtrlNode,Dir,Prefix,TRDstorage,Dbg,Nodes) -> - LogSpecList=build_logspeclist(Nodes,TRDstorage), - case inviso_fetch_log(inviso_tool_lib:inviso_cmd(CtrlNode, - fetch_log, - [LogSpecList,Dir,Prefix])) of - {ok,Result} -> - Files=get_all_filenames_fetchlog_result(Result,Dbg), - FailedNodes=get_all_failednodes_fetchlog_result(Result), - {ok,FailedNodes,Files}; - {error,Reason} -> % Some general failure! - {error,{fetch_log,Reason}} - end. - -%% Help function which constructs a list {Node,TracerData} for all nodes in Nodes. -%% Note that there may be more than one tracerdata for a node, resulting in multiple -%% tuples for that node. -build_logspeclist(Nodes,TRDstorage) -> - build_logspeclist_2(Nodes,TRDstorage,[]). - -build_logspeclist_2([Node|Rest],TRDstorage,Acc) -> - TRDlist=find_tracerdata_for_node_trd(Node,TRDstorage), % A list of all tracerdata. - build_logspeclist_2(Rest, - TRDstorage, - [lists:map(fun(TRD)->{Node,TRD} end,TRDlist)|Acc]); -build_logspeclist_2([],_,Acc) -> - lists:flatten(Acc). - -%% Help function which translates inviso:fetch_log return values to what I -%% want! -inviso_fetch_log({error,Reason}) -> - {error,Reason}; -inviso_fetch_log({_Success,ResultList}) -> - {ok,ResultList}. - -%% Help function which collects all filenames mentioned in a noderesult structure. -%% The files may or may not be complete. -%% Returns a list of list of filenames. Each sublist contains files which belong -%% together, i.e because they are a wrap-set. -get_all_filenames_fetchlog_result(NodeResult,Dbg) -> - get_all_filenames_fetchlog_result_2(NodeResult,Dbg,[]). - -get_all_filenames_fetchlog_result_2([{Node,{Success,FileInfo}}|Rest],Dbg,Accum) - when Success=/=error, list(FileInfo) -> - SubAccum=get_all_filenames_fetchlog_result_3(FileInfo,[]), - get_all_filenames_fetchlog_result_2(Rest,Dbg,[{Node,SubAccum}|Accum]); -get_all_filenames_fetchlog_result_2([{Node,{error,FReason}}|Rest],Dbg,Accum) -> - inviso_tool_lib:debug(fetch_files,Dbg,[Node,FReason]), - get_all_filenames_fetchlog_result_2(Rest,Dbg,Accum); -get_all_filenames_fetchlog_result_2([],_Dbg,Accum) -> - Accum. - -get_all_filenames_fetchlog_result_3([{FType,Files}|Rest],SubAccum) -> - FilesOnly=lists:foldl(fun({ok,FName},Acc)->[FName|Acc];(_,Acc)->Acc end,[],Files), - get_all_filenames_fetchlog_result_3(Rest,[{FType,FilesOnly}|SubAccum]); -get_all_filenames_fetchlog_result_3([],SubAccum) -> - SubAccum. - -%% Help function which traverses a noderesult and builds a list as return -%% value containing the nodenames of all nodes not being complete. -%% Note that a node may occur multiple times since may have fetched logfiles -%% for several tracerdata from the same node. Makes sure the list contains -%% unique node names. -%% Returns a list nodes. -get_all_failednodes_fetchlog_result(NodeResult) -> - get_all_failednodes_fetchlog_result_2(NodeResult,[]). - -get_all_failednodes_fetchlog_result_2([{_Node,{complete,_}}|Rest],Acc) -> - get_all_failednodes_fetchlog_result_2(Rest,Acc); -get_all_failednodes_fetchlog_result_2([{Node,{_Severity,_}}|Rest],Acc) -> - case lists:member(Node,Acc) of - true -> % Already in the list. - get_all_failednodes_fetchlog_result_2(Rest,Acc); - false -> % Not in Acc, add it! - get_all_failednodes_fetchlog_result_2(Rest,[Node|Acc]) - end; -get_all_failednodes_fetchlog_result_2([],Acc) -> - Acc. -%% ------------------------------------------------------------------------------ - -%% Help function which copies files from one location to Dir and at the same time -%% adds the Prefix to the filename. NodeSpecs contains full path to the files. The -%% reason the node information is still part of NodeSpecs is that otherwise we can -%% not report faulty nodes. Note that one node may occur multiple times since there -%% may be more than one tracerdata for a node. -%% Returns {FailedNodes,Files} where FailedNodes is a list of nodes where problems -%% occurred. Files is a tuple list of [{Node,[{FType,FileNames},...]},...]. -fetch_logfiles_copy(CtrlNode,Dir,Prefix,TRDstorage,Dbg,NodeSpecs) -> - CopySpecList=build_copylist(CtrlNode,Dbg,NodeSpecs,TRDstorage), - fetch_logfiles_copy_2(Dir,Prefix,Dbg,CopySpecList,[],[]). - -fetch_logfiles_copy_2(Dir,Prefix,Dbg,[{Node,CopySpecs}|Rest],FailedNodes,Files) -> - case fetch_logfiles_copy_3(Dir,Prefix,Dbg,CopySpecs,[],0) of - {0,LocalFiles} -> % Copy went ok and zero errors. - fetch_logfiles_copy_2(Dir,Prefix,Dbg,Rest,FailedNodes,[{Node,LocalFiles}|Files]); - {_N,LocalFiles} -> % Copied files, but some went wrong. - case lists:member(Node,FailedNodes) of - true -> % Node already in FailedNodes. - fetch_logfiles_copy_2(Dir,Prefix,Dbg,Rest,FailedNodes, - [{Node,LocalFiles}|Files]); - false -> % Node not marked as failed, yet. - fetch_logfiles_copy_2(Dir,Prefix,Dbg,Rest,[Node|FailedNodes], - [{Node,LocalFiles}|Files]) - end - end; -fetch_logfiles_copy_2(_,_,_,[],FailedNodes,Files) -> - {FailedNodes,Files}. % The return value from fetch_logfiles_copy. - -fetch_logfiles_copy_3(Dir,Prefix,Dbg,[{FType,RemoteFiles}|Rest],Results,Errors) -> - {Err,LocalFiles}=fetch_logfiles_copy_3_1(Dir,Prefix,Dbg,RemoteFiles,[],0), - fetch_logfiles_copy_3(Dir,Prefix,Dbg,Rest,[{FType,LocalFiles}|Results],Errors+Err); -fetch_logfiles_copy_3(_,_,_,[],Results,Errors) -> - {Errors,Results}. - -%% For each file of one file-type (e.g. trace_log). -fetch_logfiles_copy_3_1(Dir,Prefix,Dbg,[File|Rest],LocalFiles,Errors) -> - DestName=Prefix++filename:basename(File), - Destination=filename:join(Dir,DestName), - case do_copy_file(File,Destination) of - ok -> - fetch_logfiles_copy_3_1(Dir,Prefix,Dbg,Rest,[DestName|LocalFiles],Errors); - {error,Reason} -> - inviso_tool_lib:debug(copy_files,Dbg,[File,Destination,Reason]), - fetch_logfiles_copy_3_1(Dir,Prefix,Dbg,Rest,LocalFiles,Errors+1) - end; -fetch_logfiles_copy_3_1(_,_,_,[],LocalFiles,Errors) -> - {Errors,LocalFiles}. - -%% Help function which builds a [{Node,[{Type,[ListOfRemoteFiles]}},...}] -%% where Type describes trace_log or ti_log and each entry in ListOfRemoteFiles -%% is a complete path to a file to be copied. -build_copylist(CtrlNode,Dbg,NodeSpecList,TRDstorage) -> - build_copylist_2(CtrlNode,Dbg,NodeSpecList,TRDstorage,[]). - -%% For each node specified in the NodeSpecList. -build_copylist_2(CtrlNode,Dbg,[{Node,SourceDir}|Rest],TRDstorage,Acc) -> - TRDlist=find_tracerdata_for_node_trd(Node,TRDstorage), - CopySpecList=build_copylist_3(CtrlNode,Dbg,SourceDir,Node,TRDlist), - build_copylist_2(CtrlNode,Dbg,Rest,TRDstorage,[CopySpecList|Acc]); -build_copylist_2(_,_,[],_,Acc) -> - lists:flatten(Acc). - -%% For each tracerdata found for the node. -build_copylist_3(void,Dbg,SourceDir,Node,[TRD|Rest]) -> % The non-distributed case. - case inviso:list_logs(TRD) of - {ok,FileSpec} when list(FileSpec) -> % [{trace_log,Dir,Files},...] - NewFileSpec=build_copylist_4(SourceDir,FileSpec,[]), - [{Node,NewFileSpec}|build_copylist_3(void,Dbg,SourceDir,Node,Rest)]; - {ok,no_log} -> % This tracedata not associated with any log. - build_copylist_3(void,Dbg,SourceDir,Node,Rest); - {error,Reason} -> - inviso_tool_lib:debug(list_logs,Dbg,[Node,TRD,Reason]), - build_copylist_3(void,Dbg,SourceDir,Node,Rest) - end; -build_copylist_3(CtrlNode,Dbg,SourceDir,Node,[TRD|Rest]) -> % The distributed case. - case inviso_tool_lib:inviso_cmd(CtrlNode,list_logs,[[{Node,TRD}]]) of - {ok,[{Node,{ok,FileSpec}}]} when list(FileSpec) -> - NewFileSpec=build_copylist_4(SourceDir,FileSpec,[]), - [{Node,NewFileSpec}|build_copylist_3(CtrlNode,Dbg,SourceDir,Node,Rest)]; - {ok,[{Node,{ok,no_log}}]} -> % It relays to another node, no files! - build_copylist_3(CtrlNode,Dbg,SourceDir,Node,Rest); - {ok,[{Node,{error,Reason}}]} -> - inviso_tool_lib:debug(list_logs,Dbg,[Node,TRD,Reason]), - build_copylist_3(CtrlNode,Dbg,SourceDir,Node,Rest); - {error,Reason} -> % Some general failure. - inviso_tool_lib:debug(list_logs,Dbg,[Node,TRD,Reason]), - build_copylist_3(CtrlNode,Dbg,SourceDir,Node,Rest) - end; -build_copylist_3(_,_,_,_,[]) -> - []. - -%% Help function which makes a [{Type,Files},...] list where each file in Files -%% is with full path as found from our file-system. -build_copylist_4(SourceDir,[{Type,_Dir,Files}|Rest],Accum) -> - NewFiles= - lists:foldl(fun(FName,LocalAcc)->[filename:join(SourceDir,FName)|LocalAcc] end, - [], - Files), - build_copylist_4(SourceDir,Rest,[{Type,NewFiles}|Accum]); -build_copylist_4(_,[],Accum) -> - Accum. - - -%% Help function which copies a file using os:cmd. -%% Returns 'ok' or {error,Reason}. -do_copy_file(Source,Destination) -> - case os:type() of - {win32,_} -> - os:cmd("copy "++Source++" "++Destination), % Perhaps a test on success? - ok; - {unix,_} -> - os:cmd("cp "++Source++" "++Destination), % Perhaps a test on success? - ok - end. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ - -%% ============================================================================== -%% Various help functions. -%% ============================================================================== - -%% Help function going through the Nodes list and checking that only nodes -%% mentioned in OurNodes gets returned. It also makes the nodes in the return -%% value unique. -remove_nodes_not_ours(Nodes,OurNodes) -> - remove_nodes_not_ours_2(Nodes,OurNodes,[],[]). - -remove_nodes_not_ours_2([Node|Rest],OurNodes,OurAcc,OtherAcc) -> - case lists:member(Node,OurNodes) of - true -> % Ok it is one of our nodes. - case lists:member(Node,OurAcc) of - true -> % Already in the list, skip. - remove_nodes_not_ours_2(Rest,OurNodes,OurAcc,OtherAcc); - false -> - remove_nodes_not_ours_2(Rest,OurNodes,[Node|OurAcc],OtherAcc) - end; - false -> - case lists:member(Node,OtherAcc) of - true -> - remove_nodes_not_ours_2(Rest,OurNodes,OurAcc,OtherAcc); - false -> - remove_nodes_not_ours_2(Rest,OurNodes,OurAcc,[Node|OtherAcc]) - end - end; -remove_nodes_not_ours_2([],_,OurAcc,OtherAcc) -> - {lists:reverse(OurAcc),lists:reverse(OtherAcc)}. -%% ------------------------------------------------------------------------------ - -%% Help function which returns 'true' or 'false' depending on if TracerData is -%% meant to be used by the session handler (true) or if it supposed to be passed -%% on to the trace system. -is_tool_internal_tracerdata(_) -> % CURRENTLY NO INTERNAL TRACER DATA! - false. -%% ------------------------------------------------------------------------------ - -%% Help function which checks that all nodes in the first list of nodes exists -%% in the second list of nodes. Returns 'true' or 'false'. The latter if as much -%% as one incorrect node was found. -check_our_nodes([Node|Rest],AllNodes) -> - case lists:member(Node,AllNodes) of - true -> - check_our_nodes(Rest,AllNodes); - false -> % Then we can stop right here. - false - end; -check_our_nodes([],_) -> - true. -%% ------------------------------------------------------------------------------ - -%% Help function which checks that a directory actually exists. Returns 'true' or -%% 'false'. -check_directory_exists(Dir) -> - case file:read_file_info(Dir) of - {ok,#file_info{type=directory}} -> - true; - _ -> % In all other cases it is not valid. - false - end. -%% ------------------------------------------------------------------------------ - -%% This function stops the tracing on all nodes in Nodes. Preferably Nodes is a list -%% of only tracing runtime components. Not that there will actually be any difference -%% since the return value does not reflect how stopping the nodes went. -%% Returns 'ok' or {error,Reason}, the latter only in case of general failure. -stop_all_tracing(void,Dbg,[?LOCAL_RUNTIME]) -> % The non-distributed case, and is tracing. - case inviso:stop_tracing() of - {ok,_State} -> - ok; - {error,Reason} -> % We actually don't care. - inviso_tool_lib:debug(stop_tracing,Dbg,[?LOCAL_RUNTIME,Reason]), - ok - end; -stop_all_tracing(void,_,_) -> % There is no local runtime started. - ok; -stop_all_tracing(CtrlNode,Dbg,Nodes) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,stop_tracing,[Nodes]) of - {ok,Result} -> % The result is only used for debug. - Failed=lists:foldl(fun({N,{error,Reason}},Acc)->[{N,{error,Reason}}|Acc]; - (_,Acc)->Acc - end, - [], - Result), - if - Failed==[] -> - ok; - true -> - inviso_tool_lib:debug(stop_tracing,Dbg,[Nodes,Failed]), - ok - end; - {error,Reason} -> - {error,{stop_tracing,Reason}} - end. -%% ------------------------------------------------------------------------------ - -%% Help function removing all local logs using the tracerdata to determine what -%% logs to remove from where. -%% There is no significant return value since it is not really clear what to do -%% if removal went wrong. The function can make debug-reports thought. -remove_all_local_logs(CtrlNode,TRDstorage,Nodes,Dbg) -> - LogSpecList=build_logspeclist_remove_logs(Nodes,TRDstorage), - case inviso_tool_lib:inviso_cmd(CtrlNode,delete_log,[LogSpecList]) of - {ok,Results} -> - case look_for_errors_resultlist(Results) of - [] -> % No errors found in the result! - true; - Errors -> - inviso_tool_lib:debug(remove_all_local_logs,Dbg,[Errors]), - true - end; - {error,Reason} -> % Some general error. - inviso_tool_lib:debug(remove_all_local_logs,Dbg,[{error,Reason}]), - true - end. - -%% Help function which puts together a list of {Node,Tracerdata} tuples. Note that -%% we must build one tuple for each tracerdata for one node. -build_logspeclist_remove_logs(Nodes,TRDstorage) -> - [{Node,TracerData}||Node<-Nodes,TracerData<-find_tracerdata_for_node_trd(Node,TRDstorage)]. -%% ------------------------------------------------------------------------------ - -%% Help function which traverses a resultlist from an inviso function. Such are -%% built up as [{Node,SubResults},...] where SubResult is a list of tuples for each -%% file-type (e.g trace_log) {FType,FileList} where a FileList is either {error,Reason} -%% or {ok,FileName}. -%% Returns a list of {Node,[{error,Reason},...]}. -look_for_errors_resultlist([{Node,{error,Reason}}|Rest]) -> - [{Node,{error,Reason}}|look_for_errors_resultlist(Rest)]; -look_for_errors_resultlist([{Node,{ok,NResults}}|Rest]) when list(NResults) -> - case look_for_errors_resultlist_2(NResults,[]) of - [] -> - look_for_errors_resultlist(Rest); - Errors -> % A list of lists. - [{Node,lists:flatten(Errors)}|look_for_errors_resultlist(Rest)] - end; -look_for_errors_resultlist([_|Rest]) -> - look_for_errors_resultlist(Rest); -look_for_errors_resultlist([]) -> - []. - -look_for_errors_resultlist_2([{_FType,NSubResult}|Rest],Accum) -> - case lists:filter(fun({error,_Reason})->true;(_)->false end,NSubResult) of - [] -> % No errors for this node. - look_for_errors_resultlist_2(Rest,Accum); - Errors -> % A list of at least one error. - look_for_errors_resultlist_2(Rest,[Errors|Accum]) - end; -look_for_errors_resultlist_2([],Accum) -> - Accum. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Functions working on the loopdata structure. -%% Its main purpose is to store information about runtime components participating -%% in the session and their current status. -%% ------------------------------------------------------------------------------ - --record(ld,{parent, - ctrlnode, - ctrlpid, % To where to send inviso cmd. - rtstates, - tracerdata, - safetycatches, - dbg, - actstorage % Activity storage, for reactivate. - }). - -%% Function creating the initial datastructure. -%% The datastructure is [{Node,State},...]. -%% -%% The tracerdata table is a bag simply for the reason that if we try to insert -%% the same tracerdata for a node twice, we will end up with one tracerdata after -%% all. This is useful when we insert tracerdata ourselves, the tracerdata will -%% come as a state-change too. -mk_ld(Parent,CtrlNode,CtrlPid,RTStates,NodeParams,OtherNodes,SafetyCatches,Dbg) -> - TRDtableName=list_to_atom("inviso_tool_sh_trdstorage_"++pid_to_list(self())), - TRDtid=ets:new(TRDtableName,[bag]), - ACTtableName=list_to_atom("inviso_tool_sh_actstorage_"++pid_to_list(self())), - ACTtid=ets:new(ACTtableName,[bag]), - mk_ld_fill_tracerdata(CtrlNode,TRDtid,NodeParams,OtherNodes), % Fill the ETS table. - #ld{parent=Parent, % The tool main process. - ctrlnode=CtrlNode, % Node name where the control component is. - ctrlpid=CtrlPid, % The process id of the control component. - rtstates=RTStates, % All nodes and their state/status. - tracerdata=TRDtid, - safetycatches=SafetyCatches, - dbg=Dbg, - actstorage=ACTtid - }. - -%% Help function which inserts tracer data for the nodes. Note that we can get -%% tracer data either from the return value from init_tracing or by asking the -%% node for it. The latter is necessary for the nodes which were marked not to -%% be initiated by the session handler. This maybe because those nodes have -%% autostarted. -mk_ld_fill_tracerdata(CtrlNode,TId,NodeParams,OtherNodes) -> - mk_ld_fill_tracerdata_nodeparams(TId,NodeParams), - mk_ld_fill_tracerdata_othernodes(CtrlNode,TId,OtherNodes). - -mk_ld_fill_tracerdata_nodeparams(TId,[{Node,TracerData}|Rest]) -> - ets:insert(TId,{Node,TracerData}), - mk_ld_fill_tracerdata_nodeparams(TId,Rest); -mk_ld_fill_tracerdata_nodeparams(_,[]) -> - ok. - -mk_ld_fill_tracerdata_othernodes(_,_,[]) -> % Then not necessary to do anything. - ok; -mk_ld_fill_tracerdata_othernodes(void,TId,[Node]) -> % The non-distributed case. - case inviso:get_tracerdata() of - {error,_Reason} -> % Perhaps in state new or disconnected. - ok; % Do nothing. - {ok,TracerData} -> - ets:insert(TId,{Node,TracerData}) - end; -mk_ld_fill_tracerdata_othernodes(CtrlNode,TId,Nodes) -> - case inviso_tool_lib:invisomd(CtrlNode,get_tracerdata,[Nodes]) of - {ok,Results} -> - mk_ld_fill_tracerdata_othernodes_2(TId,Results); - {error,_Reason} -> % Strange, we will probably crash later. - ok - end. - -mk_ld_fill_tracerdata_othernodes_2(TId,[{_Node,{ok,no_tracerdata}}|Rest]) -> - mk_ld_fill_tracerdata_othernodes_2(TId,Rest); % It was not initiated then! -mk_ld_fill_tracerdata_othernodes_2(TId,[{Node,{ok,TracerData}}|Rest]) -> - ets:insert(TId,{Node,TracerData}), - mk_ld_fill_tracerdata_othernodes_2(TId,Rest); -mk_ld_fill_tracerdata_othernodes_2(_,[]) -> - ok. -%% ------------------------------------------------------------------------------ - -get_ctrlnode_ld(#ld{ctrlnode=CtrlNode}) -> - CtrlNode. -%% ------------------------------------------------------------------------------ - - -get_ctrlpid_ld(#ld{ctrlpid=CtrlPid}) -> - CtrlPid. -%% ------------------------------------------------------------------------------ - -get_rtstates_ld(#ld{rtstates=RTStates}) -> - RTStates. - -put_rtstates_ld(NewRTStates,LD) -> - LD#ld{rtstates=NewRTStates}. -%% ------------------------------------------------------------------------------ - -get_trdstorage_ld(#ld{tracerdata=TId}) -> - TId. - -put_trdstorage_ld(_NewTId,LD) -> - LD. -%% ------------------------------------------------------------------------------ - -%% Help function which adds the current tracerdata of node Node to the tracerdata -%% storage. We only want to add tracerdata we have not seen before. We therefore -%% avoid adding it if the node already is in state ?TRACING. -%% Returns a new tracerdata (what ever it is)! -add_current_tracerdata_ld(CtrlNode,Node,RTStates,TId) -> - case get_statestatus_rtstates(Node,RTStates) of - {ok,{?TRACING,_}} -> % Then we have already added the tracerdata. - TId; % Then do nothing. - {ok,_} -> % Since we were not tracing before. - case add_current_tracerdata_ld_fetchtracerdata(CtrlNode,Node) of - {ok,TracerData} -> - ets:insert(TId,{Node,TracerData}); - no_tracerdata -> % Strange, how could we become tracing - ok; - {error,_Reason} -> % The node perhaps disconnected!? - ok - end; - false -> % Very strange, not our node! - ok % Do nothing. - end. - -add_current_tracerdata_ld_fetchtracerdata(void,_Node) -> - case inviso:get_tracerdata() of - {ok,TracerData} -> - {ok,TracerData}; - {error,no_tracerdata} -> - no_tracerdata; - {error,Reason} -> - {error,Reason} - end; -add_current_tracerdata_ld_fetchtracerdata(CtrlNode,Node) -> - case inviso_tool_lib:inviso_cmd(CtrlNode,get_tracerdata,[[Node]]) of - {ok,[{Node,{ok,TracerData}}]} -> - {ok,TracerData}; - {ok,[{Node,{error,no_tracerdata}}]} -> - no_tracerdata; - {ok,[{Node,{error,Reason}}]} -> - {error,Reason}; - {error,Reason} -> - {error,Reason} - end. -%% ------------------------------------------------------------------------------ - - -get_safetycatches_ld(#ld{safetycatches=SCs}) -> - SCs. -%% ------------------------------------------------------------------------------ - -get_dbg_ld(#ld{dbg=Dbg}) -> - Dbg. -%% ------------------------------------------------------------------------------ - -get_actstorage_ld(#ld{actstorage=ACTstorage}) -> - ACTstorage. - -put_actstorage_ld(_NewACTstorage,LD) -> - LD. -%% ------------------------------------------------------------------------------ - - - -%% ------------------------------------------------------------------------------ -%% Functions working on the rtstates structure (which is a substructure of loopdata). -%% It is either: -%% [{Node,StateStatus,Opts},...] -%% Node is either the node name of the runtime component erlang node or -%% ?LOCAL_RUNTIME as returned from the trace control component. -%% StateStatus is {State,Status}, 'unavailable' or 'unknown'. -%% Status is the returnvalue from trace control component. -%% i.e: running | {suspended,Reason} -%% ------------------------------------------------------------------------------ - -%% Function contructing an rtstates structure from a list of [{Node,StateStatus,Opts},...]. -to_rtstates(ListOfStates) when list(ListOfStates) -> - ListOfStates. -%% ------------------------------------------------------------------------------ - -%% Function which takes a rtstates structure and returns a list of [{Node,StateStatus},...]. -from_rtstates(RTStates) -> - RTStates. -%% ------------------------------------------------------------------------------ - -%% Function which takes an rtstates structure and a result as returned from -%% init_tracing. The RTStates is modified for the nodes that changed state as a -%% result of successful init_tracing. -%% Returns a new RTStates. -set_tracing_rtstates([E={Node,_StateStatus,Opts}|Rest],Result) -> - case lists:keysearch(Node,1,Result) of - {value,{_,ok}} -> % Means state-change to tracing! - [{Node,{tracing,running},Opts}|set_tracing_rtstates(Rest,Result)]; - _ -> % Otherwise, leave it as is. - [E|set_tracing_rtstates(Rest,Result)] - end; -set_tracing_rtstates([],_Result) -> - []. -%% ------------------------------------------------------------------------------ - -%% Function updating the state/status for a certain runtime component. -%% Returns a new RTStates structure. Note that Node must not necessarily be one -%% of the nodes in the session. Meaning that Node shall not be added to RTStates -%% should it not already be in there. -statechange_rtstates(Node,State,Status,RTStates) when list(RTStates) -> - case lists:keysearch(Node,1,RTStates) of - {value,{_,_,Opts}} -> - lists:keyreplace(Node,1,RTStates,{Node,{State,Status},Opts}); - _ -> % Then Node does not exist. - RTStates % Just keep it as is, as keyreplace would have done. - end. -%% ------------------------------------------------------------------------------ - -%% Function updating the state/status for a certain runtime component. The -%% state/status is set to 'unavailable'. -%% Returns a new RTStates structure. -set_unavailable_rtstates(Node,RTStates) when list(RTStates) -> - case lists:keysearch(Node,1,RTStates) of - {value,{_,_,Opts}} -> - lists:keyreplace(Node,1,RTStates,{Node,unavailable,Opts}); - _ -> % Then Node does not exist. - RTStates % Just keep it as is, as keyreplace would have done. - end. -%% ------------------------------------------------------------------------------ - -%% Function finding the statestatus associated with Node in the RTStates structure. -%% Returns {ok,StateStatus} or 'false'. -get_statestatus_rtstates(Node,RTStates) -> - case lists:keysearch(Node,1,RTStates) of - {value,{_,StateStatus,_}} -> - {ok,StateStatus}; - false -> - false - end. -%% ------------------------------------------------------------------------------ - -%% Help function which returns a list of all nodes that are currently marked -%% as available to us in the runtime state structure. -get_all_available_nodes_rtstates(RTStates) -> - get_all_session_nodes_rtstates(lists:filter(fun({_N,unavailable,_})->false; - (_)->true - end, - RTStates)). -%% ------------------------------------------------------------------------------ - -%% Help function returning a list of all nodes belonging to this session. -get_all_session_nodes_rtstates(RTStates) -> - lists:map(fun({Node,_,_})->Node end,RTStates). -%% ------------------------------------------------------------------------------ - -%% Function which returns a list of nodes that are indicated as tracing in the -%% RTStates structure. -get_all_tracing_nodes_rtstates(RTStates) -> - lists:map(fun({N,_,_})->N end, - lists:filter(fun({_,{tracing,_},_})->true;(_)->false end,RTStates)). -%% ------------------------------------------------------------------------------ - -%% Returns the options associated with Node in the RTStates structure. -get_opts_rtstates(Node,RTStates) -> - case lists:keysearch(Node,1,RTStates) of - {value,{_,_,Opts}} -> - {ok,Opts}; - false -> - false - end. - -%% ------------------------------------------------------------------------------ -%% Functions working on the tracerdata structure, which is a part of the loopdata. -%% The tracerdata structure is an ETS-table of type bag storing: -%% {Node,TracerData}. -%% Note that there can of course be multiple entries for a node. -%% ------------------------------------------------------------------------------ - -%% Help function which takes a tracerdata loopdata structure and returns a list -%% of all stored tracerdata for a certain Node. -find_tracerdata_for_node_trd(Node,TRD) -> - case ets:lookup(TRD,Node) of - Result when list(Result) -> - lists:map(fun({_Node,TracerData})->TracerData end,Result); - _ -> % Should probably never happend. - [] - end. -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Functions working on the activity storage structure, which is part of the -%% loopdata. It stores entries about things that needs to be "redone" in case -%% of a reactivation of the node. The time order is also important. -%% Note that for every ActivityType there must be a "handler" in the reactivation -%% functionality. -%% -%% The structure is a bag of {Node,ActivityType,What}. -%% ActivityType/What=tf/{Op,TraceConfList}|tpm/{Op,[Mod,Func,Arity,MS,CallFunc]} -%% /{Op,[Mod,Func,Arity,MS,CallFunc,ReturnFunc]} -%% /{Op,[]} -%% TraceConfList=[{Proc,Flags},...] -%% How=true|false -%% ------------------------------------------------------------------------------ - -%% Function that adds meta-pattern activities to the activity storage. Note -%% that one of the parameters to the function is a return value from an -%% inviso call. In that way we do not enter activities that were unsuccessful. -%% Op can be either the setting or clearing of a meta pattern. -%% Returns a new ACTstorage. -add_tpm_actstorage([{Node,ok}|Rest],Op,InvisoCmdParams,ACTstorage) -> - true=ets:insert(ACTstorage,{Node,tpm,{Op,InvisoCmdParams}}), - add_tpm_actstorage(Rest,Op,InvisoCmdParams,ACTstorage); -add_tpm_actstorage([_|Rest],Op,InvisoCmdParams,ACTstorage) -> - add_tpm_actstorage(Rest,Op,InvisoCmdParams,ACTstorage); -add_tpm_actstorage([],_,_,ACTstorage) -> - ACTstorage. - -%% Function that adds process trace-flags to the activity storage. Note that one -%% of the parameters is the return value from an inviso function. Meaning that -%% if the flags failed in their entirety, no activity will be saved. If only -%% some of the flags failed, we will not go through the effort of trying to find -%% out exactly which. -%% Returns a new activity storage structure. -add_tf_actstorage([{_Node,{error,_Reason}}|Rest],Op,TraceConfList,ACTstorage) -> - add_tf_actstorage(Rest,Op,TraceConfList,ACTstorage); -add_tf_actstorage([{Node,_Result}|Rest],Op,TraceConfList,ACTstorage) -> - true=ets:insert(ACTstorage,{Node,tf,{Op,TraceConfList}}), - add_tf_actstorage(Rest,Op,TraceConfList,ACTstorage); -add_tf_actstorage([],_,_,ACTstorage) -> - ACTstorage. -%% ------------------------------------------------------------------------------ - -%% Finds all activities associated with Node. Returns a list of them in the -%% same order as they were inserted. -get_activities_actstorage(Node,ACTstorage) -> - case ets:lookup(ACTstorage,Node) of - [] -> - false; - Result when list(Result) -> - {ok,lists:map(fun({_N,Type,What})->{Type,What} end,Result)} - end. -%% ------------------------------------------------------------------------------ - -%% Function removing all activity entries associated with Node. This is useful -%% if the Node disconnects for instance. -del_node_actstorage(Node,ACTstorage) -> - ets:delete(ACTstorage,Node), - ACTstorage. -%% ------------------------------------------------------------------------------ - diff --git a/lib/inviso/test/Makefile b/lib/inviso/test/Makefile deleted file mode 100644 index 2650faa392..0000000000 --- a/lib/inviso/test/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -MODULES = \ - inviso_tool_SUITE - -ERL_FILES= $(MODULES:%=%.erl) - -TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) -INSTALL_PROGS= $(TARGET_FILES) - -EMAKEFILE=Emakefile - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/inviso_test - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_MAKE_FLAGS += -ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include - -EBIN = . - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -make_emakefile: - $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ - > $(EMAKEFILE) - -tests debug opt: make_emakefile - erl $(ERL_MAKE_FLAGS) -make - -clean: - rm -f $(EMAKEFILE) - rm -f $(TARGET_FILES) - rm -f core - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - -release_tests_spec: make_emakefile - $(INSTALL_DIR) "$(RELSYSDIR)" - $(INSTALL_DATA) inviso.spec inviso.cover $(ERL_FILES) "$(RELSYSDIR)" - chmod -R u+w "$(RELSYSDIR)" - @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) - -release_docs_spec: - - diff --git a/lib/inviso/test/inviso.cover b/lib/inviso/test/inviso.cover deleted file mode 100644 index e23b9fa59b..0000000000 --- a/lib/inviso/test/inviso.cover +++ /dev/null @@ -1,2 +0,0 @@ -{incl_app,inviso,details}. - diff --git a/lib/inviso/test/inviso.spec b/lib/inviso/test/inviso.spec deleted file mode 100644 index 49f9b0b460..0000000000 --- a/lib/inviso/test/inviso.spec +++ /dev/null @@ -1 +0,0 @@ -{suites,"../inviso_test",all}. diff --git a/lib/inviso/test/inviso_tool_SUITE.erl b/lib/inviso/test/inviso_tool_SUITE.erl deleted file mode 100644 index e14f32de44..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE.erl +++ /dev/null @@ -1,1166 +0,0 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%% Description:
-%% Test suite for the inviso_tool. It is here assumed that inviso works
-%% properly.
-%%
-%% Authors:
-%% Lennart Öhman, [email protected]
-%% -----------------------------------------------------------------------------
-
--module(inviso_tool_SUITE).
--compile(export_all).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("kernel/include/file.hrl").
-
--define(l,?line).
-
-suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [dist_basic_1, dist_rtc, dist_reconnect, dist_adopt, - dist_history, dist_start_session_special]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%% -----------------------------------------------------------------------------
-
-init_per_suite(Config) ->
- case test_server:is_native(lists) of - true -> - {skip,"Native libs -- tracing doesn't work"}; - false -> - Config - end. -%% -----------------------------------------------------------------------------
-
-end_per_suite(_Config) ->
- ok.
-%% -----------------------------------------------------------------------------
-
-%% For each distributed testcase, we need two other distributed nodes to run the
-%% runtime components on. Since they are freshly started every time there is no
-%% need to clean them up first.
-init_per_testcase(_Case,Config) ->
- ?l TH=test_server:timetrap(100000),
- ?l {ok,Node1}=test_server:start_node(inviso1,peer,[]),
- ?l {ok,Node2}=test_server:start_node(inviso2,peer,[]),
- ?l SuiteDir=filename:dirname(code:which(?MODULE)),
-
- %% Otherwise peer nodes will not find this module!
- ?l true=rpc:call(Node1,code,add_patha,[SuiteDir]),
- ?l true=rpc:call(Node2,code,add_patha,[SuiteDir]),
-
- %% SPECIAL FOR MY PRIVATE TEST ENVIROMENT
-% ?l rpc:call(Node1,code,add_patha,["/clearcase/otp/tools/runtime_tools/ebin"]),
-% ?l rpc:call(Node1,code,add_patha,["/clearcase/otp/tools/inviso/ebin"]),
-% ?l rpc:call(Node2,code,add_patha,["/clearcase/otp/tools/runtime_tools/ebin"]),
-% ?l rpc:call(Node2,code,add_patha,["/clearcase/otp/tools/inviso/ebin"]),
-
-% %% SPECIAL FOR MY PRIVATE TEST ENVIROMENT, windows.
-% ?l rpc:call(Node1,code,add_patha,["C:/DATA/PROJECTS/inviso_project/runtime_tools/ebin"]),
-% ?l rpc:call(Node1,code,add_patha,["C:/DATA/PROJECTS/inviso_project/inviso/ebin"]),
-% ?l rpc:call(Node2,code,add_patha,["C:/DATA/PROJECTS/inviso_project/runtime_tools/ebin"]),
-% ?l rpc:call(Node2,code,add_patha,["C:/DATA/PROJECTS/inviso_project/inviso/ebin"]),
-
- ?l ok=rpc:call(Node1,application,start,[runtime_tools]),
- ?l ok=rpc:call(Node2,application,start,[runtime_tools]),
- ?l timer:sleep(100), % Problem with autostarted runtime.
- %% The following is a test that the inviso_rt processes which are autostarted
- %% are now gone.
-
- ?l ok=poll(rpc,call,[Node1,erlang,whereis,[inviso_rt]],undefined,20),
- ?l ok=poll(rpc,call,[Node2,erlang,whereis,[inviso_rt]],undefined,20),
-
- NewConfig1=insert_remotenode_config(inviso1,Node1,Config),
- NewConfig2=insert_remotenode_config(inviso2,Node2,NewConfig1),
- insert_timetraphandle_config(TH,NewConfig2).
-%% -----------------------------------------------------------------------------
-
-end_per_testcase(_Case,Config) ->
- ?l test_server:stop_node(get_remotenode_config(inviso1,Config)),
- ?l test_server:stop_node(get_remotenode_config(inviso2,Config)),
- ?l test_server:timetrap_cancel(get_timetraphandle_config(Config)),
- ?l case whereis(inviso_tool) of % In case inviso_tool did not stop.
- Pid when is_pid(Pid) ->
- ?l io:format("Had to kill inviso_tool!~n",[]),
- ?l exit(Pid,kill);
- _ ->
- true
- end,
- ?l case whereis(inviso_rt) of % In case we ran a runtime here.
- Pid2 when is_pid(Pid2) ->
- ?l io:format("Had to kill inviso_rt!~n",[]),
- ?l exit(Pid2,kill);
- _ ->
- true
- end,
- ?l case whereis(inviso_c) of % In case we ran the controll component here.
- Pid3 when is_pid(Pid3) ->
- ?l io:format("Had to kill inviso_c!~n",[]),
- ?l exit(Pid3,kill);
- _ ->
- true
- end,
- NewConfig1=remove_remotenode_config(inviso1,Config),
- NewConfig2=remove_remotenode_config(inviso2,NewConfig1),
- remove_timetraphandle_config(NewConfig2).
-%% -----------------------------------------------------------------------------
-
-%% ==============================================================================
-%% Testcases.
-%% ==============================================================================
-
-%% -----------------------------------------------------------------------------
-%% Functional tests:
-%% API:
-%% start/0 dist_basic_1
-%% stop/0 dist_basic_1
-%% reconnect_nodes/1 dist_reconnect
-%% start_session/0 dist_basic_1
-%% reinitiate_session/1 dist_reconnect
-%% stop_session/0 dist_basic_1
-%% atc/3 dist_basic_1
-%% sync_atc/3 dist_basic_1
-%% sync_rtc/2, dist_rtc
-%% dtc/2 dist_basic_1
-%% sync_dtc/2 dist_basic_1
-%% inviso/2 dist_basic_1
-%% reactivate/1 dist_basic_1
-%% get_autostart_data/2 dist_basic_1
-%% get_activities/0 dist_basic_1
-%% save_history/1 dist_history
-%% restore_session/1 dist_history
-%% get_node_status/1 dist_basic_1
-%% get_session_data/0 dist_basic_1
-%% flush/0 dist_basic_1
-%% -----------------------------------------------------------------------------
-
-%% Non functional tests:
-%% Run the control component on both the dist_history
-%% same node as the tool and on a
-%% different node.
-%% Let a trace case crash in its execution dist_basic_1
-%% and check that it does not become
-%% part of the history.
-%% Check that tracer data becomes what the NOT IMPLEMENTED
-%% tdg function generates.
-%% Check that all inviso runtime stop_inviso_tool/2
-%% components terminate if the tool is
-%% killed.
-%% Check that activation/deactivation dist_basic_1
-%% cancels each other out in the history.
-%% Check that regexp expansion is done on dist_reconnect
-%% another node if regexp_node is down.
-%% Test that tool-commands activating dist_basic_1
-%% something done during a reactivation
-%% are actually done a bit later at the
-%% reactivated node (this since the the
-%% command being reactivated at the momen
-%% at the reactivating node may not
-%% be finished at the time the new tool
-%% command is issued).
-%% Check that deactivating tracecases are dist_basic_1
-%% not redone at a reactivating node.
-%% (to prevent it from being redone and
-%% then just deactivated).
-%% Check that on-going reactivators and NOT IMPLEMENTED
-%% tracecases are killed when stop_session.
-%% Check that inviso_tool can and will adopt
-%% a running runtime component. dist_adopt
-%% -----------------------------------------------------------------------------
-
--define(TC_DEF_FILE,filename:join(DataDir,"tracecase_def.txt")).
-
-%% TEST CASE: Basic, distributed, start of inviso_tool with simple tracing.
-dist_basic_1(doc) -> ["Simple test"];
-dist_basic_1(suite) -> [];
-dist_basic_1(Config) when is_list(Config) ->
- RemoteNodes=get_remotenodes_config(Config),
- [RegExpNode|_]=RemoteNodes,
- CNode=node(),
- Nodes=RemoteNodes,
- DataDir=?config(data_dir,Config),
- PrivDir=filename:join(?config(priv_dir,Config),""),
- Opts=[{regexp_node,RegExpNode},
- {tdg,{?MODULE,tdg,[PrivDir]}},
- {tc_def_file,?TC_DEF_FILE},
- {initial_tcs,[{tracecase_init,[]}]},
- {dir,DataDir}], % This is where we find tracecases.
- ?l start_inviso_tool(Nodes,CNode,Opts),
- %% Now we know that all inviso runtimes are running and are not tracing.
- ?l {error,no_session}=inviso_tool:inviso(tpl,[lists,module_info,0,[]]),
- ?l {error,no_session}=inviso_tool:get_session_data(),
- ?l start_inviso_tool_session(CNode,[],1,Nodes),
- ?l {ok,{tracing,1,TDGargs}}=inviso_tool:get_session_data(),
- ?l true=is_list(TDGargs),
- %% Check that the initial tracecase has been executed at all tracing nodes.
- ?l lists:foreach(fun(N)->
- ok=poll(rpc,
- call,
- [N,
- erlang,
- trace_info,
- [{lists,module_info,1},traced]],
- {traced,local},
- 20)
- end,
- Nodes),
- %% Start a test process at every node with a runtime component.
- ?l lists:foreach(fun(N)->spawn(N,?MODULE,test_proc_init,[]) end,Nodes),
- - %% Let the processes start - timer:sleep(100), - - %% Find the pids of the test processes.
- ?l TestProcs=lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_tool_test_proc]) end,
- Nodes),
- ?l true=(1=<length(TestProcs)),
-
- %% Activate a trace case.
- ?l {error,unknown_tracecase}=inviso_tool:atc(nonexistant,id,[]),
- ?l {error,{missing_variable,'ProcessName'}}=
- inviso_tool:atc(tracecase1,id1,[]),
- ?l ok=inviso_tool:atc(tracecase1,id1,[{'ProcessName',inviso_tool_test_proc}]),
- ?l {error,activating}=inviso_tool:atc(tracecase1,id1,[{'ProcessName',inviso_tool_test_proc}]),
- ?l {ok,[{tracecases,[{{tracecase1,id1},activating}]}]}=inviso_tool:get_activities(),
- ?l timer:sleep(1700), % There is a 500 ms delay in the tracecase.
- ?l {error,already_started}=
- inviso_tool:atc(tracecase1,id1,[{'ProcessName',inviso_tool_test_proc}]),
-
- %% Now check that the trace case was executed at Nodes.
- ?l lists:foreach(fun(P)->
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[P,flags]],
- {flags,[call]},
- 10),
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[{math,module_info,1},traced]],
- {traced,local},
- 10)
- end,
- TestProcs),
- ?l lists:foreach(fun(P) ->
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[{math,module_info,0},traced]],
- {traced,false},
- 1)
- end,
- TestProcs),
-
- %% Test inviso_tool:inviso/2.
- ?l {ok,NodeResults1}=inviso_tool:inviso(tpl,[math,module_info,0,[]]),
- ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults1),
- ?l lists:foreach(fun(P) ->
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[{math,module_info,0},traced]],
- {traced,local},
- 10)
- end,
- TestProcs),
-
- %% Test inviso_tool:sync_atc/3.
- ?l a_return_value=inviso_tool:sync_atc(tracecase2,id2,[]), % This will take 3000 ms.
- ?l lists:foreach(fun(P) ->
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[{math,pi,0},traced]],
- {traced,local},
- 10)
- end,
- TestProcs),
-
- %% Test the reactivation mechanism.
- ?l [ANode|OtherNodes]=Nodes, % Get a node to suspend.
- ?l {ok,{tracing,running}}=inviso_tool:get_node_status(ANode),
- ?l {ok,[{ANode,ok}]}=rpc:call(CNode,inviso,suspend,[[ANode],test]),
- ?l [APid|_]=TestProcs, % The first process is at ANode.
- %% Now check that trace flags were removed at ANode. This is actually testing inviso.
- ?l ok=poll(rpc,call,[node(APid),erlang,trace_info,[APid,flags]],{flags,[]},10),
- ?l {ok,{tracing,suspended}}=inviso_tool:get_node_status(ANode),
- %% Now reactivate it and expect the history to be redone. But it will take
- %% 3000 ms since there is a delay in tracecase2. Use that delay to issue a new
- %% tool command.
- ?l ok=inviso_tool:reactivate(ANode),
- ?l {ok,reactivating}=inviso_tool:get_node_status(ANode),
- ?l {ok,NodeResults2}=inviso_tool:inviso(tpl,[math,sin,1,[]]),
- ?l true=check_noderesults(OtherNodes,{ok,[1]},NodeResults2),
- %% Verify that the inviso command was not done (yet) at ANode.
- ?l {traced,false}=rpc:call(ANode,erlang,trace_info,[{math,sin,1},traced]),
- ?l {ok,[{reactivating_nodes,[ANode]}]}=inviso_tool:get_activities(),
- ?l timer:sleep(3600),
- %% Now the history shall have been redone including the new inviso command.
- ?l ok=poll(rpc,call,[ANode,erlang,trace_info,[{math,sin,1},traced]],{traced,local},10),
- ?l {flags,[call]}=rpc:call(ANode,erlang,trace_info,[APid,flags]),
- ?l {ok,[]}=inviso_tool:get_activities(),
-
- %% Check the get_autostart function. We know that we use the standard options
- %% generator and the tracecases activated above.
- ?l {ok,{AutostartData1,NodeResults3}}=
- inviso_tool:get_autostart_data(Nodes,{dependency,infinity}),
- ?l true=check_noderesults(Nodes,
- fun({_N,{ok,{[{dependency,infinity}],{tdg,{_M,_F,TDlist}}}}})
- when is_list(TDlist)->
- true;
- (_) ->
- false
- end,
- NodeResults3),
- %% Check the tracecase that shall be activated and their order.
- ?l TraceCaseFileNameInit=filename:join(DataDir,"./tracecase_init.trc"),
- ?l TraceCaseFileName1=filename:join(DataDir,"./tracecase1_on.trc"),
- ?l TraceCaseFileName2=filename:join(DataDir,"./tracecase2_on.trc"),
- ?l [{file,{TraceCaseFileNameInit,[]}},
- {file,{TraceCaseFileName1,[{'ProcessName',inviso_tool_test_proc}]}},
- {mfa,{inviso,tpl,[math,module_info,0,[]]}},
- {file,{TraceCaseFileName2,[]}},
- {mfa,{inviso,tpl,[math,sin,1,[]]}}]=AutostartData1,
-
- %% Try to activate a faulty tracecase. We shall get the same history as before.
- ?l ok=inviso_tool:atc(tracecase3,id3,[]),
- ?l ok=poll(inviso_tool,get_activities,[],{ok,[]},10),
- ?l {ok,{AutostartData1,NodeResults3}}=
- inviso_tool:get_autostart_data(Nodes,{dependency,infinity}),
-
- %% Now deactivate a trace case.
- ?l inviso_tool:dtc(tracecase1,id1),
- %% Check that the now deactivated trace case is not part of autostart data
- %% if requested from the tool.
- ?l {ok,{AutostartData2,_NodeResults}}=
- inviso_tool:get_autostart_data(Nodes,{dependency,infinity}),
- ?l [{file,{TraceCaseFileNameInit,[]}},
- {mfa,{inviso,tpl,[math,module_info,0,[]]}},
- {file,{TraceCaseFileName2,[]}},
- {mfa,{inviso,tpl,[math,sin,1,[]]}}]=AutostartData2,
- %% Now tracing shall be removed since we deactivated tracecase1.
- ?l lists:foreach(fun(P)->
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[P,flags]],
- {flags,[]},
- 10),
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[{math,module_info,1},traced]],
- {traced,false},
- 10)
- end,
- TestProcs),
-
- %% Suspend the ANode again and check that when it is reactivated that
- %% tracecase1 is not redone at all. We use an ets table with a counter that is
- %% incremented every time the tracecase1 is executed.
- ?l {ok,[{ANode,ok}]}=rpc:call(CNode,inviso,suspend,[[ANode],testagain]),
- ?l [{counter,SideEffectCounter1}]=rpc:call(ANode,ets,lookup,[test_proc_tab,counter]),
- ?l true=(SideEffectCounter1>0),
- ?l ok=inviso_tool:reactivate(ANode),
- ?l timer:sleep(3000), % The delay in tracecase2.
- ?l ok=poll(inviso_tool,get_activities,[],{ok,[]},10),
- %% Now the reactivation is done, check that tracecase1 was not redone at ANode.
- ?l [{counter,SideEffectCounter1}]=rpc:call(ANode,ets,lookup,[test_proc_tab,counter]),
-
- %% Deactivate tracecase2.
- ?l another_return_value=inviso_tool:sync_dtc(tracecase2,id2),
- %% Immediately check the autostart data (again!). This time we want to see
- %% that the two inviso commands have been joined since there is no tracecase
- %% in between.
- ?l {ok,{AutostartData3,NodeResults}}=
- inviso_tool:get_autostart_data(Nodes,{dependency,infinity}),
- ?l [{file,{TraceCaseFileNameInit,[]}},
- {mfa,{inviso,tpl,[math,module_info,0,[]]}},
- {mfa,{inviso,tpl,[math,sin,1,[]]}}]=AutostartData3,
-
- %% Check that a deactivating tracecase is not redone at a reactivating node.
- ?l inviso_tool:sync_atc(tracecase5,id5,[]), % Updates the counter.
- %% Yet again suspend the node when we know that tracecase5 has been executed.
- ?l {ok,[{ANode,ok}]}=rpc:call(CNode,inviso,suspend,[[ANode],testagain2]),
- ?l timer:sleep(100), % Subscription reaches the tool.
- ?l [{counter,SideEffectCounter2A}]=rpc:call(ANode,ets,lookup,[test_proc_tab,counter]),
- ?l [BNode|_]=OtherNodes,
- ?l [{counter,SideEffectCounter2B}]=rpc:call(BNode,ets,lookup,[test_proc_tab,counter]),
- ?l ok=inviso_tool:dtc(tracecase5,id5), % In here there is a 2000 ms delay!
- ?l ok=inviso_tool:reactivate(ANode),
- %% Check that the reactivator is done, but that the tracecase remains. The
- %% reactivator should be done pretty quickly since there are no delays in the
- %% still active tracecases.
- ?l ok=poll(inviso_tool,
- get_activities,
- [],
- {ok,[{tracecases,[{{tracecase5,id5},deactivating}]}]},
- 10),
- ?l ok=poll(inviso_tool,get_activities,[],{ok,[]},30),
- ?l [{counter,SideEffectCounter2A}]=rpc:call(ANode,ets,lookup,[test_proc_tab,counter]),
- ?l SideEffectCounter2B1=SideEffectCounter2B+1,
- ?l [{counter,SideEffectCounter2B1}]=rpc:call(BNode,ets,lookup,[test_proc_tab,counter]),
-
- %% Check the flush function. It is difficult to find out if it really flushed.
- ?l {ok,NodeResults4}=inviso_tool:flush(),
- ?l true=check_noderesults(Nodes,ok,NodeResults4),
-
- %% Check that this function still has a trace pattern. We are going to stop session
- %% and check that it is still there.
- ?l lists:foreach(fun(N)->
- ok=poll(rpc,
- call,
- [N,
- erlang,
- trace_info,
- [{math,sin,1},traced]],
- {traced,local},
- 20)
- end,
- Nodes),
-
- ?l stop_inviso_tool_session(CNode,1,Nodes),
- ?l {ok,{not_tracing,1,TDGargs}}=inviso_tool:get_session_data(),
-
- ?l {ok,NodeResults5}=inviso_tool:flush(Nodes),
- ?l true=check_noderesults(Nodes,fun({_,{error,_}})->true;(_)->false end,NodeResults5),
- ?l {ok,[]}=inviso_tool:flush(),
-
- %% Check that you can not start trace cases when the session is stopped.
- ?l {error,no_session}=inviso_tool:atc(tracecase2,id3,[]),
- %% But the history shall be there to retrieve.
- ?l {ok,{AutostartData3,NodeResults}}=
- inviso_tool:get_autostart_data(Nodes,{dependency,infinity}),
- ?l {ok,{inactive,running}}=inviso_tool:get_node_status(ANode),
-
- %% Check that the trace pattern is still there.
- ?l lists:foreach(fun(N)->
- ok=poll(rpc,
- call,
- [N,
- erlang,
- trace_info,
- [{math,sin,1},traced]],
- {traced,local},
- 20)
- end,
- Nodes),
-
- %% Now start a session and check that the trace patterns is gone.
- ?l start_inviso_tool_session(CNode,[],2,Nodes),
- ?l lists:foreach(fun(N)->
- ok=poll(rpc,
- call,
- [N,
- erlang,
- trace_info,
- [{math,sin,1},traced]],
- {traced,false},
- 20)
- end,
- Nodes),
- ?l stop_inviso_tool_session(CNode,2,Nodes),
-
- ?l stop_inviso_tool(CNode,Nodes),
- ok.
-%% -----------------------------------------------------------------------------
-
-%% This test case tests the rtc trace case mechanism.
-dist_rtc(doc) -> [""];
-dist_rtc(suite) -> [];
-dist_rtc(Config) when is_list(Config) ->
- RemoteNodes=get_remotenodes_config(Config),
- [RegExpNode|_]=RemoteNodes,
- CNode=node(),
- Nodes=RemoteNodes,
- DataDir=?config(data_dir,Config),
- PrivDir=filename:join(?config(priv_dir,Config),""),
- Opts=[{regexp_node,RegExpNode},
- {tdg,{?MODULE,tdg,[PrivDir]}},
- {tc_def_file,?TC_DEF_FILE},
- {initial_tcs,[{tracecase_init,[]}]},
- {dir,DataDir}], % This is where we find tracecases.
- ?l start_inviso_tool(Nodes,CNode,Opts),
- ?l start_inviso_tool_session(CNode,[],1,Nodes),
- %% Check that the initial tracecase has been executed at all tracing nodes.
- ?l lists:foreach(fun(N)->
- ok=poll(rpc,
- call,
- [N,
- erlang,
- trace_info,
- [{lists,module_info,1},traced]],
- {traced,local},
- 20)
- end,
- Nodes),
- %% Start a test process at every node with a runtime component.
- ?l lists:foreach(fun(N)->spawn(N,?MODULE,test_proc_init,[]) end,Nodes),
- - %% Let the processes start - timer:sleep(100), - - %% Find the pids of the test processes.
- ?l TestProcs=lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_tool_test_proc]) end,
- Nodes),
- ?l true=(1=<length(TestProcs)),
- ?l [ANode|_]=Nodes,
- ?l [{counter,Val}]=rpc:call(ANode,ets,lookup,[test_proc_tab,counter]),
- %% Call the tracecase as an rtc.
- ?l inviso_tool:sync_rtc(tracecase5,[]), % Updates the counter.
- ?l [{counter,Val2}]=rpc:call(ANode,ets,lookup,[test_proc_tab,counter]),
- ?l true=(Val2==Val+1),
- ?l inviso_tool:sync_rtc(tracecase5,[]), % Updates the counter.
- ?l [{counter,Val3}]=rpc:call(ANode,ets,lookup,[test_proc_tab,counter]),
- ?l true=(Val3==Val2+1),
-
- %% Now we stop the session and restore it again.
- ?l stop_inviso_tool_session(CNode,1,Nodes),
- ?l {ok,{2,_InvisoReturn}}=inviso_tool:restore_session(),
- %% The tracecase shall be done twice then.
- ?l ok=poll(rpc,call,[ANode,ets,lookup,[test_proc_tab,counter]],
- fun([{counter,V}]) when V==Val3+2 -> true;
- (_) -> false
- end,
- 20),
- ?l stop_inviso_tool_session(CNode,2,Nodes),
-
- ?l {ok,{AutostartData,_NodeResults}}=
- inviso_tool:get_autostart_data(Nodes,{dependency,infinity}),
- ?l [{file,{_FileNameInit,_}},{file,{FileName,Bindings}},{file,{FileName,Bindings}}]=
- AutostartData,
- ?l stop_inviso_tool(CNode,Nodes),
- ok.
-%% -----------------------------------------------------------------------------
-
-
-%% This test case tests mainly that reconnect and reinitiations of a node works.
-dist_reconnect(doc) -> [""];
-dist_reconnect(suite) -> [];
-dist_reconnect(Config) when is_list(Config) ->
- RemoteNodes=get_remotenodes_config(Config),
- [RegExpNode|OtherNodes]=RemoteNodes,
- CNode=node(),
- Nodes=RemoteNodes,
- DataDir=?config(data_dir,Config),
- PrivDir=filename:join(?config(priv_dir,Config),""),
- Opts=[{regexp_node,RegExpNode},
- {tdg,{?MODULE,tdg,[PrivDir]}},
- {tc_def_file,?TC_DEF_FILE},
- {initial_tcs,[{tracecase_init,[]}]},
- {dir,DataDir}], % This is where we find tracecases.
- ?l start_inviso_tool(Nodes,CNode,Opts),
- ?l start_inviso_tool_session(CNode,[],1,Nodes),
- %% Start a test process at every node with a runtime component.
- ?l lists:foreach(fun(N)->spawn(N,?MODULE,test_proc_init,[]) end,Nodes),
- - %% Let the processes start - timer:sleep(100), - - %% Find the pids of the test processes.
- ?l TestProcs=lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_tool_test_proc]) end,
- Nodes),
- ?l true=(1=<length(TestProcs)),
- ?l ok=inviso_tool:atc(tracecase1,id1,[{'ProcessName',inviso_tool_test_proc}]),
- ?l ok=poll(inviso_tool,get_activities,[],{ok,[]},20),
-
- %% Now we want to crash a node. Lets choose the RegExp node, then we can test
- %% that regexp expansion is done elsewhere too.
- ?l test_server:stop_node(RegExpNode),
- ?l ok=poll(net_adm,ping,[RegExpNode],pang,10),
- %% Make time for the monitoring signal to reach inviso_c and for inviso_c to
- %% inform its subscribers e.g inviso_tool.
- ?l timer:sleep(100),
- ?l {_,[{_Node,Modules}]}=
- inviso_tool_lib:expand_module_names([node()],"application.*",[]),
- ?l NrOfModules=length(Modules),
- %% This also checks that regexp expansion can be made at another node
- %% than RexExpNode.
- ?l {ok,NodeResults1}=inviso_tool:inviso(tp,["application.*",module_info,0,[]]),
- ?l true=check_noderesults(OtherNodes,
- fun({_N,{ok,Ints}}) when is_list(Ints) ->
- NrOfModules=lists:sum(Ints),
- true;
- (_) ->
- false
- end,
- NodeResults1),
-
- %% Do some faulty tests on the dead node.
- ?l {ok,{ok,[{RegExpNode,{error,down}}]}}=
- inviso_tool:reinitiate_session([RegExpNode]),
- ?l {ok,down}=inviso_tool:get_node_status(RegExpNode),
-
- %% Now it is time to restart the crashed node and reconnect it and then
- %% finally reinitiate it.
- ?l RegExpNodeString=atom_to_list(RegExpNode), - ?l [NodeNameString,_HostNameString] = string:tokens(RegExpNodeString,[$@]), - ?l RegExpNodeName=list_to_atom(NodeNameString), - ?l test_server:start_node(RegExpNodeName,peer,[]),
- ?l ok=poll(net_adm,ping,[RegExpNode],pong,20),
- ?l SuiteDir=filename:dirname(code:which(?MODULE)),
- ?l true=rpc:call(RegExpNode,code,add_patha,[SuiteDir]),
- ?l ok=rpc:call(RegExpNode,application,start,[runtime_tools]),
- ?l ok=poll(rpc,call,[RegExpNode,erlang,whereis,[inviso_rt]],undefined,20),
- ?l {ok,down}=inviso_tool:get_node_status(RegExpNode),
-
- %% Restart the test process.
- ?l spawn(RegExpNode,?MODULE,test_proc_init,[]),
- ?l ok=poll(rpc,
- call,
- [RegExpNode,erlang,whereis,[inviso_tool_test_proc]],
- fun(P) when is_pid(P) -> true;
- (undefined) -> false
- end,
- 10),
- ?l TPid=rpc:call(RegExpNode,erlang,whereis,[inviso_tool_test_proc]),
- ?l {ok,[{RegExpNode,{ok,{inactive,running}}}]}=inviso_tool:reconnect_nodes([RegExpNode]),
- %% Try to reconnect the node again and an unknown node.
- ?l UnknownNode='unknown@nonexistant',
- ?l {ok,[{RegExpNode,{error,already_connected}},{UnknownNode,{error,unknown_node}}]}=
- inviso_tool:reconnect_nodes([RegExpNode,UnknownNode]),
- ?l {ok,{ok,[{RegExpNode,{ok,_}}]}}=inviso_tool:reinitiate_session([RegExpNode]),
- ?l ok=poll(rpc,
- call,
- [RegExpNode,erlang,trace_info,[TPid,flags]],
- {flags,[call]},
- 10),
- ?l {ok,{ok,[{RegExpNode,{error,already_in_session}},{UnknownNode,{error,unknown_node}}]}}=
- inviso_tool:reinitiate_session([RegExpNode,UnknownNode]),
-
- %% Suspend RegExpNode and test that it can not be reinitiated.
- ?l {ok,[{RegExpNode,ok}]}=rpc:call(CNode,inviso,suspend,[[RegExpNode],yetatest]),
- ?l {ok,[{RegExpNode,{error,already_connected}}]}=inviso_tool:reconnect_nodes([RegExpNode]),
- ?l {ok,{ok,[{RegExpNode,{error,suspended}}]}}=inviso_tool:reinitiate_session([RegExpNode]),
-
- %% Now we start a tracecase that will never terminate. We then reactivate the
- %% suspended node. Then there will be a running reactivator and a running
- %% tracecase to kill.
- ?l ok=inviso_tool:atc(tracecase4,id4,[]), % This one will not terminate.
- ?l ok=inviso_tool:reactivate(RegExpNode),
- ?l ok=poll(inviso_tool,
- get_activities,
- [],
- fun({ok,L}) when length(L)==2 -> true;
- (_) -> false
- end,
- 20),
- %% Now the reactivator and the tracecase shall be stuck(!)
- ?l {links,ToolLinks}=process_info(whereis(inviso_tool),links),
- ?l [P1,P2]=lists:foldl(fun(P,Acc)->case process_info(P,initial_call) of
- {initial_call,{inviso_tool,_,_}} ->
- [P|Acc];
- _ ->
- Acc
- end
- end,
- [],
- ToolLinks),
- ?l stop_inviso_tool_session(CNode,1,Nodes),
- %% Check that the processes are killed.
- ?l ok=poll(erlang,process_info,[P1],undefined,10),
- ?l ok=poll(erlang,process_info,[P2],undefined,10),
- ?l stop_inviso_tool(CNode,Nodes),
- ok.
-%% -----------------------------------------------------------------------------
-
-%% This test tests that we can adopt a running inviso runtime component and
-%% mark it as tracing-running.
-dist_adopt(doc) -> [""];
-dist_adopt(suite) -> [];
-dist_adopt(Config) when is_list(Config) ->
- RemoteNodes=get_remotenodes_config(Config),
- [RegExpNode|_]=RemoteNodes,
- CNode=node(),
- Nodes=RemoteNodes,
- DataDir=?config(data_dir,Config),
- PrivDir=filename:join(?config(priv_dir,Config),""),
-
- %% Then first start runtime components at different nodes for us to
- %% later adopt.
- ?l {ok,_IPid}=inviso:start(),
- ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_tag,[{dependency,infinity}]),
- ?l true=check_noderesults(Nodes,{ok,new},NodeResults1),
- ?l [ANode|OtherNodes]=Nodes,
- ?l {ok,[{ANode,_LogResult}]}=
- inviso:init_tracing([ANode],
- [{trace,{file,filename:join(PrivDir,"dist_adopt_adoptednode.log")}},
- {ti,{file,filename:join(PrivDir,"dist_adopt_adoptednode.ti")}}]),
- ?l inviso:stop(),
- ?l ok=poll(erlang,whereis,[inviso_c],undefined,10),
- ?l lists:foreach(fun(N)->true=(is_pid(rpc:call(N,erlang,whereis,[inviso_rt]))) end,
- Nodes),
-
- %% Now start the tool and watch it adopt the runtimes.
- Opts=[{regexp_node,RegExpNode},
- {tdg,{?MODULE,tdg,[PrivDir]}},
- {tc_def_file,?TC_DEF_FILE},
- {initial_tcs,[{tracecase_init,[]}]},
- {dir,DataDir}], % This is where we find tracecases.
- ?l Options=[{nodes,Nodes},{c_node,CNode}|Opts],
- ?l {ok,_Pid}=inviso_tool:start(Options),
- ?l ok=poll(erlang,whereis,[inviso_tool],fun(X)->true=is_pid(X) end,10),
- ?l io:format("LoopData:~p~n",[inviso_tool:get_loopdata()]),
- ?l {ok,{1,InvisoReturn}}=inviso_tool:start_session([]),
- ?l io:format("Invisoreturn:~p~n",[InvisoReturn]),
- %% Now check that all nodes are tracing.
- ?l lists:foreach(fun(N)->ok=poll(rpc,
- call,
- [CNode,inviso,get_status,[[N]]],
- fun({ok,[{_N,{ok,{tracing,running}}}]})->true;
- (_) ->false
- end,
- 10)
- end,
- Nodes),
-
- %% At this point all nodes shall be tracing. However the initial tracecase
- %% shall not have been executed at ANode since it was adopted by the tool.
- ?l {traced,false}=rpc:call(ANode,erlang,trace_info,[{lists,module_info,1},traced]),
- ?l lists:foreach(fun(N)->
- {traced,local}=
- rpc:call(N,erlang,trace_info,[{lists,module_info,1},traced])
- end,
- OtherNodes),
- ?l stop_inviso_tool_session(CNode,1,Nodes),
- ?l [BNode|_]=OtherNodes,
- %% Since nodes are not cleared the pattern still be there.
- ?l {traced,local}=rpc:call(BNode,erlang,trace_info,[{lists,module_info,1},traced]),
- ?l start_inviso_tool_session(CNode,[],2,Nodes),
- ?l stop_inviso_tool_session(CNode,2,Nodes),
- ?l {ok,_NodeResults}=inviso_tool:stop(),
- ?l ok=poll(erlang,whereis,[inviso_tool],undefined,10),
- ?l ok=poll(rpc,call,[CNode,erlang,whereis,[inviso_c]],undefined,10),
-
- ok.
-%% -----------------------------------------------------------------------------
-
-%% This test tests that saving and restoring a history works.
-dist_history(doc) -> [""];
-dist_history(suite) -> [];
-dist_history(Config) when is_list(Config) ->
- RemoteNodes=get_remotenodes_config(Config),
- [RegExpNode|_]=RemoteNodes,
- CNode=RegExpNode, % We use a remote control component.
- Nodes=RemoteNodes,
- DataDir=?config(data_dir,Config),
- PrivDir=filename:join(?config(priv_dir,Config),""),
-
- %% Start up the tool and a couple of inviso runtimes.
- Opts=[{regexp_node,RegExpNode},
- {tdg,{?MODULE,tdg,[PrivDir]}},
- {tc_def_file,?TC_DEF_FILE},
- {initial_tcs,[{tracecase_init,[]}]},
- {dir,DataDir}], % This is where we find tracecases.
- ?l start_inviso_tool(Nodes,CNode,Opts),
- ?l start_inviso_tool_session(CNode,[],1,Nodes),
- %% Start a test process at every node with a runtime component.
- ?l lists:foreach(fun(N)->spawn(N,?MODULE,test_proc_init,[]) end,Nodes),
-
- %% Activate tracing of the test process.
- ?l ok=inviso_tool:atc(tracecase1,id1,[{'ProcessName',inviso_tool_test_proc}]),
- ?l ok=poll(inviso_tool,get_activities,[],{ok,[]},10),
- ?l TestProcs=lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_tool_test_proc]) end,
- Nodes),
- ?l lists:foreach(fun(P)->
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[P,flags]],
- {flags,[call]},
- 10),
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[{math,module_info,1},traced]],
- {traced,local},
- 10)
- end,
- TestProcs),
-
- %% Create a history file.
- ?l AbsFileName=filename:join(PrivDir,"dist_history.his"),
- ?l {ok,AbsFileName}=inviso_tool:save_history(AbsFileName),
- ?l {ok,_FileInfo}=file:read_file_info(AbsFileName),
-
- %% Stop the tracing of the test process.
- ?l inviso_tool:sync_dtc(tracecase1,id1),
- ?l lists:foreach(fun(P)->
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[P,flags]],
- {flags,[]},
- 10),
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[{math,module_info,1},traced]],
- {traced,false},
- 10)
- end,
- TestProcs),
- %% Now stop the session.
- ?l stop_inviso_tool_session(CNode,1,Nodes),
- %% Restart the session using the previously saved history.
- ?l {ok,{2,_InvisoReturn}}=inviso_tool:restore_session(AbsFileName),
- ?l ok=poll(inviso_tool,get_activities,[],{ok,[]},10),
- %% Check that the history has been redone.
- ?l lists:foreach(fun(P)->
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[P,flags]],
- {flags,[call]},
- 10),
- ?l ok=poll(rpc,
- call,
- [node(P),erlang,trace_info,[{math,module_info,1},traced]],
- {traced,local},
- 10)
- end,
- TestProcs),
- ?l {ok,_NodeResults1}=inviso_tool:inviso(tpl,[math,module_info,0,[]]),
- %% Also check that the restored history now is our history.
- ?l {ok,{AutostartData,_NodeResults2}}=
- inviso_tool:get_autostart_data(Nodes,{dependency,infinity}),
- ?l FNameInit=filename:join(DataDir,"tracecase_init.trc"),
- ?l FName1=filename:join(DataDir,"tracecase1_on.trc"),
- ?l [{file,{FNameInit,[]}},
- {file,{FName1,[{'ProcessName',inviso_tool_test_proc}]}},
- {mfa,{inviso,tpl,[math,module_info,0,[]]}}]=AutostartData,
- ?l stop_inviso_tool_session(CNode,2,Nodes),
- ?l NodeCounters=lists:foldl(fun(N,Acc)->[{_,X}]=rpc:call(N,ets,lookup,[test_proc_tab,counter]),
- [{N,X}|Acc]
- end,
- [],
- Nodes),
- %% Remove the patterns set by the initial tracecase.
- ?l lists:foreach(fun(N)->rpc:call(N,
- erlang,
- trace_pattern,
- [{lists,module_info,1},false,[local]])
- end,
- Nodes),
- %% Now we want to test that we can do restore on the current session.
- ?l {ok,{3,_InvisoReturn2}}=inviso_tool:restore_session(),
- ?l ok=poll(inviso_tool,get_activities,[],{ok,[]},10),
- %% Check that the history has been redone yet again.
- ?l lists:foreach(fun({N,X})->
- [{counter,Y}]=
- rpc:call(N,ets,lookup,[test_proc_tab,counter]),
- Y=X+1
- end,
- NodeCounters),
- ?l lists:foreach(fun(N)->
- {traced,local}=
- rpc:call(N,erlang,trace_info,[{lists,module_info,1},traced])
- end,
- Nodes),
-
- ?l {error,session_active}=inviso_tool:reset_nodes(Nodes),
- %% Now stop the session and check that we can clear the nodes.
- ?l stop_inviso_tool_session(CNode,3,Nodes),
- ?l lists:foreach(fun(N)->{traced,local}=
- rpc:call(N,erlang,trace_info,[{lists,module_info,1},traced])
- end,
- Nodes),
- ?l {ok,NodeResults3}=inviso_tool:reset_nodes(Nodes),
- ?l true=check_noderesults(Nodes,{ok,{new,running}},NodeResults3),
- ?l lists:foreach(fun(N)->{traced,false}=
- rpc:call(N,erlang,trace_info,[{lists,module_info,1},traced])
- end,
- Nodes),
- ?l stop_inviso_tool(CNode,Nodes),
-
- %% Now we want to test that restoring a session at no active nodes will
- %% not result in a crash. (Previous error).
- ?l FaultyNodes=[gurka@nonexistant,tomat@nonexistant],
- ?l Options=[{nodes,FaultyNodes},{c_node,CNode}|Opts],
- ?l {ok,_Pid}=inviso_tool:start(Options),
- ?l ok=poll(erlang,whereis,[inviso_tool],fun(X)->true=is_pid(X) end,10),
- %% Now try to restore a session.
- ?l {ok,{_,{ok,[]}}}=inviso_tool:restore_session(AbsFileName),
- ?l {ok,down}=inviso_tool:get_node_status(gurka@nonexistant),
- %% Now stop the (useless) session.
- ?l {ok,{_,[]}}=inviso_tool:stop_session(),
- ?l stop_inviso_tool(CNode,[]),
- ok.
-%% -----------------------------------------------------------------------------
-
-%% This test tests a few strange situations when activating a session and there
-%% are no nodes that can be initiated or reinitiated.
-dist_start_session_special(doc) -> [""];
-dist_start_session_special(suite) -> [];
-dist_start_session_special(Config) when is_list(Config) ->
- RemoteNodes=get_remotenodes_config(Config),
- [RegExpNode|_]=RemoteNodes,
- CNode=RegExpNode, % We use a remote control component.
-% Nodes=RemoteNodes,
- DataDir=?config(data_dir,Config),
- PrivDir=filename:join(?config(priv_dir,Config),""),
-
- %% Start up the tool but with no exiting nodes.
- FaultyNodes=[gurka@nonexistant,tomat@nonexistant],
- Opts=[{regexp_node,RegExpNode},
- {tdg,{?MODULE,tdg,[PrivDir]}},
- {tc_def_file,?TC_DEF_FILE},
- {initial_tcs,[{tracecase_init,[]}]},
- {dir,DataDir}], % This is where we find tracecases.
- ?l Options=[{nodes,FaultyNodes},{c_node,CNode}|Opts],
- ?l {ok,_Pid}=inviso_tool:start(Options),
- ?l ok=poll(erlang,whereis,[inviso_tool],fun(X)->true=is_pid(X) end,10),
- %% Now try to initate a session.
- ?l {ok,{SessionNr,{ok,[]}}}=inviso_tool:start_session(),
- ?l {ok,down}=inviso_tool:get_node_status(gurka@nonexistant),
- %% Now stop the (useless) session.
- ?l {ok,{SessionNr,[]}}=inviso_tool:stop_session(),
-
- %% Now start again, still no useful nodes.
- ?l {ok,{SessionNr2,{ok,[]}}}=inviso_tool:start_session(),
- ?l {ok,{SessionNr2,[]}}=inviso_tool:stop_session(),
- ?l stop_inviso_tool(CNode,[]), % No nodes are connected.
-
- ok.
-%% -----------------------------------------------------------------------------
-
-
-%% ==============================================================================
-%% Help functions.
-%% ==============================================================================
-
-%% Help function starting the inviso_tool with runtime components at Nodes
-%% and the inviso control component at CNode. OtherOpts shall contain all other
-%% necessary options except nodes and c_node. Returns nothing significant.
-start_inviso_tool(Nodes,CNode,OtherOpts) ->
- ?l Options=[{nodes,Nodes},{c_node,CNode}|OtherOpts],
- ?l {ok,_Pid}=inviso_tool:start(Options),
- ?l ok=poll(erlang,whereis,[inviso_tool],fun(X)->true=is_pid(X) end,10),
- %% Now the runtime components shall be started but no tracing started.
- ?l lists:foreach(fun(N)->ok=poll(rpc,
- call,
- [CNode,inviso,get_status,[[N]]],
- fun({ok,[{_N,{ok,{new,running}}}]})->true;
- (_) ->false
- end,
- 10)
- end,
- Nodes),
- true.
-%% -----------------------------------------------------------------------------
-
-%% Stops the inviso_tool.
-stop_inviso_tool(CNode,Nodes) ->
- ?l {ok,NodeResults}=inviso_tool:stop(),
- ?l true=check_noderesults(Nodes,ok,NodeResults),
- ?l ok=poll(erlang,whereis,[inviso_tool],undefined,10),
- %% Check that all inviso components are gone.
- ?l ok=poll(rpc,call,[CNode,erlang,whereis,[inviso_c]],undefined,10),
- ?l lists:foreach(fun(N)->ok=poll(rpc,
- call,
- [N,erlang,whereis,[inviso_rt]],
- undefined,
- 10)
- end,
- Nodes),
- true.
-%% -----------------------------------------------------------------------------
-
-%% Starts a trace session. Returns the InvisoReturn part of the return value.
-start_inviso_tool_session(CNode,MoreTDGargs,SessionNr,Nodes) ->
- ?l {ok,{SessionNr,InvisoReturn}}=inviso_tool:start_session(MoreTDGargs),
- %% Now check that all nodes are tracing.
- ?l lists:foreach(fun(N)->ok=poll(rpc,
- call,
- [CNode,inviso,get_status,[[N]]],
- fun({ok,[{_N,{ok,{tracing,running}}}]})->true;
- (_) ->false
- end,
- 10),
- %% Check that the initial trace case is executed.
- ?l ok=poll(rpc,
- call,
- [N,erlang,trace_info,[{lists,module_info,1},traced]],
- {traced,local},
- 10)
- end,
- Nodes),
- InvisoReturn.
-%% -----------------------------------------------------------------------------
-
-%% Stops a trace session.
-stop_inviso_tool_session(CNode,SessionNr,Nodes) ->
- ?l {ok,{SessionNr,NodeResults}}=inviso_tool:stop_session(),
- ?l true=check_noderesults(Nodes,ok,NodeResults),
- %% Now the runtimes shall not be tracing any longer.
- ?l lists:foreach(fun(N)->ok=poll(rpc,
- call,
- [CNode,inviso,get_status,[[N]]],
- fun({ok,[{_N,{ok,{idle,running}}}]})->true;
- (_) ->false
- end,
- 10)
- end,
- Nodes),
- true.
-%% -----------------------------------------------------------------------------
-
-%% Help function checking that there is a Result for each node in Nodes.
-%% Returns 'true' if successful.
-check_noderesults(Nodes,Fun,[{Node,Result}|Rest]) when is_function(Fun) ->
- case Fun({Node,Result}) of
- true ->
- case lists:member(Node,Nodes) of
- true ->
- check_noderesults(lists:delete(Node,Nodes),Fun,Rest);
- false -> % Not good.
- unknown_node_in_returnvalue
- end;
- _ ->
- illegal_result
- end;
-check_noderesults(Nodes,Result,[{Node,Result}|Rest]) ->
- case lists:member(Node,Nodes) of
- true ->
- check_noderesults(lists:delete(Node,Nodes),Result,Rest);
- false -> % Not good.
- unknown_node_in_returnvalue
- end;
-check_noderesults([],_,[]) ->
- true;
-check_noderesults(X,Y,Z) ->
- io:format("Bad arguments to check noderesults:~w~n~w~n~w~n",[X,Y,Z]),
- false.
-%% ------------------------------------------------------------------------------
-
-%% Help function which waits for a function call to become Result. This is useful
-%% if what we are waiting for can happend independantly of indications we have
-%% access to.
-poll(_,_,_,_,0) ->
- error;
-poll(M,F,Args,Result,Times) ->
- try apply(M,F,Args) of
- What when is_function(Result) ->
- case Result(What) of
- true ->
- ok;
- X ->
- io:format("Poll: ~w:~w ~w ~w ~w~n",[M,F,Args,Result,X]),
- timer:sleep(100),
- poll(M,F,Args,Result,Times-1)
- end;
- Result ->
- ok;
- X ->
- io:format("Poll: ~w:~w ~w ~w ~w~n",[M,F,Args,Result,X]),
- timer:sleep(100),
- poll(M,F,Args,Result,Times-1)
- catch
- error:Reason ->
- io:format("Apply in suite-function poll/5 failed, ~w~n",[Reason]),
- timer:sleep(100),
- poll(M,F,Args,Result,Times-1)
- end.
-%% ------------------------------------------------------------------------------
-
-%% ------------------------------------------------------------------------------
-%% The Tracer Data Generator function.
-%% ------------------------------------------------------------------------------
-
--define(I2L(Arg),integer_to_list(Arg)).
-
-tdg(Node,{{Y,Mo,D},{H,Mi,S}},PrivDir) ->
- NameStr=atom_to_list(Node)++"_"++?I2L(Y)++"-"++?I2L(Mo)++"-"++?I2L(D)++"_"++
- ?I2L(H)++"-"++?I2L(Mi)++"-"++?I2L(S),
- LogTD={file,filename:join(PrivDir,NameStr++".log")},
- TiTD={file,filename:join(PrivDir,NameStr++".ti")},
- [{trace,LogTD},{ti,TiTD}].
-%% ------------------------------------------------------------------------------
-
-
-%% ------------------------------------------------------------------------------
-%% Handling the test server Config.
-%% ------------------------------------------------------------------------------
-
-insert_remotenode_config(Name,Node,Config) ->
- [{remotenode,{Name,Node}}|Config].
-%% ------------------------------------------------------------------------------
-
-insert_timetraphandle_config(Handle,Config) ->
- [{timetraphandle,Handle}|Config].
-%% ------------------------------------------------------------------------------
-
-get_remotenode_config(Name, [{remotenode, {Name, Node}}| _Cs]) ->
- Node;
-get_remotenode_config(Name, [_C | Cs]) ->
- get_remotenode_config(Name, Cs);
-get_remotenode_config(Name, []) ->
- exit({no_remotenode, Name}).
-
-%% ------------------------------------------------------------------------------
-
-get_timetraphandle_config(Config) ->
- {value,{_,Handle}}=lists:keysearch(timetraphandle,1,Config),
- Handle.
-%% ------------------------------------------------------------------------------
-
-get_remotenodes_config([{remotenode,{_Name,Node}}|Config]) ->
- [Node|get_remotenodes_config(Config)];
-get_remotenodes_config([_|Config]) ->
- get_remotenodes_config(Config);
-get_remotenodes_config([]) ->
- [].
-%% ------------------------------------------------------------------------------
-
-remove_remotenode_config(Name, [{remotenode, {Name, _}} | Cs]) ->
- Cs;
-remove_remotenode_config(Name, [C | Cs]) ->
- [C | remove_remotenode_config(Name, Cs)];
-remove_remotenode_config(_Name, []) ->
- [].
-%% ------------------------------------------------------------------------------
-
-remove_timetraphandle_config(Config) ->
- lists:keydelete(timetraphandle,1,Config).
-%% ------------------------------------------------------------------------------
-
-
-%% ==============================================================================
-%% Code for a test process which can be started.
-%% ==============================================================================
-
-%% The test proc is also responsible for owning a side effect table. The table
-%% can be updated by tracecases.
-test_proc_init() ->
- register(inviso_tool_test_proc,self()),
- ets:new(test_proc_tab,[named_table,public]),
- ets:insert(test_proc_tab,{counter,0}),
- test_proc_loop().
-
-test_proc_loop() ->
- receive
- {apply,M,F,Args} ->
- apply(M,F,Args),
- test_proc_loop();
- X ->
- io:format("Got ~w~n",[X]),
- test_proc_loop()
- end.
-%% ------------------------------------------------------------------------------
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase1_off.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase1_off.trc deleted file mode 100644 index 426c1ed9f9..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase1_off.trc +++ /dev/null @@ -1,12 +0,0 @@ -%% TRACECASE1_OFF.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% Trace case deactivating the trace started by the activation case tracecase1_on.
-%%
-%% ProcessName=atom(), variable set in the test environment.
-%% Nodes=list(), inviso_tool variable - all traced nodes.
-%% -----------------------------------------------------------------------------
-
-inviso:ctf(Nodes,ProcessName,[call]).
-inviso:ctpl(Nodes,math,module_info,1).
-%% END-OF-TRACE-CASE
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase1_on.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase1_on.trc deleted file mode 100644 index a9106dbc78..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase1_on.trc +++ /dev/null @@ -1,17 +0,0 @@ -%% TRACECASE1_ON.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% Trace case setting a local pattern on math:module_info/1 and process flags
-%% on a test process which is supposed to be started by the test environment.
-%%
-%% ProcessName=atom(), variable set in the test environment.
-%% Nodes=list(), inviso_tool variable - all traced nodes.
-%% -----------------------------------------------------------------------------
-
-inviso:tpl(Nodes,math,module_info,1,[]).
-inviso:tf(Nodes,ProcessName,[call]).
-lists:foreach(fun(N)->rpc:call(N,ets,update_counter,[test_proc_tab,counter,1]) end,
- Nodes).
-timer:sleep(500).
-%% END-OF-TRACE-CASE
-
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase2_off.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase2_off.trc deleted file mode 100644 index cc89c3aa03..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase2_off.trc +++ /dev/null @@ -1,12 +0,0 @@ -%% TRACECASE2_OFF.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% The tracecase is mainly used for testing that synchronous tracecases return
-%% values.
-%%
-%% Nodes=list(), inviso_tool variable - all traced nodes.
-%% -----------------------------------------------------------------------------
-
-inviso:ctpl(Nodes,math,pi,0).
-another_return_value.
-%% END-OF-TRACE-CASE
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase2_on.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase2_on.trc deleted file mode 100644 index a3ab5fcfc7..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase2_on.trc +++ /dev/null @@ -1,16 +0,0 @@ -%% TRACECASE2_ON.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% The tracecase is mainly used for testing that synchronous tracecases return
-%% values.
-%% We also use this tracecase to check that reactivation works when it comes to
-%% handling simulataneously issued tool commands (issued during reactivation).
-%%
-%% Nodes=list(), inviso_tool variable - all traced nodes.
-%% -----------------------------------------------------------------------------
-
-inviso:tpl(Nodes,math,pi,0,[]).
-timer:sleep(3000).
-a_return_value.
-%% END-OF-TRACE-CASE
-
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase3_on.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase3_on.trc deleted file mode 100644 index e6c5ff78b1..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase3_on.trc +++ /dev/null @@ -1,9 +0,0 @@ -%% TRACECASE3_ON.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% It is faulty and meant to cause a crash!
-%% -----------------------------------------------------------------------------
-
-1=2.
-%% END-OF-TRACE-CASE
-
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase4_on.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase4_on.trc deleted file mode 100644 index d14c11f78c..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase4_on.trc +++ /dev/null @@ -1,9 +0,0 @@ -%% TRACECASE4_ON.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% It contains an infinity timer in order for the tracecase executer to hang.
-%% -----------------------------------------------------------------------------
-
-timer:sleep(infinity).
-%% END-OF-TRACE-CASE
-
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase5_off.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase5_off.trc deleted file mode 100644 index feb67acb11..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase5_off.trc +++ /dev/null @@ -1,11 +0,0 @@ -%% TRACECASE5_OFF.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% Contains a 2 second sleep.
-%% -----------------------------------------------------------------------------
-
-lists:foreach(fun(N)->rpc:call(N,ets,update_counter,[test_proc_tab,counter,1]) end,
- Nodes).
-timer:sleep(2000).
-%% END-OF-TRACE-CASE
-
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase5_on.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase5_on.trc deleted file mode 100644 index 724c617c5a..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase5_on.trc +++ /dev/null @@ -1,11 +0,0 @@ -%% TRACECASE5_ON.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% This tracecase updates an ETS table. Can be used to verify that it has been
-%% done (or not done!).
-%% -----------------------------------------------------------------------------
-
-lists:foreach(fun(N)->rpc:call(N,ets,update_counter,[test_proc_tab,counter,1]) end,
- Nodes).
-%% END-OF-TRACE-CASE
-
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase_def.txt b/lib/inviso/test/inviso_tool_SUITE_data/tracecase_def.txt deleted file mode 100644 index 5b08fa32a5..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase_def.txt +++ /dev/null @@ -1,8 +0,0 @@ -{tracecase_init,on,[],"./tracecase_init.trc"}.
-{tracecase1,on_off,['ProcessName'],"./tracecase1_on.trc","./tracecase1_off.trc"}.
-{tracecase2,on_off,[],"./tracecase2_on.trc","./tracecase2_off.trc"}.
-{tracecase3,on,[],"./tracecase3_on.trc"}.
-{tracecase4,on,[],"./tracecase4_on.trc"}.
-{tracecase5,on_off,[],"./tracecase5_on.trc","./tracecase5_off.trc"}.
-
-
diff --git a/lib/inviso/test/inviso_tool_SUITE_data/tracecase_init.trc b/lib/inviso/test/inviso_tool_SUITE_data/tracecase_init.trc deleted file mode 100644 index 49a79cd3a5..0000000000 --- a/lib/inviso/test/inviso_tool_SUITE_data/tracecase_init.trc +++ /dev/null @@ -1,10 +0,0 @@ -%% TRACECASE_INIT.TRC
-%% -----------------------------------------------------------------------------
-%% This is a test trace case to be used by the inviso_tool_SUITE.
-%% Initial trace case executed at session start.
-%%
-%% Nodes=list(), inviso_tool variable - all traced nodes.
-%% -----------------------------------------------------------------------------
-
-inviso:tpl(Nodes,lists,module_info,1,[]).
-%% END-OF-TRACE-CASE
diff --git a/lib/inviso/vsn.mk b/lib/inviso/vsn.mk deleted file mode 100644 index c6b0398bde..0000000000 --- a/lib/inviso/vsn.mk +++ /dev/null @@ -1 +0,0 @@ -INVISO_VSN = 0.6.3 diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index ee687511a3..bb111a2242 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -728,16 +728,13 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>is_module_native(Module) -> boolean() | undefined</name> + <name name="is_module_native" arity="1"/> <fsummary>Test whether a module has native code</fsummary> - <type> - <v>Module = module()</v> - </type> <desc> - <p>This function returns <c>true</c> if <c>Module</c> is + <p>This function returns <c>true</c> if <c><anno>Module</anno></c> is name of a loaded module that has native code loaded, and - <c>false</c> if <c>Module</c> is loaded but does not have - native. If <c>Module</c> is not loaded, this function returns + <c>false</c> if <c><anno>Module</anno></c> is loaded but does not have + native. If <c><anno>Module</anno></c> is not loaded, this function returns <c>undefined</c>.</p> </desc> </func> diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index 1911fb628e..26db11cfcd 100644 --- a/lib/kernel/doc/src/erl_ddll.xml +++ b/lib/kernel/doc/src/erl_ddll.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2011</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -182,11 +182,8 @@ </datatypes> <funcs> <func> - <name>demonitor(MonitorRef) -> ok</name> + <name name="demonitor" arity="1"/> <fsummary>Remove a monitor for a driver</fsummary> - <type> - <v>MonitorRef = reference()</v> - </type> <desc> <p>Removes a driver monitor in much the same way as <seealso marker="erts:erlang#erlang:demonitor/1">erlang:demonitor/1</seealso> does with process @@ -232,24 +229,19 @@ </desc> </func> <func> - <name>info(Name, Tag) -> Value</name> + <name name="info" arity="2"/> <fsummary>Retrieve specific information about one driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>Tag = processes | driver_options | port_count | linked_in_driver | permanent | awaiting_load | awaiting_unload</v> - <v>Value = term()</v> - </type> <desc> <p>This function returns specific information about one aspect - of a driver. The <c>Tag</c> parameter specifies which aspect - to get information about. The <c>Value</c> return differs + of a driver. The <c><anno>Tag</anno></c> parameter specifies which aspect + to get information about. The <c><anno>Value</anno></c> return differs between different tags:</p> <taglist> <tag><em>processes</em></tag> <item> <p>Return all processes containing <seealso marker="#users">users</seealso> of the specific drivers - as a list of tuples <c>{pid(),int()}</c>, where the - <c>int()</c> denotes the number of users in the process + as a list of tuples <c>{pid(),integer() >= 0}</c>, where the + <c>integer()</c> denotes the number of users in the process <c>pid()</c>.</p> </item> <tag><em>driver_options</em></tag> @@ -261,16 +253,16 @@ </item> <tag><em>port_count</em></tag> <item> - <p>Return the number of ports (an <c>int()</c>) using the driver.</p> + <p>Return the number of ports (an <c>integer >= 0()</c>) using the driver.</p> </item> <tag><em>linked_in_driver</em></tag> <item> - <p>Return a <c>bool()</c>, being <c>true</c> if the driver is a + <p>Return a <c>boolean()</c>, being <c>true</c> if the driver is a statically linked in one and <c>false</c> otherwise.</p> </item> <tag><em>permanent</em></tag> <item> - <p>Return a <c>bool()</c>, being <c>true</c> if the driver has made + <p>Return a <c>boolean()</c>, being <c>true</c> if the driver has made itself permanent (and is <em>not</em> a statically linked in driver). <c>false</c> otherwise.</p> </item> @@ -278,14 +270,14 @@ <item> <p>Return a list of all processes having monitors for <c>loading</c> active, each process returned as - <c>{pid(),int()}</c>, where the <c>int()</c> is the + <c>{pid(),integer() >= 0}</c>, where the <c>integer()</c> is the number of monitors held by the process <c>pid()</c>.</p> </item> <tag><em>awaiting_unload</em></tag> <item> <p>Return a list of all processes having monitors for <c>unloading</c> active, each process returned as - <c>{pid(),int()}</c>, where the <c>int()</c> is the + <c>{pid(),integer() >= 0}</c>, where the <c>integer()</c> is the number of monitors held by the process <c>pid()</c>.</p> </item> </taglist> @@ -377,41 +369,34 @@ </desc> </func> <func> - <name>monitor(Tag, Item) -> MonitorRef</name> + <name name="monitor" arity="2"/> <fsummary>Create a monitor for a driver</fsummary> - <type> - <v>Tag = driver </v> - <v>Item = {Name, When}</v> - <v>Name = atom() | string()</v> - <v>When = loaded | unloaded | unloaded_only</v> - <v>MonitorRef = reference()</v> - </type> <desc> <p>This function creates a driver monitor and works in many ways as the function <seealso marker="erts:erlang#erlang:monitor/2">erlang:monitor/2</seealso>, does for processes. When a driver changes state, the monitor results in a monitor-message being sent to the calling - process. The <c>MonitorRef</c> returned by this function is + process. The <c><anno>MonitorRef</anno></c> returned by this function is included in the message sent.</p> <p>As with process monitors, each driver monitor set will only generate <em>one single message</em>. The monitor is "destroyed" after the message is sent and there is then no need to call <seealso marker="#demonitor/1">demonitor/1</seealso>.</p> - <p>The <c>MonitorRef</c> can also be used in subsequent calls + <p>The <c><anno>MonitorRef</anno></c> can also be used in subsequent calls to <seealso marker="#demonitor/1">demonitor/1</seealso> to remove a monitor.</p> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Tag</em></tag> + <tag><em><anno>Tag</anno></em></tag> <item> <p>The monitor tag is always <c>driver</c> as this function can only be used to create driver monitors. In the future, driver monitors will be integrated with process monitors, why this parameter has to be given for consistence.</p> </item> - <tag><em>Item</em></tag> + <tag><em><anno>Item</anno></em></tag> <item> - <p>The <c>Item</c> parameter specifies which driver one + <p>The <c><anno>Item</anno></c> parameter specifies which driver one wants to monitor (the name of the driver) as well as which state change one wants to monitor. The parameter is a tuple of arity two whose first element is the @@ -588,22 +573,8 @@ </desc> </func> <func> - <name>try_load(Path, Name, OptionList) -> {ok,Status} | {ok, PendingStatus, Ref} | {error, ErrorDesc}</name> + <name name="try_load" arity="3"/> <fsummary>Load a driver</fsummary> - <type> - <v>Path = Name = string() | atom()</v> - <v>OptionList = [ Option ]</v> - <v>Option = {driver_options, DriverOptionList} | {monitor, MonitorOption} | {reload, ReloadOption}</v> - <v>DriverOptionList = [ DriverOption ]</v> - <v>DriverOption = kill_ports</v> - <v>MonitorOption = pending_driver | pending</v> - <v>ReloadOption = pending_driver | pending</v> - <v>Status = loaded | already_loaded | PendingStatus </v> - <v>PendingStatus = pending_driver | pending_process</v> - <v>Ref = reference()</v> - <v>ErrorDesc = ErrorAtom | OpaqueError</v> - <v>ErrorAtom = linked_in_driver | inconsistent | permanent | not_loaded_by_this_process | not_loaded | pending_reload | pending_process</v> - </type> <desc> <p>This function provides more control than the <c>load/2</c>/<c>reload/2</c> and @@ -655,65 +626,65 @@ <p>When the function returns <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c>, one might want to get information about when the driver is <em>actually</em> loaded. This can - be achieved by using the <c>{monitor, PendingOption}</c> option.</p> + be achieved by using the <c>{monitor, <anno>MonitorOption</anno>}</c> option.</p> <p>When monitoring is requested, and a corresponding <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c> would be - returned, the function will instead return a tuple <c>{ok, PendingStatus, reference()}</c> and the process will, at a later + returned, the function will instead return a tuple <c>{ok, <anno>PendingStatus</anno>, reference()}</c> and the process will, at a later time when the driver actually gets loaded, get a monitor message. The monitor message one can expect is described in the <seealso marker="#monitor/2">monitor/2</seealso> function description. </p> <note> <p>Note that in case of loading, monitoring can - <em>not</em> only get triggered by using the <c>{reload, ReloadOption}</c> option, but also in special cases where + <em>not</em> only get triggered by using the <c>{reload, <anno>ReloadOption</anno>}</c> option, but also in special cases where the load-error is transient, why <c>{monitor, pending_driver}</c> should be used under basically <em>all</em> real world circumstances!</p> </note> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Path</em></tag> + <tag><em><anno>Path</anno></em></tag> <item> <p>The filesystem path to the directory where the driver object file is situated. The filename of the object file (minus extension) must correspond to the driver name (used in the name parameter) and the driver must identify itself with the very same name. The - <c>Path</c> might be provided as an <em>io_list</em>, - meaning it can be a list of other io_lists, characters + <c><anno>Path</anno></c> might be provided as an <em>iolist()</em>, + meaning it can be a list of other <c>iolist()</c>s, characters (eight bit integers) or binaries, all to be flattened into a sequence of characters.</p> - <p>The (possibly flattened) <c>Path</c> parameter must be + <p>The (possibly flattened) <c><anno>Path</anno></c> parameter must be consistent throughout the system, a driver should, by all <seealso marker="#users">users</seealso>, be loaded - using the same <em>literal</em><c>Path</c>. The + using the same <em>literal</em><c><anno>Path</anno></c>. The exception is when <em>reloading</em> is requested, in - which case the <c>Path</c> may be specified + which case the <c><anno>Path</anno></c> may be specified differently. Note that all <seealso marker="#users">users</seealso> trying to load the - driver at a later time will need to use the <em>new</em><c>Path</c> if the <c>Path</c> is changed using a + driver at a later time will need to use the <em>new</em><c><anno>Path</anno></c> if the <c><anno>Path</anno></c> is changed using a <c>reload</c> option. This is yet another reason to have <em>only one loader</em> of a driver one wants to upgrade in a running system! </p> </item> - <tag><em>Name</em></tag> + <tag><em><anno>Name</anno></em></tag> <item> <p>The name parameter is the name of the driver to be used in subsequent calls to <seealso marker="erts:erlang#open_port/2">open_port</seealso>. The - name can be specified either as an <c>io_list()</c> or + name can be specified either as an <c>iolist()</c> or as an <c>atom()</c>. The name given when loading is used to find the actual object file (with the - help of the <c>Path</c> and the system implied + help of the <c><anno>Path</anno></c> and the system implied extension suffix, i.e. <c>.so</c>). The name by which the driver identifies itself must also be consistent - with this <c>Name</c> parameter, much as a beam-file's + with this <c><anno>Name</anno></c> parameter, much as a beam-file's module name much correspond to its filename.</p> </item> - <tag><em>OptionList</em></tag> + <tag><em><anno>OptionList</anno></em></tag> <item> <p>A number of options can be specified to control the loading operation. The options are given as a list of two-tuples, the tuples having the following values and meanings:</p> <taglist> - <tag><em>{driver_options, DriverOptionsList}</em></tag> + <tag><em>{driver_options, <anno>DriverOptionList</anno>}</em></tag> <item> <p>This option is to provide options that will change its general behavior and will "stick" to the driver @@ -729,14 +700,14 @@ when the last <seealso marker="#users">user</seealso> calls <seealso marker="#try_unload/2">try_unload/2</seealso>, or the last process having loaded the driver exits.</p> </item> - <tag><em>{monitor, MonitorOption}</em></tag> + <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag> <item> - <p>A <c>MonitorOption</c> tells <c>try_load/3</c> to + <p>A <c><anno>MonitorOption</anno></c> tells <c>try_load/3</c> to trigger a driver monitor under certain conditions. When the monitor is triggered, the - function will return a three-tuple <c>{ok, PendingStatus, reference()}</c>, where the <c>reference()</c> is + function will return a three-tuple <c>{ok, <anno>PendingStatus</anno>, reference()}</c>, where the <c>reference()</c> is the monitor ref for the driver monitor.</p> - <p>Only one <c>MonitorOption</c> can be specified and + <p>Only one <c><anno>MonitorOption</anno></c> can be specified and it is either the atom <c>pending</c>, which means that a monitor should be created whenever a load operation is delayed, and the atom @@ -747,7 +718,7 @@ is present for completeness, it is very well defined which reload-options might give rise to which delays. It might, however, be a good idea to use the - same <c>MonitorOption</c> as the <c>ReloadOption</c> + same <c><anno>MonitorOption</anno></c> as the <c><anno>ReloadOption</anno></c> if present.</p> <p>If reloading is not requested, it might still be useful to specify the <c>monitor</c> option, as @@ -760,12 +731,12 @@ <c>{monitor, pending_driver}</c> in production code (see the monitor discussion above). </p> </item> - <tag><em>{reload,RealoadOption}</em></tag> + <tag><em>{reload,<anno>ReloadOption</anno>}</em></tag> <item> <p>This option is used when one wants to <em>reload</em> a driver from disk, most often in a code upgrade scenario. Having a <c>reload</c> option - also implies that the <c>Path</c> parameter need + also implies that the <c><anno>Path</anno></c> parameter need <em>not</em> be consistent with earlier loads of the driver.</p> <p>To reload a driver, the process needs to have previously @@ -814,9 +785,9 @@ <tag><em>{error,inconsistent}</em></tag> <item> <p>The driver has already been loaded with either other - <c>DriverOptions</c> or a different <em>literal</em><c>Path</c> argument.</p> + <c><anno>DriverOptionList</anno></c> or a different <em>literal</em><c>Path</c> argument.</p> <p>This can happen even if a <c>reload</c> option is given, - if the <c>DriverOptions</c> differ from the current.</p> + if the <c>DriverOptionList</c> differ from the current.</p> </item> <tag><em>{error, permanent}</em></tag> <item> @@ -830,19 +801,19 @@ </item> <tag><em>{error, pending_reload}</em></tag> <item> - <p>Driver reload is already requested by another <seealso marker="#users">user</seealso> when the <c>{reload, ReloadOption}</c> option was given.</p> + <p>Driver reload is already requested by another <seealso marker="#users">user</seealso> when the <c>{reload, <anno>ReloadOption</anno>}</c> option was given.</p> </item> <tag><em>{error, not_loaded_by_this_process}</em></tag> <item> <p>Appears when the <c>reload</c> option is given. The - driver <c>Name</c> is present in the system, but there is no + driver <c><anno>Name</anno></c> is present in the system, but there is no <seealso marker="#users">user</seealso> of it in this process.</p> </item> <tag><em>{error, not_loaded}</em></tag> <item> <p>Appears when the <c>reload</c> option is given. The - driver <c>Name</c> is not in the system. Only drivers + driver <c><anno>Name</anno></c> is not in the system. Only drivers loaded by this process can be reloaded.</p> </item> </taglist> @@ -856,18 +827,8 @@ </desc> </func> <func> - <name>try_unload(Name, OptionList) -> {ok,Status} | {ok, PendingStatus, Ref} | {error, ErrorAtom}</name> + <name name="try_unload" arity="2"/> <fsummary>Unload a driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>OptionList = [ Option ]</v> - <v>Option = {monitor, MonitorOption} | kill_ports</v> - <v>MonitorOption = pending_driver | pending</v> - <v>Status = unloaded | PendingStatus </v> - <v>PendingStatus = pending_driver | pending_process</v> - <v>Ref = reference()</v> - <v>ErrorAtom = linked_in_driver | not_loaded | not_loaded_by_this_process | permanent</v> - </type> <desc> <p>This is the low level function to unload (or decrement reference counts of) a driver. It can be used to force port @@ -948,15 +909,15 @@ </taglist> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Name</em></tag> + <tag><em><anno>Name</anno></em></tag> <item> <p>The name parameter is the name of the driver to be unloaded. The name can be specified either as an - <c>io_list()</c> or as an <c>atom()</c>. </p> + <c>iolist()</c> or as an <c>atom()</c>. </p> </item> - <tag><em>OptionList</em></tag> + <tag><em><anno>OptionList</anno></em></tag> <item> - <p>The <c>OptionList</c> argument can be used to specify + <p>The <c><anno>OptionList</anno></c> argument can be used to specify certain behavior regarding ports as well as triggering monitors under certain conditions:</p> <taglist> @@ -972,10 +933,10 @@ unloads, one should use the driver option <c>kill_ports</c> when loading the driver instead.</p> </item> - <tag><em>{monitor, MonitorOption}</em></tag> + <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag> <item> <p>This option creates a driver monitor if the condition - given in <c>MonitorOptions</c> is true. The valid + given in <c><anno>MonitorOption</anno></c> is true. The valid options are:</p> <taglist> <tag><em>pending_driver</em></tag> @@ -989,7 +950,7 @@ <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c>.</p> </item> </taglist> - <p>The <c>pending_driver</c> <c>MonitorOption</c> is by far + <p>The <c>pending_driver</c> <c><anno>MonitorOption</anno></c> is by far the most useful and it has to be used to ensure that the driver has really been unloaded and the ports closed whenever the <c>kill_ports</c> option is used or the @@ -1016,11 +977,11 @@ </item> <tag><em>{error, not_loaded}</em></tag> <item> - <p>The driver <c>Name</c> is not present in the system.</p> + <p>The driver <c><anno>Name</anno></c> is not present in the system.</p> </item> <tag><em>{error, not_loaded_by_this_process}</em></tag> <item> - <p>The driver <c>Name</c> is present in the system, but + <p>The driver <c><anno>Name</anno></c> is present in the system, but there is no <seealso marker="#users">user</seealso> of it in this process. </p> <p>As a special case, drivers can be unloaded from @@ -1088,12 +1049,8 @@ </desc> </func> <func> - <name>loaded_drivers() -> {ok, Drivers}</name> + <name name="loaded_drivers" arity="0"/> <fsummary>List loaded drivers</fsummary> - <type> - <v>Drivers = [Driver]</v> - <v>Driver = string()</v> - </type> <desc> <p>Returns a list of all the available drivers, both (statically) linked-in and dynamically loaded ones.</p> diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml index ec3274965a..cd86b364f6 100644 --- a/lib/kernel/doc/src/error_logger.xml +++ b/lib/kernel/doc/src/error_logger.xml @@ -127,11 +127,8 @@ ok</pre> </desc> </func> <func> - <name>warning_map() -> Tag</name> + <name name="warning_map" arity="0"/> <fsummary>Return the current mapping for warning events</fsummary> - <type> - <v>Tag = error | warning | info</v> - </type> <desc> <p>Returns the current mapping for warning events. Events sent using <c>warning_msg/1,2</c> or <c>warning_report/1,2</c> diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 772eff13cc..b2a259080d 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -412,7 +412,7 @@ </desc> </func> <func> - <name>file_info(Filename) -> {ok, FileInfo} | {error, Reason}</name> + <name name="file_info" arity="1"/> <fsummary>Get information about a file (deprecated)</fsummary> <desc> <p>This function is obsolete. Use <c>read_file_info/1,2</c> @@ -598,7 +598,7 @@ </desc> </func> <func> - <name>native_name_encoding() -> latin1 | utf8</name> + <name name="native_name_encoding" arity="0"/> <fsummary>Return the VM's configured filename encoding.</fsummary> <desc> <p>This function returns the configured default file name encoding to use for raw file names. Generally an application supplying file names raw (as binaries), should obey the character encoding returned by this function.</p> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index b727960d96..32b4a429dd 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -446,16 +446,6 @@ fe80::204:acff:fe17:bf38 faster than the receiver can read.</p> </item> - <tag><c>{bit8, clear | set | on | off}</c></tag> - <item> - <p> - Scans every byte in received data-packets and checks if the 8 bit - is set in any of them. Information is retrieved with - <c>inet:getopts/2</c>. - </p> - <p>Note that the <c>bit8</c> option is deprecated and will be removed in Erlang/OTP R16.</p> - </item> - <tag><c>{broadcast, Boolean}</c>(UDP sockets)</tag> <item> <p>Enable/disable permission to send broadcasts.</p> diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml index e94119845a..621ca6e9ee 100644 --- a/lib/kernel/doc/src/os.xml +++ b/lib/kernel/doc/src/os.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2011</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -73,7 +73,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </desc> </func> <func> - <name>getenv() -> [string()]</name> + <name name="getenv" arity="0"/> <fsummary>List all environment variables</fsummary> <desc> <p>Returns a list of all environment variables. @@ -83,55 +83,40 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </desc> </func> <func> - <name>getenv(VarName) -> Value | false</name> + <name name="getenv" arity="1"/> <fsummary>Get the value of an environment variable</fsummary> - <type> - <v>VarName = string() </v> - <v>Value = string()</v> - </type> <desc> - <p>Returns the <c>Value</c> of the environment variable - <c>VarName</c>, or <c>false</c> if the environment variable + <p>Returns the <c><anno>Value</anno></c> of the environment variable + <c><anno>VarName</anno></c>, or <c>false</c> if the environment variable is undefined.</p> </desc> </func> <func> - <name>getpid() -> Value </name> + <name name="getpid" arity="0"/> <fsummary>Return the process identifier of the emulator process</fsummary> - <type> - <v>Value = string()</v> - </type> <desc> <p>Returns the process identifier of the current Erlang emulator in the format most commonly used by the operating system - environment. <c>Value</c> is returned as a string containing + environment. <c><anno>Value</anno></c> is returned as a string containing the (usually) numerical identifier for a process. On Unix, this is typically the return value of the <c>getpid()</c> - system call. On VxWorks, <c>Value</c> contains the task id - (decimal notation) of the Erlang task. On Windows, + system call. On Windows, the process id as returned by the <c>GetCurrentProcessId()</c> system call is used.</p> </desc> </func> <func> - <name>putenv(VarName, Value) -> true</name> + <name name="putenv" arity="2"/> <fsummary>Set a new value for an environment variable</fsummary> - <type> - <v>VarName = string() </v> - <v>Value = string()</v> - </type> <desc> - <p>Sets a new <c>Value</c> for the environment variable - <c>VarName</c>.</p> + <p>Sets a new <c><anno>Value</anno></c> for the environment variable + <c><anno>VarName</anno></c>.</p> </desc> </func> <func> - <name>timestamp() -> Timestamp</name> + <name name="timestamp" arity="0"/> + <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc> <fsummary>Returna a timestamp from the OS in the erlang:now/0 format</fsummary> - <type> - <v>Timestamp = {MegaSecs, Secs, MicroSecs} = <seealso marker="erts:erlang#type-timestamp">erlang:timestamp()</seealso></v> - <v>MegaSecs = Secs = MicroSecs = integer() >= 0</v> - </type> <desc> <p>Returns a tuple in the same format as <seealso marker="erts:erlang#now/0">erlang:now/0</seealso>. The difference is that this function returns what the operating system thinks (a.k.a. the wall clock time) without any attempts at time correction. The result of two different calls to this function is <em>not</em> guaranteed to be different.</p> <p>The most obvious use for this function is logging. The tuple can be used together with the function <seealso marker="stdlib:calendar#now_to_universal_time/1">calendar:now_to_universal_time/1</seealso> @@ -168,8 +153,6 @@ format_utc_timestamp() -> Solaris 1 and 2, it will be <c>sunos</c>.</p> <p>In Windows, <c><anno>Osname</anno></c> will be either <c>nt</c> (on Windows NT), or <c>windows</c> (on Windows 95).</p> - <p>On VxWorks the OS family alone is returned, that is - <c>vxworks</c>.</p> <note> <p>Think twice before using this function. Use the <c>filename</c> module if you want to inspect or build diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 363072951e..c808ac7cb7 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -70,46 +70,6 @@ -include_lib("kernel/include/file.hrl"). -%% User interface. -%% -%% objfile_extension() -> ".beam" -%% get_path() -> [Dir] -%% set_path([Dir]) -> true | {error, bad_directory | bad_path} -%% add_path(Dir) -> true | {error, bad_directory} -%% add_patha(Dir) -> true | {error, bad_directory} -%% add_pathz(Dir) -> true | {error, bad_directory} -%% add_paths([Dir]) -> ok -%% add_pathsa([Dir]) -> ok -%% add_pathsz([Dir]) -> ok -%% del_path(Dir) -> boolean() | {error, bad_name} -%% replace_path(Name, Dir) -> true | {error, bad_directory | bad_name -%% | {badarg,_}} -%% load_file(Module) -> {module, Module} | {error, What :: atom()} -%% load_abs(File) -> {module, Module} | {error, What :: atom()} -%% load_abs(File, Module) -> {module, Module} | {error, What :: atom()} -%% load_binary(Module, File, Bin)-> {module, Module} | {error, What :: atom()} -%% ensure_loaded(Module) -> {module, Module} | {error, What :: atom()} -%% delete(Module) -> boolean() -%% purge(Module) -> boolean() kills all procs running old code -%% soft_purge(Module) -> boolean() -%% is_loaded(Module) -> {file, loaded_filename()} | false -%% all_loaded() -> [{Module, loaded_filename()}] -%% get_object_code(Module) -> {Module, Bin, Filename} | error -%% stop() -> no_return() -%% root_dir() -> Dir -%% compiler_dir() -> Dir -%% lib_dir() -> Dir -%% lib_dir(Application) -> Dir | {error, bad_name} -%% priv_dir(Application) -> Dir | {error, bad_name} -%% stick_dir(Dir) -> ok | error -%% unstick_dir(Dir) -> ok | error -%% stick_mod(Module) -> true -%% unstick_mod(Module) -> true -%% is_sticky(Module) -> boolean() -%% which(Module) -> Filename | loaded_ret_atoms() | non_existing -%% set_primary_archive((FileName, ArchiveBin, FileInfo, ParserFun) -> ok | {error, Reason} -%% clash() -> ok prints out number of clashes - %%---------------------------------------------------------------------------- %% Some types for basic exported functions of this module %%---------------------------------------------------------------------------- @@ -125,6 +85,39 @@ -type loaded_ret_atoms() :: 'cover_compiled' | 'preloaded'. -type loaded_filename() :: (Filename :: file:filename()) | loaded_ret_atoms(). +%%% BIFs + +-export([get_chunk/2, is_module_native/1, make_stub_module/3, module_md5/1]). + +-spec get_chunk(Bin, Chunk) -> + binary() | undefined when + Bin :: binary(), + Chunk :: string(). + +get_chunk(_, _) -> + erlang:nif_error(undef). + +-spec is_module_native(Module) -> true | false | undefined when + Module :: module(). + +is_module_native(_) -> + erlang:nif_error(undef). + +-spec make_stub_module(Module, Beam, Info) -> Module when + Module :: module(), + Beam :: binary(), + Info :: {list(), list()}. + +make_stub_module(_, _, _) -> + erlang:nif_error(undef). + +-spec module_md5(binary()) -> binary() | undefined. + +module_md5(_) -> + erlang:nif_error(undef). + +%%% End of BIFs + %%---------------------------------------------------------------------------- %% User interface %%---------------------------------------------------------------------------- diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl index 266df84a03..0cb1ed579a 100644 --- a/lib/kernel/src/disk_log_1.erl +++ b/lib/kernel/src/disk_log_1.erl @@ -1495,7 +1495,7 @@ fwrite_close2(Fd, FileName, B) -> pwrite_close2(Fd, FileName, Position, B) -> case file:pwrite(Fd, Position, B) of ok -> ok; - Error -> file_error(FileName, {error, Error}) + {error,Error} -> file_error(FileName, {error, Error}) end. position2(Fd, FileName, Pos) -> diff --git a/lib/kernel/src/erl_ddll.erl b/lib/kernel/src/erl_ddll.erl index 646cac99c5..f967fcc2ef 100644 --- a/lib/kernel/src/erl_ddll.erl +++ b/lib/kernel/src/erl_ddll.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,9 +30,99 @@ %%---------------------------------------------------------------------------- -type path() :: string() | atom(). --type driver() :: string() | atom(). +-type driver() :: iolist() | atom(). %%---------------------------------------------------------------------------- +%%% BIFs + +-export([demonitor/1, info/2, format_error_int/1, monitor/2, + try_load/3, try_unload/2, loaded_drivers/0]). + +-spec demonitor(MonitorRef) -> ok when + MonitorRef :: reference(). + +demonitor(_) -> + erlang:nif_error(undef). + +-spec info(Name, Tag) -> Value when + Name :: driver(), + Tag :: processes | driver_options | port_count | linked_in_driver + | permanent | awaiting_load | awaiting_unload, + Value :: term(). + +info(_, _) -> + erlang:nif_error(undef). + +-spec format_error_int(ErrSpec) -> string() when + ErrSpec :: inconsisten | linked_in_driver | permanent + | not_loaded | not_loaded_by_this_process | not_pending + | already_loaded | unloading. + +format_error_int(_) -> + erlang:nif_error(undef). + +-spec monitor(Tag, Item) -> MonitorRef when + Tag :: driver, + Item :: {Name, When}, + Name :: driver(), + When :: loaded | unloaded | unloaded_only, + MonitorRef :: reference(). + +monitor(_, _) -> + erlang:nif_error(undef). + +-spec try_load(Path, Name, OptionList) -> + {ok,Status} | + {ok, PendingStatus, Ref} | + {error, ErrorDesc} when + Path :: path(), + Name :: driver(), + OptionList :: [Option], + Option :: {driver_options, DriverOptionList} + | {monitor, MonitorOption} + | {reload, ReloadOption}, + DriverOptionList :: [DriverOption], + DriverOption :: kill_ports, + MonitorOption :: pending_driver | pending, + ReloadOption :: pending_driver | pending, + Status :: loaded | already_loaded | PendingStatus, + PendingStatus :: pending_driver | pending_process, + Ref :: reference(), + ErrorDesc :: ErrorAtom | OpaqueError, + ErrorAtom :: linked_in_driver | inconsistent | permanent + | not_loaded_by_this_process | not_loaded + | pending_reload | pending_process, + OpaqueError :: term(). + +try_load(_, _, _) -> + erlang:nif_error(undef). + +-spec try_unload(Name, OptionList) -> + {ok, Status} | + {ok, PendingStatus, Ref} | + {error, ErrorAtom} when + Name :: driver(), + OptionList :: [Option], + Option :: {monitor, MonitorOption} | kill_ports, + MonitorOption :: pending_driver | pending, + Status :: unloaded | PendingStatus, + PendingStatus :: pending_driver | pending_process, + Ref :: reference(), + ErrorAtom :: linked_in_driver | not_loaded | + not_loaded_by_this_process | permanent. + +try_unload(_, _) -> + erlang:nif_error(undef). + +-spec loaded_drivers() -> {ok, Drivers} when + Drivers :: [Driver], + Driver :: string(). + +loaded_drivers() -> + erlang:nif_error(undef). + +%%% End of BIFs + -spec start() -> {'error', {'already_started', 'undefined'}}. diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl index a67b11a888..f8bc5f499c 100644 --- a/lib/kernel/src/error_handler.erl +++ b/lib/kernel/src/error_handler.erl @@ -90,7 +90,7 @@ int() -> int. crash(Fun, Args) -> crash({Fun,Args,[]}). --spec crash(atom(), atom(), arity()) -> no_return(). +-spec crash(atom(), atom(), arity() | [term()]) -> no_return(). crash(M, F, A) -> crash({M,F,A,[]}). diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl index f94cca000f..92c1eb80dc 100644 --- a/lib/kernel/src/error_logger.erl +++ b/lib/kernel/src/error_logger.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -42,6 +42,18 @@ -type state() :: {non_neg_integer(), non_neg_integer(), [term()]}. +%%% BIF + +-export([warning_map/0]). + +-spec warning_map() -> Tag when + Tag :: error | warning | info. + +warning_map() -> + erlang:nif_error(undef). + +%%% End of BIF + %%----------------------------------------------------------------- -spec start() -> {'ok', pid()} | {'error', any()}. diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl index b8871e0d45..6654cd9ee7 100644 --- a/lib/kernel/src/erts_debug.erl +++ b/lib/kernel/src/erts_debug.erl @@ -28,6 +28,135 @@ %% same/2 %% flat_size/1 +%%% BIFs + +-export([breakpoint/2, disassemble/1, display/1, dist_ext_to_term/2, + dump_monitors/1, dump_links/1, flat_size/1, + get_internal_state/1, instructions/0, lock_counters/1, + same/2, set_internal_state/2]). + +-spec breakpoint(MFA, Flag) -> non_neg_integer() when + MFA :: {Module :: module(), + Function :: atom(), + Arity :: arity() | '_'}, + Flag :: boolean(). + +breakpoint(_, _) -> + erlang:nif_error(undef). + +-spec disassemble(What) -> false | undef | Result when + What :: MFA | Address, + Result :: {Address, Code, MFA}, + MFA :: mfa(), + Address :: non_neg_integer(), + Code :: binary(). + +disassemble(_) -> + erlang:nif_error(undef). + +-spec display(Term) -> string() when + Term :: term(). + +display(_) -> + erlang:nif_error(undef). + +-spec dist_ext_to_term(Tuple, Binary) -> term() when + Tuple :: tuple(), + Binary :: binary(). + +dist_ext_to_term(_, _) -> + erlang:nif_error(undef). + +-spec dump_monitors(Id) -> true when + Id :: pid() | atom(). + +dump_monitors(_) -> + erlang:nif_error(undef). + +-spec dump_links(Id) -> true when + Id :: pid() | port() | atom(). + +dump_links(_) -> + erlang:nif_error(undef). + +-spec flat_size(Term) -> non_neg_integer() when + Term :: term(). + +flat_size(_) -> + erlang:nif_error(undef). + +-spec get_internal_state(W) -> term() when + W :: reds_left | node_and_dist_references | monitoring_nodes + | next_pid | 'DbTable_words' | check_io_debug + | process_info_args | processes | processes_bif_info + | max_atom_out_cache_index | nbalance | available_internal_state + | force_heap_frags | memory + | {process_status, pid()} + | {link_list, pid() | port() | node()} + | {monitor_list, pid() | node()} + | {channel_number, non_neg_integer()} + | {have_pending_exit, pid() | port() | atom()} + | {binary_info, binary()} + | {term_to_binary_no_funs, term()} + | {dist_port, port()} + | {atom_out_cache_index, atom()} + | {fake_scheduler_bindings, + default_bind | spread | processor_spread | thread_spread + | thread_no_node_processor_spread | no_node_processor_spread + | no_node_thread_spread | no_spread | unbound} + | {reader_groups_map, non_neg_integer()}. + +get_internal_state(_) -> + erlang:nif_error(undef). + +-spec instructions() -> [string()]. + +instructions() -> + erlang:nif_error(undef). + +-spec lock_counters(info) -> term(); + (clear) -> ok; + ({copy_save, boolean()}) -> boolean(); + ({process_locks, boolean()}) -> boolean(). + +lock_counters(_) -> + erlang:nif_error(undef). + +-spec same(Term1, Term2) -> boolean() when + Term1 :: term(), + Term2 :: term(). + +same(_, _) -> + erlang:nif_error(undef). + +-spec set_internal_state(available_internal_state, boolean()) -> boolean(); + (reds_left, non_neg_integer()) -> true; + (block, non_neg_integer()) -> true; + (sleep, non_neg_integer()) -> true; + (block_scheduler, non_neg_integer()) -> true; + (next_pid, non_neg_integer()) -> false | integer(); + (force_gc, pid() | atom()) -> boolean(); + (send_fake_exit_signal, {pid() | port(), pid(), term()}) -> dead | message | unaffected | exit; + (colliding_names, {atom(), non_neg_integer()}) -> + [atom()]; + (binary_loop_limit, default) -> -1; + (binary_loop_limit, non_neg_integer()) -> non_neg_integer(); + (re_loop_limit, default) -> -1; + (re_loop_limit, non_neg_integer()) -> non_neg_integer(); + (unicode_loop_limit, default) -> -1; + (unicode_loop_limit, non_neg_integer()) -> non_neg_integer(); + (hipe_test_reschedule_suspend, term()) -> nil(); + (hipe_test_reschedule_resume, pid() | port()) -> boolean(); + (test_long_gc_sleep, non_neg_integer()) -> true; + (kill_dist_connection, port()) -> boolean(); + (not_running_optimization, boolean()) -> boolean(); + (wait, deallocations) -> ok. + +set_internal_state(_, _) -> + erlang:nif_error(undef). + +%%% End of BIFs + %% size(Term) %% Returns the size of Term in actual heap words. Shared subterms are %% counted once. Example: If A = [a,b], B =[A,A] then size(B) returns 8, diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index cdb984c333..22af38c598 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -111,6 +111,24 @@ -type sendfile_option() :: {chunk_size, non_neg_integer()}. -type file_info_option() :: {'time', 'local'} | {'time', 'universal'} | {'time', 'posix'}. +%%% BIFs + +-export([file_info/1, native_name_encoding/0]). + +-spec file_info(Filename) -> {ok, FileInfo} | {error, Reason} when + Filename :: name(), + FileInfo :: file_info(), + Reason :: posix() | badarg. + +file_info(_) -> + erlang:nif_error(undef). + +-spec native_name_encoding() -> latin1 | utf8. + +native_name_encoding() -> + erlang:nif_error(undef). + +%%% End of BIFs %%%----------------------------------------------------------------- diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index 8b3aa0286d..06d404905d 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -34,6 +34,13 @@ -module(hipe_unified_loader). +-compile(no_native). +% 'no_native' is a workaround to avoid "The code server called unloaded module" +% caused by Mod:module_info(exports) in patch_to_emu_step1() called by post_beam_load. +% Reproducable with hipelibs and asn1_SUITE. +% I think the real solution would be to let BIF erlang:load_module/2 redirect all +% hipe calls to the module and thereby remove post_beam_load. + -export([chunk_name/1, %% Only the code and code_server modules may call the entries below! load_native_code/2, @@ -330,11 +337,16 @@ exports(ExportMap, BaseAddress) -> exports(ExportMap, BaseAddress, [], []). exports([Offset,M,F,A,IsClosure,IsExported|Rest], BaseAddress, MFAs, Addresses) -> - MFA = {M,F,A}, - Address = BaseAddress + Offset, - FunDef = #fundef{address=Address, mfa=MFA, is_closure=IsClosure, - is_exported=IsExported}, - exports(Rest, BaseAddress, [MFA|MFAs], [FunDef|Addresses]); + case IsExported andalso erlang:is_builtin(M, F, A) of + true -> + exports(Rest, BaseAddress, MFAs, Addresses); + _false -> + MFA = {M,F,A}, + Address = BaseAddress + Offset, + FunDef = #fundef{address=Address, mfa=MFA, is_closure=IsClosure, + is_exported=IsExported}, + exports(Rest, BaseAddress, [MFA|MFAs], [FunDef|Addresses]) + end; exports([], _, MFAs, Addresses) -> {MFAs, Addresses}. @@ -498,7 +510,7 @@ patch_offset(Type, Data, Address, ConstAndZone, Addresses) -> Atom = Data, patch_atom(Address, Atom); sdesc -> - patch_sdesc(Data, Address, ConstAndZone); + patch_sdesc(Data, Address, ConstAndZone, Addresses); x86_abs_pcrel -> patch_instr(Address, Data, x86_abs_pcrel) %% _ -> @@ -511,14 +523,16 @@ patch_atom(Address, Atom) -> patch_instr(Address, hipe_bifs:atom_to_word(Atom), atom). patch_sdesc(?STACK_DESC(SymExnRA, FSize, Arity, Live), - Address, {_ConstMap2,CodeAddress}) -> + Address, {_ConstMap2,CodeAddress}, _Addresses) -> ExnRA = case SymExnRA of [] -> 0; % No catch LabelOffset -> CodeAddress + LabelOffset end, ?ASSERT(assert_local_patch(Address)), - hipe_bifs:enter_sdesc({Address, ExnRA, FSize, Arity, Live}). + DBG_MFA = ?IF_DEBUG(address_to_mfa_lth(Address, _Addresses), {undefined,undefined,0}), + hipe_bifs:enter_sdesc({Address, ExnRA, FSize, Arity, Live, DBG_MFA}). + %%---------------------------------------------------------------- %% Handle a 'load_address'-type patch. @@ -725,7 +739,7 @@ find_const(ConstNo, []) -> %% add_ref(CalleeMFA, Address, Addresses, RefType, Trampoline, RemoteOrLocal) -> - CallerMFA = address_to_mfa(Address, Addresses), + CallerMFA = address_to_mfa_lth(Address, Addresses), %% just a sanity assertion below true = case RemoteOrLocal of local -> @@ -738,11 +752,31 @@ add_ref(CalleeMFA, Address, Addresses, RefType, Trampoline, RemoteOrLocal) -> %% io:format("Adding ref ~w\n",[{CallerMFA, CalleeMFA, Address, RefType}]), hipe_bifs:add_ref(CalleeMFA, {CallerMFA,Address,RefType,Trampoline,RemoteOrLocal}). -address_to_mfa(Address, [#fundef{address=Adr, mfa=MFA}|_Rest]) when Address >= Adr -> MFA; -address_to_mfa(Address, [_ | Rest]) -> address_to_mfa(Address, Rest); -address_to_mfa(Address, []) -> - ?error_msg("Local adddress not found ~w\n",[Address]), - exit({?MODULE, local_address_not_found}). +% For FunDefs sorted from low to high addresses +address_to_mfa_lth(Address, FunDefs) -> + case address_to_mfa_lth(Address, FunDefs, false) of + false -> + ?error_msg("Local adddress not found ~w\n",[Address]), + exit({?MODULE, local_address_not_found}); + MFA -> + MFA + end. + +address_to_mfa_lth(Address, [#fundef{address=Adr, mfa=MFA}|Rest], Prev) -> + if Address < Adr -> + Prev; + true -> + address_to_mfa_lth(Address, Rest, MFA) + end; +address_to_mfa_lth(_Address, [], Prev) -> + Prev. + +% For FunDefs sorted from high to low addresses +%% address_to_mfa_htl(Address, [#fundef{address=Adr, mfa=MFA}|_Rest]) when Address >= Adr -> MFA; +%% address_to_mfa_htl(Address, [_ | Rest]) -> address_to_mfa_htl(Address, Rest); +%% address_to_mfa_htl(Address, []) -> +%% ?error_msg("Local adddress not found ~w\n",[Address]), +%% exit({?MODULE, local_address_not_found}). %%---------------------------------------------------------------- %% Change callers of the given module to instead trap to BEAM. diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 0bb5444dbb..41460c948b 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -535,7 +535,7 @@ options() -> buffer, header, active, packet, deliver, mode, multicast_if, multicast_ttl, multicast_loop, exit_on_close, high_watermark, low_watermark, - bit8, send_timeout, send_timeout_close + send_timeout, send_timeout_close ]. %% Return a list of statistics options @@ -552,7 +552,7 @@ stats() -> connect_options() -> [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, header, active, packet, packet_size, buffer, mode, deliver, - exit_on_close, high_watermark, low_watermark, bit8, send_timeout, + exit_on_close, high_watermark, low_watermark, send_timeout, send_timeout_close, delay_send,raw]. connect_options(Opts, Family) -> @@ -608,7 +608,7 @@ con_add(Name, Val, R, Opts, AllOpts) -> listen_options() -> [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, header, active, packet, buffer, mode, deliver, backlog, - exit_on_close, high_watermark, low_watermark, bit8, send_timeout, + exit_on_close, high_watermark, low_watermark, send_timeout, send_timeout_close, delay_send, packet_size,raw]. listen_options(Opts, Family) -> @@ -1255,7 +1255,10 @@ tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) -> _ -> case prim_inet:getopt(S, active) of {ok, A0} -> - prim_inet:setopt(S, active, false), + case A0 of + false -> ok; + _ -> prim_inet:setopt(S, active, false) + end, case tcp_sync_input(S, NewOwner, false) of true -> %% socket already closed, ok; @@ -1263,7 +1266,10 @@ tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) -> try erlang:port_connect(S, NewOwner) of true -> unlink(S), %% unlink from port - prim_inet:setopt(S, active, A0), + case A0 of + false -> ok; + _ -> prim_inet:setopt(S, active, A0) + end, ok catch error:Reason -> diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl index 1ddbdcec25..526baca335 100644 --- a/lib/kernel/src/inet_config.erl +++ b/lib/kernel/src/inet_config.erl @@ -197,16 +197,6 @@ do_load_resolv({win32,Type}, longnames) -> win32_load_from_registry(Type), inet_db:set_lookup([native]); -do_load_resolv(vxworks, _) -> - vxworks_load_hosts(), - inet_db:set_lookup([file, dns]), - case os:getenv("ERLRESCONF") of - false -> - no_ERLRESCONF; - Resolv -> - load_resolv(Resolv, resolv) - end; - do_load_resolv(_, _) -> inet_db:set_lookup([native]). @@ -408,55 +398,6 @@ win32_get_strings(Reg, [Name|Rest], Result) -> win32_get_strings(_, [], Result) -> lists:reverse(Result). -%% -%% Load host data from VxWorks hostShow command -%% - -vxworks_load_hosts() -> - HostShow = os:cmd("hostShow"), - case check_hostShow(HostShow) of - Hosts when is_list(Hosts) -> - case inet_parse:hosts_vxworks({chars, Hosts}) of - {ok, Ls} -> - foreach( - fun({IP, Name, Aliases}) -> - inet_db:add_host(IP, [Name|Aliases]) - end, - Ls); - {error,Reason} -> - error("parser error VxWorks hostShow ~s", [Reason]) - end; - _Error -> - error("error in VxWorks hostShow~s~n", [HostShow]) - end. - -%% -%% Check if hostShow yields at least two line; the first one -%% starting with "hostname", the second one starting with -%% "--------". -%% Returns: list of hosts in VxWorks notation -%% rows of 'Name IP [Aliases] \n' -%% if hostShow yielded these two lines, false otherwise. -check_hostShow(HostShow) -> - check_hostShow(["hostname", "--------"], HostShow). - -check_hostShow([], HostShow) -> - HostShow; -check_hostShow([String_match|Rest], HostShow) -> - case lists:prefix(String_match, HostShow) of - true -> - check_hostShow(Rest, next_line(HostShow)); - false -> - false - end. - -next_line([]) -> - []; -next_line([$\n|Rest]) -> - Rest; -next_line([_First|Rest]) -> - next_line(Rest). - read_rc() -> {RcFile,CfgList} = read_inetrc(), case extract_cfg_files(CfgList, [], []) of diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index cf893c73eb..467c4d5065 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -134,7 +134,6 @@ -define(INET_LOPT_EXITONCLOSE, 26). -define(INET_LOPT_TCP_HIWTRMRK, 27). -define(INET_LOPT_TCP_LOWTRMRK, 28). --define(INET_LOPT_BIT8, 29). -define(INET_LOPT_TCP_SEND_TIMEOUT, 30). -define(INET_LOPT_TCP_DELAY_SEND, 31). -define(INET_LOPT_PACKET_SIZE, 32). @@ -186,12 +185,6 @@ -define(TCP_PB_HTTP_BIN,13). -define(TCP_PB_HTTPH_BIN,14). -%% bit options, INET_LOPT_BIT8 --define(INET_BIT8_CLEAR, 0). --define(INET_BIT8_SET, 1). --define(INET_BIT8_ON, 2). --define(INET_BIT8_OFF, 3). - %% getstat, INET_REQ_GETSTAT -define(INET_STAT_RECV_CNT, 1). diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl index 65edddcb46..ba62a59068 100644 --- a/lib/kernel/src/inet_parse.erl +++ b/lib/kernel/src/inet_parse.erl @@ -23,7 +23,6 @@ %% Avoid warning for local function error/2 clashing with autoimported BIF. -compile({no_auto_import,[error/2]}). -export([hosts/1, hosts/2]). --export([hosts_vxworks/1]). -export([protocols/1, protocols/2]). -export([netmasks/1, netmasks/2]). -export([networks/1, networks/2]). @@ -107,18 +106,6 @@ hosts(Fname,File) -> parse_file(Fname, File, Fn). %% -------------------------------------------------------------------------- -%% Parse hostShow vxworks style -%% Syntax: -%% Name IP [Aliases] \n -%% -------------------------------------------------------------------------- -hosts_vxworks(Hosts) -> - Fn = fun([Name, Address | Aliases]) -> - {ok,IP} = address(Address), - {IP, Name, Aliases} - end, - parse_file(Hosts, Fn). - -%% -------------------------------------------------------------------------- %% Parse resolv file unix style %% Syntax: %% domain Domain \n @@ -291,9 +278,6 @@ networks(Fname, File) -> %% %% -------------------------------------------------------------------------- -parse_file(File, Fn) -> - parse_file(noname, File, Fn). - parse_file(Fname, {fd,Fd}, Fn) -> parse_fd(Fname,Fd, 1, Fn, []); parse_file(Fname, {chars,Cs}, Fn) when is_list(Cs) -> diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index bded2408a7..54628800a8 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -17,11 +17,11 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max two major revisions back - [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13 + [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14 %% Down to - max two major revisions back - [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13 + [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14 }. diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index 9e3d730cee..0d59e7af67 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -142,6 +142,17 @@ -include("net_address.hrl"). +%%% BIF + +-export([dflag_unicode_io/1]). + +-spec dflag_unicode_io(pid()) -> boolean(). + +dflag_unicode_io(_) -> + erlang:nif_error(undef). + +%%% End of BIF + %% Interface functions kernel_apply(M,F,A) -> request({apply,M,F,A}). diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index f6769df585..e20a2434b4 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,16 +24,48 @@ -include("file.hrl"). --spec type() -> vxworks | {Osfamily, Osname} when +%%% BIFs + +-export([getenv/0, getenv/1, getpid/0, putenv/2, timestamp/0]). + +-spec getenv() -> [string()]. + +getenv() -> erlang:nif_error(undef). + +-spec getenv(VarName) -> Value | false when + VarName :: string(), + Value :: string(). + +getenv(_) -> + erlang:nif_error(undef). + +-spec getpid() -> Value when + Value :: string(). + +getpid() -> + erlang:nif_error(undef). + +-spec putenv(VarName, Value) -> true when + VarName :: string(), + Value :: string(). + +putenv(_, _) -> + erlang:nif_error(undef). + +-spec timestamp() -> Timestamp when + Timestamp :: erlang:timestamp(). + +timestamp() -> + erlang:nif_error(undef). + +%%% End of BIFs + +-spec type() -> {Osfamily, Osname} when Osfamily :: unix | win32, Osname :: atom(). type() -> - case erlang:system_info(os_type) of - {vxworks, _} -> - vxworks; - Else -> Else - end. + erlang:system_info(os_type). -spec version() -> VersionString | {Major, Minor, Release} when VersionString :: string(), @@ -83,25 +115,14 @@ find_executable1(_Name, [], _Extensions) -> verify_executable(Name0, [Ext|Rest], OrigExtensions) -> Name1 = Name0 ++ Ext, - case os:type() of - vxworks -> - %% We consider all existing VxWorks files to be executable - case file:read_file_info(Name1) of - {ok, _} -> - {ok, Name1}; - _ -> - verify_executable(Name0, Rest, OrigExtensions) - end; + case file:read_file_info(Name1) of + {ok, #file_info{type=regular,mode=Mode}} + when Mode band 8#111 =/= 0 -> + %% XXX This test for execution permission is not fool-proof + %% on Unix, since we test if any execution bit is set. + {ok, Name1}; _ -> - case file:read_file_info(Name1) of - {ok, #file_info{type=regular,mode=Mode}} - when Mode band 8#111 =/= 0 -> - %% XXX This test for execution permission is not fool-proof - %% on Unix, since we test if any execution bit is set. - {ok, Name1}; - _ -> - verify_executable(Name0, Rest, OrigExtensions) - end + verify_executable(Name0, Rest, OrigExtensions) end; verify_executable(Name, [], OrigExtensions) when OrigExtensions =/= [""] -> %% Windows %% Will only happen on windows, hence case insensitivity @@ -154,8 +175,7 @@ reverse_element(List) -> extensions() -> case type() of {win32, _} -> [".exe",".com",".cmd",".bat"]; - {unix, _} -> [""]; - vxworks -> [""] + {unix, _} -> [""] end. %% Executes the given command in the default shell for the operating system. @@ -173,11 +193,6 @@ cmd(Cmd) -> {Cspec,_} -> lists:concat([Cspec," /c",Cmd]) end, Port = open_port({spawn, Command}, [stream, in, eof, hide]), - get_data(Port, []); - %% VxWorks uses a 'sh -c hook' in 'vxcall.c' to run os:cmd. - vxworks -> - Command = lists:concat(["sh -c '", Cmd, "'"]), - Port = open_port({spawn, Command}, [stream, in, eof]), get_data(Port, []) end. diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 3e8bdaf1ff..69197d4915 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -25,6 +25,7 @@ replace_path/1, load_file/1, load_abs/1, ensure_loaded/1, delete/1, purge/1, soft_purge/1, is_loaded/1, all_loaded/1, load_binary/1, dir_req/1, object_code/1, set_path_file/1, + upgrade/1, sticky_dir/1, pa_pz_option/1, add_del_path/1, dir_disappeared/1, ext_mod_dep/1, clash/1, load_cached/1, start_node_with_cache/1, add_and_rehash/1, @@ -43,6 +44,8 @@ handle_event/2, handle_call/2, handle_info/2, terminate/2]). +-export([compile_load/4]). + suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -50,6 +53,7 @@ all() -> replace_path, load_file, load_abs, ensure_loaded, delete, purge, soft_purge, is_loaded, all_loaded, load_binary, dir_req, object_code, set_path_file, + upgrade, pa_pz_option, add_del_path, dir_disappeared, ext_mod_dep, clash, load_cached, start_node_with_cache, add_and_rehash, where_is_file_no_cache, @@ -450,6 +454,46 @@ load_binary(Config) when is_list(Config) -> code:delete(code_b_test), ok. +upgrade(Config) -> + DataDir = ?config(data_dir, Config), + + %%T = [beam, hipe], + T = [beam], + + [upgrade_do(DataDir, Client, U1, U2, O1, O2) + || Client<-T, U1<-T, U2<-T, O1<-T, O2<-T], + + ok. + +upgrade_do(DataDir, Client, U1, U2, O1, O2) -> + compile_load(upgrade_client, DataDir, undefined, Client), + upgrade_client:run(DataDir, U1, U2, O1, O2), + ok. + +compile_load(Mod, Dir, Ver, CodeType) -> + Version = case Ver of + undefined -> + io:format("Compiling '~p' as ~p\n", [Mod, CodeType]), + []; + _ -> + io:format("Compiling version ~p of '~p' as ~p\n", + [Ver, Mod, CodeType]), + [{d,list_to_atom("VERSION_" ++ integer_to_list(Ver))}] + end, + Target = case CodeType of + beam -> []; + hipe -> [native] + end, + CompOpts = [binary, report] ++ Target ++ Version, + + Src = filename:join(Dir, atom_to_list(Mod) ++ ".erl"), + %io:format("compile:file(~p,~p)\n", [Src, CompOpts]), + {ok,Mod,Code} = compile:file(Src, CompOpts), + ObjFile = filename:basename(Src,".erl") ++ ".beam", + {module,Mod} = code:load_binary(Mod, ObjFile, Code), + %IsNative = code:is_module_native(Mod), + ok. + dir_req(suite) -> []; dir_req(doc) -> []; dir_req(Config) when is_list(Config) -> @@ -535,30 +579,25 @@ sticky_compiler(File) -> pa_pz_option(suite) -> []; pa_pz_option(doc) -> ["Test that the -pa and -pz options work as expected"]; pa_pz_option(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Slave nodes not supported on VxWorks"}; - _ -> - DDir = ?config(data_dir,Config), - PaDir = filename:join(DDir,"pa"), - PzDir = filename:join(DDir,"pz"), - ?line {ok, Node}=?t:start_node(pa_pz1, slave, - [{args, - "-pa " ++ PaDir - ++ " -pz " ++ PzDir}]), - ?line Ret=rpc:call(Node, code, get_path, []), - ?line [PaDir|Paths] = Ret, - ?line [PzDir|_] = lists:reverse(Paths), - ?t:stop_node(Node), - ?line {ok, Node2}=?t:start_node(pa_pz2, slave, - [{args, - "-mode embedded " ++ "-pa " - ++ PaDir ++ " -pz " ++ PzDir}]), - ?line Ret2=rpc:call(Node2, code, get_path, []), - ?line [PaDir|Paths2] = Ret2, - ?line [PzDir|_] = lists:reverse(Paths2), - ?t:stop_node(Node2) - end. + DDir = ?config(data_dir,Config), + PaDir = filename:join(DDir,"pa"), + PzDir = filename:join(DDir,"pz"), + {ok, Node}=?t:start_node(pa_pz1, slave, + [{args, + "-pa " ++ PaDir + ++ " -pz " ++ PzDir}]), + Ret=rpc:call(Node, code, get_path, []), + [PaDir|Paths] = Ret, + [PzDir|_] = lists:reverse(Paths), + ?t:stop_node(Node), + {ok, Node2}=?t:start_node(pa_pz2, slave, + [{args, + "-mode embedded " ++ "-pa " + ++ PaDir ++ " -pz " ++ PzDir}]), + Ret2=rpc:call(Node2, code, get_path, []), + [PaDir|Paths2] = Ret2, + [PzDir|_] = lists:reverse(Paths2), + ?t:stop_node(Node2). add_del_path(suite) -> []; diff --git a/lib/kernel/test/code_SUITE_data/other.erl b/lib/kernel/test/code_SUITE_data/other.erl new file mode 100644 index 0000000000..58ce87f222 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/other.erl @@ -0,0 +1,38 @@ +-module(other). + +-ifdef(VERSION_1). +-define(VERSION,1). +-export([exp1/0]). +-export([exp1loc2/0]). +-export([exp1exp2/0]). +exp1() -> check([loc1(),exp1loc2(),exp1exp2(),loc1exp2(),loc1loc2()]). +loc1() -> check([exp1loc2(),exp1exp2(),loc1exp2(),loc1loc2()]). +exp1loc2() -> check([exp1exp2(),loc1exp2(),loc1loc2()]). +exp1exp2() -> check([loc1exp2(),loc1loc2()]). +loc1exp2() -> check([loc1loc2()]). +-endif. % VERSION_1 + +-ifdef(VERSION_2). +-define(VERSION,2). +-export([exp2/0]). +-export([loc1exp2/0]). +-export([exp1exp2/0]). +loc1exp2() -> check([exp1exp2(),exp1loc2(),loc2(),exp2(),loc1loc2()]). +exp1exp2() -> check([exp1loc2(),loc2(),exp2(),loc1loc2()]). +exp1loc2() -> check([loc2(),exp2(),loc1loc2()]). +loc2() -> check([exp2(),loc1loc2()]). +exp2() -> check([loc1loc2()]). + +-endif. % VERSION_2 + +loc1loc2() -> ?VERSION. + + +check(VerList) -> + case lists:all(fun(?VERSION) -> true; (_) -> false end, + VerList) of + true -> + ?VERSION; + false -> + VerList + end. diff --git a/lib/kernel/test/code_SUITE_data/upgrade_client.erl b/lib/kernel/test/code_SUITE_data/upgrade_client.erl new file mode 100644 index 0000000000..bb655e01d3 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/upgrade_client.erl @@ -0,0 +1,259 @@ +-module(upgrade_client). + +-export([run/5]). + +%%-define(line, io:format("~s:~p\n", [?MODULE,?LINE]),). +-define(line,). + +run(Dir, Upgradee1, Upgradee2, Other1, Other2) -> + %% Load version 1 of upgradee + code_SUITE:compile_load(upgradee, Dir, 1, Upgradee1), + + ?line 1 = upgradee:exp1(), + ?line 1 = upgradee:exp1exp2(), + ?line 1 = upgradee:exp1loc2(), + + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1loc2()), + + P = spawn_link(upgradee,dispatch_loop,[]), + + ?line 1 = proxy_call(P, local, exp1), + ?line 1 = proxy_call(P, local, loc1), + ?line 1 = proxy_call(P, local, exp1exp2), + ?line 1 = proxy_call(P, local, exp1loc2), + ?line 1 = proxy_call(P, local, loc1exp2), + ?line 1 = proxy_call(P, local, loc1loc2), + ?line 1 = proxy_call(P, external, exp1), + ?line 1 = proxy_call(P, external, exp1exp2), + ?line 1 = proxy_call(P, external, exp1loc2), + + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc2), + ?line {cannot_compile,1} = proxy_call(P, local, exp2), + ?line {cannot_compile,1} = proxy_call(P, local, loc2), + + ?line {'EXIT',{undef,_}} = (catch other:exp1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:exp1exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc11exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + %% + %% Load version 1 of other + %% + code_SUITE:compile_load(other, Dir, 1, Other1), + ?line 1 = other:exp1(), + ?line 1 = other:exp1loc2(), + ?line 1 = other:exp1exp2(), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + + ?line 1 = proxy_call(P, other, exp1), + ?line 1 = proxy_call(P, other, exp1loc2), + ?line 1 = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + %% + %% Load version 2 of upgradee + %% + code_SUITE:compile_load(upgradee, Dir, 2, Upgradee2), + + ?line 2 = upgradee:exp2(), + ?line 2 = upgradee:exp1exp2(), + ?line 2 = upgradee:loc1exp2(), + + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc2()), + + ?line 1 = proxy_call(P, local, exp1), + ?line 1 = proxy_call(P, local, loc1), + ?line 1 = proxy_call(P, local, exp1exp2), + ?line 1 = proxy_call(P, local, exp1loc2), + ?line 1 = proxy_call(P, local, loc1exp2), + ?line 1 = proxy_call(P, local, loc1loc2), + ?line {cannot_compile,1} = proxy_call(P, local, exp2), + ?line {cannot_compile,1} = proxy_call(P, local, loc2), + + ?line 2 = proxy_call(P, external, exp1exp2), + ?line 2 = proxy_call(P, external, loc1exp2), + ?line 2 = proxy_call(P, external, exp2), + + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc2), + + ?line 1 = other:exp1(), + ?line 1 = other:exp1loc2(), + ?line 1 = other:exp1exp2(), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + + ?line 1 = proxy_call(P, other, exp1), + ?line 1 = proxy_call(P, other, exp1loc2), + ?line 1 = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + %% + %% Load version 2 of other + %% + code_SUITE:compile_load(other, Dir, 2, Other2), + + ?line 2 = upgradee:exp2(), + ?line 2 = upgradee:exp1exp2(), + ?line 2 = upgradee:loc1exp2(), + + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc2()), + + ?line 1 = proxy_call(P, local, exp1), + ?line 1 = proxy_call(P, local, loc1), + ?line 1 = proxy_call(P, local, exp1exp2), + ?line 1 = proxy_call(P, local, exp1loc2), + ?line 1 = proxy_call(P, local, loc1exp2), + ?line 1 = proxy_call(P, local, loc1loc2), + ?line {cannot_compile,1} = proxy_call(P, local, exp2), + ?line {cannot_compile,1} = proxy_call(P, local, loc2), + + ?line 2 = proxy_call(P, external, exp1exp2), + ?line 2 = proxy_call(P, external, loc1exp2), + ?line 2 = proxy_call(P, external, exp2), + + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc2), + + ?line 2 = other:exp2(), + ?line 2 = other:loc1exp2(), + ?line 2 = other:exp1exp2(), + ?line {'EXIT',{undef,_}} = (catch other:exp1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + + ?line 2 = proxy_call(P, other, exp2), + ?line 2 = proxy_call(P, other, loc1exp2), + ?line 2 = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + + %% + %% Upgrade proxy to version 2 + %% + P ! upgrade_order, + + + %% + io:format("Delete version 2 of 'upgradee'\n",[]), + %% + code:purge(upgradee), + code:delete(upgradee), + + ?line {'EXIT',{undef,_}} = (catch upgradee:exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc2()), + + ?line 2 = proxy_call(P, local, exp2), + ?line 2 = proxy_call(P, local, loc2), + ?line 2 = proxy_call(P, local, exp1exp2), + ?line 2 = proxy_call(P, local, exp1loc2), + ?line 2 = proxy_call(P, local, loc1exp2), + ?line 2 = proxy_call(P, local, loc1loc2), + ?line {cannot_compile,2} = proxy_call(P, local, exp1), + ?line {cannot_compile,2} = proxy_call(P, local, loc1), + + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc2), + + ?line 2 = other:exp2(), + ?line 2 = other:loc1exp2(), + ?line 2 = other:exp1exp2(), + ?line {'EXIT',{undef,_}} = (catch other:exp1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + + ?line 2 = proxy_call(P, other, exp2), + ?line 2 = proxy_call(P, other, loc1exp2), + ?line 2 = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + unlink(P), + exit(P, die_please), + + io:format("Purge 'upgradee'\n",[]), + code:purge(upgradee), + + io:format("Delete and purge 'other'\n",[]), + code:purge(other), + code:delete(other), + code:purge(other), + ok. + +proxy_call(Pid, CallType, Func) -> + Pid ! {self(), CallType, Func}, + receive + {Pid, call_result, Func, Ret} -> Ret + end. diff --git a/lib/kernel/test/code_SUITE_data/upgradee.erl b/lib/kernel/test/code_SUITE_data/upgradee.erl new file mode 100644 index 0000000000..62b1d95e30 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/upgradee.erl @@ -0,0 +1,123 @@ +-module(upgradee). + +-export([dispatch_loop/0]). + +-ifdef(VERSION_1). +-define(VERSION,1). + +-export([exp1/0]). % only exported in v1 +-export([exp1loc2/0]). % exported in v1, local in v2 +-export([exp1exp2/0]). % exported in v1 and v2 + +exp1() -> ?VERSION. +loc1() -> ?VERSION. + +-endif. % VERSION_1 + +-ifdef(VERSION_2). +-define(VERSION,2). + +-export([exp2/0]). +-export([loc1exp2/0]). +-export([exp1exp2/0]). + +exp2() -> ?VERSION. +loc2() -> ?VERSION. + +-endif. % VERSION_2 + +exp1exp2() -> ?VERSION. +exp1loc2() -> ?VERSION. +loc1exp2() -> ?VERSION. +loc1loc2() -> ?VERSION. + +dispatch_loop() -> + receive + upgrade_order -> + %%erlang:display({"upgradee version", ?VERSION, "got upgrade_order"}), + ?MODULE:dispatch_loop(); + + Msg -> + %%erlang:display({"upgradee version", ?VERSION, "got msg", Msg}), + {Func,Ret} = case Msg of + %% Local calls + {Pid, local, F=exp1} -> + {F, local_exp1()}; + {Pid, local, F=loc1} -> + {F, local_loc1()}; + {Pid, local, F=exp1exp2} -> + {F, catch exp1exp2()}; + {Pid, local, F=exp1loc2} -> + {F, catch exp1loc2()}; + {Pid, local, F=loc1exp2} -> + {F, catch loc1exp2()}; + {Pid, local, F=loc1loc2} -> + {F, catch loc1loc2()}; + {Pid, local, F=exp2} -> + {F, local_exp2()}; + {Pid, local, F=loc2} -> + {F, local_loc2()}; + + %% Extern calls to own module + {Pid, external, F=exp1} -> + {F, catch ?MODULE:exp1()}; + {Pid, external, F=loc1} -> + {F, catch ?MODULE:loc1()}; + {Pid, external, F=exp1exp2} -> + {F, catch ?MODULE:exp1exp2()}; + {Pid, external, F=exp1loc2} -> + {F, catch ?MODULE:exp1loc2()}; + {Pid, external, F=loc1exp2} -> + {F, catch ?MODULE:loc1exp2()}; + {Pid, external, F=loc1loc2} -> + {F, catch ?MODULE:loc1loc2()}; + {Pid, external, F=exp2} -> + {F, catch ?MODULE:exp2()}; + {Pid, external, F=loc2} -> + {F, catch ?MODULE:loc2()}; + + %% External calls to other module + {Pid, other, F=exp1} -> + {F, catch other:exp1()}; + {Pid, other, F=loc1} -> + {F, catch other:loc1()}; + {Pid, other, F=exp1exp2} -> + {F, catch other:exp1exp2()}; + {Pid, other, F=exp1loc2} -> + {F, catch other:exp1loc2()}; + {Pid, other, F=loc1exp2} -> + {F, catch other:loc1exp2()}; + {Pid, other, F=loc1loc2} -> + {F, catch other:loc1loc2()}; + {Pid, other, F=exp2} -> + {F, catch other:exp2()}; + {Pid, other, F=loc2} -> + {F, catch other:loc2()} + end, + Pid ! {self(), call_result, Func, Ret}, + + dispatch_loop() % A local call, we don't want to upgrade the dispatcher + end. + + + +-ifdef(VERSION_1). +local_exp1() -> catch exp1(). +local_loc1() -> catch loc1(). +-else. +local_exp1() -> + %%erlang:display({"upgradee:local_exp1 in version", ?VERSION}), + {cannot_compile,?VERSION}. +local_loc1() -> {cannot_compile,?VERSION}. +-endif. + +-ifdef(VERSION_2). +local_exp2() -> catch exp2(). +local_loc2() -> catch loc2(). +-else. +local_exp2() -> + %%erlang:display({"upgradee:local_exp2 in version", ?VERSION}), + {cannot_compile,?VERSION}. +local_loc2() -> + {cannot_compile,?VERSION}. +-endif. diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl index 0c3f5c3514..0f811b8f73 100644 --- a/lib/kernel/test/disk_log_SUITE.erl +++ b/lib/kernel/test/disk_log_SUITE.erl @@ -126,11 +126,6 @@ error, chunk, truncate, many_users, info, change_size, change_attribute, distribution, evil, otp_6278, otp_10131]). -%% The following two lists should be mutually exclusive. To skip a case -%% on VxWorks altogether, use the kernel.spec.vxworks file instead. -%% PLEASE don't skip out of laziness, the goal is to make every -%% testcase runnable on VxWorks. - %% These test cases should be skipped if the VxWorks card is %% configured without NFS cache. -define(SKIP_NO_CACHE,[distribution]). @@ -5126,33 +5121,8 @@ stop_node(Node) -> %% If the board is configured without NFS, the port program will fail to load %% and this will return 0, which may or may not be the wrong thing to do. -check_nfs(Config) -> - case (catch check_cache(Config)) of - N when is_integer(N) -> - N; - _ -> - 0 - end. - -check_cache(Config) -> - ?line Check = filename:join(?datadir(Config), "nfs_check"), - ?line P = open_port({spawn, Check}, [{line,100}, eof]), - ?line Size = receive - {P,{data,{eol,S}}} -> - list_to_integer(S) - after 1000 -> - erlang:display(got_timeout), - exit(timeout) - end, - ?line receive - {P, eof} -> - ok - end, - ?line P ! {self(), close}, - ?line receive - {P, closed} -> ok - end, - Size. +check_nfs(_Config) -> + 0. skip_expand([]) -> []; @@ -5175,13 +5145,8 @@ skip_list(Config) -> skip_expand(?SKIP_LARGE_CACHE) end. -should_skip(Test,Config) -> - case os:type() of - vxworks -> - lists:member(Test, skip_list(Config)); - _ -> - false - end. +should_skip(_Test,_Config) -> + false. %%----------------------------------------------------------------- %% The error_logger handler used. diff --git a/lib/kernel/test/disk_log_SUITE_data/Makefile.src b/lib/kernel/test/disk_log_SUITE_data/Makefile.src deleted file mode 100644 index cae2f23d29..0000000000 --- a/lib/kernel/test/disk_log_SUITE_data/Makefile.src +++ /dev/null @@ -1,15 +0,0 @@ -CC = @CC@ -LD = @LD@ -CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@ -CROSSLDFLAGS = @CROSSLDFLAGS@ - -PROGS = nfs_check@exe@ - -all: $(PROGS) - -nfs_check@exe@: nfs_check@obj@ - $(LD) $(CROSSLDFLAGS) -o nfs_check nfs_check@obj@ @LIBS@ - -nfs_check@obj@: nfs_check.c - $(CC) -c -o nfs_check@obj@ $(CFLAGS) nfs_check.c - diff --git a/lib/kernel/test/disk_log_SUITE_data/nfs_check.c b/lib/kernel/test/disk_log_SUITE_data/nfs_check.c deleted file mode 100644 index 31e9ba8190..0000000000 --- a/lib/kernel/test/disk_log_SUITE_data/nfs_check.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Author: Patrik Nyblom - * Purpose: A port program to check the NFS cache size on VxWorks (returns 0 - * for other platforms). - */ - -#ifdef VXWORKS -#include <vxWorks.h> -#include <taskVarLib.h> -#include <taskLib.h> -#include <sysLib.h> -#include <string.h> -#include <ioLib.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#ifdef VXWORKS -extern unsigned nfsCacheSize; -#define MAIN(argc, argv) nfs_check(argc, argv) -#else -#define MAIN(argc, argv) main(argc, argv) -#endif - - -MAIN(argc, argv) -int argc; -char *argv[]; -{ -#ifdef VXWORKS - char str[100]; - sprintf(str,"%d\n", nfsCacheSize); - write(1, str, strlen(str)); -#else - fprintf(stdout,"0"); - fflush(stdout); -#endif - return 0; -} - diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl index 72239641e9..35502a1d27 100644 --- a/lib/kernel/test/erl_prim_loader_SUITE.erl +++ b/lib/kernel/test/erl_prim_loader_SUITE.erl @@ -110,56 +110,46 @@ get_file(Config) when is_list(Config) -> inet_existing(doc) -> ["Start a node using the 'inet' loading method, ", "from an already started boot server."]; inet_existing(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "VxWorks: tested separately"}; - _ -> - ?line Name = erl_prim_test_inet_existing, - ?line Host = host(), - ?line Cookie = atom_to_list(erlang:get_cookie()), - ?line IpStr = ip_str(Host), - ?line LFlag = get_loader_flag(os:type()), - ?line Args = LFlag ++ " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, - ?line {ok, BootPid} = erl_boot_server:start_link([Host]), - ?line {ok, Node} = start_node(Name, Args), - ?line {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), - ?line stop_node(Node), - ?line unlink(BootPid), - ?line exit(BootPid, kill), - ok - end. + Name = erl_prim_test_inet_existing, + Host = host(), + Cookie = atom_to_list(erlang:get_cookie()), + IpStr = ip_str(Host), + LFlag = get_loader_flag(os:type()), + Args = LFlag ++ " -hosts " ++ IpStr ++ + " -setcookie " ++ Cookie, + {ok, BootPid} = erl_boot_server:start_link([Host]), + {ok, Node} = start_node(Name, Args), + {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), + stop_node(Node), + unlink(BootPid), + exit(BootPid, kill), + ok. inet_coming_up(doc) -> ["Start a node using the 'inet' loading method, ", "but start the boot server afterwards."]; inet_coming_up(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "VxWorks: tested separately"}; - _ -> - ?line Name = erl_prim_test_inet_coming_up, - ?line Cookie = atom_to_list(erlang:get_cookie()), - ?line Host = host(), - ?line IpStr = ip_str(Host), - ?line LFlag = get_loader_flag(os:type()), - ?line Args = LFlag ++ - " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, - ?line {ok, Node} = start_node(Name, Args, [{wait, false}]), - - %% Wait a while, then start boot server, and wait for node to start. - ?line test_server:sleep(test_server:seconds(6)), - io:format("erl_boot_server:start_link([~p]).", [Host]), - ?line {ok, BootPid} = erl_boot_server:start_link([Host]), - ?line wait_really_started(Node, 25), - - %% Check loader argument, then cleanup. - ?line {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), - ?line stop_node(Node), - ?line unlink(BootPid), - ?line exit(BootPid, kill), - ok - end. + Name = erl_prim_test_inet_coming_up, + Cookie = atom_to_list(erlang:get_cookie()), + Host = host(), + IpStr = ip_str(Host), + LFlag = get_loader_flag(os:type()), + Args = LFlag ++ + " -hosts " ++ IpStr ++ + " -setcookie " ++ Cookie, + {ok, Node} = start_node(Name, Args, [{wait, false}]), + + %% Wait a while, then start boot server, and wait for node to start. + test_server:sleep(test_server:seconds(6)), + io:format("erl_boot_server:start_link([~p]).", [Host]), + {ok, BootPid} = erl_boot_server:start_link([Host]), + wait_really_started(Node, 25), + + %% Check loader argument, then cleanup. + {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), + stop_node(Node), + unlink(BootPid), + exit(BootPid, kill), + ok. wait_really_started(Node, 0) -> test_server:fail({not_booted,Node}); @@ -249,8 +239,6 @@ multiple_slaves(doc) -> "verify that the boot server manages"]; multiple_slaves(Config) when is_list(Config) -> case os:type() of - vxworks -> - {comment, "VxWorks: tested separately"}; {ose,_} -> {comment, "OSE: multiple nodes not supported"}; _ -> diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 2b6af7e1fb..985aeb51e8 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -492,8 +492,6 @@ cur_dir_1(Config) when is_list(Config) -> ?line case os:type() of {unix, _} -> ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:"); - vxworks -> - ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:"); {win32, _} -> win_cur_dir_1(Config) end, @@ -1038,32 +1036,29 @@ file_info_basic_file(Config) when is_list(Config) -> file_info_basic_directory(suite) -> []; file_info_basic_directory(doc) -> []; file_info_basic_directory(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), + Dog = test_server:timetrap(test_server:seconds(5)), %% Note: filename:join/1 removes any trailing slash, %% which is essential for ?FILE_MODULE:file_info/1 to work on %% platforms such as Windows95. - ?line RootDir = filename:join([?config(priv_dir, Config)]), + RootDir = filename:join([?config(priv_dir, Config)]), %% Test that the RootDir directory has the expected attributes. - ?line test_directory(RootDir, read_write), + test_directory(RootDir, read_write), %% Note that on Windows file systems, %% "/" or "c:/" are *NOT* directories. %% Therefore, test that ?FILE_MODULE:file_info/1 behaves as if they were %% directories. - ?line case os:type() of - {win32, _} -> - ?line test_directory("/", read_write), - ?line test_directory("c:/", read_write), - ?line test_directory("c:\\", read_write); - {unix, _} -> - ?line test_directory("/", read); - vxworks -> - %% Check is just done for owner - ?line test_directory("/", read_write) - end, - ?line test_server:timetrap_cancel(Dog). + case os:type() of + {win32, _} -> + ?line test_directory("/", read_write), + ?line test_directory("c:/", read_write), + ?line test_directory("c:\\", read_write); + {unix, _} -> + ?line test_directory("/", read) + end, + test_server:timetrap_cancel(Dog). test_directory(Name, ExpectedAccess) -> ?line {ok,#file_info{size=Size,type=Type,access=Access, @@ -1784,9 +1779,7 @@ e_delete(Config) when is_list(Config) -> Base, #file_info {mode=8#600}); {win32, _} -> %% Remove a character device. - ?line {error, eacces} = ?FILE_MODULE:delete("nul"); - vxworks -> - ok + ?line {error, eacces} = ?FILE_MODULE:delete("nul") end, ?line [] = flush(), @@ -1801,148 +1794,133 @@ e_delete(Config) when is_list(Config) -> e_rename(suite) -> []; e_rename(doc) -> []; e_rename(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Windriver: dosFs must be fixed first!"}; - _ -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line RootDir = ?config(priv_dir, Config), - ?line Base = filename:join(RootDir, - atom_to_list(?MODULE)++"_e_rename"), - ?line ok = ?FILE_MODULE:make_dir(Base), - - %% Create an empty directory. - ?line EmptyDir = filename:join(Base, "empty_dir"), - ?line ok = ?FILE_MODULE:make_dir(EmptyDir), - - %% Create a non-empty directory. - ?line NonEmptyDir = filename:join(Base, "non_empty_dir"), - ?line ok = ?FILE_MODULE:make_dir(NonEmptyDir), - ?line ok = ?FILE_MODULE:write_file( - filename:join(NonEmptyDir, "a_file"), - "hello\n"), - - %% Create another non-empty directory. - ?line ADirectory = filename:join(Base, "a_directory"), - ?line ok = ?FILE_MODULE:make_dir(ADirectory), - ?line ok = ?FILE_MODULE:write_file( - filename:join(ADirectory, "a_file"), - "howdy\n\n"), - - %% Create a data file. - ?line File = filename:join(Base, "just_a_file"), - ?line ok = ?FILE_MODULE:write_file(File, "anything goes\n\n"), - - %% Move an existing directory to a non-empty directory. - ?line {error, eexist} = - ?FILE_MODULE:rename(ADirectory, NonEmptyDir), - - %% Move a root directory. - ?line {error, einval} = ?FILE_MODULE:rename("/", "arne"), - - %% Move Base into Base/new_name. - ?line {error, einval} = - ?FILE_MODULE:rename(Base, filename:join(Base, "new_name")), - - %% Overwrite a directory with a file. - ?line expect({error, eexist}, %FreeBSD (?) - {error, eisdir}, - ?FILE_MODULE:rename(File, EmptyDir)), - ?line expect({error, eexist}, %FreeBSD (?) - {error, eisdir}, - ?FILE_MODULE:rename(File, NonEmptyDir)), - - %% Move a non-existing file. - ?line NonExistingFile = - filename:join(Base, "non_existing_file"), - ?line {error, enoent} = - ?FILE_MODULE:rename(NonExistingFile, NonEmptyDir), - - %% Overwrite a file with a directory. - ?line expect({error, eexist}, %FreeBSD (?) - {error, enotdir}, - ?FILE_MODULE:rename(ADirectory, File)), - - %% Move a file to another filesystem. - %% XXX - This test case is bogus. We cannot be guaranteed that - %% the source and destination are on - %% different filesystems. - %% - %% XXX - Gross hack! - ?line Comment = - case os:type() of - {unix, _} -> - OtherFs = "/tmp", - ?line NameOnOtherFs = - filename:join(OtherFs, filename:basename(File)), - ?line {ok, Com} = - case ?FILE_MODULE:rename(File, NameOnOtherFs) of - {error, exdev} -> - %% The file could be in - %% the same filesystem! - {ok, ok}; - ok -> - {ok, {comment, - "Moving between filesystems " - "suceeded, files are probably " - "in the same filesystem!"}}; - {error, eperm} -> - {ok, {comment, "SBS! You don't " - "have the permission to do " - "this test!"}}; - Else -> - Else - end, - Com; - {win32, _} -> - %% At least Windows NT can - %% successfully move a file to - %% another drive. - ok - end, - ?line [] = flush(), - ?line test_server:timetrap_cancel(Dog), - Comment - end. + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = ?config(priv_dir, Config), + Base = filename:join(RootDir, + atom_to_list(?MODULE)++"_e_rename"), + ok = ?FILE_MODULE:make_dir(Base), + + %% Create an empty directory. + EmptyDir = filename:join(Base, "empty_dir"), + ok = ?FILE_MODULE:make_dir(EmptyDir), + + %% Create a non-empty directory. + NonEmptyDir = filename:join(Base, "non_empty_dir"), + ok = ?FILE_MODULE:make_dir(NonEmptyDir), + ok = ?FILE_MODULE:write_file( + filename:join(NonEmptyDir, "a_file"), + "hello\n"), + + %% Create another non-empty directory. + ADirectory = filename:join(Base, "a_directory"), + ok = ?FILE_MODULE:make_dir(ADirectory), + ok = ?FILE_MODULE:write_file( + filename:join(ADirectory, "a_file"), + "howdy\n\n"), + + %% Create a data file. + File = filename:join(Base, "just_a_file"), + ok = ?FILE_MODULE:write_file(File, "anything goes\n\n"), + + %% Move an existing directory to a non-empty directory. + {error, eexist} = ?FILE_MODULE:rename(ADirectory, NonEmptyDir), + + %% Move a root directory. + {error, einval} = ?FILE_MODULE:rename("/", "arne"), + + %% Move Base into Base/new_name. + {error, einval} = + ?FILE_MODULE:rename(Base, filename:join(Base, "new_name")), + + %% Overwrite a directory with a file. + expect({error, eexist}, %FreeBSD (?) + {error, eisdir}, + ?FILE_MODULE:rename(File, EmptyDir)), + expect({error, eexist}, %FreeBSD (?) + {error, eisdir}, + ?FILE_MODULE:rename(File, NonEmptyDir)), + + %% Move a non-existing file. + NonExistingFile = filename:join(Base, "non_existing_file"), + {error, enoent} = ?FILE_MODULE:rename(NonExistingFile, NonEmptyDir), + + %% Overwrite a file with a directory. + expect({error, eexist}, %FreeBSD (?) + {error, enotdir}, + ?FILE_MODULE:rename(ADirectory, File)), + + %% Move a file to another filesystem. + %% XXX - This test case is bogus. We cannot be guaranteed that + %% the source and destination are on + %% different filesystems. + %% + %% XXX - Gross hack! + Comment = case os:type() of + {unix, _} -> + OtherFs = "/tmp", + NameOnOtherFs = filename:join(OtherFs, filename:basename(File)), + {ok, Com} = case ?FILE_MODULE:rename(File, NameOnOtherFs) of + {error, exdev} -> + %% The file could be in + %% the same filesystem! + {ok, ok}; + ok -> + {ok, {comment, + "Moving between filesystems " + "suceeded, files are probably " + "in the same filesystem!"}}; + {error, eperm} -> + {ok, {comment, "SBS! You don't " + "have the permission to do " + "this test!"}}; + Else -> + Else + end, + Com; + {win32, _} -> + %% At least Windows NT can + %% successfully move a file to + %% another drive. + ok + end, + [] = flush(), + test_server:timetrap_cancel(Dog), + Comment. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% e_make_dir(suite) -> []; e_make_dir(doc) -> []; e_make_dir(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line RootDir = ?config(priv_dir, Config), - ?line Base = filename:join(RootDir, - atom_to_list(?MODULE)++"_e_make_dir"), - ?line ok = ?FILE_MODULE:make_dir(Base), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = ?config(priv_dir, Config), + Base = filename:join(RootDir, + atom_to_list(?MODULE)++"_e_make_dir"), + ok = ?FILE_MODULE:make_dir(Base), %% A component of the path does not exist. - ?line {error, enoent} = - ?FILE_MODULE:make_dir(filename:join([Base, "a", "b"])), + {error, enoent} = ?FILE_MODULE:make_dir(filename:join([Base, "a", "b"])), %% Use a path-name with a non-directory component. - ?line Afile = filename:join(Base, "a_directory"), - ?line ok = ?FILE_MODULE:write_file(Afile, "hello\n"), - ?line case ?FILE_MODULE:make_dir( - filename:join(Afile, "another_directory")) of - {error, enotdir} -> io:format("Result: enotdir"); - {error, enoent} -> io:format("Result: enoent") - end, + Afile = filename:join(Base, "a_directory"), + ok = ?FILE_MODULE:write_file(Afile, "hello\n"), + case ?FILE_MODULE:make_dir( + filename:join(Afile, "another_directory")) of + {error, enotdir} -> io:format("Result: enotdir"); + {error, enoent} -> io:format("Result: enoent") + end, %% No permission (on Unix only). case os:type() of {unix, _} -> - ?line ?FILE_MODULE:write_file_info(Base, #file_info {mode=0}), - ?line {error, eacces} = - ?FILE_MODULE:make_dir(filename:join(Base, "xxxx")), - ?line ?FILE_MODULE:write_file_info( + ?FILE_MODULE:write_file_info(Base, #file_info {mode=0}), + {error, eacces} = ?FILE_MODULE:make_dir(filename:join(Base, "xxxx")), + ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#600}); {win32, _} -> - ok; - vxworks -> ok end, - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1950,57 +1928,50 @@ e_make_dir(Config) when is_list(Config) -> e_del_dir(suite) -> []; e_del_dir(doc) -> []; e_del_dir(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line RootDir = ?config(priv_dir, Config), - ?line Base = test_server:temp_name(filename:join(RootDir, "e_del_dir")), - ?line io:format("Base: ~p", [Base]), - ?line ok = ?FILE_MODULE:make_dir(Base), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = ?config(priv_dir, Config), + Base = test_server:temp_name(filename:join(RootDir, "e_del_dir")), + io:format("Base: ~p", [Base]), + ok = ?FILE_MODULE:make_dir(Base), %% Delete a non-existent directory. - ?line {error, enoent} = + {error, enoent} = ?FILE_MODULE:del_dir(filename:join(Base, "non_existing")), %% Use a path-name with a non-directory component. - ?line Afile = filename:join(Base, "a_directory"), - ?line ok = ?FILE_MODULE:write_file(Afile, "hello\n"), - ?line {error, E1} = - expect({error, enotdir}, {error, enoent}, - ?FILE_MODULE:del_dir( - filename:join(Afile, "another_directory"))), - ?line io:format("Result: ~p", [E1]), + Afile = filename:join(Base, "a_directory"), + ok = ?FILE_MODULE:write_file(Afile, "hello\n"), + {error, E1} = expect({error, enotdir}, {error, enoent}, + ?FILE_MODULE:del_dir( + filename:join(Afile, "another_directory"))), + io:format("Result: ~p", [E1]), %% Delete a non-empty directory. - ?line {error, E2} = - expect({error, enotempty}, {error, eexist}, {error, eacces}, + {error, E2} = expect({error, enotempty}, {error, eexist}, {error, eacces}, ?FILE_MODULE:del_dir(Base)), - ?line io:format("Result: ~p", [E2]), + io:format("Result: ~p", [E2]), %% Remove the current directory. - ?line {error, E3} = - expect({error, einval}, + {error, E3} = expect({error, einval}, {error, eperm}, % Linux and DUX {error, eacces}, {error, ebusy}, ?FILE_MODULE:del_dir(".")), - ?line io:format("Result: ~p", [E3]), + io:format("Result: ~p", [E3]), %% No permission. case os:type() of {unix, _} -> - ?line ADirectory = filename:join(Base, "no_perm"), - ?line ok = ?FILE_MODULE:make_dir(ADirectory), - ?line ?FILE_MODULE:write_file_info( - Base, #file_info {mode=0}), - ?line {error, eacces} = ?FILE_MODULE:del_dir(ADirectory), - ?line ?FILE_MODULE:write_file_info( - Base, #file_info {mode=8#600}); + ADirectory = filename:join(Base, "no_perm"), + ok = ?FILE_MODULE:make_dir(ADirectory), + ?FILE_MODULE:write_file_info( Base, #file_info {mode=0}), + {error, eacces} = ?FILE_MODULE:del_dir(ADirectory), + ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#600}); {win32, _} -> - ok; - vxworks -> ok end, - ?line [] = flush(), - ?line test_server:timetrap_cancel(Dog), + [] = flush(), + test_server:timetrap_cancel(Dog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2563,147 +2534,123 @@ delayed_write(doc) -> ["Tests the file open option {delayed_write, Size, Delay}"]; delayed_write(Config) when is_list(Config) -> - ?line Dog = ?t:timetrap(?t:seconds(20)), - %% - ?line RootDir = ?config(priv_dir, Config), - ?line File = filename:join(RootDir, - atom_to_list(?MODULE)++"_delayed_write.txt"), - ?line Data1 = "asdfghjkl", - ?line Data2 = "qwertyuio", - ?line Data3 = "zxcvbnm,.", - ?line Size = length(Data1), - ?line Size = length(Data2), - ?line Size = length(Data3), - ?line Data1Data1 = Data1++Data1, - ?line Data1Data1Data1 = Data1Data1++Data1, - ?line Data1Data1Data1Data1 = Data1Data1++Data1Data1, + Dog = ?t:timetrap(?t:seconds(20)), + + RootDir = ?config(priv_dir, Config), + File = filename:join(RootDir, + atom_to_list(?MODULE)++"_delayed_write.txt"), + Data1 = "asdfghjkl", + Data2 = "qwertyuio", + Data3 = "zxcvbnm,.", + Size = length(Data1), + Size = length(Data2), + Size = length(Data3), + Data1Data1 = Data1++Data1, + Data1Data1Data1 = Data1Data1++Data1, + Data1Data1Data1Data1 = Data1Data1++Data1Data1, %% %% Test caching and normal close of non-raw file - ?line {ok, Fd1} = + {ok, Fd1} = ?FILE_MODULE:open(File, [write, {delayed_write, Size+1, 2000}]), - ?line ok = ?FILE_MODULE:write(Fd1, Data1), - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Fd2} = ?FILE_MODULE:open(File, [read]), - ?line case os:type() of - vxworks -> - io:format("Line ~p skipped on vxworks", [?LINE]); - _ -> - ?line eof = ?FILE_MODULE:read(Fd2, 1) - end, - ?line ok = ?FILE_MODULE:write(Fd1, Data1), % Data flush on size - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 2*Size+1), - ?line ok = ?FILE_MODULE:write(Fd1, Data1), - ?line ?t:sleep(3000), % Wait until data flush on timeout - ?line {ok, Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 3*Size+1), - ?line ok = ?FILE_MODULE:write(Fd1, Data1), - ?line ok = ?FILE_MODULE:close(Fd1), % Data flush on close - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Data1Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 4*Size+1), - ?line ok = ?FILE_MODULE:close(Fd2), + ok = ?FILE_MODULE:write(Fd1, Data1), + ?t:sleep(1000), % Just in case the file system is slow + {ok, Fd2} = ?FILE_MODULE:open(File, [read]), + eof = ?FILE_MODULE:read(Fd2, 1), + ok = ?FILE_MODULE:write(Fd1, Data1), % Data flush on size + ?t:sleep(1000), % Just in case the file system is slow + {ok, Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 2*Size+1), + ok = ?FILE_MODULE:write(Fd1, Data1), + ?t:sleep(3000), % Wait until data flush on timeout + {ok, Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 3*Size+1), + ok = ?FILE_MODULE:write(Fd1, Data1), + ok = ?FILE_MODULE:close(Fd1), % Data flush on close + ?t:sleep(1000), % Just in case the file system is slow + {ok, Data1Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 4*Size+1), + ok = ?FILE_MODULE:close(Fd2), %% %% Test implicit close through exit by file owning process, %% raw file, default parameters. - ?line Parent = self(), - ?line Fun = - fun () -> - Child = self(), - Test = - fun () -> - ?line {ok, Fd} = - ?FILE_MODULE:open(File, - [raw, write, - delayed_write]), - ?line ok = ?FILE_MODULE:write(Fd, Data1), - ?line Parent ! {Child, wrote}, - ?line receive - {Parent, continue, Reason} -> - {ok, Reason} - end - end, - case (catch Test()) of - {ok, Reason} -> - exit(Reason); - Unknown -> - exit({Unknown, get(test_server_loc)}) - end - end, - ?line Child1 = spawn(Fun), - ?line Mref1 = erlang:monitor(process, Child1), - ?line receive - {Child1, wrote} -> - ok; - {'DOWN', Mref1, _, _, _} = Down1a -> - ?t:fail(Down1a) - end, - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Fd3} = ?FILE_MODULE:open(File, [read]), - ?line case os:type() of - vxworks -> - io:format("Line ~p skipped on vxworks", [?LINE]); - _ -> - ?line eof = ?FILE_MODULE:read(Fd3, 1) - end, - ?line Child1 ! {Parent, continue, normal}, - ?line receive - {'DOWN', Mref1, process, Child1, normal} -> - ok; - {'DOWN', Mref1, _, _, _} = Down1b -> - ?t:fail(Down1b) - end, - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Data1} = ?FILE_MODULE:pread(Fd3, bof, Size+1), - ?line ok = ?FILE_MODULE:close(Fd3), + Parent = self(), + Fun = fun() -> + Child = self(), + Test = + fun () -> + {ok, Fd} = ?FILE_MODULE:open(File, + [raw, write, delayed_write]), + ok = ?FILE_MODULE:write(Fd, Data1), + Parent ! {Child, wrote}, + receive + {Parent, continue, Reason} -> + {ok, Reason} + end + end, + case (catch Test()) of + {ok, Reason} -> exit(Reason); + Unknown -> + exit({Unknown, get(test_server_loc)}) + end + end, + Child1 = spawn(Fun), + Mref1 = erlang:monitor(process, Child1), + receive + {Child1, wrote} -> + ok; + {'DOWN', Mref1, _, _, _} = Down1a -> + ?t:fail(Down1a) + end, + ?t:sleep(1000), % Just in case the file system is slow + {ok, Fd3} = ?FILE_MODULE:open(File, [read]), + eof = ?FILE_MODULE:read(Fd3, 1), + Child1 ! {Parent, continue, normal}, + receive + {'DOWN', Mref1, process, Child1, normal} -> + ok; + {'DOWN', Mref1, _, _, _} = Down1b -> + ?t:fail(Down1b) + end, + ?t:sleep(1000), % Just in case the file system is slow + {ok, Data1} = ?FILE_MODULE:pread(Fd3, bof, Size+1), + ok = ?FILE_MODULE:close(Fd3), %% %% The same again, but this time with reason 'kill'. - ?line Child2 = spawn(Fun), - ?line Mref2 = erlang:monitor(process, Child2), - ?line receive - {Child2, wrote} -> - ok; - {'DOWN', Mref2, _, _, _} = Down2a -> - ?t:fail(Down2a) - end, - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Fd4} = ?FILE_MODULE:open(File, [read]), - ?line case os:type() of - vxworks -> - io:format("Line ~p skipped on vxworks", [?LINE]); - _ -> - ?line eof = ?FILE_MODULE:read(Fd4, 1) - end, - ?line Child2 ! {Parent, continue, kill}, - ?line receive - {'DOWN', Mref2, process, Child2, kill} -> - ok; - {'DOWN', Mref2, _, _, _} = Down2b -> - ?t:fail(Down2b) - end, - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line eof = ?FILE_MODULE:pread(Fd4, bof, 1), - ?line ok = ?FILE_MODULE:close(Fd4), + Child2 = spawn(Fun), + Mref2 = erlang:monitor(process, Child2), + receive + {Child2, wrote} -> + ok; + {'DOWN', Mref2, _, _, _} = Down2a -> + ?t:fail(Down2a) + end, + ?t:sleep(1000), % Just in case the file system is slow + {ok, Fd4} = ?FILE_MODULE:open(File, [read]), + eof = ?FILE_MODULE:read(Fd4, 1), + Child2 ! {Parent, continue, kill}, + receive + {'DOWN', Mref2, process, Child2, kill} -> + ok; + {'DOWN', Mref2, _, _, _} = Down2b -> + ?t:fail(Down2b) + end, + ?t:sleep(1000), % Just in case the file system is slow + eof = ?FILE_MODULE:pread(Fd4, bof, 1), + ok = ?FILE_MODULE:close(Fd4), %% %% Test if file position works with delayed_write - ?line {ok, Fd5} = ?FILE_MODULE:open(File, [raw, read, write, - delayed_write]), - ?line ok = ?FILE_MODULE:truncate(Fd5), - ?line ok = ?FILE_MODULE:write(Fd5, [Data1|Data2]), - ?line {ok, 0} = ?FILE_MODULE:position(Fd5, bof), - ?line ok = ?FILE_MODULE:write(Fd5, [Data3]), - ?line {ok, Data2} = ?FILE_MODULE:read(Fd5, Size+1), - ?line {ok, 0} = ?FILE_MODULE:position(Fd5, bof), - ?line Data3Data2 = Data3++Data2, - ?line {ok, Data3Data2} = ?FILE_MODULE:read(Fd5, 2*Size+1), - ?line ok = ?FILE_MODULE:close(Fd5), + {ok, Fd5} = ?FILE_MODULE:open(File, [raw, read, write, + delayed_write]), + ok = ?FILE_MODULE:truncate(Fd5), + ok = ?FILE_MODULE:write(Fd5, [Data1|Data2]), + {ok, 0} = ?FILE_MODULE:position(Fd5, bof), + ok = ?FILE_MODULE:write(Fd5, [Data3]), + {ok, Data2} = ?FILE_MODULE:read(Fd5, Size+1), + {ok, 0} = ?FILE_MODULE:position(Fd5, bof), + Data3Data2 = Data3++Data2, + {ok, Data3Data2} = ?FILE_MODULE:read(Fd5, 2*Size+1), + ok = ?FILE_MODULE:close(Fd5), %% - ?line [] = flush(), - ?line ?t:timetrap_cancel(Dog), - ?line case os:type() of - vxworks -> - {comment, "Some lines skipped on vxworks"}; - _ -> - ok - end. + [] = flush(), + ?t:timetrap_cancel(Dog), + ok. pid2name(doc) -> "Tests file:pid2name/1."; diff --git a/lib/kernel/test/gen_tcp_echo_SUITE.erl b/lib/kernel/test/gen_tcp_echo_SUITE.erl index 5bbaeb02ad..94f95798a0 100644 --- a/lib/kernel/test/gen_tcp_echo_SUITE.erl +++ b/lib/kernel/test/gen_tcp_echo_SUITE.erl @@ -190,24 +190,19 @@ echo_test_1(SockOpts, EchoFun, Config0) -> ok. echo_packet(SockOpts, EchoFun, Opts) -> - ?line Type = - case lists:keysearch(type, 1, Opts) of - {value, {type, T}} -> - T; - _ -> - {value, {packet, T}} = lists:keysearch(packet, 1, SockOpts), - T - end, + Type = case lists:keysearch(type, 1, Opts) of + {value, {type, T}} -> + T; + _ -> + {value, {packet, T}} = lists:keysearch(packet, 1, SockOpts), + T + end, %% Connect to the echo server. - ?line EchoPort = ?config(echo_port, Opts), - ?line {ok, Echo} = gen_tcp:connect(localhost, EchoPort, SockOpts), + EchoPort = ?config(echo_port, Opts), + {ok, Echo} = gen_tcp:connect(localhost, EchoPort, SockOpts), - ?line SlowEcho = - case os:type() of - vxworks -> true; - _ -> lists:member(slow_echo, Opts) - end, + SlowEcho = lists:member(slow_echo, Opts), case Type of http -> diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 1592399996..5d45b91ee5 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -340,39 +340,23 @@ no_accept(doc) -> "a tcp_closed message."]; no_accept(suite) -> []; no_accept(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skip,"Too tough for vxworks"}; - _ -> - no_accept2() + {ok, L} = gen_tcp:listen(0, []), + {ok, {_, Port}} = inet:sockname(L), + {ok, Client} = gen_tcp:connect(localhost, Port, []), + ok = gen_tcp:close(L), + receive + {tcp_closed, Client} -> + ok + after 5000 -> + ?line test_server:fail(never_closed) + end. -no_accept2() -> - ?line {ok, L} = gen_tcp:listen(0, []), - ?line {ok, {_, Port}} = inet:sockname(L), - ?line {ok, Client} = gen_tcp:connect(localhost, Port, []), - ?line ok = gen_tcp:close(L), - ?line receive - {tcp_closed, Client} -> - ok - after 5000 -> - ?line test_server:fail(never_closed) - - end. - close_with_pending_output(doc) -> ["Send several packets to a socket and close it. All packets should arrive ", "to the other end."]; close_with_pending_output(suite) -> []; close_with_pending_output(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skipped,"Too tough for vxworks"}; - _ -> - close_with_pending_output2() - end. - -close_with_pending_output2() -> ?line {ok, L} = gen_tcp:listen(0, [binary, {active, false}]), ?line {ok, {_, Port}} = inet:sockname(L), ?line Packets = 16, @@ -423,22 +407,16 @@ otp_3924(doc) -> otp_3924(suite) -> []; otp_3924(Config) when is_list(Config) -> MaxDelay = (case has_superfluous_schedulers() of - true -> 4; - false -> 1 - end - * case {erlang:system_info(debug_compiled), - erlang:system_info(lock_checking)} of - {true, _} -> 6; - {_, true} -> 2; - _ -> 1 - end * ?OTP_3924_MAX_DELAY), - case os:type() of - vxworks -> -%% {skip,"Too tough for vxworks"}; - otp_3924_1(MaxDelay); - _ -> - otp_3924_1(MaxDelay) - end. + true -> 4; + false -> 1 + end + * case {erlang:system_info(debug_compiled), + erlang:system_info(lock_checking)} of + {true, _} -> 6; + {_, true} -> 2; + _ -> 1 + end * ?OTP_3924_MAX_DELAY), + otp_3924_1(MaxDelay). otp_3924_1(MaxDelay) -> Dog = test_server:timetrap(test_server:seconds(240)), @@ -559,26 +537,18 @@ otp_3924_sender(Receiver, Host, Port, Data) -> data_before_close(doc) -> ["Tests that a huge amount of data can be received before a close."]; data_before_close(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skip,"Too tough for vxworks"}; - _ -> - data_before_close2() - end. - -data_before_close2() -> - ?line {ok, L} = gen_tcp:listen(0, [binary]), - ?line {ok, {_, TcpPort}} = inet:sockname(L), - ?line Bytes = 256*1024, - ?line spawn_link(fun() -> huge_sender(TcpPort, Bytes) end), - ?line {ok, A} = gen_tcp:accept(L), - ?line case count_bytes_recv(A, 0) of - {Bytes, Result} -> - io:format("Result: ~p", [Result]); - {Wrong, Result} -> - io:format("Result: ~p", [Result]), - test_server:fail({wrong_count, Wrong}) - end, + {ok, L} = gen_tcp:listen(0, [binary]), + {ok, {_, TcpPort}} = inet:sockname(L), + Bytes = 256*1024, + spawn_link(fun() -> huge_sender(TcpPort, Bytes) end), + {ok, A} = gen_tcp:accept(L), + case count_bytes_recv(A, 0) of + {Bytes, Result} -> + io:format("Result: ~p", [Result]); + {Wrong, Result} -> + io:format("Result: ~p", [Result]), + test_server:fail({wrong_count, Wrong}) + end, ok. count_bytes_recv(Sock, Total) -> @@ -611,32 +581,18 @@ get_status(Config) when is_list(Config) -> ?line {ok,{socket,Pid,_,_}} = gen_tcp:listen(5678,[]), ?line {status,Pid,_,_} = sys:get_status(Pid). +-define(RECOVER_SLEEP, 60000). +-define(RETRY_SLEEP, 15000). + iter_max_socks(doc) -> ["Open as many sockets as possible. Do this several times and check ", "that we get the same number of sockets every time."]; iter_max_socks(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skip,"Too tough for vxworks"}; - _ -> - iter_max_socks2() - end. - --define(RECOVER_SLEEP, 60000). --define(RETRY_SLEEP, 15000). - -iter_max_socks2() -> - ?line N = - case os:type() of - vxworks -> - 10; - _ -> - 20 - end, + N = 20, L = do_iter_max_socks(N, initalize), - ?line io:format("Result: ~p",[L]), - ?line all_equal(L), - ?line {comment, "Max sockets: " ++ integer_to_list(hd(L))}. + io:format("Result: ~p",[L]), + all_equal(L), + {comment, "Max sockets: " ++ integer_to_list(hd(L))}. do_iter_max_socks(0, _) -> []; diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl index 233e438dc9..31005a01e2 100644 --- a/lib/kernel/test/heart_SUITE.erl +++ b/lib/kernel/test/heart_SUITE.erl @@ -266,13 +266,8 @@ dont_drop(doc) -> "set just before halt on very high I/O load."]; dont_drop(Config) when is_list(Config) -> %%% Have to do it some times to make it happen... - case os:type() of - vxworks -> - {comment, "No use to run with slaves on other nodes..."}; - _ -> - [ok,ok,ok,ok,ok,ok,ok,ok,ok,ok] = do_dont_drop(Config,10), - ok - end. + [ok,ok,ok,ok,ok,ok,ok,ok,ok,ok] = do_dont_drop(Config,10), + ok. do_dont_drop(_,0) -> []; @@ -333,13 +328,7 @@ kill_pid(doc) -> ["Tests that heart kills the old erlang node before executing ", "heart command."]; kill_pid(Config) when is_list(Config) -> - %%% Have to do it some times to make it happen... - case os:type() of - vxworks -> - {comment, "No use to run with slaves on other nodes..."}; - _ -> - ok = do_kill_pid(Config) - end. + ok = do_kill_pid(Config). do_kill_pid(_Config) -> Name = heart_test, diff --git a/lib/kernel/test/heart_SUITE_data/simple_echo.c b/lib/kernel/test/heart_SUITE_data/simple_echo.c index 0093dbce9b..a92bb8af95 100644 --- a/lib/kernel/test/heart_SUITE_data/simple_echo.c +++ b/lib/kernel/test/heart_SUITE_data/simple_echo.c @@ -2,11 +2,7 @@ #include <stdlib.h> #include <string.h> -#ifdef VXWORKS -int simple_echo(void){ -#else int main(void){ -#endif int x; while((x = getchar()) != EOF){ putchar(x); @@ -14,4 +10,3 @@ int main(void){ } return 0; } - diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 7241b093d0..ce138b6804 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -66,7 +66,7 @@ required(v6) -> {require, test_dummy_ipv6_host}]; required(hosts) -> case os:type() of - {OS, _} when OS =:= win32; OS =:= vxworks -> + {OS, _} when OS =:= win32 -> [{require, hardcoded_hosts}, {require, hardcoded_ipv6_hosts}]; _Else -> @@ -614,17 +614,12 @@ t_gethostnative(Config) when is_list(Config) -> %% this will result in 26 bytes sent which causes problem in Windows %% if the port-program has not assured stdin to be read in BINARY mode %% OTP-2555 - case os:type() of - vxworks -> - {skipped, "VxWorks has no native gethostbyname()"}; - _ -> - ?line case inet_gethost_native:gethostbyname( - "a23456789012345678901234") of - {error,notfound} -> - ?line ok; - {error,no_data} -> - ?line ok - end + ?line case inet_gethost_native:gethostbyname( + "a23456789012345678901234") of + {error,notfound} -> + ?line ok; + {error,no_data} -> + ?line ok end. gethostnative_parallell(suite) -> diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl index 0c63a6d653..087ae6055b 100644 --- a/lib/kernel/test/inet_sockopt_SUITE.erl +++ b/lib/kernel/test/inet_sockopt_SUITE.erl @@ -623,7 +623,6 @@ all_listen_options() -> {exit_on_close, true, false, true, true}, %{high_watermark,4096,8192,true,true}, %{low_watermark,2048,4096,true,true}, - {bit8,on,off,true,true}, {send_timeout,infinity,1000,true,true}, {send_timeout_close,false,true,true,true}, {delay_send,false,true,true,true}, @@ -647,7 +646,6 @@ all_connect_options() -> {exit_on_close, true, false, true, true}, {high_watermark,4096,8192,false,true}, {low_watermark,2048,4096,false,true}, - {bit8,on,off,true,true}, {send_timeout,infinity,1000,true,true}, {send_timeout_close,false,true,true,true}, {delay_send,false,true,true,true}, diff --git a/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c b/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c index f24c93edf5..9c8f8eb91a 100644 --- a/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c +++ b/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c @@ -1,12 +1,3 @@ -#if defined(VXWORKS) -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -int sockopt_helper(void){ - return 0; -} -#else - #if defined(__WIN32__) #define WIN32_LEAN_AND_MEAN #include <winsock2.h> @@ -215,5 +206,3 @@ int main(void){ } while (x != C_QUIT); return 0; } -#endif - diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl index e3fa4642b7..1993cd0b32 100644 --- a/lib/kernel/test/init_SUITE.erl +++ b/lib/kernel/test/init_SUITE.erl @@ -256,47 +256,42 @@ get_plain_arguments(Config) when is_list(Config) -> boot_var(doc) -> []; boot_var(suite) -> {req, [distribution, {local_slave_nodes, 1}]}; boot_var(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Not run on VxWorks"}; + ?line Dog = ?t:timetrap(?t:seconds(100)), + + {BootScript, TEST_VAR, KernelVsn, StdlibVsn} = create_boot(Config), + + %% Should fail as we have not given -boot_var TEST_VAR + ?line {error, timeout} = + start_node(init_test, "-boot " ++ BootScript), + + case is_real_system(KernelVsn, StdlibVsn) of + true -> + %% Now it should work !! + ?line {ok, Node} = + start_node(init_test, + "-boot " ++ BootScript ++ + " -boot_var TEST_VAR " ++ TEST_VAR), + stop_node(Node), + Res = ok; _ -> - ?line Dog = ?t:timetrap(?t:seconds(100)), - - {BootScript, TEST_VAR, KernelVsn, StdlibVsn} = create_boot(Config), - - %% Should fail as we have not given -boot_var TEST_VAR - ?line {error, timeout} = - start_node(init_test, "-boot " ++ BootScript), - - case is_real_system(KernelVsn, StdlibVsn) of - true -> - %% Now it should work !! - ?line {ok, Node} = - start_node(init_test, - "-boot " ++ BootScript ++ - " -boot_var TEST_VAR " ++ TEST_VAR), - stop_node(Node), - Res = ok; - _ -> -%% What we need is not so much version numbers on the directories, but -%% for the boot var TEST_VAR to appear in the boot script, and it doesn't -%% if we give the 'local' option to systools:make_script. - ?t:format( - "Test case not complete as we are not~n" - "running in a real system!~n" - "Probably this test is performed in a " - "clearcase view or source tree.~n" - "Need version numbers on the kernel and " - "stdlib directories!~n", - []), - Res = {skip, - "Test case only partially run since it is run " - "in a clearcase view or in a source tree. " - "Need an installed system to complete this test."} - end, - ?line ?t:timetrap_cancel(Dog), - Res - end. + %% What we need is not so much version numbers on the directories, but + %% for the boot var TEST_VAR to appear in the boot script, and it doesn't + %% if we give the 'local' option to systools:make_script. + ?t:format( + "Test case not complete as we are not~n" + "running in a real system!~n" + "Probably this test is performed in a " + "clearcase view or source tree.~n" + "Need version numbers on the kernel and " + "stdlib directories!~n", + []), + Res = {skip, + "Test case only partially run since it is run " + "in a clearcase view or in a source tree. " + "Need an installed system to complete this test."} + end, + ?line ?t:timetrap_cancel(Dog), + Res. create_boot(Config) -> ?line {ok, OldDir} = file:get_cwd(), @@ -579,55 +574,47 @@ script_id(Config) when is_list(Config) -> boot1(doc) -> []; boot1(suite) -> {req, [distribution, {local_slave_nodes, 1}, {time, 35}]}; boot1(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Not run on VxWorks"}; - _ -> - ?line Dog = ?t:timetrap(?t:seconds(80)), - Args = args() ++ " -boot start_sasl", - ?line {ok, Node} = start_node(init_test, Args), - ?line stop_node(Node), - - %% Try to start with non existing boot file. - Args1 = args() ++ " -boot dummy_script", - ?line {error, timeout} = start_node(init_test, Args1), - - ?line ?t:timetrap_cancel(Dog), - ok - end. + ?line Dog = ?t:timetrap(?t:seconds(80)), + Args = args() ++ " -boot start_sasl", + ?line {ok, Node} = start_node(init_test, Args), + ?line stop_node(Node), + + %% Try to start with non existing boot file. + Args1 = args() ++ " -boot dummy_script", + ?line {error, timeout} = start_node(init_test, Args1), + + ?line ?t:timetrap_cancel(Dog), + ok. boot2(doc) -> []; boot2(suite) -> {req, [distribution, {local_slave_nodes, 1}, {time, 35}]}; boot2(Config) when is_list(Config) -> + Dog = ?t:timetrap(?t:seconds(80)), + + %% Absolute boot file name + Boot = filename:join([code:root_dir(), "bin", "start_sasl"]), + + Args = args() ++ " -boot \"" ++ Boot++"\"", + {ok, Node} = start_node(init_test, Args), + stop_node(Node), + case os:type() of - vxworks -> - {comment, "Not run on VxWorks"}; + {win32, _} -> + %% Absolute boot file name for Windows -- all slashes are + %% converted to backslashes. + Win_boot = lists:map(fun + ($/) -> $\\; + (C) -> C + end, Boot), + Args2 = args() ++ " -boot \"" ++ Win_boot ++ "\"", + {ok, Node2} = start_node(init_test, Args2), + stop_node(Node2); _ -> - ?line Dog = ?t:timetrap(?t:seconds(80)), - - %% Absolute boot file name - Boot = filename:join([code:root_dir(), "bin", "start_sasl"]), - - Args = args() ++ " -boot \"" ++ Boot++"\"", - ?line {ok, Node} = start_node(init_test, Args), - ?line stop_node(Node), - - case os:type() of - {win32, _} -> - %% Absolute boot file name for Windows -- all slashes are - %% converted to backslashes. - Win_boot = lists:map(fun($/) -> $\\; (C) -> C end, - Boot), - Args2 = args() ++ " -boot \"" ++ Win_boot ++ "\"", - ?line {ok, Node2} = start_node(init_test, Args2), - ?line stop_node(Node2); - _ -> - ok - end, - - ?line ?t:timetrap_cancel(Dog), ok - end. + end, + + ?t:timetrap_cancel(Dog), + ok. %% Misc. functions diff --git a/lib/kernel/test/kernel.spec.wxworks b/lib/kernel/test/kernel.spec.wxworks deleted file mode 100644 index 370e474e64..0000000000 --- a/lib/kernel/test/kernel.spec.wxworks +++ /dev/null @@ -1,63 +0,0 @@ -%% -*- erlang -*- -{suites,"kernel_test",all}. -{skip_cases,"kernel_test",bif_SUITE,[spawn_link_race1],"Known bug."}. -{skip_cases,"kernel_test",file_SUITE, - [read_write_file], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [cur_dir_0], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [open1], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [file_info_times], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [file_write_file_info], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [truncate], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [rename], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [e_delete], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [e_rename], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [delayed_write], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [read_ahead], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [segment_write], - "VxWorks filesystem would overload"}. -{skip_cases,"kernel_test",file_SUITE, - [segment_read], - "VxWorks filesystem would overload"}. -{skip_cases,"kernel_test",file_SUITE, - [compress_errors], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",init_SUITE,[restart],"Uses peer nodes"}. -{skip_cases,"kernel_test",os_SUITE,[space_in_cwd],"VxWorks can't handle this"}. -{skip_cases,"kernel_test",os_SUITE, - [space_in_name], - "VxWorks can't handle this"}. -{skip_cases,"kernel_test",os_SUITE,[quoting],"VxWorks can't handle this"}. -{skip_cases,"kernel_test",prim_file_SUITE, - [open1], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",prim_file_SUITE, - [compress_errors], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",seq_trace_SUITE, - [distributed_recv], - "Test not adopted to slaves on different machine"}. -{skip_cases,"kernel_test",seq_trace_SUITE, - [distributed_exit], - "Test not adopted to slaves on different machine"}. diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl index ae3410d13f..3f2195b609 100644 --- a/lib/kernel/test/os_SUITE.erl +++ b/lib/kernel/test/os_SUITE.erl @@ -202,8 +202,6 @@ find_executable(Config) when is_list(Config) -> %% Never return a directory name. ?line false = os:find_executable("unix", [DataDir]), - ok; - vxworks -> ok end. diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl index 8afdfc8a47..60b818cbe3 100644 --- a/lib/kernel/test/pdict_SUITE.erl +++ b/lib/kernel/test/pdict_SUITE.erl @@ -152,7 +152,6 @@ heavy(Config) when is_list(Config) -> time(5000), ?M([],get()), case {os:type(),?t:is_debug()} of - {vxworks,_} -> ok; {_,true} -> ok; _ -> time(50000), diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 3e2202922c..a56746bbc4 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -406,9 +406,6 @@ cur_dir_1(Config, Handle) -> {unix, _} -> ?line {error, enotsup} = ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); - vxworks -> - ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); {win32, _} -> win_cur_dir_1(Config, Handle) end, @@ -843,10 +840,7 @@ file_info_basic_directory(Config, Handle) -> ?line test_directory("c:/", read_write, Handle), ?line test_directory("c:\\", read_write, Handle); {unix, _} -> - ?line test_directory("/", read, Handle); - vxworks -> - %% Check is just done for owner - ?line test_directory("/", read_write, Handle) + ?line test_directory("/", read, Handle) end, ?line test_server:timetrap_cancel(Dog). @@ -1508,9 +1502,7 @@ e_delete(Config) when is_list(Config) -> Base, #file_info {mode=8#600}); {win32, _} -> %% Remove a character device. - ?line {error, eacces} = ?PRIM_FILE:delete("nul"); - vxworks -> - ok + ?line {error, eacces} = ?PRIM_FILE:delete("nul") end, ?line test_server:timetrap_cancel(Dog), @@ -1524,110 +1516,105 @@ e_delete(Config) when is_list(Config) -> e_rename(suite) -> []; e_rename(doc) -> []; e_rename(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Windriver: dosFs must be fixed first!"}; - _ -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line RootDir = ?config(priv_dir, Config), - ?line Base = filename:join(RootDir, - atom_to_list(?MODULE)++"_e_rename"), - ?line ok = ?PRIM_FILE:make_dir(Base), - - %% Create an empty directory. - ?line EmptyDir = filename:join(Base, "empty_dir"), - ?line ok = ?PRIM_FILE:make_dir(EmptyDir), - - %% Create a non-empty directory. - ?line NonEmptyDir = filename:join(Base, "non_empty_dir"), - ?line ok = ?PRIM_FILE:make_dir(NonEmptyDir), - ?line ok = ?PRIM_FILE:write_file( - filename:join(NonEmptyDir, "a_file"), - "hello\n"), - - %% Create another non-empty directory. - ?line ADirectory = filename:join(Base, "a_directory"), - ?line ok = ?PRIM_FILE:make_dir(ADirectory), - ?line ok = ?PRIM_FILE:write_file( - filename:join(ADirectory, "a_file"), - "howdy\n\n"), + ?line Dog = test_server:timetrap(test_server:seconds(10)), + ?line RootDir = ?config(priv_dir, Config), + ?line Base = filename:join(RootDir, + atom_to_list(?MODULE)++"_e_rename"), + ?line ok = ?PRIM_FILE:make_dir(Base), - %% Create a data file. - ?line File = filename:join(Base, "just_a_file"), - ?line ok = ?PRIM_FILE:write_file(File, "anything goes\n\n"), - - %% Move an existing directory to a non-empty directory. - ?line {error, eexist} = - ?PRIM_FILE:rename(ADirectory, NonEmptyDir), - - %% Move a root directory. - ?line {error, einval} = ?PRIM_FILE:rename("/", "arne"), - - %% Move Base into Base/new_name. - ?line {error, einval} = - ?PRIM_FILE:rename(Base, filename:join(Base, "new_name")), - - %% Overwrite a directory with a file. - ?line expect({error, eexist}, % FreeBSD (?) - {error, eisdir}, - ?PRIM_FILE:rename(File, EmptyDir)), - ?line expect({error, eexist}, % FreeBSD (?) - {error, eisdir}, - ?PRIM_FILE:rename(File, NonEmptyDir)), - - %% Move a non-existing file. - ?line NonExistingFile = filename:join( - Base, "non_existing_file"), - ?line {error, enoent} = - ?PRIM_FILE:rename(NonExistingFile, NonEmptyDir), - - %% Overwrite a file with a directory. - ?line expect({error, eexist}, % FreeBSD (?) - {error, enotdir}, - ?PRIM_FILE:rename(ADirectory, File)), - - %% Move a file to another filesystem. - %% XXX - This test case is bogus. We cannot be guaranteed that - %% the source and destination are on - %% different filesystems. - %% - %% XXX - Gross hack! - ?line Comment = - case os:type() of - {unix, _} -> - OtherFs = "/tmp", - ?line NameOnOtherFs = - filename:join(OtherFs, - filename:basename(File)), - ?line {ok, Com} = - case ?PRIM_FILE:rename( - File, NameOnOtherFs) of - {error, exdev} -> - %% The file could be in - %% the same filesystem! - {ok, ok}; - ok -> - {ok, {comment, - "Moving between filesystems " - "suceeded, files are probably " - "in the same filesystem!"}}; - {error, eperm} -> - {ok, {comment, "SBS! You don't " - "have the permission to do " - "this test!"}}; - Else -> - Else - end, - Com; - {win32, _} -> - %% At least Windows NT can - %% successfully move a file to - %% another drive. - ok - end, - ?line test_server:timetrap_cancel(Dog), - Comment - end. + %% Create an empty directory. + ?line EmptyDir = filename:join(Base, "empty_dir"), + ?line ok = ?PRIM_FILE:make_dir(EmptyDir), + + %% Create a non-empty directory. + ?line NonEmptyDir = filename:join(Base, "non_empty_dir"), + ?line ok = ?PRIM_FILE:make_dir(NonEmptyDir), + ?line ok = ?PRIM_FILE:write_file( + filename:join(NonEmptyDir, "a_file"), + "hello\n"), + + %% Create another non-empty directory. + ?line ADirectory = filename:join(Base, "a_directory"), + ?line ok = ?PRIM_FILE:make_dir(ADirectory), + ?line ok = ?PRIM_FILE:write_file( + filename:join(ADirectory, "a_file"), + "howdy\n\n"), + + %% Create a data file. + ?line File = filename:join(Base, "just_a_file"), + ?line ok = ?PRIM_FILE:write_file(File, "anything goes\n\n"), + + %% Move an existing directory to a non-empty directory. + ?line {error, eexist} = + ?PRIM_FILE:rename(ADirectory, NonEmptyDir), + + %% Move a root directory. + ?line {error, einval} = ?PRIM_FILE:rename("/", "arne"), + + %% Move Base into Base/new_name. + ?line {error, einval} = + ?PRIM_FILE:rename(Base, filename:join(Base, "new_name")), + + %% Overwrite a directory with a file. + ?line expect({error, eexist}, % FreeBSD (?) + {error, eisdir}, + ?PRIM_FILE:rename(File, EmptyDir)), + ?line expect({error, eexist}, % FreeBSD (?) + {error, eisdir}, + ?PRIM_FILE:rename(File, NonEmptyDir)), + + %% Move a non-existing file. + ?line NonExistingFile = filename:join( + Base, "non_existing_file"), + ?line {error, enoent} = + ?PRIM_FILE:rename(NonExistingFile, NonEmptyDir), + + %% Overwrite a file with a directory. + ?line expect({error, eexist}, % FreeBSD (?) + {error, enotdir}, + ?PRIM_FILE:rename(ADirectory, File)), + + %% Move a file to another filesystem. + %% XXX - This test case is bogus. We cannot be guaranteed that + %% the source and destination are on + %% different filesystems. + %% + %% XXX - Gross hack! + ?line Comment = + case os:type() of + {unix, _} -> + OtherFs = "/tmp", + ?line NameOnOtherFs = + filename:join(OtherFs, + filename:basename(File)), + ?line {ok, Com} = + case ?PRIM_FILE:rename( + File, NameOnOtherFs) of + {error, exdev} -> + %% The file could be in + %% the same filesystem! + {ok, ok}; + ok -> + {ok, {comment, + "Moving between filesystems " + "suceeded, files are probably " + "in the same filesystem!"}}; + {error, eperm} -> + {ok, {comment, "SBS! You don't " + "have the permission to do " + "this test!"}}; + Else -> + Else + end, + Com; + {win32, _} -> + %% At least Windows NT can + %% successfully move a file to + %% another drive. + ok + end, + ?line test_server:timetrap_cancel(Dog), + Comment. e_make_dir(suite) -> []; e_make_dir(doc) -> []; @@ -1660,8 +1647,6 @@ e_make_dir(Config) when is_list(Config) -> ?line ?PRIM_FILE:write_file_info(Base, #file_info {mode=8#600}); {win32, _} -> - ok; - vxworks -> ok end, ?line test_server:timetrap_cancel(Dog), @@ -1716,8 +1701,6 @@ e_del_dir(Config) when is_list(Config) -> ?line ?PRIM_FILE:write_file_info( Base, #file_info {mode=8#600}); {win32, _} -> - ok; - vxworks -> ok end, ?line test_server:timetrap_cancel(Dog), diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index c494f8a864..46a991eb38 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.15.2 +KERNEL_VSN = 2.16 diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in index 42c50b8961..722ccc3fb4 100644 --- a/lib/megaco/configure.in +++ b/lib/megaco/configure.in @@ -145,7 +145,7 @@ AC_ARG_ENABLE(megaco_flex_scanner_lineno, AC_SUBST(ENABLE_MEGACO_FLEX_SCANNER_LINENO) -dnl This is the os flavour, should be unix, vxworks or win32 +dnl This is the os flavour, should be unix or win32 if test "X$host" = "Xwin32"; then ERLANG_OSTYPE=win32 else diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in index 976ecaa4f7..cb1d7d2a5c 100644 --- a/lib/megaco/src/flex/Makefile.in +++ b/lib/megaco/src/flex/Makefile.in @@ -104,10 +104,6 @@ ENABLE_MEGACO_FLEX_SCANNER_LINENO = @ENABLE_MEGACO_FLEX_SCANNER_LINENO@ endif endif -ifeq ($(findstring vxworks,$(TARGET)),vxworks) - DED_INCLUDES += -I$(ERL_TOP)/erts/etc/vxworks -endif - PRIVDIR = ../../priv LIBDIR = $(PRIVDIR)/lib/$(TARGET) OBJDIR = $(PRIVDIR)/obj/$(TARGET) @@ -146,15 +142,10 @@ ifeq ($(findstring win32,$(TARGET)), win32) FLEX_SCANNER_SO = SOLIBS = $(FLEX_SCANNER_SO) else -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -FLEX_SCANNER_SO = -SOLIBS = $(FLEX_SCANNER_SO) -else FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).$(DED_EXT) FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).$(DED_EXT) SOLIBS = $(FLEX_SCANNER_SO) $(FLEX_SCANNER_MT_SO) endif -endif # ---------------------------------------------------- diff --git a/lib/megaco/src/rules.mk b/lib/megaco/src/rules.mk index 20fbed2a76..a59060032d 100644 --- a/lib/megaco/src/rules.mk +++ b/lib/megaco/src/rules.mk @@ -29,10 +29,6 @@ PERL = perl # Erlang language section # ---------------------------------------------------- EMULATOR = beam -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -# VxWorks jam object files should be compressed -ERL_COMPILE_FLAGS += +compressed -endif ERLC_WFLAGS = -W ERLC = erlc $(ERLC_WFLAGS) $(ERLC_FLAGS) ERL.beam = erl.beam -boot start_clean diff --git a/lib/megaco/test/megaco.spec.vxworks b/lib/megaco/test/megaco.spec.vxworks deleted file mode 100644 index 2ac250e443..0000000000 --- a/lib/megaco/test/megaco.spec.vxworks +++ /dev/null @@ -1,5 +0,0 @@ -{topcase, {dir, "../megaco_test"}}. -{require_nodenames, 1}. -{skip, {megaco_digit_map_test, all, "Not yet implemented"}}. -{skip, {megaco_measure_test, all, "Not yet implemented"}}. -%{skip, {M, F, "Not yet implemented"}}. diff --git a/lib/mnesia/examples/mnesia_tpcb.erl b/lib/mnesia/examples/mnesia_tpcb.erl index 903c53a21c..f36b43a495 100644 --- a/lib/mnesia/examples/mnesia_tpcb.erl +++ b/lib/mnesia/examples/mnesia_tpcb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -99,9 +99,13 @@ replica_test/1, sticky_replica_test/1, remote_test/1, - remote_frag2_test/1 + remote_frag2_test/1, + + conflict_benchmark/1 ]). +-include_lib("common_test/include/ct_event.hrl"). + -define(SECOND, 1000000). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -191,8 +195,10 @@ driver_nodes = [node()], n_drivers_per_node = 1, use_running_mnesia = false, + seed, stop_after = timer:minutes(15), % Minimum 15 min report_interval = timer:minutes(1), + send_bench_report = false, use_sticky_locks = false, spawn_near_branch = false, activity_type = transaction, @@ -397,8 +403,30 @@ config(remote_frag2_test, ReplicaType) -> {stop_after, timer:minutes(1)}, {report_interval, timer:seconds(10)}, {reuse_history_id, true} + ]; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Ten drivers per node, tables replicated to all nodes, single branch + +config(conflict_benchmark, ReplicaType) -> + Remote = nodes(), + Local = node(), + Nodes = [Local | Remote], + [{seed, {1326,448637,337711}}, + {db_nodes, Nodes}, + {driver_nodes, Nodes}, + {replica_nodes, Nodes}, + {n_drivers_per_node, 10}, + {n_branches, 1}, + {n_accounts_per_branch, 10}, + {replica_type, ReplicaType}, + {stop_after, timer:minutes(1)}, + {report_interval, timer:seconds(10)}, + {send_bench_report, true}, + {reuse_history_id, true} ]. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start(What, ReplicaType) -> @@ -422,6 +450,9 @@ remote_test(ReplicaType) -> remote_frag2_test(ReplicaType) -> start(remote_frag2_test, ReplicaType). +conflict_benchmark(ReplicaType) -> + start(config(conflict_benchmark, ReplicaType)). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Args is a list of {Key, Val} tuples where Key is a field name %% in either the record tab_config or run_config. Unknown keys are ignored. @@ -866,6 +897,7 @@ add_time(Acc, New) -> show_report(State) -> Now = now_to_micros(erlang:now()), Iters = State#reporter_state.n_iters, + Cfg = State#reporter_state.run_config, Time = State#reporter_state.curr, Max = Time#time.max_time, N = Time#time.n_trans, @@ -888,7 +920,17 @@ show_report(State) -> "duration of longest transaction was ~p milliseconds~n", [Tps, BruttoTps, Max div 1000]) end, - State#reporter_state{prev_tps = Tps, prev_micros = Now}. + case Cfg#run_config.send_bench_report of + true -> + ct_event:notify( + #event{name = benchmark_data, + data = [{suite,"mnesia_tpcb"}, + {value,Tps}]}); + _ -> + ok + end, + + State#reporter_state{prev_tps = Tps, prev_micros = Now}. signed_diff(Iters, Curr, Prev) -> case Iters > 1 of @@ -955,7 +997,13 @@ alloc_local_branches([], Specs, OrphanBranches) -> {Specs, OrphanBranches}. driver_init(DS, AllBranches) -> - Seed = erlang:now(), + case (DS#driver_state.run_config)#run_config.seed of + undefined -> + Seed = erlang:now(); + Seed -> + Seed + end, + DS2 = if DS#driver_state.n_local_branches =:= 0 -> diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile index 0451da697d..32453bc74e 100644 --- a/lib/mnesia/test/Makefile +++ b/lib/mnesia/test/Makefile @@ -26,6 +26,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk MODULES= \ mt \ mnesia_SUITE \ + mnesia_bench_SUITE \ mnesia_test_lib \ mnesia_install_test \ mnesia_registry_test \ @@ -117,7 +118,7 @@ release_spec: opt release_tests_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)" - $(INSTALL_DATA) mnesia.spec mnesia.cover $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)" + $(INSTALL_DATA) mnesia.spec mnesia_bench.spec mnesia.cover $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)" $(INSTALL_SCRIPT) mt $(INSTALL_PROGS) "$(RELSYSDIR)" # chmod -R u+w "$(RELSYSDIR)" # @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) diff --git a/lib/mnesia/test/mnesia.spec.vxworks b/lib/mnesia/test/mnesia.spec.vxworks deleted file mode 100644 index 11c01ea3fe..0000000000 --- a/lib/mnesia/test/mnesia.spec.vxworks +++ /dev/null @@ -1,362 +0,0 @@ -{topcase, {dir, "../mnesia_test"}}. -{require_nodenames, 3}. -{diskless, true}. -{skip, {mnesia_measure_test, all, "Too heavy"}}. -%{mnesia_install_test, silly_durability} 'IMPL' -%{mnesia_install_test, silly_move} 'IMPL' -{skip, {mnesia_install_test, silly_upgrade, "Uses disk"}}. -%{mnesia_install_test, conflict} 'IMPL' -%{mnesia_install_test, dist} 'IMPL' -{skip, {mnesia_examples_test, all, "Uses disk"}}. -{skip, {mnesia_nice_coverage_test, all, "Uses disk"}}. - -%{mnesia_evil_coverage_test, system_info} 'IMPL' -%{mnesia_evil_coverage_test, table_info} 'IMPL' -%{mnesia_evil_coverage_test, error_description} 'IMPL' -{skip, {mnesia_evil_coverage_test, db_node_lifecycle, "Uses disk"}}. -{skip, {mnesia_evil_coverage_test, local_content, "Uses disk"}}. -%{mnesia_evil_coverage_test, start_and_stop} 'IMPL' -%{mnesia_evil_coverage_test, transaction} 'IMPL' -{skip, {mnesia_evil_coverage_test, checkpoint, "Uses disk"}}. -{skip, {mnesia_evil_backup, backup, "Uses disk"}}. -{skip, {mnesia_evil_backup, global_backup_checkpoint, "Uses disk"}}. -{skip, {mnesia_evil_backup, incremental_backup_checkpoint, "Uses disk"}}. -{skip, {mnesia_evil_backup, local_backup_checkpoint, "Uses disk"}}. -{skip, {mnesia_evil_backup, selective_backup_checkpoint, "Uses disk"}}. -{skip, {mnesia_evil_backup, restore_errors, "Uses disk"}}. -{skip, {mnesia_evil_backup, restore_clear, "Uses disk"}}. -{skip, {mnesia_evil_backup, restore_keep, "Uses disk"}}. -{skip, {mnesia_evil_backup, restore_recreate, "Uses disk"}}. -{skip, {mnesia_evil_backup, traverse_backup, "Uses disk"}}. -{skip, {mnesia_evil_backup, install_fallback, "Uses disk"}}. -{skip, {mnesia_evil_backup, uninstall_fallback, "Uses disk"}}. -{skip, {mnesia_evil_backup, local_fallback, "Uses disk"}}. -%{mnesia_evil_coverage_test, table_lifecycle} 'IMPL' -{skip, {mnesia_evil_coverage_test, replica_management, "Uses disk"}}. -%{mnesia_evil_coverage_test, change_table_access_mode} 'IMPL' -%{mnesia_evil_coverage_test, change_table_load_order} 'IMPL' -{skip, {mnesia_evil_coverage_test, set_master_nodes, "Uses disk"}}. -{skip, {mnesia_evil_coverage_test, offline_set_master_nodes, "Uses disk"}}. -{skip, {mnesia_evil_coverage_test, replica_location, "Uses disk"}}. -%{mnesia_evil_coverage_test, add_table_index_ram} 'IMPL' -{skip, {mnesia_trans_access_test, add_table_index_disc, "Uses disc"}}. -{skip, {mnesia_trans_access_test, add_table_index_disc_only, "Uses disc"}}. -%{mnesia_evil_coverage_test, create_live_table_index_ram} 'IMPL' -{skip, {mnesia_trans_access_test, create_live_table_index_disc, "Uses disc"}}. -{skip, {mnesia_trans_access_test, create_live_table_index_disc_only, "Uses disc"}}. -%{mnesia_evil_coverage_test, del_table_index_ram} 'IMPL' -{skip, {mnesia_trans_access_test, del_table_index_disc, "Uses disc"}}. -{skip, {mnesia_trans_access_test, del_table_index_disc_only, "Uses disc"}}. -{skip, {mnesia_trans_access_test, idx_schema_changes_ram, "Uses disk"}}. -{skip, {mnesia_trans_access_test, idx_schema_changes_disc, "Uses disc"}}. -{skip, {mnesia_trans_access_test, idx_schema_changes_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_write_ram} 'IMPL' - -{skip, {mnesia_dirty_access_test, dirty_write_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_write_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_read_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_read_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_read_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_update_counter_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_update_counter_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_update_counter_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_delete_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_delete_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_delete_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_delete_object_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_delete_object_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_delete_object_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_match_object_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_match_object_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_match_object_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_index_match_object_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_index_match_object_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_index_match_object_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_index_read_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_index_read_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_index_read_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_index_update_set_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_index_update_set_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_index_update_set_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_index_update_bag_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_index_update_bag_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_index_update_bag_disc_only, "Uses disc"}}. -%{mnesia_dirty_access_test, dirty_iter_ram} 'IMPL' -{skip, {mnesia_dirty_access_test, dirty_iter_disc, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, dirty_iter_disc_only, "Uses disc"}}. -{skip, {mnesia_dirty_access_test, admin_tests, "Uses disk"}}. - -%{mnesia_trans_access_test, write} 'IMPL' -%{mnesia_trans_access_test, read} 'IMPL' -%{mnesia_trans_access_test, wread} 'IMPL' -%{mnesia_trans_access_test, delete} 'IMPL' -%{mnesia_trans_access_test, delete_object} 'IMPL' -%{mnesia_trans_access_test, match_object} 'IMPL' -%{mnesia_trans_access_test, all_keys} 'IMPL' -%{mnesia_trans_access_test, index_match_object} 'IMPL' -%{mnesia_trans_access_test, index_read} 'IMPL' -%{mnesia_trans_access_test, index_update_set} 'IMPL' -%{mnesia_trans_access_test, index_update_bag} 'IMPL' -{skip, {mnesia_evil_coverage_test, dump_tables, "Uses disk"}}. -{skip, {mnesia_evil_coverage_test, dump_log, "Uses disk"}}. -%{mnesia_evil_coverage_test, wait_for_tables} 'IMPL' -{skip, {mnesia_evil_coverage_test, force_load_table, "Uses disk"}}. -%{mnesia_evil_coverage_test, user_properties} 'IMPL' -%{mnesia_evil_coverage_test, record_name_dirty_access_ram} 'IMPL' -{skip, {mnesia_evil_coverage_test, record_name_dirty_access_disc, "Uses disc"}}. -{skip, {mnesia_evil_coverage_test, record_name_dirty_access_disc_only, "Uses disc"}}. -%{mnesia_evil_coverage_test, snmp_open_table} 'IMPL' -%{mnesia_evil_coverage_test, snmp_close_table} 'IMPL' -%{mnesia_evil_coverage_test, snmp_get_next_index} 'IMPL' -%{mnesia_evil_coverage_test, snmp_get_row} 'IMPL' -%{mnesia_evil_coverage_test, snmp_get_mnesia_key} 'IMPL' -%{mnesia_evil_coverage_test, snmp_update_counter} 'IMPL' -%{mnesia_evil_coverage_test, info} 'IMPL' -%{mnesia_evil_coverage_test, schema_0} 'IMPL' -%{mnesia_evil_coverage_test, schema_1} 'IMPL' -%{mnesia_evil_coverage_test, view_0} 'IMPL' -{skip, {mnesia_evil_coverage_test, view_1, "Uses disk"}}. -{skip, {mnesia_evil_coverage_test, view_2, "Uses disk"}}. -%{mnesia_evil_coverage_test, lkill} 'IMPL' -%{mnesia_evil_coverage_test, kill} 'IMPL' - -%{mnesia_config_test, access_module} 'IMPL' -%{mnesia_config_test, auto_repair} 'IMPL' -{skip, {mnesia_config_test, backup_module, "Uses disk"}}. -{skip, {mnesia_config_test, dynamic_connect, "Uses disk"}}. -%{mnesia_config_test, debug} 'IMPL' -%{mnesia_config_test, dir} 'IMPL' -{skip, {mnesia_config_test, dump_log_load_regulation, "Uses disk"}}. -{skip, {mnesia_config_test, dump_log_time_threshold, "Uses disk"}}. -{skip, {mnesia_config_test, dump_log_write_threshold, "Uses disk"}}. -{skip, {mnesia_config_test, dump_log_update_in_place, "Uses disk"}}. -{skip, {mnesia_config_test, embedded_mnemosyne, "Uses Mnemosyne"}}. -%{mnesia_config_test, event_module} 'IMPL' -{skip, {mnesia_config_test, ignore_fallback_at_startup, "Not Yet impl"}}. -%{mnesia_config_test, inconsistent_database} 'IMPL' -{skip, {mnesia_config_test, max_wait_for_decision, "Not Yet impl"}}. -{skip, {mnesia_config_test, start_one_disc_full_then_one_disc_less, "Uses disc"}}. -{skip, {mnesia_config_test, start_first_one_disc_less_then_one_disc_full, "Uses disc"}}. -%%{skip, {mnesia_config_test, start_first_one_disc_less_then_two_more_disc_less, "Uses disc"}}. -{skip, {mnesia_config_test, schema_location_and_extra_db_nodes_combinations, "Uses disk"}}. -{skip, {mnesia_config_test, table_load_to_disc_less_nodes, "Uses disc"}}. -{skip, {mnesia_config_test, schema_merge, "Uses Disc"}}. -%{mnesia_config_test, unknown_config} 'IMPL' -%{mnesia_registry_test, good_dump} 'IMPL' -%{mnesia_registry_test, bad_dump} 'IMPL' - -%{mnesia_atomicity_test, explicit_abort_in_middle_of_trans} 'IMPL' -%{mnesia_atomicity_test, runtime_error_in_middle_of_trans} 'IMPL' -%{mnesia_atomicity_test, kill_self_in_middle_of_trans} 'IMPL' -%{mnesia_atomicity_test, throw_in_middle_of_trans} 'IMPL' -%{mnesia_atomicity_test, mnesia_down_during_infinite_trans} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_sw_rt} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_sw_wt} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wr_r} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_sw_sw} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_sw_w} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_sw_wr} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wr_wt} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wr_sw} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wr_w} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_r_sw} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_r_w} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_r_wt} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_rt_sw} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_rt_w} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_rt_wt} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wt_r} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wt_w} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wt_rt} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wt_wt} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wt_wr} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_wt_sw} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_w_wr} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_w_sw} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_w_r} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_w_w} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_w_rt} 'IMPL' -%{mnesia_atomicity_test, lock_waiter_w_wt} 'IMPL' -%{mnesia_atomicity_test, restart_r_one} 'IMPL' -%{mnesia_atomicity_test, restart_w_one} 'IMPL' -%{mnesia_atomicity_test, restart_rt_one} 'IMPL' -%{mnesia_atomicity_test, restart_wt_one} 'IMPL' -%{mnesia_atomicity_test, restart_wr_one} 'IMPL' -%{mnesia_atomicity_test, restart_sw_one} 'IMPL' -%{mnesia_atomicity_test, restart_r_two} 'IMPL' -%{mnesia_atomicity_test, restart_w_two} 'IMPL' -%{mnesia_atomicity_test, restart_rt_two} 'IMPL' -%{mnesia_atomicity_test, restart_wt_two} 'IMPL' -%{mnesia_atomicity_test, restart_wr_two} 'IMPL' -%{mnesia_atomicity_test, restart_sw_two} 'IMPL' - -%{mnesia_isolation_test, no_conflict} 'IMPL' -%{mnesia_isolation_test, simple_queue_conflict} 'IMPL' -%{mnesia_isolation_test, advanced_queue_conflict} 'IMPL' -%{mnesia_isolation_test, simple_deadlock_conflict} 'IMPL' -%{mnesia_isolation_test, advanced_deadlock_conflict} 'IMPL' -%{mnesia_isolation_test, lock_burst} 'IMPL' -%{mnesia_isolation_test, basic_sticky_functionality} 'IMPL' -%{mnesia_isolation_test, create_table} 'IMPL' -%{mnesia_isolation_test, delete_table} 'IMPL' -%{mnesia_isolation_test, move_table_copy} 'IMPL' -%{mnesia_isolation_test, add_table_index} 'IMPL' -%{mnesia_isolation_test, del_table_index} 'IMPL' -%{mnesia_isolation_test, transform_table} 'IMPL' -%{mnesia_isolation_test, snmp_open_table} 'IMPL' -%{mnesia_isolation_test, snmp_close_table} 'IMPL' -{skip, {mnesia_isolation_test, change_table_copy_type, "Uses disk"}}. -%{mnesia_isolation_test, change_table_access} 'IMPL' -%{mnesia_isolation_test, add_table_copy} 'IMPL' -%{mnesia_isolation_test, del_table_copy} 'IMPL' -{skip, {mnesia_isolation_test, dump_tables, "Uses disk"}}. -{skip, {mnesia_isolation_test, extra_admin_tests, "Uses disk"}}. -%{mnesia_isolation_test, del_table_copy_1} 'IMPL' -%{mnesia_isolation_test, del_table_copy_2} 'IMPL' -%{mnesia_isolation_test, del_table_copy_3} 'IMPL' -%{mnesia_isolation_test, add_table_copy_1} 'IMPL' -%{mnesia_isolation_test, add_table_copy_2} 'IMPL' -%{mnesia_isolation_test, add_table_copy_3} 'IMPL' -%{mnesia_isolation_test, add_table_copy_4} 'IMPL' -%{mnesia_isolation_test, move_table_copy_1} 'IMPL' -%{mnesia_isolation_test, move_table_copy_2} 'IMPL' -%{mnesia_isolation_test, move_table_copy_3} 'IMPL' -%{mnesia_isolation_test, move_table_copy_4} 'IMPL' -%{mnesia_isolation_test, dirty_updates_visible_direct} 'IMPL' -%{mnesia_isolation_test, dirty_reads_regardless_of_trans} 'IMPL' -%{mnesia_isolation_test, trans_update_invisibible_outside_trans} 'IMPL' -%{mnesia_isolation_test, trans_update_visible_inside_trans} 'IMPL' -%{mnesia_isolation_test, write_shadows} 'IMPL' -%{mnesia_isolation_test, delete_shadows} 'IMPL' -%{mnesia_isolation_test, write_delete_shadows_bag} 'IMPL' - -{skip, {mnesia_durability_test, all, "Uses disk "}}. -%{mnesia_durability_test, load_local_contents_directly} 'IMPL' -%{mnesia_durability_test, load_directly_when_all_are_ram_copiesA} 'IMPL' -%{mnesia_durability_test, load_directly_when_all_are_ram_copiesB} 'IMPL' -%{skip, {mnesia_durability_test, late_load_when_all_are_ram_copies_on_ram_nodes1, "Uses disk schema"}}. -%{skip, {mnesia_durability_test, late_load_when_all_are_ram_copies_on_ram_nodes2, "Uses disk schema"}}. -%{skip, {mnesia_durability_test, load_when_last_replica_becomes_available, "Uses disk"}}. -%{skip, {mnesia_durability_test, load_when_we_have_down_from_all_other_replica_nodes, "Uses disk"}}. -%{skip, {mnesia_durability_test, late_load_transforms_into_disc_load, "Uses disc"}}. -%{mnesia_durability_test, late_load_leads_to_hanging} 'IMPL' -%{mnesia_durability_test, force_load_when_nobody_intents_to_load} 'IMPL' -%{mnesia_durability_test, force_load_when_someone_has_decided_to_load} 'IMPL' -%{mnesia_durability_test, force_load_when_someone_else_already_has_loaded} 'IMPL' -%{mnesia_durability_test, force_load_when_we_has_loaded} 'IMPL' -%{mnesia_durability_test, force_load_on_a_non_local_table} 'IMPL' -%{mnesia_durability_test, force_load_when_the_table_does_not_exist} 'IMPL' -%{mnesia_durability_test, master_nodes} 'IMPL' -%{mnesia_durability_test, master_on_non_local_tables} 'IMPL' -%{mnesia_durability_test, remote_force_load_with_local_master_node} 'IMPL' -%{mnesia_durability_test, dump_ram_copies} 'IMPL' -%{skip, {mnesia_durability_test, dump_disc_copies, "Uses disc"}}. -%{skip, {mnesia_durability_test, dump_disc_only, "Uses disc"}}. -%{skip, {mnesia_durability_test, durability_of_disc_copies, "Uses disc"}}. -%{skip, {mnesia_durability_test, durability_of_disc_only_copies, "Uses disc"}}. - -{skip, {mnesia_recovery_test, mnesia_down, "Uses Disk"}}. -%{mnesia_recovery_test, no_master_2} 'IMPL' -%{mnesia_recovery_test, no_master_3} 'IMPL' -%{mnesia_recovery_test, one_master_2} 'IMPL' -%{mnesia_recovery_test, one_master_3} 'IMPL' -%{mnesia_recovery_test, two_master_2} 'IMPL' -%{mnesia_recovery_test, two_master_3} 'IMPL' -%{mnesia_recovery_test, all_master_2} 'IMPL' -%{mnesia_recovery_test, all_master_3} 'IMPL' -{skip, {mnesia_recovery_test, mnesia_down_during_startup_disk_ram, "Uses disk"}}. -%{mnesia_recovery_test, mnesia_down_during_startup_init_ram} 'IMPL' -{skip, {mnesia_recovery_test, mnesia_down_during_startup_init_disc, "Uses disc"}}. -{skip, {mnesia_recovery_test, mnesia_down_during_startup_init_disc_only, "Uses disc"}}. -%{mnesia_recovery_test, mnesia_down_during_startup_tm_ram} 'IMPL' -{skip, {mnesia_recovery_test, mnesia_down_during_startup_tm_disc, "Uses disc"}}. -{skip, {mnesia_recovery_test, mnesia_down_during_startup_tm_disc_only, "Uses disc"}}. -%{mnesia_recovery_test, explicit_stop_during_snmp} 'IMPL' - -{skip, {mnesia_recovery_test, schema_trans, "Uses Disk, needs disk log"}}. -{skip, {mnesia_recovery_test, async_dirty, "Uses disc"}}. -{skip, {mnesia_recovery_test, sync_dirty, "Uses disc"}}. -{skip, {mnesia_recovery_test, sym_trans, "Uses disc"}}. -{skip, {mnesia_recovery_test, asym_trans, "Uses disc"}}. - -{skip, {mnesia_recovery_test, after_full_disc_partition, "Not Yet impl"}}. -{skip, {mnesia_recovery_test, after_corrupt_files, "Uses disk"}}. - -%{mnesia_evil_coverage_test, subscriptions} 'IMPL' -%{mnesia_evil_coverage_test, nested_trans_both_ok} 'IMPL' -%{mnesia_evil_coverage_test, nested_trans_child_dies} 'IMPL' -%{mnesia_evil_coverage_test, nested_trans_parent_dies} 'IMPL' -%{mnesia_evil_coverage_test, nested_trans_both_dies} 'IMPL' -%{mnesia_evil_coverage_test, mix_of_trans_sync_dirty} 'IMPL' -%{mnesia_evil_coverage_test, mix_of_trans_async_dirty} 'IMPL' -%{mnesia_evil_coverage_test, mix_of_trans_ets} 'IMPL' - -{skip, {mnesia_recovery_test, disc_less, "Uses disc (on the other nodes)"}}. -{skip, {mnesia_recovery_test, system_upgrade, "Not Yet impl"}}. -%{mnesia_consistency_test, consistency_after_restart_1_ram} 'IMPL' -{skip, {mnesia_consistency_test, consistency_after_restart_1_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_restart_1_disc_only, "Uses disc"}}. -%{mnesia_consistency_test, consistency_after_restart_2_ram} 'IMPL' -{skip, {mnesia_consistency_test, consistency_after_restart_2_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_restart_2_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_dump_tables_1_ram, "Uses disk"}}. -{skip, {mnesia_consistency_test, consistency_after_dump_tables_2_ram, "Uses disk"}}. -%{mnesia_consistency_test, consistency_after_add_replica_2_ram} 'IMPL' -{skip, {mnesia_consistency_test, consistency_after_add_replica_2_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_add_replica_2_disc_only, "Uses disc"}}. -%{mnesia_consistency_test, consistency_after_add_replica_3_ram} 'IMPL' -{skip, {mnesia_consistency_test, consistency_after_add_replica_3_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_add_replica_3_disc_only, "Uses disc"}}. -%{mnesia_consistency_test, consistency_after_del_replica_2_ram} 'IMPL' -{skip, {mnesia_consistency_test, consistency_after_del_replica_2_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_del_replica_2_disc_only, "Uses disc"}}. -%{mnesia_consistency_test, consistency_after_del_replica_3_ram} 'IMPL' -{skip, {mnesia_consistency_test, consistency_after_del_replica_3_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_del_replica_3_disc_only, "Uses disc"}}. -%{mnesia_consistency_test, consistency_after_move_replica_2_ram} 'IMPL' -{skip, {mnesia_consistency_test, consistency_after_move_replica_2_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_move_replica_2_disc_only, "Uses disc"}}. -%{mnesia_consistency_test, consistency_after_move_replica_3_ram} 'IMPL' -{skip, {mnesia_consistency_test, consistency_after_move_replica_3_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_move_replica_3_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_transform_table, "Not yet implemented"}}. -{skip, {mnesia_consistency_test, consistency_after_change_table_copy_type, "Not yet implemented"}}. -{skip, {mnesia_consistency_test, consistency_after_fallback_2_ram, "Uses disk"}}. -{skip, {mnesia_consistency_test, consistency_after_fallback_2_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_fallback_2_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_fallback_3_ram, "Uses disk"}}. -{skip, {mnesia_consistency_test, consistency_after_fallback_3_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_fallback_3_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_restore_clear_ram, "Uses disk"}}. -{skip, {mnesia_consistency_test, consistency_after_restore_clear_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_restore_clear_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_restore_recreate_ram, "Uses disk"}}. -{skip, {mnesia_consistency_test, consistency_after_restore_recreate_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_restore_recreate_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, consistency_after_rename_of_node, "Not yet implemented"}}. -{skip, {mnesia_consistency_test, updates_during_checkpoint_activation, "Uses disk"}}. -%{skip, {mnesia_consistency_test, updates_during_checkpoint_activation_2_disc, "Uses disc"}}. -%{skip, {mnesia_consistency_test, updates_during_checkpoint_activation_2_disc_only, "Uses disc"}}. -%%{mnesia_consistency_test, updates_during_checkpoint_activation_3_ram} 'IMPL' -%{skip, {mnesia_consistency_test, updates_during_checkpoint_activation_3_disc, "Uses disc"}}. -%{skip, {mnesia_consistency_test, updates_during_checkpoint_activation_3_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, updates_during_checkpoint_iteration, "Uses disk"}}. -%{skip, {mnesia_consistency_test, updates_during_checkpoint_iteration_2_disc, "Uses disc"}}. -%{skip, {mnesia_consistency_test, updates_during_checkpoint_iteration_2_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, load_table_with_activated_checkpoint_ram, "Uses disk"}}. -{skip, {mnesia_consistency_test, load_table_with_activated_checkpoint_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, load_table_with_activated_checkpoint_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, add_table_copy_to_table_with_activated_checkpoint_ram, "Uses disk"}}. -{skip, {mnesia_consistency_test, add_table_copy_to_table_with_activated_checkpoint_disc, "Uses disc"}}. -{skip, {mnesia_consistency_test, add_table_copy_to_table_with_activated_checkpoint_disc_only, "Uses disc"}}. -{skip, {mnesia_consistency_test, inst_fallback_process_dies, "Uses disk"}}. -{skip, {mnesia_consistency_test, fatal_when_inconsistency, "Uses disk"}}. -{skip, {mnesia_consistency_test, after_delete, "Uses disk"}}. -{skip, {mnesia_consistency_test, mnesia_down_during_backup_causes_switch, "Uses disk"}}. -{skip, {mnesia_consistency_test, mnesia_down_during_backup_causes_abort, "Uses disk"}}. -%{mnesia_consistency_test, cause_switch_after} 'IMPL' -%{mnesia_consistency_test, cause_abort_before} 'IMPL' -%{mnesia_consistency_test, cause_abort_after} 'IMPL' -%{mnesia_consistency_test, change_schema_before} 'IMPL' -%{mnesia_consistency_test, change_schema_after} 'IMPL' - diff --git a/lib/mnesia/test/mnesia_bench.spec b/lib/mnesia/test/mnesia_bench.spec new file mode 100644 index 0000000000..7b17cb5c4e --- /dev/null +++ b/lib/mnesia/test/mnesia_bench.spec @@ -0,0 +1 @@ +{suites,"../mnesia_test",[mnesia_bench_SUITE]}.
\ No newline at end of file diff --git a/lib/mnesia/test/mnesia_bench_SUITE.erl b/lib/mnesia/test/mnesia_bench_SUITE.erl new file mode 100644 index 0000000000..7cbf77f046 --- /dev/null +++ b/lib/mnesia/test/mnesia_bench_SUITE.erl @@ -0,0 +1,69 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(mnesia_bench_SUITE). +-author('[email protected]'). +-compile(export_all). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}]. + + +all() -> + [{group,tpcb}]. + +groups() -> + [{tpcb,[{repeat,2}],[tpcb_conflict_ramcopies, + tpcb_conflict_disk_only_copies]}]. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +init_per_suite(Config) -> + Config. + +end_per_suite(Config) -> + Config. + +init_per_testcase(_Func, Conf) -> + Conf. + +end_per_testcase(_Func, _Conf) -> + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +tpcb_conflict_ramcopies(_Config) -> + mnesia_tpcb:conflict_benchmark(ram_copies). + +tpcb_conflict_disk_only_copies(_Config) -> + mnesia_tpcb:conflict_benchmark(disc_only_copies). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl index ba5bf84e24..57cbc61495 100644 --- a/lib/mnesia/test/mnesia_test_lib.erl +++ b/lib/mnesia/test/mnesia_test_lib.erl @@ -272,25 +272,13 @@ slave_start_link(Host, Name, Retries) -> end. starter(Host, Name, Args) -> - case os:type() of - vxworks -> - X = test_server:start_node(Name, slave, [{args,Args}]), - timer:sleep(5000), - X; - _ -> - slave:start(Host, Name, Args) - end. + slave:start(Host, Name, Args). slave_sup() -> process_flag(trap_exit, true), receive {'EXIT', _, _} -> - case os:type() of - vxworks -> - erlang:halt(); - _ -> - ignore - end + ignore end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/orber/c_src/Makefile.in b/lib/orber/c_src/Makefile.in index 5953d41ff3..4aee760189 100644 --- a/lib/orber/c_src/Makefile.in +++ b/lib/orber/c_src/Makefile.in @@ -58,15 +58,9 @@ ifeq ($(findstring win32,$(TARGET)),win32) orber: echo "Nothing to build on NT" else -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -orber: - echo "Nothing to build for VxWorks" - -else orber: echo "Nothing to build" endif -endif clean: @@ -94,20 +88,12 @@ release_spec: opt $(INSTALL_PROGRAM) $(CC_FILES) "$(RELSYSDIR)/priv/src" $(INSTALL_PROGRAM) $(HH_FILES) "$(RELSYSDIR)/priv/include" else -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -release_spec: - $(INSTALL_DIR) "$(RELSYSDIR)/priv/src" - $(INSTALL_DIR) "$(RELSYSDIR)/priv/include" - $(INSTALL_PROGRAM) $(CC_FILES) "$(RELSYSDIR)/priv/src" - $(INSTALL_PROGRAM) $(HH_FILES) "$(RELSYSDIR)/priv/include" -else release_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)/priv/src" $(INSTALL_DIR) "$(RELSYSDIR)/priv/include" $(INSTALL_DATA) $(CC_FILES) "$(RELSYSDIR)/priv/src" $(INSTALL_DATA) $(HH_FILES) "$(RELSYSDIR)/priv/include" endif -endif release_docs_spec: diff --git a/lib/orber/test/csiv2_SUITE.erl b/lib/orber/test/csiv2_SUITE.erl index 60ffa1eb09..b89bf0a56c 100644 --- a/lib/orber/test/csiv2_SUITE.erl +++ b/lib/orber/test/csiv2_SUITE.erl @@ -668,67 +668,57 @@ code_OpenSSL509_api(_Config) -> ssl_server_peercert_api(doc) -> ["Test ssl:peercert (server side)"]; ssl_server_peercert_api(suite) -> []; ssl_server_peercert_api(_Config) -> - case os:type() of - vxworks -> - {skipped, "No SSL-support for VxWorks."}; - _ -> - Options = orber_test_lib:get_options(iiop_ssl, server, - 2, [{iiop_ssl_port, 0}]), - {ok, ServerNode, ServerHost} = - ?match({ok,_,_}, orber_test_lib:js_node(Options)), - ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_ssl_port, []), - SSLOptions = orber_test_lib:get_options(ssl, client), - {ok, Socket} = - ?match({ok, _}, fake_client_ORB(ssl, ServerHost, ServerPort, SSLOptions)), - {ok, _PeerCert} = ?match({ok, _}, orber_socket:peercert(ssl, Socket)), - %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])), - %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])), - % ?match({ok, #'Certificate'{}}, - % 'OrberCSIv2':decode('Certificate', PeerCert)), - destroy_fake_ORB(ssl, Socket), - ok - end. + Options = orber_test_lib:get_options(iiop_ssl, server, + 2, [{iiop_ssl_port, 0}]), + {ok, ServerNode, ServerHost} = + ?match({ok,_,_}, orber_test_lib:js_node(Options)), + ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_ssl_port, []), + SSLOptions = orber_test_lib:get_options(ssl, client), + {ok, Socket} = + ?match({ok, _}, fake_client_ORB(ssl, ServerHost, ServerPort, SSLOptions)), + {ok, _PeerCert} = ?match({ok, _}, orber_socket:peercert(ssl, Socket)), + %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])), + %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])), + % ?match({ok, #'Certificate'{}}, + % 'OrberCSIv2':decode('Certificate', PeerCert)), + destroy_fake_ORB(ssl, Socket), + ok. ssl_client_peercert_api(doc) -> ["Test ssl:peercert (client side)"]; ssl_client_peercert_api(suite) -> []; ssl_client_peercert_api(_Config) -> - case os:type() of - vxworks -> - {skipped, "No SSL-support for VxWorks."}; - _ -> - Options = orber_test_lib:get_options(iiop_ssl, client, - 2, [{iiop_ssl_port, 0}]), - {ok, ClientNode, _ClientHost} = - ?match({ok,_,_}, orber_test_lib:js_node(Options)), - crypto:start(), - ssl:start(), - SSLOptions = orber_test_lib:get_options(ssl, server), - {ok, LSock} = ?match({ok, _}, ssl:listen(0, SSLOptions)), - {ok, {_Address, LPort}} = ?match({ok, {_, _}}, ssl:sockname(LSock)), - IOR = ?match({'IOP_IOR',_,_}, - iop_ior:create_external({1, 2}, "IDL:FAKE:1.0", - "localhost", 6004, "FAKE", - [#'IOP_TaggedComponent' - {tag=?TAG_SSL_SEC_TRANS, - component_data=#'SSLIOP_SSL' - {target_supports = 2, - target_requires = 2, - port = LPort}}])), - spawn(orber_test_lib, remote_apply, - [ClientNode, corba_object, non_existent, [IOR]]), - {ok, Socket} = ?match({ok, _}, ssl:transport_accept(LSock)), - ?match(ok, ssl:ssl_accept(Socket)), - - {ok, _PeerCert} = ?match({ok, _}, orber_socket:peercert(ssl, Socket)), - %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])), - %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])), - % ?match({ok, #'Certificate'{}}, - % 'OrberCSIv2':decode('Certificate', PeerCert)), - ssl:close(Socket), - ssl:close(LSock), - ssl:stop(), - ok - end. + Options = orber_test_lib:get_options(iiop_ssl, client, + 2, [{iiop_ssl_port, 0}]), + {ok, ClientNode, _ClientHost} = + ?match({ok,_,_}, orber_test_lib:js_node(Options)), + crypto:start(), + ssl:start(), + SSLOptions = orber_test_lib:get_options(ssl, server), + {ok, LSock} = ?match({ok, _}, ssl:listen(0, SSLOptions)), + {ok, {_Address, LPort}} = ?match({ok, {_, _}}, ssl:sockname(LSock)), + IOR = ?match({'IOP_IOR',_,_}, + iop_ior:create_external({1, 2}, "IDL:FAKE:1.0", + "localhost", 6004, "FAKE", + [#'IOP_TaggedComponent' + {tag=?TAG_SSL_SEC_TRANS, + component_data=#'SSLIOP_SSL' + {target_supports = 2, + target_requires = 2, + port = LPort}}])), + spawn(orber_test_lib, remote_apply, + [ClientNode, corba_object, non_existent, [IOR]]), + {ok, Socket} = ?match({ok, _}, ssl:transport_accept(LSock)), + ?match(ok, ssl:ssl_accept(Socket)), + + {ok, _PeerCert} = ?match({ok, _}, orber_socket:peercert(ssl, Socket)), + %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])), + %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])), + % ?match({ok, #'Certificate'{}}, + % 'OrberCSIv2':decode('Certificate', PeerCert)), + ssl:close(Socket), + ssl:close(LSock), + ssl:stop(), + ok. %%----------------------------------------------------------------- %% Local functions. diff --git a/lib/orber/test/orber_test_lib.erl b/lib/orber/test/orber_test_lib.erl index 2bfa1ef871..00fd1e0625 100644 --- a/lib/orber/test/orber_test_lib.erl +++ b/lib/orber/test/orber_test_lib.erl @@ -278,24 +278,13 @@ check_options(Options) -> end. starter(Host, Name, Args) -> - case os:type() of - vxworks -> - test_server:start_node(Name, slave, [{args,Args}]); - _ -> - io:format("slave:start_link(~p,~p,~p).~n",[Host,Name,Args]), - slave:start_link(Host, Name, Args) - end. + io:format("slave:start_link(~p,~p,~p).~n",[Host,Name,Args]), + slave:start_link(Host, Name, Args). slave_sup() -> process_flag(trap_exit, true), receive - {'EXIT', _, _} -> - case os:type() of - vxworks -> - erlang:halt(); - _ -> - ignore - end + {'EXIT', _, _} -> ignore end. start_ssl(true, Node) -> @@ -419,12 +408,7 @@ destroy_node(Node, Type) -> stopper(Node, Type). stopper(Node, _Type) -> - case os:type() of - vxworks -> - test_server:stop_node(Node); - _ -> - slave:stop(Node) - end. + slave:stop(Node). %%------------------------------------------------------------ diff --git a/lib/os_mon/c_src/Makefile.in b/lib/os_mon/c_src/Makefile.in index 45dc01e993..adc14f0bb1 100644 --- a/lib/os_mon/c_src/Makefile.in +++ b/lib/os_mon/c_src/Makefile.in @@ -63,14 +63,10 @@ ENTRY_OBJ=$(ERL_TOP)/erts/obj/$(TARGET)/port_entry.o PORT_ENTRY_POINT=erl_port_entry ENTRY_LDFLAGS=-entry:$(PORT_ENTRY_POINT) else -ifeq ($(findstring vxworks_simso,$(TARGET)),vxworks_simso) -PROGRAMS = -else PROGRAMS = \ memsup @os_mon_programs@ C_FILES= $(PROGRAMS:%=%.c) endif -endif TARGET_FILES= $(PROGRAMS:%=$(BINDIR)/%) @@ -127,14 +123,10 @@ $(OBJDIR)/memsup.o: memsup.h # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -ifeq ($(findstring vxworks_simso,$(TARGET)),vxworks_simso) -release_spec: -else release_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)/src" $(INSTALL_DATA) $(C_FILES) "$(RELSYSDIR)/src" $(INSTALL_DIR) "$(RELSYSDIR)/priv/bin" $(INSTALL_PROGRAM) $(TARGET_FILES) "$(RELSYSDIR)/priv/bin" -endif release_docs_spec: diff --git a/lib/os_mon/c_src/memsup.c b/lib/os_mon/c_src/memsup.c index 593a066f98..3a1a8e9444 100644 --- a/lib/os_mon/c_src/memsup.c +++ b/lib/os_mon/c_src/memsup.c @@ -31,7 +31,7 @@ * * This program is started from Erlang as follows, * - * Port = open_port({spawn, 'memsup'}, [{packet,1}]) for UNIX and VxWorks + * Port = open_port({spawn, 'memsup'}, [{packet,1}]) for UNIX * * Erlang sends one of the request condes defined in memsup.h and this program * answers in one of two ways: @@ -75,10 +75,6 @@ * that there is no process at the other end of the connection * having the connection open for writing (end-of-file). * - * COMPILING - * - * When the target is VxWorks the identifier VXWORKS must be defined for - * the preprocessor (usually by a -D option). */ #if defined(sgi) || defined(__sgi) || defined(__sgi__) @@ -90,9 +86,7 @@ #include <stddef.h> #include <stdlib.h> -#ifndef VXWORKS #include <unistd.h> -#endif #if (defined(__unix__) || defined(unix)) && !defined(USG) #include <sys/param.h> @@ -104,12 +98,6 @@ #include <time.h> #include <errno.h> -#ifdef VXWORKS -#include <vxWorks.h> -#include <ioLib.h> -#include <memLib.h> -#endif - #ifdef BSD4_4 #include <sys/types.h> #include <sys/sysctl.h> @@ -143,20 +131,8 @@ /* prototypes */ static void print_error(const char *,...); -#ifdef VXWORKS -extern int erl_mem_info_get(MEM_PART_STATS *); -#endif - -#ifdef VXWORKS -#define MAIN memsup -static MEM_PART_STATS latest; -static unsigned long latest_system_total; /* does not fit in the struct */ - -#else #define MAIN main -#endif - /* * example, we want procfs information, now give them something equivalent: @@ -282,16 +258,6 @@ send_tag(int value){ } } - -#ifdef VXWORKS -static void load_statistics(void){ - if(memPartInfoGet(memSysPartId,&latest) != OK) - memset(&latest,0,sizeof(latest)); - latest_system_total = latest.numBytesFree + latest.numBytesAlloc; - erl_mem_info_get(&latest); /* if it fails, latest is untouched */ -} -#endif - #ifdef BSD4_4 static int get_vmtotal(struct vmtotal *vt) { @@ -358,19 +324,6 @@ get_mem_procfs(memory_ext *me){ /* arch specific functions */ -#if defined(VXWORKS) -static int -get_extended_mem_vxwork(memory_ext *me) { - load_statistics(); - me->total = (latest.numBytesFree + latest.numBytesAlloc); - me->free = latest.numBytesFree; - me->pagesize = 1; - me->flag = F_MEM_TOTAL | F_MEM_FREE; - return 1; -} -#endif - - #if defined(__linux__) /* ifdef SYSINFO */ /* sysinfo does not include cached memory which is a problem. */ static int @@ -442,12 +395,8 @@ get_extended_mem_sgi(memory_ext *me) { static void get_extended_mem(memory_ext *me) { -/* vxworks */ -#if defined(VXWORKS) - if (get_extended_mem_vxworks(me)) return; - /* linux */ -#elif defined(__linux__) +#if defined(__linux__) if (get_mem_procfs(me)) return; if (get_extended_mem_sysinfo(me)) return; @@ -477,12 +426,7 @@ get_extended_mem(memory_ext *me) { static void get_basic_mem(unsigned long *tot, unsigned long *used, unsigned long *pagesize){ -#if defined(VXWORKS) - load_statistics(); - *tot = (latest.numBytesFree + latest.numBytesAlloc); - *used = latest.numBytesAlloc; - *pagesize = 1; -#elif defined(_SC_AVPHYS_PAGES) /* Does this exist on others than Solaris2? */ +#if defined(_SC_AVPHYS_PAGES) /* Does this exist on others than Solaris2? */ unsigned long avPhys, phys, pgSz; phys = sysconf(_SC_PHYS_PAGES); @@ -557,17 +501,8 @@ extended_show_mem(void){ if (me.flag & F_SWAP_TOTAL) { send_tag(SWAP_TOTAL); send(me.total_swap, ps); } if (me.flag & F_SWAP_FREE) { send_tag(SWAP_FREE); send(me.free_swap, ps); } -#ifdef VXWORKS - send_tag(SM_SYSTEM_TOTAL); - send(latest_system_total, 1); - send_tag(SM_LARGEST_FREE); - send(latest.maxBlockSizeFree, 1); - send_tag(SM_NUMBER_OF_FREE); - send(latest.numBlocksFree, 1); -#else /* total is system total*/ if (me.flag & F_MEM_TOTAL) { send_tag(MEM_SYSTEM_TOTAL); send(me.total, ps); } -#endif send_tag(SHOW_SYSTEM_MEM_END); } diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl index 54771b4703..a1b8591c8c 100644 --- a/lib/os_mon/src/memsup.erl +++ b/lib/os_mon/src/memsup.erl @@ -185,7 +185,6 @@ init([]) -> {unix, irix} -> true; {unix, sunos} -> true; {win32, _OSname} -> false; - vxworks -> true; _ -> exit({unsupported_os, OS}) end, @@ -617,8 +616,7 @@ code_change(Vsn, PrevState, "1.8") -> {unix, openbsd} -> true; {unix, netbsd} -> true; {unix, sunos} -> true; - {win32, _OSname} -> false; - vxworks -> true + {win32, _OSname} -> false end, Pid = if PortMode -> spawn_link(fun() -> port_init() end); diff --git a/lib/os_mon/src/os_mon.erl b/lib/os_mon/src/os_mon.erl index 2b6cd7c498..df1eccb064 100644 --- a/lib/os_mon/src/os_mon.erl +++ b/lib/os_mon/src/os_mon.erl @@ -177,8 +177,6 @@ services({unix, _}) -> % Other unix. [cpu_sup, disksup, memsup]; services({win32, _}) -> [disksup, memsup, os_sup, sysinfo]; -services(vxworks) -> - [memsup]; services(_) -> []. diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in index 754e6ccd78..586f649924 100644 --- a/lib/runtime_tools/c_src/Makefile.in +++ b/lib/runtime_tools/c_src/Makefile.in @@ -46,9 +46,6 @@ LDFLAGS += $(DED_LDFLAGS) DTRACE_LIBNAME = dyntrace SYSINCLUDE = $(DED_SYS_INCLUDE) -ifeq ($(findstring vxworks,$(TARGET)),vxworks) - SYSINCLUDE += -I$(ERL_TOP)/erts/etc/vxworks -endif TRACE_DRV_INCLUDES = $(SYSINCLUDE) @@ -101,12 +98,8 @@ ifeq ($(findstring win32,$(TARGET)), win32) SOLIBS = $(LIBDIR)/trace_ip_drv.dll $(LIBDIR)/trace_file_drv.dll LN=cp else -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -SOLIBS = $(LIBDIR)/trace_ip_drv.eld $(LIBDIR)/trace_file_drv.eld -else SOLIBS = $(LIBDIR)/trace_ip_drv.so $(LIBDIR)/trace_file_drv.so endif -endif # ---------------------------------------------------- # Targets # ---------------------------------------------------- @@ -165,15 +158,6 @@ $(LIBDIR)/trace_ip_drv.dll: $(TRACE_IP_DRV_OBJS) $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(LIBDIR)/trace_file_drv.dll: $(TRACE_FILE_DRV_OBJS) $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) -# -# VxWorks is simply to different from Unix in this sense. -# Here are the inference rules for VxWorks -# -$(LIBDIR)/trace_ip_drv.eld: $(TRACE_IP_DRV_OBJS) - $(LD) $(LDFLAGS) -o $@ $^ - -$(LIBDIR)/trace_file_drv.eld: $(TRACE_FILE_DRV_OBJS) - $(LD) $(LDFLAGS) -o $@ $^ clean: rm -f $(SOLIBS) $(TRACE_IP_DRV_OBJS) $(TRACE_FILE_DRV_OBJS) diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c index 6b77128761..a7d132ca6e 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -34,21 +34,12 @@ #include <stdlib.h> #include <string.h> #ifndef __WIN32__ -# ifdef VXWORKS -# include <sockLib.h> -# include <sys/times.h> -# include <iosLib.h> -# include <taskLib.h> -# include <selectLib.h> -# include <ioLib.h> -# include "reclaim.h" -# endif -# include <unistd.h> -# include <errno.h> -# include <sys/types.h> -# include <sys/socket.h> -# include <netinet/in.h> -# include <fcntl.h> +# include <unistd.h> +# include <errno.h> +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <fcntl.h> #endif #ifdef DEBUG @@ -910,7 +901,7 @@ static void stop_select(ErlDrvEvent event, void* _) WSACloseEvent((HANDLE)event); } -#else /* UNIX/VXWORKS */ +#else /* UNIX */ static int my_driver_select(TraceIpData *desc, SOCKET fd, int flags, enum MySelectOp op) { diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile index d240b287c3..51d93df418 100644 --- a/lib/runtime_tools/doc/src/Makefile +++ b/lib/runtime_tools/doc/src/Makefile @@ -43,9 +43,11 @@ XML_APPLICATION_FILES = ref_man.xml XML_REF3_FILES = dbg.xml dyntrace.xml erts_alloc_config.xml XML_REF6_FILES = runtime_tools_app.xml -XML_PART_FILES = part_notes.xml part_notes_history.xml +XML_PART_FILES = part_notes.xml part_notes_history.xml part.xml XML_CHAPTER_FILES = notes.xml notes_history.xml +GENERATED_XML_FILES = DTRACE.xml SYSTEMTAP.xml + BOOK_FILES = book.xml XML_FILES = \ @@ -78,6 +80,11 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +$(XML_FILES): $(GENERATED_XML_FILES) + +%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml + $(ERL_TOP)/make/emd2exml $< $@ + $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ diff --git a/lib/runtime_tools/doc/src/book.xml b/lib/runtime_tools/doc/src/book.xml index 3f0dd7d55e..ad7d709644 100644 --- a/lib/runtime_tools/doc/src/book.xml +++ b/lib/runtime_tools/doc/src/book.xml @@ -34,6 +34,9 @@ <preamble> <contents level="2"></contents> </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> <applications> <xi:include href="ref_man.xml"/> </applications> diff --git a/lib/runtime_tools/doc/src/dyntrace.xml b/lib/runtime_tools/doc/src/dyntrace.xml index 5fc5530f25..f0149d0665 100644 --- a/lib/runtime_tools/doc/src/dyntrace.xml +++ b/lib/runtime_tools/doc/src/dyntrace.xml @@ -42,7 +42,7 @@ </list> <p>Both building with dynamic trace probes and using them is experimental and unsupported by Erlang/OTP. It is included as an option for the developer to trace and debug performance issues in their systems.</p> <p>The original implementation is mostly done by Scott Lystiger Fritchie as an Open Source Contribution and it should be viewed as such even though the source for dynamic tracing as well as this module is included in the main distribution. However, the ability to use dynamic tracing of the virtual machine is a very valuable contribution which OTP has every intention to maintain as a tool for the developer.</p> - <p>How to write <c>d</c> programs or <c>systemtap</c> scripts can be learned from books and from a lot of pages on the Internet. This manual page does not include any documentation about using the dynamic trace tools of respective platform. The <c>examples</c> directory of the <c>runtime_tools</c> application however contains comprehensive examples of both <c>d</c> and <c>systemtap</c> programs that will help you get started. Another source of information is the <c>README.dtrace(.md)</c> and <c>README.systemtap(.md)</c> files in the Erlang source top directory.</p> + <p>How to write <c>d</c> programs or <c>systemtap</c> scripts can be learned from books and from a lot of pages on the Internet. This manual page does not include any documentation about using the dynamic trace tools of respective platform. The <c>examples</c> directory of the <c>runtime_tools</c> application however contains comprehensive examples of both <c>d</c> and <c>systemtap</c> programs that will help you get started. Another source of information is the <seealso marker="DTRACE">dtrace</seealso> and <seealso marker="SYSTEMTAP">systemtap</seealso> chapters in the Runtime Tools Users' Guide.</p> </description> <funcs> <func> diff --git a/lib/inviso/doc/src/part.xml b/lib/runtime_tools/doc/src/part.xml index 08ced28f47..948d4a8020 100644 --- a/lib/inviso/doc/src/part.xml +++ b/lib/runtime_tools/doc/src/part.xml @@ -4,7 +4,7 @@ <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2006</year><year>2009</year> + <year>2012</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,15 +21,22 @@ </legalnotice> - <title>Inviso User's Guide</title> - <prepared></prepared> + <title>Runtime Tools User's Guide</title> + <prepared>Lukas Larsson</prepared> <docno></docno> - <date></date> + <date>2012-07-18</date> <rev></rev> + <file>part.xml</file> </header> + <description> - <p><em>Inviso</em>, an Erlang trace tool.</p> + <p><em>Runtime Tools</em></p> </description> - <xi:include href="inviso_chapter.xml"/> + + <xi:include href="DTRACE.xml"/> + <xi:include href="SYSTEMTAP.xml"/> </part> + + + diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile index 810e3e8741..d6750f3a88 100644 --- a/lib/runtime_tools/src/Makefile +++ b/lib/runtime_tools/src/Makefile @@ -36,12 +36,6 @@ RELSYSDIR = $(RELEASE_PATH)/lib/runtime_tools-$(VSN) MODULES= \ erts_alloc_config \ - inviso_rt \ - inviso_rt_meta \ - inviso_rt_lib \ - inviso_as_lib \ - inviso_autostart \ - inviso_autostart_server \ runtime_tools \ runtime_tools_sup \ dbg \ diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index 385047ee73..d35c8e781e 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -431,10 +431,8 @@ trace_port1(file, Filename, Options) -> fun() -> Name = filename:absname(Filename), %% Absname is needed since the driver uses - %% the supplied name without further investigations, - %% and if the name is relative the resulting path - %% might be too long which can cause a bus error - %% on vxworks instead of a nice error code return. + %% the supplied name without further investigations. + %% Also, the absname must be found inside the fun, %% in case the actual node where the port shall be %% started is on another node (or even another host) diff --git a/lib/runtime_tools/src/inviso_as_lib.erl b/lib/runtime_tools/src/inviso_as_lib.erl deleted file mode 100644 index 75f3d9d004..0000000000 --- a/lib/runtime_tools/src/inviso_as_lib.erl +++ /dev/null @@ -1,155 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%%% File : inviso_as_lib.erl -%%% Author : Lennart �hman <[email protected]> -%%% Description : -%% The purpose of the inviso autostart library is to provide useful functions -%% for anyone wanting to customize the autostart mechanism in the inviso -%% tracer. It is intended to work well with the example 'inviso_autostart_server'. -%%% -%%% Created : 15 Dec 2005 by Lennart �hman -%% ----------------------------------------------------------------------------- - --module(inviso_as_lib). - --export([setup_autostart/7,setup_autostart/8,setup_autostart/9, - inhibit_autostart/1, - set_repeat/2,set_repeat_2/2]). -%% ----------------------------------------------------------------------------- - -%% setup_autostart(Node,Repeat,Options,TracerData,CmdFiles,Bindings) = ok|{error,Reason}. -%% Repeat=integer(), where 0 means no (more) autostarts. -%% Options=List of options as taken by the runtime component at start-up. -%% TracerData= Tracerdata as given to inviso_rt:init_tracing. -%% CmdFiles=[FileName,...] list of string(), files that will be executed -%% by the subprocess started during autostart. -%% Bindings=[{VarName,Value},...] Variable bindings for CmdFiles. -%% VarName=atom(), -%% -%% This function creates the inviso_autostart.config file on Erlang node Node. -%% This is useful when you wish to prepare for an autostarted trace. -setup_autostart(Node,Repeat,Options,TracerData,CmdFiles,Bindings,Translations) -> - setup_autostart(Node,Repeat,Options,TracerData,CmdFiles, - Bindings,Translations,inviso_std_ref,off). -setup_autostart(Node,Repeat,Options,TracerData,CmdFiles,Bindings,Translations,RTtag) -> - setup_autostart(Node,Repeat,Options,TracerData,CmdFiles, - Bindings,Translations,RTtag,off). -setup_autostart(Node,Repeat,Options,TracerData,CmdFiles,Bindings,Translations,RTtag,Dbg) -> - case rpc:call(Node,inviso_autostart,which_config_file,[]) of - FileName when is_list(FileName) -> % Write to this file then. - {String,Args}=format_config_file(Repeat,TracerData,Options,CmdFiles, - Bindings,Translations,RTtag,Dbg), - Bytes=list_to_binary(io_lib:format(String,Args)), - case rpc:call(Node,file,write_file,[FileName,Bytes]) of - ok -> - ok; - {error,Reason} -> - {error,{write_file,Reason}}; - {badrpc,Reason} -> - {error,{badrpc,{write_file,Reason}}} - end; - {error,Reason} -> - {error,{which_config_file,Reason}}; - {badrpc,Reason} -> - {error,{badrpc,{which_config_file,Reason}}} - end. -%% ----------------------------------------------------------------------------- - -%% inhibit_autostart(Node) = ok|{error,Reason} -%% -%% Inhibits autostart by simply making the repeat parameter zero in the -%% configuration file at node Node. All other parameters are left untouched. -inhibit_autostart(Node) -> - set_repeat(Node,0). -%% ----------------------------------------------------------------------------- - -%% set_repeat(Node,N)=ok | {error,Reason} -%% N=integer(), the number of time autostart shall be allowed. -set_repeat(Node,N) -> - case examine_config_file(Node) of - {ok,FileName,Terms} -> - NewTerms=[{repeat,N}|lists:keydelete(repeat,1,Terms)], - case rpc:call(Node,?MODULE,set_repeat_2,[FileName,NewTerms]) of - {badrpc,Reason} -> - {error,{badrpc,{open,Reason}}}; - Result -> - Result - end; - {error,Reason} -> - {error,Reason} - end. - -%% Must be a sepparate function to do rpc on. The entire function must be done -%% in one rpc call. Otherwise the FD will die since it is linked to the opening -%% process. -set_repeat_2(FileName,NewTerms) -> - case file:open(FileName,[write]) of - {ok,FD} -> - String=lists:flatten(lists:map(fun(_)->"~w.~n" end,NewTerms)), - case catch io:format(FD,String,NewTerms) of - ok -> - file:close(FD), - ok; - {'EXIT',Reason} -> - file:close(FD), - {error,{format,Reason}} - end; - {error,Reason} -> - {error,Reason} - end. -%% ----------------------------------------------------------------------------- - -examine_config_file(Node) -> - case rpc:call(Node,inviso_autostart,which_config_file,[]) of - FileName when is_list(FileName) -> % Read this file, and then modify it. - case rpc:call(Node,file,consult,[FileName]) of - {ok,Terms} -> - {ok,FileName,Terms}; - {error,Reason} -> - {error,{consult,Reason}}; - {badrpc,Reason} -> - {error,{badrpc,{consult,Reason}}} - end; - {error,Reason} -> - {error,{which_config_file,Reason}}; - {badrpc,Reason} -> - {error,{badrpc,{which_config_file,Reason}}} - end. -%% ----------------------------------------------------------------------------- - -format_config_file(Repeat,TracerData,Options,CmdFiles,Bindings,Translations,RTtag,Dbg) -> - String="~w.~n~w.~n~w.~n~w.~n", - Args=[{repeat,Repeat}, - {mfa,{inviso_autostart_server,init,[[{tracerdata,TracerData}, - {cmdfiles,CmdFiles}, - {bindings,Bindings}, - {translations,Translations}, - {debug,Dbg}]]}}, - {options,Options}, - {tag,RTtag}], - {String,Args}. -%% ----------------------------------------------------------------------------- - - - - - - - diff --git a/lib/runtime_tools/src/inviso_autostart.erl b/lib/runtime_tools/src/inviso_autostart.erl deleted file mode 100644 index 787292e244..0000000000 --- a/lib/runtime_tools/src/inviso_autostart.erl +++ /dev/null @@ -1,201 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Author: Lennart �hman, [email protected] --module(inviso_autostart). - --export([autostart/1,which_config_file/0]). - -%% This module implements the default autostart module for the inviso runtime -%% component. -%% It will: -%% (1) Open the autostart configuration file (either the default or the one -%% pointed out by the runtime_tools application parameter inviso_autostart_config). -%% (2) Check that the incarnation counter has not reached 0. If so, we do not -%% allow (yet) one autostart. -%% (3) Rewrite the configuration file if there was an incarnation counter. -%% (With the counter decreased). -%% (4) Inspect the content of the configuration file and pass paramters in the -%% return value (which is interpreted by the runtime component). -%% -%% CONTENT OF A CONFIGURATION FILE: -%% A plain text file containing erlang tuple terms, each ended with a period(.). -%% The following parameters are recognized: -%% {repeat,N} N=interger(), -%% The number of remaining allowed autostart incarnations of inviso. -%% {options,Options} Options=list() -%% The options which controls the runtime component, such as overload and -%% dependency. -%% {mfa,{Mod,Func,Args}} Args=list() -%% Controls how a spy process initiating tracing, patterns and flags shall -%% be started. -%% {tag,Tag} -%% The tag identifying the runtime component to control components. -%% ============================================================================= - -%% This function is run in the runtime component's context during autostart -%% to determine whether to continue and if, then how. -autostart(_AutoModArgs) -> - ConfigFile= - case application:get_env(inviso_autostart_conf) of - {ok,FileName} when is_list(FileName) -> % Use this filename then. - FileName; - {ok,{load,FileNames,{M,F}}} -> % First load the module, then... - case try_load_module(FileNames) of - ok -> - autostart_apply(M,F); - - false -> % No such module available - "inviso_autostart.config" - end; - {ok,{M,F}} -> % Use M:F(node()) - autostart_apply(M,F); - {ok,no_autostart} -> - false; - _ -> % Use a default name, in CWD! - "inviso_autostart.config" - end, - if - is_list(ConfigFile) -> - case file:consult(ConfigFile) of - {ok,Terms} -> % There is a configuration. - case handle_repeat(ConfigFile,Terms) of - ok -> % Handled or not, we shall continue. - {get_mfa(Terms),get_options(Terms),get_tag(Terms)}; - stop -> % We are out of allowed starts. - true % Then no autostart. - end; - {error,_} -> % There is no config file - true % Then no autostart! - end; - true -> % Skip it then. - true - end. - -autostart_apply(M,F) -> - case catch M:F(node()) of - FileName when is_list(FileName) -> - FileName; - no_autostart -> % No autostart after all. - false; - _ -> - "inviso_autostart.config" - end. - -%% This function is necessary since it is not always the case that all code-paths -%% are set at the time of an autostart. -try_load_module([AbsFileName|Rest]) when is_list(AbsFileName) -> - case catch code:load_abs(AbsFileName) of % May not be a proper filename. - {module,_Mod} -> - try_load_module(Rest); - _ -> - false - end; -try_load_module([]) -> % Load all beam files successfully. - ok; -try_load_module(AbsFileName) when is_list(AbsFileName) -> - try_load_module([AbsFileName]). -%% ----------------------------------------------------------------------------- - -%% Function returning the filename probably used as autostart config file. -%% Note that this function must be executed at the node in question. -which_config_file() -> - case application:get_env(runtime_tools,inviso_autostart_conf) of - {ok,FileName} when is_list(FileName) -> % Use this filename then. - FileName; - {ok,{M,F}} -> % Use M:F(node()) - case catch M:F(node()) of - FileName when is_list(FileName) -> - FileName; - _ -> - {ok,CWD}=file:get_cwd(), - filename:join(CWD,"inviso_autostart.config") - end; - _ -> % Use a default name, in CWD! - {ok,CWD}=file:get_cwd(), - filename:join(CWD,"inviso_autostart.config") - end. -%% ----------------------------------------------------------------------------- - - -%% Help function which finds out if there is a limit on the number of times -%% we shall autostart. If there is a repeat parameter and it is greater than -%% zero, the file must be rewritten with the parameter decreased with one. -%% Returns 'ok' or 'stop'. -handle_repeat(FileName,Terms) -> - case lists:keysearch(repeat,1,Terms) of - {value,{_,N}} when N>0 -> % Controlls how many time more. - handle_repeat_rewritefile(FileName,Terms,N-1), - ok; % Indicate that we shall continue. - {value,_} -> % No we have reached the limit. - stop; - false -> % There is no repeat parameter. - ok % No restrictions then! - end. - -%% Help function which writes the configuration file again, but with the -%% repeat parameter set to NewN. -%% Returns nothing significant. -handle_repeat_rewritefile(FileName,Term,NewN) -> - case file:open(FileName,[write]) of - {ok,FD} -> - NewTerm=lists:keyreplace(repeat,1,Term,{repeat,NewN}), - handle_repeat_rewritefile_2(FD,NewTerm), - file:close(FD); - {error,_Reason} -> % Not much we can do then?! - error - end. - -handle_repeat_rewritefile_2(FD,[Tuple|Rest]) -> - io:format(FD,"~w.~n",[Tuple]), - handle_repeat_rewritefile_2(FD,Rest); -handle_repeat_rewritefile_2(_,[]) -> - true. -%% ----------------------------------------------------------------------------- - -%% Three help functions finding the parameters possible to give to the runtime -%% component. Note that some of them have default values, should the parameter -%% not exist. -get_mfa(Terms) -> - case lists:keysearch(mfa,1,Terms) of - {value,{_,MFA}} -> - MFA; - false -> - false - end. - -get_options(Terms) -> - case lists:keysearch(options,1,Terms) of - {value,{_,Options}} -> - Options; - false -> - [] - end. - -get_tag(Terms) -> - case lists:keysearch(tag,1,Terms) of - {value,{_,Tag}} -> - Tag; - false -> - default_tag - end. -%% ----------------------------------------------------------------------------- - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - diff --git a/lib/runtime_tools/src/inviso_autostart_server.erl b/lib/runtime_tools/src/inviso_autostart_server.erl deleted file mode 100644 index 1e352822f4..0000000000 --- a/lib/runtime_tools/src/inviso_autostart_server.erl +++ /dev/null @@ -1,311 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Author: Lennart �hman, [email protected] -%% --module(inviso_autostart_server). --export([init/1]). - -%% ----------------------------------------------------------------------------- -%% Internal exports -%% ----------------------------------------------------------------------------- --export([cmd_file_interpreter_init/4]). -%% ----------------------------------------------------------------------------- - - -%% This module provides a (well working) example of how to program an -%% autostart server responsible for initializing trace, setting patterns -%% and flags. -%% -%% The general idea is that this code spawns interpreter processes in order to -%% execute commands concurrently. Each of the interpreter processes opens one or -%% several files (in sequence) containing erlang function calls which are evaluated -%% in the interpreter process context. -%% The argument provided to init shall be a list of options controlling -%% how to initialize tracing, which file(s) to open and variable bindings. -%% -%% This autostart_server interpreters understands standard inviso trace case files. -%% -%% The runtime component provides an API very similar to the API provided -%% by the control component. It is therefore easy to translate inviso calls to -%% inviso_rt calls. -%% -%% This process may be killed by the inviso_rt process if stop_tracing is called. -%% The reason is that there is no time limit to the interpreter processes. Hence -%% they should be killed if tracing is not possible anylonger. -%% ============================================================================= - - -%% ----------------------------------------------------------------------------- - -%% The independent autostart process spawned by the runtime component to carry -%% out initializations is spawened on this function (if using the example -%% autostart which comes with inviso). -%% ArgsFromConfig is as can be heard from the name comming from a paramater in -%% the autostart configuration file. Here it is supposed to be: -%% ArgsFromConfig=[ServerParam,...] -%% ServerParam={tracerdata,TracerData}|{cmdfiles,Files}|{bindings,Bindings}| -%% {translations,Translations}|{debug,DbgLevel} -%% TracerData=tracerdata given to inviso_rt:init_tracing/1 function. -%% Files=[FileNameSpecs,...] where each FileNameSpecs will be executed in -%% a separate process. Making each FileNameSpec parallel. -%% FileNameSpecs=[FileNameSpec,...] -%% FileNameSpec=FileName | {FileName,Bindings} -%% Bindings=[{Var,Value},...] variable environment understood by -%% erl_eval:exprs/2. -%% Translations=[Translation,...] -%% A translation file is a text-file with following tuples -%% Translation={{Mod,Func,Arity,{Mod2,Func2,ParamMF}}}| -%% {{Func,Arity,{Mod2,Func2,ParamMF}}} -%% ParamMF={M,F} | any() -%% Translates Mod:Func/Arity to Mod2:Func2 with the arguments to -%% Mod:Func translated using M:F/1. Note that ParamMF is not -%% necessarily an MF. If no translation shall be done, ParamMF -%% shall be anything else but an MF. -%% Also note that Mod is optional in a Translation. That means that -%% function calls without a module in the trace case file will -%% be translated according to that translation. -init(ArgsFromConfig) -> - case get_tracerdata_opts(ArgsFromConfig) of - {ok,TracerData} -> % Otherwise we can not start a trace! - case inviso_rt:init_tracing(TracerData) of - {ok,_Response} -> % Ok, tracing has been initiated. - case get_cmdfiles_opts(ArgsFromConfig) of - {ok,CmdFiles} -> % List of cmd-files. - Bindings=get_initialbindings_opts(ArgsFromConfig), - Translations=get_translations_opts(ArgsFromConfig), - Dbg=get_dbg_opts(ArgsFromConfig), - Procs=start_cmd_file_interpreters(CmdFiles, - Bindings, - Translations, - Dbg), - loop(Procs,Dbg); % Wait for procs to be done. - false -> % Then we can terminate normally. - true - end; - {error,Reason} -> % This is fault, lets terminate abnormally. - exit({inviso,{error,Reason}}) - end; - false -> % Then there is not much use then. - true % Just terminate normally. - end. -%% ----------------------------------------------------------------------------- - -%% Help function which starts a process for each item found in the FileNames -%% list. The idea is that each item will be processed concurrently. The items -%% them selves may be a sequence of filenames. -%% Returns a list of spawned interpret processes. -start_cmd_file_interpreters([FileNames|Rest],Bindings,Translations,Dbg) -> - P=spawn_link(?MODULE,cmd_file_interpreter_init,[FileNames,Bindings,Translations,Dbg]), - MRef=erlang:monitor(process,P), % Can't trap exits in this process. - [{P,MRef}|start_cmd_file_interpreters(Rest,Bindings,Translations,Dbg)]; -start_cmd_file_interpreters([],_,_,_) -> - []. -%% ----------------------------------------------------------------------------- - - -%% The loop where this process simply waits for all of the interpreters to be -%% done. Note that that may take som time. An interpreter may take as long time -%% necessary to do its task. -loop(Procs,Dbg) -> - receive - {'DOWN',MRef,process,Pid,_Reason} -> - case lists:keysearch(MRef,1,Procs) of - {value,{Pid,_}} -> % It was an interpreter that terminated. - case lists:keydelete(MRef,1,Procs) of - [] -> % No more interpreters. - true; % Then terminate. - NewProcs -> - loop(NewProcs,Dbg) - end; - false -> - loop(Procs,Dbg) - end; - _ -> - loop(Procs,Dbg) - end. - - -%% ----------------------------------------------------------------------------- -%% The interpret process. -%% -%% An interpreter process executes trace case files. Several interpreter processes -%% may be running in parallel. It is not within the scoop of this implementation -%% of an autostart server to solve conflicts. (You may implement your own autostart -%% server!). -%% An interpret process may run for as long as necessary. Hence the function called -%% within the trace case file can contain wait functions, waiting for a certain -%% system state to occure before continuing. -%% Note that this process also mixes global and local bindings. GlobalBindings -%% is a binding() structure, where LocalBindings is a list of {Var,Value}. -%% Further it is possible to let FileName be a {inviso,Func,Args} tuple instead. -%% ----------------------------------------------------------------------------- - -%% Init function for an interpreter process instance. -cmd_file_interpreter_init(FileNames,GlobalBindings,Translations,Dbg) -> - interpret_cmd_files(FileNames,GlobalBindings,Translations,Dbg). - -interpret_cmd_files([{FileName,LocalBindings}|Rest],GlobalBindings,Translations,Dbg) -> - Bindings=join_local_and_global_vars(LocalBindings,GlobalBindings), - interpret_cmd_files_1(FileName,Bindings,Translations,Dbg), - interpret_cmd_files(Rest,GlobalBindings,Translations,Dbg); -interpret_cmd_files([],_,_,_) -> % Done, return nothing significant! - true; -interpret_cmd_files(FileName,GlobalBindings,Translations,Dbg) -> - interpret_cmd_files_1(FileName,GlobalBindings,Translations,Dbg). -% interpret_cmd_files(Rest,GlobalBindings,Translations,Dbg). - -%% This is "inline" inviso calls. -interpret_cmd_files_1({inviso,F,Args},Bindings,Translations,Dbg) -> - {ok,Tokens1,_}=erl_scan:string("inviso:"++atom_to_list(F)++"("), - Tokens2=tokenize_args(Args), - {ok,Tokens3,_}=erl_scan:string(")."), - case erl_parse:parse_exprs(Tokens1++Tokens2++Tokens3) of - {ok,Exprs} -> - interpret_cmd_files_3(Bindings,Exprs,Translations,Dbg); - {error,_Reason} -> - error - end; -interpret_cmd_files_1({Mod,Func,Args},_Bindings,_Translations,_Dbg) -> - catch apply(Mod,Func,Args); -%% This is the case when it actually is a trace case file. -interpret_cmd_files_1(FileName,Bindings,Translations,Dbg) -> - case file:open(FileName,[read]) of - {ok,FD} -> - interpret_cmd_files_2(FD,Bindings,io:parse_erl_exprs(FD,""),Translations,Dbg), - file:close(FD); - {error,Reason} -> % Something wrong with the file. - inviso_rt_lib:debug(Dbg,interpret_cmd_files,[FileName,{error,Reason}]) - end. - -%% Help function which handles Exprs returned from io:parse_erl_exprs and -%% tries to eval them. It is the side-effects we are interested in, like -%% setting flags and patterns. Note that we will get a failure should there -%% be a variable conflict. -%% Also note that there is logic to translate control component API calls to -%% corresponding runtime component calls. -%% Returns nothing significant. -interpret_cmd_files_2(FD,Bindings,{ok,Exprs,_},Translations,Dbg) -> - {next,NewBindings}=interpret_cmd_files_3(Bindings,Exprs,Translations,Dbg), - interpret_cmd_files_2(FD,NewBindings,io:parse_erl_exprs(FD,""),Translations,Dbg); -interpret_cmd_files_2(FD,Bindings,{error,ErrorInfo,Line},Translations,Dbg) -> - inviso_rt_lib:debug(Dbg,parse_erl_exprs,[ErrorInfo,Line]), - interpret_cmd_files_2(FD,Bindings,io:parse_erl_exprs(FD,""),Translations,Dbg); -interpret_cmd_files_2(_,_,{eof,_},_,_) -> % End of file. - true. - -interpret_cmd_files_3(Bindings,Exprs,Translations,Dbg) -> - case catch inviso_rt_lib:transform(Exprs,Translations) of - NewExprs when is_list(NewExprs) -> % We may have translated the API. - case catch erl_eval:exprs(NewExprs,Bindings) of - {'EXIT',Reason} -> - inviso_rt_lib:debug(Dbg,exprs,[Exprs,Bindings,{'EXIT',Reason}]), - {next,Bindings}; - {value,_Val,NewBindings} -> % Only interested in the side effects! - {next,NewBindings} - end; - {'EXIT',Reason} -> - inviso_rt_lib:debug(Dbg,translate2runtime_funcs,[Exprs,Reason]), - {next,Bindings} - end. - -%% Help function adding variables to a bindings structure. If the variable already -%% is assigned in the structure, it will be overridden. Returns a new -%% bindings structure. -join_local_and_global_vars([{Var,Val}|Rest],Bindings) when is_atom(Var) -> - join_local_and_global_vars(Rest,erl_eval:add_binding(Var,Val,Bindings)); -join_local_and_global_vars([_|Rest],Bindings) -> - join_local_and_global_vars(Rest,Bindings); -join_local_and_global_vars([],Bindings) -> - Bindings. - -%% Help function returning a string of tokens, including "," separation -%% between the arguments. -tokenize_args(Args=[Arg|Rest]) when length(Args)>1 -> - AbsTerm=erl_parse:abstract(Arg), - Tokens=erl_parse:tokens(AbsTerm), - {ok,Token,_}=erl_scan:string(","), - Tokens++Token++tokenize_args(Rest); -tokenize_args([Arg]) -> - AbsTerm=erl_parse:abstract(Arg), - erl_parse:tokens(AbsTerm); -tokenize_args([]) -> - "". -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% Help functions working on the options given as argument to init during spawn. -%% ----------------------------------------------------------------------------- - -get_tracerdata_opts(ArgsFromConfig) -> - case lists:keysearch(tracerdata,1,ArgsFromConfig) of - {value,{_,{mfa,{M,F,CompleteTDGargs}}}} -> % Dynamic tracerdata. - case catch apply(M,F,CompleteTDGargs) of - {'EXIT',_Reason} -> - false; - TracerData -> - {ok,TracerData} - end; - {value,{_,TracerData}} -> % Interpret this as static tracerdata. - {ok,TracerData}; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -get_cmdfiles_opts(ArgsFromConfig) -> - case lists:keysearch(cmdfiles,1,ArgsFromConfig) of - {value,{_,CmdFiles}} -> - {ok,CmdFiles}; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -get_initialbindings_opts(ArgsFromConfig) -> - case lists:keysearch(bindings,1,ArgsFromConfig) of - {value,{_,Bindings}} -> - Bindings; - false -> % Then we use empty bindings. - erl_eval:new_bindings() - end. -%% ----------------------------------------------------------------------------- - -get_translations_opts(ArgsFromConfig) -> - case lists:keysearch(translations,1,ArgsFromConfig) of - {value,{_,Translations}} -> - Translations; - false -> % This becomes nearly point less. - [] - end. -%% ----------------------------------------------------------------------------- - -get_dbg_opts(ArgsFromConfig) -> - case lists:keysearch(debug,1,ArgsFromConfig) of - {value,{_,DbgLevel}} -> - DbgLevel; - false -> - off - end. -%% ----------------------------------------------------------------------------- - -%% EOF - - - diff --git a/lib/runtime_tools/src/inviso_rt.erl b/lib/runtime_tools/src/inviso_rt.erl deleted file mode 100644 index b162f5b045..0000000000 --- a/lib/runtime_tools/src/inviso_rt.erl +++ /dev/null @@ -1,2885 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Description: -%% The runtime component of the trace tool Inviso. -%% -%% Authors: -%% Ann-Marie L�f, [email protected] -%% Lennart �hman, [email protected] -%% ----------------------------------------------------------------------------- - --module(inviso_rt). - - -%% ----------------------------------------------------------------------------- -%% interface for supervisor -%% ----------------------------------------------------------------------------- --export([start_link_man/3,start_link_auto/1]). - -%% API for controll component. --export([start/4,stop/1, - init_tracing/2,stop_tracing_parallel/1, - try_to_adopt/3,confirm_connection/2,get_node_info/1, - suspend/2,call_suspend/2,cancel_suspension/1,change_options/2, - clear/2,clear_all_tp/1, - flush/1, - trace_patterns_parallel/3, - trace_flags_parallel/3,trace_flags_parallel/2,trace_flags_parallel/1, - meta_tracer_call_parallel/2, - get_status/1,get_tracerdata/1,list_logs/1,list_logs/2,fetch_log/2,fetch_log/3, - delete_log/1,delete_log/2, - state/1]). -%% ----------------------------------------------------------------------------- - -%% API mostly for autostart scripts, instead of corresponding control component -%% apis not available doing local function calls. --export([init_tracing/1,tp/4,tp/5,tp/1,tpg/4,tpg/5,tpg/1, - tpl/4,tpl/5,tpl/1, - ctp/1,ctp/3,ctpg/1,ctpg/3,ctpl/1,ctpl/3, - init_tpm/4,init_tpm/7, - tpm/4,tpm/5,tpm/8,tpm_tracer/4,tpm_tracer/5,tpm_tracer/8, - tpm_ms/5,tpm_ms_tracer/5, - ctpm_ms/4, - local_register/0,global_register/0, - ctpm/3,remove_local_register/0,remove_global_register/0, - tf/2,tf/1,ctf/2,ctf/1]). -%% ----------------------------------------------------------------------------- - -%% Internal exports. --export([init/4,auto_init/2,fetch_init/4]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Constants. -%% ----------------------------------------------------------------------------- - --define(DEFAULT_OVERLOAD_FUNC,default_overload_func). --define(NO_LOADCHECK,no_loadcheck). - --define(RT_SUP,runtime_tools_sup). % Refers to the registered name. --define(CTRL,inviso_c). % Refers to the registered name. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Record definition. -%% ----------------------------------------------------------------------------- - -%% #rt -%% All record fields must be bound to listed values when leaving init or -%% auto_init. -%% dependency: Timeout accepting being without control component. -%% overload : Controlls which module to call, if any, when time for a check. -%% timer_ref: Used when timing delayed shutdown due to lost control component. --record(rt,{state = new, % new | idle | tracing - status = running, % running | {suspended, Reason} - next_loadcheck = now(), % now | "No Loadcheck" - parent, % pid() - tracerdata, % undefined|{fun(),term()}|{file,Param}|{ip,Param} - tracer_port, % port() | undefined - handler, % {fun(), term()} | undefined - auto_starter, % pid() | undefined; proc starting interpreters. - meta_tracer, % undefined | pid() - fetchers=[], % [pid(),...] processes transfering logfiles. -% spies = [], - dependency={infinity,node()}, % {TOut,Node} | TOut; TOut=int()|infinity - overload=no_loadcheck, % ?NO_LOADCHECK|{LoadMF,Interval,InitMFA,RemoveMFA} - overload_data=void, % Datastructure given to LoadMF and RemoveMFA. - timer_ref, % undefined | reference() - ctrl, % undefined | pid() - ctrl_ref, % undefined | reference() - vsn, % list() - tag % term() - }). -%% ----------------------------------------------------------------------------- - - -%% ============================================================================== -%% Start API -%% ============================================================================== - -%% Note that the runtime component may be started in many different ways. -%% It can be autostarted by the runtime_tools_sup during initial start-up of the -%% system. It is actually most likely that it will be started that way. However -%% if there are no autostart trace-cases to run, the inviso_rt runtime component -%% will terminate. It will then however remain as a child of the runtime_tools_sup -%% supervisor. This means that if the runtime component is started again, manually, -%% by the control component, some actions must be taken. -%% For instance is it very likely that the child already exists. But since it -%% must be started with different arguments when started manually, the child-spec -%% must be changed. -%% -%% The runtime component is not a proper gen_server, to allow full control of -%% what happens. It however mimcs gen_server behaviour to be managed by the -%% runtime_tools_sup supervisor. - - -%% start_link_auto(AutoModArgs)={ok,Pid} -%% -%% This function is entered into the child-spec when planning on doing autostart -%% of the runtime component. The autostart is controlled by the so called -%% inviso_autostart_mod. It is an application environment parameter of the -%% runtime_tools application. If it exists, it shall point out a module name. -%% If it does not exist, the default 'inviso_autostart' module will be tried. -%% Note that these start_link functions do not implement proper otp-behaviour. -%% For instance they return {ok,Pid} immediately making the init-phase of the -%% runtime component process empty. -%% -%% The inviso_autostart_mod shall export one function: -%% autostart(AutoModArgs) -> {MFA,Options,Tag}, where -%% AutoModArgs=term(), comes from the application start parameters in the -%% runtime_tools application resource file. -%% MFA={Mod,Func,Args} | term(). -%% If it is MFA it will cause a trace initiator process to start spawning -%% on spawn_link(Mod,Func,Args). The trace initiator may for instance -%% initiate the wanted tracing. -start_link_auto(AutoModArgs) -> - {ok,spawn_link(?MODULE,auto_init,[AutoModArgs,self()])}. -%% ------------------------------------------------------------------------------ - -%% This function is entered into the child-specification of the runtime_tools_sup -%% if the runtime component shall be started manually via the control component. -start_link_man(Ctrl,Options,Tag) -> - {ok,spawn_link(?MODULE,init,[Ctrl,Options,Tag,self()])}. -%% ------------------------------------------------------------------------------ - -%% start(Node,Options,Tag,Condition)=tbd -%% Node=The node where the runtime component shall be started. -%% Options=[Opt]; List of options to the runtime component. -%% Opt={dependency,Val}|{dependency,{Val,Node}} -%% Val=int()|infinity -%% If the runtime component may run on its own or not. Val=0 means a runtime -%% component which will terminate immediately without its control component. -%% Note that if the runtime component is started manually, the Node part -%% is never used. The runtime is supposed to be dependent of the Ctrl mentioned -%% in the start_link_man parameters. -%% Opt={overload,OverLoad} | overload -%% The latter means no loadcheck. Necessary if changing the options. -%% Overload=Iterval (int() in milliseconds) | -%% {LoadMF,Interval}|{LoadMF,Interval,InitMFA,RemoveMFA} -%% LoadMF={Mod,Func}|function() -%% InitMFA,RemoveMFA={Mod,Func,ArgList} where -%% apply(InitM,InitF,InitArgs) -> {ok,DataStruct}|'void'. -%% apply(RemoveM,RemoveF,[DataStruct|Args]) -> don't care -%% LoadMF is called each time loadcheck is performed. -%% Mod:Func(DataStruct)->ok|{suspend,Reason} -%% If just Interval is used, it means using a default overload check. -%% Tag=term(), used to identify an incarnation of a runtime component so that -%% a control component reconnecting will know if it was its own incarnation -%% still alive, or some elses. -%% Condition='if_ref'|term(). Controls if we want to adopt the runtime component. -%% If 'if_ref' is stated it means that we only want to adopt a runtime component -%% with the suggested Tag. -%% -%% This is the API used by the control component when tries to start a runtime -%% component. Note that it will try to adopt an already running, if possible. -%% Adoptions are only possible if the runtime component at hand is running -%% without control component. -start(Node, Options, Tag, Condition) when Node == node() -> - ChildSpec = {?MODULE, {?MODULE, start_link_man, [self(), Options, Tag]}, - temporary, 5000, worker, [?MODULE]}, - case catch supervisor:start_child(?RT_SUP, ChildSpec) of - {ok, Pid} when is_pid(Pid) -> - {node_info, _Node, Pid, VSN, State, Status, _Tag} = - get_node_info(Pid), - {node_info, Node, Pid, VSN, State, Status, new}; - {error, already_present} -> - supervisor:delete_child(?RT_SUP, ?MODULE), - start(Node, Options, Tag, Condition); - {error, {already_started, Pid}} -> - try_to_adopt(Pid, Tag, Condition); - {error,Reason} -> - {error,Reason}; - {'EXIT',Reason} -> - {error,Reason} - end; -start(Node, Options, Tag, Condition) -> - case rt_version(Node) of - {error,Error} -> - {error,Error}; - _VSN -> - ChildSpec = {?MODULE, {?MODULE, start_link_man, - [self(), Options, Tag]}, - temporary, 5000, worker, [?MODULE]}, - case catch rpc:call(Node, supervisor, start_child, - [?RT_SUP, ChildSpec]) of - {ok, Pid} when is_pid(Pid) -> - {node_info, _Node, Pid, - VSN, State, Status, _Tag} = get_node_info(Pid), - {node_info, Node, Pid, VSN, State, Status, new}; - {error, already_present} -> - rpc:call(Node, supervisor, delete_child, - [?RT_SUP, ?MODULE]), - start(Node, Options, Tag, Condition); - {error, {already_started, Pid}} -> - try_to_adopt(Pid, Tag, Condition); - {error,Reason} -> % Could not start child. - {error,Reason}; - {badrpc,nodedown} -> - {error,nodedown}; - {badrpc,Reason} -> - {error,{badrpc,Reason}}; - {'EXIT',Reason} -> - {error,Reason} - end - end. - -rt_version(Node) -> - case catch rpc:call(Node,application,loaded_applications,[]) of - List when is_list(List) -> - case lists:keysearch(runtime_tools,1,List) of - {value,{_,_,VSN}} -> - VSN; - false -> - {error,not_loaded} - end; - {badrpc,nodedown} -> - {error,nodedown}; - {'EXIT',Reason} -> - {error,Reason} - end. -%% ------------------------------------------------------------------------------ - -%% stop(Node)=ok|{error,Reason} -%% Stops the runtim component on node Node. Note that this is mearly calling the -%% supervisor API to shutdown the inviso_rt child belonging to the runtime_tools_sup. -stop(Node) when Node==node() -> - supervisor:terminate_child(?RT_SUP,?MODULE), - supervisor:delete_child(?RT_SUP,?MODULE), - ok; -stop(Node) -> - case catch rpc:call(Node,supervisor,terminate_child,[?RT_SUP,?MODULE]) of - ok -> - stop_delete_child(Node); - {error,_} -> % No child running. - stop_delete_child(Node); % Make sure we remove it also. - {badrpc,Reason} -> - {error,{badrpc,Reason}}; - {'EXIT',Reason} -> - {error,Reason} - end. - -stop_delete_child(Node) -> - case catch rpc:call(Node,supervisor,delete_child,[?RT_SUP,?MODULE]) of - ok -> - ok; - {error,_} -> % No child running. - ok; - {badrpc,Reason} -> - {error,{badrpc,Reason}}; - {'EXIT',Reason} -> - {error,Reason} - end. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% API for the control component. -%% ============================================================================== - -%% init_tracing(TracerData) -> -%% TracerData = LogTD | [{trace,LogTD},{ti,TiTD}] -%% LogTD = {HandlerFun, Data} | collector | -%% {relayer, pid()} | {ip, IPPortParameters} | -%% {file, FilePortParameters} -%% TiTD = {file,FileName} | {file,FileName,{InitPublLD,RemovePublLD,CleanPublLD}} -%% | {relay,Node} | {relay,Node,{InitPublLD,RemovePublLD,CleanPublLD}} -%% HandlerFun=fun(TraceMsg,Data)->NewData -%% IPPortParameters = Portno | {Portno, Qsiz} -%% Qsiz = -%% FilePortParameters = {Filename, wrap, Tail, {time, WrapTime}, WrapCnt} | -%% {FileName, wrap, Tail, WrapSize, WrapCnt} | -%% {FileName, wrap, Tail, WrapSize} | -%% {FileName, wrap, Tail} | FileName -%% Defines a tracer: -%% {HandlerFun, Data} - will be used as handler inside the runtime component for -%% every incomming trace message. -%% relayer - the runtime component will relay all comming trace messages to -%% the runtime component Pid. -%% collector - the runtime component is used as tracer or collector of relayed -%% trace messages using the default handler writing them to io. -%% ip | file - will start a tracer port using PortParameters -init_tracing(Pid,TracerData) -> - call(Pid,{init_tracing,TracerData}). -%% ------------------------------------------------------------------------------ - -%% stop_tracing(RTpids)=[{Node,NodeResult},...] -%% RTpids=[RTinfo,...] -%% RTinfo={RTpid,Node} | {{error,Reason},Node} -%% NodeResult={ok,State} | {error,Reason} -%% Sends a request to stop tracing to all nodes in RTpids, in parallel. Stop -%% tracing means that all trace flags are removed and the nodes go to idle -%% state. -stop_tracing_parallel(RTpids) -> - call_parallel(lists:map(fun({Pid,Node})->{Pid,Node,stop_tracing}; - (Error)->Error - end, - RTpids)). -%% ------------------------------------------------------------------------------ - -%% try_to_adopt(Pid,NewTag,Condition)= -%% {node_info,node(),self(),VSN,State,Status,{tag,PreviousTag}}|{error,Reason} -%% NewTag=term(), the identification tag we want the runtime component to use -%% from now on if adoption was successful. -%% Condition='if_ref', only adopt if current tag is NewTag. -%% PreviousTag= the tag the runtime component had before it accepted the -%% adoption. -%% This function shall only be used by a control component wishing to adopt this -%% runtime component. -try_to_adopt(Pid, Tag, Condition) -> - call(Pid,{try_to_adopt,Tag,Condition}). -%% ------------------------------------------------------------------------------ - -%% confirm_connection(Pid,Tag)= {node_info,node(),self(),VSN,State,Status,Tag}| -%% {error,refused}. -%% Must only be used by a control component having been contacted by the runtime -%% component Pid. It confirms to the runtime component that the control component -%% has accepted the connect request. -confirm_connection(Pid,Tag) -> - call(Pid,{confirm_connection,Tag}). -%% ------------------------------------------------------------------------------ - -%% get_node_info(Pid)={node_info,Node,Pid,VSN,State,Status,Tag}. -get_node_info(Pid) -> - call(Pid,get_node_info). -%% ------------------------------------------------------------------------------ - -%% suspend(NodeOrPid,Reason)=ok -%% call_suspend(NodeOrPid,Reason)=ok -%% Makes the runtime component and all of its helpers suspend. suspend/2 is -%% assynchronous. -suspend(NodeOrPid,Reason) -> - cast(NodeOrPid,{suspend,Reason}). - -call_suspend(NodeOrPid,Reason) -> - call(NodeOrPid,{suspend,Reason}). -%% ------------------------------------------------------------------------------ - -%% cancel_suspension(Pid)=ok -%% Function moving the runtime component to status running. Regardless of its -%% current status. -cancel_suspension(Pid) -> - call(Pid,cancel_suspension). -%% ------------------------------------------------------------------------------ - -%% change_options(Pid,Options)=ok -%% Options=list(); see the start_link_XXX functions. -%% Changes options according to Options list. -%% Changing the control component we shall be depending on has no effect. The -%% dependency value in self can however be changed, and takes effect immediately. -change_options(Pid,Options) -> - call(Pid,{change_options,Options}). -%% ------------------------------------------------------------------------------ - -%% clear_all_tp(Pid)=ok -%% Function removing all, both local and global trace-patterns from the node. -clear_all_tp(Pid) -> - call(Pid,clear_all_tp). -%% ------------------------------------------------------------------------------ - -%% clear(Pid,Options)={ok,{new,Status}} -%% Options=[Opt,...] -%% Opt=keep_trace_patterns | keep_log_files -%% Resets the runtime component to state 'new' by stopping all ongoing tracing, -%% closing and removing all associated logfiles. The Options can be used to -%% prevent the runtime component from being totally erased. -clear(Pid,Options) -> - call(Pid,{clear,Options}). -%% ------------------------------------------------------------------------------ - -%% flush(Pid)=ok | {error,Reason} -%% Sends the flush command to the trace-port, if we are using a trace-port and -%% are tracing. -flush(Pid) -> - call(Pid,flush). -%% ------------------------------------------------------------------------------ - -%% trace_patterns_parallel(RTpids,Args,Flags)=[{Node,Answer},...] -%% RTpids=[{RTpid,Node},...] or [{Error,Node},...] -%% Args=[Arg,...] -%% Arg={Mod,Func,Arity,MS}|{Mod,Func,Arity,MS,Opts} -%% Mod=atom()|reg_exp()|{Dir,reg_exp()} -%% Dir=reg_exp() -%% Answer=[Answer,...] -%% Answer=int()|{error,Reason} -%% API function for the control component sending trace-patterns to a list of -%% runtime components. Returns a [{Node,Answer},...] list in the same order. -trace_patterns_parallel(RTpids,Args,Flags) -> % Same args and flags for all. - call_parallel(lists:map(fun({Pid,Node})when is_pid(Pid)->{Pid,Node,{tp,Args,Flags}}; - (Error)-> Error - end, - RTpids)). -%% ------------------------------------------------------------------------------ - -%% trace_flags_parallel(RTpids,Args,How)= -%% trace_flags_parallel(RTpidsArgs,How)= -%% trace_flags_parallel(RTpidsArgsHow)=[{Node,Reply},...] -%% RTpids=[RTpidEntry,...] -%% RTpidEntry={RTpid,Node}|{Error,Node} -%% Error=term(), any term you wish to have as reply in Answer assoc. to Node. -%% Args=[{Process,Flags},...] -%% Process=pid()|registeredname()|'all'|'new'|'existing' -%% Flags=List of the allowed process trace flags. -%% RTpidsArgs=[RTpidArgEntry,...] -%% RTpidArgEntry={RTpid,Node,Args}|{Error,Node} -%% RTpidsArgsHow=[RTpidArgsHowEntry,...] -%% RTpidArgsHowEntry={RTpid,Node,Args,How}|{Error,Node} -%% How=true|false -%% Reply={ok,Answers} -%% Answers=[Answer,...], one for each Args and in the same order. -%% Answer=int()|{error,Reason} -%% API function used by the control component to send flags to a list of runtime -%% components. Returns a list of [{Node,Answer},... ] in the same order. -trace_flags_parallel(RTpids,Args,How) -> % Same args for every node! - call_parallel(lists:map(fun({Pid,Node})when is_pid(Pid)->{Pid,Node,{tf,Args,How}}; - (Error)-> Error - end, - RTpids)). - -trace_flags_parallel(RTpidArgs,How) -> % Different args but same how. - call_parallel(lists:map(fun({Pid,Node,Args})when is_pid(Pid)-> - {Pid,Node,{tf,Args,How}}; - (Error)-> - Error - end, - RTpidArgs)). - -trace_flags_parallel(RTpidArgsHow) -> % Both different args and hows. - call_parallel(lists:map(fun({Pid,Node,Args,How})when is_pid(Pid)-> - {Pid,Node,{tf,Args,How}}; - (Error)-> - Error - end, - RTpidArgsHow)). -%% ------------------------------------------------------------------------------ - -%% meta_pattern(RTpids,Args)=[{Node,Answer},...] -%% RTpids=[{RTpid,Node},...] or [{Error,Node},...] -%% Args={FunctionName,ArgList} -%% FunctionName=atom() -%% ArgList=list(), list of the arguments to FunctionName. -%% Answer=[Answer,...] -%% Answer=int()|{error,Reason} -%% Makes a call to the meta-tracer through its runtime component. Returns a list -%% a answers in the same order as RTpids. Note that if "someone" has discovered -%% that there is an error with a particular node, the error answer can be placed -%% in the RTpids list from the start. -meta_tracer_call_parallel(RTpids,Args) -> % Same args for all nodes. - call_parallel(lists:map(fun({Pid,Node})when is_pid(Pid)-> - {Pid,Node,{meta_tracer_call,Args}}; - (Error)-> - Error - end, - RTpids)). -%% ------------------------------------------------------------------------------ - -%% get_status(Pid)={ok,{State,Status}} -%% State=new|tracing|idle -%% Status=running|{suspended,Reason} -get_status(Pid) -> - call(Pid,get_status). -%% ------------------------------------------------------------------------------ - -%% get_tracerdata(Pid)={ok,TracerData} | {ok,no_tracerdata} | {error,Reason} -%% TracerData=see init_tracing -%% Fetches the current tracerdata from the runtime component. -get_tracerdata(Pid) -> - call(Pid,get_tracerdata). -%% ------------------------------------------------------------------------------ - -%% list_log(Pid)={ok,no_log}|{ok,LogCollection}|{error,Reason} -%% list_log(Pid,TracerData)= -%% LogCollection=[LogTypes,...] -%% LogTypes={trace_log,Dir,Files}|{ti_log,Dir,Files} -%% Dir=string() -%% Files=[FileNameWithoutDir,...] -%% Lists all files associated with the current tracerdata. Or finds out which -%% files there are stored in this node given a tracerdata. -list_logs(Pid) -> - call(Pid,list_logs). -list_logs(Pid,TD) -> - call(Pid,{list_logs,TD}). -%% ------------------------------------------------------------------------------ - -%% fetch_log(Pid,CollectPid)={ok,FetcherPid}|{complete,no_log}|{error,Reason} -%% fetch_log(Pid,CollectPid,Spec)= -%% CollectPid=pid(), the process which will be given the transfered logs. -%% Spec=TracerData|LogCollection -%% Transferes a number of files using ditributed Erlang to CollectPid. This -%% function is supposed to be used internally by a control component. It returns -%% when the transfer is initiated and does not mean it is done or successful. -fetch_log(Pid,CollectPid) -> - call(Pid,{fetch_log,CollectPid}). -fetch_log(Pid,CollectPid,Spec) -> - call(Pid,{fetch_log,CollectPid,Spec}). -%% ------------------------------------------------------------------------------ - -%% delete_log(Pid,TracerDataOrLogList)={ok,Results}|{error,Reason} -%% TracerDataOrLogList=[FileNameWithPath,...]|LogCollection|TracerData -%% Results=[LogType,...] -%% LogType={trace_log,FileSpecs}|{ti_log,FilesSpecs} -%% FilesSpecs=[FileSpec,...] -%% FileSpec={ok,FileName}|{error,{Posix,FileName}} -%% Filename=string(), the filename without dir-path. -delete_log(Pid) -> - call(Pid,delete_logs). -delete_log(Pid,TracerDataOrLogList) -> - call(Pid,{delete_logs,TracerDataOrLogList}). -%% ------------------------------------------------------------------------------ - -%% state(NodeOrPid)=LoopData -%% Returns the loopdata of the runtime component. Only meant for debugging. -state(NodeOrPid) -> - call(NodeOrPid,state). -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% API for local calls made from the same node. E.g autostart. -%% ============================================================================== - -%% init_tracing(TracerData)= -%% See init_tracing/2. -init_tracing(TracerData) -> - call_regname(?MODULE,{init_tracing,TracerData}). -%% ------------------------------------------------------------------------------ - - -%% Meaning that these function does most often not have to be called by a -%% control component because there are more efficient ones above. - -%% tp(Module,Function,Arity,MatchSpec) -> -%% tp(Module,Function,Arity,MatchSpec,Opts) -> -%% tp(PatternList) -> -%% Module = '_'|atom()|ModRegExp|{DirRegExp,ModRegExp} -%% Function == atom() | '_' -%% Arity = integer() | '_' -%% MatchSpec = true | false | [] | matchspec() see ERTS User's guide for a -%% description of match specifications. -%% Opts=list(); 'only_loaded' -%% PatternList = [Pattern], -%% Pattern = {Module,Function,Arity,MatchSpec,Opts}, -%% Set trace pattern (global). -tp(Module,Function,Arity,MatchSpec) -> - tp(Module,Function,Arity,MatchSpec,[]). -tp(Module,Function,Arity,MatchSpec,Opts) -> - call_regname(?MODULE,{tp,[{Module,Function,Arity,MatchSpec,Opts}],[global]}). -tp(PatternList) -> - call_regname(?MODULE,{tp,PatternList,[global]}). -%% ------------------------------------------------------------------------------ - -tpg(Mod,Func,Arity,MatchSpec) -> - tp(Mod,Func,Arity,MatchSpec). -tpg(Mod,Func,Arity,MatchSpec,Opts) -> - tp(Mod,Func,Arity,MatchSpec,Opts). -tpg(PatternList) -> - tp(PatternList). -%% ------------------------------------------------------------------------------ - -%% tpl(Module,Function,Arity,MatchSpec) -> -%% tpl(Module,Function,Arity,MatchSpec,Opts) -> -%% tpl(PatternList) -> -%% Module = Function == atom() | '_' | RegExpMod | {RegExpDir,RegExpMod} -%% Arity = integer() | '_' -%% MatchSpec = true | false | [] | matchspec() see ERTS User's guide for a -%% Opts=list(); 'only_loaded' -%% description of match specifications. -%% PatternList = [Pattern], -%% Pattern = {Module, Function, Arity, MatchSpec}, -%% Set trace pattern (local). -tpl(Module,Function,Arity,MatchSpec) -> - call_regname(?MODULE,{tp,[{Module,Function,Arity,MatchSpec,[]}],[local]}). -tpl(Module,Function,Arity,MatchSpec,Opts) -> - call_regname(?MODULE,{tp,[{Module,Function,Arity,MatchSpec,Opts}],[local]}). -tpl(PatternList) -> - call_regname(?MODULE,{tp,PatternList,[local]}). -%% ------------------------------------------------------------------------------ - -%% ctp(Module,Function,Arity) -> -%% ctp(PatternList)= -%% Module = atom()|'_'|RegExpMod|{RegExpDir,RegExpMod} -%% Function == atom() | '_' -%% Arity = integer() | '_' -%% PatternList=[{Mod,Func,Arity},...] -%% Clear trace pattern (global). -%% Note that it is possible to clear patterns using regexps. But we can for -%% natural reasons only clear patterns for loaded modules. Further more there -%% seems to be a fault in the emulator (<=R10B) crashing if we remove patterns -%% for deleted modules. Therefore we use the only_loaded option. -ctp(Module,Function,Arity) -> - call_regname(?MODULE,{tp,[{Module,Function,Arity,false,[only_loaded]}],[global]}). -ctp(PatternList) -> - call_regname(?MODULE, - {tp, - lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList), - [global]}). -%% ------------------------------------------------------------------------------ - -ctpg(Mod,Func,Arity) -> - ctp(Mod,Func,Arity). -ctpg(PatternList) -> - ctp(PatternList). -%% ------------------------------------------------------------------------------ - -%% ctpl(Module,Function,Arity) -> -%% Module = atom()|'_'|RegExpMod|{RegExpDir,RegExpMod} -%% Function == atom() | '_' -%% Arity = integer() | '_' -%% PatternList=[{Mod,Func,Arity},...] -%% Clear trace pattern (local). -ctpl(Module,Function,Arity) -> - call_regname(?MODULE,{tp,[{Module,Function,Arity,false,[only_loaded]}],[local]}). -ctpl(PatternList) -> - call_regname(?MODULE, - {tp, - lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList), - [local]}). -%% ------------------------------------------------------------------------------ - -init_tpm(Mod,Func,Arity,CallFunc) -> - call_regname(?MODULE,{meta_tracer_call,{init_tpm,[Mod,Func,Arity,CallFunc]}}). - -init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - call_regname(?MODULE, - {meta_tracer_call, - {init_tpm, - [Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}}). -%% ------------------------------------------------------------------------------ - -tpm(Mod,Func,Arity,MS) -> - call_regname(?MODULE,{meta_tracer_call,{tpm,[Mod,Func,Arity,MS]}}). -tpm(Mod,Func,Arity,MS,CallFunc) -> - call_regname(?MODULE,{meta_tracer_call,{tpm,[Mod,Func,Arity,MS,CallFunc]}}). -tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - call_regname(?MODULE, - {meta_tracer_call, - {tpm, - [Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}}). -%% ------------------------------------------------------------------------------ - -tpm_tracer(Mod,Func,Arity,MS) -> - call_regname(?MODULE,{meta_tracer_call,{tpm_tracer,[Mod,Func,Arity,MS]}}). -tpm_tracer(Mod,Func,Arity,MS,CallFunc) -> - call_regname(?MODULE,{meta_tracer_call,{tpm_tracer,[Mod,Func,Arity,MS,CallFunc]}}). -tpm_tracer(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - call_regname(?MODULE, - {meta_tracer_call, - {tpm_tracer, - [Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}}). -%% ------------------------------------------------------------------------------ - -tpm_ms(Mod,Func,Arity,MSname,MS) -> - call_regname(?MODULE,{meta_tracer_call,{tpm_ms,[Mod,Func,Arity,MSname,MS]}}). -%% ------------------------------------------------------------------------------ - -tpm_ms_tracer(Mod,Func,Arity,MSname,MS) -> - call_regname(?MODULE,{meta_tracer_call,{tpm_ms_tracer,[Mod,Func,Arity,MSname,MS]}}). -%% ------------------------------------------------------------------------------ - -ctpm_ms(Mod,Func,Arity,MSname) -> - call_regname(?MODULE,{meta_tracer_call,{ctpm_ms,[Mod,Func,Arity,MSname]}}). -%% ------------------------------------------------------------------------------ - -local_register() -> - call_regname(?MODULE,{meta_tracer_call,{local_register,[]}}). -%% ------------------------------------------------------------------------------ - -global_register() -> - call_regname(?MODULE,{meta_tracer_call,{global_register,[]}}). -%% ------------------------------------------------------------------------------ - -ctpm(Mod,Func,Arity) -> - call_regname(?MODULE,{meta_tracer_call,{ctpm,[Mod,Func,Arity]}}). -%% ------------------------------------------------------------------------------ - -remove_local_register() -> - call_regname(?MODULE,{meta_tracer_call,{remove_local_register,[]}}). -%% ------------------------------------------------------------------------------ - -remove_global_register() -> - call_regname(?MODULE,{meta_tracer_call,{remove_global_register,[]}}). -%% ------------------------------------------------------------------------------ - -%% tf(PidSpec, FlagList) -> -%% tf(TraceConfList) -> -%% TraceConfList = [{PidSpec, FlagList}], -%% FlagList = [Flags], -%% PidSpec = all | new | existing | pid() | registeredname() -%% Flags = all | send | 'receive' | procs | call | silent | return_to | -%% running | garbage_collection | timestamp | cpu_timestamp | arity | -%% set_on_spawn | set_on_first_spawn | set_on_link | set_on_first_link -%% Set trace flags. -tf(PidSpec, FlagList) -> - call_regname(?MODULE,{tf,[{PidSpec,FlagList}],true}). - -tf(TraceConfList) -> - call_regname(?MODULE,{tf,TraceConfList,true}). -%% ------------------------------------------------------------------------------ - -%% ctf(PidSpec, FlagList) -> -%% ctf(TraceConfList) -> -%% TraceConfList = [{PidSpec, FlagList}], -%% FlagList = [Flags], -%% PidSpec = all | new | existing | pid() | registeredname() -%% Flags = all | send | 'receive' | procs | call | silent | return_to | -%% running | garbage_collection | timestamp | cpu_timestamp | arity | -%% set_on_spawn | set_on_first_spawn | set_on_link | set_on_first_link -%% Clear trace flags. -ctf(PidSpec, FlagList) -> - call_regname(?MODULE,{tf,[{PidSpec,FlagList}],false}). - -ctf(TraceConfList) -> - call_regname(?MODULE,{tf_as,TraceConfList,false}). -%% ------------------------------------------------------------------------------ - - -%% ------------------------------------------------------------------------------ -%% Client side functions. -%% ------------------------------------------------------------------------------ - -%% Call function managing the client to server communication. This function may -%% be run by a client on a different node. -%% Note that we must use two different functions for calling a named process and -%% calling the runtime component at a specified node. -call(Pid,Request) when is_pid(Pid) -> - call_2(Pid,Request); -call(Node,Request) when Node==node() -> % To our node! - call_2(?MODULE,Request); -call(Node,Request) when is_atom(Node) -> - call_2({?MODULE,Node},Request); -call(To,_Request) -> - {error,{badarg,To}}. - -call_regname(Name,Request) when is_atom(Name) -> % To a registered name. - call_2(Name,Request). - -call_2(To,Request) -> - MRef=erlang:monitor(process,To), % Use a monitor to avoid waiting for ever. - Ref=make_ref(), - case catch To ! {Request,self(),Ref} of % Can be a remote pid. - {'EXIT',_} -> % If we use registered name. - erlang:demonitor(MRef), % Maybe not necessary!? - receive - {'DOWN',MRef,_Type,_Obj,_Info} -> - true - after - 0 -> - true - end, - {error,not_started}; - _ -> % At least no obvious error. - receive - {Msg,Ref} -> - erlang:demonitor(MRef), - Msg; - {'DOWN',MRef,_Type,_Obj,Info} -> % The runtime component disapeared. - {error,{no_response,Info}} - end - end. -%% ----------------------------------------------------------------------------- - -%% Multicall function taking a list of [{Pid,Node,Request},...] and sends -%% a request to every Pid. This function then also allows you to send multiple -%% requests to the same Pid since it will sit and wait for all replies. -%% Note that RTspec may also be an [{{error,Reason},Node},...]. That tuple will -%% then be used as reply in the reply list. -%% Returns [{Node,Reply},...] for every element in RTspec, in the same order. -call_parallel(RTspec) -> - Ref=make_ref(), - {Nr,Pending}=call_parallel_2(RTspec,Ref,0,[]), - Replies=call_parallel_3(Ref,Pending,Nr,[],[]), - call_parallel_build_reply(RTspec,1,Replies). - -call_parallel_2([{Pid,Node,Request}|Rest],Ref,Nr,Pending) when is_pid(Pid) -> - Pid ! {Request,self(),{Ref,Nr+1}}, - MRef=erlang:monitor(process,Pid), % So we won't wait for ever for it. - call_parallel_2(Rest,Ref,Nr+1,[{Nr+1,Node,MRef}|Pending]); -call_parallel_2([{{error,_Reason},_Node}|Rest],Ref,Nr,Pending) -> - call_parallel_2(Rest,Ref,Nr,Pending); % Just skip it. This is no process. -call_parallel_2([_Faulty|Rest],Ref,Nr,Pending) -> % Should not happend. - call_parallel_2(Rest,Ref,Nr,Pending); % But we choose to skip it instead of crash. -call_parallel_2([],_,Nr,Pending) -> - {Nr,Pending}. - -%% Help function collecting reply-messages sent from the runtime components. We -%% count down until we got a reply for every pending request. Or if we get a DOWN -%% message indicating that the runtime component is no longer present. Note that -%% we can by accident read away DOWN messages not belonging to this procedure. -%% They are collected to be reissued after we are done. -call_parallel_3(_Ref,_Pending,0,Replies,DownMsgs) -> % All expected received. - lists:foreach(fun({MRef,Pid,Info}) -> self() ! {'DOWN',MRef,process,Pid,Info} end, - DownMsgs), % Reissue the down messages! - Replies; -call_parallel_3(Ref,Pending,NrOfPending,Replies,DownMsgs) -> - receive - {Reply,{Ref,Nr}} -> - case lists:keysearch(Nr,1,Pending) of - {value,{_Nr,Node,MRef}} -> - erlang:demonitor(MRef), - call_parallel_3(Ref,Pending,NrOfPending-1, - [{Nr,Node,Reply}|Replies],DownMsgs); - false -> % Really strange! - call_parallel_3(Ref,Pending,NrOfPending,Replies,DownMsgs) - end; - {'DOWN',MRef,process,Pid,Info} -> % Probably process we monitor terminated. - case lists:keysearch(MRef,3,Pending) of - {value,{Nr,Node,_}} -> % Yes it was one of our processes. - call_parallel_3(Ref,Pending,NrOfPending-1, - [{Nr,Node,{error,no_reponse}}|Replies],DownMsgs); - false -> % We picked up a DOWN msg by misstake. - call_parallel_3(Ref,Pending,NrOfPending,Replies, - [{MRef,Pid,Info}|DownMsgs]) - end - end. - -%% Help function which build up the [{Node,Reply},...] list in the same order as RTspec. -call_parallel_build_reply([],_,_) -> - []; -call_parallel_build_reply([{Pid,Node,_Request}|Rest],Nr,Replies) when is_pid(Pid) -> - {value,{_Nr,_Node,Reply}}=lists:keysearch(Nr,1,Replies), - [{Node,Reply}|call_parallel_build_reply(Rest,Nr+1,Replies)]; -call_parallel_build_reply([{{error,Reason},Node}|Rest],Nr,Replies) -> - [{Node,{error,Reason}}|call_parallel_build_reply(Rest,Nr,Replies)]; -call_parallel_build_reply([_Faulty|Rest],Nr,Replies) -> - call_parallel_build_reply(Rest,Nr,Replies). -%% ------------------------------------------------------------------------------ - -cast(Pid,Request) when is_pid(Pid) -> - cast2(Pid,Request); -cast(Node,Request) when Node==node() -> - catch cast2(?MODULE,Request), - ok; -cast(Node,Request) when is_atom(Node) -> - catch cast2({?MODULE,Node},Request), - ok; -cast(BadAddress,_Request) -> - {error,{badarg,BadAddress}}. - -cast2(To,Request) -> - To ! {Request,void,void}. % Mimics the call protocol. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% Implementation of the runtime component (server side). -%% ============================================================================== - -%% Since the runtime component is not implemented using gen_sever we are "free" -%% to use what ever functionnames we like. - -%% Initial function on which the runtime component is spawned on if started by -%% a controlcomponent. -init(Ctrl, Options, Tag, Parent) when is_list(Options) -> - %% started from controller - process_flag(trap_exit,true), - register(?MODULE,self()), % Will crash if rt is already running - do_clear_trace_patterns(), % Remove potential old patterns left. - LD1=read_option_list(Options, - #rt{state=new, - parent=Parent, - ctrl=Ctrl, - vsn=get_application_vsn(), - tag=Tag}), - OverloadData=initialize_overload(LD1), - CtrlRef=erlang:monitor(process,Ctrl), % Monitor our control component. - loop1(LD1#rt{ctrl_ref=CtrlRef,overload_data=OverloadData}). -%% ---------------------------------------------------------------------------- - -%% Initial function on which the runtime component is spawned on if started -%% by the runtime_tools supervisor. It is here it is determined if we shall -%% autostart. -auto_init(AutoModArgs,Parent) -> - %% autostart - process_flag(trap_exit, true), - register(?MODULE, self()), % Will crash if a rt is already running - AutoMod=get_autostart_module(), % Determine which module to use! - case catch AutoMod:autostart(AutoModArgs) of - {MFA,Options,Tag} -> - do_clear_trace_patterns(), % Remove previously left patterns. - LD1=read_option_list(Options,#rt{state=new, - parent=Parent, - vsn=get_application_vsn(), - tag=Tag}), - case auto_init_connect_control(LD1) of - {ok,LD2} -> % Either connected or running_alone. - OverloadData=initialize_overload(LD2), - case auto_init_check_mfa(MFA) of - {ok,{M,F,A}} -> % We shall start somekind of tracing! - P=spawn_link(M,F,A), % It lives its own life, only link! - loop1(LD2#rt{auto_starter=P,overload_data=OverloadData}); - false -> - loop1(LD2#rt{overload_data=OverloadData}) - end; - stop -> % Not allowed to run alone! - true % Simply terminate. - end; - _ -> % Non existent or faulty autostart mod! - true % Terminate normally. - end. - -auto_init_connect_control(LD1) -> - case auto_init_connect_find_pid(LD1#rt.dependency) of - Pid when is_pid(Pid) -> % There is a control component. - CtrlRef=erlang:monitor(process,Pid), - Pid ! {connect,node(),self(),LD1#rt.vsn,LD1#rt.tag}, - {ok,LD1#rt{ctrl_ref=CtrlRef,ctrl=Pid}}; - _ -> % There is no control component. - do_down_message(LD1) % Will return 'stop' or a LoopData. - end. - -%% Help function which finds the pid of the control component. -auto_init_connect_find_pid({_TimeOut,Node}) when Node==node() -> - whereis(?CTRL); -auto_init_connect_find_pid({_TimeOut,Node}) when is_atom(Node) -> - rpc:call(Node,erlang,whereis,[?CTRL]); -auto_init_connect_find_pid(_) -> % Node is not a proper node. - undefined. % Act as could not find control comp. - -%% Help function checking that the parameter is reasonable to be used as -%% spawn_link argument. -auto_init_check_mfa({M,F,A}) when is_atom(M),is_atom(F),is_list(A) -> - {ok,{M,F,A}}; -auto_init_check_mfa(_) -> - false. - -%% Help function to init_auto which finds out which module to call for -%% guidance on how to proceed. Returns an atom. -get_autostart_module() -> - case application:get_env(inviso_autostart_mod) of - {ok,Mod} when is_atom(Mod) -> - Mod; - _ -> - inviso_autostart % The default autostart module. - end. -%% ---------------------------------------------------------------------------- - - -%% This is the preloop function which performs loadcheck if necessary. Note -%% that it calculates the timeout used in the after in the real loop. There is -%% further no use doing overload checks if we are not tracing or already -%% suspended. There is yet one more situation, we do not want to perform -%% overload checks if the interval is set to infinity. This can be the case if -%% we are using an external source pushing overload information instead. -loop1(LD=#rt{overload=Overload}) -> - if - Overload/=?NO_LOADCHECK,element(2,Overload)/=infinity -> - Now=now(), - if - LD#rt.status==running, - LD#rt.state==tracing, - Now>LD#rt.next_loadcheck -> % Do loadcheck only then! - {NewLD,TimeOut}=do_check_overload(LD,{timeout,LD#rt.overload_data}), - loop(NewLD,TimeOut); - LD#rt.status==running,LD#rt.state==tracing -> - Timeout=calc_diff_to_now(Now,LD#rt.next_loadcheck), - loop(LD,Timeout); - true -> % Do not spend CPU on this! :-) - loop(LD,infinity) - end; - true -> % Either no check or infinity. - loop(LD,infinity) - end. - -loop(LoopData,Timeout) -> - receive - Msg when element(1,Msg)==trace_ts; - element(1,Msg)==trace; - element(1,Msg)==drop; - element(1,Msg)==seq_trace -> - case LoopData#rt.handler of - {HandlerFun,Data} -> - NewData=HandlerFun(Msg,Data), - loop1(LoopData#rt{handler={HandlerFun,NewData}}); - _ -> - loop1(LoopData) - end; - {{tp,Args,Flags},From,Ref} -> - if - LoopData#rt.status==running -> % Not when suspended. - Reply=do_set_trace_patterns(Args,Flags), - if - LoopData#rt.state==new -> % No longer new when tp set. - reply_and_loop({ok,Reply},From,Ref,LoopData#rt{state=idle}); - true -> - reply_and_loop({ok,Reply},From,Ref,LoopData) - end; - true -> % We are suspended! - reply_and_loop({error,suspended},From,Ref,LoopData) - end; - {{tf,Args,How},From,MRef} -> - Reply= - case How of - true -> - if - LoopData#rt.status==running -> - case {LoopData#rt.tracer_port,LoopData#rt.handler} of - {Port,_} when is_port(Port) -> - do_set_trace_flags(Port,Args,How); - {_,{Handler,_D}} when is_function(Handler) -> - do_set_trace_flags(self(),Args,How); - _ -> - {error,no_tracer} - end; - true -> % Can't turn *on* flags if suspended. - {error, suspended} - end; - false -> % No tracer needed when turning off. - do_set_trace_flags(void,Args,How) - end, - reply_and_loop(Reply,From,MRef,LoopData); - {{meta_tracer_call,Args},From,MRef} -> - if - LoopData#rt.status==running -> - case LoopData#rt.meta_tracer of - MPid when is_pid(MPid) -> - Reply=do_meta_pattern(MPid,Args), - reply_and_loop(Reply,From,MRef,LoopData); - _ -> - reply_and_loop({error,no_metatracer},From,MRef,LoopData) - end; - true -> - reply_and_loop({error,suspended},From,MRef,LoopData) - end; - {clear_all_tp,From,MRef} -> - do_clear_trace_patterns(), - reply_and_loop(ok,From,MRef,LoopData); - {{init_tracing,TracerData},From,MRef} -> - {NewLoopData,Reply}= - if - LoopData#rt.status==running -> - if - LoopData#rt.state==tracing -> - {LoopData,{error,already_initiated}}; - true -> % Otherwise, try to init-tracing! - case translate_td(TracerData) of - {ok,LogTD,MetaTD} -> - do_init_tracing(LoopData,TracerData,LogTD,MetaTD); - Error -> - {LoopData,Error} - end - end; - true -> % Can't init tracing if not running. - {LoopData,{error,suspended}} - end, - reply_and_loop(Reply,From,MRef,NewLoopData); - {stop_tracing,From,MRef} -> - case LoopData#rt.state of - tracing -> % Only case we need to do anything. - reply_and_loop({ok,idle},From,MRef,do_stop_tracing(LoopData)); - idle -> % Already idle! - reply_and_loop({ok,idle},From,MRef,LoopData); - new -> % Have actually never traced! - reply_and_loop({ok,new},From,MRef,LoopData) - end; - {{suspend,Reason},From,MRef} -> - if - LoopData#rt.status==running -> - NewLD=do_suspend(LoopData,Reason), - reply_and_loop(ok,From,MRef,NewLD); - true -> % No need suspend if not running! - reply_and_loop(ok,From,MRef,LoopData) - end; - {cancel_suspension,From,MRef} -> - NewLoopData=LoopData#rt{status=running,next_loadcheck=now()}, - send_event(state_change,NewLoopData), - reply_and_loop(ok,From,MRef,NewLoopData); - {{clear,Options},From,MRef} -> - NewLoopData=do_clear(LoopData,Options), - reply_and_loop({ok,{new,NewLoopData#rt.status}},From,MRef,NewLoopData); - {flush,From,MRef} -> - case LoopData#rt.state of - tracing -> % Can only flush if we are tracing. - if - is_port(LoopData#rt.tracer_port) -> - trace_port_control(LoopData#rt.tracer_port,flush), - reply_and_loop(ok,From,MRef,LoopData); - true -> % Not necessary but lets pretend. - reply_and_loop(ok,From,MRef,LoopData) - end; - State -> - reply_and_loop({error,{not_tracing,State}},From,MRef,LoopData) - end; - {list_logs,From,MRef} -> - TracerData=LoopData#rt.tracerdata, % Current tracerdata. - if - TracerData/=undefined -> % There is tracerdata! - reply_and_loop(do_list_logs(TracerData),From,MRef,LoopData); - true -> % Have no current tracerdata! - reply_and_loop({error,no_tracerdata},From,MRef,LoopData) - end; - {{list_logs,TracerData},From,MRef} -> - reply_and_loop(do_list_logs(TracerData),From,MRef,LoopData); - {{fetch_log,CollectPid},From,MRef} -> % Fetch according to current tracerdata. - TracerData=LoopData#rt.tracerdata, % Current tracerdata. - if - TracerData/=undefined -> % There is tracerdata! - {Reply,NewLD}=do_fetch_log(LoopData,CollectPid,TracerData), - reply_and_loop(Reply,From,MRef,NewLD); - true -> % No tracerdata! - reply_and_loop({error,no_tracerdata},From,MRef,LoopData) - end; - {{fetch_log,CollectPid,Spec},From,MRef} -> % Either list of files or tracerdata. - {Reply,NewLD}=do_fetch_log(LoopData,CollectPid,Spec), - reply_and_loop(Reply,From,MRef,NewLD); - {delete_logs,From,MRef} -> - if - LoopData#rt.state==tracing -> % Can't remove then! - reply_and_loop({error,tracing},From,MRef,LoopData); - true -> - TracerData=LoopData#rt.tracerdata, - reply_and_loop(do_delete_logs(TracerData),From,MRef,LoopData) - end; - {{delete_logs,TracerDataOrLogList},From,MRef} -> - if - LoopData#rt.state==tracing -> % Can't remove then! - reply_and_loop({error,tracing},From,MRef,LoopData); - true -> - reply_and_loop(do_delete_logs(TracerDataOrLogList),From,MRef,LoopData) - end; - {get_node_info,From,MRef} -> - Reply=collect_node_info(LoopData), - reply_and_loop(Reply,From,MRef,LoopData); - {{try_to_adopt,Tag,Condition},From,MRef} -> - if - LoopData#rt.ctrl_ref==undefined -> % We have no control component. - {Reply,NewLoopData}=do_try_to_adopt(Tag,Condition,LoopData,From), - reply_and_loop(Reply,From,MRef,NewLoopData); - true -> % We already have a control component. - reply_and_loop({error,refused},From,MRef,LoopData) - end; - {{confirm_connection,_Tag},From,MRef} -> - if - LoopData#rt.ctrl==From -> % It must be from this process! - Reply=collect_node_info(LoopData), - reply_and_loop(Reply,From,MRef,LoopData); - true -> % Strange, some one is joking? - reply_and_loop({error,refused},From,MRef,LoopData) - end; - {{change_options,Options},From,MRef} -> - case do_change_options(Options,LoopData) of - stop -> % Can't run alone with these options! - terminate_overload(LoopData), - From ! {ok,MRef}; % Don't care if From not a proper pid! - NewLoopData when is_record(NewLoopData,rt) -> - reply_and_loop(ok,From,MRef,NewLoopData) - end; - {get_status,From,MRef} -> - Reply={ok,{LoopData#rt.state,LoopData#rt.status}}, - reply_and_loop(Reply,From,MRef,LoopData); - {get_tracerdata,From,MRef} -> - case LoopData#rt.tracerdata of - undefined -> - reply_and_loop({ok,no_tracerdata},From,MRef,LoopData); - TracerData -> - reply_and_loop({ok,TracerData},From,MRef,LoopData) - end; - {state,From,MRef} -> % For debugging purposes. - reply_and_loop(LoopData,From,MRef,LoopData); - - {'DOWN',CtrlRef,process,_,_} when CtrlRef==LoopData#rt.ctrl_ref -> - case do_down_message(LoopData) of - stop -> % inviso_c gone and we must stop! - terminate_overload(LoopData), - exit(running_alone); - {ok,NewLoopData} -> - loop1(NewLoopData) - end; - {'EXIT',Pid,Reason} -> - case act_on_exit(Pid,Reason,LoopData) of - exit -> - terminate_overload(LoopData), - exit(Reason); - NewLoopData when is_record(NewLoopData,rt) -> - loop1(NewLoopData); - {NewLoopData,NewTimeOut} when is_record(NewLoopData,rt) -> - loop(NewLoopData,NewTimeOut) - end; - Other -> % Check if it concerns overload. - if - LoopData#rt.overload/=?NO_LOADCHECK, - LoopData#rt.status==running, - LoopData#rt.state==tracing -> - {NewLD,NewTimeOut}= - do_check_overload(LoopData, - {msg,{Other,LoopData#rt.overload_data}}), - loop(NewLD,NewTimeOut); - true -> - NewTimeOut=calc_diff_to_now(now(),LoopData#rt.next_loadcheck), - loop(LoopData,NewTimeOut) - end - after - Timeout -> - loop1(LoopData) - end. - -reply_and_loop(Reply,To,MRef,LoopData) when is_pid(To) -> - To ! {Reply,MRef}, - loop1(LoopData); -reply_and_loop(_,_,_,LoopData) -> % Used together with incoming casts. - loop1(LoopData). -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% File transfer process implementation. -%% ============================================================================= - -%% Files that are to to be transfered from the runtime component to the control -%% component are done so by reading them as binaries and sending them with -%% normal message passing (over distributed Erlang). -%% Reading the files are done in a process separate to the runtime component, -%% to both make the code more simple. But also to free up the runtime component. -%% -%% This help process must be capable of recognizing the fact that the runtime -%% component has been suspended, and then of course also discontinue any file -%% transfere. -fetch_init(Parent,Files,CollectPid,ChunkSize) -> - process_flag(trap_exit,true), % We must clean-up. - process_flag(priority,low), % Lets be careful. - case fetch_open_file(Files,CollectPid) of - {ok,FileName,FD,RestFiles} -> - MRef=erlang:monitor(process,CollectPid), - fetch_loop(Parent,RestFiles,CollectPid,ChunkSize,FileName,FD,MRef); - done -> - fetch_end(CollectPid); - error -> - fetch_incomplete(CollectPid) - end. - -fetch_loop(Parent,Files,CollectPid,ChunkSize,FName,FD,MRef) -> - receive - {suspend,Parent} -> % The runtime component is suspended. - file:close(FD), % We must clean-up. - fetch_incomplete(CollectPid); - {'DOWN',MRef,process,_,_} -> % The CollectPid terminated! - file:close(FD); % Close file and terminate. - {'EXIT',Parent,_Reason} -> % The runtime component terminated. - file:close(FD), - fetch_incomplete(CollectPid); - _ -> - fetch_loop(Parent,Files,CollectPid,ChunkSize,FName,FD,MRef) - after - 0 -> % If non of the above, get to work! - case file:read(FD,ChunkSize) of - {ok,Bin} -> - fetch_send_chunk(CollectPid,Bin), - case fetch_wait_for_chunk_ack(CollectPid,MRef) of - ok -> % Collector ready to receive next chunk. - fetch_loop(Parent,Files,CollectPid,ChunkSize,FName,FD,MRef); - cancel -> % Send no more files! - file:close(FD), % Close file, send incomplete, terminate! - fetch_incomplete(CollectPid); - 'DOWN' -> % Collector has terminate, stop! - file:close(FD) % Close file and terminate. - end; - eof -> % Ok, go on with the next file. - file:close(FD), - fetch_send_eof(CollectPid), - case fetch_open_file(Files,CollectPid) of - {ok,NewFName,NewFD,RestFiles} -> - fetch_loop(Parent,RestFiles,CollectPid, - ChunkSize,NewFName,NewFD,MRef); - done -> - fetch_end(CollectPid); - error -> - fetch_incomplete(CollectPid) - end; - {error,Reason} -> % Do not continue. - file:close(FD), - fetch_send_readerror(CollectPid,FName,Reason), - fetch_incomplete(CollectPid) - end - end. -%% ----------------------------------------------------------------------------- - -%% Help function which opens the next file to be transferred. It also communicates -%% the opening of the file to the collector process. -%% We know here that it will be a list of three-tuples. But there is no guarantee -%% that Dir or FileName are proper strings. -%% Returns {ok,FileName,FileDescriptor,RemainingFiles} or 'done'. -fetch_open_file([{FType,Dir,FileName}|RestFiles],CollectPid) -> - case catch file:open(filename:join(Dir,FileName),[read,raw,binary]) of - {ok,FD} -> - CollectPid ! {node(),open,{FType,FileName}}, - {ok,FileName,FD,RestFiles}; - {error,_Reason} -> - CollectPid ! {node(),open_failure,{FType,FileName}}, - error; - {'EXIT',_Reason} -> % Faulty Dir or FileName. - CollectPid ! {node(),open_failure,{FType,FileName}}, - error - end; -fetch_open_file([],_CollectPid) -> - done. -%% ----------------------------------------------------------------------------- - -%% A group of help functions sending information to the collector process. -%% Returns nothing significant. -fetch_send_chunk(CollectPid,Bin) -> - CollectPid ! {node(),payload,Bin,self()}. -%% ----------------------------------------------------------------------------- - -fetch_send_eof(CollectPid) -> - CollectPid ! {node(),end_of_file}. -%% ----------------------------------------------------------------------------- - -fetch_end(CollectPid) -> - CollectPid ! {node(),end_of_transmission}. -%% ----------------------------------------------------------------------------- - -fetch_send_readerror(CollectPid,FName,Reason) -> - CollectPid ! {node(),{error,{file_read,{Reason,FName}}}}. -%% ----------------------------------------------------------------------------- - -fetch_incomplete(CollectPid) -> - CollectPid ! {node(),incomplete}. -%% ----------------------------------------------------------------------------- - -%% Help function waiting for the collector to respond that it is ready to receive -%% the next chunk. This is in order to exercise flow control protecting the -%% collector to get swamped if the node where the collector runs is busy. -fetch_wait_for_chunk_ack(CollectPid,MRef) -> - receive - {CollectPid,chunk_ack} -> - ok; - {CollectPid,cancel_transmission} -> % Some problem at collector side. - cancel; - {'DOWN',MRef,process,_,_} -> % The collector terminated. - 'DOWN' - end. -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% First level do-functions, called from the main server loop on incomming -%% requests. -%% ============================================================================= - -%% Function performing the overload check. Returns {NewLoopData,TimeOut}. -%% Note that this function may also cause a suspend to be carried out if the -%% loadcheck turns out negative. -do_check_overload(LD,Data) -> - case do_check_overload_2(LD#rt.overload,Data) of - ignore -> % Load check not performed. - {LD,calc_diff_to_now(now(),LD#rt.next_loadcheck)}; - {ok,Interval} -> % No problem, continue. - NextLoadCheck=add_to_now(now(),Interval), - {LD#rt{next_loadcheck=NextLoadCheck},Interval}; - {suspend,Reason} -> % Emergency! suspend, suspend! - NewLD=do_suspend(LD,Reason), - {NewLD,infinity}; % No need to do load-checks now! - {new,NewData,Interval} -> % The overload was restarted or something. - NextLoadCheck=add_to_now(now(),Interval), - {LD#rt{overload_data=NewData,next_loadcheck=NextLoadCheck},Interval}; - error -> % Inhibit overload check then. - {LD#rt{overload=?NO_LOADCHECK},infinity} - end. - -%% Help function performing an overload check. Returns {ok,Interval}, -%% {suspend,Reason}, 'error' ir 'ignore'. -do_check_overload_2({{Mod,Func},Interval,_,_},Data) -> - do_check_overload_3(Interval,catch Mod:Func(Data)); -do_check_overload_2({Fun,Interval,_,_},Data) when is_function(Fun) -> - do_check_overload_3(Interval,catch Fun(Data)); -do_check_overload_2(_,_) -> % Bad loadcheck configuration. - error. % Stop using load checks then. - -do_check_overload_3(Interval,ok) -> - {ok,Interval}; -do_check_overload_3(Interval,{new,NewData}) -> - {new,NewData,Interval}; -do_check_overload_3(_Interval,{suspend,Reason}) -> - {suspend,Reason}; -do_check_overload_3(_Interval,ignore) -> % Loadcheck not triggered. - ignore; -do_check_overload_3(_Interval,_) -> % Failure or other return value. - error. % Stop doing loadchecks from now on. -%% ------------------------------------------------------------------------------ - -%% Function setting the trace-pattern according to Args and Flags. Note that -%% Args can contain regexps which must be expanded here. -%% Returns a list: [Result], where Result can be: int()|{error,Reason}. -%% Sometimes an error tuple will represent an entire pattern, sometimes the -%% pattern will expand to a number of error-tuples. -do_set_trace_patterns(Args,Flags) -> - Replies=do_set_trace_patterns_2(Args,Flags,[]), - lists:reverse(Replies). - -do_set_trace_patterns_2([{M,F,Arity,MS}|Rest],Flags,Replies) -> % Option-less. - do_set_trace_patterns_2([{M,F,Arity,MS,[]}|Rest],Flags,Replies); -do_set_trace_patterns_2(Mlist = [{M,F,Arity,MS,Opts}|Rest],Flags,Replies) when is_atom(M) -> - case length(Mlist) rem 10 of - 0 -> - timer:sleep(100); - _ -> - ok - end, - %% sleep 100 ms for every 10:th element in the list to let other - %% processes run since this is a potentially - %% heavy operation that might result in an unresponsive Erlang VM for - %% several seconds otherwise - case load_module_on_option(M,Opts) of - true -> % Already present, loaded or no option! - case catch erlang:trace_pattern({M,F,Arity},MS,Flags) of - No when is_integer(No) -> - do_set_trace_patterns_2(Rest,Flags,[No|Replies]); - {'EXIT',Reason} -> - do_set_trace_patterns_2(Rest, - Flags, - [{error,{bad_trace_args,[{M,F,Arity,MS},Reason]}}| - Replies]) - end; - false -> % Module not present, or not found! - do_set_trace_patterns_2(Rest,Flags,[0|Replies]) - end; -do_set_trace_patterns_2([{M,F,Arity,MS,Opts}|Rest],Flags,Replies) when is_list(M) -> - do_set_trace_patterns_2([{{void,M},F,Arity,MS,Opts}|Rest],Flags,Replies); -do_set_trace_patterns_2([{{Dir,M},F,Arity,MS,Opts}|Rest],Flags,Replies) - when is_list(Dir),is_list(M) -> - case check_pattern_parameters('_',F,Arity,MS) of % We don't want to repeat bad params. - true -> - case inviso_rt_lib:expand_regexp(Dir,M,Opts) of % Get a list of real modulnames. - Mods when is_list(Mods) -> - MoreReplies= - do_set_trace_patterns_2(lists:map(fun(Mod)-> - {Mod,F,Arity,MS,Opts} - end, - Mods), - Flags, - Replies), - do_set_trace_patterns_2(Rest,Flags,MoreReplies); - {error,Reason} -> - do_set_trace_patterns_2(Rest,Flags,[{error,Reason}|Replies]) - end; - false -> % Bad pattern parameters. - do_set_trace_patterns_2(Rest, - Flags, - [{error,{bad_trace_args,{M,F,Arity,MS}}}|Replies]) - end; -do_set_trace_patterns_2([Arg|Rest],Flags,Replies) -> - do_set_trace_patterns_2(Rest,Flags,[{error,{bad_trace_args,Arg}}|Replies]); -do_set_trace_patterns_2([],_Flags,Replies) -> - Replies. -%% ----------------------------------------------------------------------------- - -%% Help function which sets the trace flags for all processes specifed in Args. -%% Args shall be a list of {ProcessSpecification,ProcessTraceFlags}. -%% Returns {ok,Answers} where Answers is a list of integer and error descriptions. -%% Note that a process specification may be a particular pid or a {global,Name}. -%% In the case the process does not exist we will fake a zero instead of an -%% error. -do_set_trace_flags(Tracer,Args,How) -> - Fun=fun({Proc,Flags}) -> - case check_traceflag_pidspec(Proc) of - {ok,Proc2} -> % Reg-names converted. - case check_flags(Flags) of - Flags2 when is_list(Flags2) -> % No error! - case (catch - case How of - true -> - erlang:trace(Proc2, - true, - [{tracer,Tracer}|Flags2]); - false -> % No tracer of turning off. - erlang:trace(Proc2, - false, - Flags2) - end) of - N when is_integer(N) -> - N; - {'EXIT',Reason} -> - if - is_pid(Proc2) -> - 0; % Proc2 not alive or not at this node! - true -> % Otherwise, just error! - {error, - {bad_trace_args, - [Reason,Proc2,How,Flags2,Tracer]}} - end - end; - FlagError -> - FlagError - end; - false -> % Skip it. - 0; % Indicate that zero processes matched. - {error,Reason} -> % Bad process specification. - {error,{bad_process,[Reason,Proc]}} - end; - (Faulty) -> - {error,{bad_process,Faulty}} - end, - {ok,lists:map(Fun,Args)}. -%% ------------------------------------------------------------------------------ - -%% Function calling API:s in the trace information server. Note that we have -%% given the responsibility to form a correct functionsname and argument list -%% to the caller. -%% Returns whatever the called function returns. -do_meta_pattern(MPid,{FuncName,ArgList}) -> - case catch apply(inviso_rt_meta,FuncName,[MPid|ArgList]) of - {'EXIT',_Reason} -> - {error,{badarg,{FuncName,ArgList}}}; - Result -> - Result - end; -do_meta_pattern(_MPid,BadArgs) -> - {error,{bad_args,BadArgs}}. -%% ------------------------------------------------------------------------------ - -%% Function removing *all* patterns. Beaware that the one for local patterns -%% causes a walkthrough of all loaded modules. -do_clear_trace_patterns() -> - erlang:trace_pattern({'_','_','_'},false,[local]), %% inc. meta, call_count - erlang:trace_pattern({'_','_','_'},false,[global]). -%% ------------------------------------------------------------------------------ - -%% Function that takes TracerData and initializes the tracing. That can be -%% opening appropriate logfiles, starting meta-tracer. There must be one -%% clause here for every "type" of logging we want to be able to do. -%% Returns the Reply to be forwarded to the caller. -do_init_tracing(LoopData,TD,{HandlerFun,Data},TiTD) when is_function(HandlerFun) -> - {NewLoopData,Reply}= - case do_init_metatracing(TiTD,self()) of - {ok,MetaPid} -> - {LoopData#rt{handler={HandlerFun,Data}, - tracerdata=TD, - meta_tracer=MetaPid, - state=tracing}, - {ok,[{trace_log,ok},{ti_log,ok}]}}; - false -> % No meta tracing requested. - {LoopData#rt{handler={HandlerFun,Data}, - tracerdata=TD, - state=tracing}, - {ok,[{trace_log,ok}]}}; - {error,Reason} -> % Problems starting meta tracing. - {LoopData#rt{handler={HandlerFun,Data}, - tracerdata=TD, - state=tracing}, - {ok,[{trace_log,ok},{ti_log,{error,Reason}}]}} - end, - send_event(state_change,NewLoopData), % Send to subscribing processes. - {NewLoopData,Reply}; -do_init_tracing(LoopData,TD,{Type,Parameters},TiTD) when Type==ip;Type==file -> - case check_traceport_parameters(Type,Parameters) of - ok -> - case catch trace_port(Type,Parameters) of - Fun when is_function(Fun) -> - case catch Fun() of - Port when is_port(Port) -> % Ok, our trace-port is open. - {NewLoopData,Reply}= - case do_init_metatracing(TiTD,Port) of - {ok,MetaPid} -> - {LoopData#rt{tracer_port=Port, - tracerdata=TD, - meta_tracer=MetaPid, - state=tracing}, - {ok,[{trace_log,ok},{ti_log,ok}]}}; - false -> % No meta tracing requested. - {LoopData#rt{tracer_port=Port, - tracerdata=TD, - state=tracing}, - {ok,[{trace_log,ok}]}}; - {error,Reason} -> % Problems starting meta tracing. - {LoopData#rt{tracer_port=Port, - tracerdata=TD, - state=tracing}, - {ok,[{trace_log,ok},{ti_log,{error,Reason}}]}} - end, - send_event(state_change,NewLoopData), - {NewLoopData,Reply}; - {'EXIT',Reason} -> - {LoopData,{error,{bad_port_fun,[Parameters,Reason]}}} - end; - {'EXIT',Reason} -> - {LoopData,{error,{bad_port_args,[Parameters,Reason]}}} - end; - {error,Reason} -> % Bad traceport parameters. - {LoopData,{error,Reason}} - end. - -%% Help function that starts the meta-tracing. Note that the runtime component -%% will becom linked to it. -%% Currently the meta tracer handles two types, 'file' and 'relay'. -%% Note that Tracer tells the meta tracer where regular trace messages shall be -%% sent. This is because the meta tracer is capable of appending a {tracer,Tracer} -%% action term to meta match specs. -do_init_metatracing(LogSpec={_Type,_Arg},Tracer) -> - case inviso_rt_meta:start(LogSpec,Tracer) of - {ok,MetaPid} -> - {ok,MetaPid}; - {error,Reason} -> - {error,Reason} - end; -do_init_metatracing({Type,Arg,{InitPublLDmfa,RemovePublLDmf,CleanPublLDmf}},Tracer)-> - case inviso_rt_meta:start({Type,Arg},Tracer,InitPublLDmfa,RemovePublLDmf,CleanPublLDmf) of - {ok,MetaPid} -> - {ok,MetaPid}; - {error,Reason} -> - {error,Reason} - end; -do_init_metatracing(void,_) -> % Means no meta tracer. - false. -%% ----------------------------------------------------------------------------- - -%% Function that stops all tracing and closes all open files. This function -%% can't fail :-) It tries as hard as it can. -%% This function also kills the autostarter process if one exists. Otherwise it -%% will not be possible from a control component to end an ongoing autostarted -%% tracing. -%% Returns a new loopdata structure since stopping tracing involves updating it. -do_stop_tracing(LoopData) -> - do_stop_tracing_kill_autostarter(LoopData#rt.auto_starter), - do_clear_trace_flags(), % Do not generate any more traces. - NewLoopData1=do_stop_tracing_tracelog(LoopData), - NewLoopData2=do_stop_tracing_metatracing(NewLoopData1), - NewLoopData3=NewLoopData2#rt{state=idle,auto_starter=undefined}, - send_event(state_change,NewLoopData3), - NewLoopData3. - -do_stop_tracing_tracelog(LoopData=#rt{tracer_port=Port}) when is_port(Port) -> - trace_port_control(Port,flush), % Write buffered trace messages. - catch port_close(Port), - LoopData#rt{tracer_port=undefined}; -do_stop_tracing_tracelog(LoopData) -> - LoopData#rt{handler=undefined}. - -do_stop_tracing_metatracing(LoopData=#rt{meta_tracer=MPid}) when is_pid(MPid) -> - inviso_rt_meta:stop(MPid), - LoopData#rt{meta_tracer=undefined}; -do_stop_tracing_metatracing(LoopData) -> % No meta tracer running! - LoopData. - -%% Help function killing the autostarter, if one is active. -do_stop_tracing_kill_autostarter(P) when is_pid(P) -> - exit(P,stop_tracing); -do_stop_tracing_kill_autostarter(_) -> % No autostarter, do nothing. - true. -%% ----------------------------------------------------------------------------- - -%% Help function implementing suspending the runtime component. -%% Returns a new loopdata structure. -do_suspend(LD,Reason) -> - do_clear_trace_flags(), % If no process flags, no output! - do_suspend_metatracer(LD#rt.meta_tracer), - do_suspend_fetchers(LD#rt.fetchers), - do_stop_tracing_kill_autostarter(LD#rt.auto_starter), - NewLD=LD#rt{fetchers=[],status={suspended,Reason},auto_starter=undefined}, - send_event(state_change,NewLD), % Notify subscribers. - NewLD. - -do_suspend_metatracer(MetaTracer) when is_pid(MetaTracer) -> - inviso_rt_meta:suspend(MetaTracer); % This makes it suspended. -do_suspend_metatracer(_) -> - true. - -do_suspend_fetchers([FetcherPid|Rest]) -> - FetcherPid ! {suspend,self()}, % This makes it terminate. - do_suspend_fetchers(Rest); -do_suspend_fetchers([]) -> - true. -%% ------------------------------------------------------------------------------ - -%% Function that stops all tracing, removes all trace-patterns and removes all -%% logfiles. The idea is to return the runtime component to the 'new' state. -do_clear(LoopData,Opts) when is_list(Opts) -> - NewLoopData=do_stop_tracing(LoopData), % First stop tracing, if tracing. - case lists:member(keep_trace_patterns,Opts) of - false -> - do_clear_trace_patterns(); - _ -> - true - end, - case lists:member(keep_log_files,Opts) of - false -> - if - NewLoopData#rt.tracerdata/=undefined -> - do_delete_logs(NewLoopData#rt.tracerdata); - true -> % If no tracerdata, nothing to remove! - true % Do nothing then. - end; - _ -> - true - end, - NewLoopData#rt{state=new,tracerdata=undefined}; -do_clear(LoopData,_Opts) -> % Faulty Opts. - do_clear(LoopData,[]). % Then just ignore the options. -%% ----------------------------------------------------------------------------- - -%% Function which takes a tracerdata, either our own or a "suggested" -%% and tries to find the corresponding files. Note that the return value only -%% contains "types" of logs that the tracerdata is pointing out. Hence -%% is there no ti-log, no one will be mentioned in the return value. -do_list_logs(TracerData) -> % Handles both list and tuple. - case translate_td(TracerData) of - {ok,LogTD,TiTD} -> - {TraceDir,TraceLogs}=list_logs_tracelog(LogTD), - {TiDir,TiLogs}=list_logs_tilog(TiTD), - case {TraceLogs,TiLogs} of - {no_log,no_log} -> % Tracerdata not generating logs! - {ok,no_log}; - {_,no_log} -> % No ti logs. - {ok,[{trace_log,TraceDir,TraceLogs}]}; - {no_log,_} -> % Only ti-logs, unusual! - {ok,[{ti_log,TiDir,TiLogs}]}; - _ -> % Both trace and ti logs. - {ok,[{trace_log,TraceDir,TraceLogs},{ti_log,TiDir,TiLogs}]} - end; - {error,Reason} -> - {error,Reason} - end. -%% ----------------------------------------------------------------------------- - -%% Help function implementing fetching logfiles using distributed Erlang. -%% This function works for both situations, a list of specific files are -%% requested, or a tracerdata is specified. -%% Returns {Reply,NewLoopData}. -do_fetch_log(LD,CollectPid,What) -> - if - LD#rt.state/=tracing -> - case is_list_of_files_or_tracerdata(What) of - files -> - FetcherPid=do_fetch_log_listoffiles(CollectPid,What), - {{ok,FetcherPid},add_fetcher_ld(FetcherPid,LD)}; - tracerdata -> - case do_fetch_log_tracerdata(CollectPid,What) of - {Reply,FetcherPid} when is_pid(FetcherPid) -> - {Reply,add_fetcher_ld(FetcherPid,LD)}; - {Reply,_} -> % No fetch process was started. - {Reply,LD} - end; - false -> % It is an empty list! - {{complete,no_log},LD}; - error -> % Incorrect parameter. - {{error,badarg},LD} - end; - true -> % No transfere during tracing. - {{error,tracing},LD} - end. - -%% Function taking tracerdata to find out what files to send over to the RemotePid. -%% Note that we will not go back to the loop function from here but rather call -%% the fetch_loop instead, prepresenting the fetch-log state. Unless we encounter -%% a problem. -do_fetch_log_tracerdata(CollectPid,TracerData) -> - case do_list_logs(TracerData) of - {ok,no_log} -> - {{complete,no_log},void}; - {ok,Logs} -> % Ok, some trace_log and ti_log. - FetcherPid=do_fetch_log_listoffiles(CollectPid,Logs), - {{ok,FetcherPid},FetcherPid}; - {error,Reason} -> % Problem with tracerdata! - {{error,Reason},void} - end. - -do_fetch_log_listoffiles(CollectPid,FileSpec) -> - ExpandedFileSpec=do_fetch_log_expand_filespec(FileSpec), -%% !!! try out different ChunkSizes -% ChunkSize = 60, -% ChunkSize = 7*1024, - ChunkSize=1024, - _Fetcher=spawn_link(?MODULE, - fetch_init, - [self(),ExpandedFileSpec,CollectPid,ChunkSize]). - -%% Help function which expands the list of logs to have tags in front of every -%% file, as required by the fetch_loop. -do_fetch_log_expand_filespec(Logs) -> - TraceLogs= - case lists:keysearch(trace_log,1,Logs) of - {value,{_,Dir1,Logs1}} -> % There is a list of trace-logs. - lists:map(fun(File)->{trace_log,Dir1,File} end,Logs1); - false -> % No trace-logs! - [] - end, - TiLogs= - case lists:keysearch(ti_log,1,Logs) of - {value,{_,Dir2,Logs2}} -> - lists:map(fun(File)->{ti_log,Dir2,File} end,Logs2); - false -> - [] - end, - TiLogs++TraceLogs. - -%% ------------------------------------------------------------------------------ - -%% Function that removes all logfiles associated with a certain tracerdata. -do_delete_logs(TracerDataOrLogList) -> - case is_list_of_files_or_tracerdata(TracerDataOrLogList) of - tracerdata -> - case translate_td(TracerDataOrLogList) of - {ok,LogTD,TiTD} -> - case {list_logs_tracelog(LogTD),list_logs_tilog(TiTD)} of - {{_,no_log},{_,no_log}} -> % No logs nowhere! - {ok,no_log}; - {{LogDir,LogFiles},{_,no_log}} -> % No ti. - {ok,[{trace_log,delete_files(LogDir,LogFiles)}]}; - {{_,no_log},{TiDir,TiFiles}} -> - {ok,[{ti_log,delete_files(TiDir,TiFiles)}]}; - {{LogDir,LogFiles},{TiDir,TiFiles}} -> - {ok,[{trace_log,delete_files(LogDir,LogFiles)}, - {ti_log,delete_files(TiDir,TiFiles)}]} - end; - {error,Reason} -> - {error,Reason} - end; - files -> % It is [{trace_log,Dir,Files},.. - if - is_list(hd(TracerDataOrLogList)) -> % Just a list of files. - {ok,delete_files(".",TracerDataOrLogList)}; - is_tuple(hd(TracerDataOrLogList)) -> % A "modern" logspec. - case {lists:keysearch(trace_log,1,TracerDataOrLogList), - lists:keysearch(ti_log,1,TracerDataOrLogList)} of - {false,false} -> % Hmm, no logs specified! - {ok,[]}; % Easy response! - {{value,{_,LogDir,LogFiles}},false} -> - {ok,[{trace_log,delete_files(LogDir,LogFiles)}]}; - {false,{value,{_,TiDir,TiFiles}}} -> - {ok,[{ti_log,delete_files(TiDir,TiFiles)}]}; - {{value,{_,LogDir,LogFiles}},{value,{_,TiDir,TiFiles}}} -> - {ok,[{trace_log,delete_files(LogDir,LogFiles)}, - {ti_log,delete_files(TiDir,TiFiles)}]} - end - end; - false -> % Can't tell which! - {ok,[]}; - error -> - {error,{badarg,TracerDataOrLogList}} - end. -%% ----------------------------------------------------------------------------- - -%% Function handling the request when a control component wishing to take -%% control over this already existing control component. It does not matter -%% what state it is in. It can very well already be tracing. -%% Returns {Reply,NewLoopData}. -%% Where the Reply tells the control component wether it took control of it -%% or not. {node_info,node(),self(),Vsn,State,Status,{tag,Tag}} means that we -%% can be adopted (and more precisely considers ourselves being adopted now). -do_try_to_adopt(Tag,if_ref,LoopData=#rt{tag=Tag},_Ctrl) -> - {{error,{wrong_reference,LoopData#rt.tag}},LoopData}; -do_try_to_adopt(NewTag,_Condition,LoopData,CtrlPid) -> - case LoopData#rt.timer_ref of % Do we have a running-alone timer? - undefined -> % No we don't. - true; - TimerRef -> - timer:cancel(TimerRef) - end, - CtrlRef=erlang:monitor(process,CtrlPid), % Lets monitor our new "master"! - {DepVal,_}=LoopData#rt.dependency, - {node_info,Node,Pid,VSN,State,Status,Tag}=collect_node_info(LoopData), - NewLoopData= - LoopData#rt{dependency={DepVal,node(CtrlPid)}, - ctrl=CtrlPid, - ctrl_ref=CtrlRef, % Monitoring our new master. - tag=NewTag, % Use this tag from now on. - timer_ref=undefined}, - {{node_info,Node,Pid,VSN,State,Status,{tag,Tag}},NewLoopData}. -%% ----------------------------------------------------------------------------- - -%% Function changing parameters accoring to a new options list. Note that we -%% can not change control component if the one we have is still working. -%% We can however of course change how this runtime component will react to -%% a running alone scenario. -%% Returns 'stop' or NewLoopData. -do_change_options(Options,LoopData) -> - NewLoopData=read_option_list(Options,LoopData), - if - NewLoopData/=LoopData -> % Some options changed. - case do_change_options_ctrl(LoopData,NewLoopData) of - stop -> - stop; - {ok,NewLoopData2} -> - NewLoopData3=do_change_options_overload(LoopData,NewLoopData2), - NewLoopData3#rt{next_loadcheck=now()} % Force a load check next. - end; - true -> - LoopData - end. - -%% Help function which sets up the new dependencies. Note that we only do that -%% if do not have a working control component. -%% Returns {ok,NewLoopData} or 'stop'. -do_change_options_ctrl(OldLD,NewLD) -> - if - OldLD#rt.timer_ref/=undefined -> % No control and waiting to terminate. - timer:cancel(OldLD#rt.timer_ref), - do_down_message(NewLD#rt{timer_ref=undefined}); - OldLD#rt.ctrl==undefiend -> % No control component. - do_down_message(NewLD); - true -> % We have a working control component! - {ok,NewLD} - end. - -do_change_options_overload(OldLD,NewLD) -> - if - OldLD#rt.overload/=NewLD#rt.overload -> - terminate_overload(OldLD), - NewOverloadData=initialize_overload(NewLD), - NewLD#rt{overload_data=NewOverloadData}; - true -> % No changes done. - NewLD - end. -%% ----------------------------------------------------------------------------- - -%% Help function handling an incoming DOWN message from our control component. -%% If the runtime component is not allowed to run without a control component, it -%% simply terminates which closes the trace-port and process trace flags are -%% therefore automatically removed. -%% Returns 'stop' or a {ok,NewLoopData} structure. -do_down_message(LoopData) -> - case LoopData#rt.dependency of - {0,_} -> % Not allowed to run without controller. - stop; - {infinity,_} -> % Don't care. Just remove the controller. - {ok,LoopData#rt{ctrl=undefined,ctrl_ref=undefined}}; - {TimeOut,_} -> % Allowed to run TimeOut ms alone. - {ok,TimerRef}=timer:exit_after(TimeOut,self(),running_alone), - {ok,LoopData#rt{timer_ref=TimerRef,ctrl=undefined,ctrl_ref=undefined}} - end. -%% ----------------------------------------------------------------------------- - -%% Function handling incomming exit signals. We can expect exit signals from the -%% following: Our parent supervisor (runtime_tools_sup), a meta-tracer process, -%% a logfile fetcher process, or the auto_starter. -%% A trace-port may also generate an exit signal. -%% In addition it is possible that an overload mechanism generates exit-signals. -%% We can also get the running_alone exit signal from our self. This is the -%% situation if our control component has terminated and this runtime component -%% is not allowed to exist on its own for ever. -%% Also note that after we have stopped tracing, for any reason, it is not -%% impossible that we receive the EXIT signals from still working parts that -%% we are now shuting down. This is no problem, the code will mearly update -%% the loopdata structure once again. -%% Returns 'exit' indicating that the runtime component shall terminate now, -%% {NewLoopData,NewTimeOut} if the exit-signal resulted in an overload check, or -%% a new loopdata structure shall we ignore the exit, or it simply resulted in -%% a state-change. -act_on_exit(Parent,_Reason,#rt{parent=Parent}) -> - exit; -act_on_exit(_Pid,running_alone,_LoopData) -> - exit; -act_on_exit(MetaTracer,_Reason,LoopData=#rt{meta_tracer=MetaTracer}) -> - LoopData#rt{meta_tracer=undefined}; % It does not exit anylonger. -act_on_exit(Port,Reason,LoopData=#rt{tracer_port=Port}) -> - send_event({port_down,node(),Reason},LoopData), - _NewLoopData=do_stop_tracing(LoopData); -act_on_exit(AutoStarter,_Reason,LoopData=#rt{auto_starter=AutoStarter}) -> - LoopData#rt{auto_starter=undefined}; % The autostarter has terminated. -act_on_exit(Pid,Reason,LoopData) -> - case remove_fetcher_ld(Pid,LoopData) of - {true,NewLoopData} -> % Yes it really was a fetcher. - NewLoopData; - false -> % No it was not a fetcher. - act_on_exit_overload(Pid,Reason,LoopData) - end. - -%% Help function checking if this exit has anything to do with an overload -%% mechanism. Note that here we run the overload mechanism regardless of -%% if we are tracing or not. This because an exit signal from the overload -%% must most likely always be handled. -act_on_exit_overload(Pid,Reason,LoopData) -> - if - LoopData#rt.overload/=?NO_LOADCHECK -> - {_NewLD,_NewTimeOut}= - do_check_overload(LoopData, - {'EXIT',{Pid,Reason,LoopData#rt.overload_data}}); - true -> % Overload not in use. - LoopData - end. -%% ----------------------------------------------------------------------------- - - - - - - - - - - - - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -%% ============================================================================== -%% Various help functions. -%% ============================================================================== - -%% Help function which calculates a new now-tuple by adding Interval milliseconds -%% to the first argument. Note that Interval may be 'infinity' too. -%% Returns a new now-tuple or "bigvalue" which is greater than any now-tuple. -add_to_now({MegSec,Sec,MicroSec},Interval) when is_integer(Interval) -> - NewSec=Sec+(Interval div 1000), - if - NewSec>=1000000 -> - {MegSec+1,NewSec-1000000,MicroSec}; - true -> - {MegSec,NewSec,MicroSec} - end; -add_to_now(_,infinity) -> - "bigvalue". -%% ------------------------------------------------------------------------------ - -%% Help function calculating the difference in milliseconds between its first -%% and second argument. This is useful when calculating an after timeout value -%% from current now() and next_loadcheck value. -calc_diff_to_now(T1={_,_,_},T2={_,_,_}) -> - TimeOut1=timer:now_diff(T2,T1), % The difference in microseconds. - if - TimeOut1<0 -> - 0; - true -> % Make milliseconds out of it. - TimeOut1 div 1000 - end; -calc_diff_to_now(_T1,_) -> % Next loadcheck is not activated. - infinity. % The the after timeout is infinity. -%% ------------------------------------------------------------------------------ - - -%% Help function returning information about this runtime component. -collect_node_info(#rt{vsn=VSN,state=State,status=Status,tag=Tag}) -> - {node_info,node(),self(),VSN,State,Status,Tag}. -%% ------------------------------------------------------------------------------ - -%% Help function sending information to the control component that state/status -%% change has occurred. Returns nothing significant. -send_event(state_change,LoopData=#rt{ctrl=CtrlPid}) when is_pid(CtrlPid) -> - Event={trace_event,{state_change,node(),{LoopData#rt.state,LoopData#rt.status}}}, - CtrlPid ! Event; -send_event(Event,#rt{ctrl=CtrlPid}) when is_pid(CtrlPid) -> - CtrlPid ! {event,Event}; -send_event(_,_) -> % We have no control to send to! - true. % Maybe tracing alone after autostart. -%% ------------------------------------------------------------------------------ - -%% Help function initializing the overload protection mechanism. This may be -%% necessary if it is a port program or similar. Returns {ok,Data} or 'void'. -%% The datastructure vill be given to LoadMF as argument whenever loadchecks -%% are done. -initialize_overload(#rt{overload={_MF,_Interval,{M,F,Args},_RemoveMFA}}) -> - case catch apply(M,F,Args) of - {ok,Data} -> - Data; - _ -> % 'EXIT' or other faulty returnvalue. - void - end; -initialize_overload(_) -> - void. -%% ------------------------------------------------------------------------------ - -%% Help function which terminates an overload protection mechanism. -%% Returns nothing significant. -terminate_overload(#rt{overload={_MF,_Interval,_InitMFA,{M,F,Args}}, - overload_data=Data}) -> - catch apply(M,F,[Data|Args]), % Interested in the side-effect. - true; -terminate_overload(_) -> - true. -%% ------------------------------------------------------------------------------ - - -%% Help function which checks that a process specified for trace flags is correct. -%% Either the built-in "aliases" for groups of processes, a pid, a locally registered -%% name. This function also works for globally registered names. It must then -%% first be established that the process is local for this node before setting any -%% process flags. -%% Returns {ok,PidSpec}, 'false' or {error,Reason}. -check_traceflag_pidspec(all) -> {ok,all}; -check_traceflag_pidspec(new) -> {ok,new}; -check_traceflag_pidspec(existing) -> {ok,existing}; -check_traceflag_pidspec(Name) when is_atom(Name) -> - check_traceflag_pidspec({local,Name}); -check_traceflag_pidspec({local,A}) when is_atom(A) -> - case whereis(A) of - undefined -> % Then it is considered faulty. - {error,{nonexistent_name,A}}; - Pid when is_pid(Pid) -> - {ok,Pid} - end; -check_traceflag_pidspec({global,Name}) when is_atom(Name) -> - case global:whereis_name(Name) of - undefined -> % Then the name does not exist at all. - {error,{nonexistent_name,{global,Name}}}; - Pid when is_pid(Pid) -> % Ok, but must check that it is here. - if - node()==node(Pid) -> - {ok,Pid}; - true -> % Pid is not at this node. - false % Not an error but cant be used. - end - end; -check_traceflag_pidspec(Pid) when is_pid(Pid) -> - {ok,Pid}; -check_traceflag_pidspec(Proc) -> - {error,{faulty,Proc}}. -%% ------------------------------------------------------------------------------ - -%% Help function removing all trace flags from all processes. Useful in connection -%% with suspend. Returns nothing significant. -do_clear_trace_flags() -> - erlang:trace(all, false, [all]). -%% ------------------------------------------------------------------------------ - -%% Help function which checks that only valid process trace flags are mentioned. -%% In order to create better fault reports. -%% Returns a list of the approved flags, or {error,Reason}. -check_flags(Flags) -> - check_flags_2(Flags,Flags). - -check_flags_2([send|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2(['receive'|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([call|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([return_to|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([procs|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([garbage_collection|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([running|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([set_on_spawn|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([set_on_first_spawn|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([set_on_link|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([timestamp|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([arity|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([silent|Rest],Flags) -> check_flags_2(Rest,Flags); -check_flags_2([],Flags) -> Flags; -check_flags_2([Faulty|_],_Flags) -> {error,{bad_flag,Faulty}}. -%% ------------------------------------------------------------------------------ - -%% Help function which checks parameters to erlang:trace_pattern. The purpose of -%% the function is to avoid to get multiple error return values in the return -%% list for a pattern used together with a regexp expanded module name. -check_pattern_parameters(Mod,Func,Arity,MS) -> - MSresult = check_MS(MS), - MFAresult = check_MFA(Mod,Func,Arity), - MFAresult and MSresult. - -check_MS(MS) when is_list(MS) -> true; -check_MS(true) -> true; -check_MS(false) -> true. - -check_MFA('_','_','_') -> true; -check_MFA(Mod,'_','_') when is_atom(Mod) -> true; -check_MFA(Mod,'_',A) when is_atom(Mod), is_integer(A) -> false; -check_MFA(Mod,F,'_') when is_atom(Mod), is_atom(F) -> true; -check_MFA(Mod,F,A) when is_atom(Mod), is_atom(F), is_integer(A) -> true. - -%% ----------------------------------------------------------------------------- - -%% Help function finding out if Mod is loaded, and if not, if it can successfully -%% be loaded. The Opts list can prevent modules from being loaded. -%% Returns 'true' or 'false'. -load_module_on_option(Mod,Opts) when is_list(Opts) -> - case lists:member(no_loadcheck,Opts) of - true -> % Then just skip this, return true. - true; - false -> - case erlang:module_loaded(Mod) of - true -> - true; % It is loaded, do no more. - false -> - case lists:member(only_loaded,Opts) of - true -> % Then, make no attempts to load. - false; - false -> % Try to load! - case code:ensure_loaded(Mod) of - {module,_Mod} -> % Successfully loaded! - true; - {error,_Reason} -> - false - end - end - end - end; -load_module_on_option(Mod,_Opts) -> % Most likely Opts not a list! - load_module_on_option(Mod,[]). % Call without options. -%% ----------------------------------------------------------------------------- - -%% Help function taking a tuplelist of options turning them into a loopdata -%% structure. Returns the loopdata structure with the new values changed. -read_option_list([],LD) -> % Done, return loopdata. - LD; -read_option_list([{dependency,{Value,Node}}|Rest],LD) -> - read_option_list(Rest,LD#rt{dependency={Value,Node}}); -read_option_list([{dependency,Value}|Rest],LD) when is_integer(Value);Value==infinity -> - read_option_list(Rest,LD#rt{dependency={Value,node()}}); -read_option_list([overload|Rest],LD) -> % So that we can remove loadcheck. - read_option_list(Rest,LD#rt{overload=?NO_LOADCHECK}); -read_option_list([{overload,{MF,Interval}}|Rest],LD) - when is_integer(Interval);Interval==infinity -> - read_option_list(Rest,LD#rt{overload={MF,Interval,void,void}}); -read_option_list([{overload,{MF,Interval,InitMFA,RemoveMFA}}|Rest],LD) - when is_integer(Interval);Interval==infinity -> - read_option_list(Rest,LD#rt{overload={MF,Interval,InitMFA,RemoveMFA}}); -read_option_list([{overload,Interval}|Rest],LD) - when is_integer(Interval);Interval==infinity -> - read_option_list(Rest,LD#rt{overload={fun ?DEFAULT_OVERLOAD_FUNC/1, - Interval, - void, - void}}); -read_option_list([_|Rest],LD) -> % Unknown option. - read_option_list(Rest,LD). -%% ----------------------------------------------------------------------------- - -%% Help function which returns the version number for the runtime_tools -%% application. Since it is called from within the runtime_tools application -%% we can be "sure" that it really exists. -get_application_vsn() -> - {value,{_,_,VSN}}=lists:keysearch(runtime_tools,1,application:loaded_applications()), - VSN. -%% ----------------------------------------------------------------------------- - -%% Help function that examines an argument to determine if it is a list of files -%% or tracerdata. This since they are both complex structures, looking alike. -%% Returns 'tracerdata', 'files', 'false' or 'error'. Error is returned if it -%% can not be decided which it is. -is_list_of_files_or_tracerdata(What) -> - case inviso_rt_lib:is_tracerdata(What) of - true -> - tracerdata; - false -> - if - What==[] -> - false; - is_list(What),is_list(hd(What)) -> - files; - is_list(What) -> - case lists:keysearch(trace_log,1,What) of - {value,_} -> - files; - false -> - case lists:keysearch(ti_log,1,What) of - {value,_} -> - files; - false -> - error % Neither tracerdata nor list of files. - end - end; - true -> - error - end - end. -%% ------------------------------------------------------------------------------ - -%% Help function which removes all files in the ListOfFiles, assuming they -%% are located in Dir. -%% Returns a list of [{ok,FileName},...{error,Reason},...] -delete_files(Dir,ListOfFiles) -> - delete_files_2(Dir,ListOfFiles, []). - -delete_files_2(Dir,[File|Tail],Reply) when is_list(Dir),is_list(File) -> - case catch file:delete(filename:join(Dir,File)) of - ok -> - delete_files_2(Dir,Tail,[{ok,File}|Reply]); - {error,Posix} -> - delete_files_2(Dir,Tail,[{error,{Posix,File}}|Reply]); - {'EXIT',_Reason} -> % Probably not proper string. - delete_files_2(Dir,Tail,[{error,{badarg,[Dir,File]}}|Reply]) - end; -delete_files_2(Dir,[Faulty|Tail],Reply) -> - delete_files_2(Dir,Tail,[{error,{badarg,[Dir,Faulty]}}|Reply]); -delete_files_2(_,[],Reply) -> - Reply. -%% ----------------------------------------------------------------------------- - -%% Help function which lists all trace logs belonging to this tracerdata. -%% Note that this function operates on internal LogTD structures. -list_logs_tracelog({file,FileName}) when is_list(FileName) -> - case file:read_file_info(FileName) of - {ok,_} -> % The file exists. - {filename:dirname(FileName),[filename:basename(FileName)]}; - _ -> % The file does not exist - {filename:dirname(FileName),[]} - end; -list_logs_tracelog({file,Wrap}) when is_tuple(Wrap),element(2,Wrap)==wrap -> - case {element(1,Wrap),element(3,Wrap)} of - {FileName,Tail} when is_list(FileName),is_list(Tail) -> - case catch {filename:dirname(FileName),list_wrapset(FileName,Tail)} of - {'EXIT',_Reason} -> % Garbage in either lists. - {"",no_log}; % Interpret as no log for tracerdata. - Tuple -> - Tuple - end; - _ -> - {"",no_log} - end; -list_logs_tracelog(void) -> % Trace log not used. - {"",no_log}; -list_logs_tracelog(_) -> % Some fun or similar. - {"",no_log}. % Then there are no files to report. -%% ----------------------------------------------------------------------------- - -%% Help function which lists all ti-files belonging to this tracerdata. -%% Note that this function operates on the internal TiTD structure. -list_logs_tilog(TiTD) - when tuple_size(TiTD)>=2,element(1,TiTD)==file,is_list(element(2,TiTD)) -> - FileName=element(2,TiTD), - case file:read_file_info(FileName) of - {ok,_} -> % Yes the file exists. - {filename:dirname(FileName),[filename:basename(FileName)]}; - _ -> - {filename:dirname(FileName),[]} - end; -list_logs_tilog(void) -> % Internal representation for - {"",no_log}; % ti-file not in use. -list_logs_tilog(_) -> - {"",no_log}. -%% ----------------------------------------------------------------------------- - -%% Help function which lists all files belonging to the wrap-set specified by -%% Prefix and Suffix. Note that there can be a directory in Prefix as well. -%% Will fail if either of Prefix or Suffix are not proper strings. -%% Returns a list of files, without dirname. -list_wrapset(Prefix,Suffix) -> - Name=filename:basename(Prefix), - Dirname=filename:dirname(Prefix), - case file:list_dir(Dirname) of - {ok,Files} -> - RegExp="^"++list_wrapset_escapes(Name)++"[0-9]+"++ - list_wrapset_escapes(Suffix)++"$", - list_wrapset_2(Files,RegExp); - {error,_Reason} -> % Translate this to no files! - [] - end. - -list_wrapset_2([File|Rest],RegExp) -> - Length=length(File), - case re:run(File,RegExp) of - {match,[{0,Length}]} -> % This is a member of the set. - [File|list_wrapset_2(Rest,RegExp)]; - _ -> - list_wrapset_2(Rest,RegExp) - end; -list_wrapset_2([],_) -> - []. - -%% Help function which inserts escape characters infront of characters which -%% will otherwise be missinterpreted by the regexp function as meta rather than -%% just the character itself. -list_wrapset_escapes([$.|Rest]) -> - [$\\,$.|list_wrapset_escapes(Rest)]; -list_wrapset_escapes([Char|Rest]) -> - [Char|list_wrapset_escapes(Rest)]; -list_wrapset_escapes([]) -> - []. -%% ----------------------------------------------------------------------------- - - - - - - -%% ============================================================================== -%% Handler functions for implementing simple trace-message handlers. -%% ============================================================================== -%% -%% A handler must be a function taking two arguments. The first is the trace- -%% message. The second is datastructure used by the handler. The handler shall -%% returns (possibly) new datastructure. - -%% ------------------------------------------------------------------------------ -%% Function implementing a relayer. This function is used to creat a fun handler -%% if the relay option is used in tracer-data. -%% ------------------------------------------------------------------------------ -relay_handler(Msg,Tracer) -> - Tracer ! Msg, - Tracer. - -%% ------------------------------------------------------------------------------ -%% Function implementing a default terminal io handler. -%% ------------------------------------------------------------------------------ - -dhandler(end_of_trace, Out) -> - Out; -dhandler(Trace, Out) when element(1, Trace) == trace, - tuple_size(Trace) >= 3 -> - dhandler1(Trace, tuple_size(Trace), Out); -dhandler(Trace, Out) when element(1, Trace) == trace_ts, - tuple_size(Trace) >= 4 -> - dhandler1(Trace, tuple_size(Trace)-1, Out); -dhandler(Trace, Out) when element(1, Trace) == drop, - tuple_size(Trace) == 2 -> - io:format(Out, "*** Dropped ~p messages.~n", [element(2,Trace)]), - Out; -dhandler(Trace, Out) when element(1, Trace) == seq_trace, - tuple_size(Trace) >= 3 -> - SeqTraceInfo = case Trace of - {seq_trace, Lbl, STI, TS} -> - io:format(Out, "SeqTrace ~p [~p]: ", - [TS, Lbl]), - STI; - {seq_trace, Lbl, STI} -> - io:format(Out, "SeqTrace [~p]: ", - [Lbl]), - STI - end, - case SeqTraceInfo of - {send, Ser, Fr, To, Mes} -> - io:format(Out, "(~p) ~p ! ~p [Serial: ~p]~n", - [Fr, To, Mes, Ser]); - {'receive', Ser, Fr, To, Mes} -> - io:format(Out, "(~p) << ~p [Serial: ~p, From: ~p]~n", - [To, Mes, Ser, Fr]); - {print, Ser, Fr, _, Info} -> - io:format(Out, "-> ~p [Serial: ~p, From: ~p]~n", - [Info, Ser, Fr]); - Else -> - io:format(Out, "~p~n", [Else]) - end, - Out; -dhandler(_Trace, Out) -> - Out. - -dhandler1(Trace, Size, Out) -> -%%%! Self = self(), - From = element(2, Trace), - case element(3, Trace) of - 'receive' -> - case element(4, Trace) of - {dbg,ok} -> ok; - Message -> io:format(Out, "(~p) << ~p~n", [From,Message]) - end; - 'send' -> - Message = element(4, Trace), - case element(5, Trace) of -%%%! This causes messages to disappear when used by ttb (observer). Tests -%%%! so far show that there is no difference in results with dbg even if I -%%%! comment it out, so I hope this is only some old code which isn't -%%%! needed anymore... /siri -%%%! Self -> ok; - To -> io:format(Out, "(~p) ~p ! ~p~n", [From,To,Message]) - end; - call -> - case element(4, Trace) of - MFA when Size == 5 -> - Message = element(5, Trace), - io:format(Out, "(~p) call ~s (~p)~n", - [From,ffunc(MFA),Message]); - MFA -> - io:format(Out, "(~p) call ~s~n", [From,ffunc(MFA)]) - end; - return -> %% To be deleted... - case element(4, Trace) of - MFA when Size == 5 -> - Ret = element(5, Trace), - io:format(Out, "(~p) old_ret ~s -> ~p~n", - [From,ffunc(MFA),Ret]); - MFA -> - io:format(Out, "(~p) old_ret ~s~n", [From,ffunc(MFA)]) - end; - return_from -> - MFA = element(4, Trace), - Ret = element(5, Trace), - io:format(Out, "(~p) returned from ~s -> ~p~n", - [From,ffunc(MFA),Ret]); - return_to -> - MFA = element(4, Trace), - io:format(Out, "(~p) returning to ~s~n", [From,ffunc(MFA)]); - spawn when Size == 5 -> - Pid = element(4, Trace), - MFA = element(5, Trace), - io:format(Out, "(~p) spawn ~p as ~s~n", [From,Pid,ffunc(MFA)]); - Op -> - io:format(Out, "(~p) ~p ~s~n", [From,Op,ftup(Trace,4,Size)]) - end, - Out. - - -%%% These f* functions returns non-flat strings - -%% {M,F,[A1, A2, ..., AN]} -> "M:F(A1, A2, ..., AN)" -%% {M,F,A} -> "M:F/A" -ffunc({M,F,Argl}) when is_list(Argl) -> - io_lib:format("~p:~p(~s)", [M, F, fargs(Argl)]); -ffunc({M,F,Arity}) -> - io_lib:format("~p:~p/~p", [M,F,Arity]); -ffunc(X) -> io_lib:format("~p", [X]). - -%% Integer -> "Integer" -%% [A1, A2, ..., AN] -> "A1, A2, ..., AN" -fargs(Arity) when is_integer(Arity) -> integer_to_list(Arity); -fargs([]) -> []; -fargs([A]) -> io_lib:format("~p", [A]); %% last arg -fargs([A|Args]) -> [io_lib:format("~p,", [A]) | fargs(Args)]; -fargs(A) -> io_lib:format("~p", [A]). % last or only arg - -%% {A_1, A_2, ..., A_N} -> "A_Index A_Index+1 ... A_Size" -ftup(Trace, Index, Index) -> - io_lib:format("~p", [element(Index, Trace)]); -ftup(Trace, Index, Size) -> - [io_lib:format("~p ", [element(Index, Trace)]) - | ftup(Trace, Index+1, Size)]. -%% ------------------------------------------------------------------------------ - -%% ============================================================================== -%% Functions handling the trace-port. Copied from dbg.erl -%% ============================================================================== - -trace_port_control(Port, flush) -> - case trace_port_control(Port, $f, "") of - {ok, [0]} -> ok; - {ok, _} -> {error, not_supported_by_trace_driver}; - Other -> Other - end. - -trace_port_control(Port, Command, Arg) when is_port(Port)-> - case catch port_control(Port, Command, Arg) of - {'EXIT', _} -> {error, {no_trace_driver, node()}}; - Result -> Result - end. - - -trace_port(file, {Filename, wrap, Tail}) -> - trace_port(file, {Filename, wrap, Tail, 128*1024}); -trace_port(file, {Filename, wrap, Tail, WrapSize}) -> - trace_port(file, {Filename, wrap, Tail, WrapSize, 8}); -trace_port(file, {Filename, wrap, Tail, WrapSize, WrapCnt}) - when is_list(Tail), - is_integer(WrapSize), WrapSize >= 0, WrapSize < (1 bsl 32), - is_integer(WrapCnt), WrapCnt >= 1, WrapCnt < (1 bsl 32) -> - trace_port1(file, Filename, {wrap, Tail, WrapSize, WrapCnt, 0}); -trace_port(file, {Filename, wrap, Tail, {time, WrapTime}, WrapCnt}) - when is_list(Tail), - is_integer(WrapTime), WrapTime >= 1, WrapTime < (1 bsl 32), - is_integer(WrapCnt), WrapCnt >= 1, WrapCnt < (1 bsl 32) -> - trace_port1(file, Filename, {wrap, Tail, 0, WrapCnt, WrapTime}); -trace_port(file, Filename) when is_list(Filename) -> - trace_port1(file, Filename, nowrap); - -trace_port(ip, Portno) when is_integer(Portno) -> - trace_port(ip,{Portno,50}); - -trace_port(ip, {Portno, Qsiz}) when is_integer(Portno), is_integer(Qsiz) -> - fun() -> - Driver = "trace_ip_drv", - Dir1 = filename:join(code:priv_dir(runtime_tools), "lib"), - case catch erl_ddll:load_driver(Dir1, Driver) of - ok -> - ok; - _ -> - Dir2 = filename:join( - Dir1, - erlang:system_info(system_architecture)), - catch erl_ddll:load_driver(Dir2, Driver) - end, - L = lists:flatten( - io_lib:format("~s ~p ~p 2", - [Driver, Portno, Qsiz])), - open_port({spawn, L}, [eof]) - end. - -trace_port1(file, Filename, Options) -> - Driver = "trace_file_drv", - fun() -> - Name = filename:absname(Filename), - %% Absname is needed since the driver uses - %% the supplied name without further investigations, - %% and if the name is relative the resulting path - %% might be too long which can cause a bus error - %% on vxworks instead of a nice error code return. - %% Also, the absname must be found inside the fun, - %% in case the actual node where the port shall be - %% started is on another node (or even another host) - {Wrap, Tail} = - case Options of - {wrap, T, WrapSize, WrapCnt, WrapTime} -> - {lists:flatten( - io_lib:format("w ~p ~p ~p ~p ", - [WrapSize, WrapCnt, WrapTime, - length(Name)])), - T}; - nowrap -> - {"", ""} - end, - Command = Driver ++ " " ++ Wrap ++ "n " ++ Name ++ Tail, - Dir1 = filename:join(code:priv_dir(runtime_tools), "lib"), - case catch erl_ddll:load_driver(Dir1, Driver) of - ok -> - ok; - _ -> - Dir2 = filename:join( - Dir1, - erlang:system_info(system_architecture)), - catch erl_ddll:load_driver(Dir2, Driver) - end, - if element(1, Options) == wrap -> - %% Delete all files from any previous wrap log - Files = wrap_postsort(wrap_presort(Name, Tail)), - lists:foreach( - fun(N) -> file:delete(N) end, - Files); - true -> ok - end, - open_port({spawn, Command}, [eof]) - end. - -%% Find all possible wrap log files. -%% Returns: a list of sort converted filenames. -%% -%% The sort conversion is done by extracting the wrap sequence counter -%% from the filename, and calling wrap_encode/2. -wrap_presort(Filename, Tail) -> - Name = filename:basename(Filename), - Dirname = filename:dirname(Filename), - case file:list_dir(Dirname) of - {ok, Files} -> - lists:zf( - fun(N) -> - case match_front(N, Name) of - false -> - false; - X -> - case match_rear(X, Tail) of - false -> - false; - C -> % Counter - case match_0_9(C) of - true -> - {true, -% filename:join(Dirname, N)} - wrap_encode( - filename:join(Dirname, N), - C)}; - false -> - false - end - end - end - end, - Files); - _ -> - [] - end. - -%% Extract the filenames from a list of sort converted ones. -wrap_postsort(Files) -> - lists:map(fun wrap_name/1, Files). - -wrap_encode(N, C) -> - {list_to_integer(C), N}. - -wrap_name({_C, N}) -> - N. - -%% Returns what is left of ListA when removing all matching -%% elements from ListB, or false if some element did not match, -%% or if ListA runs out of elements before ListB. -match_front(ListA, []) when is_list(ListA) -> - ListA; -match_front([], ListB) when is_list(ListB) -> - false; -match_front([Hd|TlA], [Hd|TlB]) -> - match_front(TlA,TlB); -match_front([_HdA|_], [_HdB|_]) -> - false. - -%% Reversed version of match_front/2 -match_rear(ListA, ListB) when is_list(ListA), is_list(ListB) -> - case match_front(lists:reverse(ListA), lists:reverse(ListB)) of - false -> - false; - List -> - lists:reverse(List) - end. - -%% Returns true if the non-empty list arguments contains all -%% characters $0 .. $9. -match_0_9([]) -> - false; -match_0_9([H]) when is_integer(H), $0 =< H, H =< $9 -> - true; -match_0_9([H|T]) when is_integer(H), $0 =< H, H =< $9 -> - match_0_9(T); -match_0_9(L) when is_list(L) -> - false. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% Functions working on the tracerdata structure. -%% ----------------------------------------------------------------------------- - -%% Tracerdata is the structure which specifies to where tracing is logged at this -%% runtime component. It may now (and in the future specify) several things. -%% Currently it can consist of: -%% LogTD: specifying how trace-log data shall be handled. -%% TiTD : trace information, specifying how trace information shall be handled. -%% -%% Tracerdata may also contain quick or standard forms of LogTD and/or TiTD. -%% For instance if a standard handler-fun shall be used. The handler fun is not -%% part of the tracerdata but rather specified by a constant. - - -%% Help function that translates an input-tracerdata to useful internal formats. -%% This since the tracerdata may consist of specifications which shall be -%% translated into funs or similar. -%% Returns {ok,LogTD,TiTD} or {error,Reason}. -%% Note that TiTD may be 'void' since TiTD is not mandatory. -translate_td(TracerData) when is_list(TracerData) -> % Both log and ti. - case translate_td_logtd(get_trace_log_tracerdata(TracerData)) of - {ok,LogTD} -> - case translate_td_titd(get_ti_log_tracerdata(TracerData)) of - {ok,TiTD} -> - {ok,LogTD,TiTD}; - {error,Reason} -> - {error,Reason} - end; - {error,Reason} -> - {error,Reason} - end; -translate_td(TracerData) -> % The it is just LogTD!? - case translate_td_logtd(TracerData) of - {ok,LogTD} -> - {ok,LogTD,void}; - {error,Reason} -> - {error,Reason} - end. -%% ----------------------------------------------------------------------------- - -%% Help function translating trace-log tracerdata. -translate_td_logtd(collector) -> % This rt will act as receiver. - {ok,{fun dhandler/2,user}}; % Simple terminal io. -translate_td_logtd({relayer,Tracer}) when is_pid(Tracer) -> - {ok,{fun relay_handler/2,Tracer}}; % Relay trace-msg to Tracer-pid. -translate_td_logtd({HandlerFun,Data}) when is_function(HandlerFun) -> - {ok,{HandlerFun,Data}}; % Own invented fun. -translate_td_logtd({Type,Parameters}) when Type==ip;Type==file -> - {ok,{Type,Parameters}}; % Built in trace-port -translate_td_logtd(false) -> % Unusual but no trace log. - {ok,void}; -translate_td_logtd(Arg) -> - {error,{bad_log_td,Arg}}. -%% ----------------------------------------------------------------------------- - -%% Help function translating ti-log tracerdata. -translate_td_titd(TiTD={file,FileName}) when is_list(FileName) -> - {ok,TiTD}; -translate_td_titd({file,FileName, - {InitPublLDmfa={M1,F1,L1}, - RemovePublLDmf={M2,F2}, - CleanPublLDmf={M3,F3}}}) - when is_list(FileName),is_atom(M1),is_atom(F1),is_atom(M2),is_atom(F2),is_list(L1),is_atom(M3),is_atom(F3) -> - {ok,{file,FileName,{InitPublLDmfa,RemovePublLDmf,CleanPublLDmf}}}; -translate_td_titd({file,FileName, - {InitPublLDmfa={M1,F1,L1}, - void, - CleanPublLDmf={M3,F3}}}) - when is_list(FileName),is_atom(M1),is_atom(F1),is_list(L1),is_atom(M3),is_atom(F3) -> - {ok,{file,FileName,{InitPublLDmfa,void,CleanPublLDmf}}}; -translate_td_titd(false) -> % Means no ti-tracerdata. - {ok,void}; -translate_td_titd(TiTD) -> - {error,{bad_ti_td,TiTD}}. -%% ----------------------------------------------------------------------------- - -%% This function retrieves the trace-log part of a TracerData list structure. -%% Returns TraceLogTD or 'false'. -get_trace_log_tracerdata(TracerData) -> - case lists:keysearch(trace,1,TracerData) of - {value,{_,LogTD}} -> - LogTD; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -%% This function retrieves the ti-log part of a TracerData list structure. -%% Returns TiLogTD or 'false'. -get_ti_log_tracerdata(TracerData) -> - case lists:keysearch(ti,1,TracerData) of - {value,{_,TiTD}} -> - TiTD; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -%% Help function which checks that parameters to the built in trace-port are -%% sane. -check_traceport_parameters(Type,Args) -> - case {Type,Args} of - {file,{FileName,wrap,Tail}} when is_list(FileName),is_list(Tail) -> - ok; - {file,{FileName,wrap,Tail,WrapSize}} - when is_list(FileName), - is_list(Tail), - is_integer(WrapSize),WrapSize>=0,WrapSize< (1 bsl 32) -> - ok; - {file,{FileName,wrap,Tail,WrapSize,WrapCnt}} - when is_list(FileName),is_list(Tail), - is_integer(WrapSize), WrapSize >= 0, WrapSize < (1 bsl 32), - is_integer(WrapCnt), WrapCnt >= 1, WrapCnt < (1 bsl 32) -> - ok; - {file,{FileName,wrap,Tail,{time,WrapTime},WrapCnt}} - when is_list(FileName),is_list(Tail), - is_integer(WrapTime), WrapTime >= 1, WrapTime < (1 bsl 32), - is_integer(WrapCnt), WrapCnt >= 1, WrapCnt < (1 bsl 32) -> - ok; - {file,FileName} when is_list(FileName) -> - ok; - {ip,Portno} when is_integer(Portno),Portno=<16#FFFF -> - ok; - {ip,{Portno,Qsiz}} when is_integer(Portno),Portno=<16#FFFF,is_integer(Qsiz) -> - ok; - _ -> - {error,{trace_port_args,[Type,Args]}} - end. -%% ----------------------------------------------------------------------------- - - -%% ----------------------------------------------------------------------------- -%% Default overload functionality. -%% ----------------------------------------------------------------------------- - -%% A default overload protection function. An overload function must take -%% one argument and return 'ok' or {suspend,SuspendReason}. -default_overload_func(_) -> - case process_info(self(),message_queue_len) of - {message_queue_len,N} when N > 1000 -> - {suspend,rt_max_queue_len}; - _ -> - ok - end. -%% ----------------------------------------------------------------------------- - -%% ============================================================================= -%% Functions working on the internal loopdata structure. -%% ============================================================================= - -%% Help function simply adding Fetcher as a fetcher process to the loopdata. -%% Returns a new loopdata structure. -add_fetcher_ld(Fetcher,LD) -> - LD#rt{fetchers=[Fetcher|LD#rt.fetchers]}. -%% ----------------------------------------------------------------------------- - -%% Help function investigating if the first argument is a known fetcher process -%% or not. If it is, it also removed it from the fetchers list in the loopdata -%% structure. -%% Returns {true,NewLoopData} or 'false'. -remove_fetcher_ld(Fetcher,LD) -> - NewFetchers=lists:delete(Fetcher,LD#rt.fetchers), - if - NewFetchers/=LD#rt.fetchers -> - {true,LD#rt{fetchers=NewFetchers}}; - true -> % No it was not a fetcher process. - false - end. -%% ----------------------------------------------------------------------------- - -%%% end of file - diff --git a/lib/runtime_tools/src/inviso_rt_lib.erl b/lib/runtime_tools/src/inviso_rt_lib.erl deleted file mode 100644 index 5dfe14068a..0000000000 --- a/lib/runtime_tools/src/inviso_rt_lib.erl +++ /dev/null @@ -1,474 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% ------------------------------------------------------------------------------ -%% File : inviso_rt_lib.erl -%% Author : Lennart �hman <[email protected]> -%% Description : -%% -%% Created : 27 Sep 2005 by Lennart �hman <[email protected]> -%% ------------------------------------------------------------------------------ --module(inviso_rt_lib). - --export([expand_regexp/2,expand_regexp/3,expand_regexp/4]). --export([is_tracerdata/1]). --export([transform/2]). - --export([rpc/4,rpc/5,match_modules/2,match_modules/3]). --export([debug/3]). - -%% ------------------------------------------------------------------------------ - -%% ============================================================================== -%% Exported API functions. -%% ============================================================================== - -%% ------------------------------------------------------------------------------ -%% expand_regexp(Nodes,RegExpDir,RegExpMod,Opts) = [{Node,Answer},...] | {error,Reason} -%% expand_regexp(Nodes,RegExpMod,Opts) = [{Node,Answer},...] | {error,Reason} -%% expand_regexp(RegExpDir,RegExpMod,Opts) = ListOfModules | {error,Reason} -%% expand_regexp(RegExpMod,Opts) = ListOfModules | {error,Reason} -%% Nodes=List of all nodes (atoms) where to expand. -%% RegExpDir=Reg.exp (string) specifying directories. -%% RegExpMod=Reg.exp (string) specifying module names. -%% Node=node name (atom). -%% Opts=[Opt,...] -%% Opt=only_loaded -%% Answer=List of modules (atoms) | 'badrpc' -%% -%% Expands, concurrently, the regular expression on Nodes and returns a list -%% of what modules it expanded to on the different nodes. Note that it may -%% differ between Erlang nodes depending on whether the modules are the same -%% or not. Also note that all modules becomes loaded as a result. -%% RegExpDir can further limit the modules. It introduces the requirement that -%% a module must be loaded from a directory with a path satisfying the RegExpDir. -%% All regular expression are according to the standard lib regexp module. -expand_regexp(RegExpMod,Opts) when is_list(RegExpMod),is_list(Opts) -> - match_modules(RegExpMod,Opts); -expand_regexp(RegExpMod,Opts) -> - {error,{badarg,[RegExpMod,Opts]}}. -expand_regexp(NodesOrRegExpDir,RegExpMod,Opts) - when is_list(NodesOrRegExpDir),is_list(RegExpMod),is_list(Opts) -> - case is_list_of_atoms(NodesOrRegExpDir) of - true -> % Interpret as list of nodes. - lists:foreach(fun(N)->spawn(?MODULE,rpc,[self(),N,RegExpMod,Opts]) end, - NodesOrRegExpDir), - expand_regexp_answers(NodesOrRegExpDir,[]); - false -> % Interpret as a string. - match_modules(NodesOrRegExpDir,RegExpMod,Opts) - end; -expand_regexp(NodesOrRegExpDir,RegExpMod,Opts) -> - {error,{badarg,[NodesOrRegExpDir,RegExpMod,Opts]}}. -expand_regexp(Nodes,RegExpDir,RegExpMod,Opts) - when is_list(Nodes),is_list(RegExpDir),is_list(RegExpMod),is_list(Opts) -> - lists:foreach(fun(N)-> - spawn(?MODULE,rpc,[self(),N,RegExpDir,RegExpMod,Opts]) - end, - Nodes), - expand_regexp_answers(Nodes,[]); -expand_regexp(Nodes,RegExpDir,RegExpMod,Opts) -> - {error,{badarg,[Nodes,RegExpDir,RegExpMod,Opts]}}. - -expand_regexp_answers([],Answers) -> Answers; % List of [{Node,Answer},...]. -expand_regexp_answers(Nodes,Answers) -> - receive - {?MODULE,Node,Answer} -> - expand_regexp_answers(lists:delete(Node,Nodes),[{Node,Answer}|Answers]) - end. -%% ------------------------------------------------------------------------------ - -%% is_tracerdata(TracerData)=true|false -%% Answers the question if TracerData is proper tracerdata. Note that true can be -%% returned if it resembles tracerdata very closely. -is_tracerdata({Fun,_Data}) when is_function(Fun) -> true; -is_tracerdata({relayer,To}) when is_pid(To);is_atom(To) -> true; -is_tracerdata(collector) -> true; -is_tracerdata({file,Param}) when is_tuple(Param);is_list(Param) -> true; -is_tracerdata({ip,_Param}) -> true; -is_tracerdata([{trace,LogTD}|Rest]) -> - case is_tracerdata(LogTD) of - true -> - is_tracerdata(Rest); - false -> - false - end; -is_tracerdata([{ti,TiData}|Rest]) -> - case is_tidata(TiData) of - true -> - is_tracerdata(Rest); - false -> - false - end; -is_tracerdata([]) -> - true; -is_tracerdata(_) -> - false. - -is_tidata({file,FileName}) when is_list(FileName) -> true; -is_tidata({file,FileName,{M,F,Args}}) when is_list(FileName),is_atom(M),is_atom(F),is_list(Args) -> - true; -is_tidata(_) -> false. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% Help functions. -%% ============================================================================== - -%% Help function intended to be run in its own process. Will report with -%% a message when done. -%% This function will be spawned on. -rpc(Parent,Node,RegExpMod,Opts) -> - case rpc:call(Node,?MODULE,match_modules,[RegExpMod,Opts]) of - {badrpc,_Reason} -> % The node is probably not healthy. - Parent ! {?MODULE,Node,badrpc}; - Modules -> - Parent ! {?MODULE,Node,Modules} - end. - -rpc(Parent,Node,RegExpDir,RegExpMod,Opts) -> - case rpc:call(Node,?MODULE,match_modules,[RegExpDir,RegExpMod,Opts]) of - {badrpc,_Reason} -> % The node is probably not healthy. - Parent ! {?MODULE,Node,badrpc}; - Modules -> - Parent ! {?MODULE,Node,Modules} - end. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% Exported function which actually shall be in code.erl. -%% ============================================================================== - -%% match_modules(RegExpMod,Actions) = [Module,...] | {error,Reason} -%% match_modules(RegExpDir,RegExpMod,Actions)=[Module,...] | {error,Reason} -%% RegExpMod=Erlang regular expression describing module names (string). -%% RegExpDir=Erlang regular expression describing directory paths(string) | -%% void -%% Actions=List of;'only_loaded'. -%% -%% Function which matches a regular expresion against module names. The function -%% can also match the directory from where the module is loaded or will be loaded -%% against a regular expresion for directory paths. -%% The function uses the same strategy as code-loading if the same module is -%% discovered in several places. -%% (1) An already loaded module shadows all other occurancies. -%% (2) .beams found in by a path shadows .beams found by paths later in the -%% code paths. -%% -%% Description of actions: -%% only_loaded: Only consider modules which are loaded. -match_modules(RegExpMod,Actions) -> - match_modules(void,RegExpMod,Actions). -match_modules(RegExpDir,RegExpMod,Actions) -> - AllLoaded=code:all_loaded(), - Mods1=handle_expand_regexp_2(AllLoaded,RegExpDir,RegExpMod,[]), - case lists:member(only_loaded,Actions) of % Shall we do not loaded too? - false -> % Ok, search all paths too then. - Paths=code:get_path(), - handle_expand_regexp_3(Paths,RegExpDir,RegExpMod,AllLoaded,Mods1); - true -> % Only loaded modules then. - Mods1 - end. - - -%% Help function which traverses all loaded modules and determines -%% which shall be returned. First we check that the module satisfies the -%% module-regexp. Then we, if a dir reg-exp is given, checks that the -%% module is loaded from an approved path. Note that if it can not be -%% determined from where it was loaded (like preloaded or cover-compiled -%% etc), but dir reg-exps are used. That module will be excluded. -%% Returns a list of modules. -handle_expand_regexp_2([{Mod,Path}|Rest],RegExpDir,RegExpMod,Result) -> - ModStr=atom_to_list(Mod), - ModLen=length(ModStr), - case re:run(ModStr,RegExpMod) of - {match,[{0,ModLen}]} -> % Ok, The regexp matches the module. - if - is_list(RegExpDir),is_atom(Path) -> % Preloaded or covercompiled... - handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,Result); - is_list(RegExpDir),is_list(Path) -> % Dir reg-exp is used! - PathOnly=filename:dirname(Path), % Must remove beam-file name. - case re:run(PathOnly,RegExpDir,[{capture,none}]) of - match -> % Did find a match, that is enough! - handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,[Mod|Result]); - _ -> % Either error or nomatch. - handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,Result) - end; - true -> % Otherwise already done! - handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,[Mod|Result]) - end; - _ -> % Then Mod is not part of the set. - handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,Result) - end; -handle_expand_regexp_2([],_,_,Result) -> Result. - -%% Help function which traverses all paths and looks for modules satisfying -%% the module reg.exp. -%% Returns a list of unique module names. -handle_expand_regexp_3([Path|Rest],RegExpDir,RegExpMod,AllLoaded,Result) -> - if - is_list(RegExpDir) -> % We must consider the directory name. - AbsPath= - case filename:pathtype(Path) of - absolute -> % Is already abs. - Path; - relative -> % Then it must be made absolute. - filename:absname(Path); - volumerelative -> % Only on Windows!? - filename:absname(Path) - end, - case re:run(AbsPath,RegExpDir,[{capture,none}]) of - match -> % Ok, the directory is allowed. - NewResult=handle_expand_regexp_3_1(Path,RegExpMod,AllLoaded,Result), - handle_expand_regexp_3(Rest,RegExpDir,RegExpMod,AllLoaded,NewResult); - _ -> % This directory does not qualify. - handle_expand_regexp_3(Rest,RegExpDir,RegExpMod,AllLoaded,Result) - end; - true -> % RegExpDir is not used! - NewResult=handle_expand_regexp_3_1(Path,RegExpMod,AllLoaded,Result), - handle_expand_regexp_3(Rest,RegExpDir,RegExpMod,AllLoaded,NewResult) - end; -handle_expand_regexp_3([],_,_,_,Result) -> Result. - -handle_expand_regexp_3_1(Path,RegExpMod,AllLoaded,Result) -> - case file:list_dir(Path) of - {ok,FileNames} -> - handle_expand_regexp_3_2(FileNames,RegExpMod,AllLoaded,Result); - {error,_Reason} -> % Bad path!? Skip it. - Result - end. - -handle_expand_regexp_3_2([File|Rest],RegExpMod,AllLoaded,Result) -> - case filename:extension(File) of - ".beam" -> % It is a beam-file. Consider it! - ModStr=filename:basename(File,".beam"), - Mod=list_to_atom(ModStr), - case {lists:keysearch(Mod,1,AllLoaded),lists:member(Mod,Result)} of - {false,false} -> % This module is not tried before. - ModLen=length(ModStr), - case re:run(ModStr,RegExpMod) of - {match,[{0,ModLen}]} -> % This module satisfies the regexp. - handle_expand_regexp_3_2(Rest,RegExpMod,AllLoaded,[Mod|Result]); - _ -> % Error or not perfect match. - handle_expand_regexp_3_2(Rest,RegExpMod,AllLoaded,Result) - end; - {_,_} -> % This module is already tested. - handle_expand_regexp_3_2(Rest,RegExpMod,AllLoaded,Result) - end; - _ -> % Not a beam-file, skip it. - handle_expand_regexp_3_2(Rest,RegExpMod,AllLoaded,Result) - end; -handle_expand_regexp_3_2([],_,_,Result) -> Result. -%% ------------------------------------------------------------------------------ - -%% Help function which finds out if its argument is a list of zero or more -%% atoms. -%% Returns 'true' or 'false'. -is_list_of_atoms([A|Rest]) when is_atom(A) -> - is_list_of_atoms(Rest); -is_list_of_atoms([_|_]) -> - false; -is_list_of_atoms([]) -> - true. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================= -%% Functions transforming function calls in trace-case file. -%% ============================================================================= - -%% transform(Exprs,Translations)=NewExprs -%% Exprs=list(); List of abstract format erlang terms, as returned by -%% io:parse_erl_exprs/2. -%% Translations=list(); List of translations from function calls to other -%% function calls. [{Mod,Func,Arity,{NewMod,NewFunc,ParamTransformMF}},...] -%% Mod can actually be omitted, ParamTransformMF shall be {M,F} where F is -%% a function taking one argument (the parameter list), and returning the -%% new parameter list. It can also be anything else should no transformation -%% of the parameters be the case. -%% -%% Function that transforms function calls in a trace-case file. The transform/2 -%% can only transform shallow function calls. I.e where both module and function -%% name are specified as atoms. Any binding-environment is not examined. -transform([Expr|Rest],Translations) -> - [transform_2(Expr,Translations)|transform(Rest,Translations)]; -transform([],_) -> - []. - -%% Help function handling a single expr. -transform_2({call,L1,{remote,L2,ModExpr,FuncExpr},Params},Translations) -> - case transform_2(ModExpr,Translations) of - {atom,L3,M} -> - case transform_2(FuncExpr,Translations) of - {atom,L4,F} -> % Now we have a M:F/Arity! - case do_call_translation(M,F,Params,Translations) of - {ok,NewM,NewF,NewP} -> - NewParams=transform(NewP,Translations), - {call,L1,{remote,L2,{atom,L3,NewM},{atom,L4,NewF}},NewParams}; - false -> % No translation or faulty. - NewParams=transform(Params,Translations), - {call,L1,{remote,L2,ModExpr,FuncExpr},NewParams} - end; - NewFuncExpr -> % Not translated to a shallow term. - NewParams=transform(Params,Translations), - {call,L1,{remote,L2,ModExpr,NewFuncExpr},NewParams} - end; - NewModExpr -> % Not translated to a shallow term. - NewFuncExpr=transform_2(FuncExpr,Translations), - NewParams=transform(Params,Translations), - {call,L1,{remote,L2,NewModExpr,NewFuncExpr},NewParams} - end; -transform_2({call,L1,FuncExpr,Params},Translations) -> - case transform_2(FuncExpr,Translations) of - {atom,L3,F} -> % Now we have a M:F/Arity! - case do_call_translation(F,Params,Translations) of - {ok,NewM,NewF,NewP} -> % It is turned into a global call. - NewParams=transform(NewP,Translations), - {call,L1,{remote,L1,{atom,L3,NewM},{atom,L3,NewF}},NewParams}; - false -> % No translation or faulty. - NewParams=transform(Params,Translations), - {call,L1,FuncExpr,NewParams} - end; - NewFuncExpr -> % Not translated to a shallow term. - NewParams=transform(Params,Translations), - {call,L1,NewFuncExpr,NewParams} - end; -transform_2({match,L,P,E},Translations) -> - NewPattern=transform_2(P,Translations), - NewExpr=transform_2(E,Translations), - {match,L,NewPattern,NewExpr}; -transform_2({op,L,Op,Arg1,Arg2},Translations) -> - NewArg1=transform_2(Arg1,Translations), - NewArg2=transform_2(Arg2,Translations), - {op,L,Op,NewArg1,NewArg2}; -transform_2({op,L,Op,Arg},Translations) -> - NewArg=transform_2(Arg,Translations), - {op,L,Op,NewArg}; -transform_2({block,L,Body},Translations) -> - NewBody=transform(Body,Translations), - {block,L,NewBody}; -transform_2({'if',L,Clauses},Translations) -> - NewClauses=transform_clauses(Clauses,Translations), - {'if',L,NewClauses}; -transform_2({'case',L,Func,Clauses},Translations) -> - NewFunc=transform_2(Func,Translations), - NewClauses=transform_clauses(Clauses,Translations), - {'case',L,NewFunc,NewClauses}; -transform_2({'fun',L,{clauses,Clauses}},Translations) -> - NewClauses=transform_clauses(Clauses,Translations), - {'fun',L,NewClauses}; -transform_2({lc,L,Items,GeneratorsFilters},Translations) -> - NewItem=transform_2(Items,Translations), - NewGensAndFilters=transform_gensandfilters(GeneratorsFilters,Translations), - {lc,L,NewItem,NewGensAndFilters}; -transform_2({'catch',L,Expr},Translations) -> - NewExpr=transform_2(Expr,Translations), - {'catch',L,NewExpr}; -transform_2({tuple,L,Elements},Translations) -> - NewElements=transform(Elements,Translations), - {tuple,L,NewElements}; -transform_2({cons,L,Element,Tail},Translations) -> - NewElement=transform_2(Element,Translations), - NewTail=transform_2(Tail,Translations), - {cons,L,NewElement,NewTail}; -transform_2({nil,L},_) -> - {nil,L}; -transform_2({bin,L,Elements},Translations) -> - NewElements=transform_binary(Elements,Translations), - {bin,L,NewElements}; -transform_2(Expr,_) -> % Can be a var for instance. - Expr. - -transform_binary([{bin_element,L,Val,Size,TSL}|Rest],Translations) -> - NewVal=transform_2(Val,Translations), - NewSize=transform_2(Size,Translations), - [{bin_element,L,NewVal,NewSize,TSL}|transform_binary(Rest,Translations)]; -transform_binary([],_) -> - []. - -transform_clauses([{clause,L,Pattern,Guards,Body}|Rest],Translations) -> - NewPattern=transform(Pattern,Translations), - NewBody=transform(Body,Translations), - [{clause,L,NewPattern,Guards,NewBody}|transform_clauses(Rest,Translations)]; -transform_clauses([],_Translations) -> - []. - -transform_gensandfilters([{generator,L,Pattern,Exprs}|Rest],Translations) -> - NewExprs=transform(Exprs,Translations), - [{generator,L,Pattern,NewExprs}|transform_gensandfilters(Rest,Translations)]; -transform_gensandfilters([Expr|Rest],Translations) -> - [transform_2(Expr,Translations)|transform_gensandfilters(Rest,Translations)]; -transform_gensandfilters([],_) -> - []. -%% ------------------------------------------------------------------------------ - -%% This is the heart of the translation functionality. Here we actually try to -%% replace calls to certain functions with other calls. This can include removing -%% arguments. -do_call_translation(M,F,Params,Translations) -> - case lists:keysearch({M,F,length(Params)},1,Translations) of - {value,{_,{NewM,NewF,ArgFun}}} -> % Lets transform the function. - do_call_translation_2(Params,NewM,NewF,ArgFun); - _ -> - false % No translations at all. - end. -do_call_translation(F,Params,Translations) -> - case lists:keysearch({F,length(Params)},1,Translations) of - {value,{_,{NewM,NewF,ArgFun}}} -> % Lets transform the function. - do_call_translation_2(Params,NewM,NewF,ArgFun); - _ -> - false % No translations at all. - end. - -do_call_translation_2(Params,NewM,NewF,ArgFun) -> - case ArgFun of - {M,F} when is_atom(M),is_atom(F) -> - case catch M:F(Params) of - {'EXIT',_Reason} -> - false; % If it does not work, skipp it. - MungedParams when is_list(MungedParams) -> - {ok,NewM,NewF,MungedParams}; - _ -> - false - end; - _ -> % No munging of parameters. - {ok,NewM,NewF,Params} - end. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================= -%% Functions for the runtime component internal debugging system. -%% ============================================================================= - -%% The debug system is meant to provide tracing of ttb at different levels. -%% -%% debug(What,Level,Description) -> nothing significant. -%% What : controls what kind of event. This can both be certain parts of ttb -%% as well as certain levels (info to catastrophy). -%% Level: Determines if What shall be printed or not. -%% Description: this is what happend. -debug(off,_What,_Description) -> - true; % Debug is off, no action. -debug(On,What,Description) -> - debug_2(On,What,Description). - -debug_2(_,What,Description) -> - io:format("INVISO DEBUG:~w, ~p~n",[What,Description]). -%% ----------------------------------------------------------------------------- diff --git a/lib/runtime_tools/src/inviso_rt_meta.erl b/lib/runtime_tools/src/inviso_rt_meta.erl deleted file mode 100644 index 6865dc2242..0000000000 --- a/lib/runtime_tools/src/inviso_rt_meta.erl +++ /dev/null @@ -1,1207 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Author: Lennart �hman, [email protected] -%% -%% This module implements the meta tracer process belonging to the -%% runtime component. Its main purpose is to write the ti-file (traceinformation). -%% The ti-file contains translations between process id:s and what ever "you" -%% want to read in the merged and formatted logfile. -%% This process interacts with the runtime component process. -%% -%% Currently it handles the following types of ti-files: -%% Plain raw, binary log. -%% Relay to other inviso_rt_meta process on another node. -%% -%% The TI file will be on binary format and each entry is: -%% <<LengthIndicator:32, {Pid,Alias,Op,NowStamp} >> -%% Pid=pid(), or if OP==unalias pid()|any_other_than_pid() -%% Op=alias|unalias -%% ----------------------------------------------------------------------------- --module(inviso_rt_meta). - -%% ----------------------------------------------------------------------------- -%% API exports. -%% ----------------------------------------------------------------------------- - --export([start/2,start/5]). --export([stop/1,suspend/1]). --export([init_tpm/5,init_tpm/8]). --export([tpm/5,tpm/6,tpm/9,tpm_tracer/5,tpm_tracer/6,tpm_tracer/9]). --export([tpm_ms/6,tpm_ms_tracer/6,ctpm_ms/5,ctpm/4]). --export([local_register/1,global_register/1]). --export([remove_local_register/1,remove_global_register/1]). - --export([write_ti/1]). - --export([get_tracer/0,tpm_ms/5,tpm_ms_tracer/5,list_tpm_ms/3,ctpm_ms/4]). - --export([metacast_call/5,metacast_return_from/6]). --export([get_state/1]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Internal exports. -%% ----------------------------------------------------------------------------- - --export([init/6]). --export([init_std_publld/2,clean_std_publld/1]). -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Constants. -%% ----------------------------------------------------------------------------- - --define(NAMED_MS_TAB,inviso_rt_meta_named_ms). - -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% Exported API (Meant to be used by a runtime component). -%% ============================================================================= - -%% start(TiData,Tracer)={ok,Pid} | {error,Reason} -%% start(TiData,Tracer,InitPublLDmfa,RemovePublLDmfa,CleanPublLDmf)= -%% {ok,Pid} | {error,Reason} -%% TiData={file,FileName}|{relay,Node} -%% Tracer=pid()|port() -%% FileName=string() -%% InitPublLDmfa={Mod,Func,ArgList} -%% RemovePublLDmf={Mod,Func} | void -%% RemovePublLDmf(PublLD)->nothing significant. -%% These functions are called to create and destroy the public loopdata -%% structure available to the meta-trace CallFunc and ReturnFunc. -%% CleanPublLDmf={Mod,Func} -%% This function will periodically be called to clean the public LD from -%% pending meta-trace messages waiting for a corresponding return_from -%% message. -%% -%% Starts a meta-tracer process, opening the ti-file specified in TiData. PublLD -%% is used to communicate data, typically between a call and return_from. -%% If no special initialization function is specified a standard one is used. -%% Note that the meta tracer function must know "who" is the regular tracer -%% (process or port). This because it must be possible to append {tracer,Tracer} -%% in meta match specs. -start(TiData,Tracer) -> - Pid=spawn_link(?MODULE, - init, - [self(), - TiData, - Tracer, - {?MODULE,init_std_publld,[2,[]]}, - void, - {?MODULE,clean_std_publld}]), - wait_for_reply(Pid). -start(TiData,Tracer,InitPublLDmfa,RemovePublLDmf,CleanPublLDmf) -> - Pid=spawn_link(?MODULE, - init, - [self(),TiData,Tracer,InitPublLDmfa,RemovePublLDmf,CleanPublLDmf]), - wait_for_reply(Pid). - -wait_for_reply(Pid) -> - receive - {Pid,ok} -> - {ok,Pid}; - {Pid,{error,Reason}} -> - {error,Reason} - after - 10000 -> % After very long time. - exit(Pid,kill), % It must be hanging. - {error,time_out} - end. -%% ----------------------------------------------------------------------------- - -%% stop(Pid)=ok -%% Pid=Adders to the meta tracer, pid(). -%% Shutsdown the metatracer. -stop(Pid) -> - Pid ! {stop,self()}, - ok. -%% ----------------------------------------------------------------------------- - -%% suspend(Pid)=ok -%% Pid=Adders to the meta tracer, pid(). -%% Suspends the meta tracer by removing all meta trace patterns. -suspend(Pid) -> - Pid ! {suspend,self()}, - ok. -%% ----------------------------------------------------------------------------- - -%% init_tpm(Pid,Mod,Func,Arity,CallFunc)= -%% init_tpm(Pid,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=ok|{error,Reason}. -%% Pid=Address to meta tracer process, pid(). -%% Mod,Func=Pointing out the function which shall be meta traced, atom(). -%% Arity=As above, integer(). -%% InitFunc,RemoveFunc={Module,Function}|fun(), functions being called when -%% to initialize the public loopdata structure, and to reset it. -%% InitFunc(Mod,Func,Arity,PublLD)->{ok,NewPublLD,Output} -%% Supposed to initialize whatever needs to be done before -%% handling any incoming meta-trace message for the Mod:Func/Arity. -%% RemoveFunc(Mod,Func,Arity,PublLD)->{ok,NewPublLD} -%% Called when meta tracing of Mod:Func/Arity is stopped. It is supposed -%% to clear datastructures away from the PublLD. -%% Initializes the public loopdata for this function. Note that we can not use wildcards -%% here (even if it is perfectly legal in Erlang). It also sets the CallFunc and -%% ReturnFunc for the meta traced function. The function is hence ready to be -%% meta traced with either tpm/5 or tpm_ms/5. -%% This function is synchronous, waiting for a reply from the meta server. -init_tpm(Pid,Mod,Func,Arity,CallFunc) -> - init_tpm(Pid,Mod,Func,Arity,void,CallFunc,void,void). -init_tpm(Pid,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) -> - send_wait(Pid, - {init_tpm,{Mod,Func,Arity},InitFunc,CallFunc,ReturnFunc,RemoveFunc}). -%% ----------------------------------------------------------------------------- - -%% tpm(Pid,Mod,Func,Arity,MatchSpec)={ok,N}|{error,Reason} -%% tpm(Pid,Mod,Func,Arity,MatchSpec,CallFunc)={ok,N}|{error,Reason} -%% tpm(Pid,Mod,Func,Arity,MatchSpec,InitFunc,CallFunc,ReturnFunc,RemoveFunc)= -%% Pid=Address to meta tracer process, pid(). -%% Mod,Func=Pointing out the function which shall be meta traced, atom(). -%% Arity=As above, integer(). -%% MatchSpec=List of match specification, possibly empty. Remember {return_trace} -%% if expecting return_from messages. -%% InitFunc,CallFunc,ReturnFunc,RemoveFunc={Module,Function}|fun(), -%% functions being called when these functions are called by the meta trace -%% server at certain events. -%% CallFunc(CallingPid,ActualArgList,PublLD)->{ok,NewPrivLD,Output} -%% ReturnFunc(CallingPid,ReturnValue,PublLD)->{ok,NewPrivLD,Output} -%% When a call respectively return_from trace message arrives for the meta -%% traced function, the corresponding function is called. -%% The ReturnFunc must handle the fact that a return_from message arrives -%% for a call which was never noticed. This because the message queue of the -%% meta tracer may have been emptied. -%% Reason=badarg | -%% Output=Characters to be written to the ti-file, bin() | 'void' -%% The tpm/5 function simply starts meta tracing for the function. It must -%% previously have been initialized. -%% tpm/6 & /9 initializes the function and starts meta tracing. -tpm(Pid,Mod,Func,Arity,MatchSpec) - when is_atom(Mod),is_atom(Func),is_integer(Arity),is_list(MatchSpec),Mod/='_',Func/='_'-> - send_wait(Pid,{tpm,{Mod,Func,Arity,MatchSpec}}); -tpm(_,_,_,_,_) -> - {error,badarg}. - -tpm(Pid,Mod,Func,Arity,MatchSpec,CallFunc) -> - tpm(Pid,Mod,Func,Arity,MatchSpec,void,CallFunc,void,void). - -tpm(Pid,Mod,Func,Arity,MatchSpec,InitFunc,CallFunc,ReturnFunc,RemoveFunc) - when is_atom(Mod),is_atom(Func),is_integer(Arity),is_list(MatchSpec),Mod/='_',Func/='_' -> - send_wait(Pid,{tpm,{Mod,Func,Arity,MatchSpec},InitFunc,CallFunc,ReturnFunc,RemoveFunc}); -tpm(_,_,_,_,_,_,_,_,_) -> - {error,badarg}. -%% ----------------------------------------------------------------------------- - -%% Same as tpm/X but the meta tracer will automatically append {tracer,Tracer} -%% to the enable list in a {trace,Disable,Enable} match spec action term. -tpm_tracer(Pid,Mod,Func,Arity,MatchSpec) - when is_atom(Mod),is_atom(Func),is_integer(Arity),is_list(MatchSpec),Mod/='_',Func/='_'-> - send_wait(Pid,{tpm_tracer,{Mod,Func,Arity,MatchSpec}}); -tpm_tracer(_,_,_,_,_) -> - {error,badarg}. - -tpm_tracer(Pid,Mod,Func,Arity,MatchSpec,CallFunc) -> - tpm_tracer(Pid,Mod,Func,Arity,MatchSpec,void,CallFunc,void,void). - -tpm_tracer(Pid,Mod,Func,Arity,MatchSpec,InitFunc,CallFunc,ReturnFunc,RemoveFunc) - when is_atom(Mod),is_atom(Func),is_integer(Arity),is_list(MatchSpec),Mod/='_',Func/='_' -> - send_wait(Pid,{tpm_tracer, - {Mod,Func,Arity,MatchSpec}, - InitFunc,CallFunc,ReturnFunc,RemoveFunc}); -tpm_tracer(_,_,_,_,_,_,_,_,_) -> - {error,badarg}. -%% ----------------------------------------------------------------------------- - -%% tpm_ms(Pid,Mod,Func,Arity,MSname,MS)={ok,N}|{error,Reason} -%% Pid=Address to meta tracer process, pid(). -%% Mod,Func=Pointing out the function to which we shall add a match-spec., atom(). -%% Arity=As above, integer(). -%% MSname=A name to be used if this MS shall be removed later. term(). -%% MatchSpec=List of match specification, Remember {return_trace} -%% if expecting return_from messages. -%% This function adds a list of match-specs to the already existing ones. It -%% uses an internal database to keep track of existing match-specs. If the -%% match-spec does not result in any meta traced functions (for whatever reason), -%% the MS is not saved in the database. The previously known match-specs are -%% not removed. -tpm_ms(Pid,Mod,Func,Arity,MSname,MS) -> - send_wait(Pid,{tpm_ms,{Mod,Func,Arity},MSname,MS}). -%% ----------------------------------------------------------------------------- - -%% Same as tpm_ms/6 but the meta tracer will automatically append {tracer,Tracer} -%% to the enable list in a {trace,Disable,Enable} match spec action term. -tpm_ms_tracer(Pid,Mod,Func,Arity,MSname,MS) -> - send_wait(Pid,{tpm_ms_tracer,{Mod,Func,Arity},MSname,MS}). -%% ----------------------------------------------------------------------------- - -%% ctpm_ms(Pid,Mod,Func,Arity)=ok -%% -%% Removes a names match-spec from the meta traced function. Note that is never -%% a fault to remove an MS. Not even from a function which is non existant. -ctpm_ms(Pid,Mod,Func,Arity,MSname) -> - send_wait(Pid,{ctpm_ms,{Mod,Func,Arity},MSname}). -%% ----------------------------------------------------------------------------- - -%% Quick versions for erlang:register/2 which also uses a default CallFunc -%% and a default ReturnFunc. -local_register(Pid) -> - Res1=tpm(Pid, - erlang,register,2,[{'_',[],[{exception_trace}]}], - fun metafunc_init/4,fun local_register_call/3, - fun local_register_return/3,void), - Res2=tpm(Pid, - erlang,unregister,1,[], - void,fun local_unregister_call/3,void,void), - {Res1,Res2}. -%% ----------------------------------------------------------------------------- - -%% Quick version for global:register_name/2, /3. -global_register(Pid) -> - Res1=tpm(Pid,global,handle_call,3,[{[{register,'_','_','_'},'_','_'],[],[]}], - void,fun global_register_call/3,void,void), - Res2=tpm(Pid,global,delete_global_name,2,[], - void,fun global_unregister_call/3,void,void), - {Res1,Res2}. -%% ----------------------------------------------------------------------------- - -%% ctpm(Pid,Mod,Func,Arity)=ok|{error,bad_mfa} -%% -%% Removes the meta trace pattern for the function, means stops generating output -%% for this function. The public LD may be cleared by the previously entered -%% RemoveFunc. -ctpm(Pid,Mod,Func,Arity) -> - send_wait(Pid,{ctpm,{Mod,Func,Arity}}). -%% ----------------------------------------------------------------------------- - -%% remove_local_register(Pid)={Res1,Res2} -%% Res1,Res2=ok|{error,Reason} -remove_local_register(Pid) -> - Res1=ctpm(Pid,erlang,register,2), - Res2=ctpm(Pid,erlang,unregister,1), - {Res1,Res2}. -%% ----------------------------------------------------------------------------- - -%% remove_global_register(Pid)={Res1,Res2} -%% Res1,Res2=ok|{error,Reason} -remove_global_register(Pid) -> - Res1=ctpm(Pid,global,handle_call,3), - Res2=ctpm(Pid,global,delete_global_name,2), - {Res1,Res2}. -%% ----------------------------------------------------------------------------- - -%% Exported help functions which may be used in programming CallFunc and/or -%% ReturnFunc. Useful if the call is done on one node but must trigger the -%% start of something at other nodes. -metacast_call(Nodes,OrigPid,M,F,Args) -> - multicast(Nodes,{trace_ts,OrigPid,call,{M,F,Args},void}), - ok. - -metacast_return_from(Nodes,OrigPid,M,F,Arity,Value) -> - multicast(Nodes,{trace_ts,OrigPid,return_from,{M,F,Arity},Value,void}), - ok. - -multicast([Node|Rest],Msg) -> - {?MODULE,Node} ! Msg, - multicast(Rest,Msg); -multicast([],_) -> - true. -%% ----------------------------------------------------------------------------- - -%% get_states(Pid)={ok,LD,PubLD}. -get_state(Pid) -> - send_wait(Pid,get_state). -%% ----------------------------------------------------------------------------- - - -send_wait(To,Msg) -> - Ref=make_ref(), - MRef=erlang:monitor(process,To), - To ! {Msg,Ref,self()}, - receive - {inviso_rt_meta_reply,Ref,Reply} -> - erlang:demonitor(MRef), - Reply; - {'DOWN',MRef,_,_To,_Reason} -> - {error,no_metatracer} - end. - -reply(To,Ref,Reply) -> - To ! {inviso_rt_meta_reply,Ref,Reply}. -%% ----------------------------------------------------------------------------- - -%% ============================================================================= -%% Special API. -%% ============================================================================= - -%% write_ti(OutPut)= -%% OutPut=binary() -%% Makes an extra entry into the trace information file (ti-file). This is useful -%% if a pid-alias association is learned in another way than through a meta traced -%% function call. Note that this API can only be used locally at the node in -%% question. -write_ti(OutPut) -> - catch ?MODULE ! {write_ti,OutPut}. -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% API intended to be used on CallFuncs and RemoveFuncs. -%% ============================================================================= - -%% The reason there must be a special API for CallFuncs and RemoveFuncs are is -%% that those functions are executed inside *this* process context. Hence they -%% can not make function calls requiering this process to receive messages. - -%% Returns the tracer used for regular tracing. The reason this is implemented -%% in this way is that this function is intended to be used in meta trace call- -%% back functions. And there we can not have message passing API:s to the meta -%% trace(!). -get_tracer() -> - get(tracer). -%% ----------------------------------------------------------------------------- - -%% Function equivalent to inviso_rt:tpm_ms/6. This function can *only* be used -%% inside a CallFunc or a RemoveFunc. -tpm_ms(Mod,Func,Arity,MSname,MS) -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - {ok,h_tpm_ms(Mod,Func,Arity,MSname,MS)}; - no -> - {error,not_initiated} - end. -%% ----------------------------------------------------------------------------- - -tpm_ms_tracer(Mod,Func,Arity,MSname,MS) -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - NewMS=add_tracer(MS,get_tracer()), - {ok,h_tpm_ms(Mod,Func,Arity,MSname,NewMS)}; - no -> - {error,not_initiated} - end. -%% ----------------------------------------------------------------------------- - -%% Function that returns all MSname in use for Mod:Func/Arity -list_tpm_ms(Mod,Func,Arity) -> - {ok,h_list_tpm_ms(Mod,Func,Arity)}. -%% ----------------------------------------------------------------------------- - -%% Function equivalent to inviso_rt:ctpm_ms/5. This function can *only* be used -%% inside a CallFunc or a RemoveFunc. -ctpm_ms(Mod,Func,Arity,MSname) -> - h_ctpm_ms(Mod,Func,Arity,MSname), - ok. -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% The server implemenation. -%% ============================================================================= - -init(Parent,TiData,Tracer,InitPublLDmfa,RemovePublLDmf,CleanPublLDmf) -> - process_flag(priority,high), % Since we may receive from many procs. - register(?MODULE,self()), % So we can act as relay receiver. - case open_traceinfo_file(TiData) of - {ok,TI} -> % The ti.-file. - TId=ets:new(?NAMED_MS_TAB,[named_table,set,protected]), - PublLD=do_init_publ_ld(InitPublLDmfa), - Parent ! {self(),ok}, - put(tracer,Tracer), % Uggly quick fix! - loop(Parent, - Tracer, - TI, - mk_new_ld(InitPublLDmfa,RemovePublLDmf,CleanPublLDmf,TId), - PublLD, - now()); - {error,Reason} -> - Parent ! {self(),{error,Reason}} - end. -%% ----------------------------------------------------------------------------- - -loop(Parent,Tracer,TI,LD,PrevPublLD,PrevCleanTime) -> - {PublLD,CleanTime}=throw_old_failed(get_cleanpublldmf_ld(LD),PrevPublLD,PrevCleanTime), - receive - {{init_tpm,{Mod,Func,Arity},InitFunc,CallFunc,ReturnFunc,RemoveFunc},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - no -> % Good then we can add it! - case check_tpm_args(Mod,Func,Arity) of - true -> % Args are ok. - {NewLD,NewPublLD}= - h_init_tpm(Mod,Func,Arity, - InitFunc,CallFunc,ReturnFunc,RemoveFunc, - TI,LD,PublLD), - reply(Parent,Ref,ok), - loop(Parent,Tracer,TI,NewLD,NewPublLD,CleanTime); - false -> % Faulty arguments, - reply(Parent,Ref,{error,bad_mfa}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - yes -> % If it already exists, cant init again. - reply(Parent,Ref,{error,already_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm,{Mod,Func,Arity,MS},InitFunc,CallFunc,ReturnFunc,RemoveFunc},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - no -> % Good then we can add it! - case check_tpm_args(Mod,Func,Arity) of - true -> % Args are ok. - {NewLD,NewPublLD,N}= - h_tpm(Mod,Func,Arity,MS, - InitFunc,CallFunc,ReturnFunc,RemoveFunc, - TI,LD,PublLD), - reply(Parent,Ref,{ok,N}), - loop(Parent,Tracer,TI,NewLD,NewPublLD,CleanTime); - false -> - reply(Parent,Ref,{error,bad_mfa}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - yes -> - reply(Parent,Ref,{error,already_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm,{Mod,Func,Arity,MS}},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - {NewLD,N}=h_tpm(Mod,Func,Arity,MS,LD), - reply(Parent,Ref,{ok,N}), - loop(Parent,Tracer,TI,NewLD,PublLD,CleanTime); - no -> % Must be initiated before. - reply(Parent,Ref,{error,not_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm_tracer,{Mod,Func,Arity,MS},InitFunc,CallFunc,ReturnFunc,RemoveFunc},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - no -> % Good then we can add it! - case check_tpm_args(Mod,Func,Arity) of - true -> % Args are ok. - NewMS=add_tracer(MS,Tracer), - {NewLD,NewPublLD,N}= - h_tpm(Mod,Func,Arity,NewMS, - InitFunc,CallFunc,ReturnFunc,RemoveFunc, - TI,LD,PublLD), - reply(Parent,Ref,{ok,N}), - loop(Parent,Tracer,TI,NewLD,NewPublLD,CleanTime); - false -> - reply(Parent,Ref,{error,bad_mfa}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - yes -> - reply(Parent,Ref,{error,already_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm_tracer,{Mod,Func,Arity,MS}},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - NewMS=add_tracer(MS,Tracer), - {NewLD,N}=h_tpm(Mod,Func,Arity,NewMS,LD), - reply(Parent,Ref,{ok,N}), - loop(Parent,Tracer,TI,NewLD,PublLD,CleanTime); - no -> % Must be initiated before. - reply(Parent,Ref,{error,not_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm_ms,{Mod,Func,Arity},MSname,MS},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - reply(Parent,Ref,{ok,h_tpm_ms(Mod,Func,Arity,MSname,MS)}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - no -> - reply(Parent,Ref,{error,not_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{tpm_ms_tracer,{Mod,Func,Arity},MSname,MS},Ref,Parent} -> - case check_mfarity_exists(Mod,Func,Arity) of - yes -> % Ok, and args must be ok then also. - NewMS=add_tracer(MS,Tracer), - reply(Parent,Ref,{ok,h_tpm_ms(Mod,Func,Arity,MSname,NewMS)}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - no -> - reply(Parent,Ref,{error,not_initiated}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {{ctpm_ms,{Mod,Func,Arity},MSname},Ref,Parent} -> - reply(Parent,Ref,ok), - h_ctpm_ms(Mod,Func,Arity,MSname), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - {{ctpm,{Mod,Func,Arity}},Ref,Parent} -> - case get_remove_func_ld(Mod,Func,Arity,LD) of - false -> % Incorrect Mod:Func/Arity! - reply(Parent,Ref,{error,bad_mfa}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); % Do nothing! - MF -> % {M,F}, Func or 'void'. - catch erlang:trace_pattern({Mod,Func,Arity},false,[meta]), - NewPublLD=do_removefunc(MF,Mod,Func,Arity,PublLD), - NewLD=ctpm_ld(Mod,Func,Arity,LD), - reply(Parent,Ref,ok), - loop(Parent,Tracer,TI,NewLD,NewPublLD,CleanTime) - end; - {suspend,Parent} -> % Removes all meta trace patterns. - stop_all_meta_tracing(get_all_meta_funcs_ld(LD),PublLD,LD), - do_remove_publ_ld(get_removepublldmf_ld(LD),PublLD), - NewPublLD=do_init_publ_ld(get_initpublldmfa_ld(LD)), - loop(Parent,Tracer,TI,reset_ld(LD),NewPublLD,CleanTime); - {stop,Parent} -> % Make a controlled shutdown. - stop_all_meta_tracing(get_all_meta_funcs_ld(LD),PublLD,LD), - do_remove_publ_ld(get_removepublldmf_ld(LD),PublLD), - close_traceinfo_file(TI); % And then simply terminate. - {trace_ts,Pid,call,{M,F,Args},TS} -> - case handle_meta(get_call_func_ld(M,F,length(Args),LD),Pid,{call,Args,TS},PublLD) of - {ok,NewPublLD,Output} when is_binary(Output);is_list(Output) -> - write_output(TI,Output), - loop(Parent,Tracer,TI,LD,NewPublLD,CleanTime); - {ok,NewPublLD,_} -> % No output to the ti-file this time. - loop(Parent,Tracer,TI,LD,NewPublLD,CleanTime); - _ -> % Not handled correct, not much to do. - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {trace_ts,Pid,TypeTag,{M,F,Arity},Value,TS} - when TypeTag==return_from;TypeTag==exception_from -> - case handle_meta(get_return_func_ld(M,F,Arity,LD),Pid,{TypeTag,Value,TS},PublLD) of - {ok,NewPublLD,Output} when is_binary(Output);is_list(Output) -> - write_output(TI,Output), - loop(Parent,Tracer,TI,LD,NewPublLD,CleanTime); - {ok,NewPublLD,_} -> % No output to the ti-file this time. - loop(Parent,Tracer,TI,LD,NewPublLD,CleanTime); - _ -> % Not handled correct, not much to do. - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end; - {relayed_meta,Bin} -> - write_output(TI,Bin), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - {write_ti,OutPut} -> - write_output(TI,OutPut), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - {get_state,Ref,From} -> % Debug function. - reply(From,Ref,{ok,LD,PublLD}), - loop(Parent,Tracer,TI,LD,PublLD,CleanTime); - _Other -> - loop(Parent,Tracer,TI,LD,PublLD,CleanTime) - end. - - -%% ============================================================================= -%% First level help functions. -%% ============================================================================= - -%% Function which opens the trace-information file(s). It must understand -%% the tidata specification which is part of the tracerdata given to the -%% runtime component during init_tracing. -%% It must return an internal notation of the time of file open and a -%% useful descriptor the write_output function can use. -%% Returns {ok,TiDescriptor} or {error,Reason}. -open_traceinfo_file({file,FileName}) -> % A plain raw binary file. - case file:open(FileName,[write,raw,binary]) of - {ok,FD} -> - {ok,{file,FD}}; - {error,Reason} -> - {error,{open,[FileName,Reason]}} - end; -open_traceinfo_file({relay,ToNode}) -> % Use distributed Erlang. - {ok,{relay,ToNode}}; -open_traceinfo_file(IncorrectTI) -> - {error,{badarg,IncorrectTI}}. -%% ----------------------------------------------------------------------------- - -close_traceinfo_file({file,FD}) -> - file:close(FD); -close_traceinfo_file(_) -> - ok. -%% ----------------------------------------------------------------------------- - -%% Help function handling initializing meta tracing of a function. -%% Returns {NewLD,NewPublLD}. -h_init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc,TI,LD,PublLD) -> - case do_initfunc(InitFunc,Mod,Func,Arity,PublLD) of - {NewPublLD,Output} -> - write_output(TI,Output), - NewLD=init_tpm_ld(Mod,Func,Arity,CallFunc,ReturnFunc,RemoveFunc,LD), - {NewLD,NewPublLD}; - false -> % The initfunc did not do anything. - NewLD=init_tpm_ld(Mod,Func,Arity,CallFunc,ReturnFunc,RemoveFunc,LD), - {NewLD,PublLD} - end. -%% ----------------------------------------------------------------------------- - -%% Help function handling initializing meta tracing of a function and also -%% set the meta trace pattern as specified. -%% Returns {NewLD,NewPublLD,N}. -h_tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc,TI,LD,PublLD) -> - {NewLD,NewPublLD}= - h_init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc,TI,LD,PublLD), - case set_meta_tracing(Mod,Func,Arity,MS) of - true -> % Ok, set one pattern. - {NewLD,NewPublLD,1}; - false -> - {NewLD,NewPublLD,0} - end. -%% ----------------------------------------------------------------------------- - -%% Help function handling setting meta trace patter for a function which has -%% already been intialized. Note that we must remove all potentially stored -%% match-specs, if this function has been given match-specs before with -%% tpm_ms. -%% Returns a {NewLD,N}. -h_tpm(Mod,Func,Arity,MS,LD) -> - case set_meta_tracing(Mod,Func,Arity,MS) of - true -> - {remove_ms_ld(Mod,Func,Arity,LD),1}; - false -> - {LD,0} - end. -%% ----------------------------------------------------------------------------- - -%% Help function that adds a match-spec to Mod:Func/Arity. It is not defined -%% in which order the match-specs will be given to the BIF. -%% Note that if an MS with the same name as an exiting is inserted, the previous -%% match-spec will be removed. -%% Very important to realise is that the empty meta match spec [] imposes no -%% restrictions what so ever on the generating of meta trace call messages. -%% Uncontrolled sending of such messages may quickly drain power from the system. -%% Since an empty match-spec will "disappear" when added to other match specs, -%% the empty match is transformed to what it actually is: [{'_',[],[]}]. -%% Returns 0 or 1 indicating failure or success. -h_tpm_ms(Mod,Func,Arity,MSname,MS) -> - MSsNames=get_ms_ld(Mod,Func,Arity), % Fetch all previous match-specs. - TransformedMS=h_tpm_ms_convert_null_ms(MS), - MSsNames1=lists:keydelete(MSname,1,MSsNames), % If it already existed, it is gone! - NewMSs=lists:flatten([TransformedMS,lists:map(fun({_Name,MSx})->MSx end,MSsNames1)]), - case set_meta_tracing(Mod,Func,Arity,NewMSs) of - true -> % We only save the MS if it was good. - put_ms_ld(Mod,Func,Arity,MSname,TransformedMS,MSsNames1), - 1; - false -> - 0 - end. - -%% Help function converting the null match spec into, still a null match spec, -%% on a proper match spec format. This because it will otherwise be difficult -%% to see the difference between no active tpm_ms and all a set of null ms. -h_tpm_ms_convert_null_ms([]) -> - [{'_',[],[]}]; -h_tpm_ms_convert_null_ms(MS) -> - MS. -%% ----------------------------------------------------------------------------- - -%% Help function returning a list of all names used for match-functions for -%% the Mod:Func/Arity in question. -h_list_tpm_ms(Mod,Func,Arity) -> - MSsNames=get_ms_ld(Mod,Func,Arity), % A list of {MSname,MS}. - lists:map(fun({MSname,_})->MSname end,MSsNames). -%% ----------------------------------------------------------------------------- - -%% Function that removes a named match-spec. Returns nothing significant. -%% Note that if we end up with no match-specs, we must remove the meta trace -%% patten all together. That is bringing the function back to just initiated. -h_ctpm_ms(Mod,Func,Arity,MSname) -> - case get_ms_ld(Mod,Func,Arity) of - [] -> % The name does certainly not exist! - true; % We don't have to do anything. - MSsNames -> - case lists:keysearch(MSname,1,MSsNames) of - {value,{_,_MS}} -> % Ok, we must do something! - NewMSsNames=lists:keydelete(MSname,1,MSsNames), - case lists:flatten(lists:map(fun({_Name,MS})->MS end,NewMSsNames)) of - [] -> % This means stop meta tracing. - set_meta_tracing(Mod,Func,Arity,false); - NewMSs -> - set_meta_tracing(Mod,Func,Arity,NewMSs) - end, - set_ms_ld(Mod,Func,Arity,NewMSsNames); - false -> % But this name does not exist. - true % So we do not have to do anything. - end - end. -%% ----------------------------------------------------------------------------- - -%% Function that checks the arguments to the meta trace pattern. The reason we -%% must do this is that we can only allow meta tracing on specific functions and -%% not using wildpatterns. Otherwise the meta trace server will not understand -%% which callfunc for instance to call when a meta-trace message is generated -%% for a function. -%% Returns 'true' or 'false'. -check_tpm_args(Mod,Func,Arity) - when is_atom(Mod),is_atom(Func),is_integer(Arity),Mod/='_',Func/='_' -> - true; -check_tpm_args(_,_,_) -> - false. -%% ----------------------------------------------------------------------------- - -%% Help function which calls the actual BIF setting meta-trace-patterns. -%% Returns 'true' or 'false'. -set_meta_tracing(Mod,Func,Arity,MS) when is_atom(Mod) -> - case erlang:module_loaded(Mod) of - true -> - set_meta_tracing_2(Mod,Func,Arity,MS); - false -> % The module is not loaded. - case code:ensure_loaded(Mod) of - {module,_Mod} -> - set_meta_tracing_2(Mod,Func,Arity,MS); - {error,_Reason} -> % Could not load the module. - false % No use try to trace. - end - end; -set_meta_tracing(_,_,_,_) -> - false. - -set_meta_tracing_2(Mod,Func,Arity,MS) -> - case catch erlang:trace_pattern({Mod,Func,Arity},MS,[meta]) of - 0 -> % Hmm, nothing happend :-) - false; - N when is_integer(N) -> % The normal case, some functions were hit. - true; - {'EXIT',_Reason} -> - false - end. -%% ----------------------------------------------------------------------------- - -%% Help function which removes all meta trace pattern for the functions mentioned -%% in the list being first argument. It also executes the remove funcs for each -%% and every no longer meta traced function. This done since some of the remove -%% functions may do side-effects (like deleteing ETS tables). -%% Returns nothing significant. -stop_all_meta_tracing([{M,F,Arity}|Rest],PublLD,LD) -> - catch erlang:trace_pattern({M,F,Arity},false,[meta]), - NewPublLD=do_removefunc(get_remove_func_ld(M,F,Arity,LD),M,F,Arity,PublLD), - stop_all_meta_tracing(Rest,NewPublLD,LD); -stop_all_meta_tracing([],_,_) -> - true. -%% ----------------------------------------------------------------------------- - -%% This function calls the function registered to be handler for a certain -%% meta-traced function. Such a function or fun must take three arguments -%% and return {ok,NewPrivLD,OutPutBinary} or 'false'. OutPutBinary may be -%% something else, and is then ignored. -handle_meta({M,F},Pid,Arg1,PrivLD) -> - (catch M:F(Pid,Arg1,PrivLD)); -handle_meta(Fun,Pid,Arg1,PrivLD) when is_function(Fun) -> - (catch Fun(Pid,Arg1,PrivLD)); -handle_meta(_,_,_,_) -> % Don't know how to do this. - false. -%% ----------------------------------------------------------------------------- - -%% Help function writing output from a callback function to the ti-file. -%% Output can be a binary or a list of binaries. -write_output(TI,[OutPut|Rest]) -> - write_output(TI,OutPut), - write_output(TI,Rest); -write_output({file,FD},Bin) when is_binary(Bin) -> % Plain direct-binary file - Size=byte_size(Bin), - file:write(FD,list_to_binary([<<0,Size:32>>,Bin])); -write_output({relay,ToNode},Bin) when is_atom(ToNode),is_binary(Bin) -> - {inviso_rt_meta,ToNode} ! {relayed_meta,Bin}; -write_output(_,_) -> % Don't understand, just skip. - true. -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% Various help functions. -%% ============================================================================= - -%% Help function initializing the public loopdata structure. Note that if the -%% supplied InitPublLDmfa is faulty we let the structure become the error. -%% The error will most likely turn up in an error report somewhere, eventually. -do_init_publ_ld({M,F,Args}) when is_atom(M),is_atom(F),is_list(Args) -> - case catch apply(M,F,Args) of - {'EXIT',_Reason} -> - {error,init_publ_ld_func}; % Let the struct be this error! - InitialPublLD -> - InitialPublLD - end; -do_init_publ_ld(_) -> - {error,init_publ_ld_func}. -%% ----------------------------------------------------------------------------- - -%% Help function which removes the public loopdata structure. The function does -%% not necessarily have to exist. Returns nothing significant. -do_remove_publ_ld({M,F},PublLD) when is_atom(M),is_atom(F) -> - catch M:F(PublLD); -do_remove_publ_ld(_,_) -> - true. -%% ----------------------------------------------------------------------------- - -%% Hlp function initializing a particular meta traced function into the public -%% loopdata. Note that the function is not mandatory. -%% Returns {NewPublLD,Output} or 'false'. -do_initfunc({M,F},Mod,Func,Arity,PublLD) when is_atom(M),is_atom(F) -> - case catch M:F(Mod,Func,Arity,PublLD) of - {ok,NewPublLD,Output} -> - {NewPublLD,Output}; - _ -> % Everything else is an error. - false % Act as no initialization function. - end; -do_initfunc(Fun,Mod,Func,Arity,PublLD) when is_function(Fun) -> - case catch Fun(Mod,Func,Arity,PublLD) of - {ok,NewPublLD,Output} -> - {NewPublLD,Output}; - _ -> % Everything else is an error. - false % Act as no initialization function. - end; -do_initfunc(_,_,_,_,_) -> % Perhaps too generous, should be 'void' only. - false. -%% ----------------------------------------------------------------------------- - -%% Help function removing a particular meta traced function from the public -%% loopdata. Note that we do not make much noice should the call back function -%% be faulty. -do_removefunc({M,F},Mod,Func,Arity,PublLD) when is_atom(M),is_atom(F) -> - case catch M:F(Mod,Func,Arity,PublLD) of - {ok,NewPublLD} -> - NewPublLD; - _ -> % Everything else is an error. - PublLD % Act as no initialization function. - end; -do_removefunc(Fun,Mod,Func,Arity,PublLD) when is_function(Fun) -> - case catch Fun(Mod,Func,Arity,PublLD) of - {ok,NewPublLD} -> - NewPublLD; - _ -> % Everything else is an error. - PublLD % Act as no initialization function. - end; -do_removefunc(_,_,_,_,PublLD) -> - PublLD. -%% ----------------------------------------------------------------------------- - -%% Function that, if the time has come, goes through the priv-ld structure and -%% cleans away entryn left behind. The usual cause is that the function call -%% caused an exception and there were therefore no matching return_from. -%% Returns {NewPrivLD,now()}. -throw_old_failed({M,F},PrivLD,PrevClean) -> - case difference_in_now(PrevClean,now(),60) of % We clean once every minute. - true -> - case catch apply(M,F,[PrivLD]) of - {'EXIT',_Reason} -> % Something went wrong, ignore it. - {PrivLD,now()}; % Just keep the old priv-ld. - NewPrivLD -> % The function must return a priv-ld. - {NewPrivLD,now()} - end; - false -> % Not time yet! - {PrivLD,PrevClean} - end. -%% ----------------------------------------------------------------------------- - -%% Help function comparing two now timestamps. Returns true or false depending -%% on if S2 is more than DiffS seconds after S1. Only works for differences -%% less than 1 million seconds. -difference_in_now({MegaS1,S1,_},{MegaS2,S2,_},DiffS) -> - if - MegaS1+1<MegaS2 -> % More than 1 Mega sec. difference. - true; - MegaS1==MegaS2,S1+DiffS<S2 -> - true; - MegaS1+1==MegaS2,S1+DiffS<S2+1000000 -> - true; - true -> - false - end. -%% ----------------------------------------------------------------------------- - -%% This help function adds a {tracer,Tracer} to the enable-list in a 'trace' -%% match spec action. The reason for this is that the author of the a meta -%% match spec meant to turn tracing on for the process executing the match spec -%% can not know the tracer. This since the match spec is most likely authored -%% at the control component's node, and not here. -%% Note the double tuple necessary to make it just precise a tuple! -%% Returns a new match spec. -add_tracer([MS1|Rest],Tracer) -> - [add_tracer_2(MS1,Tracer)|add_tracer(Rest,Tracer)]; -add_tracer([],_) -> - []; -add_tracer(NotList,_Tracer) -> % Can be 'false', but also an error. - NotList. - -add_tracer_2({Head,Cond,Body},Tracer) -> - {Head,Cond,add_tracer_3(Body,Tracer)}; -add_tracer_2(Faulty,_Tracer) -> - Faulty. - -add_tracer_3([{trace,Disable,Enable}|Rest],Tracer) when is_list(Enable) -> - [{trace,Disable,Enable++[{{tracer,Tracer}}]}|Rest]; -add_tracer_3([ActionTerm|Rest],Tracer) -> - [ActionTerm|add_tracer_3(Rest,Tracer)]; -add_tracer_3([],_Tracer) -> - []; -add_tracer_3(FaultyBody,_Tracer) -> - FaultyBody. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Help functions handling internal loopdata. -%% ----------------------------------------------------------------------------- - --record(ld,{init_publ_ld_mfa, % {M,F,Args} - remove_publ_ld_mf, % {M,F} | void - clean_publ_ld_mf, % {Mod,Func} - ms_mfarities=notable, % ETS holding names match functions. - call_mfarities=[], % [{{M,F,Arity},2-TupleOrFun},...] - return_mfarities=[], % [{{M,F,Arity},2-TupleOrFun},...] - remove_mfarities=[] - }). - -mk_new_ld(InitPublLDmfa,RemovePublLDmf,CleanPublLDmf,TId) -> - #ld{ - init_publ_ld_mfa=InitPublLDmfa, - remove_publ_ld_mf=RemovePublLDmf, - clean_publ_ld_mf=CleanPublLDmf, - ms_mfarities=TId - }. -%% ----------------------------------------------------------------------------- - -%% Function which restores the internal loop data to somekind of initial state. -%% This is useful when tracing has been suspended. -reset_ld(#ld{init_publ_ld_mfa=InitPublLDmfa, - remove_publ_ld_mf=RemovePublLDmf, - clean_publ_ld_mf=CleanPublLDmf, - ms_mfarities=TId}) -> - ets:match_delete(TId,{'_','_'}), % Empty the table. - #ld{init_publ_ld_mfa=InitPublLDmfa, - remove_publ_ld_mf=RemovePublLDmf, - clean_publ_ld_mf=CleanPublLDmf, - ms_mfarities=TId}. -%% ----------------------------------------------------------------------------- - -get_initpublldmfa_ld(#ld{init_publ_ld_mfa=InitPublLDmfa}) -> - InitPublLDmfa. -%% ----------------------------------------------------------------------------- - -get_removepublldmf_ld(#ld{remove_publ_ld_mf=RemovePublLDmf}) -> - RemovePublLDmf. -%% ----------------------------------------------------------------------------- - -get_cleanpublldmf_ld(#ld{clean_publ_ld_mf=CleanPublLDmf}) -> - CleanPublLDmf. -%% ----------------------------------------------------------------------------- - -%% Help function adding data associated with a meta traced function to the -%% internal loopdata. Called when meta tracing is activated for M:F/Arity. -init_tpm_ld(M,F,Arity,CallFunc,ReturnFunc,RemoveFunc,LD) -> - ets:insert(LD#ld.ms_mfarities,{{M,F,Arity},[]}), - CallFuncs=LD#ld.call_mfarities, - ReturnFuncs=LD#ld.return_mfarities, - RemoveFuncs=LD#ld.remove_mfarities, - LD#ld{call_mfarities=[{{M,F,Arity},CallFunc}|CallFuncs], - return_mfarities=[{{M,F,Arity},ReturnFunc}|ReturnFuncs], - remove_mfarities=[{{M,F,Arity},RemoveFunc}|RemoveFuncs]}. -%% ----------------------------------------------------------------------------- - -%% Help function which answers the question if we have already initiated the -%% function. It is done by looking in the ETS-table with named match-functions. -%% If there is an entry in the set-type table for M:F/Arity, the function is -%% initiated. -%% Returns 'yes' or 'no'. -check_mfarity_exists(M,F,Arity) -> - case ets:lookup(?NAMED_MS_TAB,{M,F,Arity}) of - [] -> - no; - [_] -> - yes - end. -%% ----------------------------------------------------------------------------- - -%% Help function adding an entry with [{MSname,MSlist}|MSsNames] for M:F/Arity. -%% Note that any already existing entry is removed. -%% Returns nothing significant. -put_ms_ld(M,F,Arity,MSname,MS,MSsNames) -> - ets:insert(?NAMED_MS_TAB,{{M,F,Arity},[{MSname,MS}|MSsNames]}). -%% ----------------------------------------------------------------------------- - -%% Help function taking a list of {MSname,MSs} and storing them in the -%% internal loop data structure. The storage is actually implemented as an ETS -%% table. Any previous list of {MSname,MSs} associated with this {M,F,Arity} will -%% be lost. Returns nothing significant. -set_ms_ld(M,F,Arity,MSsNames) -> - ets:insert(?NAMED_MS_TAB,{{M,F,Arity},MSsNames}). -%% ----------------------------------------------------------------------------- - -%% Help function fetching a list of {MSname,MatchSpecs} for a M:F/Arity. The -%% match-functions are stored in an ETS table searchable on {M,F,Arity}. -get_ms_ld(M,F,Arity) -> - case ets:lookup(?NAMED_MS_TAB,{M,F,Arity}) of - [{_MFArity,MSsNames}] -> - MSsNames; - [] -> - [] - end. -%% ----------------------------------------------------------------------------- - -%% Help function removing all saved match-specs for a certain M:F/Arity. -%% Returns a new loopdata structure. -remove_ms_ld(M,F,Arity,LD) -> - ets:delete(LD#ld.ms_mfarities,{M,F,Arity}), - LD. -%% ----------------------------------------------------------------------------- - -%% Help function which removes all information about a meta traced function from -%% the internal loopdata. Returns a new loopdata structure. -ctpm_ld(M,F,Arity,LD) -> - ets:delete(LD#ld.ms_mfarities,{M,F,Arity}), - NewCallFuncs=lists:keydelete({M,F,Arity},1,LD#ld.call_mfarities), - NewReturnFuncs=lists:keydelete({M,F,Arity},1,LD#ld.return_mfarities), - NewRemoveFuncs=lists:keydelete({M,F,Arity},1,LD#ld.remove_mfarities), - LD#ld{call_mfarities=NewCallFuncs, - return_mfarities=NewReturnFuncs, - remove_mfarities=NewRemoveFuncs}. -%% ----------------------------------------------------------------------------- - -get_call_func_ld(M,F,Arity,#ld{call_mfarities=CallFuncs}) -> - case lists:keysearch({M,F,Arity},1,CallFuncs) of - {value,{_,MF}} -> - MF; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -get_return_func_ld(M,F,Arity,#ld{return_mfarities=CallFuncs}) -> - case lists:keysearch({M,F,Arity},1,CallFuncs) of - {value,{_,MF}} -> - MF; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -get_remove_func_ld(M,F,Arity,#ld{remove_mfarities=RemoveFuncs}) -> - case lists:keysearch({M,F,Arity},1,RemoveFuncs) of - {value,{_,MF}} -> - MF; - false -> - false - end. -%% ----------------------------------------------------------------------------- - -%% Function returning a list of all {Mod,Func,Arity} which are currently meta -%% traced. It does do by listifying the call_mfarities field in the internal -%% loopdata. -get_all_meta_funcs_ld(#ld{call_mfarities=CallFuncs}) -> - lists:map(fun({MFArity,_})->MFArity end,CallFuncs). -%% ----------------------------------------------------------------------------- - - -%% ============================================================================= -%% Functions for the standard PublLD structure. -%% -%% It is tuple {Part1,GlobalData} where Part1 is of length at least 2. -%% Where each field is a list of tuples. The last item in each tuple shall be -%% a now tuple, making it possible to clean it away should it be too old to be -%% relevant (there was no return_from message due to a failure). -%% Other fields can be used for other functions. -%% The GlobalData is not cleaned but instead meant to store data must be passed -%% to each CallFunc when a meta trace message arrives. -%% ============================================================================= - -%% Function returning our standard priv-loopdata structure. -init_std_publld(Size,GlobalData) -> - {list_to_tuple(lists:duplicate(Size,[])),GlobalData}. -%% ----------------------------------------------------------------------------- - -%% Function capable of cleaning out a standard publ-ld. The last element of each -%% tuple must be the now item. -%% Returns a new publ-ld structure. -clean_std_publld({Part1,GlobalData}) -> - {clean_std_publld_2(Part1,now(),tuple_size(Part1),[]),GlobalData}. - -clean_std_publld_2(_,_,0,Accum) -> - list_to_tuple(Accum); -clean_std_publld_2(PublLD,Now,Index,Accum) -> - NewTupleList=clean_std_publld_3(element(Index,PublLD),Now), - clean_std_publld_2(PublLD,Now,Index-1,[NewTupleList|Accum]). - -clean_std_publld_3([Tuple|Rest],Now) -> - PrevNow=element(tuple_size(Tuple),Tuple), % Last item shall be the now item. - case difference_in_now(PrevNow,Now,30) of - true -> % Remove it then! - clean_std_publld_3(Rest,Now); - false -> % Keep it! - [Tuple|clean_std_publld_3(Rest,Now)] - end; -clean_std_publld_3([],_) -> - []. -%% ----------------------------------------------------------------------------- - -%% ============================================================================= -%% Functions used as handling functions (as funs) for registered process names. -%% (Given that we use the standard priv-ld, otherwise you must do your own!). -%% ============================================================================= - -%% Call-back for initializing the meta traced functions there are quick functions -%% for. Returns a new public loop data structure. -metafunc_init(erlang,register,2,{Part1,GlobalData}) -> - {setelement(1,Part1,[]),GlobalData}. -%% ----------------------------------------------------------------------------- - -%% Call-function for erlang:register/2. -%% This function adds the call to register/2 to a standard priv-ld structure. -%% Note that we *must* search for previous entries from the same process. If such -%% still in structure it means a failed register/2 call. It must first be removed -%% so it can not be mixed up with this one. Since meta-trace message will arrive -%% in order, there was no return_from message for that call if we are here now. -local_register_call(CallingPid,{call,[Alias,Pid],TS},{Part1,GlobalData}) -> - TupleList=element(1,Part1), % The register/2 entry in a std. priv-ld. - NewTupleList=lists:keydelete(CallingPid,1,TupleList), % If present, remove previous call. - {ok, - {setelement(1,Part1,[{CallingPid,{Alias,Pid},TS}|NewTupleList]),GlobalData}, - void}. - -%% Return-function for the erlang:register/2 BIF. -%% This function formulates the output and removes the corresponding call entry -%% from the standard priv-ld structure. -local_register_return(CallingPid,{return_from,_Val,_TS},PublLD={Part1,GlobalData}) -> - TupleList=element(1,Part1), % The register/2 entry in a std. priv-ld. - case lists:keysearch(CallingPid,1,TupleList) of - {value,{_,{Alias,Pid},NowTS}} -> - NewTupleList=lists:keydelete(CallingPid,1,TupleList), - {ok, - {setelement(1,Part1,NewTupleList),GlobalData}, - term_to_binary({Pid,Alias,alias,NowTS})}; - false -> % Strange, then don't know what to do. - {ok,PublLD,void} % Do nothing seems safe. - end; -local_register_return(CallingPid,{exception_from,_Val,_TS},{Part1,GlobalData}) -> - TupleList=element(1,Part1), % The register/2 entry in a std. priv-ld. - NewTupleList=lists:keydelete(CallingPid,1,TupleList), - {ok,{setelement(1,Part1,NewTupleList),GlobalData},void}; % No association then. -local_register_return(_,_,PublLD) -> % Don't understand this. - {ok,PublLD,void}. - -%% When unregister/1 us called we simply want a unalias entry in the ti-file. -%% We can unfortunately not connect it with a certain pid. -local_unregister_call(_CallingPid,{_TypeTag,[Alias],TS},PublLD) -> - {ok,PublLD,term_to_binary({undefined,Alias,unalias,TS})}. -%% ----------------------------------------------------------------------------- - -%% Call-function for global:register_name/2,/3. -%% This function is actually the call function for the handle_call/3 in the -%% global server. Note that we must check that we only do this on the node -%% where Pid actually resides. -global_register_call(_CallingPid,{call,[{register,Alias,P,_},_,_],TS},PublLD) - when node(P)==node()-> - {ok,PublLD,term_to_binary({P,{global,Alias},alias,TS})}; -global_register_call(_CallingPid,_,PublLD) -> - {ok,PublLD,void}. - -%% Call-function for global:unregister_name. It acutally checks on the use of -%% global:delete_global_name/2 which is called when ever a global name is removed. -global_unregister_call(_CallingPid,{call,[Alias,P],TS},PublLD) when node(P)==node()-> - {ok,PublLD,term_to_binary({P,{global,Alias},unalias,TS})}; -global_unregister_call(_CallingPid,_,PublLD) -> - {ok,PublLD,void}. -%% ----------------------------------------------------------------------------- - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src index 1152f7259d..84cd6ee10d 100644 --- a/lib/runtime_tools/src/runtime_tools.app.src +++ b/lib/runtime_tools/src/runtime_tools.app.src @@ -20,8 +20,6 @@ [{description, "RUNTIME_TOOLS version 1"}, {vsn, "%VSN%"}, {modules, [dbg,observer_backend,percept_profile, - inviso_rt,inviso_rt_lib,inviso_rt_meta, - inviso_as_lib,inviso_autostart,inviso_autostart_server, runtime_tools,runtime_tools_sup,erts_alloc_config, ttb_autostart,dyntrace]}, {registered, [runtime_tools_sup,inviso_rt,inviso_rt_meta]}, diff --git a/lib/runtime_tools/test/Makefile b/lib/runtime_tools/test/Makefile index 4979b9c7b1..bcabdf13ed 100644 --- a/lib/runtime_tools/test/Makefile +++ b/lib/runtime_tools/test/Makefile @@ -5,8 +5,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk MODULES = \ dyntrace_SUITE \ runtime_tools_SUITE \ - inviso_testmodule1_foo \ - inviso_SUITE \ dbg_SUITE \ erts_alloc_config_SUITE diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl index bd908c1f3a..4071b159a1 100644 --- a/lib/runtime_tools/test/dbg_SUITE.erl +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -394,41 +394,36 @@ file_port2(suite) -> file_port2(doc) -> ["Test tracing to file port with 'follow_file'"]; file_port2(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skipped, "VxWorks NFS cache ruins it all."}; - _ -> - ?line stop(), - ?line {A,B,C} = erlang:now(), - ?line FTMP = atom_to_list(?MODULE) ++ integer_to_list(A) ++ - "-" ++ integer_to_list(B) ++ "-" ++ integer_to_list(C), - ?line FName = filename:join([?config(data_dir, Config), FTMP]), - %% Ok, lets try with flush and follow_file, not a chance on VxWorks - %% with NFS caching... - ?line Port2 = dbg:trace_port(file, FName), - ?line {ok, _} = dbg:tracer(port, Port2), - try - ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), - ?line {ok, _} = dbg:tp(dbg, ltp,[{'_',[],[{message, {self}}]}]), - ?line {ok, _} = dbg:tp(dbg, ln, [{'_',[],[{message, hej}]}]), - ?line ok = dbg:ltp(), - ?line ok = dbg:flush_trace_port(), - ?line dbg:trace_client(follow_file, FName, - {fun myhandler/2, self()}), - ?line S = self(), - ?line [{trace,S,call,{dbg,ltp,[]},S}] = flush(), - ?line ok = dbg:ln(), - ?line ok = dbg:flush_trace_port(), - ?line receive after 1000 -> ok end, %% Polls every second... - ?line [{trace,S,call,{dbg,ln,[]},hej}] = flush(), - ?line stop(), - ?line [] = flush() - after - ?line stop(), - ?line file:delete(FName) - end, - ok - end. + stop(), + {A,B,C} = erlang:now(), + FTMP = atom_to_list(?MODULE) ++ integer_to_list(A) ++ + "-" ++ integer_to_list(B) ++ "-" ++ integer_to_list(C), + FName = filename:join([?config(data_dir, Config), FTMP]), + %% Ok, lets try with flush and follow_file, not a chance on VxWorks + %% with NFS caching... + Port2 = dbg:trace_port(file, FName), + {ok, _} = dbg:tracer(port, Port2), + try + {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + {ok, _} = dbg:tp(dbg, ltp,[{'_',[],[{message, {self}}]}]), + {ok, _} = dbg:tp(dbg, ln, [{'_',[],[{message, hej}]}]), + ok = dbg:ltp(), + ok = dbg:flush_trace_port(), + dbg:trace_client(follow_file, FName, + {fun myhandler/2, self()}), + S = self(), + [{trace,S,call,{dbg,ltp,[]},S}] = flush(), + ok = dbg:ln(), + ok = dbg:flush_trace_port(), + receive after 1000 -> ok end, %% Polls every second... + [{trace,S,call,{dbg,ln,[]},hej}] = flush(), + stop(), + [] = flush() + after + stop(), + file:delete(FName) + end, + ok. file_port_schedfix(suite) -> []; diff --git a/lib/runtime_tools/test/inviso_SUITE.erl b/lib/runtime_tools/test/inviso_SUITE.erl deleted file mode 100644 index c64c40b945..0000000000 --- a/lib/runtime_tools/test/inviso_SUITE.erl +++ /dev/null @@ -1,2838 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2012. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Description: -%% Test suite for inviso (basic parts, i.e not inviso tools). Note that -%% inviso basic parts have modules in both the runtime_tools and -%% inviso applications. -%% -%% Authors: -%% Ann-Marie L�f, [email protected] -%% Lennart �hman, [email protected] -%% ----------------------------------------------------------------------------- - --module(inviso_SUITE). --compile(export_all). - --include_lib("common_test/include/ct.hrl"). --include_lib("kernel/include/file.hrl"). - --define(l,?line). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [basic_dist_trace_1, basic_dist_trace_2, - basic_dist_trace_3, basic_dist_trace_ti_1, - basic_dist_trace_ti_2, basic_dist_trace_ti_3, - suspend_dist_trace_ti_1, suspend_dist_trace_ti_2, - meta_cleanfunc_dist_1, basic_handlerfun_dist_1, - delete_log_dist_1, autostart_dist_1, autostart_dist_2, - autostart_dist_3, running_alone_dist_1, - running_alone_dist_2, running_alone_dist_3, - running_alone_dist_4, running_alone_dist_5, - overload_dist_1, overload_dist_2, overload_dist_3, - overload_dist_4, overload_dist_5, subscribe_dist_1, - lfm_trace_dist_1, lfm_trace_ti_dist_2, - handle_logfile_sort_wrapset, fetch_log_dist_trace_1, - fetch_log_dist_trace_2, fetch_log_dist_trace_3, - fetch_log_dist_error_1, fetch_log_dist_error_2, - expand_regexp_dist_1, only_loaded_dist_1]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - - -init_per_suite(Config) -> - case test_server:is_native(lists) of - true -> - {skip,"Native libs -- tracing doesn't work"}; - false -> - %% We never know who messed up this node before this suite! :-) - erlang:trace_pattern({'_','_','_'},[],[local]), - erlang:trace_pattern({'_','_','_'},[],[global]), - erlang:trace(all,false,[all]), - - ok=application:start(runtime_tools), - Config - end. - -end_per_suite(_Config) -> - ?l ok=application:stop(runtime_tools). - - -%% For each distributed testcase, we need two other distributed nodes to run the -%% runtime components on. Since they are freshly started every time there is no -%% need to clean them up first. -init_per_testcase(_Case,Config) -> - ?l TH=test_server:timetrap(100000), - ?l {ok,Node1}=test_server:start_node(inviso1,peer,[]), - ?l {ok,Node2}=test_server:start_node(inviso2,peer,[]), - ?l SuiteDir=filename:dirname(code:which(?MODULE)), - - %% Otherwise peer nodes will not find this module! - ?l true=rpc:call(Node1,code,add_patha,[SuiteDir]), - ?l true=rpc:call(Node2,code,add_patha,[SuiteDir]), - - ?l start_side_effect_logger(node()), - ?l start_side_effect_logger(Node1), - ?l start_side_effect_logger(Node2), - - - %% SPECIAL FOR MY PRIVATE TEST ENVIROMENT -% ?l rpc:call(Node1,code,add_patha,["/clearcase/otp/tools/runtime_tools/ebin"]), -% ?l rpc:call(Node1,code,add_patha,["/clearcase/otp/tools/inviso/ebin"]), -% ?l rpc:call(Node2,code,add_patha,["/clearcase/otp/tools/runtime_tools/ebin"]), -% ?l rpc:call(Node2,code,add_patha,["/clearcase/otp/tools/inviso/ebin"]), - -% %% SPECIAL FOR MY PRIVATE TEST ENVIROMENT, windows. -% ?l rpc:call(Node1,code,add_patha,["Z:/DATA/PROJECTS/inviso_project/runtime_tools/ebin"]), -% ?l rpc:call(Node1,code,add_patha,["Z:/DATA/PROJECTS/inviso_project/inviso/ebin"]), -% ?l rpc:call(Node2,code,add_patha,["Z:/DATA/PROJECTS/inviso_project/runtime_tools/ebin"]), -% ?l rpc:call(Node2,code,add_patha,["Z:/DATA/PROJECTS/inviso_project/inviso/ebin"]), - - ?l ok=rpc:call(Node1,application,start,[runtime_tools]), - ?l ok=rpc:call(Node2,application,start,[runtime_tools]), - ?l timer:sleep(100), % Problem with autostarted runtime. - %% The following is a test that the inviso_rt processes which are autostarted - %% are now gone. - - ?l ok=poll(rpc,call,[Node1,erlang,whereis,[inviso_rt]],undefined,20), - ?l ok=poll(rpc,call,[Node2,erlang,whereis,[inviso_rt]],undefined,20), - -% ?l ok=poll(rpc,call,[Node1,supervisor,which_children,[runtime_tools_sup]],[],20), -% ?l ok=poll(rpc,call,[Node2,supervisor,which_children,[runtime_tools_sup]],[],20), - NewConfig1=insert_remotenode_config(inviso1,Node1,Config), - NewConfig2=insert_remotenode_config(inviso2,Node2,NewConfig1), - insert_timetraphandle_config(TH,NewConfig2). -%% ----------------------------------------------------------------------------- - -end_per_testcase(Case,Config) -> - ?l test_server:stop_node(get_remotenode_config(inviso1,Config)), - ?l test_server:stop_node(get_remotenode_config(inviso2,Config)), - - case whereis(inviso_c) of - undefined -> % Should not exist. - true; - Pid when is_pid(Pid) -> % But if it exists... - exit(Pid,kill), % Remove it! - io:format("Had to kill the control component in end_per_testcase,~p.~n",[Case]) - end, - case whereis(inviso_rt) of - undefined -> % Should not exist. - true; - Pid2 when is_pid(Pid2) -> % But if it exists... - exit(Pid2,kill), % Remove it! - io:format("Had to kill local runtime component in end_per_testcase,~p.~n",[Case]) - end, - ?l process_killer([inviso_test_proc, - inviso_tab_proc, - inviso_collector_proc, - global_inviso_test_proc]), - ?l test_server:timetrap_cancel(get_timetraphandle_config(Config)), - - NewConfig1=remove_remotenode_config(inviso1,Config), - NewConfig2=remove_remotenode_config(inviso2,NewConfig1), - remove_timetraphandle_config(NewConfig2). -%% ----------------------------------------------------------------------------- - -%% ============================================================================== -%% Testcases. -%% ============================================================================== - -%% TEST CASE: Basic, distributed, trace only. -basic_dist_trace_1(suite) -> []; -basic_dist_trace_1(doc) -> - ["Basic case, start of distributed tracing, using only trac."]; -basic_dist_trace_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList=lists:map(fun(N)->{N,{file,filename:join([PrivDir, - "tf1_"++ - atom_to_list(N) - ])}} end, - Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), - activate_local_tracing(Nodes), - deactivate_local_tracing(Nodes), - stop_tracing(Nodes), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - - -%% TEST CASE: Basic, distributed, activate global tracing for functions in modules -%% pointed out using a regexp. No tracing will be done. -basic_dist_trace_2(suite) -> []; -basic_dist_trace_2(doc) -> - [""]; -basic_dist_trace_2(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList=lists:map(fun(N)->{N,{file,filename:join([PrivDir, - "tf1a_"++ - atom_to_list(N) - ])}} end, - Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), - Funcs1=activate_global_tracing_regexp(Nodes), - deactivate_global_tracing_regexp(Nodes,Funcs1), - stop_tracing(Nodes), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Basic, distributed, activate global tracing for functions in modules -%% pointed out using a dir-regexp. No tracing will be done. -basic_dist_trace_3(suite) -> []; -basic_dist_trace_3(doc) -> - [""]; -basic_dist_trace_3(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList=lists:map(fun(N)->{N,{file,filename:join([PrivDir, - "tf1b_"++ - atom_to_list(N) - ])}} end, - Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), - Funcs1=activate_global_tracing_regexp_dir(Nodes), - deactivate_global_tracing_regexp_dir(Nodes,Funcs1), - stop_tracing(Nodes), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Basic, distributed, trace and ti. -basic_dist_trace_ti_1(suite) -> []; -basic_dist_trace_ti_1(doc) -> - [""]; -basic_dist_trace_ti_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf2_"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"tf2_"++atom_to_list(N)++".ti"])}}]} - end, - TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - activate_local_tracing(Nodes), - activate_meta_tracing(Nodes), - ?l true=(is_pid(whereis(inviso_rt))), - ?l true=(is_pid(whereis(inviso_rt_meta))), - deactivate_meta_tracing(Nodes), - deactivate_local_tracing(Nodes), - stop_tracing(Nodes), - ?l true=(is_pid(whereis(inviso_rt))), % Shall still be running. - ?l ok=poll(erlang,whereis,[inviso_rt_meta],undefined,3), - stop(Nodes), - timer:sleep(200), % Give it time to terminate. - ?l ok=poll(erlang,whereis,[inviso_rt],undefined,3),% Shall be gone now. - ?l undefined=whereis(inviso_rt_meta), % Still gone. - ok. -%% ----------------------------------------------------------------------------- - -%% Test CASE: Testing that the tpm_tracer functionality works. That is appending -%% {tracer,Tracer} to a meta match spec. -basic_dist_trace_ti_2(suite) -> []; -basic_dist_trace_ti_2(doc) -> - [""]; -basic_dist_trace_ti_2(Config) when is_list(Config) -> - case erlang:system_info(version) of - "5.4"++_ -> % Perhaps not perfect, but work now :-) - {skip,"Old emulator"}; - _ -> - basic_dist_trace_ti_2_do(Config) - end. - -basic_dist_trace_ti_2_do(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf3_"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"tf3_"++atom_to_list(N)++".ti"])}}]} - end, - TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - activate_deactivate_meta_tracing_tracer(Nodes), - stop_tracing(Nodes), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Basic, distributed, trace and ti, where we try to use ctp_all to -%% check that all global and local patterns are removed but that meta patterns -%% remain. -%% This test also checks that if the meta tracer is terminated an error value -%% is generated when trying to do meta tracing at that node. -basic_dist_trace_ti_3(suite) -> []; -basic_dist_trace_ti_3(doc) -> - [""]; -basic_dist_trace_ti_3(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf4_"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"tf4_"++atom_to_list(N)++".ti"])}}]} - end, - TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - activate_local_tracing(Nodes), - activate_global_tracing(Nodes), - activate_meta_tracing(Nodes), - ?l true=(is_pid(whereis(inviso_rt))), - ?l true=(is_pid(whereis(inviso_rt_meta))), - ?l {ok,NodeResults1}=inviso:ctp_all(Nodes), % Removes local and global patterns. - ?l true=check_noderesults(Nodes,ok,NodeResults1), - ?l true=check_on_nodes(Nodes,erlang,trace_info,[{code,which,1},traced],{traced,false}), - ?l true=check_on_nodes(Nodes,erlang,trace_info,[{code,get_path,0},traced],{traced,false}), - %% But meta patters shall remain. - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{lists,module_info,0},meta_match_spec], - fun({meta_match_spec,L})when length(L)>0 ->true end), - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{lists,module_info,0},meta], - fun({meta,P})when is_pid(P) -> - P=rpc:call(node(P),erlang,whereis,[inviso_rt_meta]), - true - end), - %% Now kill the meta tracer somewhere and try to activate meta tracing. - ?l [ANode|_]=Nodes, - ?l AMetaPid=rpc:call(ANode,erlang,whereis,[inviso_rt_meta]), - ?l rpc:call(ANode,erlang,exit,[AMetaPid,kill]), - ?l {ok,NodeResults2}=inviso:tpm(Nodes,math,pi,0,[],void), - ?l {value,{ANode,{error,_}}}=lists:keysearch(ANode,1,NodeResults2), - - ?l stop_tracing(Nodes), - ?l stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% ----------------------------------------------------------------------------- -%% Test cases for SUSPEND -%% ----------------------------------------------------------------------------- - -%% TEST CASE: In this test case a trace with ti is started. Trace flags are set, -%% trace patterns are set and meta trace patterns. We then check that the trace -%% flags and the meta patterns are removed when tracing suspended. -%% The suspension is cancelled and we check that it is possible to reactivate -%% tracing by setting the process flags and meta patterns again. -suspend_dist_trace_ti_1(suite) -> []; -suspend_dist_trace_ti_1(doc) -> - [""]; -suspend_dist_trace_ti_1(Config) when is_list(Config) -> - ?l RemoteNodes=get_remotenodes_config(Config), - ?l Nodes=[node()|RemoteNodes], - ?l PrivDir=filename:join(?config(priv_dir,Config),""), - ?l TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_suspend1_"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"tf_suspend1_"++atom_to_list(N)++".ti"])}}]} - end, - ?l TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - activate_local_tracing(Nodes), - activate_meta_tracing(Nodes), - ?l true=(is_pid(whereis(inviso_rt))), - ?l true=(is_pid(whereis(inviso_rt_meta))), - %% Set some trace flags on some newly started test procs. - activate_traceflags(Nodes), - - %% Now suspend the tracing on all nodes. That shall result in the removal - %% of trace flags and meta trace patterns, but not local trace patterns. - ?l {ok,NodeResults1}=inviso:suspend(Nodes,test), - ?l true=check_noderesults(Nodes,ok,NodeResults1), - %% Trace flags gone? - ?l TestProcs=lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_test_proc]) end,Nodes), - ?l lists:foreach(fun(P)-> - {flags,[]}= - rpc:call(node(P),erlang,trace_info,[P,flags]) - end, - TestProcs), - %% Meta patterns shall be gone too, but local functions still there. - ?l lists:foreach(fun(N)-> - {meta,false}= - rpc:call(N, - erlang, - trace_info, - [{math,module_info,1},meta]), - {traced,local}= - rpc:call(N, - erlang, - trace_info, - [{code,which,1},traced]) - end, - Nodes), - - %% Try to activate trace flags, trace patterns and meta tracing while - %% suspended. Should not succeed of course! - ?l ThisNode=node(), - ?l {ok,[{ThisNode,{error,suspended}}]}= - inviso:tf([ThisNode],inviso_test_proc,[call]), - ?l {ok,[{ThisNode,{error,suspended}}]}= - inviso:tpl([ThisNode],math,module_info,1,[]), - ?l {ok,[{ThisNode,{error,suspended}}]}= - inviso:init_tpm([ThisNode], - math, - module_info, - 1, - {?MODULE,tpm_init_func2}, % Does not exist on purpose. - {?MODULE,tpm_call_func2}, % Does not exist on purpose. - {?MODULE,tpm_return_func2}, % Does not exist on purpose. - {?MODULE,tpm_remove_func2}), % Does not exist on purpose. - - %% Now we want to cancel suspension and see that we can reactivate tracing. - ?l {ok,NodeResults2}=inviso:cancel_suspension(Nodes), - ?l true=check_noderesults(Nodes,ok,NodeResults2), - - ?l {ok,NodeResults3}= - inviso:init_tpm(math, - module_info, - 1, - {?MODULE,tpm_init_func2}, % Does not exist on purpose. - {?MODULE,tpm_call_func2}, % Does not exist on purpose. - {?MODULE,tpm_return_func2}, % Does not exist on purpose. - {?MODULE,tpm_remove_func2}), % Does not exist on purpose. - ?l true=check_noderesults(Nodes,ok,NodeResults3), - ?l {ok,NodeResults5}= - inviso:tpm_ms(math,module_info,1,ms1,[{'_',[],[{return_trace}]}]), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults5), - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{math,module_info,1},meta_match_spec], - {meta_match_spec,[{'_',[],[{return_trace}]}]}), - ?l {ok,NodeResults6}=inviso:tf(Nodes,inviso_test_proc,[call]), - ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults6), - - %deactivate_meta_tracing(Nodes), - %deactivate_local_tracing(Nodes), - stop_tracing(Nodes), - ?l true=(is_pid(whereis(inviso_rt))), % Shall still be running. - ?l ok=poll(erlang,whereis,[inviso_rt_meta],undefined,3), - stop(Nodes), - ?l timer:sleep(200), % Give it time to terminate. - ?l ok=poll(erlang,whereis,[inviso_rt],undefined,3),% Shall be gone now. - ?l undefined=whereis(inviso_rt_meta), % Still gone. - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: In this test case a trace with ti is started. Trace flags are set, -%% trace patterns are set and meta trace patterns. We then suspend tracing at -%% all nodes, then stop tracing which shall be allowed. We then try to initiate -%% tracing again which shall not be possible. -suspend_dist_trace_ti_2(suite) -> []; -suspend_dist_trace_ti_2(doc) -> - [""]; -suspend_dist_trace_ti_2(Config) when is_list(Config) -> - ?l RemoteNodes=get_remotenodes_config(Config), - ?l Nodes=[node()|RemoteNodes], - ?l PrivDir=filename:join(?config(priv_dir,Config),""), - ?l TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_suspend2_"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"tf_suspend2_"++atom_to_list(N)++".ti"])}}]} - end, - ?l TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - activate_local_tracing(Nodes), - activate_meta_tracing(Nodes), - ?l true=(is_pid(whereis(inviso_rt))), - ?l true=(is_pid(whereis(inviso_rt_meta))), - %% Set some trace flags on some newly started test procs. - activate_traceflags(Nodes), - - %% Now suspend the tracing on all nodes. That shall result in the removal - %% of trace flags and meta trace patterns, but not local trace patterns. - ?l {ok,NodeResults1}=inviso:suspend(Nodes,test), - ?l true=check_noderesults(Nodes,ok,NodeResults1), - - %% Now stop tracing. - ?l {ok,NodeResults3}=inviso:stop_tracing(Nodes), - ?l true=check_noderesults(Nodes,{ok,idle},NodeResults3), - %% Now try to initiate tracing again. - ThisNode=node(), - ?l {ok,[{ThisNode,{error,suspended}}]}= - inviso:init_tracing([ThisNode], - [{trace,{file,filename:join([PrivDir,"tf_suspend3_"++ - atom_to_list(ThisNode)])}}, - {ti,{file,{filename:join([PrivDir,"tf_suspend3_"++ - atom_to_list(ThisNode)])}}}]), - - %% Cancel the suspension and initiate tracing again. - ?l {ok,NodeResults2}=inviso:cancel_suspension(Nodes), - ?l true=check_noderesults(Nodes,ok,NodeResults2), - ?l TracerDataFun2= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_suspend4_"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"tf_suspend4_"++atom_to_list(N)++".ti"])}}]} - end, - ?l TracerDataList2=lists:map(TracerDataFun2,Nodes), - ?l {ok,NodeResults4}=inviso:init_tracing(TracerDataList2), - ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok},{ti_log,ok}]},NodeResults4), - stop_tracing(Nodes), - ?l true=(is_pid(whereis(inviso_rt))), % Shall still be running. - stop(Nodes), - ?l timer:sleep(200), % Give it time to terminate. - ?l ok=poll(erlang,whereis,[inviso_rt],undefined,3),% Shall be gone now. - ok. -%% ----------------------------------------------------------------------------- - - - -%% TEST CASE: This test case tests that the clean function removes (prosumed) -%% expired data from the internal public-loopdata structure in the inviso_rt_meta -%% process. -meta_cleanfunc_dist_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"mcf1_"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"mcf1_"++atom_to_list(N)++".ti"])}}]} - end, - TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - %% Now initialize meta tracing, but the call_func is a bit "fixed". - ?l {ok,NodeResults1}= - inviso:tpm(Nodes,math,module_info,1,[], - {?MODULE,meta_cleanfunc_initfunc_1}, - {?MODULE,meta_cleanfunc_callfunc_1}, - void,void), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults1), - %% Nothing in the "our" part of the public loop data. - ?l true=check_on_nodes(Nodes, - inviso_rt_meta,get_state,[inviso_rt_meta], - fun({ok,_LD,{{_,[]},_}})->true end), - ?l lists:foreach(fun(N)->rpc:call(N,math,module_info,[exports]) end,Nodes), - %% Check that it has been added to the public loopdata structure. - ?l true=check_on_nodes(Nodes, - ?MODULE,poll,[inviso_rt_meta, - get_state, - [inviso_rt_meta], - fun({ok,_LD,{{_,[{meta_cleanfunc_test1,_Now}]},_}})-> - true; - (_)->false - end, - 20], - ok), - %% While we wait for 60 seconds to pass, we test a few other things. - ?l {ok,NodeResults2}= - inviso:tpm(Nodes,?MODULE,slowfunction2,0,[{'_',[],[{return_trace}]}], - {?MODULE,meta_cleanfunc_initfunc_2}, - {?MODULE,meta_cleanfunc_callfunc_2}, - {?MODULE,meta_cleanfunc_returnfunc_2}, - void), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults2), - ?l lists:foreach(fun(N)->rpc:call(N,?MODULE,slowfunction,[]) end,Nodes), - %% Believe it or not but slowfunction is still running, in its own process, - %% we are therefore free now to examine the meta tracer. - ?l true=check_on_nodes(Nodes, - ?MODULE,poll,[inviso_rt_meta, - get_state, - [inviso_rt_meta], - fun({ok,_LD,{{[],Tuples},_}})-> - {value,_}= - lists:keysearch(meta_cleanfunc_test2, - 1, - Tuples), - {value,_}= - lists:keysearch(meta_cleanfunc_test1, - 1, - Tuples), - true; - (_)-> - false - end, - 20], - ok), - %% Now we wait for slowfunction to return and that the meta_cleanfunc_test2 - %% to be removed from public loopdata strucuture. - ?l timer:sleep(10000), - %% The only thing remaining should be the meta_cleanfunc_test1 which will not - %% go away for less than that the clean functionality removes it. - ?l true=check_on_nodes(Nodes, - ?MODULE,poll,[inviso_rt_meta, - get_state, - [inviso_rt_meta], - fun({ok,_LD,{{_,[{meta_cleanfunc_test1,_Now}]},_}})-> - true; - (_)-> - false - end, - 20], - ok), - %% Wait for the clean function to clean meta_cleanfunc_test1 away. - ?l timer:sleep(51000), % Shall be gone after 5 seconds. - ?l true=check_on_nodes(Nodes, - ?MODULE,poll,[inviso_rt_meta, - get_state, - [inviso_rt_meta], - fun({ok,_LD,{{_,[]},_}})->true; - (_)->false - end, - 20], - ok), - stop_tracing(Nodes), - stop(Nodes), - ok. - -%% This function acts as tpm initialization function when we are going to test -%% that the clean function works. Note that we here assume standard public loop -%% datastructure. -meta_cleanfunc_initfunc_1(_M,_F,_Arity,{E1,_E2}) -> - {ok,{E1,[]},void}. -%% Function that is supposed to be called when the meta traced function is -%% called. -meta_cleanfunc_callfunc_1(_Pid,_Args,{{E1,E2},Global}) -> - {ok,{{E1,[{meta_cleanfunc_test1,now()}|E2]},Global},void}. - -meta_cleanfunc_initfunc_2(_M,_F,_Arity,PublLD) -> - {ok,PublLD,void}. -meta_cleanfunc_callfunc_2(_Pid,_Args,{{E1,E2},Global}) -> - {ok,{{E1,[{meta_cleanfunc_test2,now()}|E2]},Global},void}. -meta_cleanfunc_returnfunc_2(_Pid,_,{{E1,E2},Global}) -> - {value,_}=lists:keysearch(meta_cleanfunc_test2,1,E2), - {ok,{{E1,lists:keydelete(meta_cleanfunc_test2,1,E2)},Global},void}. - -slowfunction() -> - spawn(?MODULE,slowfunction1,[]). -slowfunction1() -> - slowfunction2(). % Meta trace on this function call. -slowfunction2() -> - timer:sleep(2000), - true. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Testing that a runtime component can be started instructing it -%% to use a handler fun. Checks that the handler fun is called if a trace -%% message comes in. -basic_handlerfun_dist_1(suite) -> []; -basic_handlerfun_dist_1(doc) -> - [""]; -basic_handlerfun_dist_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l lists:foreach(fun(N)->rpc:call(N,ets,insert,[inviso_sideeffect_tab,{bhf1,0}]) end, - Nodes), - TracerDataFun= - fun(N)->{N,{fun basic_handlerfun_dist_1_fun/2,inviso_sideeffect_tab}} end, - TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), - activate_local_tracing(Nodes), - activate_traceflags(Nodes), - ?l lists:foreach(fun(N)->[{bhf1,0}]= - rpc:call(N,ets,lookup,[inviso_sideeffect_tab,bhf1]) - end, - Nodes), - ?l inviso_test_proc ! {apply,code,which,[lists]}, - ok=poll(ets,lookup,[inviso_sideeffect_tab,bhf1],[{bhf1,1}],20), - deactivate_traceflags(Nodes), - deactivate_local_tracing(Nodes), - stop_tracing(Nodes), - timer:sleep(100), - ?l [{bhf1,1}]=ets:lookup(inviso_sideeffect_tab,bhf1), - stop(Nodes), - ok. - -%% Function used as handler fun for testcase above. -basic_handlerfun_dist_1_fun(_Msg,TId) -> - ets:update_counter(TId,bhf1,1), - TId. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Here we test that delete_log removes the files at the involved -%% runtime nodes. In this case we test that we remove logs according to last -%% used tracer data. -delete_log_dist_1(suite) -> []; -delete_log_dist_1(doc) -> [""]; -delete_log_dist_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"dl1_"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"dl1_"++atom_to_list(N)++".ti"])}}]} - end, - TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - ?l Files=lists:map(fun({N,TD})-> - ?l {value,{_,{_,TraceFile}}}=lists:keysearch(trace,1,TD), - ?l {value,{_,{_,TiFile}}}=lists:keysearch(ti,1,TD), - ?l {N,{TraceFile,TiFile}} - end, - TracerDataList), - io:format("The Files is:~w~n",[Files]), - ?l {ok,NodeResults1}=inviso:delete_log(Nodes), % Should not work! - ?l true=check_noderesults(Nodes,{error,tracing},NodeResults1), - stop_tracing(Nodes), - %% Files still here. - ?l lists:foreach(fun({N,{F1,F2}})-> - ?l {ok,_}=rpc:call(N,file,read_file_info,[F1]), - ?l {ok,_}=rpc:call(N,file,read_file_info,[F2]) - end, - Files), - ?l {ok,NodeResults2}=inviso:delete_log(Nodes), - ?l true=check_noderesults(Nodes, - fun({_N,{ok,LogInfos}})-> - ?l {value,{_,[{ok,_FName1}]}}= - lists:keysearch(trace_log,1,LogInfos), - ?l {value,{_,[{ok,_FName2}]}}= - lists:keysearch(ti_log,1,LogInfos), - true - end, - NodeResults2), - %% The files shall be gone now. - ?l lists:foreach(fun({N,{F1,F2}})-> - ?l {error,enoent}=rpc:call(N,file,read_file_info,[F1]), - ?l {error,enoent}=rpc:call(N,file,read_file_info,[F2]) - end, - Files), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - - -%% TEST CASE: Test of the autostart behaviour of the runtime component. -%% Here we test that a runtime component is started according to the autostart.conf -%% file. Note that the repeat parameter is set to 2. -autostart_dist_1(suite) -> []; -autostart_dist_1(doc) -> - [""]; -autostart_dist_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - PrivDir=filename:join(?config(priv_dir,Config),""), - AutoConfFile=filename:join(PrivDir,"autostart1.conf"), - [RNode|_]=RemoteNodes, - ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), - ?l ok=rpc:call(RNode,application,set_env,[runtime_tools, - inviso_autostart_conf, - AutoConfFile]), - ?l {ok,FD}=file:open(AutoConfFile,[write]), - ?l ok=io:format(FD,"~w.~n~w.~n",[{repeat,2},{tag,c_ref}]), - ?l file:close(FD), - ?l ok=rpc:call(RNode,application,start,[runtime_tools]), - timer:sleep(1000), - ?l P1=rpc:call(RNode,erlang,whereis,[inviso_rt]), - ?l true=is_pid(P1), - ?l rpc:call(RNode,erlang,exit,[P1,kill]), - ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), - ?l ok=rpc:call(RNode,application,start,[runtime_tools]), - timer:sleep(1000), - ?l P2=rpc:call(RNode,erlang,whereis,[inviso_rt]), - ?l true=is_pid(P2), - ?l rpc:call(RNode,erlang,exit,[P2,kill]), - ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), - ?l ok=rpc:call(RNode,application,start,[runtime_tools]), - timer:sleep(1000), - ?l undefined=rpc:call(RNode,erlang,whereis,[inviso_rt]), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Test of autostart. Here we focus on that an autostarted -%% runtime component actually follows the trace case command file and -%% initiates tracing. -autostart_dist_2(suite) -> []; -autostart_dist_2(doc) -> - [""]; -autostart_dist_2(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - PrivDir=filename:join(?config(priv_dir,Config),""), - AutoConfFile=filename:join(PrivDir,"autostart2.conf"), - [RNode|_]=RemoteNodes, - ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), - ?l ok=rpc:call(RNode,application,set_env,[runtime_tools, - inviso_autostart_conf, - AutoConfFile]), - ?l CmdFileName=filename:join(PrivDir,"autostart_cmd_as1"), - ?l {ok,FD}=file:open(CmdFileName,[write]), - ?l ok=io:format(FD, - "inviso:tpl(Nodes,M,F,Arity,[]).~n" - "inviso:tf(Nodes,inviso_test_proc,[call]).~n", - []), - ?l file:close(FD), - ?l TraceFileName=filename:join([PrivDir,"as1_"++atom_to_list(RNode)]), - ?l TiFileName=filename:join([PrivDir,"as1_"++atom_to_list(RNode)++".ti"]), - ?l inviso_as_lib:setup_autostart(RNode, - 2, - [], - [{trace,{file,TraceFileName}}, - {ti,{file,TiFileName}}], - [[CmdFileName]], - [{'M',code},{'F',which},{'Arity',1}], - [{{inviso,tpl,5},{inviso_rt,tpl,{erlang,tl}}}, - {{inviso,tf,3},{inviso_rt,tf,{erlang,tl}}}]), - ?l TestP=spawn(RNode,?MODULE,test_proc_init,[]), - ?l ok=rpc:call(RNode,application,start,[runtime_tools]), - ?l timer:sleep(1000), - ?l {ok,_}=file:read_file_info(TraceFileName), - ?l {ok,_}=file:read_file_info(TiFileName), - ?l true=is_pid(P=rpc:call(RNode,erlang,whereis,[inviso_rt])), - ?l ok=poll(rpc,call,[RNode,erlang,trace_info,[{code,which,1},traced]],{traced,local},10), - ?l {flags,[call]}=rpc:call(RNode,erlang,trace_info,[TestP,flags]), - ?l rpc:call(RNode,erlang,exit,[P,kill]), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Here we test that an autostarted runtime component with a dependency -%% to a specific control component tries to connect to that control component -%% during its start-up. -autostart_dist_3(suite) -> []; -autostart_dist_3(doc) -> - [""]; -autostart_dist_3(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - PrivDir=filename:join(?config(priv_dir,Config),""), - AutoConfFile=filename:join(PrivDir,"autostart3.conf"), - [RNode|_]=RemoteNodes, - ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), - ?l ok=rpc:call(RNode,application,set_env,[runtime_tools, - inviso_autostart_conf, - AutoConfFile]), - ?l {ok,FD}=file:open(AutoConfFile,[write]), - ?l ok=io:format(FD,"~w.~n~w.~n~w.~n", - [{options,[{dependency,{infinity,node()}}]},{repeat,2},{tag,c_ref}]), - ?l file:close(FD), - %% Now start inviso at this node here for the runtime to connect. - ?l {ok,_Pid}=inviso:start(), - ?l ok=poll(erlang,whereis,[inviso_c],fun(P) when is_pid(P)->true;(_)->false end,10), - %% Make the runtime component start. - ?l ok=rpc:call(RNode,application,start,[runtime_tools]), - ?l ok=poll(rpc,call,[RNode,erlang,whereis,[inviso_rt]], - fun(P) when is_pid(P)->true;(_)->false end,10), - %% Check that the runtime component started. - ?l ok=poll(inviso,get_status,[[RNode]],{ok,[{RNode,{ok,{new,running}}}]},20), -% ?l {ok,[{RNode,{ok,{new,running}}}]}=inviso:get_status([RNode]), - stop([RNode]), - ok. -%% ----------------------------------------------------------------------------- - - - -%% TEST CASE: Test of the dependency mechanism in the runtime component. -%% Default behaviour is dependency=infinity, i.e the runtime components remains. -%% We also test here that we can reconnect to the runtime. -running_alone_dist_1(suite) -> []; -running_alone_dist_1(doc) -> - [""]; -running_alone_dist_1(Config) when is_list(Config) -> - ?l {ok,_Pid1}=inviso:start(), % Start a control component. - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,[]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l shutdown=inviso:stop(), % Stop the control component! - ?l undefined=whereis(inviso_c), - timer:sleep(3000), % How long shall we wait? :-) - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, - Nodes), - ?l {ok,_Pid2}=inviso:start(), - ?l {ok,NodeResults2}=inviso:add_nodes(Nodes,b_ref,[]), - ?l true=check_noderesults(Nodes,{ok,{adopted,new,running,a_ref}},NodeResults2), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Test of the dependency mechanism in the runtime component. -%% Test that the runtime components terminates after the specified 5000 ms. -running_alone_dist_2(suite) -> []; -running_alone_dist_2(doc) -> - [""]; -running_alone_dist_2(Config) when is_list(Config) -> - ?l {ok,_Pid1}=inviso:start(), % Start a control component. - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,[{dependency,5000}]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l shutdown=inviso:stop(), % Stop the control component! - ?l undefined=whereis(inviso_c), - timer:sleep(2000), - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, - Nodes), - timer:sleep(4000), % Now they shall be dead! - ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt]) end, - Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Test of the dependency mechanism in the runtime component. -%% Test that the runtime components terminates after the specified 5000 ms. -running_alone_dist_3(suite) -> []; -running_alone_dist_3(doc) -> - [""]; -running_alone_dist_3(Config) when is_list(Config) -> - ?l {ok,_Pid1}=inviso:start(), % Start a control component. - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,[{dependency,1000}]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l {ok,NodeResults2}=inviso:change_options(Nodes,[{dependency,5000}]), - ?l true=check_noderesults(Nodes,ok,NodeResults2), - ?l shutdown=inviso:stop(), % Stop the control component! - ?l undefined=whereis(inviso_c), - timer:sleep(3000), - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, - Nodes), - timer:sleep(3000), % Now they shall be dead! - ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt]) end, - Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Test of the dependency mechanism in the runtime component. -%% Test that the runtime components terminates after the specified 5000 ms, -%% like we did in running_alone_dist_2. But now we also start tracing and checks -%% that all inviso processes actually disappears when the time-out is reached. -running_alone_dist_4(suite) -> []; -running_alone_dist_4(doc) -> - [""]; -running_alone_dist_4(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - %% Start some tracing! - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_ra4"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"tf_ra4_"++atom_to_list(N)++".ti"])}}]} - end, - TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes, - [{dependency,5000}], - TracerDataList, - {ok,[{trace_log,ok},{ti_log,ok}]}), - - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, - Nodes), - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt_meta])) end, - Nodes), - %% Stop control component and wait for the runtimes to terminate after - %% running alone timer has expired. - ?l shutdown=inviso:stop(), % Stop the control component! - ?l undefined=whereis(inviso_c), - timer:sleep(2000), - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, - Nodes), - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt_meta])) end, - Nodes), - timer:sleep(4000), % Now they shall be dead! - ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt]) end, - Nodes), - ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt_meta]) end, - Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Test of the dependency mechanism in the runtime component. -%% Test that the runtime components terminates imeediately when the control -%% component is stopped. Check that all processes are gone. -running_alone_dist_5(suite) -> []; -running_alone_dist_5(doc) -> - [""]; -running_alone_dist_5(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - %% Start some tracing! - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataFun= - fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_ra5"++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir,"tf_ra5_"++atom_to_list(N)++".ti"])}}]} - end, - TracerDataList=lists:map(TracerDataFun,Nodes), - start_and_init_tracing2(Nodes, - [{dependency,0}], - TracerDataList, - {ok,[{trace_log,ok},{ti_log,ok}]}), - - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, - Nodes), - ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt_meta])) end, - Nodes), - %% Stop control component and check that all runtime component processes have - %% terminate more or less immediately afterwards, since dependency==0. - ?l shutdown=inviso:stop(), % Stop the control component! - timer:sleep(100), - ?l undefined=whereis(inviso_c), - timer:sleep(500), - ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt]) end, - Nodes), - ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt_meta]) end, - Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Test of the overload protection mechanism. The mechanism checks -%% for overload using the callback approximately at the interval specified. -%% Check that it does not start protection until start of tracing. -overload_dist_1(suite) -> []; -overload_dist_1(doc) -> - [""]; -overload_dist_1(Config) when is_list(Config) -> - ?l {ok,_Pid1}=inviso:start(), % Start a control component. - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l lists:foreach(fun(N)->true=rpc:call(N,ets,insert,[inviso_sideeffect_tab,{ovl1,0}]) end, - Nodes), % Initiate the counter. - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes, - a_ref, - [{overload,{{?MODULE,overload1},500}}]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - timer:sleep(1000), % Give the loadcheck time to perform. - ?l [{_,0}]=ets:lookup(inviso_sideeffect_tab,ovl1), % Nothing should have happened. - - %% Overload check shall not start until we start tracing. - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList=lists:map(fun(N)->{N,[{trace, - {file,filename:join([PrivDir, - "tf_ovl1."++atom_to_list(N) - ])}}]} - end, - Nodes), - ?l {ok,NodeResults2}=inviso:init_tracing(TracerDataList), - ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults2), - timer:sleep(1500), % Give the loadcheck time to perform. - ?l [{_,N}]=ets:lookup(inviso_sideeffect_tab,ovl1), - ?l true=(N>=2), % After 1,5 seconds, at least 2 checks. - - %% Now change options and remove overload checking! - ?l {ok,NodeResults3}=inviso:change_options(Nodes,[overload]), - ?l true=check_noderesults(Nodes,ok,NodeResults3), - ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl1), - timer:sleep(1000), - ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl1), % No more loadchecks! - - stop_tracing(Nodes), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Test of the overload protection mechanism. In this case we focus -%% in that the init and remove functions are carried out at change_options and -%% when starting and stoping the runtime component. -overload_dist_2(suite) -> []; -overload_dist_2(doc) -> - [""]; -overload_dist_2(Config) when is_list(Config) -> - ?l {ok,_Pid1}=inviso:start(), % Start a control component. - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes, - a_ref, - [{overload,{{?MODULE,overload2}, - 500, - {?MODULE,overload2i,[]}, - {?MODULE,overload2r,[]}}}]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l [{_,0}]=ets:lookup(inviso_sideeffect_tab,ovl2), - - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList=lists:map(fun(N)->{N,[{trace, - {file,filename:join([PrivDir, - "tf_ovl2."++atom_to_list(N) - ])}}]} - end, - Nodes), - ?l {ok,NodeResults2}=inviso:init_tracing(TracerDataList), - ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults2), - timer:sleep(1500), % Give the loadcheck time to perform. - ?l [{_,N}]=ets:lookup(inviso_sideeffect_tab,ovl2), - io:format("� is:~p~n",[N]), - ?l true=(N>=2), % After 1,5 seconds, at least 2 checks. - ?l {ok,NodeResults3}=inviso:change_options(Nodes,[{overload,{{?MODULE,overload3}, - 500, - {?MODULE,overload3i,[]}, - {?MODULE,overload3r,[]}}}]), - ?l true=check_noderesults(Nodes,ok,NodeResults3), - ?l []=ets:lookup(inviso_sideeffect_tab,ovl2), - timer:sleep(1500), - ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl3), - ?l true=(N2>=2), % After 1,5 seconds, at least 2 checks. - stop_tracing(Nodes), - ?l []=ets:lookup(inviso_sideeffect_tab,ovl3r), % Remove function shall not be called. - ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl3), - timer:sleep(1000), % Check that overloadchecking has stopped. - ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl3), - stop(Nodes), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,ovl3r],[{ovl3r,done}],20), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Test of the overload protections mechanism. Here we focus on testing -%% that if overload is reached tracing is really suspended. -overload_dist_3(suite) -> []; -overload_dist_3(doc) -> - [""]; -overload_dist_3(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList= - lists:map(fun(N)->{N,[{trace,{file,filename:join([PrivDir, - "tf_ovl3."++atom_to_list(N)])}}, - {ti,{file,filename:join([PrivDir, - "tf_ovl3_ti."++atom_to_list(N)])}}]} - end, - Nodes), - ?l lists:foreach(fun(N)-> - true=rpc:call(N,ets,insert,[inviso_sideeffect_tab,{ovl4,0}]) - end, - Nodes), - start_and_init_tracing2(Nodes, - [{overload,{{?MODULE,overload4},500}}], - TracerDataList, - {ok,[{trace_log,ok},{ti_log,ok}]}), - activate_local_tracing(Nodes), - activate_meta_tracing(Nodes), - activate_traceflags(Nodes), - timer:sleep(600), - ?l [{_,N1}]=ets:lookup(inviso_sideeffect_tab,ovl4), - ?l true=(N1>=1), % Overload check has been done! - ?l Node=node(), - ?l {ok,[{Node,{ok,{tracing,running}}}]}=inviso:get_status([node()]), - ?l true=ets:insert(inviso_sideeffect_tab,{ovl4_suspend,true}), - timer:sleep(600), - ?l {ok,[{Node,{ok,{tracing,{suspended,test}}}}]}=inviso:get_status([node()]), - ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl4), - ?l {flags,[]}=erlang:trace_info(whereis(inviso_test_proc),flags), - ?l {meta,false}=erlang:trace_info({lists,module_info,0},meta), - ?l {traced,local}=erlang:trace_info({code,which,1},traced), - ?l true=(is_pid(whereis(inviso_rt_meta))), - ?l true=ets:delete(inviso_sideeffect_tab,ovl4_suspend), - timer:sleep(600), - ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl4), % No checking while suspended! - ?l {ok,[{Node,ok}]}=inviso:cancel_suspension([node()]), - ?l {ok,NodeResults1}=inviso:get_status(Nodes), - ?l true=check_noderesults(Nodes,{ok,{tracing,running}},NodeResults1), - timer:sleep(600), - ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl4), - ?l true=(N3>N2), - ?l deactivate_local_tracing(Nodes), - ?l stop_tracing(Nodes), - ?l stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE. Test that the overload mechanism is triggered by to the runtime -%% component incomming messages, and nothing else. -overload_dist_4(suite) -> []; -overload_dist_4(doc) -> - [""]; -overload_dist_4(Config) when is_list(Config) -> - ?l {ok,_Pid1}=inviso:start(), % Start a control component. - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes, - a_ref, - [{overload,{{?MODULE,overload5}, - infinity, - {?MODULE,overload5i,[]}, - {?MODULE,overload5r,[]}}}]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l [{_,0}]=ets:lookup(inviso_sideeffect_tab,ovl5), - - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList=lists:map(fun(N)->{N,[{trace, - {file,filename:join([PrivDir, - "tf_ovl4."++atom_to_list(N) - ])}}]} - end, - Nodes), - ?l {ok,NodeResults2}=inviso:init_tracing(TracerDataList), - ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults2), - timer:sleep(2000), % Give the loadcheck time to perform. - ?l [{_,N}]=ets:lookup(inviso_sideeffect_tab,ovl5), - ?l true=(N==0), % And nothing shall have happend! - %% Now we send a message to the inviso_rt, then the load check function - %% shall be called. - ?l whereis(inviso_rt) ! test_of_loadcheck, - timer:sleep(200), % Make sure the inviso_rt gets scheduled. - ?l [{_,1}]=ets:lookup(inviso_sideeffect_tab,ovl5), - stop_tracing(Nodes), - ?l []=ets:lookup(inviso_sideeffect_tab,ovl5r), % Remove function shall not be called. - ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl5), - ?l whereis(inviso_rt) ! test_of_loadcheck, - timer:sleep(1000), % Check that overloadchecking has stopped. - ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl5), - stop(Nodes), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,ovl5r],[{ovl5r,done}],20), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE. Test that the overload mechanism correctly calculates remaining time -%% to next load check if a message comes into the runtime component "interupting" -%% the waiting for loadcheck timeout. (Loadcheck timeout is implemented as an after -%% in the receive). -overload_dist_5(suite) -> []; -overload_dist_5(doc) -> - [""]; -overload_dist_5(Config) when is_list(Config) -> - ?l {ok,_Pid1}=inviso:start(), % Start a control component. - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l lists:foreach(fun(N)->true=rpc:call(N,ets,insert,[inviso_sideeffect_tab,{ovl6,0}]) end, - Nodes), % Initiate the counter. - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes, - a_ref, - [{overload,{{?MODULE,overload6},1000}}]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - %% Overload check shall not start until we start tracing. - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList=lists:map(fun(N)->{N,[{trace, - {file,filename:join([PrivDir, - "tf_ovl5."++atom_to_list(N) - ])}}]} - end, - Nodes), - ?l {ok,NodeResults2}=inviso:init_tracing(TracerDataList), - ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults2), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,ovl6],[{ovl6,2}],25), - %% Now we know that exactly 2 checks have been made. Try to Distract the runtime :-) - ?l inviso_rt:state(whereis(inviso_rt)), % Make it have to receive a message. - timer:sleep(500), - ?l [{_,2}]=ets:lookup(inviso_sideeffect_tab,ovl6), % Should still be 2. - timer:sleep(600), - ?l [{_,3}]=ets:lookup(inviso_sideeffect_tab,ovl6), % We expect yet one check. - timer:sleep(1100), - ?l [{_,4}]=ets:lookup(inviso_sideeffect_tab,ovl6), - - stop_tracing(Nodes), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - - -%% TEST CASE: Test of the subscription mechanism. -subscribe_dist_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - Pid=spawn(?MODULE,inviso_msg_collector,[]), - CtrlPid=whereis(inviso_c), - - ?l {ok,_Pid}=inviso:start(), % Start a control component. - ?l ok=inviso:subscribe(Pid), - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,[]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l {ok,NodeResults2}=inviso:get_status(Nodes), - ?l true=check_noderesults(Nodes,{ok,{new,running}},NodeResults2), - check_msg_collector(Nodes, - fun({inviso_event,CP,_,{connected,N,{_Tag,{idle,running}}}}) - when CP==CtrlPid -> - {true,N}; - (_) -> - false - end, - 13), - TracerDataList=lists:map(fun(N)->{N,{file, - filename:join([PrivDir, - "tf_sub1"++atom_to_list(N)])}} - end, - Nodes), - ?l {ok,NodeResults3}=inviso:init_tracing(TracerDataList), - ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults3), - check_msg_collector(Nodes, - fun({inviso_event,CP,_,{state_change,N,{tracing,running}}}) - when CP==CtrlPid -> - {true,N}; - (_) -> - false - end, - 13), - ?l {ok,NodeResults4}=inviso:suspend(Nodes,test), - ?l true=check_noderesults(Nodes,ok,NodeResults4), - check_msg_collector(Nodes, - fun({inviso_event,CP,_,{state_change,N,{tracing,{suspended,test}}}}) - when CP==CtrlPid -> - {true,N}; - (_) -> - false - end, - 13), - ?l [RNode|_]=RemoteNodes, - ?l RInvisoPid=rpc:call(RNode,erlang,whereis,[inviso_rt]), - ?l rpc:call(RNode,erlang,exit,[RInvisoPid,kill]), - check_msg_collector([RNode], - fun({inviso_event,CP,_,{disconnected,N,_Info}}) - when CP==CtrlPid -> - {true,N}; - (_) -> - false - end, - 11), - - ?l {ok,_NodeResults5}=inviso:stop_tracing(Nodes), - ?l {ok,_NodeResults6}=inviso:stop_nodes(Nodes), - ?l shutdown=inviso:stop(), - ok. -%% ----------------------------------------------------------------------------- - - -%% TEST CASE: fetch_log test of single straight trace_log file in distributed -%% environment. -fetch_log_dist_trace_1(suite) -> []; -fetch_log_dist_trace_1(doc) -> - ["fetch_log test of single straight trace_log file in distributed" - "environment."]; -fetch_log_dist_trace_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList=lists:map(fun(N)->{N,[{trace,{file,filename:join([PrivDir, - "testfile1."++ - atom_to_list(N) - ])}}]} end, - Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), - - %% Put some output in the logs. - ?l inviso:tp(Nodes,math,module_info,0,[]), - ?l inviso:tf(Nodes,all,[call]), - ?l lists:foreach(fun(N)->rpc:call(N,math,module_info,[]) end,Nodes), - - stop_tracing(Nodes), - {H,M,S}=time(), - FetchToDir=filename:join([PrivDir, - "fetch_log_test1_"++integer_to_list(H)++"_"++ - integer_to_list(M)++"_"++integer_to_list(S)]), - ?l ok=file:make_dir(FetchToDir), - ?l {ok,NodeResults}=inviso:fetch_log(RemoteNodes,FetchToDir,"p1"), - io:format("~p~n",[NodeResults]), - ?l true=check_noderesults(RemoteNodes, - fun({N,{complete,[{trace_log,[{ok,File}]},{ti_log,[]}]}}) -> - ?l File="p1testfile1."++atom_to_list(N), - true; - (_)-> - false - end, - NodeResults), - ?l ON=filename:join(PrivDir,"testfile1."), - ?l FN=filename:join(FetchToDir,"p1testfile1."), - ?l lists:foreach(fun(N)-> - {ok,#file_info{size=Size}}= - file:read_file_info(ON++atom_to_list(N)), - {ok,#file_info{size=Size}}= - file:read_file_info(FN++atom_to_list(N)) - end, - RemoteNodes), - %% Now we wish to see that we get an incomplete if we try to fetch to a - %% directory that does not exist. - ?l FetchToErrorDir=filename:join([PrivDir,nonexistingingdir]), - ?l {ok,NodeResults2}=inviso:fetch_log(RemoteNodes,FetchToErrorDir,"p1"), - ?l io:format("NodeResults2:~w~n",[NodeResults2]), - ?l true=check_noderesults(RemoteNodes, - fun({_,{incomplete,_}}) -> - true; - (_)-> - false - end, - NodeResults2), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -fetch_log_dist_trace_2(suite) -> []; -fetch_log_dist_trace_2(doc) -> - [""]; -fetch_log_dist_trace_2(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - - {H,M,S}=time(), - ?l Name="wrap"++integer_to_list(H)++"_"++integer_to_list(M)++"_"++integer_to_list(S), - ?l BaseName=filename:join(PrivDir,Name), - Fun=fun(N)->{N,[{trace,{file,{BaseName++atom_to_list(N),wrap,".log",512,2}}}, - {ti,{file,BaseName++"_ti_"++atom_to_list(N)++".ti"}}]} - end, - ?l TracerDataList=lists:map(Fun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - fill_and_reach_two_wrapfiles(PrivDir,"^"++Name,Nodes), - - stop_tracing(Nodes), - FetchToDir=filename:join([PrivDir, - "fetch_log_test2_"++integer_to_list(H)++"_"++ - integer_to_list(M)++"_"++integer_to_list(S)]), - ?l ok=file:make_dir(FetchToDir), - ?l {ok,NodeResults}=inviso:fetch_log(RemoteNodes,FetchToDir,"p1"), - io:format("~p~n",[NodeResults]), - CheckFun=fun({N,{complete,[{trace_log,FileResults1},{ti_log,[{ok,TiFile}]}]}}) -> - Fun2=fun({ok,File}) -> - match= - re:run(File, - "^"++"p1"++Name++atom_to_list(N), - [{capture,none}]), - true; - (_) -> - false - end, - ?l true=lists:all(Fun2,FileResults1), - ?l TiFile="p1"++Name++"_ti_"++atom_to_list(N)++".ti", - true; - (_)-> - false - end, - ?l true=check_noderesults(RemoteNodes,CheckFun,NodeResults), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -fetch_log_dist_trace_3(suite) -> []; -fetch_log_dist_trace_3(doc) -> - [""]; -fetch_log_dist_trace_3(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - - {H,M,S}=time(), - ?l Name="wrap2_"++integer_to_list(H)++"_"++integer_to_list(M)++"_"++integer_to_list(S), - ?l BaseName=filename:join(PrivDir,Name), - Fun=fun(N)->{N,[{trace,{file,{BaseName++atom_to_list(N),wrap,".log",512,2}}}, - {ti,{file,BaseName++"_ti_"++atom_to_list(N)++".ti"}}]} - end, - ?l TracerDataList=lists:map(Fun,Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - fill_and_reach_two_wrapfiles(PrivDir,"^"++Name,Nodes), - - stop_tracing(Nodes), - FetchToDir=filename:join([PrivDir, - "fetch_log_test3_"++integer_to_list(H)++"_"++ - integer_to_list(M)++"_"++integer_to_list(S)]), - ?l ok=file:make_dir(FetchToDir), - ?l {ok,NodeResults1}=inviso:list_logs(Nodes), - CheckFun=fun({N,{ok,[{trace_log,PrivDir2,[F1,F2]},{ti_log,PrivDir2,[F3]}]}})-> - PrivDir2=PrivDir, - RegExp="^"++Name++atom_to_list(N)++"[0-9]+"++"\.log", - match=re:run(F1,RegExp,[{capture,none}]), - match=re:run(F2,RegExp,[{capture,none}]), - F3=Name++"_ti_"++atom_to_list(N)++".ti", - true; - (_) -> - false - end, - ?l true=check_noderesults(Nodes,CheckFun,NodeResults1), - ?l NodeFileSpecList=lists:map(fun({N,{ok,L}})->{N,L} end, - lists:keydelete(node(),1,NodeResults1)), - ?l {ok,NodeResults2}=inviso:fetch_log(NodeFileSpecList,FetchToDir,"p1"), -io:format("~p~n",[NodeResults2]), - CheckFun2=fun({N,{complete,[{trace_log,FileResults1},{ti_log,[{ok,TiFile}]}]}}) -> - Fun2=fun({ok,File}) -> - match= - re:run(File, - "^"++"p1"++Name++atom_to_list(N), - [{capture,none}]), - true; - (_) -> - false - end, - ?l true=lists:all(Fun2,FileResults1), - ?l TiFile="p1"++Name++"_ti_"++atom_to_list(N)++".ti", - true; - (_)-> - false - end, - ?l true=check_noderesults(RemoteNodes,CheckFun2,NodeResults2), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -fetch_log_dist_error_1(suite) -> []; -fetch_log_dist_error_1(doc) -> - [""]; -fetch_log_dist_error_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - ?l {ok,_Pid}=inviso:start(), % Start a control component. - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l {ok,NodeResults2}=inviso:fetch_log(RemoteNodes,"foo","bar"), -io:format("~p~n",[NodeResults2]), - ?l true=check_noderesults(RemoteNodes, - fun({_N,{error,no_tracerdata}})->true; - (_)->false - end, - NodeResults2), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -fetch_log_dist_error_2(suite) -> []; -fetch_log_dist_error_2(doc) -> - [""]; -fetch_log_dist_error_2(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - PrivDir=filename:join(?config(priv_dir,Config),""), - ?l {ok,_Pid}=inviso:start(), % Start a control component. - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l NodeLogList=lists:map(fun(N)->{N,[{trace_log, - PrivDir, - ["f1,fil","f2.fil"]}, - {ti_log, - PrivDir, - ["f.ti"]}]} - end, - RemoteNodes), - ?l {ok,NodeResults2}=inviso:fetch_log(NodeLogList,"foo","bar"), - io:format("~p~n",[NodeResults2]), - ?l true=check_noderesults(RemoteNodes, - fun({_N,{incomplete,_}}) -> - true; - (_) -> - false - end, - NodeResults2), - ?l NodeTracerData=lists:map(fun(N)->{N, - [{trace,{file,filename:join(PrivDir,"foo")}}, - {ti,{file,filename:join(PrivDir,"bar.ti")}}]} - end, - RemoteNodes), - {ok,NodeResults3}=inviso:fetch_log(NodeTracerData,"foo","bar"), - io:format("~p~n",[NodeResults3]), -%% This should work this way. Now it says complete [], which is not entirely -%% incorrect. But to follow the sematics of when fetching named files should -%% say incomplete. -%% Must do some rework to make that work. No real danger leaving it this way -%% for now. -% ?l true=check_noderesults(RemoteNodes, -% fun({_N,{incomplete,_}}) -> -% true; -% (_) -> -% false -% end, -% NodeResults3), - stop(Nodes), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: This case tests that the log file merger merges files in the -%% correct order, based on the timestamps. -lfm_trace_dist_1(suite) -> []; -lfm_trace_dist_1(doc) -> - [""]; -lfm_trace_dist_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - [RNode1,RNode2|_]=RemoteNodes, - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList= - lists:map(fun(N)->{N,{file,filename:join([PrivDir,"lfm1_"++atom_to_list(N)])}} end, - Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), - activate_local_tracing(Nodes), - activate_traceflags(Nodes), - - {inviso_test_proc,RNode2} ! {apply,code,which,[lists]}, - timer:sleep(300), - {inviso_test_proc,RNode1} ! {apply,code,which,[lists]}, - timer:sleep(300), - {inviso_test_proc,RNode1} ! {apply,code,which,[lists]}, - timer:sleep(300), - inviso_test_proc ! {apply,code,which,[lists]}, - timer:sleep(300), - {inviso_test_proc,RNode2} ! {apply,code,which,[lists]}, - timer:sleep(300), - inviso_test_proc ! {apply,code,which,[lists]}, - - deactivate_traceflags(Nodes), - deactivate_local_tracing(Nodes), - stop_tracing(Nodes), - stop(Nodes), - - DestFile=filename:join(PrivDir,"lfm1_out.txt"), - ?l {ok,6}= - inviso_lfm:merge([{node(), - [{trace_log, - [filename:join(PrivDir,"lfm1_"++atom_to_list(node()))]}]}, - {RNode1, - [{trace_log, - [filename:join(PrivDir,"lfm1_"++atom_to_list(RNode1))]}]}, - {RNode2, - [{trace_log, - [filename:join(PrivDir,"lfm1_"++atom_to_list(RNode2))]}]}], - DestFile), - ?l {ok,FD}=file:open(DestFile,[read]), - ?l S1=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode2),S1), - ?l S2=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode1),S2), - ?l S3=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode1),S3), - ?l S4=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(node()),S4), - ?l S5=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode2),S5), - ?l S6=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(node()),S6), - ?l file:close(FD), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: Testing to the full extent that pid-mappings work with both -%% local and global registration. Also checks that pidmappings can be removed -%% and that consequently the mappings in the resulting merged file stops. -lfm_trace_ti_dist_2(suite) -> []; -lfm_trace_ti_dist_2(doc) -> - [""]; -lfm_trace_ti_dist_2(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - [RNode1,RNode2|_]=RemoteNodes, - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList= - lists:map(fun(N)->{N,[{trace,{file,filename:join(PrivDir,"lfm2_"++atom_to_list(N))}}, - {ti,{file,filename:join(PrivDir,"lfm2_ti_"++atom_to_list(N))}}]} - end, - Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), - activate_local_tracing(Nodes), - activate_meta_tracing(Nodes), - activate_traceflags(Nodes), - - {inviso_test_proc,RNode2} ! {apply,code,which,[lists]}, - timer:sleep(300), - {inviso_test_proc,RNode1} ! {apply,code,which,[lists]}, - timer:sleep(300), - {inviso_test_proc,RNode1} ! {apply,code,which,[lists]}, - timer:sleep(300), - inviso_test_proc ! {apply,code,which,[lists]}, - timer:sleep(300), - - P2=spawn(RNode2,?MODULE,test_proc_loop,[]), - P1=spawn(RNode1,?MODULE,test_proc_loop,[]), - P0=spawn_link(?MODULE,test_proc_loop,[]), - ThisNode=node(), - ?l {ok,[{ThisNode,{ok,[1]}}]}=inviso:tf([node()],P0,[call,timestamp]), - ?l {ok,[{RNode1,{ok,[1]}}]}=inviso:tf([RNode1],P1,[call,timestamp]), - ?l {ok,[{RNode2,{ok,[1]}}]}=inviso:tf([RNode2],P2,[call,timestamp]), - P2 ! {apply,code,which,[lists]}, - timer:sleep(300), - P1 ! {apply,code,which,[lists]}, - timer:sleep(300), - P0 ! {apply,code,which,[lists]}, - timer:sleep(300), - - P3=spawn(RNode2,?MODULE,test_proc_loop,[]), - ?l yes=global:register_name(inviso_test_proc_globalname,P3), - ?l {ok,[{RNode2,{ok,[1]}}]}=inviso:tf([RNode2],P3,[call,timestamp]), - timer:sleep(300), - P3 ! {apply,code,which,[lists]}, - timer:sleep(300), - - P4=rpc:call(RNode1,erlang,whereis,[inviso_test_proc]), - ?l true=rpc:call(RNode1,erlang,unregister,[inviso_test_proc]), - timer:sleep(300), - P4 ! {apply,code,which,[lists]}, - timer:sleep(300), - - ?l true=rpc:call(RNode1,erlang,register,[inviso_test_proc,P4]), - - ?l global:unregister_name(inviso_test_proc_globalname), - timer:sleep(300), - ?l P3 ! {apply,code,which,[lists]}, - timer:sleep(300), - - deactivate_traceflags(Nodes), - deactivate_local_tracing(Nodes), - stop_tracing(Nodes), - stop(Nodes), - - DestFile=filename:join(PrivDir,"lfm2_out.txt"), - ?l {ok,10}= - inviso_lfm:merge([ - {node(), - [{trace_log, - [filename:join(PrivDir,"lfm2_"++atom_to_list(node()))]}, - {ti_log, - [filename:join(PrivDir,"lfm2_ti_"++atom_to_list(node()))]}]}, - {RNode1, - [{trace_log, - [filename:join(PrivDir,"lfm2_"++atom_to_list(RNode1))]}, - {ti_log, - [filename:join(PrivDir,"lfm2_ti_"++atom_to_list(RNode1))]}]}, - {RNode2, - [{trace_log, - [filename:join(PrivDir,"lfm2_"++atom_to_list(RNode2))]}, - {ti_log, - [filename:join(PrivDir,"lfm2_ti_"++atom_to_list(RNode2))]}]} - ], - DestFile), - ?l {ok,FD}=file:open(DestFile,[read]), - ?l S1=io:get_line(FD,""), -io:format("S1 is:~p~n",[S1]), - ?l true=lists:prefix(atom_to_list(RNode2)++" [inviso_test_proc",S1), - ?l S2=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode1)++" [inviso_test_proc",S2), - ?l S3=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode1)++" [inviso_test_proc",S3), - ?l S4=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(node())++" [inviso_test_proc",S4), - ?l S5=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode2)++" []",S5), - ?l S6=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode1)++" []",S6), - ?l S7=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(node())++" []",S7), - ?l S8=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode2)++" [{global,inviso_test_proc_globalname}]",S8), - ?l S9=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode1)++" []",S9), - ?l S10=io:get_line(FD,""), - ?l true=lists:prefix(atom_to_list(RNode2)++" []",S10), - ?l file:close(FD), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: This tests that the wrapset sorter works. -handle_logfile_sort_wrapset(suite) -> []; -handle_logfile_sort_wrapset(doc) -> - [""]; -handle_logfile_sort_wrapset(Config) when is_list(Config) -> - File0="prefix10.fil", - File1="prefix11.fil", - File2="prefix12.fil", - File3="prefix13.fil", - ?l [File0,File1,File2,File3]= - inviso_lfm_tpfreader:handle_logfile_sort_wrapset([File2,File1,File0,File3]), - File5="prefix15.fil", - ?l [File5,File0,File1,File2,File3]= - inviso_lfm_tpfreader:handle_logfile_sort_wrapset([File2,File5,File1,File0,File3]), - ok. -%% ----------------------------------------------------------------------------- - -%% TEST CASE: This case tests that the regexp mechanism in the inviso_rt_lib can -%% find modules using regexps and that its only_loaded mechanism works. -%% This test case can not be run when using cover because cover will make the -%% modules no longer loaded from the path containing "runtime_tools". -expand_regexp_dist_1(suite) -> []; -expand_regexp_dist_1(doc) -> - [""]; -expand_regexp_dist_1(Config) when is_list(Config) -> - case ?t:is_cover() of - true -> - {skip,"Cover is running"}; - false -> - expand_regexp_dist_1_nocover(Config) - end. - -expand_regexp_dist_1_nocover(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - [RNode1|_]=RemoteNodes, - ?l NodeResults1=inviso_rt_lib:expand_regexp(Nodes,"^inviso_rt.*",[]), - ?l L1=length(Nodes), - ?l L1=length(NodeResults1), - ?l true=lists:all(fun({_,Mods})-> - ?l 3=length(Mods), - ?l true=lists:member(inviso_rt,Mods), - ?l true=lists:member(inviso_rt_lib,Mods), - ?l true=lists:member(inviso_rt_meta,Mods), - true; - (_) -> - false - end, - NodeResults1), - %% Check the dir-option. In the following inviso_tool_lib shall not be found. - ?l NodeResults2=inviso_rt_lib:expand_regexp(Nodes,"runtime_tools","invi.*lib.*",[]), -?l io:format("NodeResults2:~w~n",[NodeResults2]), - ?l L1=length(NodeResults2), % Same number of nodes replying. - ?l true=lists:all(fun({_,Mods})-> - 2=length(Mods), - true=lists:member(inviso_as_lib,Mods), - true=lists:member(inviso_rt_lib,Mods), - true; - (_) -> - false - end, - NodeResults2), - ?l [{RNode1,[]}]= - inviso_rt_lib:expand_regexp([RNode1],"^inviso_testmodule1.*",[only_loaded]), - ?l [{RNode1,[inviso_testmodule1_foo]}]= - inviso_rt_lib:expand_regexp([RNode1],"^inviso_testmodule1.*",[]), - ok. -%% ----------------------------------------------------------------------------- - - -only_loaded_dist_1(suite) -> []; -only_loaded_dist_1(doc) -> - [""]; -only_loaded_dist_1(Config) when is_list(Config) -> - RemoteNodes=get_remotenodes_config(Config), - Nodes=[node()|RemoteNodes], - [RNode1|_]=RemoteNodes, - PrivDir=filename:join(?config(priv_dir,Config),""), - TracerDataList= - lists:map(fun(N)->{N,[{trace,{file,filename:join(PrivDir,"ol_1_"++atom_to_list(N))}}]} - end, - Nodes), - start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), - ?l false=rpc:call(RNode1,erlang,module_loaded,[inviso_testmodule1_foo]), - ?l {ok,[{RNode1,{ok,[0]}}]}= - inviso:tpl([RNode1],inviso_testmodule1_foo,'_','_',[],[only_loaded]), - ?l false=rpc:call(RNode1,erlang,module_loaded,[inviso_testmodule1_foo]), - ?l {ok,[{RNode1,{ok,[3]}}]}= - inviso:tpl([RNode1],inviso_testmodule1_foo,'_','_',[],[]), - stop_tracing(Nodes), - stop(Nodes), - ok. - - -%% ============================================================================== -%% Common functions setting up inviso. -%% ============================================================================== - -%% Starts controlcomponent and adds runtime components on the nodes specified. -%% Also initiates tracing on the nodes. -start_and_init_tracing1(Nodes,Options,TracerData,Reply) when is_list(Nodes) -> - ?l {ok,_Pid}=inviso:start(), % Start a control component. - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,Options), - io:format("~p~n",[NodeResults1]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l {ok,NodeResults2}=inviso:get_status(Nodes), - ?l true=check_noderesults(Nodes,{ok,{new,running}},NodeResults2), - ?l {ok,NodeResults3}=inviso:init_tracing(Nodes,TracerData), - ?l true=check_noderesults(Nodes,Reply,NodeResults3), - ok. -start_and_init_tracing2(Nodes,Options,TracerDataList,Reply) -> - ?l {ok,_Pid}=inviso:start(), % Start a control component. - ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,Options), - io:format("~p~n",[NodeResults1]), - ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), - ?l {ok,NodeResults2}=inviso:get_status(Nodes), - ?l true=check_noderesults(Nodes,{ok,{new,running}},NodeResults2), - ?l {ok,NodeResults4}=inviso:get_tracerdata(Nodes), - ?l true=check_noderesults(Nodes,{ok,no_tracerdata},NodeResults4), - ?l {ok,NodeResults3}=inviso:init_tracing(TracerDataList), - io:format("Tracerdatalist:~p~n",[TracerDataList]), - ?l true=check_noderesults(Nodes,Reply,NodeResults3), - - ?l Fun1=fun({N,{ok,TD}}) when is_list(TD)-> - ?l {value,{trace,Trace}}=lists:keysearch(trace,1,TD), - ?l {value,{N,TD2}}=lists:keysearch(N,1,TracerDataList), - ?l true=lists:member({trace,Trace},TD2), - %% Check that the trace file really exists. - ?l case Trace of % Trace={file,FilePortParameters} - {file,FileName1} when is_list(FileName1) -> - ?l {ok,_}=rpc:call(N,file,read_file_info,[FileName1]); - _ -> % This should be extended with more cases. - true - end, - ?l case lists:keysearch(ti,1,TD2) of - {value,{_,Ti}} -> % Ok, we have ti too. - ?l {value,{_,Ti}}=lists:keysearch(ti,1,TD), - ?l FileName2=element(2,Ti), - ?l {ok,_}=rpc:call(N,file,read_file_info,[FileName2]), - true; - false -> % No ti, we are done now. - true - end; - ({N,{ok,{file,FileName}}}) -> - ?l {value,{N,{file,FileName}}}=lists:keysearch(N,1,TracerDataList), - ?l {ok,_}=rpc:call(N,file,read_file_info,[FileName]), - true; - ({N,{ok,LogTD}}) -> % The case using a fun. - ?l {value,{N,LogTD}}=lists:keysearch(N,1,TracerDataList), - true - end, - ?l {ok,NodeResults5}=inviso:get_tracerdata(Nodes), - ?l true=check_noderesults(Nodes,Fun1,NodeResults5), - ok. -%% ------------------------------------------------------------------------------ - -%% Stops tracing on Nodes. -stop_tracing(Nodes) when is_list(Nodes) -> - ?l {ok,NodeResults1}=inviso:stop_tracing(Nodes), - ?l true=check_noderesults(Nodes,{ok,idle},NodeResults1), - ?l {ok,NodeResults2}=inviso:get_status(Nodes), - ?l true=check_noderesults(Nodes,{ok,{idle,running}},NodeResults2), - %% The implementation says that the meta tracer shall be stopped when - %% tracing is stopped. Check that. - ?l lists:foreach(fun(N)-> - ok=poll(erlang,whereis,[inviso_rt_meta],undefined,20) - end, - Nodes). -%% ------------------------------------------------------------------------------ - -%% Stops the runtime components on Nodes and stops the control component at this -%% Erlang node. -stop(Nodes) when is_list(Nodes) -> - ?l true=check_on_nodes(Nodes,erlang,whereis,[inviso_rt],fun(P) when is_pid(P)->true end), - ?l {ok,NodeResults}=inviso:stop_nodes(Nodes), - ?l true=check_noderesults(Nodes,ok,NodeResults), - ?l true=check_on_nodes(Nodes,erlang,whereis,[inviso_rt],fun(undefined)->true end), - ?l true=is_pid(whereis(inviso_c)), - ?l shutdown=inviso:stop(), - ?l ok=poll(erlang,whereis,[inviso_c],undefined,20). -%% ------------------------------------------------------------------------------ - -%% Help function activating local tracing. -activate_local_tracing(Nodes) when is_list(Nodes) -> - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{code,which,1},traced], - {traced,false}), - ?l {ok,NodeResults}=inviso:tpl(Nodes,code,which,1,[]), - ?l true=check_noderesults(Nodes,fun({_,{ok,[1]}})->true end,NodeResults), - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{code,which,1},traced], - {traced,local}). -%% ------------------------------------------------------------------------------ - -%% Help function activating global tracing. -activate_global_tracing(Nodes) when is_list(Nodes) -> - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{code,get_path,0},traced], - {traced,false}), - ?l {ok,NodeResults}=inviso:tp(Nodes,code,get_path,0,[]), - ?l true=check_noderesults(Nodes,fun({_,{ok,[1]}})->true end,NodeResults), - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{code,get_path,0},traced], - {traced,global}). -%% ------------------------------------------------------------------------------ - - -%% Help function activating local tracing and using a regexp to point out modules. -%% Returns the structure of modules and functions that were activated. Must be used -%% when deactivating. -activate_global_tracing_regexp(Nodes) when is_list(Nodes) -> - %% First find out which modules will be effected. - ?l Mods1=inviso_rt_lib:expand_regexp("application.*",[]), - ?l true=(length(Mods1)>1), % Should find more than one module! - ?l Funcs1=lists:foldl(fun(M,Acc)->[{M,M:module_info(exports)}|Acc] end,[],Mods1), - %% Check that these functions are not traced. - io:format("Modules:~w~n",[Mods1]), - ?l {ok,NodeResults}=inviso:tp(Nodes,"application.*",'_','_',[],[]), - io:format("Here 2~w~n",[NodeResults]), - ?l N=lists:foldl(fun({_,L1},A1)->lists:foldl(fun(_,A2)->A2+1 end,A1,L1) end,0,Funcs1), - ?l true=check_noderesults(Nodes,fun({_,{ok,L}})-> N==lists:sum(L) end,NodeResults), - io:format("Here 3~n",[]), - %% Check again! - ?l lists:foreach(fun({M,Funcs})-> - lists:foreach(fun({F,Arity})-> - true=check_on_nodes(Nodes, - erlang, - trace_info, - [{M,F,Arity},traced], - {traced,global}) - end, - Funcs) - end, - Funcs1), - Funcs1. -%% ------------------------------------------------------------------------------ - -%% Help function as above but uses the dir feature as well. -activate_global_tracing_regexp_dir(Nodes) when is_list(Nodes) -> - %% First find out which modules will be effected. - ?l Mods1=inviso_rt_lib:expand_regexp(".*kernel.*","application.*",[]), - ?l true=(length(Mods1)>1), % Should find more than one module! - ?l Funcs1=lists:foldl(fun(M,Acc)->[{M,M:module_info(exports)}|Acc] end,[],Mods1), - %% Check that these functions are not traced. - io:format("Modules:~w~n",[Mods1]), - ?l {ok,NodeResults}=inviso:tp(Nodes,{".*kernel.*","application.*"},'_','_',[],[]), - io:format("Here 2~w~n",[NodeResults]), - ?l N=lists:foldl(fun({_,L1},A1)->lists:foldl(fun(_,A2)->A2+1 end,A1,L1) end,0,Funcs1), - ?l true=check_noderesults(Nodes,fun({_,{ok,L}})-> N==lists:sum(L) end,NodeResults), - io:format("Here 3~n",[]), - %% Check again! - ?l lists:foreach(fun({M,Funcs})-> - lists:foreach(fun({F,Arity})-> - true=check_on_nodes(Nodes, - erlang, - trace_info, - [{M,F,Arity},traced], - {traced,global}) - end, - Funcs) - end, - Funcs1), - Funcs1. -%% ------------------------------------------------------------------------------ - -deactivate_local_tracing(Nodes) when is_list(Nodes) -> - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{code,which,1},traced], - {traced,local}), - ?l {ok,NodeResults}=inviso:ctpl(Nodes,code,'_','_'), - ?l true=check_noderesults(Nodes,fun({_,{ok,[N]}})when is_integer(N)->true end,NodeResults), - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{code,which,1},traced], - {traced,false}). -%% ------------------------------------------------------------------------------ - -deactivate_global_tracing(Nodes) when is_list(Nodes) -> - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{code,get_path,0},traced], - {traced,global}), - ?l {ok,NodeResults}=inviso:ctp(Nodes,code,'_','_'), - ?l true=check_noderesults(Nodes,fun({_,{ok,[N]}})when is_integer(N)->true end,NodeResults), - ?l true=check_on_nodes(Nodes, - erlang, - trace_info, - [{code,get_path,0},traced], - {traced,false}). -%% ------------------------------------------------------------------------------ - - -%% Function deactivating the functions activated by activate_global_tracing_regexp/1. -deactivate_global_tracing_regexp(Nodes,Funcs1) -> - ?l lists:foreach(fun({M,Funcs})-> - lists:foreach(fun({F,Arity})-> - true=check_on_nodes(Nodes, - erlang, - trace_info, - [{M,F,Arity},traced], - {traced,global}) - end, - Funcs) - end, - Funcs1), - ?l {ok,NodeResults}=inviso:ctp(Nodes,"application.*",'_','_'), - ?l N=lists:foldl(fun({_,L1},A1)->lists:foldl(fun(_,A2)->A2+1 end,A1,L1) end,0,Funcs1), - io:format("Noderesult from deactivate;~w~n",[NodeResults]), - ?l true=check_noderesults(Nodes,fun({_,{ok,L}})-> N==lists:sum(L) end,NodeResults), - ?l lists:foreach(fun({M,Funcs})-> - lists:foreach(fun({F,Arity})-> - true=check_on_nodes(Nodes, - erlang, - trace_info, - [{M,F,Arity},traced], - {traced,false}) - end, - Funcs) - end, - Funcs1). -%% ------------------------------------------------------------------------------ - -%% Function deactivating the functions activated by activate_global_tracing_regexp_dir/1. -deactivate_global_tracing_regexp_dir(Nodes,Funcs1) -> - ?l lists:foreach(fun({M,Funcs})-> - lists:foreach(fun({F,Arity})-> - true=check_on_nodes(Nodes, - erlang, - trace_info, - [{M,F,Arity},traced], - {traced,global}) - end, - Funcs) - end, - Funcs1), - ?l {ok,NodeResults}=inviso:ctp(Nodes,{".*kernel.*","application.*"},'_','_'), - ?l N=lists:foldl(fun({_,L1},A1)->lists:foldl(fun(_,A2)->A2+1 end,A1,L1) end,0,Funcs1), - io:format("Noderesult from deactivate;~w~n",[NodeResults]), - ?l true=check_noderesults(Nodes,fun({_,{ok,L}})-> N==lists:sum(L) end,NodeResults), - ?l lists:foreach(fun({M,Funcs})-> - lists:foreach(fun({F,Arity})-> - true=check_on_nodes(Nodes, - erlang, - trace_info, - [{M,F,Arity},traced], - {traced,false}) - end, - Funcs) - end, - Funcs1). -%% ------------------------------------------------------------------------------ - -%% Help function which starts the inviso_test_proc on all nodes and then sets -%% the call flag on that process. -activate_traceflags(Nodes) -> - ?l lists:foreach(fun(N)->spawn(N,?MODULE,test_proc_init,[]) end,Nodes), - ?l lists:foreach(fun(N)-> - P=rpc:call(N,erlang,whereis,[inviso_test_proc]), - {flags,[]}=rpc:call(N,erlang,trace_info,[P,flags]) - end, - Nodes), - ?l {ok,NodeResults}=inviso:tf(Nodes,inviso_test_proc,[call,timestamp]), - ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults), - ?l lists:foreach(fun(N)-> - P=rpc:call(N,erlang,whereis,[inviso_test_proc]), - {flags,Flags}=rpc:call(N,erlang,trace_info,[P,flags]), - true=lists:member(call,Flags), - true=lists:member(timestamp,Flags) - end, - Nodes), - %% Now try a globally registered process. - ?l [ANode|_]=Nodes, - ?l GPid=spawn(ANode,?MODULE,global_test_proc_init,[]), - ?l ok=poll(global,whereis_name,[global_inviso_test_proc], - fun(P) when is_pid(P)->true;(_)->false end, - 10), - ?l {ok,NodeResults2}= - inviso:tf(Nodes,{global,global_inviso_test_proc},[call,timestamp]), - ?l true=check_noderesults(Nodes, - fun({N,{ok,[1]}}) when N==ANode->true; - ({_,{ok,[0]}})->true; - (_)->false - end, - NodeResults2), - ?l {flags,Flags2}=rpc:call(ANode,erlang,trace_info,[GPid,flags]), - ?l 2=length(Flags2), - ?l true=lists:member(call,Flags2), - ?l true=lists:member(timestamp,Flags2), - true. -%% ------------------------------------------------------------------------------ - -deactivate_traceflags(Nodes) -> - ?l lists:foreach(fun(N)-> - P=rpc:call(N,erlang,whereis,[inviso_test_proc]), - {flags,Flags}=rpc:call(N,erlang,trace_info,[P,flags]), - true=lists:member(call,Flags), - true=lists:member(timestamp,Flags) - end, - Nodes), - ?l {ok,NodeResults}=inviso:ctf(Nodes,inviso_test_proc,[call,timestamp]), - ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults), - ?l lists:foreach(fun(N)-> - P=rpc:call(N,erlang,whereis,[inviso_test_proc]), - {flags,[]}=rpc:call(N,erlang,trace_info,[P,flags]) - end, - Nodes), - ?l GPid=global:whereis_name(global_inviso_test_proc), - ?l ANode=node(GPid), - ?l {flags,Flags2}=rpc:call(ANode,erlang,trace_info,[GPid,flags]), - ?l 2=length(Flags2), - ?l {ok,NodeResults2}=inviso:ctf(Nodes,{global,global_inviso_test_proc},[call,timestamp]), - ?l true=check_noderesults(Nodes, - fun({N,{ok,[1]}}) when N==ANode->true; - ({_,{ok,[0]}})->true; - (_)->false - end, - NodeResults2). -%% ------------------------------------------------------------------------------ - - -activate_meta_tracing(Nodes) -> - ?l {ok,NodeResults1}=inviso:tpm_localnames(), - ?l true=check_noderesults(Nodes,{{ok,1},{ok,1}},NodeResults1), - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N,erlang,trace_info,[{erlang,register,2},meta]) - end, - Nodes), - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N,erlang,trace_info,[{erlang,unregister,1},meta]) - end, - Nodes), - ?l {ok,NodeResults2}=inviso:tpm_globalnames(), - ?l true=check_noderesults(Nodes,{{ok,1},{ok,1}},NodeResults2), - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N, - erlang, - trace_info, - [{global,handle_call,3},meta]) - end, - Nodes), - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N, - erlang, - trace_info, - [{global,delete_global_name,2},meta]) - end, - Nodes), - - ?l lists:foreach(fun(N)->true=rpc:call(N, - ets, - insert, - [inviso_sideeffect_tab,{tpm_init_func1,0}]), - true=rpc:call(N, - ets, - insert, - [inviso_sideeffect_tab,{tpm_call_func1,0}]), - true=rpc:call(N, - ets, - insert, - [inviso_sideeffect_tab,{tpm_return_func1,0}]) - end, - Nodes), - ?l {ok,NodeResults3}= - inviso:init_tpm(lists, - module_info, - 0, - {?MODULE,tpm_init_func1}, - {?MODULE,tpm_call_func1}, - {?MODULE,tpm_return_func1}, - {?MODULE,tpm_remove_func1}), - ?l true=check_noderesults(Nodes,ok,NodeResults3), - ?l [{_,1}]=ets:lookup(inviso_sideeffect_tab,tpm_init_func1), - ?l {ok,NodeResults3a}= - inviso:init_tpm(lists, - module_info, - 0, - {?MODULE,tpm_init_func1}, - {?MODULE,tpm_call_func1}, - {?MODULE,tpm_return_func1}, - {?MODULE,tpm_remove_func1}), - ?l true=check_noderesults(Nodes,{error,already_initiated},NodeResults3a), -% %% Try more forbidden things. Wildcards not allowed in meta tracing! -% ?l {ok,NodeResults3b}=inviso:tpm(Nodes,lists,'_',0,[{'_',[],[{return_trace}]}]), -% io:format("The noderesults3b is:~w~n",[NodeResults3b]), -% ?l true=check_noderesults(Nodes,{error,bad_mfa},NodeResults3b), - ?l {ok,NodeResults3c}=inviso:tpm(Nodes,lists,module_info,0,[{'_',[],[{return_trace}]}]), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults3c), - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]) - end, - Nodes), - ?l lists:foreach(fun(N)->rpc:call(N,lists,module_info,[]) end,Nodes), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_call_func1],[{tpm_call_func1,1}],20), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_return_func1],[{tpm_return_func1,1}],20), - ?l lists:foreach(fun(N)->rpc:call(N,lists,module_info,[]) end,Nodes), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_call_func1],[{tpm_call_func1,2}],20), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_return_func1],[{tpm_return_func1,2}],20), - - ?l {ok,NodeResults4}= - inviso:init_tpm(math, - module_info, - 1, - {?MODULE,tpm_init_func2}, % Does not exist on purpose. - {?MODULE,tpm_call_func2}, % Does not exist on purpose. - {?MODULE,tpm_return_func2}, % Does not exist on purpose. - {?MODULE,tpm_remove_func2}), % Does not exist on purpose. - ?l true=check_noderesults(Nodes,ok,NodeResults4), - ?l {ok,NodeResults5}= - inviso:tpm_ms(math,module_info,1,ms1,[{'_',[],[{return_trace}]}]), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults5), - ?l lists:foreach(fun(N)->{meta_match_spec,[{'_',[],[{return_trace}]}]}= - rpc:call(N,erlang,trace_info,[{math,module_info,1}, - meta_match_spec]) - end, - Nodes), - - ?l {ok,NodeResults6}=inviso:tpm_ms(math,module_info,1,ms2,[{[exports],[],[]}]), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults6), - ?l lists:foreach(fun(N)->{meta_match_spec,[{[exports],[],[]},{'_',[],[{return_trace}]}]}= - rpc:call(N,erlang,trace_info,[{math,module_info,1}, - meta_match_spec]) - end, - Nodes), - ?l {ok,NodeResults7}=inviso:tpm_ms(math,module_info,1,ms3,[{[attributes],[],[]}]), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults7), - ?l lists:foreach(fun(N)->{meta_match_spec,[{[attributes],[],[]}, - {[exports],[],[]}, - {'_',[],[{return_trace}]}]}= - rpc:call(N,erlang,trace_info,[{math,module_info,1}, - meta_match_spec]) - end, - Nodes), - ?l {ok,NodeResults8}=inviso:ctpm_ms(math,module_info,1,ms2), - ?l true=check_noderesults(Nodes,ok,NodeResults8), - ?l lists:foreach(fun(N)->{meta_match_spec,[{[attributes],[],[]}, - {'_',[],[{return_trace}]}]}= - rpc:call(N,erlang,trace_info,[{math,module_info,1}, - meta_match_spec]) - end, - Nodes), - ?l io:format("whereis:~w~n",[lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_rt_meta]) end,Nodes)]), - ?l {ok,NodeResults8}=inviso:ctpm_ms(math,module_info,1,ms3), - ?l io:format("whereis:~w~n",[lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_rt_meta]) end,Nodes)]), - ?l {ok,NodeResults8}=inviso:ctpm_ms(math,module_info,1,ms1), - ?l lists:foreach(fun(N)->{meta_match_spec,false}= - rpc:call(N,erlang,trace_info,[{math,module_info,1}, - meta_match_spec]) - end, - Nodes), - - %% Now try to do this with exception tracing instead. - %% Reset the side effect tables. - ?l lists:foreach(fun(N)->true=rpc:call(N, - ets, - insert, - [inviso_sideeffect_tab,{tpm_init_func1,0}]), - true=rpc:call(N, - ets, - insert, - [inviso_sideeffect_tab,{tpm_call_func1,0}]), - true=rpc:call(N, - ets, - insert, - [inviso_sideeffect_tab,{tpm_return_func1,0}]) - end, - Nodes), - ?l {ok,NodeResults9}= - inviso:init_tpm(?MODULE, - failing_function, - 1, - {?MODULE,tpm_init_func1}, - {?MODULE,tpm_call_func1}, - {?MODULE,tpm_return_func1}, - {?MODULE,tpm_remove_func1}), - ?l true=check_noderesults(Nodes,ok,NodeResults9), - ?l [{_,1}]=ets:lookup(inviso_sideeffect_tab,tpm_init_func1), - ?l {ok,NodeResults10}=inviso:tpm(Nodes,?MODULE,failing_function,1,[{'_',[],[{exception_trace}]}]), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults10), - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N,erlang,trace_info,[{?MODULE,failing_function,1},meta]) - end, - Nodes), - ?l lists:foreach(fun(N)->rpc:call(N,?MODULE,failing_function,[nofailure]) end,Nodes), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_call_func1],[{tpm_call_func1,1}],20), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_return_func1],[{tpm_return_func1,1}],20), - ?l lists:foreach(fun(N)->rpc:call(N,?MODULE,failing_function,[failure]) end,Nodes), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_call_func1],[{tpm_call_func1,2}],20), - ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_return_func1],[{tpm_return_func1,3}],20), - - ok. -%% ------------------------------------------------------------------------------ - -%% This function is for testing that appending the tracer to a trace action term -%% works. -activate_deactivate_meta_tracing_tracer(Nodes) -> - ?l {ok,NodeResults}= - inviso:tpm_tracer(Nodes,lists,module_info,0,[{'_',[],[{trace,[all],[call]}]}],void), - ?l true=check_noderesults(Nodes,{ok,1},NodeResults), - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]), - {meta_match_spec,[{'_',[],[{trace,[all],Enable}]}]}= - rpc:call(N,erlang,trace_info,[{lists,module_info,0}, - meta_match_spec]), - true=list_search(Enable,fun({{tracer,P}}) when is_port(P)->true; - (_) -> false - end) - end, - Nodes), - ?l {ok,NodeResults2}= - inviso:ctpm(Nodes,lists,module_info,0), - ?l true=check_noderesults(Nodes,ok,NodeResults2), - ?l lists:foreach(fun(N)->{meta,false}= - rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]) - end, - Nodes), - ok. -%% ------------------------------------------------------------------------------ - -deactivate_meta_tracing(Nodes) -> - ?l lists:foreach(fun(N)->{meta,P}= - rpc:call(N,erlang,trace_info,[{erlang,register,2},meta]), - true=is_pid(P) - end, - Nodes), - ?l lists:foreach(fun(N)->{meta,P}= - rpc:call(N,erlang,trace_info,[{erlang,unregister,1},meta]), - true=is_pid(P) - end, - Nodes), - ?l {ok,NodeResults1}=inviso:ctpm_localnames(), - ?l lists:foreach(fun(N)->{meta,false}= - rpc:call(N,erlang,trace_info,[{erlang,register,2},meta]) end, - Nodes), - ?l lists:foreach(fun(N)->{meta,false}= - rpc:call(N,erlang,trace_info,[{erlang,unregister,1},meta]) - end, - Nodes), - ?l true=check_noderesults(Nodes,{ok,ok},NodeResults1), - - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N, - erlang, - trace_info, - [{global,handle_call,3},meta]) - end, - Nodes), - ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), - {meta,P}=rpc:call(N, - erlang, - trace_info, - [{global,delete_global_name,2},meta]) - end, - Nodes), - ?l {ok,NodeResults1b}=inviso:ctpm_globalnames(), - ?l true=check_noderesults(Nodes,{ok,ok},NodeResults1b), - ?l lists:foreach(fun(N)-> - {meta,false}=rpc:call(N, - erlang, - trace_info, - [{global,handle_call,3},meta]) - end, - Nodes), - ?l lists:foreach(fun(N)-> - {meta,false}=rpc:call(N, - erlang, - trace_info, - [{global,delete_global_name,2},meta]) - end, - Nodes), - - ?l lists:foreach(fun(N)->{meta,P}= - rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]), - true=is_pid(P) - end, - Nodes), - ?l {ok,NodeResults2}=inviso:ctpm(lists,module_info,0), - ?l true=check_noderesults(Nodes,ok,NodeResults2), - ?l lists:foreach(fun(N)->{meta,false}= - rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]) end, - Nodes), - ?l [{_,0}]=ets:lookup(inviso_sideeffect_tab,tpm_init_func1), - ?l {ok,NodeResults3}=inviso:ctpm(math,module_info,1), - ?l true=check_noderesults(Nodes,ok,NodeResults3), - ok. -%% ------------------------------------------------------------------------------ - -%% Functions acting as callbacks for testing the meta tracing mechanisms. -tpm_init_func1(_M,_F,_Arity,PublLD) -> - ets:update_counter(inviso_sideeffect_tab,tpm_init_func1,1), - {ok,PublLD,void}. -tpm_call_func1(_Pid,{call,_Args,_TS},PublLD) -> - ets:update_counter(inviso_sideeffect_tab,tpm_call_func1,1), - {ok,PublLD,void}. -tpm_return_func1(_Pid,{return_from,_ReturnVal,_TS},PublLD) -> - ets:update_counter(inviso_sideeffect_tab,tpm_return_func1,1), - {ok,PublLD,void}; -tpm_return_func1(_Pid,{exception_from,_ReturnVal,_TS},PublLD) -> - ets:update_counter(inviso_sideeffect_tab,tpm_return_func1,1), - ets:update_counter(inviso_sideeffect_tab,tpm_return_func1,1), - {ok,PublLD,void}. -tpm_remove_func1(_M,_F,_Arity,PublLD) -> - ets:update_counter(inviso_sideeffect_tab,tpm_init_func1,-1), - {ok,PublLD}. -%% ------------------------------------------------------------------------------ - - -%% Help function which traces on a function and makes function calls until there -%% are two files in the wrap-set. -fill_and_reach_two_wrapfiles(PrivDir,RegExp,Nodes) -> - ?l lists:foreach(fun(N)->spawn(N,?MODULE,test_proc_init,[]) end,Nodes), - ?l {ok,NodeResults1}=inviso:tpl(Nodes,?MODULE,test_function,0,[]), - ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults1), - ?l {ok,NodeResults2}=inviso:tf(Nodes,inviso_test_proc,[call]), - ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults2), - fill_and_reach_two_wrapfiles_2(PrivDir,RegExp,Nodes), - ?l {ok,NodeResults3}=inviso:ctf(Nodes,inviso_test_proc,[call]), - ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults3), - ?l {ok,NodeResults4}=inviso:ctpl(Nodes,?MODULE,test_function,0), - ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults4), - ok. - -fill_and_reach_two_wrapfiles_2(PrivDir,RegExp,[Node|Rest]) -> - ?l ok=rpc:call(Node,?MODULE,fill_and_reach_two_wrapfiles_3,[PrivDir,RegExp]), - fill_and_reach_two_wrapfiles_2(PrivDir,RegExp,Rest); -fill_and_reach_two_wrapfiles_2(_,_,[]) -> - ok. - -fill_and_reach_two_wrapfiles_3(Dir,RegExp) -> - ok=send_to_test_proc({apply,?MODULE,test_function,[]}, - fun reach_two_wraps_stopfun/1, - {Dir,RegExp++atom_to_list(node())}, - 100). - -%% Help function intended to be used as fun in a send_to_test_proc/4 call. -%% The function lists the content of Dir and looks for occurancies of String. -%% If two files containing the string String are found, 'done' is returned. -%% Otherwise 'continue'. -reach_two_wraps_stopfun({Dir,RegExp}) -> - case file:list_dir(Dir) of - {ok,FileNames} -> - case how_many_files_regexp(FileNames,RegExp,0) of - {ok,2} -> - done; - _ -> - continue - end; - {error,_Reason} -> - error - end. -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Help function for the overload tests. These functions are used as callbacks. -%% ------------------------------------------------------------------------------ - -overload1(_) -> - ets:update_counter(inviso_sideeffect_tab,ovl1,1), - ok. -%% This function is used when timeout occurs inside the runtime component. -%% That is it is time to check for overload. -overload2({timeout,overload2i_data}) -> - ets:update_counter(inviso_sideeffect_tab,ovl2,1), - ok. -overload2i() -> - ets:insert(inviso_sideeffect_tab,{ovl2,0}), - {ok,overload2i_data}. -overload2r(overload2i_data) -> - ets:delete(inviso_sideeffect_tab,ovl2). - -%% This function is used when timeout occurs inside the runtime component. -%% That is it is time to check for overload. -overload3({timeout,overload3i_data}) -> - ets:update_counter(inviso_sideeffect_tab,ovl3,1), - ok; -overload3(_) -> % Must handle garbage too. - ignore. -overload3i() -> - ets:insert(inviso_sideeffect_tab,{ovl3,0}), - {ok,overload3i_data}. -overload3r(overload3i_data) -> - ets:insert(inviso_sideeffect_tab,{ovl3r,done}), - ets:delete(inviso_sideeffect_tab,ovl3). - -overload4(_) -> - case ets:lookup(inviso_sideeffect_tab,ovl4_suspend) of - [] -> % We are supposed to be running. - ets:update_counter(inviso_sideeffect_tab,ovl4,1), - ok; - [_] -> - {suspend,test} - end. - -%% This function is used when overload check is done by icomming message. -overload5({msg,{test_of_loadcheck,overload5i_data}}) -> - ets:update_counter(inviso_sideeffect_tab,ovl5,1), - ok; -overload5(_) -> - ignore. -overload5i() -> - ets:insert(inviso_sideeffect_tab,{ovl5,0}), - {ok,overload5i_data}. -overload5r(overload5i_data) -> - ets:delete(inviso_sideeffect_tab,ovl5), - ets:insert(inviso_sideeffect_tab,{ovl5r,done}); -overload5r(X) -> - erlang:display({'***',overload5r,X}). - -overload6(_) -> - ets:update_counter(inviso_sideeffect_tab,ovl6,1), - ok. -%% ------------------------------------------------------------------------------ - -%% ------------------------------------------------------------------------------ -%% Help function for the subscription tests. These function implements a collector -%% process which will subscribe to inviso_events from the control component. -%% ------------------------------------------------------------------------------ - -%% Function which can be used to check if an inviso_event has arrived. The function -%% takes a fun which tests the messages. -check_msg_collector([],_,_) -> - true; -check_msg_collector(_,_,0) -> - false; -check_msg_collector(Nodes,Fun,T) -> - Ref=make_ref(), - inviso_collector_proc ! {fetch_message,self(),Ref,Fun}, - receive - {inviso,Ref,{true,Node}} -> - check_msg_collector(lists:delete(Node,Nodes),Fun,T-1); - {inviso,Ref,false} -> - timer:sleep(100), - check_msg_collector(Nodes,Fun,T-1) - end. - -%% Spawn on this function to get a subscriber. -inviso_msg_collector() -> - register(inviso_collector_proc,self()), - inviso_msg_collector_loop([]). - -inviso_msg_collector_loop(Msgs) -> - receive - {fetch_message,From,Ref,Fun} -> - {NewMsgs,Reply}=inviso_msg_collector_selector(Msgs,Fun,[]), - From ! {inviso,Ref,Reply}, - inviso_msg_collector_loop(NewMsgs); - Msg -> - inviso_msg_collector_loop([Msg|Msgs]) - end. - -inviso_msg_collector_selector([M|Rest],Fun,Accum) -> - case Fun(M) of - {true,X} -> - {Rest++Accum,{true,X}}; - _ -> - inviso_msg_collector_selector(Rest,Fun,[M|Accum]) - end; -inviso_msg_collector_selector([],_,Accum) -> - {Accum,false}. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% Help functions -%% ============================================================================== - -list_search([E|Rest],Fun) -> - case Fun(E) of - true -> - true; - false -> - list_search(Rest,Fun) - end; -list_search([],_Fun) -> - false. -%% ------------------------------------------------------------------------------ - -%% Help function checking that there is a Result for each node in Nodes. -%% Returns 'true' if successful. -check_noderesults(Nodes,Fun,[{Node,Result}|Rest]) when is_function(Fun) -> - case Fun({Node,Result}) of - true -> - case lists:member(Node,Nodes) of - true -> - check_noderesults(lists:delete(Node,Nodes),Fun,Rest); - false -> % Not good. - unknown_node_in_returnvalue - end; - _ -> - illegal_result - end; -check_noderesults(Nodes,Result,[{Node,Result}|Rest]) -> - case lists:member(Node,Nodes) of - true -> - check_noderesults(lists:delete(Node,Nodes),Result,Rest); - false -> % Not good. - unknown_node_in_returnvalue - end; -check_noderesults([],_,[]) -> - true; -check_noderesults(X,Y,Z) -> - io:format("Bad arguments to check noderesults:~w~n~w~n~w~n",[X,Y,Z]), - false. -%% ------------------------------------------------------------------------------ - -%% Help function doing rpc on all nodes in Nodes calling M:F. Returns 'true' if -%% successful. -check_on_nodes([Node|Rest],M,F,Args,Result) when Node==node() -> - if - is_function(Result) -> - ?l true=Result(apply(M,F,Args)); - true -> - ?l Result=apply(M,F,Args) - end, - check_on_nodes(Rest,M,F,Args,Result); -check_on_nodes([Node|Rest],M,F,Args,Result) -> - if - is_function(Result) -> - ?l true=Result(rpc:call(Node,M,F,Args)); - true -> - ?l Result=rpc:call(Node,M,F,Args) - end, - check_on_nodes(Rest,M,F,Args,Result); -check_on_nodes([],_,_,_,_) -> - true. -%% ------------------------------------------------------------------------------ - -%% Help function which given a list of files searches through it and returns -%% how many satisfies the RegExp. -%% Returns {ok,N}. -how_many_files_regexp([],_,N) -> - {ok,N}; -how_many_files_regexp([FName|Rest],RegExp,N) -> - case re:run(FName,RegExp,[{capture,none}]) of - match -> - how_many_files_regexp(Rest,RegExp,N+1); - nomatch -> - how_many_files_regexp(Rest,RegExp,N); - {error,Reason} -> - test_server:fail(Reason) - end. -%% ------------------------------------------------------------------------------ - -%% Help function killing a bunch of registered processes. -process_killer([RegName|Rest]) -> - case whereis(RegName) of - undefined -> - case global:whereis_name(RegName) of - undefined -> - process_killer(Rest); - P when is_pid(P) -> - if - node()==node(P) -> - exit(P,kill); - true -> - true - end, - process_killer(Rest) - end; - P when is_pid(P) -> - exit(P,kill), - process_killer(Rest) - end; -process_killer([]) -> - true. -%% ------------------------------------------------------------------------------ - -%% Help function which waits for a function call to become Result. This is useful -%% if what we are waiting for can happend independantly of indications we have -%% access to. -poll(_,_,_,_,0) -> - error; -poll(M,F,Args,Result,Times) -> - try apply(M,F,Args) of - What when is_function(Result) -> - case Result(What) of - true -> - ok; - _ -> - timer:sleep(100), - poll(M,F,Args,Result,Times-1) - end; - Result -> - ok; - _ -> - timer:sleep(100), - poll(M,F,Args,Result,Times-1) - catch - error:Reason -> - io:format("Apply in suite-function poll/5 failed, ~w~n",[Reason]), - timer:sleep(100), - poll(M,F,Args,Result,Times-1) - end. -%% ------------------------------------------------------------------------------ - -insert_remotenode_config(Name,Node,Config) -> - [{remotenode,{Name,Node}}|Config]. -%% ------------------------------------------------------------------------------ - -insert_timetraphandle_config(Handle,Config) -> - [{timetraphandle,Handle}|Config]. -%% ------------------------------------------------------------------------------ - -get_remotenode_config(Name, [{remotenode, {Name, Node}}| _Cs]) -> - Node; -get_remotenode_config(Name, [_ | Cs]) -> - get_remotenode_config(Name, Cs); -get_remotenode_config(Name, []) -> - exit({no_remotenode, Name}). - -%% ------------------------------------------------------------------------------ - -get_timetraphandle_config(Config) -> - {value,{_,Handle}}=lists:keysearch(timetraphandle,1,Config), - Handle. -%% ------------------------------------------------------------------------------ - -get_remotenodes_config([{remotenode,{_Name,Node}}|Config]) -> - [Node|get_remotenodes_config(Config)]; -get_remotenodes_config([_|Config]) -> - get_remotenodes_config(Config); -get_remotenodes_config([]) -> - []. -%% ------------------------------------------------------------------------------ - -remove_remotenode_config(Name, [{remotenode, {Name, _}} | Cs]) -> - Cs; -remove_remotenode_config(Name, [C | Cs]) -> - [C | remove_remotenode_config(Name, Cs)]; -remove_remotenode_config(_Name, []) -> - []. - -%% ------------------------------------------------------------------------------ - -remove_timetraphandle_config(Config) -> - lists:keydelete(timetraphandle,1,Config). -%% ------------------------------------------------------------------------------ - -%% This function can be meta traced in order to check that exception_trace works. -%% Must be exported. -failing_function(nofailure) -> - true; -failing_function(failure) -> - exit(failure). -%% ------------------------------------------------------------------------------ - -%% ============================================================================== -%% Code for a test process which can be started. -%% ============================================================================== - -test_proc_init() -> - register(inviso_test_proc,self()), - test_proc_loop(). - -test_proc_loop() -> - receive - {apply,M,F,Args} -> - apply(M,F,Args), - test_proc_loop(); - X -> - io:format("Got ~w~n",[X]), - test_proc_loop() - end. - -global_test_proc_init() -> - global:register_name(global_inviso_test_proc,self()), - test_proc_loop(). -%% ------------------------------------------------------------------------------ - -send_to_test_proc(_,_,_,0) -> - error; -send_to_test_proc(Msg,Fun,FunArg,N) -> - inviso_test_proc ! Msg, - case Fun(FunArg) of - done -> - ok; - error -> - test_server:fail(send_to_test_proc); - _ -> - send_to_test_proc(Msg,Fun,FunArg,N-1) - end. -%% ------------------------------------------------------------------------------ - - -%% This function is here to be traced on by the inviso_test_proc. Must be exported. -test_function() -> - 1+1. -%% ------------------------------------------------------------------------------ - - -%% ============================================================================== -%% Code for a test side effect table process. -%% ============================================================================== - -%% The side effect logger is a process owning a public ETS table. The idea is that -%% various callback functions can write in the table when called. In that way -%% correct calling of the call-backs can be verified. -start_side_effect_logger(Node) -> - ?l true=is_pid(spawn(Node,?MODULE,side_effect_logger_proc,[])), - ?l ok=poll(rpc,call,[Node,ets,lookup,[inviso_sideeffect_tab,foo]],[],20). - -%% This one must be exported. -side_effect_logger_proc() -> - register(inviso_tab_proc,self()), % So we can kill it later. - ets:new(inviso_sideeffect_tab,[public,named_table]), - side_effect_logger_proc_2(). - -side_effect_logger_proc_2() -> - receive - _X -> % This process is not expecting anything! - side_effect_logger_proc_2() - end. -%% ------------------------------------------------------------------------------ diff --git a/lib/runtime_tools/test/inviso_testmodule1_foo.erl b/lib/runtime_tools/test/inviso_testmodule1_foo.erl deleted file mode 100644 index a7a22cad39..0000000000 --- a/lib/runtime_tools/test/inviso_testmodule1_foo.erl +++ /dev/null @@ -1,9 +0,0 @@ --module(inviso_testmodule1_foo). - --compile(export_all). - -%% The purpose of this module is simply to have a module that is -%% guaranteed not loaded. - -foo() -> - true. diff --git a/lib/snmp/test/exp/snmp_agent_bl_test.erl b/lib/snmp/test/exp/snmp_agent_bl_test.erl index a5a6e8260b..263319aa5d 100644 --- a/lib/snmp/test/exp/snmp_agent_bl_test.erl +++ b/lib/snmp/test/exp/snmp_agent_bl_test.erl @@ -95,24 +95,13 @@ end_per_testcase(_Case, Config) when list(Config) -> Config. cases() -> - case ?OSTYPE() of - vxworks -> - %% No crypto app, so skip v3 testcases - [ - app_info, - test_v1, test_v2, test_v1_v2, - test_multi_threaded, - mib_storage, - tickets]; - _Else -> - [ - app_info, - test_v1, test_v2, test_v1_v2, test_v3, - test_multi_threaded, - mib_storage, - tickets - ] - end. + [ + app_info, + test_v1, test_v2, test_v1_v2, test_v3, + test_multi_threaded, + mib_storage, + tickets + ]. %%%----------------------------------------------------------------- @@ -1187,21 +1176,16 @@ init_v3(Config) when list(Config) -> %% and we will be stuck with a bunch of mnesia tables for %% the rest of this suite... ?DBG("start_agent -> start crypto app",[]), - case os:type() of - vxworks -> - no_crypto; - _ -> - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end + case ?CRYPTO_START() of + ok -> + case ?CRYPTO_SUPPORT() of + {no, Reason} -> + ?SKIP({unsupported_encryption, Reason}); + yes -> + ok + end; + {error, Reason} -> + ?SKIP({failed_starting_crypto, Reason}) end, SaNode = ?config(snmp_sa, Config), create_tables(SaNode), @@ -5071,12 +5055,7 @@ run(F, A, Opts) -> CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), Community = snmp_misc:get_option(community, Opts, "all-rights"), ?DBG("run -> start crypto app",[]), - Crypto = case os:type() of - vxworks -> - no_crypto; - _ -> - ?CRYPTO_START() - end, + Crypto = ?CRYPTO_START(), ?DBG("run -> Crypto: ~p",[Crypto]), catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", diff --git a/lib/snmp/test/exp/snmp_agent_ms_test.erl b/lib/snmp/test/exp/snmp_agent_ms_test.erl index d5eaea55fa..340b95f512 100644 --- a/lib/snmp/test/exp/snmp_agent_ms_test.erl +++ b/lib/snmp/test/exp/snmp_agent_ms_test.erl @@ -231,17 +231,13 @@ end_per_testcase(_Case, Config) when list(Config) -> Config. cases() -> -case ?OSTYPE() of - vxworks -> - [app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_multi_threaded}, - {group, mib_storage}, {group, tickets}]; - _Else -> - [app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_v3}, - {group, test_multi_threaded}, {group, mib_storage}, - {group, tickets}] -end. + [ + app_info, + {group, test_v1}, {group, test_v2}, + {group, test_v1_v2}, {group, test_v3}, + {group, test_multi_threaded}, {group, mib_storage}, + {group, tickets} + ]. %%%----------------------------------------------------------------- @@ -1221,21 +1217,16 @@ init_v3(Config) when list(Config) -> %% and we will be stuck with a bunch of mnesia tables for %% the rest of this suite... ?DBG("start_agent -> start crypto app",[]), - case os:type() of - vxworks -> - no_crypto; - _ -> - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end + case ?CRYPTO_START() of + ok -> + case ?CRYPTO_SUPPORT() of + {no, Reason} -> + ?SKIP({unsupported_encryption, Reason}); + yes -> + ok + end; + {error, Reason} -> + ?SKIP({failed_starting_crypto, Reason}) end, SaNode = ?config(snmp_sa, Config), create_tables(SaNode), @@ -5066,12 +5057,7 @@ run(F, A, Opts) -> CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), Community = snmp_misc:get_option(community, Opts, "all-rights"), ?DBG("run -> start crypto app",[]), - Crypto = case os:type() of - vxworks -> - no_crypto; - _ -> - ?CRYPTO_START() - end, + Crypto = ?CRYPTO_START(), ?DBG("run -> Crypto: ~p",[Crypto]), catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", diff --git a/lib/snmp/test/exp/snmp_agent_mt_test.erl b/lib/snmp/test/exp/snmp_agent_mt_test.erl index d62bc6c2e7..33d104305a 100644 --- a/lib/snmp/test/exp/snmp_agent_mt_test.erl +++ b/lib/snmp/test/exp/snmp_agent_mt_test.erl @@ -231,17 +231,13 @@ end_per_testcase(_Case, Config) when list(Config) -> Config. cases() -> -case ?OSTYPE() of - vxworks -> - [app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_multi_threaded}, - {group, mib_storage}, {group, tickets}]; - _Else -> - [app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_v3}, - {group, test_multi_threaded}, {group, mib_storage}, - {group, tickets}] -end. + [ + app_info, + {group, test_v1}, {group, test_v2}, + {group, test_v1_v2}, {group, test_v3}, + {group, test_multi_threaded}, {group, mib_storage}, + {group, tickets} + ]. %%%----------------------------------------------------------------- @@ -1221,21 +1217,16 @@ init_v3(Config) when list(Config) -> %% and we will be stuck with a bunch of mnesia tables for %% the rest of this suite... ?DBG("start_agent -> start crypto app",[]), - case os:type() of - vxworks -> - no_crypto; - _ -> - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end + case ?CRYPTO_START() of + ok -> + case ?CRYPTO_SUPPORT() of + {no, Reason} -> + ?SKIP({unsupported_encryption, Reason}); + yes -> + ok + end; + {error, Reason} -> + ?SKIP({failed_starting_crypto, Reason}) end, SaNode = ?config(snmp_sa, Config), create_tables(SaNode), @@ -5066,12 +5057,7 @@ run(F, A, Opts) -> CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), Community = snmp_misc:get_option(community, Opts, "all-rights"), ?DBG("run -> start crypto app",[]), - Crypto = case os:type() of - vxworks -> - no_crypto; - _ -> - ?CRYPTO_START() - end, + Crypto = ?CRYPTO_START(), ?DBG("run -> Crypto: ~p",[Crypto]), catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", diff --git a/lib/snmp/test/exp/snmp_agent_v2_test.erl b/lib/snmp/test/exp/snmp_agent_v2_test.erl index a86449ca72..dc3d2efbb3 100644 --- a/lib/snmp/test/exp/snmp_agent_v2_test.erl +++ b/lib/snmp/test/exp/snmp_agent_v2_test.erl @@ -231,17 +231,13 @@ end_per_testcase(_Case, Config) when list(Config) -> Config. cases() -> -case ?OSTYPE() of - vxworks -> - [app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_multi_threaded}, - {group, mib_storage}, {group, tickets}]; - _Else -> - [app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_v3}, - {group, test_multi_threaded}, {group, mib_storage}, - {group, tickets}] -end. + [ + app_info, + {group, test_v1}, {group, test_v2}, + {group, test_v1_v2}, {group, test_v3}, + {group, test_multi_threaded}, {group, mib_storage}, + {group, tickets} + ]. %%%----------------------------------------------------------------- @@ -1221,21 +1217,16 @@ init_v3(Config) when list(Config) -> %% and we will be stuck with a bunch of mnesia tables for %% the rest of this suite... ?DBG("start_agent -> start crypto app",[]), - case os:type() of - vxworks -> - no_crypto; - _ -> - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end + case ?CRYPTO_START() of + ok -> + case ?CRYPTO_SUPPORT() of + {no, Reason} -> + ?SKIP({unsupported_encryption, Reason}); + yes -> + ok + end; + {error, Reason} -> + ?SKIP({failed_starting_crypto, Reason}) end, SaNode = ?config(snmp_sa, Config), create_tables(SaNode), @@ -5066,12 +5057,7 @@ run(F, A, Opts) -> CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), Community = snmp_misc:get_option(community, Opts, "all-rights"), ?DBG("run -> start crypto app",[]), - Crypto = case os:type() of - vxworks -> - no_crypto; - _ -> - ?CRYPTO_START() - end, + Crypto = ?CRYPTO_START(), ?DBG("run -> Crypto: ~p",[Crypto]), catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", diff --git a/lib/snmp/test/exp/snmp_agent_v3_test.erl b/lib/snmp/test/exp/snmp_agent_v3_test.erl index c72d845bf2..b0bc6384e8 100644 --- a/lib/snmp/test/exp/snmp_agent_v3_test.erl +++ b/lib/snmp/test/exp/snmp_agent_v3_test.erl @@ -231,17 +231,12 @@ end_per_testcase(_Case, Config) when list(Config) -> Config. cases() -> -case ?OSTYPE() of - vxworks -> - [app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_multi_threaded}, - {group, mib_storage}, {group, tickets}]; - _Else -> - [app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_v3}, - {group, test_multi_threaded}, {group, mib_storage}, - {group, tickets}] -end. + [ + app_info, {group, test_v1}, {group, test_v2}, + {group, test_v1_v2}, {group, test_v3}, + {group, test_multi_threaded}, {group, mib_storage}, + {group, tickets} + ]. %%%----------------------------------------------------------------- @@ -1221,21 +1216,16 @@ init_v3(Config) when list(Config) -> %% and we will be stuck with a bunch of mnesia tables for %% the rest of this suite... ?DBG("start_agent -> start crypto app",[]), - case os:type() of - vxworks -> - no_crypto; - _ -> - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end + case ?CRYPTO_START() of + ok -> + case ?CRYPTO_SUPPORT() of + {no, Reason} -> + ?SKIP({unsupported_encryption, Reason}); + yes -> + ok + end; + {error, Reason} -> + ?SKIP({failed_starting_crypto, Reason}) end, SaNode = ?config(snmp_sa, Config), create_tables(SaNode), @@ -5066,12 +5056,7 @@ run(F, A, Opts) -> CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), Community = snmp_misc:get_option(community, Opts, "all-rights"), ?DBG("run -> start crypto app",[]), - Crypto = case os:type() of - vxworks -> - no_crypto; - _ -> - ?CRYPTO_START() - end, + Crypto = ?CRYPTO_START(), ?DBG("run -> Crypto: ~p",[Crypto]), catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk index a444cab6d6..3d658bf8e8 100644 --- a/lib/snmp/test/modules.mk +++ b/lib/snmp/test/modules.mk @@ -79,5 +79,5 @@ MIB_FILES = \ Test2.mib \ Test3.mib -SPECS = snmp.spec snmp.spec.vxworks +SPECS = snmp.spec diff --git a/lib/snmp/test/snmp.spec.vxworks b/lib/snmp/test/snmp.spec.vxworks deleted file mode 100644 index 654aa96d8c..0000000000 --- a/lib/snmp/test/snmp.spec.vxworks +++ /dev/null @@ -1,4 +0,0 @@ -{topcase, {dir, "../snmp_test"}}. -{skip, {snmp_SUITE, test_v3, "Requires crypto"}}. - - diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index 8ee5dd534d..3575dcc970 100644 --- a/lib/snmp/test/snmp_agent_test.erl +++ b/lib/snmp/test/snmp_agent_test.erl @@ -433,29 +433,16 @@ end_per_testcase2(_Case, Config) -> cases() -> - case ?OSTYPE() of - vxworks -> - [ - {group, misc}, - {group, test_v1}, - {group, test_v2}, - {group, test_v1_v2}, - {group, test_multi_threaded}, - {group, mib_storage}, - {group, tickets1} - ]; - _Else -> - [ - {group, misc}, - {group, test_v1}, - {group, test_v2}, - {group, test_v1_v2}, - {group, test_v3}, - {group, test_multi_threaded}, - {group, mib_storage}, - {group, tickets1} - ] - end. + [ + {group, misc}, + {group, test_v1}, + {group, test_v2}, + {group, test_v1_v2}, + {group, test_v3}, + {group, test_multi_threaded}, + {group, mib_storage}, + {group, tickets1} + ]. %%%----------------------------------------------------------------- @@ -1280,21 +1267,16 @@ init_v3(Config) when is_list(Config) -> %% and we will be stuck with a bunch of mnesia tables for %% the rest of this suite... ?DBG("start_agent -> start crypto app",[]), - case os:type() of - vxworks -> - no_crypto; - _ -> - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end + case ?CRYPTO_START() of + ok -> + case ?CRYPTO_SUPPORT() of + {no, Reason} -> + ?SKIP({unsupported_encryption, Reason}); + yes -> + ok + end; + {error, Reason} -> + ?SKIP({failed_starting_crypto, Reason}) end, SaNode = ?config(snmp_sa, Config), create_tables(SaNode), diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl index 238832b7c1..757aebfa9b 100644 --- a/lib/snmp/test/snmp_agent_test_lib.erl +++ b/lib/snmp/test/snmp_agent_test_lib.erl @@ -338,12 +338,7 @@ run(Mod, Func, Args, Opts) -> CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), Community = snmp_misc:get_option(community, Opts, "all-rights"), ?DBG("run -> start crypto app",[]), - Crypto = case os:type() of - vxworks -> - no_crypto; - _ -> - ?CRYPTO_START() - end, + Crypto = ?CRYPTO_START(), ?DBG("run -> Crypto: ~p", [Crypto]), catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", @@ -729,7 +724,6 @@ expect2(Id, F) -> get_timeout() -> get_timeout(os:type()). -get_timeout(vxworks) -> 7000; get_timeout(_) -> 3500. receive_pdu(To) -> @@ -1540,7 +1534,6 @@ rpc(Node, F, A) -> %% timeout() -> %% timeout(os:type()). %% -%% timeout(vxworks) -> 7000; %% timeout(_) -> 3500. diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl index 26115a0c74..e327456bc4 100644 --- a/lib/snmp/test/snmp_test_lib.erl +++ b/lib/snmp/test/snmp_test_lib.erl @@ -516,8 +516,6 @@ warning_msg(F, A) -> timeout(T) -> trunc(timeout(T, os:type())). -timeout(T, vxworks) -> - 5 * T * timetrap_scale_factor(); timeout(T, _) -> T * timetrap_scale_factor(). diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl index 499cf7abcf..40fcbce8f1 100644 --- a/lib/snmp/test/snmp_test_mgr.erl +++ b/lib/snmp/test/snmp_test_mgr.erl @@ -161,7 +161,6 @@ get_timeout() -> get_timeout(os:type()) end. -get_timeout(vxworks) -> 7000; get_timeout(_) -> 3500. %%---------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh.spec.vxworks b/lib/ssh/test/ssh.spec.vxworks deleted file mode 100644 index 81f665283c..0000000000 --- a/lib/ssh/test/ssh.spec.vxworks +++ /dev/null @@ -1,3 +0,0 @@ -{topcase, {dir, "../ssh_test"}}. -{require_nodenames, 1}. -%{skip, {M, F, "Not yet implemented"}}. diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml index 7b8e279788..06cfad0b0b 100644 --- a/lib/stdlib/doc/src/binary.xml +++ b/lib/stdlib/doc/src/binary.xml @@ -77,41 +77,30 @@ </datatypes> <funcs> <func> - <name>at(Subject, Pos) -> byte()</name> + <name name="at" arity="2"/> <fsummary>Returns the byte at a specific position in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pos = integer() >= 0</v> - </type> <desc> - <p>Returns the byte at position <c>Pos</c> (zero-based) in the binary - <c>Subject</c> as an integer. If <c>Pos</c> >= <c>byte_size(Subject)</c>, + <p>Returns the byte at position <c><anno>Pos</anno></c> (zero-based) in the binary + <c><anno>Subject</anno></c> as an integer. If <c><anno>Pos</anno></c> >= <c>byte_size(<anno>Subject</anno>)</c>, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>bin_to_list(Subject) -> [byte()]</name> + <name name="bin_to_list" arity="1"/> <fsummary>Convert a binary to a list of integers</fsummary> - <type> - <v>Subject = binary()</v> - </type> <desc> - <p>The same as <c>bin_to_list(Subject,{0,byte_size(Subject)})</c>.</p> + <p>The same as <c>bin_to_list(<anno>Subject</anno>,{0,byte_size(<anno>Subject</anno>)})</c>.</p> </desc> </func> <func> - <name>bin_to_list(Subject, PosLen) -> [byte()]</name> + <name name="bin_to_list" arity="2"/> <fsummary>Convert a binary to a list of integers</fsummary> - <type> - <v>Subject = binary()</v> - <v>PosLen = part()</v> - </type> <desc> - <p>Converts <c>Subject</c> to a list of <c>byte()</c>s, each representing + <p>Converts <c><anno>Subject</anno></c> to a list of <c>byte()</c>s, each representing the value of one byte. The <c>part()</c> denotes which part of the <c>binary()</c> to convert. Example:</p> @@ -120,27 +109,19 @@ "rla" %% or [114,108,97] in list notation. </code> - <p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> + <p>If <c><anno>PosLen</anno></c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>bin_to_list(Subject, Pos, Len) -> [byte()]</name> + <name name="bin_to_list" arity="3"/> <fsummary>Convert a binary to a list of integers</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pos = integer() >= 0</v> - <v>Len = integer() >= 0</v> - </type> <desc> - <p>The same as<c> bin_to_list(Subject,{Pos,Len})</c>.</p> + <p>The same as<c> bin_to_list(<anno>Subject</anno>,{<anno>Pos</anno>,<anno>Len</anno>})</c>.</p> </desc> </func> <func> - <name>compile_pattern(Pattern) -> cp()</name> + <name name="compile_pattern" arity="1"/> <fsummary>Pre-compiles a binary search pattern</fsummary> - <type> - <v>Pattern = binary() | [ binary() ]</v> - </type> <desc> <p>Builds an internal structure representing a compilation of a @@ -155,7 +136,7 @@ <p>When a list of binaries is given, it denotes a set of alternative binaries to search for. I.e if <c>[<<"functional">>,<<"programming">>]</c> - is given as <c>Pattern</c>, this + is given as <c><anno>Pattern</anno></c>, this means "either <c><<"functional">></c> or <c><<"programming">></c>". The pattern is a set of alternatives; when only a single binary is given, the set has @@ -163,32 +144,25 @@ <p>The list of binaries used for search alternatives shall be flat and proper.</p> - <p>If <c>Pattern</c> is not a binary or a flat proper list of binaries with length > 0, + <p>If <c><anno>Pattern</anno></c> is not a binary or a flat proper list of binaries with length > 0, a <c>badarg</c> exception will be raised.</p> </desc> </func> <func> - <name>copy(Subject) -> binary()</name> + <name name="copy" arity="1"/> <fsummary>Creates a duplicate of a binary</fsummary> - <type> - <v>Subject = binary()</v> - </type> <desc> - <p>The same as <c>copy(Subject, 1)</c>.</p> + <p>The same as <c>copy(<anno>Subject</anno>, 1)</c>.</p> </desc> </func> <func> - <name>copy(Subject,N) -> binary()</name> + <name name="copy" arity="2"/> <fsummary>Duplicates a binary N times and creates a new</fsummary> - <type> - <v>Subject = binary()</v> - <v>N = integer() >= 0</v> - </type> <desc> - <p>Creates a binary with the content of <c>Subject</c> duplicated <c>N</c> times.</p> + <p>Creates a binary with the content of <c><anno>Subject</anno></c> duplicated <c><anno>N</anno></c> times.</p> - <p>This function will always create a new binary, even if <c>N = + <p>This function will always create a new binary, even if <c><anno>N</anno> = 1</c>. By using <c>copy/1</c> on a binary referencing a larger binary, one might free up the larger binary for garbage collection.</p> @@ -201,32 +175,23 @@ large binaries are no longer used in any process, deliberate copying might be a good idea.</p> </note> - <p>If <c>N</c> < <c>0</c>, a <c>badarg</c> exception is raised.</p> + <p>If <c><anno>N</anno></c> < <c>0</c>, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>decode_unsigned(Subject) -> Unsigned</name> + <name name="decode_unsigned" arity="1"/> <fsummary>Decode a whole binary into an integer of arbitrary size</fsummary> - <type> - <v>Subject = binary()</v> - <v>Unsigned = integer() >= 0</v> - </type> <desc> - <p>The same as <c>decode_unsigned(Subject,big)</c>.</p> + <p>The same as <c>decode_unsigned(<anno>Subject</anno>, big)</c>.</p> </desc> </func> <func> - <name>decode_unsigned(Subject, Endianess) -> Unsigned</name> + <name name="decode_unsigned" arity="2"/> <fsummary>Decode a whole binary into an integer of arbitrary size</fsummary> - <type> - <v>Subject = binary()</v> - <v>Endianess = big | little</v> - <v>Unsigned = integer() >= 0</v> - </type> <desc> <p>Converts the binary digit representation, in big or little - endian, of a positive integer in <c>Subject</c> to an Erlang <c>integer()</c>.</p> + endian, of a positive integer in <c><anno>Subject</anno></c> to an Erlang <c>integer()</c>.</p> <p>Example:</p> @@ -237,22 +202,15 @@ </desc> </func> <func> - <name>encode_unsigned(Unsigned) -> binary()</name> + <name name="encode_unsigned" arity="1"/> <fsummary>Encodes an unsigned integer into the minimal binary</fsummary> - <type> - <v>Unsigned = integer() >= 0</v> - </type> <desc> - <p>The same as <c>encode_unsigned(Unsigned,big)</c>.</p> + <p>The same as <c>encode_unsigned(<anno>Unsigned</anno>, big)</c>.</p> </desc> </func> <func> - <name>encode_unsigned(Unsigned,Endianess) -> binary()</name> + <name name="encode_unsigned" arity="2"/> <fsummary>Encodes an unsigned integer into the minimal binary</fsummary> - <type> - <v>Unsigned = integer() >= 0</v> - <v>Endianess = big | little</v> - </type> <desc> <p>Converts a positive integer to the smallest possible @@ -268,51 +226,39 @@ </desc> </func> <func> - <name>first(Subject) -> byte()</name> + <name name="first" arity="1"/> <fsummary>Returns the first byte of a binary</fsummary> - <type> - <v>Subject = binary()</v> - </type> <desc> - <p>Returns the first byte of the binary <c>Subject</c> as an integer. If the - size of <c>Subject</c> is zero, a <c>badarg</c> exception is raised.</p> + <p>Returns the first byte of the binary <c><anno>Subject</anno></c> as an integer. If the + size of <c><anno>Subject</anno></c> is zero, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>last(Subject) -> byte()</name> + <name name="last" arity="1"/> <fsummary>Returns the last byte of a binary</fsummary> - <type> - <v>Subject = binary()</v> - </type> <desc> - <p>Returns the last byte of the binary <c>Subject</c> as an integer. If the - size of <c>Subject</c> is zero, a <c>badarg</c> exception is raised.</p> + <p>Returns the last byte of the binary <c><anno>Subject</anno></c> as an integer. If the + size of <c><anno>Subject</anno></c> is zero, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>list_to_bin(ByteList) -> binary()</name> + <name name="list_to_bin" arity="1"/> <fsummary>Convert a list of integers and binaries to a binary</fsummary> - <type> - <v>ByteList = iodata() (see module erlang)</v> - </type> <desc> <p>Works exactly as <c>erlang:list_to_binary/1</c>, added for completeness.</p> </desc> </func> <func> - <name>longest_common_prefix(Binaries) -> integer() >= 0</name> + <name name="longest_common_prefix" arity="1"/> <fsummary>Returns length of longest common prefix for a set of binaries</fsummary> - <type> - <v>Binaries = [ binary() ]</v> - </type> <desc> <p>Returns the length of the longest common prefix of the - binaries in the list <c>Binaries</c>. Example:</p> + binaries in the list <c><anno>Binaries</anno></c>. Example:</p> <code> 1> binary:longest_common_prefix([<<"erlang">>,<<"ergonomy">>]). @@ -321,19 +267,16 @@ 0 </code> - <p>If <c>Binaries</c> is not a flat list of binaries, a <c>badarg</c> exception is raised.</p> + <p>If <c><anno>Binaries</anno></c> is not a flat list of binaries, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>longest_common_suffix(Binaries) -> integer() >= 0</name> + <name name="longest_common_suffix" arity="1"/> <fsummary>Returns length of longest common suffix for a set of binaries</fsummary> - <type> - <v>Binaries = [ binary() ]</v> - </type> <desc> <p>Returns the length of the longest common suffix of the - binaries in the list <c>Binaries</c>. Example:</p> + binaries in the list <c><anno>Binaries</anno></c>. Example:</p> <code> 1> binary:longest_common_suffix([<<"erlang">>,<<"fang">>]). @@ -347,35 +290,24 @@ </desc> </func> <func> - <name>match(Subject, Pattern) -> Found | <c>nomatch</c></name> + <name name="match" arity="2"/> <fsummary>Searches for the first match of a pattern in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pattern = binary() | [ binary() ] | cp()</v> - <v>Found = part()</v> - </type> <desc> - <p>The same as <c>match(Subject, Pattern, [])</c>.</p> + <p>The same as <c>match(<anno>Subject</anno>, <anno>Pattern</anno>, [])</c>.</p> </desc> </func> <func> - <name>match(Subject,Pattern,Options) -> Found | <c>nomatch</c></name> + <name name="match" arity="3"/> + <type name="part"/> <fsummary>Searches for the first match of a pattern in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pattern = binary() | [ binary() ] | cp()</v> - <v>Found = part()</v> - <v>Options = [ Option ]</v> - <v>Option = {scope, part()}</v> - </type> <desc> - <p>Searches for the first occurrence of <c>Pattern</c> in <c>Subject</c> and + <p>Searches for the first occurrence of <c><anno>Pattern</anno></c> in <c><anno>Subject</anno></c> and returns the position and length.</p> - <p>The function will return <c>{Pos,Length}</c> for the binary - in <c>Pattern</c> starting at the lowest position in - <c>Subject</c>, Example:</p> + <p>The function will return <c>{Pos, Length}</c> for the binary + in <c><anno>Pattern</anno></c> starting at the lowest position in + <c><anno>Subject</anno></c>, Example:</p> <code> 1> binary:match(<<"abcde">>, [<<"bcde">>,<<"cd">>],[]). @@ -391,16 +323,16 @@ <p>Summary of the options:</p> <taglist> - <tag>{scope, {Start, Length}}</tag> + <tag>{scope, {<anno>Start</anno>, <anno>Length</anno>}}</tag> <item><p>Only the given part is searched. Return values still have - offsets from the beginning of <c>Subject</c>. A negative <c>Length</c> is - allowed as described in the <c>TYPES</c> section of this manual.</p></item> + offsets from the beginning of <c><anno>Subject</anno></c>. A negative <c>Length</c> is + allowed as described in the <c>DATA TYPES</c> section of this manual.</p></item> </taglist> <p>If none of the strings in - <c>Pattern</c> is found, the atom <c>nomatch</c> is returned.</p> + <c><anno>Pattern</anno></c> is found, the atom <c>nomatch</c> is returned.</p> - <p>For a description of <c>Pattern</c>, see + <p>For a description of <c><anno>Pattern</anno></c>, see <seealso marker="#compile_pattern-1">compile_pattern/1</seealso>.</p> <p>If <c>{scope, {Start,Length}}</c> is given in the options @@ -412,32 +344,21 @@ </desc> </func> <func> - <name>matches(Subject, Pattern) -> Found</name> + <name name="matches" arity="2"/> <fsummary>Searches for all matches of a pattern in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pattern = binary() | [ binary() ] | cp()</v> - <v>Found = [ part() ] | []</v> - </type> <desc> - <p>The same as <c>matches(Subject, Pattern, [])</c>.</p> + <p>The same as <c>matches(<anno>Subject</anno>, <anno>Pattern</anno>, [])</c>.</p> </desc> </func> <func> - <name>matches(Subject,Pattern,Options) -> Found</name> + <name name="matches" arity="3"/> + <type name="part"/> <fsummary>Searches for all matches of a pattern in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pattern = binary() | [ binary() ] | cp()</v> - <v>Found = [ part() ] | []</v> - <v>Options = [ Option ]</v> - <v>Option = {scope, part()}</v> - </type> <desc> - <p>Works like match, but the <c>Subject</c> is searched until + <p>Works like <c>match/2</c>, but the <c><anno>Subject</anno></c> is searched until exhausted and a list of all non-overlapping parts matching - <c>Pattern</c> is returned (in order). </p> + <c><anno>Pattern</anno></c> is returned (in order). </p> <p>The first and longest match is preferred to a shorter, which is illustrated by the following example:</p> @@ -458,26 +379,22 @@ <p>If none of the strings in pattern is found, an empty list is returned.</p> - <p>For a description of <c>Pattern</c>, see <seealso marker="#compile_pattern-1">compile_pattern/1</seealso> and for a + <p>For a description of <c><anno>Pattern</anno></c>, see <seealso marker="#compile_pattern-1">compile_pattern/1</seealso> and for a description of available options, see <seealso marker="#match-3">match/3</seealso>.</p> - <p>If <c>{scope, {Start,Length}}</c> is given in the options such that - <c>Start</c> is larger than the size of <c>Subject</c>, <c>Start + Length</c> is - less than zero or <c>Start + Length</c> is larger than the size of - <c>Subject</c>, a <c>badarg</c> exception is raised.</p> + <p>If <c>{scope, {<anno>Start</anno>,<anno>Length</anno>}}</c> is given in the options such that + <c><anno>Start</anno></c> is larger than the size of <c><anno>Subject</anno></c>, <c><anno>Start</anno> + <anno>Length</anno></c> is + less than zero or <c><anno>Start</anno> + <anno>Length</anno></c> is larger than the size of + <c><anno>Subject</anno></c>, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>part(Subject, PosLen) -> binary()</name> + <name name="part" arity="2"/> <fsummary>Extracts a part of a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>PosLen = part()</v> - </type> <desc> - <p>Extracts the part of the binary <c>Subject</c> described by <c>PosLen</c>.</p> + <p>Extracts the part of the binary <c><anno>Subject</anno></c> described by <c><anno>PosLen</anno></c>.</p> <p>Negative length can be used to extract bytes at the end of a binary:</p> @@ -494,25 +411,20 @@ <c>binary_part/3</c>. Those BIFs are allowed in guard tests.</p> </note> - <p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception + <p>If <c><anno>PosLen</anno></c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>part(Subject, Pos, Len) -> binary()</name> + <name name="part" arity="3"/> <fsummary>Extracts a part of a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pos = integer() >= 0</v> - <v>Len = integer()</v> - </type> <desc> - <p>The same as <c>part(Subject, {Pos, Len})</c>.</p> + <p>The same as <c>part(<anno>Subject</anno>, {<anno>Pos</anno>, <anno>Len</anno>})</c>.</p> </desc> </func> <func> - <name>referenced_byte_size(binary()) -> integer() >= 0</name> + <name name="referenced_byte_size" arity="1"/> <fsummary>Determines the size of the actual binary pointed out by a sub-binary</fsummary> <desc> diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index 487b06473f..7880bf8fbb 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -128,11 +128,17 @@ <datatypes> <datatype> + <name name="access"/> + </datatype> + <datatype> <name><marker id="type-continuation">continuation()</marker></name> <desc> <p>Opaque continuation used by <seealso marker="#select/1"> - <c>select/1</c></seealso> and <seealso marker="#select/3"> - <c>select/3</c></seealso>.</p> + <c>select/1,3</c></seealso>, <seealso marker="#select_reverse/1"> + <c>select_reverse/1,3</c></seealso>, <seealso + marker="#match/1"> + <c>match/1,3</c></seealso>, and <seealso marker="#match_object/1"> + <c>match_object/1,3</c></seealso>.</p> </desc> </datatype> <datatype> @@ -149,14 +155,14 @@ <name name="tid"/> <desc><p>A table identifier, as returned by new/2.</p></desc> </datatype> + <datatype> + <name name="type"/> + </datatype> </datatypes> <funcs> <func> - <name>all() -> [Tab]</name> + <name name="all" arity="0"/> <fsummary>Return a list of all ETS tables.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - </type> <desc> <p>Returns a list of all tables at the node. Named tables are given by their names, unnamed tables are given by their @@ -164,48 +170,34 @@ </desc> </func> <func> - <name>delete(Tab) -> true</name> + <name name="delete" arity="1"/> <fsummary>Delete an entire ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - </type> <desc> - <p>Deletes the entire table <c>Tab</c>.</p> + <p>Deletes the entire table <c><anno>Tab</anno></c>.</p> </desc> </func> <func> - <name>delete(Tab, Key) -> true</name> + <name name="delete" arity="2"/> <fsummary>Delete all objects with a given key from an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - </type> <desc> - <p>Deletes all objects with the key <c>Key</c> from the table - <c>Tab</c>.</p> + <p>Deletes all objects with the key <c><anno>Key</anno></c> from the table + <c><anno>Tab</anno></c>.</p> </desc> </func> <func> - <name>delete_all_objects(Tab) -> true</name> + <name name="delete_all_objects" arity="1"/> <fsummary>Delete all objects in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - </type> <desc> - <p>Delete all objects in the ETS table <c>Tab</c>. + <p>Delete all objects in the ETS table <c><anno>Tab</anno></c>. The operation is guaranteed to be <seealso marker="#concurrency">atomic and isolated</seealso>.</p> </desc> </func> <func> - <name>delete_object(Tab,Object) -> true</name> + <name name="delete_object" arity="2"/> <fsummary>Deletes a specific from an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Object = tuple()</v> - </type> <desc> - <p>Delete the exact object <c>Object</c> from the ETS table, + <p>Delete the exact object <c><anno>Object</anno></c> from the ETS table, leaving objects with the same key but other differences (useful for type <c>bag</c>). In a <c>duplicate_bag</c>, all instances of the object will be deleted.</p> @@ -257,14 +249,10 @@ </desc> </func> <func> - <name>first(Tab) -> Key | '$end_of_table'</name> + <name name="first" arity="1"/> <fsummary>Return the first key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - </type> <desc> - <p>Returns the first key <c>Key</c> in the table <c>Tab</c>. + <p>Returns the first key <c><anno>Key</anno></c> in the table <c><anno>Tab</anno></c>. If the table is of the <c>ordered_set</c> type, the first key in Erlang term order will be returned. If the table is of any other type, the first key according to the table's internal @@ -336,7 +324,7 @@ the source file.</p> <p>The fun is very restricted, it can take only a single parameter (the object to match): a sole variable or a - tuple. It needs to use the <c>is_</c>XXX guard tests. + tuple. It needs to use the <c>is_</c> guard tests. Language constructs that have no representation in a match_spec (like <c>if</c>, <c>case</c>, <c>receive</c> etc) are not allowed.</p> @@ -386,19 +374,14 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>give_away(Tab, Pid, GiftData) -> true</name> + <name name="give_away" arity="3"/> <fsummary>Change owner of a table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pid = pid()</v> - <v>GiftData = term()</v> - </type> <desc> - <p>Make process <c>Pid</c> the new owner of table <c>Tab</c>. + <p>Make process <c><anno>Pid</anno></c> the new owner of table <c><anno>Tab</anno></c>. If successful, the message - <c>{'ETS-TRANSFER',Tab,FromPid,GiftData}</c> will be sent + <c>{'ETS-TRANSFER',<anno>Tab</anno>,FromPid,<anno>GiftData</anno>}</c> will be sent to the new owner.</p> - <p>The process <c>Pid</c> must be alive, local and not already the + <p>The process <c><anno>Pid</anno></c> must be alive, local and not already the owner of the table. The calling process must be the table owner.</p> <p>Note that <c>give_away</c> does not at all affect the <seealso marker="#heir">heir</seealso> option of the table. A table @@ -421,81 +404,72 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>info(Tab) -> [{Item, Value}] | undefined</name> + <name name="info" arity="1"/> <fsummary>Return information about an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Item = atom(), see below</v> - <v>Value = term(), see below</v> - </type> <desc> - <p>Returns information about the table <c>Tab</c> as a list of - <c>{Item, Value}</c> tuples. If <c>Tab</c> has the correct type + <p>Returns information about the table <c><anno>Tab</anno></c> as a list of + tuples. If <c><anno>Tab</anno></c> has the correct type for a table identifier, but does not refer to an existing ETS - table, <c>undefined</c> is returned. If <c>Tab</c> is not of the + table, <c>undefined</c> is returned. If <c><anno>Tab</anno></c> is not of the correct type, this function fails with reason <c>badarg</c>.</p> <list type="bulleted"> - <item><c>Item=memory, Value=integer()</c> <br></br> - - The number of words allocated to the table.</item> - <item><c>Item=owner, Value=pid()</c> <br></br> + <item><c>{compressed, boolean()}</c> <br></br> - The pid of the owner of the table.</item> - <item><c>Item=heir, Value=pid()|none</c> <br></br> + Indicates if the table is compressed or not.</item> + <item><c>{heir, pid() | none}</c> <br></br> The pid of the heir of the table, or <c>none</c> if no heir is set.</item> - <item><c>Item=name, Value=atom()</c> <br></br> + <item><c>{keypos, integer() >= 1}</c> <br></br> - The name of the table.</item> - <item><c>Item=size, Value=integer()</c> <br></br> + The key position.</item> + <item><c>{memory, integer() >= 0</c> <br></br> - The number of objects inserted in the table.</item> - <item><c>Item=node, Value=atom()</c> <br></br> + The number of words allocated to the table.</item> + <item><c>{name, atom()}</c> <br></br> - The node where the table is stored. This field is no longer - meaningful as tables cannot be accessed from other nodes.</item> - <item><c>Item=named_table, Value=true|false</c> <br></br> + The name of the table.</item> + <item><c>{named_table, boolean()}</c> <br></br> Indicates if the table is named or not.</item> - <item><c>Item=type, Value=set|ordered_set|bag|duplicate_bag</c> <br></br> + <item><c>{node, node()}</c> <br></br> - The table type.</item> - <item><c>Item=keypos, Value=integer()</c> <br></br> + The node where the table is stored. This field is no longer + meaningful as tables cannot be accessed from other nodes.</item> + <item><c>{owner, pid()}</c> <br></br> - The key position.</item> - <item><c>Item=protection, Value=public|protected|private</c> <br></br> + The pid of the owner of the table.</item> + <item><c>{protection, <seealso marker="#type-access">access()</seealso>}</c> <br></br> The table access rights.</item> - <item><c>Item=compressed, Value=true|false</c> <br></br> + <item><c>{size, integer() >= 0</c> <br></br> - Indicates if the table is compressed or not.</item> + The number of objects inserted in the table.</item> + <item><c>{type, <seealso marker="#type-type">type()</seealso>}</c> <br></br> + + The table type.</item> </list> </desc> </func> <func> - <name>info(Tab, Item) -> Value | undefined</name> + <name name="info" arity="2"/> <fsummary>Return the information associated with given item for an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Item, Value - see below</v> - </type> <desc> <p>Returns the information associated with <c>Item</c> for - the table <c>Tab</c>, or returns <c>undefined</c> if <c>Tab</c> + the table <c><anno>Tab</anno></c>, or returns <c>undefined</c> if <c>Tab</c> does not refer an existing ETS table. - If <c>Tab</c> is not of the correct type, or if <c>Item</c> is not + If <c><anno>Tab</anno></c> is not of the correct type, or if <c><anno>Item</anno></c> is not one of the allowed values, this function fails with reason <c>badarg</c>.</p> <warning><p>In R11B and earlier, this function would not fail but return <c>undefined</c> for invalid values for <c>Item</c>.</p> </warning> - <p>In addition to the <c>{Item,Value}</c> + <p>In addition to the <c>{<anno>Item</anno>,<anno>Value</anno>}</c> pairs defined for <c>info/1</c>, the following items are allowed:</p> <list type="bulleted"> - <item><c>Item=fixed, Value=true|false</c> <br></br> + <item><c>Item=fixed, Value=boolean()</c> <br></br> Indicates if the table is fixed by any process or not.</item> <item> @@ -547,15 +521,11 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>insert(Tab, ObjectOrObjects) -> true</name> + <name name="insert" arity="2"/> <fsummary>Insert an object into an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>ObjectOrObjects = tuple() | [tuple()]</v> - </type> <desc> <p>Inserts the object or all of the objects in the list - <c>ObjectOrObjects</c> into the table <c>Tab</c>. + <c><anno>ObjectOrObjects</anno></c> into the table <c><anno>Tab</anno></c>. If the table is a <c>set</c> and the key of the inserted objects <em>matches</em> the key of any object in the table, the old object will be replaced. If the table is an @@ -572,19 +542,15 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>insert_new(Tab, ObjectOrObjects) -> boolean()</name> + <name name="insert_new" arity="2"/> <fsummary>Insert an object into an ETS table if the key is not already present.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>ObjectOrObjects = tuple() | [tuple()]</v> - </type> <desc> <p>This function works exactly like <c>insert/2</c>, with the exception that instead of overwriting objects with the same key (in the case of <c>set</c> or <c>ordered_set</c>) or adding more objects with keys already existing in the table (in the case of <c>bag</c> and <c>duplicate_bag</c>), it - simply returns <c>false</c>. If <c>ObjectOrObjects</c> is a + simply returns <c>false</c>. If <c><anno>ObjectOrObjects</anno></c> is a list, the function checks <em>every</em> key prior to inserting anything. Nothing will be inserted if not <em>all</em> keys present in the list are absent from the @@ -593,11 +559,8 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>is_compiled_ms(Term) -> boolean()</name> + <name name="is_compiled_ms" arity="1"/> <fsummary>Checks if an Erlang term is the result of ets:match_spec_compile</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> <p>This function is used to check if a term is a valid compiled <seealso marker="#match_spec">match_spec</seealso>. @@ -626,14 +589,10 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>last(Tab) -> Key | '$end_of_table'</name> + <name name="last" arity="1"/> <fsummary>Return the last key in an ETS table of type<c>ordered_set</c>.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - </type> <desc> - <p>Returns the last key <c>Key</c> according to Erlang term + <p>Returns the last key <c><anno>Key</anno></c> according to Erlang term order in the table <c>Tab</c> of the <c>ordered_set</c> type. If the table is of any other type, the function is synonymous to <c>first/2</c>. If the table is empty, @@ -642,16 +601,11 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>lookup(Tab, Key) -> [Object]</name> + <name name="lookup" arity="2"/> <fsummary>Return all objects with a given key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - <v>Object = tuple()</v> - </type> <desc> - <p>Returns a list of all objects with the key <c>Key</c> in - the table <c>Tab</c>.</p> + <p>Returns a list of all objects with the key <c><anno>Key</anno></c> in + the table <c><anno>Tab</anno></c>.</p> <p>In the case of <c>set, bag and duplicate_bag</c>, an object is returned only if the given key <em>matches</em> the key of the object in the table. If the table is an @@ -681,22 +635,16 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>lookup_element(Tab, Key, Pos) -> Elem</name> + <name name="lookup_element" arity="3"/> <fsummary>Return the <c>Pos</c>:th element of all objects with a given key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - <v>Pos = integer()</v> - <v>Elem = term() | [term()]</v> - </type> <desc> - <p>If the table <c>Tab</c> is of type <c>set</c> or - <c>ordered_set</c>, the function returns the <c>Pos</c>:th - element of the object with the key <c>Key</c>.</p> + <p>If the table <c><anno>Tab</anno></c> is of type <c>set</c> or + <c>ordered_set</c>, the function returns the <c><anno>Pos</anno></c>:th + element of the object with the key <c><anno>Key</anno></c>.</p> <p>If the table is of type <c>bag</c> or <c>duplicate_bag</c>, - the functions returns a list with the <c>Pos</c>:th element of - every object with the key <c>Key</c>.</p> - <p>If no object with the key <c>Key</c> exists, the function + the functions returns a list with the <c><anno>Pos</anno></c>:th element of + every object with the key <c><anno>Key</anno></c>.</p> + <p>If no object with the key <c><anno>Key</anno></c> exists, the function will exit with reason <c>badarg</c>.</p> <p>The difference between <c>set</c>, <c>bag</c> and <c>duplicate_bag</c> on one hand, and <c>ordered_set</c> on @@ -708,16 +656,11 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match(Tab, Pattern) -> [Match]</name> + <name name="match" arity="2"/> <fsummary>Match the objects in an ETS table against a pattern.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pattern = tuple()</v> - <v>Match = [term()]</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> against the - pattern <c>Pattern</c>.</p> + <p>Matches the objects in the table <c><anno>Tab</anno></c> against the + pattern <c><anno>Pattern</anno></c>.</p> <p>A pattern is a term that may contain:</p> <list type="bulleted"> <item>bound parts (Erlang terms),</item> @@ -744,18 +687,12 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match(Tab, Pattern, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="match" arity="3"/> <fsummary>Match the objects in an ETS table against a pattern and returns part of the answers.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pattern = tuple()</v> - <v>Match = [term()]</v> - <v>Continuation = term()</v> - </type> <desc> <p>Works like <c>ets:match/2</c> but only returns a limited - (<c>Limit</c>) number of matching objects. The - <c>Continuation</c> term can then be used in subsequent calls + (<c><anno>Limit</anno></c>) number of matching objects. The + <c><anno>Continuation</anno></c> term can then be used in subsequent calls to <c>ets:match/1</c> to get the next chunk of matching objects. This is a space efficient way to work on objects in a table which is still faster than traversing the table object @@ -764,16 +701,12 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="match" arity="1"/> <fsummary>Continues matching objects in an ETS table.</fsummary> - <type> - <v>Match = [term()]</v> - <v>Continuation = term()</v> - </type> <desc> <p>Continues a match started with <c>ets:match/3</c>. The next chunk of the size given in the initial <c>ets:match/3</c> - call is returned together with a new <c>Continuation</c> + call is returned together with a new <c><anno>Continuation</anno></c> that can be used in subsequent calls to this function.</p> <p><c>'$end_of_table'</c> is returned when there are no more objects in the table.</p> @@ -789,15 +722,11 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match_object(Tab, Pattern) -> [Object]</name> + <name name="match_object" arity="2"/> <fsummary>Match the objects in an ETS table against a pattern.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pattern = Object = tuple()</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> against the - pattern <c>Pattern</c>. See <c>match/2</c> for a description + <p>Matches the objects in the table <c><anno>Tab</anno></c> against the + pattern <c><anno>Pattern</anno></c>. See <c>match/2</c> for a description of patterns. The function returns a list of all objects which match the pattern.</p> <p>If the key is specified in the pattern, the match is very @@ -809,18 +738,12 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match_object(Tab, Pattern, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="match_object" arity="3"/> <fsummary>Match the objects in an ETS table against a pattern and returns part of the answers.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pattern = tuple()</v> - <v>Match = [term()]</v> - <v>Continuation = term()</v> - </type> <desc> <p>Works like <c>ets:match_object/2</c> but only returns a - limited (<c>Limit</c>) number of matching objects. The - <c>Continuation</c> term can then be used in subsequent calls + limited (<c><anno>Limit</anno></c>) number of matching objects. The + <c><anno>Continuation</anno></c> term can then be used in subsequent calls to <c>ets:match_object/1</c> to get the next chunk of matching objects. This is a space efficient way to work on objects in a table which is still faster than traversing the table object @@ -829,29 +752,23 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match_object(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="match_object" arity="1"/> <fsummary>Continues matching objects in an ETS table.</fsummary> - <type> - <v>Match = [term()]</v> - <v>Continuation = term()</v> - </type> <desc> <p>Continues a match started with <c>ets:match_object/3</c>. The next chunk of the size given in the initial <c>ets:match_object/3</c> call is returned together with a - new <c>Continuation</c> that can be used in subsequent calls + new <c><anno>Continuation</anno></c> that can be used in subsequent calls to this function.</p> <p><c>'$end_of_table'</c> is returned when there are no more objects in the table.</p> </desc> </func> <func> - <name>match_spec_compile(MatchSpec) -> CompiledMatchSpec</name> + <name name="match_spec_compile" arity="1"/> + <type name="comp_match_spec"/> + <type_desc name="comp_match_spec">A compiled match specification.</type_desc> <fsummary>Compiles a match specification into its internal representation</fsummary> - <type> - <v>MatchSpec = match_spec()</v> - <v>CompiledMatchSpec = comp_match_spec()</v> - </type> <desc> <p>This function transforms a <seealso marker="#match_spec">match_spec</seealso> into an @@ -863,7 +780,7 @@ ets:is_compiled_ms(Broken).</code> valid compiled match_spec, nor can it be stored on disk). The validity of a compiled match_spec can be checked using <c>ets:is_compiled_ms/1</c>.</p> - <p>If the term <c>MatchSpec</c> can not be compiled (does not + <p>If the term <c><anno>MatchSpec</anno></c> can not be compiled (does not represent a valid match_spec), a <c>badarg</c> fault is thrown.</p> <note> @@ -873,25 +790,23 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match_spec_run(List,CompiledMatchSpec) -> list()</name> + <name name="match_spec_run" arity="2"/> + <type name="comp_match_spec"/> + <type_desc name="comp_match_spec">A compiled match specification.</type_desc> <fsummary>Performs matching, using a compiled match_spec, on a list of tuples</fsummary> - <type> - <v>List = [ tuple() ]</v> - <v>CompiledMatchSpec = comp_match_spec()</v> - </type> <desc> <p>This function executes the matching specified in a compiled <seealso marker="#match_spec">match_spec</seealso> on - a list of tuples. The <c>CompiledMatchSpec</c> term should be + a list of tuples. The <c><anno>CompiledMatchSpec</anno></c> term should be the result of a call to <c>ets:match_spec_compile/1</c> and is hence the internal representation of the match_spec one wants to use.</p> - <p>The matching will be executed on each element in <c>List</c> + <p>The matching will be executed on each element in <c><anno>List</anno></c> and the function returns a list containing all results. If an - element in <c>List</c> does not match, nothing is returned + element in <c><anno>List</anno></c> does not match, nothing is returned for that element. The length of the result list is therefore equal or less than the the length of the parameter - <c>List</c>. The two calls in the following example will give + <c><anno>List</anno></c>. The two calls in the following example will give the same result (but certainly not the same execution time...):</p> <code type="none"> @@ -910,37 +825,23 @@ ets:select(Table,MatchSpec),</code> </desc> </func> <func> - <name>member(Tab, Key) -> true | false</name> + <name name="member" arity="2"/> <fsummary>Tests for occurrence of a key in an ETS table</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - </type> <desc> <p>Works like <c>lookup/2</c>, but does not return the objects. The function returns <c>true</c> if one or more elements in - the table has the key <c>Key</c>, <c>false</c> otherwise.</p> + the table has the key <c><anno>Key</anno></c>, <c>false</c> otherwise.</p> </desc> </func> <func> - <name>new(Name, Options) -> tid() | atom()</name> + <name name="new" arity="2"/> <fsummary>Create a new ETS table.</fsummary> - <type> - <v>Name = atom()</v> - <v>Options = [Option]</v> - <v> Option = Type | Access | named_table | {keypos,Pos} | {heir,pid(),HeirData} | {heir,none} | Tweaks</v> - <v> Type = set | ordered_set | bag | duplicate_bag</v> - <v> Access = public | protected | private</v> - <v> Tweaks = {write_concurrency,boolean()} | {read_concurrency,boolean()} | compressed</v> - <v> Pos = integer()</v> - <v> HeirData = term()</v> - </type> <desc> <p>Creates a new table and returns a table identifier which can be used in subsequent operations. The table identifier can be sent to other processes so that a table can be shared between different processes within a node.</p> - <p>The parameter <c>Options</c> is a list of atoms which + <p>The parameter <c><anno>Options</anno></c> is a list of atoms which specifies table type, access rights, key position and if the table is named or not. If one or more options are left out, the default values are used. This means that not specifying @@ -997,27 +898,27 @@ ets:select(Table,MatchSpec),</code> </item> <item> <p><c>named_table</c> - If this option is present, the name <c>Name</c> is + If this option is present, the name <c><anno>Name</anno></c> is associated with the table identifier. The name can then be used instead of the table identifier in subsequent operations.</p> </item> <item> - <p><c>{keypos,Pos}</c> + <p><c>{keypos,<anno>Pos</anno>}</c> Specfies which element in the stored tuples should be used as key. By default, it is the first element, i.e. - <c>Pos=1</c>. However, this is not always appropriate. In + <c><anno>Pos</anno>=1</c>. However, this is not always appropriate. In particular, we do not want the first element to be the key if we want to store Erlang records in a table.</p> <p>Note that any tuple stored in the table must have at - least <c>Pos</c> number of elements.</p> + least <c><anno>Pos</anno></c> number of elements.</p> </item> <item> <marker id="heir"></marker> - <p><c>{heir,Pid,HeirData} | {heir,none}</c><br></br> + <p><c>{heir,<anno>Pid</anno>,<anno>HeirData</anno>} | {heir,none}</c><br></br> Set a process as heir. The heir will inherit the table if the owner terminates. The message - <c>{'ETS-TRANSFER',tid(),FromPid,HeirData}</c> will be sent to + <c>{'ETS-TRANSFER',tid(),FromPid,<anno>HeirData</anno>}</c> will be sent to the heir when that happens. The heir must be a local process. Default heir is <c>none</c>, which will destroy the table when the owner terminates.</p> @@ -1082,15 +983,11 @@ ets:select(Table,MatchSpec),</code> </desc> </func> <func> - <name>next(Tab, Key1) -> Key2 | '$end_of_table'</name> + <name name="next" arity="2"/> <fsummary>Return the next key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key1 = Key2 = term()</v> - </type> <desc> - <p>Returns the next key <c>Key2</c>, following the key - <c>Key1</c> in the table <c>Tab</c>. If the table is of the + <p>Returns the next key <c><anno>Key2</anno></c>, following the key + <c><anno>Key1</anno></c> in the table <c><anno>Tab</anno></c>. If the table is of the <c>ordered_set</c> type, the next key in Erlang term order is returned. If the table is of any other type, the next key according to the table's internal order is returned. If there @@ -1105,16 +1002,12 @@ ets:select(Table,MatchSpec),</code> </desc> </func> <func> - <name>prev(Tab, Key1) -> Key2 | '$end_of_table'</name> + <name name="prev" arity="2"/> <fsummary>Return the previous key in an ETS table of type<c>ordered_set</c>.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key1 = Key2 = term()</v> - </type> <desc> - <p>Returns the previous key <c>Key2</c>, preceding the key - <c>Key1</c> according the Erlang term order in the table - <c>Tab</c> of the <c>ordered_set</c> type. If the table is of + <p>Returns the previous key <c><anno>Key2</anno></c>, preceding the key + <c><anno>Key1</anno></c> according the Erlang term order in the table + <c><anno>Tab</anno></c> of the <c>ordered_set</c> type. If the table is of any other type, the function is synonymous to <c>next/2</c>. If there is no previous key, <c>'$end_of_table'</c> is returned.</p> @@ -1122,14 +1015,11 @@ ets:select(Table,MatchSpec),</code> </desc> </func> <func> - <name>rename(Tab, Name) -> Name</name> + <name name="rename" arity="2"/> <fsummary>Rename a named ETS table.</fsummary> - <type> - <v>Tab = Name = atom()</v> - </type> <desc> - <p>Renames the named table <c>Tab</c> to the new name - <c>Name</c>. Afterwards, the old name can not be used to + <p>Renames the named table <c><anno>Tab</anno></c> to the new name + <c><anno>Name</anno></c>. Afterwards, the old name can not be used to access the table. Renaming an unnamed table has no effect.</p> </desc> </func> @@ -1186,18 +1076,15 @@ ets:select(ets:repair_continuation(Broken,MS)).</code> </desc> </func> <func> - <name>safe_fixtable(Tab, true|false) -> true</name> + <name name="safe_fixtable" arity="2"/> <fsummary>Fix an ETS table for safe traversal.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - </type> <desc> <p>Fixes a table of the <c>set</c>, <c>bag</c> or <c>duplicate_bag</c> table type for safe traversal.</p> <p>A process fixes a table by calling - <c>safe_fixtable(Tab,true)</c>. The table remains fixed until + <c>safe_fixtable(<anno>Tab</anno>, true)</c>. The table remains fixed until the process releases it by calling - <c>safe_fixtable(Tab,false)</c>, or until the process + <c>safe_fixtable(<anno>Tab</anno>, false)</c>, or until the process terminates.</p> <p>If several processes fix a table, the table will remain fixed until all processes have released it (or terminated). @@ -1242,15 +1129,10 @@ clean_all_with_value(Tab,X,Key) -> </desc> </func> <func> - <name>select(Tab, MatchSpec) -> [Match]</name> + <name name="select" arity="2"/> <fsummary>Match the objects in an ETS table against a match_spec.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Match = term()</v> - <v>MatchSpec = match_spec()</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> using a + <p>Matches the objects in the table <c><anno>Tab</anno></c> using a <seealso marker="#match_spec">match_spec</seealso>. This is a more general call than the <c>ets:match/2</c> and <c>ets:match_object/2</c> calls. In its simplest forms the @@ -1337,18 +1219,12 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select(Tab, MatchSpec, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="select" arity="3"/> <fsummary>Match the objects in an ETS table against a match_spec and returns part of the answers.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Match = term()</v> - <v>MatchSpec = match_spec()</v> - <v>Continuation = term()</v> - </type> <desc> <p>Works like <c>ets:select/2</c> but only returns a limited - (<c>Limit</c>) number of matching objects. The - <c>Continuation</c> term can then be used in subsequent calls + (<c><anno>Limit</anno></c>) number of matching objects. The + <c><anno>Continuation</anno></c> term can then be used in subsequent calls to <c>ets:select/1</c> to get the next chunk of matching objects. This is a space efficient way to work on objects in a table which is still faster than traversing the table object @@ -1357,33 +1233,23 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="select" arity="1"/> <fsummary>Continue matching objects in an ETS table.</fsummary> - <type> - <v>Match = term()</v> - <v>Continuation = term()</v> - </type> <desc> <p>Continues a match started with <c>ets:select/3</c>. The next chunk of the size given in the initial <c>ets:select/3</c> - call is returned together with a new <c>Continuation</c> + call is returned together with a new <c><anno>Continuation</anno></c> that can be used in subsequent calls to this function.</p> <p><c>'$end_of_table'</c> is returned when there are no more objects in the table.</p> </desc> </func> <func> - <name>select_count(Tab, MatchSpec) -> NumMatched</name> + <name name="select_count" arity="2"/> <fsummary>Match the objects in an ETS table against a match_spec and returns the number of objects for which the match_spec returned 'true'</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Object = tuple()</v> - <v>MatchSpec = match_spec()</v> - <v>NumMatched = integer()</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> using a + <p>Matches the objects in the table <c><anno>Tab</anno></c> using a <seealso marker="#match_spec">match_spec</seealso>. If the match_spec returns <c>true</c> for an object, that object considered a match and is counted. For any other result from @@ -1396,16 +1262,10 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select_delete(Tab, MatchSpec) -> NumDeleted</name> + <name name="select_delete" arity="2"/> <fsummary>Match the objects in an ETS table against a match_spec and deletes objects where the match_spec returns 'true'</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Object = tuple()</v> - <v>MatchSpec = match_spec()</v> - <v>NumDeleted = integer()</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> using a + <p>Matches the objects in the table <c><anno>Tab</anno></c> using a <seealso marker="#match_spec">match_spec</seealso>. If the match_spec returns <c>true</c> for an object, that object is removed from the table. For any other result from the @@ -1422,13 +1282,8 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select_reverse(Tab, MatchSpec) -> [Match]</name> + <name name="select_reverse" arity="2"/> <fsummary>Match the objects in an ETS table against a match_spec.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Match = term()</v> - <v>MatchSpec = match_spec()</v> - </type> <desc> <p>Works like <c>select/2</c>, but returns the list in reverse @@ -1438,14 +1293,8 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select_reverse(Tab, MatchSpec, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="select_reverse" arity="3"/> <fsummary>Match the objects in an ETS table against a match_spec and returns part of the answers.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Match = term()</v> - <v>MatchSpec = match_spec()</v> - <v>Continuation = term()</v> - </type> <desc> <p>Works like <c>select/3</c>, but for the <c>ordered_set</c> @@ -1456,18 +1305,14 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> <p>Note that this is <em>not</em> equivalent to reversing the result list of a <c>select/3</c> call, as the result list - is not only reversed, but also contains the last <c>Limit</c> + is not only reversed, but also contains the last <c><anno>Limit</anno></c> matching objects in the table, not the first.</p> </desc> </func> <func> - <name>select_reverse(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="select_reverse" arity="1"/> <fsummary>Continue matching objects in an ETS table.</fsummary> - <type> - <v>Match = term()</v> - <v>Continuation = term()</v> - </type> <desc> <p>Continues a match started with @@ -1477,7 +1322,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> returned list will also contain objects with keys in reverse order.</p> - <p>For all other table types, the behaviour is exatly that of <c>select/1</c>.</p> + <p>For all other table types, the behaviour is exactly that of <c>select/1</c>.</p> <p>Example:</p> <code> 1> T = ets:new(x,[ordered_set]). @@ -1501,14 +1346,8 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>setopts(Tab, Opts) -> true</name> + <name name="setopts" arity="2"/> <fsummary>Set table options.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Opts = Opt | [Opt]</v> - <v>Opt = {heir,pid(),HeirData} | {heir,none}</v> - <v>HeirData = term()</v> - </type> <desc> <p>Set table options. The only option that currently is allowed to be set after the table has been created is @@ -1517,28 +1356,23 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>slot(Tab, I) -> [Object] | '$end_of_table'</name> + <name name="slot" arity="2"/> <fsummary>Return all objects in a given slot of an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>I = integer()</v> - <v>Object = tuple()</v> - </type> <desc> <p>This function is mostly for debugging purposes, Normally one should use <c>first/next</c> or <c>last/prev</c> instead.</p> - <p>Returns all objects in the <c>I</c>:th slot of the table - <c>Tab</c>. A table can be traversed by repeatedly calling - the function, starting with the first slot <c>I=0</c> and + <p>Returns all objects in the <c><anno>I</anno></c>:th slot of the table + <c><anno>Tab</anno></c>. A table can be traversed by repeatedly calling + the function, starting with the first slot <c><anno>I</anno>=0</c> and ending when <c>'$end_of_table'</c> is returned. The function will fail with reason <c>badarg</c> if the - <c>I</c> argument is out of range.</p> + <c><anno>I</anno></c> argument is out of range.</p> <p>Unless a table of type <c>set</c>, <c>bag</c> or <c>duplicate_bag</c> is protected using <c>safe_fixtable/2</c>, see above, a traversal may fail if concurrent updates are made to the table. If the table is of type <c>ordered_set</c>, the function returns a list - containing the <c>I</c>:th object in Erlang term order.</p> + containing the <c><anno>I</anno></c>:th object in Erlang term order.</p> </desc> </func> <func> @@ -1754,16 +1588,16 @@ true</pre> </desc> </func> <func> - <name>update_counter(Tab, Key, UpdateOp) -> Result</name> - <name>update_counter(Tab, Key, [UpdateOp]) -> [Result]</name> - <name>update_counter(Tab, Key, Incr) -> Result</name> + <name name="update_counter" arity="3" clause_i="1"/> + <name name="update_counter" arity="3" clause_i="2"/> + <name name="update_counter" arity="3" clause_i="3"/> + <type variable="Tab"/> + <type variable="Key"/> + <type variable="UpdateOp" name_i="1"/> + <type variable="Pos" name_i="1"/> + <type variable="Threshold" name_i="1"/> + <type variable="SetValue" name_i="1"/> <fsummary>Update a counter object in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - <v>UpdateOp = {Pos,Incr} | {Pos,Incr,Threshold,SetValue}</v> - <v>Pos = Incr = Threshold = SetValue = Result = integer()</v> - </type> <desc> <p>This function provides an efficient way to update one or more counters, without the hassle of having to look up an object, update @@ -1771,22 +1605,22 @@ true</pre> into the table again. (The update is done atomically; i.e. no process can access the ets table in the middle of the operation.) </p> - <p>It will destructively update the object with key <c>Key</c> - in the table <c>Tab</c> by adding <c>Incr</c> to the element - at the <c>Pos</c>:th position. The new counter value is + <p>It will destructively update the object with key <c><anno>Key</anno></c> + in the table <c><anno>Tab</anno></c> by adding <c><anno>Incr</anno></c> to the element + at the <c><anno>Pos</anno></c>:th position. The new counter value is returned. If no position is specified, the element directly following the key (<c><![CDATA[<keypos>+1]]></c>) is updated.</p> - <p>If a <c>Threshold</c> is specified, the counter will be - reset to the value <c>SetValue</c> if the following + <p>If a <c><anno>Threshold</anno></c> is specified, the counter will be + reset to the value <c><anno>SetValue</anno></c> if the following conditions occur:</p> <list type="bulleted"> - <item>The <c>Incr</c> is not negative (<c>>= 0</c>) and the - result would be greater than (<c>></c>) <c>Threshold</c></item> - <item>The <c>Incr</c> is negative (<c><![CDATA[< 0]]></c>) and the + <item>The <c><anno>Incr</anno></c> is not negative (<c>>= 0</c>) and the + result would be greater than (<c>></c>) <c><anno>Threshold</anno></c></item> + <item>The <c><anno>Incr</anno></c> is negative (<c><![CDATA[< 0]]></c>) and the result would be less than (<c><![CDATA[<]]></c>) - <c>Threshold</c></item> + <c><anno>Threshold</anno></c></item> </list> - <p>A list of <c>UpdateOp</c> can be supplied to do several update + <p>A list of <c><anno>UpdateOp</anno></c> can be supplied to do several update operations within the object. The operations are carried out in the order specified in the list. If the same counter position occurs more than one time in the list, the corresponding counter will thus @@ -1797,7 +1631,7 @@ true</pre> returned. If the function should fail, no updates will be done at all. </p> - <p>The given Key is used to identify the object by either + <p>The given <c><anno>Key</anno></c> is used to identify the object by either <em>matching</em> the key of an object in a <c>set</c> table, or <em>compare equal</em> to the key of an object in an <c>ordered_set</c> table (see @@ -1812,29 +1646,28 @@ true</pre> <item>the object has the wrong arity,</item> <item>the element to update is not an integer,</item> <item>the element to update is also the key, or,</item> - <item>any of <c>Pos</c>, <c>Incr</c>, <c>Threshold</c> or - <c>SetValue</c> is not an integer</item> + <item>any of <c><anno>Pos</anno></c>, <c><anno>Incr</anno></c>, <c><anno>Threshold</anno></c> or + <c><anno>SetValue</anno></c> is not an integer</item> </list> </desc> </func> <func> - <name>update_element(Tab, Key, {Pos,Value}) -> true | false</name> - <name>update_element(Tab, Key, [{Pos,Value}]) -> true | false</name> + <name name="update_element" arity="3" clause_i="1"/> + <name name="update_element" arity="3" clause_i="2"/> + <type variable="Tab"/> + <type variable="Key"/> + <type variable="Value"/> + <type variable="Pos"/> <fsummary>Updates the <c>Pos</c>:th element of the object with a given key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = Value = term()</v> - <v>Pos = integer()</v> - </type> <desc> <p>This function provides an efficient way to update one or more elements within an object, without the hassle of having to look up, update and write back the entire object. </p> - <p>It will destructively update the object with key <c>Key</c> - in the table <c>Tab</c>. The element at the <c>Pos</c>:th position - will be given the value <c>Value</c>. </p> - <p>A list of <c>{Pos,Value}</c> can be supplied to update several + <p>It will destructively update the object with key <c><anno>Key</anno></c> + in the table <c><anno>Tab</anno></c>. The element at the <c><anno>Pos</anno></c>:th position + will be given the value <c><anno>Value</anno></c>. </p> + <p>A list of <c>{<anno>Pos</anno>,<anno>Value</anno>}</c> can be supplied to update several elements within the same object. If the same position occurs more than one in the list, the last value in the list will be written. If the list is empty or the function fails, no updates will be done at @@ -1842,9 +1675,9 @@ true</pre> can never see any intermediate results. </p> <p>The function returns <c>true</c> if an object with the key - <c>Key</c> was found, <c>false</c> otherwise. + <c><anno>Key</anno></c> was found, <c>false</c> otherwise. </p> - <p>The given Key is used to identify the object by either + <p>The given <c><anno>Key</anno></c> is used to identify the object by either <em>matching</em> the key of an object in a <c>set</c> table, or <em>compare equal</em> to the key of an object in an <c>ordered_set</c> table (see @@ -1855,7 +1688,7 @@ true</pre> <list type="bulleted"> <item>the table is not of type <c>set</c> or <c>ordered_set</c>,</item> - <item><c>Pos</c> is less than 1 or greater than the object + <item><c><anno>Pos</anno></c> is less than 1 or greater than the object arity, or,</item> <item>the element to update is also the key</item> </list> diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml index 8b31f3ac3d..b6c0fa4e05 100644 --- a/lib/stdlib/doc/src/lists.xml +++ b/lib/stdlib/doc/src/lists.xml @@ -248,18 +248,13 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name>keyfind(Key, N, TupleList) -> Tuple | false</name> + <name name="keyfind" arity="3"/> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Search for an element in a list of tuples</fsummary> - <type> - <v>Key = term()</v> - <v>N = 1..tuple_size(Tuple)</v> - <v>TupleList = [Tuple]</v> - <v>Tuple = tuple()</v> - </type> - <desc> - <p>Searches the list of tuples <c>TupleList</c> for a - tuple whose <c>N</c>th element compares equal to <c>Key</c>. - Returns <c>Tuple</c> if such a tuple is found, + <desc> + <p>Searches the list of tuples <c><anno>TupleList</anno></c> for a + tuple whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>. + Returns <c><anno>Tuple</anno></c> if such a tuple is found, otherwise <c>false</c>.</p> </desc> </func> @@ -281,17 +276,12 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name>keymember(Key, N, TupleList) -> boolean()</name> + <name name="keymember" arity="3"/> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Test for membership of a list of tuples</fsummary> - <type> - <v>Key = term()</v> - <v>N = 1..tuple_size(Tuple)</v> - <v>TupleList = [Tuple]</v> - <v> Tuple = tuple()</v> - </type> - <desc> - <p>Returns <c>true</c> if there is a tuple in <c>TupleList</c> - whose <c>N</c>th element compares equal to <c>Key</c>, otherwise + <desc> + <p>Returns <c>true</c> if there is a tuple in <c><anno>TupleList</anno></c> + whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>, otherwise <c>false</c>.</p> </desc> </func> @@ -321,18 +311,13 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name>keysearch(Key, N, TupleList) -> {value, Tuple} | false</name> + <name name="keysearch" arity="3"/> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Search for an element in a list of tuples</fsummary> - <type> - <v>Key = term()</v> - <v>N = 1..tuple_size(Tuple)</v> - <v>TupleList = [Tuple]</v> - <v>Tuple = tuple()</v> - </type> - <desc> - <p>Searches the list of tuples <c>TupleList</c> for a - tuple whose <c>N</c>th element compares equal to <c>Key</c>. - Returns <c>{value, Tuple}</c> if such a tuple is found, + <desc> + <p>Searches the list of tuples <c><anno>TupleList</anno></c> for a + tuple whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>. + Returns <c>{value, <anno>Tuple</anno>}</c> if such a tuple is found, otherwise <c>false</c>.</p> <note><p>This function is retained for backward compatibility. The function <c>lists:keyfind/3</c> (introduced in R13A) @@ -425,15 +410,11 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name>member(Elem, List) -> boolean()</name> + <name name="member" arity="2"/> <fsummary>Test for membership of a list</fsummary> - <type> - <v>Elem = term()</v> - <v>List = [term()]</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Elem</c> matches some element of - <c>List</c>, otherwise <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Elem</anno></c> matches some element of + <c><anno>List</anno></c>, otherwise <c>false</c>.</p> </desc> </func> <func> @@ -562,14 +543,11 @@ c</pre> </desc> </func> <func> - <name>reverse(List1, Tail) -> List2</name> + <name name="reverse" arity="2"/> <fsummary>Reverse a list appending a tail</fsummary> - <type> - <v>List1 = Tail = List2 = [term()]</v> - </type> <desc> - <p>Returns a list with the elements in <c>List1</c> - in reverse order, with the tail <c>Tail</c> appended. For + <p>Returns a list with the elements in <c><anno>List1</anno></c> + in reverse order, with the tail <c><anno>Tail</anno></c> appended. For example:</p> <pre> > <input>lists:reverse([1, 2, 3, 4], [a, b, c]).</input> diff --git a/lib/stdlib/doc/src/math.xml b/lib/stdlib/doc/src/math.xml index 518457d5d8..0219dcce10 100644 --- a/lib/stdlib/doc/src/math.xml +++ b/lib/stdlib/doc/src/math.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1996</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -52,54 +52,47 @@ </desc> </func> <func> - <name>sin(X)</name> - <name>cos(X)</name> - <name>tan(X)</name> - <name>asin(X)</name> - <name>acos(X)</name> - <name>atan(X)</name> - <name>atan2(Y, X)</name> - <name>sinh(X)</name> - <name>cosh(X)</name> - <name>tanh(X)</name> - <name>asinh(X)</name> - <name>acosh(X)</name> - <name>atanh(X)</name> - <name>exp(X)</name> - <name>log(X)</name> - <name>log10(X)</name> - <name>pow(X, Y)</name> - <name>sqrt(X)</name> + <name name="sin" arity="1"/> + <name name="cos" arity="1"/> + <name name="tan" arity="1"/> + <name name="asin" arity="1"/> + <name name="acos" arity="1"/> + <name name="atan" arity="1"/> + <name name="atan2" arity="2"/> + <name name="sinh" arity="1"/> + <name name="cosh" arity="1"/> + <name name="tanh" arity="1"/> + <name name="asinh" arity="1"/> + <name name="acosh" arity="1"/> + <name name="atanh" arity="1"/> + <name name="exp" arity="1"/> + <name name="log" arity="1"/> + <name name="log10" arity="1"/> + <name name="pow" arity="2"/> + <name name="sqrt" arity="1"/> + <type variable="X" name_i="7"/> + <type variable="Y" name_i="7"/> <fsummary>Diverse math functions</fsummary> - <type> - <v>X = Y = number()</v> - </type> <desc> <p>A collection of math functions which return floats. Arguments are numbers. </p> </desc> </func> <func> - <name>erf(X) -> float()</name> + <name name="erf" arity="1"/> <fsummary>Error function.</fsummary> - <type> - <v>X = number()</v> - </type> <desc> - <p>Returns the error function of <c>X</c>, where</p> + <p>Returns the error function of <c><anno>X</anno></c>, where</p> <pre> erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt. </pre> </desc> </func> <func> - <name>erfc(X) -> float()</name> + <name name="erfc" arity="1"/> <fsummary>Another error function</fsummary> - <type> - <v>X = number()</v> - </type> <desc> <p><c>erfc(X)</c> returns <c>1.0 - erf(X)</c>, computed by - methods that avoid cancellation for large <c>X</c>. </p> + methods that avoid cancellation for large <c><anno>X</anno></c>. </p> </desc> </func> </funcs> diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml index 6d5336796c..c6f45fb1e1 100644 --- a/lib/stdlib/doc/src/re.xml +++ b/lib/stdlib/doc/src/re.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2007</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -78,28 +78,15 @@ </datatypes> <funcs> <func> - <name>compile(Regexp) -> {ok, MP} | {error, ErrSpec}</name> + <name name="compile" arity="1"/> <fsummary>Compile a regular expression into a match program</fsummary> - <type> - <v>Regexp = iodata()</v> - </type> <desc> - <p>The same as <c>compile(Regexp,[])</c></p> + <p>The same as <c>compile(<anno>Regexp</anno>,[])</c></p> </desc> </func> <func> - <name>compile(Regexp,Options) -> {ok, MP} | {error, ErrSpec}</name> + <name name="compile" arity="2"/> <fsummary>Compile a regular expression into a match program</fsummary> - <type> - <v>Regexp = iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>Options = [ Option ]</v> - <v>Option = <seealso marker="#type-compile_option">compile_option()</seealso></v> - <v>NLSpec = <seealso marker="#type-nl_spec">nl_spec()</seealso></v> - <v>MP = <seealso marker="#type-mp">mp()</seealso></v> - <v>ErrSpec = {ErrString, Position}</v> - <v>ErrString = string()</v> - <v>Position = non_neg_integer()</v> - </type> <desc> <p>This function compiles a regular expression with the syntax described below into an internal format to be used later as a @@ -165,44 +152,23 @@ This option makes it possible to include comments inside complicated patterns. N </func> <func> - <name>run(Subject,RE) -> {match, Captured} | nomatch</name> + <name name="run" arity="2"/> <fsummary>Match a subject against regular expression and capture subpatterns</fsummary> - <type> - <v>Subject = iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>RE = <seealso marker="#type-mp">mp()</seealso> | iodata()</v> - <v>Captured = [ CaptureData ]</v> - <v>CaptureData = {integer(),integer()}</v> - </type> <desc> - <p>The same as <c>run(Subject,RE,[])</c>.</p> + <p>The same as <c>run(<anno>Subject</anno>,<anno>RE</anno>,[])</c>.</p> </desc> </func> <func> - <name>run(Subject,RE,Options) -> {match, Captured} | match | nomatch</name> + <name name="run" arity="3"/> + <type_desc variable="CompileOpt">See <seealso marker="#compile_options">compile/2</seealso> above.</type_desc> <fsummary>Match a subject against regular expression and capture subpatterns</fsummary> - <type> - <v>Subject = iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>RE = <seealso marker="#type-mp">mp()</seealso> | iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>Options = [ Option ]</v> - <v>Option = anchored | global | notbol | noteol | notempty | {offset, integer() >= 0} | {newline, NLSpec} | bsr_anycrlf | bsr_unicode | {capture, ValueSpec} | {capture, ValueSpec, Type} | CompileOpt</v> - <v>Type = index | list | binary</v> - <v>ValueSpec = all | all_but_first | first | none | ValueList</v> - <v>ValueList = [ ValueID ]</v> - <v>ValueID = integer() | string() | atom()</v> - <v>CompileOpt = <seealso marker="#type-compile_option">compile_option()</seealso></v> - <d>See <seealso marker="#compile_options">compile/2</seealso> above.</d> - <v>NLSpec = <seealso marker="#type-nl_spec">nl_spec()</seealso></v> - <v>Captured = [ CaptureData ] | [ [ CaptureData ] ... ]</v> - <v>CaptureData = {integer(),integer()} | ListConversionData | binary()</v> - <v>ListConversionData = string() | {error, string(), binary()} | {incomplete, string(), binary()}</v> - </type> <desc> <p>Executes a regexp matching, returning <c>match/{match, - Captured}</c> or <c>nomatch</c>. The regular expression can be + <anno>Captured</anno>}</c> or <c>nomatch</c>. The regular expression can be given either as <c>iodata()</c> in which case it is automatically compiled (as by <c>re:compile/2</c>) and executed, - or as a pre compiled <c>mp()</c> in which case it is executed + or as a pre-compiled <c>mp()</c> in which case it is executed against the subject directly.</p> <p>When compilation is involved, the exception <c>badarg</c> is @@ -214,23 +180,23 @@ This option makes it possible to include comments inside complicated patterns. N list can only contain the options <c>anchored</c>, <c>global</c>, <c>notbol</c>, <c>noteol</c>, <c>notempty</c>, <c>{offset, integer() >= 0}</c>, <c>{newline, - NLSpec}</c> and <c>{capture, ValueSpec}/{capture, ValueSpec, - Type}</c>. Otherwise all options valid for the + <anno>NLSpec</anno>}</c> and <c>{capture, <anno>ValueSpec</anno>}/{capture, <anno>ValueSpec</anno>, + <anno>Type</anno>}</c>. Otherwise all options valid for the <c>re:compile/2</c> function are allowed as well. Options allowed both for compilation and execution of a match, namely - <c>anchored</c> and <c>{newline, NLSpec}</c>, will affect both + <c>anchored</c> and <c>{newline, <anno>NLSpec</anno>}</c>, will affect both the compilation and execution if present together with a non pre-compiled regular expression.</p> <p>If the regular expression was previously compiled with the - option <c>unicode</c>, the <c>Subject</c> should be provided as + option <c>unicode</c>, the <c><anno>Subject</anno></c> should be provided as a valid Unicode <c>charlist()</c>, otherwise any <c>iodata()</c> will do. If compilation is involved and the option - <c>unicode</c> is given, both the <c>Subject</c> and the regular + <c>unicode</c> is given, both the <c><anno>Subject</anno></c> and the regular expression should be given as valid Unicode <c>charlists()</c>.</p> - <p>The <c>{capture, ValueSpec}/{capture, ValueSpec, Type}</c> + <p>The <c>{capture, <anno>ValueSpec</anno>}/{capture, <anno>ValueSpec</anno>, <anno>Type</anno>}</c> defines what to return from the function upon successful matching. The <c>capture</c> tuple may contain both a value specification telling which of the captured @@ -244,9 +210,9 @@ This option makes it possible to include comments inside complicated patterns. N at all is to be done (<c>{capture, none}</c>), the function will return the single atom <c>match</c> upon successful matching, otherwise the tuple - <c>{match, ValueList}</c> is returned. Disabling capturing can + <c>{match, <anno>ValueList</anno>}</c> is returned. Disabling capturing can be done either by specifying <c>none</c> or an empty list as - <c>ValueSpec</c>.</p> + <c><anno>ValueSpec</anno></c>.</p> <p>The options relevant for execution are:</p> @@ -266,7 +232,7 @@ This option makes it possible to include comments inside complicated patterns. N Perl). Each match is returned as a separate <c>list()</c> containing the specific match as well as any matching subexpressions (or as specified by the <c>capture - option</c>). The <c>Captured</c> part of the return value will + option</c>). The <c><anno>Captured</anno></c> part of the return value will hence be a <c>list()</c> of <c>list()</c>s when this option is given.</p> @@ -362,7 +328,7 @@ This option makes it possible to include comments inside complicated patterns. N subject string. The offset is zero-based, so that the default is <c>{offset,0}</c> (all of the subject string).</item> - <tag><c>{newline, NLSpec}</c></tag> + <tag><c>{newline, <anno>NLSpec</anno>}</c></tag> <item> <p>Override the default definition of a newline in the subject string, which is LF (ASCII 10) in Erlang.</p> <taglist> @@ -383,7 +349,7 @@ This option makes it possible to include comments inside complicated patterns. N <tag><c>bsr_unicode</c></tag> <item>Specifies specifically that \R is to match all the Unicode newline characters (including crlf etc, the default).(overrides compilation option)</item> - <tag><c>{capture, ValueSpec}</c>/<c>{capture, ValueSpec, Type}</c></tag> + <tag><c>{capture, <anno>ValueSpec</anno>}</c>/<c>{capture, <anno>ValueSpec</anno>, <anno>Type</anno>}</c></tag> <item> <p>Specifies which captured substrings are returned and in what @@ -392,7 +358,7 @@ This option makes it possible to include comments inside complicated patterns. N substring as well as all capturing subpatterns (all of the pattern is automatically captured). The default return type is (zero-based) indexes of the captured parts of the string, given as - <c>{Offset,Length}</c> pairs (the <c>index</c> <c>Type</c> of + <c>{Offset,Length}</c> pairs (the <c>index</c> <c><anno>Type</anno></c> of capturing).</p> <p>As an example of the default behavior, the following call:</p> @@ -422,8 +388,8 @@ This option makes it possible to include comments inside complicated patterns. N <p>The capture tuple is built up as follows:</p> <taglist> - <tag><c>ValueSpec</c></tag> - <item><p>Specifies which captured (sub)patterns are to be returned. The ValueSpec can either be an atom describing a predefined set of return values, or a list containing either the indexes or the names of specific subpatterns to return.</p> + <tag><c><anno>ValueSpec</anno></c></tag> + <item><p>Specifies which captured (sub)patterns are to be returned. The <c><anno>ValueSpec</anno></c> can either be an atom describing a predefined set of return values, or a list containing either the indexes or the names of specific subpatterns to return.</p> <p>The predefined sets of subpatterns are:</p> <taglist> <tag><c>all</c></tag> @@ -437,7 +403,7 @@ This option makes it possible to include comments inside complicated patterns. N </taglist> <p>The value list is a list of indexes for the subpatterns to return, where index 0 is for all of the pattern, and 1 is for the first explicit capturing subpattern in the regular expression, and so forth. When using named captured subpatterns (see below) in the regular expression, one can use <c>atom()</c>s or <c>string()</c>s to specify the subpatterns to be returned. For example, consider the regular expression:</p> <code> ".*(abcd).*"</code> - <p>matched against the string ""ABCabcdABC", capturing only the "abcd" part (the first explicit subpattern):</p> + <p>matched against the string "ABCabcdABC", capturing only the "abcd" part (the first explicit subpattern):</p> <code> re:run("ABCabcdABC",".*(abcd).*",[{capture,[1]}]).</code> <p>The call will yield the following result:</p> <code> {match,[{3,4}]}</code> @@ -460,8 +426,8 @@ This option makes it possible to include comments inside complicated patterns. N or list respectively.</p> </item> - <tag><c>Type</c></tag> - <item><p>Optionally specifies how captured substrings are to be returned. If omitted, the default of <c>index</c> is used. The <c>Type</c> can be one of the following:</p> + <tag><c><anno>Type</anno></c></tag> + <item><p>Optionally specifies how captured substrings are to be returned. If omitted, the default of <c>index</c> is used. The <c><anno>Type</anno></c> can be one of the following:</p> <taglist> <tag><c>index</c></tag> <item>Return captured substrings as pairs of byte indexes into the subject string and length of the matching string in the subject (as if the subject string was flattened with <c>iolist_to_binary/1</c> or <c>unicode:characters_to_binary/2</c> prior to matching). Note that the <c>unicode</c> option results in <em>byte-oriented</em> indexes in a (possibly virtual) <em>UTF-8 encoded</em> binary. A byte index tuple <c>{0,2}</c> might therefore represent one or two characters when <c>unicode</c> is in effect. This might seem counter-intuitive, but has been deemed the most effective and useful way to way to do it. To return lists instead might result in simpler code if that is desired. This return type is the default.</item> @@ -478,7 +444,7 @@ This option makes it possible to include comments inside complicated patterns. N <code> "ABCabcdABC"</code> <p>the subpattern at index 2 won't match, as "abdd" is not present in the string, but the complete pattern matches (due to the alternative <c>a(..d)</c>. The subpattern at index 2 is therefore unassigned and the default return value will be:</p> <code> {match,[{0,10},{3,4},{-1,0},{4,3}]}</code> - <p>Setting the capture <c>Type</c> to <c>binary</c> would give the following:</p> + <p>Setting the capture <c><anno>Type</anno></c> to <c>binary</c> would give the following:</p> <code> {match,[<<"ABCabcdABC">>,<<"abcd">>,<<>>,<<"bcd">>]}</code> <p>where the empty binary (<c><<>></c>) represents the unassigned subpattern. In the <c>binary</c> case, some information about the matching is therefore lost, the <c><<>></c> might just as well be an empty string captured.</p> <p>If differentiation between empty matches and non existing subpatterns is necessary, use the <c>type</c> <c>index</c> diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml index 48867ffe72..549c871aed 100644 --- a/lib/stdlib/doc/src/string.xml +++ b/lib/stdlib/doc/src/string.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -255,18 +255,12 @@ sub_string("Hello World", 4, 8). </desc> </func> <func> - <name>to_float(String) -> {Float,Rest} | {error,Reason} </name> + <name name="to_float" arity="1"/> <fsummary>Returns a float whose text representation is the integers (ASCII values) in String.</fsummary> - <type> - <v>String = string()</v> - <v>Float = float()</v> - <v>Rest = string()</v> - <v>Reason = no_float | not_a_list</v> - </type> <desc> - <p>Argument <c>String</c> is expected to start with a valid text + <p>Argument <c><anno>String</anno></c> is expected to start with a valid text represented float (the digits being ASCII values). Remaining characters - in the string after the float are returned in <c>Rest</c>.</p> + in the string after the float are returned in <c><anno>Rest</anno></c>.</p> <p>Example:</p> <code type="none"> > {F1,Fs} = string:to_float("1.0-1.0e-1"), @@ -280,18 +274,12 @@ sub_string("Hello World", 4, 8). </desc> </func> <func> - <name>to_integer(String) -> {Int,Rest} | {error,Reason} </name> + <name name="to_integer" arity="1"/> <fsummary>Returns an integer whose text representation is the integers (ASCII values) in String.</fsummary> - <type> - <v>String = string()</v> - <v>Int = integer()</v> - <v>Rest = string()</v> - <v>Reason = no_integer | not_a_list</v> - </type> <desc> - <p>Argument <c>String</c> is expected to start with a valid text + <p>Argument <c><anno>String</anno></c> is expected to start with a valid text represented integer (the digits being ASCII values). Remaining characters - in the string after the integer are returned in <c>Rest</c>.</p> + in the string after the integer are returned in <c><anno>Rest</anno></c>.</p> <p>Example:</p> <code type="none"> > {I1,Is} = string:to_integer("33+22"), diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml index 1001ebbae4..1f6cbaccd7 100644 --- a/lib/stdlib/doc/src/unicode.xml +++ b/lib/stdlib/doc/src/unicode.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1996</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -130,34 +130,24 @@ </desc> </func> <func> - <name>characters_to_list(Data, InEncoding) -> Result</name> + <name name="characters_to_list" arity="2"/> <fsummary>Convert a collection of characters to list of Unicode characters</fsummary> - <type> - <v>Data = <seealso marker="#type-latin1_chardata">latin1_chardata()</seealso> - | <seealso marker="#type-chardata">chardata()</seealso> - | <seealso marker="#type-external_chardata">external_chardata()</seealso></v> - <v>Result = list() | {error, list(), RestData} | {incomplete, list(), binary()}</v> - <v>RestData = <seealso marker="#type-latin1_chardata">latin1_chardata()</seealso> - | <seealso marker="#type-chardata">chardata()</seealso> - | <seealso marker="#type-external_chardata">external_chardata()</seealso></v> - <v>InEncoding = <seealso marker="#type-encoding">encoding()</seealso></v> - </type> <desc> <p>This function converts a possibly deep list of integers and binaries into a list of integers representing unicode characters. The binaries in the input may have characters encoded as latin1 (0 - 255, one character per byte), in which - case the <c>InEncoding</c> parameter should be given as + case the <c><anno>InEncoding</anno></c> parameter should be given as <c>latin1</c>, or have characters encoded as one of the - UTF-encodings, which is given as the <c>InEncoding</c> - parameter. Only when the <c>InEncoding</c> is one of the UTF + UTF-encodings, which is given as the <c><anno>InEncoding</anno></c> + parameter. Only when the <c><anno>InEncoding</anno></c> is one of the UTF encodings, integers in the list are allowed to be grater than 255.</p> - <p>If <c>InEncoding</c> is <c>latin1</c>, the <c>Data</c> parameter + <p>If <c><anno>InEncoding</anno></c> is <c>latin1</c>, the <c><anno>Data</anno></c> parameter corresponds to the <c>iodata()</c> type, but for <c>unicode</c>, - the <c>Data</c> parameter can contain integers greater than 255 + the <c><anno>Data</anno></c> parameter can contain integers greater than 255 (unicode characters beyond the iso-latin-1 range), which would make it invalid as <c>iodata()</c>.</p> @@ -188,16 +178,16 @@ depth as the original data. The error occurs when traversing the list and whatever's left to decode is simply returned as is.</p> - <p>However, if the input <c>Data</c> is a pure binary, the third + <p>However, if the input <c><anno>Data</anno></c> is a pure binary, the third part of the error tuple is guaranteed to be a binary as well.</p> <p>Errors occur for the following reasons:</p> <list type="bulleted"> - <item>Integers out of range - If <c>InEncoding</c> is + <item>Integers out of range - If <c><anno>InEncoding</anno></c> is <c>latin1</c>, an error occurs whenever an integer greater - than 255 is found in the lists. If <c>InEncoding</c> is + than 255 is found in the lists. If <c><anno>InEncoding</anno></c> is of a Unicode type, an error occurs whenever an integer <list type="bulleted"> <item>greater than <c>16#10FFFF</c> @@ -208,7 +198,7 @@ is found. </item> - <item>UTF encoding incorrect - If <c>InEncoding</c> is + <item>UTF encoding incorrect - If <c><anno>InEncoding</anno></c> is one of the UTF types, the bytes in any binaries have to be valid in that encoding. Errors can occur for various reasons, including "pure" decoding errors @@ -220,7 +210,7 @@ number should have been encoded in fewer bytes. The case of a truncated UTF is handled specially, see the paragraph about incomplete binaries below. If - <c>InEncoding</c> is <c>latin1</c>, binaries are always valid + <c><anno>InEncoding</anno></c> is <c>latin1</c>, binaries are always valid as long as they contain whole bytes, as each byte falls into the valid iso-latin-1 range.</item> @@ -238,7 +228,7 @@ the first part of a (so far) valid UTF character.</p> <p>If one UTF characters is split over two consecutive - binaries in the <c>Data</c>, the conversion succeeds. This means + binaries in the <c><anno>Data</anno></c>, the conversion succeeds. This means that a character can be decoded from a range of binaries as long as the whole range is given as input without errors occurring. Example:</p> @@ -274,21 +264,11 @@ </desc> </func> <func> - <name>characters_to_binary(Data,InEncoding) -> Result</name> + <name name="characters_to_binary" arity="2"/> <fsummary>Convert a collection of characters to an UTF-8 binary</fsummary> - <type> - <v>Data = <seealso marker="#type-latin1_chardata">latin1_chardata()</seealso> - | <seealso marker="#type-chardata">chardata()</seealso> - | <seealso marker="#type-external_chardata">external_chardata()</seealso></v> - <v>Result = binary() | {error, binary(), RestData} | {incomplete, binary(), binary()}</v> - <v>RestData = <seealso marker="#type-latin1_chardata">latin1_chardata()</seealso> - | <seealso marker="#type-chardata">chardata()</seealso> - | <seealso marker="#type-external_chardata">external_chardata()</seealso></v> - <v>InEncoding = <seealso marker="#type-encoding">encoding()</seealso></v> - </type> <desc> - <p>Same as characters_to_binary(Data, InEncoding, unicode).</p> + <p>Same as characters_to_binary(<anno>Data</anno>, <anno>InEncoding</anno>, unicode).</p> </desc> </func> <func> diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl index cb1e12ae46..0e95372a76 100644 --- a/lib/stdlib/src/binary.erl +++ b/lib/stdlib/src/binary.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,29 +18,185 @@ %% -module(binary). %% -%% The following functions implemented as BIF's -%% binary:compile_pattern/1 -%% binary:match/{2,3} -%% binary:matches/{2,3} -%% binary:longest_common_prefix/1 -%% binary:longest_common_suffix/1 -%% binary:first/1 -%% binary:last/1 -%% binary:at/2 -%% binary:part/{2,3} -%% binary:bin_to_list/{1,2,3} -%% binary:list_to_bin/1 -%% binary:copy/{1,2} -%% binary:referenced_byte_size/1 -%% binary:decode_unsigned/{1,2} -%% - Not yet: -%% %% Implemented in this module: -export([split/2,split/3,replace/3,replace/4]). -opaque cp() :: tuple(). -type part() :: {Start :: non_neg_integer(), Length :: integer()}. +%%% BIFs. + +-export([at/2, bin_to_list/1, bin_to_list/2, bin_to_list/3, + compile_pattern/1, copy/1, copy/2, decode_unsigned/1, + decode_unsigned/2, encode_unsigned/1, encode_unsigned/2, + first/1, last/1, list_to_bin/1, longest_common_prefix/1, + longest_common_suffix/1, match/2, match/3, matches/2, + matches/3, part/2, part/3, referenced_byte_size/1]). + +-spec at(Subject, Pos) -> byte() when + Subject :: binary(), + Pos :: non_neg_integer(). + +at(_, _) -> + erlang:nif_error(undef). + +-spec bin_to_list(Subject) -> [byte()] when + Subject :: binary(). + +bin_to_list(_) -> + erlang:nif_error(undef). + +-spec bin_to_list(Subject, PosLen) -> [byte()] when + Subject :: binary(), + PosLen :: part(). + +bin_to_list(_, _) -> + erlang:nif_error(undef). + +-spec bin_to_list(Subject, Pos, Len) -> [byte()] when + Subject :: binary(), + Pos :: non_neg_integer(), + Len :: non_neg_integer(). + +bin_to_list(_, _, _) -> + erlang:nif_error(undef). + +-spec compile_pattern(Pattern) -> cp() when + Pattern :: binary() | [binary()]. + +compile_pattern(_) -> + erlang:nif_error(undef). + +-spec copy(Subject) -> binary() when + Subject :: binary(). + +copy(_) -> + erlang:nif_error(undef). + +-spec copy(Subject, N) -> binary() when + Subject :: binary(), + N :: non_neg_integer(). + +copy(_, _) -> + erlang:nif_error(undef). + +-spec decode_unsigned(Subject) -> Unsigned when + Subject :: binary(), + Unsigned :: non_neg_integer(). + +decode_unsigned(_) -> + erlang:nif_error(undef). + +-spec decode_unsigned(Subject, Endianess) -> Unsigned when + Subject :: binary(), + Endianess :: big | little, + Unsigned :: non_neg_integer(). + +decode_unsigned(_, _) -> + erlang:nif_error(undef). + +-spec encode_unsigned(Unsigned) -> binary() when + Unsigned :: non_neg_integer(). + +encode_unsigned(_) -> + erlang:nif_error(undef). + +-spec encode_unsigned(Unsigned, Endianess) -> binary() when + Unsigned :: non_neg_integer(), + Endianess :: big | little. + +encode_unsigned(_, _) -> + erlang:nif_error(undef). + +-spec first(Subject) -> byte() when + Subject :: binary(). + +first(_) -> + erlang:nif_error(undef). + +-spec last(Subject) -> byte() when + Subject :: binary(). + +last(_) -> + erlang:nif_error(undef). + +-spec list_to_bin(ByteList) -> binary() when + ByteList :: iodata(). + +list_to_bin(_) -> + erlang:nif_error(undef). + +-spec longest_common_prefix(Binaries) -> non_neg_integer() when + Binaries :: [binary()]. + +longest_common_prefix(_) -> + erlang:nif_error(undef). + +-spec longest_common_suffix(Binaries) -> non_neg_integer() when + Binaries :: [binary()]. + +longest_common_suffix(_) -> + erlang:nif_error(undef). + +-spec match(Subject, Pattern) -> Found | nomatch when + Subject :: binary(), + Pattern :: binary() | [binary()] | cp(), + Found :: part(). + +match(_, _) -> + erlang:nif_error(undef). + +-spec match(Subject, Pattern, Options) -> Found | nomatch when + Subject :: binary(), + Pattern :: binary() | [binary()] | cp(), + Found :: part(), + Options :: [Option], + Option :: {scope, part()}. + +match(_, _, _) -> + erlang:nif_error(undef). + +-spec matches(Subject, Pattern) -> Found when + Subject :: binary(), + Pattern :: binary() | [binary()] | cp(), + Found :: [part()]. + +matches(_, _) -> + erlang:nif_error(undef). + +-spec matches(Subject, Pattern, Options) -> Found when + Subject :: binary(), + Pattern :: binary() | [binary()] | cp(), + Found :: [part()], + Options :: [Option], + Option :: {scope, part()}. + +matches(_, _, _) -> + erlang:nif_error(undef). + +-spec part(Subject, PosLen) -> binary() when + Subject :: binary(), + PosLen :: part(). + +part(_, _) -> + erlang:nif_error(undef). + +-spec part(Subject, Pos, Len) -> binary() when + Subject :: binary(), + Pos :: non_neg_integer(), + Len :: non_neg_integer(). + +part(_, _, _) -> + erlang:nif_error(undef). + +-spec referenced_byte_size(Binary) -> non_neg_integer() when + Binary :: binary(). + +referenced_byte_size(_) -> + erlang:nif_error(undef). + +%%% End of BIFs. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% split %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl index afa914a456..817b397cc4 100644 --- a/lib/stdlib/src/ets.erl +++ b/lib/stdlib/src/ets.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -46,7 +46,12 @@ %%----------------------------------------------------------------------------- +-type access() :: public | protected | private. -type tab() :: atom() | tid(). +-type type() :: set | ordered_set | bag | duplicate_bag. +-type continuation() :: '$end_of_table' + | {tab(),integer(),integer(),binary(),list(),integer()} + | {tab(),_,_,integer(),binary(),list(),integer(),integer()}. %% a similar definition is also in erl_types -opaque tid() :: integer(). @@ -57,59 +62,398 @@ %%----------------------------------------------------------------------------- -%% The following functions used to be found in this module, but -%% are now BIFs (i.e. implemented in C). -%% -%% all/0 -%% new/2 -%% delete/1 -%% delete/2 -%% first/1 -%% info/1 -%% info/2 -%% safe_fixtable/2 -%% lookup/2 -%% lookup_element/3 -%% insert/2 -%% is_compiled_ms/1 -%% last/1 -%% member/2 -%% next/2 -%% prev/2 -%% rename/2 -%% slot/2 -%% match/1 -%% match/2 -%% match/3 -%% match_object/1 -%% match_object/2 -%% match_object/3 -%% match_spec_compile/1 -%% match_spec_run_r/3 -%% select/1 -%% select/2 -%% select/3 -%% select_count/2 -%% select_reverse/1 -%% select_reverse/2 -%% select_reverse/3 -%% select_delete/2 -%% setopts/2 -%% update_counter/3 -%% update_element/3 -%% +%%% BIFs + +-export([all/0, delete/1, delete/2, delete_all_objects/1, + delete_object/2, first/1, give_away/3, info/1, info/2, + insert/2, insert_new/2, is_compiled_ms/1, last/1, lookup/2, + lookup_element/3, match/1, match/2, match/3, match_object/1, + match_object/2, match_object/3, match_spec_compile/1, + match_spec_run_r/3, member/2, new/2, next/2, prev/2, + rename/2, safe_fixtable/2, select/1, select/2, select/3, + select_count/2, select_delete/2, select_reverse/1, + select_reverse/2, select_reverse/3, setopts/2, slot/2, + update_counter/3, update_element/3]). + +-spec all() -> [Tab] when + Tab :: tab(). + +all() -> + erlang:nif_error(undef). + +-spec delete(Tab) -> true when + Tab :: tab(). + +delete(_) -> + erlang:nif_error(undef). + +-spec delete(Tab, Key) -> true when + Tab :: tab(), + Key :: term(). + +delete(_, _) -> + erlang:nif_error(undef). + +-spec delete_all_objects(Tab) -> true when + Tab :: tab(). + +delete_all_objects(_) -> + erlang:nif_error(undef). + +-spec delete_object(Tab, Object) -> true when + Tab :: tab(), + Object :: tuple(). + +delete_object(_, _) -> + erlang:nif_error(undef). + +-spec first(Tab) -> Key | '$end_of_table' when + Tab :: tab(), + Key :: term(). + +first(_) -> + erlang:nif_error(undef). + +-spec give_away(Tab, Pid, GiftData) -> true when + Tab :: tab(), + Pid :: pid(), + GiftData :: term(). + +give_away(_, _, _) -> + erlang:nif_error(undef). + +-spec info(Tab) -> InfoList | undefined when + Tab :: tab(), + InfoList :: [InfoTuple], + InfoTuple :: {compressed, boolean()} + | {heir, pid() | none} + | {keypos, pos_integer()} + | {memory, non_neg_integer()} + | {name, atom()} + | {named_table, boolean()} + | {node, node()} + | {owner, pid()} + | {protection, access()} + | {size, non_neg_integer()} + | {type, type()}. + +info(_) -> + erlang:nif_error(undef). + +-spec info(Tab, Item) -> Value | undefined when + Tab :: tab(), + Item :: compressed | fixed | heir | keypos | memory + | name | named_table | node | owner | protection + | safe_fixed | size | stats | type, + Value :: term(). + +info(_, _) -> + erlang:nif_error(undef). + +-spec insert(Tab, ObjectOrObjects) -> true when + Tab :: tab(), + ObjectOrObjects :: tuple() | [tuple()]. + +insert(_, _) -> + erlang:nif_error(undef). + +-spec insert_new(Tab, ObjectOrObjects) -> boolean() when + Tab :: tab(), + ObjectOrObjects :: tuple() | [tuple()]. + +insert_new(_, _) -> + erlang:nif_error(undef). + +-spec is_compiled_ms(Term) -> boolean() when + Term :: term(). + +is_compiled_ms(_) -> + erlang:nif_error(undef). + +-spec last(Tab) -> Key | '$end_of_table' when + Tab :: tab(), + Key :: term(). + +last(_) -> + erlang:nif_error(undef). + +-spec lookup(Tab, Key) -> [Object] when + Tab :: tab(), + Key :: term(), + Object :: tuple(). + +lookup(_, _) -> + erlang:nif_error(undef). + +-spec lookup_element(Tab, Key, Pos) -> Elem when + Tab :: tab(), + Key :: term(), + Pos :: pos_integer(), + Elem :: term() | [term()]. + +lookup_element(_, _, _) -> + erlang:nif_error(undef). + +-spec match(Tab, Pattern) -> [Match] when + Tab :: tab(), + Pattern :: match_pattern(), + Match :: [term()]. + +match(_, _) -> + erlang:nif_error(undef). + +-spec match(Tab, Pattern, Limit) -> {[Match], Continuation} | + '$end_of_table' when + Tab :: tab(), + Pattern :: match_pattern(), + Limit :: pos_integer(), + Match :: [term()], + Continuation :: continuation(). + +match(_, _, _) -> + erlang:nif_error(undef). + +-spec match(Continuation) -> {[Match], Continuation} | + '$end_of_table' when + Match :: [term()], + Continuation :: continuation(). + +match(_) -> + erlang:nif_error(undef). + +-spec match_object(Tab, Pattern) -> [Object] when + Tab :: tab(), + Pattern :: match_pattern(), + Object :: tuple(). + +match_object(_, _) -> + erlang:nif_error(undef). + +-spec match_object(Tab, Pattern, Limit) -> {[Match], Continuation} | + '$end_of_table' when + Tab :: tab(), + Pattern :: match_pattern(), + Limit :: pos_integer(), + Match :: [term()], + Continuation :: continuation(). + +match_object(_, _, _) -> + erlang:nif_error(undef). + +-spec match_object(Continuation) -> {[Match], Continuation} | + '$end_of_table' when + Match :: [term()], + Continuation :: continuation(). + +match_object(_) -> + erlang:nif_error(undef). + +-spec match_spec_compile(MatchSpec) -> CompiledMatchSpec when + MatchSpec :: match_spec(), + CompiledMatchSpec :: comp_match_spec(). + +match_spec_compile(_) -> + erlang:nif_error(undef). + +-spec match_spec_run_r(List, CompiledMatchSpec, list()) -> list() when + List :: [tuple()], + CompiledMatchSpec :: comp_match_spec(). + +match_spec_run_r(_, _, _) -> + erlang:nif_error(undef). + +-spec member(Tab, Key) -> boolean() when + Tab :: tab(), + Key :: term(). + +member(_, _) -> + erlang:nif_error(undef). + +-spec new(Name, Options) -> tid() | atom() when + Name :: atom(), + Options :: [Option], + Option :: Type | Access | named_table | {keypos,Pos} + | {heir, Pid :: pid(), HeirData} | {heir, none} | Tweaks, + Type :: type(), + Access :: access(), + Tweaks :: {write_concurrency, boolean()} + | {read_concurrency, boolean()} + | compressed, + Pos :: pos_integer(), + HeirData :: term(). + +new(_, _) -> + erlang:nif_error(undef). + +-spec next(Tab, Key1) -> Key2 | '$end_of_table' when + Tab :: tab(), + Key1 :: term(), + Key2 :: term(). + +next(_, _) -> + erlang:nif_error(undef). + +-spec prev(Tab, Key1) -> Key2 | '$end_of_table' when + Tab :: tab(), + Key1 :: term(), + Key2 :: term(). + +prev(_, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: ets:rename/2 +-spec rename(Tab, Name) -> Name when + Tab :: tab(), + Name :: atom(). + +rename(_, _) -> + erlang:nif_error(undef). + +-spec safe_fixtable(Tab, Fix) -> true when + Tab :: tab(), + Fix :: boolean(). + +safe_fixtable(_, _) -> + erlang:nif_error(undef). + +-spec select(Tab, MatchSpec) -> [Match] when + Tab :: tab(), + MatchSpec :: match_spec(), + Match :: term(). + +select(_, _) -> + erlang:nif_error(undef). + +-spec select(Tab, MatchSpec, Limit) -> {[Match],Continuation} | + '$end_of_table' when + Tab :: tab(), + MatchSpec :: match_spec(), + Limit :: pos_integer(), + Match :: term(), + Continuation :: continuation(). + +select(_, _, _) -> + erlang:nif_error(undef). + +-spec select(Continuation) -> {[Match],Continuation} | '$end_of_table' when + Match :: term(), + Continuation :: continuation(). + +select(_) -> + erlang:nif_error(undef). + +-spec select_count(Tab, MatchSpec) -> NumMatched when + Tab :: tab(), + MatchSpec :: match_spec(), + NumMatched :: non_neg_integer(). + +select_count(_, _) -> + erlang:nif_error(undef). + +-spec select_delete(Tab, MatchSpec) -> NumDeleted when + Tab :: tab(), + MatchSpec :: match_spec(), + NumDeleted :: non_neg_integer(). + +select_delete(_, _) -> + erlang:nif_error(undef). + +-spec select_reverse(Tab, MatchSpec) -> [Match] when + Tab :: tab(), + MatchSpec :: match_spec(), + Match :: term(). + +select_reverse(_, _) -> + erlang:nif_error(undef). + +-spec select_reverse(Tab, MatchSpec, Limit) -> {[Match],Continuation} | + '$end_of_table' when + Tab :: tab(), + MatchSpec :: match_spec(), + Limit :: pos_integer(), + Match :: term(), + Continuation :: continuation(). + +select_reverse(_, _, _) -> + erlang:nif_error(undef). + +-spec select_reverse(Continuation) -> {[Match],Continuation} | + '$end_of_table' when + Continuation :: continuation(), + Match :: term(). + +select_reverse(_) -> + erlang:nif_error(undef). + +-spec setopts(Tab, Opts) -> true when + Tab :: tab(), + Opts :: Opt | [Opt], + Opt :: {heir, pid(), HeirData} | {heir,none}, + HeirData :: term(). + +setopts(_, _) -> + erlang:nif_error(undef). + +-spec slot(Tab, I) -> [Object] | '$end_of_table' when + Tab :: tab(), + I :: non_neg_integer(), + Object :: tuple(). + +slot(_, _) -> + erlang:nif_error(undef). + +-spec update_counter(Tab, Key, UpdateOp) -> Result when + Tab :: tab(), + Key :: term(), + UpdateOp :: {Pos, Incr} | {Pos, Incr, Threshold, SetValue}, + Pos :: integer(), + Incr :: integer(), + Threshold :: integer(), + SetValue :: integer(), + Result :: integer(); + (Tab, Key, [UpdateOp]) -> [Result] when + Tab :: tab(), + Key :: term(), + UpdateOp :: {Pos, Incr} | {Pos, Incr, Threshold, SetValue}, + Pos :: integer(), + Incr :: integer(), + Threshold :: integer(), + SetValue :: integer(), + Result :: integer(); + (Tab, Key, Incr) -> Result when + Tab :: tab(), + Key :: term(), + Incr :: integer(), + Result :: integer(). + +update_counter(_, _, _) -> + erlang:nif_error(undef). + +-spec update_element(Tab, Key, ElementSpec :: {Pos, Value}) -> boolean() when + Tab :: tab(), + Key :: term(), + Pos :: pos_integer(), + Value :: term(); + (Tab, Key, ElementSpec :: [{Pos, Value}]) -> boolean() when + Tab :: tab(), + Key :: term(), + Pos :: pos_integer(), + Value :: term(). + +update_element(_, _, _) -> + erlang:nif_error(undef). + +%%% End of BIFs -opaque comp_match_spec() :: any(). %% this one is REALLY opaque --spec match_spec_run([tuple()], comp_match_spec()) -> [term()]. +-spec match_spec_run(List, CompiledMatchSpec) -> list() when + List :: [tuple()], + CompiledMatchSpec :: comp_match_spec(). match_spec_run(List, CompiledMS) -> lists:reverse(ets:match_spec_run_r(List, CompiledMS, [])). --type continuation() :: '$end_of_table' - | {tab(),integer(),integer(),binary(),list(),integer()} - | {tab(),_,_,integer(),binary(),list(),integer(),integer()}. - -spec repair_continuation(Continuation, MatchSpec) -> Continuation when Continuation :: continuation(), MatchSpec :: match_spec(). diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index e73c087753..eb527471d5 100644 --- a/lib/stdlib/src/lists.erl +++ b/lib/stdlib/src/lists.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -33,9 +33,6 @@ keysort/2, keymerge/3, rkeymerge/3, rukeymerge/3, ukeysort/2, ukeymerge/3, keymap/3]). -%% Bifs: member/2, reverse/2 -%% Bifs: keymember/3, keysearch/3, keyfind/3 - -export([merge/3, rmerge/3, sort/2, umerge/3, rumerge/3, usort/2]). -export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2, @@ -43,6 +40,60 @@ mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2, split/2]). +%%% BIFs +-export([keyfind/3, keymember/3, keysearch/3, member/2, reverse/2]). + +%% Shadowed by erl_bif_types: lists:keyfind/3 +-spec keyfind(Key, N, TupleList) -> Tuple | false when + Key :: term(), + N :: pos_integer(), + TupleList :: [Tuple], + Tuple :: tuple(). + +keyfind(_, _, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: lists:keymember/3 +-spec keymember(Key, N, TupleList) -> boolean() when + Key :: term(), + N :: pos_integer(), + TupleList :: [Tuple], + Tuple :: tuple(). + +keymember(_, _, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: lists:keysearch/3 +-spec keysearch(Key, N, TupleList) -> {value, Tuple} | false when + Key :: term(), + N :: pos_integer(), + TupleList :: [Tuple], + Tuple :: tuple(). + +keysearch(_, _, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: lists:member/2 +-spec member(Elem, List) -> boolean() when + Elem :: T, + List :: [T], + T :: term(). + +member(_, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: lists:reverse/2 +-spec reverse(List1, Tail) -> List2 when + List1 :: [T], + Tail :: term(), + List2 :: [T], + T :: term(). + +reverse(_, _) -> + erlang:nif_error(undef). + +%%% End of BIFs + %% member(X, L) -> (true | false) %% test if X is a member of the list L %% Now a BIF! @@ -84,7 +135,7 @@ append([]) -> []. subtract(L1, L2) -> L1 -- L2. -%% reverse(L) reverse all elements in the list L. Is now a BIF! +%% reverse(L) reverse all elements in the list L. reverse/2 is now a BIF! -spec reverse(List1) -> List2 when List1 :: [T], @@ -581,6 +632,7 @@ flatlength([_|T], L) -> flatlength([], L) -> L. %% keymember(Key, Index, [Tuple]) Now a BIF! +%% keyfind(Key, Index, [Tuple]) A BIF! %% keysearch(Key, Index, [Tuple]) Now a BIF! %% keydelete(Key, Index, [Tuple]) %% keyreplace(Key, Index, [Tuple], NewTuple) diff --git a/lib/stdlib/src/math.erl b/lib/stdlib/src/math.erl index b2ea6195c5..c3fb684ec3 100644 --- a/lib/stdlib/src/math.erl +++ b/lib/stdlib/src/math.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -20,6 +20,116 @@ -export([pi/0]). +%%% BIFs + +-export([sin/1, cos/1, tan/1, asin/1, acos/1, atan/1, atan2/2, sinh/1, + cosh/1, tanh/1, asinh/1, acosh/1, atanh/1, exp/1, log/1, + log10/1, pow/2, sqrt/1, erf/1, erfc/1]). + +-spec acos(X) -> float() when + X :: number(). +acos(_) -> + erlang:nif_error(undef). + +-spec acosh(X) -> float() when + X :: number(). +acosh(_) -> + erlang:nif_error(undef). + +-spec asin(X) -> float() when + X :: number(). +asin(_) -> + erlang:nif_error(undef). + +-spec asinh(X) -> float() when + X :: number(). +asinh(_) -> + erlang:nif_error(undef). + +-spec atan(X) -> float() when + X :: number(). +atan(_) -> + erlang:nif_error(undef). + +-spec atan2(X, Y) -> float() when + X :: number(), + Y :: number(). +atan2(_, _) -> + erlang:nif_error(undef). + +-spec atanh(X) -> float() when + X :: number(). +atanh(_) -> + erlang:nif_error(undef). + +-spec cos(X) -> float() when + X :: number(). +cos(_) -> + erlang:nif_error(undef). + +-spec cosh(X) -> float() when + X :: number(). +cosh(_) -> + erlang:nif_error(undef). + +-spec erf(X) -> float() when + X :: number(). +erf(_) -> + erlang:nif_error(undef). + +-spec erfc(X) -> float() when + X :: number(). +erfc(_) -> + erlang:nif_error(undef). + +-spec exp(X) -> float() when + X :: number(). +exp(_) -> + erlang:nif_error(undef). + +-spec log(X) -> float() when + X :: number(). +log(_) -> + erlang:nif_error(undef). + +-spec log10(X) -> float() when + X :: number(). +log10(_) -> + erlang:nif_error(undef). + +-spec pow(X, Y) -> float() when + X :: number(), + Y :: number(). +pow(_, _) -> + erlang:nif_error(undef). + +-spec sin(X) -> float() when + X :: number(). +sin(_) -> + erlang:nif_error(undef). + +-spec sinh(X) -> float() when + X :: number(). +sinh(_) -> + erlang:nif_error(undef). + +-spec sqrt(X) -> float() when + X :: number(). +sqrt(_) -> + erlang:nif_error(undef). + +-spec tan(X) -> float() when + X :: number(). +tan(_) -> + erlang:nif_error(undef). + +-spec tanh(X) -> float() when + X :: number(). +tanh(_) -> + erlang:nif_error(undef). + +%%% End of BIFs + -spec pi() -> float(). pi() -> 3.1415926535897932. diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index b9fbef9ed0..cddf345c76 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -349,7 +349,7 @@ obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver -> obsolete_1(ssl, pid, 1) -> {deprecated,"deprecated (will be removed in R17); is no longer needed"}; obsolete_1(inviso, _, _) -> - {deprecated,"the inviso application has been deprecated and will be removed in R16"}; + {removed,"the inviso application was removed in R16"}; %% Added in R15B01. obsolete_1(gs, _, _) -> diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index 21504d707b..ad25fd559c 100644 --- a/lib/stdlib/src/qlc_pt.erl +++ b/lib/stdlib/src/qlc_pt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -2186,7 +2186,7 @@ try_ms(E, P, Fltr, State) -> {function,L,foo,0,[{clause,L,[],[],[MS0]}]} = lists:last(X), MS = erl_parse:normalise(var2const(MS0)), XMS = ets:match_spec_compile(MS), - true = is_binary(XMS), + true = ets:is_compiled_ms(XMS), {ok, MS, MS0} end of {'EXIT', _Reason} -> diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl index 246d535943..359afc8c14 100644 --- a/lib/stdlib/src/re.erl +++ b/lib/stdlib/src/re.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,11 +30,65 @@ | {newline, nl_spec()}| bsr_anycrlf | bsr_unicode. -%% Emulator builtins in this module: -%% re:compile/1 -%% re:compile/2 -%% re:run/2 -%% re:run/3 +%%% BIFs + +-export([compile/1, compile/2, run/2, run/3]). + +-spec compile(Regexp) -> {ok, MP} | {error, ErrSpec} when + Regexp :: iodata(), + MP :: mp(), + ErrSpec :: {ErrString :: string(), Position :: non_neg_integer()}. + +compile(_) -> + erlang:nif_error(undef). + +-spec compile(Regexp, Options) -> {ok, MP} | {error, ErrSpec} when + Regexp :: iodata() | unicode:charlist(), + Options :: [Option], + Option :: compile_option(), + MP :: mp(), + ErrSpec :: {ErrString :: string(), Position :: non_neg_integer()}. + +compile(_, _) -> + erlang:nif_error(undef). + +-spec run(Subject, RE) -> {match, Captured} | nomatch when + Subject :: iodata() | unicode:charlist(), + RE :: mp() | iodata(), + Captured :: [CaptureData], + CaptureData :: {integer(), integer()}. + +run(_, _) -> + erlang:nif_error(undef). + +-spec run(Subject, RE, Options) -> {match, Captured} | + match | + nomatch when + Subject :: iodata() | unicode:charlist(), + RE :: mp() | iodata() | unicode:charlist(), + Options :: [Option], + Option :: anchored | global | notbol | noteol | notempty + | {offset, non_neg_integer()} | + {newline, NLSpec :: nl_spec()} | + bsr_anycrlf | bsr_unicode | {capture, ValueSpec} | + {capture, ValueSpec, Type} | CompileOpt, + Type :: index | list | binary, + ValueSpec :: all | all_but_first | first | none | ValueList, + ValueList :: [ValueID], + ValueID :: integer() | string() | atom(), + CompileOpt :: compile_option(), + Captured :: [CaptureData] | [[CaptureData]], + CaptureData :: {integer(), integer()} + | ListConversionData + | binary(), + ListConversionData :: string() + | {error, string(), binary()} + | {incomplete, string(), binary()}. + +run(_, _, _) -> + erlang:nif_error(undef). + +%%% End of BIFs -spec split(Subject, RE) -> SplitList when Subject :: iodata() | unicode:charlist(), diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src index 94e81188b5..55c8087475 100644 --- a/lib/stdlib/src/stdlib.appup.src +++ b/lib/stdlib/src/stdlib.appup.src @@ -17,11 +17,11 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max two major revisions back - [{<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"1\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13 + [{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14 %% Down to - max two major revisions back - [{<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"1\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13 + [{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14 }. diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl index 30eac4f07d..fc029a582f 100644 --- a/lib/stdlib/src/string.erl +++ b/lib/stdlib/src/string.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -29,6 +29,30 @@ %%--------------------------------------------------------------------------- +%%% BIFs + +-export([to_float/1, to_integer/1]). + +-spec to_float(String) -> {Float, Rest} | {error, Reason} when + String :: string(), + Float :: float(), + Rest :: string(), + Reason :: no_float | not_a_list. + +to_float(_) -> + erlang:nif_error(undef). + +-spec to_integer(String) -> {Int, Rest} | {error, Reason} when + String :: string(), + Int :: integer(), + Rest :: string(), + Reason :: no_integer | not_a_list. + +to_integer(_) -> + erlang:nif_error(undef). + +%%% End of BIFs + %% Robert's bit %% len(String) diff --git a/lib/stdlib/src/unicode.erl b/lib/stdlib/src/unicode.erl index e9b90befe6..8b9412fb1b 100644 --- a/lib/stdlib/src/unicode.erl +++ b/lib/stdlib/src/unicode.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,13 +18,6 @@ %% -module(unicode). -%% Implemented in the emulator: -%% characters_to_binary/2 (will trap to characters_to_binary_int/2 -%% if InEncoding is not {latin1 | unicode | utf8}) -%% characters_to_list/2 (will trap to characters_to_list_int/2 if -%% InEncoding is not {latin1 | unicode | utf8}) -%% - -export([characters_to_list/1, characters_to_list_int/2, characters_to_binary/1, characters_to_binary_int/2, characters_to_binary/3, @@ -52,6 +45,45 @@ -type latin1_charlist() :: [latin1_char() | latin1_binary() | latin1_charlist()]. +%%% BIFs +%%% +%%% characters_to_binary/2 (will trap to characters_to_binary_int/2 +%%% if InEncoding is not {latin1 | unicode | utf8}) +%%% characters_to_list/2 (will trap to characters_to_list_int/2 if +%%% InEncoding is not {latin1 | unicode | utf8}) + +-export([bin_is_7bit/1, characters_to_binary/2, characters_to_list/2]). + +-spec bin_is_7bit(Binary) -> boolean() when + Binary :: binary(). + +bin_is_7bit(_) -> + erlang:nif_error(undef). + +-spec characters_to_binary(Data, InEncoding) -> Result when + Data :: latin1_chardata() | chardata() | external_chardata(), + InEncoding :: encoding(), + Result :: binary() + | {error, binary(), RestData} + | {incomplete, binary(), binary()}, + RestData :: latin1_chardata() | chardata() | external_chardata(). + +characters_to_binary(_, _) -> + erlang:nif_error(undef). + +-spec characters_to_list(Data, InEncoding) -> Result when + Data :: latin1_chardata() | chardata() | external_chardata(), + InEncoding :: encoding(), + Result :: list() + | {error, list(), RestData} + | {incomplete, list(), binary()}, + RestData :: latin1_chardata() | chardata() | external_chardata(). + +characters_to_list(_, _) -> + erlang:nif_error(undef). + +%%% End of BIFs + -spec characters_to_list(Data) -> Result when Data :: latin1_chardata() | chardata() | external_chardata(), Result :: list() diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 6f77cff2b9..7b7bb1a713 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -38,7 +38,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, - not_run/1, newly_started/1, basic_v8/1, basic_v9/1, + newly_started/1, basic_v8/1, basic_v9/1, open_v8/1, open_v9/1, sets_v8/1, sets_v9/1, bags_v8/1, bags_v9/1, duplicate_bags_v8/1, duplicate_bags_v9/1, access_v8/1, access_v9/1, dirty_mark/1, dirty_mark2/1, @@ -95,27 +95,25 @@ end_per_testcase(_Case, _Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - case os:type() of - vxworks -> [not_run]; - _ -> - [basic_v8, basic_v9, open_v8, open_v9, sets_v8, sets_v9, - bags_v8, bags_v9, duplicate_bags_v8, duplicate_bags_v9, - newly_started, open_file_v8, open_file_v9, - init_table_v8, init_table_v9, repair_v8, repair_v9, - access_v8, access_v9, oldbugs_v8, oldbugs_v9, - unsafe_assumptions, truncated_segment_array_v8, - truncated_segment_array_v9, dirty_mark, dirty_mark2, - bag_next_v8, bag_next_v9, hash_v8b_v8c, phash, fold_v8, - fold_v9, fixtable_v8, fixtable_v9, match_v8, match_v9, - select_v8, select_v9, update_counter, badarg, - cache_sets_v8, cache_sets_v9, cache_bags_v8, - cache_bags_v9, cache_duplicate_bags_v8, - cache_duplicate_bags_v9, otp_4208, otp_4989, - many_clients, otp_4906, otp_5402, simultaneous_open, - insert_new, repair_continuation, otp_5487, otp_6206, - otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898, - otp_8899, otp_8903, otp_8923, otp_9282, otp_9607] - end. + [ + basic_v8, basic_v9, open_v8, open_v9, sets_v8, sets_v9, + bags_v8, bags_v9, duplicate_bags_v8, duplicate_bags_v9, + newly_started, open_file_v8, open_file_v9, + init_table_v8, init_table_v9, repair_v8, repair_v9, + access_v8, access_v9, oldbugs_v8, oldbugs_v9, + unsafe_assumptions, truncated_segment_array_v8, + truncated_segment_array_v9, dirty_mark, dirty_mark2, + bag_next_v8, bag_next_v9, hash_v8b_v8c, phash, fold_v8, + fold_v9, fixtable_v8, fixtable_v9, match_v8, match_v9, + select_v8, select_v9, update_counter, badarg, + cache_sets_v8, cache_sets_v9, cache_bags_v8, + cache_bags_v9, cache_duplicate_bags_v8, + cache_duplicate_bags_v9, otp_4208, otp_4989, + many_clients, otp_4906, otp_5402, simultaneous_open, + insert_new, repair_continuation, otp_5487, otp_6206, + otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898, + otp_8899, otp_8903, otp_8923, otp_9282, otp_9607 + ]. groups() -> []. @@ -132,10 +130,6 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. -not_run(suite) -> []; -not_run(Conf) when is_list(Conf) -> - {comment, "Not runnable VxWorks/NFS"}. - newly_started(doc) -> ["OTP-3621"]; newly_started(suite) -> diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 97ac433cb9..b9576b434e 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -4206,21 +4206,13 @@ heavy_lookup_element(Config) when is_list(Config) -> repeat_for_opts(heavy_lookup_element_do). heavy_lookup_element_do(Opts) -> - ?line EtsMem = etsmem(), - ?line Tab = ets_new(foobar_table, [set, protected, {keypos, 2} | Opts]), - ?line ok = fill_tab2(Tab, 0, 7000), - case os:type() of - vxworks -> - ?line ?t:do_times(5, ?MODULE, do_lookup_element, - [Tab, 6999, 1]); - % lookup ALL elements 5 times. - _ -> - ?line ?t:do_times(50, ?MODULE, do_lookup_element, - [Tab, 6999, 1]) - % lookup ALL elements 50 times. - end, - ?line true = ets:delete(Tab), - ?line verify_etsmem(EtsMem). + EtsMem = etsmem(), + Tab = ets_new(foobar_table, [set, protected, {keypos, 2} | Opts]), + ok = fill_tab2(Tab, 0, 7000), + % lookup ALL elements 50 times + ?t:do_times(50, ?MODULE, do_lookup_element, [Tab, 6999, 1]), + true = ets:delete(Tab), + verify_etsmem(EtsMem). do_lookup_element(_Tab, 0, _) -> ok; do_lookup_element(Tab, N, M) -> diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl index 4cfa589660..1f3bdbc115 100644 --- a/lib/stdlib/test/filename_SUITE.erl +++ b/lib/stdlib/test/filename_SUITE.erl @@ -112,19 +112,6 @@ absname(Config) when is_list(Config) -> ?line "/erlang/src" = filename:absname(["/erl",'a','ng',"/",'s',"rc"]), ?line "/erlang/src" = filename:absname("/erlang///src"), ?line "/file_sorter.erl" = filename:absname([file_sorter|'.erl']), - ok; - vxworks -> - Test_dir = ?config(priv_dir, Config), - Test1 = Test_dir ++ "/foo", - Test2 = Test_dir ++ "/ebin", - ?line ok = file:set_cwd(Test_dir), - ?line Test1 = filename:absname(foo), - ?line Test1= filename:absname("foo"), - ?line Test2 = filename:absname("foo/../ebin"), - ?line "/erlang" = filename:absname("/erlang"), - ?line "/erlang/src" = filename:absname("/erlang/src"), - ?line "/erlang/src" = filename:absname(["/erlan",'g/s',"rc"]), - ?line "/erlang/src" = filename:absname("/erlang///src"), ok end. @@ -179,15 +166,6 @@ absname_2(Config) when is_list(Config) -> ?line "/erlang" = filename:absname("/erlang", "/"), ?line "/erlang/src" = filename:absname("/erlang/src", "/"), ?line "/erlang/src" = filename:absname("/erlang///src", "/"), - ok; - vxworks -> - ?line "/usr/foo" = filename:absname(foo, "/usr"), - ?line "/usr/foo" = filename:absname("foo", "/usr"), - ?line "/usr/ebin" = filename:absname("../ebin", "/usr"), - ?line "/usr/ebin" = filename:absname("../ebin", "/usr/src"), - ?line "/erlang" = filename:absname("/erlang", "/usr"), - ?line "/erlang/src" = filename:absname("/erlang/src", "/usr"), - ?line "/erlang/src" = filename:absname("/erlang///src", "/usr"), ok end. @@ -213,11 +191,7 @@ basename_1(Config) when is_list(Config) -> ?line "foo" = filename:basename("A:foo"); {unix, _} -> ?line "strange\\but\\true" = - filename:basename("strange\\but\\true"); - vxworks -> - ?line "foo" = filename:basename(["usr\\foo\\"]), - ?line "foo" = filename:basename("elrond:usr\\foo\\"), - ?line "foo" = filename:basename("disk:/foo") + filename:basename("strange\\but\\true") end, ?line test_server:timetrap_cancel(Dog), ok. @@ -249,15 +223,7 @@ basename_2(Config) when is_list(Config) -> ?line "strange\\but\\true" = filename:basename("strange\\but\\true.erl", ".erl"), ?line "strange\\but\\true" = - filename:basename("strange\\but\\true", ".erl"); - vxworks -> - ?line "foo" = filename:basename("net:foo", ".erl"), - ?line "foo.erl" = filename:basename("net:\\usr\\foo.erl", - ".hrl"), - ?line "foo.erl" = - filename:basename("/disk0:\\usr.hrl\\foo.erl", - ".hrl"), - ?line "foo" = filename:basename("/home\\usr\\foo", ".hrl") + filename:basename("strange\\but\\true", ".erl") end, ?line test_server:timetrap_cancel(Dog), ok. @@ -267,37 +233,25 @@ basename_2(Config) when is_list(Config) -> dirname(Config) when is_list(Config) -> case os:type() of {win32,_} -> - ?line "A:/usr" = filename:dirname("A:/usr/foo.erl"), - ?line "A:usr" = filename:dirname("A:usr/foo.erl"), - ?line "/usr" = filename:dirname("\\usr\\foo.erl"), - ?line "/" = filename:dirname("\\usr"), - ?line "A:" = filename:dirname("A:"); - vxworks -> - ?line "net:/usr" = filename:dirname("net:/usr/foo.erl"), - ?line "/disk0:/usr" = filename:dirname("/disk0:/usr/foo.erl"), - ?line "/usr" = filename:dirname("\\usr\\foo.erl"), - ?line "/usr" = filename:dirname("\\usr"), - ?line "net:" = filename:dirname("net:"); + "A:/usr" = filename:dirname("A:/usr/foo.erl"), + "A:usr" = filename:dirname("A:usr/foo.erl"), + "/usr" = filename:dirname("\\usr\\foo.erl"), + "/" = filename:dirname("\\usr"), + "A:" = filename:dirname("A:"); _ -> true end, - ?line "usr" = filename:dirname("usr///foo.erl"), - ?line "." = filename:dirname("foo.erl"), - ?line "." = filename:dirname("."), - ?line "usr" = filename:dirname('usr/foo.erl'), - ?line "usr" = filename:dirname(['usr','/foo.erl']), - ?line "usr" = filename:dirname(['us','r/foo.erl']), - ?line "usr" = filename:dirname(['usr/','/foo.erl']), - ?line "usr" = filename:dirname(['usr/','foo.erl']), - ?line "usr" = filename:dirname(['usr/'|'foo.erl']), - ?line "usr" = filename:dirname(['usr/f','oo.erl']), - case os:type() of - vxworks -> - ?line "/" = filename:dirname("/"), - ?line "/usr" = filename:dirname("/usr"); - _ -> - ?line "/" = filename:dirname("/"), - ?line "/" = filename:dirname("/usr") - end, + "usr" = filename:dirname("usr///foo.erl"), + "." = filename:dirname("foo.erl"), + "." = filename:dirname("."), + "usr" = filename:dirname('usr/foo.erl'), + "usr" = filename:dirname(['usr','/foo.erl']), + "usr" = filename:dirname(['us','r/foo.erl']), + "usr" = filename:dirname(['usr/','/foo.erl']), + "usr" = filename:dirname(['usr/','foo.erl']), + "usr" = filename:dirname(['usr/'|'foo.erl']), + "usr" = filename:dirname(['usr/f','oo.erl']), + "/" = filename:dirname("/"), + "/" = filename:dirname("/usr"), ok. @@ -319,12 +273,6 @@ extension(Config) when is_list(Config) -> filename:extension("A:/usr.bar/foo.nisse.erl"), ?line "" = filename:extension("A:/usr.bar/foo"), ok; - vxworks -> - ?line "" = filename:extension("/disk0:\\usr\\foo"), - ?line ".erl" = - filename:extension("net:/usr.bar/foo.nisse.erl"), - ?line "" = filename:extension("net:/usr.bar/foo"), - ok; _ -> ok end. @@ -369,25 +317,6 @@ join(Config) when is_list(Config) -> filename:join(["A:","C:usr","foo.erl"]), ?line "d:/foo" = filename:join([$D, $:, $/, []], "foo"), ok; - vxworks -> - ?line "Net:" = filename:join(["Net:/"]), - ?line "net:" = filename:join(["net:\\"]), - ?line "net:/abc" = filename:join(["net:/", "abc"]), - ?line "net:/abc" = filename:join(["net:", "abc"]), - ?line "a/b/c/d/e/f/g" = - filename:join(["a//b\\c//\\/\\d/\\e/f\\g"]), - ?line "net:/usr/foo.erl" = - filename:join(["net:","usr","foo.erl"]), - ?line "/usr/foo.erl" = - filename:join(["net:","/usr","foo.erl"]), - ?line "/target:usr" = filename:join("net:","/target:usr"), - ?line "kernel:/usr" = filename:join("net:", "kernel:/usr"), - ?line "foo:/usr/foo.erl" = - filename:join(["A:","foo:/usr","foo.erl"]), - ?line "/disk0:usr/foo.erl" = - filename:join(["kalle:","/disk0:usr","foo.erl"]), - ?line "D:/foo" = filename:join([$D, $:, $/, []], "foo"), - ok; {unix, _} -> ok end. @@ -406,10 +335,6 @@ pathtype(Config) when is_list(Config) -> {unix, _} -> ?line absolute = filename:pathtype("/"), ?line absolute = filename:pathtype("/usr/local/bin"), - ok; - vxworks -> - ?line absolute = filename:pathtype("/usr/local/bin"), - ?line absolute = filename:pathtype("net:usr/local/bin"), ok end. @@ -424,12 +349,7 @@ rootname(Config) when is_list(Config) -> ok. split(Config) when is_list(Config) -> - case os:type() of - vxworks -> - ?line ["/usr","local","bin"] = filename:split("/usr/local/bin"); - _ -> - ?line ["/","usr","local","bin"] = filename:split("/usr/local/bin") - end, + ?line ["/","usr","local","bin"] = filename:split("/usr/local/bin"), ?line ["foo","bar"]= filename:split("foo/bar"), ?line ["foo", "bar", "hello"]= filename:split("foo////bar//hello"), ?line ["foo", "bar", "hello"]= filename:split(["foo//",'//bar//h',"ello"]), @@ -447,18 +367,6 @@ split(Config) when is_list(Config) -> ?line ["a:","msdev","include"] = filename:split("a:msdev\\include"), ok; - vxworks -> - ?line ["net:","msdev","include"] = - filename:split("net:/msdev/include"), - ?line ["Target:","msdev","include"] = - filename:split("Target:/msdev/include"), - ?line ["msdev","include"] = - filename:split("msdev\\include"), - ?line ["/disk0:","msdev","include"] = - filename:split("/disk0:\\msdev\\include"), - ?line ["a:","msdev","include"] = - filename:split("a:msdev\\include"), - ok; _ -> ok end. @@ -657,56 +565,38 @@ basename_bin_2(Config) when is_list(Config) -> dirname_bin(Config) when is_list(Config) -> case os:type() of {win32,_} -> - ?line <<"A:/usr">> = filename:dirname(<<"A:/usr/foo.erl">>), - ?line <<"A:usr">> = filename:dirname(<<"A:usr/foo.erl">>), - ?line <<"/usr">> = filename:dirname(<<"\\usr\\foo.erl">>), - ?line <<"/">> = filename:dirname(<<"\\usr">>), - ?line <<"A:">> = filename:dirname(<<"A:">>); - vxworks -> - ?line <<"net:/usr">> = filename:dirname(<<"net:/usr/foo.erl">>), - ?line <<"/disk0:/usr">> = filename:dirname(<<"/disk0:/usr/foo.erl">>), - ?line <<"/usr">> = filename:dirname(<<"\\usr\\foo.erl">>), - ?line <<"/usr">> = filename:dirname(<<"\\usr">>), - ?line <<"net:">> = filename:dirname(<<"net:">>); + <<"A:/usr">> = filename:dirname(<<"A:/usr/foo.erl">>), + <<"A:usr">> = filename:dirname(<<"A:usr/foo.erl">>), + <<"/usr">> = filename:dirname(<<"\\usr\\foo.erl">>), + <<"/">> = filename:dirname(<<"\\usr">>), + <<"A:">> = filename:dirname(<<"A:">>); _ -> true end, - ?line <<"usr">> = filename:dirname(<<"usr///foo.erl">>), - ?line <<".">> = filename:dirname(<<"foo.erl">>), - ?line <<".">> = filename:dirname(<<".">>), - case os:type() of - vxworks -> - ?line <<"/">> = filename:dirname(<<"/">>), - ?line <<"/usr">> = filename:dirname(<<"/usr">>); - _ -> - ?line <<"/">> = filename:dirname(<<"/">>), - ?line <<"/">> = filename:dirname(<<"/usr">>) - end, + <<"usr">> = filename:dirname(<<"usr///foo.erl">>), + <<".">> = filename:dirname(<<"foo.erl">>), + <<".">> = filename:dirname(<<".">>), + <<"/">> = filename:dirname(<<"/">>), + <<"/">> = filename:dirname(<<"/usr">>), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% extension_bin(Config) when is_list(Config) -> - ?line <<".erl">> = filename:extension(<<"A:/usr/foo.erl">>), - ?line <<".erl">> = filename:extension(<<"A:/usr/foo.nisse.erl">>), - ?line <<".erl">> = filename:extension(<<"A:/usr.bar/foo.nisse.erl">>), - ?line <<"">> = filename:extension(<<"A:/usr.bar/foo">>), - ?line <<"">> = filename:extension(<<"A:/usr/foo">>), - ?line case os:type() of - {win32, _} -> - ?line <<"">> = filename:extension(<<"A:\\usr\\foo">>), - ?line <<".erl">> = - filename:extension(<<"A:/usr.bar/foo.nisse.erl">>), - ?line <<"">> = filename:extension(<<"A:/usr.bar/foo">>), - ok; - vxworks -> - ?line <<"">> = filename:extension(<<"/disk0:\\usr\\foo">>), - ?line <<".erl">> = - filename:extension(<<"net:/usr.bar/foo.nisse.erl">>), - ?line <<"">> = filename:extension(<<"net:/usr.bar/foo">>), - ok; - _ -> ok - end. + <<".erl">> = filename:extension(<<"A:/usr/foo.erl">>), + <<".erl">> = filename:extension(<<"A:/usr/foo.nisse.erl">>), + <<".erl">> = filename:extension(<<"A:/usr.bar/foo.nisse.erl">>), + <<"">> = filename:extension(<<"A:/usr.bar/foo">>), + <<"">> = filename:extension(<<"A:/usr/foo">>), + case os:type() of + {win32, _} -> + ?line <<"">> = filename:extension(<<"A:\\usr\\foo">>), + ?line <<".erl">> = + filename:extension(<<"A:/usr.bar/foo.nisse.erl">>), + ?line <<"">> = filename:extension(<<"A:/usr.bar/foo">>), + ok; + _ -> ok + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -754,53 +644,47 @@ join_bin(Config) when is_list(Config) -> end. pathtype_bin(Config) when is_list(Config) -> - ?line relative = filename:pathtype(<<"..">>), - ?line relative = filename:pathtype(<<"foo">>), - ?line relative = filename:pathtype(<<"foo/bar">>), - ?line relative = filename:pathtype('foo/bar'), + relative = filename:pathtype(<<"..">>), + relative = filename:pathtype(<<"foo">>), + relative = filename:pathtype(<<"foo/bar">>), + relative = filename:pathtype('foo/bar'), case os:type() of {win32, _} -> - ?line volumerelative = filename:pathtype(<<"/usr/local/bin">>), - ?line volumerelative = filename:pathtype(<<"A:usr/local/bin">>), + volumerelative = filename:pathtype(<<"/usr/local/bin">>), + volumerelative = filename:pathtype(<<"A:usr/local/bin">>), ok; {unix, _} -> - ?line absolute = filename:pathtype(<<"/">>), - ?line absolute = filename:pathtype(<<"/usr/local/bin">>), + absolute = filename:pathtype(<<"/">>), + absolute = filename:pathtype(<<"/usr/local/bin">>), ok end. rootname_bin(Config) when is_list(Config) -> - ?line <<"/jam.src/kalle">> = filename:rootname(<<"/jam.src/kalle">>), - ?line <<"/jam.src/foo">> = filename:rootname(<<"/jam.src/foo.erl">>), - ?line <<"/jam.src/foo">> = filename:rootname(<<"/jam.src/foo.erl">>, <<".erl">>), - ?line <<"/jam.src/foo.jam">> = filename:rootname(<<"/jam.src/foo.jam">>, <<".erl">>), - ?line <<"/jam.src/foo.jam">> = filename:rootname(["/jam.sr",'c/foo.j',"am"],<<".erl">>), - ?line <<"/jam.src/foo.jam">> = filename:rootname(["/jam.sr",'c/foo.j'|am],<<".erl">>), + <<"/jam.src/kalle">> = filename:rootname(<<"/jam.src/kalle">>), + <<"/jam.src/foo">> = filename:rootname(<<"/jam.src/foo.erl">>), + <<"/jam.src/foo">> = filename:rootname(<<"/jam.src/foo.erl">>, <<".erl">>), + <<"/jam.src/foo.jam">> = filename:rootname(<<"/jam.src/foo.jam">>, <<".erl">>), + <<"/jam.src/foo.jam">> = filename:rootname(["/jam.sr",'c/foo.j',"am"],<<".erl">>), + <<"/jam.src/foo.jam">> = filename:rootname(["/jam.sr",'c/foo.j'|am],<<".erl">>), ok. split_bin(Config) when is_list(Config) -> - case os:type() of - vxworks -> - ?line [<<"/usr">>,<<"local">>,<<"bin">>] = filename:split(<<"/usr/local/bin">>); - _ -> - ?line [<<"/">>,<<"usr">>,<<"local">>,<<"bin">>] = filename:split(<<"/usr/local/bin">>) - end, - ?line [<<"foo">>,<<"bar">>]= filename:split(<<"foo/bar">>), - ?line [<<"foo">>, <<"bar">>, <<"hello">>]= filename:split(<<"foo////bar//hello">>), + [<<"/">>,<<"usr">>,<<"local">>,<<"bin">>] = filename:split(<<"/usr/local/bin">>), + [<<"foo">>,<<"bar">>]= filename:split(<<"foo/bar">>), + [<<"foo">>, <<"bar">>, <<"hello">>]= filename:split(<<"foo////bar//hello">>), case os:type() of {win32,_} -> - ?line [<<"a:/">>,<<"msdev">>,<<"include">>] = + [<<"a:/">>,<<"msdev">>,<<"include">>] = filename:split(<<"a:/msdev/include">>), - ?line [<<"a:/">>,<<"msdev">>,<<"include">>] = + [<<"a:/">>,<<"msdev">>,<<"include">>] = filename:split(<<"A:/msdev/include">>), - ?line [<<"msdev">>,<<"include">>] = + [<<"msdev">>,<<"include">>] = filename:split(<<"msdev\\include">>), - ?line [<<"a:/">>,<<"msdev">>,<<"include">>] = + [<<"a:/">>,<<"msdev">>,<<"include">>] = filename:split(<<"a:\\msdev\\include">>), - ?line [<<"a:">>,<<"msdev">>,<<"include">>] = + [<<"a:">>,<<"msdev">>,<<"include">>] = filename:split(<<"a:msdev\\include">>), ok; _ -> ok end. - diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl index bdb4ea65b5..22f66a6c14 100644 --- a/lib/stdlib/test/gen_fsm_SUITE.erl +++ b/lib/stdlib/test/gen_fsm_SUITE.erl @@ -281,21 +281,12 @@ start12(Config) when is_list(Config) -> %% Check that time outs in calls work abnormal1(suite) -> []; abnormal1(Config) when is_list(Config) -> - ?line {ok, _Pid} = - gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []), + {ok, _Pid} = gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []), %% timeout call. - case os:type() of - vxworks -> - %% timeout call for VxWorks must be in 16ms increments. - ?line delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 17), - ?line {'EXIT',{timeout,_}} = - (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,17}, 1)); - _ -> - ?line delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 100), - ?line {'EXIT',{timeout,_}} = - (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,10}, 1)) - end, + delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 100), + {'EXIT',{timeout,_}} = + (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,10}, 1)), test_server:messages_get(), ok. diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index 48ef7e55ed..24c72e4f31 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -231,14 +231,6 @@ start(Config) when is_list(Config) -> end, test_server:messages_get(), - %% Must wait for all error messages before going to next test. - %% (otherwise it interferes too much with real time characteristics). - case os:type() of - vxworks -> - receive after 5000 -> ok end; - _ -> - ok - end, process_flag(trap_exit, OldFl), ok. diff --git a/lib/stdlib/test/stdlib.spec.vxworks b/lib/stdlib/test/stdlib.spec.vxworks deleted file mode 100644 index ddc804b831..0000000000 --- a/lib/stdlib/test/stdlib.spec.vxworks +++ /dev/null @@ -1,8 +0,0 @@ -{topcase, {dir, "../stdlib_test"}}. -{skip,{dets_SUITE,"Not runnable VxWorks/NFS"}}. -{skip,{slave_SUITE,"VxWorks: slave nodes are not supported"}}. -{skip,{tar_SUITE,errors,"VxWorks filesystem too primitive"}}. -{skip,{tar_SUITE,create_long_names,"VxWorks names too short"}}. -{skip,{epp_SUITE,"Test not adopted to VxWorks"}}. -{skip,{select_SUITE,"Test too memory consuming for VxWorks"}}. -{skip,{beam_lib_SUITE,error,"All sections not present in stripped beam files"}}. diff --git a/lib/stdlib/test/sys_SUITE.erl b/lib/stdlib/test/sys_SUITE.erl index fe039e8bcc..b2e1d12b2a 100644 --- a/lib/stdlib/test/sys_SUITE.erl +++ b/lib/stdlib/test/sys_SUITE.erl @@ -56,70 +56,60 @@ end_per_group(_GroupName, Config) -> log(suite) -> []; log(Config) when is_list(Config) -> - ?line {ok,_Server} = start(), - ?line ok = sys:log(?server,true), - ?line {ok,-44} = public_call(44), - ?line ok = sys:log(?server,false), - ?line ok = sys:log(?server,print), - ?line stop(), + {ok,_Server} = start(), + ok = sys:log(?server,true), + {ok,-44} = public_call(44), + ok = sys:log(?server,false), + ok = sys:log(?server,print), + stop(), ok. log_to_file(suite) -> []; log_to_file(Config) when is_list(Config) -> TempName = test_server:temp_name(?config(priv_dir,Config) ++ "sys."), - ?line {ok,_Server} = start(), - ?line ok = sys:log_to_file(?server,TempName), - ?line {ok,-44} = public_call(44), - ?line ok = sys:log_to_file(?server,false), - ?line {ok,Fd} = file:open(TempName,[read]), - ?line Msg1 = io:get_line(Fd,''), - ?line Msg2 = io:get_line(Fd,''), - ?line file:close(Fd), - ?line lists:prefix("*DBG* sys_SUITE_server got call {req,44} from ",Msg1), - ?line lists:prefix("*DBG* sys_SUITE_server sent {ok,-44} to ",Msg2), - ?line stop(), + {ok,_Server} = start(), + ok = sys:log_to_file(?server,TempName), + {ok,-44} = public_call(44), + ok = sys:log_to_file(?server,false), + {ok,Fd} = file:open(TempName,[read]), + Msg1 = io:get_line(Fd,''), + Msg2 = io:get_line(Fd,''), + file:close(Fd), + lists:prefix("*DBG* sys_SUITE_server got call {req,44} from ",Msg1), + lists:prefix("*DBG* sys_SUITE_server sent {ok,-44} to ",Msg2), + stop(), ok. stats(suite) -> []; stats(Config) when is_list(Config) -> - ?line Self = self(), - ?line {ok,_Server} = start(), - ?line ok = sys:statistics(?server,true), - ?line {ok,-44} = public_call(44), - ?line {ok,Stats} = sys:statistics(?server,get), - ?line lists:member({messages_in,1},Stats), - ?line lists:member({messages_out,1},Stats), - ?line ok = sys:statistics(?server,false), - ?line {status,_Pid,{module,_Mod},[_PDict,running,Self,_,_]} = + Self = self(), + {ok,_Server} = start(), + ok = sys:statistics(?server,true), + {ok,-44} = public_call(44), + {ok,Stats} = sys:statistics(?server,get), + lists:member({messages_in,1},Stats), + lists:member({messages_out,1},Stats), + ok = sys:statistics(?server,false), + {status,_Pid,{module,_Mod},[_PDict,running,Self,_,_]} = sys:get_status(?server), - ?line {ok,no_statistics} = sys:statistics(?server,get), - ?line stop(), + {ok,no_statistics} = sys:statistics(?server,get), + stop(), ok. trace(suite) -> []; trace(Config) when is_list(Config) -> - ?line {ok,_Server} = start(), - case os:type() of - vxworks -> - ?line test_server:sleep(20000); - _ -> - ?line test_server:sleep(2000) - end, - ?line test_server:capture_start(), - ?line sys:trace(?server,true), - ?line {ok,-44} = public_call(44), + {ok,_Server} = start(), + test_server:sleep(2000), + test_server:capture_start(), + sys:trace(?server,true), + {ok,-44} = public_call(44), %% ho, hum, allow for the io to reach us.. - case os:type() of - vxworks -> - ?line test_server:sleep(10000); - _ -> - ?line test_server:sleep(1000) - end, - ?line test_server:capture_stop(), - ?line [Msg1,Msg2] = test_server:capture_get(), - ?line lists:prefix("*DBG* sys_SUITE_server got call {req,44} from ",Msg1), - ?line lists:prefix("*DBG* sys_SUITE_server sent {ok,-44} to ",Msg2), - ?line stop(), + test_server:sleep(1000), + test_server:capture_stop(), + [Msg1,Msg2] = test_server:capture_get(), + lists:prefix("*DBG* sys_SUITE_server got call {req,44} from ",Msg1), + lists:prefix("*DBG* sys_SUITE_server sent {ok,-44} to ",Msg2), + stop(), ok. suspend(suite) -> []; diff --git a/lib/stdlib/test/timer_SUITE.erl b/lib/stdlib/test/timer_SUITE.erl index f84c72b0f8..1110891ab8 100644 --- a/lib/stdlib/test/timer_SUITE.erl +++ b/lib/stdlib/test/timer_SUITE.erl @@ -32,7 +32,6 @@ %% functions I guess. But I don't have time for that now. %% %% Expect it to run for at least 5-10 minutes! -%% Except for VxWorks of course, where a couple of hours is more apropriate... %% The main test case in this module is "do_big_test", which @@ -77,12 +76,7 @@ end_per_group(_GroupName, Config) -> do_big_test(TConfig) when is_list(TConfig) -> Dog = ?t:timetrap(?t:minutes(20)), Save = process_flag(trap_exit, true), - Result = case os:type() of - vxworks -> - big_test(10); - _ -> - big_test(200) - end, + Result = big_test(200), process_flag(trap_exit, Save), ?t:timetrap_cancel(Dog), report_result(Result). diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index 3df7495ec4..33d7a57cc3 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 1.18.2 +STDLIB_VSN = 1.19 diff --git a/lib/test_server/doc/src/ts.xml b/lib/test_server/doc/src/ts.xml index f9b48d8372..7a356755ba 100644 --- a/lib/test_server/doc/src/ts.xml +++ b/lib/test_server/doc/src/ts.xml @@ -85,8 +85,7 @@ <p><c>ts:install/1</c> or <c>ts:install/2</c> is used if the target platform is different from the controller host, i.e. if you run on "remote target" or if special options are required - for your system. VxWorks is currently supported - as remote target platform. + for your system. </p> <p>See the reference manual for detailed information about <c>ts:install/0/1/2</c>. @@ -249,9 +248,8 @@ <p>Installs and configures the Test Server Framework for running test suites. If a remote host is to be used, the <c>TargetSystem</c> argument must be given so that "cross - installation" can be done. This should be used for testing on - VxWorks. Installation is required for any of the - functions in <c>ts</c> to work. + installation" can be done. Installation is required for + any of the functions in <c>ts</c> to work. </p> <p>Opts may be one or more of </p> diff --git a/lib/test_server/src/Makefile b/lib/test_server/src/Makefile index a75855eaab..682507ba65 100644 --- a/lib/test_server/src/Makefile +++ b/lib/test_server/src/Makefile @@ -44,8 +44,7 @@ MODULES= test_server_ctrl \ test_server \ test_server_sup \ test_server_h \ - erl2html2 \ - vxworks_client + erl2html2 TS_MODULES= \ ts \ @@ -55,9 +54,9 @@ TS_MODULES= \ ts_make \ ts_erl_config \ ts_autoconf_win32 \ - ts_autoconf_vxworks \ ts_install \ - ts_install_cth + ts_install_cth \ + ts_benchmark TARGET_MODULES= $(MODULES:%=$(EBIN)/%) TS_TARGET_MODULES= $(TS_MODULES:%=$(EBIN)/%) diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 6e94e4861a..1b8221e73c 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -2118,14 +2118,10 @@ timetrap_scale_factor() -> {false,true} -> 2 * F0; {false,false} -> F0 end, - F2 = case has_superfluous_schedulers() of + F = case has_superfluous_schedulers() of true -> 3*F1; false -> F1 end, - F = case test_server_sup:get_os_family() of - vxworks -> 5 * F2; - _ -> F2 - end, case test_server:is_cover() of true -> 10 * F; false -> F diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 5ed296d215..803406bcb2 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -429,14 +429,6 @@ run_test(CommandLine) -> testcase_callback(TCCB), add_job(Name, {command_line,SpecList}), - %% adding of jobs involves file i/o which may take long time - %% when running a nfs mounted file system (VxWorks). - case controller_call(get_target_info) of - #target_info{os_family=vxworks} -> - receive after 30000 -> ready_to_wait end; - _ -> - wait_now - end, wait_finish(). %% Converted CoverFile to a string unless it is 'none' diff --git a/lib/test_server/src/test_server_internal.hrl b/lib/test_server/src/test_server_internal.hrl index c9c52854e3..b58b42805e 100644 --- a/lib/test_server/src/test_server_internal.hrl +++ b/lib/test_server/src/test_server_internal.hrl @@ -25,7 +25,7 @@ %% test_server_ctrl:contact_main_target/2 %% Once initiated, this information will never change!! -record(target_info, {where, % local | Socket - os_family, % atom(); win32 | unix | vxworks | ose + os_family, % atom(); win32 | unix os_type, % result of os:type() host, % string(); the name of the target machine version, % string() diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl index 6358efa764..17c02dfbe5 100644 --- a/lib/test_server/src/test_server_node.erl +++ b/lib/test_server/src/test_server_node.erl @@ -35,7 +35,6 @@ -include("test_server_internal.hrl"). -record(slave_info, {name,socket,client}). --define(VXWORKS_ACCEPT_TIMEOUT,?ACCEPT_TIMEOUT). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% %%% @@ -72,14 +71,6 @@ start_remote_main_target(Parameters) -> lists:foreach(fun(T) -> maybe_reboot_target({TargetType,T}) end, [list_to_atom(TargetHost)|SlaveTargets]), - % Must give the targets a chance to reboot... - case TargetType of - vxworks -> - receive after 15000 -> ok end; - _ -> - ok - end, - Cmd0 = get_main_target_start_command(TargetType,TargetHost,Naming, MasterNode,MasterCookie), Cmd = @@ -462,9 +453,6 @@ start_node_peer(SlaveName, OptList, From, TI) -> %% %% Slave nodes are started on a remote host if %% - the option remote is given when calling test_server:start_node/3 -%% or -%% - the target type is vxworks, since only one erlang node -%% can be started on each vxworks host. %% start_node_slave(SlaveName, OptList, From, TI) -> SuppliedArgs = start_node_get_option_value(args, OptList, []), @@ -787,19 +775,6 @@ kill_node(SI,TI) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Platform specific code -start_target(vxworks,TargetHost,Cmd) -> - case vxworks_client:open(TargetHost) of - {ok,P} -> - case vxworks_client:send_data(P,Cmd,"start_erl called") of - {ok,_} -> - {ok,{vxworks,P},?VXWORKS_ACCEPT_TIMEOUT}; - Error -> - Error - end; - Error -> - Error - end; - start_target(unix,TargetHost,Cmd0) -> Cmd = case test_server_sup:hoststr() of @@ -809,19 +784,9 @@ start_target(unix,TargetHost,Cmd0) -> open_port({spawn, Cmd}, [stream]), {ok,undefined,?ACCEPT_TIMEOUT}. -maybe_reboot_target({vxworks,P}) when is_pid(P) -> - %% Reboot the vxworks card. - %% Client is also closed after this, even if reboot fails - vxworks_client:send_data_wait_for_close(P,"q"); -maybe_reboot_target({vxworks,T}) when is_atom(T) -> - %% Reboot the vxworks card. - %% Client is also closed after this, even if reboot fails - vxworks_client:reboot(T); maybe_reboot_target(_) -> {error, cannot_reboot_target}. -close_target_client({vxworks,P}) -> - vxworks_client:close(P); close_target_client(undefined) -> ok. @@ -830,11 +795,6 @@ close_target_client(undefined) -> %% %% Command for starting main target %% -get_main_target_start_command(vxworks,_TargetHost,Naming, - _MasterNode,_MasterCookie) -> - "e" ++ Naming ++ " test_server -boot start_sasl" - " -sasl errlog_type error" - " -s test_server start " ++ test_server_sup:hoststr(); get_main_target_start_command(unix,_TargetHost,Naming, _MasterNode,_MasterCookie) -> Prog = pick_erl_program(default), @@ -845,9 +805,6 @@ get_main_target_start_command(unix,_TargetHost,Naming, %% %% Command for starting slave nodes %% -get_slave_node_start_command(vxworks, _Prog, _MasterNode) -> - "e"; - %"e-noinput -master " ++ MasterNode; get_slave_node_start_command(unix, Prog, MasterNode) -> cast_to_list(Prog) ++ " -detached -master " ++ MasterNode. diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl index 4899f38d2b..a30f6c65fe 100644 --- a/lib/test_server/src/ts.erl +++ b/lib/test_server/src/ts.erl @@ -28,6 +28,7 @@ clean/0, clean/1, tests/0, tests/1, install/0, install/1, index/0, + bench/0, bench/1, bench/2, benchmarks/0, estone/0, estone/1, cross_cover_analyse/1, compile_testcases/0, compile_testcases/1, @@ -40,20 +41,20 @@ %%% the modules: %%% %%% +-- ts_install --+------ ts_autoconf_win32 -%%% | | -%%% | +------ ts_autoconf_vxworks +%%% | +%%% | %%% | %%% ts ---+ +------ ts_erl_config %%% | | ts_lib %%% | +------ ts_make %%% | | %%% +-- ts_run -----+ -%%% | ts_filelib -%%% +------ ts_make_erl -%%% | -%%% +------ ts_reports (indirectly) -%%% -%%% +%%% | | ts_filelib +%%% | +------ ts_make_erl +%%% | | +%%% | +------ ts_reports (indirectly) +%%% | +%%% +-- ts_benchmark %%% %%% The modules ts_lib and ts_filelib contains utilities used by %%% the other modules. @@ -63,8 +64,7 @@ %%% ts Frontend to the test server framework. Contains all %%% interface functions. %%% ts_install Installs the test suite. On Unix, `autoconf' is -%%% is used; on Windows, ts_autoconf_win32 is used, -%%% on VxWorks, ts_autoconf_vxworks is used. +%%% is used; on Windows, ts_autoconf_win32 is used. %%% The result is written to the file `variables'. %%% ts_run Supervises running of the tests. %%% ts_autconf_win32 An `autoconf' for Windows. @@ -81,6 +81,7 @@ %%% of the tests run. %%% ts_lib Miscellanous utility functions, each used by several %%% other modules. +%%% ts_benchmark Supervises otp benchmarks and collects results. %%%---------------------------------------------------------------------- -include_lib("kernel/include/file.hrl"). @@ -128,7 +129,7 @@ help(installed) -> " ts:run(Spec, Mod) - Run a single test suite.\n", " ts:run(Spec, Mod, Case)\n", " - Run a single test case.\n", - " All above run functions can have the additional Options argument\n", + " All above run functions can have an additional Options argument\n", " which is a list of options.\n", "\n", "Run options supported:\n", @@ -158,7 +159,7 @@ help(installed) -> " {ctp | ctpl, Mod, Func}\n", " {ctp | ctpl, Mod, Func, Arity}\n", "\n", - "Support functions\n", + "Support functions:\n", " ts:tests() - Shows all available families of tests.\n", " ts:tests(Spec) - Shows all available test modules in Spec,\n", " i.e. ../Spec_test/*_SUITE.erl\n", @@ -179,6 +180,13 @@ help(installed) -> " - Compile all testcases for usage in a cross ~n" " compile environment." " \n" + "Benchmark functions:\n" + " ts:benchmarks() - Get all available families of benchmarks\n" + " ts:bench() - Runs all benchmarks\n" + " ts:bench(Spec) - Runs all benchmarks in the given spec file.\n" + " The spec file is actually ../*_test/Spec_bench.spec\n\n" + " ts:bench can take the same Options argument as ts:run.\n" + "\n" "Installation (already done):\n" ], show_help([H,?install_help]). @@ -491,6 +499,25 @@ tests(Spec) -> {ok, Cwd} = file:get_cwd(), ts_lib:suites(Cwd, atom_to_list(Spec)). +%% Benchmark related functions + +bench() -> + bench([]). + +bench(Opts) when is_list(Opts) -> + bench(benchmarks(),Opts); +bench(Spec) -> + bench([Spec],[]). + +bench(Spec, Opts) when is_atom(Spec) -> + bench([Spec],Opts); +bench(Specs, Opts) -> + check_and_run(fun(Vars) -> ts_benchmark:run(Specs, Opts, Vars) end). + +benchmarks() -> + ts_benchmark:benchmarks(). + + %% %% estone/0, estone/1 diff --git a/lib/test_server/src/ts_autoconf_vxworks.erl b/lib/test_server/src/ts_autoconf_vxworks.erl deleted file mode 100644 index f4535cd89a..0000000000 --- a/lib/test_server/src/ts_autoconf_vxworks.erl +++ /dev/null @@ -1,191 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%%% Purpose : Autoconf for cross environments. - --module(ts_autoconf_vxworks). --export([configure/1]). -%%% Supported cross platforms: --define(PLATFORMS, ["vxworks_cpu32", "vxworks_ppc860", "vxworks_ppc603", - "vxworks_sparc", "vxworks_ppc750", "vxworks_simso"]). --include("ts.hrl"). - -%% takes an argument {Target_arch, Target_host} (e.g. {vxworks_ppc860, thorin}). -configure({Target_arch, Target_host}) -> - case variables({Target_arch, Target_host}) of - {ok, Vars} -> - ts_lib:subst_file("conf_vars.in", "conf_vars", Vars); - Error -> - Error - end. - -variables(Cross_spec) -> - run_tests(Cross_spec, tests(), []). - -run_tests(Cross_spec, [{Prompt, Tester}|Rest], Vars) -> - io:format("checking ~s... ", [Prompt]), - case catch Tester(Cross_spec, Vars) of - {'EXIT', Reason} -> - io:format("FAILED~nExit status: ~p~n", [Reason]), - {error, auto_conf_failed}; - {Result, NewVars} -> - io:format("~s~n", [lists:concat([Result])]), - run_tests(Cross_spec, Rest, NewVars) - end; -run_tests(_Cross_spec, [], Vars) -> - {ok, Vars}. - - -%%% The tests. - -tests() -> - [{"supported target architecture", fun target_architecture/2}, - {"cross target host to run tests on", fun target_host/2}, - {"CPU type", fun cpu/2}, - {"for cross-compiling gcc", fun find_gcc/2}, - {"for cross-linker", fun find_ld/2}, - {"for object extension", fun find_obj/2}, - {"for shared libraries extension", fun find_dll/2}, - {"for executables extension", fun find_exe/2}, - {"for make", fun find_make/2}]. - -target_architecture({Architecture, _Target_host}, Vars) -> - case lists:member(Architecture, ?PLATFORMS) of - true -> - {Architecture, [{host_os, os_type(Architecture)}, {host, Architecture}|Vars]}; - false -> - {"unsupported_platform", Vars} - end. - -target_host({_Architecture, Target_host}, Vars) -> - {Target_host, [{target_host, Target_host} | Vars]}. - -cpu({Arch, _Target_host}, Vars) -> - Cpu = processor(Arch), - {Cpu, [{host_cpu, Cpu}|Vars]}. - -find_gcc({Arch, _Target_host}, Vars) -> - Gcc = "cc" ++ gnu_suffix(Arch), - case os:find_executable(Gcc) of - false -> - {no, Vars}; - Path when is_list(Path) -> - Cflags = cflags(Arch), - {Path, [{'CC', Gcc}, - {'CFLAGS', Cflags}, - {'EI_CFLAGS', Cflags}, - {'ERTS_CFLAGS', Cflags}, - {'DEFS', ""}, - {'ERTS_LIBS', ""}, - {'LIBS', ""}, - {'SHLIB_CFLAGS', Cflags}, - {test_c_compiler, "{gnuc, undefined}"} | Vars]} - end. - -find_ld({Arch, _Target_host}, Vars) -> - Linker = "ld" ++ gnu_suffix(Arch), - case os:find_executable(Linker) of - false -> - {no, Vars}; - Path when is_list(Path) -> - {Path, [{'LD', Linker}, - {'CROSSLDFLAGS', ldflags(Arch)}, - {'SHLIB_EXTRACT_ALL', ""}, - {'SHLIB_LD', Linker}, - {'SHLIB_LDFLAGS', ""}, - {'SHLIB_LDLIBS', ""} | Vars]} - end. - -find_obj({Arch, _Target_host}, Vars) -> - Obj = obj_ext(Arch), - {Obj, [{obj, Obj}|Vars]}. - -find_dll({Arch, _Target_host}, Vars) -> - Dll = dll_ext(Arch), - {Dll, [{'SHLIB_SUFFIX', Dll}|Vars]}. - -find_exe({Arch, _Target_host}, Vars) -> - Exe = exe_ext(Arch), - {Exe, [{exe, Exe}|Vars]}. - -find_make(_, Vars) -> - {"make", [{make_command, "make"} | Vars]}. - -%%% some utility functions -gnu_suffix(Arch) -> - {_, _, _, _, Suffix, _Cpu, _Cflags, _} = cross_data(Arch), - Suffix. - -processor(Arch) -> - {_, _, _, _, _Suffix, Cpu, _Cflags, _} = cross_data(Arch), - Cpu. - -cflags(Arch) -> - {_, _, _, _, _Suffix, _Cpu, Cflags, _} = cross_data(Arch), - Cflags. - -ldflags(Arch) -> - {_, _, _, _, _Suffix, _Cpu, _Cflags, Ldflags} = cross_data(Arch), - Ldflags. - -os_type(Arch) -> - {Os_type, _, _, _, _, _, _, _} = cross_data(Arch), - Os_type. - -obj_ext(Arch) -> - {_, _, Obj, _, _, _, _, _} = cross_data(Arch), - Obj. - -dll_ext(Arch) -> - {_, _, _, Dll, _, _, _, _} = cross_data(Arch), - Dll. - -exe_ext(Arch) -> - {_, Exe, _, _, _, _, _, _} = cross_data(Arch), - Exe. - -cross_data(Arch) -> - case Arch of - "vxworks_cpu32" -> - {"VxWorks", "", ".o", ".eld", "68k", "cpu32", - "-DCPU=CPU32 -DVXWORKS -I$(WIND_BASE)/target/h -mnobitfield -fno-builtin -nostdinc -fvolatile -msoft-float", - "-r -d"}; - "vxworks_ppc860" -> - {"VxWorks", "", ".o", ".eld", "ppc", "ppc860", - "-DCPU=PPC860 -DVXWORKS -I$(WIND_BASE)/target/h -mcpu=860 -fno-builtin -fno-for-scope -msoft-float -D_GNU_TOOL -nostdinc", - "-r -d"}; - "vxworks_ppc603" -> - {"VxWorks", "", ".o", ".eld", "ppc", "ppc603", - "-DCPU=PPC603 -DVXWORKS -I$(WIND_BASE)/target/h -fno-builtin -fno-for-scope -D_GNU_TOOL -nostdinc", - "-r -d"}; - "vxworks_sparc" -> - %%% The Sparc Architecture is included for private use (i.e. not Tornado 1.0.1 compatible). - {"VxWorks", "", ".o", ".eld", "sparc", "sparc", - "-DCPU=SPARC -DVXWORKS -I/home/gandalf/bsproj/BS.2/UOS/vw/5.2/h -fno-builtin -nostdinc", - "-r -d"}; - "vxworks_ppc750" -> - {"VxWorks", "", ".o", ".eld", "ppc", "ppc604", - "-DCPU=PPC604 -DVXWORKS -DTOOL_FAMILY=gnu -DTOOL=gnu -I$(WIND_BASE)/target/h -fno-builtin -fno-for-scope -D_GNU_TOOL", - "-r -d"}; - "vxworks_simso" -> - {"VxWorks", "", ".o", ".eld", "simso", "simso", - "-DCPU=SIMSPARCSOLARIS -DVXWORKS -DTOOL_FAMILY=gnu -DTOOL=gnu -I$(WIND_BASE)/target/h -I$(WIND_GCC_INCLUDE) -fno-builtin -fno-for-scope -D_GNU_TOOL", - "-r -d"} - - end. diff --git a/lib/test_server/src/ts_benchmark.erl b/lib/test_server/src/ts_benchmark.erl new file mode 100644 index 0000000000..516d22fd2d --- /dev/null +++ b/lib/test_server/src/ts_benchmark.erl @@ -0,0 +1,91 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012-2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(ts_benchmark). + +-include_lib("common_test/include/ct_event.hrl"). +-include_lib("kernel/include/file.hrl"). +-include("ts.hrl"). + +-export([benchmarks/0, + run/3]). + +%% gen_event callbacks +-export([init/1, handle_event/2]). + +benchmarks() -> + {ok, Cwd} = file:get_cwd(), + Benches = filelib:wildcard( + filename:join([Cwd,"..","*_test","*_bench.spec"])), + [begin + Base = filename:basename(N), + list_to_atom(string:substr(Base,1,string:rstr(Base,"_")-1)) + end || N <- Benches]. + +run(Specs, Opts, Vars) -> + {ok, Cwd} = file:get_cwd(), + {{YY,MM,DD},{HH,Mi,SS}} = calendar:local_time(), + BName = lists:concat([YY,"_",MM,"_",DD,"T",HH,"_",Mi,"_",SS]), + BDir = filename:join([Cwd,BName]), + file:make_dir(BDir), + [ts_run:run(atom_to_list(Spec), + [{spec, [atom_to_list(Spec)++"_bench.spec"]}], + [{event_handler, {ts_benchmark, [Spec,BDir]}}|Opts],Vars) + || Spec <- Specs], + file:delete(filename:join(Cwd,"latest_benchmark")), + {ok,D} = file:open(filename:join(Cwd,"latest_benchmark"),[write]), + io:format(D,BDir,[]), + file:close(D). + + +%%%=================================================================== +%%% gen_event callbacks +%%%=================================================================== + +-record(state, { spec, suite, tc, stats_dir}). + +init([Spec,Dir]) -> + {ok, #state{ spec = Spec, stats_dir = Dir }}. + +handle_event(#event{name = tc_start, data = {Suite,Tc}}, State) -> + {ok,State#state{ suite = Suite, tc = Tc}}; +handle_event(#event{name = benchmark_data, data = Data}, State) -> + Spec = proplists:get_value(application, Data, State#state.spec), + Suite = proplists:get_value(suite, Data, State#state.suite), + Tc = proplists:get_value(name, Data, State#state.tc), + Value = proplists:get_value(value, Data), + {ok, D} = file:open(filename:join( + [State#state.stats_dir, + lists:concat([e(Spec),"-",e(Suite),"-", + e(Tc),".ebench"])]), + [append]), + io:format(D, "~p~n",[Value]), + file:close(D), + {ok, State}; +handle_event(_Event, State) -> + {ok, State}. + + +e(Atom) when is_atom(Atom) -> + Atom; +e(Str) when is_list(Str) -> + lists:map(fun($/) -> + $\\; + (C) -> + C + end,Str). diff --git a/lib/test_server/src/ts_erl_config.erl b/lib/test_server/src/ts_erl_config.erl index 45d88016a4..83f8362735 100644 --- a/lib/test_server/src/ts_erl_config.erl +++ b/lib/test_server/src/ts_erl_config.erl @@ -160,7 +160,6 @@ system_include(Root, Vars) -> SysDir = case ts_lib:var(os, Vars) of "Windows" ++ _T -> "sys/win32"; - "VxWorks" -> "sys.vxworks"; _ -> "sys/unix" end, " -I" ++ quote(filename:nativename(filename:join([Root, "erts", "emulator", SysDir]))). @@ -176,9 +175,6 @@ erl_interface(Vars,OsType) -> {installed, _Root} -> {filename:join(Dir, "lib"), filename:join(Dir, "src")}; - {srctree, _Root, _Target} when OsType =:= vxworks -> - {filename:join(Dir, "lib"), - filename:join([Dir, "src"])}; {srctree, _Root, Target} -> {filename:join([Dir, "obj", Target]), filename:join([Dir, "src", Target])} @@ -218,7 +214,7 @@ erl_interface(Vars,OsType) -> {unix,_} -> "-lpthread"; _ -> - "" % VxWorks + "" end, [{erl_interface_libpath, quote(filename:nativename(LibPath))}, {erl_interface_sock_libs, sock_libraries(OsType)}, @@ -318,16 +314,12 @@ get_var(Key, Vars) -> sock_libraries({win32, _}) -> "ws2_32.lib"; sock_libraries({unix, _}) -> - ""; % Included in general libraries if needed. -sock_libraries(vxworks) -> - "". + "". % Included in general libraries if needed. link_library(LibName,{win32, _}) -> LibName ++ ".lib"; link_library(LibName,{unix, _}) -> "lib" ++ LibName ++ ".a"; -link_library(LibName,vxworks) -> - "lib" ++ LibName ++ ".a"; link_library(_LibName,_Other) -> exit({link_library, not_supported}). diff --git a/lib/test_server/src/ts_install.erl b/lib/test_server/src/ts_install.erl index 99ccfbc9bc..8edb1ed5c6 100644 --- a/lib/test_server/src/ts_install.erl +++ b/lib/test_server/src/ts_install.erl @@ -55,8 +55,7 @@ build_install(TargetSystem, Options) -> end. os_type({unix,_}=OsType) -> OsType; -os_type({win32,_}=OsType) -> OsType; -os_type(_Other) -> vxworks. +os_type({win32,_}=OsType) -> OsType. target_install(CrossVars) -> io:format("Cross installation detected, skipping configure and data_dir make~n"), @@ -76,7 +75,6 @@ target_install(CrossVars) -> %% Autoconf for various platforms. %% unix uses the configure script %% win32 uses ts_autoconf_win32 -%% VxWorks uses ts_autoconf_vxworks. autoconf(TargetSystem, XComp) -> case autoconf1(TargetSystem, XComp) of @@ -90,8 +88,6 @@ autoconf1({win32, _},[{cross,"no"}]) -> ts_autoconf_win32:configure(); autoconf1({unix, _},XCompFile) -> unix_autoconf(XCompFile); -autoconf1(Other,[{cross,"no"}]) -> - ts_autoconf_vxworks:configure(Other); autoconf1(_,_) -> io:format("cross compilation not supported for that this platform~n"), throw(cross_installation_failed). diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl index d521d2beda..93d5d78289 100644 --- a/lib/test_server/src/ts_lib.erl +++ b/lib/test_server/src/ts_lib.erl @@ -108,8 +108,16 @@ interesting_logs(Dir) -> specs(Dir) -> Specs = filelib:wildcard(filename:join([filename:dirname(Dir), - "*_test", "*.{dyn,}spec"])), - sort_tests([filename_to_atom(Name) || Name <- Specs]). + "*_test", "*.{dyn,}spec"])), + % Filter away all spec which end with _bench.spec + NoBench = fun(SpecName) -> + case lists:reverse(SpecName) of + "ceps.hcneb_"++_ -> false; + _ -> true + end + end, + + sort_tests([filename_to_atom(Name) || Name <- Specs, NoBench(Name)]). suites(Dir, Spec) -> Glob=filename:join([filename:dirname(Dir), Spec++"_test", diff --git a/lib/test_server/src/ts_run.erl b/lib/test_server/src/ts_run.erl index a61028e4bc..5ce8e66660 100644 --- a/lib/test_server/src/ts_run.erl +++ b/lib/test_server/src/ts_run.erl @@ -157,7 +157,6 @@ get_config_files() -> [TSConfig | case os:type() of {unix,_} -> ["ts.unix.config"]; {win32,_} -> ["ts.win32.config"]; - vxworks -> ["ts.vxworks.config"]; _ -> [] end]. @@ -329,8 +328,7 @@ start_xterm(Command) -> path_separator() -> case os:type() of {win32, _} -> ";"; - {unix, _} -> ":"; - vxworks -> ":" + {unix, _} -> ":" end. diff --git a/lib/test_server/src/vxworks_client.erl b/lib/test_server/src/vxworks_client.erl deleted file mode 100644 index ca65eca02a..0000000000 --- a/lib/test_server/src/vxworks_client.erl +++ /dev/null @@ -1,243 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% --module(vxworks_client). - --export([open/1, close/1, send_data/2, send_data/3, send_data_wait_for_close/2, reboot/1]). --export([init/2]). - --include("ts.hrl"). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% This is a client talking to a test server daemon on a VxWorks card. -%%% -%%% User interface: -%%% -%%% open/1 -%%% Start a client and establish the connection with the test server daemon -%%% -%%% send_data/2 -%%% Send data/command to the test server daemon, don't wait for any return -%%% -%%% send_data/3 -%%% Send data/command to the test server daemon and wait for the given -%%% return value. -%%% -%%% send_data_wait_for_close/2 -%%% Send data/command to the test server daemon and wait for the daemon to -%%% close the connection. -%%% -%%% close/1 -%%% Close the client. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -%% -%% User interface -%% - -reboot(Target) -> - {ok, {_,_,_,_,_,[Addr|_]}} = inet:gethostbyname(Target), - Fun = fun({ok, Socket}) -> - gen_tcp:send(Socket, "q\n"), - receive - {tcp_closed, Socket} -> - gen_tcp:close(Socket), - {ok, socket_closed} - after 5000 -> - exit({timeout, tryagain}) - end - end, - io:format("Stopping (rebooting) ~p ",[Target]), - case fun_target(Addr, Fun) of - {ok, socket_closed} -> - ok; - _Else -> - io:format("No contact with ts daemon - exiting ...~n"), - exit({stop, no_ts_daemon_contact}) - end. - - -%% open(Target) -> {ok,Client} | {error, Reason} -open(Target) -> - {ok, {_,_,_,_,_,[Addr|_]}} = inet:gethostbyname(Target), - Fun = fun({ok, Socket}) -> - P = spawn(?MODULE,init,[Target,Socket]), - inet_tcp:controlling_process(Socket,P), - {ok,P} - end, - case fun_target(Addr,Fun) of - {ok, Pid} -> - {ok, Pid}; - {error,Reason} -> - {error, Reason} - end. - -%% send_data(Client,Data) -> ok -send_data(Pid,Data) -> - Pid ! {send_data,Data++"\n"}, - ok. - -%% send_data(Client,Data,ExpectedReturn) -> {ok,ExpectedReturn} | {error,Reason} -send_data(Pid,Data,Return) -> - Pid ! {send_data,Data++"\n",Return,self()}, - receive {Pid,Result} -> Result end. - -%% send_data_wait_for_close(Client,Data) -> ok | {error,Reason} -send_data_wait_for_close(Pid,Data) -> - send_data(Pid,Data,tcp_closed). - -%% close(Client) -> ok -close(Pid) -> - Pid ! close, - ok. - - -%% -%% Internal -%% - -init(Target,Socket) -> - process_flag(trap_exit,true), - loop(Target,Socket). - -loop(Target,Socket) -> - receive - {send_data,Data} -> - %% io:format("vx client sending: ~p~n", [Data]), - gen_tcp:send(Socket, Data), - loop(Socket,Target); - {send_data,Data,tcp_closed,From} -> - %% io:format("vx client sending: ~p~n", [Data]), - gen_tcp:send(Socket, Data), - receive - {tcp_closed, Socket} -> - From ! {self(),ok} - after 5000 -> - From ! {self(),{error,timeout}} - end, - closed(Socket,normal); - {send_data,Data,Return,From} -> - %% io:format("vx client sending: ~p~n", [Data]), - gen_tcp:send(Socket, Data), - case receive_line(Socket,[],Return,200) of - {tcp_closed, Socket} -> - From ! {self(),{error,{socket_closed,Target}}}, - closed(Socket,{socket_closed,Target}); - {tcp,Socket,_Rest} -> - From ! {self(),{ok,Data}}, - got_data(Target,Socket,Data); - error -> - From ! {self(),{error,{catatonic,Target}}} - end; - close -> - closed(Socket,normal); - {tcp_closed, Socket} -> - closed(Socket,{socket_closed,Target}); - {tcp,Socket,Data} -> - got_data(Target,Socket,Data) - end. - - - -closed(Socket,Reason) -> - gen_tcp:close(Socket), - exit(Reason). - -got_data(Target,Socket,Data) -> - if is_atom(Target) -> - io:format("~w: ~s",[Target,uncr(Data)]); - true -> - io:format("~s: ~s",[Target,uncr(Data)]) - end, - loop(Target,Socket). - -uncr([]) -> - []; -uncr([$\r | T]) -> - uncr(T); -uncr([H | T]) -> - [H | uncr(T)]. - -strip_line(Line) -> - RPos = string:rchr(Line, $\n), - string:substr(Line,RPos+1). - -maybe_done_receive(Socket,Ack,Match,C) -> - case string:str(Ack,Match) of - 0 -> - receive_line(Socket,strip_line(Ack),Match,C); - _ -> - {tcp,Socket,strip_line(Ack)} - end. - - -receive_line(_Socket,_Ack,_Match,0) -> - error; -receive_line(Socket,Ack,Match,Counter) -> - receive - {tcp_closed, Socket} -> - {tcp_closed, Socket}; - {tcp,Socket,Data} -> - NewAck = Ack ++ Data, - case {string:str(NewAck,"\r") > 0, - string:str(NewAck,"\n") > 0} of - {true,_} -> - maybe_done_receive(Socket,NewAck,Match,Counter-1); - {_,true} -> - maybe_done_receive(Socket,NewAck,Match,Counter-1); - _ -> - receive_line(Socket,NewAck,Match,Counter) - end - after 20000 -> - error - end. - - -%% Misc functions -fun_target(Addr, Fun) -> - io:format("["), - fun_target(Addr, Fun, 60). %Vx-cards need plenty of time. - -fun_target(_Addr, _Fun, 0) -> - io:format(" no contact with ts daemon]~n"), - {error,failed_to_connect}; -fun_target(Addr, Fun, Tries_left) -> - receive after 1 -> ok end, - case do_connect(Addr, Fun) of - {ok, Value} -> - io:format(" ok]~n"), - {ok, Value}; - _Error -> % typical {error, econnrefused} - io:format("."), - receive after 10000 -> ok end, - fun_target(Addr, Fun, Tries_left-1) - end. - -do_connect(Addr, Fun) -> - case gen_tcp:connect(Addr, ?TS_PORT, [{reuseaddr, true}], 60000) of - {ok, Socket} -> - Fun({ok, Socket}); - Error -> - Error - end. - - - diff --git a/lib/test_server/test/test_server.cover b/lib/test_server/test/test_server.cover index 5c59bab494..c16212567e 100644 --- a/lib/test_server/test/test_server.cover +++ b/lib/test_server/test/test_server.cover @@ -11,12 +11,11 @@ test_server_node, test_server_sup, ts, - ts_autoconf_vxworks, ts_autoconf_win32, ts_erl_config, ts_install, ts_lib, ts_make, - ts_run, - vxworks_client]}. + ts_run + ]}. diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index 8f98d6c85c..6c723a5c1c 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -483,10 +483,6 @@ function.") "*Non-nil means TAB in Erlang mode should always re-indent the current line, regardless of where in the line point is when the TAB command is used.") -(defvar erlang-error-regexp-alist - '(("^\\([^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)[:) \t]" . (1 2))) - "*Patterns for matching Erlang errors.") - (defvar erlang-man-inhibit (eq system-type 'windows-nt) "Inhibit the creation of the Erlang Manual Pages menu. @@ -1327,7 +1323,6 @@ Other commands: (erlang-menu-init) (erlang-mode-variables) (erlang-check-module-name-init) - (erlang-add-compilation-alist erlang-error-regexp-alist) (erlang-man-init) (erlang-tags-init) (erlang-font-lock-init) @@ -1443,31 +1438,6 @@ Other commands: (set (make-local-variable 'outline-level) (lambda () 1)) (set (make-local-variable 'add-log-current-defun-function) 'erlang-current-defun)) - - -;; Compilation. -;; -;; The following code is compatible with the standard package `compilation', -;; making it possible to go to errors using `erlang-next-error' (or just -;; `next-error' in Emacs 21). -;; -;; The normal `compile' command works of course. For best result, please -;; execute `make' with the `-w' flag. -;; -;; Please see the variables named `compiling-..' above. - -(defun erlang-add-compilation-alist (alist) - (require 'compile) - (cond ((boundp 'compilation-error-regexp-alist) ; Emacs 19 - (while alist - (or (assoc (car (car alist)) compilation-error-regexp-alist) - (setq compilation-error-regexp-alist - (cons (car alist) compilation-error-regexp-alist))) - (setq alist (cdr alist)))) - ((boundp 'compilation-error-regexp) - ;; Emacs 18, Only one regexp is allowed. - (funcall (symbol-function 'set) - 'compilation-error-regexp (car (car alist)))))) (defun erlang-font-lock-init () "Initialize Font Lock for Erlang mode." @@ -4896,7 +4866,6 @@ The following special commands are available: (set (make-local-variable 'compilation-old-error-list) nil)) ;; Needed when compiling directly from the Erlang shell. (setq compilation-last-buffer (current-buffer)) - (erlang-add-compilation-alist erlang-error-regexp-alist) (setq comint-prompt-regexp "^[^>=]*> *") (setq comint-eol-on-send t) (setq comint-input-ignoredups t) diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl index 1e40b8926e..4f1d46ee6c 100644 --- a/lib/typer/src/typer.erl +++ b/lib/typer/src/typer.erl @@ -1007,7 +1007,7 @@ msg(Msg) -> port_command(P, Msg), true = port_close(P), ok; - _ -> % win32, vxworks + _ -> % win32 io:format("~s", [Msg]) end. diff --git a/make/emd2exml.in b/make/emd2exml.in index 16c38379d9..b677ef8ed4 100644 --- a/make/emd2exml.in +++ b/make/emd2exml.in @@ -266,8 +266,11 @@ parse(#state{code = true, type = blank, line = CB, code_blank = CBs} = S) -> parse(#state{code = true, code_blank = CB, list_lvl = Lvl, - type = {text, TxtLvl}, - line = Line} = S) when TxtLvl > Lvl -> + type = {Type, TxtLvl}, + line = Line} = S) when TxtLvl > Lvl, + (Type == text orelse + Type == uolist orelse + Type == olist) -> Data = code(strip_lvls(Lvl+1, Line)), parse(get_line(put_chars(S#state{code_blank = []}, [strip_code_blank(Lvl+1, CB), Data]))); @@ -994,7 +997,7 @@ resolve_link([_|Cs], start, "", "", "") -> resolve_link(Cs, start, "", "", ""); resolve_link("]:" ++ Rest, key, Yek, "", "") -> resolve_link(Rest, url, Yek, "", ""); -resolve_link([C|Cs], url, Yek, Lru, "") when C == $"; C == $' -> +resolve_link([C|Cs], url, Yek, Lru, "") when C == $"; C == $' -> %" resolve_link(Cs, {title, C}, Yek, Lru, ""); resolve_link([$(|Cs], url, Yek, Lru, "") -> resolve_link(Cs, {title, $)}, Yek, Lru, ""); @@ -1010,9 +1013,21 @@ resolve_link([_|Cs], drop, Yek, Lru, Eltit) -> resolve_link(Cs, drop, Yek, Lru, Eltit); resolve_link([], _, Yek, Lru, Eltit) -> {ws_strip(lists:reverse(Yek)), - ws_strip(lists:reverse(Lru)), + ws_strip(md_strip_n_reverse(Lru)), ws_strip(lists:reverse(Eltit))}. +%% Remove .md at end of references. +md_strip_n_reverse(Lru) -> + md_strip_n_reverse(Lru,[]). +md_strip_n_reverse("\ndm."++Lru,Acc) -> + md_strip_n_reverse(Lru,Acc); +md_strip_n_reverse("#dm."++Lru,Acc) -> + md_strip_n_reverse(Lru,[$#|Acc]); +md_strip_n_reverse([C|T],Acc) -> + md_strip_n_reverse(T,[C|Acc]); +md_strip_n_reverse([], Acc) -> + Acc. + %% %% Misc %% diff --git a/make/otp.mk.in b/make/otp.mk.in index 756cc85443..ed2fd8a70b 100644 --- a/make/otp.mk.in +++ b/make/otp.mk.in @@ -77,19 +77,13 @@ OTP_RELEASE = @OTP_RELEASE@ # Erlang language section # ---------------------------------------------------- EMULATOR = beam -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -# VxWorks object files should be compressed. -# Other object files should have debug_info. - ERL_COMPILE_FLAGS += +compressed +ifeq ($(findstring ose_ppc750,$(TARGET)),ose_ppc750) +ERL_COMPILE_FLAGS += +compressed else - ifeq ($(findstring ose_ppc750,$(TARGET)),ose_ppc750) - ERL_COMPILE_FLAGS += +compressed + ifdef BOOTSTRAP + ERL_COMPILE_FLAGS += +slim else - ifdef BOOTSTRAP - ERL_COMPILE_FLAGS += +slim - else - ERL_COMPILE_FLAGS += +debug_info - endif + ERL_COMPILE_FLAGS += +debug_info endif endif ERLC_WFLAGS = -W diff --git a/system/README b/system/README index b8ff18119d..b1e18ef55c 100644 --- a/system/README +++ b/system/README @@ -51,10 +51,9 @@ Release of Erlang 5.9/OTP R15B ------------------------------- 3.1 The platform VxWorks is discontinued in the sense that only the - libraries (erl_interface and ic's libraries) are supported. Running - the Erlang emulator on VxWorks might still possible but it's no longer - maintained. The VxWorks release is still packaged as a full release, - but no support will be available for anything but the communication libraries. + libraries (erl_interface and ic's libraries) are supported. The VxWorks + release is still packaged as a full release, but no support will be + available for anything but the communication libraries. 4 NOTES ABOUT THE LINUX VERSIONS ----------------------------- diff --git a/system/doc/embedded/vxworks.xml b/system/doc/embedded/vxworks.xml deleted file mode 100644 index 52143a42e3..0000000000 --- a/system/doc/embedded/vxworks.xml +++ /dev/null @@ -1,193 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>1997</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>VxWorks</title> - <prepared>Patrik Winroth</prepared> - <responsible></responsible> - <docno></docno> - <approved></approved> - <checked></checked> - <date>2000-10-17</date> - <rev></rev> - <file>vxworks.xml</file> - </header> - <p>This chapter describes the OS specific parts of OTP which relate - to VxWorks. - </p> - - <section> - <title>Introduction</title> - <p>The Erlang/OTP distribution for VxWorks is limited to what - Switchboard requires (Switchboard is a general purpose - switching hardware developed by Ericsson). - </p> - <p>Please consult the README file, included at root level in the - installation, for latest information on the distribution. - </p> - </section> - - <section> - <title>Memory Usage</title> - <p>Memory required is 32 Mbyte. - </p> - </section> - - <section> - <title>Disk Usage</title> - <p>The disk space required is 22 Mbyte, the documentation included. - </p> - </section> - - <section> - <title>Installation</title> - <p>OTP/VxWorks is supplied in a distribution file named - <c><![CDATA[<PREFIX>.tar.gz]]></c>; i.e. a tar archive that is - compressed with gzip. <c><![CDATA[<PREFIX>]]></c> represents the - name of the release, - e.g. <c>otp_LXA12345_vxworks_cpu32_R42A</c>. Assuming you are - installing to a Solaris file system, the installation is - performed by following these steps: < - </p> - <p></p> - <list type="bulleted"> - <item>Change to the directory where you want to install - OTP/VxWorks (<c><![CDATA[<ROOTDIR>]]></c>): <c><![CDATA[cd <ROOTDIR>]]></c></item> - <item>Make a directory to put OTP/VxWorks in: <c>mkdir otp_vxworks_cpu32</c> (or whatever you want to call it)</item> - <item>Change directory to the newly created one: <c>cd otp_vxworks_cpu32</c></item> - <item>Copy the distribution file there from where it is located - (<c><![CDATA[<RELDIR>]]></c>): <c><![CDATA[cp <RELDIR>/<PREFIX>.tar.gz .]]></c></item> - <item>Unzip the distribution file: <c><![CDATA[gunzip <PREFIX>.tar.gz]]></c></item> - <item>Untar <c><![CDATA[<PREFIX>.tar]]></c>: <c><![CDATA[tar xvf <PREFIX>.tar]]></c></item> - <item>Create a bin directory: <c>mkdir bin</c></item> - <item>Copy the VxWorks Erlang/OTP start-up script to the bin directory: - <c>cp erts-Vsn/bin/erl bin/.</c></item> - <item>Copy the example start scripts to the bin directory: - <c>cp releases/R42A/*.boot bin/.</c></item> - </list> - <p>If you use VxWorks nfs mounting facility to mount the Solaris - file system, this installation may be directly used. An other - possibility is to copy the installation to a local VxWorks DOS - file system, from where it is used. - </p> - </section> - - <section> - <title>OS Specific Functionality/Information</title> - <p>There are a couple of files that are unique to the VxWorks - distribution of Erlang/OTP, these files are described here. - </p> - <list type="bulleted"> - <item>README - this files has some information on VxWorks - specifics that you are advised to consult. This includes the - latest information on what parts of OTP are included in the - VxWorks distribution of Erlang/OTP. If you want us to - include more parts, please contact us to discuss - this.</item> - <item>erts-Vsn/bin/resolv.conf - A resolver configuration EXAMPLE file. - You have to edit this file.</item> - <item>erts-Vsn/bin/erl - This is an EXAMPLE start script for VxWorks. - You have to edit this file to suit your needs.</item> - <item>erts-Vsn/bin/erl_io - One possible solution to the problem - of competing Erlang and VxWorks shell. Contains the function - 'start_erl' called by the erl script. Also contains the - function 'to_erl' to be used when connecting to the Erlang - shell from VxWorks' shell.</item> - <item>erts-Vsn/bin/erl_exec - Rearranges command line arguments - and starts Erlang.</item> - <item>erts-Vsn/bin/vxcall - Allows spawning of standard VxWorks - shell functions (which is just about any function in the - system...) from open_port/2. E.g. open_port({spawn, 'vxcall - func arg1 arg2'}, []) will cause the output that 'func arg1, - arg2' would have given in the shell to be received from the - port.</item> - <item>erts-Vsn/bin/rdate - Set the time from a networked host, - like the SunOS command. Nothing Erlang-specific, but nice - if you want date/0 and time/0 to give meaningful values (you - also need a TIMEZONE environment setting if GMT isn't - acceptable). For example: <c>putenv "TIMEZONE=CET::-60:033002:102603"</c> sets central european - time.</item> - <item>erts-Vsn/src - Contains source for the above files, and - additionally config.c, driver.h, preload.c and - reclaim.h. Reclaim.h defines the interface to a simple - mechanism for "resource reclamation" that is part of the - Erlang runtime system - may be useful to "port program" writers (and - possibly others). Take careful note of the caveats listed in - the file!</item> - </list> - </section> - - <section> - <title>Starting Erlang</title> - <p>Start (and restart) of the system depends on what file system - is used. To be able to start the system from a nfs mounted - file system you can use VxWorks start script facility to run a - start script similar to the example below. Note that the - Erlang/OTP start-up script is run at the end of this script. - </p> - <code type="none"><![CDATA[ -# start.script v1.0 1997/09/08 patrik -# -# File name: start.script -# Purpose: Starting the VxWorks/cpu32 erlang/OTP -# Author: [email protected] -# Resides in: ~tornado/wind/target/config/ads360/ - -# -# Set shell prompt -# -shellPromptSet("sauron-> ") - -# -# Set default gateway -# -hostAdd "router-20","150.236.20.251" -routeAdd "0","router-20" - -# -# Mount /home from gandalf -# -hostAdd "gandalf","150.236.20.16" -usergroup=10 -nfsAuthUnixSet("gandalf", 452, 10, 1, &usergroup) -nfsMount("gandalf", "/export/home", "/home") - -# -# Load and run rdate.o to set correct date on the target -# -ld < /home/gandalf/tornado/wind/target/config/ads360/rdate.o -rdate("gandalf") - -# -# Setup timezone information (Central European time) -# -putenv "TIMEZONE=CET::-60:033002:102603" - -# -# Run the Erlang/OTP start script -# -cd "/home/gandalf/tornado/wind/target/erlang_cpu32_R42A/bin" -<erl - ]]></code> - </section> -</chapter> - diff --git a/system/doc/embedded/xmlfiles.mk b/system/doc/embedded/xmlfiles.mk index 2bdc34ae28..0001a55b9a 100644 --- a/system/doc/embedded/xmlfiles.mk +++ b/system/doc/embedded/xmlfiles.mk @@ -18,5 +18,4 @@ # EMBEDDED_CHAPTER_FILES = \ embedded_solaris.xml \ - embedded_nt.xml \ - vxworks.xml + embedded_nt.xml diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile index 4636650570..5ad9af4be9 100644 --- a/system/doc/installation_guide/Makefile +++ b/system/doc/installation_guide/Makefile @@ -58,7 +58,8 @@ XML_FILES = \ GENERATED_XML_FILES = \ INSTALL.xml \ INSTALL-CROSS.xml \ - INSTALL-WIN32.xml + INSTALL-WIN32.xml \ + MARKDOWN.xml # ---------------------------------------------------- @@ -73,7 +74,8 @@ REDIRECT_HTML_DIR = $(HTMLDIR)/source REDIRECT_HTML_FILES = \ $(REDIRECT_HTML_DIR)/INSTALL.html \ $(REDIRECT_HTML_DIR)/INSTALL-CROSS.html \ - $(REDIRECT_HTML_DIR)/INSTALL-WIN32.html + $(REDIRECT_HTML_DIR)/INSTALL-WIN32.html \ + $(REDIRECT_HTML_DIR)/MARKDOWN.html # ---------------------------------------------------- # FLAGS @@ -85,7 +87,7 @@ DVIPS_FLAGS += # Targets # ---------------------------------------------------- -%.xml: $(ERL_TOP)/%.md $(ERL_TOP)/make/emd2exml +%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml $(ERL_TOP)/make/emd2exml $< $@ $(REDIRECT_HTML_DIR)/%.html: Makefile diff --git a/system/doc/installation_guide/part.xml b/system/doc/installation_guide/part.xml index fceacdd8f6..648beb0afd 100644 --- a/system/doc/installation_guide/part.xml +++ b/system/doc/installation_guide/part.xml @@ -36,5 +36,5 @@ <xi:include href="INSTALL.xml"/> <xi:include href="INSTALL-CROSS.xml"/> <xi:include href="INSTALL-WIN32.xml"/> -</part> - + <xi:include href="MARKDOWN.xml"/> +</part>
\ No newline at end of file diff --git a/system/doc/installation_guide/xmlfiles.mk b/system/doc/installation_guide/xmlfiles.mk index dee67b3c70..8ea2b296aa 100644 --- a/system/doc/installation_guide/xmlfiles.mk +++ b/system/doc/installation_guide/xmlfiles.mk @@ -21,4 +21,5 @@ INST_GUIDE_CHAPTER_FILES = \ verification.xml \ INSTALL.xml \ INSTALL-CROSS.xml \ - INSTALL-WIN32.xml + INSTALL-WIN32.xml \ + MARKDOWN.xml diff --git a/xcomp/README.md b/xcomp/README.md index 5f4b36bdca..d08b3160ba 100644..120000 --- a/xcomp/README.md +++ b/xcomp/README.md @@ -1,555 +1 @@ -Cross Compiling Erlang/OTP -========================== - -Introduction ------------- - -This document describes how to cross compile Erlang/OTP-%OTP-REL%. Note that -the support for cross compiling Erlang/OTP should be considered as -experimental. As far as we know, the %OTP-REL% release should cross compile -fine, but since we currently have a very limited set of cross compilation -environments to test with we cannot be sure. The cross compilation support -will remain in an experimental state until we get a lot more cross compilation -environments to test with. - -You are advised to read the whole document before attempting to cross -compile Erlang/OTP. However, before reading this document, you should read -the [$ERL_TOP/INSTALL.md][] document which describes building and installing -Erlang/OTP in general. `$ERL_TOP` is the top directory in the source tree. - -### otp\_build Versus configure/make ### - -Building Erlang/OTP can be done either by using the `$ERL_TOP/otp_build` -script, or by invoking `$ERL_TOP/configure` and `make` directly. Building using -`otp_build` is easier since it involves fewer steps, but the `otp_build` build -procedure is not as flexible as the `configure`/`make` build procedure. Note -that `otp_build configure` will produce a default configuration that differs -from what `configure` will produce by default. For example, currently -`--disable-dynamic-ssl-lib` is added to the `configure` command line arguments -unless `--enable-dynamic-ssl-lib` has been explicitly passed. The binary -releases that we deliver are built using `otp_build`. The defaults used by -`otp_build configure` may change at any time without prior notice. - -### Cross Configuration ### - -The `$ERL_TOP/xcomp/erl-xcomp.conf.template` file contains all available cross -configuration variables and can be used as a template when creating a cross -compilation configuration. All [cross configuration variables][] are also -listed at the end of this document. For examples of working cross -configurations see the `$ERL_TOP/xcomp/erl-xcomp-TileraMDE2.0-tilepro.conf` -file and the `$ERL_TOP/xcomp/erl-xcomp-x86_64-saf-linux-gnu.conf` file. If the -default behavior of a variable is satisfactory, the variable does not need to -be set. However, the `configure` script will issue a warning when a default -value is used. When a variable has been set, no warning will be issued. - -A cross configuration file can be passed to `otp_build configure` using the -`--xcomp-conf` command line argument. Note that `configure` does not accept -this command line argument. When using the `configure` script directly, pass -the configuration variables as arguments to `configure` using a -`<VARIABLE>=<VALUE>` syntax. Variables can also be passed as environment -variables to `configure`. However, if you pass the configuration in the -environment, make sure to unset all of these environment variables before -invoking `make`; otherwise, the environment variables might set make variables -in some applications, or parts of some applications, and you may end up with -an erroneously configured build. - -### What can be Cross Compiled? ### - -All Erlang/OTP applications except the `wx` application can be cross compiled. -The build of the `wx` driver will currently be automatically disabled when -cross compiling. - -### Compatibility ### - -The build system, including cross compilation configuration variables used, -may be subject to non backward compatible changes without prior notice. -Current cross build system has been tested when cross compiling some Linux/GNU -systems, but has only been partly tested for more esoteric platforms. The -VxWorks example file is highly dependent on our environment and is here more -or less only for internal use. - -### Patches ### - -Please submit any patches for cross compiling in a way consistent with this -system. All input is welcome as we have a very limited set of cross compiling -environments to test with. If a new configuration variable is needed, add it -to `$ERL_TOP/xcomp/erl-xcomp.conf.template`, and use it in `configure.in`. -Other files that might need to be updated are: - -- `$ERL_TOP/xcomp/erl-xcomp-vars.sh` -- `$ERL_TOP/erl-build-tool-vars.sh` -- `$ERL_TOP/erts/aclocal.m4` -- `$ERL_TOP/xcomp/README.md` -- `$ERL_TOP/xcomp/erl-xcomp-*.conf` - -Note that this might be an incomplete list of files that need to be updated. - -General information on how to submit patches can be found at: - <http://wiki.github.com/erlang/otp/submitting-patches> - -Build and Install Procedure ---------------------------- - -If you are building in Git, you want to read the [Building in Git][] section -of [$ERL_TOP/INSTALL.md][] before proceeding. - -We will first go through the `configure`/`make` build procedure which people -probably are most familiar with. - -### Building With configure/make Directly ### - - (1) - -Change directory into the top directory of the Erlang/OTP source tree. - - $ cd $ERL_TOP - -In order to compile Erlang code, a small Erlang bootstrap system has to be -built, or an Erlang/OTP system of the same release as the one being built -has to be provided in the `$PATH`. The Erlang/OTP for the target system will -be built using this Erlang system, together with the cross compilation tools -provided. - -If you want to build the documentation out of the same source tree as you are -cross compiling in, you currently need a full Erlang/OTP system of the same -release as the one being built for the build machine. If this is the case, -build and install one for the build machine (or use one already built) and add -it to the `$PATH` before cross building, and building the documentation. See -the [How to Build the Documentation][] section in the [$ERL_TOP/INSTALL.md][] -document for information on how to build the documentation. - -If you want to build using a compatible Erlang/OTP system in the `$PATH`, -jump to (3). - -#### Building a Bootstrap System #### - - (2) - - $ ./configure --enable-bootstrap-only - $ make - -The `--enable-bootstrap-only` argument to `configure` isn't strictly necessary, -but will speed things up. It will only run `configure` in applications -necessary for the bootstrap, and will disable a lot of things not needed by -the bootstrap system. If you run `configure` without `--enable-boostrap-only` -you also have to run make as `make bootstrap`; otherwise, the whole system will -be built. - -#### Cross Building the System #### - - (3) - - $ ./configure --host=<HOST> --build=<BUILD> [Other Config Args] - $ make - -`<HOST>` is the host/target system that you build for. It does not have to be -a full `CPU-VENDOR-OS` triplet, but can be. The full `CPU-VENDOR-OS` triplet -will be created by executing `$ERL_TOP/erts/autoconf/config.sub <HOST>`. If -`config.sub` fails, you need to be more specific. - -`<BUILD>` should equal the `CPU-VENDOR-OS` triplet of the system that you -build on. If you execute `$ERL_TOP/erts/autoconf/config.guess`, it will in -most cases print the triplet you want to use for this. - -Pass the cross compilation variables as command line arguments to `configure` -using a `<VARIABLE>=<VALUE>` syntax. - -> *NOTE*: You can *not* pass a configuration file using the `--xcomp-conf` -> argument when you invoke `configure` directly. The `--xcomp-conf` argument -> can only be passed to `otp_build configure`. - -`make` will verify that the Erlang/OTP system used when building is of the -same release as the system being built, and will fail if this is not the case. -It is possible, however not recommended, to force the cross compilation even -though the wrong Erlang/OTP system is used. This by invoking `make` like this: -`make ERL_XCOMP_FORCE_DIFFERENT_OTP=yes`. - -> *WARNING*: Invoking `make ERL_XCOMP_FORCE_DIFFERENT_OTP=yes` might fail, -> silently produce suboptimal code, or silently produce erroneous code. - -#### Installing #### - -You can either install using the installation paths determined by `configure` -(4), or install manually using (5). - -##### Installing Using Paths Determined by configure ##### - - (4) - - $ make install DESTDIR=<TEMPORARY_PREFIX> - -`make install` will install at a location specified when doing `configure`. -`configure` arguments specifying where the installation should reside are for -example: `--prefix`, `--exec-prefix`, `--libdir`, `--bindir`, etc. By default -it will install under `/usr/local`. You typically do not want to install your -cross build under `/usr/local` on your build machine. Using [DESTDIR][] -will cause the installation paths to be prefixed by `$DESTDIR`. This makes it -possible to install and package the installation on the build machine without -having to place the installation in the same directory on the build machine as -it should be executed from on the target machine. - -When `make install` has finished, change directory into `$DESTDIR`, package -the system, move it to the target machine, and unpack it. Note that the -installation will only be working on the target machine at the location -determined by `configure`. - -##### Installing Manually ##### - - (5) - - $ make release RELEASE_ROOT=<RELEASE_DIR> - -`make release` will copy what you have built for the target machine to -`<RELEASE_DIR>`. The `Install` script will not be run. The content of -`<RELEASE_DIR>` is what by default ends up in `/usr/local/lib/erlang`. - -The `Install` script used when installing Erlang/OTP requires common Unix -tools such as `sed` to be present in your `$PATH`. If your target system -does not have such tools, you need to run the `Install` script on your -build machine before packaging Erlang/OTP. The `Install` script should -currently be invoked as follows in the directory where it resides -(the top directory): - - $ ./Install [-cross] [-minimal|-sasl] <ERL_ROOT> - -where: - -* `-minimal` Creates an installation that starts up a minimal amount - of applications, i.e., only `kernel` and `stdlib` are started. The - minimal system is normally enough, and is what `make install` uses. -* `-sasl` Creates an installation that also starts up the `sasl` - application. -* `-cross` For cross compilation. Informs the install script that it - is run on the build machine. -* `<ERL_ROOT>` - The absolute path to the Erlang installation to use - at run time. This is often the same as the current working directory, - but does not have to be. It can follow any other path through the file - system to the same directory. - -If neither `-minimal`, nor `-sasl` is passed as argument you will be -prompted. - -You can now either do: - - (6) - -* Decide where the installation should be located on the target machine, - run the `Install` script on the build machine, and package the installed - installation. The installation just need to be unpacked at the right - location on the target machine: - - $ cd <RELEASE_DIR> - $ ./Install -cross [-minimal|-sasl] <ABSOLUTE_INSTALL_DIR_ON_TARGET> - -or: - - (7) - -* Package the installation in `<RELEASE_DIR>`, place it wherever you want - on your target machine, and run the `Install` script on your target - machine: - - $ cd <ABSOLUTE_INSTALL_DIR_ON_TARGET> - $ ./Install [-minimal|-sasl] <ABSOLUTE_INSTALL_DIR_ON_TARGET> - -### Building With the otp\_build Script ### - - (8) - - $ cd $ERL_TOP - - (9) - - $ ./otp_build configure --xcomp-conf=<FILE> [Other Config Args] - -alternatively: - - $ ./otp_build configure --host=<HOST> --build=<BUILD> [Other Config Args] - -If you have your cross compilation configuration in a file, pass it using the -`--xcomp-conf=<FILE>` command line argument. If not, pass `--host=<HOST>`, -`--build=<BUILD>`, and the configuration variables using a `<VARIABLE>=<VALUE>` -syntax on the command line (same as in (3)). Note that `<HOST>` and `<BUILD>` -have to be passed one way or the other; either by using `erl_xcomp_host=<HOST>` -and `erl_xcomp_build=<BUILD>` in the configuration file, or by using the -`--host=<HOST>`, and `--build=<BUILD>` command line arguments. - -`otp_build configure` will configure both for the boostrap system on the -build machine and the cross host system. - - (10) - - $ ./otp_build boot -a - -`otp_build boot -a` will first build a bootstrap system for the build machine -and then do the cross build of the system. - - (11) - - $ ./otp_build release -a <RELEASE_DIR> - -`otp_build release -a` will do the same as (5), and you will after this have -to do a manual install either by doing (6), or (7). - -Testing the cross compiled system --------------------------------------- -Some of the tests that come with erlang use native code to test. This means -that when cross compiling erlang you also have to cross compile test suites -in order to run tests on the target host. To do this you first have to release -the tests as usual. - - $ make release_tests - -or - - $ ./otp_build tests - -The tests will be released into `$ERL_TOP/release/tests`. After releasing the -tests you have to install the tests on the build machine. You supply the same -xcomp file as to `./otp_build` in (9). - - $ cd $ERL_TOP/release/tests/test_server/ - $ $ERL_TOP/bootstrap/bin/erl -eval 'ts:install([{xcomp,"<FILE>"}])' -s ts compile_testcases -s init stop - -You should get a lot of printouts as the testcases are compiled. Once done you -should copy the entire `$ERL_TOP/release/tests` folder to the cross host system. - -Then go to the cross host system and setup the erlang installed in (4) or (5) -to be in your `$PATH`. Then go to what previously was -`$ERL_TOP/release/tests/test_server` and issue the following command. - - $ erl -s ts install -s ts run all_tests -s init stop - -The configure should be skipped and all tests should hopefully pass. For more -details about how to use ts run `erl -s ts help -s init stop` - -Currently Used Configuration Variables --------------------------------------- - -Note that you cannot define arbitrary variables in a cross compilation -configuration file. Only the ones listed below will be guaranteed to be -visible throughout the whole execution of all `configure` scripts. Other -variables needs to be defined as arguments to `configure` or exported in -the environment. - -### Variables for otp\_build Only ### - -Variables in this section are only used, when configuring Erlang/OTP for -cross compilation using `$ERL_TOP/otp_build configure`. - -> *NOTE*: These variables currently have *no* effect if you configure using -> the `configure` script directly. - -* `erl_xcomp_build` - The build system used. This value will be passed as - `--build=$erl_xcomp_build` argument to the `configure` script. It does - not have to be a full `CPU-VENDOR-OS` triplet, but can be. The full - `CPU-VENDOR-OS` triplet will be created by - `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_build`. If set to `guess`, - the build system will be guessed using - `$ERL_TOP/erts/autoconf/config.guess`. - -* `erl_xcomp_host` - Cross host/target system to build for. This value will - be passed as `--host=$erl_xcomp_host` argument to the `configure` script. - It does not have to be a full `CPU-VENDOR-OS` triplet, but can be. The - full `CPU-VENDOR-OS` triplet will be created by - `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_host`. - -* `erl_xcomp_configure_flags` - Extra configure flags to pass to the - `configure` script. - -### Cross Compiler and Other Tools ### - -If the cross compilation tools are prefixed by `<HOST>-` you probably do -not need to set these variables (where `<HOST>` is what has been passed as -`--host=<HOST>` argument to `configure`). - -All variables in this section can also be used when native compiling. - -* `CC` - C compiler. - -* `CFLAGS` - C compiler flags. - -* `STATIC_CFLAGS` - Static C compiler flags. - -* `CFLAG_RUNTIME_LIBRARY_PATH` - This flag should set runtime library - search path for the shared libraries. Note that this actually is a - linker flag, but it needs to be passed via the compiler. - -* `CPP` - C pre-processor. - -* `CPPFLAGS` - C pre-processor flags. - -* `CXX` - C++ compiler. - -* `CXXFLAGS` - C++ compiler flags. - -* `LD` - Linker. - -* `LDFLAGS` - Linker flags. - -* `LIBS` - Libraries. - -#### Dynamic Erlang Driver Linking #### - -> *NOTE*: Either set all or none of the `DED_LD*` variables. - -* `DED_LD` - Linker for Dynamically loaded Erlang Drivers. - -* `DED_LDFLAGS` - Linker flags to use with `DED_LD`. - -* `DED_LD_FLAG_RUNTIME_LIBRARY_PATH` - This flag should set runtime library - search path for shared libraries when linking with `DED_LD`. - -#### Large File Support #### - -> *NOTE*: Either set all or none of the `LFS_*` variables. - -* `LFS_CFLAGS` - Large file support C compiler flags. - -* `LFS_LDFLAGS` - Large file support linker flags. - -* `LFS_LIBS` - Large file support libraries. - -#### Other Tools #### - -* `RANLIB` - `ranlib` archive index tool. - -* `AR` - `ar` archiving tool. - -* `GETCONF` - `getconf` system configuration inspection tool. `getconf` is - currently used for finding out large file support flags to use, and - on Linux systems for finding out if we have an NPTL thread library or - not. - -### Cross System Root Locations ### - -* `erl_xcomp_sysroot` - The absolute path to the system root of the cross - compilation environment. Currently, the `crypto`, `odbc`, `ssh` and - `ssl` applications need the system root. These applications will be - skipped if the system root has not been set. The system root might be - needed for other things too. If this is the case and the system root - has not been set, `configure` will fail and request you to set it. - -* `erl_xcomp_isysroot` - The absolute path to the system root for includes - of the cross compilation environment. If not set, this value defaults - to `$erl_xcomp_sysroot`, i.e., only set this value if the include system - root path is not the same as the system root path. - -### Optional Feature, and Bug Tests ### - -These tests cannot (always) be done automatically when cross compiling. You -usually do not need to set these variables. - -> *WARNING*: Setting these variables wrong may cause hard to detect -> runtime errors. If you need to change these values, *really* make sure -> that the values are correct. - -> *NOTE*: Some of these values will override results of tests performed -> by `configure`, and some will not be used until `configure` is sure that -> it cannot figure the result out. - -The `configure` script will issue a warning when a default value is used. -When a variable has been set, no warning will be issued. - -* `erl_xcomp_after_morecore_hook` - `yes|no`. Defaults to `no`. If `yes`, - the target system must have a working `__after_morecore_hook` that can be - used for tracking used `malloc()` implementations core memory usage. - This is currently only used by unsupported features. - -* `erl_xcomp_bigendian` - `yes|no`. No default. If `yes`, the target system - must be big endian. If `no`, little endian. This can often be - automatically detected, but not always. If not automatically detected, - `configure` will fail unless this variable is set. Since no default - value is used, `configure` will try to figure this out automatically. - -* `erl_xcomp_clock_gettime_cpu_time` - `yes|no`. Defaults to `no`. If `yes`, - the target system must have a working `clock_gettime()` implementation - that can be used for retrieving process CPU time. - -* `erl_xcomp_getaddrinfo` - `yes|no`. Defaults to `no`. If `yes`, the target - system must have a working `getaddrinfo()` implementation that can - handle both IPv4 and IPv6. - -* `erl_xcomp_gethrvtime_procfs_ioctl` - `yes|no`. Defaults to `no`. If `yes`, - the target system must have a working `gethrvtime()` implementation and - is used with procfs `ioctl()`. - -* `erl_xcomp_dlsym_brk_wrappers` - `yes|no`. Defaults to `no`. If `yes`, the - target system must have a working `dlsym(RTLD_NEXT, <S>)` implementation - that can be used on `brk` and `sbrk` symbols used by the `malloc()` - implementation in use, and by this track the `malloc()` implementations - core memory usage. This is currently only used by unsupported features. - -* `erl_xcomp_kqueue` - `yes|no`. Defaults to `no`. If `yes`, the target - system must have a working `kqueue()` implementation that returns a file - descriptor which can be used by `poll()` and/or `select()`. If `no` and - the target system has not got `epoll()` or `/dev/poll`, the kernel-poll - feature will be disabled. - -* `erl_xcomp_linux_clock_gettime_correction` - `yes|no`. Defaults to `yes` on - Linux; otherwise, `no`. If `yes`, `clock_gettime(CLOCK_MONOTONIC, _)` on - the target system must work. This variable is recommended to be set to - `no` on Linux systems with kernel versions less than 2.6. - -* `erl_xcomp_linux_nptl` - `yes|no`. Defaults to `yes` on Linux; otherwise, - `no`. If `yes`, the target system must have NPTL (Native POSIX Thread - Library). Older Linux systems have LinuxThreads instead of NPTL (Linux - kernel versions typically less than 2.6). - -* `erl_xcomp_linux_usable_sigaltstack` - `yes|no`. Defaults to `yes` on Linux; - otherwise, `no`. If `yes`, `sigaltstack()` must be usable on the target - system. `sigaltstack()` on Linux kernel versions less than 2.4 are - broken. - -* `erl_xcomp_linux_usable_sigusrx` - `yes|no`. Defaults to `yes`. If `yes`, - the `SIGUSR1` and `SIGUSR2` signals must be usable by the ERTS. Old - LinuxThreads thread libraries (Linux kernel versions typically less than - 2.2) used these signals and made them unusable by the ERTS. - -* `erl_xcomp_poll` - `yes|no`. Defaults to `no` on Darwin/MacOSX; otherwise, - `yes`. If `yes`, the target system must have a working `poll()` - implementation that also can handle devices. If `no`, `select()` will be - used instead of `poll()`. - -* `erl_xcomp_putenv_copy` - `yes|no`. Defaults to `no`. If `yes`, the target - system must have a `putenv()` implementation that stores a copy of the - key/value pair. - -* `erl_xcomp_reliable_fpe` - `yes|no`. Defaults to `no`. If `yes`, the target - system must have reliable floating point exceptions. - -Copyright and License ---------------------- - -%CopyrightBegin% - -Copyright Ericsson AB 2009-2010. All Rights Reserved. - -The contents of this file are subject to the Erlang Public License, -Version 1.1, (the "License"); you may not use this file except in -compliance with the License. You should have received a copy of the -Erlang Public License along with this software. If not, it can be -retrieved online at http://www.erlang.org/. - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -the License for the specific language governing rights and limitations -under the License. - -%CopyrightEnd% - -Modifying This Document ------------------------ - -Before modifying this document you need to have a look at the -`$ERL_TOP/README.md.txt` document. - - - - [$ERL_TOP/INSTALL.md]: INSTALL - [Building in Git]: INSTALL#How-to-Build-and-Install-ErlangOTP_Building-in-Git - [How to Build the Documentation]: INSTALL#The-ErlangOTP-Documentation_How-to-Build-the-Documentation - [cross configuration variables]: #Currently-Used-Configuration-Variables - [DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html - - [?TOC]: true +../HOWTO/INSTALL-CROSS.md
\ No newline at end of file |