Commit graph

89 commits

Author SHA1 Message Date
Ashod Nakashian
6c0be6d90d loolwsd: move admin updates into DocumentBroker
Change-Id: Ic35198a7e4457a775fac25954279501e37b94b42
Reviewed-on: https://gerrit.libreoffice.org/30199
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-23 21:05:28 +00:00
Pranav Kant
d4fbc92023 loolwsd: Fix admin console document add
Change-Id: I987f26b4aae2c4ea8ef65919f570576ef8c5d2a7
2016-10-17 18:34:22 +05:30
Ashod Nakashian
d266d124df loolwsd: argument cleanup
Pass std::string instead of char* and length where
a string is always constructed anyway. Also cleaner
and safer code.

Change-Id: I1c9341e2c81bbdb7adeb29d3fba59849b2617e95
Reviewed-on: https://gerrit.libreoffice.org/29954
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-16 22:14:00 +00:00
Ashod Nakashian
4f4472ffa6 loolwsd: shutdown client sockets and cleanup when kit dies
Change-Id: I4d59553d744a8075d4d873ff520d9f3e417521b3
Reviewed-on: https://gerrit.libreoffice.org/29947
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-16 22:10:43 +00:00
Ashod Nakashian
7043b95f4d loolwsd: fix convert-to after removing Prisoner WS
Change-Id: I652a9fffa267e01043262eb25d3c2e19bf9eb447
Reviewed-on: https://gerrit.libreoffice.org/29940
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-16 22:06:05 +00:00
Ashod Nakashian
35fcaa1592 loolwsd: don't join unjoinable thread and contain exceptions
Change-Id: I309153c3c05a152e4ef3bbbbd5a0948bcc589c9c
Reviewed-on: https://gerrit.libreoffice.org/29939
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-16 22:05:32 +00:00
Ashod Nakashian
b44d71f0ae loolwsd: no need to create prisoner WS anymore
Change-Id: Iaebac49f47353a6848fd2232a1838e4eaadaeefc
Reviewed-on: https://gerrit.libreoffice.org/29937
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-16 22:04:31 +00:00
Ashod Nakashian
75c99ed9b6 loolwsd: cleanup child process WS interface
Change-Id: I30d74fc25434301145da292711fe5e33972ac876
Reviewed-on: https://gerrit.libreoffice.org/29936
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-16 22:03:56 +00:00
Pranav Kant
9ebd7a15e2 loolwsd: Improved loolwsd -> storage communication
Reduces the number of WOPI calls made during a document load. Earlier
effort was made in edfd3266f8
This commit cleans up and uses better approach for the same.

Other than that, access token of each session is now correctly
used when interacting with the storage. Earlier, we used to
use the same access token for each upload to storage which means
that irrespective of who clicked the save button, changes to the
document were only made on behalf of one person (of whom the
access token is used). This is fixed now.

Also includes minor cleanup left and right.

