Multi-page SPA on Python

3r3-31. Bridge between Python and React 3r31036.  
An owl is a nano-framework that can be embedded into other frameworks. 3r31036.  
Picture from, which runs 3 http servers: 3r31036. - just Falcon - just Django - just Python (login: ? password: 1)
There are source codes and installation instructions. There is no advertising. 3r31036.  
Multi-page SPA on Python 3r31036.  
framework. Why do something else? 3r31036.  
I explain: Owl is not designed for site development. It is a tool for replacing thick clients with browser-based applications (desktop applications). 3r31036.  
- What is a web client? 3r31036.  
- Not. This is not a web client. This application works in a browser. 3r31036.  
- I do not understand. 3r31036.  
- Unfortunately, many developers do not understand. 3r31036.  
As a general, I actively worked with several Internet applications. 3r31036.  
Online client of the bank Ugra (bank closed). 3r3393917. 3r31036.  
It was a good application, but it was a Java applet, i.e. fat client launched from browser. And the Bank of Ugra, and applets in the past. 3r31036.  
[b] Online client of VTB-24 bank (bank is closed). 3r3393917. 3r31036.  
I am a humanist, but after working with this miracle, cruel thoughts like: “Make the developer register 1000 payments in him” began to appear. 3r31036.  
At the same time as a web client, he is beautiful. Animation, opens on a mobile phone. Wow Cool! 3r31036.  
I asked an accountant friend: how do you work with him? 3r31036.  
She says: beautiful! I load the data in 1s, I work in 1s, I upload the results back. 3r31036.  
[b] Online client Sberbank
Satisfactory customer, you can work. When I was asked to rate him, I gave him 3 points out of 5 and gave a list of comments. This is with my 10 payments per month. Those who make 100 bills a day are likely to upload information. 3r31036.  
Filling payment. 3r31036.  
The green area that occupies 20% of the screen is the menu. It does not just interfere (position: fixed), it says that the developer is not a professional. If I started making a payment, on the db screen. 3 buttons: “Create”, “Save as template”, “Cancel”. These buttons are (for some reason below). This is not a multi-page SPA: go to the menu item - the data in the form will disappear. 3r31036.  
The one who did this will not even understand what the hitting is: “It’s normally done, everyone is doing it, such a library, people are working ”. And he is right. You need to ask the project manager, and for the manager, the main thing is the database and the layers in the conceptual model. And the forms - we will hire boys, they will draw. And they are proud, perhaps, of this hack. 3r31036.  
Trading platforms (5 pieces, 44 FZ) 3r31036.  
These are really applications (not web clients). But I don't like field controllers. 3r31036.  
Examples: 3r31036.  
Aligned strangely, the width of the field is clearly insufficient, there is no autoheight in the input field. 3r31036.  
Another example. In the field “Date of publication” there is no template, calendar with an error, calendar icon scares:
3r3117. 3r31036.  
List on rts-tender: there is a current record highlighted in color, arrows can move through the list, but there is no autoscrolling (you can run off the screen), neither Enter nor a space opens the link, the tab is not tied to the current record. Although the link can only be opened with a mouse, I appreciate the control with a plus sign. This functionality (remember and highlight the current document) is not enough for me in
It seems like little things. But the professional application differs from the semi-professional in the details. The end user does not care what your database is and how many layers there are in the conceptual model. It works with screen forms and it has 3 requirements: functionally, conveniently, quickly. 3r31036.  
Unfortunately, the choice of the system is determined by IT specialists and bosses who did not work with the system themselves and will not work. They will appreciate the speed, the functionality will be assessed as they understand it, and they do not care about convenience, the main thing is that it is beautiful. 3r31036.  
Pavel Valerievich Durov did not invent either the social network or the instant messenger. He did what users want, comfortable and beautiful. And people appreciated it, including materially. 3r31036.  
Owl is a tool for building a professional interface. 3r31036.  
What does this mean, for example, SED. 3r31036.  
There are EDS, it has 3 groups of users:
The heads 3r31036.  
Specialists preparing documents
Clerks. 3r31036.  
Chiefs, they are like children. They need to just and beautiful. Ideally, 1 button and 1 field. And to ponte more. Web client and, of course, mobile client to show off. 3r31036.  
Specialists. Web client, a social network /mailer mix. Do not forget that there are a lot of specialists and they need to be trained. The more familiar the environment is to them, the better. A mobile client is also useful if the security service allows it. 3r31036.  
Clerks. This is where the Owl comes in handy. Clerks are a backbone user group. All others can get sick /go on vacation /stop using, - SED will work. If registration stops, everything will come up. 3r31036.  
Workflow is a conveyor, and here everything is important, every little thing: fonts, halftones, automatic filling, checking values, ease of entry, etc. 3r31036.  
SED "Delo". Performers' cabinets are made on the web client, the office is a fat client. Everything is fine, but it will work until the government bans Windows in state structures. I love Win ? but if I were the ruler, the it-market would cheer up with new orders, and MS would remain in bright memory. By the way, on December ? Anton Siluanov signed 3r3162. directive 3r3393921. about the transition to domestic software. 3r31036.  
3r31036. 3r31036.  
How owl opens the form. 3r31036.  
Without multi-page. 3r31036.  
The central element of the Owl is the Document component. By pressing ctrl-U on the start page, you will see everything you need to create an object of the Document class:
- data fields of the database; 3r31036.  
- form url to display; 3r31036.  
- dbAlias, unid - to work with the database; 3r31036.  
- something else there. 3r31036.  
To some extent, a Document is an analogue of a redux form. 3r31036.  
The form is loaded as a JSON string, then the former dictionary becomes an object having style, className and an array (list) of elements. The array will be inserted into the element with id = root as
3r3638. 3r3194. array 3r31045. 3r33876. 3r3r777. 3r31036.  
The array elements are objects that describe the tags 3r33838. 3r3638. 3r3r2202. , 3r33876. 3r3r777. 3r31036.  
Img is smarter than standard - in props you can set href and target:
Python: 3r31036.  
dict (img = 'image? react.ico', style = {'width': 16}, href = 'https: //')
Fragment of the parser that converts an array of objects into components (boxing.js):
3r33838. 3r33842. if (td.img) {//td is an element of the
array. let img = ;
return td.href?
3r33333. {img}
3r33876. 3r3r777. 3r31036.  
Type in the search engine "react component library". The result is predictable - a lot. But all this abundance is intended for websites, not applications: 3r31036.  
Smart-textarea - perhaps the only control that gave me. 3r31036.  
React-select - simplified and redid the drop-down list
Data-picker /calendar - did not find anything suitable. I wrote my own, taking as a model built into G.Chrome. 3r31036.  
Upload /Download - nothing suitable, wrote your own. 3r31036.  
Imho: websites have a sad future. The vast majority of users will no longer use browsers (or have already ceased) in the near future. The phone will be merged with the tablet, and 1 dash of 10 applications will fully meet your needs. 3r31036.  
I have already come across twice with programmers who do not know how to write an e-mail address correctly. Why should they remember what they do not use. The world is changing. 3r31036.  
In the Sovereign, the controllers are not ideal, but they were designed for the operator, not the web user. 3r31036.  
As an example, the “Transmission Mark” form. A fairly universal form, used where there is a boss. Red on the screenshot encircled fields that control the hide. Additional resolutions open automatically as they are completed, if there are several instructions in the operative part for different groups of performers with different terms. Two terms per group: 1st term to the 1st performer, 2nd term co-performers. 3r31036.  
You can touch the form [leech=] HERE
The controller is the React component associated with the database field. 3r31036.  
A detailed description of the controllers with the ability to check their work is on 3r31036.  
Pay attention to the types of rtf and json. Rtf is displayed as text, but if the text contains the {_ {object} _} construct, the Owl will perform json.parse for this construct and add the result to the form. The json type field must store the description of the array of markup elements:[{элем1}, {элем2}, …]. json.parse is executed before rendering. 3r31036.  
Fields with these types allow you to store markup in the database or in files. Useful when generating reports and writing documentation. 3r31036.  
List of controllers for all field types (controllers.js):
3r33838. 3r33842. export const controller = prop => {
switch (prop.type) {//field type
case 'chb': return
case 'lbse': //listbox single enable (allow non-list values)
case 'lbme': //listbox multivalue enable
//lbse /lbme is a text box with a button that opens the
case 'tx': return
; //smart-textarea
case 'lbsd': //listbox single disables (prohibit non-list values)
case 'lbmd': return
case 'dt': return (prop.readOnly?
case 'fd': return
case 'table':
case 'gr': return
case 'rtf': return
case 'json': return
case 'list': return
case 'view': return
console.warn ('Unknown field type', prop.xName, prop.type);
3r33876. 3r3r777. 3r31036.  
The application requires a manipulation mechanism for the controllers. 3r31036.  
In the board, all document controllers are stored in the document variable 3r31036.  
I did not dare to use refs due to rumors that the redaxophiles would cancel it. 3r31036.  
The controller may have the following interfaces:
getValue (param)
setValue (value, param)
setFocus ()
changeDropList ()
In order to access the desired field, there are methods of the document
getField (fieldName, param)
setField (fieldName, value, param)
changeDropList (fieldName, param)
setFocus (fieldName)
For fields of type FileShow, there is a fileShow['FILES1_']method. .hasAtt (), where FILES1_ is the name of the area with the files. Returns true if there are attachments. In the mark of the transfer of such areas 2. 3r31036.  
Controllers can generate a recalc event. If a handler is registered for this field, it will be executed. Handlers are in loadable js-files. 3r31036.  
An example and a somewhat simplified description:
There is a “Transmission Mark” form ( It contains a downloadable file o.js
are registered in o.js.  
3r33838. 3r33842. recalc: {
PROJECTO: doc => doc.forceUpdate (),
WHOPRJ2: doc => doc.forceUpdate (),
WHOPRJ3: doc => doc.forceUpdate (),
other handlers
} 3r3r777. 3r31036.  
, as well as the conditions for hiding are specified (project, op, prj? prj2 prj5 - this is the “name” property in the description of the divs): 3r31036.  
3r33838. 3r33842. hide: {
project: doc =>! doc.getField ('projectO'), //hide if the PROJECTO field is empty
op: doc => doc.getField ('projectO'), //hide if the PROJECTO field is not empty
prj1: doc =>! doc.getField ('projectO'),
prj2: doc =>! doc.getField ('projectO'),
prj3: doc =>! doc.getField ('projectO') || (! doc.getField ('whoPrj2') &&! doc.getField ('whoPrj3')),
prj4: doc =>! doc.getField ('projectO') || (! doc.getField ('whoPrj3') &&! doc.getField ('whoPrj4')),
prj5: doc =>! doc.getField ('projectO') || (! doc.getField ('whoPrj4') &&! doc.getField ('whoPrj5')),
}, 3r33876. 3r3r777. 3r31036.  
How it works: the PROJECTO field is the checkbox; when the value changes, the controller generates a recalc event, the document calls the recalc.PROJECTO (this) handler. 3r31036.  
The handler simply calls forceUpdate () to redraw the document. 3r31036.  
When redrawing, it is checked whether the components have a name in the name, if the name has a hide function for[]and whether it returns true. 3r31036.  
prj3: doc =>! doc.getField ('projectO') || (! doc.getField ('whoPrj2') &&! doc.getField ('whoPrj3'))
Hide the third resolution (area with === 'prj3'), if the projectO checkbox is OFF or the resolution 2 and 3 fields are not entered (both 'whoPrj2' and 'whoPrj3' fields are empty). 3r31036.  
The name of a field when calling functions is case-insensitive. 3r31036.  
WHOPRJ2 is a combo box, when selecting a value, the controller will also generate a recalc event, which will also cause a redraw. Selecting the artist in the second resolution, you will open the third one. 3r31036.  
In the uploaded js-files you can:
- manage the hide; 3r31036.  
- manage reading only; 3r31036.  
- respond to changes in fields; 3r31036.  
- execute commands of buttons; 3r31036.  
- do validation of fields and forms before saving; 3r31036.  
The downloadable file for the form 'fo':
3r33838. 3r33842.
window.sovaActions = window.sovaActions || {}; = {//fo - the name of the form in lower case
recalc: {//handler is called when changing the values ​​of checkboxes and combo boxes 3r31049. PROJECTO: doc => doc.forceUpdate (),
}, 3r3-1049.
hide: {//hide the named area if true
project: doc =>! doc.getField ('projectO'),
}, 3r3-1049.
readOnly: {//read only for the named area, if true
who: doc => doc.getField ('SENTFROMDB'),
}, 3r3-1049.
validate: {//checking fields and forms before sending them to the server 3r31049. who: doc => doc.getField ('who')? '': 'The' To Whom 'is not filled in' field,
form: doc => new Promise ((yes, no) => {
let disableAutoOrder = false; 3r31049. for (let i = 1; i <= 5; i++) {
let val = doc.getField ('RESPRJ' + i);
. disableAutoOrder | = /under my signature /.test (val); 3r310349.} 3r3-331049. disableAutoOrder && doc.setField ('AUTOORDER', '');
yes ();
Cmd: {//execution of commands of buttons
Logoff: doc => {window.location.href = '/logoff'},
} 3rr3777.  
Validation of fields is a function, returns empty if everything is OK, or a message about what is wrong. The owl will set the focus to an invalid field. 3r31036.  
Form validation - promis. In the example, there are no checks (yes is always called), just something is done before being sent to the server. 3r31036.  
In redux-form, validation is done through trow - some kind of wildness. 3r31036.  
3r33586. For those who are not familiar with promises, the simplest example is 3r3-33587. 3r31036.  
3r33838. 3r33842. const confirmDlg = msg => new Promise ((ok, cancel) => confirm (msg)? ok ('OK button pressed'): cancel ('cancel pressed button'));
confirmDlg ('The easiest promis')
.then (s => console.log (s))
.catch (s => console.log (s)); 3r33876. 3r3r777. 3r31036.  
The Document class has several predefined commands that can be used in buttons: 3r31036.  
edit: go to the form edit mode
save: save the form
close: close form
saveClose: save and close the
prn: print the form with the choice of template for printing
docOpen: open the document
dbOpen: open the
xopen: open the url
newDoc: create a new document with the required form
In the Redux-form api is richer, - in the Owl, only necessary. 3r31036.  
[b] Multi-page. 3r3393917. 3r31036.  
The Document class creates an object (form) that is embedded in the element 3r33870. 3r3638.
3r3-1045. 3r33876. 3r3r777. . 3r31036.  
Let's call it the “root document”. If you add the element
to the root document.  
, it is also possible to insert another Document object into it. 3r31036.  
How to deal with loadable command handlers? Everything is simple: each form has its own handler (its js), and the root document must load those that may be required. 3r31036.  
Example for the start page of (
The form opens documents with the forms “rkckg”, “outlet”, “outlet.gru”, and “o” to demonstrate its multiplicity. 3r31036.  
In order for all forms to work correctly, you need to register in scripts for these forms:
3r33838. 3r33871. jаvascriptUrl =['jsv?api/forms/rkckg/rkckg.js',
'jsv?api/forms/home/home.js']3r33876. 3r3r777. 3r31036.  
Since when calling any handler function, the first parameter is a link to the document, actions will be performed on the required document. 3r31036.  
OOP and no miracles. 3r31036.  
React is not React
I have already described the form "report". It opens from the report manager (“React” arrow) and describes the parameters for collecting the report. 3r31036.  
3r38282. 3r31036.  
The reports themselves (arrow "not React") are stored in subordinate documents with the form "rreport" in the form of html attachments. We were engaged in the development of reports, when React was not there, the form “rreport” turned out to be simple (20 html lines and 15 simple-js lines), why change what works for 8 years. 3r31036.  
Open report manager. 3r? 3921. 3r31036.  
The “rreport” form consists of 4 buttons and an iframe. Owl before opening the document replaces in the src = "" address with a line with the url for downloading the html-attachment, the browser does the rest. 3r31036.  
The EXCEL /WORD buttons are similar: paste the url buttons for downloading with the file name “report.html.xls” or “report.html.doc” and the corresponding mime-type. Excel /Word does the rest (“these smart animals understand everything they want from them”). 3r31036.  
3r33838. 3r33871. downloadUrl = '/download /' + fn + '?' + '&'. join ([d.db.alias, d.unid, idbl, fsName, fzip, ctype, flen])
excel = '/download/%s.xls?%s'% (fn, '&'. join ([d.db.alias, d.unid, idbl, fsName, fzip, 'application/x-excel', flen]))
word = '/download/%s.doc?%s'% (fn, '&'. join ([d.db.alias, d.unid, idbl, fsName, fzip, 'application/msword', flen]))
html = html.replace ('src = ""', 'src = "% s"'% downloadUrl) .replace ('openExcel', excel) .replace ('openWord', word) 3r33876. 3r3r777. 3r31036.  
When opening html in Excel /Word, the differences from the browser are, but small. And the article is not about that. 3r31036.  
[b] Making a form from scratch. 3r3393917. 3r31036.  
There are 3 functions 3r31036.  
def snd (* msg, cat = 'snd'):
def err (* msg, cat = 'all'):
def dbg (* msg, cat = 'snd'):
which are more or less evenly distributed throughout the code and write error messages and other crap to the log file. 3r31036.  
The message format is transferred to logging.Formatter in the form:
'% (asctime) s% (levelname) s[%(name)s]% (message) s'
The file is filled with messages

09/02/???:50:07 DEBUG[http-server]addr ('???.1', 49964), “GET /arm HTTP /1.1” 200 - 3r31036.  
09/02/???:54:07 INFO[Free space]Attachments are saved in ".DBfiles" Free 68557 Mb
09/02/???:58:07 ERROR[]getScript:[Errno 2]No such file or directory: 'sova /api /forms /o /oo.js'

Date-time, then level, then in square brackets the category within the level, then the message. 3r31036.  
Task: 3r31036.  
Make a page to view the log file. What type 3r31036.  
3r3761. 3r31036.  
Let's call the form “lm”, it will be formed as a function of page in the module api /forms / 3r31036.  
3r33838. 3r33871. def page (dbAlias, mode, userName, multiPage):
return dict (
style (background = 'url (/image?bg51.jpg)', backgroundSize = '100% 100%'),
div =[
style(width='200px', float='left', background='rgba(210,218,203, 0.5)', padding='0 5px'),
_field('type', 'list',['Весь журнал|all', 'Ошибки|err', 'Сообщения|info', 'Отладка|debug'],
saveAlias ​​= ?
** style ( margin = '10px auto', width = 17? height = 110)
_field ( 'cat', 'list', 'TYPE_ALIAS ||| api.get loadDropList & logger |? keys_ {FIELD}'.,
listItemClassName = 'repName',
listItemSelClassName = 'repNameSel',
** style (height = 'calc (100vh - 133px)', overflow = 'auto')
], 3r31049. ), 3r31049.
_field ('msg', 'fd',
br = ?
** style (overflow = 'auto', height = '100vh', font = 'bold 12px Courier', background = 'rgba (25?25?25? 0.8 ) ')
) 3r33876. 3r3r777. 3r31036.  
In the left part there are 2 fields, both with the type “list”: type and cat (message type and category). 3r31036.  
In the right one msg field with type fd (forDisplayOnly). 3r31036.  
The types of messages are specified in the field description (['Весь журнал|all', 'Ошибки|err',),
категории вытягиваются по xhr из глобального словаря с вызовом хитрого url:
api.get?loadDropList&logger|keys_err вернет в json-формате массив (список) категорий из глобального словаря. Что-то типа well('logger', 'keys_err').
Сообщения формируются при открытии документа функцией queryOpen в
def queryOpen(d, mode, ground):
ls = well('logger_all', 'A L L')
s = 'n'.join(reversed(ls))
d.msg = s
d.type_alias = 'all'[/code]
logParser считывает и парсит log-файл. Результаты раскладывает в несколько массивов и сохраняет их в глобальном словаре. Ничего интересного: 2 простейших re и цикл по итератору.
Функции для работы с глобальным словарем:
toWell(o, key1,[key2]) - save the object “o”
in the global dictionary.  
well (key?[key2]) - take an object from the global dictionary by key (by two keys). 3r31036.  
For the first drawing of this is enough. To be able to display messages of the desired type and desired category, you need to make loadable js. 3r31036.  
In add the line
jаvascriptUrl = 'jsv? api /forms /lm /lm.js'
and create lm.js:
3r33838. 3r33842. window.sovaActions = window.sovaActions || {};
window.sovaActions.lm = {//handlers of the form "lm"
init: doc => doc.changeDropList ('CAT'),
recalc: {
TYPE: (doc, label, alias) => {
doc.changeDropList ('CAT');
getLogData (doc, alias + '| A L L');
}, 3r3-1049. CAT: (doc, label) => getLogData (doc, doc.getField ('type_alias') + '|' + label),
}, 3r3-1049.};
//*** *** ***
let getLogData = (doc, keys) => {
fetch ('api.get? getLogData &' + keys, {method: 'get', credentials: 'include'})
.then (response => response.text ())
.then (txt => doc.setField ('msg', txt))
.catch (err => doc.setField ('msg', err.message));
}; 3r33876. 3r3r777. 3r31036.  
getLogData pulls messages from the server of the desired type and category: 3r31036.  
3r33838. 3r33871. def getLogData (par, un):
lg, _, cat = par.partition ('|')
msg = well ('logger_' + lg, cat)
return 20? 'text /html; charset = UTF-8 ',' n'.join (reversed (msg))
3r33876. 3r3r777. 3r31036.  
You can enjoy the shape of
. 3r31036.  
Initially, logging was done based on the standard logging module
using logging.FileHandler, .addHandler, and others getLogger and setFormatter. 3r31036.  
As taught. But at the same time it was buggy. You can throw stones, but when I threw out the logging and just started writing to the file, the code became shorter, clearer and the glitches disappeared. 3r31036.  
Included is a self-hosted multi-threaded wsgi server with Digest authorization. This is not for sites. Why was he needed at all? 3r31036.  
The customer has 40 jur. Persons, in most cases 1-2-3 people work with the system. Store data on the Internet is prohibited. All win 7. Requires easy installation and configuration. 3r31036.  
Solution: using cx-Freeze and Inno Setup, we install the installer, run it on the computer of the most responsible one and get a mini-http server for the local network that starts as a Windows service. Nothing extra. It is impossible to use wsgiref.simple_server or wsgi_Werkzeug built into Python. they are single-threaded: until one request is completed, the others will wait. 3r31036.  
I can hardly surprise anyone by saying that the built-in WSGIServer /0.2 CPython /??? in Django is many times faster than the self-written Python one. Only it doesn’t matter - forms and directories are cached on the client, only the database data is transmitted very quickly over the local network. 3r31036.  
There is one more reason: the desktop application has access to computer resources (EDS, files, scanner ). To get the same access from the browser, you need to either write a plugin, or hang up a small http server in the services, which can snoop with the main server and perform the necessary actions on the locale. 3r31036.  
Owl does not use framework tools to work with the database. In the dbToolkit directory, something similar in structure to MongoDB (or Lotus Notes) to SQLite3:
Book class - db (in MongoDB and Lotus Notes terminology) 3r31036.  
The DocumentCollection class is a collection of documents from Book
Document class - a document (an object containing any number of fields). 3r31036.  
[b] Installation: 3r33917. 3r31036.  
Download from archive
In the archive directory owl, from which you can run the Owl from django, falcon or without frameworks. 3r31036.  
Download, unzip. 3r31036.  
Install Python3 (3.5+) 3r31036.  
1. owl - without frameworks. Attention! Login: ? password: 1
Linux: 3r31036.  
cd ./owl
or in a separate window
screen -Udm python3
Windows: 3r31036.  
cd ./owl
2. Django
Linux: 3r31036.  
Install django:
pip3 install django
cd ./owl
python3 runserver
or in a separate window
screen -Udm python3 runserver ???.1:8000
Windows: 3r31036.  
Install django:
pip install django
cd ./owl runserver
3. falcon
Linux: 3r31036.  
pip3 install falcon
cd ./owl
python3 falconApp: api 8001 log_falcon /falcon
Windows: 3r31036.  
pip install falcon
cd ./owl falconApp: api 8001 log_falcon /falcon
- the name of the article is strange, did you understand what a “Multipage SPA” is? 3r31036.  
- The usual marketing pitch 3r31036.  
- why not Redux? Everyone uses Redux
- I do not like the word “reducer”
- and seriously? CombineReducers at any level of the hierarchy It is so beautiful
- it's multipage, baby. Command handlers should be inside the form, not like the horns of a deer
- why did you even write an article? 3r31036.  
- PR r3r31045.
3r31042. ! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d,! 1): e.attachEvent ("onload", d ): d ()}}} t ("//"""_mediator") () ();
+ 0 -

Add comment