Compare commits

..

No commits in common. 'prd' and 'dev-linux' have entirely different histories.

3
.gitignore vendored

@ -17,9 +17,6 @@
/**/OpenRPA_Orchestrator.exe
/**/OpenRPAOrchestrator.exe
/**/OpenRPARobotGUIx32.exe
/**/orpa-std.exe
/**/orpa-rbt.exe
/**/orpa-agt.exe
/**/orpa-orc.exe
/**/orpa-agent.exe
/**/OpenRPARobotGUIx64.exe

@ -1,3 +1,3 @@
cd %~dp0
taskkill /F /FI "USERNAME eq %username%" /IM orpa-agent.exe
cd %~dp0
taskkill /F /FI "USERNAME eq %username%" /IM orpa-agent.exe
pause >nul

@ -1,6 +1,5 @@
chcp 65001
cd /d "%~dp0"
taskkill /im "orpa-agent.exe" /F /fi "username eq %username%"
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\pythonw.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-agent.exe
.\..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-agent.exe "config.py"
cd %~dp0
taskkill /im "orpa-agent.exe" /F /fi "username eq %username%"
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\pythonw.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-agent.exe
.\..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-agent.exe "config.py"
pause >nul

@ -1,6 +1,5 @@
chcp 65001
cd /d "%~dp0"
taskkill /im "orpa-agent.exe" /F /fi "username eq %username%"
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-agent.exe
.\..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-agent.exe "config.py"
cd %~dp0
taskkill /im "orpa-agent.exe" /F /fi "username eq %username%"
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-agent.exe
.\..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-agent.exe "config.py"
pause >nul

@ -1,3 +1,3 @@
git clean -f -d
git reset --hard
git clean -f -d
git reset --hard
pause>nul

@ -0,0 +1,2 @@
git pull
pause>nul

@ -1,2 +0,0 @@
git pull
pause>nul

@ -1,5 +1,8 @@
Copyright (c) 2019 Ivan Maslov, 2022 LLC pyOpenRPA
Правообладатель: 2019 Маслов Иван Дмитриевич, 2022 ООО ОПЕН РПА
pyOpenRPA open license
pyOpenRPA открытая лицензия
Copyright (c) 2019 Ivan Maslov
Правообладатель: 2019 Маслов Иван Дмитриевич
Текст лицензии см. в файле: LICENSE.PDF (в корне репозитория) или по адресу: https://pyopenrpa.ru/license/oferta.pdf

@ -0,0 +1,57 @@
# !ATTENTION - Current Control panel works only from pyOpenRPA v1.2.0!
from pyOpenRPA import Orchestrator
def CPRender(inGSettings):
lJSCheckVersion="""
lT = 9;
lY="123";
console.log(lT+1);
if (lT==9) {
alert(123)
}
"""
lResultDict={
"HeaderLeftText":"CP_TEST",
"HeaderRightText":"NAME",
"DataStorageKey":"", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText":"",
"BodyKeyValueList":[
{"Key": "HTMLLinkURL", "Value": Orchestrator.Web.Basic.HTMLLinkURL(inURLStr="test",inColorStr="orange")},
{"Key": "HTMLLinkJSOnClick", "Value": Orchestrator.Web.Basic.HTMLLinkJSOnClick(inJSOnClickStr=lJSCheckVersion, inTitleStr="!Click me!",inColorStr="green")},
],
"FooterText":"",
"FooterButtonX2List":[],
"FooterButtonX1List":[],
"GlobalStorage": "" # UNCOMMENT FOR DEBUG PURPOSE TO WATCH inGSettings on client side
}
return lResultDict
# Check in control panel, that process is runnning
# Test JSON generator when page init
def JSONGenerator():
lJSONDict=[1,2,2,4,2,2,2]
return lJSONDict
# Test JS when page init
def JSInitGenerator():
lJSCheckVersion="""
lT = 9;
lY="123";
//console.log(lT+1);
if (lT==9) {
//alert(123)
}
"""
return lJSCheckVersion
def test():
#Orchestrator.WebRequestGet()
Orchestrator.WebRequestResponseSend("Hello my friend!")
#Orchestrator settings
def SettingsUpdate(inGSettings):
# New way to add CP defs in orchestrator - no gSettings..
Orchestrator.WebCPUpdate(inGSettings=inGSettings, inCPKeyStr="TEST", inHTMLRenderDef=CPRender, inJSONGeneratorDef=JSONGenerator, inJSInitGeneratorDef=JSInitGenerator)
Orchestrator.WebURLConnectDef(inMethodStr="GET", inURLStr="/test", inMatchTypeStr="Equal", inDef=test, inUACBool=False)
return inGSettings

@ -0,0 +1,54 @@
# !ATTENTION - Current Control panel works only from pyOpenRPA v1.2.0!
from pyOpenRPA import Orchestrator
from pyOpenRPA.Orchestrator import Managers
def ControlPanelRenderDict(inGSettings):
# Example of the JS code in Python code
lJSCheckVersion = f"""
if (!('VersionStr' in mGlobal)) {{
window.location.reload(true);
}} else {{
if (mGlobal.VersionStr != "{inGSettings["VersionStr"]}") {{
window.location.reload(true);
}} else {{
$('div.orchestrator-version').html(mGlobal['VersionStr']);
}}
}}
"""
lResultDict={
"HeaderLeftText":"Version check",
"HeaderRightText":"Orchestrator",
"DataStorageKey":"", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText":f"<script>{lJSCheckVersion}</script>",
"BodyKeyValueList":[
{"Key": "Client", "Value": '<div class="orchestrator-version" style="display:inline;"></div>'},
{"Key": "Server", "Value": inGSettings["VersionStr"]},
],
"FooterText":"",
"FooterButtonX2List":[],
"FooterButtonX1List":[],
"GlobalStorage": "" # UNCOMMENT FOR DEBUG PURPOSE TO WATCH inGSettings on client side
}
return lResultDict
# Check in control panel, that process is runnning
#Orchestrator settings
def SettingsUpdate(inGSettings):
#Add RobotRDPActive in control panel
Orchestrator.WebCPUpdate(inCPKeyStr="VersionCheck", inHTMLRenderDef=ControlPanelRenderDict)
#Orchestrator.Managers.ControlPanel(inControlPanelNameStr="TestTTT",inRefreshHTMLJinja2TemplatePathStr="ControlPanel\\test.html", inJinja2TemplateRefreshBool = True)
lProcess = Orchestrator.Managers.ProcessInitSafe(inAgentHostNameStr="IVANMASLOV-DESKTOP",inAgentUserNameStr="ND",
inProcessNameWOExeStr="notepad",inStartCMDStr="notepad",inStopSafeTimeoutSecFloat=3)
# Some test
Orchestrator.OrchestratorInitWait()
#lProcess.ScheduleStatusCheckEverySeconds(inIntervalSecondsInt=5)
#lProcess.Start(inIsManualBool=False)
lProcess.StartCheck()
#Orchestrator.OrchestratorScheduleGet().every(2).seconds.do(Orchestrator.OrchestratorThreadStart,
# lProcess.StartCheck)
#Orchestrator.OrchestratorScheduleGet().every(5).seconds.do(Orchestrator.OrchestratorThreadStart,lProcess.StatusCheckStart)
#lProcess.Start()
lGit = Orchestrator.Managers.Git(inAgentHostNameStr="IVANMASLOV-DESKTOP",inAgentUserNameStr="ND",inGitPathStr="C:\Abs\Archive\scopeSrcUL\pyStore")
lGit.BranchRevLastGetInterval(inBranchLocalStr="prd", inBranchRemoteStr="origin/prd", inPreviousBranchRestoreBool=False,inIntervalSecFloat=10.0)
lGit.ProcessConnect(inProcess=lProcess)
return inGSettings

@ -1,28 +0,0 @@
from pyOpenRPA import Orchestrator
from pyOpenRPA.Orchestrator.Managers import ControlPanel
from pyOpenRPA.Orchestrator.Managers import Process
from pyOpenRPA.Tools import CrossOS
import os
import sys
import socket
import datetime
import urllib.parse
import time
g_cp_name_str = "HELLO"
g_repo_name_str = os.path.abspath(__file__).split("\\")[-5]
g_repo_package_path_str = os.path.abspath("\\".join(os.path.abspath(__file__).split("\\")[:-1]))
# User settings
g_host_str = socket.gethostname().upper() # Identify PC
g_control_panel = ControlPanel(inControlPanelNameStr=g_cp_name_str,
inRefreshHTMLJinja2TemplatePathStr=os.path.join(g_repo_package_path_str, "html_jinja2.xhtml"),
inJinja2TemplateRefreshBool=True,inRobotNameStr=g_repo_name_str)
g_jinja_context_dict = {"settings": sys.modules[__name__],
"urllib_parse_quote_plus": urllib.parse.quote_plus, "g_host_str": g_host_str, "g_repo_name_str": g_repo_name_str}
g_control_panel.Jinja2DataUpdateDictSet(inJinja2DataUpdateDict=g_jinja_context_dict)
g_control_panel.InitJSJinja2TemplatePathSet(inJinja2TemplatePathStr=os.path.join(g_repo_package_path_str, "js.js"))

@ -1,79 +0,0 @@
<div class="card" style="width:100%">
<div class="content">
<div class="right floated mini ui ">
</div>
<center>
<h1>Добро пожаловать <span>
{% if UserInfoDict["UserNameUpperStr"] %}
{{UserInfoDict["UserNameUpperStr"]}}
{% endif %}
</span>!</h1>
</center>
<div class="ui divider"></div>
<div class="description cp-hello-description">
<div>
<h5>Предлагаем ознакомиться с демонстрационным стэндом оркестратора pyOpenRPA.</h5>
pyOpenRPA это прогрессивная RPA платформа, которая позволяет сочетать в рамках одного проекта все перспективные технологии, такие как:
<ul>
<li>OCR / NLP / NER: Распознавание изображений и текста</li>
<li>CV: Компьютерное зрение</li>
<li>AI: Искусственный интеллект</li>
<li>ML: Машинное обучение</li>
<li>BIGDATA: Большие данные</li>
<li>VOICE & CHAT: Голосовые и чат-боты</li>
</ul>
Роботов pyOpenRPA невозможно отключить принудительно - управлять ими будете только вы!
<br><br>
Здесь представлены примеры роботов для таких специалистов как:
<ul>
<li>Экономистов</li>
<li>Финансистов</li>
<li>Продавцов</li>
<li>Закупщиков</li>
<li>Маркетологов</li>
<li>Кадровиков</li>
<li>Рекрутёров</li>
<li>Казначеев</li>
<li>Юристов</li>
<li>Бухгалтеров</li>
<li>Операционистов</li>
<li>Безопасников</li>
<li>ИТ специалистов</li>
</ul>
<h5>pyOpenRPA - роботы помогут!</h5>
</div>
</div>
<br>
<center>
<button class="ui primary basic button cp-hello-button-1">Свернуть</button>
</center>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
cp_hello_expand=function() {
$("button.cp-hello-button-1")[0].innerHTML="СВЕРНУТЬ ПРИВЕТСТВИЕ"
$("button.cp-hello-button-1")[0].setAttribute("onclick","cp_hello_collapse();")
$("div.cp-hello-description")[0].style["display"]=""
}
cp_hello_collapse=function() {
$("button.cp-hello-button-1")[0].innerHTML="РАЗВЕРНУТЬ ПРИВЕТСТВИЕ"
$("button.cp-hello-button-1")[0].setAttribute("onclick","cp_hello_expand();")
$("div.cp-hello-description")[0].style["display"]="none"
}
cp_hello_expand();
});
</script>

@ -1,4 +0,0 @@
$(document).ready(function() {
$('#test8-progress').progress();
});

@ -1,3 +0,0 @@
Ник;Полное имя;Логика;Язык;Время(мин);Решение
@floidd;Влад Клычков;5;9;0;Отказ
@floidd;Влад Клычков;8;8;0;Отказ
1 Ник Полное имя Логика Язык Время(мин) Решение
2 @floidd Влад Клычков 5 9 0 Отказ
3 @floidd Влад Клычков 8 8 0 Отказ

@ -1,39 +0,0 @@
Button {
color: white;
background: rgb(82, 105, 95);
border-radius: 5px;
border-color: #FFFFFF #FFFFFF #FFFFFF;
border-width: 2px 2px;
padding: .5em 2em;
cursor: pointer;
}
Button:hover { background: rgb(53, 167, 110); }
i#first {
position: absolute;
top: 280px;
left: 135px;
}
i#second {
position: absolute;
top: 340px;
left: 135px;
}
h4 {
width: 100%;
text-align: center;
border-bottom: 5px solid teal;
line-height: 0.1em;
margin: 10px 0 20px;
}
h4 span {
background:#fff;
padding:0 7px;
}

@ -1,74 +0,0 @@
$('.ui.selection.dropdown')
.dropdown("clear")
;
var switchFlag = "1,";
document.getElementById("Vacancy1Status").innerHTML = "Робот на вакансию 1 оффлайн"
document.getElementById("Vacancy2Status").innerHTML = "Робот на вакансию 2 оффлайн"
var btn1 = document.createElement("Button")
btn1.innerHTML = "Старт"
btn1.onclick = function() {
if (switchFlag == "1,"){
document.getElementById("Vacancy1Status").innerHTML = "Робот на вакансию 1 онлайн"
}
else {
document.getElementById("Vacancy2Status").innerHTML = "Робот на вакансию 2 онлайн"
}
}
var btn2 = document.createElement("Button")
btn2.innerHTML = "Стоп"
btn2.onclick = function() {
if (switchFlag == "1,"){
document.getElementById("Vacancy1Status").innerHTML = "Робот на вакансию 1 оффлайн"
}
else {
document.getElementById("Vacancy2Status").innerHTML = "Робот на вакансию 2 оффлайн"
}
}
function get_data(i)
{
var link = document.createElement('a');
if (i == 'question') {
link.setAttribute('href', '/HR_officer01/questions');
link.setAttribute('download', 'Questions.csv');
link.click();
} else if (i == "results") {
link.setAttribute('href', '/HR_officer01/results');
link.setAttribute('download', 'All_results.csv');
link.click();
} else if (i == "logs"){
link.setAttribute('href', '/HR_officer01/logs');
link.setAttribute('download', 'log.txt');
link.click();
}
return false;
}
function bot_change() {
switchFlag = $('.ui.selection.dropdown').dropdown("get value")
if ($('.ui.selection.dropdown').dropdown("get value") == "1,") {
document.getElementById("conteiner").appendChild(btn1)
document.getElementById("conteiner").appendChild(btn2)
}
else if ($('.ui.selection.dropdown').dropdown("get value") == "0,"){
document.getElementById("conteiner").appendChild(btn1)
document.getElementById("conteiner").appendChild(btn2)
}
}

@ -1,31 +0,0 @@
Вопрос;Ответ1 ;Ответ2;Ответ3;Ответ4;Правильный ответ
Шмурдик боится как мышей, так и тараканов;Шмурдик не боится тараканов;Шмурдик боится мышей;Шмурдик боится мышей больше, чем тараканов, но и тараканов боится тоже;;2
Известно, что грымзик обязательно или полосат, или рогат, или то и другое вместе;Грымзик не может быть однотонным и безрогим одновременно;Грымзик не может быть безрогим;Грымзик не может быть полосатым и безрогим одновременно;;1
Если запырку отравить, то она сразу начнет пускать пузыри;Если запырка пускает пузыри, то она была отравлена;Если запырку не отравить, то она не будет пускать пузыри;Если запырка не пускает пузыри, то она не отравлена;;3
Все охлотушки умеют играть в шашки;Не бывает охлотушек, которые не умеют играть в шашки;Все, кто умеет играть в шашки, являются охлотушками;Не бывает охлотушек, которые умеют играть в шашки;;1
Дубараторы бывают либо хорошими, либо плохими\. Неправда, что этот дубаратор не плохой;Этот дубаратор хороший;Этот дубаратор средненький;Этот дубаратор плохой;;3
В природе обнаружено более десятка тиалей\. Все обнаруженные тиали сплошь красного цвета;По крайней мере некоторые из тиалей красного цвета;По крайней мере некоторые из тиалей зеленые;Некоторые тиали \(из тех, что уже обнаружены\) могут оказаться не красными;;1
Существуют шакалы с больной мухропендией\. Мухропендия может быть, или больной, или здоровой;Не всякий шакал может похвастаться здоровой мухропендией;У некоторых шакалов мухропендия нездоровая;Существуют шакалы со здоровой мухропендией;;2
Неправда, что наша тумельница большая и круглая;Наша тумельница маленькая и некруглая;Наша тумельница маленькая, или некруглая, или то и другое вместе;Наша тумельница маленькая, или некруглая, но не то и другое вместе;;2
Джон всегда либо урдит, либо мурлит;Джон иногда урдит и мурлит;Джон иногда урдит, иногда мурлит, а иногда не мурлит;Джон никогда не занимается одновременно и урдением, и мурлением;;3
Журналисты наврали, что бздыш болотный безграмотен и нахален;На самом деле бздыш болотный образован и тактичен;На самом деле бздыш болотный безграмотен, но не нахален;Те журналисты солгали;;3
Если тряхнуть перпелькой, то немедленно начнется стрельба\. За последний час стрельбы не было;В течении последнего часа перпелькой не трясли;В течении последнего часа перпелькой трясли;А нечего было трясти чем попало;;1
Огромный бутряк напугал деревенского старосту;Старосте приснился ночной кошмар;Староста попробовал некачественной выпивки;Староста был напуган;;3
Если почесать угубку за ухом, он начнет довольно шипеть\. Если угубок довольно зашипит, то молоко поблизости скиснет;Если не чесать угубка за ухом, то молоко поблизости не скиснет;Если почесать угубка за ухом, молоко поблизости скиснет;Молоко вдалеке никогда не скисает от чесания угубков;;2
Всех, кто громко обуривает, обязательно съедают\. Все ухмырки постоянно громко обуривают;Все, кто громко обуривает \- ухмырки;Всех ухмырков обязательно съедают;Некоторых ухмырков не съедают;;2
В реках близ Тимуграда обитает и вобла, и щука;В реках близ Тимуграда не бывает воблы;В реках близ Тимуграда обитает щука;В реках близ Тимуграда обитает только вобла и щука;;2
Выберите верное утверждение;Бизнес\-процесс ничем не отличается от алгоритма;Бизнес\-процесс является агрегацией алгоритмов;Алгоритм является агерацией бизнес\-процессов;;2
Выберите верное утверждение;Задача и цель \- это синонимы;"Задача, чтобы задавать\; Цель, чтобы целиться";Цель \- это итоговая метрика, задача \- это действие, которое направлено на достижение цели;;3
Как правильно произносится\?;пАйтон;пайтОн;питОн;пифОн;1
Что является операндом в выражении\: x \= 6 \* 8 \/ y;x,y,6,8;\=,\*,\/;6,8,\*;6,8,y,\=;1
Как определяется working directory при запуске процесса\?;По расположению запускаемого файла;По местонахождению папки с исходными кодами;По текущему установленному пути оболочки Shell\/cmd, из под которой происходит запуск;;3
Список является массивом\?;Да;Нет;;;2
Какое отличие между str и bytes\?;Отличий нет \- типы являются синонимами;Str является декодированным представлением bytes;Str является енкодированным представлением bytes;;2
Какая операция в GIT отвечает за скачивание перечня ревизий с сервера\?;git push;git pull;git fetch;;3
Какое отличие между многопроцессными и многопроцессорными вычислениями\?;Отличий нет;В многопроцессных вычислениях может использоваться только 1 процессор, а в многопроцессорных вычислениях всегда может использоваться от 2\-х и более процессоров;В многопроцессорных вычислениях может использоваться только 1 процессор, а в многопроцессных вычислениях может использоваться от 2\-х и более процессоров;;2
Что является эквивалентом выражения\: \(X and Y\) or \(Z and Y\);not X and not Y and not Z;\(not X or not Y\) and \(not Z or not Y\);\(X and Y\) or \(X and Y\);not \(not X or not Y\) or not \(not Z or not Y\);4
Какое число в десятичной системе счисления является образом числа 11 в пятиричной системе счисления\?;3;11;6;7;3
Укажите корректное определение для SQL иснтрукции: SELECT \* FROM T1 INNER JOIN T2 ON T1\.ID \=\= T2\.T1\_ID;Выбрать все строки из таблицы T1;Выбрать все строки из таблицы T1, по связке с которыми имеется строка в T2;Выбрать все строки из таблицы T1 и показать строки из таблицы T2, если по ним имеется связь с T1;Выбрать все строки из таблицы T2 и показать строки из таблицы T1, если по ним имеется связь с T2;2
Что делает команда SQL\: DELETE\?;Удаляет таблицу из БД;Чистит строки внутри таблицы;;;2
Чем отличается относительный путь от абсолютного\?;Нет разницы \- оба пути указывают на один и тот же файл;Абсолютный путь в любом окружении будет указывать на один и тот же файл\. Относительный \- нет;Относительный путь в любом окружении будет указывать на один и тот же файл\. Абсолютный \- нет;;2
Можно ли из ветки except повторно сгенерировать то же самое исключение exception \(тот же самый экземпляр\)\?;Нет \- исключение уже было сформировано, повторно его вызвать будет невозможно;Да \- исключение уже было сформировано, но его можно будет вызвать повторно;Наверное \- не понимаю как работает try \.\. Except;;2
1 Вопрос Ответ1 Ответ2 Ответ3 Ответ4 Правильный ответ
2 Шмурдик боится как мышей, так и тараканов Шмурдик не боится тараканов Шмурдик боится мышей Шмурдик боится мышей больше, чем тараканов, но и тараканов боится тоже 2
3 Известно, что грымзик обязательно или полосат, или рогат, или то и другое вместе Грымзик не может быть однотонным и безрогим одновременно Грымзик не может быть безрогим Грымзик не может быть полосатым и безрогим одновременно 1
4 Если запырку отравить, то она сразу начнет пускать пузыри Если запырка пускает пузыри, то она была отравлена Если запырку не отравить, то она не будет пускать пузыри Если запырка не пускает пузыри, то она не отравлена 3
5 Все охлотушки умеют играть в шашки Не бывает охлотушек, которые не умеют играть в шашки Все, кто умеет играть в шашки, являются охлотушками Не бывает охлотушек, которые умеют играть в шашки 1
6 Дубараторы бывают либо хорошими, либо плохими\. Неправда, что этот дубаратор не плохой Этот дубаратор хороший Этот дубаратор средненький Этот дубаратор плохой 3
7 В природе обнаружено более десятка тиалей\. Все обнаруженные тиали сплошь красного цвета По крайней мере некоторые из тиалей красного цвета По крайней мере некоторые из тиалей зеленые Некоторые тиали \(из тех, что уже обнаружены\) могут оказаться не красными 1
8 Существуют шакалы с больной мухропендией\. Мухропендия может быть, или больной, или здоровой Не всякий шакал может похвастаться здоровой мухропендией У некоторых шакалов мухропендия нездоровая Существуют шакалы со здоровой мухропендией 2
9 Неправда, что наша тумельница большая и круглая Наша тумельница маленькая и некруглая Наша тумельница маленькая, или некруглая, или то и другое вместе Наша тумельница маленькая, или некруглая, но не то и другое вместе 2
10 Джон всегда либо урдит, либо мурлит Джон иногда урдит и мурлит Джон иногда урдит, иногда мурлит, а иногда не мурлит Джон никогда не занимается одновременно и урдением, и мурлением 3
11 Журналисты наврали, что бздыш болотный безграмотен и нахален На самом деле бздыш болотный образован и тактичен На самом деле бздыш болотный безграмотен, но не нахален Те журналисты солгали 3
12 Если тряхнуть перпелькой, то немедленно начнется стрельба\. За последний час стрельбы не было В течении последнего часа перпелькой не трясли В течении последнего часа перпелькой трясли А нечего было трясти чем попало 1
13 Огромный бутряк напугал деревенского старосту Старосте приснился ночной кошмар Староста попробовал некачественной выпивки Староста был напуган 3
14 Если почесать угубку за ухом, он начнет довольно шипеть\. Если угубок довольно зашипит, то молоко поблизости скиснет Если не чесать угубка за ухом, то молоко поблизости не скиснет Если почесать угубка за ухом, молоко поблизости скиснет Молоко вдалеке никогда не скисает от чесания угубков 2
15 Всех, кто громко обуривает, обязательно съедают\. Все ухмырки постоянно громко обуривают Все, кто громко обуривает \- ухмырки Всех ухмырков обязательно съедают Некоторых ухмырков не съедают 2
16 В реках близ Тимуграда обитает и вобла, и щука В реках близ Тимуграда не бывает воблы В реках близ Тимуграда обитает щука В реках близ Тимуграда обитает только вобла и щука 2
17 Выберите верное утверждение Бизнес\-процесс ничем не отличается от алгоритма Бизнес\-процесс является агрегацией алгоритмов Алгоритм является агерацией бизнес\-процессов 2
18 Выберите верное утверждение Задача и цель \- это синонимы Задача, чтобы задавать\; Цель, чтобы целиться Цель \- это итоговая метрика, задача \- это действие, которое направлено на достижение цели 3
19 Как правильно произносится\? пАйтон пайтОн питОн пифОн 1
20 Что является операндом в выражении\: x \= 6 \* 8 \/ y x,y,6,8 \=,\*,\/ 6,8,\* 6,8,y,\= 1
21 Как определяется working directory при запуске процесса\? По расположению запускаемого файла По местонахождению папки с исходными кодами По текущему установленному пути оболочки Shell\/cmd, из под которой происходит запуск 3
22 Список является массивом\? Да Нет 2
23 Какое отличие между str и bytes\? Отличий нет \- типы являются синонимами Str является декодированным представлением bytes Str является енкодированным представлением bytes 2
24 Какая операция в GIT отвечает за скачивание перечня ревизий с сервера\? git push git pull git fetch 3
25 Какое отличие между многопроцессными и многопроцессорными вычислениями\? Отличий нет В многопроцессных вычислениях может использоваться только 1 процессор, а в многопроцессорных вычислениях всегда может использоваться от 2\-х и более процессоров В многопроцессорных вычислениях может использоваться только 1 процессор, а в многопроцессных вычислениях может использоваться от 2\-х и более процессоров 2
26 Что является эквивалентом выражения\: \(X and Y\) or \(Z and Y\) not X and not Y and not Z \(not X or not Y\) and \(not Z or not Y\) \(X and Y\) or \(X and Y\) not \(not X or not Y\) or not \(not Z or not Y\) 4
27 Какое число в десятичной системе счисления является образом числа 11 в пятиричной системе счисления\? 3 11 6 7 3
28 Укажите корректное определение для SQL иснтрукции: SELECT \* FROM T1 INNER JOIN T2 ON T1\.ID \=\= T2\.T1\_ID Выбрать все строки из таблицы T1 Выбрать все строки из таблицы T1, по связке с которыми имеется строка в T2 Выбрать все строки из таблицы T1 и показать строки из таблицы T2, если по ним имеется связь с T1 Выбрать все строки из таблицы T2 и показать строки из таблицы T1, если по ним имеется связь с T2 2
29 Что делает команда SQL\: DELETE\? Удаляет таблицу из БД Чистит строки внутри таблицы 2
30 Чем отличается относительный путь от абсолютного\? Нет разницы \- оба пути указывают на один и тот же файл Абсолютный путь в любом окружении будет указывать на один и тот же файл\. Относительный \- нет Относительный путь в любом окружении будет указывать на один и тот же файл\. Абсолютный \- нет 2
31 Можно ли из ветки except повторно сгенерировать то же самое исключение exception \(тот же самый экземпляр\)\? Нет \- исключение уже было сформировано, повторно его вызвать будет невозможно Да \- исключение уже было сформировано, но его можно будет вызвать повторно Наверное \- не понимаю как работает try \.\. Except 2

@ -1,206 +0,0 @@
import time
time.sleep(1)
splitter1 = 'Рабочий процесс'
splitter2 = 'Пример доступных данных'
splitter3 = 'Пример запуска роботов'
title = 'КАДРОВИК'
introHeader = 'Применение:'
introText = 'Робот-кадровик помогает проводить отбор кандидатов'
workflowHeader1 = 'Шаг 1: Размещение вакансии'
workflowDescription1 = 'Выполняет человек'
workflowHint1 = 'Размещение вакансии в telegram/HH.ru'
workflowHeader2 = 'Шаг 2: Тестирование'
workflowDescription2 = 'Выполняет робот'
workflowHint2 = 'Автоматическое тестирования кандидатов'
workflowHeader3 = 'Шаг 3: Подведение итогов'
workflowDescription3 = 'Выполняет робот'
workflowHint3 = 'Автоматическое подведение итогов тестирования'
workflowHeader4 = 'Шаг 4: Личное собеседование'
workflowDescription4 = 'Выполняет человек'
workflowHint4 = 'Собеседование с лучшими кандидатами'
workflowHeader5 = 'Шаг 5: Оформление будущего сотрудника'
workflowDescription5 = 'Выполняет человек'
workflowHint5 = 'Подписание трудового договора'
questionHeaderMsg = 'Вопросы'
questionDescriptionMsg = 'Список вопросов для первого этапа'
resultHeaderMsg = 'Результаты'
resultDescriptionMsg = 'Сводка по всем рекрутам'
logHeaderMsg = 'Лог'
logDescriptionMsg = 'Лог за текущие сутки'
dropdownInit = 'Выберите робота...'
dropdownRobot1 = 'Робот на вакансию 1'
dropdownRobot2 = 'Робот на вакансию 2'
html = f'''<!doctype html>
<html lang="en">
<head>
<title> Test </title>
<link rel="stylesheet" href="/HR_01/styles">
</head>
<body>
<div class="card" style="width:450px;" id="card1">
<div class="content">
<center><h1>{title}</h1></center><br>
<div class="ui message">
<div class="header">{introHeader}</div>
<p>{introText}</p>
</div>
<h4><span>{splitter1}</span></h4>
<div class="ui relaxed divided list">
<div class="item">
<i class="user icon"></i>
<div class="content">
<div class="header" data-tooltip="{workflowHint1}">{workflowHeader1}</div>
<div class="description">{workflowDescription1}</div>
</div>
</div>
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="{workflowHint2}">{workflowHeader2}</div>
<div class="description">{workflowDescription2}</div>
</div>
</div>
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="{workflowHint3}">{workflowHeader3}</div>
<div class="description">{workflowDescription3}</div>
</div>
</div>
<div class="item">
<i class="user icon"></i>
<div class="content">
<div class="header" data-tooltip="{workflowHint4}">{workflowHeader4}</div>
<div class="description">{workflowDescription4}</div>
</div>
</div>
<div class="item">
<i class="user icon"></i>
<div class="content">
<div class="header" data-tooltip="{workflowHint5}">{workflowHeader5}</div>
<div class="description">{workflowDescription5}</div>
</div>
</div>
</div>
<h4><span>{splitter2}</span></h4>
<div class="ui list">
<div class="item">
<i class="file icon"></i>
<div class="content">
<a class="header" onclick="get_data('question')">{questionHeaderMsg}</a>
<div class="description">{questionDescriptionMsg}</div>
</div>
</div>
<div class="item">
<i class="adress book icon"></i>
<div class="content">
<a class="header" onclick="get_data('results')">{resultHeaderMsg}</a>
<div class="description">{resultDescriptionMsg}</div>
</div>
</div>
<div class="item">
<i class="file alternate icon"></i>
<div class="content">
<a class="header" onclick="get_data('logs')">{logHeaderMsg}</a>
<div class="description">{logDescriptionMsg}</div>
</div>
</div>
</div>
<h4><span>{splitter3}</span></h4>
<div class="ui list">
<div class="item">
<i class="telegram icon"></i>
<div id="Vacancy1Status" class="content"></div>
</div>
<div class="item">
<i class="telegram icon"></i>
<div id="Vacancy2Status" class="content"></div>
</div>
</div>
<div class="ui selection dropdown" onchange="bot_change()">
<input type="hidden" name="bot">
<i class="dropdown icon"></i>
<div class="default text">{dropdownInit}</div>
<div class="menu">
<div class="item" data-value="1">{dropdownRobot1}</div>
<div class="item" data-value="0">{dropdownRobot2}</div>
</div>
</div>
<p><div id="conteiner"></div></p>
</div>
</div>
<script src="/HR_01/scripts"></script>
<script type="text/javascript" src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>
</body>
</html>'''
from pyOpenRPA.Tools import CrossOS
from pyOpenRPA import Orchestrator # Import orchestrator main
from pyOpenRPA.Orchestrator.Server import app
import threading
from fastapi import Depends
from fastapi.responses import PlainTextResponse
from fastapi.responses import FileResponse
# Подключени файлов связанных с роботом-кадровиком01
@app.get(path="/HR_01/questions",tags=["HR_01"])
def get_file():
return FileResponse(CrossOS.PathStr("Demo\\HR_01\\Questions.csv"))
@app.get(path="/HR_01/results",tags=["HR_01"])
def get_file():
return FileResponse(CrossOS.PathStr("Demo\\HR_01\\All_results.csv"))
@app.get(path="/HR_01/logs",tags=["HR_01"])
def get_file():
return FileResponse(CrossOS.PathStr("Demo\\HR_01\\log.txt"))
@app.get(path="/HR_01/scripts",tags=["HR_01"])
def get_file():
return FileResponse(CrossOS.PathStr("Demo\\HR_01\\HR_officer01.js"))
@app.get(path="/HR_01/styles",tags=["HR_01"])
def get_file():
return FileResponse(CrossOS.PathStr("Demo\\HR_01\\HR_officer01.css"))
lCPManager = Orchestrator.Managers.ControlPanel(inControlPanelNameStr="HR_officer01ControlPanel",
inRefreshHTMLJinja2TemplatePathStr=CrossOS.PathStr("Demo\\HR_01\\index.html"), inJinja2TemplateRefreshBool = True)
with open(CrossOS.PathStr("Demo\\HR_01\\index.html"), 'w', encoding='UTF-8') as file:
file.write(html)

@ -1,125 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title> Test </title>
<link rel="stylesheet" href="/HR_01/styles">
</head>
<body>
<div class="card" style="width:450px;" id="card1">
<div class="content">
<center><h1>КАДРОВИК</h1></center><br>
<div class="ui message">
<div class="header">Применение:</div>
<p>Робот-кадровик помогает проводить отбор кандидатов</p>
</div>
<h4><span>Рабочий процесс</span></h4>
<div class="ui relaxed divided list">
<div class="item">
<i class="user icon"></i>
<div class="content">
<div class="header" data-tooltip="Размещение вакансии в telegram/HH.ru">Шаг 1: Размещение вакансии</div>
<div class="description">Выполняет человек</div>
</div>
</div>
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="Автоматическое тестирования кандидатов">Шаг 2: Тестирование</div>
<div class="description">Выполняет робот</div>
</div>
</div>
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="Автоматическое подведение итогов тестирования">Шаг 3: Подведение итогов</div>
<div class="description">Выполняет робот</div>
</div>
</div>
<div class="item">
<i class="user icon"></i>
<div class="content">
<div class="header" data-tooltip="Собеседование с лучшими кандидатами">Шаг 4: Личное собеседование</div>
<div class="description">Выполняет человек</div>
</div>
</div>
<div class="item">
<i class="user icon"></i>
<div class="content">
<div class="header" data-tooltip="Подписание трудового договора">Шаг 5: Оформление будущего сотрудника</div>
<div class="description">Выполняет человек</div>
</div>
</div>
</div>
<h4><span>Пример доступных данных</span></h4>
<div class="ui list">
<div class="item">
<i class="file icon"></i>
<div class="content">
<a class="header" onclick="get_data('question')">Вопросы</a>
<div class="description">Список вопросов для первого этапа</div>
</div>
</div>
<div class="item">
<i class="adress book icon"></i>
<div class="content">
<a class="header" onclick="get_data('results')">Результаты</a>
<div class="description">Сводка по всем рекрутам</div>
</div>
</div>
<div class="item">
<i class="file alternate icon"></i>
<div class="content">
<a class="header" onclick="get_data('logs')">Лог</a>
<div class="description">Лог за текущие сутки</div>
</div>
</div>
</div>
<h4><span>Пример запуска роботов</span></h4>
<div class="ui list">
<div class="item">
<i class="telegram icon"></i>
<div id="Vacancy1Status" class="content"></div>
</div>
<div class="item">
<i class="telegram icon"></i>
<div id="Vacancy2Status" class="content"></div>
</div>
</div>
<div class="ui selection dropdown" onchange="bot_change()">
<input type="hidden" name="bot">
<i class="dropdown icon"></i>
<div class="default text">Выберите робота...</div>
<div class="menu">
<div class="item" data-value="1">Робот на вакансию 1</div>
<div class="item" data-value="0">Робот на вакансию 2</div>
</div>
</div>
<p><div id="conteiner"></div></p>
</div>
</div>
<script src="/HR_01/scripts"></script>
<script type="text/javascript" src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>
</body>
</html>

@ -1,31 +0,0 @@
from pyOpenRPA import Orchestrator
from pyOpenRPA.Orchestrator.Managers import ControlPanel
from pyOpenRPA.Orchestrator.Managers import Process
from pyOpenRPA.Tools import CrossOS
import os
import sys
import socket
import datetime
import urllib.parse
import time
g_cp_name_str = "CP_JUPYTER"
g_repo_name_str = os.path.abspath(__file__).split("\\")[-5]
g_repo_package_path_str = os.path.abspath("\\".join(os.path.abspath(__file__).split("\\")[:-1]))
#g_repo_package_path_str = os.path.join(g_repo_path_str, "Orchestrator","Demo","JUPITER_01")
#g_repo_package_path_str = os.path.join(g_repo_package_path_str, g_cp_name_str)
# User settings
g_host_str = socket.gethostname().upper() # Identify PC
time.sleep(2)
g_control_panel = ControlPanel(inControlPanelNameStr=g_cp_name_str,
inRefreshHTMLJinja2TemplatePathStr=os.path.join(g_repo_package_path_str, "html_jinja2.xhtml"),
inJinja2TemplateRefreshBool=True,inRobotNameStr=g_repo_name_str)
g_jinja_context_dict = {"settings": sys.modules[__name__],
"urllib_parse_quote_plus": urllib.parse.quote_plus, "g_host_str": g_host_str, "g_repo_name_str": g_repo_name_str}
g_control_panel.Jinja2DataUpdateDictSet(inJinja2DataUpdateDict=g_jinja_context_dict)
g_control_panel.InitJSJinja2TemplatePathSet(inJinja2TemplatePathStr=os.path.join(g_repo_package_path_str, "js.js"))