Change-Id: Id32702ff02aea4f63b7cc6afa9f62664807bb57d
Reviewed-on: https://gerrit.libreoffice.org/29931
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-16 22:02:25 +00:00
Pranav Kant
07f10570cc loolwsd: Add wopiloadduration - time taken to interact with WOPI host
Change-Id: Ia2d763ef721128450bf402a61d0e0f3e75701441
2016-10-16 23:01:50 +05:30
László Németh
2c744f75c6 loolwsd: count rendered tiles and serve the number for debugging
extend the 'pong' server message with the data "rendercount=num",
where "num" is the total number of rendered tiles of the document.
2016-10-11 17:18:16 +02:00
Ashod Nakashian
128cd73154 loolwsd: send child messages to client via unified wsd-kit WS
Change-Id: I237120e5a81a2e6d8772a2b6f1e98b1ba567f97e
Reviewed-on: https://gerrit.libreoffice.org/29647
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-10 06:29:32 +00:00
Ashod Nakashian
38cbfa96b0 loolwsd: forward client message to child via the process WS
Change-Id: I368e727b79b44b509ba49ed30218b8368c5eaad8
Reviewed-on: https://gerrit.libreoffice.org/29637
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-10 06:23:51 +00:00
Ashod Nakashian
6cf9cdf032 loolwsd: forward to child
Change-Id: I308963a78fb05e85bcb2e6c257640b56583859b5
Reviewed-on: https://gerrit.libreoffice.org/29636
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-10 06:23:07 +00:00
Ashod Nakashian
f17ff9c1d9 loolwsd: forward client messages to the respective client's WS
Change-Id: Ie28223f985a7f24a7569300b846432bf77813ab0
Reviewed-on: https://gerrit.libreoffice.org/29634
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-10 06:20:25 +00:00
Ashod Nakashian
22fb71c672 loolwsd: cleanup lastEditableSession flag in DocumentBroker
Change-Id: Iab3a226e3ff089c6bdab264d6f1b1d639bcf3b37
Reviewed-on: https://gerrit.libreoffice.org/29630
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-10-10 06:15:44 +00:00
Tor Lillqvist
96e6ad7502 Re-think disk full handling
Instead of trying to inform the sysadmin (which we did not yet try to
do in any meaningful way), inform all connected clients (even those
editing other documents).

We use 'error: cmd=internal kind=diskfull' as the message to the
clients. The loleaflet code needs to be updated to handle that
carefully by displaying a very prominent message that tells the user
that all bets are off.

Also add a unit test for the functionality.

Document the new protocol details.

The code for this alert functionalty became a bit less elegant than I
like because of the way we include Util.cpp in the unit test 'test'
program.

Still need to add code to check for disk full in more places, not just
when saving a cached tile or font. Probably we should even actually
check for disk space on the file system(s) we use getting alarmingly
low, not just check for file writing operations that fail. Later.
2016-09-29 00:23:14 +03:00
Ashod Nakashian
9d883bfc71 Revert "bccu#2018 - Missing tiles when finished typing"
This reverts commit 342125b8ea.

Change-Id: I2f509f5044b7a432c978138e31edef679f2aca78
Reviewed-on: https://gerrit.libreoffice.org/29280
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-09-26 02:36:33 +00:00
Ashod Nakashian
342125b8ea bccu#2018 - Missing tiles when finished typing
aka: don't save invalidated tiles into cache

Tiles that are rendered when invalidation is recieved are outdated.

What we do is remember the last tile version when we get an invalidation.
This tile version, and any preceding it, is out of date and should not
get saved in the tile cache.

This fixes a race between rendering and invalidation, which happens
in the following scenario.

1. Tile requested for rendering.
2. User inputs key.
3. While tile is rendering, the tile is invalidated in Core
   (the shared lock between rendering and processing input doesn't
   include parsing tile request or preparing the payload back).
4. Once the tile rendering is done, but before it's encoded and sent back,
   the invalidation is received on the callback.
5. Tile cache is cleared of that tile.
6. The outdated tile is received on its way to the client, saved in cache.
7. Client requests the tile anew upon getting the invalidation.
8. The tile is served from the cache, which is outdated, therefore
   missing the last key input form the user.

The fix is in #3 to remember the version number of the tile being
rendered. Then in #6 we forward the tile to the client, but we
do not store it in cache. In #8 the tile request results in a new
rendering, since the cache will not have the tile. Only this last
rendering of the tile is saved in cache for future requests.

Change-Id: I0b0a3c2b917906c0d0c9046e3e6d3d4d354a7777
Reviewed-on: https://gerrit.libreoffice.org/29209
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-09-23 02:25:10 +00:00
Ashod Nakashian
9640fd1e78 loolwsd: handle invalidatetiles in DocumentBroker
Change-Id: I05e70f82af9b5c8bdb590a64688ffa70c6ba2034
Reviewed-on: https://gerrit.libreoffice.org/29124
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-09-21 05:17:27 +00:00
Ashod Nakashian
8f213bc170 loolwsd: canceltiles re-designed using tilecache instead of queue
Reviewed-on: https://gerrit.libreoffice.org/28526
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
(cherry picked from commit 571ff06906)

