2015-02-26

Numeric CombSort Benchmark update!

As I've written before, CombSort are quite good sort algorithm. Let's compare this algorithm when implemented in various programming language. The benchmark should not use any other built-in function other than array generation and printing. The benchmark uses AMD A8-6600K, 16GB RAM with Non-SSD disk.

$ alias | grep 'alias time'
alias time='/usr/bin/time -f "\nCPU: %Us\tReal: %es\tRAM: %MKB"'
$ time --version
GNU time 1.7

g++ --version
g++ (GCC) 4.9.2 20141224 (prerelease)
$ time g++ comb.cpp
CPU: 0.05s      Real: 0.12s     RAM: 19428KB
$ time ./a.out
CPU: 1.94s      Real: 1.97s     RAM: 79804KB
$ time g++ -O2 comb.cpp
CPU: 0.07s      Real: 0.11s     RAM: 21260KB
$ time ./a.out
CPU: 0.88s      Real: 0.90s     RAM: 79804KB

clang --version
clang version 3.5.1 (tags/RELEASE_351/final)
$ time clang++ comb.cpp
CPU: 0.05s      Real: 0.08s     RAM: 33564KB
$ time ./a.out
CPU: 1.83s      Real: 1.86s     RAM: 79764KB
$ time clang++ -O2 comb.cpp
CPU: 0.08s      Real: 0.14s     RAM: 37860KB
$ time ./a.out
CPU: 0.89s      Real: 0.91s     RAM: 79804KB

java -version
java version "1.7.0_71" 
$ time javac comb.java
CPU: 1.05s      Real: 0.73s     RAM: 65952KB
$ time java comb
CPU: 1.32s      Real: 1.32s     RAM: 110488KB

php --version
PHP 5.6.4 (cli) (built: Dec 17 2014 21:45:04)
$ time php comb.php
CPU: 102.69s    Real: 104.20s   RAM: 2497508KB

hhvm --version
HipHop VM 3.5.0 (rel)
$ time hhvm -v Eval.Jit=true comb.php 
CPU: 12.56s     Real: 14.83s    RAM: 362488KB

ruby --version
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
$ time ruby comb.rb
CPU: 52.87s     Real: 53.02s    RAM: 87892KB

rbx --version
rubinius 2.5.2 (2.1.0 7a5b05b1 2015-01-30 3.5.1 JI) [x86_64-linux-gnu]
$ time rbx comb.rb
CPU: 74.89s     Real: 74.30s    RAM: 135320KB

node --version
v0.10.35
$ time node comb1.js
CPU: 2.64s      Real: 2.64s     RAM: 92240KB
$ time node comb2.js
CPU: 2.68s      Real: 2.72s     RAM: 140612KB

rhino < /dev/null 
Rhino 1.7 release 4 2014 07 01
$ rhino comb2.js
CPU: 87.39s     Real: 61.16s    RAM: 1993848KB

$ pacman -Qo `which jsc-3`
/usr/bin/jsc-3 is owned by webkitgtk 2.4.8-1
$ time jsc-3 comb1.js
CPU: 23.74s     Real: 23.93s    RAM: 93740KB
$ time jsc-3 comb2.js
CPU: 18.99s     Real: 19.16s    RAM: 181644KB

js24 --help | grep Version
Version: JavaScript-C24.2.0
$ time js24 --ion-eager comb1.js
CPU: 2.13s      Real: 2.15s     RAM: 89688KB
$ time js24 --ion-eager comb2.js
CPU: 1.53s      Real: 1.58s     RAM: 92384KB

go version
go version go1.4.1 linux/amd64
$ time go build comb.go 
CPU: 0.14s      Real: 0.17s     RAM: 31568KB
$ time ./comb
CPU: 1.10s      Real: 1.14s     RAM: 79824KB

rustc --version
rustc 1.0.0-dev
$ time rustc comb.rs
CPU: 0.39s      Real: 0.49s     RAM: 106844KB
$ time ./comb
CPU: 10.62s     Real: 10.71s    RAM: 86020KB
$ time rustc -O comb.rs
CPU: 0.41s      Real: 0.49s     RAM: 110204KB
$ time ./comb
CPU: 0.97s      Real: 0.99s     RAM: 86108KB