@ -1,33 +0,0 @@
<div class="card" style=""">
<div class="content">
<div class="right floated mini ui ">
{{settings.g_cp_name_str}}
</div>
<div class="header">
ИТ - JUPYTER
</div>
<div class="ui divider"></div>
<div class="meta">
<div>Рабочая область PYTHON JUPYTER. <br> Сотрудник: {{UserInfoDict["UserNameUpperStr"]}}</div>
<div class="ui divider"></div>
<div class="description">
<button class="massive ui button" >
Открыть в новой вкладке
</button>
</div>
</div>
<div class="extra content">
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
});
</script>

@ -1,4 +0,0 @@
$(document).ready(function() {
$('#test8-progress').progress();
});

@ -1,23 +0,0 @@
from pyOpenRPA import Orchestrator
from pyOpenRPA.Orchestrator.Managers import ControlPanel
import time
import os
import sys
import socket
import datetime
import urllib.parse
time.sleep(1.5)
g_cp_name_str = "OPER_00"
g_repo_name_str = os.path.abspath(__file__).split("\\")[-5]
g_repo_package_cp_path_str = os.path.abspath("\\".join(os.path.abspath(__file__).split("\\")[:-1]))
# User settings
g_host_str = socket.gethostname().upper() # Identify PC
g_control_panel = ControlPanel(inControlPanelNameStr=g_cp_name_str,
inRefreshHTMLJinja2TemplatePathStr=os.path.join(g_repo_package_cp_path_str, "html_jinja2.xhtml"),
inJinja2TemplateRefreshBool=True,inRobotNameStr=g_repo_name_str)
g_jinja_context_dict = {"settings": sys.modules[__name__],
"urllib_parse_quote_plus": urllib.parse.quote_plus, "g_host_str": g_host_str, "g_repo_name_str": g_repo_name_str}
g_control_panel.Jinja2DataUpdateDictSet(inJinja2DataUpdateDict=g_jinja_context_dict)

@ -1,85 +0,0 @@
<div class="card" style="width: 450px;"">
<div class="content">
<div class="right floated mini ui ">
OPER_00
</div>
<div class="header">
ОПЕРАЦИОНИСТ
</div>
<div class="meta">
<div>Робот бухгалтер.</div>
Сотрудник: {{UserInfoDict["UserNameUpperStr"]}}
</div>
<div class="ui divider"></div>
<div class="description">
<span style="font-weight: bold;">Статус за 05.04.2022:</span>
<div class="ui vertical fluid steps">
<div class="completed step">
<i class="arrow circle right card icon"></i>
<div class="content">
<div class="title">Шаг 1: Выгрузка</div>
<div class="description">Ежедневно в 08:22 (STARTED)</div>
</div>
</div>
<div class="active step">
<i class="arrow circle right card icon"></i>
<div class="content">
<div class="title">Шаг 2: Опрос</div>
<div class="description">Производить до 12:00</div>
</div>
</div>
<div class="step">
<i class="hourglass half card icon"></i>
<div class="content">
<div class="title">Шаг 3: Отчет</div>
<div class="description">Отправка вручную в период с 12:00 до 12:30</div>
</div>
</div>
</div>
<div class="ui divider"></div>
<div class="ui placeholder">
<div class="image header">
<div class="line"></div>
<div class="line"></div>
</div>
<div class="paragraph">
<div class="line"></div>
<div class="line"></div>
<div class="line"></div>
<div class="line"></div>
<div class="line"></div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$('.ui.accordion.per').accordion();
per_log_download = function () {
var l_now = new Date();
l_month_str = String(l_now.getMonth()+1)
if (l_month_str.length == 1){ l_month_str = "0"+l_month_str }
l_day_str = String(l_now.getDate())
if (l_day_str.length == 1){ l_day_str = "0"+l_day_str }
l_log_date_str = String(l_now.getFullYear())+"_"+l_month_str+"_"+l_day_str
l_log_date_str = window.prompt("Укажите дату лог файла для скачивания (формат: гггг_мм_дд)", l_log_date_str);
if (l_log_date_str != null) {
l_url_str = "/logs/"+l_log_date_str+".log"
window.open(l_url_str, '_blank');
}
}
</script>

@ -1,207 +0,0 @@
import time
time.sleep(1)
splitter1 = 'Рабочий процесс'
splitter2 = 'Окно настройки робота'
title = 'КАЗНАЧЕЙ'
introHeader = 'Применение:'
introText = 'Робот-казначей выполняет выгрузку банковских выписок'
workflowHeader1 = 'Шаг 1: Авторизация в клиент-банке'
workflowDescription1 = 'Выполняет робот'
workflowHint1 = 'Авторизация на сайте банка'
workflowHeader2 = 'Шаг 2: Выгрузка выписок'
workflowDescription2 = 'Выполняет робот'
workflowHint2 = 'Скачивание выписок с сайта банка'
workflowHeader3 = 'Шаг 3: Перенаправление выписок'
workflowDescription3 = 'Выполняет робот'
workflowHint3 = 'Например, размещение в сетевой папке'
dropBankTitle = 'Выберите банк...'
dropBank1 = 'Сбербанк'
dropBank2 = 'ВТБ'
dropBank3 = 'Альфа'
dropBankAccountTitle = 'Выберите счет'
dropBankAccount1 = 'Счет 1'
dropBankAccount2 = 'Счет 2'
dropBankAccount3 = 'Счет 3'
dropBankAccountAll = 'Счет XY'
checkboxPerTitle = 'Период:'
checkboxPer1 = 'За день'
checkboxPer2 = 'За месяц'
checkboxFormTitle = ''
checkboxForm1 = 'PDF'
checkboxForm2 = '1C'
checkboxForm3 = 'WORD'
checkboxForm4 = 'EXCEL'
emailTitle = 'Укажите почту (необязательно):'
emailWindow = 'example@mail.ru'
btnDownload = 'Скачать'
btnEmail = 'Отправить'
html = f'''<!doctype html>
<html lang="en">
<head>
<title> Treasurer </title>
</head>
<body>
<div class="card" style="width:450px;" id="card1">
<div class="content">
<center><h1>{title}</h1></center><br>
<div class="ui message">
<div class="header">{introHeader}</div>
<p>{introText}</p>
</div>
<h4><span>{splitter1}</span></h4>
<div class="ui relaxed divided list">
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="{workflowHint1}">{workflowHeader1}</div>
<div class="description">{workflowDescription1}</div>
</div>
</div>
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="{workflowHint2}">{workflowHeader2}</div>
<div class="description">{workflowDescription2}</div>
</div>
</div>
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="{workflowHint3}">{workflowHeader3}</div>
<div class="description">{workflowDescription3}</div>
</div>
</div>
</div>
<h4><span>{splitter2}</span></h4>
<div class="ui selection dropdown">
<input type="hidden" name="bank">
<i class="dropdown icon"></i>
<div class="default text">{dropBankTitle}</div>
<div class="menu">
<div class="item" data-value="2">{dropBank1}</div>
<div class="item" data-value="1">{dropBank2}</div>
<div class="item" data-value="0">{dropBank3}</div>
</div>
</div><br><br>
<select class="ui fluid search dropdown" style="font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif" multiple="">
<option value="">{dropBankAccountTitle}</option>
<option value="All">{dropBankAccountAll}</option>
<option value="Ch1">{dropBankAccount1}</option>
<option value="Ch2">{dropBankAccount2}</option>
<option value="Ch3">{dropBankAccount3}</option>
</select><br>
<div class="ui form">
<div class="inline fields">
<label>{checkboxPerTitle}</label>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="time">
<label>{checkboxPer1}</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="time">
<label>{checkboxPer2}</label>
</div>
</div>
</div>
</div>
<div class="ui form">
<div class="inline fields">
<label>{checkboxFormTitle}</label>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="format">
<label>{checkboxForm1}</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="format">
<label>{checkboxForm2}</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="format">
<label>{checkboxForm3}</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="format">
<label>{checkboxForm4}</label>
</div>
</div>
</div>
</div>
<div><b>{emailTitle}</b></div>
<p><div class="ui input focus">
<input type="text" placeholder="{emailWindow}">
</div></p>
<button class="ui right labeled icon button"><i class="download icon"></i> {btnDownload} </button>
<button class="ui right labeled icon button"><i class="envelope icon"></i> {btnEmail} </button>
</div>
</div>
<script src="/TREASURER_01/scripts"></script>
</body>
</html>'''
from pyOpenRPA.Tools import CrossOS
from pyOpenRPA import Orchestrator # Import orchestrator main
from pyOpenRPA.Orchestrator.Server import app
import threading
from fastapi import Depends
from fastapi.responses import PlainTextResponse
from fastapi.responses import FileResponse
# Подключени файлов связанных с роботом-казначеем01
@app.get(path="/TREASURER_01/scripts",tags=["TREASURER_01"])
def get_file():
return FileResponse("Demo\\TREASURER_01\\Treasurer01.js")
lCPManager = Orchestrator.Managers.ControlPanel(inControlPanelNameStr="Treasurer01ControlPanel",
inRefreshHTMLJinja2TemplatePathStr=CrossOS.PathStr("Demo\\TREASURER_01\\index.html"), inJinja2TemplateRefreshBool = True)
with open("Demo\\TREASURER_01\\index.html", 'w', encoding='UTF-8') as file:
file.write(html)

@ -1,135 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title> Treasurer </title>
</head>
<body>
<div class="card" style="width:450px;" id="card1">
<div class="content">
<center><h1>КАЗНАЧЕЙ</h1></center><br>
<div class="ui message">
<div class="header">Применение:</div>
<p>Робот-казначей выполняет выгрузку банковских выписок</p>
</div>
<h4><span>Рабочий процесс</span></h4>
<div class="ui relaxed divided list">
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="Авторизация на сайте банка">Шаг 1: Авторизация в клиент-банке</div>
<div class="description">Выполняет робот</div>
</div>
</div>
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="Скачивание выписок с сайта банка">Шаг 2: Выгрузка выписок</div>
<div class="description">Выполняет робот</div>
</div>
</div>
<div class="item">
<i class="reddit alien icon"></i>
<div class="content">
<div class="header" data-tooltip="Например, размещение в сетевой папке">Шаг 3: Перенаправление выписок</div>
<div class="description">Выполняет робот</div>
</div>
</div>
</div>
<h4><span>Окно настройки робота</span></h4>
<div class="ui selection dropdown">
<input type="hidden" name="bank">
<i class="dropdown icon"></i>
<div class="default text">Выберите банк...</div>
<div class="menu">
<div class="item" data-value="2">Сбербанк</div>
<div class="item" data-value="1">ВТБ</div>
<div class="item" data-value="0">Альфа</div>
</div>
</div><br><br>
<select class="ui fluid search dropdown" style="font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif" multiple="">
<option value="">Выберите счет</option>
<option value="All">Счет XY</option>
<option value="Ch1">Счет 1</option>
<option value="Ch2">Счет 2</option>
<option value="Ch3">Счет 3</option>
</select><br>
<div class="ui form">
<div class="inline fields">
<label>Период:</label>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="time">
<label>За день</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="time">
<label>За месяц</label>
</div>
</div>
</div>
</div>
<div class="ui form">
<div class="inline fields">
<label></label>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="format">
<label>PDF</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="format">
<label>1C</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="format">
<label>WORD</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="format">
<label>EXCEL</label>
</div>
</div>
</div>
</div>
<div><b>Укажите почту (необязательно):</b></div>
<p><div class="ui input focus">
<input type="text" placeholder="example@mail.ru">
</div></p>
<button class="ui right labeled icon button"><i class="download icon"></i> Скачать </button>
<button class="ui right labeled icon button"><i class="envelope icon"></i> Отправить </button>
</div>
</div>
<script src="/TREASURER_01/scripts"></script>
</body>
</html>

@ -1,7 +0,0 @@
$('.ui.dropdown')
.dropdown('clear')
;
$('.ui.dropdown')
.dropdown('clear')
;

@ -12,28 +12,6 @@ if lPyOpenRPASourceFolderPathStr != "": sys.path.insert(0,os.path.abspath(os.pat
from pyOpenRPA.Orchestrator import SettingsTemplate # Import functionallity
from pyOpenRPA.Tools import CrossOS
from pyOpenRPA import Orchestrator # Import orchestrator main
from pyOpenRPA.Orchestrator.Server import app
import threading
from fastapi import Depends
from fastapi.responses import PlainTextResponse
from fastapi.responses import FileResponse
# Пример создания функции на сервере (FASTAPI) /test/threads
@app.get(path="/test/threads",tags=["Test"],response_class=PlainTextResponse)
def Threads():# inAuthDict:dict=Depends(IdentifyAuthorize)
#def Threads(inAuthDict:dict=Depends(IdentifyAuthorize)):# Используй, если требуется авторизация
lThreadStr = ""
for thread in threading.enumerate():
lThreadStr+=f"ПОТОК: {thread.name}\n"
#print(thread.name)
return lThreadStr
#Run as administrator (ONLY FOR WINDOWS)
if not Orchestrator.OrchestratorIsAdmin() and CrossOS.IS_WINDOWS_BOOL:
Orchestrator.OrchestratorRerunAsAdmin()
@ -44,11 +22,10 @@ else:
Orchestrator.OrchestratorLoggerGet().setLevel(logging.INFO)
# TEST Add User ND - Add Login ND to superuser of the Orchestrator
lUACClientDict = SettingsTemplate.__UACClientAdminCreate__()
gSettings["ServerDict"]["AccessUsers"]["FlagCredentialsAsk"]=False
Orchestrator.UACUpdate(inGSettings=gSettings, inADLoginStr="ND", inADStr="", inADIsDefaultBool=True, inURLList=[], inRoleHierarchyAllowedDict=lUACClientDict)
Orchestrator.UACUpdate(inGSettings=gSettings, inADLoginStr="rpa00", inADStr="", inADIsDefaultBool=True, inURLList=[], inRoleHierarchyAllowedDict=lUACClientDict)
# TEST Add User IMaslov - Add Login IMaslov to superuser of the Orchestrator
Orchestrator.UACUpdate(inGSettings=gSettings, inADLoginStr="VLADICK", inADStr="", inADIsDefaultBool=True, inURLList=[])
Orchestrator.UACUpdate(inGSettings=gSettings, inADLoginStr="IMaslov", inADStr="", inADIsDefaultBool=True, inURLList=[])
# TEST Add Supertoken for the all access between robots
Orchestrator.UACSuperTokenUpdate(inGSettings=gSettings, inSuperTokenStr="1992-04-03-0643-ru-b4ff-openrpa52zzz")
# Add first interface!
@ -59,7 +36,7 @@ else:
# Restore DUMP
Orchestrator.OrchestratorSessionRestore(inGSettings=gSettings)
# Autoinit control panels starts with CP_
lPyModules = Orchestrator.OrchestratorPySearchInit(inGlobPatternStr="Demo\\*\\config.py", inAsyncInitBool=True)
lPyModules = Orchestrator.OrchestratorPySearchInit(inGlobPatternStr="ControlPanel\\CP_*.py", inDefStr="SettingsUpdate", inDefArgNameGSettingsStr="inGSettings", inAsyncInitBool=True)
# Call the orchestrator def
Orchestrator.Orchestrator(inGSettings=gSettings, inDumpRestoreBool=False)

@ -1,24 +0,0 @@
chcp 65001
@echo off
echo Формат использования init-python-env.cmd [имя запускаемого процесса.exe] [имя убиваемого процесса.exe]
echo Пример использования init-python-env.cmd orpa-rbt.exe orpa-rbt.exe
if [%1]==[] goto :python-env
goto create-exe
:create-exe
copy /Y "%~dp0..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe" "%~dp0..\Resources\WPy64-3720\python-3.7.2.amd64\%1"
if [%2]==[] goto :python-env
goto taskkill
:taskkill
taskkill /im "%2" /F /fi "username eq %username%"
goto :python-env
:python-env
set CD_PREV=%cd%
cd /d "%~dp0..\Resources\WPy64-3720\python-3.7.2.amd64"
set PATH=%cd%;%cd%\Scripts;%PATH%
cd /d "%~dp0..\Sources"
set PYTHONPATH=%cd%;%PYTHONPATH%
cd %CD_PREV%
:eof
echo Инициализация Python окружения прошла успешно!
@echo on

@ -1,4 +0,0 @@
chcp 65001
cd /d "%~dp0"
call init-python-env.cmd orpa-rbt.exe orpa-rbt.exe
cmd

@ -1,5 +1,5 @@
chcp 65001
cd /d "%~dp0"
call init-python-env.cmd orpa-orc.exe orpa-orc.exe
orpa-orc.exe "config.py"
cd %~dp0
taskkill /im "orpa-orc.exe" /F /fi "username eq %username%"
copy /Y ..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe ..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-orc.exe
.\..\Resources\WPy64-3720\python-3.7.2.amd64\orpa-orc.exe "config.py"
pause>nul

@ -1 +0,0 @@
https://github.com/intxcc/pyaudio_portaudio

File diff suppressed because it is too large Load Diff

Binary file not shown.

@ -1,172 +0,0 @@
#pyaudio loopback
import pyaudio
import wave
import os
defaultframes = 512
class textcolors:
if not os.name == 'nt':
blue = '\033[94m'
green = '\033[92m'
warning = '\033[93m'
fail = '\033[91m'
end = '\033[0m'
else:
blue = ''
green = ''
warning = ''
fail = ''
end = ''
recorded_frames = []
device_info = {}
useloopback = False
recordtime = 5
#Use module
p = pyaudio.PyAudio()
#Set default to first in list or ask Windows
try:
default_device_index = p.get_default_input_device_info()
except IOError:
default_device_index = -1
#Select Device
print (textcolors.blue + "Available devices:\n" + textcolors.end)
for i in range(0, p.get_device_count()):
info = p.get_device_info_by_index(i)
print (textcolors.green + str(info["index"]) + textcolors.end + ": \t %s \n \t %s \n" % (info["name"], p.get_host_api_info_by_index(info["hostApi"])["name"]))
if default_device_index == -1:
default_device_index = info["index"]
#Handle no devices available
if default_device_index == -1:
print (textcolors.fail + "No device available. Quitting." + textcolors.end)
exit()
#Get input or default
device_id = int(input("Choose device [" + textcolors.blue + str(default_device_index) + textcolors.end + "]: ") or default_device_index)
print ("")
#Get device info
try:
device_info = p.get_device_info_by_index(device_id)
except IOError:
device_info = p.get_device_info_by_index(default_device_index)
print (textcolors.warning + "Selection not available, using default." + textcolors.end)
#Choose between loopback or standard mode
is_input = device_info["maxInputChannels"] > 0
is_wasapi = (p.get_host_api_info_by_index(device_info["hostApi"])["name"]).find("WASAPI") != -1
if is_input:
print (textcolors.blue + "Selection is input using standard mode.\n" + textcolors.end)
else:
if is_wasapi:
useloopback = True;
print (textcolors.green + "Selection is output. Using loopback mode.\n" + textcolors.end)
else:
print (textcolors.fail + "Selection is input and does not support loopback mode. Quitting.\n" + textcolors.end)
exit()
recordtime = int(input("Record time in seconds [" + textcolors.blue + str(recordtime) + textcolors.end + "]: ") or recordtime)
#Open stream
channelcount = device_info["maxInputChannels"] if (device_info["maxOutputChannels"] < device_info["maxInputChannels"]) else device_info["maxOutputChannels"]
stream = p.open(format = pyaudio.paInt16,
channels = channelcount,
rate = int(device_info["defaultSampleRate"]),
input = True,
frames_per_buffer = defaultframes,
input_device_index = device_info["index"],
as_loopback = useloopback)
#Start Recording
print (textcolors.blue + "Starting..." + textcolors.end)
for i in range(0, int(int(device_info["defaultSampleRate"]) / defaultframes * recordtime)):
recorded_frames.append(stream.read(defaultframes))
print (".")
print (textcolors.blue + "End." + textcolors.end)
#Stop Recording
stream.stop_stream()
stream.close()
#Close module
p.terminate()
filename = input("Save as [" + textcolors.blue + "out.wav" + textcolors.end + "]: ") or "out.wav"
from pydub import AudioSegment
# Advanced usage, if you have raw audio data:
sound = AudioSegment(
# raw audio data (bytes)
data=b''.join(recorded_frames),
# 2 byte (16 bit) samples
sample_width=p.get_sample_size(pyaudio.paInt16),
# 44.1 kHz frame rate
frame_rate=int(device_info["defaultSampleRate"]),
# stereo
channels=channelcount
)
sound.export("out.mp3", format="mp3")
#waveFile = wave.open(filename, 'wb')
#waveFile.setnchannels(channelcount)
#waveFile.setsampwidth(p.get_sample_size(pyaudio.paInt16))
#waveFile.setframerate(int(device_info["defaultSampleRate"]))
#waveFile.writeframes(b''.join(recorded_frames))
#waveFile.close()
#pyaudio classic
from sys import byteorder
from array import array
from struct import pack
import pyaudio
import wave
THRESHOLD = 500
CHUNK_SIZE = 1024
FORMAT = pyaudio.paInt16
RATE = 44100
STOP_BOOL = False
import time
STOP_SEC_INT = 10
TIME_LAST = time.time()
def is_silent(snd_data):
"Returns 'True' if below the 'silent' threshold"
return max(snd_data) < THRESHOLD
def normalize(snd_data):
"Average the volume out"
MAXIMUM = 16384
times = float(MAXIMUM)/max(abs(i) for i in snd_data)
r = array('h')
for i in snd_data:
r.append(int(i*times))
return r
def trim(snd_data):
"Trim the blank spots at the start and end"
def _trim(snd_data):
snd_started = False
r = array('h')
for i in snd_data:
if not snd_started and abs(i)>THRESHOLD:
snd_started = True
r.append(i)
elif snd_started:
r.append(i)
return r
# Trim to the left
snd_data = _trim(snd_data)
# Trim to the right
snd_data.reverse()
snd_data = _trim(snd_data)
snd_data.reverse()
return snd_data

@ -1,12 +1,13 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.3.1
Summary: The powerful open source RPA platform for business
Version: 1.2.14
Summary: First open source RPA platform for business
Home-page: https://pyopenrpa.ru/
Author: Ivan Maslov
Author-email: Ivan.Maslov@pyopenrpa.ru
License: Текст лицензии см. в файле: LICENSE.PDF (в корне) или по адресу: https://pyopenrpa.ru/license/oferta.pdf
Keywords: pyOpenRPA OpenRPA RPA Robot Automation Robotization OpenSource IT4Business
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: Free For Educational Use
Classifier: License :: Free For Home Use
@ -91,3 +92,4 @@ Ivan Maslov contacts (CEO & FOUNDER):
- Web: https://pyopenrpa.ru/
- Telegram: https://t.me/pyopenrpa
- WhatsApp | Telegram: +7 906 722 39 25 | @IvanMaslov

@ -1,19 +1,13 @@
pyOpenRPA-1.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.3.1.dist-info/METADATA,sha256=oy_kdDRYfQHXr9MUOp_vO-WZ9AOOGvtMKIfYDanGAHY,4359
pyOpenRPA-1.3.1.dist-info/RECORD,,
pyOpenRPA-1.3.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA-1.3.1.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.3.1.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/.idea/inspectionProfiles/profiles_settings.xml,sha256=YXLFmX7rPNGcnKK1uX1uKYPN0fpgskYNe7t0BV7cqkY,174
pyOpenRPA/.idea/misc.xml,sha256=V-fQnOz-bYEZULgfbFgm-8mURphZrKfXMSd0wKjeEyA,188
pyOpenRPA/.idea/modules.xml,sha256=Q__U1JIA2cjxbLRXAv-SfYY00fZA0TNlpkkbY4s3ncg,277
pyOpenRPA/.idea/pyOpenRPA.iml,sha256=EXh41F8lqRiSBMVg-n2tKaEaHC6_3gGSuKkPJA12Na0,408
pyOpenRPA/.idea/vcs.xml,sha256=2HygA1oRAwc3VBf-irxHrX5JJG9DXuQwrN0BlubhoKY,191
pyOpenRPA/.idea/workspace.xml,sha256=6tJZehshdK4And6tEoUvkIB0KE7waL_NnTSkTYYAeFA,3802
pyOpenRPA/Agent/A2O.py,sha256=iSjYhWS2GrL6vdJ0Gc9PVtgfiqzqVwBc5jX0HsOrFdo,1713
pyOpenRPA/Agent/O2A.py,sha256=DpFWS1uKfFNsuyiSwj5LLI862oe58aJbQilRv3Hgm9o,6205
pyOpenRPA-1.2.14.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.2.14.dist-info/METADATA,sha256=msxiHoe4JlRNqXnlKGZWthHNr5JPV7OWXJzgXwzZTcc,4372
pyOpenRPA-1.2.14.dist-info/RECORD,,
pyOpenRPA-1.2.14.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA-1.2.14.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.2.14.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/Agent/A2O.py,sha256=PlIZZCTnVrYF2i6DSAi_KbzZfc2gtcBPmOerrEZq68U,1718
pyOpenRPA/Agent/O2A.py,sha256=XHl5nytUoUqfPvmYWh5auYo-s0GIThNmkOA9ON-JCis,5535
pyOpenRPA/Agent/Processor.py,sha256=xNZfQ_HcV-qm_x90tBLKYJqvnENiTqHSoUk2LhDfqWQ,6346
pyOpenRPA/Agent/__Agent__.py,sha256=rUvtEGEmlsd3ZujkQnPhL3mGaALmM2iNvfWBoF0Puc4,15167
pyOpenRPA/Agent/__Agent__.py,sha256=gqKxqu9XEEdgLNRvAlaGqDaQR2sgn_n_Vskf8dv2cQo,12692
pyOpenRPA/Agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Agent/__pycache__/A2O.cpython-37.pyc,,
pyOpenRPA/Agent/__pycache__/O2A.cpython-37.pyc,,
@ -23,18 +17,18 @@ pyOpenRPA/Agent/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Agent/readme.md,sha256=QF_Bnv204OK3t1JUEhjfICkxFmSdX6bvaRl_HI6lH9I,19
pyOpenRPA/Info.md,sha256=u4Nv-PjniSF0Zlbtr6jEJX2vblK3_1zhSLNUgOdtDaA,85
pyOpenRPA/LICENSE.pdf,sha256=8L-9X_kCCt8yWvjy0E_xV-C6Im79hZnH7WcfZHRz8uM,4322139
pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=cYsvzgtjpGtD1qW8GRIq7WjHktsPZ0kefN47g9awhDc,39641
pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=ymWcw6ZKg6-sSiykQK8iolhBjK2amTyQx7u8QKPnewc,37947
pyOpenRPA/Orchestrator/ControlPanel.py,sha256=OzS8HjG__8OZgqhajr8L8owyugXPuSLWHLtXuKdEP78,103
pyOpenRPA/Orchestrator/Core.py,sha256=OHa3mSC3_wRAizqrWBVjlR6ln4-xVVvBpOSnWl6qVvY,529
pyOpenRPA/Orchestrator/Managers/ControlPanel.py,sha256=VJoWVZoGE0dOQ-_jeezG8NNsk0mETUrJQztE8AfqxBY,17531
pyOpenRPA/Orchestrator/Managers/Git.py,sha256=VCXXc-enJhvrAJvYc8jHK9GcGe02meMdszU0tlJDHiQ,12879
pyOpenRPA/Orchestrator/Managers/Process.py,sha256=JW6cMsgAKmTtSkNMlW7zHhLh3N8lBdZI95wDadxCgtw,42537
pyOpenRPA/Orchestrator/Managers/ControlPanel.py,sha256=nBJqwBd6y9yeE49XOn83r8Dtvb3yReujrp-frxOhNL8,16671
pyOpenRPA/Orchestrator/Managers/Git.py,sha256=dgXx2UzSwiEev4ov2hBbb-5MhXVhFKWZo2lmr19QSCQ,12582
pyOpenRPA/Orchestrator/Managers/Process.py,sha256=DYX1pBK4gaxcfmDj-1OaLNyk83D_R_7ztZyt0SHWoik,41377
pyOpenRPA/Orchestrator/Managers/__init__.py,sha256=4my0XiwmI_QLRQVhOzNvWTggCosF3tb2yRxGkehOCq0,71
pyOpenRPA/Orchestrator/Managers/__pycache__/ControlPanel.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Managers/__pycache__/Git.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Managers/__pycache__/Process.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Managers/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Processor.py,sha256=WXA_OC8tWVU-R8dsYR6O7-griwcxn6HH27qRs3GWnoU,10368
pyOpenRPA/Orchestrator/Processor.py,sha256=FtNmdIsBStkLHLlOe6MDWzSmZv9m7ntlQs-NirA6OgQ,10264
pyOpenRPA/Orchestrator/ProcessorOld.py,sha256=Vh5zLRpWWf-vt9CCYI8nDY7oaefiufnu6Pnl4tp27pY,13749
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=GQCB1NElDCsJ8e9CKs9ivi91BjQVBSPL4Uqt9DTFn2A,1976
@ -42,7 +36,7 @@ pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=hvuXDlmcacN6GqBuICWJcu
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=wwH9JOoMFFxDKQ7IyNyh1OkFkZ23o1cD8Jm3n31ycII,657
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=bMahu6wRznmoLYsopgbNOLqufcQnEDanIepuGvXIsac,12405
pyOpenRPA/Orchestrator/RobotRDPActive/Recovery.py,sha256=jneD474V-ZBYnmQFxWoY_feGNMSL0lGaRK6TEfQ6gOc,2954
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=LQexk8eb4YOa8A51XwyZdng3AzLadgHNAgJfW2OAF0E,13065
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=5FX48HlIn8NKfs7q_rp3lpumWtNcwdHq7J8ygnOwU_g,12284
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp,sha256=YjIxCXyIvDtZx-MPpyHPj3quT9dlUZPuuILiB21eRpU,2462
pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py,sha256=y8--fUvg10qEFomecl_cmdWpdGjarZBlFpMbs_GvzoQ,1077
@ -60,7 +54,7 @@ pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/ConsoleStart.bat,sha256=_HNadUKHOYI5y6foG3srh8wjSzhX33xaKNylFtDjOJk,114
pyOpenRPA/Orchestrator/RobotScreenActive/Monitor.py,sha256=GQt40zD9X0R4RPaa2Cnbn-17oR2gUZvRGk3T3uGdKuY,603
pyOpenRPA/Orchestrator/RobotScreenActive/Monitor.py,sha256=YjS23qinMk_2z47MGRVSDxbvsUMImnhqLi1F4BqW2OE,602
pyOpenRPA/Orchestrator/RobotScreenActive/Screen.py,sha256=VnYcvCVymrD35l2J4ln_tlVn7CilZhxE4Ggw9P-OhIw,606
pyOpenRPA/Orchestrator/RobotScreenActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/RobotScreenActive/__main__.py,sha256=JASxDDVKWUU7DAbDkRrGTrPk-P7LZchTZFh8usp6b4U,593
@ -68,18 +62,20 @@ pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Screen.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=kejcfciuREYHc8Wl0ZgO6_1Kim0QtgfugPWYQq3VD54,12723
pyOpenRPA/Orchestrator/ServerBC.py,sha256=hwaFRtw1XN3D1rankd2HwH139-z5vfYvXO1I9skF0bI,23719
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=1mHElwL46J_dT3qTF3-DaP_u4HekC4C5uGv2rRSngHc,35111
pyOpenRPA/Orchestrator/SettingsTemplate.py,sha256=dVL-JZpAUQP3LLXE_7IUuE7RkLTYBAA-RX4e5FZ_DU0,21499
pyOpenRPA/Orchestrator/Server.py,sha256=YOQgZQ97nM_XQYVRbusj_b50aqEiNBJFF3bs7wA-O6k,36240
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=260YPXINLrora8pBBVHQSPNBkc8wdlyadsoQTQKdpAs,32590
pyOpenRPA/Orchestrator/SettingsTemplate.py,sha256=TR6WQVm-0sFoQjnV08t9K5oQOcpC7dbKOnWQS31m9dQ,21443
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Utils/LoggerHandlerDumpLogList.py,sha256=hD47TiOuKR-G8IWu9lJD2kG28qlH7YZV63i3qv1N5Dk,681
pyOpenRPA/Orchestrator/Utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/Utils/__pycache__/LoggerHandlerDumpLogList.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Utils/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Web/Basic.py,sha256=pPH55rPwZz1ktpzNIcC51jeV2MgZI10Zf0Q0DncihDw,7757
pyOpenRPA/Orchestrator/Web/Index.js,sha256=YACiZAvjr6NmFlDhQu6urkJp49BX7L8WJU9p-MeIlCI,43508
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=5JUAs5rEiU0XtHM9QO6EdNMBGt-W6QOVGY7xJ_HLPFM,19257
pyOpenRPA/Orchestrator/Web/__pycache__/Basic.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__Orchestrator__.py,sha256=E7kysFDJmcmBejKt8_0pk624U6ohLqM32CjvJ-FysoQ,214440
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Orchestrator/__Orchestrator__.py,sha256=C0gVOwB3bYRJMALXLPLdkHw0wobQBly5_G7pLWBjGcg,204085
pyOpenRPA/Orchestrator/__init__.py,sha256=nJhjYtBXKOUNX_yNu1rRFk5y9cDz6AFiL0M6KgX_utQ,207
pyOpenRPA/Orchestrator/__main__.py,sha256=czJrc7_57WiO3EPIYfPeF_LG3pZsQVmuAYgbl_YXcVU,273
pyOpenRPA/Orchestrator/__pycache__/BackwardCompatibility.cpython-37.pyc,,
@ -88,7 +84,6 @@ pyOpenRPA/Orchestrator/__pycache__/Core.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/ProcessorOld.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Server.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/ServerBC.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/ServerSettings.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/SettingsTemplate.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Timer.cpython-37.pyc,,
@ -248,7 +243,7 @@ pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/package.js,sha256=BHq6qGCSMdDXDGJ
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/package.json,sha256=Sy3ZVA4SxFzecOO88h1IVAnBiuDpRtXiUg6ME_YArI0,524
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.css,sha256=aje_ma2N_7VT1k2QTOLeqr3SfQ3Cr-7vB05D2-uo-YQ,869203
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.js,sha256=t-thIOFbQol3-vcB3C7kRbS49jG2_LC5dEp7NLxBpuA,759089
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.css,sha256=o4apE2I4Au57fkNgduz1J0rhbTPc04IlvCzBmEeapGE,628944
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.css,sha256=f5Dpq5VRrbzn8POovxN9HR3S7LhHQIAiCKYz4PB4ZZA,628934
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.js,sha256=69cT25pJVUmAyniwWMglXlEOEeZYuhmD8Hbj58gCS7Y,275740
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.eot,sha256=0CPFX94iBJXxOoe3KZXg35jI0ok1dymdGZ2lu_W0_gI,98640
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.svg,sha256=IcTTApw6luFW48z0iPvWxbD_LpBQYBaIN5LGFInrfpU,508636
@ -268,50 +263,9 @@ pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outli
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.woff2,sha256=TSiDRDsk5CRSf2oKeqKJez33HyOdtANzxP92DkgUeAE,12240
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/images/flags.png,sha256=lNXH8WYTAcSm3Ekdct1VmgYgzZF6gm8N8bAju5bqnd0,28123
pyOpenRPA/Resources/Web/jQuery/jquery-3.1.1.min.js,sha256=HPMOWdIdSuVgr3FD9ZE-_MgiK8qk_MdQjrgCtfqp6U4,86713
pyOpenRPA/Resources/Web/orpa/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Resources/Web/orpa/footer.xhtml,sha256=xB-uUWvzdgD686l8rXWYOzwp3y7DKnZrvJeBS0ClPLI,3482
pyOpenRPA/Resources/Web/orpa/header.xhtml,sha256=kJF-9Ea9DV2v6Y3F0r3FvF3odfYmw14F5_SAbbq2uyk,3658
pyOpenRPA/Resources/Web/orpa/logo.png,sha256=7rulXo_C57xJQEaYWmAkChxXb6xbDW2zq-werzVbDbc,4899
pyOpenRPA/Resources/Web/orpa/orc.js,sha256=aVKy_YTcpcOUiXcUyE1hyW7lpSmfFJY3sVjgEgMdXrw,38487
pyOpenRPA/Resources/Web/orpa/orc.xhtml,sha256=6WQ5fidSF8EW8PzqZ9AMVptVVCJAzQleqEFqfRIqQvo,19324
pyOpenRPA/Resources/Web/orpa/std.xhtml,sha256=lNg0WRW-sM5J2EGCkqtwqtOzv5n21KFZ8vHv9KlquEY,43547
pyOpenRPA/Resources/Web/orpa/styleset/Lato-Bold.woff2,sha256=roj8DXqWGDL4CVJ9ML05g6aGbUL2alat4j9UNoFZTbY,184912
pyOpenRPA/Resources/Web/orpa/styleset/Lato-Italic.woff2,sha256=RGV2Xy9u3c2tNP_XyrVZ5WvA515F4ZL4XpVisHcUgdw,195704
pyOpenRPA/Resources/Web/orpa/styleset/Lato-Regular.woff2,sha256=mDsMrzNuhUIhT8FwGaT8XgNghkuSgGyhTVXB_BwsWg8,182708
pyOpenRPA/Resources/Web/orpa/styleset/bg1.jpg,sha256=63vfRzL-rLY_hW634p8rFps-BKFUKK9O0e4zaeHFxKw,251041
pyOpenRPA/Resources/Web/orpa/styleset/bg10.jpg,sha256=ZY_Z27kqavsjccDUrqoURz71zvkk81hdYB7u8TPciwI,256648
pyOpenRPA/Resources/Web/orpa/styleset/bg2.jpg,sha256=UlHtxLzqoypCTm1d_cIO3UFDrpYFNmTfAUQr3RtADdo,249670
pyOpenRPA/Resources/Web/orpa/styleset/bg3.jpg,sha256=N5Lp18GyFzCSaDXfcPAwrtVfCW7uoNIOvRos0F-qryg,245168
pyOpenRPA/Resources/Web/orpa/styleset/bg4.jpg,sha256=nckyiY8IgPYYUcprl0kOGE7-RzFnik4uqfFZc5V7aU8,258568
pyOpenRPA/Resources/Web/orpa/styleset/bg5.jpg,sha256=9AeZLTygYTWTlyyFaHnQSkj50m7eZ6iTCb0xt8oe_xM,261562
pyOpenRPA/Resources/Web/orpa/styleset/bg6.jpg,sha256=SXF3wNssI2dEHnBOfTWjRijXWA-BMq9YXXixq8ajVNk,260686
pyOpenRPA/Resources/Web/orpa/styleset/bg7.jpg,sha256=tZ2LP0BKZCxZnxlTUCCmXUSvdReRKb0AyX6ea7hAe0k,261376
pyOpenRPA/Resources/Web/orpa/styleset/bg8.jpg,sha256=x3l1TJaepQnMkeRvkhjOp_g6tUSebqp2-AEUDM2QCkg,261288
pyOpenRPA/Resources/Web/orpa/styleset/bg9.jpg,sha256=cRfXuOGYv_DCKBGrh7-Js1NGmtdrZWgYxXW9pi8c5Wo,261559
pyOpenRPA/Resources/Web/orpa/styleset/docs.css,sha256=XmeLuUmo_tTGFSurYJPZgaBb_gD_nMZX1TCzqBbKz7k,55821
pyOpenRPA/Resources/Web/orpa/styleset/docs.css.bak,sha256=uDJOPZxwDDgBOhhy12G1hYIBvOm6nuYQCdw0BoyidII,55845
pyOpenRPA/Resources/Web/orpa/styleset/docs.js,sha256=6MvOXSzLAeQLjzUt7IkRLhOn0QE1xRYZRgQQhu6y3mQ,44749
pyOpenRPA/Resources/Web/orpa/styleset/dropdown.css,sha256=Gra8mTrxFli1BxnYTArvthaDUajJPbB2Yta5y86C1rA,37642
pyOpenRPA/Resources/Web/orpa/styleset/easing.min.js,sha256=lP963PCWRotqEmscc9mBLkieNsnZ1d9KCD4unl3ZpVU,3794
pyOpenRPA/Resources/Web/orpa/styleset/header.css,sha256=kZg2wcwEoerMGyaKa4aMoYPBbJNCmovrml4WoWpBvQc,13723
pyOpenRPA/Resources/Web/orpa/styleset/highlight.min.js,sha256=Z39RBsR8A-knGdSdh8Bs2h9uA6grKSb4OyVhkmv48uk,21964
pyOpenRPA/Resources/Web/orpa/styleset/home.css,sha256=rr3HRdvfuzkK2H46rChyyswywWEDnCpHcCQ7D_xuQRU,16245
pyOpenRPA/Resources/Web/orpa/styleset/home.js,sha256=e65zKntsXHUK0DORA6gaoTlom0fsF4p8Unh74UsA85s,8926
pyOpenRPA/Resources/Web/orpa/styleset/jquery.min.js,sha256=3ks8PR3CUGtmk_D5iITh3AdM2p1myrObe0ihFf38TA8,84349
pyOpenRPA/Resources/Web/orpa/styleset/less.min.js,sha256=lqonJQsjeXmDk-iZDpqlyAO5tzY5F93xFP-eUIdTUZM,136781
pyOpenRPA/Resources/Web/orpa/styleset/metadata.json,sha256=RBNvo1WzZ4oRRq0W9-hknpT7T8If536DEMBg9hyq_4o,2
pyOpenRPA/Resources/Web/orpa/styleset/nan.jpg,sha256=oZRYv31pGnf65BGA3fTzQ-HV8ulj7VoT-hB4nFVG3lc,23839
pyOpenRPA/Resources/Web/orpa/styleset/ogImage.JPG,sha256=-WVra6DU8SusAWtJWR6fEEROlJE_UxlOAodO7G82E3U,242713
pyOpenRPA/Resources/Web/orpa/styleset/ogImage.PNG,sha256=7-C8f1hHBHUPi_Y6gscUK04S3qso8lywT7KGCCYSMBM,131928
pyOpenRPA/Resources/Web/orpa/styleset/pyOpenRPA_logo.png,sha256=7rulXo_C57xJQEaYWmAkChxXb6xbDW2zq-werzVbDbc,4899
pyOpenRPA/Resources/Web/orpa/styleset/segment.css,sha256=wzmuVZPMT1Y1Ymn52U8WQLiqmo7zNvwcXOVYr6ePfts,20287
pyOpenRPA/Resources/Web/orpa/styleset/sidebar.js,sha256=fnype3guWOx0kmyP7rL2I0mkyMR1_V9u8u2_W5E_4vk,34482
pyOpenRPA/Resources/Web/orpa/styleset/transition.js,sha256=esNkWoCwl6ksZewJkNDMLKCE4nDTdJZDJW3tdE7dlAo,36070
pyOpenRPA/Resources/Web/orpa/styleset/visibility.js,sha256=ulme0GrsuqHAHXTQunq96J0mESTl6Lux8msdK1_fcm4,44174
pyOpenRPA/Resources/Web/orpa/styleset/white-image.png,sha256=D7WJFGDtAIp_OXUU6Tz4zeYm_1yHRd8u7aTu0F35Kcw,5951
pyOpenRPA/Robot/Audio.py,sha256=kHvFnb3t_vnw-NjfSf1zaL3w1Th-984KMx1S8-6BX5I,22176
pyOpenRPA/Resources/Web/pyOpenRPA_logo.png,sha256=7rulXo_C57xJQEaYWmAkChxXb6xbDW2zq-werzVbDbc,4899
pyOpenRPA/Robot/Clipboard.py,sha256=QXClSH1ccCl8KfKbMY1Wk_SynEgfDZqZ_0h-OZYn4kA,1962
pyOpenRPA/Robot/Keyboard.py,sha256=0pe4C5vqYD9LRBm61dZmJ39lyNoI0BXMLCA0bWjvm8I,26589
pyOpenRPA/Robot/Keyboard.py,sha256=3RCogucSWPCtq7YbFKIUvJOSBvFE04P6Lo3hjCGUHi8,26071
pyOpenRPA/Robot/Mouse.py,sha256=R-2q5Q-nDhvvQjcQxFz8FRM9tHjhPUKdnK3KuPc_OZw,16361
pyOpenRPA/Robot/OrchestratorConnector.py,sha256=JUtdiUXCruqUqBD19gJBl9jk_b-tpWWx_v3MfBoKzoQ,20445
pyOpenRPA/Robot/README.md,sha256=bwiTAygxuMZzBlwpsndw2QgxA2smIjUyOPZnsnR341k,1623
@ -319,7 +273,7 @@ pyOpenRPA/Robot/Screen.py,sha256=nH80ghKw7OseNF_fVwfUrih0y9o1Ul2VPEl_WT5b598,454
pyOpenRPA/Robot/SettingsTemplate.py,sha256=Rp5XPeV2I4tCS2uf4Zkqm_ERJ6pZMg4-e5_lMqGJYLk,1453
pyOpenRPA/Robot/Test.py,sha256=qXr990nXiFZX5SNv6QN9GLb_U4HZRmJnbZR2qSnwilY,2878
pyOpenRPA/Robot/UIDesktop.py,sha256=WLy8wUVDFSUN5S7hXUjijQIH0B71c5tj-pBCVex7uFc,125314
pyOpenRPA/Robot/UIWeb.py,sha256=DLr6cPvFdUmGMTKGLVrksaVKHqBmbxzFkkT4qT0WLfo,32589
pyOpenRPA/Robot/UIWeb.py,sha256=AaAuX32i8nzTlXORp-l6rCp383JCX28TmJO7iyrqF1c,32351
pyOpenRPA/Robot/Utils/JSONNormalize.py,sha256=aIuVzuZDazhxkCOzoOjfhHVz66mp2FWdfPv5E7KWF5Y,3890
pyOpenRPA/Robot/Utils/ProcessBitness.py,sha256=NvzuTxNWL_EMmdU1Isu0bUck1Iud0Kkzn8GsVCzIAAM,4591
pyOpenRPA/Robot/Utils/ProcessCommunicator.py,sha256=8GfmLnOvAdosmt7YNT86uEV9cjhKippssCX62wOMJwM,8039
@ -335,7 +289,6 @@ pyOpenRPA/Robot/Utils/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Robot/Window.py,sha256=UJl-sg4RvvJ35aG9jZOzqGVwE15XK7qPHqoOBD13xFk,431
pyOpenRPA/Robot/__init__.py,sha256=eYyMsU33rGlEZcsO-MH9UtXs47UcTCtg4Uc4lxKmmQo,255
pyOpenRPA/Robot/__main__.py,sha256=xtzw5siZZJV2Nmn-zXPZY5u3Tk0wxe-l8lxq3VPEEiI,2029
pyOpenRPA/Robot/__pycache__/Audio.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/Keyboard.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/Mouse.cpython-37.pyc,,
@ -351,8 +304,10 @@ pyOpenRPA/Robot/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Studio/JSONNormalize.py,sha256=g0Z8G2wojCgTAdZtyRiCfe0_FHSeAi72Va7R7mk27gg,3347
pyOpenRPA/Studio/ProcessCommunicator.py,sha256=HD3XASJae31_HV3OznFe8E2MgZFXnwt7YveVN82M8nU,7912
pyOpenRPA/Studio/RobotConnector.py,sha256=CYO0dQoqfs44SYD_VZ_TJh3WFu_DXigHBLHj4GJ2Icc,5038
pyOpenRPA/Studio/Studio.py,sha256=pf9feDUyvKRJfhREkxK9uN49dWawYdn3ImkdxuH5mM0,18518
pyOpenRPA/Studio/Studio.py,sha256=RYwjb7KKEK2EgGz4lb95IQXvKk0-QACObBxoMh2IEFE,8689
pyOpenRPA/Studio/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777
pyOpenRPA/Studio/Web/Index.xhtml,sha256=X_fLnzxdcJ8ML9VRORpaMmQwlu1Pcr0CR2Krzt65Hes,48119
pyOpenRPA/Studio/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Studio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Studio/__main__.py,sha256=_57Rnq9DKbmmlpGFqIwVrWn_LRcU8jjmMTOny4_zlP8,308
pyOpenRPA/Studio/__pycache__/JSONNormalize.cpython-37.pyc,,
@ -362,13 +317,13 @@ pyOpenRPA/Studio/__pycache__/Studio.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/ValueVerify.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/CrossOS.py,sha256=6yq7cit6dgs0KCk6zknoy699r7a3gC0UrnYYe-ZrobM,3539
pyOpenRPA/Tools/Debugger.py,sha256=nLDzlghYnRghULjGze6_yVg5Du25I8K5s3uhFw1hh3w,570
pyOpenRPA/Tools/CrossOS.py,sha256=smXZ_DSx1YwLt9aUor0se51sEIkUhm2BicfoxU6qVl8,2569
pyOpenRPA/Tools/Debugger.py,sha256=2slOSaPnUAwfDlyjhaqqhhchXUBgEKQImTzXagJt4Jw,535
pyOpenRPA/Tools/License.py,sha256=r4z9HExUzpk2Q_6WhzgUnHlOPPHK1MLevtdlLwtZ7Hk,10378
pyOpenRPA/Tools/RobotDB/ExcelCom.py,sha256=hp0dvXOEC7Au00ueh7pqxkdixV-PC-km7tCt-wRunYs,343
pyOpenRPA/Tools/RobotDB/HowToUse,sha256=TUXPZAFcse-PSlKFM6jcaYuuZZEmXOSSvgeqrbmIDoc,1473
pyOpenRPA/Tools/RobotDB/RobotDB.py,sha256=qtGu8PS2atd0L8taCNpk-08Qpxp8Qz1lqwAcBkyLFLM,1655
pyOpenRPA/Tools/RobotDB/Server.py,sha256=idGpXDU9rPv-NZcOW1Wrku_acEqEYnhSXNtUmFTs1dU,20019
pyOpenRPA/Tools/RobotDB/Server.py,sha256=rjW9Sg-j9P8pFQD66Uih-rke6-f6sCulinwi4_W-3mc,19933
pyOpenRPA/Tools/RobotDB/ServerSettings.py,sha256=5p9JwrpKHh68oVHIWazTajB6AOfzeapARbvGcJOFmNc,7406
pyOpenRPA/Tools/RobotDB/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Tools/RobotDB/__main__.py,sha256=w9sXIF4r_PeWJjHJutTuH8DSYpXxpgcAN0KUOjiJ6PI,140
@ -396,7 +351,7 @@ pyOpenRPA/Tools/SafeSource/__pycache__/Crypter.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/DistrCreate.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/StopSafe.py,sha256=BIMiW8cFyQfX3KpRHaspdbw6-FcImTilqXRC_XXzyik,2346
pyOpenRPA/Tools/StopSafe.py,sha256=BNTtMmvsRE1Wtri3EkwhoBi6gGOjEPRQnJSV1C03c84,2176
pyOpenRPA/Tools/Template.py,sha256=3COsenafs8yoRUTAPQUjR-b18TepiWjS9Rv3Jq01rw0,5490
pyOpenRPA/Tools/Usage.py,sha256=GVGpC1E6qt1FjjD-RSyn4l9koI5FNfXBIWEBHGKbdK4,2996
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@ -407,14 +362,6 @@ pyOpenRPA/Tools/__pycache__/StopSafe.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/Template.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/Usage.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Utils/Dictionary.py,sha256=dXmsFZoufUxpf_f_grQIsWcto1qwLCRrxN6m93NJCu8,2261
pyOpenRPA/Utils/Disk.py,sha256=MKD9nIGKNOJeQow1qGDTEz-GffkFbWaNxf3Hj76AyTo,364
pyOpenRPA/Utils/Network.py,sha256=UHTvc_ut_Fimeg-tBISUYPgkLKQTBkte3EsIh8BW7a8,600
pyOpenRPA/Utils/Render.py,sha256=VCU5cCCwyCFvMmRQwq7MGllgqzeDAp_s8om3UChIoPk,6703
pyOpenRPA/Utils/Text.py,sha256=ZFIIPaCB8lJ7kwF9bwpVR-lmf_p1o6jz8npBdl_7eNc,214
pyOpenRPA/Utils/__pycache__/Dictionary.cpython-37.pyc,,
pyOpenRPA/Utils/__pycache__/Disk.cpython-37.pyc,,
pyOpenRPA/Utils/__pycache__/Render.cpython-37.pyc,,
pyOpenRPA/Utils/__pycache__/Text.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=Uj0nKJ5lCErziv4h_RMQxX1M13lF_oHY2NJIJ9UndSI,155
pyOpenRPA/__init__.py,sha256=ZYKWkmhslD3FNo1wNQ-nV3i7qwvmOgf85JgP1u5glgI,156
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/test.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@ -15,7 +15,7 @@ def _A2ODataSend(inGSettings, inDataDict):
lProtocolStr= "https" if inGSettings["OrchestratorDict"]["IsHTTPSBool"] else "http"
lHostStr = inGSettings["OrchestratorDict"]["HostStr"]
lPortInt = inGSettings["OrchestratorDict"]["PortInt"]
lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/orpa/agent/a2o"
lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/pyOpenRPA/Agent/A2O"
lResponse = requests.post(url= lURLStr, cookies = {"AuthToken":inGSettings["OrchestratorDict"]["SuperTokenStr"]}, json=inDataDict, timeout=inGSettings["A2ODict"]["ConnectionTimeoutSecFloat"])
except Exception as e:
if lL: lL.exception(f"A2O Error handler.")

@ -30,7 +30,7 @@ def O2A_Loop(inGSettings):
lProtocolStr= "https" if inGSettings["OrchestratorDict"]["IsHTTPSBool"] else "http"
lHostStr = inGSettings["OrchestratorDict"]["HostStr"]
lPortInt = inGSettings["OrchestratorDict"]["PortInt"]
lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/orpa/agent/o2a"
lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/pyOpenRPA/Agent/O2A"
lDataDict = { "HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"], "UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"], "ActivityLastGUIDStr": lActivityLastGUIDStr}
lResponse = requests.post(url= lURLStr, cookies = {"AuthToken":inGSettings["OrchestratorDict"]["SuperTokenStr"]}, json=lDataDict, timeout=inGSettings["O2ADict"]["ConnectionTimeoutSecFloat"])
lCEPhaseFastTimeLastGoodFloat = time.time()
@ -53,27 +53,27 @@ def O2A_Loop(inGSettings):
# Log full version if bytes size is less than limit . else short
lAgentLimitLogSizeBytesInt = 500
if lBodyLenInt <= lAgentLimitLogSizeBytesInt:
if lL: lL.info(f"Словарь ActivityItem, полученный от оркестратора: {lQueueItem}")
if lL: lL.info(f"ActivityItem from orchestrator: {lQueueItem}");
else:
if lL: lL.info(f"Словарь ActivityItem, полученный от оркестратора: содержимое свернуто из-за большого размера ({lBodyLenInt} байт")
if lL: lL.info(f"ActivityItem from orchestrator: Supressed - big size. Size is {lBodyLenInt} bytes");
else:
if lL: lL.debug(f"Поступил пустой ответ от оркестратора - цикл попытается обновить соединение между оркестратором и агентом");
if lL: lL.debug(f"Empty response from the orchestrator - loop when refresh the connection between Orc and Agent");
except requests.exceptions.ConnectionError as e:
if time.time() - lCEPhaseFastTimeLastGoodFloat <= lCEPhaseFastDurationSecFloat:
if lL: lL.error(f"О2А Ошибка соединения - оркестратор недоступен. Повторить попытку через {lCEPhaseFastRetrySecFloat} с.")
if lL: lL.error(f"O2A Connection error - orchestrator is not available. Sleep for {lCEPhaseFastRetrySecFloat} s.")
time.sleep(lCEPhaseFastRetrySecFloat)
else:
if lL: lL.error(f"О2А Ошибка соединения - оркестратор недоступен. Повторить попытку через {lCEPhaseLongRetrySecFloat} с.")
if lL: lL.error(f"O2A Connection error - orchestrator is not available. Sleep for {lCEPhaseLongRetrySecFloat} s.")
time.sleep(lCEPhaseLongRetrySecFloat)
except ConnectionResetError as e:
if lL: lL.error(f"О2А Ошибка сброса соединения - оркестратор недоступен. Повторить попытку через {inGSettings['O2ADict']['RetryTimeoutSecFloat']} с.")
if lL: lL.error(f"O2A Connection reset error - orchestrator is not available. Sleep for {inGSettings['O2ADict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except json.decoder.JSONDecodeError as e:
if lL: lL.error(f"О2А Ошибка декодирования JSON - далее представлено содержимое, которое поступило на обработку: {lRequestBody}")
if lL: lL.error(f"O2A JSON decode error - See body of the recieved content from the Orchestrator: {lRequestBody}")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except requests.exceptions.Timeout as e:
if lL: lL.exception(f"О2А Ошибка соединения (превышено время ожидания). Повторить попытку через {inGSettings['O2ADict']['RetryTimeoutSecFloat']} с.")
if lL: lL.exception(f"O2A requests timeout error (no response for long time). Sleep for {inGSettings['O2ADict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])
except Exception as e:
if lL: lL.exception(f"О2А Общая ошибка. Повторить попытку через {inGSettings['O2ADict']['RetryTimeoutSecFloat']} с.")
if lL: lL.exception(f"O2A Error handler. Sleep for {inGSettings['O2ADict']['RetryTimeoutSecFloat']} s.")
time.sleep(inGSettings["O2ADict"]["RetryTimeoutSecFloat"])

@ -3,69 +3,66 @@ from . import O2A, A2O # Data flow Orchestrator To Agent
from . import Processor # Processor Queue
from ..Tools import Usage
from ..Tools import License
from pyOpenRPA.Tools import CrossOS
if CrossOS.IS_WINDOWS_BOOL: from subprocess import CREATE_NEW_CONSOLE # Flag to create new process in another CMD
if CrossOS.IS_LINUX_BOOL: pass
from subprocess import CREATE_NEW_CONSOLE # Flag to create new process in another CMD
import os
gSettings = None
# Create binary file by the base64 string (safe for JSON transmition)
def OSFileBinaryDataBase64StrCreate(inFilePathStr, inFileDataBase64Str,inGSettings = None):
"""L+,W+: Создать бинарный файл на стороне Агента по полученной строке в формате base64 (формат безопасен для передачи по JSON протоколу)
"""
Create binary file by the base64 string (safe for JSON transmition)
"""
inFilePathStr = CrossOS.PathStr(inPathStr=inFilePathStr)
lFile = open(inFilePathStr, "wb")
lFile.write(base64.b64decode(inFileDataBase64Str))
lFile.close()
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
lMessageStr = f"АГЕНТ: бинарный файл {inFilePathStr} создан успешно"
lMessageStr = f"AGENT Binary file {inFilePathStr} has been created."
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
# Append binary file by the base64 string (safe for JSON transmition)
def OSFileBinaryDataBase64StrAppend(inFilePathStr, inFileDataBase64Str,inGSettings = None):
"""L+,W+: Create binary file by the base64 string (safe for JSON transmition)
"""
Create binary file by the base64 string (safe for JSON transmition)
"""
inFilePathStr = CrossOS.PathStr(inPathStr=inFilePathStr)
lFile = open(inFilePathStr, "ab")
lFile.write(base64.b64decode(inFileDataBase64Str))
lFile.close()
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
lMessageStr = f"АГЕНТ: Данные успешно добавлены в бинарный файл {inFilePathStr}"
lMessageStr = f"AGENT Binary file {inFilePathStr} has been appended."
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
# Create text file by the string
def OSFileTextDataStrCreate(inFilePathStr, inFileDataStr, inEncodingStr = "utf-8",inGSettings = None):
"""L+,W+:Создать текстовый файл на стороне Агента
"""
Create text file in the agent GUI session
:param inFilePathStr: Абсолютный путь к создаваемому файлу
:param inFileDataStr: Текст, отправляемый в создаваемый файл
:param inEncodingStr: Кодировка создаваемого файла. По-умолчанию 'utf-8'
:param inGSettings: Глобальный файл настроек
:param inFilePathStr: File abs path
:param inFileDataStr: File data text content
:param inEncodingStr: Write file encoding
:param inGSettings: global settings of the Agent (singleton)
:return:
"""
inFilePathStr = CrossOS.PathStr(inPathStr=inFilePathStr)
lFile = open(inFilePathStr, "w", encoding=inEncodingStr)
lFile.write(inFileDataStr)
lFile.close()
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
lMessageStr = f"АГЕНТ: Текстовый файл {inFilePathStr} успешно создан"
lMessageStr = f"AGENT Text file {inFilePathStr} has been created."
if lL: lL.info(lMessageStr)
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
def OSFileBinaryDataBase64StrReceive(inFilePathStr, inGSettings=None):
"""L+,W+: Прочитать бинарный файл на стороне агента и отправить на сторону оркестратора в формате base64 (формат безопасный для передачи в формате JSON)
"""
Read binary file and encode in base64 to transmit (safe for JSON transmition)
:param inFilePathStr: Абсолютный путь к читаемому файлу
:param inGSettings: Глобальный словарь настроек Агента (необязательный)
:return: Содержимое бинарного файле, преобразованное в формат base64 (используй base64.b64decode для декодирования в байты). Вернет None запрашиваемый файл не существует
:param inFilePathStr: File path to read
:param inGSettings: global settings of the Agent (singleton)
:return: File content in string base64 format (use base64.b64decode to decode data). Return None if file is not exist
"""
inFilePathStr = CrossOS.PathStr(inPathStr=inFilePathStr)
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
lFileDataBase64Str = None
if os.path.exists(inFilePathStr):
@ -73,55 +70,56 @@ def OSFileBinaryDataBase64StrReceive(inFilePathStr, inGSettings=None):
lFileDataBytes = lFile.read()
lFile.close()
lFileDataBase64Str = base64.b64encode(lFileDataBytes).decode("utf-8")
lMessageStr = f"Функция OSFileBinaryDataBase64StrReceive: файл {inFilePathStr} прочитан успешно"
lMessageStr = f"OSFileBinaryDataBase64StrReceive: file {inFilePathStr} has been read"
if lL: lL.debug(lMessageStr)
#A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
else:
if lL: lL.debug(f"Функция OSFileBinaryDataBase64StrReceive: файл {inFilePathStr} не существует - отправить None")
if lL: lL.debug(f"OSFileBinaryDataBase64StrReceive: file {inFilePathStr} is not exists - return None")
return lFileDataBase64Str
def OSFileMTimeGet(inFilePathStr: str) -> float or None:
"""L+,W+: Read file modification time timestamp format (float)
"""
Read file modification time timestamp format (float)
:param inFilePathStr: Абсолютный путь к файлу, дату которого требуется получить
:return: Временной слепок (timestamp) в формате float. Вернет None, если запрашиваемый файл не существует
:param inFilePathStr: File path to read
:return: timestamp (float) Return None if file is not exist
"""
inFilePathStr = CrossOS.PathStr(inPathStr=inFilePathStr)
global gSettings
lL = gSettings.get("Logger", None) if type(gSettings) is dict else None
lFileMTimeFloat = None
if os.path.exists(inFilePathStr):
lFileMTimeFloat = os.path.getmtime(inFilePathStr)
if lL: lL.debug(f"Функция OSFileMTimeGet: файл {inFilePathStr} прочитан успешно")
if lL: lL.debug(f"OSFileMTimeGet: file {inFilePathStr} has been read")
else:
if lL: lL.debug(f"Функция OSFileMTimeGet: file {inFilePathStr} не существует - вернуть None")
if lL: lL.debug(f"OSFileMTimeGet: file {inFilePathStr} is not exists - return None")
return lFileMTimeFloat
def OSFileTextDataStrReceive(inFilePathStr, inEncodingStr="utf-8", inGSettings=None):
"""L+,W+: Прочитать текстовый файл на стороне агента и отправить на сторону оркестратора
"""
Read text file in the agent GUI session
:param inFilePathStr: Абсолютный путь к читаемому файлу
:param inEncodingStr: Кодировка создаваемого файла. По-умолчанию 'utf-8'
:param inGSettings: Глобальный словарь настроек
:return: Строка - содержимое текстового файла. Возвращает None, если файл не существует
:param inFilePathStr: File abs path
:param inEncodingStr: Read file encoding. Default utf-8
:param inGSettings: global settings of the Agent (singleton)
:return: File text content in string format (use base64.b64decode to decode data). Return None if file is not exist
"""
inFilePathStr = CrossOS.PathStr(inPathStr=inFilePathStr)
lFileDataStr = None
lL = inGSettings.get("Logger", None) if type(inGSettings) is dict else None
if os.path.exists(inFilePathStr):
lFile = open(inFilePathStr, "r", encoding=inEncodingStr)
lFileDataStr = lFile.read()
lFile.close()
lMessageStr = f"АГЕНТ: Текстовый файл {inFilePathStr} прочитан успешно"
lMessageStr = f"OSFileTextDataStrReceive: file {inFilePathStr} has been read"
if lL: lL.info(lMessageStr)
#A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
else:
if lL: lL.info(f"АГЕНТ: Текстовый файл {inFilePathStr} не существует - вернуть None")
if lL: lL.info(f"OSFileTextDataStrReceive: file {inFilePathStr} is not exists - return None")
return lFileDataStr
# Send CMD to OS. Result return to log + Orchestrator by the A2O connection
def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrchestratorLogsBool = True, inCMDEncodingStr = "cp1251", inCaptureBool = True):
"""L-,W+: Execute CMD on the Agent daemonic process
"""
Execute CMD on the Agent daemonic process
:param inCMDStr: command to execute on the Agent session
:param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution
@ -144,13 +142,10 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrche
if inCaptureBool == True:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
if CrossOS.IS_WINDOWS_BOOL:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=None, stderr=None,
creationflags=CREATE_NEW_CONSOLE)
if CrossOS.IS_LINUX_BOOL:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=None, stderr=None)
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=None, stderr=None,
creationflags=CREATE_NEW_CONSOLE)
lListenBool = True
lMessageStr = f"{lOSCMDKeyStr}: # # # # АГЕНТ: Терминальная сессия запущена # # # # "
lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been STARTED # # # # "
if lL: lL.info(lMessageStr)
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
A2O.LogListSend(inGSettings=inGSettings,inLogList=[lMessageStr])
@ -177,7 +172,7 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrche
time.sleep(2)
else:
lListenBool = False
lMessageStr = f"{lOSCMDKeyStr}: # # # # АГЕНТ: Терминальная сессия завершена # # # # "
lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been FINISHED # # # # "
if lL: lL.info(lMessageStr)
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
@ -186,7 +181,7 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrche
if inRunAsyncBool:
lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inGSettings":inGSettings, "inSendOutputToOrchestratorLogsBool":inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr":inCMDEncodingStr, "inCaptureBool": inCaptureBool })
lThread.start()
lResultStr="Список ActivityList отправлен на исполнение в асинхронном режиме - захват текста недоступен"
lResultStr="ActivityList has been started in async mode - no output is available here."
else:
lResultStr = _CMDRunAndListenLogs(inCMDStr=inCMDStr, inGSettings=inGSettings, inSendOutputToOrchestratorLogsBool = inSendOutputToOrchestratorLogsBool, inCMDEncodingStr = inCMDEncodingStr, inCaptureBool=inCaptureBool)
#lCMDCode = "cmd /c " + inCMDStr
@ -196,9 +191,11 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrche
def ProcessWOExeUpperUserListGet():
"""L-,W+: Вернуть список процессов, запущенных под пользователем на стороне агента
"""
Return the process list only for the current user (where Agent is running) without .EXE in upper case. Can use in ActivityItem from Orchestrator to Agent
:return: Список процессов в формате: ["NOTEPAD","..."] (без постфикса .exe и в верхнем регистре)
:param inProcessNameWOExeList:
:return: list of the agent user process in upper case without .EXE. Example ["NOTEPAD","..."],
"""
lUserNameStr = getpass.getuser()
@ -241,7 +238,7 @@ def Agent(inGSettings):
lProcessorThread = threading.Thread(target= Processor.ProcessorRunSync, kwargs={"inGSettings":inGSettings})
lProcessorThread.daemon = True # Run the thread in daemon mode.
lProcessorThread.start() # Start the thread execution.
if lL: lL.info("Модуль процессора pyOpenRPA был успешно запущен") #Logging
if lL: lL.info("Processor has been started (ProcessorDict)") #Logging
# Start thread to wait data from Orchestrator (O2A)
lO2AThread = threading.Thread(target=O2A.O2A_Loop, kwargs={"inGSettings":inGSettings})
@ -250,4 +247,4 @@ def Agent(inGSettings):
# Send log that Agent has been started
A2O.LogListSend(inGSettings=inGSettings, inLogList=[f'Хост: {inGSettings["AgentDict"]["HostNameUpperStr"]}, Логин: {inGSettings["AgentDict"]["UserUpperStr"]}, Агент инициализирован успешно'])
A2O.LogListSend(inGSettings=inGSettings, inLogList=[f'Host: {inGSettings["AgentDict"]["HostNameUpperStr"]}, User: {inGSettings["AgentDict"]["UserUpperStr"]}, Agent has been started.'])