Change-Id: Ie8f2c87a705aac14dd6f139c384f000df98db909
Reviewed-on: https://gerrit.libreoffice.org/29117
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-09-21 05:13:18 +00:00
Miklos Vajna
ef4ca0507a loolwsd: remove takeedit and editlock commands
As a follow-up to commit 77e219ceff
(loleaflet: Kill editlock code, completely, 2016-09-20).

Change-Id: I48a58bb738c0939f99d220eca7a8fd3f4c3debe4
2016-09-20 09:47:25 +02:00
Jan Holesovsky
27bed804d5 bccu#2005: Make sure we don't create 2 jails for the same document.
When 2 users opened the document at the very same time, it happened that new
jails / instances were created for the document twice.

As a solution, insert a dummy (marked to destroy) document into the map of
DocumentBrokers, which will lead into synchronization between the two
instances.

[I suppose the synchronization did not work previously either, as emplace()
does not seem to modify the value when the key is already in the map.]
2016-09-15 12:50:26 +02:00
Michael Meeks
8182dd8c54 Assign priority based on intersection with the cursor.
Should help to reduce visual tearing when cursor spans a tile join.
2016-09-01 21:18:38 +01:00
Ashod Nakashian
16605b9289 Revert "loolwsd: canceltiles re-designed using tilecache instead of queue"
This reverts commit 571ff06906.

Change-Id: Icf9caeafc640b815f64211f240cfdac8e91694a1
Reviewed-on: https://gerrit.libreoffice.org/28595
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-09-01 12:37:47 +00:00
Ashod Nakashian
571ff06906 loolwsd: canceltiles re-designed using tilecache instead of queue
Change-Id: I4b9ba91ee08bc9dd8d27df275e303f5517d9740c
Reviewed-on: https://gerrit.libreoffice.org/28526
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-08-31 04:44:56 +00:00
Miklos Vajna
e4bbc15132 Avoid inclusion of deprecated C++ headers
Change-Id: I29abf3feeb8419f4e15ccb8dc7c34c086696ce07
2016-08-30 09:06:47 +02:00
Pranav Kant
f8ebb54af0 loolwsd: Receive WOPI userid, username
Change-Id: I0bd5e5a155b8f8486fbeffb1c1413d5e9c177fc3
2016-08-29 19:39:50 +05:30
Pranav Kant
ff5704a3cf loolwsd: Drop forward decl. and add missing include
... instead of including Storage.hpp through some funny inclusion
of header files.

Change-Id: I7b6d63b687ef92c4523c01455172ad9fa08fe14a
2016-07-19 22:53:48 +05:30
Pranav Kant
da6af8b4ec loolwsd: Don't upload to storage if document is unmodified
If core says that document save operation failed because document
was in unmodified state, don't upload to storage (hence no
revision)

Change-Id: I47fbc8a7bc632bb7977d263d697d665161f3b076
2016-07-18 12:12:12 +05:30
Pranav Kant
06dc3fd1bc loolwsd: Give editlock correctly when adding a new session
This should be given to first editable(non-readonly) session.

Change-Id: I3b6e53df4b2450cc799c4b4e6a800f662d90a2c1
2016-07-11 11:25:20 +05:30
Pranav Kant
62814d29cf loolwsd: Introduce a readonly mode
Specified when websocket is initialized. Documents once
opened in readonly mode cannot edit throughout the life of the session.
This is very much like present view mode except the ability to
change to edit mode.