scala -version
Scala code runner version 2.11.5 -- Copyright 2002-2013, LAMP/EPFL
$ time scala comb.scala
CPU: 5.43s      Real: 6.30s     RAM: 206088KB
$ time scalac comb.scala
CPU: 10.62s     Real: 7.00s     RAM: 143460KB
$ time scala Comb
CPU: 5.49s      Real: 5.05s     RAM: 206300KB

python --version
Python 3.4.2
$ time python comb1.py
CPU: 90.47s     Real: 90.83s    RAM: 403192KB
$ time python comb2.py
CPU: 106.82s    Real: 107.26s   RAM: 87248KB

pypy --version
Python 2.7.8 (c6ad44ecf5d8, Nov 18 2014, 18:04:31) [PyPy 2.4.0 with GCC 4.9.2]
$ time pypy comb1.py
CPU: 5.34s      Real: 5.40s     RAM: 136764KB
$ time pypy comb2.py
CPU: 5.85s      Real: 6.04s     RAM: 204588KB

mcs --version
Mono C# compiler version 3.12.0.0
$ time mcs -o+ comb.cs
CPU: 0.44s      Real: 0.47s     RAM: 45908KB
$ time ./comb.exe
CPU: 1.38s      Real: 1.41s     RAM: 90472KB

lua -v
Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
$ time lua comb.lua
CPU: 65.64s     Real: 65.81s    RAM: 264096KB

luajit -v
LuaJIT 2.0.3 -- Copyright (C) 2005-2014 Mike Pall.
$ time luajit comb.lua
CPU: 6.30s      Real: 6.34s     RAM: 132964KB

dart --version
Dart VM version: 1.8.5 (Tue Jan 13 12:44:14 2015) on "linux_x64"
$ time dart scomb.dart
CPU: 2.12s      Real: 2.24s     RAM: 93392KB

The code can be found on my dropbox (folder: num-comb), and here's the summary:

Compiler / InterpreterLanguageCompile DurationCompile RAMRuntime DurationRuntime RAMTotal Duration
g++ (debug)C++50194281940798041990
g++ (-O2)C++702126088079804950
clang++ (debug)C++50335641830797641880
clang++ (-O2)C++803786089079804970
javac, javaJava10506595213201104882370
phpPHP1026902497508102690
hhvmPHP1256036248812560
rubyRuby528708789252870
rbxRuby7489013532074890
node (typed array)Javascript2640922402640
node (untyped array)Javascript26801406122680
rhino (untyped array)Javascript87039199384887039
jsc-3 (typed array)Javascript237409374023740
jsc-3 (untyped array)Javascript1899018164418990
js24 (typed array)Javascript2130896882130
js24 (untyped array)Javascript1530923841530
goGo140315681100798241240
rustc (debug)Rust390106844106208602011010
rustc (-O2)Rust410110204970861081380
scalaScala54302060885430
python3Python 39047040319290470
python3 (array)Python 310682087248106820
pypyPython 253401367645340
pypy (array)Python 258502045885850
mcsC#440459081380904721820
luaLua6564026409665640
luajitLua63001329646300
dartDart2120933922120

Write down your opinion (or pastie if you found a bug on these source, or if you want to add more language implementation) on the comment section ^^)b

Note #1Opal (0.6.8) and JRuby (both 1.7.18 and 9.0.0pre1) failed to run this benchmark (they exceed 300s runtime limit even when using -J-Xmx3000M -J-Djruby.compile.mode=FORCE flag).

Note #2: Yes, it's unfair to compare array of integer and array of double, life is unfair by design, get over it...

String CombSort Benchmark update!

Previously, we have benchmark CombSort algorithm implemented in various programming language for array of number. Let's compare this algorithm with addition integer to string conversion the language's built-in string library. The benchmark should not use any other built-in function other than string, integer conversion and array generation and printing. The benchmark uses AMD A8-6600K, 16GB RAM with Non-SSD disk.