@ -77,7 +77,7 @@ def v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
}
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr] = lSessionNew # Set new session in dict
inRequest.OpenRPAResponseDict["SetCookies"]["SessionGUIDStr"] = lCookieSessionGUIDStr # Set SessionGUIDStr in cookies
if lL: lL.info(f"РДП сессия инициализирована. Идентификатор сессии:{lCookieSessionGUIDStr}")
if lL: lL.info(f"New session GUID is created. GUID {lCookieSessionGUIDStr}")
return lCookieSessionGUIDStr
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
lCreateNewSessionBool = False # Flag to create new session structure
@ -108,7 +108,7 @@ def v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
if lCookieSessionGUIDStr in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
if (time.time() - lTimeStartSecFloat) >= lLifetimeRequestSecFloat: # Check if lifetime client request is over or has no key
if lL: lL.debug(f"Время жизни HTTP запроса истекло - удалить из отслеживаемых!")
if lL: lL.debug(f"Client request lifetime is over")
lDoWhileBool = False # Stop the iterations
if lDoWhileBool:
TechnicalCheck() # Calculate the CP
@ -277,7 +277,7 @@ def v1_2_0_ProcessorOld2NewActivityDict(inActivityOld):
"ArgLogger": "inLogger" # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
else:
raise Exception(f"Обратная совместимость до v1.2.0, старый процессор: Тип {inActivityOld['Type']} был обнаружен в старом процессоре")
raise Exception(f"BackwardCompatibility up to v1.2.0, old processor: No type {inActivityOld['Type']} has been found in old processor.")
return lResult # return the result
@ -295,7 +295,7 @@ def Update(inGSettings):
inGSettings["Autocleaner"] = { # Some gurbage is collecting in g settings. So you can configure autocleaner to periodically clear gSettings
"IntervalSecFloat": 7200.0, # Sec float to periodically clear gsettings
}
if lL: lL.warning(f"Обратная совместимость (от v1.1.13 до v1.1.14): Добавить 'Autocleaner' структуру") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Autocleaner' structure") # Log about compatibility
if "Client" not in inGSettings: # Add "Client" structure
inGSettings["Client"] = { # Settings about client web orchestrator
"Session":{ # Settings about web session. Session algorythms works only for special requests (URL in ServerSettings)
@ -318,14 +318,14 @@ def Update(inGSettings):
}
}
}
if lL: lL.warning(f"Обратная совместимость (v1.1.13 -> v1.1.14): Добавить структуру 'Client'") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Client' structure") # Log about compatibility
if "Server" in inGSettings and "RequestTimeoutSecFloat" not in inGSettings["Server"]: # Add Server > "RequestTimeoutSecFloat" property
inGSettings["Server"]["RequestTimeoutSecFloat"] = 300 # Time to handle request in seconds
if lL: lL.warning(
f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Server' > 'RequestTimeoutSecFloat' property") # Log about compatibility
if "DefSettingsUpdatePathList" not in inGSettings["OrchestratorStart"]: # Add OrchestratorStart > "DefSettingsUpdatePathList" property
inGSettings["OrchestratorStart"]["DefSettingsUpdatePathList"] = [] # List of the .py files which should be loaded before init the algorythms
if lL: lL.warning(f"Обратная совместимость (v1.1.13 -> v1.1.14): Преобразовать структуру 'OrchestratorStart' > 'DefSettingsUpdatePathList'") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'OrchestratorStart' > 'DefSettingsUpdatePathList' property list") # Log about compatibility
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# v1.1.20 to v1.2.0
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@ -338,14 +338,14 @@ def Update(inGSettings):
"DumpLogList": [], # Will be filled automatically
"DumpLogListHashStr": None, # Will be filled automatically
})
if lL: lL.warning(f"Обратная совместимость (v1.1.20 -> v1.2.0): Создать атрибут 'Client > DumpLog... с параметрами по умолчанию'") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'Client > DumpLog... with default parameters'") # Log about compatibility
if "Processor" in inGSettings: # Check if Processor exist
# Update Logger
if lL is not None:
SettingsTemplate.LoggerDumpLogHandlerAdd(inLogger=lL, inGSettingsClientDict=inGSettings["Client"])
if lL: lL.warning(f"Обратная совместимость (v1.1.20 -> v1.2.0): Добавить веб дамп для отображения лога на веб клиенте оркестратора") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Add web dump log in logger as handler") # Log about compatibility
del inGSettings["Processor"] # Remove the key
if lL: lL.warning(f"Обратная совместимость (v1.1.20 -> v1.2.0): Удалить структуру старого процессора 'Processor'") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Remove old structure 'Processor'") # Log about compatibility
if "ProcessorDict" not in inGSettings: # Create new ProcessorDict structure
inGSettings["ProcessorDict"]={
"ActivityList": [ # List of the activities
@ -361,14 +361,14 @@ def Update(inGSettings):
"ExecuteBool": True, # Flag to execute thread processor
"ThreadIdInt": None # Fill thread id when processor will be inited
}
if lL: lL.warning(f"Обратная совместимость (v1.1.20 -> v1.2.0): Создать новую структуру 'ProcessorDict'") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new structure 'ProcessorDict'") # Log about compatibility
if "VersionStr" not in inGSettings: # Create new ProcessorDict structure
inGSettings["VersionStr"] = None
if lL: lL.warning(f"Обратная совместимость (v1.1.20 -> v1.2.0): Создать новую структуру 'VersionStr'") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'VersionStr'") # Log about compatibility
if "AgentDict" not in inGSettings: # Create new AgentDict structure
inGSettings["AgentDict"]= {}
if lL: lL.warning(
f"Обратная совместимость (v1.1.20 -> v1.2.0): Создать новую структуру 'AgentDict'") # Log about compatibility
f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'AgentDict'") # Log about compatibility
# Alg to convert UAC ControlPanelAllawedList to UACClient hierarchy
# if inGSettings["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True:
# lUserRights = inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(), inRequest.OpenRPA["User"].upper())]
@ -379,7 +379,7 @@ def Update(inGSettings):
# Check if Server is active > convert to ServerDict
inGSettings["ServerDict"] = inGSettings["Server"]
if lL: lL.warning(
f"Обратная совместимость (v1.1.20 -> v1.2.0): Преобразовать 'Server' -> 'ServerDict'") # Log about compatibility
f"Backward compatibility (v1.1.20 to v1.2.0): Convert Server to ServerDict") # Log about compatibility
# Remove old structure Scheduler
del inGSettings["Server"]
lShowWarnBool = False
@ -401,7 +401,7 @@ def Update(inGSettings):
# remove "ControlPanelKeyAllowedList" - will be removed in __Orchestrator__.UACUpdate
#del inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"][lItemKeyTurple]["ControlPanelKeyAllowedList"]
if lShowWarnBool: # Show only 1 warning per all run
if lL: lL.warning(f"Обратная совместимость (v1.1.20 -> v1.2.0): Интегрировать структуру доступа к панелям управления в общую UAC иерархию") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert CP allowed list to UAC Client hierarchy (consolidated)") # Log about compatibility
# Check if ControlPanelDict is active > convert to CPDict
if "ControlPanelDict" in inGSettings:
if "CPDict" not in inGSettings: inGSettings["CPDict"]={}
@ -409,7 +409,7 @@ def Update(inGSettings):
inGSettings["CPDict"][lItemDict["KeyStr"]]={"HTMLRenderDef":lItemDict["RenderFunction"], "JSONGeneratorDef":None, "JSInitGeneratorDef":None}
# Remove old structure ControlPanel
del inGSettings["ControlPanelDict"]
if lL: lL.warning(f"Обратная совместимость (v1.1.20 -> v1.2.0): Преобразовать 'ControlPanelDict' -> 'CPDict'") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert ControlPanelDict to CPDict") # Log about compatibility
# Check if Scheduler is active > convert to SchedulerDict
if "Scheduler" in inGSettings:
if "SchedulerDict" not in inGSettings: inGSettings["SchedulerDict"]={ "CheckIntervalSecFloat": 5.0, "ActivityTimeList":[]}
@ -423,27 +423,27 @@ def Update(inGSettings):
inGSettings["SchedulerDict"]["ActivityTimeList"].append(lItemDict)
# Remove old structure Scheduler
del inGSettings["Scheduler"]
if lL: lL.warning(f"Обратная совместимость (v1.1.20 -> v1.2.0): Преобразовать 'Scheduler' -> 'SchedulerDict' с новыми функциональными возможностями") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert Scheduler to SchedulerDict with new features") # Log about compatibility
# # Convert to Storage to StorageDict
if "Storage" in inGSettings:
# Check if Server is active > convert to ServerDict
inGSettings["StorageDict"] = inGSettings["Storage"]
if lL: lL.warning(
f"Обратная совместимость (v1.2.1 -> v1.2.2): Преобразовать 'Storage' -> 'StorageDict'") # Log about compatibility
f"Backward compatibility (v1.2.1 to v1.2.2): Convert Storage to StorageDict") # Log about compatibility
# Remove old structure Scheduler
del inGSettings["Storage"]
# Add new key WarningExecutionMoreThanSecFloat in ProcessorDict
if "WarningExecutionMoreThanSecFloat" not in inGSettings["ProcessorDict"]:
inGSettings["ProcessorDict"]["WarningExecutionMoreThanSecFloat"] = 60.0
if lL: lL.warning(
f"Обратная совместимость (v1.2.1 -> v1.2.2): Добавить ключ 'WarningExecutionMoreThanSecFloat' -> 'ProcessorDict'") # Log about compatibility
f"Backward compatibility (v1.2.1 to v1.2.2): Add key WarningExecutionMoreThanSecFloat in ProcessorDict") # Log about compatibility
# Add new key AgentActivityLifetimeSecFloat, AgentConnectionLifetimeSecFloat, AgentLoopSleepSecFloat in ProcessorDict > ServerDict
if "AgentActivityLifetimeSecFloat" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["AgentActivityLifetimeSecFloat"] = 1200.0
inGSettings["ServerDict"]["AgentConnectionLifetimeSecFloat"] = 300.0
inGSettings["ServerDict"]["AgentLoopSleepSecFloat"] = 2.0
if lL: lL.warning(
f"Обратная совместимость (v1.2.1 -> v1.2.2): Добавить ключи: 'AgentActivityLifetimeSecFloat', 'AgentConnectionLifetimeSecFloat', 'AgentLoopSleepSecFloat' -> 'ProcessorDict' > 'ServerDict'") # Log about compatibility
f"Backward compatibility (v1.2.1 to v1.2.2): Add key AgentActivityLifetimeSecFloat, AgentConnectionLifetimeSecFloat, AgentLoopSleepSecFloat in ProcessorDict > ServerDict") # Log about compatibility
# Add new key RecoveryDict in ProcessorDict > RobotRDPActive
if "RecoveryDict" not in inGSettings["RobotRDPActive"]:
inGSettings["RobotRDPActive"]["RecoveryDict"] = {
@ -457,7 +457,7 @@ def Update(inGSettings):
}
}
if lL: lL.warning(
f"Обратная совместимость (v1.2.1 -> v1.2.2): Добавить ключ 'RecoveryDict' -> 'ProcessorDict' > 'RobotRDPActive'") # Log about compatibility
f"Backward compatibility (v1.2.1 to v1.2.2): Add new key RecoveryDict in ProcessorDict > RobotRDPActive") # Log about compatibility
# Add new key ServerDict > ListenDict
if "ListenDict" not in inGSettings["ServerDict"]:
lPortInt = inGSettings.get("ServerDict",{}).get("ListenPort",80)
@ -471,7 +471,7 @@ def Update(inGSettings):
}
}
if lL: lL.warning(
f"Обратная совместимость (v1.2.2 -> v1.2.3): Добавить ключ 'ServerDict' > 'ListenDict'. Изменение свойства, отвечающее за прослушиваемый порт 'ServerDict' > 'ListenPort'") # Log about compatibility
f"Backward compatibility (v1.2.2 to v1.2.3): Add new key ServerDict > ListenDict. Transfer port from ServerDict > ListenPort") # Log about compatibility
# Add new key
#"ServerDict": {
# "AgentFileChunkBytesSizeInt": 50000000, # size of the each chunk for the agent transmition
@ -479,24 +479,24 @@ def Update(inGSettings):
if "AgentFileChunkBytesSizeInt" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["AgentFileChunkBytesSizeInt"]= 50000000
if lL: lL.warning(
f"Обратная совместимость (v1.2.3 -> v1.2.4): Добавить ключ ServerDict > AgentFileChunkBytesSizeInt") # Log about compatibility
f"Backward compatibility (v1.2.3 to v1.2.4): Add new key ServerDict > AgentFileChunkBytesSizeInt") # Log about compatibility
if "AgentFileChunkCheckIntervalSecFloat" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["AgentFileChunkCheckIntervalSecFloat"]= 0.2
if lL: lL.warning(
f"Обратная совместимость (v1.2.3 -> v1.2.4): Добавить ключ ServerDict > AgentFileChunkCheckIntervalSecFloat") # Log about compatibility
f"Backward compatibility (v1.2.3 to v1.2.4): Add new key ServerDict > AgentFileChunkCheckIntervalSecFloat") # Log about compatibility
if "ServerThread" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["ServerThread"]= None
if lL: lL.warning(
f"Обратная совместимость (v1.2.3 -> v1.2.4): Добавить ключ ServerDict > ServerThread") # Log about compatibility
f"Backward compatibility (v1.2.3 to v1.2.4): Add new key ServerDict > ServerThread") # Log about compatibility
if "AgentLimitLogSizeBytesInt" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["AgentLimitLogSizeBytesInt"] = 300
if lL: lL.warning(
f"Обратная совместимость (v1.2.3 -> v1.2.4): Добавить ключ ServerDict > AgentLimitLogSizeBytesInt") # Log about compatibility
f"Backward compatibility (v1.2.3 to v1.2.4): Add new key ServerDict > AgentLimitLogSizeBytesInt") # Log about compatibility
# Remove ControlPanelDict and CPDict > go to ServerDict > ControlPanelDict
if "ControlPanelDict" in inGSettings:
del inGSettings["ControlPanelDict"]
if lL: lL.warning(
f"Обратная совместимость (v1.2.4 -> v1.2.7): Удалить ключ ControlPanelDict") # Log about compatibility
f"Backward compatibility (v1.2.4 to v1.2.7): Remove old key: ControlPanelDict") # Log about compatibility
if "CPDict" in inGSettings:
for lCPKeyStr in inGSettings["CPDict"]:
lCPItemDict = inGSettings["CPDict"][lCPKeyStr]
@ -505,40 +505,40 @@ def Update(inGSettings):
inJSInitGeneratorDef=lCPItemDict["JSInitGeneratorDef"])
del inGSettings["CPDict"]
if lL: lL.warning(
f"Обратная совместимость (v1.2.4 -> v1.2.7): Удалить ключ: CPDict") # Log about compatibility
f"Backward compatibility (v1.2.4 to v1.2.7): Remove old key: CPDict") # Log about compatibility
if "ControlPanelDict" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["ControlPanelDict"]={}
if lL: lL.warning(
f"Обратная совместимость (v1.2.4 -> v1.2.7): Добавить ключ: ServerDict > ControlPanelDict") # Log about compatibility
f"Backward compatibility (v1.2.4 to v1.2.7): Create new key: ServerDict > ControlPanelDict") # Log about compatibility
# ManagersProcessDict
if "ManagersProcessDict" not in inGSettings:
inGSettings["ManagersProcessDict"]={}
if lL: lL.warning(
f"Обратная совместимость (v1.2.4 -> v1.2.7): Добавить ключ: ManagersProcessDict") # Log about compatibility
f"Backward compatibility (v1.2.4 to v1.2.7): Create new key: ManagersProcessDict") # Log about compatibility
# Check "SchedulerDict": { "Schedule": schedule, # https://schedule.readthedocs.io/en/stable/examples.html
if inGSettings.get("SchedulerDict",{}).get("Schedule",None) is None:
inGSettings["SchedulerDict"]["Schedule"] = schedule
if lL: lL.warning(f"Backward compatibility (v1.2.4 to v1.2.7): Подключить новый модуль расписания (см. schedule.readthedocs.io)") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.2.4 to v1.2.7): Create new module schedule (schedule.readthedocs.io)") # Log about compatibility
# ManagersGitDict
if "ManagersGitDict" not in inGSettings:
inGSettings["ManagersGitDict"]={}
if lL: lL.warning(
f"Обратная совместимость (v1.2.4 -> v1.2.7): Добавить ключ: ManagersGitDict") # Log about compatibility
f"Backward compatibility (v1.2.4 to v1.2.7): Create new key: ManagersGitDict") # Log about compatibility
# ProcessorDict > ActivityItemNowDict
if "ActivityItemNowDict" not in inGSettings["ProcessorDict"]:
inGSettings["ProcessorDict"]["ActivityItemNowDict"]=None
if lL: lL.warning(
f"Обратная совместимость (v1.2.4 -> v1.2.7): Добавить ключ: ProcessorDict > ActivityItemNowDict") # Log about compatibility
f"Backward compatibility (v1.2.4 to v1.2.7): Create new key: ProcessorDict > ActivityItemNowDict") # Log about compatibility
# # "UACBool": True # True - check user access before do this URL item
for lURLItemDict in inGSettings["ServerDict"]["URLList"]:
if "UACBool" not in lURLItemDict:
lURLItemDict["UACBool"]=None
if lL: lL.warning(
f"Обратная совместимость (v1.2.4 -> v1.2.7): ServerDict > URLList > item и UACBool = None") # Log about compatibility
f"Backward compatibility (v1.2.4 to v1.2.7): ServerDict > URLList > item: add UACBool = None") # Log about compatibility
# "URLIndexStr"
if "URLIndexStr" not in inGSettings["ServerDict"]:
inGSettings["ServerDict"]["URLIndexStr"] = "/"
if lL: lL.warning(
f"Обратная совместимость (v1.2.11 -> v1.2.12): ServerDict > URLIndexStr и URLIndexStr = /") # Log about compatibility
if lL: lL.warning(
f"Backward compatibility (v1.2.11 to v1.2.12): ServerDict > URLIndexStr: add URLIndexStr = /") # Log about compatibility