Change-Id: I176e3bbf210c3383268d1a5b50dc17f0cbfb26b8
2016-07-11 11:24:16 +05:30
Ashod Nakashian
157386e3bc loolwsd: process tiles under the cursor with priority
Change-Id: I7993ee049c5c0835cae588ff54163f135c4f8b02
Reviewed-on: https://gerrit.libreoffice.org/25345
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-23 01:57:16 +00:00
Ashod Nakashian
e5aaac7631 loolwsd: Tile versioning and fix to race conditions
Tile invalidation and painting can race with one another.

A race when the user types two characters in quick succession:
1. After the first key press, the tile is invalidated.
2. The client request the tile on receiving the invalidate.
3. TileCache doesn't find it, and adds subscription.
 A. Sometime before rendering, the second key press is received.
 B. This invalidates the very same tile.
 C. The client request the same tile.
 D. TileCache finds a subscription and ignores the new one.
4. The tile is rendered and sent back.
5. Subscription is found and the tile is forwarded to clients.
6. Subcription is removed as the request is fullfilled.
 E. The second tile is rendered and sent back.
 F. TileCache finds no subscription and the tile is dropped.

End result: Only the first character appears on the screen.

Versioning fixes the above situation by making sure that in
step 5 the subscription will show to belong to a different
(and newer version) and so the tile will be ignored.
Instead, at F the TileCache will find both subscription
and a matching version and the lastest version will always
be sent back to the client.

Change-Id: I7d7fe1407cda1908d794683c3ce4c2fd18609a2f
Reviewed-on: https://gerrit.libreoffice.org/25341
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-23 01:52:36 +00:00
Ashod Nakashian
114a6bc373 loolwsd: combined tile rendering
Tiles can be rendered in large batches and sent back
as combined payloads, all reduce latency and overhead
significantly.

Initial tests show a reduction in total latency by 2x.
This without sending tiles back to the client in combined
form, which will reduce latency further.

Change-Id: Iee06503f2a6c741fadb2c890266ea514c809c0dc
Reviewed-on: https://gerrit.libreoffice.org/25339
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-23 01:49:54 +00:00
Ashod Nakashian
fae850189d loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.

Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.

This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.

Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).

Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 15:52:54 +00:00
Ashod Nakashian
7f767e7cf6 loolwsd: MasterProcessSession splitting: removed MasterProcessSession
Change-Id: If132e8787f6ed7fa21d235cc355d7a29395b3c4d
Reviewed-on: https://gerrit.libreoffice.org/25049
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-17 03:23:07 +00:00
Ashod Nakashian
b2881306f1 loolwsd: MasterProcessSession splitting: moved input queue
Change-Id: Id1c2b0f76a96ca48905d354c02a96b35ba29fadc
Reviewed-on: https://gerrit.libreoffice.org/25046
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-17 03:21:44 +00:00
Ashod Nakashian
7c76e4b6bc loolwsd: MasterProcessSession splitting: using ClientSession
Change-Id: I2ee089c04d2e5fbdae91cfc5cada437f5aae8e5b
Reviewed-on: https://gerrit.libreoffice.org/25038
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-17 03:13:07 +00:00
Ashod Nakashian
73f0e2a190 loolwsd: MasterProcessSession splitting into ClientSession and PrisonerSession
Change-Id: I29bcc5f791acf2313830e21d102e25f2232329d1
Reviewed-on: https://gerrit.libreoffice.org/25037
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-17 03:12:28 +00:00
Ashod Nakashian
d18bca992c loolwsd: use TileDesc instead of explicit values
Change-Id: I56ba6c4e63a495500093e7353477175d40152d11
Reviewed-on: https://gerrit.libreoffice.org/25020
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-15 23:00:43 +00:00
Ashod Nakashian
909c996a6d bccu#1774: poor API never fails to frustrate
The tile and tilecombine messages apparently have optional
appendages at their rear ends. Not one, but two (at least).