$ alias | grep 'alias time'
alias time='/usr/bin/time -f "\nCPU: %Us\tReal: %es\tRAM: %MKB"'
$ time --version
GNU time 1.7

g++ --version
g++ (GCC) 4.9.2 20141224 (prerelease)
$ time g++ -std=c++11 scomb.cpp
CPU: 0.18s      Real: 0.20s     RAM: 35868KB
$ time ./a.out
CPU: 19.32s     Real: 19.60s    RAM: 548912KB
$ time g++ -std=c++11 -O2 scomb.cpp
CPU: 0.20s      Real: 0.24s     RAM: 38184KB
$ time ./a.out
CPU: 13.76s     Real: 14.05s    RAM: 548816KB

clang --version
clang version 3.5.1 (tags/RELEASE_351/final)
$ time clang++ -std=c++11 scomb.cpp
CPU: 0.15s      Real: 0.20s     RAM: 42240KB
$ time ./a.out
CPU: 18.89s     Real: 19.21s    RAM: 548868KB
$ time clang++ -std=c++11 -O2 scomb.cpp
CPU: 0.20s      Real: 0.23s     RAM: 45824KB
$ time ./a.out
CPU: 13.87s     Real: 14.15s    RAM: 548820KB

javac -version
javac 1.7.0_71
$ time javac scomb.java
CPU: 1.13s      Real: 0.80s     RAM: 65324KB
$ time java scomb
CPU: 48.96s     Real: 27.59s    RAM: 906652KB

hhvm --version
HipHop VM 3.5.0 (rel)
$ time hhvm -v Eval.Jit=true scomb.php
CPU: 89.92s     Real: 90.38s    RAM: 877468KB

ruby --version
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
$ time ruby scomb.rb
CPU: 114.67s    Real: 115.21s   RAM: 870612KB

node --version
v0.10.35
$ time node scomb.js
CPU: 17.44s     Real: 17.41s    RAM: 411144KB

$ pacman -Qo `which jsc-3`
/usr/bin/jsc-3 is owned by webkitgtk 2.4.8-1
$ time jsc-3 scomb.js
CPU: 60.08s     Real: 43.66s    RAM: 834744KB

js24 --help | grep Version
Version: JavaScript-C24.2.0
$ time js24 scomb.js
CPU: 19.27s     Real: 19.62s    RAM: 735556KB

go version
go version go1.4.1 linux/amd64
$ time go build scomb.go
CPU: 0.14s      Real: 0.17s     RAM: 30428KB
$ time ./scomb
CPU: 11.45s     Real: 11.54s    RAM: 251628KB

scala -version
Scala code runner version 2.11.5 -- Copyright 2002-2013, LAMP/EPFL
$ time scala -J-Xmx3000M scomb.scala
CPU: 83.42s     Real: 46.10s    RAM: 1093924KB

python --version
Python 3.4.2
$ time python scomb.py
CPU: 121.33s    Real: 122.06s   RAM: 641844KB

pypy --version
Python 2.7.8 (c6ad44ecf5d8, Nov 18 2014, 18:04:31) [PyPy 2.4.0 with GCC 4.9.2]
$ time pypy scomb.py
CPU: 14.72s     Real: 14.97s    RAM: 522080KB

lua -v
Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
$ time lua scomb.lua
CPU: 98.11s     Real: 98.54s    RAM: 863880KB

luajit -v
LuaJIT 2.0.3 -- Copyright (C) 2005-2014 Mike Pall.
$ time luajit scomb.lua
CPU: 21.30s     Real: 21.61s    RAM: 511268KB

dart --version
Dart VM version: 1.8.5 (Tue Jan 13 12:44:14 2015) on "linux_x64"
$ time dart scomb.dart
CPU: 11.92s     Real: 12.15s    RAM: 497788KB

The code can be found on my dropbox (folder: str-comb), and here's the summary:

Compiler / InterpreterLanguageCompile DurationCompile RAMRuntime DurationRuntime RAMTotal Duration
g++ (debug)C++180358681932054891219500
g++ (-O2)C++200381841376054881613960
clang++ (debug)C++150422401889054886819040
clang++ (-O2)C++200458241387054882014070
javac, javaJava1130653244896090665250090
hhvmPHP8992087746889920
rubyRuby114670870612114670
nodeJavascript1744041114417440
jsc-3Javascript6008083474460080
js24Javascript1927073555619270
goGo140304281145025162811590
scalaScala83420109392483420
python3Python 3121330641844121330
pypyPython 21472052208014720
luaLua9811086388098110
luajitLua2130051126821300
dartDart1192049778811920

Write down your opinion (or pastie if you found a bug on these source, or if you want to add more language implementation) on the comment section ^^)b

Note #1PHP 5.6.4, Rubinius 2.5.2, JRuby 9.0.0a1, Rhino 1.7, MCS 3.12 failed to end their execution within approx. 120s timeout

2015-02-25

Techempower Framework Benchmark 10 Preview

As you can see from this link, preliminary result has been published on their mailing list. C++ still dominating, JavaScript (NodeJS), Scala, and Dart gotten better, Go, PHP (HHVM), and Java still at the top tier.


One more point worth seeing, PostgreSQL above MySQL in single query benchmark (after SQLite), I'm so happy ^_^]b


As usual, this is just a benchmark, happy programming experience is also important: available libraries, ease of coding -- writing and reading other people source codes, available editors/tools, great documentation, start-up/compile/test duration.

2015-02-24

Command line to power off portable harddisk / usb drive on Linux

Sometimes we plug and mount a portable harddisk or USB on Linux server and want to unplug it using command line :3 script ninja! You can use udisks comand to do this, just find which drive are your portable disk attached as, for example using lsblkfdisk, or df command

$ lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda      8:0    0 931.5G  0 disk 
└─sda1   8:1    0 931.5G  0 part 
sdb      8:16   0 458.6G  0 disk 
├─sdb1   8:17   0     1G  0 part /boot
├─sdb2   8:18   0     2G  0 part [SWAP]
├─sdb3   8:19   0    64G  0 part /
└─sdb4   8:20   0 391.6G  0 part /home
sr0     11:0    1  1024M  0 rom  

$ fdisk -l 
Disk /dev/sdb: 458.6 GiB, 492387172352 bytes, 961693696 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc5900613

Device     Boot     Start       End   Sectors   Size Id Type
/dev/sdb1  *           63   2104514   2104452     1G 83 Linux
/dev/sdb2         2104515   6313544   4209030     2G 82 Linux swap / Solaris
/dev/sdb3         6313545 140536619 134223075    64G 83 Linux
/dev/sdb4       140536620 961683029 821146410 391.6G 83 Linux

Disk /dev/sda: 931.5 GiB, 1000204885504 bytes, 1953525167 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 33553920 bytes
Disklabel type: dos
Disk identifier: 0x9a70439c

Device     Boot Start        End    Sectors   Size Id Type
/dev/sda1        2048 1953521663 1953519616 931.5G  7 HPFS/NTFS/exFAT

$ df | grep -v tmpfs
Filesystem     Type     1M-blocks  Used Available Use% Mounted on
/dev/sdb3      ext4         64381 33387     27701  55% /
/dev/sdb1      ext2          1012    40       921   5% /boot
/dev/sdb4      ext4        394531 59129    315339  16% /home

$ cat /proc/partitions 
major minor  #blocks  name
   8       16  480846848 sdb
   8       17    1052226 sdb1
   8       18    2104515 sdb2
   8       19   67111537 sdb3
   8       20  410573205 sdb4
  11        0    1048575 sr0
   8        0  976762583 sda
   8        1  976759808 sda1

Then just call udisks with --detach flag to safely remove the device, for example:

sudo udisks --detach /dev/sda

Or you can use this script, download/save then you can execute it, for example:

sudo sh suspend-usb-device.sh -v /dev/sda 

now your portable disk can be removed safely.

Note: if you're using kernel newer than 2.6.32, there would be an error line 180: echo: write error: Invalid argument, change that script on line 180 from suspend into auto. And of course if you have Nemo (or maybe Nautilus too, but not for Thunar) installed you can always right click and then safely remove the drive without command line.