@ -84,11 +84,11 @@ class ControlPanel():
"""
# Connect self witch pyOpenRPA via ControlPanelNameStr
if inControlPanelNameStr in Orchestrator.GSettingsGet()["ServerDict"]["ControlPanelDict"]:
raise Exception(f"Ошибка: Ранее уже была инициализирована панель управления с идентификатором: {inControlPanelNameStr}. Устраните ошибку и перезапустите оркестратор")
raise Exception(f"Another control panel with name {inControlPanelNameStr} is already exists. Please resolve the error and restart")
Orchestrator.GSettingsGet()["ServerDict"]["ControlPanelDict"][inControlPanelNameStr] = self
self.mControlPanelNameStr = inControlPanelNameStr # Set the name of the control panel
self.RefreshHTMLJinja2TemplatePathSet(inJinja2TemplatePathStr = inRefreshHTMLJinja2TemplatePathStr)
self.mJinja2TemplateRefreshBool = inJinja2TemplateRefreshBool
self.mControlPanelNameStr = inControlPanelNameStr # Set the name of the control panel
self.mRobotNameStr = inRobotNameStr # Set the robot name for robot it execute
def Jinja2DataUpdateDictSet(self, inJinja2DataUpdateDict):
@ -116,7 +116,7 @@ class ControlPanel():
self.mRefreshHTMLJinja2Env = jinja2.Environment(loader=self.mRefreshHTMLJinja2Loader, trim_blocks=True)
self.mRefreshHTMLJinja2Template = self.mRefreshHTMLJinja2Env.get_template(lTemplateFileNameStr)
except Exception as e:
Orchestrator.OrchestratorLoggerGet().exception(f"Ошибка при инициализации Jinja2 ({inJinja2TemplatePathStr}). Панель управления: {self.mControlPanelNameStr}")
Orchestrator.OrchestratorLoggerGet().exception("EXCEPTION WHEN INIT Jinja2")
def RefreshHTMLJinja2StrGenerate(self, inDataDict):
"""
@ -145,7 +145,7 @@ class ControlPanel():
self.mInitJSJinja2Env = jinja2.Environment(loader=self.mInitJSJinja2Loader, trim_blocks=True)
self.mInitJSJinja2Template = self.mInitJSJinja2Env.get_template(lTemplateFileNameStr)
except Exception as e:
Orchestrator.OrchestratorLoggerGet().exception(f"Ошибка при инициализации Jinja2 ({inJinja2TemplatePathStr}). Панель управления: {self.mControlPanelNameStr}")
Orchestrator.OrchestratorLoggerGet().exception("EXCEPTION WHEN INIT Jinja2")
def InitJSJinja2StrGenerate(self, inDataDict):
"""
@ -290,7 +290,7 @@ class ControlPanel():
# Call backward compatibility HTML generator
lResultStr = Basic.HTMLControlPanelBC(inCPDict=lHTMLResult)
except Exception as e:
if lL: lL.exception(f"Ошибка в функции генерации HTML контента (HTMLRenderDef). Идентификатор панели управления: {self.mControlPanelNameStr}")
if lL: lL.exception(f"Error in control panel HTMLRenderDef. CP Key {self.mControlPanelNameStr}. Exception are below")
return lResultStr
@ -317,10 +317,10 @@ class ControlPanel():
if lType is str or lJSONResult is None or lType is int or lType is list or lType is dict or lType is bool or lType is float:
lResultDict = lJSONResult
else:
if lL: lL.warning(f"Функция генерации JSON сформировала некорректную структуру: {str(type(lJSONResult))}, идентификатор панели управления: {self.mControlPanelNameStr}")
if lL: lL.warning(f"JSONGenerator return bad type: {str(type(lJSONResult))}, CP Key {self.mControlPanelNameStr}")
except Exception as e:
if lL: lL.exception(
f"Ошибка при формирвоании JSON (JSONGeneratorDef). Идентификатор панели управления {self.mControlPanelNameStr}")
f"Error in control panel JSONGeneratorDef. CP Key {self.mControlPanelNameStr}. Exception are below")
return lResultDict
def BackwardAdapterJSDef(self,inRequest):
@ -343,8 +343,8 @@ class ControlPanel():
if type(lJSResult) is str:
lResultStr = lJSResult # Add delimiter to some cases
else:
if lL: lL.warning(f"Функция JSInitGenerator вернула неверный формат данных: {str(type(lJSResult))}, идентификатор панели управления {self.mControlPanelNameStr}")
if lL: lL.warning(f"JSInitGenerator return bad type: {str(type(lJSResult))}, CP Key {self.mControlPanelNameStr}")
except Exception as e:
if lL: lL.exception(
f"Ошибка в функции формирования кода JavaScript (JSInitGeneratorDef). Идентификатор панели управления {self.mControlPanelNameStr}")
f"Error in control panel JSInitGeneratorDef. CP Key {self.mControlPanelNameStr}. Exception are below")
return lResultStr

@ -34,7 +34,7 @@ class Git():
self.mAgentHostNameStr = inAgentHostNameStr
self.mAgentUserNameStr = inAgentUserNameStr
lGS["ManagersGitDict"][(inAgentHostNameStr.upper(), inAgentUserNameStr.upper(), lAbsPathUpperStr)]=self
else: raise Exception(f"Модуль Managers.Git ({inAgentHostNameStr}, {inAgentUserNameStr}, {lAbsPathUpperStr}): Невозможно инициализировать экземпляр класса, так как он уже был инициализирован ранее")
else: raise Exception(f"Managers.Git ({inAgentHostNameStr}, {inAgentUserNameStr}, {lAbsPathUpperStr}): Can't init the Git instance because it already inited in early")
def ProcessConnect(self, inProcess: Process):
"""
@ -151,11 +151,11 @@ class Git():
:param inBranchRemoteStr: [description]
:type inBranchRemoteStr: str
"""
Orchestrator.OrchestratorLoggerGet().debug(f"Модуль Managers.Git ({self.mAbsPathStr}): функция self.BranchRevLastGet успешно инициализирована")
Orchestrator.OrchestratorLoggerGet().debug(f"Managers.Git ({self.mAbsPathStr}): self.BranchRevLastGet has been init")
# check if the correct revision
lCMDResultStr = None
if self.BranchRevIsLast(inBranchLocalStr=inBranchLocalStr, inBranchRemoteStr=inBranchRemoteStr) == False:
Orchestrator.OrchestratorLoggerGet().info(f"Модуль Managers.Git ({self.mAbsPathStr}): функуция self.BranchRevLastGet, новая ревизия (ветка: {inBranchLocalStr}) была удалена - выполнить слияние (ветка на сервере: {inBranchRemoteStr})")
Orchestrator.OrchestratorLoggerGet().info(f"Managers.Git ({self.mAbsPathStr}): self.BranchRevLastGet, new rev (branch: {inBranchLocalStr}) has been detected - merge (branch: {inBranchRemoteStr})")
# Do the stop safe for the connected process
self.ProcessListSaveStopSafe()
lBranchNameCurrentStr = self.BranchNameGet()
@ -170,7 +170,7 @@ class Git():
# checkout to the source branch which was
self.BranchCheckout(inBranchNameStr=lBranchNameCurrentStr)
# do the orc restart
Orchestrator.OrchestratorLoggerGet().info(f"Модуль Managers.Git ({self.mAbsPathStr}): self.BranchRevLastGet, merge done, restart orc")
Orchestrator.OrchestratorLoggerGet().info(f"Managers.Git ({self.mAbsPathStr}): self.BranchRevLastGet, merge done, restart orc")
Orchestrator.OrchestratorRestart()
return lCMDResultStr

@ -108,7 +108,7 @@ class Process():
__Orchestrator__.ProcessorActivityItemAppend(inActivityItemDict=lActivityDict)
if inStatusCheckIntervalSecFloat is not None: __Orchestrator__.OrchestratorScheduleGet().every(inStatusCheckIntervalSecFloat).seconds.do(Orchestrator.OrchestratorThreadStart,self.StatusCheck)
self.mStatusCheckIntervalSecFloat = inStatusCheckIntervalSecFloat
else: raise Exception(f"Модуль Managers.Process ({inAgentHostNameStr}, {inAgentUserNameStr}, {inProcessNameWOExeStr}): Невозможно инициализировать процесс, так как он был инициализирован ранее (см. ProcessInitSafe)")
else: raise Exception(f"Managers.Process ({inAgentHostNameStr}, {inAgentUserNameStr}, {inProcessNameWOExeStr}): Can't init the Process instance because it already inited in early (see ProcessInitSafe)")
def ManualStopTriggerSet(self, inMSTdTSecFloat: float, inMSTdNInt: int) -> None:
"""
@ -145,7 +145,7 @@ class Process():
self.mStatusStr = "1_STOPPED_MANUAL"
# Log info about process
lL = __Orchestrator__.OrchestratorLoggerGet()
lL.info(f"Модуль Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Триггер ручной остановки активирован. {self.mMSTdNInt} повторить попытку через {self.mMSTdTSecFloat} сек.")
lL.info(f"Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): ManualStopTrigger is activated. {self.mMSTdNInt} start tries in {self.mMSTdTSecFloat} sec.")
return self.mStatusStr
def ManualStopListClear(self) -> None:
@ -180,7 +180,7 @@ class Process():
"""
if inIsManualBool == False: self.ManualStopTriggerNewStart() # Set the time
if self.mStatusStr is not None and (self.mStatusStr == "1_STOPPED_MANUAL" or "STOP_SAFE" in self.mStatusStr) and inIsManualBool == False:
lStr = f"Модуль Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Процесс не будет запущен, так как инициализирован триггер ручной остановки или активен режим безопасного отключения"
lStr = f"Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Process will not start because of stopped manual or stop safe is now."
__Orchestrator__.OrchestratorLoggerGet().warning(lStr)
return self.mStatusStr
# Send activity item to agent - wait result
@ -259,7 +259,7 @@ class Process():
if "SAFE" in self.mStatusStr:
# Log info about process
lL = __Orchestrator__.OrchestratorLoggerGet()
lL.info(f"Модуль Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Алгоритм безопасной остановки ожидал завершение процесса в течение {inStopSafeTimeoutSecFloat} сек. Выполнить принудительную остановку")
lL.info(f"Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Safe stop has been wait for {inStopSafeTimeoutSecFloat} sec. Now do the force stop.")
self.StopForce(inIsManualBool=inIsManualBool,inMuteIgnoreBool=True)
# Log info about process
# self.StatusChangeLog() status check has already log status (see above)
@ -350,7 +350,7 @@ class Process():
if self.mStatusStr == "2_STOP_SAFE": self.mStatusSavedStr = "0_STOPPED"
elif self.mStatusStr == "3_STOP_SAFE_MANUAL": self.mStatusSavedStr = "1_STOPPED_MANUAL"
else: self.mStatusSavedStr = self.mStatusStr; lWarnSafeBool = False
if lWarnSafeBool==True: __Orchestrator__.OrchestratorLoggerGet().warning(f"Модуль Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Состояние безопасной остановки было обнаружено при попытке сохранить состояние > зафиксировать состояние как остановленное")
if lWarnSafeBool==True: __Orchestrator__.OrchestratorLoggerGet().warning(f"Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Safe status has been catched when safe > change saved status to stopped.")
return self.mStatusStr
@ -358,7 +358,7 @@ class Process():
"""Call from orchestrator when init
"""
if self.mStatusCheckIntervalSecFloat is not None:
__Orchestrator__.OrchestratorLoggerGet().info(f"Модуль Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Восстановить периодическую проверку состояния с интервалом в {self.mStatusCheckIntervalSecFloat} сек.")
__Orchestrator__.OrchestratorLoggerGet().info(f"Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Restore schedule to StatusCheck in interval of {self.mStatusCheckIntervalSecFloat} sec.")
__Orchestrator__.OrchestratorScheduleGet().every(self.mStatusCheckIntervalSecFloat).seconds.do(Orchestrator.OrchestratorThreadStart,self.StatusCheck)
def StatusRestore(self):
@ -377,7 +377,7 @@ class Process():
self.StopSafe(inIsManualBool=True)
if "STARTED" in self.mStatusSavedStr and "STARTED" not in self.mStatusStr:
self.Start(inIsManualBool=True)
Orchestrator.OrchestratorLoggerGet().info(f"Модуль Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Статус процесса был восстановлен на: {self.mStatusSavedStr}")
Orchestrator.OrchestratorLoggerGet().info(f"Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Status has been restored to {self.mStatusSavedStr}")
self.mStatusStr = self.mStatusSavedStr
self.mStatusSavedStr = None
return self.mStatusStr
@ -390,10 +390,10 @@ class Process():
"""
# Log info about process
lL = __Orchestrator__.OrchestratorLoggerGet()
lL.info(f"Модуль Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Состояние процесса изменилось на {self.mStatusStr})")
lL.info(f"Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Status has been changed to {self.mStatusStr})")
def StatusCheck(self, inTimeoutSecFloat=9.0, inRaiseExceptionBool=False):
def StatusCheck(self):
"""
Check if process is alive. The def will save the manual flag is exists. Don't wait mute but set mute if it is not set.
@ -405,27 +405,21 @@ class Process():
#self.MuteWait()
self.mAgentMuteBool=True
lGUIDStr = __Orchestrator__.AgentActivityItemAdd(inHostNameStr=self.mAgentHostNameStr,inUserStr=self.mAgentUserNameStr,inActivityItemDict=lActivityItemUserProcessList)
try:
lUserProcessList = __Orchestrator__.AgentActivityItemReturnGet(inGUIDStr=lGUIDStr,inTimeoutSecFloat=inTimeoutSecFloat)
if self.mProcessNameWOExeStr.upper() in lUserProcessList:
if self.mStatusStr == "1_STOPPED_MANUAL": self.mStatusStr = "5_STARTED_MANUAL"; lLogBool=True
if self.mStatusStr == "0_STOPPED": self.mStatusStr = "4_STARTED"; lLogBool=True
if self.mStatusStr is None: self.mStatusStr = "4_STARTED"; lLogBool=True
else:
if self.mStatusStr == "2_STOP_SAFE": self.mStatusStr = "0_STOPPED"; lLogBool = True
if self.mStatusStr == "3_STOP_SAFE_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool = True
if self.mStatusStr == "5_STARTED_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool=True
if self.mStatusStr == "4_STARTED": self.mStatusStr = "0_STOPPED"; lLogBool=True
if self.mStatusStr is None: self.mStatusStr = "0_STOPPED"; lLogBool=True
# Log info about process
if lLogBool == True: self.StatusChangeLog()
self.mAgentMuteBool = False
return self.mStatusStr
except Exception as e:
self.mAgentMuteBool=False
if inRaiseExceptionBool: raise e
else: return "TIMEOUT"
lUserProcessList = __Orchestrator__.AgentActivityItemReturnGet(inGUIDStr=lGUIDStr)
if self.mProcessNameWOExeStr.upper() in lUserProcessList:
if self.mStatusStr == "1_STOPPED_MANUAL": self.mStatusStr = "5_STARTED_MANUAL"; lLogBool=True
if self.mStatusStr == "0_STOPPED": self.mStatusStr = "4_STARTED"; lLogBool=True
if self.mStatusStr is None: self.mStatusStr = "4_STARTED"; lLogBool=True
else:
if self.mStatusStr == "2_STOP_SAFE": self.mStatusStr = "0_STOPPED"; lLogBool = True
if self.mStatusStr == "3_STOP_SAFE_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool = True
if self.mStatusStr == "5_STARTED_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool=True
if self.mStatusStr == "4_STARTED": self.mStatusStr = "0_STOPPED"; lLogBool=True
if self.mStatusStr is None: self.mStatusStr = "0_STOPPED"; lLogBool=True
# Log info about process
if lLogBool == True: self.StatusChangeLog()
self.mAgentMuteBool = False
return self.mStatusStr
def StatusCheckStart(self):
"""
Check process status and run it if auto stopped self.mStatusStr is "0_STOPPED"

@ -70,7 +70,7 @@ def ActivityListExecute(inGSettings, inActivityList):
lResultList = [] # init the result list
try:
for lActivityItem in inActivityList: # Iterate throught the activity list
if lL: lL.info(f'Процессор:: Исполнение функции def:{str(lActivityItem["Def"])}. В целях информационной безопасности параметры недоступны для просмотра')
if lL: lL.info(f'pyOpenRPA Processor.ActivityListExecute:: Def:{str(lActivityItem["Def"])}. Parameters are not available to see.')
lDef = None # Def variable
if callable(lActivityItem["Def"]): # CHeck if def is callable
lDef = lActivityItem["Def"] # Get the def
@ -79,7 +79,7 @@ def ActivityListExecute(inGSettings, inActivityList):
#gSettings
lGSettingsDictKey = lActivityItem.pop("ArgGSettings",None)
# # Prepare arg dict - gSettings
if type(lGSettingsDictKey) is str and lGSettingsDictKey != "": # check if gSetting key is in ArgDict 13.02.2021 - Fix when ArgGSettings is ""
if type(lGSettingsDictKey) is str and lGSettingsDictKey is not "": # check if gSetting key is in ArgDict 13.02.2021 - Fix when ArgGSettings is ""
lActivityItem["ArgDict"][lGSettingsDictKey] = inGSettings # Set the gSettings in dict
# # Prepare arg list
elif type(lGSettingsDictKey) is int: # check if gSetting key is in ArgDict
@ -87,7 +87,7 @@ def ActivityListExecute(inGSettings, inActivityList):
#Logger
lLoggerDictKey = lActivityItem.pop("ArgLogger",None)
# # Prepare arg dict - Logger
if type(lLoggerDictKey) is str and lLoggerDictKey != "": # check if gSetting key is in ArgDict 13.02.2021 - Fix when ArgLogger is ""
if type(lLoggerDictKey) is str and lLoggerDictKey is not "": # check if gSetting key is in ArgDict 13.02.2021 - Fix when ArgLogger is ""
lActivityItem["ArgDict"][lLoggerDictKey] = lL # Set the lLogger in dict
# # Prepare arg list
elif type(lLoggerDictKey) is int: # check if gSetting key is in ArgDict