While the first (timestamp) seems to be truely optional
(in the sense that leaving it out doesn't break anything,)
the same can't be said of the second (id).

For Impress slides this id is used to identify the slide
to which the tile belongs. Or rather the slide being
rendered, as it seems meaningful only for the slide
thumbnails.

Previously the complete arguments of tile were copied
verbatim from the input to the output (i.e. back to the
client) and so any extra payload was also echoed back.

But when id is missing (when expected) loleaflet not
only fails to show these tiles (understandably,) but
it also fails to show the scrollbar for said slide
thumbnails altogether!

With the new logic to move the tile communication to
the child socket instead of the clients, the arguments
are parsed and then serialized back in the response.
So all fields must be explicitly known in advance.

This change is necessary because tilecombine is broken
to tile commands and so both share common code. This
means that echoing back the request verbatim will
break loleaflet since tilecombine arguments (which
is a list) is not a valid response (which has the
format of tile). So the internal representation
has to be something neutral/common.

The fix is to parse the timestamp and id only when
provided and to echo back the id only in that case.

Change-Id: Ic97cf0de4083d412a4b3543e8b9a8713ac27a27c
Reviewed-on: https://gerrit.libreoffice.org/24669
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-05 02:41:59 +00:00
Ashod Nakashian
a240f2666f loolwsd: tile traffic is now completely centralized
WSD's DocumentBroker and Kit's Document now handle
the communication of tiles as well as all aspects
of rendering, caching, unifying requests and
distributing results etc.

Change-Id: Ie22fbaaae26b91185ee348ec7077f30430eec0f6
Reviewed-on: https://gerrit.libreoffice.org/24640
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-04 10:36:01 +00:00
Ashod Nakashian
ff0d4a3a91 Revert "Revert "loolwsd: establish communication with...
...child from DocumentBroker""

Restore the communication with child from DocumentBroker.

This reverts commit 20ab6e8ae7.

Change-Id: I248bededff7074d8fb482b2cdd172048f80c02b2
Reviewed-on: https://gerrit.libreoffice.org/24639
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-04 10:33:48 +00:00
Jan Holesovsky
20ab6e8ae7 Revert "loolwsd: establish communication with child from DocumentBroker"
Unfortunately this causes a deadlock in the unit tests.

This reverts commit 10417c9447.
2016-05-02 11:49:58 +02:00
Ashod Nakashian
10417c9447 loolwsd: establish communication with child from DocumentBroker
The WebSocket that each child created with WSD is not used
except to request the child to load the document a client
requests. Beyond this point, it was not utilized for anything.

In fact, there are no handlers in WSD for messages coming
from the child; it is a one-way communication.

That is until now. With the move to unify communication
between WSD and each child, DocumentBroker can now
receive and handle messages from its ChildProcess.

Change-Id: Ie7f030a92db8303cd7087fff2325f136a49bc7fc
Reviewed-on: https://gerrit.libreoffice.org/24581
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-02 02:55:53 +00:00
Ashod Nakashian
3dc72cab18 loolwsd: ChildProcess cleanup
Change-Id: I1ae4911d3f5d527af86f39ed2723bbceef12cffe
Reviewed-on: https://gerrit.libreoffice.org/24577
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-02 02:52:28 +00:00
Ashod Nakashian
bdfda58386 loolwsd: don't autosave when document not loaded
Change-Id: I44e9c2ad234ee05348b47415add3933c81fce968
Reviewed-on: https://gerrit.libreoffice.org/24525
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-04-30 14:36:28 +00:00
Jan Holesovsky
9f5ca3f0ff Help the autodoc. 2016-04-29 13:42:01 +02:00
Ashod Nakashian
d07a582469 loolwsd: merged autoSave and waitSave
This makes for amore compact API and avoids
a race between issuing the save and waiting for it.

Also added force flag and autoSave now checks the
modified state of the document. If a document is
not modified, nor save forced, autoSave checks
the last activity on the document and only
if there is any since last save does it issue
a save command.

Change-Id: I962e36df18d7edf5f658992e97b5def5f6247dc3
Reviewed-on: https://gerrit.libreoffice.org/24382
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-04-26 10:40:35 +00:00