Ngrok: easiest way to Tunnel to localhost

Ngrok is a tool that could help you publish your local web so it can be accessed by public. The example use case is when you want to publish your development server, so client or your boss can access it from another place. Yes, it's easy to install your web application to a VPS or hosting server or use VPN remote desktop software (Hamachi or TeamViewer), but it would took some time and probably bigger bandwidth. It's really easy to install ngrok since it's portable (built using Go programming language), in ArchLinux you can type:

yaourt --needed --noconfirm -S --force ngrok

Or you can download the binary from their website. To use ngrok, just type the program name followed with service port on your localhost that you want to publish, for example:

ngrok 8080

After running the program, there would be a link given (HTTP and HTTPS) that can be acessed by public, if people visit that link it would give the same output as http://localhost:8080.


You can view the visit log on the web interface http://127.0.0.1:4040.


If you have already registered to their website you can use subdomain feature, by adding authtoken (get it after registering) for the first time, for example:

ngrok -authtoken ndf8gus0n958t 8080

Then you can use subdomain feature for example:

ngrok -subdomain mysubdomain 8081

This would create a subdomain on Ngrok's domain, for example mysubdomain.ngrok.com that linked to your  http://localhost:8081. One more cool feature about Ngrok is you can replay the request, just press the replay button on the web interface. Minor flaw of this program, if you run multiple instance of Ngrok, only the first instance will get web interface (http://127.0.0.1:4040), the next instance would not get the web interface.


State of Go REPL (February 2015)

REPL is one thing that quite important to test simple snippet, useful to make sure that a part of code would work as expected. Previously I have tried go-repl, go-eval, rango, but none of them enjoyable to use.

One of the promising one is go-fish, with limited import option, you can install it using these commands:

go get -u -v github.com/rocky/go-types
go get -u -v github.com/rocky/go-loader
go get -u -v github.com/rocky/go-fish
go build make_env.go
make
mv go-fish $GOPATH/bin

One thing that annoys me is no history (Up/Down key) and limited set of import (that can be added), but I haven't found a way to import package on runtime.


Another one that quite promising is gore, to install it use run these commands:

# workaround for moved astutil repository
mkdir $GOPATH/src/golang.org/x/tools/go/ast
ln -s $GOPATH/src/golang.org/x/tools/astutil $GOPATH/src/golang.org/x/tools/go/ast

go get -u -v github.com/nsf/gocode
go get -u -v github.com/k0kubun/pp 
go get -u -v github.com/davecgh/go-spew

go get -u -v golang.org/x/tools/cmd/godoc
go get -u -v github.com/motemen/gore

Gore is one that works fine, to import package use colon, import and package name without quote, for example:

:import fmt

You can also use Tab key for auto complete, Up/Down key to see typed commands, Ctrl+D for canceling last command, but you cannot erase 1 previous word using Alt+Backspace. I think this program has the less annoyance than other alternatives.



How to make IntelliJ IDEA load faster

IntelliJ IDEA is one of the best IDE around, but the default configuration isn't that good. The initial loading of this software took about 5-15 minutes because of the initial configuration of JVM. There are some workaround to make it work faster, just go to your IDEA installation directory, bin directory, and look for idea.vmoptions (or idea64.vmoptions), change the content of that file into something like this:

-server
-Xms512m
-Xmx8192m
-XX:MaxPermSize=1024m
-XX:ReservedCodeCacheSize=512m
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-Dawt.useSystemAAFontSettings=lcd

The Xmx sets the maximum memory that could be used by JVM, if you have a huge amount of RAM (4 GB+) you may change it at least half and at most three quarter of your RAM. After changing that configuration, close the IDEA and start it again IDEA now should load faster (in my PC it took about 10 seconds to start loading the project and 20 seconds more to complete loading the project).


2015-02-23

How to install h2o: HTTP/2 Web Server