@ -62,22 +62,22 @@ def RobotRDPActive(inGSettings, inThreadControlDict):
try:
Connector.Session(lRDPConfigurationDict, inScreenSize550x350Bool = True)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
if lL: lL.info(f"Хост: {lRDPConfigurationDict['Host']}, Логин: {lRDPConfigurationDict['Login']}, Идентификатор сессии: {str(lRDPConfigurationDict['SessionHex'])}:: Сессия была инициализирована!") #Logging
if lL: lL.info(f"Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}, SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
if lL: lL.warning(f"Хост: {lRDPConfigurationDict['Host']}, Логин: {lRDPConfigurationDict['Login']}, Идентификатор сессии: {str(lRDPConfigurationDict['SessionHex'])}:: Сессия не обнаружена - попытаться подключиться!") #Logging
if lL: lL.warning(f"Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}, SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist! Mark the retry") #Logging
# Recovery operations
Recovery.RetryMark(inRDPSessionKeyStr=lRDPSessionKeyStr,inGSettings=inGSettings)
if Recovery.RetryIsTriggered(inRDPSessionKeyStr=lRDPSessionKeyStr,inGSettings=inGSettings) == True:
if lL: lL.warning(f"!ВНИМАНИЕ! Хост: {lRDPConfigurationDict['Host']}, Логин: {lRDPConfigurationDict['Login']}; сессия РДП недоступна при попытках подключения - инициализация режима восстановления")
if lL: lL.warning(f"!ATTENTION! Host: {lRDPConfigurationDict['Host']}, Login: {lRDPConfigurationDict['Login']}; RDP is not responsible for many times - run recovery mode")
Recovery.RetryHostClear(inHostStr=lRDPConfigurationDict['Host'],inGSettings=inGSettings) # Clear the stat about current host
if inGSettings["RobotRDPActive"]["RecoveryDict"]["DoDict"]["OSRemotePCRestart"] == True:
if lL: lL.warning(f"!ВНИМАНИЕ! Хост: {lRDPConfigurationDict['Host']}, отправить сигнал на перезагрузку удаленной машины")
if lL: lL.warning(f"!ATTENTION! Host: {lRDPConfigurationDict['Host']}, Send signal to restart remote PC.")
__Orchestrator__.OSRemotePCRestart(inLogger=lL,inHostStr=lRDPConfigurationDict['Host'],inForceBool=True)
# general exceptions
except Exception as e:
if lL: lL.exception(f"!!! ВНИМАНИЕ !!! Неопознанная ошибка. Обратитесь в тех. поддержку pyOpenRPA") #Logging
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging
pass
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Connector.SystemRDPWarningClickOk() # Click all warning messages
@ -125,7 +125,7 @@ def RobotRDPActive(inGSettings, inThreadControlDict):
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
except Exception as e:
if lL: lL.exception(f"РДП: Ошибка при обработке активности в процессоре РДП сессии - активность будет проигнорирована. Активность: {lActivityItem}") #Logging
if lL: lL.exception(f"RDP::main: Exception when run def in processor.py - activity will be ignored. Activity item: {lActivityItem}") #Logging
lActivityItemResult = True # True - clear from repeat list
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
@ -137,7 +137,7 @@ def RobotRDPActive(inGSettings, inThreadControlDict):
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
except RuntimeError as e:
# case noGUI error passed - do nothing
if lL: lL.warning(f"Оркестратор потерял графическую сессию - повторить попытку через несколько секунд") #Logging
if lL: lL.warning(f"Host session has lost the GUI") #Logging
finally:
# Wait for the next iteration
time.sleep(0.7)
@ -145,4 +145,4 @@ def RobotRDPActive(inGSettings, inThreadControlDict):
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#Monitor.Monitor(mGSettingsRDPActiveDict, 1)
except Exception as e:
if lL: lL.exception(f"!!! ВНИМАНИ !!! В модуле РДП произошла критическая ошибка. Обратитесь в службу тех. поддержки pyOpenRPA") #Logging
if lL: lL.exception(f"!!! ATTENTION !!! Global error handler - look at code") #Logging

@ -10,7 +10,7 @@ def CheckScreen(inIntervalSeconds=1):
#Send os command to create console version (base screen)
Screen.ConsoleScreenBase()
#Delay to create console screen
time.sleep(15)
time.sleep(5)
#Delay
time.sleep(inIntervalSeconds)
return None

@ -6,221 +6,664 @@
# lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
# self.OpenRPAResponseDict = lResponseDict
#from http.client import HTTPException
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import threading
import json
from threading import Thread
import inspect
from pyOpenRPA.Tools import CrossOS
from http import cookies
from . import ServerBC
# объявление import
from fastapi import FastAPI, Form, Request, HTTPException, Depends, Header, Response, Body
from fastapi.responses import PlainTextResponse, HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel
import uvicorn
import io
from starlette.responses import StreamingResponse
from typing import Union
from pyOpenRPA import __version__
from . import Processor # Add new processor
from . import ProcessorOld # Support old processor - deprecated defs only for backward compatibility
import urllib.parse # decode URL in string
import importlib
import pdb
import base64
import uuid
import datetime
import os #for path operations
from http import cookies
global gSettingsDict
from . import ServerSettings
from . import __Orchestrator__
import copy
import mimetypes
mimetypes.add_type("font/woff2",".woff2")
# ИНИЦИАЛИЗАЦИЯ FASTAPI!
app = FastAPI(
title = "pyOpenRPA (ORPA) Orchestrator",
description = "Сервер оркестратора pyOpenRPA Orchestrator",
version = __version__,
openapi_url="/orpa/fastapi/openapi.json",
docs_url = "/orpa/fastapi/docs",
redoc_url = "/orpa/fastapi/redoc",
swagger_ui_oauth2_redirect_url = "/orpa/fastapi/docs/oauth2-redirect",
)
gCacheDict = {}
def IdentifyAuthorize(inRequest:Request, inResponse:Response,
inCookiesStr: Union[str, None] = Header(default=None,alias="Cookie"),
inAuthorizationStr: Union[str, None] = Header(default="",alias="Authorization")):
if __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False)==True:
lResult={"Domain": "", "User": ""}
######################################
#Way 1 - try to find AuthToken
lCookies = cookies.SimpleCookie(inCookiesStr) # inRequest.headers.get("Cookie", "")
__Orchestrator__.GSettingsGet()
lHeaderAuthorization = inAuthorizationStr.split(" ")
if "AuthToken" in lCookies:
lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken:
#Find AuthToken in GlobalDict
if lCookieAuthToken in __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
#Auth Token Has Been Founded
lResult["Domain"] = __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token
mOpenRPA={}
mOpenRPA["AuthToken"] = lCookieAuthToken
mOpenRPA["Domain"] = lResult["Domain"]
mOpenRPA["User"] = lResult["User"]
mOpenRPA["IsSuperToken"] = __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(mOpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
return lCookieAuthToken
######################################
#Way 2 - try to logon
if len(lHeaderAuthorization) == 2:
llHeaderAuthorizationDecodedUserPasswordList = base64.b64decode(lHeaderAuthorization[1]).decode("utf-8").split(
":")
lUser = llHeaderAuthorizationDecodedUserPasswordList[0]
lPassword = llHeaderAuthorizationDecodedUserPasswordList[1]
lDomain = ""
if "\\" in lUser:
lDomain = lUser.split("\\")[0]
lUser = lUser.split("\\")[1]
lLogonBool = __Orchestrator__.OSCredentialsVerify(inUserStr=lUser, inPasswordStr=lPassword, inDomainStr=lDomain)
#Check result
if lLogonBool:
lResult["Domain"] = lDomain
lResult["User"] = lUser
#Create token
lAuthToken=str(uuid.uuid1())
__Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
__Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
__Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
__Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
__Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inResponse.set_cookie(key="AuthToken",value=lAuthToken)
mOpenRPA={}
mOpenRPA["AuthToken"] = lAuthToken
mOpenRPA["Domain"] = lResult["Domain"]
mOpenRPA["User"] = lResult["User"]
mOpenRPA["IsSuperToken"] = __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(mOpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
return lAuthToken
#inRequest.OpenRPASetCookie = {}
#New engine of server
#inRequest.OpenRPAResponseDict["SetCookies"]["AuthToken"] = lAuthToken
# Tool to merge complex dictionaries
def __ComplexDictMerge2to1__(in1Dict, in2Dict):
lPathList=None
if lPathList is None: lPathList = []
for lKeyStr in in2Dict:
if lKeyStr in in1Dict:
if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict):
__ComplexDictMerge2to1__(in1Dict[lKeyStr], in2Dict[lKeyStr])
elif in1Dict[lKeyStr] == in2Dict[lKeyStr]:
pass # same leaf value
else:
raise HTTPException(status_code=401, detail="Попытка авторизации не прошла успешно (неверная пара логин / пароль)", headers={})
######################################
raise Exception('Conflict at %s' % '.'.join(lPathList + [str(lKeyStr)]))
else:
raise HTTPException(status_code=401, detail="Попытка авторизации не прошла успешно (неполная пара логин / пароль)", headers={'Content-type':'text/html', 'WWW-Authenticate':'Basic'})
else: return None # Credentials are not required - return none
lRouteList =[]
for lItem in app.router.routes:
lRouteList.append(lItem)
app.router.routes=[]
for lItem in lRouteList:
app.add_api_route(
path=lItem.path,
endpoint=lItem.endpoint,
methods=["GET"],
dependencies=[Depends(IdentifyAuthorize)],
tags=["FastAPI"]
)
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
from . import ServerSettings
# Tool to merge complex dictionaries - no exceptions, just overwrite dict 2 in dict 1
def __ComplexDictMerge2to1Overwrite__(in1Dict, in2Dict):
"""
Merge in2Dict in in1Dict. In conflict override and get value from dict 2
def BackwardCompatibility(inRequest:Request, inResponse:Response, inBodyStr:str = Body(""), inAuthTokenStr = None):
lHTTPRequest = ServerBC.HTTPRequestOld(inRequest=inRequest, inResponse=inResponse, inAuthTokenStr=inAuthTokenStr)
lHTTPRequest.path = inRequest.url.path
lHTTPRequest.body = inBodyStr
lHTTPRequest.client_address = [inRequest.client.host]
threading.current_thread().request = lHTTPRequest
lResult = lHTTPRequest.do_GET(inBodyStr=inBodyStr)
if lResult is None:
lResult = lHTTPRequest.do_POST(inBodyStr=inBodyStr)
if lHTTPRequest.OpenRPAResponseDict["Headers"]["Content-type"] != None:
return StreamingResponse(io.BytesIO(lResult), media_type=lHTTPRequest.OpenRPAResponseDict["Headers"]["Content-type"])
#WRAPPERS!
def BackwardCompatibityWrapperAuth(inRequest:Request, inResponse:Response, inBodyStr:str = Body(""),
inAuthTokenStr:str=Depends(ServerSettings.IdentifyAuthorize)): # Old from v1.3.1 (updated to FastAPI)
return BackwardCompatibility(inRequest = inRequest, inResponse = inResponse, inBodyStr = inBodyStr, inAuthTokenStr=inAuthTokenStr)
def BackwardCompatibityWrapperNoAuth(inRequest:Request, inResponse:Response, inBodyStr:str = Body("")): # Old from v1.3.1 (updated to FastAPI)
return BackwardCompatibility(inRequest = inRequest, inResponse = inResponse, inBodyStr = inBodyStr, inAuthTokenStr=None)
def BackwardCompatibityBeginWrapperAuth(inBeginTokenStr, inRequest:Request, inResponse:Response, inBodyStr:str = Body(""),
inAuthTokenStr:str=Depends(ServerSettings.IdentifyAuthorize)): # Old from v1.3.1 (updated to FastAPI)
return BackwardCompatibility(inRequest = inRequest, inResponse = inResponse, inBodyStr = inBodyStr, inAuthTokenStr=inAuthTokenStr)
def BackwardCompatibityBeginWrapperNoAuth(inBeginTokenStr, inRequest:Request, inResponse:Response, inBodyStr:str = Body("")): # Old from v1.3.1 (updated to FastAPI)
return BackwardCompatibility(inRequest = inRequest, inResponse = inResponse, inBodyStr = inBodyStr, inAuthTokenStr=None)
:param in1Dict: Source dict. Save the link (structure)
:param in2Dict: New data dict
:return: Merged dict 1
"""
lPathList=None
if lPathList is None: lPathList = []
for lKeyStr in in2Dict:
if lKeyStr in in1Dict:
if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict):
__ComplexDictMerge2to1Overwrite__(in1Dict[lKeyStr], in2Dict[lKeyStr])
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
#Authenticate function ()
# return dict
# {
# "Domain": "", #Empty if Auth is not success
# "User": "" #Empty if Auth is not success
# }
def AuthenticateVerify(inRequest):
lResult={"Domain": "", "User": ""}
######################################
#Way 1 - try to find AuthToken
lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", ""))
#pdb.set_trace()
if "AuthToken" in lCookies:
lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken:
#Find AuthToken in GlobalDict
if lCookieAuthToken in gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
#Auth Token Has Been Founded
lResult["Domain"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
inRequest.OpenRPA["User"] = lResult["User"]
#Exit earlier
return lResult
######################################
#Way 2 - try to logon
lHeaderAuthorization = inRequest.headers.get("Authorization", "").split(" ")
if len(lHeaderAuthorization) == 2:
llHeaderAuthorizationDecodedUserPasswordList = base64.b64decode(lHeaderAuthorization[1]).decode("utf-8").split(
":")
lUser = llHeaderAuthorizationDecodedUserPasswordList[0]
lPassword = llHeaderAuthorizationDecodedUserPasswordList[1]
lDomain = ""
if "\\" in lUser:
lDomain = lUser.split("\\")[0]
lUser = lUser.split("\\")[1]
lLogonBool = __Orchestrator__.OSCredentialsVerify(inUserStr=lUser, inPasswordStr=lPassword, inDomainStr=lDomain)
#Check result
if lLogonBool:
lResult["Domain"] = lDomain
lResult["User"] = lUser
#Create token
lAuthToken=str(uuid.uuid1())
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
inRequest.OpenRPA["User"] = lResult["User"]
inRequest.OpenRPASetCookie = {}
#New engine of server
inRequest.OpenRPAResponseDict["SetCookies"]["AuthToken"] = lAuthToken
#inRequest.OpenRPAResponse["Set-Cookie"]=[]lResult["Set-Cookie"] = lAuthToken
#pdb.set_trace()
#inRequest.send_header("Set-Cookie:", f"AuthToken={lAuthToken}")
######################################
return lResult
def AuthenticateBlock(inRequest):
# Send response status code
inRequest.send_response(401)
# Send headers
inRequest.send_header('Content-type', 'text/html')
inRequest.send_header('WWW-Authenticate', 'Basic') # Always ask login pass
inRequest.end_headers()
# Write content as utf-8 data
inRequest.wfile.write(bytes("", "utf8"))
#Check access before execute the action
#return bool True - go execute, False - dont execute
def UserAccessCheckBefore(inMethod, inRequest):
# Help def - Get access flag from dict
#pdb.set_trace()
def HelpGetFlag(inAccessRuleItem, inRequest, inGlobalDict, inAuthenticateDict):
if "FlagAccess" in inAccessRuleItem:
return inAccessRuleItem["FlagAccess"]
elif "FlagAccessDefRequestGlobalAuthenticate" in inAccessRuleItem:
return inAccessRuleItem["FlagAccessDefRequestGlobalAuthenticate"](inRequest, inGlobalDict,
inAuthenticateDict)
##########################################
inMethod=inMethod.upper()
#Prepare result false
lResult = False
lAuthToken = inRequest.OpenRPA["AuthToken"]
#go next if user is identified
lUserDict = None
if lAuthToken:
lUserDict = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace()
########################################
########################################
#Check general before rule (without User domain)
#Check rules
inRuleMatchURLList = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", [])
for lAccessRuleItem in inRuleMatchURLList:
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
if lAccessRuleItem["Method"].upper() == inMethod:
#check Match type variant: BeginWith
if lAccessRuleItem["MatchType"].upper() == "BEGINWITH":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#########################################
#########################################
#Do check if lResult is false
if not lResult:
#Check access by User Domain
#Check rules to find first appicable
#Check rules
lMethodMatchURLList = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", [])
if len(lMethodMatchURLList) > 0:
for lAccessRuleItem in lMethodMatchURLList:
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
if lAccessRuleItem["Method"].upper() == inMethod:
#check Match type variant: BeginWith
if lAccessRuleItem["MatchType"].upper() == "BEGINWITH":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
else:
return True
#####################################
#####################################
#Return lResult
return lResult
# HTTPRequestHandler class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Def to check User Role access grants
def UACClientCheck(self, inRoleKeyList): # Alias
return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList)
def UserRoleAccessAsk(self, inRoleKeyList):
lResult = True # Init flag
lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy
# Try to get value from key list
lKeyValue = lRoleHierarchyDict # Init the base
for lItem in inRoleKeyList:
if type(lKeyValue) is dict:
if lItem in lKeyValue: # Has key
lKeyValue = lKeyValue[lItem] # Get the value and go to the next loop iteration
else: # Else branch - true or false
if len(lKeyValue)>0: # False - if Dict has some elements
lResult = False # Set the False Flag
else:
lResult = True # Set the True flag
break # Stop the loop
else: # Has element with no detalization - return True
lResult = True # Set the flag
break # Close the loop
return lResult # Return the result
# Def to get hierarchy of the current user roles
# if return {} - all is available
def UserRoleHierarchyGet(self):
lDomainUpperStr = self.OpenRPA["Domain"].upper()
lUserUpperStr = self.OpenRPA["User"].upper()
return gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {})
from . import __Orchestrator__
import mimetypes
mimetypes.add_type("font/woff2",".woff2")
mimetypes.add_type("text/javascript",".js")
from typing import Union
#Tech def
#return {"headers":[],"body":"","statuscode":111}
def URLItemCheckDo(self, inURLItem, inMethod, inOnlyFlagUACBool = False):
###############################
#Tech sub def - do item
################################
def URLItemDo(inURLItem,inRequest,inGlobalDict):
global gCacheDict
inResponseDict = inRequest.OpenRPAResponseDict
inResponseDict["Headers"]["Content-type"]= None
#Set status code 200
inResponseDict["StatusCode"] = 200
#Content-type
if "ResponseContentType" in inURLItem:
inResponseDict["Headers"]["Content-type"] = inURLItem["ResponseContentType"]
#If file path is set
if "ResponseFilePath" in inURLItem:
# Check cache
if inURLItem.get("UseCacheBool",False) == True:
if inURLItem["ResponseFilePath"] in gCacheDict:
# Write content as utf-8 data
inResponseDict["Body"] = gCacheDict[inURLItem["ResponseFilePath"]]
else:
lFileObject = open(CrossOS.PathStr(inURLItem["ResponseFilePath"]), "rb")
# Write content as utf-8 data
gCacheDict[inURLItem["ResponseFilePath"]] = lFileObject.read()
inResponseDict["Body"] = gCacheDict[inURLItem["ResponseFilePath"]]
# Закрыть файловый объект
lFileObject.close()
else:
lFileObject = open(CrossOS.PathStr(inURLItem["ResponseFilePath"]), "rb")
# Write content as utf-8 data
inResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект
lFileObject.close()
# detect MIME type if none
if inResponseDict["Headers"]["Content-type"] is None:
inResponseDict["Headers"]["Content-type"]= mimetypes.guess_type(inURLItem["ResponseFilePath"])[0]
#If function is set
if "ResponseDefRequestGlobal" in inURLItem:
lDef = inURLItem["ResponseDefRequestGlobal"]
lDefSignature = inspect.signature(lDef)
if len(lDefSignature.parameters) == 2:
inURLItem["ResponseDefRequestGlobal"](inRequest, inGlobalDict)
elif len(lDefSignature.parameters) == 1:
inURLItem["ResponseDefRequestGlobal"](inRequest)
else:
inURLItem["ResponseDefRequestGlobal"]()
if "ResponseFolderPath" in inURLItem:
def InitFastAPI():
global app
lL = __Orchestrator__.OrchestratorLoggerGet()
__Orchestrator__.GSettingsGet()["ServerDict"]["ServerThread"] = app
ServerSettings.SettingsUpdate()
BCURLUpdate()
#lRequestPath = inRequest.path
lRequestPath = urllib.parse.unquote(inRequest.path)
if inURLItem["URL"][-1]!="/": inURLItem["URL"]+= "/" # Fix for settings
lFilePathSecondPart = lRequestPath.replace(inURLItem["URL"],"")
lFilePathSecondPart = lFilePathSecondPart.split("?")[0]
lFilePath = os.path.join(CrossOS.PathStr(inURLItem["ResponseFolderPath"]),lFilePathSecondPart)
#print(f"File full path {lFilePath}")
#Check if file exist
if os.path.exists(lFilePath) and os.path.isfile(lFilePath):
# Check cache
if inURLItem.get("UseCacheBool",False) == True:
if lFilePath in gCacheDict:
# Write content as utf-8 data
inResponseDict["Body"] = gCacheDict[lFilePath]
else:
lFileObject = open(lFilePath, "rb")
# Write content as utf-8 data
gCacheDict[lFilePath] = lFileObject.read()
inResponseDict["Body"] = gCacheDict[lFilePath]
# Закрыть файловый объект
lFileObject.close()
else:
lFileObject = open(lFilePath, "rb")
# Write content as utf-8 data
inResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект
lFileObject.close()
# detect MIME type if none
if inResponseDict["Headers"]["Content-type"] is None:
inResponseDict["Headers"]["Content-type"]= mimetypes.guess_type(lFilePath)[0]
# If No content-type
if inResponseDict["Headers"]["Content-type"] is None:
inResponseDict["Headers"]["Content-type"]= "application/octet-stream"
##############################################
# UAC Check
if inOnlyFlagUACBool == True and inURLItem.get("UACBool",None) in [None, True]:
return False
if inURLItem["Method"].upper() == inMethod.upper():
# check Match type variant: BeginWith
if inURLItem["MatchType"].upper() == "BEGINWITH":
lURLPath = urllib.parse.unquote(self.path)
lURLPath = lURLPath.upper()
if lURLPath.startswith(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Contains
elif inURLItem["MatchType"].upper() == "CONTAINS":
lURLPath = urllib.parse.unquote(self.path)
lURLPath = lURLPath.upper()
if lURLPath.contains(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: Equal
elif inURLItem["MatchType"].upper() == "EQUAL":
if inURLItem["URL"].upper() == urllib.parse.unquote(self.path).upper():
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: EqualNoParam
elif inURLItem["MatchType"].upper() == "EQUALNOPARAM":
if inURLItem["URL"].upper() == urllib.parse.unquote(self.path).upper().split("?")[0]:
URLItemDo(inURLItem, self, gSettingsDict)
return True
# check Match type variant: EqualCase
elif inURLItem["MatchType"].upper() == "EQUALCASE":
if inURLItem["URL"] == urllib.parse.unquote(self.path):
URLItemDo(inURLItem, self, gSettingsDict)
return True
return False
#ResponseContentTypeFile
def SendResponseContentTypeFile(self, inContentType, inFilePath):
# Send response status code
self.send_response(200)
# Send headers
self.send_header('Content-type', inContentType)
#Check if var exist
if hasattr(self, "OpenRPASetCookie"):
self.send_header("Set-Cookie", f"AuthToken={self.OpenRPA['AuthToken']}")
self.end_headers()
lFileObject = open(inFilePath, "rb")
# Write content as utf-8 data
self.wfile.write(lFileObject.read())
#Закрыть файловый объект
lFileObject.close()
# ResponseContentTypeFile
def ResponseDictSend(self):
lL = gSettingsDict["Logger"]
inResponseDict = self.OpenRPAResponseDict
# Send response status code
self.send_response(inResponseDict["StatusCode"])
# Send headers
for lItemKey, lItemValue in inResponseDict["Headers"].items():
self.send_header(lItemKey, lItemValue)
# Send headers: Set-Cookie
for lItemKey, lItemValue in inResponseDict["SetCookies"].items():
self.send_header("Set-Cookie", f"{lItemKey}={lItemValue}")
#Close headers section in response
try:
self.end_headers()
# Write content as utf-8 data
self.wfile.write(inResponseDict["Body"])
except (ConnectionResetError, ConnectionAbortedError) as e:
if lL: lL.warning(f"SERVER: Connection was forcibly closed by the client side - OK for the network interactions (ConnectionResetError: [WinError 10054] or ConnectionAbortedError: [WinError 10053])")
def BCURLUpdate():
for lConnectItemDict in __Orchestrator__.GSettingsGet()["ServerDict"]["URLList"]:
if "BCBool" not in lConnectItemDict:
if "ResponseFolderPath" in lConnectItemDict:
app.mount(lConnectItemDict["URL"],
StaticFiles(directory=CrossOS.PathStr(lConnectItemDict["ResponseFolderPath"])),
name=lConnectItemDict["URL"].replace('/',"_"))
def do_GET(self):
try:
threading.current_thread().request = self
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
############################
#First - all with Flag UACBool
############################
for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(inURLItem=lURLItem, inMethod="GET", inOnlyFlagUACBool=True)
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
# gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
if lConnectItemDict.get("MatchType") in ["EqualCase", "Equal","EqualNoParam"]:
if lConnectItemDict.get("UACBool",True):
app.add_api_route(
path=lConnectItemDict["URL"],
endpoint=BackwardCompatibityWrapperAuth,
response_class=PlainTextResponse,
methods=[lConnectItemDict["Method"]],
tags=["BackwardCompatibility"]
)
else:
app.add_api_route(
path=lConnectItemDict["URL"],
endpoint=BackwardCompatibityWrapperNoAuth,
response_class=PlainTextResponse,
methods=[lConnectItemDict["Method"]],
tags=["BackwardCompatibility"]
)
elif lConnectItemDict.get("MatchType") in ["BeginWith", "Contains"]:
lURLStr = lConnectItemDict["URL"]
if lURLStr[-1]!="/": lURLStr+="/"
lURLStr+="{inBeginTokenStr}"
if lConnectItemDict.get("UACBool",True):
app.add_api_route(
path=lURLStr,
endpoint=BackwardCompatibityBeginWrapperAuth,
response_class=PlainTextResponse,
methods=[lConnectItemDict["Method"]],
tags=["BackwardCompatibility"]
)
else:
app.add_api_route(
path=lURLStr,
endpoint=BackwardCompatibityBeginWrapperNoAuth,
response_class=PlainTextResponse,
methods=[lConnectItemDict["Method"]],
tags=["BackwardCompatibility"]
)
lConnectItemDict["BCBool"]=True
def InitUvicorn(inHostStr=None, inPortInt=None, inSSLCertPathStr=None, inSSLKeyPathStr=None, inSSLPasswordStr=None):
if inHostStr is None: inHostStr="0.0.0.0"
if inPortInt is None: inPortInt=1024
if inSSLCertPathStr != None: inSSLCertPathStr=CrossOS.PathStr(inSSLCertPathStr)
if inSSLKeyPathStr != None: inSSLKeyPathStr=CrossOS.PathStr(inSSLKeyPathStr)
global app
lL = __Orchestrator__.OrchestratorLoggerGet()
#uvicorn.run('pyOpenRPA.Orchestrator.Server:app', host='0.0.0.0', port=1024)
uvicorn.run(app, host=inHostStr, port=inPortInt,ssl_keyfile=inSSLKeyPathStr,ssl_certfile=inSSLCertPathStr,ssl_keyfile_password=inSSLPasswordStr)
if lL and inSSLKeyPathStr != None: lL.info(f"Сервер инициализирован успешно (с поддержкой SSL):: Слушает URL: {inHostStr}, Слушает порт: {inPortInt}, Путь к файлу сертификата (.pem, base64): {inSSLCertPathStr}")
if lL and inSSLKeyPathStr == None: lL.info(f"Сервер инициализирован успешно (без поддержки SSL):: Слушает URL: {inHostStr}, Слушает порт: {inPortInt}")
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
if CrossOS.IS_WINDOWS_BOOL: lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
if CrossOS.IS_LINUX_BOOL: lOrchestratorFolder = "/".join(__file__.split("/")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Monitor
if self.path == '/Monitor/JSONDaemonListGet':
# Send response status code
self.send_response(200)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Send message back to client
message = json.dumps(gSettingsDict)
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
#Filemanager function
if self.path.lower().startswith('/filemanager/'):
lFileURL=self.path[13:]
# check if file in FileURL - File Path Mapping Dict
if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL])
# Index page
elif self.path == gSettingsDict["ServerDict"]["URLIndexStr"]:
lURLItemDict = {
"Method":"GET",
"URL": gSettingsDict["ServerDict"]["URLIndexStr"],
"MatchType": "EqualCase",
"ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\Index.xhtml"),
"ResponseContentType": "text/html"}
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItemDict, "GET")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
else:
#Set access denied code
# Send response status code
self.send_response(403)
# Send headers
self.end_headers()
except Exception as e:
lL = gSettingsDict["Logger"]
if lL: lL.exception(f"Server.do_GET: Global error handler - look traceback below.")
# POST
def do_POST(self):
try:
threading.current_thread().request = self
lL = gSettingsDict["Logger"]
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
#pdb.set_trace()
lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
############################
#First - all with Flag UACBool
############################
for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(inURLItem=lURLItem, inMethod="POST", inOnlyFlagUACBool=True)
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Централизованная функция получения запросов/отправки
if self.path == '/Utils/Processor':
#ReadRequest
lInputObject={}
if self.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(self.headers.get('Content-Length'))
lInputByteArray=self.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lInputObject=json.loads(lInputByteArray.decode('utf8'))
# Send response status code
self.send_response(200)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Logging info about processor activity if not SuperToken ()
if not lIsSuperToken:
lActivityTypeListStr = ""
try:
if type(lInputObject) is list:
for lActivityItem in lInputObject:
lActivityTypeListStr+=f"{lActivityItem['Type']}; "
else:
lActivityTypeListStr += f"{lInputObject['Type']}"
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"Server:: !ATTENTION! /Utils/Processor will be deprecated in future. Use /pyOpenRPA/Processor or /pyOpenRPA/ActivityListExecute. User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Send message back to client
message = json.dumps(ProcessorOld.ActivityListOrDict(lInputObject))
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
return
else:
#Set access denied code
# Send response status code
self.send_response(403)
# Send headers
self.end_headers()
return
except Exception as e:
lL = gSettingsDict["Logger"]
if lL: lL.exception(f"Server.do_POST: Global error handler - look traceback below.")
#Logging
#!Turn it on to stop print in console
#def log_message(self, format, *args):
# return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
"""Handle requests in a separate thread."""
def finish_request(self, request, client_address):
request.settimeout(gSettingsDict["ServerDict"]["RequestTimeoutSecFloat"])
# "super" can not be used because BaseServer is not created from object
HTTPServer.finish_request(self, request, client_address)
#inGlobalDict
# "JSONConfigurationDict":<JSON>
import ssl
class RobotDaemonServer(Thread):
def __init__(self,name,inGlobalDict):
Thread.__init__(self)
self.name = name
# Update the global dict
ServerSettings.SettingsUpdate(inGlobalDict)
def run(self):
lL = gSettingsDict.get("Logger",None)
try:
lServerDict = gSettingsDict["ServerDict"]["ListenDict"][self.name]
lAddressStr=lServerDict["AddressStr"]
lPortInt=lServerDict["PortInt"]
lCertFilePathStr = lServerDict["CertFilePEMPathStr"]
lKeyFilePathStr = lServerDict["KeyFilePathStr"]
if lCertFilePathStr == "": lCertFilePathStr = None
if lKeyFilePathStr == "": lKeyFilePathStr = None
# Server settings
# Choose port 8080, for port 80, which is normally used for a http server, you need root access
server_address = (lAddressStr, lPortInt)
#httpd = HTTPServer(server_address, testHTTPServer_RequestHandler)
#httpd.serve_forever()
httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler)
if lCertFilePathStr is not None:
if lKeyFilePathStr is not None:
httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile=lCertFilePathStr, keyfile=lKeyFilePathStr)
else:
httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile=lCertFilePathStr)
if lL: lL.info(f"Web Server init (with SSL). Name: {self.name}, Listen URL: {lAddressStr}, Listen port: {lPortInt}, Cert path: {lCertFilePathStr}")
else:
if lL: lL.info(f"Web Server init. Name: {self.name}, Listen URL: {lAddressStr}, Listen port: {lPortInt}")
#print('Starting server, use <Ctrl-C> to stop')
httpd.serve_forever()
except Exception as e:
if lL: lL.exception(f"Web Server execution exception")

@ -1,424 +0,0 @@
import inspect
from pyOpenRPA.Tools import CrossOS
import urllib.parse # decode URL in string
import os #for path operations
from . import __Orchestrator__
import mimetypes
mimetypes.add_type("font/woff2",".woff2")
mimetypes.add_type("application/javascript",".js")
# объявление import
from fastapi import FastAPI, Form, Request, HTTPException, Depends, Header, Response, Body
gCacheDict = {}
# Tool to merge complex dictionaries
def __ComplexDictMerge2to1__(in1Dict, in2Dict):
lPathList=None
if lPathList is None: lPathList = []
for lKeyStr in in2Dict:
if lKeyStr in in1Dict:
if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict):
__ComplexDictMerge2to1__(in1Dict[lKeyStr], in2Dict[lKeyStr])
elif in1Dict[lKeyStr] == in2Dict[lKeyStr]:
pass # same leaf value
else:
raise Exception('Conflict at %s' % '.'.join(lPathList + [str(lKeyStr)]))
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
# Tool to merge complex dictionaries - no exceptions, just overwrite dict 2 in dict 1
def __ComplexDictMerge2to1Overwrite__(in1Dict, in2Dict):
"""
Merge in2Dict in in1Dict. In conflict override and get value from dict 2
:param in1Dict: Source dict. Save the link (structure)
:param in2Dict: New data dict
:return: Merged dict 1
"""
lPathList=None
if lPathList is None: lPathList = []
for lKeyStr in in2Dict:
if lKeyStr in in1Dict:
if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict):
__ComplexDictMerge2to1Overwrite__(in1Dict[lKeyStr], in2Dict[lKeyStr])
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
def AuthenticateBlock(inRequest):
raise HTTPException(status_code=401, detail="here is the details", headers={'Content-type':'text/html', 'WWW-Authenticate':'Basic'})
#Check access before execute the action
#return bool True - go execute, False - dont execute
def UserAccessCheckBefore(inMethod, inRequest):
# Help def - Get access flag from dict
#pdb.set_trace()
def HelpGetFlag(inAccessRuleItem, inRequest, inGlobalDict, inAuthenticateDict):
if "FlagAccess" in inAccessRuleItem:
return inAccessRuleItem["FlagAccess"]
elif "FlagAccessDefRequestGlobalAuthenticate" in inAccessRuleItem:
return inAccessRuleItem["FlagAccessDefRequestGlobalAuthenticate"](inRequest, inGlobalDict,
inAuthenticateDict)
##########################################
inMethod=inMethod.upper()
#Prepare result false
lResult = False
lAuthToken = inRequest.OpenRPA["AuthToken"]
#go next if user is identified
lUserDict = None
#print(f"lAuthToken: {lAuthToken}")
if lAuthToken:
lUserDict = __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#print(f"lUserDict: {lUserDict}")
#pdb.set_trace()
########################################
########################################
#Check general before rule (without User domain)
#Check rules
inRuleMatchURLList = __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", [])
for lAccessRuleItem in inRuleMatchURLList:
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
if lAccessRuleItem["Method"].upper() == inMethod:
#check Match type variant: BeginWith
if lAccessRuleItem["MatchType"].upper() == "BEGINWITH":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict)
# check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict)
#########################################
#########################################
#Do check if lResult is false
if not lResult:
#Check access by User Domain
#Check rules to find first appicable
#Check rules
lMethodMatchURLList = __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", [])
if len(lMethodMatchURLList) > 0:
for lAccessRuleItem in lMethodMatchURLList:
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
if lAccessRuleItem["Method"].upper() == inMethod:
#check Match type variant: BeginWith
if lAccessRuleItem["MatchType"].upper() == "BEGINWITH":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict)
else:
return True
#####################################
#####################################
#Return lResult
return lResult
class HTTPRequestOld():
mRequest:Request = None
mResponse:Response = None
OpenRPA: dict = {}
headers={}
def __init__(self,inRequest,inResponse,inAuthTokenStr):
self.mRequest = inRequest
self.mResponse = inResponse
if inAuthTokenStr != None:
self.OpenRPA = {}
self.OpenRPA["IsSuperToken"] = __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr)
self.OpenRPA["AuthToken"] = inAuthTokenStr
self.OpenRPA["Domain"] = __Orchestrator__.WebUserDomainGet(inAuthTokenStr=inAuthTokenStr)
self.OpenRPA["User"] = __Orchestrator__.WebUserLoginGet(inAuthTokenStr=inAuthTokenStr)
else: self.OpenRPA = {"IsSuperToken":False, "AuthToken":None, "Domain":None, "User":None}
self.headers=inRequest.headers
# Def to check User Role access grants
def UACClientCheck(self, inRoleKeyList): # Alias
return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList)
def UserRoleAccessAsk(self, inRoleKeyList):
lResult = True # Init flag
lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy
# Try to get value from key list
lKeyValue = lRoleHierarchyDict # Init the base
for lItem in inRoleKeyList:
if type(lKeyValue) is dict:
if lItem in lKeyValue: # Has key
lKeyValue = lKeyValue[lItem] # Get the value and go to the next loop iteration
else: # Else branch - true or false
if len(lKeyValue)>0: # False - if Dict has some elements
lResult = False # Set the False Flag
else:
lResult = True # Set the True flag
break # Stop the loop
else: # Has element with no detalization - return True
lResult = True # Set the flag
break # Close the loop
return lResult # Return the result
# Def to get hierarchy of the current user roles
# if return {} - all is available
def UserRoleHierarchyGet(self):
try:
lDomainUpperStr = self.OpenRPA["Domain"].upper()
lUserUpperStr = self.OpenRPA["User"].upper()
return __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {})
except Exception as e:
return {}
#Tech def
#return {"headers":[],"body":"","statuscode":111}
def URLItemCheckDo(self, inURLItem, inMethod, inOnlyFlagUACBool = False):
###############################
#Tech sub def - do item
################################
def URLItemDo(inURLItem,inRequest,inGlobalDict):
global gCacheDict
inResponseDict = inRequest.OpenRPAResponseDict
inResponseDict["Headers"]["Content-type"]= None
#Set status code 200
inResponseDict["StatusCode"] = 200
#Content-type
if "ResponseContentType" in inURLItem:
inResponseDict["Headers"]["Content-type"] = inURLItem["ResponseContentType"]
#If file path is set
if "ResponseFilePath" in inURLItem:
# Check cache
if inURLItem.get("UseCacheBool",False) == True:
if inURLItem["ResponseFilePath"] in gCacheDict:
# Write content as utf-8 data
inResponseDict["Body"] = gCacheDict[inURLItem["ResponseFilePath"]]
else:
if os.path.exists(inURLItem["ResponseFilePath"]) and os.path.isfile(inURLItem["ResponseFilePath"]):
lFileObject = open(CrossOS.PathStr(inURLItem["ResponseFilePath"]), "rb")
# Write content as utf-8 data
gCacheDict[inURLItem["ResponseFilePath"]] = lFileObject.read()
inResponseDict["Body"] = gCacheDict[inURLItem["ResponseFilePath"]]
# Закрыть файловый объект
lFileObject.close()
else: inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT
else:
if os.path.exists(inURLItem["ResponseFilePath"]) and os.path.isfile(inURLItem["ResponseFilePath"]):
lFileObject = open(CrossOS.PathStr(inURLItem["ResponseFilePath"]), "rb")
# Write content as utf-8 data
inResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект
lFileObject.close()
else: inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT
# detect MIME type if none
if inResponseDict["Headers"]["Content-type"] is None:
inResponseDict["Headers"]["Content-type"]= mimetypes.guess_type(inURLItem["ResponseFilePath"])[0]
#If function is set
if "ResponseDefRequestGlobal" in inURLItem:
lDef = inURLItem["ResponseDefRequestGlobal"]
lDefSignature = inspect.signature(lDef)
if len(lDefSignature.parameters) == 2:
inURLItem["ResponseDefRequestGlobal"](inRequest, inGlobalDict)
elif len(lDefSignature.parameters) == 1:
inURLItem["ResponseDefRequestGlobal"](inRequest)
else:
inURLItem["ResponseDefRequestGlobal"]()
if "ResponseFolderPath" in inURLItem:
#lRequestPath = inRequest.path
lRequestPath = urllib.parse.unquote(inRequest.path)
if inURLItem["URL"][-1]!="/": inURLItem["URL"]+= "/" # Fix for settings
lFilePathSecondPart = lRequestPath.replace(inURLItem["URL"],"")
lFilePathSecondPart = lFilePathSecondPart.split("?")[0]
lFilePath = CrossOS.PathStr(os.path.join(inURLItem["ResponseFolderPath"],lFilePathSecondPart))
#print(f"File full path {lFilePath}")
#Check if file exist
if os.path.exists(lFilePath) and os.path.isfile(lFilePath):
# Check cache
if inURLItem.get("UseCacheBool",False) == True:
if lFilePath in gCacheDict:
# Write content as utf-8 data
inResponseDict["Body"] = gCacheDict[lFilePath]
else:
lFileObject = open(lFilePath, "rb")
# Write content as utf-8 data
gCacheDict[lFilePath] = lFileObject.read()
inResponseDict["Body"] = gCacheDict[lFilePath]
# Закрыть файловый объект
lFileObject.close()
else:
lFileObject = open(lFilePath, "rb")
# Write content as utf-8 data
inResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект
lFileObject.close()
# detect MIME type if none
if inResponseDict["Headers"]["Content-type"] is None:
inResponseDict["Headers"]["Content-type"]= mimetypes.guess_type(lFilePath)[0]
else:
inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT
# If No content-type
if inResponseDict["Headers"]["Content-type"] is None:
inResponseDict["Headers"]["Content-type"]= "application/octet-stream"
##############################################
# UAC Check
if inOnlyFlagUACBool == True and inURLItem.get("UACBool",None) in [None, True]:
return False
if inURLItem["Method"].upper() == inMethod.upper():
# check Match type variant: BeginWith
if inURLItem["MatchType"].upper() == "BEGINWITH":
lURLPath = urllib.parse.unquote(self.path)
lURLPath = lURLPath.upper()
if lURLPath.startswith(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet())
return True
# check Match type variant: Contains
elif inURLItem["MatchType"].upper() == "CONTAINS":
lURLPath = urllib.parse.unquote(self.path)
lURLPath = lURLPath.upper()
if lURLPath.contains(inURLItem["URL"].upper()):
URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet())
return True
# check Match type variant: Equal
elif inURLItem["MatchType"].upper() == "EQUAL":
if inURLItem["URL"].upper() == urllib.parse.unquote(self.path).upper():
URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet())
return True
# check Match type variant: EqualNoParam
elif inURLItem["MatchType"].upper() == "EQUALNOPARAM":
if inURLItem["URL"].upper() == urllib.parse.unquote(self.path).upper().split("?")[0]:
URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet())
return True
# check Match type variant: EqualCase
elif inURLItem["MatchType"].upper() == "EQUALCASE":
if inURLItem["URL"] == urllib.parse.unquote(self.path):
URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet())
return True
return False
#ResponseContentTypeFile
def SendResponseContentTypeFile(self, inContentType, inFilePath):
inResponseDict = self.OpenRPAResponseDict
self.mResponse.status_code = 200
# Send headers
self.mResponse.headers["Content-type"]=inContentType
#Check if var exist
if hasattr(self, "OpenRPASetCookie"):
self.mResponse.set_cookie(key='AuthToken',value=self.OpenRPA['AuthToken'])
lFileObject = open(inFilePath, "rb")
# Write content as utf-8 data
lFileBytes = lFileObject.read()
#Закрыть файловый объект
lFileObject.close()
return lFileBytes
# ResponseContentTypeFile
def ResponseDictSend(self):
inResponseDict = self.OpenRPAResponseDict
self.mResponse.status_code = inResponseDict["StatusCode"]
# Send headers
for lItemKey, lItemValue in inResponseDict["Headers"].items():
self.mResponse.headers[lItemKey]=lItemValue
# Send headers: Set-Cookie
for lItemKey, lItemValue in inResponseDict["SetCookies"].items():
self.mResponse.set_cookie(key=lItemKey,value=lItemValue)
self.send_header("Set-Cookie", f"{lItemKey}={lItemValue}")
return inResponseDict["Body"]
def do_GET(self, inBodyStr):
try:
try:
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
except Exception as e:
pass
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None, "BodyIsText":True}
self.OpenRPAResponseDict = lResponseDict
#Check the user access (if flag, UAC)
####################################
lFlagUserAccess = True
#If need user authentication
if __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if self.OpenRPA["AuthToken"] != None:
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
if CrossOS.IS_WINDOWS_BOOL: lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
if CrossOS.IS_LINUX_BOOL: lOrchestratorFolder = "/".join(__file__.split("/")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in __Orchestrator__.GSettingsGet()["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
if lFlagURLIsApplied:
return self.ResponseDictSend()
else:
raise HTTPException(status_code=403, detail="here is the details", headers={})
except Exception as e:
lL = __Orchestrator__.OrchestratorLoggerGet()
if lL: lL.exception(f"Сервер (do_GET): Неопознанная ошибка сети - см. текст ошибки. Сервер продолжает работу")
# POST
def do_POST(self, inBodyStr):
try:
lL = __Orchestrator__.OrchestratorLoggerGet()
try:
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
except Exception as e:
pass
# Prepare result dict
#pdb.set_trace()
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None, "BodyIsText":True}
self.OpenRPAResponseDict = lResponseDict
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
if self.OpenRPA["AuthToken"] != None:
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in __Orchestrator__.GSettingsGet()["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
if lFlagURLIsApplied:
return self.ResponseDictSend()
else:
raise HTTPException(status_code=403, detail="here is the details", headers={})
except Exception as e:
lL = __Orchestrator__.OrchestratorLoggerGet()
if lL: lL.exception(f"Сервер, обратная совместимость (do_POST): Неопознанная ошибка сети - см. текст ошибки. Сервер продолжает работу")

@ -1,7 +1,6 @@
import json, os
import copy
from . import __Orchestrator__
from .Server import app,IdentifyAuthorize # FAST API SERVER
#ControlPanelDict
from pyOpenRPA.Tools import CrossOS
if CrossOS.IS_WINDOWS_BOOL: #CrossOS
@ -9,7 +8,7 @@ if CrossOS.IS_WINDOWS_BOOL: #CrossOS
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
getRectAsImage, getDisplaysAsImages)
if CrossOS.IS_LINUX_BOOL: import pyscreeze
if CrossOS.IS_LINUX_BOOL: pass
from http import cookies
import uuid # generate UUID4
@ -21,16 +20,6 @@ from ..Tools import Usage
from . import BackwardCompatibility # Support old up to 1.2.0 defs
from . import Processor
from . import SettingsTemplate
from fastapi import FastAPI, Form, Request, HTTPException, Depends, Header, Response, Body
from fastapi.responses import PlainTextResponse, HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel
import io
from starlette.responses import StreamingResponse
from typing import Union
from fastapi.responses import JSONResponse
# # # # # # # # # # # #
# v 1.2.0 Functionallity
@ -129,8 +118,14 @@ def HiddenAgentDictGenerate(inRequest, inGSettings):
# Client: mGlobal.pyOpenRPA.ServerDataHashStr
# Client: mGlobal.pyOpenRPA.ServerDataDict
def pyOpenRPA_ServerData(inRequest,inGSettings):
# Extract the hash value from request
lValueStr = inRequest.body
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lValueStr = (lInputByteArray.decode('utf8'))
# Generate ServerDataDict
lFlagDoGenerateBool = True
while lFlagDoGenerateBool:
@ -173,7 +168,12 @@ def pyOpenRPA_ServerJSInit(inRequest,inGSettings):
# Client: mGlobal.pyOpenRPA.ServerLogList
def pyOpenRPA_ServerLog(inRequest,inGSDict):
# Extract the hash value from request
lValueStr = inRequest.body
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lValueStr = (lInputByteArray.decode('utf8'))
# Generate ServerDataDict
lFlagDoGenerateBool = True
while lFlagDoGenerateBool:
@ -193,60 +193,53 @@ def pyOpenRPA_ServerLog(inRequest,inGSDict):
inResponseDict["Body"] = bytes(message, "utf8")
return lResult
# Get thread list /orpa/threads
@app.get(path="/orpa/client/screenshot-get",response_class=PlainTextResponse,tags=["Client"])
def pyOpenRPA_Screenshot():
def pyOpenRPA_Screenshot(inRequest,inGlobalDict):
# Get Screenshot
def SaveScreenshot(inFilePath):
# grab fullscreen
# Save the entire virtual screen as a PNG
lScreenshot = getScreenAsImage()
lScreenshot.save('screenshot.png', format='png')
# lScreenshot = ScreenshotSecondScreen.grab_screen()
# save image file
# lScreenshot.save('screenshot.png')
# Сохранить файл на диск
if CrossOS.IS_WINDOWS_BOOL:
SaveScreenshot("screenshot.png")
lFileObject = open("screenshot.png", "rb")
# Write content as utf-8 data
lImage = lFileObject.read()
# Закрыть файловый объект
lFileObject.close()
else:
pyscreeze._screenshot_linux(imageFilename='screenshot.png')
lFileObject = open("screenshot.png", "rb")
SaveScreenshot("Screenshot.png")
lFileObject = open("Screenshot.png", "rb")
# Write content as utf-8 data
lImage = lFileObject.read()
inRequest.OpenRPAResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект
lFileObject.close()
return StreamingResponse(io.BytesIO(lImage), media_type="image/png")
else: lFileObject = b''
# Add activity item or activity list to the processor queue
# Body is Activity item or Activity List
# body inauthtoken JSON
@app.post(path="/orpa/api/processor-queue-add",response_class=JSONResponse,tags=["API"])
def pyOpenRPA_Processor(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyStr:str = Body("")):
inGSettings = __Orchestrator__.GSettingsGet()
lL = __Orchestrator__.OrchestratorLoggerGet()
def pyOpenRPA_Processor(inRequest, inGSettings):
lL = inGSettings["Logger"]
# Recieve the data
lValueStr = inBodyStr
# Превращение массива байт в объект
lInput = json.loads(lValueStr)
lResult=[]
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# If list - operator plus
if type(lInput) is list:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr):
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
for lActivityItem in lInput:
lActivityTypeListStr += f"{lActivityItem['Def']}; "
except Exception as e:
lActivityTypeListStr = "Ошибка чтения типа активности"
lHostStr = __Orchestrator__.WebRequestHostGet(inRequest=inRequest)
lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inAuthTokenStr=inAuthTokenStr, inHostStr = lHostStr,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_Processor")
lActivityTypeListStr = "Has some error with Activity Type read"
lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inRequest=inRequest,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_Processor")
if lL: lL.info(lWebAuditMessageStr)
# Separate into 2 lists - sync and async
lSyncActvityList = []
lAsyncActivityList = []
for lActivityItem in lInput:
lResult.append(__Orchestrator__.ProcessorActivityItemAppend(inActivityItemDict=lActivityItem))
if lInput.get("ThreadBool", False) == False:
lSyncActvityList.append(lActivityItem)
else:
@ -260,16 +253,14 @@ def pyOpenRPA_Processor(inRequest:Request, inAuthTokenStr:str = Depends(Identify
lThread = threading.Thread(target=Processor.ActivityListExecute, kwargs=lActivityItemArgsDict)
lThread.start()
else:
lResult=__Orchestrator__.ProcessorActivityItemAppend(inActivityItemDict=lInput)
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr):
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
lActivityTypeListStr = lInput['Def']
except Exception as e:
lActivityTypeListStr = "Ошибка чтения типа активности"
lHostStr = __Orchestrator__.WebRequestHostGet(inRequest=inRequest)
lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inAuthTokenStr=inAuthTokenStr, inHostStr = lHostStr, inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_Processor")
lActivityTypeListStr = "Has some error with Activity Type read"
lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inRequest=inRequest,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_Processor")
if lL: lL.info(lWebAuditMessageStr)
if lInput.get("ThreadBool",False) == False:
# Append in list
@ -278,65 +269,61 @@ def pyOpenRPA_Processor(inRequest:Request, inAuthTokenStr:str = Depends(Identify
lActivityItemArgsDict = {"inGSettings": inGSettings, "inActivityList": [lInput]}
lThread = threading.Thread(target=Processor.ActivityListExecute, kwargs=lActivityItemArgsDict)
lThread.start()
return lResult
# Execute activity list
@app.post(path="/orpa/api/activity-list-execute",response_class=JSONResponse,tags=["API"])
def pyOpenRPA_ActivityListExecute(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyStr:str = Body("")):
def pyOpenRPA_ActivityListExecute(inRequest, inGSettings):
# Recieve the data
inGSettings = __Orchestrator__.GSettingsGet()
lL = __Orchestrator__.OrchestratorLoggerGet()
lValueStr = inBodyStr
# Превращение массива байт в объект
lInput = json.loads(lValueStr)
lL = inGSettings["Logger"]
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# If list - operator plus
if type(lInput) is list:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr):
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
for lActivityItem in lInput:
lActivityTypeListStr += f"{lActivityItem['Def']}; "
except Exception as e:
lActivityTypeListStr = "Ошибка чтения типа активности"
lHostStr = __Orchestrator__.WebRequestHostGet(inRequest=inRequest)
lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inAuthTokenStr=inAuthTokenStr, inHostStr = lHostStr,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_ActivityListExecute")
lActivityTypeListStr = "Has some error with Activity Type read"
lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inRequest=inRequest,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_ActivityListExecute")
if lL: lL.info(lWebAuditMessageStr)
# Execution
lResultList = Processor.ActivityListExecute(inGSettings = inGSettings, inActivityList = lInput)
return lResultList
#inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList), "utf8")
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList), "utf8")
else:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr):
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
lActivityTypeListStr = lInput['Def']
except Exception as e:
lActivityTypeListStr = "Ошибка чтения типа активности"
lHostStr = __Orchestrator__.WebRequestHostGet(inRequest=inRequest)
lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inAuthTokenStr=inAuthTokenStr, inHostStr = lHostStr,
lActivityTypeListStr = "Has some error with Activity Type read"
lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inRequest=inRequest,
inOperationCodeStr=lActivityTypeListStr,
inMessageStr="pyOpenRPA_ActivityListExecute")
if lL: lL.info(lWebAuditMessageStr)
# Execution
lResultList = Processor.ActivityListExecute(inGSettings = inGSettings, inActivityList = [lInput])
return lResultList
#inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList[0]), "utf8")
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList[0]), "utf8")
# See docs in Agent (pyOpenRPA.Agent.O2A)
@app.post(path="/orpa/agent/o2a",response_class=JSONResponse,tags=["Agent"])
def pyOpenRPA_Agent_O2A(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyDict = Body({})):
inGSettings = __Orchestrator__.GSettingsGet()
lL = __Orchestrator__.OrchestratorLoggerGet()
def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lL = inGSettings["Logger"] # Alias
lConnectionLifetimeSecFloat = inGSettings["ServerDict"]["AgentConnectionLifetimeSecFloat"] # 300.0 # 5 min * 60 sec 300.0
lActivityItemLifetimeLimitSecFloat = inGSettings["ServerDict"]["AgentActivityLifetimeSecFloat"]
lAgentLoopSleepSecFloat = inGSettings["ServerDict"]["AgentLoopSleepSecFloat"]
lTimeStartFloat = time.time()
# Recieve the data
#lValueStr = inBodyDict
# Превращение массива байт в объект
lInput = inBodyDict#json.loads(lValueStr)
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# Check if item is created
lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"],lInput["UserUpperStr"])
if lAgentDictItemKeyTurple not in inGSettings["AgentDict"]:
@ -387,12 +374,12 @@ def pyOpenRPA_Agent_O2A(inRequest:Request, inAuthTokenStr:str = Depends(Identify
for lItemDict in lReturnActivityItemList:
if "CreatedByDatetime" in lItemDict:
del lItemDict["CreatedByDatetime"]
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lReturnActivityItemList), "utf8")
# Log full version if bytes size is less than limit . else short
lBodyLenInt = len(lReturnActivityItemList)
lBodyLenInt = len(inRequest.OpenRPAResponseDict["Body"])
lAgentLimitLogSizeBytesInt = inGSettings["ServerDict"]["AgentLimitLogSizeBytesInt"]
if lL: lL.debug(f"ActivityItem to Agent ({lInput['HostNameUpperStr']}, {lInput['UserUpperStr']}): Item count: {len(lReturnActivityItemList)}, bytes size: {lBodyLenInt}")
lThisAgentDict["ConnectionCountInt"] -= 1 # Connection go to be closed - decrement the connection count
return lReturnActivityItemList
lDoLoopBool = False # CLose the connection
else: # Nothing to send - sleep for the next iteration
time.sleep(lAgentLoopSleepSecFloat)
else: # no queue item - sleep for the next iteration
@ -401,43 +388,42 @@ def pyOpenRPA_Agent_O2A(inRequest:Request, inAuthTokenStr:str = Depends(Identify
if lL: lL.exception("pyOpenRPA_Agent_O2A Exception!")
lThisAgentDict["ConnectionCountInt"] -= 1 # Connection go to be closed - decrement the connection count
@app.get(path="/orpa/api/helper-def-list/{inTokenStr}",response_class=JSONResponse,tags=["API"])
def pyOpenRPA_Debugging_HelperDefList(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyStr:str = Body("")):
def pyOpenRPA_Debugging_HelperDefList(inRequest, inGSettings):
# Parse query
lResultDict = {
"success": True,
"results": []
}
# Get the path
lPathSplitList = inRequest.url.path.split('/')
lPathSplitList = __Orchestrator__.WebRequestParsePath(inRequest=inRequest).split('/')
lQueryStr = None
if "HelperDefList" != lPathSplitList[-1] and "" != lPathSplitList[-1]: lQueryStr = lPathSplitList[-1]
if lQueryStr != "" and lQueryStr is not None:
lDefList = __Orchestrator__.ActivityItemHelperDefList(inDefQueryStr=lQueryStr)
for lDefStr in lDefList:
lResultDict["results"].append({"name": lDefStr, "value": lDefStr, "text": lDefStr})
return lResultDict
__Orchestrator__.WebRequestResponseSend(inRequest=inRequest, inResponeStr=json.dumps(lResultDict))
@app.get(path="/orpa/api/helper-def-autofill/{inTokenStr}",response_class=JSONResponse,tags=["API"])
def pyOpenRPA_Debugging_HelperDefAutofill(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyStr:str = Body("")):
def pyOpenRPA_Debugging_HelperDefAutofill(inRequest, inGSettings):
# Parse query
# Get the path
lPathSplitList = inRequest.url.path.split('/')
lPathSplitList = __Orchestrator__.WebRequestParsePath(inRequest=inRequest).split('/')
lQueryStr = None
if "HelperDefAutofill" != lPathSplitList[-1] and "" != lPathSplitList[-1]: lQueryStr = lPathSplitList[-1]
lResultDict = __Orchestrator__.ActivityItemHelperDefAutofill(inDef = lQueryStr)
return lResultDict
__Orchestrator__.WebRequestResponseSend(inRequest=inRequest, inResponeStr=json.dumps(lResultDict))
# See docs in Agent (pyOpenRPA.Agent.A2O)
@app.post(path="/orpa/agent/a2o",response_class=JSONResponse,tags=["Agent"])
def pyOpenRPA_Agent_A2O(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyDict = Body({})):
inGSettings = __Orchestrator__.GSettingsGet()
lL = __Orchestrator__.OrchestratorLoggerGet()
def pyOpenRPA_Agent_A2O(inRequest, inGSettings):
lL = inGSettings["Logger"]
# Recieve the data
#lValueStr = inBodyStr
# Превращение массива байт в объект
lInput = inBodyDict#json.loads(lValueStr)
lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"], lInput["UserUpperStr"])
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"], lInput["UserUpperStr"])
if "LogList" in lInput:
for lLogItemStr in lInput["LogList"]:
inGSettings["Logger"].info(lLogItemStr)
@ -446,13 +432,13 @@ def pyOpenRPA_Agent_A2O(inRequest:Request, inAuthTokenStr:str = Depends(Identify
lActivityReturnItemValue = lInput["ActivityReturnDict"][lActivityReturnItemKeyStr]
# Create item in gSettings
inGSettings["AgentActivityReturnDict"][lActivityReturnItemKeyStr]=SettingsTemplate.__AgentActivityReturnDictItemCreate__(inReturn=lActivityReturnItemValue)
lLogStr = "x байт"
lLogStr = "x bytes"
try:
if lActivityReturnItemValue is not None:
lLogStr = f"{len(lActivityReturnItemValue)} байт"
lLogStr = f"{len(lActivityReturnItemValue)} bytes"
except Exception as e:
pass
if lL: lL.debug(f"СЕРВЕР: Функция pyOpenRPA_Agent_A2O:: Получена активность от агента! Идентификатор активности: {lActivityReturnItemKeyStr}; Длина переданной активности: {lLogStr}")
if lL: lL.debug(f"SERVER: pyOpenRPA_Agent_A2O:: Has recieved result of the activity items from agent! ActivityItem GUID Str: {lActivityReturnItemKeyStr}; Return value len: {lLogStr}")
# Delete the source activity item from AgentDict
if lAgentDictItemKeyTurple in inGSettings["AgentDict"]:
lAgentDictActivityListNew = []
@ -462,23 +448,11 @@ def pyOpenRPA_Agent_A2O(inRequest:Request, inAuthTokenStr:str = Depends(Identify
lAgentDictActivityListNew.append(lActivityItem)
else:
del lActivityItem
if lL: lL.debug(f"СЕРВЕР: Функция pyOpenRPA_Agent_A2O:: Активность была удалена из процессорной очереди. Идентификатор активности: {lActivityReturnItemKeyStr}")
if lL: lL.debug(f"SERVER: pyOpenRPA_Agent_A2O:: Source activity item request was deleted from the orchestrator. ActivityItem GUID Str: {lActivityReturnItemKeyStr}")
inGSettings["AgentDict"][lAgentDictItemKeyTurple]["ActivityList"] = lAgentDictActivityListNew
from pyOpenRPA.Utils.Render import Render
lFileStr = CrossOS.PathJoinList(CrossOS.PathSplitList(__file__)[:-2] + ["Resources","Web","orpa","orc.xhtml"])
gRender = Render(inTemplatePathStr=lFileStr,inTemplateRefreshBool=True)
from pyOpenRPA import __version__
def pyOpenRPA_Index():
# Пример использования
global gRender
lStr = gRender.Generate(inDataDict={"title":"ОРКЕСТРАТОР PYOPENRPA", "subtitle":"ПАНЕЛЬ УПРАВЛЕНИЯ", "version":__version__})
__Orchestrator__.WebRequestResponseSend(inResponeStr=lStr,inContentTypeStr="text/html")
def SettingsUpdate():
def SettingsUpdate(inGlobalConfiguration):
import os
import pyOpenRPA.Orchestrator
gSettingsDict = __Orchestrator__.GSettingsGet()
if CrossOS.IS_WINDOWS_BOOL: lOrchestratorFolder = "\\".join(pyOpenRPA.Orchestrator.__file__.split("\\")[:-1])
if CrossOS.IS_LINUX_BOOL: lOrchestratorFolder = "/".join(pyOpenRPA.Orchestrator.__file__.split("/")[:-1])
lURLList = \
@ -493,38 +467,31 @@ def SettingsUpdate():
# "ResponseDefRequestGlobal": None #Function with str result
#}
#Orchestrator basic dependencies # Index page in server.py because of special settings
{"Method":"GET", "URL": gSettingsDict["ServerDict"]["URLIndexStr"],"MatchType": "EqualNoParam", "ResponseDefRequestGlobal": pyOpenRPA_Index},
{"Method":"GET", "URL": "/metadata.json", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\orpa\\metadata.json"), "ResponseContentType": "application/json"},
#{"Method":"GET", "URL": "/Index.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\Index.js"), "ResponseContentType": "text/javascript"},
{"Method":"GET", "URL": "/orpa/resources/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "..\\Resources"),"UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/orpa/client/resources/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "Web"),"UACBool":False, "UseCacheBool": True},
#{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/semantic.min.css", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\semantic.min.css"), "ResponseContentType": "text/css", "UACBool":False, "UseCacheBool": True},
#{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/semantic.min.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\semantic.min.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True},
#{"Method":"GET", "URL": "/3rdParty/jQuery/jquery-3.1.1.min.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\jQuery\\jquery-3.1.1.min.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True},
#{"Method":"GET", "URL": "/3rdParty/Google/LatoItalic.css", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Google\\LatoItalic.css"), "ResponseContentType": "font/css", "UACBool":False, "UseCacheBool": True},
#{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.woff2", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\themes\\default\\assets\\fonts\\icons.woff2"), "ResponseContentType": "font/woff2", "UACBool":False, "UseCacheBool": True},
#{"Method":"GET", "URL": "/themes/default/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\themes\\default"),"UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\orpa\\favicon.ico"), "ResponseContentType": "image/x-icon", "UACBool":False, "UseCacheBool": True},
#{"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True},
#{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"},
#{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"},
#{"Method": "GET", "URL": "/pyOpenRPA_logo.png", "MatchType": "Equal", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\pyOpenRPA_logo.png"), "ResponseContentType": "image/png", "UACBool":False, "UseCacheBool": True},
{"Method": "POST", "URL": "/orpa/client/user-role-hierarchy-get", "MatchType": "Equal","ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_UserRoleHierarchyGet, "ResponseContentType": "application/json"},
{"Method":"GET", "URL": "/Index.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\Index.js"), "ResponseContentType": "text/javascript"},
{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/semantic.min.css", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\semantic.min.css"), "ResponseContentType": "text/css", "UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/semantic.min.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\semantic.min.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/3rdParty/jQuery/jquery-3.1.1.min.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\jQuery\\jquery-3.1.1.min.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/3rdParty/Google/LatoItalic.css", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Google\\LatoItalic.css"), "ResponseContentType": "font/css", "UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.woff2", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\themes\\default\\assets\\fonts\\icons.woff2"), "ResponseContentType": "font/woff2", "UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/themes/default/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\themes\\default"),"UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\favicon.ico"), "ResponseContentType": "image/x-icon", "UACBool":False, "UseCacheBool": True},
{"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/pyOpenRPA_logo.png", "MatchType": "Equal", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\pyOpenRPA_logo.png"), "ResponseContentType": "image/png", "UACBool":False, "UseCacheBool": True},
{"Method": "POST", "URL": "/Orchestrator/UserRoleHierarchyGet", "MatchType": "Equal","ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_UserRoleHierarchyGet, "ResponseContentType": "application/json"},
# New way of the v.1.2.0 functionallity (all defs by the URL from /pyOpenRPA/...)
{"Method": "POST", "URL": "/orpa/client/server-data", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerData, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/orpa/client/server-js-init", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerJSInit, "ResponseContentType": "application/javascript"},
{"Method": "POST", "URL": "/orpa/client/server-log", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerLog, "ResponseContentType": "application/json"},
#{"Method": "GET", "URL": "/orpa/client/screenshot-get", "MatchType": "Equal", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"},
# API
#{"Method": "POST", "URL": "/orpa/api/processor-queue-add", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Processor, "ResponseContentType": "application/json"},
#{"Method": "POST", "URL": "/orpa/api/activity-list-execute", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ActivityListExecute, "ResponseContentType": "application/json"},
#{"Method": "GET", "URL": "/orpa/api/helper-def-list/", "MatchType": "BeginWith","ResponseDefRequestGlobal": pyOpenRPA_Debugging_HelperDefList, "ResponseContentType": "application/json"},
#{"Method": "GET", "URL": "/orpa/api/helper-def-autofill/", "MatchType": "BeginWith","ResponseDefRequestGlobal": pyOpenRPA_Debugging_HelperDefAutofill, "ResponseContentType": "application/json"},
# AGENT
#{"Method": "POST", "URL": "/orpa/agent/o2a", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_O2A, "ResponseContentType": "application/json"},
#{"Method": "POST", "URL": "/orpa/agent/a2o", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_A2O, "ResponseContentType": "application/json"}
{"Method": "POST", "URL": "/pyOpenRPA/ServerData", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerData, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/pyOpenRPA/ServerJSInit", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerJSInit, "ResponseContentType": "application/javascript"},
{"Method": "POST", "URL": "/pyOpenRPA/ServerLog", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerLog, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/pyOpenRPA/Screenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"},
{"Method": "POST", "URL": "/pyOpenRPA/ProcessorQueueAdd", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Processor, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/ActivityListExecute", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ActivityListExecute, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/Agent/O2A", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_O2A, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/Agent/A2O", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_A2O, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/pyOpenRPA/Debugging/HelperDefList/", "MatchType": "BeginWith","ResponseDefRequestGlobal": pyOpenRPA_Debugging_HelperDefList, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/pyOpenRPA/Debugging/HelperDefAutofill/", "MatchType": "BeginWith","ResponseDefRequestGlobal": pyOpenRPA_Debugging_HelperDefAutofill, "ResponseContentType": "application/json"},
]
Usage.Process(inComponentStr="Orchestrator")
gSettingsDict["ServerDict"]["URLList"]=gSettingsDict["ServerDict"]["URLList"]+lURLList
return gSettingsDict
inGlobalConfiguration["ServerDict"]["URLList"]=inGlobalConfiguration["ServerDict"]["URLList"]+lURLList
return inGlobalConfiguration

@ -1,7 +1,5 @@
import os, logging, datetime, sys
import schedule
from pyOpenRPA.Tools import CrossOS # https://schedule.readthedocs.io/en/stable/examples.html
import schedule # https://schedule.readthedocs.io/en/stable/examples.html
# Technical def - return GSettings structure with examples
def __Create__():
@ -342,7 +340,7 @@ def Create(inModeStr="BASIC", inLoggerLevel = None):
lL.setLevel(logging.INFO)
# create the logging file handler
mRobotLoggerFH = logging.FileHandler(
CrossOS.PathStr("Reports\\" + datetime.datetime.now().strftime("%Y_%m_%d") + ".log"))
"Reports\\" + datetime.datetime.now().strftime("%Y_%m_%d") + ".log")
mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
mRobotLoggerFH.setFormatter(mRobotLoggerFormatter)
# add handler to logger object

@ -101,6 +101,22 @@ $(document).ready(function() {
/////Controller JS module
//////////////////////////
mGlobal.Controller={};
mGlobal.Controller.CMDRunText=function(inCMDText) {
///Подготовить конфигурацию
lData = [
{"Type":"CMDStart", "Command": inCMDText}
]
///Обнулить таблицу
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3){},
dataType: "text"
});
}
mGlobal.Controller.CMDRun=function() {
///Обнулить таблицу
lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value
@ -116,7 +132,37 @@ $(document).ready(function() {
]
$.ajax({
type: "POST",
url: '/orpa/api/activity-list-execute',
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///Отправить запрос на формирование таблицы
//lHTMLCode=console.log("CMDRun result: "+lResponseJSON[0].result)
},
dataType: "text"
});
}
mGlobal.Controller.CMDRunGUILogout=function() {
///Обнулить таблицу
lCMDCode="for /f \"skip=1 tokens=2\" %s in ('query user %USERNAME%') do (tscon \\dest:console)"
//lCMDCode = lCMDCode.replace(/\\n/g, "\\n")
// .replace(/\\'/g, "\\'")
// .replace(/\\"/g, '\\"')
// .replace(/\\&/g, "\\&")
// .replace(/\\r/g, "\\r")
// .replace(/\\t/g, "\\t")
// .replace(/\\b/g, "\\b")
// .replace(/\\f/g, "\\f")
// .replace('"', "\\\"");
///Подготовить конфигурацию
lData = [
{"Type":"CMDStart", "Command": lCMDCode }
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
@ -128,33 +174,51 @@ $(document).ready(function() {
dataType: "text"
});
}
///Restart PC
mGlobal.Controller.PCRestart = function () {
mGlobal.Controller.OrchestratorSessionSave()
mGlobal.Controller.CMDRunText("shutdown -r")
}
mGlobal.Controller.OrchestratorGITPullRestart = function() {
mGlobal.Controller.OrchestratorSessionSave() //Save current RDP list session
mGlobal.Controller.CMDRunText("timeout 3 & taskkill /f /im OpenRPA_Orchestrator.exe & timeout 2 & cd "+mGlobal.WorkingDirectoryPathStr+" & git reset --hard & git pull & pyOpenRPA.Orchestrator_x64_administrator_startup.cmd");
///Orchestrator save session
mGlobal.Controller.OrchestratorSessionSave=function() {
///Подготовить конфигурацию
lData = [
{"Type":"OrchestratorSessionSave"}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
},
dataType: "text"
});
}
///Перезагрузить Orchestrator
mGlobal.Controller.OrchestratorRestart=function() {
///Подготовить конфигурацию
lData = [
{
"Def":"OrchestratorRestart", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList":[], // Args list
"ArgDict":{}, // Args dictionary
"ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": null // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
{"Type":"OrchestratorRestart"}
]
$.ajax({
type: "POST",
url: '/orpa/api/activity-list-execute',
data: JSON.stringify(lData)
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
},
dataType: "text"
});
}
mGlobal.Controller.OrchestratorGITPullRestart = function() {
mGlobal.Controller.OrchestratorSessionSave() //Save current RDP list session
mGlobal.Controller.CMDRunText("timeout 3 & taskkill /f /im OpenRPA_Orchestrator.exe & timeout 2 & cd "+mGlobal.WorkingDirectoryPathStr+" & git reset --hard & git pull & pyOpenRPA.Orchestrator_x64_administrator_startup.cmd");
}
//////////////////////////
/////Monitor JS module
//////////////////////////
@ -164,12 +228,12 @@ $(document).ready(function() {
return inPrefix+Math.round(Math.random()*1000)+"-"+Math.round(Math.random()*10000)+"-"+Math.round(Math.random()*1000)
}
//inHostURI: http://localhost:8081
mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI="") {
mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI=" ") {
$('.ui.modal.daemon-screenshot').modal({'onHide':function (inElement) {mGlobal.Monitor.ScreenshotModal.Close();} }).modal('show');
//Функция обновления картинки
lScreenshotUpdate=function() {
lScreenshotSrc=inHostURI+"/orpa/client/screenshot-get?"+mGlobal.Monitor.GenerateUniqueID()
lScreenshotSrc=inHostURI+"/GetScreenshot?"+mGlobal.Monitor.GenerateUniqueID()
$(".daemon-screenshot img").attr('src', lScreenshotSrc);
}
@ -180,7 +244,26 @@ $(document).ready(function() {
}
///Monitor
mGlobal.Monitor.DaemonList={}
mGlobal.Monitor.DaemonList.fRefreshTable=function() {
///Загрузка данных
$.ajax({
type: "GET",
url: 'Monitor/JSONDaemonListGet',
data: '',
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///Сформировать HTML код новой таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-monitor-table-general",lResponseJSON)
///Очистить дерево
//mGlobal.ElementTree.fClear();
///Прогрузить новую таблицу
$(".openrpa-monitor").html(lHTMLCode)
},
dataType: "text"
});
}
////////////////////////////////
///////Control panel
///////////////////////////////
@ -297,7 +380,7 @@ $(document).ready(function() {
lData = [inActivityItem]
$.ajax({
type: "POST",
url: '/orpa/api/activity-list-execute',
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
@ -322,7 +405,7 @@ $(document).ready(function() {
lData = inActivityList
$.ajax({
type: "POST",
url: '/orpa/api/activity-list-execute',
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
@ -347,7 +430,7 @@ $(document).ready(function() {
lData = inActivityList
$.ajax({
type: "POST",
url: '/orpa/api/processor-queue-add',
url: '/pyOpenRPA/ProcessorQueueAdd',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
@ -365,7 +448,7 @@ $(document).ready(function() {
$.ajax({
type: "GET",
headers: {},
url: '/orpa/client/server-js-init',
url: 'pyOpenRPA/ServerJSInit',
data: mGlobal.pyOpenRPA.ServerDataHashStr,
async: false,
success: function(lJSText) {
@ -429,7 +512,7 @@ $(document).ready(function() {
$.ajax({
type: "POST",
headers: {},
url: '/orpa/client/server-data',
url: 'pyOpenRPA/ServerData',
data: mGlobal.pyOpenRPA.ServerDataHashStr,
success: function(lData,l2,l3) {
try {
@ -470,7 +553,7 @@ $(document).ready(function() {
///Turn OFF rendering
mGlobal.pyOpenRPA.ServerLogListDoRenderFalse = function() {
///Set unfreeze button
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Разморозить окно логов")
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Unfreeze textarea")
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").attr("onclick","mGlobal.pyOpenRPA.ServerLogListDoRenderTrue()")
$("textarea.mGlobal-pyOpenRPA-ServerLogList").css("background-color","#b9e2e8")
mGlobal.pyOpenRPA.ServerLogListDoRenderBool = false
@ -481,7 +564,7 @@ $(document).ready(function() {
///Render last data
mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender()
///Set unfreeze button
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Заморозить окно логов")
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Freeze textarea")
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").attr("onclick","mGlobal.pyOpenRPA.ServerLogListDoRenderFalse()")
$("textarea.mGlobal-pyOpenRPA-ServerLogList").css("background-color","")
@ -504,7 +587,7 @@ $(document).ready(function() {
$.ajax({
type: "POST",
headers: {},
url: '/orpa/client/server-log',
url: 'pyOpenRPA/ServerLog',
data: mGlobal.pyOpenRPA.ServerLogListHashStr,
success: function(lData,l2,l3) {
try {
@ -541,7 +624,90 @@ $(document).ready(function() {
///Processor functions
///////////////////////////////
mGlobal.Processor = {}
mGlobal.Processor.ServerValueAppend = function(inKeyList,inValue) {
lData = [
{
"Type":"GlobalDictKeyListValueAppend",
"KeyList": inKeyList,
"Value": inValue
}
]
///Обнулить таблицу
$('.ui.modal.basic .content').html("");
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///TODO Show error if exist error
},
dataType: "text"
});
}
mGlobal.Processor.ServerValueSet = function(inKeyList,inValue) {
lData = [
{
"Type":"GlobalDictKeyListValueSet",
"KeyList": inKeyList,
"Value": inValue
}
]
///Обнулить таблицу
$('.ui.modal.basic .content').html("");
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///TODO Show error if exist error
},
dataType: "text"
});
}
mGlobal.Processor.ServerValueOperatorPlus = function(inKeyList,inValue) {
lData = [
{
"Type":"GlobalDictKeyListValueOperator+",
"KeyList": inKeyList,
"Value": inValue
}
]
///Обнулить таблицу
$('.ui.modal.basic .content').html("");
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///TODO Show error if exist error
},
dataType: "text"
});
}
mGlobal.Processor.Send = function(inData) {
lData = inData
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///TODO Show error if exist error
},
dataType: "text"
});
}
mGlobal.Server= {}
mGlobal.Server.JSONGet=function(inMethod, inURL, inDataJSON, inCallback)
{
@ -738,7 +904,7 @@ $(document).ready(function() {
lValueStr = inEvent
$.ajax({
type: "GET",
url: '/orpa/api/helper-def-autofill/'+lValueStr,
url: '/pyOpenRPA/Debugging/HelperDefAutofill/'+lValueStr,
data: null,
success:
function(lData,l2,l3)
@ -791,7 +957,7 @@ $(document).ready(function() {
lData = [lActivityItem]
$.ajax({
type: "POST",
url: '/orpa/api/activity-list-execute',
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
@ -818,15 +984,9 @@ $(document).ready(function() {
.dropdown({
apiSettings: {
// this url parses query server side and returns filtered results
url: '/orpa/api/helper-def-list/{query}'
url: '/pyOpenRPA/Debugging/HelperDefList/{query}'
},
onChange: lDropdownOnChange
})
;
mGlobal.pyOpenRPA.RDPListTest= function() {
lResponseJSON={"HandlebarsList":[{"SessionKeyStr":"test"},{"SessionKeyStr":"test2"}]};
/// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
}
});

@ -1,37 +1,15 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<!-- Yandex.Metrika counter -->
<script async="" src="https://mc.yandex.ru/metrika/tag.js"></script>
<script type="text/javascript">
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym(88079149, "init", {
clickmap:true,
trackLinks:true,
accurateTrackBounce:true,
webvisor:true
});
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/88079149" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Оркестратор pyOpenRPA</title>
<meta name="description" content="Ведущий RPA разработчик российского программного обеспечения. RPA платформа позволяет решать любые бизнес-задачи. Комплексное решение от компании RPA pyOpenRPA. Первое открытое российское RPA решение для крупного / среднего / малого бизнеса. Доступная автоматизация для каждого.">
<meta name="keywords" content="rpa, программные роботы, автоматизация бизнес-процессов, цифровые сотрудники, виртуальные сотрудники">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/semantic.min.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/orpa/styleset/home.css">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>pyOpenRPA Orchestrator</title>
<link rel="stylesheet" type="text/css" href="3rdParty/Semantic-UI-CSS-master/semantic.min.css">
<script
src="/orpa/resources/Web/jQuery/jquery-3.1.1.min.js"
src="3rdParty/jQuery/jquery-3.1.1.min.js"
crossorigin="anonymous"></script>
<script src="/orpa/resources/Web/Semantic-UI-CSS-master/semantic.min.js"></script>
<script src="/orpa/resources/Web/Handlebars/handlebars-v4.1.2.js"></script>
<script src = "/orpa/resources/Web/orpa/orc.js"></script>
<script src="3rdParty/Semantic-UI-CSS-master/semantic.min.js"></script>
<script src="3rdParty/Handlebars/handlebars-v4.1.2.js"></script>
<script src = "Index.js"></script>
<style type="text/css">
body {
@ -69,30 +47,41 @@
}
.ui.search.dropdown>input.search {
width:100%;
font-family:'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family:monospace;
font-weight: bold;
}
.ui.search.dropdown>.text {
width:100%;
font-family:'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-family:monospace;
font-weight: bold;
}
</style>
</head>
<body>
{% include 'header.xhtml' %}
<div class="ui aligned stackable grid container">
<div class="ui internally celled grid">
<div class="row black">
<div class="sixteen wide column" style="display: flex;">
<img src="pyOpenRPA_logo.png" width="70px;" height="70px"></img>
&nbsp;&nbsp;&nbsp;
<h1 class="ui header inverted" style="cursor: pointer" onclick="window.open('https://gitlab.com/UnicodeLabs/OpenRPA','_blank');">pyOpenRPA</h1>
<h5 style="cursor: pointer" onclick="window.open('https://www.facebook.com/RU.IT4Business','_blank');">by Ivan Maslov</h5>
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
<h1 class="ui header inverted">ORCHESTRATOR WEB GUI</h1>
</div>
</div>
<div class="row">
<div class="sixteen wide column openrpa-control-panel-general UACClient-pyOpenRPADict-CPKeyDict" style="display:none;" >
<h4 class="ui horizontal divider header" style="margin-bottom:30px;margin-top:30px;">
<h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i>
Роботы
Dashboard (Robot control panel)
</h4>
<div class="openrpa-control-panel"></div>
<script class="openrpa-hidden-control-panel" style="display:none" type="text/x-handlebars-template">
<div class="ui cards">
{% raw %}
{{#RenderRobotList}}
<div class="card">
<div class="content">
@ -132,7 +121,6 @@
</div>
</div>
{{/RenderRobotList}}
{% endraw %}
</div>
</script>
</div>
@ -141,7 +129,6 @@
<div class="row">
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
{% raw %}
<table class="ui celled table">
<thead>
<tr>
@ -157,11 +144,9 @@
{{/ListenURLList}}
</tbody>
</table>
{% endraw %}
</script>
<script class="openrpa-handlebar-template-table-filter" style="display:none" type="text/x-handlebars-template">
{% raw %}
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
@ -191,10 +176,8 @@
{{/Rows}}
</tbody>
</table>
{% endraw %}
</script>
<script class="openrpa-handlebar-template-list-filter" style="display:none" type="text/x-handlebars-template">
{% raw %}
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
@ -217,48 +200,44 @@
{{/List}}
</div>
</div>
{% endraw %}
</script>
<div class="eight wide column openrpa-robotrdpactive-control-panel-general UACClient-pyOpenRPADict-RDPKeyDict" style="display:none;">
<h2 class="ui header openrpa-rdpactive-title">
<i class="desktop icon"></i>
<div class="content">
РДП сессии
RDP active list
</div>
</h2>
<div class="openrpa-robotrdpactive-control-panel"></div>
<script class="openrpa-hidden-robotrdpactive-control-panel" style="display:none" type="text/x-handlebars-template">
<div class="ui inverted segment" style="background: #368279">
{% raw %}
<div class="ui inverted relaxed divided list">
{{#HandlebarsList}}
<div class="item">
<div class="content">
<div class="header">Session key: {{{SessionKeyStr}}}</div>
{{{SessionHexStr}}}
</div>
<div class="right floated content">
<div style="margin-top:10px;" class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Переподключить</div>
<div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div>
</div>
<div class="right floated content">
{{#if IsIgnoredBool}}
<div style="margin-top:10px;" class="ui button red" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','RDPList','{{{SessionKeyStr}}}','SessionIsIgnoredBool'],false);">Игнорировать</div>
<div class="ui button red" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','RDPList','{{{SessionKeyStr}}}','SessionIsIgnoredBool'],false);">Ignore</div>
{{else}}
<div style="margin-top:10px;" class="ui button" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','RDPList','{{{SessionKeyStr}}}','SessionIsIgnoredBool'],true);">Игнорировать</div>
<div class="ui button" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','RDPList','{{{SessionKeyStr}}}','SessionIsIgnoredBool'],true);">Ignore</div>
{{/if}}
</div>
<div class="right floated content">
{{#if IsFullScreenBool}}
<div style="margin-top:10px;" class="ui button green" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','FullScreenRDPSessionKeyStr'],null);">Полный экран</div>
<div class="ui button green" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','FullScreenRDPSessionKeyStr'],null);">Full screen</div>
{{else}}
<div style="margin-top:10px;" class="ui button" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','FullScreenRDPSessionKeyStr'],'{{{SessionKeyStr}}}');">Полный экран</div>
<div class="ui button" onclick="mGlobal.Processor.ServerValueSet(['RobotRDPActive','FullScreenRDPSessionKeyStr'],'{{{SessionKeyStr}}}');">Full screen</div>
{{/if}}
</div>
<div class="content">
<div class="header">Session key: {{{SessionKeyStr}}}</div>
{{{SessionHexStr}}}
</div>
</div>
{{/HandlebarsList}}
</div>
{% endraw %}
</div>
</script>
</div>
@ -266,32 +245,30 @@
<h2 class="ui header " style="">
<i class="bug icon"></i>
<div class="content">
Агент подключения
Agent active list
</div>
</h2>
<div class="pyOpenRPA-Agent-List"></div>
<script class="pyOpenRPA-Agent-ListTemplate" style="display:none" type="text/x-handlebars-template">
<div class="ui inverted segment" style="background: #368279">
{% raw %}
<div class="ui inverted relaxed divided list">
{{#HandlebarsList}}
<div class="item">
<div class="right floated content">
{{#if IsListenBool}}
<i class="circle icon green"></i>
Доступен
Online
{{else}}
<i class="circle icon red"></i>
Недоступен
Offline
{{/if}}
</div>
<div class="content">
<div class="header">Хост: {{{HostnameUpperStr}}}, Пользователь: {{{UserUpperStr}}}</div>
<div class="header">Hostname: {{{HostnameUpperStr}}}, User: {{{UserUpperStr}}}</div>
</div>
</div>
{{/HandlebarsList}}
</div>
{% endraw %}
</div>
</script>
</div>
@ -306,7 +283,7 @@
<h2 class="ui header">
<i class="settings icon"></i>
<div class="content">
Администрирование
Administration
</div>
</h2>
@ -317,48 +294,25 @@
<div class="sixteen wide column" style="">
<h4 class="ui horizontal divider header" >
<i class="clipboard list icon"></i>
Логи
Logs
</h4>
<textarea class="mGlobal-pyOpenRPA-ServerLogList UACClient-pyOpenRPADict-AdminDict-LogViewerBool" readonly="readonly" style="width:100%; display:none; resize: none; font-family:monospace; font-weight: bold;" id="textarea_id" rows="20">
</textarea>
<a class="mGlobal-pyOpenRPA-ServerLogListDoRender" onclick="" style="cursor: pointer;">Заморозить окно логов</a>
</div>
</div>
<div class="row ui">
<div class="sixteen wide column ui" style="margin-bottom:30px;">
<h4 class="ui horizontal divider header" >
<i class="settings icon"></i>
Терминал
</h4>
</div>
<div class="eight wide column ui">
<div class="ui fluid input UACClient-pyOpenRPADict-AdminDict-CMDInputBool" style="display:none;">
<input class="openrpa-controller-cmd-run-input" type="text" placeholder="Скрипт для терминала..." style="min-width:250px;">
<a class="mGlobal-pyOpenRPA-ServerLogListDoRender" onclick="" style="cursor: pointer;">Freeze textarea</a>
<div class="ui fluid action input UACClient-pyOpenRPADict-AdminDict-CMDInputBool" style="display:none;">
<input class="openrpa-controller-cmd-run-input" type="text" placeholder="CMD Code...">
<div class="ui button" onclick="mGlobal.Controller.CMDRun();">Run!</div>
<div class="ui button" onclick="mGlobal.Controller.CMDRunGUILogout();">GUI Logout</div>
</div>
</div>
<div class="three wide column ui">
<div class="ui button green" onclick="mGlobal.Controller.CMDRun();" style="">Выполнить</div>
</div>
<div class="five wide column ui">
<div class="ui button" onclick="mGlobal.Controller.CMDRunGUILogout();" style="">Выйти из сессии</div>
</div>
</div>
<div class="row UACClient-pyOpenRPADict-AdminDict-Debugging" style= "display:none;">
<div class="twelve wide column">
<h4 class="ui horizontal divider header" >
<i class="bug icon"></i>
Отладка - Отправить
Debugging - Send
</h4>
<div class="ui labeled input">
<div class="ui label">Def</div>
@ -395,12 +349,12 @@
</div>
<input type="text" placeholder="inLogger" class="mGlobal-pyOpenRPA-Debugging-ArgLoggerStr" style="width:100%; font-family:monospace; font-weight: bold;">
</div>
<div class="ui fluid button" onclick="mGlobal.pyOpenRPA.DebuggingExecute();">Выполнить</div>
<div class="ui fluid button" onclick="mGlobal.pyOpenRPA.DebuggingExecute();">Execute</div>
</div>
<div class="four wide column">
<h4 class="ui horizontal divider header" >
<i class="bug icon"></i>
Отладка - Получить
Debugging - Output
</h4>
<p><textarea class="mGlobal-pyOpenRPA-Debugging-Output" readonly="readonly" style="width:100%; font-family:monospace; font-weight: bold;" rows="16" cols="60"></textarea></p>
</div>
@ -408,53 +362,99 @@
<h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i>
Управление
Controls
</h4>
<div class="row ui buttons">
<div class="four ui buttons">
<div class="ui animated button openrpa-control-lookmachinescreenshot green UACClient-pyOpenRPADict-AdminDict-ScreenshotViewerBool" onclick="mGlobal.Monitor.ScreenshotModal.Show();" style="display: none; margin-top: 5px;">
<div class="visible content">Смотреть экран</div>
<div class="visible content">Show live screenshots</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartorchestrator orange UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorBool" onclick="mGlobal.Controller.OrchestratorRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Перезагрузить оркестратор</div>
<div class="visible content">Restart orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-gitrestartorchestrator teal UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorGITPullBool disabled" onclick="mGlobal.Controller.OrchestratorGITPullRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Обновить из GIT</div>
<div class="ui animated button openrpa-control-gitrestartorchestrator teal UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorGITPullBool" onclick="mGlobal.Controller.OrchestratorGITPullRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Git pull, restart orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartpc red UACClient-pyOpenRPADict-AdminDict-RestartPCBool disabled" onclick="mGlobal.Controller.PCRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Перезагрузить ОС</div>
<div class="ui animated button openrpa-control-restartpc red UACClient-pyOpenRPADict-AdminDict-RestartPCBool" onclick="mGlobal.Controller.PCRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart PC</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
</div>
<div class="row black">
</div>
</div>
<div class="ui inverted vertical footer segment">
<div class="ui center aligned container">
<div class="ui stackable inverted divided grid">
<div class="three wide column">
<h4 class="ui inverted header">Pywinauto</h4>
<div class="ui inverted link list">
<a href="https://pywinauto.readthedocs.io/en/latest/code/pywinauto.findwindows.html" class="item" target="_blank">Specification manual</a>
<a href="https://pywinauto.readthedocs.io/en/latest/code/code.html#main-user-modules" class="item" target="_blank">Classes manual</a>
<a href="https://pywinauto.readthedocs.io/en/latest/code/code.html#main-user-modules" class="item" target="_blank">How to use manual</a>
<a href="https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html" class="item" target="_blank">Base wrapper manual</a>
</div>
</div>
<div class="three wide column">
<h4 class="ui inverted header">Semantic UI</h4>
<div class="ui inverted link list">
<a href="https://semantic-ui.com/usage/theming.html" class="item" target="_blank">Color manual</a>
<a href="https://semantic-ui.com/elements/input.html" class="item" target="_blank">Input manual</a>
<a href="https://semantic-ui.com/elements/icon.html" class="item" target="_blank">Icon list</a>
<a href="https://semantic-ui.com/elements/button.html" class="item" target="_blank">Button manual</a>
</div>
</div>
<div class="three wide column">
<h4 class="ui inverted header">GitLab</h4>
<div class="ui inverted link list">
<a href="https://gitlab.com/UnicodeLabs/OpenRPA" class="item" target="_blank">pyOpenRPA repository</a>
<a href="https://www.facebook.com/RU.IT4Business" class="item" target="_blank">Ivan Maslov</a>
<a href="#" class="item">Link -</a>
<a href="#" class="item">Link -</a>
</div>
</div>
<div class="seven wide column">
<h4 class="ui inverted header">pyOpenRPA</h4>
<p>Open source Robotic Process Automation software by the pyOpenRPA LLC (Created by Ivan Maslov in Russia). Licensed under LICENSE.PDF or https://pyopenrpa.ru/license/oferta.pdf #IT4Business</p>
</div>
</div>
<div class="ui inverted section divider"></div>
<div class="ui horizontal inverted small divided link list">
<a class="item" href="#">Site Map</a>
<a class="item" href="#">Contact Us</a>
<a class="item" href="#">Terms and Conditions</a>
<a class="item" href="#">Privacy Policy</a>
</div>
</div>
</div>
{% include 'footer.xhtml' %}
<div class="ui basic modal">
<div class="ui icon header">
</div>
<div class="content">
<p>Добро пожаловать!</p>
<p>Here is the message text!</p>
</div>
<div class="actions">
<div class="ui red basic cancel inverted button">
<i class="remove icon"></i>
Нет
No
</div>
<div class="ui green ok inverted button">
<i class="checkmark icon"></i>
Да
Yes
</div>
</div>
</div>
@ -462,12 +462,12 @@
<div class="ui icon header">
</div>
<div class="content">
<img src="/orpa/client/screenshot-get" class="ui fluid image">
<img src="GetScreenshot" class="ui fluid image">
</div>
<div class="actions">
<div class="ui green ok inverted button" onclick="mGlobal.Monitor.ScreenshotModal.Close()">
<i class="checkmark icon"></i>
Закрыть
Close
</div>
</div>
@ -476,20 +476,20 @@
<div class="ui modal openrpa-code-list-gui-import-modal">
<i class="close icon"></i>
<div class="header">
СПисок действий
Code list import
</div>
<div class="content">
<div class="description">
<div class="ui header">Вставить JSON спецификацию:</div>
<div class="ui header">Insert your JSON specification here.</div>
<p><textarea style="width:100%" rows="6" cols="60"></textarea></p>
</div>
</div>
<div class="actions">
<div class="ui black deny button">
Отменить
Cancel
</div>
<div class="ui positive right labeled icon button" onclick="mGlobal.CodeList.fActionSpecificationImportFromJSON();">
Распознать
Parse
<i class="checkmark icon"></i>
</div>
</div>

@ -8,7 +8,7 @@
* http://opensource.org/licenses/MIT
*
*/
@import url(/orpa/resources/Web/Google/LatoItalic.css);
@import url(/3rdParty/Google/LatoItalic.css);
/*@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic&subset=latin);*//*!
* # Semantic UI 2.4.0 - Reset
* http://github.com/semantic-org/semantic-ui/

@ -1,52 +0,0 @@
<div class="ui inverted vertical footer segment">
<div class="ui center aligned container">
<div class="ui stackable inverted divided equal height stackable grid">
<div class="four wide column">
<h4 class="ui inverted header">Навигатор</h4>
<div class="ui inverted link list">
<a href="https://pyopenrpa.ru/" target="_blank" class="item">Портал</a>
<a href="https://pyopenrpa.ru/wiki/guide/v1.2.14_RUS/html/index.html" target="_blank" class="item">Документация</a>
<a href="https://t.me/pyOpenRPA" target="_blank" class="item">Сообщество</a>
<a href="mailto:support@pyopenrpa.ru" target="_blank" class="item">Тех. поддержка</a>
<a href="https://pyopenrpa.ru/verification" target="_blank" class="item">Центр цифровых сертификатов</a>
</div>
</div>
<div class="four wide column">
<h4 class="ui inverted header">Интересный факт</h4>
<p><a href="https://pyopenrpa.ru" target="_blank">Портал pyOpenRPA</a> сделан на оркестраторе pyOpenRPA за 7 дней - присоединяйся к сильной стороне!</p>
<h4 class="ui inverted header">pyOpenRPA - роботы помогут!</h4>
</div>
<div class="eight wide column">
<h4 class="ui inverted header">Контактная информация</h4>
<span>ПРАВООБЛАДАТЕЛЬ: ООО "ОПЕН РПА", ОГРН 1227700251350</span>
<br>
<span>МСК: 125310, Россия, г. Москва, улица Муравская</span>
<br>
<span>СПБ: 197022, Россия, г. Санкт-Петербург, Аптекарский проспект, 18</span>
<br>
<span>Центр поддержки клиентов: +7 995 233 45 31 (с 9:00 до 18:00 по МСК), support@pyopenrpa.ru</span>
<br>
<span>Оказываем услуги на всей территории Российской Федерации</span>
</div>
</div>
<div class="ui inverted section divider"></div>
<div class="ui horizontal inverted small divided link list">
<a class="item" href="/orpa/fastapi/docs" target="_blank">Документация API (SWAGGER)</a>
<a class="item" href="/orpa/fastapi/redoc" target="_blank">Документация API (REDOC)</a>
<a class="item" href="https://semantic-ui.com/elements/input.html" target="_blank">Справка Semantic UI</a>
<a class="item" href="https://pywinauto.readthedocs.io/en/latest/code/code.html#main-user-modules" target="_blank">Справка Pywinauto</a>
<a class="item" href="https://gitlab.com/UnicodeLabs/OpenRPA" target="_blank">Репозиторий pyOpenRPA</a>
<a class="item" href="https://pyopenrpa.ru/license/oferta.pdf" target="_blank">Оферта</a>
</div>
</div>
</div>
<script src="/orpa/resources/Web/orpa/styleset/visibility.js"></script>
<script src="/orpa/resources/Web/orpa/styleset/sidebar.js"></script>
<script src="/orpa/resources/Web/orpa/styleset/transition.js"></script>
<script src="/orpa/resources/Web/orpa/styleset/docs.js"></script>
<script src="/orpa/resources/Web/orpa/styleset/easing.min.js"></script>
<script src="/orpa/resources/Web/orpa/styleset/highlight.min.js"></script>
<script src="/orpa/resources/Web/orpa/styleset/less.min.js"></script>
<script src="/orpa/resources/Web/orpa/styleset/home.js"></script>

@ -1,101 +0,0 @@
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/reset.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/site.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/container.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/grid.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/header.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/image.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/menu.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/divider.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/dropdown.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/segment.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/button.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/list.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/icon.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/sidebar.css">
<link rel="stylesheet" type="text/css" href="/orpa/resources/Web/Semantic-UI-CSS-master/components/transition.css">
<div class="pusher tag-top">
<div class="ui inverted vertical masthead center aligned segment zoomed" style="background-color:#000000; ">
<style type="text/css">
body {
background-color: #FFFFFF;
}
.main.container {
margin-top: 2em;
}
.main.menu {
margin-top: 4em;
border-radius: 0;
border: none;
box-shadow: none;
transition:
box-shadow 0.5s ease,
padding 0.5s ease
;
}
.main.menu .item img.logo {
margin-right: 1.5em;
}
.overlay {
float: left;
margin: 0em 3em 1em 0em;
}
.overlay .menu {
position: relative;
left: 0;
transition: left 0.5s ease;
}
.main.menu.fixed {
background-color: #FFFFFF;
border: 1px solid #DDD;
box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.2);
}
.overlay.fixed .menu {
left: 800px;
}
.text.container .left.floated.image {
margin: 2em 2em 2em -4em;
}
.text.container .right.floated.image {
margin: 2em -4em 2em 2em;
}
.ui.footer.segment {
margin: 5em 0em 0em;
padding: 5em 0em;
}
</style>
<div class="ui text container tag-top">
<div class="ui middle aligned stackable grid container">
<div class="row">
<div class="four wide column">
<img src="/orpa/resources/Web/orpa/logo.png" width="140px;" height="140px"></img>
</div>
<div class="twelve wide column">
<h1 class="ui inverted header" style="margin-top:0px; margin-bottom:0px;">
<span class="library" style="text-transform: uppercase; letter-spacing: 5px; margin-top:0px; margin-bottom:5px; font-weight: bold;">{{title}}</span>
<div class="floating ui teal label">{{version}}</div>
</h1>
<h2 style="text-transform: uppercase; letter-spacing: 5px; margin-top:0px; margin-bottom:5px;">
{{subtitle}}
</h2>
</div>
</div>
</div>
</div>
</div>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

@ -1,10 +0,0 @@
/*
* jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
*
* Open source under the BSD License.
*
* Copyright é 2001 Robert Penner
* All rights reserved.
*
*/
jQuery.easing.jswing=jQuery.easing.swing;jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(e,f,a,h,g){return jQuery.easing[jQuery.easing.def](e,f,a,h,g)},easeInQuad:function(e,f,a,h,g){return h*(f/=g)*f+a},easeOutQuad:function(e,f,a,h,g){return -h*(f/=g)*(f-2)+a},easeInOutQuad:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f+a}return -h/2*((--f)*(f-2)-1)+a},easeInCubic:function(e,f,a,h,g){return h*(f/=g)*f*f+a},easeOutCubic:function(e,f,a,h,g){return h*((f=f/g-1)*f*f+1)+a},easeInOutCubic:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f+a}return h/2*((f-=2)*f*f+2)+a},easeInQuart:function(e,f,a,h,g){return h*(f/=g)*f*f*f+a},easeOutQuart:function(e,f,a,h,g){return -h*((f=f/g-1)*f*f*f-1)+a},easeInOutQuart:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f+a}return -h/2*((f-=2)*f*f*f-2)+a},easeInQuint:function(e,f,a,h,g){return h*(f/=g)*f*f*f*f+a},easeOutQuint:function(e,f,a,h,g){return h*((f=f/g-1)*f*f*f*f+1)+a},easeInOutQuint:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f*f+a}return h/2*((f-=2)*f*f*f*f+2)+a},easeInSine:function(e,f,a,h,g){return -h*Math.cos(f/g*(Math.PI/2))+h+a},easeOutSine:function(e,f,a,h,g){return h*Math.sin(f/g*(Math.PI/2))+a},easeInOutSine:function(e,f,a,h,g){return -h/2*(Math.cos(Math.PI*f/g)-1)+a},easeInExpo:function(e,f,a,h,g){return(f==0)?a:h*Math.pow(2,10*(f/g-1))+a},easeOutExpo:function(e,f,a,h,g){return(f==g)?a+h:h*(-Math.pow(2,-10*f/g)+1)+a},easeInOutExpo:function(e,f,a,h,g){if(f==0){return a}if(f==g){return a+h}if((f/=g/2)<1){return h/2*Math.pow(2,10*(f-1))+a}return h/2*(-Math.pow(2,-10*--f)+2)+a},easeInCirc:function(e,f,a,h,g){return -h*(Math.sqrt(1-(f/=g)*f)-1)+a},easeOutCirc:function(e,f,a,h,g){return h*Math.sqrt(1-(f=f/g-1)*f)+a},easeInOutCirc:function(e,f,a,h,g){if((f/=g/2)<1){return -h/2*(Math.sqrt(1-f*f)-1)+a}return h/2*(Math.sqrt(1-(f-=2)*f)+1)+a},easeInElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}return -(g*Math.pow(2,10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j))+e},easeOutElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}return g*Math.pow(2,-10*h)*Math.sin((h*k-i)*(2*Math.PI)/j)+l+e},easeInOutElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k/2)==2){return e+l}if(!j){j=k*(0.3*1.5)}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}if(h<1){return -0.5*(g*Math.pow(2,10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j))+e}return g*Math.pow(2,-10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j)*0.5+l+e},easeInBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}return i*(f/=h)*f*((g+1)*f-g)+a},easeOutBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}return i*((f=f/h-1)*f*((g+1)*f+g)+1)+a},easeInOutBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}if((f/=h/2)<1){return i/2*(f*f*(((g*=(1.525))+1)*f-g))+a}return i/2*((f-=2)*f*(((g*=(1.525))+1)*f+g)+2)+a},easeInBounce:function(e,f,a,h,g){return h-jQuery.easing.easeOutBounce(e,g-f,0,h,g)+a},easeOutBounce:function(e,f,a,h,g){if((f/=g)<(1/2.75)){return h*(7.5625*f*f)+a}else{if(f<(2/2.75)){return h*(7.5625*(f-=(1.5/2.75))*f+0.75)+a}else{if(f<(2.5/2.75)){return h*(7.5625*(f-=(2.25/2.75))*f+0.9375)+a}else{return h*(7.5625*(f-=(2.625/2.75))*f+0.984375)+a}}}},easeInOutBounce:function(e,f,a,h,g){if(f<g/2){return jQuery.easing.easeInBounce(e,f*2,0,h,g)*0.5+a}return jQuery.easing.easeOutBounce(e,f*2-g,0,h,g)*0.5+h*0.5+a}});

@ -1,737 +0,0 @@
/*
* # Semantic UI - 2.4.2
* https://github.com/Semantic-Org/Semantic-UI
* http://www.semantic-ui.com/
*
* Copyright 2014 Contributors
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
/*!
* # Semantic UI - Header
* http://github.com/semantic-org/semantic-ui/
*
*
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
/*******************************
Header
*******************************/
/* Standard */
.ui.header {
border: none;
margin: calc(2rem - 0.14285714em ) 0em 1rem;
padding: 0em 0em;
font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-weight: bold;
line-height: 1.28571429em;
text-transform: none;
color: rgba(0, 0, 0, 0.87);
}
.ui.header:first-child {
margin-top: -0.14285714em;
}
.ui.header:last-child {
margin-bottom: 0em;
}
/*--------------
Sub Header
---------------*/
.ui.header .sub.header {
display: block;
font-weight: normal;
padding: 0em;
margin: 0em;
font-size: 1rem;
line-height: 1.2em;
color: rgba(0, 0, 0, 0.6);
}
/*--------------
Icon
---------------*/
.ui.header > .icon {
display: table-cell;
opacity: 1;
font-size: 1.5em;
padding-top: 0em;
vertical-align: middle;
}
/* With Text Node */
.ui.header .icon:only-child {
display: inline-block;
padding: 0em;
margin-right: 0.75rem;
}
/*-------------------
Image
--------------------*/
.ui.header > .image:not(.icon),
.ui.header > img {
display: inline-block;
margin-top: 0.14285714em;
width: 2.5em;
height: auto;
vertical-align: middle;
}
.ui.header > .image:not(.icon):only-child,
.ui.header > img:only-child {
margin-right: 0.75rem;
}
/*--------------
Content
---------------*/
.ui.header .content {
display: inline-block;
vertical-align: top;
}
/* After Image */
.ui.header > img + .content,
.ui.header > .image + .content {
padding-left: 0.75rem;
vertical-align: middle;
}
/* After Icon */
.ui.header > .icon + .content {
padding-left: 0.75rem;
display: table-cell;
vertical-align: middle;
}
/*--------------
Loose Coupling
---------------*/
.ui.header .ui.label {
font-size: '';
margin-left: 0.5rem;
vertical-align: middle;
}
/* Positioning */
.ui.header + p {
margin-top: 0em;
}
/*******************************
Types
*******************************/
/*--------------
Page
---------------*/
h1.ui.header {
font-size: 2rem;
}
h2.ui.header {
font-size: 1.71428571rem;
}
h3.ui.header {
font-size: 1.28571429rem;
}
h4.ui.header {
font-size: 1.07142857rem;
}
h5.ui.header {
font-size: 1rem;
}
/* Sub Header */
h1.ui.header .sub.header {
font-size: 1.14285714rem;
}
h2.ui.header .sub.header {
font-size: 1.14285714rem;
}
h3.ui.header .sub.header {
font-size: 1rem;
}
h4.ui.header .sub.header {
font-size: 1rem;
}
h5.ui.header .sub.header {
font-size: 0.92857143rem;
}
/*--------------
Content Heading
---------------*/
.ui.huge.header {
min-height: 1em;
font-size: 2em;
}
.ui.large.header {
font-size: 1.71428571em;
}
.ui.medium.header {
font-size: 1.28571429em;
}
.ui.small.header {
font-size: 1.07142857em;
}
.ui.tiny.header {
font-size: 1em;
}
/* Sub Header */
.ui.huge.header .sub.header {
font-size: 1.14285714rem;
}
.ui.large.header .sub.header {
font-size: 1.14285714rem;
}
.ui.header .sub.header {
font-size: 1rem;
}
.ui.small.header .sub.header {
font-size: 1rem;
}
.ui.tiny.header .sub.header {
font-size: 0.92857143rem;
}
/*--------------
Sub Heading
---------------*/
.ui.sub.header {
padding: 0em;
margin-bottom: 0.14285714rem;
font-weight: bold;
font-size: 0.85714286em;
text-transform: uppercase;
color: '';
}
.ui.small.sub.header {
font-size: 0.78571429em;
}
.ui.sub.header {
font-size: 0.85714286em;
}
.ui.large.sub.header {
font-size: 0.92857143em;
}
.ui.huge.sub.header {
font-size: 1em;
}
/*-------------------
Icon
--------------------*/
.ui.icon.header {
display: inline-block;
text-align: center;
margin: 2rem 0em 1rem;
}
.ui.icon.header:after {
content: '';
display: block;
height: 0px;
clear: both;
visibility: hidden;
}
.ui.icon.header:first-child {
margin-top: 0em;
}
.ui.icon.header .icon {
float: none;
display: block;
width: auto;
height: auto;
line-height: 1;
padding: 0em;
font-size: 3em;
margin: 0em auto 0.5rem;
opacity: 1;
}
.ui.icon.header .content {
display: block;
padding: 0em;
}
.ui.icon.header .circular.icon {
font-size: 2em;
}
.ui.icon.header .square.icon {
font-size: 2em;
}
.ui.block.icon.header .icon {
margin-bottom: 0em;
}
.ui.icon.header.aligned {
margin-left: auto;
margin-right: auto;
display: block;
}
/*******************************
States
*******************************/
.ui.disabled.header {
opacity: 0.45;
}
/*******************************
Variations
*******************************/
/*-------------------
Inverted
--------------------*/
.ui.inverted.header {
color: #FFFFFF;
}
.ui.inverted.header .sub.header {
color: rgba(255, 255, 255, 0.8);
}
.ui.inverted.attached.header {
background: #545454 -webkit-gradient(linear, left top, left bottom, from(transparent), to(rgba(0, 0, 0, 0.05)));
background: #545454 -webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.05));
background: #545454 linear-gradient(transparent, rgba(0, 0, 0, 0.05));
-webkit-box-shadow: none;
box-shadow: none;
border-color: transparent;
}
.ui.inverted.block.header {
background: #545454 -webkit-gradient(linear, left top, left bottom, from(transparent), to(rgba(0, 0, 0, 0.05)));
background: #545454 -webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.05));
background: #545454 linear-gradient(transparent, rgba(0, 0, 0, 0.05));
-webkit-box-shadow: none;
box-shadow: none;
}
.ui.inverted.block.header {
border-bottom: none;
}
/*-------------------
Colors
--------------------*/
/*--- Red ---*/
.ui.red.header {
color: #DB2828 !important;
}
a.ui.red.header:hover {
color: #d01919 !important;
}
.ui.red.dividing.header {
border-bottom: 2px solid #DB2828;
}
/* Inverted */
.ui.inverted.red.header {
color: #FF695E !important;
}
a.ui.inverted.red.header:hover {
color: #ff5144 !important;
}
/*--- Orange ---*/
.ui.orange.header {
color: #F2711C !important;
}
a.ui.orange.header:hover {
color: #f26202 !important;
}
.ui.orange.dividing.header {
border-bottom: 2px solid #F2711C;
}
/* Inverted */
.ui.inverted.orange.header {
color: #FF851B !important;
}
a.ui.inverted.orange.header:hover {
color: #ff7701 !important;
}
/*--- Olive ---*/
.ui.olive.header {
color: #B5CC18 !important;
}
a.ui.olive.header:hover {
color: #a7bd0d !important;
}
.ui.olive.dividing.header {
border-bottom: 2px solid #B5CC18;
}
/* Inverted */
.ui.inverted.olive.header {
color: #D9E778 !important;
}
a.ui.inverted.olive.header:hover {
color: #d8ea5c !important;
}
/*--- Yellow ---*/
.ui.yellow.header {
color: #FBBD08 !important;
}
a.ui.yellow.header:hover {
color: #eaae00 !important;
}
.ui.yellow.dividing.header {
border-bottom: 2px solid #FBBD08;
}
/* Inverted */
.ui.inverted.yellow.header {
color: #FFE21F !important;
}
a.ui.inverted.yellow.header:hover {
color: #ffdf05 !important;
}
/*--- Green ---*/
.ui.green.header {
color: #21BA45 !important;
}
a.ui.green.header:hover {
color: #16ab39 !important;
}
.ui.green.dividing.header {
border-bottom: 2px solid #21BA45;
}
/* Inverted */
.ui.inverted.green.header {
color: #2ECC40 !important;
}
a.ui.inverted.green.header:hover {
color: #22be34 !important;
}
/*--- Teal ---*/
.ui.teal.header {
color: #00B5AD !important;
}
a.ui.teal.header:hover {
color: #009c95 !important;
}
.ui.teal.dividing.header {
border-bottom: 2px solid #00B5AD;
}
/* Inverted */
.ui.inverted.teal.header {
color: #6DFFFF !important;
}
a.ui.inverted.teal.header:hover {
color: #54ffff !important;
}
/*--- Blue ---*/
.ui.blue.header {
color: #2185D0 !important;
}
a.ui.blue.header:hover {
color: #1678c2 !important;
}
.ui.blue.dividing.header {
border-bottom: 2px solid #2185D0;
}
/* Inverted */
.ui.inverted.blue.header {
color: #54C8FF !important;
}
a.ui.inverted.blue.header:hover {
color: #3ac0ff !important;
}
/*--- Violet ---*/
.ui.violet.header {
color: #6435C9 !important;
}
a.ui.violet.header:hover {
color: #5829bb !important;
}
.ui.violet.dividing.header {
border-bottom: 2px solid #6435C9;
}
/* Inverted */
.ui.inverted.violet.header {
color: #A291FB !important;
}
a.ui.inverted.violet.header:hover {
color: #8a73ff !important;
}
/*--- Purple ---*/
.ui.purple.header {
color: #A333C8 !important;
}
a.ui.purple.header:hover {
color: #9627ba !important;
}
.ui.purple.dividing.header {
border-bottom: 2px solid #A333C8;
}
/* Inverted */
.ui.inverted.purple.header {
color: #DC73FF !important;
}
a.ui.inverted.purple.header:hover {
color: #d65aff !important;
}
/*--- Pink ---*/
.ui.pink.header {
color: #E03997 !important;
}
a.ui.pink.header:hover {
color: #e61a8d !important;
}
.ui.pink.dividing.header {
border-bottom: 2px solid #E03997;
}
/* Inverted */
.ui.inverted.pink.header {
color: #FF8EDF !important;
}
a.ui.inverted.pink.header:hover {
color: #ff74d8 !important;
}
/*--- Brown ---*/
.ui.brown.header {
color: #A5673F !important;
}
a.ui.brown.header:hover {
color: #975b33 !important;
}
.ui.brown.dividing.header {
border-bottom: 2px solid #A5673F;
}
/* Inverted */
.ui.inverted.brown.header {
color: #D67C1C !important;
}
a.ui.inverted.brown.header:hover {
color: #c86f11 !important;
}
/*--- Grey ---*/
.ui.grey.header {
color: #767676 !important;
}
a.ui.grey.header:hover {
color: #838383 !important;
}
.ui.grey.dividing.header {
border-bottom: 2px solid #767676;
}
/* Inverted */
.ui.inverted.grey.header {
color: #DCDDDE !important;
}
a.ui.inverted.grey.header:hover {
color: #cfd0d2 !important;
}
/*-------------------
Aligned
--------------------*/
.ui.left.aligned.header {
text-align: left;
}
.ui.right.aligned.header {
text-align: right;
}
.ui.centered.header,
.ui.center.aligned.header {
text-align: center;
}
.ui.justified.header {
text-align: justify;
}
.ui.justified.header:after {
display: inline-block;
content: '';
width: 100%;
}
/*-------------------
Floated
--------------------*/
.ui.floated.header,
.ui[class*="left floated"].header {
float: left;
margin-top: 0em;
margin-right: 0.5em;
}
.ui[class*="right floated"].header {
float: right;
margin-top: 0em;
margin-left: 0.5em;
}
/*-------------------
Fitted
--------------------*/
.ui.fitted.header {
padding: 0em;
}
/*-------------------
Dividing
--------------------*/
.ui.dividing.header {
padding-bottom: 0.21428571rem;
border-bottom: 1px solid rgba(34, 36, 38, 0.15);
}
.ui.dividing.header .sub.header {
padding-bottom: 0.21428571rem;
}
.ui.dividing.header .icon {
margin-bottom: 0em;
}
.ui.inverted.dividing.header {
border-bottom-color: rgba(255, 255, 255, 0.1);
}
/*-------------------
Block
--------------------*/
.ui.block.header {
background: #F3F4F5;
padding: 0.78571429rem 1rem;
-webkit-box-shadow: none;
box-shadow: none;
border: 1px solid #D4D4D5;
border-radius: 0.28571429rem;
}
.ui.tiny.block.header {
font-size: 0.85714286rem;
}
.ui.small.block.header {
font-size: 0.92857143rem;
}
.ui.block.header:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) {
font-size: 1rem;
}
.ui.large.block.header {
font-size: 1.14285714rem;
}
.ui.huge.block.header {
font-size: 1.42857143rem;
}
/*-------------------
Attached
--------------------*/
.ui.attached.header {
background: #FFFFFF;
padding: 0.78571429rem 1rem;
margin-left: -1px;
margin-right: -1px;
-webkit-box-shadow: none;
box-shadow: none;
border: 1px solid #D4D4D5;
}
.ui.attached.block.header {
background: #F3F4F5;
}
.ui.attached:not(.top):not(.bottom).header {
margin-top: 0em;
margin-bottom: 0em;
border-top: none;
border-radius: 0em;
}
.ui.top.attached.header {
margin-bottom: 0em;
border-radius: 0.28571429rem 0.28571429rem 0em 0em;
}
.ui.bottom.attached.header {
margin-top: 0em;
border-top: none;
border-radius: 0em 0em 0.28571429rem 0.28571429rem;
}
/* Attached Sizes */
.ui.tiny.attached.header {
font-size: 0.85714286em;
}
.ui.small.attached.header {
font-size: 0.92857143em;
}
.ui.attached.header:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) {
font-size: 1em;
}
.ui.large.attached.header {
font-size: 1.14285714em;
}
.ui.huge.attached.header {
font-size: 1.42857143em;
}
/*-------------------
Sizing
--------------------*/
.ui.header:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) {
font-size: 1.28571429em;
}
/*******************************
Theme Overrides
*******************************/
/*******************************
Site Overrides
*******************************/

@ -1,759 +0,0 @@
/*******************************
Homepage
*******************************/
body.index .pusher > .page {
background-color: #FFFFFF;
}
@media only screen and (max-width: 992px) {
html {
overflow-x: visible;
-webkit-overflow-scrolling: auto;
}
}
body > .pusher {
display: block;
min-height: 0px;
flex-direction: initial;
}
body > .pusher > .full.height {
display: block;
flex: none !important;
}
/*--------------
Masthead
---------------*/
body .masthead.segment.zoomed h1 {
text-shadow: 0px 0px 4px rgba(0, 0, 0, 0);
color: rgba(255, 255, 255, 1);
}
body .masthead.zoomed:after {
opacity: 0;
}
body .masthead.zoomed {
background-color: #25282A;
}
body .masthead {
position: relative;
overflow: hidden;
text-align: center;
padding: 0em;
color: rgba(255, 255, 255, 0.9);
margin-bottom: 0px;
border-bottom: none;
background-color: #000000;
background-position: 50% 50%;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
body .masthead:after {
position: absolute;
top: 0px;
left: 0px;
z-index: -1;
width: 100%;
height: 100%;
content: '';
background-size: cover;
opacity: 0.45;
}
body .masthead.bg1:after {
background-image: url("./bg1.jpg");
}
body .masthead.bg2:after {
background-image: url("./bg2.jpg");
}
body .masthead.bg3:after {
background-image: url("./bg3.jpg");
}
body .masthead.bg4:after {
background-image: url("./bg4.jpg");
}
body .masthead.bg5:after {
background-image: url("./bg5.jpg");
}
body .masthead.bg6:after {
background-image: url("./bg6.jpg");
}
body .masthead.bg7:after {
background-image: url("./bg7.jpg");
}
body .masthead.bg8:after {
background-image: url("./bg8.jpg");
}
body .masthead.bg9:after {
background-image: url("./bg9.jpg");
}
body .masthead.bg10:after {
background-image: url("./bg10.jpg");
}
body .masthead.bg11:after {
background-image: url("./bg1.jpg");
}
body .masthead.bg12:after {
background-image: url("./bg2.jpg");
}
body .masthead.bg13:after {
background-image: url("./bg3.jpg");
}
body .masthead.bg14:after {
background-image: url("./bg4.jpg");
}
body .masthead,
body .masthead:after {
-ms-transition:
background 6s cubic-bezier(0.680, -0.550, 0.265, 1.4) 0s,
opacity 6s cubic-bezier(0.680, -0.550, 0.265, 1.4) 0s;
-moz-transition:
background 6s cubic-bezier(0.680, -0.550, 0.265, 1.4) 0s,
opacity 6s cubic-bezier(0.680, -0.550, 0.265, 1.4) 0s;
-webkit-transition:
background 6s cubic-bezier(0.680, -0.550, 0.265, 1.4) 0s,
opacity 6s cubic-bezier(0.680, -0.550, 0.265, 1.4) 0s;
transition:
background 6s cubic-bezier(0.680, -0.550, 0.265, 1.4) 0s,
opacity 6s cubic-bezier(0.680, -0.550, 0.265, 1.4) 0s;
}
#example.index .masthead .container {
height: 55vh;
margin-left: auto !important;
margin-right: auto !important;
min-height: 600px;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
#example .masthead .container {
padding: 15rem 0em;
}
#example.index .following.bar iframe.github {
margin-top: 0px;
}
body.index .following.bar .menu .item {
display: block;
}
#example.index.pushed .masthead,
#example.index.pushed .following.bar {
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
#example.index > .pusher > .footer {
padding-left: 0em;
}
#example.index .light.following.bar {
padding: 0em 0em;
background-color: #FFFFFF;
border-bottom: 1px solid #DDDDDD;
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.04);
}
#example.index .masthead.segment .typed-cursor {
position: relative;
top: -0.05em;
left: -0.25em;
visibility: hidden;
opacity: 1;
-webkit-animation: blink 0.7s infinite;
-moz-animation: blink 0.7s infinite;
animation: blink 0.7s infinite;
-webkit-transition: opacity 0.7s ease;
-moz-transition: opacity 0.7s ease;
transition: opacity 0.7s ease;
}
#example.index .masthead.segment .typed-cursor.stop {
opacity: 0;
-moz-animation-duration: 0s;
-webkit-animation-duration: 0s;
animation-duration: 0s;
}
@keyframes blink {
0% { opacity:1; }
50% { opacity:0; }
100% { opacity:1; }
}
@-webkit-keyframes blink {
0% { opacity:1; }
50% { opacity:0; }
100% { opacity:1; }
}
@-moz-keyframes blink {
0% { opacity:1; }
50% { opacity:0; }
100% { opacity:1; }
}
#example.index .vertical.segment {
box-shadow: none;
}
#example.index .masthead.segment h1 {
font-size: 3em;
color: rgba(255, 255, 255, 1);
line-height: 1.2;
margin: 0px 0px 0px;
padding-bottom: 0px;
-moz-perspective: 500px;
-webkit-perspective: 500px;
perspective: 500px;
text-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
-moz-transform-style: preserve-3d;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
#example.index .masthead.segment h1 .tagline {
font-size: 0.75em;
}
#example.index .masthead.segment h1 > .library {
display: block;
font-size: 1.75em;
font-weight: bold;
}
#example.index .masthead.segment h1 b {
display: inline-block;
font-weight: 500;
}
#example.index .masthead.segment h1 .text {
display: inline-block;
font-weight: 300;
margin-left: -0.4em;
}
#example.index .masthead h2 {
font-weight: normal;
margin: 0px 0 16px 0px;
font-size: 1.75em;
border-bottom: none;
line-height: 1;
}
#example.index .masthead p {
font-size: 1.5em;
margin: 1em 0em 1.5em;
padding: 0px;
}
#example.index .ui.header {
font-weight: normal;
}
#example.index .footer .ui.header {
font-weight: bold;
}
#example.index .introduction {
position: relative;
clear: both;
display: block;
text-align: center;
}
#example.index .introduction .buttons {
margin-top: 3em;
}
#example.index .advertisement {
display: none !important;
padding-left: 0;
position: absolute;
left: auto;
right: 6em;
top: 50%;
transform: translateY(-50%);
vertical-align: top;
}
#example.index .fixed.launch.button {
display: none;
top: 100px;
}
#example.index .main.menu {
top: 0px;
}
#example.index pre.console {
height: 120px;
}
/*--------------
Intro
---------------*/
#example .intro.segment h1 + p {
font-size: 22px;
}
/*--------------
Demo
---------------*/
#example .demo.row .example > .ui.label:not(.empty) {
margin-bottom: 1em;
}
#example .demo.row .ui.progress {
margin-bottom: 2.5em;
}
#example .demo.row h4 {
font-weight: bold !important;
margin: 0em 0em 1em !important;
}
#example .demo.row .example {
clear: both;
padding-top: 3em;
margin-top: 3em;
}
#example .demo.row .ui.menu,
#example .demo.row .ui.card {
width: 100%;
}
#example .demo.row .ui.card {
width: 100%;
max-width: 400px;
}
/*--------------
Features
---------------*/
#example.index .hidden.code {
visibility: hidden;
}
#example.index .demo.row .example {
clear: both;
padding-top: 1.5em;
margin-top: 1.5em;
}
#example.index .demo.row .example:first-child {
margin-top: 0;
padding-top: 0;
}
#example.index .demo.row .example:last-child {
margin-bottom: 0em;
}
/*--------------
Following
---------------*/
#example.index .following.bar {
position: fixed;
top: 0px;
z-index: 900;
left: 0%;
padding: 2em 0em;
width: 100%;
box-shadow: 0px 0px 0px 0px transparent;
border-bottom: 1px solid transparent;
transition:
padding 0.5s ease,
background 0.5s ease,
box-shadow 0.5s ease,
border 0.5s ease
;
}
#example.index .following.bar > .menu .item {
transition: all 0.5s ease;
}
#example.index.pushed .following.bar .menu .item,
#example.index.pushed .following.bar {
transition: none;
}
#example.index .following.bar .additional.item[data-site="learn"]:hover {
color: #D9499A;
}
#example.index .following.bar span.additional.item {
cursor: default;
color: rgba(0, 0, 0, 0.2);
}
#example.index .following.bar .inverted span.additional.item {
color: rgba(255, 255, 255, 0.2);
}
#example.index .following.bar .column > .menu {
margin-top: 0px;
height: 35px;
}
#example.index .following.bar .network.menu .item {
font-weight: bold;
}
#example.index .following.bar .item iframe {
margin-left: 10px;
}
#example.index .following.bar .network.menu .view-ui {
margin-right: 1em;
}
#example.index .light.following.bar .network.menu .view-ui {
color: #00B5AD;
}
#example.index .light.following.bar .inverted.network.menu .view-ui {
color: #6DFFFF;
}
#example.index .following .logo {
float: left;
width: 35px;
margin-right: 1em;
}
#example.index .following .logo .side {
width: 35px;
}
#example .masthead .version.label:after {
background-color: #000000 !important;
}
#example.index .following .version.label {
margin: 0.25em 0px 0px 1em;
}
/*--------------
Stripes
---------------*/
#example.index .stripe .grid .row {
margin: 2rem 0rem;
}
#example.index .feature.stripe .grid .row {
margin: 0rem;
}
#example.index .feature.stripe .column {
display: flex;
-ms-flex-direction: column;
-webkit-flex-direction: column;
-moz-flex-direction: column;
flex-direction: column;
}
#example.index .feature.stripe p {
-webkit-flex: 1 0 auto;
-moz-flex: 1 0 auto;
-ms-flex: 1 0 auto;
flex: 1 0 auto;
margin: 0.5em 0em 2em;
}
#example .stripe .ui.vertical.divider {
font-size: 1rem;
}
#example.index .feature.stripe .icon.header .icon.image {
width: auto;
height: 65px;
margin-bottom: 20px;
}
#example.index .stripe .icon.header .icon.image {
height: 65px;
margin-bottom: 20px;
}
#example.index .community.stripe {
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.1);
padding: 4em 0;
}
#example.index .stripe .icon.header i.icon {
font-size: 2em;
}
/* Final */
#example.index .final.stripe {
border-top: 1px solid #DDDDDD;
background-color: #F8F8F8;
}
/* Alternate */
#example .alternate.stripe {
background-color: #F2F3F5;
}
/* Inverted */
#example.index .inverted.stripe {
background-color: #1B1C1D;
}
#example.index .inverted.stripe p {
color: #FFFFFF;
}
/*--------------
Legacy?
---------------*/
/* content */
#example .solid,
#example .stripe {
background-color: #FFFFFF;
padding: 10em 0px;
border-radius: 0em;
margin: 0em;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
#example .theming.stripe {
-webkit-transform: none;
transform: none;
}
#example .stripe h1 {
font-size: 40px;
}
#example .stripe h2 {
font-size: 26px;
}
#example .stripe h3 {
font-size: 20px;
}
#example .feature.stripe {
padding: 3em 0em;
}
#example .theming.stripe .left.aligned.column {
padding-top: 8em;
}
#example .theming.stripe .hljs.code {
height: 483px;
max-height: 483px;
}
#example .theming .source.grid {
display: none !important;
margin: 2rem 2rem -4rem;
}
#example .theming .source.grid.visible {
display: block;
display: flex !important;
}
#example .theming.stripe .buttons {
vertical-align: top;
}
#example .theming.stripe .button {
margin-bottom: 0.5em;
}
#example .stripe .column > p {
font-size: 16px;
line-height: 1.6;
margin: 1em 0em;
}
#example .dark.stripe {
background-color: #333333;
background: url(/images/dark-bg.png) repeat;
color: #FFFFFF;
}
#example .stripe .column > .label {
margin-bottom: 1em;
}
#example .solid {
background-color: #FFFFFF;
-webkit-box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.1);
box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.1);
}
#example .solid .column {
color: #555555;
}
#example .solid .column p b {
color: rgba(0, 0, 0, 0.9);
}
#example .solid .column p {
color: rgba(0, 0, 0, 0.5);
}
/*--------------
Promo
---------------*/
#example.index .promo.stripe {
padding: 3em 0em;
}
/*--------------
Newsletter
---------------*/
#example.index .email.stripe {
padding: 5em 0em;
}
#example.index .email.stripe p {
margin: -0.5em 0em 1em;
}
#example.index .email.stripe .input {
width: 450px;
}
#example.index .email.stripe .submit.button {
margin-left: 1em;
}
@media only screen and (max-width : 400px) {
#example.index .advertisement {
display: none;
margin-left: -130px !important;
}
#example.index .carbonad {
width: 260px !important;
}
#example.index .masthead.segment h1 {
font-size: 1.75em !important;
}
#example.index .feature.stripe {
padding: 1em;
}
}
@media only screen and (max-width : 600px) {
#example.index .solid,
#example.index .stripe {
padding: 4em 0em;
}
#example.index .masthead.segment h1 .text {
margin-left: 0em;
}
#example.index .following.bar {
display: none;
}
#example.index .masthead:before {
display: none;
}
#example.index .following.bar .column {
text-align: center;
}
#example.index .following .logo {
float: none;
}
#example.index .codebase.stripe {
display: none;
}
#example.index .following .version.label {
vertical-align: top;
margin-top: 0em;
}
#example .masthead .container {
padding: 6rem 0rem;
}
#example.index .masthead.segment h1 {
font-size: 2.25em;
}
#example.index .email.stripe .input {
width: 100%;
}
#example.index .following .secondary.menu {
display: none;
}
#example.index .email.stripe .submit.button {
margin-top: 0.5em;
}
#example.index .stripe .icon.header .icon.image {
height: 50px;
}
#example.index .stripe {
padding: 2em 0em !important;
}
}
@media only screen and (max-width : 650px) {
#example.index .fixed.launch.button {
display: none;
}
#example .stripe h1 {
font-size: 32px;
}
}
@media only screen and (min-width : 601px) {
#example .theming .source.button {
display: none;
}
#example.index .main.menu {
display: none;
}
#example.index .fixed.launch.button {
display: none;
}
}
/* Homepage */
@media only screen and (max-width : 810px) {
#example.index .masthead.segment h1 > .library {
font-size: 1.75em;
}
#example.index .feature.stripe p {
height: auto;
min-height: 0px;
}
#example.index .container {
margin-left: 0em;
margin-right: 0em;
}
#example .solid, #example .stripe {
padding: 6em 0em;
}
#example.index .masthead .container {
margin-top: 50px;
}
#example.index .following.bar span.additional.item {
display: none;
visibility: hidden !important;
}
#example.index .following.bar .network.menu .view-ui {
margin-right: 0.75em;
}
#example.index .masthead .container {
min-height: 350px;
height: auto;
}
}
@media only screen and (max-width : 1040px) {
#example.index .following.bar .network.menu .view-ui {
margin-right: 0.5em;
}
}
@media only screen and (max-width: 1300px) {
#example.index .advertisement {
position: absolute;
top: auto;
left: 50%;
bottom: 2rem;
margin-left: -175px;
-webkit-transform: none;
-moz-transform: none;
-ms-transform: none;
transform: none;
}
#example.index .inverted.advertisement .carbonad-img {
margin-top: 0px;
}
#example.index #carbonads-container {
float: none;
}
#example.index .carbonad {
width: 340px;
}
#example.index .carbonad-text,
#example.index .carbonad-tag {
float: none;
display: block;
text-align: left;
margin-left: 160px;
width: 170px;
}
}