As we already know, HTTP/2 finalized 2 weeks ago, it's a binary protocol based on SPDY, with HPACK compression. Some server benchmark has been posted, and some web server and client libraries has been supporting those specs, see the FAQ here. One of the most popular HTTP/2 is h2o that we could install in ArchLinux using this command (hipster detected):

yaourt --needed --noconfirm -S --force libuv h2o-git

You can use this configuration if you want standalone web server (h2o requires TLS encrpytion for HTTP/2):

listen: 
  port: 3030
  ssl:
    certificate-file: /path/to/localhost.crt
    key-file: /path/to/localhost.key
http2-max-concurrent-requests-per-connection: 1024
num-threads: 1
hosts:
  127.0.0.1:
    paths:
      /:
        file.dir: /path/to/htdocs
        file.dirlisting: ON

Or if you want to use it as reverse proxy (just like normal NginX use case):

listen:
  port: 3040

  ssl:
    certificate-file: /path/to/server.crt
    key-file: /path/to/server.key
http2-max-concurrent-requests-per-connection: 1024
num-threads: 1
hosts:
  localhost:
    paths:
      /:
        proxy.reverse.url: http://127.0.0.1:3030
        proxy.keepalive: ON

The h2o server seems not allowing HTTP/2 to be used when started without SSL. If you don't have any SSL certificate yet, just use this command to generate self-signed certificate:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt

To start the h2o program, just write those configuration (don't forget to change the certificate-file, key-file, and file.dir to use the correct path) to a file named h2o.conf, then just type:

$ h2o
[OCSP Stapling] disabled for certificate file:/tmp/localhost.crt
[INFO] raised RLIMIT_NOFILE to 65536
h2o server (pid:11108) is ready to serve requests
[OCSP Stapling] disabled for certificate file:/tmp/localhost.crt   

To enable browser support for this protocol, you can enable the SPDY/4 flag on chrome://flags (type it on your Chrome's address bar) or search for http2 flags inside about:config at Firefox's address bar.



To check which websites already using SPDY, you can visit chrome://net-internals/#spdy. You can also use this Chrome extension or this Firefox plugin to check is it SPDY enabled site (see the lightning sign after installing ). 


To check public website for SPDY or HTTP/2 support (labeled as h2-xx, where xx is the spec revision), you can use spdycheck.org. Another way to check a site is using HTTP/2 without browser is using latest httpie-http2 or nghttp2-git, that you can install using these commands:

# httpie
yaourt --needed --noconfirm -S --force python-pip
sudo pip3 install -U httpie httpie-http2

# nghttp2
yaourt --needed --noconfirm -S --force cunit libev
yaourt --needed --noconfirm -S --force nghttp2-git

then just execute one of these commands:

# httpie
http https://nghttp2.org/httpbin/get

# nghttp2
nghttp2 -nva https://localhost:3030

The httpie command, always failed when using self-signed certificate (even when --verify=no enabled). For nghttp2, when there are line containing The negotiated protocol: h2, it shows HTTP/2 protocol being used. 




How to make your Executable Binaries smaller

There are some good executable compressor, for example UPX. Compressor could reduce your executable size into smaller one, for example a Go compiler always produce a quite big binary, we could reduce it using goupx (requires Go installed), that you can install using this command:

yaourt --needed --noconfirm -S --force upx
go get -u -v github.com/pwaller/goupx

Then you could compress using this command:

$ goupx THE_EXE_FILE
2015/02/23 09:28:36 {Class:ELFCLASS64 Data:ELFDATA2LSB Version:EV_CURRENT OSABI:ELFOSABI_NONE ABIVersion:0 ByteOrder:LittleEndian Type:ET_EXEC Machine:EM_X86_64 Entry:4380896}
2015/02/23 09:28:36 Hemming PT_LOAD section
2015/02/23 09:28:36 File fixed!
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2013
UPX 3.91        Markus Oberhumer, Laszlo Molnar & John Reiser   Sep 30th 2013

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   8746160 ->   2413164   27.59%  linux/ElfAMD   THE_EXE_FILE


Packed 1 file.

The result is quite good (22-33%), your program will load faster on slow disk. One drawback about executable compressor is multiple instance/execution would use more RAM, since their code won't be shared.