@ -1,322 +0,0 @@
semantic.home = {};
// ready event
semantic.home.ready = function() {
var
$themeDropdown = $('.theme.dropdown'),
$header = $('.masthead'),
$ui = $header.find('h1 b'),
$phrase = $header.find('h1 span'),
$download = $header.find('.download'),
$library = $header.find('.library'),
$cursor = $header.find('.typed-cursor'),
$version = $header.find('.version'),
$themeButton = $('.theming .source.button'),
$themeGrid = $('.theming .source.grid'),
handler
;
handler = {
getRandomInt: function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
},
introduction: function() {
var
background = 'bg' + handler.getRandomInt(1, 9)
;
// zoom out
$header
.addClass(background)
.removeClass('zoomed')
;
},
changeLogo: function() {
var
$logo = $('.following .logo'),
$nextSide = $logo.find('.'+ $(this).data('site') +'.side'),
directions = [
'up',
'left',
'down',
'right'
],
direction = directions[Math.floor(Math.random() * directions.length)]
;
if($nextSide.length > 0) {
clearTimeout(handler.timer);
handler.timer = setTimeout(function() {
$logo
.shape('set next side', $nextSide)
.shape('flip ' + direction)
;
}, 50);
}
},
returnLogo: function() {
var
$logo = $('.following .logo'),
$nextSide = $logo.find('.ui.side')
;
clearTimeout(handler.timer);
handler.timer = setTimeout(function() {
$logo
.shape('set next side', $nextSide)
.shape('flip over')
;
}, 500);
},
less: {
parseFile: function(content) {
var
variables = {},
lines = content.match(/^\s*(@[\s|\S]+?;)/gm),
name,
value
;
if(lines) {
$.each(lines, function(index, line) {
// clear whitespace
line = $.trim(line);
// match variables only
if(line[0] == '@') {
name = line.match(/^@(.+?):/);
value = line.match(/:\s*([\s|\S]+?;)/);
if( ($.isArray(name) && name.length >= 2) && ($.isArray(value) && value.length >= 2) ) {
name = name[1];
value = value[1];
variables[name] = value;
}
}
});
}
console.log(variables);
return variables;
},
changeTheme: function(theme) {
var
$themeDropdown = $(this),
$variableCode = $('.variable.code'),
$overrideCode = $('.override.code'),
$existingVariables = $variableCode.closest('.existing'),
$existingOverrides = $overrideCode.closest('.existing'),
variableURL = '/src/themes/{$theme}/{$type}s/{$element}.variables',
overrideURL = '/src/themes/{$theme}/{$type}s/{$element}.overrides',
urlData = {
theme : typeof(theme === 'string')
? theme.toLowerCase()
: theme,
type : $themeDropdown.data('type'),
element : $themeDropdown.data('element')
}
;
if($existingVariables.length > 0) {
$variableCode = $('<div class="ui variable code" data-type="less" data-preserve="true" />');
$variableCode
.insertAfter($existingVariables)
;
$existingVariables.remove();
console.log($variableCode);
}
if($existingOverrides.length > 0) {
$overrideCode = $('<div class="ui override code" data-type="less" data-preserve="true" />');
$overrideCode
.insertAfter($existingOverrides)
;
$existingOverrides.remove();
console.log($overrideCode);
}
$themeDropdown
.api({
on : 'now',
url : variableURL,
dataType : 'text',
urlData : urlData,
onSuccess: function(content) {
window.less.modifyVars( handler.less.parseFile(content) );
$themeDropdown
.api({
on : 'now',
url : overrideURL,
dataType : 'text',
urlData : urlData,
onSuccess: function(content) {
if( $('style.override').length > 0 ) {
$('style.override').remove();
}
$('<style>' + content + '</style>')
.addClass('override')
.appendTo('body')
;
$('.sticky').sticky('refresh');
$overrideCode.html(content);
$.proxy(semantic.handler.initializeCode, $overrideCode[0])();
}
})
;
$variableCode.html(content);
$.proxy(semantic.handler.initializeCode, $variableCode[0])();
}
})
;
}
},
showThemeButton: function(value, text) {
if(!$themeButton.transition('is visible')) {
$themeButton.transition('scale in');
}
$.proxy(handler.less.changeTheme, this)(value);
},
createDemos: function() {
$('.demo.menu .item, .demo.buttons .button')
.on('click', function() {
if(!$(this).hasClass('dropdown')) {
$(this)
.addClass('active')
.closest('.ui.menu, .ui.buttons')
.find('.item, .button')
.not($(this))
.removeClass('active')
;
}
})
;
$('.example .message .close')
.on('click', function() {
$(this).closest('.message').transition('scale out');
})
;
},
toggleTheme: function() {
$(this).toggleClass('active');
$themeGrid.toggleClass('visible');
}
};
// intro
handler.introduction();
if($(window).width() > 600) {
$('body')
.visibility({
offset : -10,
observeChanges : false,
once : false,
continuous : false,
onTopPassed: function() {
requestAnimationFrame(function() {
$('.following.bar')
.addClass('light fixed')
.find('.menu')
.removeClass('inverted')
;
$('.following .additional.item')
.transition('scale in', 750)
;
});
},
onTopPassedReverse: function() {
requestAnimationFrame(function() {
$('.following.bar')
.removeClass('light fixed')
.find('.menu')
.addClass('inverted')
.find('.additional.item')
.transition('hide')
;
});
}
})
;
}
$('.additional.item')
.popup({
delay: {
show: 200,
hide: 50
},
position: 'bottom center'
})
;
$('.email.stripe form')
.form({
fields: {
email: {
identifier : 'email',
rules: [
{
type : 'empty',
prompt : 'Please enter an e-mail'
},
{
type : 'email',
prompt : 'Please enter a valid e-mail address'
}
]
}
}
})
;
$themeDropdown
.dropdown('setting', 'transition', 'drop')
.dropdown('setting', 'duration', 350)
.dropdown('setting', 'action', 'activate')
.dropdown('setting', 'onChange', handler.showThemeButton)
;
$themeButton
.on('click', handler.toggleTheme)
;
// demos
$('.demo .checkbox')
.checkbox()
;
$('.demo .accordion')
.accordion()
;
$('.demo .dimmer')
.dimmer({
on: 'hover'
})
;
$('.demo .ui.dropdown')
.dropdown()
;
if(window.Transifex !== undefined) {
window.Transifex.live.onTranslatePage(function(countryCode){
var fullName = $('.language.dropdown .item[data-value=' + countryCode + ']').eq(0).text();
$('.language.dropdown > .text').html(fullName);
});
}
$('.ui.sidebar')
.sidebar('setting', {
transition: 'overlay'
})
;
handler.createDemos();
};
// attach ready event
$(document)
.ready(semantic.home.ready)
;

File diff suppressed because one or more lines are too long

@ -1,889 +0,0 @@
/*
* # Semantic UI - 2.4.2
* https://github.com/Semantic-Org/Semantic-UI
* http://www.semantic-ui.com/
*
* Copyright 2014 Contributors
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
/*!
* # Semantic UI - Segment
* http://github.com/semantic-org/semantic-ui/
*
*
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
/*******************************
Segment
*******************************/
.ui.segment {
position: relative;
background: #FFFFFF;
-webkit-box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15);
box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15);
margin: 1rem 0em;
padding: 1em 1em;
border-radius: 0.28571429rem;
border: 1px solid rgba(34, 36, 38, 0.15);
}
.ui.segment:first-child {
margin-top: 0em;
}
.ui.segment:last-child {
margin-bottom: 0em;
}
/* Vertical */
.ui.vertical.segment {
margin: 0em;
padding-left: 0em;
padding-right: 0em;
background: none transparent;
border-radius: 0px;
-webkit-box-shadow: none;
box-shadow: none;
border: none;
border-bottom: 1px solid rgba(34, 36, 38, 0.15);
}
.ui.vertical.segment:last-child {
border-bottom: none;
}
/*-------------------
Loose Coupling
--------------------*/
/* Header */
.ui.inverted.segment > .ui.header {
color: #FFFFFF;
}
/* Label */
.ui[class*="bottom attached"].segment > [class*="top attached"].label {
border-top-left-radius: 0em;
border-top-right-radius: 0em;
}
.ui[class*="top attached"].segment > [class*="bottom attached"].label {
border-bottom-left-radius: 0em;
border-bottom-right-radius: 0em;
}
.ui.attached.segment:not(.top):not(.bottom) > [class*="top attached"].label {
border-top-left-radius: 0em;
border-top-right-radius: 0em;
}
.ui.attached.segment:not(.top):not(.bottom) > [class*="bottom attached"].label {
border-bottom-left-radius: 0em;
border-bottom-right-radius: 0em;
}
/* Grid */
.ui.page.grid.segment,
.ui.grid > .row > .ui.segment.column,
.ui.grid > .ui.segment.column {
padding-top: 2em;
padding-bottom: 2em;
}
.ui.grid.segment {
margin: 1rem 0em;
border-radius: 0.28571429rem;
}
/* Table */
.ui.basic.table.segment {
background: #FFFFFF;
border: 1px solid rgba(34, 36, 38, 0.15);
-webkit-box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15);
box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15);
}
.ui[class*="very basic"].table.segment {
padding: 1em 1em;
}
/*******************************
Types
*******************************/
/*-------------------
Placeholder
--------------------*/
.ui.placeholder.segment {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: stretch;
-ms-flex-align: stretch;
align-items: stretch;
max-width: initial;
-webkit-animation: none;
animation: none;
overflow: visible;
padding: 1em 1em;
min-height: 18rem;
background: #F9FAFB;
border-color: rgba(34, 36, 38, 0.15);
-webkit-box-shadow: 0px 2px 25px 0 rgba(34, 36, 38, 0.05) inset;
box-shadow: 0px 2px 25px 0 rgba(34, 36, 38, 0.05) inset;
}
.ui.placeholder.segment .button,
.ui.placeholder.segment textarea {
display: block;
}
.ui.placeholder.segment .field,
.ui.placeholder.segment textarea,
.ui.placeholder.segment > .ui.input,
.ui.placeholder.segment .button {
max-width: 15rem;
margin-left: auto;
margin-right: auto;
}
.ui.placeholder.segment .column .button,
.ui.placeholder.segment .column .field,
.ui.placeholder.segment .column textarea,
.ui.placeholder.segment .column > .ui.input {
max-width: 15rem;
margin-left: auto;
margin-right: auto;
}
.ui.placeholder.segment > .inline {
-ms-flex-item-align: center;
align-self: center;
}
.ui.placeholder.segment > .inline > .button {
display: inline-block;
width: auto;
margin: 0px 0.35714286rem 0px 0px;
}
.ui.placeholder.segment > .inline > .button:last-child {
margin-right: 0px;
}
/*-------------------
Piled
--------------------*/
.ui.piled.segments,
.ui.piled.segment {
margin: 3em 0em;
-webkit-box-shadow: '';
box-shadow: '';
z-index: auto;
}
.ui.piled.segment:first-child {
margin-top: 0em;
}
.ui.piled.segment:last-child {
margin-bottom: 0em;
}
.ui.piled.segments:after,
.ui.piled.segments:before,
.ui.piled.segment:after,
.ui.piled.segment:before {
background-color: #FFFFFF;
visibility: visible;
content: '';
display: block;
height: 100%;
left: 0px;
position: absolute;
width: 100%;
border: 1px solid rgba(34, 36, 38, 0.15);
-webkit-box-shadow: '';
box-shadow: '';
}
.ui.piled.segments:before,
.ui.piled.segment:before {
-webkit-transform: rotate(-1.2deg);
transform: rotate(-1.2deg);
top: 0;
z-index: -2;
}
.ui.piled.segments:after,
.ui.piled.segment:after {
-webkit-transform: rotate(1.2deg);
transform: rotate(1.2deg);
top: 0;
z-index: -1;
}
/* Piled Attached */
.ui[class*="top attached"].piled.segment {
margin-top: 3em;
margin-bottom: 0em;
}
.ui.piled.segment[class*="top attached"]:first-child {
margin-top: 0em;
}
.ui.piled.segment[class*="bottom attached"] {
margin-top: 0em;
margin-bottom: 3em;
}
.ui.piled.segment[class*="bottom attached"]:last-child {
margin-bottom: 0em;
}
/*-------------------
Stacked
--------------------*/
.ui.stacked.segment {
padding-bottom: 1.4em;
}
.ui.stacked.segments:before,
.ui.stacked.segments:after,
.ui.stacked.segment:before,
.ui.stacked.segment:after {
content: '';
position: absolute;
bottom: -3px;
left: 0%;
border-top: 1px solid rgba(34, 36, 38, 0.15);
background: rgba(0, 0, 0, 0.03);
width: 100%;
height: 6px;
visibility: visible;
}
.ui.stacked.segments:before,
.ui.stacked.segment:before {
display: none;
}
/* Add additional page */
.ui.tall.stacked.segments:before,
.ui.tall.stacked.segment:before {
display: block;
bottom: 0px;
}
/* Inverted */
.ui.stacked.inverted.segments:before,
.ui.stacked.inverted.segments:after,
.ui.stacked.inverted.segment:before,
.ui.stacked.inverted.segment:after {
background-color: rgba(0, 0, 0, 0.03);
border-top: 1px solid rgba(34, 36, 38, 0.35);
}
/*-------------------
Padded
--------------------*/
.ui.padded.segment {
padding: 1.5em;
}
.ui[class*="very padded"].segment {
padding: 3em;
}
/* Padded vertical */
.ui.padded.segment.vertical.segment,
.ui[class*="very padded"].vertical.segment {
padding-left: 0px;
padding-right: 0px;
}
/*-------------------
Compact
--------------------*/
.ui.compact.segment {
display: table;
}
/* Compact Group */
.ui.compact.segments {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
}
.ui.compact.segments .segment,
.ui.segments .compact.segment {
display: block;
-webkit-box-flex: 0;
-ms-flex: 0 1 auto;
flex: 0 1 auto;
}
/*-------------------
Circular
--------------------*/
.ui.circular.segment {
display: table-cell;
padding: 2em;
text-align: center;
vertical-align: middle;
border-radius: 500em;
}
/*-------------------
Raised
--------------------*/
.ui.raised.segments,
.ui.raised.segment {
-webkit-box-shadow: 0px 2px 4px 0px rgba(34, 36, 38, 0.12), 0px 2px 10px 0px rgba(34, 36, 38, 0.15);
box-shadow: 0px 2px 4px 0px rgba(34, 36, 38, 0.12), 0px 2px 10px 0px rgba(34, 36, 38, 0.15);
}
/*******************************
Groups
*******************************/
/* Group */
.ui.segments {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
position: relative;
margin: 1rem 0em;
border: 1px solid rgba(34, 36, 38, 0.15);
-webkit-box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15);
box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15);
border-radius: 0.28571429rem;
}
.ui.segments:first-child {
margin-top: 0em;
}
.ui.segments:last-child {
margin-bottom: 0em;
}
/* Nested Segment */
.ui.segments > .segment {
top: 0px;
bottom: 0px;
border-radius: 0px;
margin: 0em;
width: auto;
-webkit-box-shadow: none;
box-shadow: none;
border: none;
border-top: 1px solid rgba(34, 36, 38, 0.15);
}
.ui.segments:not(.horizontal) > .segment:first-child {
border-top: none;
margin-top: 0em;
bottom: 0px;
margin-bottom: 0em;
top: 0px;
border-radius: 0.28571429rem 0.28571429rem 0em 0em;
}
/* Bottom */
.ui.segments:not(.horizontal) > .segment:last-child {
top: 0px;
bottom: 0px;
margin-top: 0em;
margin-bottom: 0em;
-webkit-box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15), none;
box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15), none;
border-radius: 0em 0em 0.28571429rem 0.28571429rem;
}
/* Only */
.ui.segments:not(.horizontal) > .segment:only-child {
border-radius: 0.28571429rem;
}
/* Nested Group */
.ui.segments > .ui.segments {
border-top: 1px solid rgba(34, 36, 38, 0.15);
margin: 1rem 1rem;
}
.ui.segments > .segments:first-child {
border-top: none;
}
.ui.segments > .segment + .segments:not(.horizontal) {
margin-top: 0em;
}
/* Horizontal Group */
.ui.horizontal.segments {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
background-color: transparent;
border-radius: 0px;
padding: 0em;
background-color: #FFFFFF;
-webkit-box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15);
box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15);
margin: 1rem 0em;
border-radius: 0.28571429rem;
border: 1px solid rgba(34, 36, 38, 0.15);
}
/* Nested Horizontal Group */
.ui.segments > .horizontal.segments {
margin: 0em;
background-color: transparent;
border-radius: 0px;
border: none;
-webkit-box-shadow: none;
box-shadow: none;
border-top: 1px solid rgba(34, 36, 38, 0.15);
}
/* Horizontal Segment */
.ui.horizontal.segments > .segment {
-webkit-box-flex: 1;
flex: 1 1 auto;
-ms-flex: 1 1 0px;
/* Solves #2550 MS Flex */
margin: 0em;
min-width: 0px;
background-color: transparent;
border-radius: 0px;
border: none;
-webkit-box-shadow: none;
box-shadow: none;
border-left: 1px solid rgba(34, 36, 38, 0.15);
}
/* Border Fixes */
.ui.segments > .horizontal.segments:first-child {
border-top: none;
}
.ui.horizontal.segments > .segment:first-child {
border-left: none;
}
/*******************************
States
*******************************/
/*--------------
Disabled
---------------*/
.ui.disabled.segment {
opacity: 0.45;
color: rgba(40, 40, 40, 0.3);
}
/*--------------
Loading
---------------*/
.ui.loading.segment {
position: relative;
cursor: default;
pointer-events: none;
text-shadow: none !important;
color: transparent !important;
-webkit-transition: all 0s linear;
transition: all 0s linear;
}
.ui.loading.segment:before {
position: absolute;
content: '';
top: 0%;
left: 0%;
background: rgba(255, 255, 255, 0.8);
width: 100%;
height: 100%;
border-radius: 0.28571429rem;
z-index: 100;
}
.ui.loading.segment:after {
position: absolute;
content: '';
top: 50%;
left: 50%;
margin: -1.5em 0em 0em -1.5em;
width: 3em;
height: 3em;
-webkit-animation: segment-spin 0.6s linear;
animation: segment-spin 0.6s linear;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
border-radius: 500rem;
border-color: #767676 rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1);
border-style: solid;
border-width: 0.2em;
-webkit-box-shadow: 0px 0px 0px 1px transparent;
box-shadow: 0px 0px 0px 1px transparent;
visibility: visible;
z-index: 101;
}
@-webkit-keyframes segment-spin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes segment-spin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
/*******************************
Variations
*******************************/
/*-------------------
Basic
--------------------*/
.ui.basic.segment {
background: none transparent;
-webkit-box-shadow: none;
box-shadow: none;
border: none;
border-radius: 0px;
}
/*-------------------
Clearing
--------------------*/
.ui.clearing.segment:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
/*-------------------
Colors
--------------------*/
/* Red */
.ui.red.segment:not(.inverted) {
border-top: 2px solid #DB2828 !important;
}
.ui.inverted.red.segment {
background-color: #DB2828 !important;
color: #FFFFFF !important;
}
/* Orange */
.ui.orange.segment:not(.inverted) {
border-top: 2px solid #F2711C !important;
}
.ui.inverted.orange.segment {
background-color: #F2711C !important;
color: #FFFFFF !important;
}
/* Yellow */
.ui.yellow.segment:not(.inverted) {
border-top: 2px solid #FBBD08 !important;
}
.ui.inverted.yellow.segment {
background-color: #FBBD08 !important;
color: #FFFFFF !important;
}
/* Olive */
.ui.olive.segment:not(.inverted) {
border-top: 2px solid #B5CC18 !important;
}
.ui.inverted.olive.segment {
background-color: #B5CC18 !important;
color: #FFFFFF !important;
}
/* Green */
.ui.green.segment:not(.inverted) {
border-top: 2px solid #21BA45 !important;
}
.ui.inverted.green.segment {
background-color: #21BA45 !important;
color: #FFFFFF !important;
}
/* Teal */
.ui.teal.segment:not(.inverted) {
border-top: 2px solid #00B5AD !important;
}
.ui.inverted.teal.segment {
background-color: #00B5AD !important;
color: #FFFFFF !important;
}
/* Blue */
.ui.blue.segment:not(.inverted) {
border-top: 2px solid #2185D0 !important;
}
.ui.inverted.blue.segment {
background-color: #2185D0 !important;
color: #FFFFFF !important;
}
/* Violet */
.ui.violet.segment:not(.inverted) {
border-top: 2px solid #6435C9 !important;
}
.ui.inverted.violet.segment {
background-color: #6435C9 !important;
color: #FFFFFF !important;
}
/* Purple */
.ui.purple.segment:not(.inverted) {
border-top: 2px solid #A333C8 !important;
}
.ui.inverted.purple.segment {
background-color: #A333C8 !important;
color: #FFFFFF !important;
}
/* Pink */
.ui.pink.segment:not(.inverted) {
border-top: 2px solid #E03997 !important;
}
.ui.inverted.pink.segment {
background-color: #E03997 !important;
color: #FFFFFF !important;
}
/* Brown */
.ui.brown.segment:not(.inverted) {
border-top: 2px solid #A5673F !important;
}
.ui.inverted.brown.segment {
background-color: #A5673F !important;
color: #FFFFFF !important;
}
/* Grey */
.ui.grey.segment:not(.inverted) {
border-top: 2px solid #767676 !important;
}
.ui.inverted.grey.segment {
background-color: #767676 !important;
color: #FFFFFF !important;
}
/* Black */
.ui.black.segment:not(.inverted) {
border-top: 2px solid #1B1C1D !important;
}
.ui.inverted.black.segment {
background-color: #1B1C1D !important;
color: #FFFFFF !important;
}
/*-------------------
Aligned
--------------------*/
.ui[class*="left aligned"].segment {
text-align: left;
}
.ui[class*="right aligned"].segment {
text-align: right;
}
.ui[class*="center aligned"].segment {
text-align: center;
}
/*-------------------
Floated
--------------------*/
.ui.floated.segment,
.ui[class*="left floated"].segment {
float: left;
margin-right: 1em;
}
.ui[class*="right floated"].segment {
float: right;
margin-left: 1em;
}
/*-------------------
Inverted
--------------------*/
.ui.inverted.segment {
border: none;
-webkit-box-shadow: none;
box-shadow: none;
}
.ui.inverted.segment,
.ui.primary.inverted.segment {
background: #1B1C1D;
color: rgba(255, 255, 255, 0.9);
}
/* Nested */
.ui.inverted.segment .segment {
color: rgba(0, 0, 0, 0.87);
}
.ui.inverted.segment .inverted.segment {
color: rgba(255, 255, 255, 0.9);
}
/* Attached */
.ui.inverted.attached.segment {
border-color: #555555;
}
/*-------------------
Emphasis
--------------------*/
/* Secondary */
.ui.secondary.segment {
background: #F3F4F5;
color: rgba(0, 0, 0, 0.6);
}
.ui.secondary.inverted.segment {
background: #4c4f52 -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0.2)), to(rgba(255, 255, 255, 0.2)));
background: #4c4f52 -webkit-linear-gradient(rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.2) 100%);
background: #4c4f52 linear-gradient(rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.2) 100%);
color: rgba(255, 255, 255, 0.8);
}
/* Tertiary */
.ui.tertiary.segment {
background: #DCDDDE;
color: rgba(0, 0, 0, 0.6);
}
.ui.tertiary.inverted.segment {
background: #717579 -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0.35)), to(rgba(255, 255, 255, 0.35)));
background: #717579 -webkit-linear-gradient(rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0.35) 100%);
background: #717579 linear-gradient(rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0.35) 100%);
color: rgba(255, 255, 255, 0.8);
}
/*-------------------
Attached
--------------------*/
/* Middle */
.ui.attached.segment {
top: 0px;
bottom: 0px;
border-radius: 0px;
margin: 0em -1px;
width: calc(100% - (-1px * 2));
max-width: calc(100% - (-1px * 2));
-webkit-box-shadow: none;
box-shadow: none;
border: 1px solid #D4D4D5;
}
.ui.attached:not(.message) + .ui.attached.segment:not(.top) {
border-top: none;
}
/* Top */
.ui[class*="top attached"].segment {
bottom: 0px;
margin-bottom: 0em;
top: 0px;
margin-top: 1rem;
border-radius: 0.28571429rem 0.28571429rem 0em 0em;
}
.ui.segment[class*="top attached"]:first-child {
margin-top: 0em;
}
/* Bottom */
.ui.segment[class*="bottom attached"] {
bottom: 0px;
margin-top: 0em;
top: 0px;
margin-bottom: 1rem;
-webkit-box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15), none;
box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15), none;
border-radius: 0em 0em 0.28571429rem 0.28571429rem;
}
.ui.segment[class*="bottom attached"]:last-child {
margin-bottom: 0em;
}
/*-------------------
Size
--------------------*/
.ui.mini.segments .segment,
.ui.mini.segment {
font-size: 0.78571429rem;
}
.ui.tiny.segments .segment,
.ui.tiny.segment {
font-size: 0.85714286rem;
}
.ui.small.segments .segment,
.ui.small.segment {
font-size: 0.92857143rem;
}
.ui.segments .segment,
.ui.segment {
font-size: 1rem;
}
.ui.large.segments .segment,
.ui.large.segment {
font-size: 1.14285714rem;
}
.ui.big.segments .segment,
.ui.big.segment {
font-size: 1.28571429rem;
}
.ui.huge.segments .segment,
.ui.huge.segment {
font-size: 1.42857143rem;
}
.ui.massive.segments .segment,
.ui.massive.segment {
font-size: 1.71428571rem;
}
/*******************************
Theme Overrides
*******************************/
/*******************************
Site Overrides
*******************************/

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save